ruby-macho 1.4.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 50aeda7d9f7ac3c91c6e34a9d150ffbf79d89389cb591d06494fb0eb4e48023b
4
- data.tar.gz: e7f56ff39f7159c20572e66bd07b506e826152e8b1da3d78afe22f4e8516b4a9
3
+ metadata.gz: 6341c1a29aeae7169fea7f1e7fc11339331f21c2b07a3a19e7f68b5dd76af03d
4
+ data.tar.gz: 9b5dd29c4a03c18bf6261e20641c95c584958ee142d4d64a37f9db8352065727
5
5
  SHA512:
6
- metadata.gz: 2bb5bd7d605eb023b8cdf95446776507ddcfb08a7d30bc45acf3fff24d3b4edc5666b8c5f4801e226524ba60dad043a3c251819ff8b0cdd77e0e5b491a4a2e81
7
- data.tar.gz: a2d553f64c0e73882dcbce972bf8cdab7554c98f1c6daf2d504588e11d05d194ac417127d61a32f93263fa3487ab1655cf16867994018464c8d5a9f4df9b6073
6
+ metadata.gz: c3964af02f0b1abf51de625e1d69a8fd966c30d5bf93cfde410ac127fab57864ae6331441d2afa1acdd100c7187f5d05883ecd8736d88076507823b16627ab10
7
+ data.tar.gz: c5a8ec50db69dccef0161dd96d6b7f23a47713a0fb8551d1bae10afa2690ed6837b52f9f3f49bd0826610b7c7a1841fadda2d1c53f6ab91f118732e36a3a4bd7
@@ -12,7 +12,7 @@ require_relative "macho/tools"
12
12
  # The primary namespace for ruby-macho.
13
13
  module MachO
14
14
  # release version
15
- VERSION = "1.4.0".freeze
15
+ VERSION = "2.0.0".freeze
16
16
 
17
17
  # Opens the given filename as a MachOFile or FatFile, depending on its magic.
18
18
  # @param filename [String] the file being opened
@@ -194,14 +194,4 @@ module MachO
194
194
  super "Unimplemented: #{thing}"
195
195
  end
196
196
  end
197
-
198
- # Raised when attempting to create a {FatFile} from one or more {MachOFile}s
199
- # whose offsets will not fit within the resulting 32-bit {Headers::FatArch#offset} fields.
200
- class FatArchOffsetOverflowError < MachOError
201
- # @param offset [Integer] the offending offset
202
- def initialize(offset)
203
- super "Offset #{offset} exceeds the 32-bit width of a fat_arch offset." \
204
- " Consider merging with `fat64: true`"
205
- end
206
- end
207
197
  end
@@ -14,7 +14,7 @@ module MachO
14
14
  # @return [Headers::FatHeader] the file's header
15
15
  attr_reader :header
16
16
 
17
- # @return [Array<Headers::FatArch>, Array<Headers::FatArch64] an array of fat architectures
17
+ # @return [Array<Headers::FatArch>] an array of fat architectures
18
18
  attr_reader :fat_archs
19
19
 
20
20
  # @return [Array<MachOFile>] an array of Mach-O binaries
@@ -22,53 +22,37 @@ module MachO
22
22
 
23
23
  # Creates a new FatFile from the given (single-arch) Mach-Os
24
24
  # @param machos [Array<MachOFile>] the machos to combine
25
- # @param fat64 [Boolean] whether to use {Headers::FatArch64}s to represent each slice
26
25
  # @return [FatFile] a new FatFile containing the give machos
27
26
  # @raise [ArgumentError] if less than one Mach-O is given
28
- # @raise [FatArchOffsetOverflowError] if the Mach-Os are too big to be represented
29
- # in a 32-bit {Headers::FatArch} and `fat64` is `false`.
30
- def self.new_from_machos(*machos, fat64: false)
27
+ def self.new_from_machos(*machos)
31
28
  raise ArgumentError, "expected at least one Mach-O" if machos.empty?
32
29
 
33
- fa_klass, magic = if fat64
34
- [Headers::FatArch64, Headers::FAT_MAGIC_64]
35
- else
36
- [Headers::FatArch, Headers::FAT_MAGIC]
37
- end
38
-
39
30
  # put the smaller alignments further forwards in fat macho, so that we do less padding
40
31
  machos = machos.sort_by(&:segment_alignment)
41
32
 
42
- bin = if String.instance_methods.include? :+@
43
- +""
44
- else
45
- ""
46
- end
33
+ bin = +""
47
34
 
