/rust/registry/src/index.crates.io-1949cf8c6b5b557f/goblin-0.10.7/src/mach/fat.rs
Line | Count | Source |
1 | | //! A Mach-o fat binary is a multi-architecture binary container |
2 | | |
3 | | use core::fmt; |
4 | | |
5 | | if_std! { |
6 | | use std::fs::File; |
7 | | use std::io::{self, Read}; |
8 | | } |
9 | | |
10 | | use crate::error; |
11 | | use crate::mach::constants::cputype::{CPU_ARCH_ABI64, CPU_SUBTYPE_MASK, CpuSubType, CpuType}; |
12 | | use scroll::{Pread, Pwrite, SizeWith}; |
13 | | |
14 | | pub const FAT_MAGIC: u32 = 0xcafe_babe; |
15 | | pub const FAT_CIGAM: u32 = 0xbeba_feca; |
16 | | |
17 | | #[repr(C)] |
18 | | #[derive(Clone, Copy, Default, Pread, Pwrite, SizeWith)] |
19 | | /// The Mach-o `FatHeader` always has its data bigendian |
20 | | pub struct FatHeader { |
21 | | /// The magic number, `cafebabe` |
22 | | pub magic: u32, |
23 | | /// How many fat architecture headers there are |
24 | | pub nfat_arch: u32, |
25 | | } |
26 | | |
27 | | pub const SIZEOF_FAT_HEADER: usize = 8; |
28 | | |
29 | | impl fmt::Debug for FatHeader { |
30 | 0 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
31 | 0 | f.debug_struct("FatHeader") |
32 | 0 | .field("magic", &format_args!("0x{:x}", self.magic)) |
33 | 0 | .field("nfat_arch", &self.nfat_arch) |
34 | 0 | .finish() |
35 | 0 | } |
36 | | } |
37 | | |
38 | | impl FatHeader { |
39 | | /// Reinterpret a `FatHeader` from `bytes` |
40 | 0 | pub fn from_bytes(bytes: [u8; SIZEOF_FAT_HEADER]) -> FatHeader { |
41 | 0 | let mut offset = 0; |
42 | 0 | let magic = bytes.gread_with(&mut offset, scroll::BE).unwrap(); |
43 | 0 | let nfat_arch = bytes.gread_with(&mut offset, scroll::BE).unwrap(); |
44 | 0 | FatHeader { magic, nfat_arch } |
45 | 0 | } |
46 | | |
47 | | /// Reads a `FatHeader` from a `File` on disk |
48 | | #[cfg(feature = "std")] |
49 | 0 | pub fn from_fd(fd: &mut File) -> io::Result<FatHeader> { |
50 | 0 | let mut header = [0; SIZEOF_FAT_HEADER]; |
51 | 0 | fd.read_exact(&mut header)?; |
52 | 0 | Ok(FatHeader::from_bytes(header)) |
53 | 0 | } |
54 | | |
55 | | /// Parse a mach-o fat header from the `bytes` |
56 | 242 | pub fn parse(bytes: &[u8]) -> error::Result<FatHeader> { |
57 | 242 | Ok(bytes.pread_with::<FatHeader>(0, scroll::BE)?) |
58 | 242 | } |
59 | | } |
60 | | |
61 | | #[repr(C)] |
62 | | #[derive(Clone, Copy, Default, Pread, Pwrite, SizeWith)] |
63 | | /// The Mach-o `FatArch` always has its data bigendian |
64 | | pub struct FatArch { |
65 | | /// What kind of CPU this binary is |
66 | | pub cputype: u32, |
67 | | pub cpusubtype: u32, |
68 | | /// Where in the fat binary it starts |
69 | | pub offset: u32, |
70 | | /// How big the binary is |
71 | | pub size: u32, |
72 | | pub align: u32, |
73 | | } |
74 | | |
75 | | pub const SIZEOF_FAT_ARCH: usize = 20; |
76 | | |
77 | | impl fmt::Debug for FatArch { |
78 | 0 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { |
79 | 0 | fmt.debug_struct("FatArch") |
80 | 0 | .field("cputype", &self.cputype()) |
81 | 0 | .field("cmdsize", &self.cpusubtype()) |
82 | 0 | .field("offset", &format_args!("{:#x}", &self.offset)) |
83 | 0 | .field("size", &self.size) |
84 | 0 | .field("align", &self.align) |
85 | 0 | .finish() |
86 | 0 | } |
87 | | } |
88 | | |
89 | | impl FatArch { |
90 | | /// Get the slice of bytes this header describes from `bytes` |
91 | 0 | pub fn slice<'a>(&self, bytes: &'a [u8]) -> &'a [u8] { |
92 | | // FIXME: This function should ideally validate the inputs and return a `Result`. |
93 | | // Best we can do for now without `panic`ing is return an empty slice. |
94 | 0 | let start = self.offset as usize; |
95 | 0 | match start |
96 | 0 | .checked_add(self.size as usize) |
97 | 0 | .and_then(|end| bytes.get(start..end)) |
98 | | { |
99 | 0 | Some(slice) => slice, |
100 | | None => { |
101 | 0 | log::warn!("invalid `FatArch` offset"); |
102 | 0 | &[] |
103 | | } |
104 | | } |
105 | 0 | } |
106 | | |
107 | | /// Returns the cpu type |
108 | 0 | pub fn cputype(&self) -> CpuType { |
109 | 0 | self.cputype |
110 | 0 | } |
111 | | |
112 | | /// Returns the cpu subtype with the capabilities removed |
113 | 0 | pub fn cpusubtype(&self) -> CpuSubType { |
114 | 0 | self.cpusubtype & !CPU_SUBTYPE_MASK |
115 | 0 | } |
116 | | |
117 | | /// Returns the capabilities of the CPU |
118 | 0 | pub fn cpu_caps(&self) -> u32 { |
119 | 0 | (self.cpusubtype & CPU_SUBTYPE_MASK) >> 24 |
120 | 0 | } |
121 | | |
122 | | /// Whether this fat architecture header describes a 64-bit binary |
123 | 0 | pub fn is_64(&self) -> bool { |
124 | 0 | (self.cputype & CPU_ARCH_ABI64) == CPU_ARCH_ABI64 |
125 | 0 | } |
126 | | |
127 | | /// Parse a `FatArch` header from `bytes` at `offset` |
128 | 0 | pub fn parse(bytes: &[u8], offset: usize) -> error::Result<Self> { |
129 | 0 | let arch = bytes.pread_with::<FatArch>(offset, scroll::BE)?; |
130 | 0 | Ok(arch) |
131 | 0 | } |
132 | | } |