gimli/read/
macros.rs

1use crate::common::{DebugMacinfoOffset, SectionId};
2use crate::endianity::Endianity;
3use crate::read::{EndianSlice, Reader, ReaderOffset, Section, UnitRef};
4use crate::{
5    constants, DebugLineOffset, DebugMacroOffset, DebugStrOffset, DebugStrOffsetsIndex, DwMacinfo,
6    DwMacro, Error, Format, Result,
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
450#[cfg(test)]
451mod tests {
452    use super::*;
453    use crate::{test_util::GimliSectionMethods, DebugStr, LittleEndian};
454    use test_assembler::{Endian, Label, LabelMaker, Section};
455
456    #[test]
457    fn test_get_macinfo() {
458        let position = Label::new();
459
460        // Create a test section with some macinfo entries
461        let section = Section::with_endian(Endian::Little)
462            .set_start_const(0)
463            .mark(&position)
464            .D8(crate::DW_MACINFO_define.0)
465            .uleb(0) // line number: 0 - defined on the compiler command line
466            .append_bytes(b"__STDC__ 1\0")
467            .D8(crate::DW_MACINFO_define.0)
468            .uleb(1) // line number: 1 - defined in the source file
469            .append_bytes(b"__GNUC__ 1\0")
470            .D8(crate::DW_MACINFO_undef.0)
471            .uleb(2) // line number: 2 - undefined in the source file
472            .append_bytes(b"__GNUC__\0")
473            .D8(crate::DW_MACINFO_start_file.0)
474            .uleb(3) // line number: 3 - start of file
475            .uleb(4) // file number index: 4 - index into the line number table
476            .D8(crate::DW_MACINFO_end_file.0) // end of file
477            .D8(crate::DW_MACINFO_vendor_ext.0)
478            .uleb(5) // numeric constant: 5 - vendor specific
479            .append_bytes(b"foo\0")
480            .D8(0); // end of unit
481
482        // Create a DebugMacinfo instance from the section
483        let section = section.get_contents().unwrap();
484        let debug_macinfo = DebugMacinfo::from(EndianSlice::new(&section, LittleEndian));
485
486        let offset = position.value().unwrap() as usize;
487
488        let mut iter = debug_macinfo
489            .get_macinfo(DebugMacinfoOffset(offset))
490            .unwrap();
491
492        // Test getting macinfo entries
493        let entry = iter.next().unwrap().unwrap();
494        assert!(
495            matches!(entry, MacroEntry::Define { line: 0, text: MacroString::Direct(text) } if text.slice() == b"__STDC__ 1")
496        );
497
498        let entry = iter.next().unwrap().unwrap();
499        assert!(
500            matches!(entry, MacroEntry::Define { line: 1, text: MacroString::Direct(text) } if text.slice() == b"__GNUC__ 1")
501        );
502
503        let entry = iter.next().unwrap().unwrap();
504        assert!(
505            matches!(entry, MacroEntry::Undef { line: 2, name: MacroString::Direct(name) } if name.slice() == b"__GNUC__")
506        );
507
508        let entry = iter.next().unwrap().unwrap();
509        assert!(matches!(entry, MacroEntry::StartFile { line: 3, file: 4 }));
510
511        let entry = iter.next().unwrap().unwrap();
512        assert!(matches!(entry, MacroEntry::EndFile));
513
514        let entry = iter.next().unwrap().unwrap();
515        assert!(
516            matches!(entry, MacroEntry::VendorExt { numeric: 5, string } if string.slice() == b"foo")
517        );
518
519        assert_eq!(iter.next(), Ok(None));
520    }
521
522    #[test]
523    fn get_macros_1() {
524        let position = Label::new();
525
526        // The test data is originally from the DWARF v5 standard, appendix D.16
527        // 1) Figure D.71, simple DWARF encoding
528        let section = Section::with_endian(Endian::Little)
529            .set_start_const(0)
530            .mark(&position)
531            .D16(5) // Dwarf version
532            .D8(0b0000_0010) // Flags: offset_size = 0 (32-bit), debug_line_offset = 1, opcode_operands_table = 0
533            .D32(0) // debug line offset
534            .D8(crate::DW_MACRO_start_file.0) // start file: "a.c"
535            .uleb(0) // line number
536            .uleb(0) // file number
537            .D8(crate::DW_MACRO_start_file.0) // start file: "a.h"
538            .uleb(1) // line number
539            .uleb(1) // file number
540            .D8(crate::DW_MACRO_define.0) // define
541            .uleb(1) // line number
542            .append_bytes(b"LONGER_MACRO 1\0") // macro name
543            .D8(crate::DW_MACRO_define.0) // define
544            .uleb(2) // line number
545            .append_bytes(b"B 2\0") // macro name
546            .D8(crate::DW_MACRO_start_file.0) // start file: "b.h"
547            .uleb(3) // line number
548            .uleb(2) // file number
549            .D8(crate::DW_MACRO_undef.0) // undef
550            .uleb(1) // line number
551            .append_bytes(b"B\0") // macro name
552            .D8(crate::DW_MACRO_define.0) // define
553            .uleb(2) // line number
554            .append_bytes(b"D 3\0") // macro name
555            .D8(crate::DW_MACRO_define.0) // define
556            .uleb(3) // line number
557            .append_bytes(b"FUNCTION_LIKE_MACRO(x) 4+x\0") // macro name
558            .D8(crate::DW_MACRO_end_file.0) // end file: "b.h" -> "a.h"
559            .D8(crate::DW_MACRO_define.0) // define
560            .uleb(4) // line number
561            .append_bytes(b"B 3\0") // macro name
562            .D8(crate::DW_MACRO_end_file.0) // end file: "a.h" -> "a.c"
563            .D8(crate::DW_MACRO_define.0) // define
564            .uleb(2) // line number
565            .append_bytes(b"FUNCTION_LIKE_MACRO(x) 4+x\0") // macro name
566            .D8(crate::DW_MACRO_start_file.0) // start file: "b.h"
567            .uleb(3) // line number
568            .uleb(2) // file number
569            .D8(crate::DW_MACRO_undef.0) // undef
570            .uleb(1) // line number
571            .append_bytes(b"B\0") // macro name
572            .D8(crate::DW_MACRO_define.0) // define
573            .uleb(2) // line number
574            .append_bytes(b"D 3\0") // macro name
575            .D8(crate::DW_MACRO_define.0) // define
576            .uleb(3) // line number
577            .append_bytes(b"FUNCTION_LIKE_MACRO(x) 4+x\0") // macro name
578            .D8(crate::DW_MACRO_end_file.0) // end file: "b.h" -> "a.c"
579            .D8(crate::DW_MACRO_end_file.0) // end file: "a.c" -> ""
580            .D8(0); // end of unit
581
582        // Create a DebugMacro instance from the section
583        let section = section.get_contents().unwrap();
584        let debug_macro = DebugMacro::from(EndianSlice::new(&section, LittleEndian));
585
586        let offset = position.value().unwrap() as usize;
587
588        let mut iter = debug_macro.get_macros(DebugMacroOffset(offset)).unwrap();
589        let entry = iter.next().unwrap().unwrap();
590        assert!(matches!(entry, MacroEntry::StartFile { line: 0, file: 0 }));
591        let entry = iter.next().unwrap().unwrap();
592        assert!(matches!(entry, MacroEntry::StartFile { line: 1, file: 1 }));
593        let entry = iter.next().unwrap().unwrap();
594        assert!(matches!(
595            entry,
596            MacroEntry::Define {
597                line: 1, text: MacroString::Direct(text)
598            } if text.slice() == b"LONGER_MACRO 1"
599        ));
600        let entry = iter.next().unwrap().unwrap();
601        assert!(matches!(
602            entry,
603            MacroEntry::Define {
604                line: 2, text: MacroString::Direct(text)
605            } if text.slice() == b"B 2"
606        ));
607        let entry = iter.next().unwrap().unwrap();
608        assert!(matches!(entry, MacroEntry::StartFile { line: 3, file: 2 }));
609        let entry = iter.next().unwrap().unwrap();
610        assert!(matches!(
611            entry,
612            MacroEntry::Undef {
613                line: 1, name: MacroString::Direct(name)
614            } if name.slice() == b"B"
615        ));
616        let entry = iter.next().unwrap().unwrap();
617        assert!(matches!(
618            entry,
619            MacroEntry::Define {
620                line: 2, text: MacroString::Direct(text)
621            } if text.slice() == b"D 3"
622        ));
623        let entry = iter.next().unwrap().unwrap();
624        assert!(matches!(
625            entry,
626            MacroEntry::Define {
627                line: 3, text: MacroString::Direct(text)
628            } if text.slice() == b"FUNCTION_LIKE_MACRO(x) 4+x"
629        ));
630        let entry = iter.next().unwrap().unwrap();
631        assert!(matches!(entry, MacroEntry::EndFile));
632        let entry = iter.next().unwrap().unwrap();
633        assert!(matches!(
634            entry,
635            MacroEntry::Define {
636                line: 4, text: MacroString::Direct(text)
637            } if text.slice() == b"B 3"
638        ));
639        let entry = iter.next().unwrap().unwrap();
640        assert!(matches!(entry, MacroEntry::EndFile));
641        let entry = iter.next().unwrap().unwrap();
642        assert!(matches!(
643            entry,
644            MacroEntry::Define {
645                line: 2, text: MacroString::Direct(text)
646            } if text.slice() == b"FUNCTION_LIKE_MACRO(x) 4+x"
647        ));
648        let entry = iter.next().unwrap().unwrap();
649        assert!(matches!(entry, MacroEntry::StartFile { line: 3, file: 2 }));
650        let entry = iter.next().unwrap().unwrap();
651        assert!(matches!(
652            entry,
653            MacroEntry::Undef {
654                line: 1, name: MacroString::Direct(name)
655            } if name.slice() == b"B"
656        ));
657        let entry = iter.next().unwrap().unwrap();
658        assert!(matches!(
659            entry,
660            MacroEntry::Define {
661                line: 2, text: MacroString::Direct(text)
662            } if text.slice() == b"D 3"
663        ));
664        let entry = iter.next().unwrap().unwrap();
665        assert!(matches!(
666            entry,
667            MacroEntry::Define {
668                line: 3, text: MacroString::Direct(text)
669            } if text.slice() == b"FUNCTION_LIKE_MACRO(x) 4+x"
670        ));
671        let entry = iter.next().unwrap().unwrap();
672        assert!(matches!(entry, MacroEntry::EndFile));
673        let entry = iter.next().unwrap().unwrap();
674        assert!(matches!(entry, MacroEntry::EndFile));
675        assert_eq!(iter.next(), Ok(None));
676    }
677
678    #[test]
679    fn get_macros_2() {
680        let str_0 = Label::new();
681        let str_1 = Label::new();
682        let macro_unit_0 = Label::new();
683        let macro_unit_1 = Label::new();
684        let macro_unit_2 = Label::new();
685
686        // The test data is originally from the DWARF v5 standard, appendix D.16
687        // 2) Figure D.72, shareable DWARF encoding
688        let str_section = Section::with_endian(Endian::Little)
689            .set_start_const(0)
690            .mark(&str_0)
691            .append_bytes(b"FUNCTION_LIKE_MACRO(x) 4+x\0") // macro name
692            .mark(&str_1)
693            .append_bytes(b"LONGER_MACRO 1\0"); // macro name
694
695        let macro_section = Section::with_endian(Endian::Little)
696            .set_start_const(0)
697            //--------------------unit 0----------------------
698            .mark(&macro_unit_0) // start of unit 0
699            .D16(5) // Dwarf version
700            .D8(0b0000_0010) // Flags: offset_size = 0 (32-bit), debug_line_offset = 1, opcode_operands_table = 0
701            .D32(0) // debug line offset
702            .D8(crate::DW_MACRO_start_file.0) // start file: "a.c"
703            .uleb(0) // line number
704            .uleb(0) // file number
705            .D8(crate::DW_MACRO_start_file.0) // start file: "a.h"
706            .uleb(1) // line number
707            .uleb(1) // file number
708            .D8(crate::DW_MACRO_import.0) // import unit 1
709            .L32(macro_unit_1.clone()) // debug line offset to unit 1
710            .D8(crate::DW_MACRO_start_file.0) // start file: "b.h"
711            .uleb(3) // line number
712            .uleb(2) // file number
713            .D8(crate::DW_MACRO_import.0) // import unit 2
714            .L32(macro_unit_2.clone()) // debug line offset to unit 2
715            .D8(crate::DW_MACRO_end_file.0) // end file: "b.h" -> "a.h"
716            .D8(crate::DW_MACRO_define.0) // define
717            .uleb(4) // line number
718            .append_bytes(b"B 3\0") // macro name
719            .D8(crate::DW_MACRO_end_file.0) // end file: "a.h" -> "a.c"
720            .D8(crate::DW_MACRO_define_strp.0) // define: "FUNCTION_LIKE_MACRO(x) 4+x"
721            .uleb(2) // line number
722            .D32(0) // macro name offset in the string table
723            .D8(crate::DW_MACRO_start_file.0) // start file: "b.h"
724            .uleb(3) // line number
725            .uleb(2) // file number
726            .D8(crate::DW_MACRO_import.0) // import unit 2
727            .L32(&macro_unit_2) // debug line offset to unit 2
728            .D8(crate::DW_MACRO_end_file.0) // end file: "b.h" -> "a.c"
729            .D8(crate::DW_MACRO_end_file.0) // end file: "a.c" -> ""
730            .D8(0)
731            //--------------------unit 1----------------------
732            .mark(&macro_unit_1) // start of unit 1
733            .D16(5) // Dwarf version
734            .D8(0b0000_0000) // Flags: offset_size = 0 (32-bit), debug_line_offset = 0, opcode_operands_table = 0
735            .D8(crate::DW_MACRO_define_strp.0) // define strp: "LONGER_MACRO 1"
736            .uleb(1) // line number
737            .L32(str_0.clone()) // macro name offset in the string table
738            .D8(crate::DW_MACRO_define.0) // define: "B 2"
739            .uleb(2) // line number
740            .append_bytes(b"B 2\0") // macro name
741            .D8(0) // end of unit
742            //---------------------unit 2---------------------
743            .mark(&macro_unit_2) // start of unit 2
744            .D16(5) // Dwarf version
745            .D8(0b0000_0000) // Flags: offset_size = 0 (32-bit), debug_line_offset = 0, opcode_operands_table = 0
746            .D8(crate::DW_MACRO_undef.0) // undef: "B"
747            .uleb(1) // line number
748            .append_bytes(b"B\0") // macro name
749            .D8(crate::DW_MACRO_define.0) // define: "D 3"
750            .uleb(2) // line number
751            .append_bytes(b"D 3\0") // macro name
752            .D8(crate::DW_MACRO_define_strp.0) // define strp: "FUNCTION_LIKE_MACRO(x) 4+x"
753            .uleb(2) // line number
754            .L32(str_1.clone()) // macro name offset in the string table
755            .D8(0); // end of unit
756
757        // Create a DebugMacro instance from the section
758        let str_section = str_section.get_contents().unwrap();
759        let debug_str = DebugStr::from(EndianSlice::new(&str_section, LittleEndian));
760
761        // Create a DebugMacro instance from the section
762        let macro_section = macro_section.get_contents().unwrap();
763        let debug_macro = DebugMacro::from(EndianSlice::new(&macro_section, LittleEndian));
764
765        // check the content of macro unit 0
766        let offset = macro_unit_0.value().unwrap() as usize;
767        let mut iter = debug_macro.get_macros(DebugMacroOffset(offset)).unwrap();
768        let entry = iter.next().unwrap().unwrap();
769        assert!(matches!(entry, MacroEntry::StartFile { line: 0, file: 0 }));
770        let entry = iter.next().unwrap().unwrap();
771        assert!(matches!(entry, MacroEntry::StartFile { line: 1, file: 1 }));
772        let entry = iter.next().unwrap().unwrap();
773        assert!(matches!(
774            entry,
775            MacroEntry::Import { offset } if offset.0 == macro_unit_1.value().unwrap() as usize
776        ));
777        let entry = iter.next().unwrap().unwrap();
778        assert!(matches!(entry, MacroEntry::StartFile { line: 3, file: 2 }));
779        let entry = iter.next().unwrap().unwrap();
780        assert!(matches!(
781            entry,
782            MacroEntry::Import { offset } if offset.0 == macro_unit_2.value().unwrap() as usize
783        ));
784        let entry = iter.next().unwrap().unwrap();
785        assert!(matches!(entry, MacroEntry::EndFile));
786        let entry = iter.next().unwrap().unwrap();
787        assert!(matches!(
788            entry,
789            MacroEntry::Define {
790                line: 4, text: MacroString::Direct(text)
791            } if text.slice() == b"B 3"
792        ));
793        let entry = iter.next().unwrap().unwrap();
794        assert!(matches!(entry, MacroEntry::EndFile));
795        let entry = iter.next().unwrap().unwrap();
796        assert!(matches!(
797            entry,
798            MacroEntry::Define {
799                line: 2, text: MacroString::StringPointer(text_offset)
800            } if text_offset.0 == str_0.value().unwrap() as usize
801        ));
802        let entry = iter.next().unwrap().unwrap();
803        assert!(matches!(entry, MacroEntry::StartFile { line: 3, file: 2 }));
804        let entry = iter.next().unwrap().unwrap();
805        assert!(matches!(
806            entry,
807            MacroEntry::Import { offset } if offset.0 == macro_unit_2.value().unwrap() as usize
808        ));
809        let entry = iter.next().unwrap().unwrap();
810        assert!(matches!(entry, MacroEntry::EndFile));
811        let entry = iter.next().unwrap().unwrap();
812        assert!(matches!(entry, MacroEntry::EndFile));
813        assert_eq!(iter.next(), Ok(None));
814
815        // check the content of macro unit 1
816        let offset = macro_unit_1.value().unwrap() as usize;
817        let mut iter = debug_macro.get_macros(DebugMacroOffset(offset)).unwrap();
818        let entry = iter.next().unwrap().unwrap();
819        assert!(matches!(
820            entry,
821            MacroEntry::Define {
822                line: 1, text: MacroString::StringPointer(text_offset)
823            } if text_offset.0 == str_0.value().unwrap() as usize
824        ));
825        let entry = iter.next().unwrap().unwrap();
826        assert!(matches!(
827            entry,
828            MacroEntry::Define {
829                line: 2, text: MacroString::Direct(text)
830            } if text.slice() == b"B 2"
831        ));
832        assert_eq!(iter.next(), Ok(None));
833
834        // check the content of macro unit 2
835        let offset = macro_unit_2.value().unwrap() as usize;
836        let mut iter = debug_macro.get_macros(DebugMacroOffset(offset)).unwrap();
837        let entry = iter.next().unwrap().unwrap();
838        assert!(matches!(
839            entry,
840            MacroEntry::Undef {
841                line: 1, name: MacroString::Direct(name)
842            } if name.slice() == b"B"
843        ));
844        let entry = iter.next().unwrap().unwrap();
845        assert!(matches!(
846            entry,
847            MacroEntry::Define {
848                line: 2, text: MacroString::Direct(text)
849            } if text.slice() == b"D 3"
850        ));
851        let entry = iter.next().unwrap().unwrap();
852        assert!(matches!(
853            entry,
854            MacroEntry::Define {
855                line: 2, text: MacroString::StringPointer(text_offset)
856            } if text_offset.0 == str_1.value().unwrap() as usize
857        ));
858        assert_eq!(iter.next(), Ok(None));
859
860        // check the content of the string table
861        let text_offset = DebugStrOffset(str_0.value().unwrap() as usize);
862        assert_eq!(
863            debug_str.get_str(text_offset).unwrap().slice(),
864            b"FUNCTION_LIKE_MACRO(x) 4+x"
865        );
866        let text_offset = DebugStrOffset(str_1.value().unwrap() as usize);
867        assert_eq!(
868            debug_str.get_str(text_offset).unwrap().slice(),
869            b"LONGER_MACRO 1"
870        );
871    }
872}