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}