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 | 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)] |
24 | pub struct SectionTable<'data, Elf: FileHeader, R = &'data [u8]> |
25 | where |
26 | R: ReadRef<'data>, |
27 | { |
28 | sections: &'data [Elf::SectionHeader], |
29 | strings: StringTable<'data, R>, |
30 | } |
31 | |
32 | impl<'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). |
324 | pub 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). |
327 | pub 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)] |
332 | pub struct ElfSectionIterator<'data, 'file, Elf, R = &'data [u8]> |
333 | where |
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 | |
341 | impl<'data, 'file, Elf, R> Iterator for ElfSectionIterator<'data, 'file, Elf, R> |
342 | where |
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). |
358 | pub 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). |
361 | pub 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)] |
368 | pub struct ElfSection<'data, 'file, Elf, R = &'data [u8]> |
369 | where |
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 | |
378 | impl<'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 | |
450 | impl<'data, 'file, Elf, R> read::private::Sealed for ElfSection<'data, 'file, Elf, R> |
451 | where |
452 | Elf: FileHeader, |
453 | R: ReadRef<'data>, |
454 | { |
455 | } |
456 | |
457 | impl<'data, 'file, Elf, R> ObjectSection<'data> for ElfSection<'data, 'file, Elf, R> |
458 | where |
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)] |
601 | pub 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 | |
1040 | impl<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 | |
1096 | impl<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 | |