Skip to main content

macho_core/model/
header.rs

1use crate::error::{Error, Result};
2use crate::format::constants::*;
3use crate::format::io::endian::Endian;
4use std::fmt;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7/// The Bitness type.
8pub enum Bitness {
9    /// The Bits32 variant.
10    Bits32,
11    /// The Bits64 variant.
12    Bits64,
13}
14
15impl Bitness {
16    /// Performs header_size.
17    pub fn header_size(self) -> usize {
18        match self {
19            Bitness::Bits32 => 28,
20            Bitness::Bits64 => 32,
21        }
22    }
23}
24
25impl fmt::Display for Bitness {
26    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
27        match self {
28            Bitness::Bits32 => write!(f, "32-bit"),
29            Bitness::Bits64 => write!(f, "64-bit"),
30        }
31    }
32}
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq)]
35/// The MagicNumber type.
36pub enum MagicNumber {
37    /// The MachO32 variant.
38    MachO32,
39    /// The MachO64 variant.
40    MachO64,
41    /// The MachO32Swapped variant.
42    MachO32Swapped,
43    /// The MachO64Swapped variant.
44    MachO64Swapped,
45}
46
47impl MagicNumber {
48    /// Performs from_u32.
49    pub fn from_u32(v: u32) -> Result<Self> {
50        match v {
51            MH_MAGIC => Ok(Self::MachO32),
52            MH_MAGIC_64 => Ok(Self::MachO64),
53            MH_CIGAM => Ok(Self::MachO32Swapped),
54            MH_CIGAM_64 => Ok(Self::MachO64Swapped),
55            _ => Err(Error::format(format!(
56                "unrecognized Mach-O magic: {v:#010x}"
57            ))),
58        }
59    }
60
61    /// Performs endian.
62    pub fn endian(self) -> Endian {
63        match self {
64            Self::MachO32 | Self::MachO64 => {
65                // Native byte order magic means the file matches the host.
66                // On LE hosts (all modern Apple), non-swapped = Little.
67                // On BE hosts, non-swapped = Big.
68                if cfg!(target_endian = "little") {
69                    Endian::Little
70                } else {
71                    Endian::Big
72                }
73            }
74            Self::MachO32Swapped | Self::MachO64Swapped => {
75                if cfg!(target_endian = "little") {
76                    Endian::Big
77                } else {
78                    Endian::Little
79                }
80            }
81        }
82    }
83
84    /// Performs bitness.
85    pub fn bitness(self) -> Bitness {
86        match self {
87            Self::MachO32 | Self::MachO32Swapped => Bitness::Bits32,
88            Self::MachO64 | Self::MachO64Swapped => Bitness::Bits64,
89        }
90    }
91}
92
93#[derive(Debug, Clone, Copy, PartialEq, Eq)]
94/// The FatMagic type.
95pub enum FatMagic {
96    /// The Fat32 variant.
97    Fat32,
98    /// The Fat64 variant.
99    Fat64,
100}
101
102impl FatMagic {
103    /// Performs from_u32.
104    pub fn from_u32(v: u32) -> Result<Self> {
105        match v {
106            FAT_MAGIC => Ok(Self::Fat32),
107            FAT_MAGIC_64 => Ok(Self::Fat64),
108            _ => Err(Error::format(format!("unrecognized fat magic: {v:#010x}"))),
109        }
110    }
111
112    /// Performs is_64bit.
113    pub fn is_64bit(self) -> bool {
114        matches!(self, Self::Fat64)
115    }
116}
117
118#[derive(Debug, Clone)]
119/// The FatHeader type.
120pub struct FatHeader {
121    magic: FatMagic,
122    nfat_arch: u32,
123}
124
125impl FatHeader {
126    pub(crate) const fn new(magic: FatMagic, nfat_arch: u32) -> Self {
127        Self { magic, nfat_arch }
128    }
129
130    /// Fat container encoding width.
131    pub const fn magic(&self) -> FatMagic {
132        self.magic
133    }
134
135    /// Number of architecture entries declared by the validated table.
136    pub const fn architecture_count(&self) -> u32 {
137        self.nfat_arch
138    }
139}
140
141#[derive(Clone, Copy, PartialEq, Eq, Hash)]
142/// The CpuType type.
143pub struct CpuType(pub i32);
144
145impl CpuType {
146    /// Performs name.
147    pub fn name(self) -> &'static str {
148        match self.0 {
149            CPU_TYPE_X86 => "x86",
150            CPU_TYPE_X86_64 => "x86_64",
151            CPU_TYPE_ARM => "arm",
152            CPU_TYPE_ARM64 => "arm64",
153            CPU_TYPE_ARM64_32 => "arm64_32",
154            CPU_TYPE_POWERPC => "ppc",
155            CPU_TYPE_POWERPC64 => "ppc64",
156            _ => "unknown",
157        }
158    }
159
160    /// Performs is_64bit.
161    pub fn is_64bit(self) -> bool {
162        (self.0 & CPU_ARCH_ABI64) != 0
163    }
164}
165
166impl fmt::Debug for CpuType {
167    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
168        write!(f, "CpuType({}, {})", self.name(), self.0)
169    }
170}
171
172impl fmt::Display for CpuType {
173    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
174        write!(f, "{}", self.name())
175    }
176}
177
178#[derive(Clone, Copy, PartialEq, Eq, Hash)]
179/// The CpuSubtype type.
180pub struct CpuSubtype(pub i32);
181
182impl CpuSubtype {
183    /// Returns the subtype with capability bits stripped (high byte masked off).
184    pub fn masked(self) -> i32 {
185        self.0 & CPU_SUBTYPE_MASK
186    }
187
188    /// Performs name.
189    pub fn name(self, cpu_type: CpuType) -> &'static str {
190        let masked = self.masked();
191        match (cpu_type.0, masked) {
192            (CPU_TYPE_ARM64, CPU_SUBTYPE_ARM64_ALL) => "all",
193            (CPU_TYPE_ARM64, CPU_SUBTYPE_ARM64_V8) => "v8",
194            (CPU_TYPE_ARM64, CPU_SUBTYPE_ARM64E) => "arm64e",
195            (CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL) => "all",
196            (CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_H) => "haswell",
197            (_, CPU_SUBTYPE_ALL) => "all",
198            _ => "unknown",
199        }
200    }
201}
202
203impl fmt::Debug for CpuSubtype {
204    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
205        write!(f, "CpuSubtype({:#x})", self.0)
206    }
207}
208
209#[derive(Clone, Copy, PartialEq, Eq, Hash)]
210/// The ArchSpec type.
211pub struct ArchSpec {
212    /// The cpu_type field.
213    pub cpu_type: CpuType,
214    /// The cpu_subtype field.
215    pub cpu_subtype: CpuSubtype,
216}
217
218impl ArchSpec {
219    /// Performs is_x86_64.
220    pub fn is_x86_64(&self) -> bool {
221        self.cpu_type.0 == CPU_TYPE_X86_64
222    }
223
224    /// Performs is_arm64.
225    pub fn is_arm64(&self) -> bool {
226        self.cpu_type.0 == CPU_TYPE_ARM64 && self.cpu_subtype.masked() != CPU_SUBTYPE_ARM64E
227    }
228
229    /// Performs is_arm64e.
230    pub fn is_arm64e(&self) -> bool {
231        self.cpu_type.0 == CPU_TYPE_ARM64 && self.cpu_subtype.masked() == CPU_SUBTYPE_ARM64E
232    }
233
234    /// Performs name.
235    pub fn name(&self) -> String {
236        if self.is_arm64e() {
237            "arm64e".to_string()
238        } else {
239            self.cpu_type.name().to_string()
240        }
241    }
242}
243
244impl fmt::Debug for ArchSpec {
245    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
246        write!(f, "ArchSpec({})", self.name())
247    }
248}
249
250impl fmt::Display for ArchSpec {
251    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
252        write!(f, "{}", self.name())
253    }
254}
255
256#[derive(Debug, Clone, Copy, PartialEq, Eq)]
257/// The FileType type.
258pub enum FileType {
259    /// The Object variant.
260    Object,
261    /// The Execute variant.
262    Execute,
263    /// The Fvmlib variant.
264    Fvmlib,
265    /// The Core variant.
266    Core,
267    /// The Preload variant.
268    Preload,
269    /// The Dylib variant.
270    Dylib,
271    /// The Dylinker variant.
272    Dylinker,
273    /// The Bundle variant.
274    Bundle,
275    /// The DylibStub variant.
276    DylibStub,
277    /// The Dsym variant.
278    Dsym,
279    /// The KextBundle variant.
280    KextBundle,
281    /// The Fileset variant.
282    Fileset,
283    /// The GpuExecute variant.
284    GpuExecute,
285    /// The GpuDylib variant.
286    GpuDylib,
287    /// The Unknown variant.
288    Unknown(u32),
289}
290
291impl FileType {
292    /// Performs from_u32.
293    pub fn from_u32(v: u32) -> Self {
294        match v {
295            MH_OBJECT => Self::Object,
296            MH_EXECUTE => Self::Execute,
297            MH_FVMLIB => Self::Fvmlib,
298            MH_CORE => Self::Core,
299            MH_PRELOAD => Self::Preload,
300            MH_DYLIB => Self::Dylib,
301            MH_DYLINKER => Self::Dylinker,
302            MH_BUNDLE => Self::Bundle,
303            MH_DYLIB_STUB => Self::DylibStub,
304            MH_DSYM => Self::Dsym,
305            MH_KEXT_BUNDLE => Self::KextBundle,
306            MH_FILESET => Self::Fileset,
307            MH_GPU_EXECUTE => Self::GpuExecute,
308            MH_GPU_DYLIB => Self::GpuDylib,
309            _ => Self::Unknown(v),
310        }
311    }
312
313    /// Performs name.
314    pub fn name(&self) -> &'static str {
315        match self {
316            Self::Object => "MH_OBJECT",
317            Self::Execute => "MH_EXECUTE",
318            Self::Fvmlib => "MH_FVMLIB",
319            Self::Core => "MH_CORE",
320            Self::Preload => "MH_PRELOAD",
321            Self::Dylib => "MH_DYLIB",
322            Self::Dylinker => "MH_DYLINKER",
323            Self::Bundle => "MH_BUNDLE",
324            Self::DylibStub => "MH_DYLIB_STUB",
325            Self::Dsym => "MH_DSYM",
326            Self::KextBundle => "MH_KEXT_BUNDLE",
327            Self::Fileset => "MH_FILESET",
328            Self::GpuExecute => "MH_GPU_EXECUTE",
329            Self::GpuDylib => "MH_GPU_DYLIB",
330            Self::Unknown(_) => "MH_UNKNOWN",
331        }
332    }
333}
334
335#[derive(Debug, Clone)]
336/// The MachoHeader type.
337pub struct MachoHeader {
338    pub(crate) magic: MagicNumber,
339    pub(crate) cpu_type: CpuType,
340    pub(crate) cpu_subtype: CpuSubtype,
341    pub(crate) file_type: FileType,
342    pub(crate) ncmds: u32,
343    pub(crate) sizeofcmds: u32,
344    pub(crate) flags: MachoHeaderFlags,
345    pub(crate) reserved: u32,
346}
347
348impl MachoHeader {
349    /// Parsed Mach-O magic and byte-order encoding.
350    pub const fn magic(&self) -> MagicNumber {
351        self.magic
352    }
353    /// Declared CPU family.
354    pub const fn cpu_type(&self) -> CpuType {
355        self.cpu_type
356    }
357    /// Declared CPU subtype.
358    pub const fn cpu_subtype(&self) -> CpuSubtype {
359        self.cpu_subtype
360    }
361    /// Declared Mach-O file type.
362    pub const fn file_type(&self) -> FileType {
363        self.file_type
364    }
365    /// Number of validated load commands.
366    pub const fn load_command_count(&self) -> u32 {
367        self.ncmds
368    }
369    /// Declared load-command byte size.
370    pub const fn load_commands_size(&self) -> u32 {
371        self.sizeofcmds
372    }
373    /// Validated header flags.
374    pub const fn flags(&self) -> MachoHeaderFlags {
375        self.flags
376    }
377    /// Reserved 64-bit header word.
378    pub const fn reserved(&self) -> u32 {
379        self.reserved
380    }
381}