1 //! Interface for reading object files.
2 
3 use alloc::borrow::Cow;
4 use alloc::vec::Vec;
5 use core::{fmt, result};
6 
7 use crate::common::*;
8 use crate::Bytes;
9 
10 mod util;
11 pub use util::StringTable;
12 
13 mod any;
14 pub use any::*;
15 
16 #[cfg(feature = "archive")]
17 pub mod archive;
18 
19 #[cfg(feature = "coff")]
20 pub mod coff;
21 
22 #[cfg(feature = "elf")]
23 pub mod elf;
24 
25 #[cfg(feature = "macho")]
26 pub mod macho;
27 
28 #[cfg(feature = "pe")]
29 pub mod pe;
30 
31 mod traits;
32 pub use traits::*;
33 
34 #[cfg(feature = "wasm")]
35 pub mod wasm;
36 
37 mod private {
38     pub trait Sealed {}
39 }
40 
41 /// The error type used within the read module.
42 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
43 pub struct Error(&'static str);
44 
45 impl fmt::Display for Error {
46     #[inline]
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result47     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
48         f.write_str(self.0)
49     }
50 }
51 
52 #[cfg(feature = "std")]
53 impl std::error::Error for Error {}
54 
55 /// The result type used within the read module.
56 pub type Result<T> = result::Result<T, Error>;
57 
58 trait ReadError<T> {
read_error(self, error: &'static str) -> Result<T>59     fn read_error(self, error: &'static str) -> Result<T>;
60 }
61 
62 impl<T> ReadError<T> for result::Result<T, ()> {
read_error(self, error: &'static str) -> Result<T>63     fn read_error(self, error: &'static str) -> Result<T> {
64         self.map_err(|()| Error(error))
65     }
66 }
67 
68 impl<T> ReadError<T> for Option<T> {
read_error(self, error: &'static str) -> Result<T>69     fn read_error(self, error: &'static str) -> Result<T> {
70         self.ok_or(Error(error))
71     }
72 }
73 
74 /// The native executable file for the target platform.
75 #[cfg(all(
76     unix,
77     not(target_os = "macos"),
78     target_pointer_width = "32",
79     feature = "elf"
80 ))]
81 pub type NativeFile<'data> = elf::ElfFile32<'data>;
82 
83 /// The native executable file for the target platform.
84 #[cfg(all(
85     unix,
86     not(target_os = "macos"),
87     target_pointer_width = "64",
88     feature = "elf"
89 ))]
90 pub type NativeFile<'data> = elf::ElfFile64<'data>;
91 
92 /// The native executable file for the target platform.
93 #[cfg(all(target_os = "macos", target_pointer_width = "32", feature = "macho"))]
94 pub type NativeFile<'data> = macho::MachOFile32<'data>;
95 
96 /// The native executable file for the target platform.
97 #[cfg(all(target_os = "macos", target_pointer_width = "64", feature = "macho"))]
98 pub type NativeFile<'data> = macho::MachOFile64<'data>;
99 
100 /// The native executable file for the target platform.
101 #[cfg(all(target_os = "windows", target_pointer_width = "32", feature = "pe"))]
102 pub type NativeFile<'data> = pe::PeFile32<'data>;
103 
104 /// The native executable file for the target platform.
105 #[cfg(all(target_os = "windows", target_pointer_width = "64", feature = "pe"))]
106 pub type NativeFile<'data> = pe::PeFile64<'data>;
107 
108 /// The native executable file for the target platform.
109 #[cfg(all(feature = "wasm", target_arch = "wasm32", feature = "wasm"))]
110 pub type NativeFile<'data> = wasm::WasmFile<'data>;
111 
112 /// The index used to identify a section of a file.
113 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
114 pub struct SectionIndex(pub usize);
115 
116 /// The index used to identify a symbol of a file.
117 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
118 pub struct SymbolIndex(pub usize);
119 
120 /// The section where a symbol is defined.
121 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
122 pub enum SymbolSection {
123     /// The section is unknown.
124     Unknown,
125     /// The section is not applicable for this symbol (such as file symbols).
126     None,
127     /// The symbol is undefined.
128     Undefined,
129     /// The symbol has an absolute value.
130     Absolute,
131     /// The symbol is a zero-initialized symbol that will be combined with duplicate definitions.
132     Common,
133     /// The symbol is defined in the given section.
134     Section(SectionIndex),
135 }
136 
137 impl SymbolSection {
138     /// Returns the section index for the section where the symbol is defined.
139     ///
140     /// May return `None` if the symbol is not defined in a section.
141     #[inline]
index(self) -> Option<SectionIndex>142     pub fn index(self) -> Option<SectionIndex> {
143         if let SymbolSection::Section(index) = self {
144             Some(index)
145         } else {
146             None
147         }
148     }
149 }
150 
151 /// An entry in a `SymbolMap`.
152 pub trait SymbolMapEntry {
153     /// The symbol address.
address(&self) -> u64154     fn address(&self) -> u64;
155 }
156 
157 /// A map from addresses to symbols.
158 #[derive(Debug, Default, Clone)]
159 pub struct SymbolMap<T: SymbolMapEntry> {
160     symbols: Vec<T>,
161 }
162 
163 impl<T: SymbolMapEntry> SymbolMap<T> {
164     /// Construct a new symbol map.
165     ///
166     /// This function will sort the symbols by address.
new(mut symbols: Vec<T>) -> Self167     pub fn new(mut symbols: Vec<T>) -> Self {
168         symbols.sort_unstable_by_key(|s| s.address());
169         SymbolMap { symbols }
170     }
171 
172     /// Get the symbol before the given address.
get(&self, address: u64) -> Option<&T>173     pub fn get(&self, address: u64) -> Option<&T> {
174         let index = match self
175             .symbols
176             .binary_search_by_key(&address, |symbol| symbol.address())
177         {
178             Ok(index) => index,
179             Err(index) => index.checked_sub(1)?,
180         };
181         self.symbols.get(index)
182     }
183 
184     /// Get all symbols in the map.
185     #[inline]
symbols(&self) -> &[T]186     pub fn symbols(&self) -> &[T] {
187         &self.symbols
188     }
189 }
190 
191 /// A `SymbolMap` entry for symbol names.
192 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
193 pub struct SymbolMapName<'data> {
194     address: u64,
195     name: &'data str,
196 }
197 
198 impl<'data> SymbolMapName<'data> {
199     /// Construct a `SymbolMapName`.
new(address: u64, name: &'data str) -> Self200     pub fn new(address: u64, name: &'data str) -> Self {
201         SymbolMapName { address, name }
202     }
203 
204     /// The symbol address.
205     #[inline]
address(&self) -> u64206     pub fn address(&self) -> u64 {
207         self.address
208     }
209 
210     /// The symbol name.
211     #[inline]
name(&self) -> &'data str212     pub fn name(&self) -> &'data str {
213         self.name
214     }
215 }
216 
217 impl<'data> SymbolMapEntry for SymbolMapName<'data> {
218     #[inline]
address(&self) -> u64219     fn address(&self) -> u64 {
220         self.address
221     }
222 }
223 
224 /// A map from addresses to symbol names and object files.
225 ///
226 /// This is derived from STAB entries in Mach-O files.
227 #[derive(Debug, Default, Clone)]
228 pub struct ObjectMap<'data> {
229     symbols: SymbolMap<ObjectMapEntry<'data>>,
230     objects: Vec<&'data [u8]>,
231 }
232 
233 impl<'data> ObjectMap<'data> {
234     /// Get the entry containing the given address.
get(&self, address: u64) -> Option<&ObjectMapEntry<'data>>235     pub fn get(&self, address: u64) -> Option<&ObjectMapEntry<'data>> {
236         self.symbols
237             .get(address)
238             .filter(|entry| entry.size == 0 || address.wrapping_sub(entry.address) < entry.size)
239     }
240 
241     /// Get all symbols in the map.
242     #[inline]
symbols(&self) -> &[ObjectMapEntry<'data>]243     pub fn symbols(&self) -> &[ObjectMapEntry<'data>] {
244         self.symbols.symbols()
245     }
246 
247     /// Get all objects in the map.
248     #[inline]
objects(&self) -> &[&'data [u8]]249     pub fn objects(&self) -> &[&'data [u8]] {
250         &self.objects
251     }
252 }
253 
254 /// A `ObjectMap` entry.
255 #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
256 pub struct ObjectMapEntry<'data> {
257     address: u64,
258     size: u64,
259     name: &'data [u8],
260     object: usize,
261 }
262 
263 impl<'data> ObjectMapEntry<'data> {
264     /// Get the symbol address.
265     #[inline]
address(&self) -> u64266     pub fn address(&self) -> u64 {
267         self.address
268     }
269 
270     /// Get the symbol size.
271     ///
272     /// This may be 0 if the size is unknown.
273     #[inline]
size(&self) -> u64274     pub fn size(&self) -> u64 {
275         self.size
276     }
277 
278     /// Get the symbol name.
279     #[inline]
name(&self) -> &'data [u8]280     pub fn name(&self) -> &'data [u8] {
281         self.name
282     }
283 
284     /// Get the index of the object file name.
285     #[inline]
object_index(&self) -> usize286     pub fn object_index(&self) -> usize {
287         self.object
288     }
289 
290     /// Get the object file name.
291     #[inline]
object(&self, map: &ObjectMap<'data>) -> &'data [u8]292     pub fn object(&self, map: &ObjectMap<'data>) -> &'data [u8] {
293         map.objects[self.object]
294     }
295 }
296 
297 impl<'data> SymbolMapEntry for ObjectMapEntry<'data> {
298     #[inline]
address(&self) -> u64299     fn address(&self) -> u64 {
300         self.address
301     }
302 }
303 
304 /// The target referenced by a relocation.
305 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
306 pub enum RelocationTarget {
307     /// The target is a symbol.
308     Symbol(SymbolIndex),
309     /// The target is a section.
310     Section(SectionIndex),
311 }
312 
313 /// A relocation entry.
314 #[derive(Debug)]
315 pub struct Relocation {
316     kind: RelocationKind,
317     encoding: RelocationEncoding,
318     size: u8,
319     target: RelocationTarget,
320     addend: i64,
321     implicit_addend: bool,
322 }
323 
324 impl Relocation {
325     /// The operation used to calculate the result of the relocation.
326     #[inline]
kind(&self) -> RelocationKind327     pub fn kind(&self) -> RelocationKind {
328         self.kind
329     }
330 
331     /// Information about how the result of the relocation operation is encoded in the place.
332     #[inline]
encoding(&self) -> RelocationEncoding333     pub fn encoding(&self) -> RelocationEncoding {
334         self.encoding
335     }
336 
337     /// The size in bits of the place of the relocation.
338     ///
339     /// If 0, then the size is determined by the relocation kind.
340     #[inline]
size(&self) -> u8341     pub fn size(&self) -> u8 {
342         self.size
343     }
344 
345     /// The target of the relocation.
346     #[inline]
target(&self) -> RelocationTarget347     pub fn target(&self) -> RelocationTarget {
348         self.target
349     }
350 
351     /// The addend to use in the relocation calculation.
352     #[inline]
addend(&self) -> i64353     pub fn addend(&self) -> i64 {
354         self.addend
355     }
356 
357     /// Set the addend to use in the relocation calculation.
358     #[inline]
set_addend(&mut self, addend: i64)359     pub fn set_addend(&mut self, addend: i64) {
360         self.addend = addend
361     }
362 
363     /// Returns true if there is an implicit addend stored in the data at the offset
364     /// to be relocated.
365     #[inline]
has_implicit_addend(&self) -> bool366     pub fn has_implicit_addend(&self) -> bool {
367         self.implicit_addend
368     }
369 }
370 
data_range(data: Bytes, data_address: u64, range_address: u64, size: u64) -> Option<&[u8]>371 fn data_range(data: Bytes, data_address: u64, range_address: u64, size: u64) -> Option<&[u8]> {
372     let offset = range_address.checked_sub(data_address)?;
373     let data = data.read_bytes_at(offset as usize, size as usize).ok()?;
374     Some(data.0)
375 }
376 
377 /// Data that may be compressed.
378 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
379 pub struct CompressedData<'data> {
380     /// The data compression format.
381     pub format: CompressionFormat,
382     /// The compressed data.
383     pub data: &'data [u8],
384     /// The uncompressed data size.
385     pub uncompressed_size: usize,
386 }
387 
388 /// A data compression format.
389 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
390 pub enum CompressionFormat {
391     /// The data is uncompressed.
392     None,
393     /// The data is compressed, but the compression format is unknown.
394     Unknown,
395     /// ZLIB/DEFLATE.
396     ///
397     /// Used for ELF compression and GNU compressed debug information.
398     Zlib,
399 }
400 
401 impl<'data> CompressedData<'data> {
402     /// Data that is uncompressed.
403     #[inline]
none(data: &'data [u8]) -> Self404     pub fn none(data: &'data [u8]) -> Self {
405         CompressedData {
406             format: CompressionFormat::None,
407             data,
408             uncompressed_size: data.len(),
409         }
410     }
411 
412     /// Return the uncompressed data.
413     ///
414     /// Returns an error for invalid data or unsupported compression.
415     /// This includes if the data is compressed but the `compression` feature
416     /// for this crate is disabled.
decompress(self) -> Result<Cow<'data, [u8]>>417     pub fn decompress(self) -> Result<Cow<'data, [u8]>> {
418         match self.format {
419             CompressionFormat::None => Ok(Cow::Borrowed(self.data)),
420             #[cfg(feature = "compression")]
421             CompressionFormat::Zlib => {
422                 let mut decompressed = Vec::with_capacity(self.uncompressed_size);
423                 let mut decompress = flate2::Decompress::new(true);
424                 decompress
425                     .decompress_vec(
426                         self.data,
427                         &mut decompressed,
428                         flate2::FlushDecompress::Finish,
429                     )
430                     .ok()
431                     .read_error("Invalid zlib compressed data")?;
432                 Ok(Cow::Owned(decompressed))
433             }
434             _ => Err(Error("Unsupported compressed data.")),
435         }
436     }
437 }
438