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. new(section: &'input [u8], endian: Endian) -> Self22 pub fn new(section: &'input [u8], endian: Endian) -> Self { 23 Self::from(EndianSlice::new(section, endian)) 24 } 25 } 26 27 impl<R> Section<R> for DebugCuIndex<R> { id() -> SectionId28 fn id() -> SectionId { 29 SectionId::DebugCuIndex 30 } 31 reader(&self) -> &R32 fn reader(&self) -> &R { 33 &self.section 34 } 35 } 36 37 impl<R> From<R> for DebugCuIndex<R> { from(section: R) -> Self38 fn from(section: R) -> Self { 39 DebugCuIndex { section } 40 } 41 } 42 43 impl<R: Reader> DebugCuIndex<R> { 44 /// Parse the index header. index(self) -> Result<UnitIndex<R>>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. new(section: &'input [u8], endian: Endian) -> Self64 pub fn new(section: &'input [u8], endian: Endian) -> Self { 65 Self::from(EndianSlice::new(section, endian)) 66 } 67 } 68 69 impl<R> Section<R> for DebugTuIndex<R> { id() -> SectionId70 fn id() -> SectionId { 71 SectionId::DebugTuIndex 72 } 73 reader(&self) -> &R74 fn reader(&self) -> &R { 75 &self.section 76 } 77 } 78 79 impl<R> From<R> for DebugTuIndex<R> { from(section: R) -> Self80 fn from(section: R) -> Self { 81 DebugTuIndex { section } 82 } 83 } 84 85 impl<R: Reader> DebugTuIndex<R> { 86 /// Parse the index header. index(self) -> Result<UnitIndex<R>>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> { parse(mut input: R) -> Result<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`. find(&self, id: u64) -> Option<u32>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. sections(&self, mut row: u32) -> Result<UnitIndexSectionIterator<R>>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. version(&self) -> u16255 pub fn version(&self) -> u16 { 256 self.version 257 } 258 259 /// Return the number of sections. section_count(&self) -> u32260 pub fn section_count(&self) -> u32 { 261 self.section_count 262 } 263 264 /// Return the number of units. unit_count(&self) -> u32265 pub fn unit_count(&self) -> u32 { 266 self.unit_count 267 } 268 269 /// Return the number of slots. slot_count(&self) -> u32270 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 next(&mut self) -> Option<UnitIndexSection>286 fn next(&mut self) -> Option<UnitIndexSection> { 287 let section = *self.sections.next()?; 288 // The length of these arrays was validated in `UnitIndex::parse`. 289 let offset = self.offsets.read_u32().ok()?; 290 let size = 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] test_empty()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] test_version_2()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] test_version_5()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] test_version_5_invalid()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] test_version_2_sections()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] test_version_5_sections()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] test_hash()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] test_cu_index()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] test_tu_index()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