Coverage Report

Created: 2026-04-29 06:53

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/gimli-0.32.3/src/read/macros.rs
Line
Count
Source
1
use crate::common::{DebugMacinfoOffset, SectionId};
2
use crate::endianity::Endianity;
3
use crate::read::{EndianSlice, Reader, ReaderOffset, Section, UnitRef};
4
use 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)]
11
pub struct DebugMacinfo<R> {
12
    pub(crate) section: R,
13
}
14
15
impl<'input, Endian> DebugMacinfo<EndianSlice<'input, Endian>>
16
where
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
0
    pub fn new(macinfo_section: &'input [u8], endian: Endian) -> Self {
34
0
        Self::from(EndianSlice::new(macinfo_section, endian))
35
0
    }
36
}
37
38
impl<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
0
    pub fn get_macinfo(&self, offset: DebugMacinfoOffset<R::Offset>) -> Result<MacroIter<R>> {
60
0
        let mut input = self.section.clone();
61
0
        input.skip(offset.0)?;
62
0
        Ok(MacroIter {
63
0
            input,
64
0
            format: Format::Dwarf32,
65
0
            is_macro: false,
66
0
        })
67
0
    }
68
}
69
70
impl<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
0
    pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugMacinfo<R>
77
0
    where
78
0
        F: FnMut(&'a T) -> R,
79
    {
80
0
        borrow(&self.section).into()
81
0
    }
82
}
83
84
impl<R> Section<R> for DebugMacinfo<R> {
85
0
    fn id() -> SectionId {
86
0
        SectionId::DebugMacinfo
87
0
    }
Unexecuted instantiation: <gimli::read::macros::DebugMacinfo<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>> as gimli::read::Section<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::id
Unexecuted instantiation: <gimli::read::macros::DebugMacinfo<_> as gimli::read::Section<_>>::id
88
89
0
    fn reader(&self) -> &R {
90
0
        &self.section
91
0
    }
92
}
93
94
impl<R> From<R> for DebugMacinfo<R> {
95
0
    fn from(macinfo_section: R) -> Self {
96
0
        DebugMacinfo {
97
0
            section: macinfo_section,
98
0
        }
99
0
    }
Unexecuted instantiation: <gimli::read::macros::DebugMacinfo<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>> as core::convert::From<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::from
Unexecuted instantiation: <gimli::read::macros::DebugMacinfo<_> as core::convert::From<_>>::from
100
}
101
102
/// The raw contents of the `.debug_macro` section.
103
#[derive(Debug, Default, Clone, Copy)]
104
pub struct DebugMacro<R> {
105
    pub(crate) section: R,
106
}
107
108
impl<'input, Endian> DebugMacro<EndianSlice<'input, Endian>>
109
where
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
0
    pub fn new(macro_section: &'input [u8], endian: Endian) -> Self {
127
0
        Self::from(EndianSlice::new(macro_section, endian))
128
0
    }
129
}
130
131
impl<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
0
    pub fn get_macros(&self, offset: DebugMacroOffset<R::Offset>) -> Result<MacroIter<R>> {
153
0
        let mut input = self.section.clone();
154
0
        input.skip(offset.0)?;
155
0
        let header = MacroUnitHeader::parse(&mut input)?;
156
0
        Ok(MacroIter {
157
0
            input,
158
0
            format: header.format(),
159
0
            is_macro: true,
160
0
        })
161
0
    }
162
}
163
164
impl<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
0
    pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugMacro<R>
171
0
    where
