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(slice:section, endian))
24 }
25}
26
27impl<R> Section<R> for DebugCuIndex<R> {
28 fn id() -> SectionId {
29 SectionId::DebugCuIndex
30 }
31
32 fn reader(&self) -> &R {
33 &self.section
34 }
35}
36
37impl<R> From<R> for DebugCuIndex<R> {
38 fn from(section: R) -> Self {
39 DebugCuIndex { section }
40 }
41}
42
43impl<R: Reader> DebugCuIndex<R> {
44 /// Parse the index header.
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)]
54pub struct DebugTuIndex<R> {
55 section: R,
56}
57
58impl<'input, Endian> DebugTuIndex<EndianSlice<'input, Endian>>
59where
60 Endian: Endianity,
61{
62 /// Construct a new `DebugTuIndex` instance from the data in the `.debug_tu_index`
63 /// section.
64 pub fn new(section: &'input [u8], endian: Endian) -> Self {
65 Self::from(EndianSlice::new(slice:section, endian))
66 }
67}
68
69impl<R> Section<R> for DebugTuIndex<R> {
70 fn id() -> SectionId {
71 SectionId::DebugTuIndex
72 }
73
74 fn reader(&self) -> &R {
75 &self.section
76 }
77}
78
79impl<R> From<R> for DebugTuIndex<R> {
80 fn from(section: R) -> Self {
81 DebugTuIndex { section }
82 }
83}
84
85impl<R: Reader> DebugTuIndex<R> {
86 /// Parse the index header.
87 pub fn index(self) -> Result<UnitIndex<R>> {
88 UnitIndex::parse(self.section)
89 }
90}
91
92const SECTION_COUNT_MAX: u8 = 8;
93
94/// The partially parsed index from a `DebugCuIndex` or `DebugTuIndex`.
95#[derive(Debug, Clone)]
96pub 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
109impl<R: Reader> 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`.
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.
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.
255 pub fn version(&self) -> u16 {
256 self.version
257 }
258
259 /// Return the number of sections.
260 pub fn section_count(&self) -> u32 {
261 self.section_count
262 }
263
264 /// Return the number of units.
265 pub fn unit_count(&self) -> u32 {
266 self.unit_count
267 }
268
269 /// Return the number of slots.
270 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)]
277pub struct UnitIndexSectionIterator<'index, R: Reader> {
278 sections: slice::Iter<'index, SectionId>,
279 offsets: R,
280 sizes: R,
281}
282
283impl<'index, R: Reader> Iterator for UnitIndexSectionIterator<'index, R> {
284 type Item = UnitIndexSection;
285
286 fn next(&mut self) -> Option<UnitIndexSection> {
287 let section: SectionId = *self.sections.next()?;
288 // The length of these arrays was validated in `UnitIndex::parse`.
289 let offset: u32 = self.offsets.read_u32().ok()?;
290 let size: u32 = 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)]
301pub 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)]
311mod tests {
312 use super::*;
313 use crate::endianity::BigEndian;
314 use test_assembler::{Endian, Section};
315
316 #[test]
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]
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]
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]
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]
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]
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]
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]
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]
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