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