1 use core::fmt::Debug; 2 use core::{iter, mem, slice, str}; 3 4 use crate::elf; 5 use crate::endian::{self, Endianness, U32Bytes}; 6 use crate::pod::Pod; 7 use crate::read::{ 8 self, Bytes, CompressedData, CompressedFileRange, CompressionFormat, Error, ObjectSection, 9 ReadError, ReadRef, SectionFlags, SectionIndex, SectionKind, StringTable, 10 }; 11 12 use super::{ 13 CompressionHeader, ElfFile, ElfSectionRelocationIterator, FileHeader, GnuHashTable, HashTable, 14 NoteIterator, RelocationSections, SymbolTable, VerdefIterator, VerneedIterator, 15 }; 16 17 /// The table of section headers in an ELF file. 18 /// 19 /// Also includes the string table used for the section names. 20 #[derive(Debug, Default, Clone, Copy)] 21 pub struct SectionTable<'data, Elf: FileHeader, R = &'data [u8]> 22 where 23 R: ReadRef<'data>, 24 { 25 sections: &'data [Elf::SectionHeader], 26 strings: StringTable<'data, R>, 27 } 28 29 impl<'data, Elf: FileHeader, R: ReadRef<'data>> SectionTable<'data, Elf, R> { 30 /// Create a new section table. 31 #[inline] new(sections: &'data [Elf::SectionHeader], strings: StringTable<'data, R>) -> Self32 pub fn new(sections: &'data [Elf::SectionHeader], strings: StringTable<'data, R>) -> Self { 33 SectionTable { sections, strings } 34 } 35 36 /// Iterate over the section headers. 37 #[inline] iter(&self) -> slice::Iter<'data, Elf::SectionHeader>38 pub fn iter(&self) -> slice::Iter<'data, Elf::SectionHeader> { 39 self.sections.iter() 40 } 41 42 /// Return true if the section table is empty. 43 #[inline] is_empty(&self) -> bool44 pub fn is_empty(&self) -> bool { 45 self.sections.is_empty() 46 } 47 48 /// The number of section headers. 49 #[inline] len(&self) -> usize50 pub fn len(&self) -> usize { 51 self.sections.len() 52 } 53 54 /// Return the section header at the given index. section(&self, index: usize) -> read::Result<&'data Elf::SectionHeader>55 pub fn section(&self, index: usize) -> read::Result<&'data Elf::SectionHeader> { 56 self.sections 57 .get(index) 58 .read_error("Invalid ELF section index") 59 } 60 61 /// Return the section header with the given name. 62 /// 63 /// Ignores sections with invalid names. section_by_name( &self, endian: Elf::Endian, name: &[u8], ) -> Option<(usize, &'data Elf::SectionHeader)>64 pub fn section_by_name( 65 &self, 66 endian: Elf::Endian, 67 name: &[u8], 68 ) -> Option<(usize, &'data Elf::SectionHeader)> { 69 self.sections 70 .iter() 71 .enumerate() 72 .find(|(_, section)| self.section_name(endian, section) == Ok(name)) 73 } 74 75 /// Return the section name for the given section header. section_name( &self, endian: Elf::Endian, section: &'data Elf::SectionHeader, ) -> read::Result<&'data [u8]>76 pub fn section_name( 77 &self, 78 endian: Elf::Endian, 79 section: &'data Elf::SectionHeader, 80 ) -> read::Result<&'data [u8]> { 81 section.name(endian, self.strings) 82 } 83 84 /// Return the symbol table of the given section type. 85 /// 86 /// Returns an empty symbol table if the symbol table does not exist. 87 #[inline] symbols( &self, endian: Elf::Endian, data: R, sh_type: u32, ) -> read::Result<SymbolTable<'data, Elf, R>>88 pub fn symbols( 89 &self, 90 endian: Elf::Endian, 91 data: R, 92 sh_type: u32, 93 ) -> read::Result<SymbolTable<'data, Elf, R>> { 94 debug_assert!(sh_type == elf::SHT_DYNSYM || sh_type == elf::SHT_SYMTAB); 95 96 let (index, section) = match self 97 .iter() 98 .enumerate() 99 .find(|s| s.1.sh_type(endian) == sh_type) 100 { 101 Some(s) => s, 102 None => return Ok(SymbolTable::default()), 103 }; 104 105 SymbolTable::parse(endian, data, self, index, section) 106 } 107 108 /// Return the symbol table at the given section index. 109 /// 110 /// Returns an error if the section is not a symbol table. 111 #[inline] symbol_table_by_index( &self, endian: Elf::Endian, data: R, index: usize, ) -> read::Result<SymbolTable<'data, Elf, R>>112 pub fn symbol_table_by_index( 113 &self, 114 endian: Elf::Endian, 115 data: R, 116 index: usize, 117 ) -> read::Result<SymbolTable<'data, Elf, R>> { 118 let section = self.section(index)?; 119 match section.sh_type(endian) { 120 elf::SHT_DYNSYM | elf::SHT_SYMTAB => {} 121 _ => return Err(Error("Invalid ELF symbol table section type.")), 122 } 123 SymbolTable::parse(endian, data, self, index, section) 124 } 125 126 /// Create a mapping from section index to associated relocation sections. 127 #[inline] relocation_sections( &self, endian: Elf::Endian, symbol_section: usize, ) -> read::Result<RelocationSections>128 pub fn relocation_sections( 129 &self, 130 endian: Elf::Endian, 131 symbol_section: usize, 132 ) -> read::Result<RelocationSections> { 133 RelocationSections::parse(endian, self, symbol_section) 134 } 135 136 /// Return the header of a SysV hash section. 137 /// 138 /// Returns `Ok(None)` if there is no SysV GNU hash section. 139 /// Returns `Err` for invalid values. hash_header( &self, endian: Elf::Endian, data: R, ) -> read::Result<Option<&'data elf::HashHeader<Elf::Endian>>>140 pub fn hash_header( 141 &self, 142 endian: Elf::Endian, 143 data: R, 144 ) -> read::Result<Option<&'data elf::HashHeader<Elf::Endian>>> { 145 for section in self.sections { 146 if let Some(hash) = section.hash_header(endian, data)? { 147 return Ok(Some(hash)); 148 } 149 } 150 Ok(None) 151 } 152 153 /// Return the contents of a SysV hash section. 154 /// 155 /// Returns `Ok(None)` if there is no SysV hash section. 156 /// Returns `Err` for invalid values. hash( &self, endian: Elf::Endian, data: R, ) -> read::Result<Option<HashTable<'data, Elf>>>157 pub fn hash( 158 &self, 159 endian: Elf::Endian, 160 data: R, 161 ) -> read::Result<Option<HashTable<'data, Elf>>> { 162 for section in self.sections { 163 if let Some(hash) = section.hash(endian, data)? { 164 return Ok(Some(hash)); 165 } 166 } 167 Ok(None) 168 } 169 170 /// Return the header of a GNU hash section. 171 /// 172 /// Returns `Ok(None)` if there is no GNU hash section. 173 /// Returns `Err` for invalid values. gnu_hash_header( &self, endian: Elf::Endian, data: R, ) -> read::Result<Option<&'data elf::GnuHashHeader<Elf::Endian>>>174 pub fn gnu_hash_header( 175 &self, 176 endian: Elf::Endian, 177 data: R, 178 ) -> read::Result<Option<&'data elf::GnuHashHeader<Elf::Endian>>> { 179 for section in self.sections { 180 if let Some(hash) = section.gnu_hash_header(endian, data)? { 181 return Ok(Some(hash)); 182 } 183 } 184 Ok(None) 185 } 186 187 /// Return the contents of a GNU hash section. 188 /// 189 /// Returns `Ok(None)` if there is no GNU hash section. 190 /// Returns `Err` for invalid values. gnu_hash( &self, endian: Elf::Endian, data: R, ) -> read::Result<Option<GnuHashTable<'data, Elf>>>191 pub fn gnu_hash( 192 &self, 193 endian: Elf::Endian, 194 data: R, 195 ) -> read::Result<Option<GnuHashTable<'data, Elf>>> { 196 for section in self.sections { 197 if let Some(hash) = section.gnu_hash(endian, data)? { 198 return Ok(Some(hash)); 199 } 200 } 201 Ok(None) 202 } 203 204 /// Return the contents of a `SHT_GNU_VERSYM` section. 205 /// 206 /// Returns `Ok(None)` if there is no `SHT_GNU_VERSYM` section. 207 /// Returns `Err` for invalid values. gnu_versym( &self, endian: Elf::Endian, data: R, ) -> read::Result<Option<&'data [elf::Versym<Elf::Endian>]>>208 pub fn gnu_versym( 209 &self, 210 endian: Elf::Endian, 211 data: R, 212 ) -> read::Result<Option<&'data [elf::Versym<Elf::Endian>]>> { 213 for section in self.sections { 214 if let Some(syms) = section.gnu_versym(endian, data)? { 215 return Ok(Some(syms)); 216 } 217 } 218 Ok(None) 219 } 220 221 /// Return the contents of a `SHT_GNU_VERDEF` section. 222 /// 223 /// Returns `Ok(None)` if there is no `SHT_GNU_VERDEF` section. 224 /// Returns `Err` for invalid values. gnu_verdef( &self, endian: Elf::Endian, data: R, ) -> read::Result<Option<VerdefIterator<'data, Elf>>>225 pub fn gnu_verdef( 226 &self, 227 endian: Elf::Endian, 228 data: R, 229 ) -> read::Result<Option<VerdefIterator<'data, Elf>>> { 230 for section in self.sections { 231 if let Some(defs) = section.gnu_verdef(endian, data)? { 232 return Ok(Some(defs)); 233 } 234 } 235 Ok(None) 236 } 237 238 /// Return the contents of a `SHT_GNU_VERNEED` section. 239 /// 240 /// Returns `Ok(None)` if there is no `SHT_GNU_VERNEED` section. 241 /// Returns `Err` for invalid values. gnu_verneed( &self, endian: Elf::Endian, data: R, ) -> read::Result<Option<VerneedIterator<'data, Elf>>>242 pub fn gnu_verneed( 243 &self, 244 endian: Elf::Endian, 245 data: R, 246 ) -> read::Result<Option<VerneedIterator<'data, Elf>>> { 247 for section in self.sections { 248 if let Some(needs) = section.gnu_verneed(endian, data)? { 249 return Ok(Some(needs)); 250 } 251 } 252 Ok(None) 253 } 254 } 255 256 /// An iterator over the sections of an `ElfFile32`. 257 pub type ElfSectionIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> = 258 ElfSectionIterator<'data, 'file, elf::FileHeader32<Endian>, R>; 259 /// An iterator over the sections of an `ElfFile64`. 260 pub type ElfSectionIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> = 261 ElfSectionIterator<'data, 'file, elf::FileHeader64<Endian>, R>; 262 263 /// An iterator over the sections of an `ElfFile`. 264 #[derive(Debug)] 265 pub struct ElfSectionIterator<'data, 'file, Elf, R = &'data [u8]> 266 where 267 Elf: FileHeader, 268 R: ReadRef<'data>, 269 { 270 pub(super) file: &'file ElfFile<'data, Elf, R>, 271 pub(super) iter: iter::Enumerate<slice::Iter<'data, Elf::SectionHeader>>, 272 } 273 274 impl<'data, 'file, Elf, R> Iterator for ElfSectionIterator<'data, 'file, Elf, R> 275 where 276 Elf: FileHeader, 277 R: ReadRef<'data>, 278 { 279 type Item = ElfSection<'data, 'file, Elf, R>; 280 next(&mut self) -> Option<Self::Item>281 fn next(&mut self) -> Option<Self::Item> { 282 self.iter.next().map(|(index, section)| ElfSection { 283 index: SectionIndex(index), 284 file: self.file, 285 section, 286 }) 287 } 288 } 289 290 /// A section of an `ElfFile32`. 291 pub type ElfSection32<'data, 'file, Endian = Endianness, R = &'data [u8]> = 292 ElfSection<'data, 'file, elf::FileHeader32<Endian>, R>; 293 /// A section of an `ElfFile64`. 294 pub type ElfSection64<'data, 'file, Endian = Endianness, R = &'data [u8]> = 295 ElfSection<'data, 'file, elf::FileHeader64<Endian>, R>; 296 297 /// A section of an `ElfFile`. 298 #[derive(Debug)] 299 pub struct ElfSection<'data, 'file, Elf, R = &'data [u8]> 300 where 301 'data: 'file, 302 Elf: FileHeader, 303 R: ReadRef<'data>, 304 { 305 pub(super) file: &'file ElfFile<'data, Elf, R>, 306 pub(super) index: SectionIndex, 307 pub(super) section: &'data Elf::SectionHeader, 308 } 309 310 impl<'data, 'file, Elf: FileHeader, R: ReadRef<'data>> ElfSection<'data, 'file, Elf, R> { bytes(&self) -> read::Result<&'data [u8]>311 fn bytes(&self) -> read::Result<&'data [u8]> { 312 self.section 313 .data(self.file.endian, self.file.data) 314 .read_error("Invalid ELF section size or offset") 315 } 316 maybe_compressed(&self) -> read::Result<Option<CompressedFileRange>>317 fn maybe_compressed(&self) -> read::Result<Option<CompressedFileRange>> { 318 let endian = self.file.endian; 319 if (self.section.sh_flags(endian).into() & u64::from(elf::SHF_COMPRESSED)) == 0 { 320 return Ok(None); 321 } 322 let (section_offset, section_size) = self 323 .section 324 .file_range(endian) 325 .read_error("Invalid ELF compressed section type")?; 326 let mut offset = section_offset; 327 let header = self 328 .file 329 .data 330 .read::<Elf::CompressionHeader>(&mut offset) 331 .read_error("Invalid ELF compressed section offset")?; 332 if header.ch_type(endian) != elf::ELFCOMPRESS_ZLIB { 333 return Err(Error("Unsupported ELF compression type")); 334 } 335 let uncompressed_size = header.ch_size(endian).into(); 336 let compressed_size = section_size 337 .checked_sub(offset - section_offset) 338 .read_error("Invalid ELF compressed section size")?; 339 Ok(Some(CompressedFileRange { 340 format: CompressionFormat::Zlib, 341 offset, 342 compressed_size, 343 uncompressed_size, 344 })) 345 } 346 347 /// Try GNU-style "ZLIB" header decompression. maybe_compressed_gnu(&self) -> read::Result<Option<CompressedFileRange>>348 fn maybe_compressed_gnu(&self) -> read::Result<Option<CompressedFileRange>> { 349 let name = match self.name() { 350 Ok(name) => name, 351 // I think it's ok to ignore this error? 352 Err(_) => return Ok(None), 353 }; 354 if !name.starts_with(".zdebug_") { 355 return Ok(None); 356 } 357 let (section_offset, section_size) = self 358 .section 359 .file_range(self.file.endian) 360 .read_error("Invalid ELF GNU compressed section type")?; 361 let mut offset = section_offset; 362 let data = self.file.data; 363 // Assume ZLIB-style uncompressed data is no more than 4GB to avoid accidentally 364 // huge allocations. This also reduces the chance of accidentally matching on a 365 // .debug_str that happens to start with "ZLIB". 366 if data 367 .read_bytes(&mut offset, 8) 368 .read_error("ELF GNU compressed section is too short")? 369 != b"ZLIB\0\0\0\0" 370 { 371 return Err(Error("Invalid ELF GNU compressed section header")); 372 } 373 let uncompressed_size = data 374 .read::<U32Bytes<_>>(&mut offset) 375 .read_error("ELF GNU compressed section is too short")? 376 .get(endian::BigEndian) 377 .into(); 378 let compressed_size = section_size 379 .checked_sub(offset - section_offset) 380 .read_error("ELF GNU compressed section is too short")?; 381 Ok(Some(CompressedFileRange { 382 format: CompressionFormat::Zlib, 383 offset, 384 compressed_size, 385 uncompressed_size, 386 })) 387 } 388 } 389 390 impl<'data, 'file, Elf, R> read::private::Sealed for ElfSection<'data, 'file, Elf, R> 391 where 392 Elf: FileHeader, 393 R: ReadRef<'data>, 394 { 395 } 396 397 impl<'data, 'file, Elf, R> ObjectSection<'data> for ElfSection<'data, 'file, Elf, R> 398 where 399 Elf: FileHeader, 400 R: ReadRef<'data>, 401 { 402 type RelocationIterator = ElfSectionRelocationIterator<'data, 'file, Elf, R>; 403 404 #[inline] index(&self) -> SectionIndex405 fn index(&self) -> SectionIndex { 406 self.index 407 } 408 409 #[inline] address(&self) -> u64410 fn address(&self) -> u64 { 411 self.section.sh_addr(self.file.endian).into() 412 } 413 414 #[inline] size(&self) -> u64415 fn size(&self) -> u64 { 416 self.section.sh_size(self.file.endian).into() 417 } 418 419 #[inline] align(&self) -> u64420 fn align(&self) -> u64 { 421 self.section.sh_addralign(self.file.endian).into() 422 } 423 424 #[inline] file_range(&self) -> Option<(u64, u64)>425 fn file_range(&self) -> Option<(u64, u64)> { 426 self.section.file_range(self.file.endian) 427 } 428 429 #[inline] data(&self) -> read::Result<&'data [u8]>430 fn data(&self) -> read::Result<&'data [u8]> { 431 self.bytes() 432 } 433 data_range(&self, address: u64, size: u64) -> read::Result<Option<&'data [u8]>>434 fn data_range(&self, address: u64, size: u64) -> read::Result<Option<&'data [u8]>> { 435 Ok(read::util::data_range( 436 self.bytes()?, 437 self.address(), 438 address, 439 size, 440 )) 441 } 442 compressed_file_range(&self) -> read::Result<CompressedFileRange>443 fn compressed_file_range(&self) -> read::Result<CompressedFileRange> { 444 Ok(if let Some(data) = self.maybe_compressed()? { 445 data 446 } else if let Some(data) = self.maybe_compressed_gnu()? { 447 data 448 } else { 449 CompressedFileRange::none(self.file_range()) 450 }) 451 } 452 compressed_data(&self) -> read::Result<CompressedData<'data>>453 fn compressed_data(&self) -> read::Result<CompressedData<'data>> { 454 self.compressed_file_range()?.data(self.file.data) 455 } 456 name(&self) -> read::Result<&str>457 fn name(&self) -> read::Result<&str> { 458 let name = self 459 .file 460 .sections 461 .section_name(self.file.endian, self.section)?; 462 str::from_utf8(name) 463 .ok() 464 .read_error("Non UTF-8 ELF section name") 465 } 466 467 #[inline] segment_name(&self) -> read::Result<Option<&str>>468 fn segment_name(&self) -> read::Result<Option<&str>> { 469 Ok(None) 470 } 471 kind(&self) -> SectionKind472 fn kind(&self) -> SectionKind { 473 let flags = self.section.sh_flags(self.file.endian).into(); 474 let sh_type = self.section.sh_type(self.file.endian); 475 match sh_type { 476 elf::SHT_PROGBITS => { 477 if flags & u64::from(elf::SHF_ALLOC) != 0 { 478 if flags & u64::from(elf::SHF_EXECINSTR) != 0 { 479 SectionKind::Text 480 } else if flags & u64::from(elf::SHF_TLS) != 0 { 481 SectionKind::Tls 482 } else if flags & u64::from(elf::SHF_WRITE) != 0 { 483 SectionKind::Data 484 } else if flags & u64::from(elf::SHF_STRINGS) != 0 { 485 SectionKind::ReadOnlyString 486 } else { 487 SectionKind::ReadOnlyData 488 } 489 } else if flags & u64::from(elf::SHF_STRINGS) != 0 { 490 SectionKind::OtherString 491 } else { 492 SectionKind::Other 493 } 494 } 495 elf::SHT_NOBITS => { 496 if flags & u64::from(elf::SHF_TLS) != 0 { 497 SectionKind::UninitializedTls 498 } else { 499 SectionKind::UninitializedData 500 } 501 } 502 elf::SHT_NOTE => SectionKind::Note, 503 elf::SHT_NULL 504 | elf::SHT_SYMTAB 505 | elf::SHT_STRTAB 506 | elf::SHT_RELA 507 | elf::SHT_HASH 508 | elf::SHT_DYNAMIC 509 | elf::SHT_REL 510 | elf::SHT_DYNSYM 511 | elf::SHT_GROUP => SectionKind::Metadata, 512 _ => SectionKind::Elf(sh_type), 513 } 514 } 515 relocations(&self) -> ElfSectionRelocationIterator<'data, 'file, Elf, R>516 fn relocations(&self) -> ElfSectionRelocationIterator<'data, 'file, Elf, R> { 517 ElfSectionRelocationIterator { 518 section_index: self.index.0, 519 file: self.file, 520 relocations: None, 521 } 522 } 523 flags(&self) -> SectionFlags524 fn flags(&self) -> SectionFlags { 525 SectionFlags::Elf { 526 sh_flags: self.section.sh_flags(self.file.endian).into(), 527 } 528 } 529 } 530 531 /// A trait for generic access to `SectionHeader32` and `SectionHeader64`. 532 #[allow(missing_docs)] 533 pub trait SectionHeader: Debug + Pod { 534 type Elf: FileHeader<SectionHeader = Self, Endian = Self::Endian, Word = Self::Word>; 535 type Word: Into<u64>; 536 type Endian: endian::Endian; 537 sh_name(&self, endian: Self::Endian) -> u32538 fn sh_name(&self, endian: Self::Endian) -> u32; sh_type(&self, endian: Self::Endian) -> u32539 fn sh_type(&self, endian: Self::Endian) -> u32; sh_flags(&self, endian: Self::Endian) -> Self::Word540 fn sh_flags(&self, endian: Self::Endian) -> Self::Word; sh_addr(&self, endian: Self::Endian) -> Self::Word541 fn sh_addr(&self, endian: Self::Endian) -> Self::Word; sh_offset(&self, endian: Self::Endian) -> Self::Word542 fn sh_offset(&self, endian: Self::Endian) -> Self::Word; sh_size(&self, endian: Self::Endian) -> Self::Word543 fn sh_size(&self, endian: Self::Endian) -> Self::Word; sh_link(&self, endian: Self::Endian) -> u32544 fn sh_link(&self, endian: Self::Endian) -> u32; sh_info(&self, endian: Self::Endian) -> u32545 fn sh_info(&self, endian: Self::Endian) -> u32; sh_addralign(&self, endian: Self::Endian) -> Self::Word546 fn sh_addralign(&self, endian: Self::Endian) -> Self::Word; sh_entsize(&self, endian: Self::Endian) -> Self::Word547 fn sh_entsize(&self, endian: Self::Endian) -> Self::Word; 548 549 /// Parse the section name from the string table. name<'data, R: ReadRef<'data>>( &self, endian: Self::Endian, strings: StringTable<'data, R>, ) -> read::Result<&'data [u8]>550 fn name<'data, R: ReadRef<'data>>( 551 &self, 552 endian: Self::Endian, 553 strings: StringTable<'data, R>, 554 ) -> read::Result<&'data [u8]> { 555 strings 556 .get(self.sh_name(endian)) 557 .read_error("Invalid ELF section name offset") 558 } 559 560 /// Return the offset and size of the section in the file. 561 /// 562 /// Returns `None` for sections that have no data in the file. file_range(&self, endian: Self::Endian) -> Option<(u64, u64)>563 fn file_range(&self, endian: Self::Endian) -> Option<(u64, u64)> { 564 if self.sh_type(endian) == elf::SHT_NOBITS { 565 None 566 } else { 567 Some((self.sh_offset(endian).into(), self.sh_size(endian).into())) 568 } 569 } 570 571 /// Return the section data. 572 /// 573 /// Returns `Ok(&[])` if the section has no data. 574 /// Returns `Err` for invalid values. data<'data, R: ReadRef<'data>>( &self, endian: Self::Endian, data: R, ) -> read::Result<&'data [u8]>575 fn data<'data, R: ReadRef<'data>>( 576 &self, 577 endian: Self::Endian, 578 data: R, 579 ) -> read::Result<&'data [u8]> { 580 if let Some((offset, size)) = self.file_range(endian) { 581 data.read_bytes_at(offset, size) 582 .read_error("Invalid ELF section size or offset") 583 } else { 584 Ok(&[]) 585 } 586 } 587 588 /// Return the section data as a slice of the given type. 589 /// 590 /// Allows padding at the end of the data. 591 /// Returns `Ok(&[])` if the section has no data. 592 /// Returns `Err` for invalid values, including bad alignment. data_as_array<'data, T: Pod, R: ReadRef<'data>>( &self, endian: Self::Endian, data: R, ) -> read::Result<&'data [T]>593 fn data_as_array<'data, T: Pod, R: ReadRef<'data>>( 594 &self, 595 endian: Self::Endian, 596 data: R, 597 ) -> read::Result<&'data [T]> { 598 let mut data = self.data(endian, data).map(Bytes)?; 599 data.read_slice(data.len() / mem::size_of::<T>()) 600 .read_error("Invalid ELF section size or offset") 601 } 602 603 /// Return the symbols in the section. 604 /// 605 /// Also finds the corresponding string table in `sections`. 606 /// 607 /// `section_index` must be the 0-based index of this section, and is used 608 /// to find the corresponding extended section index table in `sections`. 609 /// 610 /// Returns `Ok(None)` if the section does not contain symbols. 611 /// Returns `Err` for invalid values. symbols<'data, R: ReadRef<'data>>( &self, endian: Self::Endian, data: R, sections: &SectionTable<'data, Self::Elf, R>, section_index: usize, ) -> read::Result<Option<SymbolTable<'data, Self::Elf, R>>>612 fn symbols<'data, R: ReadRef<'data>>( 613 &self, 614 endian: Self::Endian, 615 data: R, 616 sections: &SectionTable<'data, Self::Elf, R>, 617 section_index: usize, 618 ) -> read::Result<Option<SymbolTable<'data, Self::Elf, R>>> { 619 let sh_type = self.sh_type(endian); 620 if sh_type != elf::SHT_SYMTAB && sh_type != elf::SHT_DYNSYM { 621 return Ok(None); 622 } 623 SymbolTable::parse(endian, data, sections, section_index, self).map(Some) 624 } 625 626 /// Return the `Elf::Rel` entries in the section. 627 /// 628 /// Returns `Ok(None)` if the section does not contain relocations. 629 /// Returns `Err` for invalid values. rel<'data, R: ReadRef<'data>>( &self, endian: Self::Endian, data: R, ) -> read::Result<Option<&'data [<Self::Elf as FileHeader>::Rel]>>630 fn rel<'data, R: ReadRef<'data>>( 631 &self, 632 endian: Self::Endian, 633 data: R, 634 ) -> read::Result<Option<&'data [<Self::Elf as FileHeader>::Rel]>> { 635 if self.sh_type(endian) != elf::SHT_REL { 636 return Ok(None); 637 } 638 self.data_as_array(endian, data) 639 .map(Some) 640 .read_error("Invalid ELF relocation section offset or size") 641 } 642 643 /// Return the `Elf::Rela` entries in the section. 644 /// 645 /// Returns `Ok(None)` if the section does not contain relocations. 646 /// Returns `Err` for invalid values. rela<'data, R: ReadRef<'data>>( &self, endian: Self::Endian, data: R, ) -> read::Result<Option<&'data [<Self::Elf as FileHeader>::Rela]>>647 fn rela<'data, R: ReadRef<'data>>( 648 &self, 649 endian: Self::Endian, 650 data: R, 651 ) -> read::Result<Option<&'data [<Self::Elf as FileHeader>::Rela]>> { 652 if self.sh_type(endian) != elf::SHT_RELA { 653 return Ok(None); 654 } 655 self.data_as_array(endian, data) 656 .map(Some) 657 .read_error("Invalid ELF relocation section offset or size") 658 } 659 660 /// Return the symbol table for a relocation section. 661 /// 662 /// Returns `Err` for invalid values, including if the section does not contain 663 /// relocations. relocation_symbols<'data, R: ReadRef<'data>>( &self, endian: Self::Endian, data: R, sections: &SectionTable<'data, Self::Elf, R>, ) -> read::Result<SymbolTable<'data, Self::Elf, R>>664 fn relocation_symbols<'data, R: ReadRef<'data>>( 665 &self, 666 endian: Self::Endian, 667 data: R, 668 sections: &SectionTable<'data, Self::Elf, R>, 669 ) -> read::Result<SymbolTable<'data, Self::Elf, R>> { 670 let sh_type = self.sh_type(endian); 671 if sh_type != elf::SHT_REL && sh_type != elf::SHT_RELA { 672 return Err(Error("Invalid ELF relocation section type")); 673 } 674 sections.symbol_table_by_index(endian, data, self.sh_link(endian) as usize) 675 } 676 677 /// Return a note iterator for the section data. 678 /// 679 /// Returns `Ok(None)` if the section does not contain notes. 680 /// Returns `Err` for invalid values. notes<'data, R: ReadRef<'data>>( &self, endian: Self::Endian, data: R, ) -> read::Result<Option<NoteIterator<'data, Self::Elf>>>681 fn notes<'data, R: ReadRef<'data>>( 682 &self, 683 endian: Self::Endian, 684 data: R, 685 ) -> read::Result<Option<NoteIterator<'data, Self::Elf>>> { 686 if self.sh_type(endian) != elf::SHT_NOTE { 687 return Ok(None); 688 } 689 let data = self 690 .data(endian, data) 691 .read_error("Invalid ELF note section offset or size")?; 692 let notes = NoteIterator::new(endian, self.sh_addralign(endian), data)?; 693 Ok(Some(notes)) 694 } 695 696 /// Return the contents of a group section. 697 /// 698 /// The first value is a `GRP_*` value, and the remaining values 699 /// are section indices. 700 /// 701 /// Returns `Ok(None)` if the section does not define a group. 702 /// Returns `Err` for invalid values. group<'data, R: ReadRef<'data>>( &self, endian: Self::Endian, data: R, ) -> read::Result<Option<(u32, &'data [U32Bytes<Self::Endian>])>>703 fn group<'data, R: ReadRef<'data>>( 704 &self, 705 endian: Self::Endian, 706 data: R, 707 ) -> read::Result<Option<(u32, &'data [U32Bytes<Self::Endian>])>> { 708 if self.sh_type(endian) != elf::SHT_GROUP { 709 return Ok(None); 710 } 711 let mut data = self 712 .data(endian, data) 713 .read_error("Invalid ELF group section offset or size") 714 .map(Bytes)?; 715 let flag = data 716 .read::<U32Bytes<_>>() 717 .read_error("Invalid ELF group section offset or size")? 718 .get(endian); 719 let count = data.len() / mem::size_of::<U32Bytes<Self::Endian>>(); 720 let sections = data 721 .read_slice(count) 722 .read_error("Invalid ELF group section offset or size")?; 723 Ok(Some((flag, sections))) 724 } 725 726 /// Return the header of a SysV hash section. 727 /// 728 /// Returns `Ok(None)` if the section does not contain a SysV hash. 729 /// Returns `Err` for invalid values. hash_header<'data, R: ReadRef<'data>>( &self, endian: Self::Endian, data: R, ) -> read::Result<Option<&'data elf::HashHeader<Self::Endian>>>730 fn hash_header<'data, R: ReadRef<'data>>( 731 &self, 732 endian: Self::Endian, 733 data: R, 734 ) -> read::Result<Option<&'data elf::HashHeader<Self::Endian>>> { 735 if self.sh_type(endian) != elf::SHT_HASH { 736 return Ok(None); 737 } 738 let data = self 739 .data(endian, data) 740 .read_error("Invalid ELF hash section offset or size")?; 741 let header = data 742 .read_at::<elf::HashHeader<Self::Endian>>(0) 743 .read_error("Invalid hash header")?; 744 Ok(Some(header)) 745 } 746 747 /// Return the contents of a SysV hash section. 748 /// 749 /// Returns `Ok(None)` if the section does not contain a SysV hash. 750 /// Returns `Err` for invalid values. hash<'data, R: ReadRef<'data>>( &self, endian: Self::Endian, data: R, ) -> read::Result<Option<HashTable<'data, Self::Elf>>>751 fn hash<'data, R: ReadRef<'data>>( 752 &self, 753 endian: Self::Endian, 754 data: R, 755 ) -> read::Result<Option<HashTable<'data, Self::Elf>>> { 756 if self.sh_type(endian) != elf::SHT_HASH { 757 return Ok(None); 758 } 759 let data = self 760 .data(endian, data) 761 .read_error("Invalid ELF hash section offset or size")?; 762 let hash = HashTable::parse(endian, data)?; 763 Ok(Some(hash)) 764 } 765 766 /// Return the header of a GNU hash section. 767 /// 768 /// Returns `Ok(None)` if the section does not contain a GNU hash. 769 /// Returns `Err` for invalid values. gnu_hash_header<'data, R: ReadRef<'data>>( &self, endian: Self::Endian, data: R, ) -> read::Result<Option<&'data elf::GnuHashHeader<Self::Endian>>>770 fn gnu_hash_header<'data, R: ReadRef<'data>>( 771 &self, 772 endian: Self::Endian, 773 data: R, 774 ) -> read::Result<Option<&'data elf::GnuHashHeader<Self::Endian>>> { 775 if self.sh_type(endian) != elf::SHT_GNU_HASH { 776 return Ok(None); 777 } 778 let data = self 779 .data(endian, data) 780 .read_error("Invalid ELF GNU hash section offset or size")?; 781 let header = data 782 .read_at::<elf::GnuHashHeader<Self::Endian>>(0) 783 .read_error("Invalid GNU hash header")?; 784 Ok(Some(header)) 785 } 786 787 /// Return the contents of a GNU hash section. 788 /// 789 /// Returns `Ok(None)` if the section does not contain a GNU hash. 790 /// Returns `Err` for invalid values. gnu_hash<'data, R: ReadRef<'data>>( &self, endian: Self::Endian, data: R, ) -> read::Result<Option<GnuHashTable<'data, Self::Elf>>>791 fn gnu_hash<'data, R: ReadRef<'data>>( 792 &self, 793 endian: Self::Endian, 794 data: R, 795 ) -> read::Result<Option<GnuHashTable<'data, Self::Elf>>> { 796 if self.sh_type(endian) != elf::SHT_GNU_HASH { 797 return Ok(None); 798 } 799 let data = self 800 .data(endian, data) 801 .read_error("Invalid ELF GNU hash section offset or size")?; 802 let hash = GnuHashTable::parse(endian, data)?; 803 Ok(Some(hash)) 804 } 805 806 /// Return the contents of a `SHT_GNU_VERSYM` section. 807 /// 808 /// Returns `Ok(None)` if the section type is not `SHT_GNU_VERSYM`. 809 /// Returns `Err` for invalid values. gnu_versym<'data, R: ReadRef<'data>>( &self, endian: Self::Endian, data: R, ) -> read::Result<Option<&'data [elf::Versym<Self::Endian>]>>810 fn gnu_versym<'data, R: ReadRef<'data>>( 811 &self, 812 endian: Self::Endian, 813 data: R, 814 ) -> read::Result<Option<&'data [elf::Versym<Self::Endian>]>> { 815 if self.sh_type(endian) != elf::SHT_GNU_VERSYM { 816 return Ok(None); 817 } 818 self.data_as_array(endian, data) 819 .read_error("Invalid ELF GNU versym section offset or size") 820 .map(Some) 821 } 822 823 /// Return an iterator for the entries of a `SHT_GNU_VERDEF` section. 824 /// 825 /// Returns `Ok(None)` if the section type is not `SHT_GNU_VERDEF`. 826 /// Returns `Err` for invalid values. gnu_verdef<'data, R: ReadRef<'data>>( &self, endian: Self::Endian, data: R, ) -> read::Result<Option<VerdefIterator<'data, Self::Elf>>>827 fn gnu_verdef<'data, R: ReadRef<'data>>( 828 &self, 829 endian: Self::Endian, 830 data: R, 831 ) -> read::Result<Option<VerdefIterator<'data, Self::Elf>>> { 832 if self.sh_type(endian) != elf::SHT_GNU_VERDEF { 833 return Ok(None); 834 } 835 let data = self 836 .data_as_array(endian, data) 837 .read_error("Invalid ELF GNU verdef section offset or size")?; 838 Ok(Some(VerdefIterator::new(endian, data))) 839 } 840 841 /// Return an iterator for the entries of a `SHT_GNU_VERNEED` section. 842 /// 843 /// Returns `Ok(None)` if the section type is not `SHT_GNU_VERNEED`. 844 /// Returns `Err` for invalid values. gnu_verneed<'data, R: ReadRef<'data>>( &self, endian: Self::Endian, data: R, ) -> read::Result<Option<VerneedIterator<'data, Self::Elf>>>845 fn gnu_verneed<'data, R: ReadRef<'data>>( 846 &self, 847 endian: Self::Endian, 848 data: R, 849 ) -> read::Result<Option<VerneedIterator<'data, Self::Elf>>> { 850 if self.sh_type(endian) != elf::SHT_GNU_VERNEED { 851 return Ok(None); 852 } 853 let data = self 854 .data_as_array(endian, data) 855 .read_error("Invalid ELF GNU verneed section offset or size")?; 856 Ok(Some(VerneedIterator::new(endian, data))) 857 } 858 } 859 860 impl<Endian: endian::Endian> SectionHeader for elf::SectionHeader32<Endian> { 861 type Elf = elf::FileHeader32<Endian>; 862 type Word = u32; 863 type Endian = Endian; 864 865 #[inline] sh_name(&self, endian: Self::Endian) -> u32866 fn sh_name(&self, endian: Self::Endian) -> u32 { 867 self.sh_name.get(endian) 868 } 869 870 #[inline] sh_type(&self, endian: Self::Endian) -> u32871 fn sh_type(&self, endian: Self::Endian) -> u32 { 872 self.sh_type.get(endian) 873 } 874 875 #[inline] sh_flags(&self, endian: Self::Endian) -> Self::Word876 fn sh_flags(&self, endian: Self::Endian) -> Self::Word { 877 self.sh_flags.get(endian) 878 } 879 880 #[inline] sh_addr(&self, endian: Self::Endian) -> Self::Word881 fn sh_addr(&self, endian: Self::Endian) -> Self::Word { 882 self.sh_addr.get(endian) 883 } 884 885 #[inline] sh_offset(&self, endian: Self::Endian) -> Self::Word886 fn sh_offset(&self, endian: Self::Endian) -> Self::Word { 887 self.sh_offset.get(endian) 888 } 889 890 #[inline] sh_size(&self, endian: Self::Endian) -> Self::Word891 fn sh_size(&self, endian: Self::Endian) -> Self::Word { 892 self.sh_size.get(endian) 893 } 894 895 #[inline] sh_link(&self, endian: Self::Endian) -> u32896 fn sh_link(&self, endian: Self::Endian) -> u32 { 897 self.sh_link.get(endian) 898 } 899 900 #[inline] sh_info(&self, endian: Self::Endian) -> u32901 fn sh_info(&self, endian: Self::Endian) -> u32 { 902 self.sh_info.get(endian) 903 } 904 905 #[inline] sh_addralign(&self, endian: Self::Endian) -> Self::Word906 fn sh_addralign(&self, endian: Self::Endian) -> Self::Word { 907 self.sh_addralign.get(endian) 908 } 909 910 #[inline] sh_entsize(&self, endian: Self::Endian) -> Self::Word911 fn sh_entsize(&self, endian: Self::Endian) -> Self::Word { 912 self.sh_entsize.get(endian) 913 } 914 } 915 916 impl<Endian: endian::Endian> SectionHeader for elf::SectionHeader64<Endian> { 917 type Word = u64; 918 type Endian = Endian; 919 type Elf = elf::FileHeader64<Endian>; 920 921 #[inline] sh_name(&self, endian: Self::Endian) -> u32922 fn sh_name(&self, endian: Self::Endian) -> u32 { 923 self.sh_name.get(endian) 924 } 925 926 #[inline] sh_type(&self, endian: Self::Endian) -> u32927 fn sh_type(&self, endian: Self::Endian) -> u32 { 928 self.sh_type.get(endian) 929 } 930 931 #[inline] sh_flags(&self, endian: Self::Endian) -> Self::Word932 fn sh_flags(&self, endian: Self::Endian) -> Self::Word { 933 self.sh_flags.get(endian) 934 } 935 936 #[inline] sh_addr(&self, endian: Self::Endian) -> Self::Word937 fn sh_addr(&self, endian: Self::Endian) -> Self::Word { 938 self.sh_addr.get(endian) 939 } 940 941 #[inline] sh_offset(&self, endian: Self::Endian) -> Self::Word942 fn sh_offset(&self, endian: Self::Endian) -> Self::Word { 943 self.sh_offset.get(endian) 944 } 945 946 #[inline] sh_size(&self, endian: Self::Endian) -> Self::Word947 fn sh_size(&self, endian: Self::Endian) -> Self::Word { 948 self.sh_size.get(endian) 949 } 950 951 #[inline] sh_link(&self, endian: Self::Endian) -> u32952 fn sh_link(&self, endian: Self::Endian) -> u32 { 953 self.sh_link.get(endian) 954 } 955 956 #[inline] sh_info(&self, endian: Self::Endian) -> u32957 fn sh_info(&self, endian: Self::Endian) -> u32 { 958 self.sh_info.get(endian) 959 } 960 961 #[inline] sh_addralign(&self, endian: Self::Endian) -> Self::Word962 fn sh_addralign(&self, endian: Self::Endian) -> Self::Word { 963 self.sh_addralign.get(endian) 964 } 965 966 #[inline] sh_entsize(&self, endian: Self::Endian) -> Self::Word967 fn sh_entsize(&self, endian: Self::Endian) -> Self::Word { 968 self.sh_entsize.get(endian) 969 } 970 } 971