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