48
- bin << Headers::FatHeader.new(magic, machos.size).serialize
49
- offset = Headers::FatHeader.bytesize + (machos.size * fa_klass.bytesize)
35
+ bin << Headers::FatHeader.new(Headers::FAT_MAGIC, machos.size).serialize
36
+ offset = Headers::FatHeader.bytesize + (machos.size * Headers::FatArch.bytesize)
50
37
 
51
38
  macho_pads = {}
39
+ macho_bins = {}
52
40
 
53
41
  machos.each do |macho|
54
- macho_offset = Utils.round(offset, 2**macho.segment_alignment)
55
-
56
- if !fat64 && macho_offset > (2**32 - 1)
57
- raise FatArchOffsetOverflowError, macho_offset
58
- end
59
-
42
+ macho_offset = Utils.round(offset, 2**macho.segment_alignment)
60
43
  macho_pads[macho] = Utils.padding_for(offset, 2**macho.segment_alignment)
44
+ macho_bins[macho] = macho.serialize
61
45
 
62
- bin << fa_klass.new(macho.header.cputype, macho.header.cpusubtype,
63
- macho_offset, macho.serialize.bytesize,
64
- macho.segment_alignment).serialize
46
+ bin << Headers::FatArch.new(macho.header.cputype, macho.header.cpusubtype,
47
+ macho_offset, macho_bins[macho].bytesize,
48
+ macho.segment_alignment).serialize
65
49
 
66
- offset += (macho.serialize.bytesize + macho_pads[macho])
50
+ offset += (macho_bins[macho].bytesize + macho_pads[macho])
67
51
  end
68
52
 
69
53
  machos.each do |macho|
70
54
  bin << Utils.nullpad(macho_pads[macho])
71
- bin << macho.serialize
55
+ bin << macho_bins[macho]
72
56
  end
73
57
 
74
58
  new_from_bin(bin)
@@ -294,7 +278,6 @@ module MachO
294
278
  # @note Overwrites all data in the file!
295
279
  def write!
296
280
  raise MachOError, "no initial file to write to" if filename.nil?
297
-
298
281
  File.open(@filename, "wb") { |f| f.write(@raw_data) }
299
282
  end
300
283
 
@@ -344,12 +327,10 @@ module MachO
344
327
  def populate_fat_archs
345
328
  archs = []
346
329
 
347
- fa_klass = Utils.fat_magic32?(header.magic) ? Headers::FatArch : Headers::FatArch64
348
- fa_off = Headers::FatHeader.bytesize
349
- fa_len = fa_klass.bytesize
350
-
330
+ fa_off = Headers::FatHeader.bytesize
331
+ fa_len = Headers::FatArch.bytesize
351
332
  header.nfat_arch.times do |i|
352
- archs << fa_klass.new_from_bin(:big, @raw_data[fa_off + (fa_len * i), fa_len])
333
+ archs << Headers::FatArch.new_from_bin(:big, @raw_data[fa_off + (fa_len * i), fa_len])
353
334
  end
354
335
 
355
336
  archs
@@ -399,7 +380,6 @@ module MachO
399
380
 
400
381
  # Strict mode: Immediately re-raise. Otherwise: Retain, check later.
401
382
  raise error if strict
402
-
403
383
  errors << error
404
384
  end
405
385
  end
@@ -6,19 +6,11 @@ module MachO
6
6
  FAT_MAGIC = 0xcafebabe
7
7
 
8
8
  # little-endian fat magic
9
- # @note This is defined for completeness, but should never appear in ruby-macho code,
10
- # since fat headers are always big-endian.
9
+ # this is defined, but should never appear in ruby-macho code because
10
+ # fat headers are always big-endian and therefore always unpacked as such.
11
11
  # @api private
12
12
  FAT_CIGAM = 0xbebafeca
13
13
 
14
- # 64-bit big-endian fat magic
15
- FAT_MAGIC_64 = 0xcafebabf
16
-
17
- # 64-bit little-endian fat magic
18
- # @note This is defined for completeness, but should never appear in ruby-macho code,
19
- # since fat headers are always big-endian.
20
- FAT_CIGAM_64 = 0xbfbafeca
21
-
22
14
  # 32-bit big-endian magic
23
15
  # @api private
24
16
  MH_MAGIC = 0xfeedface
@@ -39,7 +31,6 @@ module MachO
39
31
  # @api private
