gimli/read/
index.rs

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