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)]
7pub enum Bitness {
9 Bits32,
11 Bits64,
13}
14
15impl Bitness {
16 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)]
35pub enum MagicNumber {
37 MachO32,
39 MachO64,
41 MachO32Swapped,
43 MachO64Swapped,
45}
46
47impl MagicNumber {
48 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 pub fn endian(self) -> Endian {
63 match self {
64 Self::MachO32 | Self::MachO64 => {
65 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 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)]
94pub enum FatMagic {
96 Fat32,
98 Fat64,
100}
101
102impl FatMagic {
103 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 pub fn is_64bit(self) -> bool {
114 matches!(self, Self::Fat64)
115 }
116}
117
118#[derive(Debug, Clone)]
119pub 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 pub const fn magic(&self) -> FatMagic {
132 self.magic
133 }
134
135 pub const fn architecture_count(&self) -> u32 {
137 self.nfat_arch
138 }
139}
140
141#[derive(Clone, Copy, PartialEq, Eq, Hash)]
142pub struct CpuType(pub i32);
144
145impl CpuType {
146 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 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)]
179pub struct CpuSubtype(pub i32);
181
182impl CpuSubtype {
183 pub fn masked(self) -> i32 {
185 self.0 & CPU_SUBTYPE_MASK
186 }
187
188 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)]
210pub struct ArchSpec {
212 pub cpu_type: CpuType,
214 pub cpu_subtype: CpuSubtype,
216}
217
218impl ArchSpec {
219 pub fn is_x86_64(&self) -> bool {
221 self.cpu_type.0 == CPU_TYPE_X86_64
222 }
223
224 pub fn is_arm64(&self) -> bool {
226 self.cpu_type.0 == CPU_TYPE_ARM64 && self.cpu_subtype.masked() != CPU_SUBTYPE_ARM64E
227 }
228
229 pub fn is_arm64e(&self) -> bool {
231 self.cpu_type.0 == CPU_TYPE_ARM64 && self.cpu_subtype.masked() == CPU_SUBTYPE_ARM64E
232 }
233
234 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)]
257pub enum FileType {
259 Object,
261 Execute,
263 Fvmlib,
265 Core,
267 Preload,
269 Dylib,
271 Dylinker,
273 Bundle,
275 DylibStub,
277 Dsym,
279 KextBundle,
281 Fileset,
283 GpuExecute,
285 GpuDylib,
287 Unknown(u32),
289}
290
291impl FileType {
292 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 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)]
336pub 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 pub const fn magic(&self) -> MagicNumber {
351 self.magic
352 }
353 pub const fn cpu_type(&self) -> CpuType {
355 self.cpu_type
356 }
357 pub const fn cpu_subtype(&self) -> CpuSubtype {
359 self.cpu_subtype
360 }
361 pub const fn file_type(&self) -> FileType {
363 self.file_type
364 }
365 pub const fn load_command_count(&self) -> u32 {
367 self.ncmds
368 }
369 pub const fn load_commands_size(&self) -> u32 {
371 self.sizeofcmds
372 }
373 pub const fn flags(&self) -> MachoHeaderFlags {
375 self.flags
376 }
377 pub const fn reserved(&self) -> u32 {
379 self.reserved
380 }
381}