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<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 | |
41 | impl<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 | |
51 | impl<R> From<R> for DebugCuIndex<R> { |
52 | fn from(section: R) -> Self { |
53 | DebugCuIndex { section } |
54 | } |
55 | } |
56 | |
57 | impl<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)] |
68 | pub struct DebugTuIndex<R> { |
69 | section: R, |
70 | } |
71 | |
72 | impl<'input, Endian> DebugTuIndex<EndianSlice<'input, Endian>> |
73 | where |
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(slice:section, endian)) |
80 | } |
81 | } |
82 | |
83 | impl<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 | |
97 | impl<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 | |
107 | impl<R> From<R> for DebugTuIndex<R> { |
108 | fn from(section: R) -> Self { |
109 | DebugTuIndex { section } |
110 | } |
111 | } |
112 | |
113 | impl<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 | |
120 | const SECTION_COUNT_MAX: u8 = 8; |
121 | |
122 | /// The partially parsed index from a `DebugCuIndex` or `DebugTuIndex`. |
123 | #[derive (Debug, Clone)] |
124 | pub 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 | |
137 | impl<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)] |
307 | pub struct UnitIndexSectionIterator<'index, R: Reader> { |
308 | sections: slice::Iter<'index, IndexSectionId>, |
309 | offsets: R, |
310 | sizes: R, |
311 | } |
312 | |
313 | impl<'index, R: Reader> Iterator for UnitIndexSectionIterator<'index, R> { |
314 | type Item = UnitIndexSection; |
315 | |
316 | fn next(&mut self) -> Option<UnitIndexSection> { |
317 | let section: IndexSectionId = *self.sections.next()?; |
318 | // The length of these arrays was validated in `UnitIndex::parse`. |
319 | let offset: u32 = self.offsets.read_u32().ok()?; |
320 | let size: u32 = 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)] |
331 | pub 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)] |
342 | pub 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 | |
365 | impl 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)] |
389 | mod 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 | } |
632 | |