1 //! Interface for reading object files.
3 use alloc
::borrow
::Cow
;
5 use core
::{fmt, result}
;
12 #[cfg(feature = "std")]
14 #[cfg(feature = "std")]
15 pub use read_cache
::*;
39 #[cfg(feature = "archive")]
42 #[cfg(feature = "coff")]
45 #[cfg(feature = "elf")]
48 #[cfg(feature = "macho")]
51 #[cfg(feature = "pe")]
54 #[cfg(feature = "wasm")]
57 #[cfg(feature = "xcoff")]
67 /// The error type used within the read module.
68 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
69 pub struct Error(&'
static str);
71 impl fmt
::Display
for Error
{
73 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
78 #[cfg(feature = "std")]
79 impl std
::error
::Error
for Error {}
81 /// The result type used within the read module.
82 pub type Result
<T
> = result
::Result
<T
, Error
>;
85 fn read_error(self, error
: &'
static str) -> Result
<T
>;
88 impl<T
> ReadError
<T
> for result
::Result
<T
, ()> {
89 fn read_error(self, error
: &'
static str) -> Result
<T
> {
90 self.map_err(|()| Error(error
))
94 impl<T
> ReadError
<T
> for result
::Result
<T
, Error
> {
95 fn read_error(self, error
: &'
static str) -> Result
<T
> {
96 self.map_err(|_
| Error(error
))
100 impl<T
> ReadError
<T
> for Option
<T
> {
101 fn read_error(self, error
: &'
static str) -> Result
<T
> {
102 self.ok_or(Error(error
))
106 /// The native executable file for the target platform.
109 not(target_os
= "macos"),
110 target_pointer_width
= "32",
113 pub type NativeFile
<'data
, R
= &'data
[u8]> = elf
::ElfFile32
<'data
, crate::Endianness
, R
>;
115 /// The native executable file for the target platform.
118 not(target_os
= "macos"),
119 target_pointer_width
= "64",
122 pub type NativeFile
<'data
, R
= &'data
[u8]> = elf
::ElfFile64
<'data
, crate::Endianness
, R
>;
124 /// The native executable file for the target platform.
125 #[cfg(all(target_os = "macos", target_pointer_width = "32", feature = "macho"))]
126 pub type NativeFile
<'data
, R
= &'data
[u8]> = macho
::MachOFile32
<'data
, crate::Endianness
, R
>;
128 /// The native executable file for the target platform.
129 #[cfg(all(target_os = "macos", target_pointer_width = "64", feature = "macho"))]
130 pub type NativeFile
<'data
, R
= &'data
[u8]> = macho
::MachOFile64
<'data
, crate::Endianness
, R
>;
132 /// The native executable file for the target platform.
133 #[cfg(all(target_os = "windows", target_pointer_width = "32", feature = "pe"))]
134 pub type NativeFile
<'data
, R
= &'data
[u8]> = pe
::PeFile32
<'data
, R
>;
136 /// The native executable file for the target platform.
137 #[cfg(all(target_os = "windows", target_pointer_width = "64", feature = "pe"))]
138 pub type NativeFile
<'data
, R
= &'data
[u8]> = pe
::PeFile64
<'data
, R
>;
140 /// The native executable file for the target platform.
141 #[cfg(all(feature = "wasm", target_arch = "wasm32", feature = "wasm"))]
142 pub type NativeFile
<'data
, R
= &'data
[u8]> = wasm
::WasmFile
<'data
, R
>;
144 /// A file format kind.
145 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
149 #[cfg(feature = "archive")]
151 /// A COFF object file.
152 #[cfg(feature = "coff")]
154 /// A dyld cache file containing Mach-O images.
155 #[cfg(feature = "macho")]
157 /// A 32-bit ELF file.
158 #[cfg(feature = "elf")]
160 /// A 64-bit ELF file.
161 #[cfg(feature = "elf")]
163 /// A 32-bit Mach-O file.
164 #[cfg(feature = "macho")]
166 /// A 64-bit Mach-O file.
167 #[cfg(feature = "macho")]
169 /// A 32-bit Mach-O fat binary.
170 #[cfg(feature = "macho")]
172 /// A 64-bit Mach-O fat binary.
173 #[cfg(feature = "macho")]
175 /// A 32-bit PE file.
176 #[cfg(feature = "pe")]
178 /// A 64-bit PE file.
179 #[cfg(feature = "pe")]
182 #[cfg(feature = "wasm")]
184 /// A 32-bit XCOFF file.
185 #[cfg(feature = "xcoff")]
187 /// A 64-bit XCOFF file.
188 #[cfg(feature = "xcoff")]
193 /// Determine a file kind by parsing the start of the file.
194 pub fn parse
<'data
, R
: ReadRef
<'data
>>(data
: R
) -> Result
<FileKind
> {
195 Self::parse_at(data
, 0)
198 /// Determine a file kind by parsing at the given offset.
199 pub fn parse_at
<'data
, R
: ReadRef
<'data
>>(data
: R
, offset
: u64) -> Result
<FileKind
> {
201 .read_bytes_at(offset
, 16)
202 .read_error("Could not read file magic")?
;
203 if magic
.len() < 16 {
204 return Err(Error("File too short"));
207 let kind
= match [magic
[0], magic
[1], magic
[2], magic
[3], magic
[4], magic
[5], magic
[6], magic
[7]] {
208 #[cfg(feature = "archive")]
209 [b'
!'
, b'
<'
, b'a'
, b'r'
, b'c'
, b'h'
, b'
>'
, b'
\n'
] => FileKind
::Archive
,
210 #[cfg(feature = "macho")]
211 [b'd'
, b'y'
, b'l'
, b'd'
, b'_'
, b'v'
, b'
1'
, b' '
] => FileKind
::DyldCache
,
212 #[cfg(feature = "elf")]
213 [0x7f, b'E'
, b'L'
, b'F'
, 1, ..] => FileKind
::Elf32
,
214 #[cfg(feature = "elf")]
215 [0x7f, b'E'
, b'L'
, b'F'
, 2, ..] => FileKind
::Elf64
,
216 #[cfg(feature = "macho")]
217 [0xfe, 0xed, 0xfa, 0xce, ..]
218 | [0xce, 0xfa, 0xed, 0xfe, ..] => FileKind
::MachO32
,
219 #[cfg(feature = "macho")]
220 | [0xfe, 0xed, 0xfa, 0xcf, ..]
221 | [0xcf, 0xfa, 0xed, 0xfe, ..] => FileKind
::MachO64
,
222 #[cfg(feature = "macho")]
223 [0xca, 0xfe, 0xba, 0xbe, ..] => FileKind
::MachOFat32
,
224 #[cfg(feature = "macho")]
225 [0xca, 0xfe, 0xba, 0xbf, ..] => FileKind
::MachOFat64
,
226 #[cfg(feature = "wasm")]
227 [0x00, b'a'
, b's'
, b'm'
, ..] => FileKind
::Wasm
,
228 #[cfg(feature = "pe")]
229 [b'M'
, b'Z'
, ..] => {
230 match pe
::optional_header_magic(data
) {
231 Ok(crate::pe
::IMAGE_NT_OPTIONAL_HDR32_MAGIC
) => {
234 Ok(crate::pe
::IMAGE_NT_OPTIONAL_HDR64_MAGIC
) => {
237 _
=> return Err(Error("Unknown MS-DOS file")),
240 // TODO: more COFF machines
241 #[cfg(feature = "coff")]
249 | [0x64, 0x86, ..] => FileKind
::Coff
,
250 #[cfg(feature = "xcoff")]
251 [0x01, 0xDF, ..] => FileKind
::Xcoff32
,
252 #[cfg(feature = "xcoff")]
253 [0x01, 0xF7, ..] => FileKind
::Xcoff64
,
254 _
=> return Err(Error("Unknown file magic")),
261 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
263 pub enum ObjectKind
{
264 /// The object kind is unknown.
266 /// Relocatable object.
270 /// Dynamic shared object.
276 /// The index used to identify a section of a file.
277 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
278 pub struct SectionIndex(pub usize);
280 /// The index used to identify a symbol of a file.
281 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
282 pub struct SymbolIndex(pub usize);
284 /// The section where a symbol is defined.
285 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
287 pub enum SymbolSection
{
288 /// The section is unknown.
290 /// The section is not applicable for this symbol (such as file symbols).
292 /// The symbol is undefined.
294 /// The symbol has an absolute value.
296 /// The symbol is a zero-initialized symbol that will be combined with duplicate definitions.
298 /// The symbol is defined in the given section.
299 Section(SectionIndex
),
303 /// Returns the section index for the section where the symbol is defined.
305 /// May return `None` if the symbol is not defined in a section.
307 pub fn index(self) -> Option
<SectionIndex
> {
308 if let SymbolSection
::Section(index
) = self {
316 /// An entry in a `SymbolMap`.
317 pub trait SymbolMapEntry
{
318 /// The symbol address.
319 fn address(&self) -> u64;
322 /// A map from addresses to symbols.
323 #[derive(Debug, Default, Clone)]
324 pub struct SymbolMap
<T
: SymbolMapEntry
> {
328 impl<T
: SymbolMapEntry
> SymbolMap
<T
> {
329 /// Construct a new symbol map.
331 /// This function will sort the symbols by address.
332 pub fn new(mut symbols
: Vec
<T
>) -> Self {
333 symbols
.sort_unstable_by_key(|s
| s
.address());
334 SymbolMap { symbols }
337 /// Get the symbol before the given address.
338 pub fn get(&self, address
: u64) -> Option
<&T
> {
339 let index
= match self
341 .binary_search_by_key(&address
, |symbol
| symbol
.address())
344 Err(index
) => index
.checked_sub(1)?
,
346 self.symbols
.get(index
)
349 /// Get all symbols in the map.
351 pub fn symbols(&self) -> &[T
] {
356 /// A `SymbolMap` entry for symbol names.
357 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
358 pub struct SymbolMapName
<'data
> {
363 impl<'data
> SymbolMapName
<'data
> {
364 /// Construct a `SymbolMapName`.
365 pub fn new(address
: u64, name
: &'data
str) -> Self {
366 SymbolMapName { address, name }
369 /// The symbol address.
371 pub fn address(&self) -> u64 {
377 pub fn name(&self) -> &'data
str {
382 impl<'data
> SymbolMapEntry
for SymbolMapName
<'data
> {
384 fn address(&self) -> u64 {
389 /// A map from addresses to symbol names and object files.
391 /// This is derived from STAB entries in Mach-O files.
392 #[derive(Debug, Default, Clone)]
393 pub struct ObjectMap
<'data
> {
394 symbols
: SymbolMap
<ObjectMapEntry
<'data
>>,
395 objects
: Vec
<&'data
[u8]>,
398 impl<'data
> ObjectMap
<'data
> {
399 /// Get the entry containing the given address.
400 pub fn get(&self, address
: u64) -> Option
<&ObjectMapEntry
<'data
>> {
403 .filter(|entry
| entry
.size
== 0 || address
.wrapping_sub(entry
.address
) < entry
.size
)
406 /// Get all symbols in the map.
408 pub fn symbols(&self) -> &[ObjectMapEntry
<'data
>] {
409 self.symbols
.symbols()
412 /// Get all objects in the map.
414 pub fn objects(&self) -> &[&'data
[u8]] {
419 /// A `ObjectMap` entry.
420 #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
421 pub struct ObjectMapEntry
<'data
> {
428 impl<'data
> ObjectMapEntry
<'data
> {
429 /// Get the symbol address.
431 pub fn address(&self) -> u64 {
435 /// Get the symbol size.
437 /// This may be 0 if the size is unknown.
439 pub fn size(&self) -> u64 {
443 /// Get the symbol name.
445 pub fn name(&self) -> &'data
[u8] {
449 /// Get the index of the object file name.
451 pub fn object_index(&self) -> usize {
455 /// Get the object file name.
457 pub fn object(&self, map
: &ObjectMap
<'data
>) -> &'data
[u8] {
458 map
.objects
[self.object
]
462 impl<'data
> SymbolMapEntry
for ObjectMapEntry
<'data
> {
464 fn address(&self) -> u64 {
469 /// An imported symbol.
470 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
471 pub struct Import
<'data
> {
472 library
: ByteString
<'data
>,
474 name
: ByteString
<'data
>,
477 impl<'data
> Import
<'data
> {
480 pub fn name(&self) -> &'data
[u8] {
484 /// The name of the library to import the symbol from.
486 pub fn library(&self) -> &'data
[u8] {
491 /// An exported symbol.
492 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
493 pub struct Export
<'data
> {
494 // TODO: and ordinal?
495 name
: ByteString
<'data
>,
499 impl<'data
> Export
<'data
> {
502 pub fn name(&self) -> &'data
[u8] {
506 /// The virtual address of the symbol.
508 pub fn address(&self) -> u64 {
514 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
515 pub struct CodeView
<'data
> {
517 path
: ByteString
<'data
>,
521 impl<'data
> CodeView
<'data
> {
522 /// The path to the PDB as stored in CodeView
524 pub fn path(&self) -> &'data
[u8] {
528 /// The age of the PDB
530 pub fn age(&self) -> u32 {
534 /// The GUID of the PDB.
536 pub fn guid(&self) -> [u8; 16] {
541 /// The target referenced by a relocation.
542 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
544 pub enum RelocationTarget
{
545 /// The target is a symbol.
547 /// The target is a section.
548 Section(SectionIndex
),
549 /// The offset is an absolute address.
553 /// A relocation entry.
555 pub struct Relocation
{
556 kind
: RelocationKind
,
557 encoding
: RelocationEncoding
,
559 target
: RelocationTarget
,
561 implicit_addend
: bool
,
565 /// The operation used to calculate the result of the relocation.
567 pub fn kind(&self) -> RelocationKind
{
571 /// Information about how the result of the relocation operation is encoded in the place.
573 pub fn encoding(&self) -> RelocationEncoding
{
577 /// The size in bits of the place of the relocation.
579 /// If 0, then the size is determined by the relocation kind.
581 pub fn size(&self) -> u8 {
585 /// The target of the relocation.
587 pub fn target(&self) -> RelocationTarget
{
591 /// The addend to use in the relocation calculation.
593 pub fn addend(&self) -> i64 {
597 /// Set the addend to use in the relocation calculation.
599 pub fn set_addend(&mut self, addend
: i64) {
603 /// Returns true if there is an implicit addend stored in the data at the offset
606 pub fn has_implicit_addend(&self) -> bool
{
611 /// A data compression format.
612 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
614 pub enum CompressionFormat
{
615 /// The data is uncompressed.
617 /// The data is compressed, but the compression format is unknown.
621 /// Used for ELF compression and GNU compressed debug information.
625 /// A range in a file that may be compressed.
626 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
627 pub struct CompressedFileRange
{
628 /// The data compression format.
629 pub format
: CompressionFormat
,
630 /// The file offset of the compressed data.
632 /// The compressed data size.
633 pub compressed_size
: u64,
634 /// The uncompressed data size.
635 pub uncompressed_size
: u64,
638 impl CompressedFileRange
{
639 /// Data that is uncompressed.
641 pub fn none(range
: Option
<(u64, u64)>) -> Self {
642 if let Some((offset
, size
)) = range
{
643 CompressedFileRange
{
644 format
: CompressionFormat
::None
,
646 compressed_size
: size
,
647 uncompressed_size
: size
,
650 CompressedFileRange
{
651 format
: CompressionFormat
::None
,
654 uncompressed_size
: 0,
659 /// Convert to `CompressedData` by reading from the file.
660 pub fn data
<'data
, R
: ReadRef
<'data
>>(self, file
: R
) -> Result
<CompressedData
<'data
>> {
662 .read_bytes_at(self.offset
, self.compressed_size
)
663 .read_error("Invalid compressed data size or offset")?
;
667 uncompressed_size
: self.uncompressed_size
,
672 /// Data that may be compressed.
673 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
674 pub struct CompressedData
<'data
> {
675 /// The data compression format.
676 pub format
: CompressionFormat
,
677 /// The compressed data.
678 pub data
: &'data
[u8],
679 /// The uncompressed data size.
680 pub uncompressed_size
: u64,
683 impl<'data
> CompressedData
<'data
> {
684 /// Data that is uncompressed.
686 pub fn none(data
: &'data
[u8]) -> Self {
688 format
: CompressionFormat
::None
,
690 uncompressed_size
: data
.len() as u64,
694 /// Return the uncompressed data.
696 /// Returns an error for invalid data or unsupported compression.
697 /// This includes if the data is compressed but the `compression` feature
698 /// for this crate is disabled.
699 pub fn decompress(self) -> Result
<Cow
<'data
, [u8]>> {
701 CompressionFormat
::None
=> Ok(Cow
::Borrowed(self.data
)),
702 #[cfg(feature = "compression")]
703 CompressionFormat
::Zlib
=> {
704 use core
::convert
::TryInto
;
709 .read_error("Uncompressed data size is too large.")?
;
710 let mut decompressed
= Vec
::with_capacity(size
);
711 let mut decompress
= flate2
::Decompress
::new(true);
716 flate2
::FlushDecompress
::Finish
,
719 .read_error("Invalid zlib compressed data")?
;
720 Ok(Cow
::Owned(decompressed
))
722 _
=> Err(Error("Unsupported compressed data.")),