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. |
22 | pub fn new(section: &'input [u8], endian: Endian) -> Self { |
23 | Self::from(EndianSlice::new(slice:section, endian)) |
24 | } |
25 | } |
26 | |
27 | impl<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 | |
37 | impl<R> From<R> for DebugCuIndex<R> { |
38 | fn from(section: R) -> Self { |
39 | DebugCuIndex { section } |
40 | } |
41 | } |
42 | |
43 | impl<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)] |
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. |
64 | pub fn new(section: &'input [u8], endian: Endian) -> Self { |
65 | Self::from(EndianSlice::new(slice:section, endian)) |
66 | } |
67 | } |
68 | |
69 | impl<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 | |
79 | impl<R> From<R> for DebugTuIndex<R> { |
80 | fn from(section: R) -> Self { |
81 | DebugTuIndex { section } |
82 | } |
83 | } |
84 | |
85 | impl<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 | |
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> { |
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)] |
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 | |
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)] |
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] |
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 | |