1 | use alloc::vec::Vec; |
2 | use core::convert::TryInto; |
3 | use core::fmt::Debug; |
4 | use core::mem; |
5 | |
6 | use crate::elf; |
7 | use crate::endian::{self, Endian, Endianness, U32}; |
8 | use crate::pod::Pod; |
9 | use crate::read::{ |
10 | self, util, Architecture, ByteString, Bytes, Error, Export, FileFlags, Import, Object, |
11 | ObjectKind, ReadError, ReadRef, SectionIndex, StringTable, SymbolIndex, |
12 | }; |
13 | |
14 | use super::{ |
15 | CompressionHeader, Dyn, ElfComdat, ElfComdatIterator, ElfDynamicRelocationIterator, ElfSection, |
16 | ElfSectionIterator, ElfSegment, ElfSegmentIterator, ElfSymbol, ElfSymbolIterator, |
17 | ElfSymbolTable, NoteHeader, ProgramHeader, Rel, Rela, RelocationSections, Relr, SectionHeader, |
18 | SectionTable, Sym, SymbolTable, |
19 | }; |
20 | |
21 | /// A 32-bit ELF object file. |
22 | /// |
23 | /// This is a file that starts with [`elf::FileHeader32`], and corresponds |
24 | /// to [`crate::FileKind::Elf32`]. |
25 | pub type ElfFile32<'data, Endian = Endianness, R = &'data [u8]> = |
26 | ElfFile<'data, elf::FileHeader32<Endian>, R>; |
27 | /// A 64-bit ELF object file. |
28 | /// |
29 | /// This is a file that starts with [`elf::FileHeader64`], and corresponds |
30 | /// to [`crate::FileKind::Elf64`]. |
31 | pub type ElfFile64<'data, Endian = Endianness, R = &'data [u8]> = |
32 | ElfFile<'data, elf::FileHeader64<Endian>, R>; |
33 | |
34 | /// A partially parsed ELF file. |
35 | /// |
36 | /// Most functionality is provided by the [`Object`] trait implementation. |
37 | #[derive (Debug)] |
38 | pub struct ElfFile<'data, Elf, R = &'data [u8]> |
39 | where |
40 | Elf: FileHeader, |
41 | R: ReadRef<'data>, |
42 | { |
43 | pub(super) endian: Elf::Endian, |
44 | pub(super) data: R, |
45 | pub(super) header: &'data Elf, |
46 | pub(super) segments: &'data [Elf::ProgramHeader], |
47 | pub(super) sections: SectionTable<'data, Elf, R>, |
48 | pub(super) relocations: RelocationSections, |
49 | pub(super) symbols: SymbolTable<'data, Elf, R>, |
50 | pub(super) dynamic_symbols: SymbolTable<'data, Elf, R>, |
51 | } |
52 | |
53 | impl<'data, Elf, R> ElfFile<'data, Elf, R> |
54 | where |
55 | Elf: FileHeader, |
56 | R: ReadRef<'data>, |
57 | { |
58 | /// Parse the raw ELF file data. |
59 | pub fn parse(data: R) -> read::Result<Self> { |
60 | let header = Elf::parse(data)?; |
61 | let endian = header.endian()?; |
62 | let segments = header.program_headers(endian, data)?; |
63 | let sections = header.sections(endian, data)?; |
64 | let symbols = sections.symbols(endian, data, elf::SHT_SYMTAB)?; |
65 | // TODO: get dynamic symbols from DT_SYMTAB if there are no sections |
66 | let dynamic_symbols = sections.symbols(endian, data, elf::SHT_DYNSYM)?; |
67 | // The API we provide requires a mapping from section to relocations, so build it now. |
68 | let relocations = sections.relocation_sections(endian, symbols.section())?; |
69 | |
70 | Ok(ElfFile { |
71 | endian, |
72 | data, |
73 | header, |
74 | segments, |
75 | sections, |
76 | relocations, |
77 | symbols, |
78 | dynamic_symbols, |
79 | }) |
80 | } |
81 | |
82 | /// Returns the endianness. |
83 | pub fn endian(&self) -> Elf::Endian { |
84 | self.endian |
85 | } |
86 | |
87 | /// Returns the raw data. |
88 | pub fn data(&self) -> R { |
89 | self.data |
90 | } |
91 | |
92 | /// Returns the raw ELF file header. |
93 | #[deprecated (note = "Use `elf_header` instead" )] |
94 | pub fn raw_header(&self) -> &'data Elf { |
95 | self.header |
96 | } |
97 | |
98 | /// Returns the raw ELF segments. |
99 | #[deprecated (note = "Use `elf_program_headers` instead" )] |
100 | pub fn raw_segments(&self) -> &'data [Elf::ProgramHeader] { |
101 | self.segments |
102 | } |
103 | |
104 | /// Get the raw ELF file header. |
105 | pub fn elf_header(&self) -> &'data Elf { |
106 | self.header |
107 | } |
108 | |
109 | /// Get the raw ELF program headers. |
110 | /// |
111 | /// Returns an empty slice if the file has no program headers. |
112 | pub fn elf_program_headers(&self) -> &'data [Elf::ProgramHeader] { |
113 | self.segments |
114 | } |
115 | |
116 | /// Get the ELF section table. |
117 | /// |
118 | /// Returns an empty section table if the file has no section headers. |
119 | pub fn elf_section_table(&self) -> &SectionTable<'data, Elf, R> { |
120 | &self.sections |
121 | } |
122 | |
123 | /// Get the ELF symbol table. |
124 | /// |
125 | /// Returns an empty symbol table if the file has no symbol table. |
126 | pub fn elf_symbol_table(&self) -> &SymbolTable<'data, Elf, R> { |
127 | &self.symbols |
128 | } |
129 | |
130 | /// Get the ELF dynamic symbol table. |
131 | /// |
132 | /// Returns an empty symbol table if the file has no dynamic symbol table. |
133 | pub fn elf_dynamic_symbol_table(&self) -> &SymbolTable<'data, Elf, R> { |
134 | &self.dynamic_symbols |
135 | } |
136 | |
137 | /// Get a mapping for linked relocation sections. |
138 | pub fn elf_relocation_sections(&self) -> &RelocationSections { |
139 | &self.relocations |
140 | } |
141 | |
142 | fn raw_section_by_name<'file>( |
143 | &'file self, |
144 | section_name: &[u8], |
145 | ) -> Option<ElfSection<'data, 'file, Elf, R>> { |
146 | self.sections |
147 | .section_by_name(self.endian, section_name) |
148 | .map(|(index, section)| ElfSection { |
149 | file: self, |
150 | index, |
151 | section, |
152 | }) |
153 | } |
154 | |
155 | #[cfg (feature = "compression" )] |
156 | fn zdebug_section_by_name<'file>( |
157 | &'file self, |
158 | section_name: &[u8], |
159 | ) -> Option<ElfSection<'data, 'file, Elf, R>> { |
160 | if !section_name.starts_with(b".debug_" ) { |
161 | return None; |
162 | } |
163 | let mut name = Vec::with_capacity(section_name.len() + 1); |
164 | name.extend_from_slice(b".zdebug_" ); |
165 | name.extend_from_slice(§ion_name[7..]); |
166 | self.raw_section_by_name(&name) |
167 | } |
168 | |
169 | #[cfg (not(feature = "compression" ))] |
170 | fn zdebug_section_by_name<'file>( |
171 | &'file self, |
172 | _section_name: &[u8], |
173 | ) -> Option<ElfSection<'data, 'file, Elf, R>> { |
174 | None |
175 | } |
176 | } |
177 | |
178 | impl<'data, Elf, R> read::private::Sealed for ElfFile<'data, Elf, R> |
179 | where |
180 | Elf: FileHeader, |
181 | R: ReadRef<'data>, |
182 | { |
183 | } |
184 | |
185 | impl<'data, Elf, R> Object<'data> for ElfFile<'data, Elf, R> |
186 | where |
187 | Elf: FileHeader, |
188 | R: ReadRef<'data>, |
189 | { |
190 | type Segment<'file> |
191 | = ElfSegment<'data, 'file, Elf, R> |
192 | where |
193 | Self: 'file, |
194 | 'data: 'file; |
195 | type SegmentIterator<'file> |
196 | = ElfSegmentIterator<'data, 'file, Elf, R> |
197 | where |
198 | Self: 'file, |
199 | 'data: 'file; |
200 | type Section<'file> |
201 | = ElfSection<'data, 'file, Elf, R> |
202 | where |
203 | Self: 'file, |
204 | 'data: 'file; |
205 | type SectionIterator<'file> |
206 | = ElfSectionIterator<'data, 'file, Elf, R> |
207 | where |
208 | Self: 'file, |
209 | 'data: 'file; |
210 | type Comdat<'file> |
211 | = ElfComdat<'data, 'file, Elf, R> |
212 | where |
213 | Self: 'file, |
214 | 'data: 'file; |
215 | type ComdatIterator<'file> |
216 | = ElfComdatIterator<'data, 'file, Elf, R> |
217 | where |
218 | Self: 'file, |
219 | 'data: 'file; |
220 | type Symbol<'file> |
221 | = ElfSymbol<'data, 'file, Elf, R> |
222 | where |
223 | Self: 'file, |
224 | 'data: 'file; |
225 | type SymbolIterator<'file> |
226 | = ElfSymbolIterator<'data, 'file, Elf, R> |
227 | where |
228 | Self: 'file, |
229 | 'data: 'file; |
230 | type SymbolTable<'file> |
231 | = ElfSymbolTable<'data, 'file, Elf, R> |
232 | where |
233 | Self: 'file, |
234 | 'data: 'file; |
235 | type DynamicRelocationIterator<'file> |
236 | = ElfDynamicRelocationIterator<'data, 'file, Elf, R> |
237 | where |
238 | Self: 'file, |
239 | 'data: 'file; |
240 | |
241 | fn architecture(&self) -> Architecture { |
242 | match ( |
243 | self.header.e_machine(self.endian), |
244 | self.header.is_class_64(), |
245 | ) { |
246 | (elf::EM_AARCH64, true) => Architecture::Aarch64, |
247 | (elf::EM_AARCH64, false) => Architecture::Aarch64_Ilp32, |
248 | (elf::EM_ARM, _) => Architecture::Arm, |
249 | (elf::EM_AVR, _) => Architecture::Avr, |
250 | (elf::EM_BPF, _) => Architecture::Bpf, |
251 | (elf::EM_CSKY, _) => Architecture::Csky, |
252 | (elf::EM_MCST_ELBRUS, false) => Architecture::E2K32, |
253 | (elf::EM_MCST_ELBRUS, true) => Architecture::E2K64, |
254 | (elf::EM_386, _) => Architecture::I386, |
255 | (elf::EM_X86_64, false) => Architecture::X86_64_X32, |
256 | (elf::EM_X86_64, true) => Architecture::X86_64, |
257 | (elf::EM_HEXAGON, _) => Architecture::Hexagon, |
258 | (elf::EM_LOONGARCH, true) => Architecture::LoongArch64, |
259 | (elf::EM_68K, false) => Architecture::M68k, |
260 | (elf::EM_MIPS, false) => { |
261 | if (self.header.e_flags(self.endian) & elf::EF_MIPS_ABI2) != 0 { |
262 | Architecture::Mips64_N32 |
263 | } else { |
264 | Architecture::Mips |
265 | } |
266 | } |
267 | (elf::EM_MIPS, true) => Architecture::Mips64, |
268 | (elf::EM_MSP430, _) => Architecture::Msp430, |
269 | (elf::EM_PPC, _) => Architecture::PowerPc, |
270 | (elf::EM_PPC64, _) => Architecture::PowerPc64, |
271 | (elf::EM_RISCV, false) => Architecture::Riscv32, |
272 | (elf::EM_RISCV, true) => Architecture::Riscv64, |
273 | // This is either s390 or s390x, depending on the ELF class. |
274 | // We only support the 64-bit variant s390x here. |
275 | (elf::EM_S390, true) => Architecture::S390x, |
276 | (elf::EM_SBF, _) => Architecture::Sbf, |
277 | (elf::EM_SHARC, false) => Architecture::Sharc, |
278 | (elf::EM_SPARC, false) => Architecture::Sparc, |
279 | (elf::EM_SPARC32PLUS, false) => Architecture::Sparc32Plus, |
280 | (elf::EM_SPARCV9, true) => Architecture::Sparc64, |
281 | (elf::EM_XTENSA, false) => Architecture::Xtensa, |
282 | _ => Architecture::Unknown, |
283 | } |
284 | } |
285 | |
286 | #[inline ] |
287 | fn is_little_endian(&self) -> bool { |
288 | self.header.is_little_endian() |
289 | } |
290 | |
291 | #[inline ] |
292 | fn is_64(&self) -> bool { |
293 | self.header.is_class_64() |
294 | } |
295 | |
296 | fn kind(&self) -> ObjectKind { |
297 | match self.header.e_type(self.endian) { |
298 | elf::ET_REL => ObjectKind::Relocatable, |
299 | elf::ET_EXEC => ObjectKind::Executable, |
300 | // TODO: check for `DF_1_PIE`? |
301 | elf::ET_DYN => ObjectKind::Dynamic, |
302 | elf::ET_CORE => ObjectKind::Core, |
303 | _ => ObjectKind::Unknown, |
304 | } |
305 | } |
306 | |
307 | fn segments(&self) -> ElfSegmentIterator<'data, '_, Elf, R> { |
308 | ElfSegmentIterator { |
309 | file: self, |
310 | iter: self.segments.iter(), |
311 | } |
312 | } |
313 | |
314 | fn section_by_name_bytes<'file>( |
315 | &'file self, |
316 | section_name: &[u8], |
317 | ) -> Option<ElfSection<'data, 'file, Elf, R>> { |
318 | self.raw_section_by_name(section_name) |
319 | .or_else(|| self.zdebug_section_by_name(section_name)) |
320 | } |
321 | |
322 | fn section_by_index(&self, index: SectionIndex) -> read::Result<ElfSection<'data, '_, Elf, R>> { |
323 | let section = self.sections.section(index)?; |
324 | Ok(ElfSection { |
325 | file: self, |
326 | index, |
327 | section, |
328 | }) |
329 | } |
330 | |
331 | fn sections(&self) -> ElfSectionIterator<'data, '_, Elf, R> { |
332 | ElfSectionIterator::new(self) |
333 | } |
334 | |
335 | fn comdats(&self) -> ElfComdatIterator<'data, '_, Elf, R> { |
336 | ElfComdatIterator::new(self) |
337 | } |
338 | |
339 | fn symbol_by_index(&self, index: SymbolIndex) -> read::Result<ElfSymbol<'data, '_, Elf, R>> { |
340 | let symbol = self.symbols.symbol(index)?; |
341 | Ok(ElfSymbol { |
342 | endian: self.endian, |
343 | symbols: &self.symbols, |
344 | index, |
345 | symbol, |
346 | }) |
347 | } |
348 | |
349 | fn symbols(&self) -> ElfSymbolIterator<'data, '_, Elf, R> { |
350 | ElfSymbolIterator::new(self.endian, &self.symbols) |
351 | } |
352 | |
353 | fn symbol_table(&self) -> Option<ElfSymbolTable<'data, '_, Elf, R>> { |
354 | if self.symbols.is_empty() { |
355 | return None; |
356 | } |
357 | Some(ElfSymbolTable { |
358 | endian: self.endian, |
359 | symbols: &self.symbols, |
360 | }) |
361 | } |
362 | |
363 | fn dynamic_symbols(&self) -> ElfSymbolIterator<'data, '_, Elf, R> { |
364 | ElfSymbolIterator::new(self.endian, &self.dynamic_symbols) |
365 | } |
366 | |
367 | fn dynamic_symbol_table(&self) -> Option<ElfSymbolTable<'data, '_, Elf, R>> { |
368 | if self.dynamic_symbols.is_empty() { |
369 | return None; |
370 | } |
371 | Some(ElfSymbolTable { |
372 | endian: self.endian, |
373 | symbols: &self.dynamic_symbols, |
374 | }) |
375 | } |
376 | |
377 | fn dynamic_relocations<'file>( |
378 | &'file self, |
379 | ) -> Option<ElfDynamicRelocationIterator<'data, 'file, Elf, R>> { |
380 | Some(ElfDynamicRelocationIterator { |
381 | section_index: SectionIndex(1), |
382 | file: self, |
383 | relocations: None, |
384 | }) |
385 | } |
386 | |
387 | fn imports(&self) -> read::Result<Vec<Import<'data>>> { |
388 | let versions = self.sections.versions(self.endian, self.data)?; |
389 | |
390 | let mut imports = Vec::new(); |
391 | for (index, symbol) in self.dynamic_symbols.enumerate() { |
392 | if symbol.is_undefined(self.endian) { |
393 | let name = symbol.name(self.endian, self.dynamic_symbols.strings())?; |
394 | if !name.is_empty() { |
395 | let library = if let Some(svt) = versions.as_ref() { |
396 | let vi = svt.version_index(self.endian, index); |
397 | svt.version(vi)?.and_then(|v| v.file()) |
398 | } else { |
399 | None |
400 | } |
401 | .unwrap_or(&[]); |
402 | imports.push(Import { |
403 | name: ByteString(name), |
404 | library: ByteString(library), |
405 | }); |
406 | } |
407 | } |
408 | } |
409 | Ok(imports) |
410 | } |
411 | |
412 | fn exports(&self) -> read::Result<Vec<Export<'data>>> { |
413 | let mut exports = Vec::new(); |
414 | for symbol in self.dynamic_symbols.iter() { |
415 | if symbol.is_definition(self.endian) { |
416 | let name = symbol.name(self.endian, self.dynamic_symbols.strings())?; |
417 | let address = symbol.st_value(self.endian).into(); |
418 | exports.push(Export { |
419 | name: ByteString(name), |
420 | address, |
421 | }); |
422 | } |
423 | } |
424 | Ok(exports) |
425 | } |
426 | |
427 | fn has_debug_symbols(&self) -> bool { |
428 | for section in self.sections.iter() { |
429 | if let Ok(name) = self.sections.section_name(self.endian, section) { |
430 | if name == b".debug_info" || name == b".zdebug_info" { |
431 | return true; |
432 | } |
433 | } |
434 | } |
435 | false |
436 | } |
437 | |
438 | fn build_id(&self) -> read::Result<Option<&'data [u8]>> { |
439 | let endian = self.endian; |
440 | // Use section headers if present, otherwise use program headers. |
441 | if !self.sections.is_empty() { |
442 | for section in self.sections.iter() { |
443 | if let Some(mut notes) = section.notes(endian, self.data)? { |
444 | while let Some(note) = notes.next()? { |
445 | if note.name() == elf::ELF_NOTE_GNU |
446 | && note.n_type(endian) == elf::NT_GNU_BUILD_ID |
447 | { |
448 | return Ok(Some(note.desc())); |
449 | } |
450 | } |
451 | } |
452 | } |
453 | } else { |
454 | for segment in self.segments { |
455 | if let Some(mut notes) = segment.notes(endian, self.data)? { |
456 | while let Some(note) = notes.next()? { |
457 | if note.name() == elf::ELF_NOTE_GNU |
458 | && note.n_type(endian) == elf::NT_GNU_BUILD_ID |
459 | { |
460 | return Ok(Some(note.desc())); |
461 | } |
462 | } |
463 | } |
464 | } |
465 | } |
466 | Ok(None) |
467 | } |
468 | |
469 | fn gnu_debuglink(&self) -> read::Result<Option<(&'data [u8], u32)>> { |
470 | let section = match self.raw_section_by_name(b".gnu_debuglink" ) { |
471 | Some(section) => section, |
472 | None => return Ok(None), |
473 | }; |
474 | let data = section |
475 | .section |
476 | .data(self.endian, self.data) |
477 | .read_error("Invalid ELF .gnu_debuglink section offset or size" ) |
478 | .map(Bytes)?; |
479 | let filename = data |
480 | .read_string_at(0) |
481 | .read_error("Missing ELF .gnu_debuglink filename" )?; |
482 | let crc_offset = util::align(filename.len() + 1, 4); |
483 | let crc = data |
484 | .read_at::<U32<_>>(crc_offset) |
485 | .read_error("Missing ELF .gnu_debuglink crc" )? |
486 | .get(self.endian); |
487 | Ok(Some((filename, crc))) |
488 | } |
489 | |
490 | fn gnu_debugaltlink(&self) -> read::Result<Option<(&'data [u8], &'data [u8])>> { |
491 | let section = match self.raw_section_by_name(b".gnu_debugaltlink" ) { |
492 | Some(section) => section, |
493 | None => return Ok(None), |
494 | }; |
495 | let mut data = section |
496 | .section |
497 | .data(self.endian, self.data) |
498 | .read_error("Invalid ELF .gnu_debugaltlink section offset or size" ) |
499 | .map(Bytes)?; |
500 | let filename = data |
501 | .read_string() |
502 | .read_error("Missing ELF .gnu_debugaltlink filename" )?; |
503 | let build_id = data.0; |
504 | Ok(Some((filename, build_id))) |
505 | } |
506 | |
507 | fn relative_address_base(&self) -> u64 { |
508 | 0 |
509 | } |
510 | |
511 | fn entry(&self) -> u64 { |
512 | self.header.e_entry(self.endian).into() |
513 | } |
514 | |
515 | fn flags(&self) -> FileFlags { |
516 | FileFlags::Elf { |
517 | os_abi: self.header.e_ident().os_abi, |
518 | abi_version: self.header.e_ident().abi_version, |
519 | e_flags: self.header.e_flags(self.endian), |
520 | } |
521 | } |
522 | } |
523 | |
524 | /// A trait for generic access to [`elf::FileHeader32`] and [`elf::FileHeader64`]. |
525 | #[allow (missing_docs)] |
526 | pub trait FileHeader: Debug + Pod { |
527 | // Ideally this would be a `u64: From<Word>`, but can't express that. |
528 | type Word: Into<u64> + Default + Copy; |
529 | type Sword: Into<i64>; |
530 | type Endian: endian::Endian; |
531 | type ProgramHeader: ProgramHeader<Elf = Self, Endian = Self::Endian, Word = Self::Word>; |
532 | type SectionHeader: SectionHeader<Elf = Self, Endian = Self::Endian, Word = Self::Word>; |
533 | type CompressionHeader: CompressionHeader<Endian = Self::Endian, Word = Self::Word>; |
534 | type NoteHeader: NoteHeader<Endian = Self::Endian>; |
535 | type Dyn: Dyn<Endian = Self::Endian, Word = Self::Word>; |
536 | type Sym: Sym<Endian = Self::Endian, Word = Self::Word>; |
537 | type Rel: Rel<Endian = Self::Endian, Word = Self::Word>; |
538 | type Rela: Rela<Endian = Self::Endian, Word = Self::Word> + From<Self::Rel>; |
539 | type Relr: Relr<Endian = Self::Endian, Word = Self::Word>; |
540 | |
541 | /// Return true if this type is a 64-bit header. |
542 | /// |
543 | /// This is a property of the type, not a value in the header data. |
544 | fn is_type_64(&self) -> bool; |
545 | |
546 | /// Return true if this type is a 64-bit header. |
547 | /// |
548 | /// This is a property of the type, not a value in the header data. |
549 | /// |
550 | /// This is the same as [`Self::is_type_64`], but is non-dispatchable. |
551 | fn is_type_64_sized() -> bool |
552 | where |
553 | Self: Sized; |
554 | |
555 | fn e_ident(&self) -> &elf::Ident; |
556 | fn e_type(&self, endian: Self::Endian) -> u16; |
557 | fn e_machine(&self, endian: Self::Endian) -> u16; |
558 | fn e_version(&self, endian: Self::Endian) -> u32; |
559 | fn e_entry(&self, endian: Self::Endian) -> Self::Word; |
560 | fn e_phoff(&self, endian: Self::Endian) -> Self::Word; |
561 | fn e_shoff(&self, endian: Self::Endian) -> Self::Word; |
562 | fn e_flags(&self, endian: Self::Endian) -> u32; |
563 | fn e_ehsize(&self, endian: Self::Endian) -> u16; |
564 | fn e_phentsize(&self, endian: Self::Endian) -> u16; |
565 | fn e_phnum(&self, endian: Self::Endian) -> u16; |
566 | fn e_shentsize(&self, endian: Self::Endian) -> u16; |
567 | fn e_shnum(&self, endian: Self::Endian) -> u16; |
568 | fn e_shstrndx(&self, endian: Self::Endian) -> u16; |
569 | |
570 | // Provided methods. |
571 | |
572 | /// Read the file header. |
573 | /// |
574 | /// Also checks that the ident field in the file header is a supported format. |
575 | fn parse<'data, R: ReadRef<'data>>(data: R) -> read::Result<&'data Self> { |
576 | let header = data |
577 | .read_at::<Self>(0) |
578 | .read_error("Invalid ELF header size or alignment" )?; |
579 | if !header.is_supported() { |
580 | return Err(Error("Unsupported ELF header" )); |
581 | } |
582 | // TODO: Check self.e_ehsize? |
583 | Ok(header) |
584 | } |
585 | |
586 | /// Check that the ident field in the file header is a supported format. |
587 | /// |
588 | /// This checks the magic number, version, class, and endianness. |
589 | fn is_supported(&self) -> bool { |
590 | let ident = self.e_ident(); |
591 | // TODO: Check self.e_version too? Requires endian though. |
592 | ident.magic == elf::ELFMAG |
593 | && (self.is_type_64() || self.is_class_32()) |
594 | && (!self.is_type_64() || self.is_class_64()) |
595 | && (self.is_little_endian() || self.is_big_endian()) |
596 | && ident.version == elf::EV_CURRENT |
597 | } |
598 | |
599 | fn is_class_32(&self) -> bool { |
600 | self.e_ident().class == elf::ELFCLASS32 |
601 | } |
602 | |
603 | fn is_class_64(&self) -> bool { |
604 | self.e_ident().class == elf::ELFCLASS64 |
605 | } |
606 | |
607 | fn is_little_endian(&self) -> bool { |
608 | self.e_ident().data == elf::ELFDATA2LSB |
609 | } |
610 | |
611 | fn is_big_endian(&self) -> bool { |
612 | self.e_ident().data == elf::ELFDATA2MSB |
613 | } |
614 | |
615 | fn endian(&self) -> read::Result<Self::Endian> { |
616 | Self::Endian::from_big_endian(self.is_big_endian()).read_error("Unsupported ELF endian" ) |
617 | } |
618 | |
619 | /// Return the first section header, if present. |
620 | /// |
621 | /// Section 0 is a special case because getting the section headers normally |
622 | /// requires `shnum`, but `shnum` may be in the first section header. |
623 | fn section_0<'data, R: ReadRef<'data>>( |
624 | &self, |
625 | endian: Self::Endian, |
626 | data: R, |
627 | ) -> read::Result<Option<&'data Self::SectionHeader>> { |
628 | let shoff: u64 = self.e_shoff(endian).into(); |
629 | if shoff == 0 { |
630 | // No section headers is ok. |
631 | return Ok(None); |
632 | } |
633 | let shentsize = usize::from(self.e_shentsize(endian)); |
634 | if shentsize != mem::size_of::<Self::SectionHeader>() { |
635 | // Section header size must match. |
636 | return Err(Error("Invalid ELF section header entry size" )); |
637 | } |
638 | data.read_at(shoff) |
639 | .map(Some) |
640 | .read_error("Invalid ELF section header offset or size" ) |
641 | } |
642 | |
643 | /// Return the `e_phnum` field of the header. Handles extended values. |
644 | /// |
645 | /// Returns `Err` for invalid values. |
646 | fn phnum<'data, R: ReadRef<'data>>( |
647 | &self, |
648 | endian: Self::Endian, |
649 | data: R, |
650 | ) -> read::Result<usize> { |
651 | let e_phnum = self.e_phnum(endian); |
652 | if e_phnum < elf::PN_XNUM { |
653 | Ok(e_phnum as usize) |
654 | } else if let Some(section_0) = self.section_0(endian, data)? { |
655 | Ok(section_0.sh_info(endian) as usize) |
656 | } else { |
657 | // Section 0 must exist if e_phnum overflows. |
658 | Err(Error("Missing ELF section headers for e_phnum overflow" )) |
659 | } |
660 | } |
661 | |
662 | /// Return the `e_shnum` field of the header. Handles extended values. |
663 | /// |
664 | /// Returns `Err` for invalid values. |
665 | fn shnum<'data, R: ReadRef<'data>>( |
666 | &self, |
667 | endian: Self::Endian, |
668 | data: R, |
669 | ) -> read::Result<usize> { |
670 | let e_shnum = self.e_shnum(endian); |
671 | if e_shnum > 0 { |
672 | Ok(e_shnum as usize) |
673 | } else if let Some(section_0) = self.section_0(endian, data)? { |
674 | section_0 |
675 | .sh_size(endian) |
676 | .into() |
677 | .try_into() |
678 | .ok() |
679 | .read_error("Invalid ELF extended e_shnum" ) |
680 | } else { |
681 | // No section headers is ok. |
682 | Ok(0) |
683 | } |
684 | } |
685 | |
686 | /// Return the `e_shstrndx` field of the header. Handles extended values. |
687 | /// |
688 | /// Returns `Err` for invalid values (including if the index is 0). |
689 | fn shstrndx<'data, R: ReadRef<'data>>( |
690 | &self, |
691 | endian: Self::Endian, |
692 | data: R, |
693 | ) -> read::Result<u32> { |
694 | let e_shstrndx = self.e_shstrndx(endian); |
695 | let index = if e_shstrndx != elf::SHN_XINDEX { |
696 | e_shstrndx.into() |
697 | } else if let Some(section_0) = self.section_0(endian, data)? { |
698 | section_0.sh_link(endian) |
699 | } else { |
700 | // Section 0 must exist if we're trying to read e_shstrndx. |
701 | return Err(Error("Missing ELF section headers for e_shstrndx overflow" )); |
702 | }; |
703 | if index == 0 { |
704 | return Err(Error("Missing ELF e_shstrndx" )); |
705 | } |
706 | Ok(index) |
707 | } |
708 | |
709 | /// Return the slice of program headers. |
710 | /// |
711 | /// Returns `Ok(&[])` if there are no program headers. |
712 | /// Returns `Err` for invalid values. |
713 | fn program_headers<'data, R: ReadRef<'data>>( |
714 | &self, |
715 | endian: Self::Endian, |
716 | data: R, |
717 | ) -> read::Result<&'data [Self::ProgramHeader]> { |
718 | let phoff: u64 = self.e_phoff(endian).into(); |
719 | if phoff == 0 { |
720 | // No program headers is ok. |
721 | return Ok(&[]); |
722 | } |
723 | let phnum = self.phnum(endian, data)?; |
724 | if phnum == 0 { |
725 | // No program headers is ok. |
726 | return Ok(&[]); |
727 | } |
728 | let phentsize = self.e_phentsize(endian) as usize; |
729 | if phentsize != mem::size_of::<Self::ProgramHeader>() { |
730 | // Program header size must match. |
731 | return Err(Error("Invalid ELF program header entry size" )); |
732 | } |
733 | data.read_slice_at(phoff, phnum) |
734 | .read_error("Invalid ELF program header size or alignment" ) |
735 | } |
736 | |
737 | /// Return the slice of section headers. |
738 | /// |
739 | /// Returns `Ok(&[])` if there are no section headers. |
740 | /// Returns `Err` for invalid values. |
741 | fn section_headers<'data, R: ReadRef<'data>>( |
742 | &self, |
743 | endian: Self::Endian, |
744 | data: R, |
745 | ) -> read::Result<&'data [Self::SectionHeader]> { |
746 | let shoff: u64 = self.e_shoff(endian).into(); |
747 | if shoff == 0 { |
748 | // No section headers is ok. |
749 | return Ok(&[]); |
750 | } |
751 | let shnum = self.shnum(endian, data)?; |
752 | if shnum == 0 { |
753 | // No section headers is ok. |
754 | return Ok(&[]); |
755 | } |
756 | let shentsize = usize::from(self.e_shentsize(endian)); |
757 | if shentsize != mem::size_of::<Self::SectionHeader>() { |
758 | // Section header size must match. |
759 | return Err(Error("Invalid ELF section header entry size" )); |
760 | } |
761 | data.read_slice_at(shoff, shnum) |
762 | .read_error("Invalid ELF section header offset/size/alignment" ) |
763 | } |
764 | |
765 | /// Get the section index of the section header string table. |
766 | /// |
767 | /// Returns `Err` for invalid values (including if the index is 0). |
768 | fn section_strings_index<'data, R: ReadRef<'data>>( |
769 | &self, |
770 | endian: Self::Endian, |
771 | data: R, |
772 | ) -> read::Result<SectionIndex> { |
773 | self.shstrndx(endian, data) |
774 | .map(|index| SectionIndex(index as usize)) |
775 | } |
776 | |
777 | /// Return the string table for the section headers. |
778 | fn section_strings<'data, R: ReadRef<'data>>( |
779 | &self, |
780 | endian: Self::Endian, |
781 | data: R, |
782 | sections: &[Self::SectionHeader], |
783 | ) -> read::Result<StringTable<'data, R>> { |
784 | if sections.is_empty() { |
785 | return Ok(StringTable::default()); |
786 | } |
787 | let index = self.section_strings_index(endian, data)?; |
788 | let shstrtab = sections.get(index.0).read_error("Invalid ELF e_shstrndx" )?; |
789 | let strings = if let Some((shstrtab_offset, shstrtab_size)) = shstrtab.file_range(endian) { |
790 | let shstrtab_end = shstrtab_offset |
791 | .checked_add(shstrtab_size) |
792 | .read_error("Invalid ELF shstrtab size" )?; |
793 | StringTable::new(data, shstrtab_offset, shstrtab_end) |
794 | } else { |
795 | StringTable::default() |
796 | }; |
797 | Ok(strings) |
798 | } |
799 | |
800 | /// Return the section table. |
801 | fn sections<'data, R: ReadRef<'data>>( |
802 | &self, |
803 | endian: Self::Endian, |
804 | data: R, |
805 | ) -> read::Result<SectionTable<'data, Self, R>> { |
806 | let sections = self.section_headers(endian, data)?; |
807 | let strings = self.section_strings(endian, data, sections)?; |
808 | Ok(SectionTable::new(sections, strings)) |
809 | } |
810 | |
811 | /// Returns whether this is a mips64el elf file. |
812 | fn is_mips64el(&self, endian: Self::Endian) -> bool { |
813 | self.is_class_64() && self.is_little_endian() && self.e_machine(endian) == elf::EM_MIPS |
814 | } |
815 | } |
816 | |
817 | impl<Endian: endian::Endian> FileHeader for elf::FileHeader32<Endian> { |
818 | type Word = u32; |
819 | type Sword = i32; |
820 | type Endian = Endian; |
821 | type ProgramHeader = elf::ProgramHeader32<Endian>; |
822 | type SectionHeader = elf::SectionHeader32<Endian>; |
823 | type CompressionHeader = elf::CompressionHeader32<Endian>; |
824 | type NoteHeader = elf::NoteHeader32<Endian>; |
825 | type Dyn = elf::Dyn32<Endian>; |
826 | type Sym = elf::Sym32<Endian>; |
827 | type Rel = elf::Rel32<Endian>; |
828 | type Rela = elf::Rela32<Endian>; |
829 | type Relr = elf::Relr32<Endian>; |
830 | |
831 | #[inline ] |
832 | fn is_type_64(&self) -> bool { |
833 | false |
834 | } |
835 | |
836 | #[inline ] |
837 | fn is_type_64_sized() -> bool |
838 | where |
839 | Self: Sized, |
840 | { |
841 | false |
842 | } |
843 | |
844 | #[inline ] |
845 | fn e_ident(&self) -> &elf::Ident { |
846 | &self.e_ident |
847 | } |
848 | |
849 | #[inline ] |
850 | fn e_type(&self, endian: Self::Endian) -> u16 { |
851 | self.e_type.get(endian) |
852 | } |
853 | |
854 | #[inline ] |
855 | fn e_machine(&self, endian: Self::Endian) -> u16 { |
856 | self.e_machine.get(endian) |
857 | } |
858 | |
859 | #[inline ] |
860 | fn e_version(&self, endian: Self::Endian) -> u32 { |
861 | self.e_version.get(endian) |
862 | } |
863 | |
864 | #[inline ] |
865 | fn e_entry(&self, endian: Self::Endian) -> Self::Word { |
866 | self.e_entry.get(endian) |
867 | } |
868 | |
869 | #[inline ] |
870 | fn e_phoff(&self, endian: Self::Endian) -> Self::Word { |
871 | self.e_phoff.get(endian) |
872 | } |
873 | |
874 | #[inline ] |
875 | fn e_shoff(&self, endian: Self::Endian) -> Self::Word { |
876 | self.e_shoff.get(endian) |
877 | } |
878 | |
879 | #[inline ] |
880 | fn e_flags(&self, endian: Self::Endian) -> u32 { |
881 | self.e_flags.get(endian) |
882 | } |
883 | |
884 | #[inline ] |
885 | fn e_ehsize(&self, endian: Self::Endian) -> u16 { |
886 | self.e_ehsize.get(endian) |
887 | } |
888 | |
889 | #[inline ] |
890 | fn e_phentsize(&self, endian: Self::Endian) -> u16 { |
891 | self.e_phentsize.get(endian) |
892 | } |
893 | |
894 | #[inline ] |
895 | fn e_phnum(&self, endian: Self::Endian) -> u16 { |
896 | self.e_phnum.get(endian) |
897 | } |
898 | |
899 | #[inline ] |
900 | fn e_shentsize(&self, endian: Self::Endian) -> u16 { |
901 | self.e_shentsize.get(endian) |
902 | } |
903 | |
904 | #[inline ] |
905 | fn e_shnum(&self, endian: Self::Endian) -> u16 { |
906 | self.e_shnum.get(endian) |
907 | } |
908 | |
909 | #[inline ] |
910 | fn e_shstrndx(&self, endian: Self::Endian) -> u16 { |
911 | self.e_shstrndx.get(endian) |
912 | } |
913 | } |
914 | |
915 | impl<Endian: endian::Endian> FileHeader for elf::FileHeader64<Endian> { |
916 | type Word = u64; |
917 | type Sword = i64; |
918 | type Endian = Endian; |
919 | type ProgramHeader = elf::ProgramHeader64<Endian>; |
920 | type SectionHeader = elf::SectionHeader64<Endian>; |
921 | type CompressionHeader = elf::CompressionHeader64<Endian>; |
922 | type NoteHeader = elf::NoteHeader32<Endian>; |
923 | type Dyn = elf::Dyn64<Endian>; |
924 | type Sym = elf::Sym64<Endian>; |
925 | type Rel = elf::Rel64<Endian>; |
926 | type Rela = elf::Rela64<Endian>; |
927 | type Relr = elf::Relr64<Endian>; |
928 | |
929 | #[inline ] |
930 | fn is_type_64(&self) -> bool { |
931 | true |
932 | } |
933 | |
934 | #[inline ] |
935 | fn is_type_64_sized() -> bool |
936 | where |
937 | Self: Sized, |
938 | { |
939 | true |
940 | } |
941 | |
942 | #[inline ] |
943 | fn e_ident(&self) -> &elf::Ident { |
944 | &self.e_ident |
945 | } |
946 | |
947 | #[inline ] |
948 | fn e_type(&self, endian: Self::Endian) -> u16 { |
949 | self.e_type.get(endian) |
950 | } |
951 | |
952 | #[inline ] |
953 | fn e_machine(&self, endian: Self::Endian) -> u16 { |
954 | self.e_machine.get(endian) |
955 | } |
956 | |
957 | #[inline ] |
958 | fn e_version(&self, endian: Self::Endian) -> u32 { |
959 | self.e_version.get(endian) |
960 | } |
961 | |
962 | #[inline ] |
963 | fn e_entry(&self, endian: Self::Endian) -> Self::Word { |
964 | self.e_entry.get(endian) |
965 | } |
966 | |
967 | #[inline ] |
968 | fn e_phoff(&self, endian: Self::Endian) -> Self::Word { |
969 | self.e_phoff.get(endian) |
970 | } |
971 | |
972 | #[inline ] |
973 | fn e_shoff(&self, endian: Self::Endian) -> Self::Word { |
974 | self.e_shoff.get(endian) |
975 | } |
976 | |
977 | #[inline ] |
978 | fn e_flags(&self, endian: Self::Endian) -> u32 { |
979 | self.e_flags.get(endian) |
980 | } |
981 | |
982 | #[inline ] |
983 | fn e_ehsize(&self, endian: Self::Endian) -> u16 { |
984 | self.e_ehsize.get(endian) |
985 | } |
986 | |
987 | #[inline ] |
988 | fn e_phentsize(&self, endian: Self::Endian) -> u16 { |
989 | self.e_phentsize.get(endian) |
990 | } |
991 | |
992 | #[inline ] |
993 | fn e_phnum(&self, endian: Self::Endian) -> u16 { |
994 | self.e_phnum.get(endian) |
995 | } |
996 | |
997 | #[inline ] |
998 | fn e_shentsize(&self, endian: Self::Endian) -> u16 { |
999 | self.e_shentsize.get(endian) |
1000 | } |
1001 | |
1002 | #[inline ] |
1003 | fn e_shnum(&self, endian: Self::Endian) -> u16 { |
1004 | self.e_shnum.get(endian) |
1005 | } |
1006 | |
1007 | #[inline ] |
1008 | fn e_shstrndx(&self, endian: Self::Endian) -> u16 { |
1009 | self.e_shstrndx.get(endian) |
1010 | } |
1011 | } |
1012 | |