ruby-macho 0.2.6 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 090544df5b83590546313bc137f4b55c1e6d270a
4
- data.tar.gz: 0d0a63b966d573b4dccb87e5ae2e9bd4cf085b40
3
+ metadata.gz: 5c4525869d67df12f84b98120b7a0e28cd2e554b
4
+ data.tar.gz: 007fa710b4d119fe5bb477d4dea2c51664ddbb8d
5
5
  SHA512:
6
- metadata.gz: abc929ddc16551d654a75234565d1bc07ced095b3c0a22b52439bcd44067458d3704a7f7d26843b475285ecff2e7556aa7ef15e85c7f18daec5cc6f653692870
7
- data.tar.gz: 4ddc78eb70a82da2ba9f1361362089b3066da0ba98aaefc234323cd00b60791eb00783c742ff35c9bd95b843978cdb7cfb6a6e642a1e415015083008588a6363
6
+ metadata.gz: c90ef356d11b1c19b28703ef5a45ef2f1f999a7836ec126b4106a17dcc39630b825a8cd860cbd70c6c31225182c348eb5d1b2f0579fe9ecc072ce39a0ffc0c7c
7
+ data.tar.gz: a8bb43dd63755f1b1db1f1e3bfc23120d88f41020aa021dea91db9c8e2c7a2e14d7c5182bf2bb315c09236decba982202461a57f8b670ee78d57e1a40b04b874
data/README.md CHANGED
@@ -14,9 +14,6 @@ executables, dynamic libraries, and so forth.
14
14
 
15
15
  ### Documentation
16
16
 
