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 +4 -4
- data/README.md +0 -3
- data/lib/macho.rb +25 -2
- data/lib/macho/fat_file.rb +10 -10
- data/lib/macho/headers.rb +552 -549
- data/lib/macho/load_commands.rb +1064 -1061
- data/lib/macho/macho_file.rb +52 -52
- data/lib/macho/sections.rb +160 -157
- data/lib/macho/utils.rb +6 -6
- metadata +3 -4
- data/lib/macho/open.rb +0 -25
data/lib/macho/load_commands.rb
CHANGED
@@ -1,1314 +1,1317 @@
|
|
1
1
|
module MachO
|
2
|
-
#
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
#
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
2
|
+
# Classes and constants for parsing load commands in Mach-O binaries.
|
3
|
+
module LoadCommands
|
4
|
+
# load commands added after OS X 10.1 need to be bitwise ORed with
|
5
|
+
# LC_REQ_DYLD to be recognized by the dynamic linder (dyld)
|
6
|
+
# @api private
|
7
|
+
LC_REQ_DYLD = 0x80000000
|
8
|
+
|
9
|
+
# association of load commands to symbol representations
|
10
|
+
# @api private
|
11
|
+
LOAD_COMMANDS = {
|
12
|
+
0x1 => :LC_SEGMENT,
|
13
|
+
0x2 => :LC_SYMTAB,
|
14
|
+
0x3 => :LC_SYMSEG,
|
15
|
+
0x4 => :LC_THREAD,
|
16
|
+
0x5 => :LC_UNIXTHREAD,
|
17
|
+
0x6 => :LC_LOADFVMLIB,
|
18
|
+
0x7 => :LC_IDFVMLIB,
|
19
|
+
0x8 => :LC_IDENT,
|
20
|
+
0x9 => :LC_FVMFILE,
|
21
|
+
0xa => :LC_PREPAGE,
|
22
|
+
0xb => :LC_DYSYMTAB,
|
23
|
+
0xc => :LC_LOAD_DYLIB,
|
24
|
+
0xd => :LC_ID_DYLIB,
|
25
|
+
0xe => :LC_LOAD_DYLINKER,
|
26
|
+
0xf => :LC_ID_DYLINKER,
|
27
|
+
0x10 => :LC_PREBOUND_DYLIB,
|
28
|
+
0x11 => :LC_ROUTINES,
|
29
|
+
0x12 => :LC_SUB_FRAMEWORK,
|
30
|
+
0x13 => :LC_SUB_UMBRELLA,
|
31
|
+
0x14 => :LC_SUB_CLIENT,
|
32
|
+
0x15 => :LC_SUB_LIBRARY,
|
33
|
+
0x16 => :LC_TWOLEVEL_HINTS,
|
34
|
+
0x17 => :LC_PREBIND_CKSUM,
|
35
|
+
(0x18 | LC_REQ_DYLD) => :LC_LOAD_WEAK_DYLIB,
|
36
|
+
0x19 => :LC_SEGMENT_64,
|
37
|
+
0x1a => :LC_ROUTINES_64,
|
38
|
+
0x1b => :LC_UUID,
|
39
|
+
(0x1c | LC_REQ_DYLD) => :LC_RPATH,
|
40
|
+
0x1d => :LC_CODE_SIGNATURE,
|
41
|
+
0x1e => :LC_SEGMENT_SPLIT_INFO,
|
42
|
+
(0x1f | LC_REQ_DYLD) => :LC_REEXPORT_DYLIB,
|
43
|
+
0x20 => :LC_LAZY_LOAD_DYLIB,
|
44
|
+
0x21 => :LC_ENCRYPTION_INFO,
|
45
|
+
0x22 => :LC_DYLD_INFO,
|
46
|
+
(0x22 | LC_REQ_DYLD) => :LC_DYLD_INFO_ONLY,
|
47
|
+
(0x23 | LC_REQ_DYLD) => :LC_LOAD_UPWARD_DYLIB,
|
48
|
+
0x24 => :LC_VERSION_MIN_MACOSX,
|
49
|
+
0x25 => :LC_VERSION_MIN_IPHONEOS,
|
50
|
+
0x26 => :LC_FUNCTION_STARTS,
|
51
|
+
0x27 => :LC_DYLD_ENVIRONMENT,
|
52
|
+
(0x28 | LC_REQ_DYLD) => :LC_MAIN,
|
53
|
+
0x29 => :LC_DATA_IN_CODE,
|
54
|
+
0x2a => :LC_SOURCE_VERSION,
|
55
|
+
0x2b => :LC_DYLIB_CODE_SIGN_DRS,
|
56
|
+
0x2c => :LC_ENCRYPTION_INFO_64,
|
57
|
+
0x2d => :LC_LINKER_OPTION,
|
58
|
+
0x2e => :LC_LINKER_OPTIMIZATION_HINT,
|
59
|
+
0x2f => :LC_VERSION_MIN_TVOS,
|
60
|
+
0x30 => :LC_VERSION_MIN_WATCHOS,
|
61
|
+
}.freeze
|
62
|
+
|
63
|
+
# association of symbol representations to load command constants
|
64
|
+
# @api private
|
65
|
+
LOAD_COMMAND_CONSTANTS = LOAD_COMMANDS.invert.freeze
|
66
|
+
|
67
|
+
# load commands responsible for loading dylibs
|
68
|
+
# @api private
|
69
|
+
DYLIB_LOAD_COMMANDS = [
|
70
|
+
:LC_LOAD_DYLIB,
|
71
|
+
:LC_LOAD_WEAK_DYLIB,
|
72
|
+
:LC_REEXPORT_DYLIB,
|
73
|
+
:LC_LAZY_LOAD_DYLIB,
|
74
|
+
:LC_LOAD_UPWARD_DYLIB,
|
75
|
+
].freeze
|
76
|
+
|
77
|
+
# load commands that can be created manually via {LoadCommand.create}
|
78
|
+
# @api private
|
79
|
+
CREATABLE_LOAD_COMMANDS = DYLIB_LOAD_COMMANDS + [
|
80
|
+
:LC_ID_DYLIB,
|
81
|
+
:LC_RPATH,
|
82
|
+
:LC_LOAD_DYLINKER,
|
83
|
+
].freeze
|
84
|
+
|
85
|
+
# association of load command symbols to string representations of classes
|
86
|
+
# @api private
|
87
|
+
LC_STRUCTURES = {
|
88
|
+
:LC_SEGMENT => "SegmentCommand",
|
89
|
+
:LC_SYMTAB => "SymtabCommand",
|
90
|
+
:LC_SYMSEG => "SymsegCommand", # obsolete
|
91
|
+
:LC_THREAD => "ThreadCommand", # seems obsolete, but not documented as such
|
92
|
+
:LC_UNIXTHREAD => "ThreadCommand",
|
93
|
+
:LC_LOADFVMLIB => "FvmlibCommand", # obsolete
|
94
|
+
:LC_IDFVMLIB => "FvmlibCommand", # obsolete
|
95
|
+
:LC_IDENT => "IdentCommand", # obsolete
|
96
|
+
:LC_FVMFILE => "FvmfileCommand", # reserved for internal use only
|
97
|
+
:LC_PREPAGE => "LoadCommand", # reserved for internal use only, no public struct
|
98
|
+
:LC_DYSYMTAB => "DysymtabCommand",
|
99
|
+
:LC_LOAD_DYLIB => "DylibCommand",
|
100
|
+
:LC_ID_DYLIB => "DylibCommand",
|
101
|
+
:LC_LOAD_DYLINKER => "DylinkerCommand",
|
102
|
+
:LC_ID_DYLINKER => "DylinkerCommand",
|
103
|
+
:LC_PREBOUND_DYLIB => "PreboundDylibCommand",
|
104
|
+
:LC_ROUTINES => "RoutinesCommand",
|
105
|
+
:LC_SUB_FRAMEWORK => "SubFrameworkCommand",
|
106
|
+
:LC_SUB_UMBRELLA => "SubUmbrellaCommand",
|
107
|
+
:LC_SUB_CLIENT => "SubClientCommand",
|
108
|
+
:LC_SUB_LIBRARY => "SubLibraryCommand",
|
109
|
+
:LC_TWOLEVEL_HINTS => "TwolevelHintsCommand",
|
110
|
+
:LC_PREBIND_CKSUM => "PrebindCksumCommand",
|
111
|
+
:LC_LOAD_WEAK_DYLIB => "DylibCommand",
|
112
|
+
:LC_SEGMENT_64 => "SegmentCommand64",
|
113
|
+
:LC_ROUTINES_64 => "RoutinesCommand64",
|
114
|
+
:LC_UUID => "UUIDCommand",
|
115
|
+
:LC_RPATH => "RpathCommand",
|
116
|
+
:LC_CODE_SIGNATURE => "LinkeditDataCommand",
|
117
|
+
:LC_SEGMENT_SPLIT_INFO => "LinkeditDataCommand",
|
118
|
+
:LC_REEXPORT_DYLIB => "DylibCommand",
|
119
|
+
:LC_LAZY_LOAD_DYLIB => "DylibCommand",
|
120
|
+
:LC_ENCRYPTION_INFO => "EncryptionInfoCommand",
|
121
|
+
:LC_DYLD_INFO => "DyldInfoCommand",
|
122
|
+
:LC_DYLD_INFO_ONLY => "DyldInfoCommand",
|
123
|
+
:LC_LOAD_UPWARD_DYLIB => "DylibCommand",
|
124
|
+
:LC_VERSION_MIN_MACOSX => "VersionMinCommand",
|
125
|
+
:LC_VERSION_MIN_IPHONEOS => "VersionMinCommand",
|
126
|
+
:LC_FUNCTION_STARTS => "LinkeditDataCommand",
|
127
|
+
:LC_DYLD_ENVIRONMENT => "DylinkerCommand",
|
128
|
+
:LC_MAIN => "EntryPointCommand",
|
129
|
+
:LC_DATA_IN_CODE => "LinkeditDataCommand",
|
130
|
+
:LC_SOURCE_VERSION => "SourceVersionCommand",
|
131
|
+
:LC_DYLIB_CODE_SIGN_DRS => "LinkeditDataCommand",
|
132
|
+
:LC_ENCRYPTION_INFO_64 => "EncryptionInfoCommand64",
|
133
|
+
:LC_LINKER_OPTION => "LinkerOptionCommand",
|
134
|
+
:LC_LINKER_OPTIMIZATION_HINT => "LinkeditDataCommand",
|
135
|
+
:LC_VERSION_MIN_TVOS => "VersionMinCommand",
|
136
|
+
:LC_VERSION_MIN_WATCHOS => "VersionMinCommand",
|
137
|
+
}.freeze
|
138
|
+
|
139
|
+
# association of segment name symbols to names
|
140
|
+
# @api private
|
141
|
+
SEGMENT_NAMES = {
|
142
|
+
:SEG_PAGEZERO => "__PAGEZERO",
|
143
|
+
:SEG_TEXT => "__TEXT",
|
144
|
+
:SEG_DATA => "__DATA",
|
145
|
+
:SEG_OBJC => "__OBJC",
|
146
|
+
:SEG_ICON => "__ICON",
|
147
|
+
:SEG_LINKEDIT => "__LINKEDIT",
|
148
|
+
:SEG_UNIXSTACK => "__UNIXSTACK",
|
149
|
+
:SEG_IMPORT => "__IMPORT",
|
150
|
+
}.freeze
|
151
|
+
|
152
|
+
# association of segment flag symbols to values
|
153
|
+
# @api private
|
154
|
+
SEGMENT_FLAGS = {
|
155
|
+
:SG_HIGHVM => 0x1,
|
156
|
+
:SG_FVMLIB => 0x2,
|
157
|
+
:SG_NORELOC => 0x4,
|
158
|
+
:SG_PROTECTED_VERSION_1 => 0x8,
|
159
|
+
}.freeze
|
160
|
+
|
161
|
+
# Mach-O load command structure
|
162
|
+
# This is the most generic load command - only cmd ID and size are
|
163
|
+
# represented, and no actual data. Used when a more specific class
|
164
|
+
# isn't available/implemented.
|
165
|
+
class LoadCommand < MachOStructure
|
166
|
+
# @return [MachO::MachOView] the raw view associated with the load command
|
167
|
+
attr_reader :view
|
168
|
+
|
169
|
+
# @return [Fixnum] the load command's identifying number
|
170
|
+
attr_reader :cmd
|
171
|
+
|
172
|
+
# @return [Fixnum] the size of the load command, in bytes
|
173
|
+
attr_reader :cmdsize
|
174
|
+
|
175
|
+
# @see MachOStructure::FORMAT
|
176
|
+
# @api private
|
177
|
+
FORMAT = "L=2".freeze
|
176
178
|
|
177
|
-
|
178
|
-
|
179
|
-
|
179
|
+
# @see MachOStructure::SIZEOF
|
180
|
+
# @api private
|
181
|
+
SIZEOF = 8
|
180
182
|
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
183
|
+
# Instantiates a new LoadCommand given a view into its origin Mach-O
|
184
|
+
# @param view [MachO::MachOView] the load command's raw view
|
185
|
+
# @return [MachO::LoadCommands::LoadCommand] the new load command
|
186
|
+
# @api private
|
187
|
+
def self.new_from_bin(view)
|
188
|
+
bin = view.raw_data.slice(view.offset, bytesize)
|
189
|
+
format = Utils.specialize_format(self::FORMAT, view.endianness)
|
188
190
|
|
189
|
-
|
190
|
-
|
191
|
+
new(view, *bin.unpack(format))
|
192
|
+
end
|
191
193
|
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
194
|
+
# Creates a new (viewless) command corresponding to the symbol provided
|
195
|
+
# @param cmd_sym [Symbol] the symbol of the load command being created
|
196
|
+
# @param args [Array] the arguments for the load command being created
|
197
|
+
def self.create(cmd_sym, *args)
|
198
|
+
raise LoadCommandNotCreatableError, cmd_sym unless CREATABLE_LOAD_COMMANDS.include?(cmd_sym)
|
197
199
|
|
198
|
-
|
199
|
-
|
200
|
+
klass = LoadCommands.const_get LC_STRUCTURES[cmd_sym]
|
201
|
+
cmd = LOAD_COMMAND_CONSTANTS[cmd_sym]
|
200
202
|
|
201
|
-
|
202
|
-
|
203
|
+
# cmd will be filled in, view and cmdsize will be left unpopulated
|
204
|
+
klass_arity = klass.instance_method(:initialize).arity - 3
|
203
205
|
|
204
|
-
|
206
|
+
raise LoadCommandCreationArityError.new(cmd_sym, klass_arity, args.size) if klass_arity != args.size
|
205
207
|
|
206
|
-
|
207
|
-
|
208
|
+
klass.new(nil, cmd, nil, *args)
|
209
|
+
end
|
208
210
|
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
211
|
+
# @param view [MachO::MachOView] the load command's raw view
|
212
|
+
# @param cmd [Fixnum] the load command's identifying number
|
213
|
+
# @param cmdsize [Fixnum] the size of the load command in bytes
|
214
|
+
# @api private
|
215
|
+
def initialize(view, cmd, cmdsize)
|
216
|
+
@view = view
|
217
|
+
@cmd = cmd
|
218
|
+
@cmdsize = cmdsize
|
219
|
+
end
|
218
220
|
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
221
|
+
# @return [Boolean] true if the load command can be serialized, false otherwise
|
222
|
+
def serializable?
|
223
|
+
CREATABLE_LOAD_COMMANDS.include?(LOAD_COMMANDS[cmd])
|
224
|
+
end
|
223
225
|
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
226
|
+
# @param context [MachO::LoadCommands::LoadCommand::SerializationContext] the context
|
227
|
+
# to serialize into
|
228
|
+
# @return [String, nil] the serialized fields of the load command, or nil
|
229
|
+
# if the load command can't be serialized
|
230
|
+
# @api private
|
231
|
+
def serialize(context)
|
232
|
+
raise LoadCommandNotSerializableError, LOAD_COMMANDS[cmd] unless serializable?
|
233
|
+
format = Utils.specialize_format(FORMAT, context.endianness)
|
234
|
+
[cmd, SIZEOF].pack(format)
|
235
|
+
end
|
234
236
|
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
237
|
+
# @return [Fixnum] the load command's offset in the source file
|
238
|
+
# @deprecated use {#view} instead
|
239
|
+
def offset
|
240
|
+
view.offset
|
241
|
+
end
|
240
242
|
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
243
|
+
# @return [Symbol] a symbol representation of the load command's identifying number
|
244
|
+
def type
|
245
|
+
LOAD_COMMANDS[cmd]
|
246
|
+
end
|
245
247
|
|
246
|
-
|
248
|
+
alias to_sym type
|
247
249
|
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
250
|
+
# @return [String] a string representation of the load command's identifying number
|
251
|
+
def to_s
|
252
|
+
type.to_s
|
253
|
+
end
|
252
254
|
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
255
|
+
# Represents a Load Command string. A rough analogue to the lc_str
|
256
|
+
# struct used internally by OS X. This class allows ruby-macho to
|
257
|
+
# pretend that strings stored in LCs are immediately available without
|
258
|
+
# explicit operations on the raw Mach-O data.
|
259
|
+
class LCStr
|
260
|
+
# @param lc [MachO::LoadCommands::LoadCommand] the load command
|
261
|
+
# @param lc_str [Fixnum, String] the offset to the beginning of the string,
|
262
|
+
# or the string itself if not being initialized with a view.
|
263
|
+
# @raise [MachO::LCStrMalformedError] if the string is malformed
|
264
|
+
# @todo devise a solution such that the `lc_str` parameter is not
|
265
|
+
# interpreted differently depending on `lc.view`. The current behavior
|
266
|
+
# is a hack to allow viewless load command creation.
|
267
|
+
# @api private
|
268
|
+
def initialize(lc, lc_str)
|
269
|
+
view = lc.view
|
270
|
+
|
271
|
+
if view
|
272
|
+
lc_str_abs = view.offset + lc_str
|
273
|
+
lc_end = view.offset + lc.cmdsize - 1
|
274
|
+
raw_string = view.raw_data.slice(lc_str_abs..lc_end)
|
275
|
+
@string, null_byte, _padding = raw_string.partition("\x00")
|
276
|
+
raise LCStrMalformedError, lc if null_byte.empty?
|
277
|
+
@string_offset = lc_str
|
278
|
+
else
|
279
|
+
@string = lc_str
|
280
|
+
@string_offset = 0
|
281
|
+
end
|
279
282
|
end
|
280
|
-
end
|
281
283
|
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
284
|
+
# @return [String] a string representation of the LCStr
|
285
|
+
def to_s
|
286
|
+
@string
|
287
|
+
end
|
286
288
|
|
287
|
-
|
288
|
-
|
289
|
-
|
289
|
+
# @return [Fixnum] the offset to the beginning of the string in the load command
|
290
|
+
def to_i
|
291
|
+
@string_offset
|
292
|
+
end
|
290
293
|
end
|
291
|
-
end
|
292
294
|
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
295
|
+
# Represents the contextual information needed by a load command to
|
296
|
+
# serialize itself correctly into a binary string.
|
297
|
+
class SerializationContext
|
298
|
+
# @return [Symbol] the endianness of the serialized load command
|
299
|
+
attr_reader :endianness
|
298
300
|
|
299
|
-
|
300
|
-
|
301
|
+
# @return [Fixnum] the constant alignment value used to pad the serialized load command
|
302
|
+
attr_reader :alignment
|
301
303
|
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
304
|
+
# @param macho [MachO::MachOFile] the file to contextualize
|
305
|
+
# @return [MachO::LoadCommands::LoadCommand::SerializationContext] the resulting context
|
306
|
+
def self.context_for(macho)
|
307
|
+
new(macho.endianness, macho.alignment)
|
308
|
+
end
|
307
309
|
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
310
|
+
# @param endianness [Symbol] the endianness of the context
|
311
|
+
# @param alignment [Fixnum] the alignment of the context
|
312
|
+
# @api private
|
313
|
+
def initialize(endianness, alignment)
|
314
|
+
@endianness = endianness
|
315
|
+
@alignment = alignment
|
316
|
+
end
|
314
317
|
end
|
315
318
|
end
|
316
|
-
end
|
317
319
|
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
320
|
+
# A load command containing a single 128-bit unique random number identifying
|
321
|
+
# an object produced by static link editor. Corresponds to LC_UUID.
|
322
|
+
class UUIDCommand < LoadCommand
|
323
|
+
# @return [Array<Fixnum>] the UUID
|
324
|
+
attr_reader :uuid
|
323
325
|
|
324
|
-
|
325
|
-
|
326
|
-
|
326
|
+
# @see MachOStructure::FORMAT
|
327
|
+
# @api private
|
328
|
+
FORMAT = "L=2a16".freeze
|
327
329
|
|
328
|
-
|
329
|
-
|
330
|
-
|
330
|
+
# @see MachOStructure::SIZEOF
|
331
|
+
# @api private
|
332
|
+
SIZEOF = 24
|
331
333
|
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
334
|
+
# @api private
|
335
|
+
def initialize(view, cmd, cmdsize, uuid)
|
336
|
+
super(view, cmd, cmdsize)
|
337
|
+
@uuid = uuid.unpack("C16") # re-unpack for the actual UUID array
|
338
|
+
end
|
337
339
|
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
340
|
+
# @return [String] a string representation of the UUID
|
341
|
+
def uuid_string
|
342
|
+
hexes = uuid.map { |e| "%02x" % e }
|
343
|
+
segs = [
|
344
|
+
hexes[0..3].join, hexes[4..5].join, hexes[6..7].join,
|
345
|
+
hexes[8..9].join, hexes[10..15].join
|
346
|
+
]
|
345
347
|
|
346
|
-
|
348
|
+
segs.join("-")
|
349
|
+
end
|
347
350
|
end
|
348
|
-
end
|
349
351
|
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
352
|
+
# A load command indicating that part of this file is to be mapped into
|
353
|
+
# the task's address space. Corresponds to LC_SEGMENT.
|
354
|
+
class SegmentCommand < LoadCommand
|
355
|
+
# @return [String] the name of the segment
|
356
|
+
attr_reader :segname
|
355
357
|
|
356
|
-
|
357
|
-
|
358
|
+
# @return [Fixnum] the memory address of the segment
|
359
|
+
attr_reader :vmaddr
|
358
360
|
|
359
|
-
|
360
|
-
|
361
|
+
# @return [Fixnum] the memory size of the segment
|
362
|
+
attr_reader :vmsize
|
361
363
|
|
362
|
-
|
363
|
-
|
364
|
+
# @return [Fixnum] the file offset of the segment
|
365
|
+
attr_reader :fileoff
|
364
366
|
|
365
|
-
|
366
|
-
|
367
|
+
# @return [Fixnum] the amount to map from the file
|
368
|
+
attr_reader :filesize
|
367
369
|
|
368
|
-
|
369
|
-
|
370
|
+
# @return [Fixnum] the maximum VM protection
|
371
|
+
attr_reader :maxprot
|
370
372
|
|
371
|
-
|
372
|
-
|
373
|
+
# @return [Fixnum] the initial VM protection
|
374
|
+
attr_reader :initprot
|
373
375
|
|
374
|
-
|
375
|
-
|
376
|
+
# @return [Fixnum] the number of sections in the segment
|
377
|
+
attr_reader :nsects
|
376
378
|
|
377
|
-
|
378
|
-
|
379
|
+
# @return [Fixnum] any flags associated with the segment
|
380
|
+
attr_reader :flags
|
379
381
|
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
# @see MachOStructure::SIZEOF
|
385
|
-
# @api private
|
386
|
-
SIZEOF = 56
|
382
|
+
# @see MachOStructure::FORMAT
|
383
|
+
# @api private
|
384
|
+
FORMAT = "L=2a16L=4l=2L=2".freeze
|
387
385
|
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
super(view, cmd, cmdsize)
|
392
|
-
@segname = segname.delete("\x00")
|
393
|
-
@vmaddr = vmaddr
|
394
|
-
@vmsize = vmsize
|
395
|
-
@fileoff = fileoff
|
396
|
-
@filesize = filesize
|
397
|
-
@maxprot = maxprot
|
398
|
-
@initprot = initprot
|
399
|
-
@nsects = nsects
|
400
|
-
@flags = flags
|
401
|
-
end
|
386
|
+
# @see MachOStructure::SIZEOF
|
387
|
+
# @api private
|
388
|
+
SIZEOF = 56
|
402
389
|
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
390
|
+
# @api private
|
391
|
+
def initialize(view, cmd, cmdsize, segname, vmaddr, vmsize, fileoff,
|
392
|
+
filesize, maxprot, initprot, nsects, flags)
|
393
|
+
super(view, cmd, cmdsize)
|
394
|
+
@segname = segname.delete("\x00")
|
395
|
+
@vmaddr = vmaddr
|
396
|
+
@vmsize = vmsize
|
397
|
+
@fileoff = fileoff
|
398
|
+
@filesize = filesize
|
399
|
+
@maxprot = maxprot
|
400
|
+
@initprot = initprot
|
401
|
+
@nsects = nsects
|
402
|
+
@flags = flags
|
412
403
|
end
|
413
404
|
|
414
|
-
|
415
|
-
|
416
|
-
|
405
|
+
# All sections referenced within this segment.
|
406
|
+
# @return [Array<MachO::Sections::Section>] if the Mach-O is 32-bit
|
407
|
+
# @return [Array<MachO::Sections::Section64>] if the Mach-O is 64-bit
|
408
|
+
def sections
|
409
|
+
klass = case self
|
410
|
+
when SegmentCommand64
|
411
|
+
MachO::Sections::Section64
|
412
|
+
when SegmentCommand
|
413
|
+
MachO::Sections::Section
|
414
|
+
end
|
415
|
+
|
416
|
+
bins = view.raw_data[view.offset + self.class.bytesize, nsects * klass.bytesize]
|
417
|
+
bins.unpack("a#{klass.bytesize}" * nsects).map do |bin|
|
418
|
+
klass.new_from_bin(view.endianness, bin)
|
419
|
+
end
|
417
420
|
end
|
418
|
-
end
|
419
421
|
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
422
|
+
# @example
|
423
|
+
# puts "this segment relocated in/to it" if sect.flag?(:SG_NORELOC)
|
424
|
+
# @param flag [Symbol] a segment flag symbol
|
425
|
+
# @return [Boolean] true if `flag` is present in the segment's flag field
|
426
|
+
def flag?(flag)
|
427
|
+
flag = SEGMENT_FLAGS[flag]
|
428
|
+
return false if flag.nil?
|
429
|
+
flags & flag == flag
|
430
|
+
end
|
428
431
|
end
|
429
|
-
end
|
430
432
|
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
433
|
+
# A load command indicating that part of this file is to be mapped into
|
434
|
+
# the task's address space. Corresponds to LC_SEGMENT_64.
|
435
|
+
class SegmentCommand64 < SegmentCommand
|
436
|
+
# @see MachOStructure::FORMAT
|
437
|
+
# @api private
|
438
|
+
FORMAT = "L=2a16Q=4l=2L=2".freeze
|
437
439
|
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
440
|
+
# @see MachOStructure::SIZEOF
|
441
|
+
# @api private
|
442
|
+
SIZEOF = 72
|
443
|
+
end
|
442
444
|
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
445
|
+
# A load command representing some aspect of shared libraries, depending
|
446
|
+
# on filetype. Corresponds to LC_ID_DYLIB, LC_LOAD_DYLIB, LC_LOAD_WEAK_DYLIB,
|
447
|
+
# and LC_REEXPORT_DYLIB.
|
448
|
+
class DylibCommand < LoadCommand
|
449
|
+
# @return [MachO::LoadCommands::LoadCommand::LCStr] the library's path name as an LCStr
|
450
|
+
attr_reader :name
|
449
451
|
|
450
|
-
|
451
|
-
|
452
|
+
# @return [Fixnum] the library's build time stamp
|
453
|
+
attr_reader :timestamp
|
452
454
|
|
453
|
-
|
454
|
-
|
455
|
+
# @return [Fixnum] the library's current version number
|
456
|
+
attr_reader :current_version
|
455
457
|
|
456
|
-
|
457
|
-
|
458
|
+
# @return [Fixnum] the library's compatibility version number
|
459
|
+
attr_reader :compatibility_version
|
458
460
|
|
459
|
-
|
460
|
-
|
461
|
-
|
461
|
+
# @see MachOStructure::FORMAT
|
462
|
+
# @api private
|
463
|
+
FORMAT = "L=6".freeze
|
462
464
|
|
463
|
-
|
464
|
-
|
465
|
-
|
465
|
+
# @see MachOStructure::SIZEOF
|
466
|
+
# @api private
|
467
|
+
SIZEOF = 24
|
466
468
|
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
469
|
+
# @api private
|
470
|
+
def initialize(view, cmd, cmdsize, name, timestamp, current_version, compatibility_version)
|
471
|
+
super(view, cmd, cmdsize)
|
472
|
+
@name = LCStr.new(self, name)
|
473
|
+
@timestamp = timestamp
|
474
|
+
@current_version = current_version
|
475
|
+
@compatibility_version = compatibility_version
|
476
|
+
end
|
475
477
|
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
478
|
+
# @param context [MachO::LoadCommands::LoadCommand::SerializationContext] the context
|
479
|
+
# @return [String] the serialized fields of the load command
|
480
|
+
# @api private
|
481
|
+
def serialize(context)
|
482
|
+
format = Utils.specialize_format(FORMAT, context.endianness)
|
483
|
+
string_payload, string_offsets = Utils.pack_strings(SIZEOF, context.alignment, :name => name.to_s)
|
484
|
+
cmdsize = SIZEOF + string_payload.bytesize
|
485
|
+
[cmd, cmdsize, string_offsets[:name], timestamp, current_version,
|
486
|
+
compatibility_version].pack(format) + string_payload
|
487
|
+
end
|
485
488
|
end
|
486
|
-
end
|
487
489
|
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
490
|
+
# A load command representing some aspect of the dynamic linker, depending
|
491
|
+
# on filetype. Corresponds to LC_ID_DYLINKER, LC_LOAD_DYLINKER, and
|
492
|
+
# LC_DYLD_ENVIRONMENT.
|
493
|
+
class DylinkerCommand < LoadCommand
|
494
|
+
# @return [MachO::LoadCommands::LoadCommand::LCStr] the dynamic linker's path name as an LCStr
|
495
|
+
attr_reader :name
|
494
496
|
|
495
|
-
|
496
|
-
|
497
|
-
|
497
|
+
# @see MachOStructure::FORMAT
|
498
|
+
# @api private
|
499
|
+
FORMAT = "L=3".freeze
|
498
500
|
|
499
|
-
|
500
|
-
|
501
|
-
|
501
|
+
# @see MachOStructure::SIZEOF
|
502
|
+
# @api private
|
503
|
+
SIZEOF = 12
|
502
504
|
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
505
|
+
# @api private
|
506
|
+
def initialize(view, cmd, cmdsize, name)
|
507
|
+
super(view, cmd, cmdsize)
|
508
|
+
@name = LCStr.new(self, name)
|
509
|
+
end
|
508
510
|
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
511
|
+
# @param context [MachO::LoadCommands::LoadCommand::SerializationContext] the context
|
512
|
+
# @return [String] the serialized fields of the load command
|
513
|
+
# @api private
|
514
|
+
def serialize(context)
|
515
|
+
format = Utils.specialize_format(FORMAT, context.endianness)
|
516
|
+
string_payload, string_offsets = Utils.pack_strings(SIZEOF, context.alignment, :name => name.to_s)
|
517
|
+
cmdsize = SIZEOF + string_payload.bytesize
|
518
|
+
[cmd, cmdsize, string_offsets[:name]].pack(format) + string_payload
|
519
|
+
end
|
517
520
|
end
|
518
|
-
end
|
519
521
|
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
522
|
+
# A load command used to indicate dynamic libraries used in prebinding.
|
523
|
+
# Corresponds to LC_PREBOUND_DYLIB.
|
524
|
+
class PreboundDylibCommand < LoadCommand
|
525
|
+
# @return [MachO::LoadCommands::LoadCommand::LCStr] the library's path name as an LCStr
|
526
|
+
attr_reader :name
|
525
527
|
|
526
|
-
|
527
|
-
|
528
|
+
# @return [Fixnum] the number of modules in the library
|
529
|
+
attr_reader :nmodules
|
528
530
|
|
529
|
-
|
530
|
-
|
531
|
+
# @return [Fixnum] a bit vector of linked modules
|
532
|
+
attr_reader :linked_modules
|
531
533
|
|
532
|
-
|
533
|
-
|
534
|
-
|
534
|
+
# @see MachOStructure::FORMAT
|
535
|
+
# @api private
|
536
|
+
FORMAT = "L=5".freeze
|
535
537
|
|
536
|
-
|
537
|
-
|
538
|
-
|
538
|
+
# @see MachOStructure::SIZEOF
|
539
|
+
# @api private
|
540
|
+
SIZEOF = 20
|
539
541
|
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
542
|
+
# @api private
|
543
|
+
def initialize(view, cmd, cmdsize, name, nmodules, linked_modules)
|
544
|
+
super(view, cmd, cmdsize)
|
545
|
+
@name = LCStr.new(self, name)
|
546
|
+
@nmodules = nmodules
|
547
|
+
@linked_modules = linked_modules
|
548
|
+
end
|
546
549
|
end
|
547
|
-
end
|
548
550
|
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
551
|
+
# A load command used to represent threads.
|
552
|
+
# @note cctools-870 has all fields of thread_command commented out except common ones (cmd, cmdsize)
|
553
|
+
class ThreadCommand < LoadCommand
|
554
|
+
# @see MachOStructure::FORMAT
|
555
|
+
# @api private
|
556
|
+
FORMAT = "L=2".freeze
|
555
557
|
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
558
|
+
# @see MachOStructure::SIZEOF
|
559
|
+
# @api private
|
560
|
+
SIZEOF = 8
|
561
|
+
end
|
560
562
|
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
563
|
+
# A load command containing the address of the dynamic shared library
|
564
|
+
# initialization routine and an index into the module table for the module
|
565
|
+
# that defines the routine. Corresponds to LC_ROUTINES.
|
566
|
+
class RoutinesCommand < LoadCommand
|
567
|
+
# @return [Fixnum] the address of the initialization routine
|
568
|
+
attr_reader :init_address
|
567
569
|
|
568
|
-
|
569
|
-
|
570
|
+
# @return [Fixnum] the index into the module table that the init routine is defined in
|
571
|
+
attr_reader :init_module
|
570
572
|
|
571
|
-
|
572
|
-
|
573
|
+
# @return [void]
|
574
|
+
attr_reader :reserved1
|
573
575
|
|
574
|
-
|
575
|
-
|
576
|
+
# @return [void]
|
577
|
+
attr_reader :reserved2
|
576
578
|
|
577
|
-
|
578
|
-
|
579
|
+
# @return [void]
|
580
|
+
attr_reader :reserved3
|
579
581
|
|
580
|
-
|
581
|
-
|
582
|
+
# @return [void]
|
583
|
+
attr_reader :reserved4
|
582
584
|
|
583
|
-
|
584
|
-
|
585
|
+
# @return [void]
|
586
|
+
attr_reader :reserved5
|
585
587
|
|
586
|
-
|
587
|
-
|
588
|
+
# @return [void]
|
589
|
+
attr_reader :reserved6
|
588
590
|
|
589
|
-
|
590
|
-
|
591
|
-
|
591
|
+
# @see MachOStructure::FORMAT
|
592
|
+
# @api private
|
593
|
+
FORMAT = "L=10".freeze
|
592
594
|
|
593
|
-
|
594
|
-
|
595
|
-
|
595
|
+
# @see MachOStructure::SIZEOF
|
596
|
+
# @api private
|
597
|
+
SIZEOF = 40
|
596
598
|
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
599
|
+
# @api private
|
600
|
+
def initialize(view, cmd, cmdsize, init_address, init_module, reserved1,
|
601
|
+
reserved2, reserved3, reserved4, reserved5, reserved6)
|
602
|
+
super(view, cmd, cmdsize)
|
603
|
+
@init_address = init_address
|
604
|
+
@init_module = init_module
|
605
|
+
@reserved1 = reserved1
|
606
|
+
@reserved2 = reserved2
|
607
|
+
@reserved3 = reserved3
|
608
|
+
@reserved4 = reserved4
|
609
|
+
@reserved5 = reserved5
|
610
|
+
@reserved6 = reserved6
|
611
|
+
end
|
609
612
|
end
|
610
|
-
end
|
611
613
|
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
614
|
+
# A load command containing the address of the dynamic shared library
|
615
|
+
# initialization routine and an index into the module table for the module
|
616
|
+
# that defines the routine. Corresponds to LC_ROUTINES_64.
|
617
|
+
class RoutinesCommand64 < RoutinesCommand
|
618
|
+
# @see MachOStructure::FORMAT
|
619
|
+
# @api private
|
620
|
+
FORMAT = "L=2Q=8".freeze
|
619
621
|
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
622
|
+
# @see MachOStructure::SIZEOF
|
623
|
+
# @api private
|
624
|
+
SIZEOF = 72
|
625
|
+
end
|
624
626
|
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
627
|
+
# A load command signifying membership of a subframework containing the name
|
628
|
+
# of an umbrella framework. Corresponds to LC_SUB_FRAMEWORK.
|
629
|
+
class SubFrameworkCommand < LoadCommand
|
630
|
+
# @return [MachO::LoadCommands::LoadCommand::LCStr] the umbrella framework name as an LCStr
|
631
|
+
attr_reader :umbrella
|
630
632
|
|
631
|
-
|
632
|
-
|
633
|
-
|
633
|
+
# @see MachOStructure::FORMAT
|
634
|
+
# @api private
|
635
|
+
FORMAT = "L=3".freeze
|
634
636
|
|
635
|
-
|
636
|
-
|
637
|
-
|
637
|
+
# @see MachOStructure::SIZEOF
|
638
|
+
# @api private
|
639
|
+
SIZEOF = 12
|
638
640
|
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
641
|
+
# @api private
|
642
|
+
def initialize(view, cmd, cmdsize, umbrella)
|
643
|
+
super(view, cmd, cmdsize)
|
644
|
+
@umbrella = LCStr.new(self, umbrella)
|
645
|
+
end
|
643
646
|
end
|
644
|
-
end
|
645
647
|
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
648
|
+
# A load command signifying membership of a subumbrella containing the name
|
649
|
+
# of an umbrella framework. Corresponds to LC_SUB_UMBRELLA.
|
650
|
+
class SubUmbrellaCommand < LoadCommand
|
651
|
+
# @return [MachO::LoadCommands::LoadCommand::LCStr] the subumbrella framework name as an LCStr
|
652
|
+
attr_reader :sub_umbrella
|
651
653
|
|
652
|
-
|
653
|
-
|
654
|
-
|
654
|
+
# @see MachOStructure::FORMAT
|
655
|
+
# @api private
|
656
|
+
FORMAT = "L=3".freeze
|
655
657
|
|
656
|
-
|
657
|
-
|
658
|
-
|
658
|
+
# @see MachOStructure::SIZEOF
|
659
|
+
# @api private
|
660
|
+
SIZEOF = 12
|
659
661
|
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
662
|
+
# @api private
|
663
|
+
def initialize(view, cmd, cmdsize, sub_umbrella)
|
664
|
+
super(view, cmd, cmdsize)
|
665
|
+
@sub_umbrella = LCStr.new(self, sub_umbrella)
|
666
|
+
end
|
664
667
|
end
|
665
|
-
end
|
666
668
|
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
669
|
+
# A load command signifying a sublibrary of a shared library. Corresponds
|
670
|
+
# to LC_SUB_LIBRARY.
|
671
|
+
class SubLibraryCommand < LoadCommand
|
672
|
+
# @return [MachO::LoadCommands::LoadCommand::LCStr] the sublibrary name as an LCStr
|
673
|
+
attr_reader :sub_library
|
672
674
|
|
673
|
-
|
674
|
-
|
675
|
-
|
675
|
+
# @see MachOStructure::FORMAT
|
676
|
+
# @api private
|
677
|
+
FORMAT = "L=3".freeze
|
676
678
|
|
677
|
-
|
678
|
-
|
679
|
-
|
679
|
+
# @see MachOStructure::SIZEOF
|
680
|
+
# @api private
|
681
|
+
SIZEOF = 12
|
680
682
|
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
683
|
+
# @api private
|
684
|
+
def initialize(view, cmd, cmdsize, sub_library)
|
685
|
+
super(view, cmd, cmdsize)
|
686
|
+
@sub_library = LCStr.new(self, sub_library)
|
687
|
+
end
|
685
688
|
end
|
686
|
-
end
|
687
689
|
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
690
|
+
# A load command signifying a shared library that is a subframework of
|
691
|
+
# an umbrella framework. Corresponds to LC_SUB_CLIENT.
|
692
|
+
class SubClientCommand < LoadCommand
|
693
|
+
# @return [MachO::LoadCommands::LoadCommand::LCStr] the subclient name as an LCStr
|
694
|
+
attr_reader :sub_client
|
693
695
|
|
694
|
-
|
695
|
-
|
696
|
-
|
696
|
+
# @see MachOStructure::FORMAT
|
697
|
+
# @api private
|
698
|
+
FORMAT = "L=3".freeze
|
697
699
|
|
698
|
-
|
699
|
-
|
700
|
-
|
700
|
+
# @see MachOStructure::SIZEOF
|
701
|
+
# @api private
|
702
|
+
SIZEOF = 12
|
701
703
|
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
704
|
+
# @api private
|
705
|
+
def initialize(view, cmd, cmdsize, sub_client)
|
706
|
+
super(view, cmd, cmdsize)
|
707
|
+
@sub_client = LCStr.new(self, sub_client)
|
708
|
+
end
|
706
709
|
end
|
707
|
-
end
|
708
710
|
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
711
|
+
# A load command containing the offsets and sizes of the link-edit 4.3BSD
|
712
|
+
# "stab" style symbol table information. Corresponds to LC_SYMTAB.
|
713
|
+
class SymtabCommand < LoadCommand
|
714
|
+
# @return [Fixnum] the symbol table's offset
|
715
|
+
attr_reader :symoff
|
714
716
|
|
715
|
-
|
716
|
-
|
717
|
+
# @return [Fixnum] the number of symbol table entries
|
718
|
+
attr_reader :nsyms
|
717
719
|
|
718
|
-
|
719
|
-
|
720
|
+
# @return the string table's offset
|
721
|
+
attr_reader :stroff
|
720
722
|
|
721
|
-
|
722
|
-
|
723
|
+
# @return the string table size in bytes
|
724
|
+
attr_reader :strsize
|
723
725
|
|
724
|
-
|
725
|
-
|
726
|
-
|
726
|
+
# @see MachOStructure::FORMAT
|
727
|
+
# @api private
|
728
|
+
FORMAT = "L=6".freeze
|
727
729
|
|
728
|
-
|
729
|
-
|
730
|
-
|
730
|
+
# @see MachOStructure::SIZEOF
|
731
|
+
# @api private
|
732
|
+
SIZEOF = 24
|
731
733
|
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
734
|
+
# @api private
|
735
|
+
def initialize(view, cmd, cmdsize, symoff, nsyms, stroff, strsize)
|
736
|
+
super(view, cmd, cmdsize)
|
737
|
+
@symoff = symoff
|
738
|
+
@nsyms = nsyms
|
739
|
+
@stroff = stroff
|
740
|
+
@strsize = strsize
|
741
|
+
end
|
739
742
|
end
|
740
|
-
end
|
741
743
|
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
744
|
+
# A load command containing symbolic information needed to support data
|
745
|
+
# structures used by the dynamic link editor. Corresponds to LC_DYSYMTAB.
|
746
|
+
class DysymtabCommand < LoadCommand
|
747
|
+
# @return [Fixnum] the index to local symbols
|
748
|
+
attr_reader :ilocalsym
|
747
749
|
|
748
|
-
|
749
|
-
|
750
|
+
# @return [Fixnum] the number of local symbols
|
751
|
+
attr_reader :nlocalsym
|
750
752
|
|
751
|
-
|
752
|
-
|
753
|
+
# @return [Fixnum] the index to externally defined symbols
|
754
|
+
attr_reader :iextdefsym
|
753
755
|
|
754
|
-
|
755
|
-
|
756
|
+
# @return [Fixnum] the number of externally defined symbols
|
757
|
+
attr_reader :nextdefsym
|
756
758
|
|
757
|
-
|
758
|
-
|
759
|
+
# @return [Fixnum] the index to undefined symbols
|
760
|
+
attr_reader :iundefsym
|
759
761
|
|
760
|
-
|
761
|
-
|
762
|
+
# @return [Fixnum] the number of undefined symbols
|
763
|
+
attr_reader :nundefsym
|
762
764
|
|
763
|
-
|
764
|
-
|
765
|
+
# @return [Fixnum] the file offset to the table of contents
|
766
|
+
attr_reader :tocoff
|
765
767
|
|
766
|
-
|
767
|
-
|
768
|
+
# @return [Fixnum] the number of entries in the table of contents
|
769
|
+
attr_reader :ntoc
|
768
770
|
|
769
|
-
|
770
|
-
|
771
|
+
# @return [Fixnum] the file offset to the module table
|
772
|
+
attr_reader :modtaboff
|
771
773
|
|
772
|
-
|
773
|
-
|
774
|
+
# @return [Fixnum] the number of entries in the module table
|
775
|
+
attr_reader :nmodtab
|
774
776
|
|
775
|
-
|
776
|
-
|
777
|
+
# @return [Fixnum] the file offset to the referenced symbol table
|
778
|
+
attr_reader :extrefsymoff
|
777
779
|
|
778
|
-
|
779
|
-
|
780
|
+
# @return [Fixnum] the number of entries in the referenced symbol table
|
781
|
+
attr_reader :nextrefsyms
|
780
782
|
|
781
|
-
|
782
|
-
|
783
|
+
# @return [Fixnum] the file offset to the indirect symbol table
|
784
|
+
attr_reader :indirectsymoff
|
783
785
|
|
784
|
-
|
785
|
-
|
786
|
+
# @return [Fixnum] the number of entries in the indirect symbol table
|
787
|
+
attr_reader :nindirectsyms
|
786
788
|
|
787
|
-
|
788
|
-
|
789
|
+
# @return [Fixnum] the file offset to the external relocation entries
|
790
|
+
attr_reader :extreloff
|
789
791
|
|
790
|
-
|
791
|
-
|
792
|
+
# @return [Fixnum] the number of external relocation entries
|
793
|
+
attr_reader :nextrel
|
792
794
|
|
793
|
-
|
794
|
-
|
795
|
+
# @return [Fixnum] the file offset to the local relocation entries
|
796
|
+
attr_reader :locreloff
|
795
797
|
|
796
|
-
|
797
|
-
|
798
|
+
# @return [Fixnum] the number of local relocation entries
|
799
|
+
attr_reader :nlocrel
|
798
800
|
|
799
|
-
|
800
|
-
|
801
|
-
|
801
|
+
# @see MachOStructure::FORMAT
|
802
|
+
# @api private
|
803
|
+
FORMAT = "L=20".freeze
|
802
804
|
|
803
|
-
|
804
|
-
|
805
|
-
|
805
|
+
# @see MachOStructure::SIZEOF
|
806
|
+
# @api private
|
807
|
+
SIZEOF = 80
|
806
808
|
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
826
|
-
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
|
809
|
+
# ugh
|
810
|
+
# @api private
|
811
|
+
def initialize(view, cmd, cmdsize, ilocalsym, nlocalsym, iextdefsym,
|
812
|
+
nextdefsym, iundefsym, nundefsym, tocoff, ntoc, modtaboff,
|
813
|
+
nmodtab, extrefsymoff, nextrefsyms, indirectsymoff,
|
814
|
+
nindirectsyms, extreloff, nextrel, locreloff, nlocrel)
|
815
|
+
super(view, cmd, cmdsize)
|
816
|
+
@ilocalsym = ilocalsym
|
817
|
+
@nlocalsym = nlocalsym
|
818
|
+
@iextdefsym = iextdefsym
|
819
|
+
@nextdefsym = nextdefsym
|
820
|
+
@iundefsym = iundefsym
|
821
|
+
@nundefsym = nundefsym
|
822
|
+
@tocoff = tocoff
|
823
|
+
@ntoc = ntoc
|
824
|
+
@modtaboff = modtaboff
|
825
|
+
@nmodtab = nmodtab
|
826
|
+
@extrefsymoff = extrefsymoff
|
827
|
+
@nextrefsyms = nextrefsyms
|
828
|
+
@indirectsymoff = indirectsymoff
|
829
|
+
@nindirectsyms = nindirectsyms
|
830
|
+
@extreloff = extreloff
|
831
|
+
@nextrel = nextrel
|
832
|
+
@locreloff = locreloff
|
833
|
+
@nlocrel = nlocrel
|
834
|
+
end
|
832
835
|
end
|
833
|
-
end
|
834
836
|
|
835
|
-
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
|
837
|
+
# A load command containing the offset and number of hints in the two-level
|
838
|
+
# namespace lookup hints table. Corresponds to LC_TWOLEVEL_HINTS.
|
839
|
+
class TwolevelHintsCommand < LoadCommand
|
840
|
+
# @return [Fixnum] the offset to the hint table
|
841
|
+
attr_reader :htoffset
|
840
842
|
|
841
|
-
|
842
|
-
|
843
|
+
# @return [Fixnum] the number of hints in the hint table
|
844
|
+
attr_reader :nhints
|
843
845
|
|
844
|
-
|
845
|
-
|
846
|
+
# @return [MachO::LoadCommands::TwolevelHintsCommand::TwolevelHintTable] the hint table
|
847
|
+
attr_reader :table
|
846
848
|
|
847
|
-
|
848
|
-
|
849
|
-
|
849
|
+
# @see MachOStructure::FORMAT
|
850
|
+
# @api private
|
851
|
+
FORMAT = "L=4".freeze
|
850
852
|
|
851
|
-
|
852
|
-
|
853
|
-
|
853
|
+
# @see MachOStructure::SIZEOF
|
854
|
+
# @api private
|
855
|
+
SIZEOF = 16
|
854
856
|
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
857
|
+
# @api private
|
858
|
+
def initialize(view, cmd, cmdsize, htoffset, nhints)
|
859
|
+
super(view, cmd, cmdsize)
|
860
|
+
@htoffset = htoffset
|
861
|
+
@nhints = nhints
|
862
|
+
@table = TwolevelHintsTable.new(view, htoffset, nhints)
|
863
|
+
end
|
862
864
|
|
863
|
-
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
865
|
+
# A representation of the two-level namespace lookup hints table exposed
|
866
|
+
# by a {TwolevelHintsCommand} (`LC_TWOLEVEL_HINTS`).
|
867
|
+
class TwolevelHintsTable
|
868
|
+
# @return [Array<MachO::LoadCommands::TwoLevelHintsCommand::TwoLevelHintsTable::TwoLevelHint>] all hints in the table
|
869
|
+
attr_reader :hints
|
868
870
|
|
869
|
-
|
870
|
-
|
871
|
-
|
872
|
-
|
873
|
-
|
874
|
-
|
875
|
-
|
876
|
-
|
871
|
+
# @param view [MachO::MachOView] the view into the current Mach-O
|
872
|
+
# @param htoffset [Fixnum] the offset of the hints table
|
873
|
+
# @param nhints [Fixnum] the number of two-level hints in the table
|
874
|
+
# @api private
|
875
|
+
def initialize(view, htoffset, nhints)
|
876
|
+
format = Utils.specialize_format("L=#{nhints}", view.endianness)
|
877
|
+
raw_table = view.raw_data[htoffset, nhints * 4]
|
878
|
+
blobs = raw_table.unpack(format)
|
877
879
|
|
878
|
-
|
879
|
-
|
880
|
+
@hints = blobs.map { |b| TwolevelHint.new(b) }
|
881
|
+
end
|
880
882
|
|
881
|
-
|
882
|
-
|
883
|
-
|
884
|
-
|
883
|
+
# An individual two-level namespace lookup hint.
|
884
|
+
class TwolevelHint
|
885
|
+
# @return [Fixnum] the index into the sub-images
|
886
|
+
attr_reader :isub_image
|
885
887
|
|
886
|
-
|
887
|
-
|
888
|
+
# @return [Fixnum] the index into the table of contents
|
889
|
+
attr_reader :itoc
|
888
890
|
|
889
|
-
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
891
|
+
# @param blob [Fixnum] the 32-bit number containing the lookup hint
|
892
|
+
# @api private
|
893
|
+
def initialize(blob)
|
894
|
+
@isub_image = blob >> 24
|
895
|
+
@itoc = blob & 0x00FFFFFF
|
896
|
+
end
|
894
897
|
end
|
895
898
|
end
|
896
899
|
end
|
897
|
-
end
|
898
900
|
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
903
|
-
|
901
|
+
# A load command containing the value of the original checksum for prebound
|
902
|
+
# files, or zero. Corresponds to LC_PREBIND_CKSUM.
|
903
|
+
class PrebindCksumCommand < LoadCommand
|
904
|
+
# @return [Fixnum] the checksum or 0
|
905
|
+
attr_reader :cksum
|
904
906
|
|
905
|
-
|
906
|
-
|
907
|
-
|
907
|
+
# @see MachOStructure::FORMAT
|
908
|
+
# @api private
|
909
|
+
FORMAT = "L=3".freeze
|
908
910
|
|
909
|
-
|
910
|
-
|
911
|
-
|
911
|
+
# @see MachOStructure::SIZEOF
|
912
|
+
# @api private
|
913
|
+
SIZEOF = 12
|
912
914
|
|
913
|
-
|
914
|
-
|
915
|
-
|
916
|
-
|
915
|
+
# @api private
|
916
|
+
def initialize(view, cmd, cmdsize, cksum)
|
917
|
+
super(view, cmd, cmdsize)
|
918
|
+
@cksum = cksum
|
919
|
+
end
|
917
920
|
end
|
918
|
-
end
|
919
921
|
|
920
|
-
|
921
|
-
|
922
|
-
|
923
|
-
|
924
|
-
|
925
|
-
|
922
|
+
# A load command representing an rpath, which specifies a path that should
|
923
|
+
# be added to the current run path used to find @rpath prefixed dylibs.
|
924
|
+
# Corresponds to LC_RPATH.
|
925
|
+
class RpathCommand < LoadCommand
|
926
|
+
# @return [MachO::LoadCommands::LoadCommand::LCStr] the path to add to the run path as an LCStr
|
927
|
+
attr_reader :path
|
926
928
|
|
927
|
-
|
928
|
-
|
929
|
-
|
929
|
+
# @see MachOStructure::FORMAT
|
930
|
+
# @api private
|
931
|
+
FORMAT = "L=3".freeze
|
930
932
|
|
931
|
-
|
932
|
-
|
933
|
-
|
933
|
+
# @see MachOStructure::SIZEOF
|
934
|
+
# @api private
|
935
|
+
SIZEOF = 12
|
934
936
|
|
935
|
-
|
936
|
-
|
937
|
-
|
938
|
-
|
939
|
-
|
937
|
+
# @api private
|
938
|
+
def initialize(view, cmd, cmdsize, path)
|
939
|
+
super(view, cmd, cmdsize)
|
940
|
+
@path = LCStr.new(self, path)
|
941
|
+
end
|
940
942
|
|
941
|
-
|
942
|
-
|
943
|
-
|
944
|
-
|
945
|
-
|
946
|
-
|
947
|
-
|
948
|
-
|
943
|
+
# @param context [MachO::LoadCommands::LoadCommand::SerializationContext] the context
|
944
|
+
# @return [String] the serialized fields of the load command
|
945
|
+
# @api private
|
946
|
+
def serialize(context)
|
947
|
+
format = Utils.specialize_format(FORMAT, context.endianness)
|
948
|
+
string_payload, string_offsets = Utils.pack_strings(SIZEOF, context.alignment, :path => path.to_s)
|
949
|
+
cmdsize = SIZEOF + string_payload.bytesize
|
950
|
+
[cmd, cmdsize, string_offsets[:path]].pack(format) + string_payload
|
951
|
+
end
|
949
952
|
end
|
950
|
-
end
|
951
953
|
|
952
|
-
|
953
|
-
|
954
|
-
|
955
|
-
|
956
|
-
|
957
|
-
|
954
|
+
# A load command representing the offsets and sizes of a blob of data in
|
955
|
+
# the __LINKEDIT segment. Corresponds to LC_CODE_SIGNATURE, LC_SEGMENT_SPLIT_INFO,
|
956
|
+
# LC_FUNCTION_STARTS, LC_DATA_IN_CODE, LC_DYLIB_CODE_SIGN_DRS, and LC_LINKER_OPTIMIZATION_HINT.
|
957
|
+
class LinkeditDataCommand < LoadCommand
|
958
|
+
# @return [Fixnum] offset to the data in the __LINKEDIT segment
|
959
|
+
attr_reader :dataoff
|
958
960
|
|
959
|
-
|
960
|
-
|
961
|
+
# @return [Fixnum] size of the data in the __LINKEDIT segment
|
962
|
+
attr_reader :datasize
|
961
963
|
|
962
|
-
|
963
|
-
|
964
|
-
|
964
|
+
# @see MachOStructure::FORMAT
|
965
|
+
# @api private
|
966
|
+
FORMAT = "L=4".freeze
|
965
967
|
|
966
|
-
|
967
|
-
|
968
|
-
|
968
|
+
# @see MachOStructure::SIZEOF
|
969
|
+
# @api private
|
970
|
+
SIZEOF = 16
|
969
971
|
|
970
|
-
|
971
|
-
|
972
|
-
|
973
|
-
|
974
|
-
|
972
|
+
# @api private
|
973
|
+
def initialize(view, cmd, cmdsize, dataoff, datasize)
|
974
|
+
super(view, cmd, cmdsize)
|
975
|
+
@dataoff = dataoff
|
976
|
+
@datasize = datasize
|
977
|
+
end
|
975
978
|
end
|
976
|
-
end
|
977
979
|
|
978
|
-
|
979
|
-
|
980
|
-
|
981
|
-
|
982
|
-
|
980
|
+
# A load command representing the offset to and size of an encrypted
|
981
|
+
# segment. Corresponds to LC_ENCRYPTION_INFO.
|
982
|
+
class EncryptionInfoCommand < LoadCommand
|
983
|
+
# @return [Fixnum] the offset to the encrypted segment
|
984
|
+
attr_reader :cryptoff
|
983
985
|
|
984
|
-
|
985
|
-
|
986
|
+
# @return [Fixnum] the size of the encrypted segment
|
987
|
+
attr_reader :cryptsize
|
986
988
|
|
987
|
-
|
988
|
-
|
989
|
+
# @return [Fixnum] the encryption system, or 0 if not encrypted yet
|
990
|
+
attr_reader :cryptid
|
989
991
|
|
990
|
-
|
991
|
-
|
992
|
-
|
992
|
+
# @see MachOStructure::FORMAT
|
993
|
+
# @api private
|
994
|
+
FORMAT = "L=5".freeze
|
993
995
|
|
994
|
-
|
995
|
-
|
996
|
-
|
996
|
+
# @see MachOStructure::SIZEOF
|
997
|
+
# @api private
|
998
|
+
SIZEOF = 20
|
997
999
|
|
998
|
-
|
999
|
-
|
1000
|
-
|
1001
|
-
|
1002
|
-
|
1003
|
-
|
1000
|
+
# @api private
|
1001
|
+
def initialize(view, cmd, cmdsize, cryptoff, cryptsize, cryptid)
|
1002
|
+
super(view, cmd, cmdsize)
|
1003
|
+
@cryptoff = cryptoff
|
1004
|
+
@cryptsize = cryptsize
|
1005
|
+
@cryptid = cryptid
|
1006
|
+
end
|
1004
1007
|
end
|
1005
|
-
end
|
1006
1008
|
|
1007
|
-
|
1008
|
-
|
1009
|
-
|
1010
|
-
|
1011
|
-
|
1009
|
+
# A load command representing the offset to and size of an encrypted
|
1010
|
+
# segment. Corresponds to LC_ENCRYPTION_INFO_64.
|
1011
|
+
class EncryptionInfoCommand64 < LoadCommand
|
1012
|
+
# @return [Fixnum] the offset to the encrypted segment
|
1013
|
+
attr_reader :cryptoff
|
1012
1014
|
|
1013
|
-
|
1014
|
-
|
1015
|
+
# @return [Fixnum] the size of the encrypted segment
|
1016
|
+
attr_reader :cryptsize
|
1015
1017
|
|
1016
|
-
|
1017
|
-
|
1018
|
+
# @return [Fixnum] the encryption system, or 0 if not encrypted yet
|
1019
|
+
attr_reader :cryptid
|
1018
1020
|
|
1019
|
-
|
1020
|
-
|
1021
|
+
# @return [Fixnum] 64-bit padding value
|
1022
|
+
attr_reader :pad
|
1021
1023
|
|
1022
|
-
|
1023
|
-
|
1024
|
-
|
1024
|
+
# @see MachOStructure::FORMAT
|
1025
|
+
# @api private
|
1026
|
+
FORMAT = "L=6".freeze
|
1025
1027
|
|
1026
|
-
|
1027
|
-
|
1028
|
-
|
1028
|
+
# @see MachOStructure::SIZEOF
|
1029
|
+
# @api private
|
1030
|
+
SIZEOF = 24
|
1029
1031
|
|
1030
|
-
|
1031
|
-
|
1032
|
-
|
1033
|
-
|
1034
|
-
|
1035
|
-
|
1036
|
-
|
1032
|
+
# @api private
|
1033
|
+
def initialize(view, cmd, cmdsize, cryptoff, cryptsize, cryptid, pad)
|
1034
|
+
super(view, cmd, cmdsize)
|
1035
|
+
@cryptoff = cryptoff
|
1036
|
+
@cryptsize = cryptsize
|
1037
|
+
@cryptid = cryptid
|
1038
|
+
@pad = pad
|
1039
|
+
end
|
1037
1040
|
end
|
1038
|
-
end
|
1039
1041
|
|
1040
|
-
|
1041
|
-
|
1042
|
-
|
1043
|
-
|
1044
|
-
|
1042
|
+
# A load command containing the minimum OS version on which the binary
|
1043
|
+
# was built to run. Corresponds to LC_VERSION_MIN_MACOSX and LC_VERSION_MIN_IPHONEOS.
|
1044
|
+
class VersionMinCommand < LoadCommand
|
1045
|
+
# @return [Fixnum] the version X.Y.Z packed as x16.y8.z8
|
1046
|
+
attr_reader :version
|
1045
1047
|
|
1046
|
-
|
1047
|
-
|
1048
|
+
# @return [Fixnum] the SDK version X.Y.Z packed as x16.y8.z8
|
1049
|
+
attr_reader :sdk
|
1048
1050
|
|
1049
|
-
|
1050
|
-
|
1051
|
-
|
1051
|
+
# @see MachOStructure::FORMAT
|
1052
|
+
# @api private
|
1053
|
+
FORMAT = "L=4".freeze
|
1052
1054
|
|
1053
|
-
|
1054
|
-
|
1055
|
-
|
1055
|
+
# @see MachOStructure::SIZEOF
|
1056
|
+
# @api private
|
1057
|
+
SIZEOF = 16
|
1056
1058
|
|
1057
|
-
|
1058
|
-
|
1059
|
-
|
1060
|
-
|
1061
|
-
|
1062
|
-
|
1059
|
+
# @api private
|
1060
|
+
def initialize(view, cmd, cmdsize, version, sdk)
|
1061
|
+
super(view, cmd, cmdsize)
|
1062
|
+
@version = version
|
1063
|
+
@sdk = sdk
|
1064
|
+
end
|
1063
1065
|
|
1064
|
-
|
1065
|
-
|
1066
|
-
|
1067
|
-
|
1068
|
-
|
1069
|
-
|
1070
|
-
|
1066
|
+
# A string representation of the binary's minimum OS version.
|
1067
|
+
# @return [String] a string representing the minimum OS version.
|
1068
|
+
def version_string
|
1069
|
+
binary = "%032b" % version
|
1070
|
+
segs = [
|
1071
|
+
binary[0..15], binary[16..23], binary[24..31]
|
1072
|
+
].map { |s| s.to_i(2) }
|
1071
1073
|
|
1072
|
-
|
1073
|
-
|
1074
|
+
segs.join(".")
|
1075
|
+
end
|
1074
1076
|
|
1075
|
-
|
1076
|
-
|
1077
|
-
|
1078
|
-
|
1079
|
-
|
1080
|
-
|
1081
|
-
|
1077
|
+
# A string representation of the binary's SDK version.
|
1078
|
+
# @return [String] a string representing the SDK version.
|
1079
|
+
def sdk_string
|
1080
|
+
binary = "%032b" % sdk
|
1081
|
+
segs = [
|
1082
|
+
binary[0..15], binary[16..23], binary[24..31]
|
1083
|
+
].map { |s| s.to_i(2) }
|
1082
1084
|
|
1083
|
-
|
1085
|
+
segs.join(".")
|
1086
|
+
end
|
1084
1087
|
end
|
1085
|
-
end
|
1086
1088
|
|
1087
|
-
|
1088
|
-
|
1089
|
-
|
1090
|
-
|
1091
|
-
|
1092
|
-
|
1089
|
+
# A load command containing the file offsets and sizes of the new
|
1090
|
+
# compressed form of the information dyld needs to load the image.
|
1091
|
+
# Corresponds to LC_DYLD_INFO and LC_DYLD_INFO_ONLY.
|
1092
|
+
class DyldInfoCommand < LoadCommand
|
1093
|
+
# @return [Fixnum] the file offset to the rebase information
|
1094
|
+
attr_reader :rebase_off
|
1093
1095
|
|
1094
|
-
|
1095
|
-
|
1096
|
+
# @return [Fixnum] the size of the rebase information
|
1097
|
+
attr_reader :rebase_size
|
1096
1098
|
|
1097
|
-
|
1098
|
-
|
1099
|
+
# @return [Fixnum] the file offset to the binding information
|
1100
|
+
attr_reader :bind_off
|
1099
1101
|
|
1100
|
-
|
1101
|
-
|
1102
|
+
# @return [Fixnum] the size of the binding information
|
1103
|
+
attr_reader :bind_size
|
1102
1104
|
|
1103
|
-
|
1104
|
-
|
1105
|
+
# @return [Fixnum] the file offset to the weak binding information
|
1106
|
+
attr_reader :weak_bind_off
|
1105
1107
|
|
1106
|
-
|
1107
|
-
|
1108
|
+
# @return [Fixnum] the size of the weak binding information
|
1109
|
+
attr_reader :weak_bind_size
|
1108
1110
|
|
1109
|
-
|
1110
|
-
|
1111
|
+
# @return [Fixnum] the file offset to the lazy binding information
|
1112
|
+
attr_reader :lazy_bind_off
|
1111
1113
|
|
1112
|
-
|
1113
|
-
|
1114
|
+
# @return [Fixnum] the size of the lazy binding information
|
1115
|
+
attr_reader :lazy_bind_size
|
1114
1116
|
|
1115
|
-
|
1116
|
-
|
1117
|
+
# @return [Fixnum] the file offset to the export information
|
1118
|
+
attr_reader :export_off
|
1117
1119
|
|
1118
|
-
|
1119
|
-
|
1120
|
+
# @return [Fixnum] the size of the export information
|
1121
|
+
attr_reader :export_size
|
1120
1122
|
|
1121
|
-
|
1122
|
-
|
1123
|
-
|
1123
|
+
# @see MachOStructure::FORMAT
|
1124
|
+
# @api private
|
1125
|
+
FORMAT = "L=12".freeze
|
1124
1126
|
|
1125
|
-
|
1126
|
-
|
1127
|
-
|
1127
|
+
# @see MachOStructure::SIZEOF
|
1128
|
+
# @api private
|
1129
|
+
SIZEOF = 48
|
1128
1130
|
|
1129
|
-
|
1130
|
-
|
1131
|
-
|
1132
|
-
|
1133
|
-
|
1134
|
-
|
1135
|
-
|
1136
|
-
|
1137
|
-
|
1138
|
-
|
1139
|
-
|
1140
|
-
|
1141
|
-
|
1142
|
-
|
1143
|
-
|
1131
|
+
# @api private
|
1132
|
+
def initialize(view, cmd, cmdsize, rebase_off, rebase_size, bind_off,
|
1133
|
+
bind_size, weak_bind_off, weak_bind_size, lazy_bind_off,
|
1134
|
+
lazy_bind_size, export_off, export_size)
|
1135
|
+
super(view, cmd, cmdsize)
|
1136
|
+
@rebase_off = rebase_off
|
1137
|
+
@rebase_size = rebase_size
|
1138
|
+
@bind_off = bind_off
|
1139
|
+
@bind_size = bind_size
|
1140
|
+
@weak_bind_off = weak_bind_off
|
1141
|
+
@weak_bind_size = weak_bind_size
|
1142
|
+
@lazy_bind_off = lazy_bind_off
|
1143
|
+
@lazy_bind_size = lazy_bind_size
|
1144
|
+
@export_off = export_off
|
1145
|
+
@export_size = export_size
|
1146
|
+
end
|
1144
1147
|
end
|
1145
|
-
end
|
1146
1148
|
|
1147
|
-
|
1148
|
-
|
1149
|
-
|
1150
|
-
|
1151
|
-
|
1149
|
+
# A load command containing linker options embedded in object files.
|
1150
|
+
# Corresponds to LC_LINKER_OPTION.
|
1151
|
+
class LinkerOptionCommand < LoadCommand
|
1152
|
+
# @return [Fixnum] the number of strings
|
1153
|
+
attr_reader :count
|
1152
1154
|
|
1153
|
-
|
1154
|
-
|
1155
|
-
|
1155
|
+
# @see MachOStructure::FORMAT
|
1156
|
+
# @api private
|
1157
|
+
FORMAT = "L=3".freeze
|
1156
1158
|
|
1157
|
-
|
1158
|
-
|
1159
|
-
|
1159
|
+
# @see MachOStructure::SIZEOF
|
1160
|
+
# @api private
|
1161
|
+
SIZEOF = 12
|
1160
1162
|
|
1161
|
-
|
1162
|
-
|
1163
|
-
|
1164
|
-
|
1163
|
+
# @api private
|
1164
|
+
def initialize(view, cmd, cmdsize, count)
|
1165
|
+
super(view, cmd, cmdsize)
|
1166
|
+
@count = count
|
1167
|
+
end
|
1165
1168
|
end
|
1166
|
-
end
|
1167
1169
|
|
1168
|
-
|
1169
|
-
|
1170
|
-
|
1171
|
-
|
1170
|
+
# A load command specifying the offset of main(). Corresponds to LC_MAIN.
|
1171
|
+
class EntryPointCommand < LoadCommand
|
1172
|
+
# @return [Fixnum] the file (__TEXT) offset of main()
|
1173
|
+
attr_reader :entryoff
|
1172
1174
|
|
1173
|
-
|
1174
|
-
|
1175
|
+
# @return [Fixnum] if not 0, the initial stack size.
|
1176
|
+
attr_reader :stacksize
|
1175
1177
|
|
1176
|
-
|
1177
|
-
|
1178
|
-
|
1178
|
+
# @see MachOStructure::FORMAT
|
1179
|
+
# @api private
|
1180
|
+
FORMAT = "L=2Q=2".freeze
|
1179
1181
|
|
1180
|
-
|
1181
|
-
|
1182
|
-
|
1182
|
+
# @see MachOStructure::SIZEOF
|
1183
|
+
# @api private
|
1184
|
+
SIZEOF = 24
|
1183
1185
|
|
1184
|
-
|
1185
|
-
|
1186
|
-
|
1187
|
-
|
1188
|
-
|
1186
|
+
# @api private
|
1187
|
+
def initialize(view, cmd, cmdsize, entryoff, stacksize)
|
1188
|
+
super(view, cmd, cmdsize)
|
1189
|
+
@entryoff = entryoff
|
1190
|
+
@stacksize = stacksize
|
1191
|
+
end
|
1189
1192
|
end
|
1190
|
-
end
|
1191
1193
|
|
1192
|
-
|
1193
|
-
|
1194
|
-
|
1195
|
-
|
1196
|
-
|
1194
|
+
# A load command specifying the version of the sources used to build the
|
1195
|
+
# binary. Corresponds to LC_SOURCE_VERSION.
|
1196
|
+
class SourceVersionCommand < LoadCommand
|
1197
|
+
# @return [Fixnum] the version packed as a24.b10.c10.d10.e10
|
1198
|
+
attr_reader :version
|
1197
1199
|
|
1198
|
-
|
1199
|
-
|
1200
|
-
|
1200
|
+
# @see MachOStructure::FORMAT
|
1201
|
+
# @api private
|
1202
|
+
FORMAT = "L=2Q=1".freeze
|
1201
1203
|
|
1202
|
-
|
1203
|
-
|
1204
|
-
|
1204
|
+
# @see MachOStructure::SIZEOF
|
1205
|
+
# @api private
|
1206
|
+
SIZEOF = 16
|
1205
1207
|
|
1206
|
-
|
1207
|
-
|
1208
|
-
|
1209
|
-
|
1210
|
-
|
1208
|
+
# @api private
|
1209
|
+
def initialize(view, cmd, cmdsize, version)
|
1210
|
+
super(view, cmd, cmdsize)
|
1211
|
+
@version = version
|
1212
|
+
end
|
1211
1213
|
|
1212
|
-
|
1213
|
-
|
1214
|
-
|
1215
|
-
|
1216
|
-
|
1217
|
-
|
1218
|
-
|
1219
|
-
|
1214
|
+
# A string representation of the sources used to build the binary.
|
1215
|
+
# @return [String] a string representation of the version
|
1216
|
+
def version_string
|
1217
|
+
binary = "%064b" % version
|
1218
|
+
segs = [
|
1219
|
+
binary[0..23], binary[24..33], binary[34..43], binary[44..53],
|
1220
|
+
binary[54..63]
|
1221
|
+
].map { |s| s.to_i(2) }
|
1220
1222
|
|
1221
|
-
|
1223
|
+
segs.join(".")
|
1224
|
+
end
|
1222
1225
|
end
|
1223
|
-
end
|
1224
1226
|
|
1225
|
-
|
1226
|
-
|
1227
|
-
|
1228
|
-
|
1229
|
-
|
1227
|
+
# An obsolete load command containing the offset and size of the (GNU style)
|
1228
|
+
# symbol table information. Corresponds to LC_SYMSEG.
|
1229
|
+
class SymsegCommand < LoadCommand
|
1230
|
+
# @return [Fixnum] the offset to the symbol segment
|
1231
|
+
attr_reader :offset
|
1230
1232
|
|
1231
|
-
|
1232
|
-
|
1233
|
+
# @return [Fixnum] the size of the symbol segment in bytes
|
1234
|
+
attr_reader :size
|
1233
1235
|
|
1234
|
-
|
1235
|
-
|
1236
|
-
|
1236
|
+
# @see MachOStructure::FORMAT
|
1237
|
+
# @api private
|
1238
|
+
FORMAT = "L=4".freeze
|
1237
1239
|
|
1238
|
-
|
1239
|
-
|
1240
|
-
|
1240
|
+
# @see MachOStructure::SIZEOF
|
1241
|
+
# @api private
|
1242
|
+
SIZEOF = 16
|
1241
1243
|
|
1242
|
-
|
1243
|
-
|
1244
|
-
|
1245
|
-
|
1246
|
-
|
1244
|
+
# @api private
|
1245
|
+
def initialize(view, cmd, cmdsize, offset, size)
|
1246
|
+
super(view, cmd, cmdsize)
|
1247
|
+
@offset = offset
|
1248
|
+
@size = size
|
1249
|
+
end
|
1247
1250
|
end
|
1248
|
-
end
|
1249
1251
|
|
1250
|
-
|
1251
|
-
|
1252
|
-
|
1253
|
-
|
1254
|
-
|
1255
|
-
|
1256
|
-
|
1252
|
+
# An obsolete load command containing a free format string table. Each string
|
1253
|
+
# is null-terminated and the command is zero-padded to a multiple of 4.
|
1254
|
+
# Corresponds to LC_IDENT.
|
1255
|
+
class IdentCommand < LoadCommand
|
1256
|
+
# @see MachOStructure::FORMAT
|
1257
|
+
# @api private
|
1258
|
+
FORMAT = "L=2".freeze
|
1257
1259
|
|
1258
|
-
|
1259
|
-
|
1260
|
-
|
1261
|
-
|
1260
|
+
# @see MachOStructure::SIZEOF
|
1261
|
+
# @api private
|
1262
|
+
SIZEOF = 8
|
1263
|
+
end
|
1262
1264
|
|
1263
|
-
|
1264
|
-
|
1265
|
-
|
1266
|
-
|
1267
|
-
|
1265
|
+
# An obsolete load command containing the path to a file to be loaded into
|
1266
|
+
# memory. Corresponds to LC_FVMFILE.
|
1267
|
+
class FvmfileCommand < LoadCommand
|
1268
|
+
# @return [MachO::LoadCommands::LoadCommand::LCStr] the pathname of the file being loaded
|
1269
|
+
attr_reader :name
|
1268
1270
|
|
1269
|
-
|
1270
|
-
|
1271
|
+
# @return [Fixnum] the virtual address being loaded at
|
1272
|
+
attr_reader :header_addr
|
1271
1273
|
|
1272
|
-
|
1273
|
-
|
1274
|
-
|
1274
|
+
# @see MachOStructure::FORMAT
|
1275
|
+
# @api private
|
1276
|
+
FORMAT = "L=4".freeze
|
1275
1277
|
|
1276
|
-
|
1277
|
-
|
1278
|
-
|
1278
|
+
# @see MachOStructure::SIZEOF
|
1279
|
+
# @api private
|
1280
|
+
SIZEOF = 16
|
1279
1281
|
|
1280
|
-
|
1281
|
-
|
1282
|
-
|
1283
|
-
|
1282
|
+
def initialize(view, cmd, cmdsize, name, header_addr)
|
1283
|
+
super(view, cmd, cmdsize)
|
1284
|
+
@name = LCStr.new(self, name)
|
1285
|
+
@header_addr = header_addr
|
1286
|
+
end
|
1284
1287
|
end
|
1285
|
-
end
|
1286
1288
|
|
1287
|
-
|
1288
|
-
|
1289
|
-
|
1290
|
-
|
1291
|
-
|
1289
|
+
# An obsolete load command containing the path to a library to be loaded into
|
1290
|
+
# memory. Corresponds to LC_LOADFVMLIB and LC_IDFVMLIB.
|
1291
|
+
class FvmlibCommand < LoadCommand
|
1292
|
+
# @return [MachO::LoadCommands::LoadCommand::LCStr] the library's target pathname
|
1293
|
+
attr_reader :name
|
1292
1294
|
|
1293
|
-
|
1294
|
-
|
1295
|
+
# @return [Fixnum] the library's minor version number
|
1296
|
+
attr_reader :minor_version
|
1295
1297
|
|
1296
|
-
|
1297
|
-
|
1298
|
+
# @return [Fixnum] the library's header address
|
1299
|
+
attr_reader :header_addr
|
1298
1300
|
|
1299
|
-
|
1300
|
-
|
1301
|
-
|
1301
|
+
# @see MachOStructure::FORMAT
|
1302
|
+
# @api private
|
1303
|
+
FORMAT = "L=5".freeze
|
1302
1304
|
|
1303
|
-
|
1304
|
-
|
1305
|
-
|
1305
|
+
# @see MachOStructure::SIZEOF
|
1306
|
+
# @api private
|
1307
|
+
SIZEOF = 20
|
1306
1308
|
|
1307
|
-
|
1308
|
-
|
1309
|
-
|
1310
|
-
|
1311
|
-
|
1309
|
+
def initialize(view, cmd, cmdsize, name, minor_version, header_addr)
|
1310
|
+
super(view, cmd, cmdsize)
|
1311
|
+
@name = LCStr.new(self, name)
|
1312
|
+
@minor_version = minor_version
|
1313
|
+
@header_addr = header_addr
|
1314
|
+
end
|
1312
1315
|
end
|
1313
1316
|
end
|
1314
1317
|
end
|