40
32
  MH_MAGICS = {
41
33
  FAT_MAGIC => "FAT_MAGIC",
42
- FAT_MAGIC_64 => "FAT_MAGIC_64",
43
34
  MH_MAGIC => "MH_MAGIC",
44
35
  MH_CIGAM => "MH_CIGAM",
45
36
  MH_MAGIC_64 => "MH_MAGIC_64",
@@ -50,11 +41,6 @@ module MachO
50
41
  # @api private
51
42
  CPU_ARCH_ABI64 = 0x01000000
52
43
 
53
- # mask for CPUs with 64-bit architectures (when running a 32-bit ABI?)
54
- # @see https://github.com/Homebrew/ruby-macho/issues/113
55
- # @api private
56
- CPU_ARCH_ABI32 = 0x02000000
57
-
58
44
  # any CPU (unused?)
59
45
  # @api private
60
46
  CPU_TYPE_ANY = -1
@@ -83,10 +69,6 @@ module MachO
83
69
  # @api private
84
70
  CPU_TYPE_ARM64 = (CPU_TYPE_ARM | CPU_ARCH_ABI64)
85
71
 
86
- # 64-bit ARM compatible CPUs (running in 32-bit mode?)
87
- # @see https://github.com/Homebrew/ruby-macho/issues/113
88
- CPU_TYPE_ARM64_32 = (CPU_TYPE_ARM | CPU_ARCH_ABI32)
89
-
90
72
  # PowerPC compatible CPUs
91
73
  # @api private
92
74
  CPU_TYPE_POWERPC = 0x12
@@ -103,7 +85,6 @@ module MachO
103
85
  CPU_TYPE_X86_64 => :x86_64,
104
86
  CPU_TYPE_ARM => :arm,
105
87
  CPU_TYPE_ARM64 => :arm64,
106
- CPU_TYPE_ARM64_32 => :arm64_32,
107
88
  CPU_TYPE_POWERPC => :ppc,
108
89
  CPU_TYPE_POWERPC64 => :ppc64,
109
90
  }.freeze
@@ -237,14 +218,6 @@ module MachO
237
218
  # @api private
238
219
  CPU_SUBTYPE_ARM64_V8 = 1
239
220
 
240
- # the v8 sub-type for `CPU_TYPE_ARM64_32`
241
- # @api private
242
- CPU_SUBTYPE_ARM64_32_V8 = 1
243
-
244
- # the e (A12) sub-type for `CPU_TYPE_ARM64`
245
- # @api private
246
- CPU_SUBTYPE_ARM64E = 2
247
-
248
221
  # the lowest common sub-type for `CPU_TYPE_MC88000`
249
222
  # @api private
250
223
  CPU_SUBTYPE_MC88000_ALL = 0
@@ -354,10 +327,6 @@ module MachO
354
327
  CPU_TYPE_ARM64 => {
355
328
  CPU_SUBTYPE_ARM64_ALL => :arm64,
356
329
  CPU_SUBTYPE_ARM64_V8 => :arm64v8,
357
- CPU_SUBTYPE_ARM64E => :arm64e,
358
- }.freeze,
359
- CPU_TYPE_ARM64_32 => {
360
- CPU_SUBTYPE_ARM64_32_V8 => :arm64_32v8,
361
330
  }.freeze,
