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 
3 use crate::error;
4 use core::convert::TryFrom;
5 use core::fmt::{self, Display};
6 use scroll::{ctx, Endian};
7 use 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
17 pub struct LoadCommandHeader {
18     pub cmd: u32,
19     pub cmdsize: u32,
20 }
21 
22 impl Display for LoadCommandHeader {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result23     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 
33 pub const SIZEOF_LOAD_COMMAND: usize = 8;
34 
35 pub type LcStr = u32;
36 
37 pub const SIZEOF_LC_STR: usize = 4;
38 
39 #[repr(C)]
40 #[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
41 pub 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 
66 pub 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)]
71 pub 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 
98 pub const SIZEOF_SECTION_64: usize = 80;
99 
100 #[repr(C)]
101 #[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
102 pub 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 
116 pub const SIZEOF_SEGMENT_COMMAND_32: usize = 56;
117 
118 impl SegmentCommand32 {
name(&self) -> error::Result<&str>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)]
126 pub 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 
140 pub const SIZEOF_SEGMENT_COMMAND_64: usize = 72;
141 
142 impl SegmentCommand64 {
name(&self) -> error::Result<&str>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)]
153 pub 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 
162 pub 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)]
171 pub 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 
180 pub 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)]
203 pub 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 
214 pub const SIZEOF_DYLIB: usize = 16;
215 
216 #[repr(C)]
217 #[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
218 pub 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 
227 pub 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)]
239 pub 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 
248 pub 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)]
259 pub 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 
268 pub 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)]
283 pub 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 
292 pub 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)]
309 pub 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 
318 pub 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)]
329 pub 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 
343 pub 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)]
348 pub struct DylinkerCommand {
349     pub cmd: u32,
350     pub cmdsize: u32,
351     pub name: LcStr,
352 }
353 
354 pub 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)]
382 pub 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 
398 impl ThreadCommand {
instruction_pointer(&self, cputype: super::cputype::CpuType) -> error::Result<u64>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 
501 impl<'a> ctx::TryFromCtx<'a, Endian> for ThreadCommand {
502     type Error = crate::error::Error;
try_from_ctx(bytes: &'a [u8], le: Endian) -> error::Result<(Self, usize)>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         // get a byte slice of the thread state
511         let thread_state_byte_length = count as usize * 4;
512         let thread_state_bytes = &bytes[16..16 + thread_state_byte_length];
513 
514         // check the length
515         if thread_state_bytes.len() < thread_state_byte_length {
516             return Err(error::Error::Malformed(format!(
517                 "thread command specifies {} bytes for thread state but has only {}",
518                 thread_state_byte_length,
519                 thread_state_bytes.len()
520             )));
521         }
522         if count > 70 {
523             return Err(error::Error::Malformed(format!(
524                 "thread command specifies {} longs for thread state but we handle only 70",
525                 count
526             )));
527         }
528 
529         // read the thread state
530         let mut thread_state: [u32; 70] = [0; 70];
531         for (i, state) in thread_state.iter_mut().enumerate().take(count as usize) {
532             *state = thread_state_bytes.pread_with(i * 4, le)?;
533         }
534 
535         Ok((
536             ThreadCommand {
537                 cmd: lc.cmd,
538                 cmdsize: lc.cmdsize,
539                 flavor,
540                 count,
541                 thread_state,
542             },
543             lc.cmdsize as _,
544         ))
545     }
546 }
547 
548 impl Clone for ThreadCommand {
clone(&self) -> Self549     fn clone(&self) -> Self {
550         *self
551     }
552 }
553 
554 impl fmt::Debug for ThreadCommand {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result555     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
556         fmt.debug_struct("ThreadCommand")
557             .field("cmd", &self.cmd)
558             .field("cmdsize", &self.cmdsize)
559             .field("flavor", &self.flavor)
560             .field("count", &self.count)
561             .field("thread_state", &&self.thread_state[..])
562             .finish()
563     }
564 }
565 
566 /// The routines command contains the address of the dynamic shared library
567 /// initialization routine and an index into the module table for the module
568 /// that defines the routine.  Before any modules are used from the library the
569 /// dynamic linker fully binds the module that defines the initialization routine
570 /// and then calls it.  This gets called before any module initialization
571 /// routines (used for C++ static constructors) in the library.
572 #[repr(C)]
573 #[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
574 pub struct RoutinesCommand32 {
575     /// LC_ROUTINES
576     pub cmd: u32,
577     /// total size of this command
578     pub cmdsize: u32,
579     /// address of initialization routine
580     pub init_address: u32,
581     /// index into the module table that the init routine is defined in
582     pub init_module: u32,
583     pub reserved1: u32,
584     pub reserved2: u32,
585     pub reserved3: u32,
586     pub reserved4: u32,
587     pub reserved5: u32,
588     pub reserved6: u32,
589 }
590 
591 /// The 64-bit routines command.  Same use as above.
592 #[repr(C)]
593 #[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
594 pub struct RoutinesCommand64 {
595     /// LC_ROUTINES_64
596     pub cmd: u32,
597     /// total size of this command
598     pub cmdsize: u32,
599     /// address of initialization routine
600     pub init_address: u64,
601     /// index into the module table that the init routine is defined in 8 bytes each
602     pub init_module: u64,
603     pub reserved1: u64,
604     pub reserved2: u64,
605     pub reserved3: u64,
606     pub reserved4: u64,
607     pub reserved5: u64,
608     pub reserved6: u64,
609 }
610 
611 #[repr(C)]
612 #[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
613 pub struct SymtabCommand {
614     pub cmd: u32,
615     pub cmdsize: u32,
616     pub symoff: u32,
617     pub nsyms: u32,
618     pub stroff: u32,
619     pub strsize: u32,
620 }
621 
622 impl Default for SymtabCommand {
default() -> Self623     fn default() -> Self {
624         SymtabCommand {
625             cmd: LC_SYMTAB,
626             cmdsize: SIZEOF_SYMTAB_COMMAND as u32,
627             symoff: 0,
628             nsyms: 0,
629             stroff: 0,
630             strsize: 0,
631         }
632     }
633 }
634 
635 impl SymtabCommand {
new() -> Self636     pub fn new() -> Self {
637         Default::default()
638     }
639 }
640 
641 pub const SIZEOF_SYMTAB_COMMAND: usize = 24;
642 
643 /// This is the second set of the symbolic information which is used to support
644 /// the data structures for the dynamically link editor.
645 ///
646 /// The original set of symbolic information in the symtab_command which contains
647 /// the symbol and string tables must also be present when this load command is
648 /// present.  When this load command is present the symbol table is organized
649 /// into three groups of symbols:
650 /// local symbols (static and debugging symbols) - grouped by module
651 /// defined external symbols - grouped by module (sorted by name if not lib)
652 /// undefined external symbols (sorted by name if MH_BINDATLOAD is not set,
653 ///             and in order the were seen by the static
654 ///        linker if MH_BINDATLOAD is set)
655 /// In this load command there are offsets and counts to each of the three groups
656 /// of symbols.
657 ///
658 /// This load command contains a the offsets and sizes of the following new
659 /// symbolic information tables:
660 /// table of contents
661 /// module table
662 /// reference symbol table
663 /// indirect symbol table
664 /// The first three tables above (the table of contents, module table and
665 /// reference symbol table) are only present if the file is a dynamically linked
666 /// shared library.  For executable and object modules, which are files
667 /// containing only one module, the information that would be in these three
668 /// tables is determined as follows:
669 ///  table of contents - the defined external symbols are sorted by name
670 /// module table - the file contains only one module so everything in the
671 ///         file is part of the module.
672 /// reference symbol table - is the defined and undefined external symbols
673 ///
674 /// For dynamically linked shared library files this load command also contains
675 /// offsets and sizes to the pool of relocation entries for all sections
676 /// separated into two groups:
677 /// external relocation entries
678 /// local relocation entries
679 /// For executable and object modules the relocation entries continue to hang
680 /// off the section structures.
681 #[repr(C)]
682 #[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
683 pub struct DysymtabCommand {
684     pub cmd: u32,
685     pub cmdsize: u32,
686     /// index to local symbols
687     pub ilocalsym: u32,
688     /// number of local symbols
689     pub nlocalsym: u32,
690     /// index to externally defined symbols
691     pub iextdefsym: u32,
692     /// number of externally defined symbols
693     pub nextdefsym: u32,
694     /// index to undefined symbols
695     pub iundefsym: u32,
696     /// number of undefined symbols
697     pub nundefsym: u32,
698     /// file offset to table of contents
699     pub tocoff: u32,
700     /// number of entries in table of contents
701     pub ntoc: u32,
702     /// file offset to module table
703     pub modtaboff: u32,
704     /// number of module table entries
705     pub nmodtab: u32,
706     /// offset to referenced symbol table
707     pub extrefsymoff: u32,
708     /// number of referenced symbol table entries
709     pub nextrefsyms: u32,
710     /// file offset to the indirect symbol table
711     pub indirectsymoff: u32,
712     /// number of indirect symbol table entries
713     pub nindirectsyms: u32,
714     /// offset to external relocation entries
715     pub extreloff: u32,
716     /// number of external relocation entries
717     pub nextrel: u32,
718     /// offset to local relocation entries
719     pub locreloff: u32,
720     /// number of local relocation entries
721     pub nlocrel: u32,
722 }
723 
724 impl Default for DysymtabCommand {
default() -> Self725     fn default() -> Self {
726         DysymtabCommand {
727             cmd: LC_DYSYMTAB,
728             cmdsize: SIZEOF_DYSYMTAB_COMMAND as u32,
729             ilocalsym: 0,
730             nlocalsym: 0,
731             iextdefsym: 0,
732             nextdefsym: 0,
733             iundefsym: 0,
734             nundefsym: 0,
735             tocoff: 0,
736             ntoc: 0,
737             modtaboff: 0,
738             nmodtab: 0,
739             extrefsymoff: 0,
740             nextrefsyms: 0,
741             indirectsymoff: 0,
742             nindirectsyms: 0,
743             extreloff: 0,
744             nextrel: 0,
745             locreloff: 0,
746             nlocrel: 0,
747         }
748     }
749 }
750 
751 impl DysymtabCommand {
new() -> Self752     pub fn new() -> Self {
753         Default::default()
754     }
755 }
756 
757 pub const SIZEOF_DYSYMTAB_COMMAND: usize = 80;
758 
759 // TODO: unimplemented
760 /// a table of contents entry
761 #[repr(C)]
762 #[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
763 pub struct DylibTableOfContents {
764     /// the defined external symbol (index into the symbol table)
765     pub symbol_index: u32,
766     /// index into the module table this symbol is defined in
767     pub module_index: u32,
768 }
769 
770 // TODO: unimplemented
771 /// a module table entry
772 #[repr(C)]
773 #[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
774 pub struct DylibModule {
775     /// the module name (index into string table)
776     pub module_name: u32,
777     ///index into externally defined symbols
778     pub iextdefsym: u32,
779     ///number of externally defined symbols
780     pub nextdefsym: u32,
781     /// index into reference symbol table
782     pub irefsym: u32,
783     ///number of reference symbol table entries
784     pub nrefsym: u32,
785     /// index into symbols for local symbols
786     pub ilocalsym: u32,
787     ///number of local symbols
788     pub nlocalsym: u32,
789 
790     /// index into external relocation entries
791     pub iextrel: u32,
792     /// number of external relocation entries
793     pub nextrel: u32,
794 
795     /// low 16 bits are the index into the init section, high 16 bits are the index into the term section
796     pub iinit_iterm: u32,
797     /// low 16 bits are the number of init section entries, high 16 bits are the number of term section entries
798     pub ninit_nterm: u32,
799     /// the (__OBJC,_module_info) section
800     pub objc_module_info_addr: u32,
801     /// the (__OBJC,__module_info) section
802     pub objc_module_info_size: u32,
803 }
804 
805 // TODO: unimplemented
806 /// a 64-bit module table entry
807 #[repr(C)]
808 #[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
809 pub struct DylibModule64 {
810     /// the module name (index into string table)
811     pub module_name: u32,
812 
813     /// index into externally defined symbols
814     pub iextdefsym: u32,
815     /// number of externally defined symbols
816     pub nextdefsym: u32,
817     /// index into reference symbol table
818     pub irefsym: u32,
819     /// number of reference symbol table entries
820     pub nrefsym: u32,
821     /// index into symbols for local symbols
822     pub ilocalsym: u32,
823     /// number of local symbols
824     pub nlocalsym: u32,
825 
826     /// index into external relocation entries
827     pub iextrel: u32,
828     /// number of external relocation entries
829     pub nextrel: u32,
830 
831     /// low 16 bits are the index into the init section, high 16 bits are the index into the term section
832     pub iinit_iterm: u32,
833     /// low 16 bits are the number of init section entries, high 16 bits are the number of term section entries
834     pub ninit_nterm: u32,
835 
836     /// the (__OBJC,__module_info) section
837     pub objc_module_info_size: u32,
838     /// the (__OBJC,__module_info) section
839     pub objc_module_info_addr: u64,
840 }
841 
842 /// The entries in the reference symbol table are used when loading the module
843 /// (both by the static and dynamic link editors) and if the module is unloaded
844 /// or replaced.  Therefore all external symbols (defined and undefined) are
845 /// listed in the module's reference table.  The flags describe the type of
846 /// reference that is being made.  The constants for the flags are defined in
847 /// <mach-o/nlist.h> as they are also used for symbol table entries.
848 #[repr(C)]
849 #[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
850 pub struct DylibReference {
851     /// 24 bits bit-field index into the symbol table
852     pub isym: [u8; 24],
853     /// flags to indicate the type of reference
854     pub flags: u64,
855 }
856 
857 /// The twolevel_hints_command contains the offset and number of hints in the
858 /// two-level namespace lookup hints table.
859 #[repr(C)]
860 #[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
861 pub struct TwolevelHintsCommand {
862     /// LC_TWOLEVEL_HINTS
863     pub cmd: u32,
864     /// sizeof(struct twolevel_hints_command)
865     pub cmdsize: u32,
866     /// offset to the hint table
867     pub offset: u32,
868     /// number of hints in the hint table
869     pub nhints: u32,
870 }
871 
872 /// The entries in the two-level namespace lookup hints table are twolevel_hint
873 /// structs.  These provide hints to the dynamic link editor where to start
874 /// looking for an undefined symbol in a two-level namespace image.  The
875 /// isub_image field is an index into the sub-images (sub-frameworks and
876 /// sub-umbrellas list) that made up the two-level image that the undefined
877 /// symbol was found in when it was built by the static link editor.  If
878 /// isub-image is 0 the the symbol is expected to be defined in library and not
879 /// in the sub-images.  If isub-image is non-zero it is an index into the array
880 /// of sub-images for the umbrella with the first index in the sub-images being
881 /// 1. The array of sub-images is the ordered list of sub-images of the umbrella
882 /// that would be searched for a symbol that has the umbrella recorded as its
883 /// primary library.  The table of contents index is an index into the
884 /// library's table of contents.  This is used as the starting point of the
885 /// binary search or a directed linear search.
886 #[repr(C)]
887 #[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
888 pub struct TwolevelHint {
889     /// index into the sub images
890     pub isub_image: u64,
891     /// 24 bit field index into the table of contents
892     pub itoc: [u8; 24],
893 }
894 
895 /// The prebind_cksum_command contains the value of the original check sum for
896 /// prebound files or zero.  When a prebound file is first created or modified
897 /// for other than updating its prebinding information the value of the check sum
898 /// is set to zero.  When the file has it prebinding re-done and if the value of
899 /// the check sum is zero the original check sum is calculated and stored in
900 /// cksum field of this load command in the output file.  If when the prebinding
901 /// is re-done and the cksum field is non-zero it is left unchanged from the
902 /// input file.
903 // TODO: unimplemented
904 #[repr(C)]
905 #[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
906 pub struct PrebindCksumCommand {
907     /// LC_PREBIND_CKSUM
908     pub cmd: u32,
909     /// sizeof(struct prebind_cksum_command)
910     pub cmdsize: u32,
911     /// the check sum or zero
912     pub cksum: u32,
913 }
914 
915 /// The uuid load command contains a single 128-bit unique random number that
916 /// identifies an object produced by the static link editor.
917 #[repr(C)]
918 #[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
919 pub struct UuidCommand {
920     /// LC_UUID
921     pub cmd: u32,
922     /// sizeof(struct uuid_command)
923     pub cmdsize: u32,
924     /// 16 bytes the 128-bit uuid
925     pub uuid: [u8; 16],
926 }
927 
928 pub const SIZEOF_UUID_COMMAND: usize = 24;
929 
930 /// The rpath_command contains a path which at runtime should be added to
931 /// the current run path used to find @rpath prefixed dylibs.
932 #[repr(C)]
933 #[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
934 pub struct RpathCommand {
935     /// LC_RPATH
936     pub cmd: u32,
937     /// includes string
938     pub cmdsize: u32,
939     /// path to add to run path
940     pub path: LcStr,
941 }
942 
943 pub const SIZEOF_RPATH_COMMAND: usize = 12;
944 
945 /// The linkedit_data_command contains the offsets and sizes of a blob
946 /// of data in the __LINKEDIT segment.
947 #[repr(C)]
948 #[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
949 pub struct LinkeditDataCommand {
950     /// LC_CODE_SIGNATURE, LC_SEGMENT_SPLIT_INFO, LC_FUNCTION_STARTS, LC_DATA_IN_CODE,
951     /// LC_DYLIB_CODE_SIGN_DRS, LC_LINKER_OPTIMIZATION_HINT, LC_DYLD_EXPORTS_TRIE, or LC_DYLD_CHAINED_FIXUPS.
952     pub cmd: u32,
953     /// sizeof(struct linkedit_data_command)
954     pub cmdsize: u32,
955     /// file offset of data in __LINKEDIT segment
956     pub dataoff: u32,
957     /// file size of data in __LINKEDIT segment
958     pub datasize: u32,
959 }
960 
961 pub const SIZEOF_LINKEDIT_DATA_COMMAND: usize = 16;
962 
963 /// The encryption_info_command contains the file offset and size of an
964 /// of an encrypted segment.
965 #[repr(C)]
966 #[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
967 pub struct EncryptionInfoCommand32 {
968     /// LC_ENCRYPTION_INFO
969     pub cmd: u32,
970     /// sizeof(struct encryption_info_command)
971     pub cmdsize: u32,
972     /// file offset of encrypted range
973     pub cryptoff: u32,
974     /// file size of encrypted range
975     pub cryptsize: u32,
976     /// which enryption system, 0 means not-encrypted yet
977     pub cryptid: u32,
978 }
979 
980 pub const SIZEOF_ENCRYPTION_INFO_COMMAND_32: usize = 20;
981 
982 /// The encryption_info_command_64 contains the file offset and size of an
983 /// of an encrypted segment (for use in x86_64 targets).
984 #[repr(C)]
985 #[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
986 pub struct EncryptionInfoCommand64 {
987     /// LC_ENCRYPTION_INFO_64
988     pub cmd: u32,
989     /// sizeof(struct encryption_info_command_64)
990     pub cmdsize: u32,
991     /// file offset of encrypted range
992     pub cryptoff: u32,
993     /// file size of encrypted range
994     pub cryptsize: u32,
995     /// which enryption system, 0 means not-encrypted yet
996     pub cryptid: u32,
997     /// padding to make this struct's size a multiple of 8 bytes
998     pub pad: u32,
999 }
1000 
1001 pub const SIZEOF_ENCRYPTION_INFO_COMMAND_64: usize = 24;
1002 
1003 /// An enumeration of platforms currently identifiable within a version_min_command.
1004 #[non_exhaustive]
1005 #[repr(u32)]
1006 #[derive(Debug)]
1007 pub enum Platform {
1008     Macos = LC_VERSION_MIN_MACOSX,
1009     Iphoneos = LC_VERSION_MIN_IPHONEOS,
1010     Tvos = LC_VERSION_MIN_TVOS,
1011     Watchos = LC_VERSION_MIN_WATCHOS,
1012 }
1013 
1014 impl TryFrom<u32> for Platform {
1015     type Error = error::Error;
1016 
try_from(cmd: u32) -> Result<Self, Self::Error>1017     fn try_from(cmd: u32) -> Result<Self, Self::Error> {
1018         Ok(match cmd {
1019             LC_VERSION_MIN_MACOSX => Platform::Macos,
1020             LC_VERSION_MIN_IPHONEOS => Platform::Iphoneos,
1021             LC_VERSION_MIN_TVOS => Platform::Tvos,
1022             LC_VERSION_MIN_WATCHOS => Platform::Watchos,
1023             _ => {
1024                 return Err(error::Error::Malformed(format!(
1025                     "unknown platform for load command: {:x}",
1026                     cmd
1027                 )))
1028             }
1029         })
1030     }
1031 }
1032 
1033 /// The version_min_command contains the min OS version on which this
1034 /// binary was built to run.
1035 ///
1036 #[repr(C)]
1037 #[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
1038 pub struct VersionMinCommand {
1039     /// LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS, LC_VERSION_MIN_TVOS, or LC_VERSION_MIN_WATCHOS.
1040     pub cmd: u32,
1041     pub cmdsize: u32,
1042     /// X.Y.Z is encoded in nibbles xxxx.yy.zz
1043     pub version: u32,
1044     /// X.Y.Z is encoded in nibbles xxxx.yy.zz
1045     pub sdk: u32,
1046 }
1047 
1048 impl VersionMinCommand {
new(platform: Platform) -> Self1049     pub fn new(platform: Platform) -> Self {
1050         VersionMinCommand {
1051             cmd: platform as u32,
1052             cmdsize: SIZEOF_VERSION_MIN_COMMAND as u32,
1053             version: 0,
1054             sdk: 0,
1055         }
1056     }
1057 
platform(&self) -> Platform1058     pub fn platform(&self) -> Platform {
1059         // A panic here indicates an incomplete API change above: VersionMinCommand
1060         // can only be constructed from one of the LC_VERSION_* commands or directly
1061         // from a Platform, so an error indicates that a new one hasn't been correctly
1062         // added to the Platform enum.
1063         Platform::try_from(self.cmd).expect("impossible platform (implementation error)")
1064     }
1065 }
1066 
1067 pub const SIZEOF_VERSION_MIN_COMMAND: usize = 16;
1068 
1069 #[repr(C)]
1070 #[derive(Default, Debug, Clone, Copy, Pread, Pwrite, SizeWith)]
1071 pub struct DyldInfoCommand {
1072     /// LC_DYLD_INFO or LC_DYLD_INFO_ONLY
1073     pub cmd: u32,
1074     /// sizeof(struct dyld_info_command)
1075     pub cmdsize: u32,
1076     /// file offset to rebase info
1077     pub rebase_off: u32,
1078     /// size of rebase info
1079     pub rebase_size: u32,
1080     /// file offset to binding info
1081     pub bind_off: u32,
1082     /// size of binding info
1083     pub bind_size: u32,
1084     /// file offset to weak binding info
1085     pub weak_bind_off: u32,
1086     /// size of weak binding info
1087     pub weak_bind_size: u32,
1088     /// file offset to lazy binding info
1089     pub lazy_bind_off: u32,
1090     /// size of lazy binding infs
1091     pub lazy_bind_size: u32,
1092     /// file offset to lazy binding info
1093     pub export_off: u32,
1094     /// size of lazy binding infs
1095     pub export_size: u32,
1096 }
1097 
1098 pub const SIZEOF_DYLIB_INFO_COMMAND: usize = 48;
1099 
1100 /// The linker_option_command contains linker options embedded in object files.
1101 #[repr(C)]
1102 #[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
1103 pub struct LinkerOptionCommand {
1104     /// LC_LINKER_OPTION only used in MH_OBJECT fipub constypes
1105     pub cmd: u32,
1106     pub cmdsize: u32,
1107     /// number of strings concatenation of zero terminated UTF8 strings. Zero filled at end to align
1108     pub count: u32,
1109 }
1110 
1111 pub const SIZEOF_LINKER_OPTION_COMMAND: usize = 12;
1112 
1113 /// The symseg_command contains the offset and size of the GNU style
1114 /// symbol table information as described in the header file <symseg.h>.
1115 /// The symbol roots of the symbol segments must also be aligned properly
1116 /// in the file.  So the requirement of keeping the offsets aligned to a
1117 /// multiple of a 4 bytes translates to the length field of the symbol
1118 /// roots also being a multiple of a long.  Also the padding must again be
1119 /// zeroed. (THIS IS OBSOLETE and no longer supported).
1120 #[repr(C)]
1121 #[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
1122 pub struct SymsegCommand {
1123     /// LC_SYMSEG
1124     pub cmd: u32,
1125     /// sizeof(struct symseg_command)
1126     pub cmdsize: u32,
1127     /// symbol segment offset
1128     pub offset: u32,
1129     /// symbol segment size in bytes
1130     pub size: u32,
1131 }
1132 
1133 pub const SIZEOF_SYMSEG_COMMAND: usize = 16;
1134 
1135 /// The ident_command contains a free format string table following the
1136 /// ident_command structure.  The strings are null terminated and the size of
1137 /// the command is padded out with zero bytes to a multiple of 4 bytes/
1138 /// (THIS IS OBSOLETE and no longer supported).
1139 #[repr(C)]
1140 #[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
1141 pub struct IdentCommand {
1142     /// LC_IDENT
1143     pub cmd: u32,
1144     /// strings that follow this command
1145     pub cmdsize: u32,
1146 }
1147 
1148 pub const SIZEOF_IDENT_COMMAND: usize = 8;
1149 
1150 /// The fvmfile_command contains a reference to a file to be loaded at the
1151 /// specified virtual address.  (Presently, this command is reserved for
1152 /// internal use.  The kernel ignores this command when loading a program into
1153 /// memory).
1154 #[repr(C)]
1155 #[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
1156 pub struct FvmfileCommand {
1157     /// LC_FVMFILE
1158     pub cmd: u32,
1159     /// includes pathname string
1160     pub cmdsize: u32,
1161     /// files pathname
1162     pub name: LcStr,
1163     /// files virtual address
1164     pub header_addr: u32,
1165 }
1166 
1167 pub const SIZEOF_FVMFILE_COMMAND: usize = 16;
1168 
1169 /// The entry_point_command is a replacement for thread_command.
1170 /// It is used for main executables to specify the location (file offset)
1171 /// of main().  If -stack_size was used at link time, the stacksize
1172 /// field will contain the stack size need for the main thread.
1173 #[repr(C)]
1174 #[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
1175 pub struct EntryPointCommand {
1176     pub cmd: u32,
1177     pub cmdsize: u32,
1178     /// uint64_t file __TEXT offset of main
1179     pub entryoff: u64,
1180     /// uint64_t if not zero, initial stack size
1181     pub stacksize: u64,
1182 }
1183 
1184 pub const SIZEOF_ENTRY_POINT_COMMAND: usize = 24;
1185 
1186 /// The source_version_command is an optional load command containing
1187 /// the version of the sources used to build the binary.
1188 #[repr(C)]
1189 #[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
1190 pub struct SourceVersionCommand {
1191     /// LC_SOURCE_VERSION
1192     pub cmd: u32,
1193     pub cmdsize: u32,
1194     /// A.B.C.D.E packed as a24.b10.c10.d10.e10
1195     pub version: u64,
1196 }
1197 
1198 /// The LC_DATA_IN_CODE load commands uses a linkedit_data_command
1199 /// to point to an array of data_in_code_entry entries. Each entry
1200 /// describes a range of data in a code section.
1201 #[repr(C)]
1202 #[derive(Debug, Clone, Copy, Pread, Pwrite, IOread, IOwrite, SizeWith)]
1203 pub struct DataInCodeEntry {
1204     /// from mach_header to start of data range
1205     pub offset: u32,
1206     /// number of bytes in data range
1207     pub length: u16,
1208     /// a DICE_KIND_* value
1209     pub kind: u16,
1210 }
1211 
1212 ///////////////////////////////////////
1213 // Constants, et. al
1214 ///////////////////////////////////////
1215 
1216 pub const LC_REQ_DYLD: u32 = 0x8000_0000;
1217 pub const LC_LOAD_WEAK_DYLIB: u32 = 0x18 | LC_REQ_DYLD;
1218 pub const LC_RPATH: u32 = 0x1c | LC_REQ_DYLD;
1219 pub const LC_REEXPORT_DYLIB: u32 = 0x1f | LC_REQ_DYLD;
1220 pub const LC_DYLD_INFO_ONLY: u32 = 0x22 | LC_REQ_DYLD;
1221 pub const LC_LOAD_UPWARD_DYLIB: u32 = 0x23 | LC_REQ_DYLD;
1222 pub const LC_MAIN: u32 = 0x28 | LC_REQ_DYLD;
1223 pub const LC_DYLD_EXPORTS_TRIE: u32 = 0x33 | LC_REQ_DYLD;
1224 pub const LC_DYLD_CHAINED_FIXUPS: u32 = 0x34 | LC_REQ_DYLD;
1225 pub const LC_SEGMENT: u32 = 0x1;
1226 pub const LC_SYMTAB: u32 = 0x2;
1227 pub const LC_SYMSEG: u32 = 0x3;
1228 pub const LC_THREAD: u32 = 0x4;
1229 pub const LC_UNIXTHREAD: u32 = 0x5;
1230 pub const LC_LOADFVMLIB: u32 = 0x6;
1231 pub const LC_IDFVMLIB: u32 = 0x7;
1232 pub const LC_IDENT: u32 = 0x8;
1233 pub const LC_FVMFILE: u32 = 0x9;
1234 pub const LC_PREPAGE: u32 = 0xa;
1235 pub const LC_DYSYMTAB: u32 = 0xb;
1236 pub const LC_LOAD_DYLIB: u32 = 0xc;
1237 pub const LC_ID_DYLIB: u32 = 0xd;
1238 pub const LC_LOAD_DYLINKER: u32 = 0xe;
1239 pub const LC_ID_DYLINKER: u32 = 0xf;
1240 pub const LC_PREBOUND_DYLIB: u32 = 0x10;
1241 pub const LC_ROUTINES: u32 = 0x11;
1242 pub const LC_SUB_FRAMEWORK: u32 = 0x12;
1243 pub const LC_SUB_UMBRELLA: u32 = 0x13;
1244 pub const LC_SUB_CLIENT: u32 = 0x14;
1245 pub const LC_SUB_LIBRARY: u32 = 0x15;
1246 pub const LC_TWOLEVEL_HINTS: u32 = 0x16;
1247 pub const LC_PREBIND_CKSUM: u32 = 0x17;
1248 pub const LC_SEGMENT_64: u32 = 0x19;
1249 pub const LC_ROUTINES_64: u32 = 0x1a;
1250 pub const LC_UUID: u32 = 0x1b;
1251 pub const LC_CODE_SIGNATURE: u32 = 0x1d;
1252 pub const LC_SEGMENT_SPLIT_INFO: u32 = 0x1e;
1253 pub const LC_LAZY_LOAD_DYLIB: u32 = 0x20;
1254 pub const LC_ENCRYPTION_INFO: u32 = 0x21;
1255 pub const LC_DYLD_INFO: u32 = 0x22;
1256 pub const LC_VERSION_MIN_MACOSX: u32 = 0x24;
1257 pub const LC_VERSION_MIN_IPHONEOS: u32 = 0x25;
1258 pub const LC_FUNCTION_STARTS: u32 = 0x26;
1259 pub const LC_DYLD_ENVIRONMENT: u32 = 0x27;
1260 pub const LC_DATA_IN_CODE: u32 = 0x29;
1261 pub const LC_SOURCE_VERSION: u32 = 0x2A;
1262 pub const LC_DYLIB_CODE_SIGN_DRS: u32 = 0x2B;
1263 pub const LC_ENCRYPTION_INFO_64: u32 = 0x2C;
1264 pub const LC_LINKER_OPTION: u32 = 0x2D;
1265 pub const LC_LINKER_OPTIMIZATION_HINT: u32 = 0x2E;
1266 pub const LC_VERSION_MIN_TVOS: u32 = 0x2F;
1267 pub const LC_VERSION_MIN_WATCHOS: u32 = 0x30;
1268 pub const LC_NOTE: u32 = 0x31;
1269 pub const LC_BUILD_VERSION: u32 = 0x32;
1270 
cmd_to_str(cmd: u32) -> &'static str1271 pub fn cmd_to_str(cmd: u32) -> &'static str {
1272     match cmd {
1273         LC_SEGMENT => "LC_SEGMENT",
1274         LC_SYMTAB => "LC_SYMTAB",
1275         LC_SYMSEG => "LC_SYMSEG",
1276         LC_THREAD => "LC_THREAD",
1277         LC_UNIXTHREAD => "LC_UNIXTHREAD",
1278         LC_LOADFVMLIB => "LC_LOADFVMLIB",
1279         LC_IDFVMLIB => "LC_IDFVMLIB",
1280         LC_IDENT => "LC_IDENT",
1281         LC_FVMFILE => "LC_FVMFILE",
1282         LC_PREPAGE => "LC_PREPAGE",
1283         LC_DYSYMTAB => "LC_DYSYMTAB",
1284         LC_LOAD_DYLIB => "LC_LOAD_DYLIB",
1285         LC_ID_DYLIB => "LC_ID_DYLIB",
1286         LC_LOAD_DYLINKER => "LC_LOAD_DYLINKER",
1287         LC_ID_DYLINKER => "LC_ID_DYLINKER",
1288         LC_PREBOUND_DYLIB => "LC_PREBOUND_DYLIB",
1289         LC_ROUTINES => "LC_ROUTINES",
1290         LC_SUB_FRAMEWORK => "LC_SUB_FRAMEWORK",
1291         LC_SUB_UMBRELLA => "LC_SUB_UMBRELLA",
1292         LC_SUB_CLIENT => "LC_SUB_CLIENT",
1293         LC_SUB_LIBRARY => "LC_SUB_LIBRARY",
1294         LC_TWOLEVEL_HINTS => "LC_TWOLEVEL_HINTS",
1295         LC_PREBIND_CKSUM => "LC_PREBIND_CKSUM",
1296         LC_LOAD_WEAK_DYLIB => "LC_LOAD_WEAK_DYLIB",
1297         LC_SEGMENT_64 => "LC_SEGMENT_64",
1298         LC_ROUTINES_64 => "LC_ROUTINES_64",
1299         LC_UUID => "LC_UUID",
1300         LC_RPATH => "LC_RPATH",
1301         LC_CODE_SIGNATURE => "LC_CODE_SIGNATURE",
1302         LC_SEGMENT_SPLIT_INFO => "LC_SEGMENT_SPLIT_INFO",
1303         LC_REEXPORT_DYLIB => "LC_REEXPORT_DYLIB",
1304         LC_LAZY_LOAD_DYLIB => "LC_LAZY_LOAD_DYLIB",
1305         LC_ENCRYPTION_INFO => "LC_ENCRYPTION_INFO",
1306         LC_DYLD_INFO => "LC_DYLD_INFO",
1307         LC_DYLD_INFO_ONLY => "LC_DYLD_INFO_ONLY",
1308         LC_LOAD_UPWARD_DYLIB => "LC_LOAD_UPWARD_DYLIB",
1309         LC_VERSION_MIN_MACOSX => "LC_VERSION_MIN_MACOSX",
1310         LC_VERSION_MIN_IPHONEOS => "LC_VERSION_MIN_IPHONEOS",
1311         LC_FUNCTION_STARTS => "LC_FUNCTION_STARTS",
1312         LC_DYLD_ENVIRONMENT => "LC_DYLD_ENVIRONMENT",
1313         LC_MAIN => "LC_MAIN",
1314         LC_DATA_IN_CODE => "LC_DATA_IN_CODE",
1315         LC_SOURCE_VERSION => "LC_SOURCE_VERSION",
1316         LC_DYLIB_CODE_SIGN_DRS => "LC_DYLIB_CODE_SIGN_DRS",
1317         LC_ENCRYPTION_INFO_64 => "LC_ENCRYPTION_INFO_64",
1318         LC_LINKER_OPTION => "LC_LINKER_OPTION",
1319         LC_LINKER_OPTIMIZATION_HINT => "LC_LINKER_OPTIMIZATION_HINT",
1320         LC_VERSION_MIN_TVOS => "LC_VERSION_MIN_TVOS",
1321         LC_VERSION_MIN_WATCHOS => "LC_VERSION_MIN_WATCHOS",
1322         LC_NOTE => "LC_NOTE",
1323         LC_BUILD_VERSION => "LC_BUILD_VERSION",
1324         LC_DYLD_EXPORTS_TRIE => "LC_DYLD_EXPORTS_TRIE",
1325         LC_DYLD_CHAINED_FIXUPS => "LC_DYLD_CHAINED_FIXUPS",
1326         _ => "LC_UNKNOWN",
1327     }
1328 }
1329 
1330 ///////////////////////////////////////////
1331 // Typesafe Command Variants
1332 ///////////////////////////////////////////
1333 
1334 #[derive(Debug)]
1335 #[allow(clippy::large_enum_variant)]
1336 /// The various load commands as a cast-free variant/enum
1337 pub enum CommandVariant {
1338     Segment32(SegmentCommand32),
1339     Segment64(SegmentCommand64),
1340     Uuid(UuidCommand),
1341     Symtab(SymtabCommand),
1342     Symseg(SymsegCommand),
1343     Thread(ThreadCommand),
1344     Unixthread(ThreadCommand),
1345     LoadFvmlib(FvmlibCommand),
1346     IdFvmlib(FvmlibCommand),
1347     Ident(IdentCommand),
1348     Fvmfile(FvmfileCommand),
1349     Prepage(LoadCommandHeader),
1350     Dysymtab(DysymtabCommand),
1351     LoadDylib(DylibCommand),
1352     IdDylib(DylibCommand),
1353     LoadDylinker(DylinkerCommand),
1354     IdDylinker(DylinkerCommand),
1355     PreboundDylib(PreboundDylibCommand),
1356     Routines32(RoutinesCommand32),
1357     Routines64(RoutinesCommand64),
1358     SubFramework(SubFrameworkCommand),
1359     SubUmbrella(SubUmbrellaCommand),
1360     SubClient(SubClientCommand),
1361     SubLibrary(SubLibraryCommand),
1362     TwolevelHints(TwolevelHintsCommand),
1363     PrebindCksum(PrebindCksumCommand),
1364     LoadWeakDylib(DylibCommand),
1365     Rpath(RpathCommand),
1366     CodeSignature(LinkeditDataCommand),
1367     SegmentSplitInfo(LinkeditDataCommand),
1368     ReexportDylib(DylibCommand),
1369     LazyLoadDylib(DylibCommand),
1370     EncryptionInfo32(EncryptionInfoCommand32),
1371     EncryptionInfo64(EncryptionInfoCommand64),
1372     DyldInfo(DyldInfoCommand),
1373     DyldInfoOnly(DyldInfoCommand),
1374     LoadUpwardDylib(DylibCommand),
1375     VersionMinMacosx(VersionMinCommand),
1376     VersionMinIphoneos(VersionMinCommand),
1377     FunctionStarts(LinkeditDataCommand),
1378     DyldEnvironment(DylinkerCommand),
1379     Main(EntryPointCommand),
1380     DataInCode(LinkeditDataCommand),
1381     SourceVersion(SourceVersionCommand),
1382     DylibCodeSignDrs(LinkeditDataCommand),
1383     LinkerOption(LinkeditDataCommand),
1384     LinkerOptimizationHint(LinkeditDataCommand),
1385     VersionMinTvos(VersionMinCommand),
1386     VersionMinWatchos(VersionMinCommand),
1387     DyldExportsTrie(LinkeditDataCommand),
1388     DyldChainedFixups(LinkeditDataCommand),
1389     Unimplemented(LoadCommandHeader),
1390 }
1391 
1392 impl<'a> ctx::TryFromCtx<'a, Endian> for CommandVariant {
1393     type Error = crate::error::Error;
try_from_ctx(bytes: &'a [u8], le: Endian) -> error::Result<(Self, usize)>1394     fn try_from_ctx(bytes: &'a [u8], le: Endian) -> error::Result<(Self, usize)> {
1395         use self::CommandVariant::*;
1396         let lc = bytes.pread_with::<LoadCommandHeader>(0, le)?;
1397         let size = lc.cmdsize as usize;
1398         //println!("offset {:#x} cmd: {:#x} size: {:?} ctx: {:?}", offset, lc.cmd, size, le);
1399         if size > bytes.len() {
1400             return Err(error::Error::Malformed(format!(
1401                 "{} has size larger than remainder of binary: {:?}",
1402                 &lc,
1403                 bytes.len()
1404             )));
1405         }
1406         match lc.cmd {
1407             LC_SEGMENT => {
1408                 let comm = bytes.pread_with::<SegmentCommand32>(0, le)?;
1409                 Ok((Segment32(comm), size))
1410             }
1411             LC_SEGMENT_64 => {
1412                 let comm = bytes.pread_with::<SegmentCommand64>(0, le)?;
1413                 Ok((Segment64(comm), size))
1414             }
1415             LC_DYSYMTAB => {
1416                 let comm = bytes.pread_with::<DysymtabCommand>(0, le)?;
1417                 Ok((Dysymtab(comm), size))
1418             }
1419             LC_LOAD_DYLINKER => {
1420                 let comm = bytes.pread_with::<DylinkerCommand>(0, le)?;
1421                 Ok((LoadDylinker(comm), size))
1422             }
1423             LC_ID_DYLINKER => {
1424                 let comm = bytes.pread_with::<DylinkerCommand>(0, le)?;
1425                 Ok((IdDylinker(comm), size))
1426             }
1427             LC_UUID => {
1428                 let comm = bytes.pread_with::<UuidCommand>(0, le)?;
1429                 Ok((Uuid(comm), size))
1430             }
1431             LC_SYMTAB => {
1432                 let comm = bytes.pread_with::<SymtabCommand>(0, le)?;
1433                 Ok((Symtab(comm), size))
1434             }
1435             LC_SYMSEG => {
1436                 let comm = bytes.pread_with::<SymsegCommand>(0, le)?;
1437                 Ok((Symseg(comm), size))
1438             }
1439             LC_THREAD => {
1440                 let comm = bytes.pread_with::<ThreadCommand>(0, le)?;
1441                 Ok((Thread(comm), size))
1442             }
1443             LC_UNIXTHREAD => {
1444                 let comm = bytes.pread_with::<ThreadCommand>(0, le)?;
1445                 Ok((Unixthread(comm), size))
1446             }
1447             LC_LOADFVMLIB => {
1448                 let comm = bytes.pread_with::<FvmlibCommand>(0, le)?;
1449                 Ok((LoadFvmlib(comm), size))
1450             }
1451             LC_IDFVMLIB => {
1452                 let comm = bytes.pread_with::<FvmlibCommand>(0, le)?;
1453                 Ok((IdFvmlib(comm), size))
1454             }
1455             LC_IDENT => {
1456                 let comm = bytes.pread_with::<IdentCommand>(0, le)?;
1457                 Ok((Ident(comm), size))
1458             }
1459             LC_FVMFILE => {
1460                 let comm = bytes.pread_with::<FvmfileCommand>(0, le)?;
1461                 Ok((Fvmfile(comm), size))
1462             }
1463             LC_PREPAGE => {
1464                 let comm = bytes.pread_with::<LoadCommandHeader>(0, le)?;
1465                 Ok((Prepage(comm), size))
1466             }
1467             LC_LOAD_DYLIB => {
1468                 let comm = bytes.pread_with::<DylibCommand>(0, le)?;
1469                 Ok((LoadDylib(comm), size))
1470             }
1471             LC_ID_DYLIB => {
1472                 let comm = bytes.pread_with::<DylibCommand>(0, le)?;
1473                 Ok((IdDylib(comm), size))
1474             }
1475             LC_PREBOUND_DYLIB => {
1476                 let comm = bytes.pread_with::<PreboundDylibCommand>(0, le)?;
1477                 Ok((PreboundDylib(comm), size))
1478             }
1479             LC_ROUTINES => {
1480                 let comm = bytes.pread_with::<RoutinesCommand32>(0, le)?;
1481                 Ok((Routines32(comm), size))
1482             }
1483             LC_ROUTINES_64 => {
1484                 let comm = bytes.pread_with::<RoutinesCommand64>(0, le)?;
1485                 Ok((Routines64(comm), size))
1486             }
1487             LC_SUB_FRAMEWORK => {
1488                 let comm = bytes.pread_with::<SubFrameworkCommand>(0, le)?;
1489                 Ok((SubFramework(comm), size))
1490             }
1491             LC_SUB_UMBRELLA => {
1492                 let comm = bytes.pread_with::<SubUmbrellaCommand>(0, le)?;
1493                 Ok((SubUmbrella(comm), size))
1494             }
1495             LC_SUB_CLIENT => {
1496                 let comm = bytes.pread_with::<SubClientCommand>(0, le)?;
1497                 Ok((SubClient(comm), size))
1498             }
1499             LC_SUB_LIBRARY => {
1500                 let comm = bytes.pread_with::<SubLibraryCommand>(0, le)?;
1501                 Ok((SubLibrary(comm), size))
1502             }
1503             LC_TWOLEVEL_HINTS => {
1504                 let comm = bytes.pread_with::<TwolevelHintsCommand>(0, le)?;
1505                 Ok((TwolevelHints(comm), size))
1506             }
1507             LC_PREBIND_CKSUM => {
1508                 let comm = bytes.pread_with::<PrebindCksumCommand>(0, le)?;
1509                 Ok((PrebindCksum(comm), size))
1510             }
1511             LC_LOAD_WEAK_DYLIB => {
1512                 let comm = bytes.pread_with::<DylibCommand>(0, le)?;
1513                 Ok((LoadWeakDylib(comm), size))
1514             }
1515             LC_RPATH => {
1516                 let comm = bytes.pread_with::<RpathCommand>(0, le)?;
1517                 Ok((Rpath(comm), size))
1518             }
1519             LC_CODE_SIGNATURE => {
1520                 let comm = bytes.pread_with::<LinkeditDataCommand>(0, le)?;
1521                 Ok((CodeSignature(comm), size))
1522             }
1523             LC_SEGMENT_SPLIT_INFO => {
1524                 let comm = bytes.pread_with::<LinkeditDataCommand>(0, le)?;
1525                 Ok((SegmentSplitInfo(comm), size))
1526             }
1527             LC_REEXPORT_DYLIB => {
1528                 let comm = bytes.pread_with::<DylibCommand>(0, le)?;
1529                 Ok((ReexportDylib(comm), size))
1530             }
1531             LC_LAZY_LOAD_DYLIB => {
1532                 let comm = bytes.pread_with::<DylibCommand>(0, le)?;
1533                 Ok((LazyLoadDylib(comm), size))
1534             }
1535             LC_ENCRYPTION_INFO => {
1536                 let comm = bytes.pread_with::<EncryptionInfoCommand32>(0, le)?;
1537                 Ok((EncryptionInfo32(comm), size))
1538             }
1539             LC_ENCRYPTION_INFO_64 => {
1540                 let comm = bytes.pread_with::<EncryptionInfoCommand64>(0, le)?;
1541                 Ok((EncryptionInfo64(comm), size))
1542             }
1543             LC_DYLD_INFO => {
1544                 let comm = bytes.pread_with::<DyldInfoCommand>(0, le)?;
1545                 Ok((DyldInfo(comm), size))
1546             }
1547             LC_DYLD_INFO_ONLY => {
1548                 let comm = bytes.pread_with::<DyldInfoCommand>(0, le)?;
1549                 Ok((DyldInfoOnly(comm), size))
1550             }
1551             LC_LOAD_UPWARD_DYLIB => {
1552                 let comm = bytes.pread_with::<DylibCommand>(0, le)?;
1553                 Ok((LoadUpwardDylib(comm), size))
1554             }
1555             LC_VERSION_MIN_MACOSX => {
1556                 let comm = bytes.pread_with::<VersionMinCommand>(0, le)?;
1557                 Ok((VersionMinMacosx(comm), size))
1558             }
1559             LC_VERSION_MIN_IPHONEOS => {
1560                 let comm = bytes.pread_with::<VersionMinCommand>(0, le)?;
1561                 Ok((VersionMinIphoneos(comm), size))
1562             }
1563             LC_FUNCTION_STARTS => {
1564                 let comm = bytes.pread_with::<LinkeditDataCommand>(0, le)?;
1565                 Ok((FunctionStarts(comm), size))
1566             }
1567             LC_DYLD_ENVIRONMENT => {
1568                 let comm = bytes.pread_with::<DylinkerCommand>(0, le)?;
1569                 Ok((DyldEnvironment(comm), size))
1570             }
1571             LC_MAIN => {
1572                 let comm = bytes.pread_with::<EntryPointCommand>(0, le)?;
1573                 Ok((Main(comm), size))
1574             }
1575             LC_DATA_IN_CODE => {
1576                 let comm = bytes.pread_with::<LinkeditDataCommand>(0, le)?;
1577                 Ok((DataInCode(comm), size))
1578             }
1579             LC_SOURCE_VERSION => {
1580                 let comm = bytes.pread_with::<SourceVersionCommand>(0, le)?;
1581                 Ok((SourceVersion(comm), size))
1582             }
1583             LC_DYLIB_CODE_SIGN_DRS => {
1584                 let comm = bytes.pread_with::<LinkeditDataCommand>(0, le)?;
1585                 Ok((DylibCodeSignDrs(comm), size))
1586             }
1587             LC_LINKER_OPTION => {
1588                 let comm = bytes.pread_with::<LinkeditDataCommand>(0, le)?;
1589                 Ok((LinkerOption(comm), size))
1590             }
1591             LC_LINKER_OPTIMIZATION_HINT => {
1592                 let comm = bytes.pread_with::<LinkeditDataCommand>(0, le)?;
1593                 Ok((LinkerOptimizationHint(comm), size))
1594             }
1595             LC_VERSION_MIN_TVOS => {
1596                 let comm = bytes.pread_with::<VersionMinCommand>(0, le)?;
1597                 Ok((VersionMinTvos(comm), size))
1598             }
1599             LC_VERSION_MIN_WATCHOS => {
1600                 let comm = bytes.pread_with::<VersionMinCommand>(0, le)?;
1601                 Ok((VersionMinWatchos(comm), size))
1602             }
1603             LC_DYLD_EXPORTS_TRIE => {
1604                 let comm = bytes.pread_with::<LinkeditDataCommand>(0, le)?;
1605                 Ok((DyldExportsTrie(comm), size))
1606             }
1607             LC_DYLD_CHAINED_FIXUPS => {
1608                 let comm = bytes.pread_with::<LinkeditDataCommand>(0, le)?;
1609                 Ok((DyldChainedFixups(comm), size))
1610             }
1611             // TODO: LC_NOTE (NoteCommand) and LC_BUILD_VERSION (BuildVersionCommand)
1612             // are unimplemented.
1613             LC_NOTE | LC_BUILD_VERSION | _ => Ok((Unimplemented(lc), size)),
1614         }
1615     }
1616 }
1617 
1618 impl CommandVariant {
cmdsize(&self) -> usize1619     pub fn cmdsize(&self) -> usize {
1620         use self::CommandVariant::*;
1621         let cmdsize = match *self {
1622             Segment32(comm) => comm.cmdsize,
1623             Segment64(comm) => comm.cmdsize,
1624             Uuid(comm) => comm.cmdsize,
1625             Symtab(comm) => comm.cmdsize,
1626             Symseg(comm) => comm.cmdsize,
1627             Thread(comm) => comm.cmdsize,
1628             Unixthread(comm) => comm.cmdsize,
1629             LoadFvmlib(comm) => comm.cmdsize,
1630             IdFvmlib(comm) => comm.cmdsize,
1631             Ident(comm) => comm.cmdsize,
1632             Fvmfile(comm) => comm.cmdsize,
1633             Prepage(comm) => comm.cmdsize,
1634             Dysymtab(comm) => comm.cmdsize,
1635             LoadDylib(comm) => comm.cmdsize,
1636             IdDylib(comm) => comm.cmdsize,
1637             LoadDylinker(comm) => comm.cmdsize,
1638             IdDylinker(comm) => comm.cmdsize,
1639             PreboundDylib(comm) => comm.cmdsize,
1640             Routines32(comm) => comm.cmdsize,
1641             Routines64(comm) => comm.cmdsize,
1642             SubFramework(comm) => comm.cmdsize,
1643             SubUmbrella(comm) => comm.cmdsize,
1644             SubClient(comm) => comm.cmdsize,
1645             SubLibrary(comm) => comm.cmdsize,
1646             TwolevelHints(comm) => comm.cmdsize,
1647             PrebindCksum(comm) => comm.cmdsize,
1648             LoadWeakDylib(comm) => comm.cmdsize,
1649             Rpath(comm) => comm.cmdsize,
1650             CodeSignature(comm) => comm.cmdsize,
1651             SegmentSplitInfo(comm) => comm.cmdsize,
1652             ReexportDylib(comm) => comm.cmdsize,
1653             LazyLoadDylib(comm) => comm.cmdsize,
1654             EncryptionInfo32(comm) => comm.cmdsize,
1655             EncryptionInfo64(comm) => comm.cmdsize,
1656             DyldInfo(comm) => comm.cmdsize,
1657             DyldInfoOnly(comm) => comm.cmdsize,
1658             LoadUpwardDylib(comm) => comm.cmdsize,
1659             VersionMinMacosx(comm) => comm.cmdsize,
1660             VersionMinIphoneos(comm) => comm.cmdsize,
1661             FunctionStarts(comm) => comm.cmdsize,
1662             DyldEnvironment(comm) => comm.cmdsize,
1663             Main(comm) => comm.cmdsize,
1664             DataInCode(comm) => comm.cmdsize,
1665             SourceVersion(comm) => comm.cmdsize,
1666             DylibCodeSignDrs(comm) => comm.cmdsize,
1667             LinkerOption(comm) => comm.cmdsize,
1668             LinkerOptimizationHint(comm) => comm.cmdsize,
1669             VersionMinTvos(comm) => comm.cmdsize,
1670             VersionMinWatchos(comm) => comm.cmdsize,
1671             DyldExportsTrie(comm) => comm.cmdsize,
1672             DyldChainedFixups(comm) => comm.cmdsize,
1673             Unimplemented(comm) => comm.cmdsize,
1674         };
1675         cmdsize as usize
1676     }
cmd(&self) -> u321677     pub fn cmd(&self) -> u32 {
1678         use self::CommandVariant::*;
1679         match *self {
1680             Segment32(comm) => comm.cmd,
1681             Segment64(comm) => comm.cmd,
1682             Uuid(comm) => comm.cmd,
1683             Symtab(comm) => comm.cmd,
1684             Symseg(comm) => comm.cmd,
1685             Thread(comm) => comm.cmd,
1686             Unixthread(comm) => comm.cmd,
1687             LoadFvmlib(comm) => comm.cmd,
1688             IdFvmlib(comm) => comm.cmd,
1689             Ident(comm) => comm.cmd,
1690             Fvmfile(comm) => comm.cmd,
1691             Prepage(comm) => comm.cmd,
1692             Dysymtab(comm) => comm.cmd,
1693             LoadDylib(comm) => comm.cmd,
1694             IdDylib(comm) => comm.cmd,
1695             LoadDylinker(comm) => comm.cmd,
1696             IdDylinker(comm) => comm.cmd,
1697             PreboundDylib(comm) => comm.cmd,
1698             Routines32(comm) => comm.cmd,
1699             Routines64(comm) => comm.cmd,
1700             SubFramework(comm) => comm.cmd,
1701             SubUmbrella(comm) => comm.cmd,
1702             SubClient(comm) => comm.cmd,
1703             SubLibrary(comm) => comm.cmd,
1704             TwolevelHints(comm) => comm.cmd,
1705             PrebindCksum(comm) => comm.cmd,
1706             LoadWeakDylib(comm) => comm.cmd,
1707             Rpath(comm) => comm.cmd,
1708             CodeSignature(comm) => comm.cmd,
1709             SegmentSplitInfo(comm) => comm.cmd,
1710             ReexportDylib(comm) => comm.cmd,
1711             LazyLoadDylib(comm) => comm.cmd,
1712             EncryptionInfo32(comm) => comm.cmd,
1713             EncryptionInfo64(comm) => comm.cmd,
1714             DyldInfo(comm) => comm.cmd,
1715             DyldInfoOnly(comm) => comm.cmd,
1716             LoadUpwardDylib(comm) => comm.cmd,
1717             VersionMinMacosx(comm) => comm.cmd,
1718             VersionMinIphoneos(comm) => comm.cmd,
1719             FunctionStarts(comm) => comm.cmd,
1720             DyldEnvironment(comm) => comm.cmd,
1721             Main(comm) => comm.cmd,
1722             DataInCode(comm) => comm.cmd,
1723             SourceVersion(comm) => comm.cmd,
1724             DylibCodeSignDrs(comm) => comm.cmd,
1725             LinkerOption(comm) => comm.cmd,
1726             LinkerOptimizationHint(comm) => comm.cmd,
1727             VersionMinTvos(comm) => comm.cmd,
1728             VersionMinWatchos(comm) => comm.cmd,
1729             DyldExportsTrie(comm) => comm.cmd,
1730             DyldChainedFixups(comm) => comm.cmd,
1731             Unimplemented(comm) => comm.cmd,
1732         }
1733     }
1734 }
1735 
1736 #[derive(Debug)]
1737 /// A tagged LoadCommand union
1738 pub struct LoadCommand {
1739     /// The offset this load command occurs at
1740     pub offset: usize,
1741     /// Which load command this is inside a variant
1742     pub command: CommandVariant,
1743 }
1744 
1745 impl LoadCommand {
1746     /// Parse a load command from `bytes` at `offset` with the `le` endianness
parse(bytes: &[u8], offset: &mut usize, le: scroll::Endian) -> error::Result<Self>1747     pub fn parse(bytes: &[u8], offset: &mut usize, le: scroll::Endian) -> error::Result<Self> {
1748         let start = *offset;
1749         let command = bytes.pread_with::<CommandVariant>(start, le)?;
1750         let size = command.cmdsize();
1751         *offset = start + size;
1752         Ok(LoadCommand {
1753             offset: start,
1754             command,
1755         })
1756     }
1757 }
1758