1 use crate::alloc::borrow::Cow;
2 use crate::alloc::fmt;
3 use target_lexicon::{Architecture, BinaryFormat};
4 use uuid::Uuid;
5 
6 #[cfg(feature = "wasm")]
7 use crate::read::wasm;
8 use crate::read::{coff, elf, macho, pe};
9 use crate::read::{
10     Object, ObjectSection, ObjectSegment, Relocation, SectionIndex, SectionKind, Symbol,
11     SymbolIndex, SymbolMap,
12 };
13 
14 /// Evaluate an expression on the contents of a file format enum.
15 ///
16 /// This is a hack to avoid virtual calls.
17 macro_rules! with_inner {
18     ($inner:expr, $enum:ident, | $var:ident | $body:expr) => {
19         match $inner {
20             $enum::Coff(ref $var) => $body,
21             $enum::Elf(ref $var) => $body,
22             $enum::MachO(ref $var) => $body,
23             $enum::Pe(ref $var) => $body,
24             #[cfg(feature = "wasm")]
25             $enum::Wasm(ref $var) => $body,
26         }
27     };
28 }
29 
30 macro_rules! with_inner_mut {
31     ($inner:expr, $enum:ident, | $var:ident | $body:expr) => {
32         match $inner {
33             $enum::Coff(ref mut $var) => $body,
34             $enum::Elf(ref mut $var) => $body,
35             $enum::MachO(ref mut $var) => $body,
36             $enum::Pe(ref mut $var) => $body,
37             #[cfg(feature = "wasm")]
38             $enum::Wasm(ref mut $var) => $body,
39         }
40     };
41 }
42 
43 /// Like `with_inner!`, but wraps the result in another enum.
44 macro_rules! map_inner {
45     ($inner:expr, $from:ident, $to:ident, | $var:ident | $body:expr) => {
46         match $inner {
47             $from::Coff(ref $var) => $to::Coff($body),
48             $from::Elf(ref $var) => $to::Elf($body),
49             $from::MachO(ref $var) => $to::MachO($body),
50             $from::Pe(ref $var) => $to::Pe($body),
51             #[cfg(feature = "wasm")]
52             $from::Wasm(ref $var) => $to::Wasm($body),
53         }
54     };
55 }
56 
57 /// Like `map_inner!`, but the result is a Result or Option.
58 macro_rules! map_inner_option {
59     ($inner:expr, $from:ident, $to:ident, | $var:ident | $body:expr) => {
60         match $inner {
61             $from::Coff(ref $var) => $body.map($to::Coff),
62             $from::Elf(ref $var) => $body.map($to::Elf),
63             $from::MachO(ref $var) => $body.map($to::MachO),
64             $from::Pe(ref $var) => $body.map($to::Pe),
65             #[cfg(feature = "wasm")]
66             $from::Wasm(ref $var) => $body.map($to::Wasm),
67         }
68     };
69 }
70 
71 /// Call `next` for a file format iterator.
72 macro_rules! next_inner {
73     ($inner:expr, $from:ident, $to:ident) => {
74         match $inner {
75             $from::Coff(ref mut iter) => iter.next().map($to::Coff),
76             $from::Elf(ref mut iter) => iter.next().map($to::Elf),
77             $from::MachO(ref mut iter) => iter.next().map($to::MachO),
78             $from::Pe(ref mut iter) => iter.next().map($to::Pe),
79             #[cfg(feature = "wasm")]
80             $from::Wasm(ref mut iter) => iter.next().map($to::Wasm),
81         }
82     };
83 }
84 
85 /// An object file.
86 ///
87 /// Most functionality is provided by the `Object` trait implementation.
88 #[derive(Debug)]
89 pub struct File<'data> {
90     inner: FileInternal<'data>,
91 }
92 
93 #[allow(clippy::large_enum_variant)]
94 #[derive(Debug)]
95 enum FileInternal<'data> {
96     Coff(coff::CoffFile<'data>),
97     Elf(elf::ElfFile<'data>),
98     MachO(macho::MachOFile<'data>),
99     Pe(pe::PeFile<'data>),
100     #[cfg(feature = "wasm")]
101     Wasm(wasm::WasmFile),
102 }
103 
104 impl<'data> File<'data> {
105     /// Parse the raw file data.
parse(data: &'data [u8]) -> Result<Self, &'static str>106     pub fn parse(data: &'data [u8]) -> Result<Self, &'static str> {
107         if data.len() < 16 {
108             return Err("File too short");
109         }
110 
111         let inner = match [data[0], data[1], data[2], data[3]] {
112             // ELF
113             [0x7f, b'E', b'L', b'F'] => FileInternal::Elf(elf::ElfFile::parse(data)?),
114             // 32-bit Mach-O
115             [0xfe, 0xed, 0xfa, 0xce]
116             | [0xce, 0xfa, 0xed, 0xfe]
117             // 64-bit Mach-O
118             | [0xfe, 0xed, 0xfa, 0xcf]
119             | [0xcf, 0xfa, 0xed, 0xfe] => FileInternal::MachO(macho::MachOFile::parse(data)?),
120             // WASM
121             #[cfg(feature = "wasm")]
122             [0x00, b'a', b's', b'm'] => FileInternal::Wasm(wasm::WasmFile::parse(data)?),
123             // MS-DOS, assume stub for Windows PE
124             [b'M', b'Z', _, _] => FileInternal::Pe(pe::PeFile::parse(data)?),
125             // TODO: more COFF machines
126             // COFF x86
127             [0x4c, 0x01, _, _]
128             // COFF x86-64
129             | [0x64, 0x86, _, _] => FileInternal::Coff(coff::CoffFile::parse(data)?),
130             _ => return Err("Unknown file magic"),
131         };
132         Ok(File { inner })
133     }
134 
135     /// Return the file format.
format(&self) -> BinaryFormat136     pub fn format(&self) -> BinaryFormat {
137         match self.inner {
138             FileInternal::Elf(_) => BinaryFormat::Elf,
139             FileInternal::MachO(_) => BinaryFormat::Macho,
140             FileInternal::Coff(_) | FileInternal::Pe(_) => BinaryFormat::Coff,
141             #[cfg(feature = "wasm")]
142             FileInternal::Wasm(_) => BinaryFormat::Wasm,
143         }
144     }
145 }
146 
147 impl<'data, 'file> Object<'data, 'file> for File<'data>
148 where
149     'data: 'file,
150 {
151     type Segment = Segment<'data, 'file>;
152     type SegmentIterator = SegmentIterator<'data, 'file>;
153     type Section = Section<'data, 'file>;
154     type SectionIterator = SectionIterator<'data, 'file>;
155     type SymbolIterator = SymbolIterator<'data, 'file>;
156 
architecture(&self) -> Architecture157     fn architecture(&self) -> Architecture {
158         with_inner!(self.inner, FileInternal, |x| x.architecture())
159     }
160 
is_little_endian(&self) -> bool161     fn is_little_endian(&self) -> bool {
162         with_inner!(self.inner, FileInternal, |x| x.is_little_endian())
163     }
164 
is_64(&self) -> bool165     fn is_64(&self) -> bool {
166         with_inner!(self.inner, FileInternal, |x| x.is_64())
167     }
168 
segments(&'file self) -> SegmentIterator<'data, 'file>169     fn segments(&'file self) -> SegmentIterator<'data, 'file> {
170         SegmentIterator {
171             inner: map_inner!(self.inner, FileInternal, SegmentIteratorInternal, |x| x
172                 .segments()),
173         }
174     }
175 
section_by_name(&'file self, section_name: &str) -> Option<Section<'data, 'file>>176     fn section_by_name(&'file self, section_name: &str) -> Option<Section<'data, 'file>> {
177         map_inner_option!(self.inner, FileInternal, SectionInternal, |x| x
178             .section_by_name(section_name))
179         .map(|inner| Section { inner })
180     }
181 
section_by_index(&'file self, index: SectionIndex) -> Option<Section<'data, 'file>>182     fn section_by_index(&'file self, index: SectionIndex) -> Option<Section<'data, 'file>> {
183         map_inner_option!(self.inner, FileInternal, SectionInternal, |x| x
184             .section_by_index(index))
185         .map(|inner| Section { inner })
186     }
187 
section_data_by_name(&self, section_name: &str) -> Option<Cow<'data, [u8]>>188     fn section_data_by_name(&self, section_name: &str) -> Option<Cow<'data, [u8]>> {
189         with_inner!(self.inner, FileInternal, |x| x
190             .section_data_by_name(section_name))
191     }
192 
sections(&'file self) -> SectionIterator<'data, 'file>193     fn sections(&'file self) -> SectionIterator<'data, 'file> {
194         SectionIterator {
195             inner: map_inner!(self.inner, FileInternal, SectionIteratorInternal, |x| x
196                 .sections()),
197         }
198     }
199 
symbol_by_index(&self, index: SymbolIndex) -> Option<Symbol<'data>>200     fn symbol_by_index(&self, index: SymbolIndex) -> Option<Symbol<'data>> {
201         with_inner!(self.inner, FileInternal, |x| x.symbol_by_index(index))
202     }
203 
symbols(&'file self) -> SymbolIterator<'data, 'file>204     fn symbols(&'file self) -> SymbolIterator<'data, 'file> {
205         SymbolIterator {
206             inner: map_inner!(self.inner, FileInternal, SymbolIteratorInternal, |x| x
207                 .symbols()),
208         }
209     }
210 
dynamic_symbols(&'file self) -> SymbolIterator<'data, 'file>211     fn dynamic_symbols(&'file self) -> SymbolIterator<'data, 'file> {
212         SymbolIterator {
213             inner: map_inner!(self.inner, FileInternal, SymbolIteratorInternal, |x| x
214                 .dynamic_symbols()),
215         }
216     }
217 
symbol_map(&self) -> SymbolMap<'data>218     fn symbol_map(&self) -> SymbolMap<'data> {
219         with_inner!(self.inner, FileInternal, |x| x.symbol_map())
220     }
221 
has_debug_symbols(&self) -> bool222     fn has_debug_symbols(&self) -> bool {
223         with_inner!(self.inner, FileInternal, |x| x.has_debug_symbols())
224     }
225 
226     #[inline]
mach_uuid(&self) -> Option<Uuid>227     fn mach_uuid(&self) -> Option<Uuid> {
228         with_inner!(self.inner, FileInternal, |x| x.mach_uuid())
229     }
230 
231     #[inline]
build_id(&self) -> Option<&'data [u8]>232     fn build_id(&self) -> Option<&'data [u8]> {
233         with_inner!(self.inner, FileInternal, |x| x.build_id())
234     }
235 
236     #[inline]
gnu_debuglink(&self) -> Option<(&'data [u8], u32)>237     fn gnu_debuglink(&self) -> Option<(&'data [u8], u32)> {
238         with_inner!(self.inner, FileInternal, |x| x.gnu_debuglink())
239     }
240 
entry(&self) -> u64241     fn entry(&self) -> u64 {
242         with_inner!(self.inner, FileInternal, |x| x.entry())
243     }
244 }
245 
246 /// An iterator over the segments of a `File`.
247 #[derive(Debug)]
248 pub struct SegmentIterator<'data, 'file>
249 where
250     'data: 'file,
251 {
252     inner: SegmentIteratorInternal<'data, 'file>,
253 }
254 
255 #[derive(Debug)]
256 enum SegmentIteratorInternal<'data, 'file>
257 where
258     'data: 'file,
259 {
260     Coff(coff::CoffSegmentIterator<'data, 'file>),
261     Elf(elf::ElfSegmentIterator<'data, 'file>),
262     MachO(macho::MachOSegmentIterator<'data, 'file>),
263     Pe(pe::PeSegmentIterator<'data, 'file>),
264     #[cfg(feature = "wasm")]
265     Wasm(wasm::WasmSegmentIterator<'file>),
266 }
267 
268 impl<'data, 'file> Iterator for SegmentIterator<'data, 'file> {
269     type Item = Segment<'data, 'file>;
270 
next(&mut self) -> Option<Self::Item>271     fn next(&mut self) -> Option<Self::Item> {
272         next_inner!(self.inner, SegmentIteratorInternal, SegmentInternal)
273             .map(|inner| Segment { inner })
274     }
275 }
276 
277 /// A segment of a `File`.
278 pub struct Segment<'data, 'file>
279 where
280     'data: 'file,
281 {
282     inner: SegmentInternal<'data, 'file>,
283 }
284 
285 #[derive(Debug)]
286 enum SegmentInternal<'data, 'file>
287 where
288     'data: 'file,
289 {
290     Coff(coff::CoffSegment<'data, 'file>),
291     Elf(elf::ElfSegment<'data, 'file>),
292     MachO(macho::MachOSegment<'data, 'file>),
293     Pe(pe::PeSegment<'data, 'file>),
294     #[cfg(feature = "wasm")]
295     Wasm(wasm::WasmSegment<'file>),
296 }
297 
298 impl<'data, 'file> fmt::Debug for Segment<'data, 'file> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result299     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
300         // It's painful to do much better than this
301         f.debug_struct("Segment")
302             .field("name", &self.name().unwrap_or("<unnamed>"))
303             .field("address", &self.address())
304             .field("size", &self.data().len())
305             .finish()
306     }
307 }
308 
309 impl<'data, 'file> ObjectSegment<'data> for Segment<'data, 'file> {
address(&self) -> u64310     fn address(&self) -> u64 {
311         with_inner!(self.inner, SegmentInternal, |x| x.address())
312     }
313 
size(&self) -> u64314     fn size(&self) -> u64 {
315         with_inner!(self.inner, SegmentInternal, |x| x.size())
316     }
317 
align(&self) -> u64318     fn align(&self) -> u64 {
319         with_inner!(self.inner, SegmentInternal, |x| x.align())
320     }
321 
file_range(&self) -> (u64, u64)322     fn file_range(&self) -> (u64, u64) {
323         with_inner!(self.inner, SegmentInternal, |x| x.file_range())
324     }
325 
data(&self) -> &'data [u8]326     fn data(&self) -> &'data [u8] {
327         with_inner!(self.inner, SegmentInternal, |x| x.data())
328     }
329 
data_range(&self, address: u64, size: u64) -> Option<&'data [u8]>330     fn data_range(&self, address: u64, size: u64) -> Option<&'data [u8]> {
331         with_inner!(self.inner, SegmentInternal, |x| x.data_range(address, size))
332     }
333 
name(&self) -> Option<&str>334     fn name(&self) -> Option<&str> {
335         with_inner!(self.inner, SegmentInternal, |x| x.name())
336     }
337 }
338 
339 /// An iterator of the sections of a `File`.
340 #[derive(Debug)]
341 pub struct SectionIterator<'data, 'file>
342 where
343     'data: 'file,
344 {
345     inner: SectionIteratorInternal<'data, 'file>,
346 }
347 
348 // we wrap our enums in a struct so that they are kept private.
349 #[derive(Debug)]
350 enum SectionIteratorInternal<'data, 'file>
351 where
352     'data: 'file,
353 {
354     Coff(coff::CoffSectionIterator<'data, 'file>),
355     Elf(elf::ElfSectionIterator<'data, 'file>),
356     MachO(macho::MachOSectionIterator<'data, 'file>),
357     Pe(pe::PeSectionIterator<'data, 'file>),
358     #[cfg(feature = "wasm")]
359     Wasm(wasm::WasmSectionIterator<'file>),
360 }
361 
362 impl<'data, 'file> Iterator for SectionIterator<'data, 'file> {
363     type Item = Section<'data, 'file>;
364 
next(&mut self) -> Option<Self::Item>365     fn next(&mut self) -> Option<Self::Item> {
366         next_inner!(self.inner, SectionIteratorInternal, SectionInternal)
367             .map(|inner| Section { inner })
368     }
369 }
370 
371 /// A Section of a File
372 pub struct Section<'data, 'file>
373 where
374     'data: 'file,
375 {
376     inner: SectionInternal<'data, 'file>,
377 }
378 
379 enum SectionInternal<'data, 'file>
380 where
381     'data: 'file,
382 {
383     Coff(coff::CoffSection<'data, 'file>),
384     Elf(elf::ElfSection<'data, 'file>),
385     MachO(macho::MachOSection<'data, 'file>),
386     Pe(pe::PeSection<'data, 'file>),
387     #[cfg(feature = "wasm")]
388     Wasm(wasm::WasmSection<'file>),
389 }
390 
391 impl<'data, 'file> fmt::Debug for Section<'data, 'file> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result392     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
393         // It's painful to do much better than this
394         let mut s = f.debug_struct("Section");
395         if let Some(segment) = self.segment_name() {
396             s.field("segment", &segment);
397         }
398         s.field("name", &self.name().unwrap_or("<invalid name>"))
399             .field("address", &self.address())
400             .field("size", &self.data().len())
401             .field("kind", &self.kind())
402             .finish()
403     }
404 }
405 
406 impl<'data, 'file> ObjectSection<'data> for Section<'data, 'file> {
407     type RelocationIterator = RelocationIterator<'data, 'file>;
408 
index(&self) -> SectionIndex409     fn index(&self) -> SectionIndex {
410         with_inner!(self.inner, SectionInternal, |x| x.index())
411     }
412 
address(&self) -> u64413     fn address(&self) -> u64 {
414         with_inner!(self.inner, SectionInternal, |x| x.address())
415     }
416 
size(&self) -> u64417     fn size(&self) -> u64 {
418         with_inner!(self.inner, SectionInternal, |x| x.size())
419     }
420 
align(&self) -> u64421     fn align(&self) -> u64 {
422         with_inner!(self.inner, SectionInternal, |x| x.align())
423     }
424 
file_range(&self) -> Option<(u64, u64)>425     fn file_range(&self) -> Option<(u64, u64)> {
426         with_inner!(self.inner, SectionInternal, |x| x.file_range())
427     }
428 
data(&self) -> Cow<'data, [u8]>429     fn data(&self) -> Cow<'data, [u8]> {
430         with_inner!(self.inner, SectionInternal, |x| x.data())
431     }
432 
data_range(&self, address: u64, size: u64) -> Option<&'data [u8]>433     fn data_range(&self, address: u64, size: u64) -> Option<&'data [u8]> {
434         with_inner!(self.inner, SectionInternal, |x| x.data_range(address, size))
435     }
436 
uncompressed_data(&self) -> Cow<'data, [u8]>437     fn uncompressed_data(&self) -> Cow<'data, [u8]> {
438         with_inner!(self.inner, SectionInternal, |x| x.uncompressed_data())
439     }
440 
name(&self) -> Option<&str>441     fn name(&self) -> Option<&str> {
442         with_inner!(self.inner, SectionInternal, |x| x.name())
443     }
444 
segment_name(&self) -> Option<&str>445     fn segment_name(&self) -> Option<&str> {
446         with_inner!(self.inner, SectionInternal, |x| x.segment_name())
447     }
448 
kind(&self) -> SectionKind449     fn kind(&self) -> SectionKind {
450         with_inner!(self.inner, SectionInternal, |x| x.kind())
451     }
452 
relocations(&self) -> RelocationIterator<'data, 'file>453     fn relocations(&self) -> RelocationIterator<'data, 'file> {
454         RelocationIterator {
455             inner: map_inner!(
456                 self.inner,
457                 SectionInternal,
458                 RelocationIteratorInternal,
459                 |x| x.relocations()
460             ),
461         }
462     }
463 }
464 
465 /// An iterator over symbol table entries.
466 #[derive(Debug)]
467 pub struct SymbolIterator<'data, 'file>
468 where
469     'data: 'file,
470 {
471     inner: SymbolIteratorInternal<'data, 'file>,
472 }
473 
474 #[derive(Debug)]
475 enum SymbolIteratorInternal<'data, 'file>
476 where
477     'data: 'file,
478 {
479     Coff(coff::CoffSymbolIterator<'data, 'file>),
480     Elf(elf::ElfSymbolIterator<'data, 'file>),
481     MachO(macho::MachOSymbolIterator<'data, 'file>),
482     Pe(pe::PeSymbolIterator<'data, 'file>),
483     #[cfg(feature = "wasm")]
484     Wasm(wasm::WasmSymbolIterator<'file>),
485 }
486 
487 impl<'data, 'file> Iterator for SymbolIterator<'data, 'file> {
488     type Item = (SymbolIndex, Symbol<'data>);
489 
next(&mut self) -> Option<Self::Item>490     fn next(&mut self) -> Option<Self::Item> {
491         with_inner_mut!(self.inner, SymbolIteratorInternal, |x| x.next())
492     }
493 }
494 
495 /// An iterator over relocation entries
496 #[derive(Debug)]
497 pub struct RelocationIterator<'data, 'file>
498 where
499     'data: 'file,
500 {
501     inner: RelocationIteratorInternal<'data, 'file>,
502 }
503 
504 #[derive(Debug)]
505 enum RelocationIteratorInternal<'data, 'file>
506 where
507     'data: 'file,
508 {
509     Coff(coff::CoffRelocationIterator<'data, 'file>),
510     Elf(elf::ElfRelocationIterator<'data, 'file>),
511     MachO(macho::MachORelocationIterator<'data, 'file>),
512     Pe(pe::PeRelocationIterator),
513     #[cfg(feature = "wasm")]
514     Wasm(wasm::WasmRelocationIterator),
515 }
516 
517 impl<'data, 'file> Iterator for RelocationIterator<'data, 'file> {
518     type Item = (u64, Relocation);
519 
next(&mut self) -> Option<Self::Item>520     fn next(&mut self) -> Option<Self::Item> {
521         with_inner_mut!(self.inner, RelocationIteratorInternal, |x| x.next())
522     }
523 }
524