362
331
  CPU_TYPE_POWERPC => {
363
332
  CPU_SUBTYPE_POWERPC_ALL => :ppc,
@@ -517,10 +486,8 @@ module MachO
517
486
  end
518
487
  end
519
488
 
520
- # 32-bit fat binary header architecture structure. A 32-bit fat Mach-O has one or more of
521
- # these, indicating one or more internal Mach-O blobs.
522
- # @note "32-bit" indicates the fact that this structure stores 32-bit offsets, not that the
523
- # Mach-Os that it points to necessarily *are* 32-bit.
489
+ # Fat binary header architecture structure. A Fat binary has one or more of
490
+ # these, representing one or more internal Mach-O blobs.
524
491
  # @see MachO::Headers::FatHeader
525
492
  class FatArch < MachOStructure
526
493
  # @return [Integer] the CPU type of the Mach-O
@@ -538,10 +505,10 @@ module MachO
538
505
  # @return [Integer] the alignment, as a power of 2
539
506
  attr_reader :align
540
507
 
541
- # @note Always big endian.
508
+ # always big-endian
542
509
  # @see MachOStructure::FORMAT
543
510
  # @api private
544
- FORMAT = "L>5".freeze
511
+ FORMAT = "N5".freeze
545
512
 
546
513
  # @see MachOStructure::SIZEOF
547
514
  # @api private
@@ -575,43 +542,6 @@ module MachO
575
542
  end
576
543
  end
577
544
 
578
- # 64-bit fat binary header architecture structure. A 64-bit fat Mach-O has one or more of
579
- # these, indicating one or more internal Mach-O blobs.
580
- # @note "64-bit" indicates the fact that this structure stores 64-bit offsets, not that the
581
- # Mach-Os that it points to necessarily *are* 64-bit.
582
- # @see MachO::Headers::FatHeader
583
- class FatArch64 < FatArch
584
- # @return [void]
585
- attr_reader :reserved
586
-
587
- # @note Always big endian.
588
- # @see MachOStructure::FORMAT
589
- # @api private
590
- FORMAT = "L>2Q>2L>2".freeze
591
-
592
- # @see MachOStructure::SIZEOF
593
- # @api private
594
- SIZEOF = 32
595
-
596
- # @api private
597
- def initialize(cputype, cpusubtype, offset, size, align, reserved = 0)
598
- super(cputype, cpusubtype, offset, size, align)
599
- @reserved = reserved
600
- end
601
-
602
- # @return [String] the serialized fields of the fat arch
603
- def serialize
604
- [cputype, cpusubtype, offset, size, align, reserved].pack(FORMAT)
605
- end
606
-
607
- # @return [Hash] a hash representation of this {FatArch64}
608
- def to_h
609
- {
610
- "reserved" => reserved,
611
- }.merge super
612
- end
613
- end
614
-
615
545
  # 32-bit Mach-O file header structure
616
546
  class MachHeader < MachOStructure
617
547
  # @return [Integer] the magic number
@@ -663,9 +593,7 @@ module MachO
663
593
  # @return [Boolean] true if `flag` is present in the header's flag section
664
594
  def flag?(flag)
665
595
  flag = MH_FLAGS[flag]
666
-
667
596
  return false if flag.nil?
668
-
669
597
  flags & flag == flag
670
598
  end
671
599
 
@@ -242,7 +242,6 @@ module MachO
242
242
  # @api private
243
243
  def serialize(context)
244
244
  raise LoadCommandNotSerializableError, LOAD_COMMANDS[cmd] unless serializable?
245
-
246
245
  format = Utils.specialize_format(FORMAT, context.endianness)
247
246
  [cmd, SIZEOF].pack(format)
248
247
  end
@@ -299,9 +298,7 @@ module MachO
299
298
  lc_end = view.offset + lc.cmdsize - 1
300
299
  raw_string = view.raw_data.slice(lc_str_abs..lc_end)
301
300
  @string, null_byte, _padding = raw_string.partition("\x00")
302
-
303
301
  raise LCStrMalformedError, lc if null_byte.empty?
304
-
305
302
  @string_offset = lc_str
306
303
  else
307
304
  @string = lc_str
@@ -476,9 +473,7 @@ module MachO
476
473
  # @return [Boolean] true if `flag` is present in the segment's flag field
477
474
  def flag?(flag)
478
475
  flag = SEGMENT_FLAGS[flag]
479
-
480
476
  return false if flag.nil?
481
-
482
477
  flags & flag == flag
483
478
  end
484
479
 
@@ -431,7 +431,6 @@ module MachO
431
431
  # @note Overwrites all data in the file!
432
432
  def write!
433
433
  raise MachOError, "no initial file to write to" if @filename.nil?
434
-
435
434
  File.open(@filename, "wb") { |f| f.write(@raw_data) }
436
435
  end
437
436
 
@@ -150,9 +150,7 @@ module MachO
150
150
  # @return [Boolean] whether the flag is present in the section's {flags}
151
151
  def flag?(flag)
152
152
  flag = SECTION_FLAGS[flag]
153
-
154
153
  return false if flag.nil?
155
-
156
154
  flags & flag == flag
157
155
  end
158
156
 
@@ -89,9 +89,8 @@ module MachO
89
89
  # Merge multiple Mach-Os into one universal (Fat) binary.
90
90
  # @param filename [String] the fat binary to create
91
91
  # @param files [Array<String>] the files to merge
92
- # @param fat64 [Boolean] whether to use {Headers::FatArch64}s to represent each slice
93
92
  # @return [void]
94
- def self.merge_machos(filename, *files, fat64: false)
93
+ def self.merge_machos(filename, *files)
95
94
  machos = files.map do |file|
96
95
  macho = MachO.open(file)
97
96
  case macho
@@ -102,7 +101,7 @@ module MachO
102
101
  end
103
102
  end.flatten
104
103
 
105
- fat_macho = MachO::FatFile.new_from_machos(*machos, :fat64 => fat64)
104
+ fat_macho = MachO::FatFile.new_from_machos(*machos)
106
105
  fat_macho.write(filename)
107
106
  end
108
107
  end
@@ -27,7 +27,7 @@ module MachO
27
27
  # @return [String] the null string (or empty string, for `size = 0`)
28
28
  # @raise [ArgumentError] if a non-positive nullpad is requested
29
29
  def self.nullpad(size)
30
- raise ArgumentError, "size < 0: #{size}" if size < 0
30
+ raise ArgumentError, "size < 0: #{size}" if size.negative?
31
31
 
32
32
  "\x00" * size
33
33
  end
@@ -75,49 +75,35 @@ module MachO
75
75
  # @param num [Integer] the number being checked
76
76
  # @return [Boolean] whether `num` is a valid Fat magic number
77
77
  def self.fat_magic?(num)
78
- [Headers::FAT_MAGIC, Headers::FAT_MAGIC_64].include? num
79
- end
80
-
81
- # Compares the given number to valid 32-bit Fat magic numbers.
82
- # @param num [Integer] the number being checked
83
- # @return [Boolean] whether `num` is a valid 32-bit fat magic number
84
- def self.fat_magic32?(num)
85
78
  num == Headers::FAT_MAGIC
86
79
  end
87
80
 
88
- # Compares the given number to valid 64-bit Fat magic numbers.
89
- # @param num [Integer] the number being checked
90
- # @return [Boolean] whether `num` is a valid 64-bit fat magic number
91
- def self.fat_magic64?(num)
92
- num == Headers::FAT_MAGIC_64
93
- end
94
-
95
81
  # Compares the given number to valid 32-bit Mach-O magic numbers.
96
82
  # @param num [Integer] the number being checked
97
83
  # @return [Boolean] whether `num` is a valid 32-bit magic number
98
84
  def self.magic32?(num)
99
- [Headers::MH_MAGIC, Headers::MH_CIGAM].include? num
85
+ num == Headers::MH_MAGIC || num == Headers::MH_CIGAM
100
86
  end
101
87
 
102
88
  # Compares the given number to valid 64-bit Mach-O magic numbers.
103
89
  # @param num [Integer] the number being checked
104
90
  # @return [Boolean] whether `num` is a valid 64-bit magic number
105
91
  def self.magic64?(num)
106
- [Headers::MH_MAGIC_64, Headers::MH_CIGAM_64].include? num
92
+ num == Headers::MH_MAGIC_64 || num == Headers::MH_CIGAM_64
107
93
  end
108
94
 
109
95
  # Compares the given number to valid little-endian magic numbers.
110
96
  # @param num [Integer] the number being checked
111
97
  # @return [Boolean] whether `num` is a valid little-endian magic number
112
98
  def self.little_magic?(num)
113
- [Headers::MH_CIGAM, Headers::MH_CIGAM_64].include? num
99
+ num == Headers::MH_CIGAM || num == Headers::MH_CIGAM_64
114
100
  end
115
101
 
116
102
  # Compares the given number to valid big-endian magic numbers.
117
103
  # @param num [Integer] the number being checked
118
104
  # @return [Boolean] whether `num` is a valid big-endian magic number
119
105
  def self.big_magic?(num)
120
- [Headers::MH_MAGIC, Headers::MH_MAGIC_64].include? num
106
+ num == Headers::MH_CIGAM || num == Headers::MH_CIGAM_64
121
107
  end
122
108
  end
123
109
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-macho
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - William Woodruff
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-02-21 00:00:00.000000000 Z
11
+ date: 2018-07-03 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A library for viewing and manipulating Mach-O files in Ruby.
14
14
  email: william@yossarian.net
@@ -42,14 +42,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
42
42
  requirements:
43
43
  - - ">="
44
44
  - !ruby/object:Gem::Version
45
- version: '2.0'
45
+ version: '2.1'
46
46
  required_rubygems_version: !ruby/object:Gem::Requirement
47
47
  requirements:
48
48
  - - ">="
49
49
  - !ruby/object:Gem::Version
50
50
  version: '0'
51
51
  requirements: []
52
- rubygems_version: 3.0.1
52
+ rubyforge_project:
53
+ rubygems_version: 2.7.6
53
54
  signing_key:
54
55
  specification_version: 4
55
56
  summary: ruby-macho - Mach-O file analyzer.