]> git.proxmox.com Git - rustc.git/blob - vendor/object-0.26.2/src/read/mod.rs
New upstream version 1.58.1+dfsg1
[rustc.git] / vendor / object-0.26.2 / src / read / mod.rs
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
9 mod read_ref;
10 pub use read_ref::*;
11
12 #[cfg(feature = "std")]
13 mod read_cache;
14 #[cfg(feature = "std")]
15 pub use read_cache::*;
16
17 mod util;
18 pub use util::*;
19
20 #[cfg(any(
21 feature = "coff",
22 feature = "elf",
23 feature = "macho",
24 feature = "pe",
25 feature = "wasm"
26 ))]
27 mod any;
28 #[cfg(any(
29 feature = "coff",
30 feature = "elf",
31 feature = "macho",
32 feature = "pe",
33 feature = "wasm"
34 ))]
35 pub use any::*;
36
37 #[cfg(feature = "archive")]
38 pub mod archive;
39
40 #[cfg(feature = "coff")]
41 pub mod coff;
42
43 #[cfg(feature = "elf")]
44 pub mod elf;
45
46 #[cfg(feature = "macho")]
47 pub mod macho;
48
49 #[cfg(feature = "pe")]
50 pub mod pe;
51
52 mod traits;
53 pub use traits::*;
54
55 #[cfg(feature = "wasm")]
56 pub mod wasm;
57
58 mod private {
59 pub trait Sealed {}
60 }
61
62 /// The error type used within the read module.
63 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
64 pub struct Error(&'static str);
65
66 impl fmt::Display for Error {
67 #[inline]
68 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
69 f.write_str(self.0)
70 }
71 }
72
73 #[cfg(feature = "std")]
74 impl std::error::Error for Error {}
75
76 /// The result type used within the read module.
77 pub type Result<T> = result::Result<T, Error>;
78
79 trait ReadError<T> {
80 fn read_error(self, error: &'static str) -> Result<T>;
81 }
82
83 impl<T> ReadError<T> for result::Result<T, ()> {
84 fn read_error(self, error: &'static str) -> Result<T> {
85 self.map_err(|()| Error(error))
86 }
87 }
88
89 impl<T> ReadError<T> for result::Result<T, Error> {
90 fn read_error(self, error: &'static str) -> Result<T> {
91 self.map_err(|_| Error(error))
92 }
93 }
94
95 impl<T> ReadError<T> for Option<T> {
96 fn read_error(self, error: &'static str) -> Result<T> {
97 self.ok_or(Error(error))
98 }
99 }
100
101 /// The native executable file for the target platform.
102 #[cfg(all(
103 unix,
104 not(target_os = "macos"),
105 target_pointer_width = "32",
106 feature = "elf"
107 ))]
108 pub type NativeFile<'data, R = &'data [u8]> = elf::ElfFile32<'data, crate::Endianness, R>;
109
110 /// The native executable file for the target platform.
111 #[cfg(all(
112 unix,
113 not(target_os = "macos"),
114 target_pointer_width = "64",
115 feature = "elf"
116 ))]
117 pub type NativeFile<'data, R = &'data [u8]> = elf::ElfFile64<'data, crate::Endianness, R>;
118
119 /// The native executable file for the target platform.
120 #[cfg(all(target_os = "macos", target_pointer_width = "32", feature = "macho"))]
121 pub type NativeFile<'data, R = &'data [u8]> = macho::MachOFile32<'data, crate::Endianness, R>;
122
123 /// The native executable file for the target platform.
124 #[cfg(all(target_os = "macos", target_pointer_width = "64", feature = "macho"))]
125 pub type NativeFile<'data, R = &'data [u8]> = macho::MachOFile64<'data, crate::Endianness, R>;
126
127 /// The native executable file for the target platform.
128 #[cfg(all(target_os = "windows", target_pointer_width = "32", feature = "pe"))]
129 pub type NativeFile<'data, R = &'data [u8]> = pe::PeFile32<'data, R>;
130
131 /// The native executable file for the target platform.
132 #[cfg(all(target_os = "windows", target_pointer_width = "64", feature = "pe"))]
133 pub type NativeFile<'data, R = &'data [u8]> = pe::PeFile64<'data, R>;
134
135 /// The native executable file for the target platform.
136 #[cfg(all(feature = "wasm", target_arch = "wasm32", feature = "wasm"))]
137 pub type NativeFile<'data, R = &'data [u8]> = wasm::WasmFile<'data, R>;
138
139 /// An object file kind.
140 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
141 #[non_exhaustive]
142 pub enum FileKind {
143 /// A Unix archive.
144 #[cfg(feature = "archive")]
145 Archive,
146 /// A COFF object file.
147 #[cfg(feature = "coff")]
148 Coff,
149 /// A dyld cache file containing Mach-O images.
150 #[cfg(feature = "macho")]
151 DyldCache,
152 /// A 32-bit ELF file.
153 #[cfg(feature = "elf")]
154 Elf32,
155 /// A 64-bit ELF file.
156 #[cfg(feature = "elf")]
157 Elf64,
158 /// A 32-bit Mach-O file.
159 #[cfg(feature = "macho")]
160 MachO32,
161 /// A 64-bit Mach-O file.
162 #[cfg(feature = "macho")]
163 MachO64,
164 /// A 32-bit Mach-O fat binary.
165 #[cfg(feature = "macho")]
166 MachOFat32,
167 /// A 64-bit Mach-O fat binary.
168 #[cfg(feature = "macho")]
169 MachOFat64,
170 /// A 32-bit PE file.
171 #[cfg(feature = "pe")]
172 Pe32,
173 /// A 64-bit PE file.
174 #[cfg(feature = "pe")]
175 Pe64,
176 /// A Wasm file.
177 #[cfg(feature = "wasm")]
178 Wasm,
179 }
180
181 impl FileKind {
182 /// Determine a file kind by parsing the start of the file.
183 pub fn parse<'data, R: ReadRef<'data>>(data: R) -> Result<FileKind> {
184 Self::parse_at(data, 0)
185 }
186
187 /// Determine a file kind by parsing at the given offset.
188 pub fn parse_at<'data, R: ReadRef<'data>>(data: R, offset: u64) -> Result<FileKind> {
189 let magic = data
190 .read_bytes_at(offset, 16)
191 .read_error("Could not read file magic")?;
192 if magic.len() < 16 {
193 return Err(Error("File too short"));
194 }
195
196 let kind = match [magic[0], magic[1], magic[2], magic[3], magic[4], magic[5], magic[6], magic[7]] {
197 #[cfg(feature = "archive")]
198 [b'!', b'<', b'a', b'r', b'c', b'h', b'>', b'\n'] => FileKind::Archive,
199 #[cfg(feature = "macho")]
200 [b'd', b'y', b'l', b'd', b'_', b'v', b'1', b' '] => FileKind::DyldCache,
201 #[cfg(feature = "elf")]
202 [0x7f, b'E', b'L', b'F', 1, ..] => FileKind::Elf32,
203 #[cfg(feature = "elf")]
204 [0x7f, b'E', b'L', b'F', 2, ..] => FileKind::Elf64,
205 #[cfg(feature = "macho")]
206 [0xfe, 0xed, 0xfa, 0xce, ..]
207 | [0xce, 0xfa, 0xed, 0xfe, ..] => FileKind::MachO32,
208 #[cfg(feature = "macho")]
209 | [0xfe, 0xed, 0xfa, 0xcf, ..]
210 | [0xcf, 0xfa, 0xed, 0xfe, ..] => FileKind::MachO64,
211 #[cfg(feature = "macho")]
212 [0xca, 0xfe, 0xba, 0xbe, ..] => FileKind::MachOFat32,
213 #[cfg(feature = "macho")]
214 [0xca, 0xfe, 0xba, 0xbf, ..] => FileKind::MachOFat64,
215 #[cfg(feature = "wasm")]
216 [0x00, b'a', b's', b'm', ..] => FileKind::Wasm,
217 #[cfg(feature = "pe")]
218 [b'M', b'Z', ..] => {
219 match pe::optional_header_magic(data) {
220 Ok(crate::pe::IMAGE_NT_OPTIONAL_HDR32_MAGIC) => {
221 FileKind::Pe32
222 }
223 Ok(crate::pe::IMAGE_NT_OPTIONAL_HDR64_MAGIC) => {
224 FileKind::Pe64
225 }
226 _ => return Err(Error("Unknown MS-DOS file")),
227 }
228 }
229 // TODO: more COFF machines
230 #[cfg(feature = "coff")]
231 // COFF arm
232 [0xc4, 0x01, ..]
233 // COFF arm64
234 | [0x64, 0xaa, ..]
235 // COFF x86
236 | [0x4c, 0x01, ..]
237 // COFF x86-64
238 | [0x64, 0x86, ..] => FileKind::Coff,
239 _ => return Err(Error("Unknown file magic")),
240 };
241 Ok(kind)
242 }
243 }
244
245 /// The index used to identify a section of a file.
246 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
247 pub struct SectionIndex(pub usize);
248
249 /// The index used to identify a symbol of a file.
250 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
251 pub struct SymbolIndex(pub usize);
252
253 /// The section where a symbol is defined.
254 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
255 #[non_exhaustive]
256 pub enum SymbolSection {
257 /// The section is unknown.
258 Unknown,
259 /// The section is not applicable for this symbol (such as file symbols).
260 None,
261 /// The symbol is undefined.
262 Undefined,
263 /// The symbol has an absolute value.
264 Absolute,
265 /// The symbol is a zero-initialized symbol that will be combined with duplicate definitions.
266 Common,
267 /// The symbol is defined in the given section.
268 Section(SectionIndex),
269 }
270
271 impl SymbolSection {
272 /// Returns the section index for the section where the symbol is defined.
273 ///
274 /// May return `None` if the symbol is not defined in a section.
275 #[inline]
276 pub fn index(self) -> Option<SectionIndex> {
277 if let SymbolSection::Section(index) = self {
278 Some(index)
279 } else {
280 None
281 }
282 }
283 }
284
285 /// An entry in a `SymbolMap`.
286 pub trait SymbolMapEntry {
287 /// The symbol address.
288 fn address(&self) -> u64;
289 }
290
291 /// A map from addresses to symbols.
292 #[derive(Debug, Default, Clone)]
293 pub struct SymbolMap<T: SymbolMapEntry> {
294 symbols: Vec<T>,
295 }
296
297 impl<T: SymbolMapEntry> SymbolMap<T> {
298 /// Construct a new symbol map.
299 ///
300 /// This function will sort the symbols by address.
301 pub fn new(mut symbols: Vec<T>) -> Self {
302 symbols.sort_unstable_by_key(|s| s.address());
303 SymbolMap { symbols }
304 }
305
306 /// Get the symbol before the given address.
307 pub fn get(&self, address: u64) -> Option<&T> {
308 let index = match self
309 .symbols
310 .binary_search_by_key(&address, |symbol| symbol.address())
311 {
312 Ok(index) => index,
313 Err(index) => index.checked_sub(1)?,
314 };
315 self.symbols.get(index)
316 }
317
318 /// Get all symbols in the map.
319 #[inline]
320 pub fn symbols(&self) -> &[T] {
321 &self.symbols
322 }
323 }
324
325 /// A `SymbolMap` entry for symbol names.
326 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
327 pub struct SymbolMapName<'data> {
328 address: u64,
329 name: &'data str,
330 }
331
332 impl<'data> SymbolMapName<'data> {
333 /// Construct a `SymbolMapName`.
334 pub fn new(address: u64, name: &'data str) -> Self {
335 SymbolMapName { address, name }
336 }
337
338 /// The symbol address.
339 #[inline]
340 pub fn address(&self) -> u64 {
341 self.address
342 }
343
344 /// The symbol name.
345 #[inline]
346 pub fn name(&self) -> &'data str {
347 self.name
348 }
349 }
350
351 impl<'data> SymbolMapEntry for SymbolMapName<'data> {
352 #[inline]
353 fn address(&self) -> u64 {
354 self.address
355 }
356 }
357
358 /// A map from addresses to symbol names and object files.
359 ///
360 /// This is derived from STAB entries in Mach-O files.
361 #[derive(Debug, Default, Clone)]
362 pub struct ObjectMap<'data> {
363 symbols: SymbolMap<ObjectMapEntry<'data>>,
364 objects: Vec<&'data [u8]>,
365 }
366
367 impl<'data> ObjectMap<'data> {
368 /// Get the entry containing the given address.
369 pub fn get(&self, address: u64) -> Option<&ObjectMapEntry<'data>> {
370 self.symbols
371 .get(address)
372 .filter(|entry| entry.size == 0 || address.wrapping_sub(entry.address) < entry.size)
373 }
374
375 /// Get all symbols in the map.
376 #[inline]
377 pub fn symbols(&self) -> &[ObjectMapEntry<'data>] {
378 self.symbols.symbols()
379 }
380
381 /// Get all objects in the map.
382 #[inline]
383 pub fn objects(&self) -> &[&'data [u8]] {
384 &self.objects
385 }
386 }
387
388 /// A `ObjectMap` entry.
389 #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
390 pub struct ObjectMapEntry<'data> {
391 address: u64,
392 size: u64,
393 name: &'data [u8],
394 object: usize,
395 }
396
397 impl<'data> ObjectMapEntry<'data> {
398 /// Get the symbol address.
399 #[inline]
400 pub fn address(&self) -> u64 {
401 self.address
402 }
403
404 /// Get the symbol size.
405 ///
406 /// This may be 0 if the size is unknown.
407 #[inline]
408 pub fn size(&self) -> u64 {
409 self.size
410 }
411
412 /// Get the symbol name.
413 #[inline]
414 pub fn name(&self) -> &'data [u8] {
415 self.name
416 }
417
418 /// Get the index of the object file name.
419 #[inline]
420 pub fn object_index(&self) -> usize {
421 self.object
422 }
423
424 /// Get the object file name.
425 #[inline]
426 pub fn object(&self, map: &ObjectMap<'data>) -> &'data [u8] {
427 map.objects[self.object]
428 }
429 }
430
431 impl<'data> SymbolMapEntry for ObjectMapEntry<'data> {
432 #[inline]
433 fn address(&self) -> u64 {
434 self.address
435 }
436 }
437
438 /// An imported symbol.
439 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
440 pub struct Import<'data> {
441 // TODO: or ordinal
442 name: ByteString<'data>,
443 library: ByteString<'data>,
444 }
445
446 impl<'data> Import<'data> {
447 /// The symbol name.
448 #[inline]
449 pub fn name(&self) -> &'data [u8] {
450 self.name.0
451 }
452
453 /// The name of the library to import the symbol from.
454 #[inline]
455 pub fn library(&self) -> &'data [u8] {
456 self.library.0
457 }
458 }
459
460 /// An exported symbol.
461 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
462 pub struct Export<'data> {
463 // TODO: and ordinal?
464 name: ByteString<'data>,
465 address: u64,
466 }
467
468 impl<'data> Export<'data> {
469 /// The symbol name.
470 #[inline]
471 pub fn name(&self) -> &'data [u8] {
472 self.name.0
473 }
474
475 /// The virtual address of the symbol.
476 #[inline]
477 pub fn address(&self) -> u64 {
478 self.address
479 }
480 }
481
482 /// PDB Information
483 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
484 pub struct CodeView<'data> {
485 guid: [u8; 16],
486 path: ByteString<'data>,
487 age: u32,
488 }
489
490 impl<'data> CodeView<'data> {
491 /// The path to the PDB as stored in CodeView
492 #[inline]
493 pub fn path(&self) -> &'data [u8] {
494 self.path.0
495 }
496
497 /// The age of the PDB
498 #[inline]
499 pub fn age(&self) -> u32 {
500 self.age
501 }
502
503 /// The GUID of the PDB.
504 #[inline]
505 pub fn guid(&self) -> [u8; 16] {
506 self.guid
507 }
508 }
509
510 /// The target referenced by a relocation.
511 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
512 #[non_exhaustive]
513 pub enum RelocationTarget {
514 /// The target is a symbol.
515 Symbol(SymbolIndex),
516 /// The target is a section.
517 Section(SectionIndex),
518 /// The offset is an absolute address.
519 Absolute,
520 }
521
522 /// A relocation entry.
523 #[derive(Debug)]
524 pub struct Relocation {
525 kind: RelocationKind,
526 encoding: RelocationEncoding,
527 size: u8,
528 target: RelocationTarget,
529 addend: i64,
530 implicit_addend: bool,
531 }
532
533 impl Relocation {
534 /// The operation used to calculate the result of the relocation.
535 #[inline]
536 pub fn kind(&self) -> RelocationKind {
537 self.kind
538 }
539
540 /// Information about how the result of the relocation operation is encoded in the place.
541 #[inline]
542 pub fn encoding(&self) -> RelocationEncoding {
543 self.encoding
544 }
545
546 /// The size in bits of the place of the relocation.
547 ///
548 /// If 0, then the size is determined by the relocation kind.
549 #[inline]
550 pub fn size(&self) -> u8 {
551 self.size
552 }
553
554 /// The target of the relocation.
555 #[inline]
556 pub fn target(&self) -> RelocationTarget {
557 self.target
558 }
559
560 /// The addend to use in the relocation calculation.
561 #[inline]
562 pub fn addend(&self) -> i64 {
563 self.addend
564 }
565
566 /// Set the addend to use in the relocation calculation.
567 #[inline]
568 pub fn set_addend(&mut self, addend: i64) {
569 self.addend = addend
570 }
571
572 /// Returns true if there is an implicit addend stored in the data at the offset
573 /// to be relocated.
574 #[inline]
575 pub fn has_implicit_addend(&self) -> bool {
576 self.implicit_addend
577 }
578 }
579
580 /// A data compression format.
581 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
582 #[non_exhaustive]
583 pub enum CompressionFormat {
584 /// The data is uncompressed.
585 None,
586 /// The data is compressed, but the compression format is unknown.
587 Unknown,
588 /// ZLIB/DEFLATE.
589 ///
590 /// Used for ELF compression and GNU compressed debug information.
591 Zlib,
592 }
593
594 /// A range in a file that may be compressed.
595 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
596 pub struct CompressedFileRange {
597 /// The data compression format.
598 pub format: CompressionFormat,
599 /// The file offset of the compressed data.
600 pub offset: u64,
601 /// The compressed data size.
602 pub compressed_size: u64,
603 /// The uncompressed data size.
604 pub uncompressed_size: u64,
605 }
606
607 impl CompressedFileRange {
608 /// Data that is uncompressed.
609 #[inline]
610 pub fn none(range: Option<(u64, u64)>) -> Self {
611 if let Some((offset, size)) = range {
612 CompressedFileRange {
613 format: CompressionFormat::None,
614 offset,
615 compressed_size: size,
616 uncompressed_size: size,
617 }
618 } else {
619 CompressedFileRange {
620 format: CompressionFormat::None,
621 offset: 0,
622 compressed_size: 0,
623 uncompressed_size: 0,
624 }
625 }
626 }
627
628 /// Convert to `CompressedData` by reading from the file.
629 pub fn data<'data, R: ReadRef<'data>>(self, file: R) -> Result<CompressedData<'data>> {
630 let data = file
631 .read_bytes_at(self.offset, self.compressed_size)
632 .read_error("Invalid compressed data size or offset")?;
633 Ok(CompressedData {
634 format: self.format,
635 data,
636 uncompressed_size: self.uncompressed_size,
637 })
638 }
639 }
640
641 /// Data that may be compressed.
642 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
643 pub struct CompressedData<'data> {
644 /// The data compression format.
645 pub format: CompressionFormat,
646 /// The compressed data.
647 pub data: &'data [u8],
648 /// The uncompressed data size.
649 pub uncompressed_size: u64,
650 }
651
652 impl<'data> CompressedData<'data> {
653 /// Data that is uncompressed.
654 #[inline]
655 pub fn none(data: &'data [u8]) -> Self {
656 CompressedData {
657 format: CompressionFormat::None,
658 data,
659 uncompressed_size: data.len() as u64,
660 }
661 }
662
663 /// Return the uncompressed data.
664 ///
665 /// Returns an error for invalid data or unsupported compression.
666 /// This includes if the data is compressed but the `compression` feature
667 /// for this crate is disabled.
668 pub fn decompress(self) -> Result<Cow<'data, [u8]>> {
669 match self.format {
670 CompressionFormat::None => Ok(Cow::Borrowed(self.data)),
671 #[cfg(feature = "compression")]
672 CompressionFormat::Zlib => {
673 use core::convert::TryInto;
674 let size = self
675 .uncompressed_size
676 .try_into()
677 .ok()
678 .read_error("Uncompressed data size is too large.")?;
679 let mut decompressed = Vec::with_capacity(size);
680 let mut decompress = flate2::Decompress::new(true);
681 decompress
682 .decompress_vec(
683 self.data,
684 &mut decompressed,
685 flate2::FlushDecompress::Finish,
686 )
687 .ok()
688 .read_error("Invalid zlib compressed data")?;
689 Ok(Cow::Owned(decompressed))
690 }
691 _ => Err(Error("Unsupported compressed data.")),
692 }
693 }
694 }