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#[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 pub fn new(section: &'input [u8], endian: Endian) -> Self {
23 Self::from(EndianSlice::new(section, endian))
24 }
25}
26
27impl<T> DebugCuIndex<T> {
28 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 pub fn index(self) -> Result<UnitIndex<R>> {
60 UnitIndex::parse(self.section)
61 }
62}
63
64#[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 pub fn new(section: &'input [u8], endian: Endian) -> Self {
79 Self::from(EndianSlice::new(section, endian))
80 }
81}
82
83impl<T> DebugTuIndex<T> {
84 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 pub fn index(self) -> Result<UnitIndex<R>> {
116 UnitIndex::parse(self.section)
117 }
118}
119
120const SECTION_COUNT_MAX: u8 = 8;
121
122#[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 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 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 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 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 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 pub fn version(&self) -> u16 {
286 self.version
287 }
288
289 pub fn section_count(&self) -> u32 {
291 self.section_count
292 }
293
294 pub fn unit_count(&self) -> u32 {
296 self.unit_count
297 }
298
299 pub fn slot_count(&self) -> u32 {
301 self.slot_count
302 }
303}
304
305#[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 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#[derive(Debug, Clone, Copy, PartialEq, Eq)]
331pub struct UnitIndexSection {
332 pub section: IndexSectionId,
334 pub offset: u32,
336 pub size: u32,
338}
339
340#[derive(Debug, Clone, Copy, PartialEq, Eq)]
342pub enum IndexSectionId {
343 DebugAbbrev,
345 DebugInfo,
347 DebugLine,
349 DebugLoc,
351 DebugLocLists,
353 DebugMacinfo,
355 DebugMacro,
357 DebugRngLists,
359 DebugStrOffsets,
361 DebugTypes,
363}
364
365impl IndexSectionId {
366 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 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 .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 .D32(2).D32(0).D32(0).D32(1)
425 .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 .D16(5).D16(0).D32(0).D32(0).D32(1)
439 .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 .D32(5).D32(0).D32(0).D32(1)
453 .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 .D32(2).D32(8).D32(1).D32(2)
466 .D64(0).D64(0).D32(0).D32(0)
468 .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 .D32(11).D32(12).D32(13).D32(14).D32(15).D32(16).D32(17).D32(18)
479 .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 .D16(5).D16(0).D32(7).D32(1).D32(2)
522 .D64(0).D64(0).D32(0).D32(0)
524 .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 .D32(11).D32(12).D32(13).D32(14).D32(15).D32(16).D32(17)
534 .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 .D16(5).D16(0).D32(2).D32(3).D32(4)
578 .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 .D32(constants::DW_SECT_INFO.0)
586 .D32(constants::DW_SECT_ABBREV.0)
587 .D32(0).D32(0).D32(0).D32(0).D32(0).D32(0)
589 .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 .D16(5).D16(0).D32(0).D32(0).D32(1)
610 .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 .D16(5).D16(0).D32(0).D32(0).D32(1)
624 .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}