Skip to main content

gimli/read/
macros.rs

1use crate::common::{DebugMacinfoOffset, SectionId};
2use crate::endianity::Endianity;
3use crate::read::{EndianSlice, Reader, ReaderOffset, Section, UnitRef};
4use crate::{
5    DebugLineOffset, DebugMacroOffset, DebugStrOffset, DebugStrOffsetsIndex, DwMacinfo, DwMacro,
6    Error, Format, Result, constants,
7};
8
9/// The raw contents of the `.debug_macinfo` section.
10#[derive(Debug, Default, Clone, Copy)]
11pub struct DebugMacinfo<R> {
12    pub(crate) section: R,
13}
14
15impl<'input, Endian> DebugMacinfo<EndianSlice<'input, Endian>>
16where
17    Endian: Endianity,
18{
19    /// Construct a new `DebugMacinfo` instance from the data in the `.debug_macinfo`
20    /// section.
21    ///
22    /// It is the caller's responsibility to read the `.debug_macinfo` section and
23    /// present it as a `&[u8]` slice. That means using some ELF loader on
24    /// Linux, a Mach-O loader on macOS, etc.
25    ///
26    /// ```
27    /// use gimli::{DebugMacinfo, LittleEndian};
28    ///
29    /// # let buf = [1, 0, 95, 95, 83, 84, 68, 67, 95, 95, 32, 49, 0];
30    /// # let read_section_somehow = || &buf;
31    /// let debug_str = DebugMacinfo::new(read_section_somehow(), LittleEndian);
32    /// ```
33    pub fn new(macinfo_section: &'input [u8], endian: Endian) -> Self {
34        Self::from(EndianSlice::new(macinfo_section, endian))
35    }
36}
37
38impl<R: Reader> DebugMacinfo<R> {
39    /// Look up a macro reference the `.debug_macinfo` section by DebugMacinfoOffset.
40    ///
41    /// A macinfo offset points to a list of macro information entries in the `.debug_macinfo` section.
42    /// To handle this, the function returns an iterator.
43    ///
44    /// ```
45    /// use gimli::{DebugMacinfo, DebugMacinfoOffset, LittleEndian};
46    ///
47    /// # fn main() -> Result<(), gimli::Error> {
48    /// # let buf = [1, 0, 95, 95, 83, 84, 68, 67, 95, 95, 32, 49, 0, 0];
49    /// # let offset = DebugMacinfoOffset(0);
50    /// # let read_section_somehow = || &buf;
51    /// # let debug_macinfo_offset_somehow = || offset;
52    /// let debug_macinfo = DebugMacinfo::new(read_section_somehow(), LittleEndian);
53    /// let mut iter = debug_macinfo.get_macinfo(debug_macinfo_offset_somehow())?;
54    /// while let Some(macinfo) = iter.next()? {
55    ///     println!("Found macro info {:?}", macinfo);
56    /// }
57    /// # Ok(()) }
58    /// ```
59    pub fn get_macinfo(&self, offset: DebugMacinfoOffset<R::Offset>) -> Result<MacroIter<R>> {
60        let mut input = self.section.clone();
61        input.skip(offset.0)?;
62        Ok(MacroIter {
63            input,
64            format: Format::Dwarf32,
65            is_macro: false,
66        })
67    }
68}
69
70impl<T> DebugMacinfo<T> {
71    /// Create a `DebugMacinfo` section that references the data in `self`.
72    ///
73    /// This is useful when `R` implements `Reader` but `T` does not.
74    ///
75    /// Used by `DwarfSections::borrow`.
76    pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugMacinfo<R>
77    where
78        F: FnMut(&'a T) -> R,
79    {
80        borrow(&self.section).into()
81    }
82}
83
84impl<R> Section<R> for DebugMacinfo<R> {
85    fn id() -> SectionId {
86        SectionId::DebugMacinfo
87    }
88
89    fn reader(&self) -> &R {
90        &self.section
91    }
92}
93
94impl<R> From<R> for DebugMacinfo<R> {
95    fn from(macinfo_section: R) -> Self {
96        DebugMacinfo {
97            section: macinfo_section,
98        }
99    }
100}
101
102/// The raw contents of the `.debug_macro` section.
103#[derive(Debug, Default, Clone, Copy)]
104pub struct DebugMacro<R> {
105    pub(crate) section: R,
106}
107
108impl<'input, Endian> DebugMacro<EndianSlice<'input, Endian>>
109where
110    Endian: Endianity,
111{
112    /// Construct a new `DebugMacro` instance from the data in the `.debug_macro`
113    /// section.
114    ///
115    /// It is the caller's responsibility to read the `.debug_macro` section and
116    /// present it as a `&[u8]` slice. That means using some ELF loader on
117    /// Linux, a Mach-O loader on macOS, etc.
118    ///
119    /// ```
120    /// use gimli::{DebugMacro, LittleEndian};
121    ///
122    /// # let buf = [1, 0, 95, 95, 83, 84, 68, 67, 95, 95, 32, 49, 0];
123    /// # let read_section_somehow = || &buf;
124    /// let debug_str = DebugMacro::new(read_section_somehow(), LittleEndian);
125    /// ```
126    pub fn new(macro_section: &'input [u8], endian: Endian) -> Self {
127        Self::from(EndianSlice::new(macro_section, endian))
128    }
129}
130
131impl<R: Reader> DebugMacro<R> {
132    /// Look up a macro reference the `.debug_macinfo` section by DebugMacroOffset.
133    ///
134    /// A macinfo offset points to a list of macro information entries in the `.debug_macinfo` section.
135    /// To handle this, the function returns an iterator.
136    ///
137    /// ```
138    /// use gimli::{DebugMacro, DebugMacroOffset, LittleEndian};
139    ///
140    /// # fn main() -> Result<(), gimli::Error> {
141    /// # let buf = [0x05, 0x00, 0x00, 0x01, 0x00, 0x5f, 0x5f, 0x53, 0x54, 0x44, 0x43, 0x5f, 0x5f, 0x20, 0x31, 0x00, 0x00];
142    /// # let offset = DebugMacroOffset(0);
143    /// # let read_section_somehow = || &buf;
144    /// # let debug_macro_offset_somehow = || offset;
145    /// let debug_macro = DebugMacro::new(read_section_somehow(), LittleEndian);
146    /// let mut iter = debug_macro.get_macros(debug_macro_offset_somehow())?;
147    /// while let Some(cur_macro) = iter.next()? {
148    ///     println!("Found macro info {:?}", cur_macro);
149    /// }
150    /// # Ok(()) }
151    /// ```
152    pub fn get_macros(&self, offset: DebugMacroOffset<R::Offset>) -> Result<MacroIter<R>> {
153        let mut input = self.section.clone();
154        input.skip(offset.0)?;
155        let header = MacroUnitHeader::parse(&mut input)?;
156        Ok(MacroIter {
157            input,
158            format: header.format(),
159            is_macro: true,
160        })
161    }
162}
163
164impl<T> DebugMacro<T> {
165    /// Create a `DebugMacro` section that references the data in `self`.
166    ///
167    /// This is useful when `R` implements `Reader` but `T` does not.
168    ///
169    /// Used by `DwarfSections::borrow`.
170    pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugMacro<R>
171    where
172        F: FnMut(&'a T) -> R,
173    {
174        borrow(&self.section).into()
175    }
176}
177
178impl<R> Section<R> for DebugMacro<R> {
179    fn id() -> SectionId {
180        SectionId::DebugMacro
181    }
182
183    fn reader(&self) -> &R {
184        &self.section
185    }
186}
187
188impl<R> From<R> for DebugMacro<R> {
189    fn from(macro_section: R) -> Self {
190        DebugMacro {
191            section: macro_section,
192        }
193    }
194}
195
196#[derive(Debug, Clone)]
197struct MacroUnitHeader<R: Reader> {
198    /// The version of the macro unit header. At the moment only version 5 is defined.
199    _version: u16,
200    flags: u8,
201    _debug_line_offset: DebugLineOffset<R::Offset>,
202}
203
204impl<R: Reader> MacroUnitHeader<R> {
205    const OFFSET_SIZE_FLAG: u8 = 0b0000_0001;
206    const DEBUG_LINE_OFFSET_FLAG: u8 = 0b0000_0010;
207    const OPCODE_OPERANDS_TABLE_FLAG: u8 = 0b0000_0100;
208
209    fn parse(input: &mut R) -> Result<Self> {
210        let version = input.read_u16()?;
211        let flags = input.read_u8()?;
212        let format = if flags & Self::OFFSET_SIZE_FLAG == 0 {
213            Format::Dwarf32
214        } else {
215            Format::Dwarf64
216        };
217        let _debug_line_offset = if flags & Self::DEBUG_LINE_OFFSET_FLAG != 0 {
218            DebugLineOffset(input.read_offset(format)?)
219        } else {
220            DebugLineOffset(R::Offset::from_u64(0)?)
221        };
222        // if the opcode operands table flag is set, there is a table in the header which currently isn't parsed
223        if flags & Self::OPCODE_OPERANDS_TABLE_FLAG != 0 {
224            return Err(Error::UnsupportedOpcodeOperandsTable);
225        }
226        Ok(MacroUnitHeader {
227            _version: version,
228            flags,
229            _debug_line_offset,
230        })
231    }
232
233    fn format(&self) -> Format {
234        if self.flags & Self::OFFSET_SIZE_FLAG == 0 {
235            Format::Dwarf32
236        } else {
237            Format::Dwarf64
238        }
239    }
240}
241
242/// A string in a macro entry.
243#[derive(Debug, Clone, PartialEq, Eq)]
244pub enum MacroString<R, Offset = <R as Reader>::Offset>
245where
246    R: Reader<Offset = Offset>,
247    Offset: ReaderOffset,
248{
249    /// The string is directly embedded in the macro entry
250    Direct(R),
251    /// The macro refers to a string in the `.debug_str` section using a `DebugStrOffset`.
252    StringPointer(DebugStrOffset<Offset>),
253    /// The macro contains an index into an array in the `.debug_str_offsets`
254    /// section, which refers to a string in the `.debug_str` section.
255    IndirectStringPointer(DebugStrOffsetsIndex<Offset>),
256    /// The macro refers to a string in the `.debug_str` section in the supplementary object file
257    Supplementary(DebugStrOffset<Offset>),
258}
259
260impl<R: Reader> MacroString<R> {
261    /// Get the string slice from the macro entry.
262    pub fn string(&self, unit: UnitRef<'_, R>) -> Result<R> {
263        match self {
264            MacroString::Direct(s) => Ok(s.clone()),
265            MacroString::StringPointer(offset) => unit.string(*offset),
266            MacroString::IndirectStringPointer(index) => {
267                let str_offset = unit.string_offset(*index)?;
268                unit.string(str_offset)
269            }
270            MacroString::Supplementary(offset) => unit.sup_string(*offset),
271        }
272    }
273}
274
275/// an Entry in the `.debug_macro` section.
276#[derive(Debug, Clone, PartialEq, Eq)]
277pub enum MacroEntry<R, Offset = <R as Reader>::Offset>
278where
279    R: Reader<Offset = Offset>,
280    Offset: ReaderOffset,
281{
282    /// A macro definition.
283    Define {
284        /// The line number where the macro is defined.
285        line: u64,
286        /// The text of the macro: The name of the macro followed immediately by any formal
287        /// parameters including the surrounding parentheses, followed by the macro definition.
288        text: MacroString<R>,
289    },
290    /// A macro undefinition.
291    Undef {
292        /// The line number where the macro is undefined.
293        line: u64,
294        /// The name of the macro without the definition.
295        name: MacroString<R>,
296    },
297    /// The start of a file.
298    StartFile {
299        /// Line number of the source file on which the inclusion macro directive occurred.
300        line: u64,
301        /// An index into the line number table of the compilation unit.
302        file: u64,
303    },
304    /// The end of the current included file.
305    EndFile,
306    /// import a macro unit
307    Import {
308        /// offset of the macro unit in the `.debug_macro` section
309        offset: DebugMacroOffset<Offset>,
310    },
311    /// import a macro unit from the supplementary object file
312    ImportSup {
313        /// offset of the macro unit in the `.debug_macro` section of the supplementary object file
314        offset: DebugMacroOffset<Offset>,
315    },
316    /// A vendor-specific extension.
317    VendorExt {
318        /// A numeric constant, whose meaning is vendor specific.
319        numeric: u64,
320        /// A string whose meaning is vendor specific.
321        string: R,
322    },
323}
324
325/// Iterator over the entries in the `.debug_macro` section.
326#[derive(Clone, Debug)]
327pub struct MacroIter<R: Reader> {
328    input: R,
329    format: Format,
330    is_macro: bool,
331}
332
333impl<R: Reader> MacroIter<R> {
334    /// Advance the iterator to the next entry in the `.debug_macro` section.
335    pub fn next(&mut self) -> Result<Option<MacroEntry<R>>> {
336        // DW_MACINFO_* and DW_MACRO_* have the same values, so we can use the same parsing logic.
337        let macro_type = DwMacro(self.input.read_u8()?);
338        match macro_type {
339            DwMacro(0) => {
340                self.input.empty();
341                Ok(None)
342            }
343            constants::DW_MACRO_define => {
344                let line = self.input.read_uleb128()?;
345                let text = self.input.read_null_terminated_slice()?;
346                Ok(Some(MacroEntry::Define {
347                    line,
348                    text: MacroString::Direct(text),
349                }))
350            }
351            constants::DW_MACRO_undef => {
352                let line = self.input.read_uleb128()?;
353                let name = self.input.read_null_terminated_slice()?;
354                Ok(Some(MacroEntry::Undef {
355                    line,
356                    name: MacroString::Direct(name),
357                }))
358            }
359            constants::DW_MACRO_start_file => {
360                let line = self.input.read_uleb128()?;
361                let file = self.input.read_uleb128()?;
362                Ok(Some(MacroEntry::StartFile { line, file }))
363            }
364            constants::DW_MACRO_end_file => Ok(Some(MacroEntry::EndFile)),
365            constants::DW_MACRO_define_strp if self.is_macro => {
366                let line = self.input.read_uleb128()?;
367                let text_offset = DebugStrOffset(self.input.read_offset(self.format)?);
368                Ok(Some(MacroEntry::Define {
369                    line,
370                    text: MacroString::StringPointer(text_offset),
371                }))
372            }
373            constants::DW_MACRO_undef_strp if self.is_macro => {
374                let line = self.input.read_uleb128()?;
375                let name_offset = DebugStrOffset(self.input.read_offset(self.format)?);
376                Ok(Some(MacroEntry::Undef {
377                    line,
378                    name: MacroString::StringPointer(name_offset),
379                }))
380            }
381            constants::DW_MACRO_import if self.is_macro => {
382                let offset = DebugMacroOffset(self.input.read_offset(self.format)?);
383                Ok(Some(MacroEntry::Import { offset }))
384            }
385            constants::DW_MACRO_define_sup if self.is_macro => {
386                let line = self.input.read_uleb128()?;
387                let text_offset = DebugStrOffset(self.input.read_offset(self.format)?);
388                Ok(Some(MacroEntry::Define {
389                    line,
390                    text: MacroString::Supplementary(text_offset),
391                }))
392            }
393            constants::DW_MACRO_undef_sup if self.is_macro => {
394                let line = self.input.read_uleb128()?;
395                let name_offset = DebugStrOffset(self.input.read_offset(self.format)?);
396                Ok(Some(MacroEntry::Undef {
397                    line,
398                    name: MacroString::Supplementary(name_offset),
399                }))
400            }
401            constants::DW_MACRO_import_sup if self.is_macro => {
402                let offset = DebugMacroOffset(self.input.read_offset(self.format)?);
403                Ok(Some(MacroEntry::ImportSup { offset }))
404            }
405            constants::DW_MACRO_define_strx if self.is_macro => {
406                let line = self.input.read_uleb128()?;
407                let index = self.input.read_uleb128().and_then(R::Offset::from_u64)?;
408                let text_index = DebugStrOffsetsIndex(index);
409                Ok(Some(MacroEntry::Define {
410                    line,
411                    text: MacroString::IndirectStringPointer(text_index),
412                }))
413            }
414            constants::DW_MACRO_undef_strx if self.is_macro => {
415                let line = self.input.read_uleb128()?;
416                let index = self.input.read_uleb128().and_then(R::Offset::from_u64)?;
417                let name_index = DebugStrOffsetsIndex(index);
418                Ok(Some(MacroEntry::Undef {
419                    line,
420                    name: MacroString::IndirectStringPointer(name_index),
421                }))
422            }
423            _ => {
424                if self.is_macro {
425                    self.input.empty();
426                    Err(Error::InvalidMacroType(macro_type))
427                } else if macro_type.0 == constants::DW_MACINFO_vendor_ext.0 {
428                    let numeric = self.input.read_uleb128()?;
429                    let string = self.input.read_null_terminated_slice()?;
430                    Ok(Some(MacroEntry::VendorExt { numeric, string }))
431                } else {
432                    self.input.empty();
433                    Err(Error::InvalidMacinfoType(DwMacinfo(macro_type.0)))
434                }
435            }
436        }
437    }
438}
439
440#[cfg(feature = "fallible-iterator")]
441impl<R: Reader> fallible_iterator::FallibleIterator for MacroIter<R> {
442    type Item = MacroEntry<R>;
443    type Error = Error;
444
445    fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Error> {
446        MacroIter::next(self)
447    }
448}
449
450impl<R: Reader> Iterator for MacroIter<R> {
451    type Item = Result<MacroEntry<R>>;
452
453    fn next(&mut self) -> Option<Self::Item> {
454        MacroIter::next(self).transpose()
455    }
456}
457
458#[cfg(test)]
459mod tests {
460    use super::*;
461    use crate::{DebugStr, LittleEndian, test_util::GimliSectionMethods};
462    use test_assembler::{Endian, Label, LabelMaker, Section};
463
464    #[test]
465    fn test_get_macinfo() {
466        let position = Label::new();
467
468        // Create a test section with some macinfo entries
469        let section = Section::with_endian(Endian::Little)
470            .set_start_const(0)
471            .mark(&position)
472            .D8(crate::DW_MACINFO_define.0)
473            .uleb(0) // line number: 0 - defined on the compiler command line
474            .append_bytes(b"__STDC__ 1\0")
475            .D8(crate::DW_MACINFO_define.0)
476            .uleb(1) // line number: 1 - defined in the source file
477            .append_bytes(b"__GNUC__ 1\0")
478            .D8(crate::DW_MACINFO_undef.0)
479            .uleb(2) // line number: 2 - undefined in the source file
480            .append_bytes(b"__GNUC__\0")
481            .D8(crate::DW_MACINFO_start_file.0)
482            .uleb(3) // line number: 3 - start of file
483            .uleb(4) // file number index: 4 - index into the line number table
484            .D8(crate::DW_MACINFO_end_file.0) // end of file
485            .D8(crate::DW_MACINFO_vendor_ext.0)
486            .uleb(5) // numeric constant: 5 - vendor specific
487            .append_bytes(b"foo\0")
488            .D8(0); // end of unit
489
490        // Create a DebugMacinfo instance from the section
491        let section = section.get_contents().unwrap();
492        let debug_macinfo = DebugMacinfo::from(EndianSlice::new(&section, LittleEndian));
493
494        let offset = position.value().unwrap() as usize;
495
496        let mut iter = debug_macinfo
497            .get_macinfo(DebugMacinfoOffset(offset))
498            .unwrap();
499
500        // Test getting macinfo entries
501        let entry = iter.next().unwrap().unwrap();
502        assert!(
503            matches!(entry, MacroEntry::Define { line: 0, text: MacroString::Direct(text) } if text.slice() == b"__STDC__ 1")
504        );
505
506        let entry = iter.next().unwrap().unwrap();
507        assert!(
508            matches!(entry, MacroEntry::Define { line: 1, text: MacroString::Direct(text) } if text.slice() == b"__GNUC__ 1")
509        );
510
511        let entry = iter.next().unwrap().unwrap();
512        assert!(
513            matches!(entry, MacroEntry::Undef { line: 2, name: MacroString::Direct(name) } if name.slice() == b"__GNUC__")
514        );
515
516        let entry = iter.next().unwrap().unwrap();
517        assert!(matches!(entry, MacroEntry::StartFile { line: 3, file: 4 }));
518
519        let entry = iter.next().unwrap().unwrap();
520        assert!(matches!(entry, MacroEntry::EndFile));
521
522        let entry = iter.next().unwrap().unwrap();
523        assert!(
524            matches!(entry, MacroEntry::VendorExt { numeric: 5, string } if string.slice() == b"foo")
525        );
526
527        assert_eq!(iter.next(), Ok(None));
528    }
529
530    #[test]
531    fn get_macros_1() {
532        let position = Label::new();
533
534        // The test data is originally from the DWARF v5 standard, appendix D.16
535        // 1) Figure D.71, simple DWARF encoding
536        let section = Section::with_endian(Endian::Little)
537            .set_start_const(0)
538            .mark(&position)
539            .D16(5) // Dwarf version
540            .D8(0b0000_0010) // Flags: offset_size = 0 (32-bit), debug_line_offset = 1, opcode_operands_table = 0
541            .D32(0) // debug line offset
542            .D8(crate::DW_MACRO_start_file.0) // start file: "a.c"
543            .uleb(0) // line number
544            .uleb(0) // file number
545            .D8(crate::DW_MACRO_start_file.0) // start file: "a.h"
546            .uleb(1) // line number
547            .uleb(1) // file number
548            .D8(crate::DW_MACRO_define.0) // define
549            .uleb(1) // line number
550            .append_bytes(b"LONGER_MACRO 1\0") // macro name
551            .D8(crate::DW_MACRO_define.0) // define
552            .uleb(2) // line number
553            .append_bytes(b"B 2\0") // macro name
554            .D8(crate::DW_MACRO_start_file.0) // start file: "b.h"
555            .uleb(3) // line number
556            .uleb(2) // file number
557            .D8(crate::DW_MACRO_undef.0) // undef
558            .uleb(1) // line number
559            .append_bytes(b"B\0") // macro name
560            .D8(crate::DW_MACRO_define.0) // define
561            .uleb(2) // line number
562            .append_bytes(b"D 3\0") // macro name
563            .D8(crate::DW_MACRO_define.0) // define
564            .uleb(3) // line number
565            .append_bytes(b"FUNCTION_LIKE_MACRO(x) 4+x\0") // macro name
566            .D8(crate::DW_MACRO_end_file.0) // end file: "b.h" -> "a.h"
567            .D8(crate::DW_MACRO_define.0) // define
568            .uleb(4) // line number
569            .append_bytes(b"B 3\0") // macro name
570            .D8(crate::DW_MACRO_end_file.0) // end file: "a.h" -> "a.c"
571            .D8(crate::DW_MACRO_define.0) // define
572            .uleb(2) // line number
573            .append_bytes(b"FUNCTION_LIKE_MACRO(x) 4+x\0") // macro name
574            .D8(crate::DW_MACRO_start_file.0) // start file: "b.h"
575            .uleb(3) // line number
576            .uleb(2) // file number
577            .D8(crate::DW_MACRO_undef.0) // undef
578            .uleb(1) // line number
579            .append_bytes(b"B\0") // macro name
580            .D8(crate::DW_MACRO_define.0) // define
581            .uleb(2) // line number
582            .append_bytes(b"D 3\0") // macro name
583            .D8(crate::DW_MACRO_define.0) // define
584            .uleb(3) // line number
585            .append_bytes(b"FUNCTION_LIKE_MACRO(x) 4+x\0") // macro name
586            .D8(crate::DW_MACRO_end_file.0) // end file: "b.h" -> "a.c"
587            .D8(crate::DW_MACRO_end_file.0) // end file: "a.c" -> ""
588            .D8(0); // end of unit
589
590        // Create a DebugMacro instance from the section
591        let section = section.get_contents().unwrap();
592        let debug_macro = DebugMacro::from(EndianSlice::new(&section, LittleEndian));
593
594        let offset = position.value().unwrap() as usize;
595
596        let mut iter = debug_macro.get_macros(DebugMacroOffset(offset)).unwrap();
597        let entry = iter.next().unwrap().unwrap();
598        assert!(matches!(entry, MacroEntry::StartFile { line: 0, file: 0 }));
599        let entry = iter.next().unwrap().unwrap();
600        assert!(matches!(entry, MacroEntry::StartFile { line: 1, file: 1 }));
601        let entry = iter.next().unwrap().unwrap();
602        assert!(matches!(
603            entry,
604            MacroEntry::Define {
605                line: 1, text: MacroString::Direct(text)
606            } if text.slice() == b"LONGER_MACRO 1"
607        ));
608        let entry = iter.next().unwrap().unwrap();
609        assert!(matches!(
610            entry,
611            MacroEntry::Define {
612                line: 2, text: MacroString::Direct(text)
613            } if text.slice() == b"B 2"
614        ));
615        let entry = iter.next().unwrap().unwrap();
616        assert!(matches!(entry, MacroEntry::StartFile { line: 3, file: 2 }));
617        let entry = iter.next().unwrap().unwrap();
618        assert!(matches!(
619            entry,
620            MacroEntry::Undef {
621                line: 1, name: MacroString::Direct(name)
622            } if name.slice() == b"B"
623        ));
624        let entry = iter.next().unwrap().unwrap();
625        assert!(matches!(
626            entry,
627            MacroEntry::Define {
628                line: 2, text: MacroString::Direct(text)
629            } if text.slice() == b"D 3"
630        ));
631        let entry = iter.next().unwrap().unwrap();
632        assert!(matches!(
633            entry,
634            MacroEntry::Define {
635                line: 3, text: MacroString::Direct(text)
636            } if text.slice() == b"FUNCTION_LIKE_MACRO(x) 4+x"
637        ));
638        let entry = iter.next().unwrap().unwrap();
639        assert!(matches!(entry, MacroEntry::EndFile));
640        let entry = iter.next().unwrap().unwrap();
641        assert!(matches!(
642            entry,
643            MacroEntry::Define {
644                line: 4, text: MacroString::Direct(text)
645            } if text.slice() == b"B 3"
646        ));
647        let entry = iter.next().unwrap().unwrap();
648        assert!(matches!(entry, MacroEntry::EndFile));
649        let entry = iter.next().unwrap().unwrap();
650        assert!(matches!(
651            entry,
652            MacroEntry::Define {
653                line: 2, text: MacroString::Direct(text)
654            } if text.slice() == b"FUNCTION_LIKE_MACRO(x) 4+x"
655        ));
656        let entry = iter.next().unwrap().unwrap();
657        assert!(matches!(entry, MacroEntry::StartFile { line: 3, file: 2 }));
658        let entry = iter.next().unwrap().unwrap();
659        assert!(matches!(
660            entry,
661            MacroEntry::Undef {
662                line: 1, name: MacroString::Direct(name)
663            } if name.slice() == b"B"
664        ));
665        let entry = iter.next().unwrap().unwrap();
666        assert!(matches!(
667            entry,
668            MacroEntry::Define {
669                line: 2, text: MacroString::Direct(text)
670            } if text.slice() == b"D 3"
671        ));
672        let entry = iter.next().unwrap().unwrap();
673        assert!(matches!(
674            entry,
675            MacroEntry::Define {
676                line: 3, text: MacroString::Direct(text)
677            } if text.slice() == b"FUNCTION_LIKE_MACRO(x) 4+x"
678        ));
679        let entry = iter.next().unwrap().unwrap();
680        assert!(matches!(entry, MacroEntry::EndFile));
681        let entry = iter.next().unwrap().unwrap();
682        assert!(matches!(entry, MacroEntry::EndFile));
683        assert_eq!(iter.next(), Ok(None));
684    }
685
686    #[test]
687    fn get_macros_2() {
688        let str_0 = Label::new();
689        let str_1 = Label::new();
690        let macro_unit_0 = Label::new();
691        let macro_unit_1 = Label::new();
692        let macro_unit_2 = Label::new();
693
694        // The test data is originally from the DWARF v5 standard, appendix D.16
695        // 2) Figure D.72, shareable DWARF encoding
696        let str_section = Section::with_endian(Endian::Little)
697            .set_start_const(0)
698            .mark(&str_0)
699            .append_bytes(b"FUNCTION_LIKE_MACRO(x) 4+x\0") // macro name
700            .mark(&str_1)
701            .append_bytes(b"LONGER_MACRO 1\0"); // macro name
702
703        let macro_section = Section::with_endian(Endian::Little)
704            .set_start_const(0)
705            //--------------------unit 0----------------------
706            .mark(&macro_unit_0) // start of unit 0
707            .D16(5) // Dwarf version
708            .D8(0b0000_0010) // Flags: offset_size = 0 (32-bit), debug_line_offset = 1, opcode_operands_table = 0
709            .D32(0) // debug line offset
710            .D8(crate::DW_MACRO_start_file.0) // start file: "a.c"
711            .uleb(0) // line number
712            .uleb(0) // file number
713            .D8(crate::DW_MACRO_start_file.0) // start file: "a.h"
714            .uleb(1) // line number
715            .uleb(1) // file number
716            .D8(crate::DW_MACRO_import.0) // import unit 1
717            .L32(macro_unit_1.clone()) // debug line offset to unit 1
718            .D8(crate::DW_MACRO_start_file.0) // start file: "b.h"
719            .uleb(3) // line number
720            .uleb(2) // file number
721            .D8(crate::DW_MACRO_import.0) // import unit 2
722            .L32(macro_unit_2.clone()) // debug line offset to unit 2
723            .D8(crate::DW_MACRO_end_file.0) // end file: "b.h" -> "a.h"
724            .D8(crate::DW_MACRO_define.0) // define
725            .uleb(4) // line number
726            .append_bytes(b"B 3\0") // macro name
727            .D8(crate::DW_MACRO_end_file.0) // end file: "a.h" -> "a.c"
728            .D8(crate::DW_MACRO_define_strp.0) // define: "FUNCTION_LIKE_MACRO(x) 4+x"
729            .uleb(2) // line number
730            .D32(0) // macro name offset in the string table
731            .D8(crate::DW_MACRO_start_file.0) // start file: "b.h"
732            .uleb(3) // line number
733            .uleb(2) // file number
734            .D8(crate::DW_MACRO_import.0) // import unit 2
735            .L32(&macro_unit_2) // debug line offset to unit 2
736            .D8(crate::DW_MACRO_end_file.0) // end file: "b.h" -> "a.c"
737            .D8(crate::DW_MACRO_end_file.0) // end file: "a.c" -> ""
738            .D8(0)
739            //--------------------unit 1----------------------
740            .mark(&macro_unit_1) // start of unit 1
741            .D16(5) // Dwarf version
742            .D8(0b0000_0000) // Flags: offset_size = 0 (32-bit), debug_line_offset = 0, opcode_operands_table = 0
743            .D8(crate::DW_MACRO_define_strp.0) // define strp: "LONGER_MACRO 1"
744            .uleb(1) // line number
745            .L32(str_0.clone()) // macro name offset in the string table
746            .D8(crate::DW_MACRO_define.0) // define: "B 2"
747            .uleb(2) // line number
748            .append_bytes(b"B 2\0") // macro name
749            .D8(0) // end of unit
750            //---------------------unit 2---------------------
751            .mark(&macro_unit_2) // start of unit 2
752            .D16(5) // Dwarf version
753            .D8(0b0000_0000) // Flags: offset_size = 0 (32-bit), debug_line_offset = 0, opcode_operands_table = 0
754            .D8(crate::DW_MACRO_undef.0) // undef: "B"
755            .uleb(1) // line number
756            .append_bytes(b"B\0") // macro name
757            .D8(crate::DW_MACRO_define.0) // define: "D 3"
758            .uleb(2) // line number
759            .append_bytes(b"D 3\0") // macro name
760            .D8(crate::DW_MACRO_define_strp.0) // define strp: "FUNCTION_LIKE_MACRO(x) 4+x"
761            .uleb(2) // line number
762            .L32(str_1.clone()) // macro name offset in the string table
763            .D8(0); // end of unit
764
765        // Create a DebugMacro instance from the section
766        let str_section = str_section.get_contents().unwrap();
767        let debug_str = DebugStr::from(EndianSlice::new(&str_section, LittleEndian));
768
769        // Create a DebugMacro instance from the section
770        let macro_section = macro_section.get_contents().unwrap();
771        let debug_macro = DebugMacro::from(EndianSlice::new(&macro_section, LittleEndian));
772
773        // check the content of macro unit 0
774        let offset = macro_unit_0.value().unwrap() as usize;
775        let mut iter = debug_macro.get_macros(DebugMacroOffset(offset)).unwrap();
776        let entry = iter.next().unwrap().unwrap();
777        assert!(matches!(entry, MacroEntry::StartFile { line: 0, file: 0 }));
778        let entry = iter.next().unwrap().unwrap();
779        assert!(matches!(entry, MacroEntry::StartFile { line: 1, file: 1 }));
780        let entry = iter.next().unwrap().unwrap();
781        assert!(matches!(
782            entry,
783            MacroEntry::Import { offset } if offset.0 == macro_unit_1.value().unwrap() as usize
784        ));
785        let entry = iter.next().unwrap().unwrap();
786        assert!(matches!(entry, MacroEntry::StartFile { line: 3, file: 2 }));
787        let entry = iter.next().unwrap().unwrap();
788        assert!(matches!(
789            entry,
790            MacroEntry::Import { offset } if offset.0 == macro_unit_2.value().unwrap() as usize
791        ));
792        let entry = iter.next().unwrap().unwrap();
793        assert!(matches!(entry, MacroEntry::EndFile));
794        let entry = iter.next().unwrap().unwrap();
795        assert!(matches!(
796            entry,
797            MacroEntry::Define {
798                line: 4, text: MacroString::Direct(text)
799            } if text.slice() == b"B 3"
800        ));
801        let entry = iter.next().unwrap().unwrap();
802        assert!(matches!(entry, MacroEntry::EndFile));
803        let entry = iter.next().unwrap().unwrap();
804        assert!(matches!(
805            entry,
806            MacroEntry::Define {
807                line: 2, text: MacroString::StringPointer(text_offset)
808            } if text_offset.0 == str_0.value().unwrap() as usize
809        ));
810        let entry = iter.next().unwrap().unwrap();
811        assert!(matches!(entry, MacroEntry::StartFile { line: 3, file: 2 }));
812        let entry = iter.next().unwrap().unwrap();
813        assert!(matches!(
814            entry,
815            MacroEntry::Import { offset } if offset.0 == macro_unit_2.value().unwrap() as usize
816        ));
817        let entry = iter.next().unwrap().unwrap();
818        assert!(matches!(entry, MacroEntry::EndFile));
819        let entry = iter.next().unwrap().unwrap();
820        assert!(matches!(entry, MacroEntry::EndFile));
821        assert_eq!(iter.next(), Ok(None));
822
823        // check the content of macro unit 1
824        let offset = macro_unit_1.value().unwrap() as usize;
825        let mut iter = debug_macro.get_macros(DebugMacroOffset(offset)).unwrap();
826        let entry = iter.next().unwrap().unwrap();
827        assert!(matches!(
828            entry,
829            MacroEntry::Define {
830                line: 1, text: MacroString::StringPointer(text_offset)
831            } if text_offset.0 == str_0.value().unwrap() as usize
832        ));
833        let entry = iter.next().unwrap().unwrap();
834        assert!(matches!(
835            entry,
836            MacroEntry::Define {
837                line: 2, text: MacroString::Direct(text)
838            } if text.slice() == b"B 2"
839        ));
840        assert_eq!(iter.next(), Ok(None));
841
842        // check the content of macro unit 2
843        let offset = macro_unit_2.value().unwrap() as usize;
844        let mut iter = debug_macro.get_macros(DebugMacroOffset(offset)).unwrap();
845        let entry = iter.next().unwrap().unwrap();
846        assert!(matches!(
847            entry,
848            MacroEntry::Undef {
849                line: 1, name: MacroString::Direct(name)
850            } if name.slice() == b"B"
851        ));
852        let entry = iter.next().unwrap().unwrap();
853        assert!(matches!(
854            entry,
855            MacroEntry::Define {
856                line: 2, text: MacroString::Direct(text)
857            } if text.slice() == b"D 3"
858        ));
859        let entry = iter.next().unwrap().unwrap();
860        assert!(matches!(
861            entry,
862            MacroEntry::Define {
863                line: 2, text: MacroString::StringPointer(text_offset)
864            } if text_offset.0 == str_1.value().unwrap() as usize
865        ));
866        assert_eq!(iter.next(), Ok(None));
867
868        // check the content of the string table
869        let text_offset = DebugStrOffset(str_0.value().unwrap() as usize);
870        assert_eq!(
871            debug_str.get_str(text_offset).unwrap().slice(),
872            b"FUNCTION_LIKE_MACRO(x) 4+x"
873        );
874        let text_offset = DebugStrOffset(str_1.value().unwrap() as usize);
875        assert_eq!(
876            debug_str.get_str(text_offset).unwrap().slice(),
877            b"LONGER_MACRO 1"
878        );
879    }
880}