ruby-macho 1.0.0 → 1.1.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.
@@ -2,7 +2,7 @@ module MachO
2
2
  # Classes and constants for parsing load commands in Mach-O binaries.
3
3
  module LoadCommands
4
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)
5
+ # LC_REQ_DYLD to be recognized by the dynamic linker (dyld)
6
6
  # @api private
7
7
  LC_REQ_DYLD = 0x80000000
8
8
 
@@ -87,14 +87,21 @@ module MachO
87
87
  LC_STRUCTURES = {
88
88
  :LC_SEGMENT => "SegmentCommand",
89
89
  :LC_SYMTAB => "SymtabCommand",
90
- :LC_SYMSEG => "SymsegCommand", # obsolete
91
- :LC_THREAD => "ThreadCommand", # seems obsolete, but not documented as such
90
+ # "obsolete"
91
+ :LC_SYMSEG => "SymsegCommand",
92
+ # seems obsolete, but not documented as such
93
+ :LC_THREAD => "ThreadCommand",
92
94
  :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
95
+ # "obsolete"
96
+ :LC_LOADFVMLIB => "FvmlibCommand",
97
+ # "obsolete"
98
+ :LC_IDFVMLIB => "FvmlibCommand",
99
+ # "obsolete"
100
+ :LC_IDENT => "IdentCommand",
101
+ # "reserved for internal use only"
102
+ :LC_FVMFILE => "FvmfileCommand",
103
+ # "reserved for internal use only", no public struct
104
+ :LC_PREPAGE => "LoadCommand",
98
105
  :LC_DYSYMTAB => "DysymtabCommand",
99
106
  :LC_LOAD_DYLIB => "DylibCommand",
100
107
  :LC_ID_DYLIB => "DylibCommand",
@@ -182,7 +189,7 @@ module MachO
182
189
 
183
190
  # Instantiates a new LoadCommand given a view into its origin Mach-O
184
191
  # @param view [MachO::MachOView] the load command's raw view
185
- # @return [MachO::LoadCommands::LoadCommand] the new load command
192
+ # @return [LoadCommand] the new load command
186
193
  # @api private
187
194
  def self.new_from_bin(view)
188
195
  bin = view.raw_data.slice(view.offset, bytesize)
@@ -218,12 +225,12 @@ module MachO
218
225
  @cmdsize = cmdsize
219
226
  end
220
227
 
221
- # @return [Boolean] true if the load command can be serialized, false otherwise
228
+ # @return [Boolean] whether the load command can be serialized
222
229
  def serializable?
223
230
  CREATABLE_LOAD_COMMANDS.include?(LOAD_COMMANDS[cmd])
224
231
  end
225
232
 
226
- # @param context [MachO::LoadCommands::LoadCommand::SerializationContext] the context
233
+ # @param context [SerializationContext] the context
227
234
  # to serialize into
228
235
  # @return [String, nil] the serialized fields of the load command, or nil
229
236
  # if the load command can't be serialized
@@ -240,14 +247,16 @@ module MachO
240
247
  view.offset
241
248
  end
242
249
 
243
- # @return [Symbol] a symbol representation of the load command's identifying number
250
+ # @return [Symbol] a symbol representation of the load command's
251
+ # identifying number
244
252
  def type
245
253
  LOAD_COMMANDS[cmd]
246
254
  end
247
255
 
248
256
  alias to_sym type
249
257
 
250
- # @return [String] a string representation of the load command's identifying number
258
+ # @return [String] a string representation of the load command's
259
+ # identifying number
251
260
  def to_s
252
261
  type.to_s
253
262
  end
@@ -257,9 +266,9 @@ module MachO
257
266
  # pretend that strings stored in LCs are immediately available without
258
267
  # explicit operations on the raw Mach-O data.
259
268
  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.
269
+ # @param lc [LoadCommand] the load command
270
+ # @param lc_str [Fixnum, String] the offset to the beginning of the
271
+ # string, or the string itself if not being initialized with a view.
263
272
  # @raise [MachO::LCStrMalformedError] if the string is malformed
264
273
  # @todo devise a solution such that the `lc_str` parameter is not
265
274
  # interpreted differently depending on `lc.view`. The current behavior
@@ -286,7 +295,8 @@ module MachO
286
295
  @string
287
296
  end
288
297
 
289
- # @return [Fixnum] the offset to the beginning of the string in the load command
298
+ # @return [Fixnum] the offset to the beginning of the string in the
299
+ # load command
290
300
  def to_i
291
301
  @string_offset
292
302
  end
@@ -298,11 +308,13 @@ module MachO
298
308
  # @return [Symbol] the endianness of the serialized load command
299
309
  attr_reader :endianness
300
310
 
301
- # @return [Fixnum] the constant alignment value used to pad the serialized load command
311
+ # @return [Fixnum] the constant alignment value used to pad the
312
+ # serialized load command
302
313
  attr_reader :alignment
303
314
 
304
315
  # @param macho [MachO::MachOFile] the file to contextualize
305
- # @return [MachO::LoadCommands::LoadCommand::SerializationContext] the resulting context
316
+ # @return [SerializationContext] the
317
+ # resulting context
306
318
  def self.context_for(macho)
307
319
  new(macho.endianness, macho.alignment)
308
320
  end
@@ -317,8 +329,9 @@ module MachO
317
329
  end
318
330
  end
319
331
 
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.
332
+ # A load command containing a single 128-bit unique random number
333
+ # identifying an object produced by static link editor. Corresponds to
334
+ # LC_UUID.
322
335
  class UUIDCommand < LoadCommand
323
336
  # @return [Array<Fixnum>] the UUID
324
337
  attr_reader :uuid
@@ -413,7 +426,10 @@ module MachO
413
426
  MachO::Sections::Section
414
427
  end
415
428
 
416
- bins = view.raw_data[view.offset + self.class.bytesize, nsects * klass.bytesize]
429
+ offset = view.offset + self.class.bytesize
430
+ length = nsects * klass.bytesize
431
+
432
+ bins = view.raw_data[offset, length]
417
433
  bins.unpack("a#{klass.bytesize}" * nsects).map do |bin|
418
434
  klass.new_from_bin(view.endianness, bin)
419
435
  end
@@ -443,10 +459,11 @@ module MachO
443
459
  end
444
460
 
445
461
  # 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.
462
+ # on filetype. Corresponds to LC_ID_DYLIB, LC_LOAD_DYLIB,
463
+ # LC_LOAD_WEAK_DYLIB, and LC_REEXPORT_DYLIB.
448
464
  class DylibCommand < LoadCommand
449
- # @return [MachO::LoadCommands::LoadCommand::LCStr] the library's path name as an LCStr
465
+ # @return [LCStr] the library's path
466
+ # name as an LCStr
450
467
  attr_reader :name
451
468
 
452
469
  # @return [Fixnum] the library's build time stamp
@@ -467,7 +484,8 @@ module MachO
467
484
  SIZEOF = 24
468
485
 
469
486
  # @api private
470
- def initialize(view, cmd, cmdsize, name, timestamp, current_version, compatibility_version)
487
+ def initialize(view, cmd, cmdsize, name, timestamp, current_version,
488
+ compatibility_version)
471
489
  super(view, cmd, cmdsize)
472
490
  @name = LCStr.new(self, name)
473
491
  @timestamp = timestamp
@@ -475,12 +493,15 @@ module MachO
475
493
  @compatibility_version = compatibility_version
476
494
  end
477
495
 
478
- # @param context [MachO::LoadCommands::LoadCommand::SerializationContext] the context
496
+ # @param context [SerializationContext]
497
+ # the context
479
498
  # @return [String] the serialized fields of the load command
480
499
  # @api private
481
500
  def serialize(context)
482
501
  format = Utils.specialize_format(FORMAT, context.endianness)
483
- string_payload, string_offsets = Utils.pack_strings(SIZEOF, context.alignment, :name => name.to_s)
502
+ string_payload, string_offsets = Utils.pack_strings(SIZEOF,
503
+ context.alignment,
504
+ :name => name.to_s)
484
505
  cmdsize = SIZEOF + string_payload.bytesize
485
506
  [cmd, cmdsize, string_offsets[:name], timestamp, current_version,
486
507
  compatibility_version].pack(format) + string_payload
@@ -491,7 +512,8 @@ module MachO
491
512
  # on filetype. Corresponds to LC_ID_DYLINKER, LC_LOAD_DYLINKER, and
492
513
  # LC_DYLD_ENVIRONMENT.
493
514
  class DylinkerCommand < LoadCommand
494
- # @return [MachO::LoadCommands::LoadCommand::LCStr] the dynamic linker's path name as an LCStr
515
+ # @return [LCStr] the dynamic linker's
516
+ # path name as an LCStr
495
517
  attr_reader :name
496
518
 
497
519
  # @see MachOStructure::FORMAT
@@ -508,12 +530,15 @@ module MachO
508
530
  @name = LCStr.new(self, name)
509
531
  end
510
532
 
511
- # @param context [MachO::LoadCommands::LoadCommand::SerializationContext] the context
533
+ # @param context [SerializationContext]
534
+ # the context
512
535
  # @return [String] the serialized fields of the load command
513
536
  # @api private
514
537
  def serialize(context)
515
538
  format = Utils.specialize_format(FORMAT, context.endianness)
516
- string_payload, string_offsets = Utils.pack_strings(SIZEOF, context.alignment, :name => name.to_s)
539
+ string_payload, string_offsets = Utils.pack_strings(SIZEOF,
540
+ context.alignment,
541
+ :name => name.to_s)
517
542
  cmdsize = SIZEOF + string_payload.bytesize
518
543
  [cmd, cmdsize, string_offsets[:name]].pack(format) + string_payload
519
544
  end
@@ -522,7 +547,8 @@ module MachO
522
547
  # A load command used to indicate dynamic libraries used in prebinding.
523
548
  # Corresponds to LC_PREBOUND_DYLIB.
524
549
  class PreboundDylibCommand < LoadCommand
525
- # @return [MachO::LoadCommands::LoadCommand::LCStr] the library's path name as an LCStr
550
+ # @return [LCStr] the library's path
551
+ # name as an LCStr
526
552
  attr_reader :name
527
553
 
528
554
  # @return [Fixnum] the number of modules in the library
@@ -549,7 +575,8 @@ module MachO
549
575
  end
550
576
 
551
577
  # A load command used to represent threads.
552
- # @note cctools-870 has all fields of thread_command commented out except common ones (cmd, cmdsize)
578
+ # @note cctools-870 and onwards have all fields of thread_command commented
579
+ # out except the common ones (cmd, cmdsize)
553
580
  class ThreadCommand < LoadCommand
554
581
  # @see MachOStructure::FORMAT
555
582
  # @api private
@@ -567,7 +594,8 @@ module MachO
567
594
  # @return [Fixnum] the address of the initialization routine
568
595
  attr_reader :init_address
569
596
 
570
- # @return [Fixnum] the index into the module table that the init routine is defined in
597
+ # @return [Fixnum] the index into the module table that the init routine
598
+ # is defined in
571
599
  attr_reader :init_module
572
600
 
573
601
  # @return [void]
@@ -627,7 +655,7 @@ module MachO
627
655
  # A load command signifying membership of a subframework containing the name
628
656
  # of an umbrella framework. Corresponds to LC_SUB_FRAMEWORK.
629
657
  class SubFrameworkCommand < LoadCommand
630
- # @return [MachO::LoadCommands::LoadCommand::LCStr] the umbrella framework name as an LCStr
658
+ # @return [LCStr] the umbrella framework name as an LCStr
631
659
  attr_reader :umbrella
632
660
 
633
661
  # @see MachOStructure::FORMAT
@@ -648,7 +676,7 @@ module MachO
648
676
  # A load command signifying membership of a subumbrella containing the name
649
677
  # of an umbrella framework. Corresponds to LC_SUB_UMBRELLA.
650
678
  class SubUmbrellaCommand < LoadCommand
651
- # @return [MachO::LoadCommands::LoadCommand::LCStr] the subumbrella framework name as an LCStr
679
+ # @return [LCStr] the subumbrella framework name as an LCStr
652
680
  attr_reader :sub_umbrella
653
681
 
654
682
  # @see MachOStructure::FORMAT
@@ -669,7 +697,7 @@ module MachO
669
697
  # A load command signifying a sublibrary of a shared library. Corresponds
670
698
  # to LC_SUB_LIBRARY.
671
699
  class SubLibraryCommand < LoadCommand
672
- # @return [MachO::LoadCommands::LoadCommand::LCStr] the sublibrary name as an LCStr
700
+ # @return [LCStr] the sublibrary name as an LCStr
673
701
  attr_reader :sub_library
674
702
 
675
703
  # @see MachOStructure::FORMAT
@@ -690,7 +718,7 @@ module MachO
690
718
  # A load command signifying a shared library that is a subframework of
691
719
  # an umbrella framework. Corresponds to LC_SUB_CLIENT.
692
720
  class SubClientCommand < LoadCommand
693
- # @return [MachO::LoadCommands::LoadCommand::LCStr] the subclient name as an LCStr
721
+ # @return [LCStr] the subclient name as an LCStr
694
722
  attr_reader :sub_client
695
723
 
696
724
  # @see MachOStructure::FORMAT
@@ -843,7 +871,8 @@ module MachO
843
871
  # @return [Fixnum] the number of hints in the hint table
844
872
  attr_reader :nhints
845
873
 
846
- # @return [MachO::LoadCommands::TwolevelHintsCommand::TwolevelHintTable] the hint table
874
+ # @return [TwolevelHintsTable]
875
+ # the hint table
847
876
  attr_reader :table
848
877
 
849
878
  # @see MachOStructure::FORMAT
@@ -865,7 +894,7 @@ module MachO
865
894
  # A representation of the two-level namespace lookup hints table exposed
866
895
  # by a {TwolevelHintsCommand} (`LC_TWOLEVEL_HINTS`).
867
896
  class TwolevelHintsTable
868
- # @return [Array<MachO::LoadCommands::TwoLevelHintsCommand::TwoLevelHintsTable::TwoLevelHint>] all hints in the table
897
+ # @return [Array<TwolevelHint>] all hints in the table
869
898
  attr_reader :hints
870
899
 
871
900
  # @param view [MachO::MachOView] the view into the current Mach-O
@@ -923,7 +952,7 @@ module MachO
923
952
  # be added to the current run path used to find @rpath prefixed dylibs.
924
953
  # Corresponds to LC_RPATH.
925
954
  class RpathCommand < LoadCommand
926
- # @return [MachO::LoadCommands::LoadCommand::LCStr] the path to add to the run path as an LCStr
955
+ # @return [LCStr] the path to add to the run path as an LCStr
927
956
  attr_reader :path
928
957
 
929
958
  # @see MachOStructure::FORMAT
@@ -940,20 +969,23 @@ module MachO
940
969
  @path = LCStr.new(self, path)
941
970
  end
942
971
 
943
- # @param context [MachO::LoadCommands::LoadCommand::SerializationContext] the context
972
+ # @param context [SerializationContext] the context
944
973
  # @return [String] the serialized fields of the load command
945
974
  # @api private
946
975
  def serialize(context)
947
976
  format = Utils.specialize_format(FORMAT, context.endianness)
948
- string_payload, string_offsets = Utils.pack_strings(SIZEOF, context.alignment, :path => path.to_s)
977
+ string_payload, string_offsets = Utils.pack_strings(SIZEOF,
978
+ context.alignment,
979
+ :path => path.to_s)
949
980
  cmdsize = SIZEOF + string_payload.bytesize
950
981
  [cmd, cmdsize, string_offsets[:path]].pack(format) + string_payload
951
982
  end
952
983
  end
953
984
 
954
985
  # 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.
986
+ # the __LINKEDIT segment. Corresponds to LC_CODE_SIGNATURE,
987
+ # LC_SEGMENT_SPLIT_INFO, LC_FUNCTION_STARTS, LC_DATA_IN_CODE,
988
+ # LC_DYLIB_CODE_SIGN_DRS, and LC_LINKER_OPTIMIZATION_HINT.
957
989
  class LinkeditDataCommand < LoadCommand
958
990
  # @return [Fixnum] offset to the data in the __LINKEDIT segment
959
991
  attr_reader :dataoff
@@ -1040,7 +1072,8 @@ module MachO
1040
1072
  end
1041
1073
 
1042
1074
  # 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.
1075
+ # was built to run. Corresponds to LC_VERSION_MIN_MACOSX and
1076
+ # LC_VERSION_MIN_IPHONEOS.
1044
1077
  class VersionMinCommand < LoadCommand
1045
1078
  # @return [Fixnum] the version X.Y.Z packed as x16.y8.z8
1046
1079
  attr_reader :version
@@ -1249,9 +1282,9 @@ module MachO
1249
1282
  end
1250
1283
  end
1251
1284
 
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.
1285
+ # An obsolete load command containing a free format string table. Each
1286
+ # string is null-terminated and the command is zero-padded to a multiple of
1287
+ # 4. Corresponds to LC_IDENT.
1255
1288
  class IdentCommand < LoadCommand
1256
1289
  # @see MachOStructure::FORMAT
1257
1290
  # @api private
@@ -1265,7 +1298,7 @@ module MachO
1265
1298
  # An obsolete load command containing the path to a file to be loaded into
1266
1299
  # memory. Corresponds to LC_FVMFILE.
1267
1300
  class FvmfileCommand < LoadCommand
1268
- # @return [MachO::LoadCommands::LoadCommand::LCStr] the pathname of the file being loaded
1301
+ # @return [LCStr] the pathname of the file being loaded
1269
1302
  attr_reader :name
1270
1303
 
1271
1304
  # @return [Fixnum] the virtual address being loaded at
@@ -1286,10 +1319,10 @@ module MachO
1286
1319
  end
1287
1320
  end
1288
1321
 
1289
- # An obsolete load command containing the path to a library to be loaded into
1290
- # memory. Corresponds to LC_LOADFVMLIB and LC_IDFVMLIB.
1322
+ # An obsolete load command containing the path to a library to be loaded
1323
+ # into memory. Corresponds to LC_LOADFVMLIB and LC_IDFVMLIB.
1291
1324
  class FvmlibCommand < LoadCommand
1292
- # @return [MachO::LoadCommands::LoadCommand::LCStr] the library's target pathname
1325
+ # @return [LCStr] the library's target pathname
1293
1326
  attr_reader :name
1294
1327
 
1295
1328
  # @return [Fixnum] the library's minor version number
@@ -1,27 +1,33 @@
1
+ require "forwardable"
2
+
1
3
  module MachO
2
4
  # Represents a Mach-O file, which contains a header and load commands
3
5
  # as well as binary executable instructions. Mach-O binaries are
4
6
  # architecture specific.
5
7
  # @see https://en.wikipedia.org/wiki/Mach-O
6
- # @see MachO::FatFile
8
+ # @see FatFile
7
9
  class MachOFile
8
- # @return [String] the filename loaded from, or nil if loaded from a binary string
10
+ extend Forwardable
11
+
12
+ # @return [String] the filename loaded from, or nil if loaded from a binary
13
+ # string
9
14
  attr_accessor :filename
10
15
 
11
16
  # @return [Symbol] the endianness of the file, :big or :little
12
17
  attr_reader :endianness
13
18
 
14
- # @return [MachO::Headers::MachHeader] if the Mach-O is 32-bit
15
- # @return [MachO::Headers::MachHeader64] if the Mach-O is 64-bit
19
+ # @return [Headers::MachHeader] if the Mach-O is 32-bit
20
+ # @return [Headers::MachHeader64] if the Mach-O is 64-bit
16
21
  attr_reader :header
17
22
 
18
- # @return [Array<MachO::LoadCommands::LoadCommand>] an array of the file's load commands
23
+ # @return [Array<LoadCommands::LoadCommand>] an array of the file's load
24
+ # commands
19
25
  # @note load commands are provided in order of ascending offset.
20
26
  attr_reader :load_commands
21
27
 
22
28
  # Creates a new MachOFile instance from a binary string.
23
29
  # @param bin [String] a binary string containing raw Mach-O data
24
- # @return [MachO::MachOFile] a new MachOFile
30
+ # @return [MachOFile] a new MachOFile
25
31
  def self.new_from_bin(bin)
26
32
  instance = allocate
27
33
  instance.initialize_from_bin(bin)
@@ -55,75 +61,44 @@ module MachO
55
61
  @raw_data
56
62
  end
57
63
 
58
- # @return [Boolean] true if the Mach-O has 32-bit magic, false otherwise
59
- def magic32?
60
- Utils.magic32?(header.magic)
61
- end
62
-
63
- # @return [Boolean] true if the Mach-O has 64-bit magic, false otherwise
64
- def magic64?
65
- Utils.magic64?(header.magic)
66
- end
67
-
68
- # @return [Fixnum] the file's internal alignment
69
- def alignment
70
- magic32? ? 4 : 8
71
- end
72
-
73
- # @return [Boolean] true if the file is of type `MH_OBJECT`, false otherwise
74
- def object?
75
- header.filetype == Headers::MH_OBJECT
76
- end
77
-
78
- # @return [Boolean] true if the file is of type `MH_EXECUTE`, false otherwise
79
- def executable?
80
- header.filetype == Headers::MH_EXECUTE
81
- end
82
-
83
- # @return [Boolean] true if the file is of type `MH_FVMLIB`, false otherwise
84
- def fvmlib?
85
- header.filetype == Headers::MH_FVMLIB
86
- end
87
-
88
- # @return [Boolean] true if the file is of type `MH_CORE`, false otherwise
89
- def core?
90
- header.filetype == Headers::MH_CORE
91
- end
92
-
93
- # @return [Boolean] true if the file is of type `MH_PRELOAD`, false otherwise
94
- def preload?
95
- header.filetype == Headers::MH_PRELOAD
96
- end
97
-
98
- # @return [Boolean] true if the file is of type `MH_DYLIB`, false otherwise
99
- def dylib?
100
- header.filetype == Headers::MH_DYLIB
101
- end
102
-
103
- # @return [Boolean] true if the file is of type `MH_DYLINKER`, false otherwise
104
- def dylinker?
105
- header.filetype == Headers::MH_DYLINKER
106
- end
107
-
108
- # @return [Boolean] true if the file is of type `MH_BUNDLE`, false otherwise
109
- def bundle?
110
- header.filetype == Headers::MH_BUNDLE
111
- end
112
-
113
- # @return [Boolean] true if the file is of type `MH_DSYM`, false otherwise
114
- def dsym?
115
- header.filetype == Headers::MH_DSYM
116
- end
117
-
118
- # @return [Boolean] true if the file is of type `MH_KEXT_BUNDLE`, false otherwise
119
- def kext?
120
- header.filetype == Headers::MH_KEXT_BUNDLE
121
- end
122
-
123
- # @return [Fixnum] the file's magic number
124
- def magic
125
- header.magic
126
- end
64
+ # @!method magic
65
+ # @return (see MachO::Headers::MachHeader#magic)
66
+ # @!method ncmds
67
+ # @return (see MachO::Headers::MachHeader#ncmds)
68
+ # @!method sizeofcmds
69
+ # @return (see MachO::Headers::MachHeader#sizeofcmds)
70
+ # @!method flags
71
+ # @return (see MachO::Headers::MachHeader#flags)
72
+ # @!method object?
73
+ # @return (see MachO::Headers::MachHeader#object?)
74
+ # @!method executable?
75
+ # @return (see MachO::Headers::MachHeader#executable?)
76
+ # @!method fvmlib?
77
+ # @return (see MachO::Headers::MachHeader#fvmlib?)
78
+ # @!method core?
79
+ # @return (see MachO::Headers::MachHeader#core?)
80
+ # @!method preload?
81
+ # @return (see MachO::Headers::MachHeader#preload?)
82
+ # @!method dylib?
83
+ # @return (see MachO::Headers::MachHeader#dylib?)
84
+ # @!method dylinker?
85
+ # @return (see MachO::Headers::MachHeader#dylinker?)
86
+ # @!method bundle?
87
+ # @return (see MachO::Headers::MachHeader#bundle?)
88
+ # @!method dsym?
89
+ # @return (see MachO::Headers::MachHeader#dsym?)
90
+ # @!method kext?
91
+ # @return (see MachO::Headers::MachHeader#kext?)
92
+ # @!method magic32?
93
+ # @return (see MachO::Headers::MachHeader#magic32?)
94
+ # @!method magic64?
95
+ # @return (see MachO::Headers::MachHeader#magic64?)
96
+ # @!method alignment
97
+ # @return (see MachO::Headers::MachHeader#alignment)
98
+ def_delegators :header, :magic, :ncmds, :sizeofcmds, :flags, :object?,
99
+ :executable?, :fvmlib?, :core?, :preload?, :dylib?,
100
+ :dylinker?, :bundle?, :dsym?, :kext?, :magic32?, :magic64?,
101
+ :alignment
127
102
 
128
103
  # @return [String] a string representation of the file's magic number
129
104
  def magic_string
@@ -145,27 +120,13 @@ module MachO
145
120
  Headers::CPU_SUBTYPES[header.cputype][header.cpusubtype]
146
121
  end
147
122
 
148
- # @return [Fixnum] the number of load commands in the Mach-O's header
149
- def ncmds
150
- header.ncmds
151
- end
152
-
153
- # @return [Fixnum] the size of all load commands, in bytes
154
- def sizeofcmds
155
- header.sizeofcmds
156
- end
157
-
158
- # @return [Fixnum] execution flags set by the linker
159
- def flags
160
- header.flags
161
- end
162
-
163
123
  # All load commands of a given name.
164
124
  # @example
165
125
  # file.command("LC_LOAD_DYLIB")
166
126
  # file[:LC_LOAD_DYLIB]
167
127
  # @param [String, Symbol] name the load command ID
168
- # @return [Array<MachO::LoadCommands::LoadCommand>] an array of load commands corresponding to `name`
128
+ # @return [Array<LoadCommands::LoadCommand>] an array of load commands
129
+ # corresponding to `name`
169
130
  def command(name)
170
131
  load_commands.select { |lc| lc.type == name.to_sym }
171
132
  end
@@ -174,12 +135,12 @@ module MachO
174
135
 
175
136
  # Inserts a load command at the given offset.
176
137
  # @param offset [Fixnum] the offset to insert at
177
- # @param lc [MachO::LoadCommands::LoadCommand] the load command to insert
138
+ # @param lc [LoadCommands::LoadCommand] the load command to insert
178
139
  # @param options [Hash]
179
140
  # @option options [Boolean] :repopulate (true) whether or not to repopulate
180
141
  # the instance fields
181
- # @raise [MachO::OffsetInsertionError] if the offset is not in the load command region
182
- # @raise [MachO::HeaderPadError] if the new command exceeds the header pad buffer
142
+ # @raise [OffsetInsertionError] if the offset is not in the load command region
143
+ # @raise [HeaderPadError] if the new command exceeds the header pad buffer
183
144
  # @note Calling this method with an arbitrary offset in the load command
184
145
  # region **will leave the object in an inconsistent state**.
185
146
  def insert_command(offset, lc, options = {})
@@ -207,11 +168,11 @@ module MachO
207
168
  end
208
169
 
209
170
  # Replace a load command with another command in the Mach-O, preserving location.
210
- # @param old_lc [MachO::LoadCommands::LoadCommand] the load command being replaced
211
- # @param new_lc [MachO::LoadCommands::LoadCommand] the load command being added
171
+ # @param old_lc [LoadCommands::LoadCommand] the load command being replaced
172
+ # @param new_lc [LoadCommands::LoadCommand] the load command being added
212
173
  # @return [void]
213
- # @raise [MachO::HeaderPadError] if the new command exceeds the header pad buffer
214
- # @see {#insert_command}
174
+ # @raise [HeaderPadError] if the new command exceeds the header pad buffer
175
+ # @see #insert_command
215
176
  # @note This is public, but methods like {#dylib_id=} should be preferred.
216
177
  def replace_command(old_lc, new_lc)
217
178
  context = LoadCommands::LoadCommand::SerializationContext.context_for(self)
@@ -226,12 +187,12 @@ module MachO
226
187
  end
227
188
 
228
189
  # Appends a new load command to the Mach-O.
229
- # @param lc [MachO::LoadCommands::LoadCommand] the load command being added
190
+ # @param lc [LoadCommands::LoadCommand] the load command being added
230
191
  # @param options [Hash]
231
192
  # @option options [Boolean] :repopulate (true) whether or not to repopulate
232
193
  # the instance fields
233
194
  # @return [void]
234
- # @see {#insert_command}
195
+ # @see #insert_command
235
196
  # @note This is public, but methods like {#add_rpath} should be preferred.
236
197
  # Setting `repopulate` to false **will leave the instance in an
237
198
  # inconsistent state** unless {#populate_fields} is called **immediately**
@@ -241,7 +202,7 @@ module MachO
241
202
  end
242
203
 
243
204
  # Delete a load command from the Mach-O.
244
- # @param lc [MachO::LoadCommands::LoadCommand] the load command being deleted
205
+ # @param lc [LoadCommands::LoadCommand] the load command being deleted
245
206
  # @param options [Hash]
246
207
  # @option options [Boolean] :repopulate (true) whether or not to repopulate
247
208
  # the instance fields
@@ -275,14 +236,14 @@ module MachO
275
236
  end
276
237
 
277
238
  # All load commands responsible for loading dylibs.
278
- # @return [Array<MachO::LoadCommands::DylibCommand>] an array of DylibCommands
239
+ # @return [Array<LoadCommands::DylibCommand>] an array of DylibCommands
279
240
  def dylib_load_commands
280
241
  load_commands.select { |lc| LoadCommands::DYLIB_LOAD_COMMANDS.include?(lc.type) }
281
242
  end
282
243
 
283
244
  # All segment load commands in the Mach-O.
284
- # @return [Array<MachO::LoadCommands::SegmentCommand>] if the Mach-O is 32-bit
285
- # @return [Array<MachO::LoadCommands::SegmentCommand64>] if the Mach-O is 64-bit
245
+ # @return [Array<LoadCommands::SegmentCommand>] if the Mach-O is 32-bit
246
+ # @return [Array<LoadCommands::SegmentCommand64>] if the Mach-O is 64-bit
286
247
  def segments
287
248
  if magic32?
288
249
  command(:LC_SEGMENT)
@@ -341,12 +302,12 @@ module MachO
341
302
 
342
303
  # Changes the shared library `old_name` to `new_name`
343
304
  # @example
344
- # file.change_install_name("/usr/lib/libWhatever.dylib", "/usr/local/lib/libWhatever2.dylib")
305
+ # file.change_install_name("abc.dylib", "def.dylib")
345
306
  # @param old_name [String] the shared library's old name
346
307
  # @param new_name [String] the shared library's new name
347
308
  # @param _options [Hash]
348
309
  # @return [void]
349
- # @raise [MachO::DylibUnknownError] if no shared library has the old name
310
+ # @raise [DylibUnknownError] if no shared library has the old name
350
311
  # @note `_options` is currently unused and is provided for signature
351
312
  # compatibility with {MachO::FatFile#change_install_name}
352
313
  def change_install_name(old_name, new_name, _options = {})
@@ -376,8 +337,8 @@ module MachO
376
337
  # @param new_path [String] the new runtime path
377
338
  # @param _options [Hash]
378
339
  # @return [void]
379
- # @raise [MachO::RpathUnknownError] if no such old runtime path exists
380
- # @raise [MachO::RpathExistsError] if the new runtime path already exists
340
+ # @raise [RpathUnknownError] if no such old runtime path exists
341
+ # @raise [RpathExistsError] if the new runtime path already exists
381
342
  # @note `_options` is currently unused and is provided for signature
382
343
  # compatibility with {MachO::FatFile#change_rpath}
383
344
  def change_rpath(old_path, new_path, _options = {})
@@ -399,7 +360,7 @@ module MachO
399
360
  # @param path [String] the new runtime path
400
361
  # @param _options [Hash]
401
362
  # @return [void]
402
- # @raise [MachO::RpathExistsError] if the runtime path already exists
363
+ # @raise [RpathExistsError] if the runtime path already exists
403
364
  # @note `_options` is currently unused and is provided for signature
404
365
  # compatibility with {MachO::FatFile#add_rpath}
405
366
  def add_rpath(path, _options = {})
@@ -417,7 +378,7 @@ module MachO
417
378
  # @param path [String] the runtime path to delete
418
379
  # @param _options [Hash]
419
380
  # @return void
420
- # @raise [MachO::RpathUnknownError] if no such runtime path exists
381
+ # @raise [RpathUnknownError] if no such runtime path exists
421
382
  # @note `_options` is currently unused and is provided for signature
422
383
  # compatibility with {MachO::FatFile#delete_rpath}
423
384
  def delete_rpath(path, _options = {})
@@ -431,15 +392,6 @@ module MachO
431
392
  populate_fields
432
393
  end
433
394
 
434
- # All sections of the segment `segment`.
435
- # @param segment [MachO::LoadCommands::SegmentCommand, MachO::LoadCommands::SegmentCommand64] the segment being inspected
436
- # @return [Array<MachO::Sections::Section>] if the Mach-O is 32-bit
437
- # @return [Array<MachO::Sections::Section64>] if the Mach-O is 64-bit
438
- # @deprecated use {MachO::LoadCommands::SegmentCommand#sections} instead
439
- def sections(segment)
440
- segment.sections
441
- end
442
-
443
395
  # Write all Mach-O data to the given filename.
444
396
  # @param filename [String] the file to write to
445
397
  # @return [void]
@@ -449,7 +401,7 @@ module MachO
449
401
 
450
402
  # Write all Mach-O data to the file used to initialize the instance.
451
403
  # @return [void]
452
- # @raise [MachO::MachOError] if the instance was initialized without a file
404
+ # @raise [MachOError] if the instance was initialized without a file
453
405
  # @note Overwrites all data in the file!
454
406
  def write!
455
407
  if @filename.nil?
@@ -462,9 +414,9 @@ module MachO
462
414
  private
463
415
 
464
416
  # The file's Mach-O header structure.
465
- # @return [MachO::Headers::MachHeader] if the Mach-O is 32-bit
466
- # @return [MachO::Headers::MachHeader64] if the Mach-O is 64-bit
467
- # @raise [MachO::TruncatedFileError] if the file is too small to have a valid header
417
+ # @return [Headers::MachHeader] if the Mach-O is 32-bit
418
+ # @return [Headers::MachHeader64] if the Mach-O is 64-bit
419
+ # @raise [TruncatedFileError] if the file is too small to have a valid header
468
420
  # @api private
469
421
  def populate_mach_header
470
422
  # the smallest Mach-O header is 28 bytes
@@ -483,8 +435,8 @@ module MachO
483
435
 
484
436
  # Read just the file's magic number and check its validity.
485
437
  # @return [Fixnum] the magic
486
- # @raise [MachO::MagicError] if the magic is not valid Mach-O magic
487
- # @raise [MachO::FatBinaryError] if the magic is for a Fat file
438
+ # @raise [MagicError] if the magic is not valid Mach-O magic
439
+ # @raise [FatBinaryError] if the magic is for a Fat file
488
440
  # @api private
489
441
  def populate_and_check_magic
490
442
  magic = @raw_data[0..3].unpack("N").first
@@ -499,7 +451,7 @@ module MachO
499
451
 
500
452
  # Check the file's CPU type.
501
453
  # @param cputype [Fixnum] the CPU type
502
- # @raise [MachO::CPUTypeError] if the CPU type is unknown
454
+ # @raise [CPUTypeError] if the CPU type is unknown
503
455
  # @api private
504
456
  def check_cputype(cputype)
505
457
  raise CPUTypeError, cputype unless Headers::CPU_TYPES.key?(cputype)
@@ -507,7 +459,7 @@ module MachO
507
459
 
508
460
  # Check the file's CPU type/subtype pair.
509
461
  # @param cpusubtype [Fixnum] the CPU subtype
510
- # @raise [MachO::CPUSubtypeError] if the CPU sub-type is unknown
462
+ # @raise [CPUSubtypeError] if the CPU sub-type is unknown
511
463
  # @api private
512
464
  def check_cpusubtype(cputype, cpusubtype)
513
465
  # Only check sub-type w/o capability bits (see `populate_mach_header`).
@@ -516,15 +468,15 @@ module MachO
516
468
 
517
469
  # Check the file's type.
518
470
  # @param filetype [Fixnum] the file type
519
- # @raise [MachO::FiletypeError] if the file type is unknown
471
+ # @raise [FiletypeError] if the file type is unknown
520
472
  # @api private
521
473
  def check_filetype(filetype)
522
474
  raise FiletypeError, filetype unless Headers::MH_FILETYPES.key?(filetype)
523
475
  end
524
476
 
525
477
  # All load commands in the file.
526
- # @return [Array<MachO::LoadCommands::LoadCommand>] an array of load commands
527
- # @raise [MachO::LoadCommandError] if an unknown load command is encountered
478
+ # @return [Array<LoadCommands::LoadCommand>] an array of load commands
479
+ # @raise [LoadCommandError] if an unknown load command is encountered
528
480
  # @api private
529
481
  def populate_load_commands
530
482
  offset = header.class.bytesize
@@ -539,7 +491,7 @@ module MachO
539
491
 
540
492
  # why do I do this? i don't like declaring constants below
541
493
  # classes, and i need them to resolve...
542
- klass = MachO::LoadCommands.const_get LoadCommands::LC_STRUCTURES[cmd_sym]
494
+ klass = LoadCommands.const_get LoadCommands::LC_STRUCTURES[cmd_sym]
543
495
  view = MachOView.new(@raw_data, endianness, offset)
544
496
  command = klass.new_from_bin(view)
545
497