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