ruby-macho 0.2.6 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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