goblin_experimental/mach/
load_command.rs

1//! Load commands tell the kernel and dynamic linker anything from how to load this binary into memory, what the entry point is, apple specific information, to which libraries it requires for dynamic linking
2
3use crate::error;
4use core::convert::TryFrom;
5use core::fmt::{self, Display};
6use scroll::{ctx, Endian};
7use scroll::{IOread, IOwrite, Pread, Pwrite, SizeWith};
8
9///////////////////////////////////////
10// Load Commands from mach-o/loader.h
11// with some rusty additions
12//////////////////////////////////////
13
14#[repr(C)]
15#[derive(Debug, Clone, Copy, Pread, Pwrite, SizeWith)]
16/// Occurs at the beginning of every load command to serve as a sort of tagged union/enum discriminant
17pub struct LoadCommandHeader {
18    pub cmd: u32,
19    pub cmdsize: u32,
20}
21
22impl Display for LoadCommandHeader {
23    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
24        write!(
25            fmt,
26            "LoadCommandHeader: {} size: {}",
27            cmd_to_str(self.cmd),
28            self.cmdsize
29        )
30    }
31}
32
33pub const SIZEOF_LOAD_COMMAND: usize = 8;
34
35pub type LcStr = u32;
36
37pub const SIZEOF_LC_STR: usize = 4;
38
39#[repr(C)]
40#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
41pub struct Section32 {
42    /// name of this section
43    pub sectname: [u8; 16],
44    /// segment this section goes in
45    pub segname: [u8; 16],
46    /// memory address of this section
47    pub addr: u32,
48    /// size in bytes of this section
49    pub size: u32,
50    /// file offset of this section
51    pub offset: u32,
52    /// section alignment (power of 2)
53    pub align: u32,
54    /// file offset of relocation entries
55    pub reloff: u32,
56    /// number of relocation entries
57    pub nreloc: u32,
58    /// flags (section type and attributes)
59    pub flags: u32,
60    /// reserved (for offset or index)
61    pub reserved1: u32,
62    /// reserved (for count or sizeof)
63    pub reserved2: u32,
64}
65
66pub const SIZEOF_SECTION_32: usize = 68;
67
68/// for 64-bit architectures
69#[repr(C)]
70#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
71pub struct Section64 {
72    /// name of this section
73    pub sectname: [u8; 16],
74    /// segment this section goes in
75    pub segname: [u8; 16],
76    /// memory address of this section
77    pub addr: u64,
78    /// size in bytes of this section
79    pub size: u64,
80    /// file offset of this section
81    pub offset: u32,
82    /// section alignment (power of 2)
83    pub align: u32,
84    /// file offset of relocation entries
85    pub reloff: u32,
86    /// number of relocation entries
87    pub nreloc: u32,
88    /// flags (section type and attributes
89    pub flags: u32,
90    /// reserved (for offset or index)
91    pub reserved1: u32,
92    /// reserved (for count or sizeof)
93    pub reserved2: u32,
94    /// reserved
95    pub reserved3: u32,
96}
97
98pub const SIZEOF_SECTION_64: usize = 80;
99
100#[repr(C)]
101#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
102pub struct SegmentCommand32 {
103    pub cmd: u32,
104    pub cmdsize: u32,
105    pub segname: [u8; 16],
106    pub vmaddr: u32,
107    pub vmsize: u32,
108    pub fileoff: u32,
109    pub filesize: u32,
110    pub maxprot: u32,
111    pub initprot: u32,
112    pub nsects: u32,
113    pub flags: u32,
114}
115
116pub const SIZEOF_SEGMENT_COMMAND_32: usize = 56;
117
118impl SegmentCommand32 {
119    pub fn name(&self) -> error::Result<&str> {
120        Ok(self.segname.pread::<&str>(0)?)
121    }
122}
123
124#[repr(C)]
125#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
126pub struct SegmentCommand64 {
127    pub cmd: u32,
128    pub cmdsize: u32,
129    pub segname: [u8; 16],
130    pub vmaddr: u64,
131    pub vmsize: u64,
132    pub fileoff: u64,
133    pub filesize: u64,
134    pub maxprot: u32,
135    pub initprot: u32,
136    pub nsects: u32,
137    pub flags: u32,
138}
139
140pub const SIZEOF_SEGMENT_COMMAND_64: usize = 72;
141
142impl SegmentCommand64 {
143    pub fn name(&self) -> error::Result<&str> {
144        Ok(self.segname.pread::<&str>(0)?)
145    }
146}
147/// Fixed virtual memory shared libraries are identified by two things.  The
148/// target pathname (the name of the library as found for execution), and the
149/// minor version number.  The address of where the headers are loaded is in
150/// header_addr. (THIS IS OBSOLETE and no longer supported).
151#[repr(C)]
152#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
153pub struct Fvmlib {
154    /// library's target pathname
155    pub name: u32,
156    /// library's minor version number
157    pub minor_version: u32,
158    /// library's header address
159    pub header_addr: u32,
160}
161
162pub const SIZEOF_FVMLIB: usize = 12;
163
164/// A fixed virtual shared library (fipub constype == MH_FVMLIB in the mach header)
165/// contains a fvmlib_command (cmd == LC_IDFVMLIB) to identify the library.
166/// An object that uses a fixed virtual shared library also contains a
167/// fvmlib_command (cmd == LC_LOADFVMLIB) for each library it uses.
168/// (THIS IS OBSOLETE and no longer supported).
169#[repr(C)]
170#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
171pub struct FvmlibCommand {
172    /// LC_IDFVMLIB or LC_LOADFVMLIB
173    pub cmd: u32,
174    /// includes pathname string
175    pub cmdsize: u32,
176    /// the library identification
177    pub fvmlib: Fvmlib,
178}
179
180pub const SIZEOF_FVMLIB_COMMAND: usize = 20;
181
182// /// Dynamicly linked shared libraries are identified by two things.  The
183// /// pathname (the name of the library as found for execution), and the
184// /// compatibility version number.  The pathname must match and the compatibility
185// /// number in the user of the library must be greater than or equal to the
186// /// library being used.  The time stamp is used to record the time a library was
187// /// built and copied into user so it can be use to determined if the library used
188// /// at runtime is exactly the same as used to built the program.
189// struct dylib {
190//     union lc_str  name;   // library's path name
191//     uint32_t timestamp;   // library's build time stamp
192//     uint32_t current_version;  // library's current version number
193//     uint32_t compatibility_version; // library's compatibility vers number
194// }
195
196/// A dynamically linked shared library (fipub constype == MH_DYLIB in the mach header)
197/// contains a dylib_command (cmd == LC_ID_DYLIB) to identify the library.
198/// An object that uses a dynamically linked shared library also contains a
199/// dylib_command (cmd == LC_LOAD_DYLIB, LC_LOAD_WEAK_DYLIB, or
200/// LC_REEXPORT_DYLIB) for each library it uses.
201#[repr(C)]
202#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
203pub struct Dylib {
204    /// library's path name
205    pub name: LcStr,
206    /// library's build time stamp
207    pub timestamp: u32,
208    /// library's current version number
209    pub current_version: u32,
210    /// library's compatibility vers number
211    pub compatibility_version: u32,
212}
213
214pub const SIZEOF_DYLIB: usize = 16;
215
216#[repr(C)]
217#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
218pub struct DylibCommand {
219    /// LC_ID_DYLIB, LC_LOAD_DYLIB, LC_LOAD_WEAK_DYLIB, LC_REEXPORT_DYLIB
220    pub cmd: u32,
221    /// includes pathname string
222    pub cmdsize: u32,
223    /// the library identification
224    pub dylib: Dylib,
225}
226
227pub const SIZEOF_DYLIB_COMMAND: usize = 20;
228
229/// A dynamically linked shared library may be a subframework of an umbrella
230/// framework.  If so it will be linked with "-umbrella umbrella_name" where
231/// Where "umbrella_name" is the name of the umbrella framework. A subframework
232/// can only be linked against by its umbrella framework or other subframeworks
233/// that are part of the same umbrella framework.  Otherwise the static link
234/// editor produces an error and states to link against the umbrella framework.
235/// The name of the umbrella framework for subframeworks is recorded in the
236/// following structure.
237#[repr(C)]
238#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
239pub struct SubFrameworkCommand {
240    /// LC_SUB_FRAMEWORK
241    pub cmd: u32,
242    /// includes umbrella string
243    pub cmdsize: u32,
244    /// the umbrella framework name
245    pub umbrella: u32,
246}
247
248pub const SIZEOF_SUB_FRAMEWORK_COMMAND: usize = 12;
249
250/// For dynamically linked shared libraries that are subframework of an umbrella
251/// framework they can allow clients other than the umbrella framework or other
252/// subframeworks in the same umbrella framework.  To do this the subframework
253/// is built with "-allowable_client client_name" and an LC_SUB_CLIENT load
254/// command is created for each -allowable_client flag.  The client_name is
255/// usually a framework name.  It can also be a name used for bundles clients
256/// where the bundle is built with "-client_name client_name".
257#[repr(C)]
258#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
259pub struct SubClientCommand {
260    /// LC_SUB_CLIENT
261    pub cmd: u32,
262    /// includes client string
263    pub cmdsize: u32,
264    /// the client name
265    pub client: LcStr,
266}
267
268pub const SIZEOF_SUB_CLIENT_COMMAND: usize = 12;
269
270/// A dynamically linked shared library may be a sub_umbrella of an umbrella
271/// framework.  If so it will be linked with "-sub_umbrella umbrella_name" where
272/// Where "umbrella_name" is the name of the sub_umbrella framework.  When
273/// staticly linking when -twolevel_namespace is in effect a twolevel namespace
274/// umbrella framework will only cause its subframeworks and those frameworks
275/// listed as sub_umbrella frameworks to be implicited linked in.  Any other
276/// dependent dynamic libraries will not be linked it when -twolevel_namespace
277/// is in effect.  The primary library recorded by the static linker when
278/// resolving a symbol in these libraries will be the umbrella framework.
279/// Zero or more sub_umbrella frameworks may be use by an umbrella framework.
280/// The name of a sub_umbrella framework is recorded in the following structure.
281#[repr(C)]
282#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
283pub struct SubUmbrellaCommand {
284    /// LC_SUB_UMBRELLA
285    pub cmd: u32,
286    /// includes sub_umbrella string
287    pub cmdsize: u32,
288    /// the sub_umbrella framework name
289    pub sub_umbrella: LcStr,
290}
291
292pub const SIZEOF_SUB_UMBRELLA_COMMAND: usize = 12;
293
294/// A dynamically linked shared library may be a sub_library of another shared
295/// library.  If so it will be linked with "-sub_library library_name" where
296/// Where "library_name" is the name of the sub_library shared library.  When
297/// staticly linking when -twolevel_namespace is in effect a twolevel namespace
298/// shared library will only cause its subframeworks and those frameworks
299/// listed as sub_umbrella frameworks and libraries listed as sub_libraries to
300/// be implicited linked in.  Any other dependent dynamic libraries will not be
301/// linked it when -twolevel_namespace is in effect.  The primary library
302/// recorded by the static linker when resolving a symbol in these libraries
303/// will be the umbrella framework (or dynamic library). Zero or more sub_library
304/// shared libraries may be use by an umbrella framework or (or dynamic library).
305/// The name of a sub_library framework is recorded in the following structure.
306/// For example /usr/lib/libobjc_profile.A.dylib would be recorded as "libobjc".
307#[repr(C)]
308#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
309pub struct SubLibraryCommand {
310    /// LC_SUB_LIBRARY
311    pub cmd: u32,
312    /// includes sub_library string
313    pub cmdsize: u32,
314    /// the sub_library name
315    pub sub_library: LcStr,
316}
317
318pub const SIZEOF_SUB_LIBRARY_COMMAND: usize = 12;
319
320/// A program (type == MH_EXECUTE) that is
321/// prebound to its dynamic libraries has one of these for each library that
322/// the static linker used in prebinding.  It contains a bit vector for the
323/// modules in the library.  The bits indicate which modules are bound (1) and
324/// which are not (0) from the library.  The bit for module 0 is the low bit
325/// of the first byte.  So the bit for the Nth module is:
326/// (linked_modules[N/8] >> N%8) & 1
327#[repr(C)]
328#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
329pub struct PreboundDylibCommand {
330    /// LC_PREBOUND_DYLIB
331    pub cmd: u32,
332    /// includes strings
333    pub cmdsize: u32,
334    /// library's path name
335    pub name: LcStr,
336    /// number of modules in library
337    pub nmodules: u32,
338    /// bit vector of linked modules
339    // TODO: fixme
340    pub linked_modules: LcStr,
341}
342
343pub const SIZEOF_PREBOUND_DYLIB_COMMAND: usize = 20;
344
345/// The name of the dynamic linker
346#[repr(C)]
347#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
348pub struct DylinkerCommand {
349    pub cmd: u32,
350    pub cmdsize: u32,
351    pub name: LcStr,
352}
353
354pub const SIZEOF_DYLINKER_COMMAND: usize = 12;
355
356/// Thread commands contain machine-specific data structures suitable for
357/// use in the thread state primitives.  The machine specific data structures
358/// follow the struct thread_command as follows.
359/// Each flavor of machine specific data structure is preceded by an unsigned
360/// long constant for the flavor of that data structure, an uint32_t
361/// that is the count of longs of the size of the state data structure and then
362/// the state data structure follows.  This triple may be repeated for many
363/// flavors.  The constants for the flavors, counts and state data structure
364/// definitions are expected to be in the header file <machine/thread_status.h>.
365/// These machine specific data structures sizes must be multiples of
366/// 4 bytes  The cmdsize reflects the total size of the thread_command
367/// and all of the sizes of the constants for the flavors, counts and state
368/// data structures.
369///
370/// For executable objects that are unix processes there will be one
371/// thread_command (cmd == LC_UNIXTHREAD) created for it by the link-editor.
372/// This is the same as a LC_THREAD, except that a stack is automatically
373/// created (based on the shell's limit for the stack size).  CommandVariant arguments
374/// and environment variables are copied onto that stack.
375// unimplemented, see machine/thread_status.h for rest of values:
376// uint32_t flavor		   flavor of thread state
377// uint32_t count		   count of longs in thread state
378// struct XXX_thread_state state   thread state for this flavor
379// ...
380#[repr(C)]
381#[derive(Copy)]
382pub struct ThreadCommand {
383    /// LC_THREAD or  LC_UNIXTHREAD
384    pub cmd: u32,
385    /// total size of this command
386    pub cmdsize: u32,
387
388    /// flavor of thread state (but you also need to know the `cputype`)
389    pub flavor: u32,
390
391    /// number of elements in `thread_state` that are valid
392    pub count: u32,
393
394    /// The raw thread state, details of which varies by CPU
395    pub thread_state: [u32; 70],
396}
397
398impl ThreadCommand {
399    pub fn instruction_pointer(&self, cputype: super::cputype::CpuType) -> error::Result<u64> {
400        // The thread command includes a `flavor` value which distinguishes between related thread
401        // states. However, `dyld` ignores this entirely, blindly interpreting the thread state
402        // values as a machine-specific set of registers matching the build configuration of the
403        // active `dyld` binary.
404        //
405        // Really the only thing that `dyld` cares is that the Mach header's `cputype`, so that's
406        // what we use here.
407        match cputype {
408            super::cputype::CPU_TYPE_X86 => {
409                // struct i386_thread_state_t {
410                //   uint32_t eax;
411                //   uint32_t ebx;
412                //   uint32_t ecx;
413                //   uint32_t edx;
414                //   uint32_t edi;
415                //   uint32_t esi;
416                //   uint32_t ebp;
417                //   uint32_t esp;
418                //   uint32_t ss;
419                //   uint32_t eflags;
420                //   uint32_t eip;
421                //   uint32_t cs;
422                //   uint32_t ds;
423                //   uint32_t es;
424                //   uint32_t fs;
425                //   uint32_t gs;
426                // }
427                let eip: u32 = self.thread_state[10];
428                Ok(u64::from(eip))
429            }
430            super::cputype::CPU_TYPE_X86_64 => {
431                // struct x86_thread_state64_t {
432                //   uint64_t rax;
433                //   uint64_t rbx;
434                //   uint64_t rcx;
435                //   uint64_t rdx;
436                //   uint64_t rdi;
437                //   uint64_t rsi;
438                //   uint64_t rbp;
439                //   uint64_t rsp;
440                //   uint64_t r8;
441                //   uint64_t r9;
442                //   uint64_t r10;
443                //   uint64_t r11;
444                //   uint64_t r12;
445                //   uint64_t r13;
446                //   uint64_t r14;
447                //   uint64_t r15;
448                //   uint64_t rip;
449                //   uint64_t rflags;
450                //   uint64_t cs;
451                //   uint64_t fs;
452                //   uint64_t gs;
453                // }
454                let rip: u64 =
455                    (u64::from(self.thread_state[32])) | ((u64::from(self.thread_state[33])) << 32);
456                Ok(rip)
457            }
458            super::cputype::CPU_TYPE_ARM => {
459                // struct arm_thread_state32_t {
460                //   uint32_t r[13];
461                //   uint32_t sp;
462                //   uint32_t lr;
463                //   uint32_t pc;
464                //   uint32_t cpsr;
465                // }
466                let pc: u32 = self.thread_state[15];
467                Ok(u64::from(pc))
468            }
469            super::cputype::CPU_TYPE_ARM64 | super::cputype::CPU_TYPE_ARM64_32 => {
470                // struct arm_thread_state64_t {
471                //   uint64_t x[29];
472                //   uint64_t fp;
473                //   uint64_t lr;
474                //   uint64_t sp;
475                //   uint64_t pc;
476                //   uint32_t cpsr;
477                //   uint32_t pad;
478                // }
479                let pc: u64 =
480                    (u64::from(self.thread_state[64])) | ((u64::from(self.thread_state[65])) << 32);
481                Ok(pc)
482            }
483            // https://github.com/m4b/goblin/issues/64
484            // Probably a G4
485            super::cputype::CPU_TYPE_POWERPC => Ok(u64::from(self.thread_state[0])),
486            // I think the G5 was the last motorola powerpc processor used by apple before switching to intel cpus.
487            // unfortunately I don't have any binaries on hand to see what its thread state looks like :/
488            // super::cputype::CPU_TYPE_POWERPC64 => {
489            // }
490            // Assuming above is added, I don't believe apple ever ported mach-o the mach kernel
491            // (and hence its binary format) to any other machines except the above,
492            // but I would be happy to learn otherwise
493            _ => Err(error::Error::Malformed(format!(
494                "unable to find instruction pointer for cputype {:?}",
495                cputype
496            ))),
497        }
498    }
499}
500
501impl<'a> ctx::TryFromCtx<'a, Endian> for ThreadCommand {
502    type Error = crate::error::Error;
503    fn try_from_ctx(bytes: &'a [u8], le: Endian) -> error::Result<(Self, usize)> {
504        let lc = bytes.pread_with::<LoadCommandHeader>(0, le)?;
505
506        // read the thread state flavor and length of the thread state
507        let flavor: u32 = bytes.pread_with(8, le)?;
508        let count: u32 = bytes.pread_with(12, le)?;
509
510        if count > 70 {
511            return Err(error::Error::Malformed(format!(
512                "thread command specifies {} longs for thread state but we handle only 70",
513                count
514            )));
515        }
516
517        // get a byte slice of the thread state
518        let thread_state_byte_length = count as usize * 4;
519
520        // check the length
521        if bytes.len() < 16 + thread_state_byte_length {
522            return Err(error::Error::Malformed(format!(
523                "thread command specifies {} bytes for thread state but has only {}",
524                thread_state_byte_length,
525                bytes.len()
526            )));
527        }
528
529        let thread_state_bytes = &bytes[16..16 + thread_state_byte_length];
530
531        // read the thread state
532        let mut thread_state: [u32; 70] = [0; 70];
533        for (i, state) in thread_state.iter_mut().enumerate().take(count as usize) {
534            *state = thread_state_bytes.pread_with(i * 4, le)?;
535        }
536
537        Ok((
538            ThreadCommand {
539                cmd: lc.cmd,
540                cmdsize: lc.cmdsize,
541                flavor,
542                count,
543                thread_state,
544            },
545            lc.cmdsize as _,
546        ))
547    }
548}
549
550impl Clone for ThreadCommand {
551    fn clone(&self) -> Self {
552        *self
553    }
554}
555
556impl fmt::Debug for ThreadCommand {
557    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
558        fmt.debug_struct("ThreadCommand")
559            .field("cmd", &self.cmd)
560            .field("cmdsize", &self.cmdsize)
561            .field("flavor", &self.flavor)
562            .field("count", &self.count)
563            .field("thread_state", &&self.thread_state[..])
564            .finish()
565    }
566}
567
568/// The routines command contains the address of the dynamic shared library
569/// initialization routine and an index into the module table for the module
570/// that defines the routine.  Before any modules are used from the library the
571/// dynamic linker fully binds the module that defines the initialization routine
572/// and then calls it.  This gets called before any module initialization
573/// routines (used for C++ static constructors) in the library.
574#[repr(C)]
575#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
576pub struct RoutinesCommand32 {
577    /// LC_ROUTINES
578    pub cmd: u32,
579    /// total size of this command
580    pub cmdsize: u32,
581    /// address of initialization routine
582    pub init_address: u32,
583    /// index into the module table that the init routine is defined in
584    pub init_module: u32,
585    pub reserved1: u32,
586    pub reserved2: u32,
587    pub reserved3: u32,
588    pub reserved4: u32,
589    pub reserved5: u32,
590    pub reserved6: u32,
591}
592
593/// The 64-bit routines command.  Same use as above.
594#[repr(C)]
595#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
596pub struct RoutinesCommand64 {
597    /// LC_ROUTINES_64
598    pub cmd: u32,
599    /// total size of this command
600    pub cmdsize: u32,
601    /// address of initialization routine
602    pub init_address: u64,
603    /// index into the module table that the init routine is defined in 8 bytes each
604    pub init_module: u64,
605    pub reserved1: u64,
606    pub reserved2: u64,
607    pub reserved3: u64,
608    pub reserved4: u64,
609    pub reserved5: u64,
610    pub reserved6: u64,
611}
612
613#[repr(C)]
614#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
615pub struct SymtabCommand {
616    pub cmd: u32,
617    pub cmdsize: u32,
618    pub symoff: u32,
619    pub nsyms: u32,
620    pub stroff: u32,
621    pub strsize: u32,
622}
623
624impl Default for SymtabCommand {
625    fn default() -> Self {
626        SymtabCommand {
627            cmd: LC_SYMTAB,
628            cmdsize: SIZEOF_SYMTAB_COMMAND as u32,
629            symoff: 0,
630            nsyms: 0,
631            stroff: 0,
632            strsize: 0,
633        }
634    }
635}
636
637impl SymtabCommand {
638    pub fn new() -> Self {
639        Default::default()
640    }
641}
642
643pub const SIZEOF_SYMTAB_COMMAND: usize = 24;
644
645/// This is the second set of the symbolic information which is used to support
646/// the data structures for the dynamically link editor.
647///
648/// The original set of symbolic information in the symtab_command which contains
649/// the symbol and string tables must also be present when this load command is
650/// present.  When this load command is present the symbol table is organized
651/// into three groups of symbols:
652/// local symbols (static and debugging symbols) - grouped by module
653/// defined external symbols - grouped by module (sorted by name if not lib)
654/// undefined external symbols (sorted by name if MH_BINDATLOAD is not set,
655///             and in order the were seen by the static
656///        linker if MH_BINDATLOAD is set)
657/// In this load command there are offsets and counts to each of the three groups
658/// of symbols.
659///
660/// This load command contains a the offsets and sizes of the following new
661/// symbolic information tables:
662/// table of contents
663/// module table
664/// reference symbol table
665/// indirect symbol table
666/// The first three tables above (the table of contents, module table and
667/// reference symbol table) are only present if the file is a dynamically linked
668/// shared library.  For executable and object modules, which are files
669/// containing only one module, the information that would be in these three
670/// tables is determined as follows:
671///  table of contents - the defined external symbols are sorted by name
672/// module table - the file contains only one module so everything in the
673///         file is part of the module.
674/// reference symbol table - is the defined and undefined external symbols
675///
676/// For dynamically linked shared library files this load command also contains
677/// offsets and sizes to the pool of relocation entries for all sections
678/// separated into two groups:
679/// external relocation entries
680/// local relocation entries
681/// For executable and object modules the relocation entries continue to hang
682/// off the section structures.
683#[repr(C)]
684#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
685pub struct DysymtabCommand {
686    pub cmd: u32,
687    pub cmdsize: u32,
688    /// index to local symbols
689    pub ilocalsym: u32,
690    /// number of local symbols
691    pub nlocalsym: u32,
692    /// index to externally defined symbols
693    pub iextdefsym: u32,
694    /// number of externally defined symbols
695    pub nextdefsym: u32,
696    /// index to undefined symbols
697    pub iundefsym: u32,
698    /// number of undefined symbols
699    pub nundefsym: u32,
700    /// file offset to table of contents
701    pub tocoff: u32,
702    /// number of entries in table of contents
703    pub ntoc: u32,
704    /// file offset to module table
705    pub modtaboff: u32,
706    /// number of module table entries
707    pub nmodtab: u32,
708    /// offset to referenced symbol table
709    pub extrefsymoff: u32,
710    /// number of referenced symbol table entries
711    pub nextrefsyms: u32,
712    /// file offset to the indirect symbol table
713    pub indirectsymoff: u32,
714    /// number of indirect symbol table entries
715    pub nindirectsyms: u32,
716    /// offset to external relocation entries
717    pub extreloff: u32,
718    /// number of external relocation entries
719    pub nextrel: u32,
720    /// offset to local relocation entries
721    pub locreloff: u32,
722    /// number of local relocation entries
723    pub nlocrel: u32,
724}
725
726impl Default for DysymtabCommand {
727    fn default() -> Self {
728        DysymtabCommand {
729            cmd: LC_DYSYMTAB,
730            cmdsize: SIZEOF_DYSYMTAB_COMMAND as u32,
731            ilocalsym: 0,
732            nlocalsym: 0,
733            iextdefsym: 0,
734            nextdefsym: 0,
735            iundefsym: 0,
736            nundefsym: 0,
737            tocoff: 0,
738            ntoc: 0,
739            modtaboff: 0,
740            nmodtab: 0,
741            extrefsymoff: 0,
742            nextrefsyms: 0,
743            indirectsymoff: 0,
744            nindirectsyms: 0,
745            extreloff: 0,
746            nextrel: 0,
747            locreloff: 0,
748            nlocrel: 0,
749        }
750    }
751}
752
753impl DysymtabCommand {
754    pub fn new() -> Self {
755        Default::default()
756    }
757}
758
759pub const SIZEOF_DYSYMTAB_COMMAND: usize = 80;
760
761// TODO: unimplemented
762/// a table of contents entry
763#[repr(C)]
764#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
765pub struct DylibTableOfContents {
766    /// the defined external symbol (index into the symbol table)
767    pub symbol_index: u32,
768    /// index into the module table this symbol is defined in
769    pub module_index: u32,
770}
771
772// TODO: unimplemented
773/// a module table entry
774#[repr(C)]
775#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
776pub struct DylibModule {
777    /// the module name (index into string table)
778    pub module_name: u32,
779    ///index into externally defined symbols
780    pub iextdefsym: u32,
781    ///number of externally defined symbols
782    pub nextdefsym: u32,
783    /// index into reference symbol table
784    pub irefsym: u32,
785    ///number of reference symbol table entries
786    pub nrefsym: u32,
787    /// index into symbols for local symbols
788    pub ilocalsym: u32,
789    ///number of local symbols
790    pub nlocalsym: u32,
791
792    /// index into external relocation entries
793    pub iextrel: u32,
794    /// number of external relocation entries
795    pub nextrel: u32,
796
797    /// low 16 bits are the index into the init section, high 16 bits are the index into the term section
798    pub iinit_iterm: u32,
799    /// low 16 bits are the number of init section entries, high 16 bits are the number of term section entries
800    pub ninit_nterm: u32,
801    /// the (__OBJC,_module_info) section
802    pub objc_module_info_addr: u32,
803    /// the (__OBJC,__module_info) section
804    pub objc_module_info_size: u32,
805}
806
807// TODO: unimplemented
808/// a 64-bit module table entry
809#[repr(C)]
810#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
811pub struct DylibModule64 {
812    /// the module name (index into string table)
813    pub module_name: u32,
814
815    /// index into externally defined symbols
816    pub iextdefsym: u32,
817    /// number of externally defined symbols
818    pub nextdefsym: u32,
819    /// index into reference symbol table
820    pub irefsym: u32,
821    /// number of reference symbol table entries
822    pub nrefsym: u32,
823    /// index into symbols for local symbols
824    pub ilocalsym: u32,
825    /// number of local symbols
826    pub nlocalsym: u32,
827
828    /// index into external relocation entries
829    pub iextrel: u32,
830    /// number of external relocation entries
831    pub nextrel: u32,
832
833    /// low 16 bits are the index into the init section, high 16 bits are the index into the term section
834    pub iinit_iterm: u32,
835    /// low 16 bits are the number of init section entries, high 16 bits are the number of term section entries
836    pub ninit_nterm: u32,
837
838    /// the (__OBJC,__module_info) section
839    pub objc_module_info_size: u32,
840    /// the (__OBJC,__module_info) section
841    pub objc_module_info_addr: u64,
842}
843
844/// The entries in the reference symbol table are used when loading the module
845/// (both by the static and dynamic link editors) and if the module is unloaded
846/// or replaced.  Therefore all external symbols (defined and undefined) are
847/// listed in the module's reference table.  The flags describe the type of
848/// reference that is being made.  The constants for the flags are defined in
849/// <mach-o/nlist.h> as they are also used for symbol table entries.
850#[repr(C)]
851#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
852pub struct DylibReference {
853    /// 24 bits bit-field index into the symbol table
854    pub isym: [u8; 24],
855    /// flags to indicate the type of reference
856    pub flags: u64,
857}
858
859/// The twolevel_hints_command contains the offset and number of hints in the
860/// two-level namespace lookup hints table.
861#[repr(C)]
862#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
863pub struct TwolevelHintsCommand {
864    /// LC_TWOLEVEL_HINTS
865    pub cmd: u32,
866    /// sizeof(struct twolevel_hints_command)
867    pub cmdsize: u32,
868    /// offset to the hint table
869    pub offset: u32,
870    /// number of hints in the hint table
871    pub nhints: u32,
872}
873
874/// The entries in the two-level namespace lookup hints table are twolevel_hint
875/// structs.  These provide hints to the dynamic link editor where to start
876/// looking for an undefined symbol in a two-level namespace image.  The
877/// isub_image field is an index into the sub-images (sub-frameworks and
878/// sub-umbrellas list) that made up the two-level image that the undefined
879/// symbol was found in when it was built by the static link editor.  If
880/// isub-image is 0 the the symbol is expected to be defined in library and not
881/// in the sub-images.  If isub-image is non-zero it is an index into the array
882/// of sub-images for the umbrella with the first index in the sub-images being
883/// 1. The array of sub-images is the ordered list of sub-images of the umbrella
884/// that would be searched for a symbol that has the umbrella recorded as its
885/// primary library.  The table of contents index is an index into the
886/// library's table of contents.  This is used as the starting point of the
887/// binary search or a directed linear search.
888#[repr(C)]
889#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
890pub struct TwolevelHint {
891    /// index into the sub images
892    pub isub_image: u64,
893    /// 24 bit field index into the table of contents
894    pub itoc: [u8; 24],
895}
896
897/// The prebind_cksum_command contains the value of the original check sum for
898/// prebound files or zero.  When a prebound file is first created or modified
899/// for other than updating its prebinding information the value of the check sum
900/// is set to zero.  When the file has it prebinding re-done and if the value of
901/// the check sum is zero the original check sum is calculated and stored in
902/// cksum field of this load command in the output file.  If when the prebinding
903/// is re-done and the cksum field is non-zero it is left unchanged from the
904/// input file.
905// TODO: unimplemented
906#[repr(C)]
907#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
908pub struct PrebindCksumCommand {
909    /// LC_PREBIND_CKSUM
910    pub cmd: u32,
911    /// sizeof(struct prebind_cksum_command)
912    pub cmdsize: u32,
913    /// the check sum or zero
914    pub cksum: u32,
915}
916
917/// The uuid load command contains a single 128-bit unique random number that
918/// identifies an object produced by the static link editor.
919#[repr(C)]
920#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
921pub struct UuidCommand {
922    /// LC_UUID
923    pub cmd: u32,
924    /// sizeof(struct uuid_command)
925    pub cmdsize: u32,
926    /// 16 bytes the 128-bit uuid
927    pub uuid: [u8; 16],
928}
929
930pub const SIZEOF_UUID_COMMAND: usize = 24;
931
932/// The rpath_command contains a path which at runtime should be added to
933/// the current run path used to find @rpath prefixed dylibs.
934#[repr(C)]
935#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
936pub struct RpathCommand {
937    /// LC_RPATH
938    pub cmd: u32,
939    /// includes string
940    pub cmdsize: u32,
941    /// path to add to run path
942    pub path: LcStr,
943}
944
945pub const SIZEOF_RPATH_COMMAND: usize = 12;
946
947/// The linkedit_data_command contains the offsets and sizes of a blob
948/// of data in the __LINKEDIT segment.
949#[repr(C)]
950#[derive(Default, Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
951pub struct LinkeditDataCommand {
952    /// LC_CODE_SIGNATURE, LC_SEGMENT_SPLIT_INFO, LC_FUNCTION_STARTS, LC_DATA_IN_CODE,
953    /// LC_DYLIB_CODE_SIGN_DRS, LC_LINKER_OPTIMIZATION_HINT, LC_DYLD_EXPORTS_TRIE, or LC_DYLD_CHAINED_FIXUPS.
954    pub cmd: u32,
955    /// sizeof(struct linkedit_data_command)
956    pub cmdsize: u32,
957    /// file offset of data in __LINKEDIT segment
958    pub dataoff: u32,
959    /// file size of data in __LINKEDIT segment
960    pub datasize: u32,
961}
962
963pub const SIZEOF_LINKEDIT_DATA_COMMAND: usize = 16;
964
965/// The encryption_info_command contains the file offset and size of an
966/// of an encrypted segment.
967#[repr(C)]
968#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
969pub struct EncryptionInfoCommand32 {
970    /// LC_ENCRYPTION_INFO
971    pub cmd: u32,
972    /// sizeof(struct encryption_info_command)
973    pub cmdsize: u32,
974    /// file offset of encrypted range
975    pub cryptoff: u32,
976    /// file size of encrypted range
977    pub cryptsize: u32,
978    /// which enryption system, 0 means not-encrypted yet
979    pub cryptid: u32,
980}
981
982pub const SIZEOF_ENCRYPTION_INFO_COMMAND_32: usize = 20;
983
984/// The encryption_info_command_64 contains the file offset and size of an
985/// of an encrypted segment (for use in x86_64 targets).
986#[repr(C)]
987#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
988pub struct EncryptionInfoCommand64 {
989    /// LC_ENCRYPTION_INFO_64
990    pub cmd: u32,
991    /// sizeof(struct encryption_info_command_64)
992    pub cmdsize: u32,
993    /// file offset of encrypted range
994    pub cryptoff: u32,
995    /// file size of encrypted range
996    pub cryptsize: u32,
997    /// which enryption system, 0 means not-encrypted yet
998    pub cryptid: u32,
999    /// padding to make this struct's size a multiple of 8 bytes
1000    pub pad: u32,
1001}
1002
1003pub const SIZEOF_ENCRYPTION_INFO_COMMAND_64: usize = 24;
1004
1005/// An enumeration of platforms currently identifiable within a version_min_command.
1006#[non_exhaustive]
1007#[repr(u32)]
1008#[derive(Debug)]
1009pub enum Platform {
1010    Macos = LC_VERSION_MIN_MACOSX,
1011    Iphoneos = LC_VERSION_MIN_IPHONEOS,
1012    Tvos = LC_VERSION_MIN_TVOS,
1013    Watchos = LC_VERSION_MIN_WATCHOS,
1014}
1015
1016impl TryFrom<u32> for Platform {
1017    type Error = error::Error;
1018
1019    fn try_from(cmd: u32) -> Result<Self, Self::Error> {
1020        Ok(match cmd {
1021            LC_VERSION_MIN_MACOSX => Platform::Macos,
1022            LC_VERSION_MIN_IPHONEOS => Platform::Iphoneos,
1023            LC_VERSION_MIN_TVOS => Platform::Tvos,
1024            LC_VERSION_MIN_WATCHOS => Platform::Watchos,
1025            _ => {
1026                return Err(error::Error::Malformed(format!(
1027                    "unknown platform for load command: {:x}",
1028                    cmd
1029                )))
1030            }
1031        })
1032    }
1033}
1034
1035/// The version_min_command contains the min OS version on which this
1036/// binary was built to run.
1037///
1038#[repr(C)]
1039#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
1040pub struct VersionMinCommand {
1041    /// LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS, LC_VERSION_MIN_TVOS, or LC_VERSION_MIN_WATCHOS.
1042    pub cmd: u32,
1043    pub cmdsize: u32,
1044    /// X.Y.Z is encoded in nibbles xxxx.yy.zz
1045    pub version: u32,
1046    /// X.Y.Z is encoded in nibbles xxxx.yy.zz
1047    pub sdk: u32,
1048}
1049
1050impl VersionMinCommand {
1051    pub fn new(platform: Platform) -> Self {
1052        VersionMinCommand {
1053            cmd: platform as u32,
1054            cmdsize: SIZEOF_VERSION_MIN_COMMAND as u32,
1055            version: 0,
1056            sdk: 0,
1057        }
1058    }
1059
1060    pub fn platform(&self) -> Platform {
1061        // A panic here indicates an incomplete API change above: VersionMinCommand
1062        // can only be constructed from one of the LC_VERSION_* commands or directly
1063        // from a Platform, so an error indicates that a new one hasn't been correctly
1064        // added to the Platform enum.
1065        Platform::try_from(self.cmd).expect("impossible platform (implementation error)")
1066    }
1067}
1068
1069pub const SIZEOF_VERSION_MIN_COMMAND: usize = 16;
1070
1071#[repr(C)]
1072#[derive(Default, Debug, Clone, Copy, Pread, Pwrite, SizeWith)]
1073pub struct DyldInfoCommand {
1074    /// LC_DYLD_INFO or LC_DYLD_INFO_ONLY
1075    pub cmd: u32,
1076    /// sizeof(struct dyld_info_command)
1077    pub cmdsize: u32,
1078    /// file offset to rebase info
1079    pub rebase_off: u32,
1080    /// size of rebase info
1081    pub rebase_size: u32,
1082    /// file offset to binding info
1083    pub bind_off: u32,
1084    /// size of binding info
1085    pub bind_size: u32,
1086    /// file offset to weak binding info
1087    pub weak_bind_off: u32,
1088    /// size of weak binding info
1089    pub weak_bind_size: u32,
1090    /// file offset to lazy binding info
1091    pub lazy_bind_off: u32,
1092    /// size of lazy binding infs
1093    pub lazy_bind_size: u32,
1094    /// file offset to lazy binding info
1095    pub export_off: u32,
1096    /// size of lazy binding infs
1097    pub export_size: u32,
1098}
1099
1100pub const SIZEOF_DYLIB_INFO_COMMAND: usize = 48;
1101
1102/// The linker_option_command contains linker options embedded in object files.
1103#[repr(C)]
1104#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
1105pub struct LinkerOptionCommand {
1106    /// LC_LINKER_OPTION only used in MH_OBJECT fipub constypes
1107    pub cmd: u32,
1108    pub cmdsize: u32,
1109    /// number of strings concatenation of zero terminated UTF8 strings. Zero filled at end to align
1110    pub count: u32,
1111}
1112
1113pub const SIZEOF_LINKER_OPTION_COMMAND: usize = 12;
1114
1115/// The symseg_command contains the offset and size of the GNU style
1116/// symbol table information as described in the header file <symseg.h>.
1117/// The symbol roots of the symbol segments must also be aligned properly
1118/// in the file.  So the requirement of keeping the offsets aligned to a
1119/// multiple of a 4 bytes translates to the length field of the symbol
1120/// roots also being a multiple of a long.  Also the padding must again be
1121/// zeroed. (THIS IS OBSOLETE and no longer supported).
1122#[repr(C)]
1123#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
1124pub struct SymsegCommand {
1125    /// LC_SYMSEG
1126    pub cmd: u32,
1127    /// sizeof(struct symseg_command)
1128    pub cmdsize: u32,
1129    /// symbol segment offset
1130    pub offset: u32,
1131    /// symbol segment size in bytes
1132    pub size: u32,
1133}
1134
1135pub const SIZEOF_SYMSEG_COMMAND: usize = 16;
1136
1137/// The ident_command contains a free format string table following the
1138/// ident_command structure.  The strings are null terminated and the size of
1139/// the command is padded out with zero bytes to a multiple of 4 bytes/
1140/// (THIS IS OBSOLETE and no longer supported).
1141#[repr(C)]
1142#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
1143pub struct IdentCommand {
1144    /// LC_IDENT
1145    pub cmd: u32,
1146    /// strings that follow this command
1147    pub cmdsize: u32,
1148}
1149
1150pub const SIZEOF_IDENT_COMMAND: usize = 8;
1151
1152/// The fvmfile_command contains a reference to a file to be loaded at the
1153/// specified virtual address.  (Presently, this command is reserved for
1154/// internal use.  The kernel ignores this command when loading a program into
1155/// memory).
1156#[repr(C)]
1157#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
1158pub struct FvmfileCommand {
1159    /// LC_FVMFILE
1160    pub cmd: u32,
1161    /// includes pathname string
1162    pub cmdsize: u32,
1163    /// files pathname
1164    pub name: LcStr,
1165    /// files virtual address
1166    pub header_addr: u32,
1167}
1168
1169pub const SIZEOF_FVMFILE_COMMAND: usize = 16;
1170
1171/// The entry_point_command is a replacement for thread_command.
1172/// It is used for main executables to specify the location (file offset)
1173/// of main().  If -stack_size was used at link time, the stacksize
1174/// field will contain the stack size need for the main thread.
1175#[repr(C)]
1176#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
1177pub struct EntryPointCommand {
1178    pub cmd: u32,
1179    pub cmdsize: u32,
1180    /// uint64_t file __TEXT offset of main
1181    pub entryoff: u64,
1182    /// uint64_t if not zero, initial stack size
1183    pub stacksize: u64,
1184}
1185
1186pub const SIZEOF_ENTRY_POINT_COMMAND: usize = 24;
1187
1188/// The build_version_command contains the min OS version on which this
1189/// binary was built to run for its platform.  The list of known platforms and
1190/// tool values following it.
1191#[repr(C)]
1192#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
1193pub struct BuildVersionCommand {
1194    /// LC_BUILD_VERSION
1195    pub cmd: u32,
1196    pub cmdsize: u32,
1197    /// platform
1198    pub platform: u32,
1199    /// X.Y.Z is encoded in nibbles xxxx.yy.zz
1200    pub minos: u32,
1201    /// X.Y.Z is encoded in nibbles xxxx.yy.zz
1202    pub sdk: u32,
1203    /// number of tool entries following this
1204    pub ntools: u32,
1205}
1206
1207/// Build tool version
1208#[repr(C)]
1209#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
1210pub struct BuildToolVersion {
1211    /// enum for the tool
1212    pub tool: u32,
1213    /// version number of the tool
1214    pub version: u32,
1215}
1216
1217/// The LC_FILESET_ENTRY command is used for Mach-O filesets which contain
1218/// multiple Mach-O's, such as the dyld shared cache and kernelcache
1219#[repr(C)]
1220#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
1221pub struct FilesetEntryCommand {
1222    /// LC_FILSET_ENTRY
1223    pub cmd: u32,
1224    pub cmdsize: u32,
1225    /// memory address of the dylib
1226    pub vmaddr: u64,
1227    /// file offset of the dylib
1228    pub fileoff: u64,
1229    /// contained entry id
1230    pub entry_id: LcStr,
1231    /// reserved
1232    pub reserved: u32,
1233}
1234
1235/// The source_version_command is an optional load command containing
1236/// the version of the sources used to build the binary.
1237#[repr(C)]
1238#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
1239pub struct SourceVersionCommand {
1240    /// LC_SOURCE_VERSION
1241    pub cmd: u32,
1242    pub cmdsize: u32,
1243    /// A.B.C.D.E packed as a24.b10.c10.d10.e10
1244    pub version: u64,
1245}
1246
1247/// The LC_DATA_IN_CODE load commands uses a linkedit_data_command
1248/// to point to an array of data_in_code_entry entries. Each entry
1249/// describes a range of data in a code section.
1250#[repr(C)]
1251#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
1252pub struct DataInCodeEntry {
1253    /// from mach_header to start of data range
1254    pub offset: u32,
1255    /// number of bytes in data range
1256    pub length: u16,
1257    /// a DICE_KIND_* value
1258    pub kind: u16,
1259}
1260
1261/// LC_NOTE commands describe a region of arbitrary data included in a Mach-O
1262/// file.  Its initial use is to record extra data in MH_CORE files.
1263#[repr(C)]
1264#[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
1265pub struct NoteCommand {
1266    /// LC_NOTE
1267    pub cmd: u32,
1268    pub cmdsize: u32,
1269    /// owner name for this LC_NOTE
1270    pub data_owner: [u8; 16],
1271    /// file offset of this data
1272    pub offset: u64,
1273    /// length of data region
1274    pub size: u64,
1275}
1276
1277///////////////////////////////////////
1278// Constants, et. al
1279///////////////////////////////////////
1280
1281pub const LC_REQ_DYLD: u32 = 0x8000_0000;
1282pub const LC_LOAD_WEAK_DYLIB: u32 = 0x18 | LC_REQ_DYLD;
1283pub const LC_RPATH: u32 = 0x1c | LC_REQ_DYLD;
1284pub const LC_REEXPORT_DYLIB: u32 = 0x1f | LC_REQ_DYLD;
1285pub const LC_DYLD_INFO_ONLY: u32 = 0x22 | LC_REQ_DYLD;
1286pub const LC_LOAD_UPWARD_DYLIB: u32 = 0x23 | LC_REQ_DYLD;
1287pub const LC_MAIN: u32 = 0x28 | LC_REQ_DYLD;
1288pub const LC_DYLD_EXPORTS_TRIE: u32 = 0x33 | LC_REQ_DYLD;
1289pub const LC_DYLD_CHAINED_FIXUPS: u32 = 0x34 | LC_REQ_DYLD;
1290pub const LC_SEGMENT: u32 = 0x1;
1291pub const LC_SYMTAB: u32 = 0x2;
1292pub const LC_SYMSEG: u32 = 0x3;
1293pub const LC_THREAD: u32 = 0x4;
1294pub const LC_UNIXTHREAD: u32 = 0x5;
1295pub const LC_LOADFVMLIB: u32 = 0x6;
1296pub const LC_IDFVMLIB: u32 = 0x7;
1297pub const LC_IDENT: u32 = 0x8;
1298pub const LC_FVMFILE: u32 = 0x9;
1299pub const LC_PREPAGE: u32 = 0xa;
1300pub const LC_DYSYMTAB: u32 = 0xb;
1301pub const LC_LOAD_DYLIB: u32 = 0xc;
1302pub const LC_ID_DYLIB: u32 = 0xd;
1303pub const LC_LOAD_DYLINKER: u32 = 0xe;
1304pub const LC_ID_DYLINKER: u32 = 0xf;
1305pub const LC_PREBOUND_DYLIB: u32 = 0x10;
1306pub const LC_ROUTINES: u32 = 0x11;
1307pub const LC_SUB_FRAMEWORK: u32 = 0x12;
1308pub const LC_SUB_UMBRELLA: u32 = 0x13;
1309pub const LC_SUB_CLIENT: u32 = 0x14;
1310pub const LC_SUB_LIBRARY: u32 = 0x15;
1311pub const LC_TWOLEVEL_HINTS: u32 = 0x16;
1312pub const LC_PREBIND_CKSUM: u32 = 0x17;
1313pub const LC_SEGMENT_64: u32 = 0x19;
1314pub const LC_ROUTINES_64: u32 = 0x1a;
1315pub const LC_UUID: u32 = 0x1b;
1316pub const LC_CODE_SIGNATURE: u32 = 0x1d;
1317pub const LC_SEGMENT_SPLIT_INFO: u32 = 0x1e;
1318pub const LC_LAZY_LOAD_DYLIB: u32 = 0x20;
1319pub const LC_ENCRYPTION_INFO: u32 = 0x21;
1320pub const LC_DYLD_INFO: u32 = 0x22;
1321pub const LC_VERSION_MIN_MACOSX: u32 = 0x24;
1322pub const LC_VERSION_MIN_IPHONEOS: u32 = 0x25;
1323pub const LC_FUNCTION_STARTS: u32 = 0x26;
1324pub const LC_DYLD_ENVIRONMENT: u32 = 0x27;
1325pub const LC_DATA_IN_CODE: u32 = 0x29;
1326pub const LC_SOURCE_VERSION: u32 = 0x2A;
1327pub const LC_DYLIB_CODE_SIGN_DRS: u32 = 0x2B;
1328pub const LC_ENCRYPTION_INFO_64: u32 = 0x2C;
1329pub const LC_LINKER_OPTION: u32 = 0x2D;
1330pub const LC_LINKER_OPTIMIZATION_HINT: u32 = 0x2E;
1331pub const LC_VERSION_MIN_TVOS: u32 = 0x2F;
1332pub const LC_VERSION_MIN_WATCHOS: u32 = 0x30;
1333pub const LC_NOTE: u32 = 0x31;
1334pub const LC_BUILD_VERSION: u32 = 0x32;
1335pub const LC_FILESET_ENTRY: u32 = 0x35 | LC_REQ_DYLD;
1336pub const PLATFORM_MACOS: u32 = 1;
1337pub const PLATFORM_IOS: u32 = 2;
1338pub const PLATFORM_TVOS: u32 = 3;
1339pub const PLATFORM_WATCHOS: u32 = 4;
1340pub const PLATFORM_BRIDGEOS: u32 = 5;
1341pub const PLATFORM_MACCATALYST: u32 = 6;
1342pub const PLATFORM_IOSSIMULATOR: u32 = 7;
1343pub const PLATFORM_TVOSSIMULATOR: u32 = 8;
1344pub const PLATFORM_WATCHOSSIMULATOR: u32 = 9;
1345pub const PLATFORM_DRIVERKIT: u32 = 10;
1346pub const PLATFORM_VISIONOS: u32 = 11;
1347pub const PLATFORM_VISIONOSSIMULATOR: u32 = 12;
1348pub const TOOL_CLANG: u32 = 1;
1349pub const TOOL_SWIFT: u32 = 2;
1350pub const TOOL_LD: u32 = 3;
1351pub const TOOL_LLD: u32 = 4;
1352
1353pub fn cmd_to_str(cmd: u32) -> &'static str {
1354    match cmd {
1355        LC_SEGMENT => "LC_SEGMENT",
1356        LC_SYMTAB => "LC_SYMTAB",
1357        LC_SYMSEG => "LC_SYMSEG",
1358        LC_THREAD => "LC_THREAD",
1359        LC_UNIXTHREAD => "LC_UNIXTHREAD",
1360        LC_LOADFVMLIB => "LC_LOADFVMLIB",
1361        LC_IDFVMLIB => "LC_IDFVMLIB",
1362        LC_IDENT => "LC_IDENT",
1363        LC_FVMFILE => "LC_FVMFILE",
1364        LC_PREPAGE => "LC_PREPAGE",
1365        LC_DYSYMTAB => "LC_DYSYMTAB",
1366        LC_LOAD_DYLIB => "LC_LOAD_DYLIB",
1367        LC_ID_DYLIB => "LC_ID_DYLIB",
1368        LC_LOAD_DYLINKER => "LC_LOAD_DYLINKER",
1369        LC_ID_DYLINKER => "LC_ID_DYLINKER",
1370        LC_PREBOUND_DYLIB => "LC_PREBOUND_DYLIB",
1371        LC_ROUTINES => "LC_ROUTINES",
1372        LC_SUB_FRAMEWORK => "LC_SUB_FRAMEWORK",
1373        LC_SUB_UMBRELLA => "LC_SUB_UMBRELLA",
1374        LC_SUB_CLIENT => "LC_SUB_CLIENT",
1375        LC_SUB_LIBRARY => "LC_SUB_LIBRARY",
1376        LC_TWOLEVEL_HINTS => "LC_TWOLEVEL_HINTS",
1377        LC_PREBIND_CKSUM => "LC_PREBIND_CKSUM",
1378        LC_LOAD_WEAK_DYLIB => "LC_LOAD_WEAK_DYLIB",
1379        LC_SEGMENT_64 => "LC_SEGMENT_64",
1380        LC_ROUTINES_64 => "LC_ROUTINES_64",
1381        LC_UUID => "LC_UUID",
1382        LC_RPATH => "LC_RPATH",
1383        LC_CODE_SIGNATURE => "LC_CODE_SIGNATURE",
1384        LC_SEGMENT_SPLIT_INFO => "LC_SEGMENT_SPLIT_INFO",
1385        LC_REEXPORT_DYLIB => "LC_REEXPORT_DYLIB",
1386        LC_LAZY_LOAD_DYLIB => "LC_LAZY_LOAD_DYLIB",
1387        LC_ENCRYPTION_INFO => "LC_ENCRYPTION_INFO",
1388        LC_DYLD_INFO => "LC_DYLD_INFO",
1389        LC_DYLD_INFO_ONLY => "LC_DYLD_INFO_ONLY",
1390        LC_LOAD_UPWARD_DYLIB => "LC_LOAD_UPWARD_DYLIB",
1391        LC_VERSION_MIN_MACOSX => "LC_VERSION_MIN_MACOSX",
1392        LC_VERSION_MIN_IPHONEOS => "LC_VERSION_MIN_IPHONEOS",
1393        LC_FUNCTION_STARTS => "LC_FUNCTION_STARTS",
1394        LC_DYLD_ENVIRONMENT => "LC_DYLD_ENVIRONMENT",
1395        LC_MAIN => "LC_MAIN",
1396        LC_DATA_IN_CODE => "LC_DATA_IN_CODE",
1397        LC_SOURCE_VERSION => "LC_SOURCE_VERSION",
1398        LC_DYLIB_CODE_SIGN_DRS => "LC_DYLIB_CODE_SIGN_DRS",
1399        LC_ENCRYPTION_INFO_64 => "LC_ENCRYPTION_INFO_64",
1400        LC_LINKER_OPTION => "LC_LINKER_OPTION",
1401        LC_LINKER_OPTIMIZATION_HINT => "LC_LINKER_OPTIMIZATION_HINT",
1402        LC_VERSION_MIN_TVOS => "LC_VERSION_MIN_TVOS",
1403        LC_VERSION_MIN_WATCHOS => "LC_VERSION_MIN_WATCHOS",
1404        LC_NOTE => "LC_NOTE",
1405        LC_BUILD_VERSION => "LC_BUILD_VERSION",
1406        LC_FILESET_ENTRY => "LC_FILESET_ENTRY",
1407        LC_DYLD_EXPORTS_TRIE => "LC_DYLD_EXPORTS_TRIE",
1408        LC_DYLD_CHAINED_FIXUPS => "LC_DYLD_CHAINED_FIXUPS",
1409        _ => "LC_UNKNOWN",
1410    }
1411}
1412
1413///////////////////////////////////////////
1414// Typesafe Command Variants
1415///////////////////////////////////////////
1416
1417#[derive(Debug)]
1418#[allow(clippy::large_enum_variant)]
1419#[non_exhaustive]
1420/// The various load commands as a cast-free variant/enum
1421pub enum CommandVariant {
1422    Segment32(SegmentCommand32),
1423    Segment64(SegmentCommand64),
1424    Uuid(UuidCommand),
1425    Symtab(SymtabCommand),
1426    Symseg(SymsegCommand),
1427    Thread(ThreadCommand),
1428    Unixthread(ThreadCommand),
1429    LoadFvmlib(FvmlibCommand),
1430    IdFvmlib(FvmlibCommand),
1431    Ident(IdentCommand),
1432    Fvmfile(FvmfileCommand),
1433    Prepage(LoadCommandHeader),
1434    Dysymtab(DysymtabCommand),
1435    LoadDylib(DylibCommand),
1436    IdDylib(DylibCommand),
1437    LoadDylinker(DylinkerCommand),
1438    IdDylinker(DylinkerCommand),
1439    PreboundDylib(PreboundDylibCommand),
1440    Routines32(RoutinesCommand32),
1441    Routines64(RoutinesCommand64),
1442    SubFramework(SubFrameworkCommand),
1443    SubUmbrella(SubUmbrellaCommand),
1444    SubClient(SubClientCommand),
1445    SubLibrary(SubLibraryCommand),
1446    TwolevelHints(TwolevelHintsCommand),
1447    PrebindCksum(PrebindCksumCommand),
1448    LoadWeakDylib(DylibCommand),
1449    Rpath(RpathCommand),
1450    CodeSignature(LinkeditDataCommand),
1451    SegmentSplitInfo(LinkeditDataCommand),
1452    ReexportDylib(DylibCommand),
1453    LazyLoadDylib(DylibCommand),
1454    EncryptionInfo32(EncryptionInfoCommand32),
1455    EncryptionInfo64(EncryptionInfoCommand64),
1456    DyldInfo(DyldInfoCommand),
1457    DyldInfoOnly(DyldInfoCommand),
1458    LoadUpwardDylib(DylibCommand),
1459    VersionMinMacosx(VersionMinCommand),
1460    VersionMinIphoneos(VersionMinCommand),
1461    FunctionStarts(LinkeditDataCommand),
1462    DyldEnvironment(DylinkerCommand),
1463    Main(EntryPointCommand),
1464    DataInCode(LinkeditDataCommand),
1465    BuildVersion(BuildVersionCommand),
1466    FilesetEntry(FilesetEntryCommand),
1467    SourceVersion(SourceVersionCommand),
1468    DylibCodeSignDrs(LinkeditDataCommand),
1469    LinkerOption(LinkeditDataCommand),
1470    LinkerOptimizationHint(LinkeditDataCommand),
1471    VersionMinTvos(VersionMinCommand),
1472    VersionMinWatchos(VersionMinCommand),
1473    DyldExportsTrie(LinkeditDataCommand),
1474    DyldChainedFixups(LinkeditDataCommand),
1475    Note(NoteCommand),
1476    Unimplemented(LoadCommandHeader),
1477}
1478
1479impl<'a> ctx::TryFromCtx<'a, Endian> for CommandVariant {
1480    type Error = crate::error::Error;
1481    fn try_from_ctx(bytes: &'a [u8], le: Endian) -> error::Result<(Self, usize)> {
1482        use self::CommandVariant::*;
1483        let lc = bytes.pread_with::<LoadCommandHeader>(0, le)?;
1484        let size = lc.cmdsize as usize;
1485        //println!("offset {:#x} cmd: {:#x} size: {:?} ctx: {:?}", offset, lc.cmd, size, le);
1486        if size > bytes.len() {
1487            return Err(error::Error::Malformed(format!(
1488                "{} has size larger than remainder of binary: {:?}",
1489                &lc,
1490                bytes.len()
1491            )));
1492        }
1493        match lc.cmd {
1494            LC_SEGMENT => {
1495                let comm = bytes.pread_with::<SegmentCommand32>(0, le)?;
1496                Ok((Segment32(comm), size))
1497            }
1498            LC_SEGMENT_64 => {
1499                let comm = bytes.pread_with::<SegmentCommand64>(0, le)?;
1500                Ok((Segment64(comm), size))
1501            }
1502            LC_DYSYMTAB => {
1503                let comm = bytes.pread_with::<DysymtabCommand>(0, le)?;
1504                Ok((Dysymtab(comm), size))
1505            }
1506            LC_LOAD_DYLINKER => {
1507                let comm = bytes.pread_with::<DylinkerCommand>(0, le)?;
1508                Ok((LoadDylinker(comm), size))
1509            }
1510            LC_ID_DYLINKER => {
1511                let comm = bytes.pread_with::<DylinkerCommand>(0, le)?;
1512                Ok((IdDylinker(comm), size))
1513            }
1514            LC_UUID => {
1515                let comm = bytes.pread_with::<UuidCommand>(0, le)?;
1516                Ok((Uuid(comm), size))
1517            }
1518            LC_SYMTAB => {
1519                let comm = bytes.pread_with::<SymtabCommand>(0, le)?;
1520                Ok((Symtab(comm), size))
1521            }
1522            LC_SYMSEG => {
1523                let comm = bytes.pread_with::<SymsegCommand>(0, le)?;
1524                Ok((Symseg(comm), size))
1525            }
1526            LC_THREAD => {
1527                let comm = bytes.pread_with::<ThreadCommand>(0, le)?;
1528                Ok((Thread(comm), size))
1529            }
1530            LC_UNIXTHREAD => {
1531                let comm = bytes.pread_with::<ThreadCommand>(0, le)?;
1532                Ok((Unixthread(comm), size))
1533            }
1534            LC_LOADFVMLIB => {
1535                let comm = bytes.pread_with::<FvmlibCommand>(0, le)?;
1536                Ok((LoadFvmlib(comm), size))
1537            }
1538            LC_IDFVMLIB => {
1539                let comm = bytes.pread_with::<FvmlibCommand>(0, le)?;
1540                Ok((IdFvmlib(comm), size))
1541            }
1542            LC_IDENT => {
1543                let comm = bytes.pread_with::<IdentCommand>(0, le)?;
1544                Ok((Ident(comm), size))
1545            }
1546            LC_FVMFILE => {
1547                let comm = bytes.pread_with::<FvmfileCommand>(0, le)?;
1548                Ok((Fvmfile(comm), size))
1549            }
1550            LC_PREPAGE => {
1551                let comm = bytes.pread_with::<LoadCommandHeader>(0, le)?;
1552                Ok((Prepage(comm), size))
1553            }
1554            LC_LOAD_DYLIB => {
1555                let comm = bytes.pread_with::<DylibCommand>(0, le)?;
1556                Ok((LoadDylib(comm), size))
1557            }
1558            LC_ID_DYLIB => {
1559                let comm = bytes.pread_with::<DylibCommand>(0, le)?;
1560                Ok((IdDylib(comm), size))
1561            }
1562            LC_PREBOUND_DYLIB => {
1563                let comm = bytes.pread_with::<PreboundDylibCommand>(0, le)?;
1564                Ok((PreboundDylib(comm), size))
1565            }
1566            LC_ROUTINES => {
1567                let comm = bytes.pread_with::<RoutinesCommand32>(0, le)?;
1568                Ok((Routines32(comm), size))
1569            }
1570            LC_ROUTINES_64 => {
1571                let comm = bytes.pread_with::<RoutinesCommand64>(0, le)?;
1572                Ok((Routines64(comm), size))
1573            }
1574            LC_SUB_FRAMEWORK => {
1575                let comm = bytes.pread_with::<SubFrameworkCommand>(0, le)?;
1576                Ok((SubFramework(comm), size))
1577            }
1578            LC_SUB_UMBRELLA => {
1579                let comm = bytes.pread_with::<SubUmbrellaCommand>(0, le)?;
1580                Ok((SubUmbrella(comm), size))
1581            }
1582            LC_SUB_CLIENT => {
1583                let comm = bytes.pread_with::<SubClientCommand>(0, le)?;
1584                Ok((SubClient(comm), size))
1585            }
1586            LC_SUB_LIBRARY => {
1587                let comm = bytes.pread_with::<SubLibraryCommand>(0, le)?;
1588                Ok((SubLibrary(comm), size))
1589            }
1590            LC_TWOLEVEL_HINTS => {
1591                let comm = bytes.pread_with::<TwolevelHintsCommand>(0, le)?;
1592                Ok((TwolevelHints(comm), size))
1593            }
1594            LC_PREBIND_CKSUM => {
1595                let comm = bytes.pread_with::<PrebindCksumCommand>(0, le)?;
1596                Ok((PrebindCksum(comm), size))
1597            }
1598            LC_LOAD_WEAK_DYLIB => {
1599                let comm = bytes.pread_with::<DylibCommand>(0, le)?;
1600                Ok((LoadWeakDylib(comm), size))
1601            }
1602            LC_RPATH => {
1603                let comm = bytes.pread_with::<RpathCommand>(0, le)?;
1604                Ok((Rpath(comm), size))
1605            }
1606            LC_CODE_SIGNATURE => {
1607                let comm = bytes.pread_with::<LinkeditDataCommand>(0, le)?;
1608                Ok((CodeSignature(comm), size))
1609            }
1610            LC_SEGMENT_SPLIT_INFO => {
1611                let comm = bytes.pread_with::<LinkeditDataCommand>(0, le)?;
1612                Ok((SegmentSplitInfo(comm), size))
1613            }
1614            LC_REEXPORT_DYLIB => {
1615                let comm = bytes.pread_with::<DylibCommand>(0, le)?;
1616                Ok((ReexportDylib(comm), size))
1617            }
1618            LC_LAZY_LOAD_DYLIB => {
1619                let comm = bytes.pread_with::<DylibCommand>(0, le)?;
1620                Ok((LazyLoadDylib(comm), size))
1621            }
1622            LC_ENCRYPTION_INFO => {
1623                let comm = bytes.pread_with::<EncryptionInfoCommand32>(0, le)?;
1624                Ok((EncryptionInfo32(comm), size))
1625            }
1626            LC_ENCRYPTION_INFO_64 => {
1627                let comm = bytes.pread_with::<EncryptionInfoCommand64>(0, le)?;
1628                Ok((EncryptionInfo64(comm), size))
1629            }
1630            LC_DYLD_INFO => {
1631                let comm = bytes.pread_with::<DyldInfoCommand>(0, le)?;
1632                Ok((DyldInfo(comm), size))
1633            }
1634            LC_DYLD_INFO_ONLY => {
1635                let comm = bytes.pread_with::<DyldInfoCommand>(0, le)?;
1636                Ok((DyldInfoOnly(comm), size))
1637            }
1638            LC_LOAD_UPWARD_DYLIB => {
1639                let comm = bytes.pread_with::<DylibCommand>(0, le)?;
1640                Ok((LoadUpwardDylib(comm), size))
1641            }
1642            LC_VERSION_MIN_MACOSX => {
1643                let comm = bytes.pread_with::<VersionMinCommand>(0, le)?;
1644                Ok((VersionMinMacosx(comm), size))
1645            }
1646            LC_VERSION_MIN_IPHONEOS => {
1647                let comm = bytes.pread_with::<VersionMinCommand>(0, le)?;
1648                Ok((VersionMinIphoneos(comm), size))
1649            }
1650            LC_FUNCTION_STARTS => {
1651                let comm = bytes.pread_with::<LinkeditDataCommand>(0, le)?;
1652                Ok((FunctionStarts(comm), size))
1653            }
1654            LC_DYLD_ENVIRONMENT => {
1655                let comm = bytes.pread_with::<DylinkerCommand>(0, le)?;
1656                Ok((DyldEnvironment(comm), size))
1657            }
1658            LC_MAIN => {
1659                let comm = bytes.pread_with::<EntryPointCommand>(0, le)?;
1660                Ok((Main(comm), size))
1661            }
1662            LC_DATA_IN_CODE => {
1663                let comm = bytes.pread_with::<LinkeditDataCommand>(0, le)?;
1664                Ok((DataInCode(comm), size))
1665            }
1666            LC_BUILD_VERSION => {
1667                let comm = bytes.pread_with::<BuildVersionCommand>(0, le)?;
1668                Ok((BuildVersion(comm), size))
1669            }
1670            LC_FILESET_ENTRY => {
1671                let comm = bytes.pread_with::<FilesetEntryCommand>(0, le)?;
1672                Ok((FilesetEntry(comm), size))
1673            }
1674            LC_SOURCE_VERSION => {
1675                let comm = bytes.pread_with::<SourceVersionCommand>(0, le)?;
1676                Ok((SourceVersion(comm), size))
1677            }
1678            LC_DYLIB_CODE_SIGN_DRS => {
1679                let comm = bytes.pread_with::<LinkeditDataCommand>(0, le)?;
1680                Ok((DylibCodeSignDrs(comm), size))
1681            }
1682            LC_LINKER_OPTION => {
1683                let comm = bytes.pread_with::<LinkeditDataCommand>(0, le)?;
1684                Ok((LinkerOption(comm), size))
1685            }
1686            LC_LINKER_OPTIMIZATION_HINT => {
1687                let comm = bytes.pread_with::<LinkeditDataCommand>(0, le)?;
1688                Ok((LinkerOptimizationHint(comm), size))
1689            }
1690            LC_VERSION_MIN_TVOS => {
1691                let comm = bytes.pread_with::<VersionMinCommand>(0, le)?;
1692                Ok((VersionMinTvos(comm), size))
1693            }
1694            LC_VERSION_MIN_WATCHOS => {
1695                let comm = bytes.pread_with::<VersionMinCommand>(0, le)?;
1696                Ok((VersionMinWatchos(comm), size))
1697            }
1698            LC_DYLD_EXPORTS_TRIE => {
1699                let comm = bytes.pread_with::<LinkeditDataCommand>(0, le)?;
1700                Ok((DyldExportsTrie(comm), size))
1701            }
1702            LC_DYLD_CHAINED_FIXUPS => {
1703                let comm = bytes.pread_with::<LinkeditDataCommand>(0, le)?;
1704                Ok((DyldChainedFixups(comm), size))
1705            }
1706            LC_NOTE => {
1707                let comm = bytes.pread_with::<NoteCommand>(0, le)?;
1708                Ok((Note(comm), size))
1709            }
1710            _ => Ok((Unimplemented(lc), size)),
1711        }
1712    }
1713}
1714
1715impl CommandVariant {
1716    pub fn cmdsize(&self) -> usize {
1717        use self::CommandVariant::*;
1718        let cmdsize = match *self {
1719            Segment32(comm) => comm.cmdsize,
1720            Segment64(comm) => comm.cmdsize,
1721            Uuid(comm) => comm.cmdsize,
1722            Symtab(comm) => comm.cmdsize,
1723            Symseg(comm) => comm.cmdsize,
1724            Thread(comm) => comm.cmdsize,
1725            Unixthread(comm) => comm.cmdsize,
1726            LoadFvmlib(comm) => comm.cmdsize,
1727            IdFvmlib(comm) => comm.cmdsize,
1728            Ident(comm) => comm.cmdsize,
1729            Fvmfile(comm) => comm.cmdsize,
1730            Prepage(comm) => comm.cmdsize,
1731            Dysymtab(comm) => comm.cmdsize,
1732            LoadDylib(comm) => comm.cmdsize,
1733            IdDylib(comm) => comm.cmdsize,
1734            LoadDylinker(comm) => comm.cmdsize,
1735            IdDylinker(comm) => comm.cmdsize,
1736            PreboundDylib(comm) => comm.cmdsize,
1737            Routines32(comm) => comm.cmdsize,
1738            Routines64(comm) => comm.cmdsize,
1739            SubFramework(comm) => comm.cmdsize,
1740            SubUmbrella(comm) => comm.cmdsize,
1741            SubClient(comm) => comm.cmdsize,
1742            SubLibrary(comm) => comm.cmdsize,
1743            TwolevelHints(comm) => comm.cmdsize,
1744            PrebindCksum(comm) => comm.cmdsize,
1745            LoadWeakDylib(comm) => comm.cmdsize,
1746            Rpath(comm) => comm.cmdsize,
1747            CodeSignature(comm) => comm.cmdsize,
1748            SegmentSplitInfo(comm) => comm.cmdsize,
1749            ReexportDylib(comm) => comm.cmdsize,
1750            LazyLoadDylib(comm) => comm.cmdsize,
1751            EncryptionInfo32(comm) => comm.cmdsize,
1752            EncryptionInfo64(comm) => comm.cmdsize,
1753            DyldInfo(comm) => comm.cmdsize,
1754            DyldInfoOnly(comm) => comm.cmdsize,
1755            LoadUpwardDylib(comm) => comm.cmdsize,
1756            VersionMinMacosx(comm) => comm.cmdsize,
1757            VersionMinIphoneos(comm) => comm.cmdsize,
1758            FunctionStarts(comm) => comm.cmdsize,
1759            DyldEnvironment(comm) => comm.cmdsize,
1760            Main(comm) => comm.cmdsize,
1761            DataInCode(comm) => comm.cmdsize,
1762            BuildVersion(comm) => comm.cmdsize,
1763            FilesetEntry(comm) => comm.cmdsize,
1764            SourceVersion(comm) => comm.cmdsize,
1765            DylibCodeSignDrs(comm) => comm.cmdsize,
1766            LinkerOption(comm) => comm.cmdsize,
1767            LinkerOptimizationHint(comm) => comm.cmdsize,
1768            VersionMinTvos(comm) => comm.cmdsize,
1769            VersionMinWatchos(comm) => comm.cmdsize,
1770            DyldExportsTrie(comm) => comm.cmdsize,
1771            DyldChainedFixups(comm) => comm.cmdsize,
1772            Note(comm) => comm.cmdsize,
1773            Unimplemented(comm) => comm.cmdsize,
1774        };
1775        cmdsize as usize
1776    }
1777    pub fn cmd(&self) -> u32 {
1778        use self::CommandVariant::*;
1779        match *self {
1780            Segment32(comm) => comm.cmd,
1781            Segment64(comm) => comm.cmd,
1782            Uuid(comm) => comm.cmd,
1783            Symtab(comm) => comm.cmd,
1784            Symseg(comm) => comm.cmd,
1785            Thread(comm) => comm.cmd,
1786            Unixthread(comm) => comm.cmd,
1787            LoadFvmlib(comm) => comm.cmd,
1788            IdFvmlib(comm) => comm.cmd,
1789            Ident(comm) => comm.cmd,
1790            Fvmfile(comm) => comm.cmd,
1791            Prepage(comm) => comm.cmd,
1792            Dysymtab(comm) => comm.cmd,
1793            LoadDylib(comm) => comm.cmd,
1794            IdDylib(comm) => comm.cmd,
1795            LoadDylinker(comm) => comm.cmd,
1796            IdDylinker(comm) => comm.cmd,
1797            PreboundDylib(comm) => comm.cmd,
1798            Routines32(comm) => comm.cmd,
1799            Routines64(comm) => comm.cmd,
1800            SubFramework(comm) => comm.cmd,
1801            SubUmbrella(comm) => comm.cmd,
1802            SubClient(comm) => comm.cmd,
1803            SubLibrary(comm) => comm.cmd,
1804            TwolevelHints(comm) => comm.cmd,
1805            PrebindCksum(comm) => comm.cmd,
1806            LoadWeakDylib(comm) => comm.cmd,
1807            Rpath(comm) => comm.cmd,
1808            CodeSignature(comm) => comm.cmd,
1809            SegmentSplitInfo(comm) => comm.cmd,
1810            ReexportDylib(comm) => comm.cmd,
1811            LazyLoadDylib(comm) => comm.cmd,
1812            EncryptionInfo32(comm) => comm.cmd,
1813            EncryptionInfo64(comm) => comm.cmd,
1814            DyldInfo(comm) => comm.cmd,
1815            DyldInfoOnly(comm) => comm.cmd,
1816            LoadUpwardDylib(comm) => comm.cmd,
1817            VersionMinMacosx(comm) => comm.cmd,
1818            VersionMinIphoneos(comm) => comm.cmd,
1819            FunctionStarts(comm) => comm.cmd,
1820            DyldEnvironment(comm) => comm.cmd,
1821            Main(comm) => comm.cmd,
1822            DataInCode(comm) => comm.cmd,
1823            BuildVersion(comm) => comm.cmd,
1824            FilesetEntry(comm) => comm.cmd,
1825            SourceVersion(comm) => comm.cmd,
1826            DylibCodeSignDrs(comm) => comm.cmd,
1827            LinkerOption(comm) => comm.cmd,
1828            LinkerOptimizationHint(comm) => comm.cmd,
1829            VersionMinTvos(comm) => comm.cmd,
1830            VersionMinWatchos(comm) => comm.cmd,
1831            DyldExportsTrie(comm) => comm.cmd,
1832            DyldChainedFixups(comm) => comm.cmd,
1833            Note(comm) => comm.cmd,
1834            Unimplemented(comm) => comm.cmd,
1835        }
1836    }
1837}
1838
1839#[derive(Debug)]
1840/// A tagged LoadCommand union
1841pub struct LoadCommand {
1842    /// The offset this load command occurs at
1843    pub offset: usize,
1844    /// Which load command this is inside a variant
1845    pub command: CommandVariant,
1846}
1847
1848impl LoadCommand {
1849    /// Parse a load command from `bytes` at `offset` with the `le` endianness
1850    pub fn parse(bytes: &[u8], offset: &mut usize, le: scroll::Endian) -> error::Result<Self> {
1851        let start = *offset;
1852        let command = bytes.pread_with::<CommandVariant>(start, le)?;
1853        let size = command.cmdsize();
1854        *offset = start + size;
1855        Ok(LoadCommand {
1856            offset: start,
1857            command,
1858        })
1859    }
1860}