/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(§ion, 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(§ion, 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(¯o_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(¯o_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(¯o_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(¯o_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(¯o_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 | | } |