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