172
0
        F: FnMut(&'a T) -> R,
173
    {
174
0
        borrow(&self.section).into()
175
0
    }
176
}
177
178
impl<R> Section<R> for DebugMacro<R> {
179
0
    fn id() -> SectionId {
180
0
        SectionId::DebugMacro
181
0
    }
Unexecuted instantiation: <gimli::read::macros::DebugMacro<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>> as gimli::read::Section<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::id
Unexecuted instantiation: <gimli::read::macros::DebugMacro<_> as gimli::read::Section<_>>::id
182
183
0
    fn reader(&self) -> &R {
184
0
        &self.section
185
0
    }
186
}
187
188
impl<R> From<R> for DebugMacro<R> {
189
0
    fn from(macro_section: R) -> Self {
190
0
        DebugMacro {
191
0
            section: macro_section,
192
0
        }
193
0
    }
Unexecuted instantiation: <gimli::read::macros::DebugMacro<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>> as core::convert::From<gimli::read::endian_slice::EndianSlice<gimli::endianity::LittleEndian>>>::from
Unexecuted instantiation: <gimli::read::macros::DebugMacro<_> as core::convert::From<_>>::from
194
}
195
196
#[derive(Debug, Clone)]
197
struct 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
204
impl<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
0
    fn parse(input: &mut R) -> Result<Self> {
210
0
        let version = input.read_u16()?;
211
0
        let flags = input.read_u8()?;
212
0
        let format = if flags & Self::OFFSET_SIZE_FLAG == 0 {
213
0
            Format::Dwarf32
214
        } else {
215
0
            Format::Dwarf64
216
        };
217
0
        let _debug_line_offset = if flags & Self::DEBUG_LINE_OFFSET_FLAG != 0 {
218
0
            DebugLineOffset(input.read_offset(format)?)
219
        } else {
220
0
            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
0
        if flags & Self::OPCODE_OPERANDS_TABLE_FLAG != 0 {
224
0
            return Err(Error::UnsupportedOpcodeOperandsTable);
225
0
        }
226
0
        Ok(MacroUnitHeader {
227
0
            _version: version,
228
0
            flags,
229
0
            _debug_line_offset,
230
0
        })
231
0
    }
232
233
0
    fn format(&self) -> Format {
234
0
        if self.flags & Self::OFFSET_SIZE_FLAG == 0 {
235
0
            Format::Dwarf32
236
        } else {
237
0
            Format::Dwarf64
238
        }
239
0
    }
240
}
241
242
/// A string in a macro entry.
243
#[derive(Debug, Clone, PartialEq, Eq)]
244
pub enum MacroString<R, Offset = <R as Reader>::Offset>
245
where
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
260
impl<R: Reader> MacroString<R> {
261
    /// Get the string slice from the macro entry.
262
0
    pub fn string(&self, unit: UnitRef<'_, R>) -> Result<R> {
263
0
        match self {
264
0
            MacroString::Direct(s) => Ok(s.clone()),
265
0
            MacroString::StringPointer(offset) => unit.string(*offset),
266
0
            MacroString::IndirectStringPointer(index) => {
267
0
                let str_offset = unit.string_offset(*index)?;
268
0
                unit.string(str_offset)
269
            }
270
0
            MacroString::Supplementary(offset) => unit.sup_string(*offset),
271
        }
272
0
    }
273
}
274
275
/// an Entry in the `.debug_macro` section.
276
#[derive(Debug, Clone, PartialEq, Eq)]
277
pub enum MacroEntry<R, Offset = <R as Reader>::Offset>
278
where
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)]
327
pub struct MacroIter<R: Reader> {
328
    input: R,
329
    format: Format,
330
    is_macro: bool,
331
}
332
333
impl<R: Reader> MacroIter<R> {
334
    /// Advance the iterator to the next entry in the `.debug_macro` section.
335
0
    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
0
        let macro_type = DwMacro(self.input.read_u8()?);
338
0
        match macro_type {
339
            DwMacro(0) => {
340
0
                self.input.empty();
341
0
                Ok(None)
342
            }
343
            constants::DW_MACRO_define => {
344
0
                let line = self.input.read_uleb128()?;
345
0
                let text = self.input.read_null_terminated_slice()?;
346
0
                Ok(Some(MacroEntry::Define {
347
0
                    line,
348
0
                    text: MacroString::Direct(text),
349
0
                }))
350
            }
351
            constants::DW_MACRO_undef => {
352
0
                let line = self.input.read_uleb128()?;
353
0
                let name = self.input.read_null_terminated_slice()?;
354
0
                Ok(Some(MacroEntry::Undef {
355
0
                    line,
356
0
                    name: MacroString::Direct(name),
357
0
                }))
358
            }
359
            constants::DW_MACRO_start_file => {
360
0
                let line = self.input.read_uleb128()?;
361
0
                let file = self.input.read_uleb128()?;
362
0
                Ok(Some(MacroEntry::StartFile { line, file }))
363
            }
364
0
            constants::DW_MACRO_end_file => Ok(Some(MacroEntry::EndFile)),
365
0
            constants::DW_MACRO_define_strp if self.is_macro => {
366
0
                let line = self.input.read_uleb128()?;
367
0
                let text_offset = DebugStrOffset(self.input.read_offset(self.format)?);
368
0
                Ok(Some(MacroEntry::Define {
369
0
                    line,
370
0
                    text: MacroString::StringPointer(text_offset),
371
0
                }))
372
            }
373
0
            constants::DW_MACRO_undef_strp if self.is_macro => {
374
0
                let line = self.input.read_uleb128()?;
375
0
                let name_offset = DebugStrOffset(self.input.read_offset(self.format)?);
376
0
                Ok(Some(MacroEntry::Undef {
377
0
                    line,
378
0
                    name: MacroString::StringPointer(name_offset),
379
0
                }))
380
            }
381
0
            constants::DW_MACRO_import if self.is_macro => {
382
0
                let offset = DebugMacroOffset(self.input.read_offset(self.format)?);
383
0
                Ok(Some(MacroEntry::Import { offset }))
384
            }
385
0
            constants::DW_MACRO_define_sup if self.is_macro => {
386
0
                let line = self.input.read_uleb128()?;
387
0
                let text_offset = DebugStrOffset(self.input.read_offset(self.format)?);
388
0
                Ok(Some(MacroEntry::Define {
389
0
                    line,
390
0
                    text: MacroString::Supplementary(text_offset),
391
0
                }))
392
            }
393
0
            constants::DW_MACRO_undef_sup if self.is_macro => {
394
0
                let line = self.input.read_uleb128()?;
395
0
                let name_offset = DebugStrOffset(self.input.read_offset(self.format)?);
396
0
                Ok(Some(MacroEntry::Undef {
397
0
                    line,
398
0
                    name: MacroString::Supplementary(name_offset),
399
0
                }))
400
            }
401
0
            constants::DW_MACRO_import_sup if self.is_macro => {
402
0
                let offset = DebugMacroOffset(self.input.read_offset(self.format)?);
403
0
                Ok(Some(MacroEntry::ImportSup { offset }))
404
            }
405
0
            constants::DW_MACRO_define_strx if self.is_macro => {
406
0
                let line = self.input.read_uleb128()?;
407
0
                let index = self.input.read_uleb128().and_then(R::Offset::from_u64)?;
408
0
                let text_index = DebugStrOffsetsIndex(index);
409
0
                Ok(Some(MacroEntry::Define {
410
0
                    line,
411
0
                    text: MacroString::IndirectStringPointer(text_index),
412
0
                }))
413
            }
414
0
            constants::DW_MACRO_undef_strx if self.is_macro => {
415
0
                let line = self.input.read_uleb128()?;
416
0
                let index = self.input.read_uleb128().and_then(R::Offset::from_u64)?;
417
0
                let name_index = DebugStrOffsetsIndex(index);
418
0
                Ok(Some(MacroEntry::Undef {
419
0
                    line,
420
0
                    name: MacroString::IndirectStringPointer(name_index),
421
0
                }))
422
            }
423
            _ => {
424
0
                if self.is_macro {
425
0
                    self.input.empty();
426
0
                    Err(Error::InvalidMacroType(macro_type))
427
0
                } else if macro_type.0 == constants::DW_MACINFO_vendor_ext.0 {
428
0
                    let numeric = self.input.read_uleb128()?;
429
0
                    let string = self.input.read_null_terminated_slice()?;
430
0
                    Ok(Some(MacroEntry::VendorExt { numeric, string }))
431
                } else {
432
0
                    self.input.empty();
433
0
                    Err(Error::InvalidMacinfoType(DwMacinfo(macro_type.0)))
434
                }
435
            }
436
        }
437
0
    }
438
}
439
440
#[cfg(feature = "fallible-iterator")]
441
impl<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)]
451
mod 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
}