1 use core::slice;
2 
3 use crate::common::SectionId;
4 use crate::constants;
5 use crate::endianity::Endianity;
6 use crate::read::{EndianSlice, Error, Reader, ReaderOffset, Result, Section};
7 
8 /// The data in the `.debug_cu_index` section of a `.dwp` file.
9 ///
10 /// This section contains the compilation unit index.
11 #[derive(Debug, Default, Clone, Copy)]
12 pub struct DebugCuIndex<R> {
13     section: R,
14 }
15 
16 impl<'input, Endian> DebugCuIndex<EndianSlice<'input, Endian>>
17 where
18     Endian: Endianity,
19 {
20     /// Construct a new `DebugCuIndex` instance from the data in the `.debug_cu_index`
21     /// section.
new(section: &'input [u8], endian: Endian) -> Self22     pub fn new(section: &'input [u8], endian: Endian) -> Self {
23         Self::from(EndianSlice::new(section, endian))
24     }
25 }
26 
27 impl<R> Section<R> for DebugCuIndex<R> {
id() -> SectionId28     fn id() -> SectionId {
29         SectionId::DebugCuIndex
30     }
31 
reader(&self) -> &R32     fn reader(&self) -> &R {
33         &self.section
34     }
35 }
36 
37 impl<R> From<R> for DebugCuIndex<R> {
from(section: R) -> Self38     fn from(section: R) -> Self {
39         DebugCuIndex { section }
40     }
41 }
42 
43 impl<R: Reader> DebugCuIndex<R> {
44     /// Parse the index header.
index(self) -> Result<UnitIndex<R>>45     pub fn index(self) -> Result<UnitIndex<R>> {
46         UnitIndex::parse(self.section)
47     }
48 }
49 
50 /// The data in the `.debug_tu_index` section of a `.dwp` file.
51 ///
52 /// This section contains the type unit index.
53 #[derive(Debug, Default, Clone, Copy)]
54 pub struct DebugTuIndex<R> {
55     section: R,
56 }
57 
58 impl<'input, Endian> DebugTuIndex<EndianSlice<'input, Endian>>
59 where
60     Endian: Endianity,
61 {
62     /// Construct a new `DebugTuIndex` instance from the data in the `.debug_tu_index`
63     /// section.
new(section: &'input [u8], endian: Endian) -> Self64     pub fn new(section: &'input [u8], endian: Endian) -> Self {
65         Self::from(EndianSlice::new(section, endian))
66     }
67 }
68 
69 impl<R> Section<R> for DebugTuIndex<R> {
id() -> SectionId70     fn id() -> SectionId {
71         SectionId::DebugTuIndex
72     }
73 
reader(&self) -> &R74     fn reader(&self) -> &R {
75         &self.section
76     }
77 }
78 
79 impl<R> From<R> for DebugTuIndex<R> {
from(section: R) -> Self80     fn from(section: R) -> Self {
81         DebugTuIndex { section }
82     }
83 }
84 
85 impl<R: Reader> DebugTuIndex<R> {
86     /// Parse the index header.
index(self) -> Result<UnitIndex<R>>87     pub fn index(self) -> Result<UnitIndex<R>> {
88         UnitIndex::parse(self.section)
89     }
90 }
91 
92 const SECTION_COUNT_MAX: u8 = 8;
93 
94 /// The partially parsed index from a `DebugCuIndex` or `DebugTuIndex`.
95 #[derive(Debug, Clone)]
96 pub struct UnitIndex<R: Reader> {
97     version: u16,
98     section_count: u32,
99     unit_count: u32,
100     slot_count: u32,
101     hash_ids: R,
102     hash_rows: R,
103     // Only `section_count` values are valid.
104     sections: [SectionId; SECTION_COUNT_MAX as usize],
105     offsets: R,
106     sizes: R,
107 }
108 
109 impl<R: Reader> UnitIndex<R> {
parse(mut input: R) -> Result<UnitIndex<R>>110     fn parse(mut input: R) -> Result<UnitIndex<R>> {
111         if input.is_empty() {
112             return Ok(UnitIndex {
113                 version: 5,
114                 section_count: 0,
115                 unit_count: 0,
116                 slot_count: 0,
117                 hash_ids: input.clone(),
118                 hash_rows: input.clone(),
119                 sections: [SectionId::DebugAbbrev; SECTION_COUNT_MAX as usize],
120                 offsets: input.clone(),
121                 sizes: input.clone(),
122             });
123         }
124 
125         // GNU split-dwarf extension to DWARF 4 uses a 32-bit version,
126         // but DWARF 5 uses a 16-bit version followed by 16-bit padding.
127         let mut original_input = input.clone();
128         let version;
129         if input.read_u32()? == 2 {
130             version = 2
131         } else {
132             version = original_input.read_u16()?;
133             if version != 5 {
134                 return Err(Error::UnknownVersion(version.into()));
135             }
136         }
137 
138         let section_count = input.read_u32()?;
139         let unit_count = input.read_u32()?;
140         let slot_count = input.read_u32()?;
141         if slot_count == 0 || slot_count & (slot_count - 1) != 0 || slot_count <= unit_count {
142             return Err(Error::InvalidIndexSlotCount);
143         }
144 
145         let hash_ids = input.split(R::Offset::from_u64(u64::from(slot_count) * 8)?)?;
146         let hash_rows = input.split(R::Offset::from_u64(u64::from(slot_count) * 4)?)?;
147 
148         let mut sections = [SectionId::DebugAbbrev; SECTION_COUNT_MAX as usize];
149         if section_count > SECTION_COUNT_MAX.into() {
150             return Err(Error::InvalidIndexSectionCount);
151         }
152         for i in 0..section_count {
153             let section = input.read_u32()?;
154             sections[i as usize] = if version == 2 {
155                 match constants::DwSectV2(section) {
156                     constants::DW_SECT_V2_INFO => SectionId::DebugInfo,
157                     constants::DW_SECT_V2_TYPES => SectionId::DebugTypes,
158                     constants::DW_SECT_V2_ABBREV => SectionId::DebugAbbrev,
159                     constants::DW_SECT_V2_LINE => SectionId::DebugLine,
160                     constants::DW_SECT_V2_LOC => SectionId::DebugLoc,
161                     constants::DW_SECT_V2_STR_OFFSETS => SectionId::DebugStrOffsets,
162                     constants::DW_SECT_V2_MACINFO => SectionId::DebugMacinfo,
163                     constants::DW_SECT_V2_MACRO => SectionId::DebugMacro,
164                     _ => return Err(Error::UnknownIndexSection),
165                 }
166             } else {
167                 match constants::DwSect(section) {
168                     constants::DW_SECT_INFO => SectionId::DebugInfo,
169                     constants::DW_SECT_ABBREV => SectionId::DebugAbbrev,
170                     constants::DW_SECT_LINE => SectionId::DebugLine,
171                     constants::DW_SECT_LOCLISTS => SectionId::DebugLocLists,
172                     constants::DW_SECT_STR_OFFSETS => SectionId::DebugStrOffsets,
173                     constants::DW_SECT_MACRO => SectionId::DebugMacro,
174                     constants::DW_SECT_RNGLISTS => SectionId::DebugRngLists,
175                     _ => return Err(Error::UnknownIndexSection),
176                 }
177             };
178         }
179 
180         let offsets = input.split(R::Offset::from_u64(
181             u64::from(unit_count) * u64::from(section_count) * 4,
182         )?)?;
183         let sizes = input.split(R::Offset::from_u64(
184             u64::from(unit_count) * u64::from(section_count) * 4,
185         )?)?;
186 
187         Ok(UnitIndex {
188             version,
189             section_count,
190             unit_count,
191             slot_count,
192             hash_ids,
193             hash_rows,
194             sections,
195             offsets,
196             sizes,
197         })
198     }
199 
200     /// Find `id` in the index hash table, and return the row index.
201     ///
202     /// `id` may be a compilation unit ID if this index is from `.debug_cu_index`,
203     /// or a type signature if this index is from `.debug_tu_index`.
find(&self, id: u64) -> Option<u32>204     pub fn find(&self, id: u64) -> Option<u32> {
205         if self.slot_count == 0 {
206             return None;
207         }
208         let mask = u64::from(self.slot_count - 1);
209         let mut hash1 = id & mask;
210         let hash2 = ((id >> 32) & mask) | 1;
211         for _ in 0..self.slot_count {
212             // The length of these arrays was validated in `UnitIndex::parse`.
213             let mut hash_ids = self.hash_ids.clone();
214             hash_ids.skip(R::Offset::from_u64(hash1 * 8).ok()?).ok()?;
215             let hash_id = hash_ids.read_u64().ok()?;
216             if hash_id == id {
217                 let mut hash_rows = self.hash_rows.clone();
218                 hash_rows.skip(R::Offset::from_u64(hash1 * 4).ok()?).ok()?;
219                 let hash_row = hash_rows.read_u32().ok()?;
220                 return Some(hash_row);
221             }
222             if hash_id == 0 {
223                 return None;
224             }
225             hash1 = (hash1 + hash2) & mask;
226         }
227         None
228     }
229 
230     /// Return the section offsets and sizes for the given row index.
sections(&self, mut row: u32) -> Result<UnitIndexSectionIterator<R>>231     pub fn sections(&self, mut row: u32) -> Result<UnitIndexSectionIterator<R>> {
232         if row == 0 {
233             return Err(Error::InvalidIndexRow);
234         }
235         row -= 1;
236         if row >= self.unit_count {
237             return Err(Error::InvalidIndexRow);
238         }
239         let mut offsets = self.offsets.clone();
240         offsets.skip(R::Offset::from_u64(
241             u64::from(row) * u64::from(self.section_count) * 4,
242         )?)?;
243         let mut sizes = self.sizes.clone();
244         sizes.skip(R::Offset::from_u64(
245             u64::from(row) * u64::from(self.section_count) * 4,
246         )?)?;
247         Ok(UnitIndexSectionIterator {
248             sections: self.sections[..self.section_count as usize].iter(),
249             offsets,
250             sizes,
251         })
252     }
253 
254     /// Return the version.
version(&self) -> u16255     pub fn version(&self) -> u16 {
256         self.version
257     }
258 
259     /// Return the number of sections.
section_count(&self) -> u32260     pub fn section_count(&self) -> u32 {
261         self.section_count
262     }
263 
264     /// Return the number of units.
unit_count(&self) -> u32265     pub fn unit_count(&self) -> u32 {
266         self.unit_count
267     }
268 
269     /// Return the number of slots.
slot_count(&self) -> u32270     pub fn slot_count(&self) -> u32 {
271         self.slot_count
272     }
273 }
274 
275 /// An iterator over the section offsets and sizes for a row in a `UnitIndex`.
276 #[derive(Debug, Clone)]
277 pub struct UnitIndexSectionIterator<'index, R: Reader> {
278     sections: slice::Iter<'index, SectionId>,
279     offsets: R,
280     sizes: R,
281 }
282 
283 impl<'index, R: Reader> Iterator for UnitIndexSectionIterator<'index, R> {
284     type Item = UnitIndexSection;
285 
next(&mut self) -> Option<UnitIndexSection>286     fn next(&mut self) -> Option<UnitIndexSection> {
287         let section = *self.sections.next()?;
288         // The length of these arrays was validated in `UnitIndex::parse`.
289         let offset = self.offsets.read_u32().ok()?;
290         let size = self.sizes.read_u32().ok()?;
291         Some(UnitIndexSection {
292             section,
293             offset,
294             size,
295         })
296     }
297 }
298 
299 /// Information about a unit's contribution to a section in a `.dwp` file.
300 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
301 pub struct UnitIndexSection {
302     /// The section kind.
303     pub section: SectionId,
304     /// The base offset of the unit's contribution to the section.
305     pub offset: u32,
306     /// The size of the unit's contribution to the section.
307     pub size: u32,
308 }
309 
310 #[cfg(test)]
311 mod tests {
312     use super::*;
313     use crate::endianity::BigEndian;
314     use test_assembler::{Endian, Section};
315 
316     #[test]
test_empty()317     fn test_empty() {
318         let buf = EndianSlice::new(&[], BigEndian);
319         let index = UnitIndex::parse(buf).unwrap();
320         assert!(index.find(0).is_none());
321     }
322 
323     #[test]
test_version_2()324     fn test_version_2() {
325         #[rustfmt::skip]
326         let section = Section::with_endian(Endian::Big)
327             // Header.
328             .D32(2).D32(0).D32(0).D32(1)
329             // Slots.
330             .D64(0).D32(0);
331         let buf = section.get_contents().unwrap();
332         let buf = EndianSlice::new(&buf, BigEndian);
333         let index = UnitIndex::parse(buf).unwrap();
334         assert_eq!(index.version, 2);
335     }
336 
337     #[test]
test_version_5()338     fn test_version_5() {
339         #[rustfmt::skip]
340         let section = Section::with_endian(Endian::Big)
341             // Header.
342             .D16(5).D16(0).D32(0).D32(0).D32(1)
343             // Slots.
344             .D64(0).D32(0);
345         let buf = section.get_contents().unwrap();
346         let buf = EndianSlice::new(&buf, BigEndian);
347         let index = UnitIndex::parse(buf).unwrap();
348         assert_eq!(index.version, 5);
349     }
350 
351     #[test]
test_version_5_invalid()352     fn test_version_5_invalid() {
353         #[rustfmt::skip]
354         let section = Section::with_endian(Endian::Big)
355             // Header.
356             .D32(5).D32(0).D32(0).D32(1)
357             // Slots.
358             .D64(0).D32(0);
359         let buf = section.get_contents().unwrap();
360         let buf = EndianSlice::new(&buf, BigEndian);
361         assert!(UnitIndex::parse(buf).is_err());
362     }
363 
364     #[test]
test_version_2_sections()365     fn test_version_2_sections() {
366         #[rustfmt::skip]
367         let section = Section::with_endian(Endian::Big)
368             // Header.
369             .D32(2).D32(8).D32(1).D32(2)
370             // Slots.
371             .D64(0).D64(0).D32(0).D32(0)
372             // Sections.
373             .D32(constants::DW_SECT_V2_INFO.0)
374             .D32(constants::DW_SECT_V2_TYPES.0)
375             .D32(constants::DW_SECT_V2_ABBREV.0)
376             .D32(constants::DW_SECT_V2_LINE.0)
377             .D32(constants::DW_SECT_V2_LOC.0)
378             .D32(constants::DW_SECT_V2_STR_OFFSETS.0)
379             .D32(constants::DW_SECT_V2_MACINFO.0)
380             .D32(constants::DW_SECT_V2_MACRO.0)
381             // Offsets.
382             .D32(11).D32(12).D32(13).D32(14).D32(15).D32(16).D32(17).D32(18)
383             // Sizes.
384             .D32(21).D32(22).D32(23).D32(24).D32(25).D32(26).D32(27).D32(28);
385         let buf = section.get_contents().unwrap();
386         let buf = EndianSlice::new(&buf, BigEndian);
387         let index = UnitIndex::parse(buf).unwrap();
388         assert_eq!(index.section_count, 8);
389         assert_eq!(
390             index.sections,
391             [
392                 SectionId::DebugInfo,
393                 SectionId::DebugTypes,
394                 SectionId::DebugAbbrev,
395                 SectionId::DebugLine,
396                 SectionId::DebugLoc,
397                 SectionId::DebugStrOffsets,
398                 SectionId::DebugMacinfo,
399                 SectionId::DebugMacro,
400             ]
401         );
402         #[rustfmt::skip]
403         let expect = [
404             UnitIndexSection { section: SectionId::DebugInfo, offset: 11, size: 21 },
405             UnitIndexSection { section: SectionId::DebugTypes, offset: 12, size: 22 },
406             UnitIndexSection { section: SectionId::DebugAbbrev, offset: 13, size: 23 },
407             UnitIndexSection { section: SectionId::DebugLine, offset: 14, size: 24 },
408             UnitIndexSection { section: SectionId::DebugLoc, offset: 15, size: 25 },
409             UnitIndexSection { section: SectionId::DebugStrOffsets, offset: 16, size: 26 },
410             UnitIndexSection { section: SectionId::DebugMacinfo, offset: 17, size: 27 },
411             UnitIndexSection { section: SectionId::DebugMacro, offset: 18, size: 28 },
412         ];
413         let mut sections = index.sections(1).unwrap();
414         for section in &expect {
415             assert_eq!(*section, sections.next().unwrap());
416         }
417         assert!(sections.next().is_none());
418     }
419 
420     #[test]
test_version_5_sections()421     fn test_version_5_sections() {
422         #[rustfmt::skip]
423         let section = Section::with_endian(Endian::Big)
424             // Header.
425             .D16(5).D16(0).D32(7).D32(1).D32(2)
426             // Slots.
427             .D64(0).D64(0).D32(0).D32(0)
428             // Sections.
429             .D32(constants::DW_SECT_INFO.0)
430             .D32(constants::DW_SECT_ABBREV.0)
431             .D32(constants::DW_SECT_LINE.0)
432             .D32(constants::DW_SECT_LOCLISTS.0)
433             .D32(constants::DW_SECT_STR_OFFSETS.0)
434             .D32(constants::DW_SECT_MACRO.0)
435             .D32(constants::DW_SECT_RNGLISTS.0)
436             // Offsets.
437             .D32(11).D32(12).D32(13).D32(14).D32(15).D32(16).D32(17)
438             // Sizes.
439             .D32(21).D32(22).D32(23).D32(24).D32(25).D32(26).D32(27);
440         let buf = section.get_contents().unwrap();
441         let buf = EndianSlice::new(&buf, BigEndian);
442         let index = UnitIndex::parse(buf).unwrap();
443         assert_eq!(index.section_count, 7);
444         assert_eq!(
445             index.sections[..7],
446             [
447                 SectionId::DebugInfo,
448                 SectionId::DebugAbbrev,
449                 SectionId::DebugLine,
450                 SectionId::DebugLocLists,
451                 SectionId::DebugStrOffsets,
452                 SectionId::DebugMacro,
453                 SectionId::DebugRngLists,
454             ]
455         );
456         #[rustfmt::skip]
457         let expect = [
458             UnitIndexSection { section: SectionId::DebugInfo, offset: 11, size: 21 },
459             UnitIndexSection { section: SectionId::DebugAbbrev, offset: 12, size: 22 },
460             UnitIndexSection { section: SectionId::DebugLine, offset: 13, size: 23 },
461             UnitIndexSection { section: SectionId::DebugLocLists, offset: 14, size: 24 },
462             UnitIndexSection { section: SectionId::DebugStrOffsets, offset: 15, size: 25 },
463             UnitIndexSection { section: SectionId::DebugMacro, offset: 16, size: 26 },
464             UnitIndexSection { section: SectionId::DebugRngLists, offset: 17, size: 27 },
465         ];
466         let mut sections = index.sections(1).unwrap();
467         for section in &expect {
468             assert_eq!(*section, sections.next().unwrap());
469         }
470         assert!(sections.next().is_none());
471 
472         assert!(index.sections(0).is_err());
473         assert!(index.sections(2).is_err());
474     }
475 
476     #[test]
test_hash()477     fn test_hash() {
478         #[rustfmt::skip]
479         let section = Section::with_endian(Endian::Big)
480             // Header.
481             .D16(5).D16(0).D32(2).D32(3).D32(4)
482             // Slots.
483             .D64(0xffff_fff2_ffff_fff1)
484             .D64(0xffff_fff0_ffff_fff1)
485             .D64(0xffff_fff1_ffff_fff1)
486             .D64(0)
487             .D32(3).D32(1).D32(2).D32(0)
488             // Sections.
489             .D32(constants::DW_SECT_INFO.0)
490             .D32(constants::DW_SECT_ABBREV.0)
491             // Offsets.
492             .D32(0).D32(0).D32(0).D32(0).D32(0).D32(0)
493             // Sizes.
494             .D32(0).D32(0).D32(0).D32(0).D32(0).D32(0);
495         let buf = section.get_contents().unwrap();
496         let buf = EndianSlice::new(&buf, BigEndian);
497         let index = UnitIndex::parse(buf).unwrap();
498         assert_eq!(index.version(), 5);
499         assert_eq!(index.slot_count(), 4);
500         assert_eq!(index.unit_count(), 3);
501         assert_eq!(index.section_count(), 2);
502         assert_eq!(index.find(0xffff_fff0_ffff_fff1), Some(1));
503         assert_eq!(index.find(0xffff_fff1_ffff_fff1), Some(2));
504         assert_eq!(index.find(0xffff_fff2_ffff_fff1), Some(3));
505         assert_eq!(index.find(0xffff_fff3_ffff_fff1), None);
506     }
507 
508     #[test]
test_cu_index()509     fn test_cu_index() {
510         #[rustfmt::skip]
511         let section = Section::with_endian(Endian::Big)
512             // Header.
513             .D16(5).D16(0).D32(0).D32(0).D32(1)
514             // Slots.
515             .D64(0).D32(0);
516         let buf = section.get_contents().unwrap();
517         let cu_index = DebugCuIndex::new(&buf, BigEndian);
518         let index = cu_index.index().unwrap();
519         assert_eq!(index.version, 5);
520     }
521 
522     #[test]
test_tu_index()523     fn test_tu_index() {
524         #[rustfmt::skip]
525         let section = Section::with_endian(Endian::Big)
526             // Header.
527             .D16(5).D16(0).D32(0).D32(0).D32(1)
528             // Slots.
529             .D64(0).D32(0);
530         let buf = section.get_contents().unwrap();
531         let tu_index = DebugTuIndex::new(&buf, BigEndian);
532         let index = tu_index.index().unwrap();
533         assert_eq!(index.version, 5);
534     }
535 }
536