Skip to main content

mach_object/
commands.rs

1#![allow(non_camel_case_types, clippy::many_single_char_names, clippy::large_enum_variant)]
2
3use std::fmt;
4use std::io::{BufRead, Cursor, Read};
5use std::ops::Deref;
6use std::rc::Rc;
7use std::str::FromStr;
8
9use byteorder::{ByteOrder, ReadBytesExt};
10use uuid::Uuid;
11
12use crate::{
13    consts::*,
14    errors::{
15        Error::{self, *},
16        Result,
17    },
18    loader::MachHeader,
19};
20
21/// The encoded version.
22///
23///  X.Y.Z is encoded in nibbles xxxx.yy.zz
24///
25#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)]
26pub struct VersionTag(u32);
27
28impl VersionTag {
29    pub fn major(self) -> u32 {
30        self.0 >> 16
31    }
32
33    pub fn minor(self) -> u32 {
34        (self.0 >> 8) & 0xFF
35    }
36
37    pub fn release(self) -> u32 {
38        self.0 & 0xFF
39    }
40}
41
42impl From<VersionTag> for u32 {
43    fn from(v: VersionTag) -> Self {
44        v.0
45    }
46}
47
48impl FromStr for VersionTag {
49    type Err = Error;
50
51    fn from_str(s: &str) -> Result<Self> {
52        let mut parts = s.split('.');
53
54        let major = match parts.next() {
55            Some(s) if !s.is_empty() => s.parse()?,
56            _ => 0,
57        };
58        let minor = match parts.next() {
59            Some(s) if !s.is_empty() => s.parse()?,
60            _ => 0,
61        };
62        let release = match parts.next() {
63            Some(s) if !s.is_empty() => s.parse()?,
64            _ => 0,
65        };
66
67        Ok(VersionTag((major << 16) + (minor << 8) + release))
68    }
69}
70
71impl fmt::Display for VersionTag {
72    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
73        if self.release() == 0 {
74            write!(f, "{}.{}", self.major(), self.minor())
75        } else {
76            write!(f, "{}.{}.{}", self.major(), self.minor(), self.release())
77        }
78    }
79}
80
81/// The packed version.
82///
83/// A.B.C.D.E packed as a24.b10.c10.d10.e10
84///
85#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)]
86pub struct SourceVersionTag(u64);
87
88impl From<SourceVersionTag> for u64 {
89    fn from(v: SourceVersionTag) -> Self {
90        v.0
91    }
92}
93
94impl From<SourceVersionTag> for (u32, u32, u32, u32, u32) {
95    fn from(v: SourceVersionTag) -> (u32, u32, u32, u32, u32) {
96        (
97            ((v.0 >> 40) & 0xFFF) as u32,
98            ((v.0 >> 30) & 0x3FF) as u32,
99            ((v.0 >> 20) & 0x3FF) as u32,
100            ((v.0 >> 10) & 0x3FF) as u32,
101            (v.0 & 0x3FF) as u32,
102        )
103    }
104}
105
106impl fmt::Display for SourceVersionTag {
107    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
108        let (a, b, c, d, e) = Self::into(*self);
109
110        if e != 0 {
111            write!(f, "{}.{}.{}.{}.{}", a, b, c, d, e)
112        } else if d != 0 {
113            write!(f, "{}.{}.{}.{}", a, b, c, d)
114        } else if c != 0 {
115            write!(f, "{}.{}.{}", a, b, c)
116        } else {
117            write!(f, "{}.{}", a, b)
118        }
119    }
120}
121
122/// The min OS version on which this binary was built to run.
123///
124#[derive(Debug, Copy, Clone, PartialEq, Eq)]
125pub enum BuildTarget {
126    MacOsX,
127    IPhoneOs,
128    WatchOs,
129    TvOs,
130}
131
132impl From<u32> for BuildTarget {
133    fn from(cmd: u32) -> Self {
134        match cmd {
135            LC_VERSION_MIN_MACOSX => BuildTarget::MacOsX,
136            LC_VERSION_MIN_IPHONEOS => BuildTarget::IPhoneOs,
137            LC_VERSION_MIN_WATCHOS => BuildTarget::WatchOs,
138            LC_VERSION_MIN_TVOS => BuildTarget::TvOs,
139            _ => unreachable!(),
140        }
141    }
142}
143impl From<BuildTarget> for u32 {
144    fn from(t: BuildTarget) -> u32 {
145        match t {
146            BuildTarget::MacOsX => LC_VERSION_MIN_MACOSX,
147            BuildTarget::IPhoneOs => LC_VERSION_MIN_IPHONEOS,
148            BuildTarget::WatchOs => LC_VERSION_MIN_WATCHOS,
149            BuildTarget::TvOs => LC_VERSION_MIN_TVOS,
150        }
151    }
152}
153
154/// A variable length string in a load command is represented by an `LcString` structure.
155///
156/// The strings are stored just after the load command structure and
157/// the offset is from the start of the load command structure.  The size
158/// of the string is reflected in the cmdsize field of the load command.
159/// Once again any padded bytes to bring the cmdsize field to a multiple
160/// of 4 bytes must be zero.
161///
162#[derive(Debug, Default, Clone, PartialEq, Eq)]
163pub struct LcString(pub usize, pub String);
164
165impl LcString {
166    pub fn size(&self) -> usize {
167        self.0
168    }
169
170    pub fn as_str(&self) -> &str {
171        self.1.as_str()
172    }
173}
174
175impl fmt::Display for LcString {
176    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
177        write!(f, "{}", self.1)
178    }
179}
180
181impl Deref for LcString {
182    type Target = str;
183
184    fn deref(&self) -> &Self::Target {
185        self.1.as_str()
186    }
187}
188
189/// Fixed virtual memory shared libraries are identified by two things.
190///
191/// The target pathname (the name of the library as found for execution),
192/// and the minor version number.
193/// The address of where the headers are loaded is in `header_addr`.
194/// (THIS IS OBSOLETE and no longer supported).
195#[derive(Debug, Default, Clone, PartialEq, Eq)]
196pub struct FvmLib {
197    /// library's target pathname
198    pub name: LcString,
199    /// library's minor version number
200    pub minor_version: u32,
201    /// library's header address
202    pub header_addr: u32,
203}
204
205/// Dynamically linked shared libraries are identified by two things.
206///
207/// The pathname (the name of the library as found for execution), and the
208/// compatibility version number.  The pathname must match and the compatibility
209/// number in the user of the library must be greater than or equal to the
210/// library being used.  The time stamp is used to record the time a library was
211/// built and copied into user so it can be use to determined if the library used
212/// at runtime is exactly the same as used to built the program.
213#[derive(Debug, Default, Clone, PartialEq, Eq)]
214pub struct DyLib {
215    /// library's path name
216    pub name: LcString,
217    /// library's build time stamp
218    pub timestamp: u32,
219    /// library's current version number
220    pub current_version: VersionTag,
221    /// library's compatibility vers number
222    pub compatibility_version: VersionTag,
223}
224
225/// a table of contents entry
226pub struct DyLibTocEntry {
227    /// the defined external symbol (index into the symbol table)
228    pub symbol_index: u32,
229    /// index into the module table this symbol is defined in
230    pub module_index: u32,
231}
232
233/// a module table entry
234pub struct DyLibModule {
235    /// the module name (index into string table)
236    pub module_name: u32,
237
238    /// index into externally defined symbols
239    pub iextdefsym: u32,
240    /// number of externally defined symbols
241    pub nextdefsym: u32,
242    /// index into reference symbol table
243    pub irefsym: u32,
244    /// number of reference symbol table entries
245    pub nrefsym: u32,
246    /// index into symbols for local symbols
247    pub ilocalsym: u32,
248    /// number of local symbols
249    pub nlocalsym: u32,
250
251    /// index into external relocation entries
252    pub iextrel: u32,
253    /// number of external relocation entries
254    pub nextrel: u32,
255
256    /// low 16 bits are the index into the init section,
257    /// high 16 bits are the index into the term section
258    pub iinit_iterm: u32,
259    /// low 16 bits are the number of init section entries,
260    /// high 16 bits are the number of term section entries
261    pub ninit_nterm: u32,
262
263    /// for this module address of the start of the (__OBJC,__module_info) section
264    pub objc_module_info_addr: u32,
265    /// for this module size of the (__OBJC,__module_info) section
266    pub objc_module_info_size: usize,
267}
268
269/// The `LinkEditData` contains the offsets and sizes of a blob
270/// of data in the __LINKEDIT segment.
271///
272#[derive(Debug, Default, Clone, PartialEq, Eq)]
273pub struct LinkEditData {
274    /// file offset of data in __LINKEDIT segment
275    pub off: u32,
276    /// file size of data in __LINKEDIT segment
277    pub size: u32,
278}
279
280#[derive(Debug, Clone, Copy, PartialEq)]
281pub enum X86ThreadFlavor {
282    x86_THREAD_STATE32 = 1,
283    x86_FLOAT_STATE32 = 2,
284    x86_EXCEPTION_STATE32 = 3,
285    x86_THREAD_STATE64 = 4,
286    x86_FLOAT_STATE64 = 5,
287    x86_EXCEPTION_STATE64 = 6,
288    x86_THREAD_STATE = 7,
289    x86_FLOAT_STATE = 8,
290    x86_EXCEPTION_STATE = 9,
291    x86_DEBUG_STATE32 = 10,
292    x86_DEBUG_STATE64 = 11,
293    x86_DEBUG_STATE = 12,
294}
295
296#[derive(Debug, Clone, Copy, PartialEq)]
297pub enum ARMThreadFlavors {
298    ARM_THREAD_STATE = 1,
299    ARM_VFP_STATE = 2,
300    ARM_EXCEPTION_STATE = 3,
301    ARM_DEBUG_STATE = 4,
302    ARN_THREAD_STATE_NONE = 5,
303    ARM_THREAD_STATE64 = 6,
304    ARM_EXCEPTION_STATE64 = 7,
305}
306
307#[derive(Debug, Clone, Copy, PartialEq)]
308pub enum PPCThreadFlavors {
309    PPC_THREAD_STATE = 1,
310    PPC_FLOAT_STATE = 2,
311    PPC_EXCEPTION_STATE = 3,
312    PPC_VECTOR_STATE = 4,
313    PPC_THREAD_STATE64 = 5,
314    PPC_EXCEPTION_STATE64 = 6,
315    PPC_THREAD_STATE_NONE = 7,
316}
317
318#[derive(Debug, Clone, PartialEq)]
319pub enum ThreadState {
320    I386 {
321        __eax: u32,
322        __ebx: u32,
323        __ecx: u32,
324        __edx: u32,
325        __edi: u32,
326        __esi: u32,
327        __ebp: u32,
328        __esp: u32,
329        __ss: u32,
330        __eflags: u32,
331        __eip: u32,
332        __cs: u32,
333        __ds: u32,
334        __es: u32,
335        __fs: u32,
336        __gs: u32,
337    },
338    X86_64 {
339        __rax: u64,
340        __rbx: u64,
341        __rcx: u64,
342        __rdx: u64,
343        __rdi: u64,
344        __rsi: u64,
345        __rbp: u64,
346        __rsp: u64,
347        __r8: u64,
348        __r9: u64,
349        __r10: u64,
350        __r11: u64,
351        __r12: u64,
352        __r13: u64,
353        __r14: u64,
354        __r15: u64,
355        __rip: u64,
356        __rflags: u64,
357        __cs: u64,
358        __fs: u64,
359        __gs: u64,
360    },
361    Arm {
362        /// General purpose register r0-r12
363        __r: [u32; 13],
364        /// Stack pointer r13
365        __sp: u32,
366        /// Link register r14
367        __lr: u32,
368        /// Program counter r15
369        __pc: u32,
370        /// Current program status register
371        __cpsr: u32,
372    },
373    Arm64 {
374        /// General purpose registers x0-x28
375        __x: [u64; 29],
376        /// Frame pointer x29
377        __fp: u64,
378        /// Link register x30
379        __lr: u64,
380        /// Stack pointer x31
381        __sp: u64,
382        /// Program counter
383        __pc: u64,
384        /// Current program status register
385        __cpsr: u32,
386        /// Same size for 32-bit or 64-bit clients
387        __pad: u32,
388    },
389    PowerPC {
390        __srr: [u32; 2],
391        __r: [u32; 32],
392        __ct: u32,
393        __xer: u32,
394        __lr: u32,
395        __ctr: u32,
396        __mq: u32,
397        __vrsave: u32,
398    },
399    PowerPC64 {
400        __srr: [u64; 2],
401        __r: [u64; 32],
402        __cr: u32,
403        __xer: u64,
404        __lr: u64,
405        __ctr: u64,
406        __vrsave: u32,
407    },
408}
409
410#[derive(Debug, Clone, PartialEq)]
411pub enum Platform {
412    macOS,
413    iOS,
414    tvOS,
415    watchOS,
416    bridgeOS,
417    Other(u32),
418}
419
420#[derive(Debug, Clone, PartialEq)]
421pub enum Tool {
422    Clang,
423    Swift,
424    LD,
425    Other(u32),
426}
427
428/// The build_version_command contains the min OS version on which this
429/// binary was built to run for its platform.  The list of known platforms and
430/// tool values following it.
431#[derive(Debug, Clone, PartialEq)]
432pub struct BuildVersion {
433    pub platform: u32,
434    /// X.Y.Z is encoded in nibbles xxxx.yy.zz
435    pub minos: VersionTag,
436    /// X.Y.Z is encoded in nibbles xxxx.yy.zz
437    pub sdk: VersionTag,
438    /// build tools
439    pub build_tools: Vec<BuildTool>,
440}
441
442impl BuildVersion {
443    pub fn platform(&self) -> Platform {
444        match self.platform {
445            PLATFORM_MACOS => Platform::macOS,
446            PLATFORM_IOS => Platform::iOS,
447            PLATFORM_TVOS => Platform::tvOS,
448            PLATFORM_WATCHOS => Platform::watchOS,
449            PLATFORM_BRIDGEOS => Platform::bridgeOS,
450            n => Platform::Other(n),
451        }
452    }
453}
454
455#[derive(Debug, Clone, PartialEq)]
456pub struct BuildTool {
457    pub tool: u32,
458    pub version: VersionTag,
459}
460
461impl BuildTool {
462    pub fn tool(&self) -> Tool {
463        match self.tool {
464            TOOL_CLANG => Tool::Clang,
465            TOOL_SWIFT => Tool::Swift,
466            TOOL_LD => Tool::LD,
467            n => Tool::Other(n),
468        }
469    }
470}
471
472/// The load commands directly follow the mach header.
473///
474#[derive(Debug, Clone)]
475pub enum LoadCommand {
476    /// The segment load command indicates that a part of this file is to be
477    /// mapped into the task's address space.
478    ///
479    /// The size of this segment in memory, vmsize, maybe equal to or
480    /// larger than the amount to map from this file, filesize.
481    /// The file is mapped starting at fileoff to the beginning of
482    /// the segment in memory, vmaddr.  The rest of the memory of the segment,
483    /// if any, is allocated zero fill on demand.  The segment's maximum virtual
484    /// memory protection and initial virtual memory protection are specified
485    /// by the maxprot and initprot fields.  If the segment has sections then the
486    /// section structures directly follow the segment command and their size is
487    /// reflected in cmdsize.
488    ///
489    Segment {
490        /// segment name
491        segname: String,
492        /// memory address of this segment
493        vmaddr: usize,
494        /// memory size of this segment
495        vmsize: usize,
496        /// file offset of this segment
497        fileoff: usize,
498        /// amount to map from the file
499        filesize: usize,
500        /// maximum VM protection
501        maxprot: vm_prot_t,
502        /// initial VM protection
503        initprot: vm_prot_t,
504        /// flags
505        flags: SegmentFlags,
506        /// sections
507        sections: Vec<Rc<Section>>,
508    },
509    /// The 64-bit segment load command indicates that a part of this file is to be
510    /// mapped into a 64-bit task's address space.
511    ///
512    /// If the 64-bit segment has sections then section_64 structures directly follow
513    /// the 64-bit segment command and their size is reflected in cmdsize.
514    ///
515    Segment64 {
516        /// segment name
517        segname: String,
518        /// memory address of this segment
519        vmaddr: usize,
520        /// memory size of this segment
521        vmsize: usize,
522        /// file offset of this segment
523        fileoff: usize,
524        /// amount to map from the file
525        filesize: usize,
526        /// maximum VM protection
527        maxprot: vm_prot_t,
528        /// initial VM protection
529        initprot: vm_prot_t,
530        /// flags
531        flags: SegmentFlags,
532        /// sections
533        sections: Vec<Rc<Section>>,
534    },
535
536    // A fixed virtual shared library (filetype == MH_FVMLIB in the mach header)
537    // contains a fvmlib_command (cmd == LC_IDFVMLIB) to identify the library.
538    //
539    // An object that uses a fixed virtual shared library also contains a
540    // fvmlib_command (cmd == LC_LOADFVMLIB) for each library it uses.
541    // (THIS IS OBSOLETE and no longer supported).
542    //
543    /// fixed VM shared library identification
544    IdFvmLib(FvmLib),
545    /// load a specified fixed VM shared library
546    LoadFvmLib(FvmLib),
547
548    // A dynamically linked shared library (filetype == MH_DYLIB in the mach header)
549    // contains a dylib_command (cmd == LC_ID_DYLIB) to identify the library.
550    //
551    // An object that uses a dynamically linked shared library also contains a
552    // dylib_command (cmd == LC_LOAD_DYLIB, LC_LOAD_WEAK_DYLIB, or
553    // LC_REEXPORT_DYLIB) for each library it uses.
554    //
555    /// dynamically linked shared lib ident
556    IdDyLib(DyLib),
557    /// load a dynamically linked shared library
558    LoadDyLib(DyLib),
559    /// load a dynamically linked shared library
560    /// that is allowed to be missing (all symbols are weak imported).
561    LoadWeakDyLib(DyLib),
562    /// load and re-export dylib
563    ReexportDyLib(DyLib),
564    /// load upward dylib
565    LoadUpwardDylib(DyLib),
566    /// delay load of dylib until first use
567    LazyLoadDylib(DyLib),
568    /// add a runtime search path for shared libraries
569    Rpath(String),
570
571    // A program that uses a dynamic linker contains a dylinker_command to identify
572    // the name of the dynamic linker (LC_LOAD_DYLINKER).  And a dynamic linker
573    // contains a dylinker_command to identify the dynamic linker (LC_ID_DYLINKER).
574    // A file can have at most one of these.
575    // This struct is also used for the LC_DYLD_ENVIRONMENT load command and
576    // contains string for dyld to treat like environment variable.
577    //
578    /// dynamic linker identification
579    IdDyLinker(LcString),
580    /// load a dynamic linker
581    LoadDyLinker(LcString),
582    /// string for dyld to treat like environment variable
583    DyLdEnv(LcString),
584
585    /// The symtab_command contains the offsets and sizes of the link-edit 4.3BSD
586    /// "stab" style symbol table information as described in the header files
587    /// <nlist.h> and <stab.h>.
588    ///
589    SymTab {
590        /// symbol table offset
591        symoff: u32,
592        /// number of symbol table entries
593        nsyms: u32,
594        /// string table offset
595        stroff: u32,
596        /// string table size in bytes
597        strsize: u32,
598    },
599
600    /// This is the second set of the symbolic information which is used to support
601    /// the data structures for the dynamically link editor.
602    ///
603    /// The original set of symbolic information in the symtab_command which contains
604    /// the symbol and string tables must also be present when this load command is
605    /// present.  When this load command is present the symbol table is organized
606    /// into three groups of symbols:
607    ///  local symbols (static and debugging symbols) - grouped by module
608    ///  defined external symbols - grouped by module (sorted by name if not lib)
609    ///  undefined external symbols (sorted by name if MH_BINDATLOAD is not set,
610    ///                      and in order the were seen by the static
611    ///                  linker if MH_BINDATLOAD is set)
612    /// In this load command there are offsets and counts to each of the three groups
613    /// of symbols.
614    ///
615    /// This load command contains a the offsets and sizes of the following new
616    /// symbolic information tables:
617    ///  table of contents
618    ///  module table
619    ///  reference symbol table
620    ///  indirect symbol table
621    /// The first three tables above (the table of contents, module table and
622    /// reference symbol table) are only present if the file is a dynamically linked
623    /// shared library.  For executable and object modules, which are files
624    /// containing only one module, the information that would be in these three
625    /// tables is determined as follows:
626    ///  table of contents - the defined external symbols are sorted by name
627    ///  module table - the file contains only one module so everything in the
628    ///             file is part of the module.
629    ///  reference symbol table - is the defined and undefined external symbols
630    ///
631    /// For dynamically linked shared library files this load command also contains
632    /// offsets and sizes to the pool of relocation entries for all sections
633    /// separated into two groups:
634    ///  external relocation entries
635    ///  local relocation entries
636    /// For executable and object modules the relocation entries continue to hang
637    /// off the section structures.
638    ///
639    DySymTab {
640        // The symbols indicated by symoff and nsyms of the LC_SYMTAB load command
641        // are grouped into the following three groups:
642        //    local symbols (further grouped by the module they are from)
643        //    defined external symbols (further grouped by the module they are from)
644        //    undefined symbols
645        //
646        // The local symbols are used only for debugging.  The dynamic binding
647        // process may have to use them to indicate to the debugger the local
648        // symbols for a module that is being bound.
649        //
650        // The last two groups are used by the dynamic binding process to do the
651        // binding (indirectly through the module table and the reference symbol
652        // table when this is a dynamically linked shared library file).
653        //
654        /// index to local symbols
655        ilocalsym: u32,
656        /// number of local symbols
657        nlocalsym: u32,
658
659        /// index to externally defined symbols
660        iextdefsym: u32,
661        /// number of externally defined symbols
662        nextdefsym: u32,
663
664        /// index to undefined symbols
665        iundefsym: u32,
666        /// number of undefined symbols
667        nundefsym: u32,
668
669        // For the for the dynamic binding process to find which module a symbol
670        // is defined in the table of contents is used (analogous to the ranlib
671        // structure in an archive) which maps defined external symbols to modules
672        // they are defined in.  This exists only in a dynamically linked shared
673        // library file.  For executable and object modules the defined external
674        // symbols are sorted by name and is use as the table of contents.
675        //
676        /// file offset to table of contents
677        tocoff: u32,
678        /// number of entries in table of contents
679        ntoc: u32,
680
681        // To support dynamic binding of "modules" (whole object files) the symbol
682        // table must reflect the modules that the file was created from.  This is
683        // done by having a module table that has indexes and counts into the merged
684        // tables for each module.  The module structure that these two entries
685        // refer to is described below.  This exists only in a dynamically linked
686        // shared library file.  For executable and object modules the file only
687        // contains one module so everything in the file belongs to the module.
688        //
689        /// file offset to module table
690        modtaboff: u32,
691        /// number of module table entries
692        nmodtab: u32,
693
694        // To support dynamic module binding the module structure for each module
695        // indicates the external references (defined and undefined) each module
696        // makes.  For each module there is an offset and a count into the
697        // reference symbol table for the symbols that the module references.
698        // This exists only in a dynamically linked shared library file.  For
699        // executable and object modules the defined external symbols and the
700        // undefined external symbols indicates the external references.
701        //
702        /// offset to referenced symbol table
703        extrefsymoff: u32,
704        /// number of referenced symbol table entries
705        nextrefsyms: u32,
706
707        // The sections that contain "symbol pointers" and "routine stubs" have
708        // indexes and (implied counts based on the size of the section and fixed
709        // size of the entry) into the "indirect symbol" table for each pointer
710        // and stub.  For every section of these two types the index into the
711        // indirect symbol table is stored in the section header in the field
712        // reserved1.  An indirect symbol table entry is simply a 32bit index into
713        // the symbol table to the symbol that the pointer or stub is referring to.
714        // The indirect symbol table is ordered to match the entries in the section.
715        //
716        /// file offset to the indirect symbol table
717        indirectsymoff: u32,
718        /// number of indirect symbol table entries
719        nindirectsyms: u32,
720
721        // To support relocating an individual module in a library file quickly the
722        // external relocation entries for each module in the library need to be
723        // accessed efficiently.  Since the relocation entries can't be accessed
724        // through the section headers for a library file they are separated into
725        // groups of local and external entries further grouped by module.  In this
726        // case the presents of this load command who's extreloff, nextrel,
727        // locreloff and nlocrel fields are non-zero indicates that the relocation
728        // entries of non-merged sections are not referenced through the section
729        // structures (and the reloff and nreloc fields in the section headers are
730        // set to zero).
731        //
732        // Since the relocation entries are not accessed through the section headers
733        // this requires the r_address field to be something other than a section
734        // offset to identify the item to be relocated.  In this case r_address is
735        // set to the offset from the vmaddr of the first LC_SEGMENT command.
736        // For MH_SPLIT_SEGS images r_address is set to the the offset from the
737        // vmaddr of the first read-write LC_SEGMENT command.
738        //
739        // The relocation entries are grouped by module and the module table
740        // entries have indexes and counts into them for the group of external
741        // relocation entries for that the module.
742        //
743        // For sections that are merged across modules there must not be any
744        // remaining external relocation entries for them (for merged sections
745        // remaining relocation entries must be local).
746        //
747        /// offset to external relocation entries
748        extreloff: u32,
749        /// number of external relocation entries
750        nextrel: u32,
751
752        // All the local relocation entries are grouped together (they are not
753        // grouped by their module since they are only used if the object is moved
754        // from it staticly link edited address).
755        //
756        /// offset to local relocation entries
757        locreloff: u32,
758        /// number of local relocation entries
759        nlocrel: u32,
760    },
761
762    /// The uuid load command contains a single 128-bit unique random number that
763    /// identifies an object produced by the static link editor.
764    ///
765    Uuid(Uuid),
766
767    // The `LinkEditData` contains the offsets and sizes of a blob
768    // of data in the __LINKEDIT segment.
769    //
770    /// local of code signature
771    CodeSignature(LinkEditData),
772    /// local of info to split segments
773    SegmentSplitInfo(LinkEditData),
774    /// compressed table of function start addresses
775    FunctionStarts(LinkEditData),
776    /// table of non-instructions in __text
777    DataInCode(LinkEditData),
778    /// Code signing DRs copied from linked dylibs
779    DylibCodeSignDrs(LinkEditData),
780    /// optimization hints in MH_OBJECT files
781    LinkerOptimizationHint(LinkEditData),
782    /// used with linkedit_data_command, payload is trie
783    DyldExportsTrie(LinkEditData),
784    /// used with linkedit_data_command
785    DyldChainedFixups(LinkEditData),
786
787    /// The version_min_command contains the min OS version on which this
788    /// binary was built to run.
789    ///
790    VersionMin {
791        target: BuildTarget,
792        version: VersionTag,
793        sdk: VersionTag,
794    },
795
796    /// The dyld_info_command contains the file offsets and sizes of
797    /// the new compressed form of the information dyld needs to
798    /// load the image.  This information is used by dyld on Mac OS X
799    /// 10.6 and later.  All information pointed to by this command
800    /// is encoded using byte streams, so no endian swapping is needed
801    /// to interpret it.
802    ///
803    DyldInfo {
804        // Dyld rebases an image whenever dyld loads it at an address different
805        // from its preferred address.  The rebase information is a stream
806        // of byte sized opcodes whose symbolic names start with REBASE_OPCODE_.
807        // Conceptually the rebase information is a table of tuples:
808        //    <seg-index, seg-offset, type>
809        // The opcodes are a compressed way to encode the table by only
810        // encoding when a column changes.  In addition simple patterns
811        // like "every n'th offset for m times" can be encoded in a few
812        // bytes.
813        //
814        /// file offset to rebase info
815        rebase_off: u32,
816        /// size of rebase info
817        rebase_size: u32,
818
819        // Dyld binds an image during the loading process, if the image
820        // requires any pointers to be initialized to symbols in other images.
821        // The bind information is a stream of byte sized
822        // opcodes whose symbolic names start with BIND_OPCODE_.
823        // Conceptually the bind information is a table of tuples:
824        //    <seg-index, seg-offset, type, symbol-library-ordinal, symbol-name, addend>
825        // The opcodes are a compressed way to encode the table by only
826        // encoding when a column changes.  In addition simple patterns
827        // like for runs of pointers initialzed to the same value can be
828        // encoded in a few bytes.
829        //
830        /// file offset to binding info
831        bind_off: u32,
832        /// size of binding info
833        bind_size: u32,
834
835        // Some C++ programs require dyld to unique symbols so that all
836        // images in the process use the same copy of some code/data.
837        // This step is done after binding. The content of the weak_bind
838        // info is an opcode stream like the bind_info.  But it is sorted
839        // alphabetically by symbol name.  This enable dyld to walk
840        // all images with weak binding information in order and look
841        // for collisions.  If there are no collisions, dyld does
842        // no updating.  That means that some fixups are also encoded
843        // in the bind_info.  For instance, all calls to "operator new"
844        // are first bound to libstdc++.dylib using the information
845        // in bind_info.  Then if some image overrides operator new
846        // that is detected when the weak_bind information is processed
847        // and the call to operator new is then rebound.
848        //
849        /// file offset to weak binding info
850        weak_bind_off: u32,
851        /// size of weak binding info
852        weak_bind_size: u32,
853
854        // Some uses of external symbols do not need to be bound immediately.
855        // Instead they can be lazily bound on first use.  The lazy_bind
856        // are contains a stream of BIND opcodes to bind all lazy symbols.
857        // Normal use is that dyld ignores the lazy_bind section when
858        // loading an image.  Instead the static linker arranged for the
859        // lazy pointer to initially point to a helper function which
860        // pushes the offset into the lazy_bind area for the symbol
861        // needing to be bound, then jumps to dyld which simply adds
862        // the offset to lazy_bind_off to get the information on what
863        // to bind.
864        //
865        /// file offset to lazy binding info
866        lazy_bind_off: u32,
867        /// size of lazy binding infs
868        lazy_bind_size: u32,
869
870        // The symbols exported by a dylib are encoded in a trie.  This
871        // is a compact representation that factors out common prefixes.
872        // It also reduces LINKEDIT pages in RAM because it encodes all
873        // information (name, address, flags) in one small, contiguous range.
874        // The export area is a stream of nodes.  The first node sequentially
875        // is the start node for the trie.
876        //
877        // Nodes for a symbol start with a uleb128 that is the length of
878        // the exported symbol information for the string so far.
879        // If there is no exported symbol, the node starts with a zero byte.
880        // If there is exported info, it follows the length.
881        //
882        // First is a uleb128 containing flags. Normally, it is followed by
883        // a uleb128 encoded offset which is location of the content named
884        // by the symbol from the mach_header for the image.  If the flags
885        // is EXPORT_SYMBOL_FLAGS_REEXPORT, then following the flags is
886        // a uleb128 encoded library ordinal, then a zero terminated
887        // UTF8 string.  If the string is zero length, then the symbol
888        // is re-export from the specified dylib with the same name.
889        // If the flags is EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER, then following
890        // the flags is two uleb128s: the stub offset and the resolver offset.
891        // The stub is used by non-lazy pointers.  The resolver is used
892        // by lazy pointers and must be called to get the actual address to use.
893        //
894        // After the optional exported symbol information is a byte of
895        // how many edges (0-255) that this node has leaving it,
896        // followed by each edge.
897        // Each edge is a zero terminated UTF8 of the addition chars
898        // in the symbol, followed by a uleb128 offset for the node that
899        // edge points to.
900        //
901        //
902        /// file offset to lazy binding info
903        export_off: u32,
904        /// size of lazy binding infs
905        export_size: u32,
906    },
907
908    /// The entry_point_command is a replacement for thread_command.
909    /// It is used for main executables to specify the location (file offset)
910    /// of main().  If -stack_size was used at link time, the stacksize
911    /// field will contain the stack size need for the main thread.
912    ///
913    EntryPoint {
914        /// file (__TEXT) offset of main()
915        entryoff: u64,
916        /// if not zero, initial stack size
917        stacksize: u64,
918    },
919    /// The source_version_command is an optional load command containing
920    /// the version of the sources used to build the binary.
921    ///
922    SourceVersion(SourceVersionTag),
923
924    /// Thread commands contain machine-specific data structures suitable for
925    /// use in the thread state primitives.  The machine specific data structures
926    /// follow the struct thread_command as follows.
927    /// Each flavor of machine specific data structure is preceded by an unsigned
928    /// long constant for the flavor of that data structure, an
929    /// that is the count of longs of the size of the state data structure and then
930    /// the state data structure follows.  This triple may be repeated for many
931    /// flavors.  The constants for the flavors, counts and state data structure
932    /// definitions are expected to be in the header file <machine/thread_status.h>.
933    /// These machine specific data structures sizes must be multiples of
934    /// 4 bytes  The cmdsize reflects the total size of the thread_command
935    /// and all of the sizes of the constants for the flavors, counts and state
936    /// data structures.
937    UnixThread {
938        /// flavor of thread state
939        flavor: u32,
940        /// count of longs in thread state
941        count: u32,
942        /// thread state for this flavor
943        state: ThreadState,
944    },
945
946    /// A dynamically linked shared library may be a subframework of an umbrella
947    /// framework.  If so it will be linked with "-umbrella umbrella_name" where
948    /// Where "umbrella_name" is the name of the umbrella framework. A subframework
949    /// can only be linked against by its umbrella framework or other subframeworks
950    /// that are part of the same umbrella framework.  Otherwise the static link
951    /// editor produces an error and states to link against the umbrella framework.
952    /// The name of the umbrella framework for subframeworks is recorded in the
953    /// following structure.
954    SubFramework(LcString),
955
956    /// A dynamically linked shared library may be a sub_umbrella of an umbrella
957    /// framework.  If so it will be linked with "-sub_umbrella umbrella_name" where
958    /// Where "umbrella_name" is the name of the sub_umbrella framework.  When
959    /// staticly linking when -twolevel_namespace is in effect a twolevel namespace
960    /// umbrella framework will only cause its subframeworks and those frameworks
961    /// listed as sub_umbrella frameworks to be implicited linked in.  Any other
962    /// dependent dynamic libraries will not be linked it when -twolevel_namespace
963    /// is in effect.  The primary library recorded by the static linker when
964    /// resolving a symbol in these libraries will be the umbrella framework.
965    /// Zero or more sub_umbrella frameworks may be use by an umbrella framework.
966    /// The name of a sub_umbrella framework is recorded in the following structure.
967    SubUmbrella(LcString),
968
969    /// For dynamically linked shared libraries that are subframework of an umbrella
970    /// framework they can allow clients other than the umbrella framework or other
971    /// subframeworks in the same umbrella framework.  To do this the subframework
972    /// is built with "-allowable_client client_name" and an LC_SUB_CLIENT load
973    /// command is created for each -allowable_client flag.  The client_name is
974    /// usually a framework name.  It can also be a name used for bundles clients
975    /// where the bundle is built with "-client_name client_name".
976    SubClient(LcString),
977
978    /// A dynamically linked shared library may be a sub_library of another shared
979    /// library.  If so it will be linked with "-sub_library library_name" where
980    /// Where "library_name" is the name of the sub_library shared library.  When
981    /// staticly linking when -twolevel_namespace is in effect a twolevel namespace
982    /// shared library will only cause its subframeworks and those frameworks
983    /// listed as sub_umbrella frameworks and libraries listed as sub_libraries to
984    /// be implicited linked in.  Any other dependent dynamic libraries will not be
985    /// linked it when -twolevel_namespace is in effect.  The primary library
986    /// recorded by the static linker when resolving a symbol in these libraries
987    /// will be the umbrella framework (or dynamic library). Zero or more sub_library
988    /// shared libraries may be use by an umbrella framework or (or dynamic library).
989    /// The name of a sub_library framework is recorded in the following structure.
990    /// For example /usr/lib/libobjc_profile.A.dylib would be recorded as "libobjc".
991    SubLibrary(LcString),
992
993    /// The linker_option_command contains linker options embedded in object files.
994    LinkerOption(Vec<String>),
995
996    /// The routines command contains the address of the dynamic shared library
997    /// initialization routine and an index into the module table for the module
998    /// that defines the routine.  Before any modules are used from the library the
999    /// dynamic linker fully binds the module that defines the initialization routine
1000    /// and then calls it.  This gets called before any module initialization
1001    /// routines (used for C++ static constructors) in the library.
1002    Routines {
1003        /// address of initialization routine
1004        init_address: u32,
1005        /// index into the module table that the init routine is defined in
1006        init_module: u32,
1007    },
1008
1009    Routines64 {
1010        /// address of initialization routine
1011        init_address: u64,
1012        /// index into the module table that the init routine is defined in
1013        init_module: u64,
1014    },
1015
1016    /// The encryption_info_command contains the file offset and size of an of an encrypted segment.
1017    EncryptionInfo {
1018        /// file offset of encrypted range
1019        offset: u32,
1020        /// file size of encrypted range
1021        size: u32,
1022        /// which enryption system,
1023        /// 0 means not-encrypted yet
1024        id: u32,
1025    },
1026
1027    EncryptionInfo64 {
1028        /// file offset of encrypted range
1029        offset: u32,
1030        /// file size of encrypted range
1031        size: u32,
1032        /// which enryption system,
1033        /// 0 means not-encrypted yet
1034        id: u32,
1035    },
1036
1037    /// The twolevel_hints_command contains the offset and number of hints in the
1038    /// two-level namespace lookup hints table.
1039    TwoLevelHints {
1040        /// offset to the hint table
1041        offset: u32,
1042        /// number of hints in the hint table
1043        nhints: u32,
1044    },
1045
1046    /// The build_version_command contains the min OS version on which this
1047    /// binary was built to run for its platform.  The list of known platforms and
1048    /// tool values following it.
1049    BuildVersion(BuildVersion),
1050
1051    Command {
1052        /// type of load command
1053        cmd: u32,
1054        ///
1055        /// command in bytes
1056        payload: Vec<u8>,
1057    },
1058}
1059
1060/// Read a fixed size string
1061pub trait ReadStringExt: Read {
1062    /// Read the fixed size string
1063    fn read_fixed_size_string(&mut self, len: usize) -> Result<String> {
1064        let mut buf = vec![0u8; len];
1065
1066        self.read_exact(&mut buf)?;
1067
1068        Ok(String::from_utf8(buf.split(|&b| b == 0).next().unwrap().to_vec())?)
1069    }
1070}
1071
1072impl<R: Read + ?Sized> ReadStringExt for R {}
1073
1074const LOAD_COMMAND_HEADER_SIZE: usize = 8; // cmd + cmdsize
1075
1076impl LoadCommand {
1077    pub fn parse<O: ByteOrder, T: AsRef<[u8]>>(
1078        header: &MachHeader,
1079        buf: &mut Cursor<T>,
1080    ) -> Result<(LoadCommand, usize)> {
1081        let begin = buf.position();
1082        let cmd = buf.read_u32::<O>()?;
1083        let cmdsize = buf.read_u32::<O>()? as usize;
1084
1085        if cmdsize < LOAD_COMMAND_HEADER_SIZE || begin as usize + cmdsize > buf.get_ref().as_ref().len() {
1086            return Err(BufferOverflow(cmdsize));
1087        }
1088
1089        let cmd = match cmd {
1090            LC_SEGMENT => {
1091                let segname = buf.read_fixed_size_string(16)?;
1092                let vmaddr = buf.read_u32::<O>()? as usize;
1093                let vmsize = buf.read_u32::<O>()? as usize;
1094                let fileoff = buf.read_u32::<O>()? as usize;
1095                let filesize = buf.read_u32::<O>()? as usize;
1096                let maxprot = buf.read_i32::<O>()?;
1097                let initprot = buf.read_i32::<O>()?;
1098                let nsects = buf.read_u32::<O>()?;
1099                let flags = buf.read_u32::<O>()?;
1100                let mut sections = Vec::new();
1101
1102                for _ in 0..nsects {
1103                    sections.push(Rc::new(Section::parse_section::<Cursor<T>, O>(buf)?));
1104                }
1105
1106                LoadCommand::Segment {
1107                    segname,
1108                    vmaddr,
1109                    vmsize,
1110                    fileoff,
1111                    filesize,
1112                    maxprot,
1113                    initprot,
1114                    flags: SegmentFlags::from_bits_truncate(flags),
1115                    sections,
1116                }
1117            }
1118            LC_SEGMENT_64 => {
1119                let segname = buf.read_fixed_size_string(16)?;
1120                let vmaddr = buf.read_u64::<O>()? as usize;
1121                let vmsize = buf.read_u64::<O>()? as usize;
1122                let fileoff = buf.read_u64::<O>()? as usize;
1123                let filesize = buf.read_u64::<O>()? as usize;
1124                let maxprot = buf.read_i32::<O>()?;
1125                let initprot = buf.read_i32::<O>()?;
1126                let nsects = buf.read_u32::<O>()?;
1127                let flags = buf.read_u32::<O>()?;
1128                let mut sections = Vec::new();
1129
1130                for _ in 0..nsects {
1131                    sections.push(Rc::new(Section::parse_section64::<Cursor<T>, O>(buf)?));
1132                }
1133
1134                LoadCommand::Segment64 {
1135                    segname,
1136                    vmaddr,
1137                    vmsize,
1138                    fileoff,
1139                    filesize,
1140                    maxprot,
1141                    initprot,
1142                    flags: SegmentFlags::from_bits_truncate(flags),
1143                    sections,
1144                }
1145            }
1146            LC_IDFVMLIB => LoadCommand::IdFvmLib(Self::read_fvmlib::<O, T>(buf)?),
1147            LC_LOADFVMLIB => LoadCommand::LoadFvmLib(Self::read_fvmlib::<O, T>(buf)?),
1148
1149            LC_ID_DYLIB => LoadCommand::IdDyLib(Self::read_dylib::<O, T>(buf)?),
1150            LC_LOAD_DYLIB => LoadCommand::LoadDyLib(Self::read_dylib::<O, T>(buf)?),
1151            LC_LOAD_WEAK_DYLIB => LoadCommand::LoadWeakDyLib(Self::read_dylib::<O, T>(buf)?),
1152            LC_REEXPORT_DYLIB => LoadCommand::ReexportDyLib(Self::read_dylib::<O, T>(buf)?),
1153            LC_LOAD_UPWARD_DYLIB => LoadCommand::LoadUpwardDylib(Self::read_dylib::<O, T>(buf)?),
1154            LC_LAZY_LOAD_DYLIB => LoadCommand::LazyLoadDylib(Self::read_dylib::<O, T>(buf)?),
1155            LC_RPATH => LoadCommand::Rpath({
1156                let offset = buf.read_u32::<O>()? as usize;
1157                buf.read_fixed_size_string(cmdsize - offset)?
1158            }),
1159
1160            LC_ID_DYLINKER => LoadCommand::IdDyLinker(Self::read_lcstr::<O, T>(buf)?),
1161            LC_LOAD_DYLINKER => LoadCommand::LoadDyLinker(Self::read_lcstr::<O, T>(buf)?),
1162            LC_DYLD_ENVIRONMENT => LoadCommand::DyLdEnv(Self::read_lcstr::<O, T>(buf)?),
1163
1164            LC_SYMTAB => LoadCommand::SymTab {
1165                symoff: buf.read_u32::<O>()?,
1166                nsyms: buf.read_u32::<O>()?,
1167                stroff: buf.read_u32::<O>()?,
1168                strsize: buf.read_u32::<O>()?,
1169            },
1170            LC_DYSYMTAB => LoadCommand::DySymTab {
1171                ilocalsym: buf.read_u32::<O>()?,
1172                nlocalsym: buf.read_u32::<O>()?,
1173                iextdefsym: buf.read_u32::<O>()?,
1174                nextdefsym: buf.read_u32::<O>()?,
1175                iundefsym: buf.read_u32::<O>()?,
1176                nundefsym: buf.read_u32::<O>()?,
1177                tocoff: buf.read_u32::<O>()?,
1178                ntoc: buf.read_u32::<O>()?,
1179                modtaboff: buf.read_u32::<O>()?,
1180                nmodtab: buf.read_u32::<O>()?,
1181                extrefsymoff: buf.read_u32::<O>()?,
1182                nextrefsyms: buf.read_u32::<O>()?,
1183                indirectsymoff: buf.read_u32::<O>()?,
1184                nindirectsyms: buf.read_u32::<O>()?,
1185                extreloff: buf.read_u32::<O>()?,
1186                nextrel: buf.read_u32::<O>()?,
1187                locreloff: buf.read_u32::<O>()?,
1188                nlocrel: buf.read_u32::<O>()?,
1189            },
1190            LC_UUID => {
1191                let mut uuid = [0; 16];
1192
1193                buf.read_exact(&mut uuid[..])?;
1194
1195                LoadCommand::Uuid(Uuid::from_slice(&uuid)?)
1196            }
1197            LC_CODE_SIGNATURE => LoadCommand::CodeSignature(Self::read_linkedit_data::<O, T>(buf)?),
1198            LC_SEGMENT_SPLIT_INFO => LoadCommand::SegmentSplitInfo(Self::read_linkedit_data::<O, T>(buf)?),
1199            LC_FUNCTION_STARTS => LoadCommand::FunctionStarts(Self::read_linkedit_data::<O, T>(buf)?),
1200            LC_DATA_IN_CODE => LoadCommand::DataInCode(Self::read_linkedit_data::<O, T>(buf)?),
1201            LC_DYLIB_CODE_SIGN_DRS => LoadCommand::DylibCodeSignDrs(Self::read_linkedit_data::<O, T>(buf)?),
1202            LC_LINKER_OPTIMIZATION_HINT => LoadCommand::LinkerOptimizationHint(Self::read_linkedit_data::<O, T>(buf)?),
1203            LC_DYLD_EXPORTS_TRIE => LoadCommand::DyldExportsTrie(Self::read_linkedit_data::<O, T>(buf)?),
1204            LC_DYLD_CHAINED_FIXUPS => LoadCommand::DyldChainedFixups(Self::read_linkedit_data::<O, T>(buf)?),
1205
1206            LC_VERSION_MIN_MACOSX | LC_VERSION_MIN_IPHONEOS | LC_VERSION_MIN_WATCHOS | LC_VERSION_MIN_TVOS => {
1207                LoadCommand::VersionMin {
1208                    target: BuildTarget::from(cmd),
1209                    version: VersionTag(buf.read_u32::<O>()?),
1210                    sdk: VersionTag(buf.read_u32::<O>()?),
1211                }
1212            }
1213            LC_DYLD_INFO | LC_DYLD_INFO_ONLY => LoadCommand::DyldInfo {
1214                rebase_off: buf.read_u32::<O>()?,
1215                rebase_size: buf.read_u32::<O>()?,
1216                bind_off: buf.read_u32::<O>()?,
1217                bind_size: buf.read_u32::<O>()?,
1218                weak_bind_off: buf.read_u32::<O>()?,
1219                weak_bind_size: buf.read_u32::<O>()?,
1220                lazy_bind_off: buf.read_u32::<O>()?,
1221                lazy_bind_size: buf.read_u32::<O>()?,
1222                export_off: buf.read_u32::<O>()?,
1223                export_size: buf.read_u32::<O>()?,
1224            },
1225            LC_MAIN => LoadCommand::EntryPoint {
1226                entryoff: buf.read_u64::<O>()?,
1227                stacksize: buf.read_u64::<O>()?,
1228            },
1229            LC_SOURCE_VERSION => LoadCommand::SourceVersion(SourceVersionTag(buf.read_u64::<O>()?)),
1230            LC_UNIXTHREAD if header.cputype == CPU_TYPE_I386 => LoadCommand::UnixThread {
1231                flavor: buf.read_u32::<O>()?,
1232                count: buf.read_u32::<O>()?,
1233                state: ThreadState::I386 {
1234                    __eax: buf.read_u32::<O>()?,
1235                    __ebx: buf.read_u32::<O>()?,
1236                    __ecx: buf.read_u32::<O>()?,
1237                    __edx: buf.read_u32::<O>()?,
1238                    __edi: buf.read_u32::<O>()?,
1239                    __esi: buf.read_u32::<O>()?,
1240                    __ebp: buf.read_u32::<O>()?,
1241                    __esp: buf.read_u32::<O>()?,
1242                    __ss: buf.read_u32::<O>()?,
1243                    __eflags: buf.read_u32::<O>()?,
1244                    __eip: buf.read_u32::<O>()?,
1245                    __cs: buf.read_u32::<O>()?,
1246                    __ds: buf.read_u32::<O>()?,
1247                    __es: buf.read_u32::<O>()?,
1248                    __fs: buf.read_u32::<O>()?,
1249                    __gs: buf.read_u32::<O>()?,
1250                },
1251            },
1252            LC_UNIXTHREAD if header.cputype == CPU_TYPE_X86_64 => LoadCommand::UnixThread {
1253                flavor: buf.read_u32::<O>()?,
1254                count: buf.read_u32::<O>()?,
1255                state: ThreadState::X86_64 {
1256                    __rax: buf.read_u64::<O>()?,
1257                    __rbx: buf.read_u64::<O>()?,
1258                    __rcx: buf.read_u64::<O>()?,
1259                    __rdx: buf.read_u64::<O>()?,
1260                    __rdi: buf.read_u64::<O>()?,
1261                    __rsi: buf.read_u64::<O>()?,
1262                    __rbp: buf.read_u64::<O>()?,
1263                    __rsp: buf.read_u64::<O>()?,
1264                    __r8: buf.read_u64::<O>()?,
1265                    __r9: buf.read_u64::<O>()?,
1266                    __r10: buf.read_u64::<O>()?,
1267                    __r11: buf.read_u64::<O>()?,
1268                    __r12: buf.read_u64::<O>()?,
1269                    __r13: buf.read_u64::<O>()?,
1270                    __r14: buf.read_u64::<O>()?,
1271                    __r15: buf.read_u64::<O>()?,
1272                    __rip: buf.read_u64::<O>()?,
1273                    __rflags: buf.read_u64::<O>()?,
1274                    __cs: buf.read_u64::<O>()?,
1275                    __fs: buf.read_u64::<O>()?,
1276                    __gs: buf.read_u64::<O>()?,
1277                },
1278            },
1279            LC_UNIXTHREAD if header.cputype == CPU_TYPE_ARM => {
1280                let flavor = buf.read_u32::<O>()?;
1281                let count = buf.read_u32::<O>()?;
1282                let mut __r = [0u32; 13];
1283
1284                buf.read_u32_into::<O>(&mut __r)?;
1285
1286                LoadCommand::UnixThread {
1287                    flavor,
1288                    count,
1289                    state: ThreadState::Arm {
1290                        __r,
1291                        __sp: buf.read_u32::<O>()?,
1292                        __lr: buf.read_u32::<O>()?,
1293                        __pc: buf.read_u32::<O>()?,
1294                        __cpsr: buf.read_u32::<O>()?,
1295                    },
1296                }
1297            }
1298            LC_UNIXTHREAD if header.cputype == CPU_TYPE_ARM64 => {
1299                let flavor = buf.read_u32::<O>()?;
1300                let count = buf.read_u32::<O>()?;
1301                let mut __x = [0u64; 29];
1302
1303                buf.read_u64_into::<O>(&mut __x)?;
1304
1305                LoadCommand::UnixThread {
1306                    flavor,
1307                    count,
1308                    state: ThreadState::Arm64 {
1309                        __x,
1310                        __fp: buf.read_u64::<O>()?,
1311                        __lr: buf.read_u64::<O>()?,
1312                        __sp: buf.read_u64::<O>()?,
1313                        __pc: buf.read_u64::<O>()?,
1314                        __cpsr: buf.read_u32::<O>()?,
1315                        __pad: buf.read_u32::<O>()?,
1316                    },
1317                }
1318            }
1319            LC_UNIXTHREAD if header.cputype == CPU_TYPE_POWERPC => {
1320                let flavor = buf.read_u32::<O>()?;
1321                let count = buf.read_u32::<O>()?;
1322                let mut __srr = [0u32; 2];
1323                let mut __r = [0u32; 32];
1324
1325                buf.read_u32_into::<O>(&mut __srr)?;
1326                buf.read_u32_into::<O>(&mut __r)?;
1327
1328                LoadCommand::UnixThread {
1329                    flavor,
1330                    count,
1331                    state: ThreadState::PowerPC {
1332                        __srr,
1333                        __r,
1334                        __ct: buf.read_u32::<O>()?,
1335                        __xer: buf.read_u32::<O>()?,
1336                        __lr: buf.read_u32::<O>()?,
1337                        __ctr: buf.read_u32::<O>()?,
1338                        __mq: buf.read_u32::<O>()?,
1339                        __vrsave: buf.read_u32::<O>()?,
1340                    },
1341                }
1342            }
1343            LC_UNIXTHREAD if header.cputype == CPU_TYPE_POWERPC64 => {
1344                let flavor = buf.read_u32::<O>()?;
1345                let count = buf.read_u32::<O>()?;
1346                let mut __srr = [0u64; 2];
1347                let mut __r = [0u64; 32];
1348
1349                buf.read_u64_into::<O>(&mut __srr)?;
1350                buf.read_u64_into::<O>(&mut __r)?;
1351
1352                LoadCommand::UnixThread {
1353                    flavor,
1354                    count,
1355                    state: ThreadState::PowerPC64 {
1356                        __srr,
1357                        __r,
1358                        __cr: buf.read_u32::<O>()?,
1359                        __xer: buf.read_u64::<O>()?,
1360                        __lr: buf.read_u64::<O>()?,
1361                        __ctr: buf.read_u64::<O>()?,
1362                        __vrsave: buf.read_u32::<O>()?,
1363                    },
1364                }
1365            }
1366            LC_SUB_FRAMEWORK => LoadCommand::SubFramework(Self::read_lcstr::<O, T>(buf)?),
1367            LC_SUB_UMBRELLA => LoadCommand::SubUmbrella(Self::read_lcstr::<O, T>(buf)?),
1368            LC_SUB_CLIENT => LoadCommand::SubClient(Self::read_lcstr::<O, T>(buf)?),
1369            LC_SUB_LIBRARY => LoadCommand::SubLibrary(Self::read_lcstr::<O, T>(buf)?),
1370            LC_LINKER_OPTION => {
1371                let count = buf.read_u32::<O>()?;
1372
1373                LoadCommand::LinkerOption(
1374                    (0..count)
1375                        .map(|_| Self::read_utf8_str(buf))
1376                        .collect::<Result<Vec<_>>>()?,
1377                )
1378            }
1379            LC_ROUTINES => LoadCommand::Routines {
1380                init_address: buf.read_u32::<O>()?,
1381                init_module: buf.read_u32::<O>()?,
1382            },
1383            LC_ROUTINES_64 => LoadCommand::Routines64 {
1384                init_address: buf.read_u64::<O>()?,
1385                init_module: buf.read_u64::<O>()?,
1386            },
1387            LC_ENCRYPTION_INFO => LoadCommand::EncryptionInfo {
1388                offset: buf.read_u32::<O>()?,
1389                size: buf.read_u32::<O>()?,
1390                id: buf.read_u32::<O>()?,
1391            },
1392            LC_ENCRYPTION_INFO_64 => LoadCommand::EncryptionInfo64 {
1393                offset: buf.read_u32::<O>()?,
1394                size: buf.read_u32::<O>()?,
1395                id: buf.read_u32::<O>()?,
1396            },
1397            LC_TWOLEVEL_HINTS => LoadCommand::TwoLevelHints {
1398                offset: buf.read_u32::<O>()?,
1399                nhints: buf.read_u32::<O>()?,
1400            },
1401            LC_BUILD_VERSION => LoadCommand::BuildVersion(BuildVersion {
1402                platform: buf.read_u32::<O>()?,
1403                minos: VersionTag(buf.read_u32::<O>()?),
1404                sdk: VersionTag(buf.read_u32::<O>()?),
1405                build_tools: (0..buf.read_u32::<O>()?)
1406                    .map(|_| {
1407                        let tool = buf.read_u32::<O>()?;
1408                        let version = VersionTag(buf.read_u32::<O>()?);
1409
1410                        Ok(BuildTool { tool, version })
1411                    })
1412                    .collect::<Result<Vec<_>>>()?,
1413            }),
1414            _ => {
1415                let mut payload = vec![0; cmdsize as usize - LOAD_COMMAND_HEADER_SIZE];
1416
1417                debug!(
1418                    "load unsupported {} command with {} bytes payload",
1419                    LoadCommand::cmd_name(cmd),
1420                    payload.len()
1421                );
1422
1423                buf.read_exact(&mut payload)?;
1424
1425                LoadCommand::Command { cmd, payload }
1426            }
1427        };
1428
1429        let read = (buf.position() - begin) as usize;
1430
1431        debug!(
1432            "parsed {} command with {}/{} bytes: {:?}",
1433            cmd.name(),
1434            read,
1435            cmdsize,
1436            cmd
1437        );
1438
1439        if cmdsize < read {
1440            return Err(BufferOverflow(cmdsize));
1441        }
1442
1443        if cmdsize > read {
1444            // skip the reserved or padding bytes
1445            buf.consume(cmdsize - read);
1446        }
1447
1448        Ok((cmd, cmdsize))
1449    }
1450
1451    fn read_lcstr<O: ByteOrder, T: AsRef<[u8]>>(buf: &mut Cursor<T>) -> Result<LcString> {
1452        let off = buf.read_u32::<O>()? as usize;
1453
1454        buf.consume(off - 12);
1455
1456        Ok(LcString(off, buf.read_cstr()?))
1457    }
1458
1459    fn read_utf8_str<T: AsRef<[u8]>>(cur: &mut Cursor<T>) -> Result<String> {
1460        let mut buf = vec![];
1461
1462        cur.read_until(0, &mut buf)?;
1463
1464        if buf.last() == Some(&0) {
1465            let _ = buf.pop();
1466        }
1467
1468        Ok(String::from_utf8(buf)?)
1469    }
1470
1471    fn read_fvmlib<O: ByteOrder, T: AsRef<[u8]>>(buf: &mut Cursor<T>) -> Result<FvmLib> {
1472        let off = buf.read_u32::<O>()? as usize;
1473        let minor_version = buf.read_u32::<O>()?;
1474        let header_addr = buf.read_u32::<O>()?;
1475
1476        buf.consume(off - 20);
1477
1478        Ok(FvmLib {
1479            name: LcString(off, buf.read_cstr()?),
1480            minor_version,
1481            header_addr,
1482        })
1483    }
1484
1485    fn read_dylib<O: ByteOrder, T: AsRef<[u8]>>(buf: &mut Cursor<T>) -> Result<DyLib> {
1486        let off = buf.read_u32::<O>()? as usize;
1487        let timestamp = buf.read_u32::<O>()?;
1488        let current_version = buf.read_u32::<O>()?;
1489        let compatibility_version = buf.read_u32::<O>()?;
1490
1491        buf.consume(off - 24);
1492
1493        Ok(DyLib {
1494            name: LcString(off, buf.read_cstr()?),
1495            timestamp,
1496            current_version: VersionTag(current_version),
1497            compatibility_version: VersionTag(compatibility_version),
1498        })
1499    }
1500
1501    fn read_linkedit_data<O: ByteOrder, T: AsRef<[u8]>>(buf: &mut Cursor<T>) -> Result<LinkEditData> {
1502        Ok(LinkEditData {
1503            off: buf.read_u32::<O>()?,
1504            size: buf.read_u32::<O>()?,
1505        })
1506    }
1507
1508    pub fn cmd(&self) -> u32 {
1509        match *self {
1510            LoadCommand::Segment { .. } => LC_SEGMENT,
1511            LoadCommand::Segment64 { .. } => LC_SEGMENT_64,
1512            LoadCommand::IdFvmLib(_) => LC_IDFVMLIB,
1513            LoadCommand::LoadFvmLib(_) => LC_LOADFVMLIB,
1514            LoadCommand::IdDyLib(_) => LC_ID_DYLIB,
1515            LoadCommand::LoadDyLib(_) => LC_LOAD_DYLIB,
1516            LoadCommand::LoadWeakDyLib(_) => LC_LOAD_WEAK_DYLIB,
1517            LoadCommand::ReexportDyLib(_) => LC_REEXPORT_DYLIB,
1518            LoadCommand::LoadUpwardDylib(_) => LC_LOAD_UPWARD_DYLIB,
1519            LoadCommand::LazyLoadDylib(_) => LC_LAZY_LOAD_DYLIB,
1520            LoadCommand::Rpath(_) => LC_RPATH,
1521            LoadCommand::IdDyLinker(_) => LC_ID_DYLINKER,
1522            LoadCommand::LoadDyLinker(_) => LC_LOAD_DYLINKER,
1523            LoadCommand::DyLdEnv(_) => LC_DYLD_ENVIRONMENT,
1524            LoadCommand::SymTab { .. } => LC_SYMTAB,
1525            LoadCommand::DySymTab { .. } => LC_DYSYMTAB,
1526            LoadCommand::Uuid(_) => LC_UUID,
1527            LoadCommand::CodeSignature(_) => LC_CODE_SIGNATURE,
1528            LoadCommand::SegmentSplitInfo(_) => LC_SEGMENT_SPLIT_INFO,
1529            LoadCommand::FunctionStarts(_) => LC_FUNCTION_STARTS,
1530            LoadCommand::DataInCode(_) => LC_DATA_IN_CODE,
1531            LoadCommand::DylibCodeSignDrs(_) => LC_DYLIB_CODE_SIGN_DRS,
1532            LoadCommand::LinkerOptimizationHint(_) => LC_LINKER_OPTIMIZATION_HINT,
1533            LoadCommand::VersionMin { target, .. } => BuildTarget::into(target),
1534            LoadCommand::DyldInfo { .. } => LC_DYLD_INFO_ONLY,
1535            LoadCommand::EntryPoint { .. } => LC_MAIN,
1536            LoadCommand::SourceVersion(_) => LC_SOURCE_VERSION,
1537            LoadCommand::UnixThread { .. } => LC_UNIXTHREAD,
1538            LoadCommand::SubFramework(_) => LC_SUB_FRAMEWORK,
1539            LoadCommand::SubUmbrella(_) => LC_SUB_UMBRELLA,
1540            LoadCommand::SubClient(_) => LC_SUB_CLIENT,
1541            LoadCommand::SubLibrary(_) => LC_SUB_LIBRARY,
1542            LoadCommand::LinkerOption(_) => LC_LINKER_OPTION,
1543            LoadCommand::Routines { .. } => LC_ROUTINES,
1544            LoadCommand::Routines64 { .. } => LC_ROUTINES_64,
1545            LoadCommand::EncryptionInfo { .. } => LC_ENCRYPTION_INFO,
1546            LoadCommand::EncryptionInfo64 { .. } => LC_ENCRYPTION_INFO_64,
1547            LoadCommand::TwoLevelHints { .. } => LC_TWOLEVEL_HINTS,
1548            LoadCommand::BuildVersion { .. } => LC_BUILD_VERSION,
1549            LoadCommand::DyldExportsTrie { .. } => LC_DYLD_EXPORTS_TRIE,
1550            LoadCommand::DyldChainedFixups { .. } => LC_DYLD_CHAINED_FIXUPS,
1551            LoadCommand::Command { cmd, .. } => cmd,
1552        }
1553    }
1554
1555    pub fn name(&self) -> &'static str {
1556        Self::cmd_name(self.cmd())
1557    }
1558
1559    fn cmd_name(cmd: u32) -> &'static str {
1560        match cmd {
1561            LC_SEGMENT => "LC_SEGMENT",
1562            LC_SYMTAB => "LC_SYMTAB",
1563            LC_SYMSEG => "LC_SYMSEG",
1564            LC_THREAD => "LC_THREAD",
1565            LC_UNIXTHREAD => "LC_UNIXTHREAD",
1566            LC_LOADFVMLIB => "LC_LOADFVMLIB",
1567            LC_IDFVMLIB => "LC_IDFVMLIB",
1568            LC_IDENT => "LC_IDENT",
1569            LC_FVMFILE => "LC_FVMFILE",
1570            LC_PREPAGE => "LC_PREPAGE",
1571            LC_DYSYMTAB => "LC_DYSYMTAB",
1572            LC_LOAD_DYLIB => "LC_LOAD_DYLIB",
1573            LC_ID_DYLIB => "LC_ID_DYLIB",
1574            LC_LOAD_DYLINKER => "LC_LOAD_DYLINKER",
1575            LC_ID_DYLINKER => "LC_ID_DYLINKER",
1576            LC_PREBOUND_DYLIB => "LC_PREBOUND_DYLIB",
1577            LC_ROUTINES => "LC_ROUTINES",
1578            LC_SUB_FRAMEWORK => "LC_SUB_FRAMEWORK",
1579            LC_SUB_UMBRELLA => "LC_SUB_UMBRELLA",
1580            LC_SUB_CLIENT => "LC_SUB_CLIENT",
1581            LC_SUB_LIBRARY => "LC_SUB_LIBRARY",
1582            LC_TWOLEVEL_HINTS => "LC_TWOLEVEL_HINTS",
1583            LC_PREBIND_CKSUM => "LC_PREBIND_CKSUM",
1584            LC_LOAD_WEAK_DYLIB => "LC_LOAD_WEAK_DYLIB",
1585            LC_SEGMENT_64 => "LC_SEGMENT_64",
1586            LC_ROUTINES_64 => "LC_ROUTINES_64",
1587            LC_UUID => "LC_UUID",
1588            LC_RPATH => "LC_RPATH",
1589            LC_CODE_SIGNATURE => "LC_CODE_SIGNATURE",
1590            LC_SEGMENT_SPLIT_INFO => "LC_SEGMENT_SPLIT_INFO",
1591            LC_REEXPORT_DYLIB => "LC_REEXPORT_DYLIB",
1592            LC_LAZY_LOAD_DYLIB => "LC_LAZY_LOAD_DYLIB",
1593            LC_ENCRYPTION_INFO => "LC_ENCRYPTION_INFO",
1594            LC_DYLD_INFO => "LC_DYLD_INFO",
1595            LC_DYLD_INFO_ONLY => "LC_DYLD_INFO_ONLY",
1596            LC_LOAD_UPWARD_DYLIB => "LC_LOAD_UPWARD_DYLIB",
1597            LC_VERSION_MIN_MACOSX => "LC_VERSION_MIN_MACOSX",
1598            LC_VERSION_MIN_IPHONEOS => "LC_VERSION_MIN_IPHONEOS",
1599            LC_FUNCTION_STARTS => "LC_FUNCTION_STARTS",
1600            LC_DYLD_ENVIRONMENT => "LC_DYLD_ENVIRONMENT",
1601            LC_MAIN => "LC_MAIN",
1602            LC_DATA_IN_CODE => "LC_DATA_IN_CODE",
1603            LC_SOURCE_VERSION => "LC_SOURCE_VERSION",
1604            LC_DYLIB_CODE_SIGN_DRS => "LC_DYLIB_CODE_SIGN_DRS",
1605            LC_ENCRYPTION_INFO_64 => "LC_ENCRYPTION_INFO_64",
1606            LC_LINKER_OPTION => "LC_LINKER_OPTION",
1607            LC_LINKER_OPTIMIZATION_HINT => "LC_LINKER_OPTIMIZATION_HINT",
1608            LC_VERSION_MIN_TVOS => "LC_VERSION_MIN_TVOS",
1609            LC_VERSION_MIN_WATCHOS => "LC_VERSION_MIN_WATCHOS",
1610            LC_NOTE => "LC_NOTE",
1611            LC_BUILD_VERSION => "LC_BUILD_VERSION",
1612            LC_DYLD_EXPORTS_TRIE => "LC_DYLD_EXPORTS_TRIE",
1613            LC_DYLD_CHAINED_FIXUPS => "LC_DYLD_CHAINED_FIXUPS",
1614            _ => "LC_COMMAND",
1615        }
1616    }
1617}
1618
1619pub trait CursorExt<T: AsRef<[u8]>> {
1620    fn read_uleb128(&mut self) -> Result<usize>;
1621
1622    fn read_cstr(&mut self) -> Result<String>;
1623}
1624
1625impl<T> CursorExt<T> for Cursor<T>
1626where
1627    T: AsRef<[u8]>,
1628{
1629    fn read_uleb128(&mut self) -> Result<usize> {
1630        let mut v = 0;
1631        let mut bits = 0;
1632
1633        loop {
1634            let b = self.read_u8()?;
1635            let n = usize::from(b & 0x7F);
1636
1637            if bits > 63 {
1638                return Err(NumberOverflow);
1639            }
1640
1641            v |= n << bits;
1642            bits += 7;
1643
1644            if (b & 0x80) == 0 {
1645                break;
1646            }
1647        }
1648
1649        Ok(v)
1650    }
1651
1652    fn read_cstr(&mut self) -> Result<String> {
1653        let mut v = Vec::new();
1654
1655        self.read_until(0, &mut v)?;
1656
1657        Ok(String::from_utf8(v.split(|&b| b == 0).next().unwrap().to_vec())?)
1658    }
1659}
1660
1661/// The flags field of a section structure is separated into two parts a section
1662/// type and section attributes.
1663///
1664/// The section types are mutually exclusive (it can only have one type)
1665/// but the section attributes are not (it may have more than one attribute).
1666///
1667#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1668pub struct SectionFlags(u32);
1669
1670impl SectionFlags {
1671    pub fn sect_type(self) -> u32 {
1672        self.0 & SECTION_TYPE
1673    }
1674
1675    pub fn sect_attrs(self) -> SectionAttributes {
1676        SectionAttributes::from_bits_truncate(self.0 & SECTION_ATTRIBUTES)
1677    }
1678}
1679
1680impl From<SectionFlags> for u32 {
1681    fn from(f: SectionFlags) -> u32 {
1682        f.0
1683    }
1684}
1685
1686/// A segment is made up of zero or more sections.
1687///
1688/// `Non-MH_OBJECT` files have all of their segments with the proper sections in each,
1689/// and padded to the specified segment alignment when produced by the link editor.
1690/// The first segment of a `MH_EXECUTE` and `MH_FVMLIB` format file contains the mach header
1691/// and load commands of the object file before its first section.  The zero
1692/// fill sections are always last in their segment (in all formats).  This
1693/// allows the zeroed segment padding to be mapped into memory where zero fill
1694/// sections might be. The gigabyte zero fill sections, those with the section
1695/// type `S_GB_ZEROFILL`, can only be in a segment with sections of this type.
1696/// These segments are then placed after all other segments.
1697///
1698/// The `MH_OBJECT` format has all of its sections in one segment for
1699/// compactness.  There is no padding to a specified segment boundary and the
1700/// mach header and load commands are not part of the segment.
1701///
1702/// Sections with the same section name, sectname, going into the same segment,
1703/// segname, are combined by the link editor.  The resulting section is aligned
1704/// to the maximum alignment of the combined sections and is the new section's
1705/// alignment.  The combined sections are aligned to their original alignment in
1706/// the combined section.  Any padded bytes to get the specified alignment are
1707/// zeroed.
1708///
1709/// The format of the relocation entries referenced by the reloff and nreloc
1710/// fields of the section structure for mach object files is described in the
1711/// header file <reloc.h>.
1712///
1713///
1714#[derive(Debug, Clone)]
1715pub struct Section {
1716    /// name of this section
1717    pub sectname: String,
1718    /// segment this section goes in
1719    pub segname: String,
1720    /// memory address of this section
1721    pub addr: usize,
1722    /// size in bytes of this section
1723    pub size: usize,
1724    /// file offset of this section
1725    pub offset: u32,
1726    /// section alignment (power of 2)
1727    pub align: u32,
1728    /// file offset of relocation entries
1729    pub reloff: u32,
1730    /// number of relocation entries
1731    pub nreloc: u32,
1732    // flags (section type and attributes)
1733    pub flags: SectionFlags,
1734    /// reserved (for offset or index)
1735    pub reserved1: u32,
1736    /// reserved (for count or sizeof)
1737    pub reserved2: u32,
1738    /// reserved
1739    pub reserved3: u32,
1740}
1741
1742impl Section {
1743    fn parse_section<T: BufRead, O: ByteOrder>(buf: &mut T) -> Result<Section> {
1744        let section = Section {
1745            sectname: buf.read_fixed_size_string(16)?,
1746            segname: buf.read_fixed_size_string(16)?,
1747            addr: buf.read_u32::<O>()? as usize,
1748            size: buf.read_u32::<O>()? as usize,
1749            offset: buf.read_u32::<O>()?,
1750            align: buf.read_u32::<O>()?,
1751            reloff: buf.read_u32::<O>()?,
1752            nreloc: buf.read_u32::<O>()?,
1753            flags: SectionFlags(buf.read_u32::<O>()?),
1754            reserved1: buf.read_u32::<O>()?,
1755            reserved2: buf.read_u32::<O>()?,
1756            reserved3: 0,
1757        };
1758
1759        Ok(section)
1760    }
1761
1762    fn parse_section64<T: BufRead, O: ByteOrder>(buf: &mut T) -> Result<Section> {
1763        let section = Section {
1764            sectname: buf.read_fixed_size_string(16)?,
1765            segname: buf.read_fixed_size_string(16)?,
1766            addr: buf.read_u64::<O>()? as usize,
1767            size: buf.read_u64::<O>()? as usize,
1768            offset: buf.read_u32::<O>()?,
1769            align: buf.read_u32::<O>()?,
1770            reloff: buf.read_u32::<O>()?,
1771            nreloc: buf.read_u32::<O>()?,
1772            flags: SectionFlags(buf.read_u32::<O>()?),
1773            reserved1: buf.read_u32::<O>()?,
1774            reserved2: buf.read_u32::<O>()?,
1775            reserved3: buf.read_u32::<O>()?,
1776        };
1777
1778        Ok(section)
1779    }
1780}
1781
1782/// The `LC_DATA_IN_CODE` load commands uses a `LinkEditData`
1783/// to point to an array of `DataInCodeEntry` entries.
1784///
1785/// Each entry describes a range of data in a code section.
1786///
1787pub struct DataInCodeEntry {
1788    pub offset: u32, // from mach_header to start of data range
1789    pub length: u16, // number of bytes in data range
1790    pub kind: u16,   // a DICE_KIND_* value
1791}
1792
1793#[cfg(test)]
1794pub mod tests {
1795    use std::io::Cursor;
1796
1797    use byteorder::LittleEndian;
1798
1799    use super::super::*;
1800
1801    include!("testdata.rs");
1802
1803    macro_rules! parse_command {
1804        ($buf:expr) => {{
1805            let header = MachHeader::default();
1806            let mut buf = Vec::new();
1807
1808            buf.extend_from_slice(&$buf[..]);
1809
1810            let mut cur = Cursor::new(buf);
1811
1812            LoadCommand::parse::<LittleEndian, Vec<u8>>(&header, &mut cur).unwrap()
1813        }};
1814    }
1815
1816    #[test]
1817    fn test_parse_segments() {
1818        if let (
1819            LoadCommand::Segment64 {
1820                ref segname,
1821                vmaddr,
1822                vmsize,
1823                fileoff,
1824                filesize,
1825                maxprot,
1826                initprot,
1827                flags,
1828                ref sections,
1829            },
1830            cmdsize,
1831        ) = parse_command!(LC_SEGMENT_64_PAGEZERO_DATA)
1832        {
1833            assert_eq!(cmdsize, 72);
1834            assert_eq!(segname, SEG_PAGEZERO);
1835            assert_eq!(vmaddr, 0);
1836            assert_eq!(vmsize, 0x0000000100000000);
1837            assert_eq!(fileoff, 0);
1838            assert_eq!(filesize, 0);
1839            assert_eq!(maxprot, 0);
1840            assert_eq!(initprot, 0);
1841            assert!(flags.is_empty());
1842            assert!(sections.is_empty());
1843        } else {
1844            panic!();
1845        }
1846
1847        if let (
1848            LoadCommand::Segment64 {
1849                ref segname,
1850                vmaddr,
1851                vmsize,
1852                fileoff,
1853                filesize,
1854                maxprot,
1855                initprot,
1856                flags,
1857                ref sections,
1858            },
1859            cmdsize,
1860        ) = parse_command!(LC_SEGMENT_64_TEXT_DATA)
1861        {
1862            assert_eq!(cmdsize, 712);
1863            assert_eq!(segname, SEG_TEXT);
1864            assert_eq!(vmaddr, 0x0000000100000000);
1865            assert_eq!(vmsize, 0x00000000001e3000);
1866            assert_eq!(fileoff, 0);
1867            assert_eq!(filesize, 0x1e3000);
1868            assert_eq!(maxprot, 7);
1869            assert_eq!(initprot, 5);
1870            assert!(flags.is_empty());
1871            assert_eq!(sections.len(), 8);
1872
1873            assert_eq!(
1874                sections
1875                    .iter()
1876                    .map(|ref sec| (*sec).sectname.clone())
1877                    .collect::<Vec<String>>(),
1878                vec![
1879                    SECT_TEXT,
1880                    "__stubs",
1881                    "__stub_helper",
1882                    "__gcc_except_tab",
1883                    "__const",
1884                    "__cstring",
1885                    "__unwind_info",
1886                    "__eh_frame",
1887                ]
1888            );
1889        } else {
1890            panic!();
1891        }
1892
1893        if let (
1894            LoadCommand::Segment64 {
1895                ref segname,
1896                vmaddr,
1897                vmsize,
1898                fileoff,
1899                filesize,
1900                maxprot,
1901                initprot,
1902                flags,
1903                ref sections,
1904            },
1905            cmdsize,
1906        ) = parse_command!(LC_SEGMENT_64_DATA_DATA)
1907        {
1908            assert_eq!(cmdsize, 872);
1909            assert_eq!(segname, SEG_DATA);
1910            assert_eq!(vmaddr, 0x00000001001e3000);
1911            assert_eq!(vmsize, 0x0000000000013000);
1912            assert_eq!(fileoff, 0x1e3000);
1913            assert_eq!(filesize, 0x12000);
1914            assert_eq!(maxprot, 7);
1915            assert_eq!(initprot, 3);
1916            assert!(flags.is_empty());
1917            assert_eq!(sections.len(), 10);
1918
1919            assert_eq!(
1920                sections
1921                    .iter()
1922                    .map(|ref sec| (*sec).sectname.clone())
1923                    .collect::<Vec<String>>(),
1924                vec![
1925                    "__nl_symbol_ptr",
1926                    "__got",
1927                    "__la_symbol_ptr",
1928                    "__mod_init_func",
1929                    "__const",
1930                    SECT_DATA,
1931                    "__thread_vars",
1932                    "__thread_data",
1933                    SECT_COMMON,
1934                    SECT_BSS,
1935                ]
1936            );
1937        } else {
1938            panic!();
1939        }
1940
1941        if let (
1942            LoadCommand::Segment64 {
1943                ref segname,
1944                vmaddr,
1945                vmsize,
1946                fileoff,
1947                filesize,
1948                maxprot,
1949                initprot,
1950                flags,
1951                ref sections,
1952            },
1953            cmdsize,
1954        ) = parse_command!(LC_SEGMENT_64_LINKEDIT_DATA)
1955        {
1956            assert_eq!(cmdsize, 72);
1957            assert_eq!(segname, SEG_LINKEDIT);
1958            assert_eq!(vmaddr, 0x00000001001f6000);
1959            assert_eq!(vmsize, 0x000000000017a000);
1960            assert_eq!(fileoff, 0x1f5000);
1961            assert_eq!(filesize, 0x1790b4);
1962            assert_eq!(maxprot, 7);
1963            assert_eq!(initprot, 1);
1964            assert!(flags.is_empty());
1965            assert!(sections.is_empty());
1966        } else {
1967            panic!();
1968        }
1969    }
1970
1971    #[test]
1972    fn test_parse_dyld_info_command() {
1973        if let (
1974            LoadCommand::DyldInfo {
1975                rebase_off,
1976                rebase_size,
1977                bind_off,
1978                bind_size,
1979                weak_bind_off,
1980                weak_bind_size,
1981                lazy_bind_off,
1982                lazy_bind_size,
1983                export_off,
1984                export_size,
1985            },
1986            cmdsize,
1987        ) = parse_command!(LC_DYLD_INFO_ONLY_DATA)
1988        {
1989            assert_eq!(cmdsize, 48);
1990            assert_eq!(rebase_off, 0x1f5000);
1991            assert_eq!(rebase_size, 3368);
1992            assert_eq!(bind_off, 0x1f5d28);
1993            assert_eq!(bind_size, 80);
1994            assert_eq!(weak_bind_off, 0x1f5d78);
1995            assert_eq!(weak_bind_size, 24);
1996            assert_eq!(lazy_bind_off, 0x1f5d90);
1997            assert_eq!(lazy_bind_size, 1688);
1998            assert_eq!(export_off, 0x1f6428);
1999            assert_eq!(export_size, 34856);
2000        } else {
2001            panic!();
2002        }
2003    }
2004
2005    #[test]
2006    fn test_parse_symtab_command() {
2007        if let (
2008            LoadCommand::SymTab {
2009                symoff,
2010                nsyms,
2011                stroff,
2012                strsize,
2013            },
2014            cmdsize,
2015        ) = parse_command!(LC_SYMTAB_DATA)
2016        {
2017            assert_eq!(cmdsize, 24);
2018            assert_eq!(symoff, 0x200d88);
2019            assert_eq!(nsyms, 36797);
2020            assert_eq!(stroff, 0x290bf4);
2021            assert_eq!(strsize, 906432);
2022        } else {
2023            panic!();
2024        }
2025    }
2026
2027    #[test]
2028    fn test_parse_dysymtab_command() {
2029        if let (
2030            LoadCommand::DySymTab {
2031                ilocalsym,
2032                nlocalsym,
2033                iextdefsym,
2034                nextdefsym,
2035                iundefsym,
2036                nundefsym,
2037                tocoff,
2038                ntoc,
2039                modtaboff,
2040                nmodtab,
2041                extrefsymoff,
2042                nextrefsyms,
2043                indirectsymoff,
2044                nindirectsyms,
2045                extreloff,
2046                nextrel,
2047                locreloff,
2048                nlocrel,
2049            },
2050            cmdsize,
2051        ) = parse_command!(LC_DYSYMTAB_DATA)
2052        {
2053            assert_eq!(cmdsize, 80);
2054            assert_eq!(ilocalsym, 0);
2055            assert_eq!(nlocalsym, 35968);
2056            assert_eq!(iextdefsym, 35968);
2057            assert_eq!(nextdefsym, 746);
2058            assert_eq!(iundefsym, 36714);
2059            assert_eq!(nundefsym, 83);
2060            assert_eq!(tocoff, 0);
2061            assert_eq!(ntoc, 0);
2062            assert_eq!(modtaboff, 0);
2063            assert_eq!(nmodtab, 0);
2064            assert_eq!(extrefsymoff, 0);
2065            assert_eq!(nextrefsyms, 0);
2066            assert_eq!(indirectsymoff, 2689368);
2067            assert_eq!(nindirectsyms, 167);
2068            assert_eq!(extreloff, 0);
2069            assert_eq!(nextrel, 0);
2070            assert_eq!(locreloff, 0);
2071            assert_eq!(nlocrel, 0);
2072        } else {
2073            panic!();
2074        }
2075    }
2076
2077    #[test]
2078    fn test_parse_load_dylinker_command() {
2079        if let (LoadCommand::LoadDyLinker(LcString(off, ref name)), cmdsize) = parse_command!(LC_LOAD_DYLINKER_DATA) {
2080            assert_eq!(cmdsize, 32);
2081            assert_eq!(off, 12);
2082            assert_eq!(name, "/usr/lib/dyld");
2083        } else {
2084            panic!();
2085        }
2086    }
2087
2088    #[test]
2089    fn test_parse_uuid_command() {
2090        if let (LoadCommand::Uuid(ref uuid), cmdsize) = parse_command!(LC_UUID_DATA) {
2091            assert_eq!(cmdsize, 24);
2092            assert_eq!(uuid.to_string(), "92e3cf1f-20da-3373-a98c-851366d353bf");
2093        } else {
2094            panic!();
2095        }
2096    }
2097
2098    #[test]
2099    fn test_parse_min_version_command() {
2100        if let (LoadCommand::VersionMin { target, version, sdk }, cmdsize) = parse_command!(LC_VERSION_MIN_MACOSX_DATA)
2101        {
2102            assert_eq!(cmdsize, 16);
2103            assert_eq!(target, BuildTarget::MacOsX);
2104            assert_eq!(version.to_string(), "10.11");
2105            assert_eq!(sdk.to_string(), "10.11");
2106        } else {
2107            panic!();
2108        }
2109    }
2110
2111    #[test]
2112    fn test_parse_source_version_command() {
2113        if let (LoadCommand::SourceVersion(version), cmdsize) = parse_command!(LC_SOURCE_VERSION_DATA) {
2114            assert_eq!(cmdsize, 16);
2115            assert_eq!(version.to_string(), "0.0");
2116        } else {
2117            panic!();
2118        }
2119    }
2120
2121    #[test]
2122    fn test_parse_main_command() {
2123        if let (LoadCommand::EntryPoint { entryoff, stacksize }, cmdsize) = parse_command!(LC_MAIN_DATA) {
2124            assert_eq!(cmdsize, 24);
2125            assert_eq!(entryoff, 0x11400);
2126            assert_eq!(stacksize, 0);
2127        } else {
2128            panic!();
2129        }
2130    }
2131
2132    #[test]
2133    fn test_load_dylib_command() {
2134        if let (LoadCommand::LoadDyLib(ref dylib), cmdsize) = parse_command!(LC_LOAD_DYLIB_DATA) {
2135            assert_eq!(cmdsize, 56);
2136            assert_eq!(dylib.name, LcString(24, String::from("/usr/lib/libSystem.B.dylib")));
2137            assert_eq!(dylib.timestamp, 2);
2138            assert_eq!(dylib.current_version.to_string(), "1226.10.1");
2139            assert_eq!(dylib.compatibility_version.to_string(), "1.0");
2140        } else {
2141            panic!();
2142        }
2143    }
2144
2145    #[test]
2146    fn test_parse_link_edit_data_command() {
2147        if let (LoadCommand::FunctionStarts(LinkEditData { off, size }), cmdsize) =
2148            parse_command!(LC_FUNCTION_STARTS_DATA)
2149        {
2150            assert_eq!(cmdsize, 16);
2151            assert_eq!(off, 0x1fec50);
2152            assert_eq!(size, 8504);
2153        } else {
2154            panic!();
2155        }
2156
2157        if let (LoadCommand::DataInCode(LinkEditData { off, size }), cmdsize) = parse_command!(LC_DATA_IN_CODE_DATA) {
2158            assert_eq!(cmdsize, 16);
2159            assert_eq!(off, 0x200d88);
2160            assert_eq!(size, 0);
2161        } else {
2162            panic!();
2163        }
2164    }
2165
2166    #[test]
2167    fn test_parse_rpath_command() {
2168        if let (LoadCommand::Rpath(path), cmdsize) = parse_command!(LC_RPATH_DATA) {
2169            assert_eq!(cmdsize, 64);
2170            assert_eq!(path, "@executable_path/../../Library/PrivateFrameworks");
2171        } else {
2172            panic!()
2173        }
2174    }
2175
2176    #[cfg(feature = "display")]
2177    #[test]
2178    fn test_build_version_command() {
2179        let (cmd, cmdsize) = parse_command!(LC_BUILD_VERSION);
2180
2181        if let LoadCommand::BuildVersion(ref version) = cmd {
2182            assert_eq!(cmdsize, 32);
2183            assert_eq!(version.platform(), Platform::Other(8));
2184            assert_eq!(version.minos.to_string(), "12.0");
2185            assert_eq!(version.sdk.to_string(), "12.0");
2186            assert_eq!(
2187                version.build_tools,
2188                vec![BuildTool {
2189                    tool: 3,
2190                    version: "409.10.0".parse().unwrap()
2191                }]
2192            );
2193        } else {
2194            panic!()
2195        }
2196
2197        assert_eq!(
2198            MachCommand(cmd, cmdsize).to_string(),
2199            "      cmd LC_BUILD_VERSION
2200  cmdsize 32
2201 platform Other(8)
2202    minos 12.0
2203      sdk 12.0
2204    tools
2205          LD 409.10
2206"
2207        );
2208    }
2209}