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 matches_selector(&self, selector: &str) -> bool {
228 self.cpu_type.name().eq_ignore_ascii_case(selector)
229 || self.name().eq_ignore_ascii_case(selector)
230 }
231
232 pub fn is_x86_64(&self) -> bool {
234 self.cpu_type.0 == CPU_TYPE_X86_64
235 }
236
237 pub fn is_x86_64h(&self) -> bool {
239 self.cpu_type.0 == CPU_TYPE_X86_64 && self.cpu_subtype.masked() == CPU_SUBTYPE_X86_64_H
240 }
241
242 pub fn is_arm64(&self) -> bool {
244 self.cpu_type.0 == CPU_TYPE_ARM64 && self.cpu_subtype.masked() != CPU_SUBTYPE_ARM64E
245 }
246
247 pub fn is_arm64e(&self) -> bool {
249 self.cpu_type.0 == CPU_TYPE_ARM64 && self.cpu_subtype.masked() == CPU_SUBTYPE_ARM64E
250 }
251
252 pub fn name(&self) -> String {
254 if self.is_arm64e() {
255 "arm64e".to_string()
256 } else if self.is_x86_64h() {
257 "x86_64h".to_string()
258 } else {
259 self.cpu_type.name().to_string()
260 }
261 }
262}
263
264impl fmt::Debug for ArchSpec {
265 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
266 write!(f, "ArchSpec({})", self.name())
267 }
268}
269
270impl fmt::Display for ArchSpec {
271 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
272 write!(f, "{}", self.name())
273 }
274}
275
276#[derive(Debug, Clone, Copy, PartialEq, Eq)]
277pub enum FileType {
279 Object,
281 Execute,
283 Fvmlib,
285 Core,
287 Preload,
289 Dylib,
291 Dylinker,
293 Bundle,
295 DylibStub,
297 Dsym,
299 KextBundle,
301 Fileset,
303 GpuExecute,
305 GpuDylib,
307 Unknown(u32),
309}
310
311impl FileType {
312 pub fn from_u32(v: u32) -> Self {
314 match v {
315 MH_OBJECT => Self::Object,
316 MH_EXECUTE => Self::Execute,
317 MH_FVMLIB => Self::Fvmlib,
318 MH_CORE => Self::Core,
319 MH_PRELOAD => Self::Preload,
320 MH_DYLIB => Self::Dylib,
321 MH_DYLINKER => Self::Dylinker,
322 MH_BUNDLE => Self::Bundle,
323 MH_DYLIB_STUB => Self::DylibStub,
324 MH_DSYM => Self::Dsym,
325 MH_KEXT_BUNDLE => Self::KextBundle,
326 MH_FILESET => Self::Fileset,
327 MH_GPU_EXECUTE => Self::GpuExecute,
328 MH_GPU_DYLIB => Self::GpuDylib,
329 _ => Self::Unknown(v),
330 }
331 }
332
333 pub fn name(&self) -> &'static str {
335 match self {
336 Self::Object => "MH_OBJECT",
337 Self::Execute => "MH_EXECUTE",
338 Self::Fvmlib => "MH_FVMLIB",
339 Self::Core => "MH_CORE",
340 Self::Preload => "MH_PRELOAD",
341 Self::Dylib => "MH_DYLIB",
342 Self::Dylinker => "MH_DYLINKER",
343 Self::Bundle => "MH_BUNDLE",
344 Self::DylibStub => "MH_DYLIB_STUB",
345 Self::Dsym => "MH_DSYM",
346 Self::KextBundle => "MH_KEXT_BUNDLE",
347 Self::Fileset => "MH_FILESET",
348 Self::GpuExecute => "MH_GPU_EXECUTE",
349 Self::GpuDylib => "MH_GPU_DYLIB",
350 Self::Unknown(_) => "MH_UNKNOWN",
351 }
352 }
353}
354
355#[derive(Debug, Clone)]
356pub struct MachoHeader {
358 pub(crate) magic: MagicNumber,
359 pub(crate) cpu_type: CpuType,
360 pub(crate) cpu_subtype: CpuSubtype,
361 pub(crate) file_type: FileType,
362 pub(crate) ncmds: u32,
363 pub(crate) sizeofcmds: u32,
364 pub(crate) flags: MachoHeaderFlags,
365 pub(crate) reserved: u32,
366}
367
368impl MachoHeader {
369 pub const fn magic(&self) -> MagicNumber {
371 self.magic
372 }
373 pub const fn cpu_type(&self) -> CpuType {
375 self.cpu_type
376 }
377 pub const fn cpu_subtype(&self) -> CpuSubtype {
379 self.cpu_subtype
380 }
381 pub const fn arch_spec(&self) -> ArchSpec {
383 ArchSpec {
384 cpu_type: self.cpu_type,
385 cpu_subtype: self.cpu_subtype,
386 }
387 }
388 pub const fn file_type(&self) -> FileType {
390 self.file_type
391 }
392 pub const fn load_command_count(&self) -> u32 {
394 self.ncmds
395 }
396 pub const fn load_commands_size(&self) -> u32 {
398 self.sizeofcmds
399 }
400 pub const fn flags(&self) -> MachoHeaderFlags {
402 self.flags
403 }
404 pub const fn reserved(&self) -> u32 {
406 self.reserved
407 }
408}