17
- **Important**: ruby-macho does not have a stable API (yet). Use it with this
18
- in mind.
19
-
20
17
  Full documentation is available on [RubyDoc](http://www.rubydoc.info/gems/ruby-macho/).
21
18
 
22
19
  A quick example of what ruby-macho can do:
@@ -5,7 +5,6 @@ require "#{File.dirname(__FILE__)}/macho/load_commands"
5
5
  require "#{File.dirname(__FILE__)}/macho/sections"
6
6
  require "#{File.dirname(__FILE__)}/macho/macho_file"
7
7
  require "#{File.dirname(__FILE__)}/macho/fat_file"
8
- require "#{File.dirname(__FILE__)}/macho/open"
9
8
  require "#{File.dirname(__FILE__)}/macho/exceptions"
10
9
  require "#{File.dirname(__FILE__)}/macho/utils"
11
10
  require "#{File.dirname(__FILE__)}/macho/tools"
@@ -13,5 +12,29 @@ require "#{File.dirname(__FILE__)}/macho/tools"
13
12
  # The primary namespace for ruby-macho.
14
13
  module MachO
15
14
  # release version
16
- VERSION = "0.2.6".freeze
15
+ VERSION = "1.0.0".freeze
16
+
17
+ # Opens the given filename as a MachOFile or FatFile, depending on its magic.
18
+ # @param filename [String] the file being opened
19
+ # @return [MachO::MachOFile] if the file is a Mach-O
20
+ # @return [MachO::FatFile] if the file is a Fat file
21
+ # @raise [ArgumentError] if the given file does not exist
22
+ # @raise [MachO::TruncatedFileError] if the file is too small to have a valid header
23
+ # @raise [MachO::MagicError] if the file's magic is not valid Mach-O magic
24
+ def self.open(filename)
25
+ raise ArgumentError, "#{filename}: no such file" unless File.file?(filename)
26
+ raise TruncatedFileError unless File.stat(filename).size >= 4
27
+
28
+ magic = File.open(filename, "rb") { |f| f.read(4) }.unpack("N").first
29
+
30
+ if Utils.fat_magic?(magic)
31
+ file = FatFile.new(filename)
32
+ elsif Utils.magic?(magic)
33
+ file = MachOFile.new(filename)
34
+ else
35
+ raise MagicError, magic
36
+ end
37
+
38
+ file
39
+ end
17
40
  end
@@ -7,10 +7,10 @@ module MachO
7
7
  # @return [String] the filename loaded from, or nil if loaded from a binary string
8
8
  attr_accessor :filename
9
9
 
10
- # @return [MachO::FatHeader] the file's header
10
+ # @return [MachO::Headers::FatHeader] the file's header
11
11
  attr_reader :header
12
12
 
13
- # @return [Array<MachO::FatArch>] an array of fat architectures
13
+ # @return [Array<MachO::Headers::FatArch>] an array of fat architectures
14
14
  attr_reader :fat_archs
15
15
 
16
16
  # @return [Array<MachO::MachOFile>] an array of Mach-O binaries
@@ -109,7 +109,7 @@ module MachO
109
109
 
110
110
  # @return [String] a string representation of the file's magic number
111
111
  def magic_string
112
- MH_MAGICS[magic]
112
+ Headers::MH_MAGICS[magic]
113
113
  end
114
114
 
115
115
  # The file's type. Assumed to be the same for every Mach-O within.
@@ -128,7 +128,7 @@ module MachO
128
128
  end
129
129
 
130
130
  # All load commands responsible for loading dylibs in the file's Mach-O's.
131
- # @return [Array<MachO::DylibCommand>] an array of DylibCommands
131
+ # @return [Array<MachO::LoadCommands::DylibCommand>] an array of DylibCommands
132
132
  def dylib_load_commands
133
133
  machos.map(&:dylib_load_commands).flatten
134
134
  end
@@ -280,7 +280,7 @@ module MachO
280
280
  private
281
281
 
282
282
  # Obtain the fat header from raw file data.
283
- # @return [MachO::FatHeader] the fat header
283
+ # @return [MachO::Headers::FatHeader] the fat header
284
284
  # @raise [MachO::TruncatedFileError] if the file is too small to have a valid header
285
285
  # @raise [MachO::MagicError] if the magic is not valid Mach-O magic
286
286
  # @raise [MachO::MachOBinaryError] if the magic is for a non-fat Mach-O file
@@ -290,7 +290,7 @@ module MachO
290
290
  # the smallest fat Mach-O header is 8 bytes
291
291
  raise TruncatedFileError if @raw_data.size < 8
292
292
 
293
- fh = FatHeader.new_from_bin(:big, @raw_data[0, FatHeader.bytesize])
293
+ fh = Headers::FatHeader.new_from_bin(:big, @raw_data[0, Headers::FatHeader.bytesize])
294
294
 
295
295
  raise MagicError, fh.magic unless Utils.magic?(fh.magic)
296
296
  raise MachOBinaryError unless Utils.fat_magic?(fh.magic)
@@ -308,15 +308,15 @@ module MachO
308
308
  end
309
309
 
310
310
  # Obtain an array of fat architectures from raw file data.
311
- # @return [Array<MachO::FatArch>] an array of fat architectures
311
+ # @return [Array<MachO::Headers::FatArch>] an array of fat architectures
312
312
  # @api private
313
313
  def populate_fat_archs
314
314
  archs = []
315
315
 
316
- fa_off = FatHeader.bytesize
317
- fa_len = FatArch.bytesize
316
+ fa_off = Headers::FatHeader.bytesize
317
+ fa_len = Headers::FatArch.bytesize
318
318
  header.nfat_arch.times do |i|
319
- archs << FatArch.new_from_bin(:big, @raw_data[fa_off + (fa_len * i), fa_len])
319
+ archs << Headers::FatArch.new_from_bin(:big, @raw_data[fa_off + (fa_len * i), fa_len])
320
320
  end
321
321
 
322
322
  archs
@@ -1,587 +1,590 @@
1
1
  module MachO
2
- # big-endian fat magic
3
- # @api private
4
- FAT_MAGIC = 0xcafebabe
5
-
6
- # little-endian fat magic
7
- # this is defined, but should never appear in ruby-macho code because
8
- # fat headers are always big-endian and therefore always unpacked as such.
9
- # @api private
10
- FAT_CIGAM = 0xbebafeca
11
-
12
- # 32-bit big-endian magic
13
- # @api private
14
- MH_MAGIC = 0xfeedface
15
-
16
- # 32-bit little-endian magic
17
- # @api private
18
- MH_CIGAM = 0xcefaedfe
19
-
20
- # 64-bit big-endian magic
21
- # @api private
22
- MH_MAGIC_64 = 0xfeedfacf
23
-
24
- # 64-bit little-endian magic
25
- # @api private
26
- MH_CIGAM_64 = 0xcffaedfe
27
-
28
- # association of magic numbers to string representations
29
- # @api private
30
- MH_MAGICS = {
31
- FAT_MAGIC => "FAT_MAGIC",
32
- MH_MAGIC => "MH_MAGIC",
33
- MH_CIGAM => "MH_CIGAM",
34
- MH_MAGIC_64 => "MH_MAGIC_64",
35
- MH_CIGAM_64 => "MH_CIGAM_64",
36
- }.freeze
37
-
38
- # mask for CPUs with 64-bit architectures (when running a 64-bit ABI?)
39
- # @api private
40
- CPU_ARCH_ABI64 = 0x01000000
41
-
42
- # any CPU (unused?)
43
- # @api private
44
- CPU_TYPE_ANY = -1
45
-
46
- # m68k compatible CPUs
47
- # @api private
48
- CPU_TYPE_MC680X0 = 0x06
49
-
50
- # i386 and later compatible CPUs
51
- # @api private
52
- CPU_TYPE_I386 = 0x07
53
-
54
- # x86_64 (AMD64) compatible CPUs
55
- # @api private
56
- CPU_TYPE_X86_64 = (CPU_TYPE_I386 | CPU_ARCH_ABI64)
57
-
58
- # 32-bit ARM compatible CPUs
59
- # @api private
60
- CPU_TYPE_ARM = 0x0c
61
-
62
- # m88k compatible CPUs
63
- # @api private
64
- CPU_TYPE_MC88000 = 0xd
65
-
66
- # 64-bit ARM compatible CPUs
67
- # @api private
68
- CPU_TYPE_ARM64 = (CPU_TYPE_ARM | CPU_ARCH_ABI64)
69
-
70
- # PowerPC compatible CPUs
71
- # @api private
72
- CPU_TYPE_POWERPC = 0x12
73
-
74
- # PowerPC64 compatible CPUs
75
- # @api private
76
- CPU_TYPE_POWERPC64 = (CPU_TYPE_POWERPC | CPU_ARCH_ABI64)
77
-
78
- # association of cpu types to symbol representations
79
- # @api private
80
- CPU_TYPES = {
81
- CPU_TYPE_ANY => :any,
82
- CPU_TYPE_I386 => :i386,
83
- CPU_TYPE_X86_64 => :x86_64,
84
- CPU_TYPE_ARM => :arm,
85
- CPU_TYPE_ARM64 => :arm64,
86
- CPU_TYPE_POWERPC => :ppc,
87
- CPU_TYPE_POWERPC64 => :ppc64,
88
- }.freeze
89
-
90
- # mask for CPU subtype capabilities
91
- # @api private
92
- CPU_SUBTYPE_MASK = 0xff000000
93
-
94
- # 64-bit libraries (undocumented!)
95
- # @see http://llvm.org/docs/doxygen/html/Support_2MachO_8h_source.html
96
- # @api private
97
- CPU_SUBTYPE_LIB64 = 0x80000000
98
-
99
- # the lowest common sub-type for `CPU_TYPE_I386`
100
- # @api private
101
- CPU_SUBTYPE_I386 = 3
102
-
103
- # the i486 sub-type for `CPU_TYPE_I386`
104
- # @api private
105
- CPU_SUBTYPE_486 = 4
106
-
107
- # the i486SX sub-type for `CPU_TYPE_I386`
108
- # @api private
109
- CPU_SUBTYPE_486SX = 132
110
-
111
- # the i586 (P5, Pentium) sub-type for `CPU_TYPE_I386`
112
- # @api private
113
- CPU_SUBTYPE_586 = 5
114
-
115
- # @see CPU_SUBTYPE_586
116
- # @api private
117
- CPU_SUBTYPE_PENT = CPU_SUBTYPE_586
118
-
119
- # the Pentium Pro (P6) sub-type for `CPU_TYPE_I386`
120
- # @api private
121
- CPU_SUBTYPE_PENTPRO = 22
122
-
123
- # the Pentium II (P6, M3?) sub-type for `CPU_TYPE_I386`
124
- # @api private
125
- CPU_SUBTYPE_PENTII_M3 = 54
126
-
127
- # the Pentium II (P6, M5?) sub-type for `CPU_TYPE_I386`
128
- # @api private
129
- CPU_SUBTYPE_PENTII_M5 = 86
130
-
131
- # the Pentium 4 (Netburst) sub-type for `CPU_TYPE_I386`
132
- # @api private
133
- CPU_SUBTYPE_PENTIUM_4 = 10
134
-
135
- # the lowest common sub-type for `CPU_TYPE_MC680X0`
136
- # @api private
137
- CPU_SUBTYPE_MC680X0_ALL = 1
138
-
139
- # @see CPU_SUBTYPE_MC680X0_ALL
140
- # @api private
141
- CPU_SUBTYPE_MC68030 = CPU_SUBTYPE_MC680X0_ALL
142
-
143
- # the 040 subtype for `CPU_TYPE_MC680X0`
144
- # @api private
145
- CPU_SUBTYPE_MC68040 = 2
146
-
147
- # the 030 subtype for `CPU_TYPE_MC680X0`
148
- # @api private
149
- CPU_SUBTYPE_MC68030_ONLY = 3
150
-
151
- # the lowest common sub-type for `CPU_TYPE_X86_64`
152
- # @api private
153
- CPU_SUBTYPE_X86_64_ALL = CPU_SUBTYPE_I386
154
-
155
- # the Haskell sub-type for `CPU_TYPE_X86_64`
156
- # @api private
157
- CPU_SUBTYPE_X86_64_H = 8
158
-
159
- # the lowest common sub-type for `CPU_TYPE_ARM`
160
- # @api private
161
- CPU_SUBTYPE_ARM_ALL = 0
162
-
163
- # the v4t sub-type for `CPU_TYPE_ARM`
164
- # @api private
165
- CPU_SUBTYPE_ARM_V4T = 5
166
-
167
- # the v6 sub-type for `CPU_TYPE_ARM`
168
- # @api private
169
- CPU_SUBTYPE_ARM_V6 = 6
170
-
171
- # the v5 sub-type for `CPU_TYPE_ARM`
172
- # @api private
173
- CPU_SUBTYPE_ARM_V5TEJ = 7
174
-
175
- # the xscale (v5 family) sub-type for `CPU_TYPE_ARM`
176
- # @api private
177
- CPU_SUBTYPE_ARM_XSCALE = 8
178
-
179
- # the v7 sub-type for `CPU_TYPE_ARM`
180
- # @api private
181
- CPU_SUBTYPE_ARM_V7 = 9
182
-
183
- # the v7f (Cortex A9) sub-type for `CPU_TYPE_ARM`
184
- # @api private
185
- CPU_SUBTYPE_ARM_V7F = 10
2
+ # Classes and constants for parsing the headers of Mach-O binaries.
3
+ module Headers
4
+ # big-endian fat magic
5
+ # @api private
6
+ FAT_MAGIC = 0xcafebabe
186
7
 
187
- # the v7s ("Swift") sub-type for `CPU_TYPE_ARM`
188
- # @api private
189
- CPU_SUBTYPE_ARM_V7S = 11
8
+ # little-endian fat magic
9
+ # this is defined, but should never appear in ruby-macho code because
10
+ # fat headers are always big-endian and therefore always unpacked as such.
11
+ # @api private
12
+ FAT_CIGAM = 0xbebafeca
190
13
 
191
- # the v7k ("Kirkwood40") sub-type for `CPU_TYPE_ARM`
192
- # @api private
193
- CPU_SUBTYPE_ARM_V7K = 12
194
-
195
- # the v6m sub-type for `CPU_TYPE_ARM`
196
- # @api private
197
- CPU_SUBTYPE_ARM_V6M = 14
198
-
199
- # the v7m sub-type for `CPU_TYPE_ARM`
200
- # @api private
201
- CPU_SUBTYPE_ARM_V7M = 15
202
-
203
- # the v7em sub-type for `CPU_TYPE_ARM`
204
- # @api private
205
- CPU_SUBTYPE_ARM_V7EM = 16
206
-
207
- # the v8 sub-type for `CPU_TYPE_ARM`
208
- # @api private
209
- CPU_SUBTYPE_ARM_V8 = 13
210
-
211
- # the lowest common sub-type for `CPU_TYPE_ARM64`
212
- # @api private
213
- CPU_SUBTYPE_ARM64_ALL = 0
214
-
215
- # the v8 sub-type for `CPU_TYPE_ARM64`
216
- # @api private
217
- CPU_SUBTYPE_ARM64_V8 = 1
218
-
219
- # the lowest common sub-type for `CPU_TYPE_MC88000`
220
- # @api private
221
- CPU_SUBTYPE_MC88000_ALL = 0
222
-
223
- # @see CPU_SUBTYPE_MC88000_ALL
224
- # @api private
225
- CPU_SUBTYPE_MMAX_JPC = CPU_SUBTYPE_MC88000_ALL
226
-
227
- # the 100 sub-type for `CPU_TYPE_MC88000`
228
- # @api private
229
- CPU_SUBTYPE_MC88100 = 1
230
-
231
- # the 110 sub-type for `CPU_TYPE_MC88000`
232
- # @api private
233
- CPU_SUBTYPE_MC88110 = 2
234
-
235
- # the lowest common sub-type for `CPU_TYPE_POWERPC`
236
- # @api private
237
- CPU_SUBTYPE_POWERPC_ALL = 0
238
-
239
- # the 601 sub-type for `CPU_TYPE_POWERPC`
240
- # @api private
241
- CPU_SUBTYPE_POWERPC_601 = 1
242
-
243
- # the 602 sub-type for `CPU_TYPE_POWERPC`
244
- # @api private
245
- CPU_SUBTYPE_POWERPC_602 = 2
246
-
247
- # the 603 sub-type for `CPU_TYPE_POWERPC`
248
- # @api private
249
- CPU_SUBTYPE_POWERPC_603 = 3
250
-
251
- # the 603e (G2) sub-type for `CPU_TYPE_POWERPC`
252
- # @api private
253
- CPU_SUBTYPE_POWERPC_603E = 4
254
-
255
- # the 603ev sub-type for `CPU_TYPE_POWERPC`
256
- # @api private
257
- CPU_SUBTYPE_POWERPC_603EV = 5
258
-
259
- # the 604 sub-type for `CPU_TYPE_POWERPC`
260
- # @api private
261
- CPU_SUBTYPE_POWERPC_604 = 6
262
-
263
- # the 604e sub-type for `CPU_TYPE_POWERPC`
264
- # @api private
265
- CPU_SUBTYPE_POWERPC_604E = 7
266
-
267
- # the 620 sub-type for `CPU_TYPE_POWERPC`
268
- # @api private
269
- CPU_SUBTYPE_POWERPC_620 = 8
270
-
271
- # the 750 (G3) sub-type for `CPU_TYPE_POWERPC`
272
- # @api private
273
- CPU_SUBTYPE_POWERPC_750 = 9
274
-
275
- # the 7400 (G4) sub-type for `CPU_TYPE_POWERPC`
276
- # @api private
277
- CPU_SUBTYPE_POWERPC_7400 = 10
278
-
279
- # the 7450 (G4 "Voyager") sub-type for `CPU_TYPE_POWERPC`
280
- # @api private
281
- CPU_SUBTYPE_POWERPC_7450 = 11
282
-
283
- # the 970 (G5) sub-type for `CPU_TYPE_POWERPC`
284
- # @api private
285
- CPU_SUBTYPE_POWERPC_970 = 100
286
-
287
- # any CPU sub-type for CPU type `CPU_TYPE_POWERPC64`
288
- # @api private
289
- CPU_SUBTYPE_POWERPC64_ALL = CPU_SUBTYPE_POWERPC_ALL
290
-
291
- # association of CPU types/subtype pairs to symbol representations in
292
- # (very) roughly descending order of commonness
293
- # @see https://opensource.apple.com/source/cctools/cctools-877.8/libstuff/arch.c
294
- # @api private
295
- CPU_SUBTYPES = {
296
- CPU_TYPE_I386 => {
297
- CPU_SUBTYPE_I386 => :i386,
298
- CPU_SUBTYPE_486 => :i486,
299
- CPU_SUBTYPE_486SX => :i486SX,
300
- CPU_SUBTYPE_586 => :i586, # also "pentium" in arch(3)
301
- CPU_SUBTYPE_PENTPRO => :i686, # also "pentpro" in arch(3)
302
- CPU_SUBTYPE_PENTII_M3 => :pentIIm3,
303
- CPU_SUBTYPE_PENTII_M5 => :pentIIm5,
304
- CPU_SUBTYPE_PENTIUM_4 => :pentium4,
305
- }.freeze,
306
- CPU_TYPE_X86_64 => {
307
- CPU_SUBTYPE_X86_64_ALL => :x86_64,
308
- CPU_SUBTYPE_X86_64_H => :x86_64h,
309
- }.freeze,
310
- CPU_TYPE_ARM => {
311
- CPU_SUBTYPE_ARM_ALL => :arm,
312
- CPU_SUBTYPE_ARM_V4T => :armv4t,
313
- CPU_SUBTYPE_ARM_V6 => :armv6,
314
- CPU_SUBTYPE_ARM_V5TEJ => :armv5,
315
- CPU_SUBTYPE_ARM_XSCALE => :xscale,
316
- CPU_SUBTYPE_ARM_V7 => :armv7,
317
- CPU_SUBTYPE_ARM_V7F => :armv7f,
318
- CPU_SUBTYPE_ARM_V7S => :armv7s,
319
- CPU_SUBTYPE_ARM_V7K => :armv7k,
320
- CPU_SUBTYPE_ARM_V6M => :armv6m,
321
- CPU_SUBTYPE_ARM_V7M => :armv7m,
322
- CPU_SUBTYPE_ARM_V7EM => :armv7em,
323
- CPU_SUBTYPE_ARM_V8 => :armv8,
324
- }.freeze,
325
- CPU_TYPE_ARM64 => {
326
- CPU_SUBTYPE_ARM64_ALL => :arm64,
327
- CPU_SUBTYPE_ARM64_V8 => :arm64v8,
328
- }.freeze,
329
- CPU_TYPE_POWERPC => {
330
- CPU_SUBTYPE_POWERPC_ALL => :ppc,
331
- CPU_SUBTYPE_POWERPC_601 => :ppc601,
332
- CPU_SUBTYPE_POWERPC_603 => :ppc603,
333
- CPU_SUBTYPE_POWERPC_603E => :ppc603e,
334
- CPU_SUBTYPE_POWERPC_603EV => :ppc603ev,
335
- CPU_SUBTYPE_POWERPC_604 => :ppc604,
336
- CPU_SUBTYPE_POWERPC_604E => :ppc604e,
337
- CPU_SUBTYPE_POWERPC_750 => :ppc750,
338
- CPU_SUBTYPE_POWERPC_7400 => :ppc7400,
339
- CPU_SUBTYPE_POWERPC_7450 => :ppc7450,
340
- CPU_SUBTYPE_POWERPC_970 => :ppc970,
341
- }.freeze,
342
- CPU_TYPE_POWERPC64 => {
343
- CPU_SUBTYPE_POWERPC64_ALL => :ppc64,
344
- # apparently the only exception to the naming scheme
345
- CPU_SUBTYPE_POWERPC_970 => :ppc970_64,
346
- }.freeze,
347
- CPU_TYPE_MC680X0 => {
348
- CPU_SUBTYPE_MC680X0_ALL => :m68k,
349
- CPU_SUBTYPE_MC68030 => :mc68030,
350
- CPU_SUBTYPE_MC68040 => :mc68040,
351
- },
352
- CPU_TYPE_MC88000 => {
353
- CPU_SUBTYPE_MC88000_ALL => :m88k,
354
- },
355
- }.freeze
356
-
357
- # relocatable object file
358
- # @api private
359
- MH_OBJECT = 0x1
360
-
361
- # demand paged executable file
362
- # @api private
363
- MH_EXECUTE = 0x2
364
-
365
- # fixed VM shared library file
366
- # @api private
367
- MH_FVMLIB = 0x3
368
-
369
- # core dump file
370
- # @api private
371
- MH_CORE = 0x4
372
-
373
- # preloaded executable file
374
- # @api private
375
- MH_PRELOAD = 0x5
376
-
377
- # dynamically bound shared library
378
- # @api private
379
- MH_DYLIB = 0x6
380
-
381
- # dynamic link editor
382
- # @api private
383
- MH_DYLINKER = 0x7
384
-
385
- # dynamically bound bundle file
386
- # @api private
387
- MH_BUNDLE = 0x8
388
-
389
- # shared library stub for static linking only, no section contents
390
- # @api private
391
- MH_DYLIB_STUB = 0x9
392
-
393
- # companion file with only debug sections
394
- # @api private
395
- MH_DSYM = 0xa
396
-
397
- # x86_64 kexts
398
- # @api private
399
- MH_KEXT_BUNDLE = 0xb
400
-
401
- # association of filetypes to Symbol representations
402
- # @api private
403
- MH_FILETYPES = {
404
- MH_OBJECT => :object,
405
- MH_EXECUTE => :execute,
406
- MH_FVMLIB => :fvmlib,
407
- MH_CORE => :core,
408
- MH_PRELOAD => :preload,
409
- MH_DYLIB => :dylib,
410
- MH_DYLINKER => :dylinker,
411
- MH_BUNDLE => :bundle,
412
- MH_DYLIB_STUB => :dylib_stub,
413
- MH_DSYM => :dsym,
414
- MH_KEXT_BUNDLE => :kext_bundle,
415
- }.freeze
416
-
417
- # association of mach header flag symbols to values
418
- # @api private
419
- MH_FLAGS = {
420
- :MH_NOUNDEFS => 0x1,
421
- :MH_INCRLINK => 0x2,
422
- :MH_DYLDLINK => 0x4,
423
- :MH_BINDATLOAD => 0x8,
424
- :MH_PREBOUND => 0x10,
425
- :MH_SPLIT_SEGS => 0x20,
426
- :MH_LAZY_INIT => 0x40,
427
- :MH_TWOLEVEL => 0x80,
428
- :MH_FORCE_FLAT => 0x100,
429
- :MH_NOMULTIDEFS => 0x200,
430
- :MH_NOPREFIXBINDING => 0x400,
431
- :MH_PREBINDABLE => 0x800,
432
- :MH_ALLMODSBOUND => 0x1000,
433
- :MH_SUBSECTIONS_VIA_SYMBOLS => 0x2000,
434
- :MH_CANONICAL => 0x4000,
435
- :MH_WEAK_DEFINES => 0x8000,
436
- :MH_BINDS_TO_WEAK => 0x10000,
437
- :MH_ALLOW_STACK_EXECUTION => 0x20000,
438
- :MH_ROOT_SAFE => 0x40000,
439
- :MH_SETUID_SAFE => 0x80000,
440
- :MH_NO_REEXPORTED_DYLIBS => 0x100000,
441
- :MH_PIE => 0x200000,
442
- :MH_DEAD_STRIPPABLE_DYLIB => 0x400000,
443
- :MH_HAS_TLV_DESCRIPTORS => 0x800000,
444
- :MH_NO_HEAP_EXECUTION => 0x1000000,
445
- :MH_APP_EXTENSION_SAFE => 0x02000000,
446
- }.freeze
447
-
448
- # Fat binary header structure
449
- # @see MachO::FatArch
450
- class FatHeader < MachOStructure
451
- # @return [Fixnum] the magic number of the header (and file)
452
- attr_reader :magic
453
-
454
- # @return [Fixnum] the number of fat architecture structures following the header
455
- attr_reader :nfat_arch
456
-
457
- # always big-endian
458
- # @see MachOStructure::FORMAT
459
- # @api private
460
- FORMAT = "N2".freeze
461
-
462
- # @see MachOStructure::SIZEOF
463
- # @api private
464
- SIZEOF = 8
465
-
466
- # @api private
467
- def initialize(magic, nfat_arch)
468
- @magic = magic
469
- @nfat_arch = nfat_arch
470
- end
471
- end
14
+ # 32-bit big-endian magic
15
+ # @api private
16
+ MH_MAGIC = 0xfeedface
472
17
 
473
- # Fat binary header architecture structure. A Fat binary has one or more of
474
- # these, representing one or more internal Mach-O blobs.
475
- # @see MachO::FatHeader
476
- class FatArch < MachOStructure
477
- # @return [Fixnum] the CPU type of the Mach-O
478
- attr_reader :cputype
18
+ # 32-bit little-endian magic
19
+ # @api private
20
+ MH_CIGAM = 0xcefaedfe
479
21
 
480
- # @return [Fixnum] the CPU subtype of the Mach-O
481
- attr_reader :cpusubtype
22
+ # 64-bit big-endian magic
23
+ # @api private
24
+ MH_MAGIC_64 = 0xfeedfacf
482
25
 
483
- # @return [Fixnum] the file offset to the beginning of the Mach-O data
484
- attr_reader :offset
26
+ # 64-bit little-endian magic
27
+ # @api private
28
+ MH_CIGAM_64 = 0xcffaedfe
485
29
 
486
- # @return [Fixnum] the size, in bytes, of the Mach-O data
487
- attr_reader :size
30
+ # association of magic numbers to string representations
31
+ # @api private
32
+ MH_MAGICS = {
33
+ FAT_MAGIC => "FAT_MAGIC",
34
+ MH_MAGIC => "MH_MAGIC",
35
+ MH_CIGAM => "MH_CIGAM",
36
+ MH_MAGIC_64 => "MH_MAGIC_64",
37
+ MH_CIGAM_64 => "MH_CIGAM_64",
38
+ }.freeze
39
+
40
+ # mask for CPUs with 64-bit architectures (when running a 64-bit ABI?)
41
+ # @api private
42
+ CPU_ARCH_ABI64 = 0x01000000
488
43
 
489
- # @return [Fixnum] the alignment, as a power of 2
490
- attr_reader :align
44
+ # any CPU (unused?)
45
+ # @api private
46
+ CPU_TYPE_ANY = -1
491
47
 
492
- # always big-endian
493
- # @see MachOStructure::FORMAT
48
+ # m68k compatible CPUs
494
49
  # @api private
495
- FORMAT = "N5".freeze
50
+ CPU_TYPE_MC680X0 = 0x06
496
51
 
497
- # @see MachOStructure::SIZEOF
52
+ # i386 and later compatible CPUs
498
53
  # @api private
499
- SIZEOF = 20
54
+ CPU_TYPE_I386 = 0x07
500
55
 
56
+ # x86_64 (AMD64) compatible CPUs
501
57
  # @api private
502
- def initialize(cputype, cpusubtype, offset, size, align)
503
- @cputype = cputype
504
- @cpusubtype = cpusubtype
505
- @offset = offset
506
- @size = size
507
- @align = align
508
- end
509
- end
58
+ CPU_TYPE_X86_64 = (CPU_TYPE_I386 | CPU_ARCH_ABI64)
510
59
 
511
- # 32-bit Mach-O file header structure
512
- class MachHeader < MachOStructure
513
- # @return [Fixnum] the magic number
514
- attr_reader :magic
60
+ # 32-bit ARM compatible CPUs
61
+ # @api private
62
+ CPU_TYPE_ARM = 0x0c
515
63
 
516
- # @return [Fixnum] the CPU type of the Mach-O
517
- attr_reader :cputype
64
+ # m88k compatible CPUs
65
+ # @api private
66
+ CPU_TYPE_MC88000 = 0xd
518
67
 
519
- # @return [Fixnum] the CPU subtype of the Mach-O
520
- attr_reader :cpusubtype
68
+ # 64-bit ARM compatible CPUs
69
+ # @api private
70
+ CPU_TYPE_ARM64 = (CPU_TYPE_ARM | CPU_ARCH_ABI64)
521
71
 
522
- # @return [Fixnum] the file type of the Mach-O
523
- attr_reader :filetype
72
+ # PowerPC compatible CPUs
73
+ # @api private
74
+ CPU_TYPE_POWERPC = 0x12
524
75
 
525
- # @return [Fixnum] the number of load commands in the Mach-O
526
- attr_reader :ncmds
76
+ # PowerPC64 compatible CPUs
77
+ # @api private
78
+ CPU_TYPE_POWERPC64 = (CPU_TYPE_POWERPC | CPU_ARCH_ABI64)
527
79
 
528
- # @return [Fixnum] the size of all load commands, in bytes, in the Mach-O
529
- attr_reader :sizeofcmds
80
+ # association of cpu types to symbol representations
81
+ # @api private
82
+ CPU_TYPES = {
83
+ CPU_TYPE_ANY => :any,
84
+ CPU_TYPE_I386 => :i386,
85
+ CPU_TYPE_X86_64 => :x86_64,
86
+ CPU_TYPE_ARM => :arm,
87
+ CPU_TYPE_ARM64 => :arm64,
88
+ CPU_TYPE_POWERPC => :ppc,
89
+ CPU_TYPE_POWERPC64 => :ppc64,
90
+ }.freeze
91
+
92
+ # mask for CPU subtype capabilities
93
+ # @api private
94
+ CPU_SUBTYPE_MASK = 0xff000000
530
95
 
531
- # @return [Fixnum] the header flags associated with the Mach-O
532
- attr_reader :flags
96
+ # 64-bit libraries (undocumented!)
97
+ # @see http://llvm.org/docs/doxygen/html/Support_2MachO_8h_source.html
98
+ # @api private
99
+ CPU_SUBTYPE_LIB64 = 0x80000000
533
100
 
534
- # @see MachOStructure::FORMAT
101
+ # the lowest common sub-type for `CPU_TYPE_I386`
535
102
  # @api private
536
- FORMAT = "L=7".freeze
103
+ CPU_SUBTYPE_I386 = 3
537
104
 
538
- # @see MachOStructure::SIZEOF
105
+ # the i486 sub-type for `CPU_TYPE_I386`
539
106
  # @api private
540
- SIZEOF = 28
107
+ CPU_SUBTYPE_486 = 4
541
108
 
109
+ # the i486SX sub-type for `CPU_TYPE_I386`
542
110
  # @api private
543
- def initialize(magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds,
544
- flags)
545
- @magic = magic
546
- @cputype = cputype
547
- # For now we're not interested in additional capability bits also to be
548
- # found in the `cpusubtype` field. We only care about the CPU sub-type.
549
- @cpusubtype = cpusubtype & ~CPU_SUBTYPE_MASK
550
- @filetype = filetype
551
- @ncmds = ncmds
552
- @sizeofcmds = sizeofcmds
553
- @flags = flags
554
- end
111
+ CPU_SUBTYPE_486SX = 132
555
112
 
556
- # @example
557
- # puts "this mach-o has position-independent execution" if header.flag?(:MH_PIE)
558
- # @param flag [Symbol] a mach header flag symbol
559
- # @return [Boolean] true if `flag` is present in the header's flag section
560
- def flag?(flag)
561
- flag = MH_FLAGS[flag]
562
- return false if flag.nil?
563
- flags & flag == flag
564
- end
565
- end
113
+ # the i586 (P5, Pentium) sub-type for `CPU_TYPE_I386`
114
+ # @api private
115
+ CPU_SUBTYPE_586 = 5
116
+
117
+ # @see CPU_SUBTYPE_586
118
+ # @api private
119
+ CPU_SUBTYPE_PENT = CPU_SUBTYPE_586
120
+
121
+ # the Pentium Pro (P6) sub-type for `CPU_TYPE_I386`
122
+ # @api private
123
+ CPU_SUBTYPE_PENTPRO = 22
124
+
125
+ # the Pentium II (P6, M3?) sub-type for `CPU_TYPE_I386`
126
+ # @api private
127
+ CPU_SUBTYPE_PENTII_M3 = 54
128
+
129
+ # the Pentium II (P6, M5?) sub-type for `CPU_TYPE_I386`
130
+ # @api private
131
+ CPU_SUBTYPE_PENTII_M5 = 86
132
+
133
+ # the Pentium 4 (Netburst) sub-type for `CPU_TYPE_I386`
134
+ # @api private
135
+ CPU_SUBTYPE_PENTIUM_4 = 10
136
+
137
+ # the lowest common sub-type for `CPU_TYPE_MC680X0`
138
+ # @api private
139
+ CPU_SUBTYPE_MC680X0_ALL = 1
140
+
141
+ # @see CPU_SUBTYPE_MC680X0_ALL
142
+ # @api private
143
+ CPU_SUBTYPE_MC68030 = CPU_SUBTYPE_MC680X0_ALL
144
+
145
+ # the 040 subtype for `CPU_TYPE_MC680X0`
146
+ # @api private
147
+ CPU_SUBTYPE_MC68040 = 2
148
+
149
+ # the 030 subtype for `CPU_TYPE_MC680X0`
150
+ # @api private
151
+ CPU_SUBTYPE_MC68030_ONLY = 3
152
+
153
+ # the lowest common sub-type for `CPU_TYPE_X86_64`
154
+ # @api private
155
+ CPU_SUBTYPE_X86_64_ALL = CPU_SUBTYPE_I386
156
+
157
+ # the Haskell sub-type for `CPU_TYPE_X86_64`
158
+ # @api private
159
+ CPU_SUBTYPE_X86_64_H = 8
160
+
161
+ # the lowest common sub-type for `CPU_TYPE_ARM`
162
+ # @api private
163
+ CPU_SUBTYPE_ARM_ALL = 0
164
+
165
+ # the v4t sub-type for `CPU_TYPE_ARM`
166
+ # @api private
167
+ CPU_SUBTYPE_ARM_V4T = 5
168
+
169
+ # the v6 sub-type for `CPU_TYPE_ARM`
170
+ # @api private
171
+ CPU_SUBTYPE_ARM_V6 = 6
172
+
173
+ # the v5 sub-type for `CPU_TYPE_ARM`
174
+ # @api private
175
+ CPU_SUBTYPE_ARM_V5TEJ = 7
176
+
177
+ # the xscale (v5 family) sub-type for `CPU_TYPE_ARM`
178
+ # @api private
179
+ CPU_SUBTYPE_ARM_XSCALE = 8
180
+
181
+ # the v7 sub-type for `CPU_TYPE_ARM`
182
+ # @api private
183
+ CPU_SUBTYPE_ARM_V7 = 9
184
+
185
+ # the v7f (Cortex A9) sub-type for `CPU_TYPE_ARM`
186
+ # @api private
187
+ CPU_SUBTYPE_ARM_V7F = 10
188
+
189
+ # the v7s ("Swift") sub-type for `CPU_TYPE_ARM`
190
+ # @api private
191
+ CPU_SUBTYPE_ARM_V7S = 11
192
+
193
+ # the v7k ("Kirkwood40") sub-type for `CPU_TYPE_ARM`
194
+ # @api private
195
+ CPU_SUBTYPE_ARM_V7K = 12
196
+
197
+ # the v6m sub-type for `CPU_TYPE_ARM`
198
+ # @api private
199
+ CPU_SUBTYPE_ARM_V6M = 14
200
+
201
+ # the v7m sub-type for `CPU_TYPE_ARM`
202
+ # @api private
203
+ CPU_SUBTYPE_ARM_V7M = 15
566
204
 
567
- # 64-bit Mach-O file header structure
568
- class MachHeader64 < MachHeader
569
- # @return [void]
570
- attr_reader :reserved
205
+ # the v7em sub-type for `CPU_TYPE_ARM`
206
+ # @api private
207
+ CPU_SUBTYPE_ARM_V7EM = 16
208
+
209
+ # the v8 sub-type for `CPU_TYPE_ARM`
210
+ # @api private
211
+ CPU_SUBTYPE_ARM_V8 = 13
212
+
213
+ # the lowest common sub-type for `CPU_TYPE_ARM64`
214
+ # @api private
215
+ CPU_SUBTYPE_ARM64_ALL = 0
216
+
217
+ # the v8 sub-type for `CPU_TYPE_ARM64`
218
+ # @api private
219
+ CPU_SUBTYPE_ARM64_V8 = 1
220
+
221
+ # the lowest common sub-type for `CPU_TYPE_MC88000`
222
+ # @api private
223
+ CPU_SUBTYPE_MC88000_ALL = 0
224
+
225
+ # @see CPU_SUBTYPE_MC88000_ALL
226
+ # @api private
227
+ CPU_SUBTYPE_MMAX_JPC = CPU_SUBTYPE_MC88000_ALL
228
+
229
+ # the 100 sub-type for `CPU_TYPE_MC88000`
230
+ # @api private
231
+ CPU_SUBTYPE_MC88100 = 1
232
+
233
+ # the 110 sub-type for `CPU_TYPE_MC88000`
234
+ # @api private
235
+ CPU_SUBTYPE_MC88110 = 2
236
+
237
+ # the lowest common sub-type for `CPU_TYPE_POWERPC`
238
+ # @api private
239
+ CPU_SUBTYPE_POWERPC_ALL = 0
240
+
241
+ # the 601 sub-type for `CPU_TYPE_POWERPC`
242
+ # @api private
243
+ CPU_SUBTYPE_POWERPC_601 = 1
244
+
245
+ # the 602 sub-type for `CPU_TYPE_POWERPC`
246
+ # @api private
247
+ CPU_SUBTYPE_POWERPC_602 = 2
248
+
249
+ # the 603 sub-type for `CPU_TYPE_POWERPC`
250
+ # @api private
251
+ CPU_SUBTYPE_POWERPC_603 = 3
252
+
253
+ # the 603e (G2) sub-type for `CPU_TYPE_POWERPC`
254
+ # @api private
255
+ CPU_SUBTYPE_POWERPC_603E = 4
256
+
257
+ # the 603ev sub-type for `CPU_TYPE_POWERPC`
258
+ # @api private
259
+ CPU_SUBTYPE_POWERPC_603EV = 5
260
+
261
+ # the 604 sub-type for `CPU_TYPE_POWERPC`
262
+ # @api private
263
+ CPU_SUBTYPE_POWERPC_604 = 6
264
+
265
+ # the 604e sub-type for `CPU_TYPE_POWERPC`
266
+ # @api private
267
+ CPU_SUBTYPE_POWERPC_604E = 7
268
+
269
+ # the 620 sub-type for `CPU_TYPE_POWERPC`
270
+ # @api private
271
+ CPU_SUBTYPE_POWERPC_620 = 8
272
+
273
+ # the 750 (G3) sub-type for `CPU_TYPE_POWERPC`
274
+ # @api private
275
+ CPU_SUBTYPE_POWERPC_750 = 9
571
276
 
572
- # @see MachOStructure::FORMAT
277
+ # the 7400 (G4) sub-type for `CPU_TYPE_POWERPC`
573
278
  # @api private
574
- FORMAT = "L=8".freeze
279
+ CPU_SUBTYPE_POWERPC_7400 = 10
575
280
 
576
- # @see MachOStructure::SIZEOF
281
+ # the 7450 (G4 "Voyager") sub-type for `CPU_TYPE_POWERPC`
577
282
  # @api private
578
- SIZEOF = 32
283
+ CPU_SUBTYPE_POWERPC_7450 = 11
579
284
 
285
+ # the 970 (G5) sub-type for `CPU_TYPE_POWERPC`
580
286
  # @api private
581
- def initialize(magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds,
582
- flags, reserved)
583
- super(magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags)
584
- @reserved = reserved
287
+ CPU_SUBTYPE_POWERPC_970 = 100
288
+
289
+ # any CPU sub-type for CPU type `CPU_TYPE_POWERPC64`
290
+ # @api private
291
+ CPU_SUBTYPE_POWERPC64_ALL = CPU_SUBTYPE_POWERPC_ALL
292
+
293
+ # association of CPU types/subtype pairs to symbol representations in
294
+ # (very) roughly descending order of commonness
295
+ # @see https://opensource.apple.com/source/cctools/cctools-877.8/libstuff/arch.c
296
+ # @api private
297
+ CPU_SUBTYPES = {
298
+ CPU_TYPE_I386 => {
299
+ CPU_SUBTYPE_I386 => :i386,
300
+ CPU_SUBTYPE_486 => :i486,
301
+ CPU_SUBTYPE_486SX => :i486SX,
302
+ CPU_SUBTYPE_586 => :i586, # also "pentium" in arch(3)
303
+ CPU_SUBTYPE_PENTPRO => :i686, # also "pentpro" in arch(3)
304
+ CPU_SUBTYPE_PENTII_M3 => :pentIIm3,
305
+ CPU_SUBTYPE_PENTII_M5 => :pentIIm5,
306
+ CPU_SUBTYPE_PENTIUM_4 => :pentium4,
307
+ }.freeze,
308
+ CPU_TYPE_X86_64 => {
309
+ CPU_SUBTYPE_X86_64_ALL => :x86_64,
310
+ CPU_SUBTYPE_X86_64_H => :x86_64h,
311
+ }.freeze,
312
+ CPU_TYPE_ARM => {
313
+ CPU_SUBTYPE_ARM_ALL => :arm,
314
+ CPU_SUBTYPE_ARM_V4T => :armv4t,
315
+ CPU_SUBTYPE_ARM_V6 => :armv6,
316
+ CPU_SUBTYPE_ARM_V5TEJ => :armv5,
317
+ CPU_SUBTYPE_ARM_XSCALE => :xscale,
318
+ CPU_SUBTYPE_ARM_V7 => :armv7,
319
+ CPU_SUBTYPE_ARM_V7F => :armv7f,
320
+ CPU_SUBTYPE_ARM_V7S => :armv7s,
321
+ CPU_SUBTYPE_ARM_V7K => :armv7k,
322
+ CPU_SUBTYPE_ARM_V6M => :armv6m,
323
+ CPU_SUBTYPE_ARM_V7M => :armv7m,
324
+ CPU_SUBTYPE_ARM_V7EM => :armv7em,
325
+ CPU_SUBTYPE_ARM_V8 => :armv8,
326
+ }.freeze,
327
+ CPU_TYPE_ARM64 => {
328
+ CPU_SUBTYPE_ARM64_ALL => :arm64,
329
+ CPU_SUBTYPE_ARM64_V8 => :arm64v8,
330
+ }.freeze,
331
+ CPU_TYPE_POWERPC => {
332
+ CPU_SUBTYPE_POWERPC_ALL => :ppc,
333
+ CPU_SUBTYPE_POWERPC_601 => :ppc601,
334
+ CPU_SUBTYPE_POWERPC_603 => :ppc603,
335
+ CPU_SUBTYPE_POWERPC_603E => :ppc603e,
336
+ CPU_SUBTYPE_POWERPC_603EV => :ppc603ev,
337
+ CPU_SUBTYPE_POWERPC_604 => :ppc604,
338
+ CPU_SUBTYPE_POWERPC_604E => :ppc604e,
339
+ CPU_SUBTYPE_POWERPC_750 => :ppc750,
340
+ CPU_SUBTYPE_POWERPC_7400 => :ppc7400,
341
+ CPU_SUBTYPE_POWERPC_7450 => :ppc7450,
342
+ CPU_SUBTYPE_POWERPC_970 => :ppc970,
343
+ }.freeze,
344
+ CPU_TYPE_POWERPC64 => {
345
+ CPU_SUBTYPE_POWERPC64_ALL => :ppc64,
346
+ # apparently the only exception to the naming scheme
347
+ CPU_SUBTYPE_POWERPC_970 => :ppc970_64,
348
+ }.freeze,
349
+ CPU_TYPE_MC680X0 => {
350
+ CPU_SUBTYPE_MC680X0_ALL => :m68k,
351
+ CPU_SUBTYPE_MC68030 => :mc68030,
352
+ CPU_SUBTYPE_MC68040 => :mc68040,
353
+ },
354
+ CPU_TYPE_MC88000 => {
355
+ CPU_SUBTYPE_MC88000_ALL => :m88k,
356
+ },
357
+ }.freeze
358
+
359
+ # relocatable object file
360
+ # @api private
361
+ MH_OBJECT = 0x1
362
+
363
+ # demand paged executable file
364
+ # @api private
365
+ MH_EXECUTE = 0x2
366
+
367
+ # fixed VM shared library file
368
+ # @api private
369
+ MH_FVMLIB = 0x3
370
+
371
+ # core dump file
372
+ # @api private
373
+ MH_CORE = 0x4
374
+
375
+ # preloaded executable file
376
+ # @api private
377
+ MH_PRELOAD = 0x5
378
+
379
+ # dynamically bound shared library
380
+ # @api private
381
+ MH_DYLIB = 0x6
382
+
383
+ # dynamic link editor
384
+ # @api private
385
+ MH_DYLINKER = 0x7
386
+
387
+ # dynamically bound bundle file
388
+ # @api private
389
+ MH_BUNDLE = 0x8
390
+
391
+ # shared library stub for static linking only, no section contents
392
+ # @api private
393
+ MH_DYLIB_STUB = 0x9
394
+
395
+ # companion file with only debug sections
396
+ # @api private
397
+ MH_DSYM = 0xa
398
+
399
+ # x86_64 kexts
400
+ # @api private
401
+ MH_KEXT_BUNDLE = 0xb
402
+
403
+ # association of filetypes to Symbol representations
404
+ # @api private
405
+ MH_FILETYPES = {
406
+ MH_OBJECT => :object,
407
+ MH_EXECUTE => :execute,
408
+ MH_FVMLIB => :fvmlib,
409
+ MH_CORE => :core,
410
+ MH_PRELOAD => :preload,
411
+ MH_DYLIB => :dylib,
412
+ MH_DYLINKER => :dylinker,
413
+ MH_BUNDLE => :bundle,
414
+ MH_DYLIB_STUB => :dylib_stub,
415
+ MH_DSYM => :dsym,
416
+ MH_KEXT_BUNDLE => :kext_bundle,
417
+ }.freeze
418
+
419
+ # association of mach header flag symbols to values
420
+ # @api private
421
+ MH_FLAGS = {
422
+ :MH_NOUNDEFS => 0x1,
423
+ :MH_INCRLINK => 0x2,
424
+ :MH_DYLDLINK => 0x4,
425
+ :MH_BINDATLOAD => 0x8,
426
+ :MH_PREBOUND => 0x10,
427
+ :MH_SPLIT_SEGS => 0x20,
428
+ :MH_LAZY_INIT => 0x40,
429
+ :MH_TWOLEVEL => 0x80,
430
+ :MH_FORCE_FLAT => 0x100,
431
+ :MH_NOMULTIDEFS => 0x200,
432
+ :MH_NOPREFIXBINDING => 0x400,
433
+ :MH_PREBINDABLE => 0x800,
434
+ :MH_ALLMODSBOUND => 0x1000,
435
+ :MH_SUBSECTIONS_VIA_SYMBOLS => 0x2000,
436
+ :MH_CANONICAL => 0x4000,
437
+ :MH_WEAK_DEFINES => 0x8000,
438
+ :MH_BINDS_TO_WEAK => 0x10000,
439
+ :MH_ALLOW_STACK_EXECUTION => 0x20000,
440
+ :MH_ROOT_SAFE => 0x40000,
441
+ :MH_SETUID_SAFE => 0x80000,
442
+ :MH_NO_REEXPORTED_DYLIBS => 0x100000,
443
+ :MH_PIE => 0x200000,
444
+ :MH_DEAD_STRIPPABLE_DYLIB => 0x400000,
445
+ :MH_HAS_TLV_DESCRIPTORS => 0x800000,
446
+ :MH_NO_HEAP_EXECUTION => 0x1000000,
447
+ :MH_APP_EXTENSION_SAFE => 0x02000000,
448
+ }.freeze
449
+
450
+ # Fat binary header structure
451
+ # @see MachO::FatArch
452
+ class FatHeader < MachOStructure
453
+ # @return [Fixnum] the magic number of the header (and file)
454
+ attr_reader :magic
455
+
456
+ # @return [Fixnum] the number of fat architecture structures following the header
457
+ attr_reader :nfat_arch
458
+
459
+ # always big-endian
460
+ # @see MachOStructure::FORMAT
461
+ # @api private
462
+ FORMAT = "N2".freeze
463
+
464
+ # @see MachOStructure::SIZEOF
465
+ # @api private
466
+ SIZEOF = 8
467
+
468
+ # @api private
469
+ def initialize(magic, nfat_arch)
470
+ @magic = magic
471
+ @nfat_arch = nfat_arch
472
+ end
473
+ end
474
+
475
+ # Fat binary header architecture structure. A Fat binary has one or more of
476
+ # these, representing one or more internal Mach-O blobs.
477
+ # @see MachO::Headers::FatHeader
478
+ class FatArch < MachOStructure
479
+ # @return [Fixnum] the CPU type of the Mach-O
480
+ attr_reader :cputype
481
+
482
+ # @return [Fixnum] the CPU subtype of the Mach-O
483
+ attr_reader :cpusubtype
484
+
485
+ # @return [Fixnum] the file offset to the beginning of the Mach-O data
486
+ attr_reader :offset
487
+
488
+ # @return [Fixnum] the size, in bytes, of the Mach-O data
489
+ attr_reader :size
490
+
491
+ # @return [Fixnum] the alignment, as a power of 2
492
+ attr_reader :align
493
+
494
+ # always big-endian
495
+ # @see MachOStructure::FORMAT
496
+ # @api private
497
+ FORMAT = "N5".freeze
498
+
499
+ # @see MachOStructure::SIZEOF
500
+ # @api private
501
+ SIZEOF = 20
502
+
503
+ # @api private
504
+ def initialize(cputype, cpusubtype, offset, size, align)
505
+ @cputype = cputype
506
+ @cpusubtype = cpusubtype
507
+ @offset = offset
508
+ @size = size
509
+ @align = align
510
+ end
511
+ end
512
+
513
+ # 32-bit Mach-O file header structure
514
+ class MachHeader < MachOStructure
515
+ # @return [Fixnum] the magic number
516
+ attr_reader :magic
517
+
518
+ # @return [Fixnum] the CPU type of the Mach-O
519
+ attr_reader :cputype
520
+
521
+ # @return [Fixnum] the CPU subtype of the Mach-O
522
+ attr_reader :cpusubtype
523
+
524
+ # @return [Fixnum] the file type of the Mach-O
525
+ attr_reader :filetype
526
+
527
+ # @return [Fixnum] the number of load commands in the Mach-O
528
+ attr_reader :ncmds
529
+
530
+ # @return [Fixnum] the size of all load commands, in bytes, in the Mach-O
531
+ attr_reader :sizeofcmds
532
+
533
+ # @return [Fixnum] the header flags associated with the Mach-O
534
+ attr_reader :flags
535
+
536
+ # @see MachOStructure::FORMAT
537
+ # @api private
538
+ FORMAT = "L=7".freeze
539
+
540
+ # @see MachOStructure::SIZEOF
541
+ # @api private
542
+ SIZEOF = 28
543
+
544
+ # @api private
545
+ def initialize(magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds,
546
+ flags)
547
+ @magic = magic
548
+ @cputype = cputype
549
+ # For now we're not interested in additional capability bits also to be
550
+ # found in the `cpusubtype` field. We only care about the CPU sub-type.
551
+ @cpusubtype = cpusubtype & ~CPU_SUBTYPE_MASK
552
+ @filetype = filetype
553
+ @ncmds = ncmds
554
+ @sizeofcmds = sizeofcmds
555
+ @flags = flags
556
+ end
557
+
558
+ # @example
559
+ # puts "this mach-o has position-independent execution" if header.flag?(:MH_PIE)
560
+ # @param flag [Symbol] a mach header flag symbol
561
+ # @return [Boolean] true if `flag` is present in the header's flag section
562
+ def flag?(flag)
563
+ flag = MH_FLAGS[flag]
564
+ return false if flag.nil?
565
+ flags & flag == flag
566
+ end
567
+ end
568
+
569
+ # 64-bit Mach-O file header structure
570
+ class MachHeader64 < MachHeader
571
+ # @return [void]
572
+ attr_reader :reserved
573
+
574
+ # @see MachOStructure::FORMAT
575
+ # @api private
576
+ FORMAT = "L=8".freeze
577
+
578
+ # @see MachOStructure::SIZEOF
579
+ # @api private
580
+ SIZEOF = 32
581
+
582
+ # @api private
583
+ def initialize(magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds,
584
+ flags, reserved)
585
+ super(magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags)
586
+ @reserved = reserved
587
+ end
585
588
  end
586
589
  end
587
590
  end