ruby-macho 0.2.4 → 0.2.5

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.
data/lib/macho/open.rb CHANGED
@@ -7,17 +7,17 @@ module MachO
7
7
  # @raise [MachO::TruncatedFileError] if the file is too small to have a valid header
8
8
  # @raise [MachO::MagicError] if the file's magic is not valid Mach-O magic
9
9
  def self.open(filename)
10
- raise ArgumentError.new("#{filename}: no such file") unless File.file?(filename)
11
- raise TruncatedFileError.new unless File.stat(filename).size >= 4
10
+ raise ArgumentError, "#{filename}: no such file" unless File.file?(filename)
11
+ raise TruncatedFileError unless File.stat(filename).size >= 4
12
12
 
13
13
  magic = File.open(filename, "rb") { |f| f.read(4) }.unpack("N").first
14
14
 
15
- if MachO.fat_magic?(magic)
15
+ if Utils.fat_magic?(magic)
16
16
  file = FatFile.new(filename)
17
- elsif MachO.magic?(magic)
17
+ elsif Utils.magic?(magic)
18
18
  file = MachOFile.new(filename)
19
19
  else
20
- raise MagicError.new(magic)
20
+ raise MagicError, magic
21
21
  end
22
22
 
23
23
  file
@@ -45,7 +45,7 @@ module MachO
45
45
  :S_ATTR_DEBUG => 0x02000000,
46
46
  :S_ATTR_SOME_INSTRUCTIONS => 0x00000400,
47
47
  :S_ATTR_EXT_RELOC => 0x00000200,
48
- :S_ATTR_LOC_RELOC => 0x00000100
48
+ :S_ATTR_LOC_RELOC => 0x00000100,
49
49
  }.freeze
50
50
 
51
51
  # association of section name symbols to names
@@ -62,7 +62,7 @@ module MachO
62
62
  :SECT_OBJC_STRINGS => "__selector_strs",
63
63
  :SECT_OBJC_REFS => "__selector_refs",
64
64
  :SECT_ICON_HEADER => "__header",
65
- :SECT_ICON_TIFF => "__tiff"
65
+ :SECT_ICON_TIFF => "__tiff",
66
66
  }.freeze
67
67
 
68
68
  # Represents a section of a segment for 32-bit architectures.
@@ -91,7 +91,7 @@ module MachO
91
91
  # @return [Fixnum] the number of relocation entries
92
92
  attr_reader :nreloc
93
93
 
94
- # @return [Fixnum] flags for type and addrributes of the section
94
+ # @return [Fixnum] flags for type and attributes of the section
95
95
  attr_reader :flags
96
96
 
97
97
  # @return [void] reserved (for offset or index)
@@ -100,12 +100,15 @@ module MachO
100
100
  # @return [void] reserved (for count or sizeof)
101
101
  attr_reader :reserved2
102
102
 
103
- FORMAT = "a16a16L=9"
103
+ # @see MachOStructure::FORMAT
104
+ FORMAT = "a16a16L=9".freeze
105
+
106
+ # @see MachOStructure::SIZEOF
104
107
  SIZEOF = 68
105
108
 
106
109
  # @api private
107
110
  def initialize(sectname, segname, addr, size, offset, align, reloff,
108
- nreloc, flags, reserved1, reserved2)
111
+ nreloc, flags, reserved1, reserved2)
109
112
  @sectname = sectname
110
113
  @segname = segname
111
114
  @addr = addr
@@ -121,12 +124,17 @@ module MachO
121
124
 
122
125
  # @return [String] the section's name, with any trailing NULL characters removed
123
126
  def section_name
124
- @sectname.delete("\x00")
127
+ sectname.delete("\x00")
125
128
  end
126
129
 
127
130
  # @return [String] the parent segment's name, with any trailing NULL characters removed
128
131
  def segment_name
129
- @segname.delete("\x00")
132
+ segname.delete("\x00")
133
+ end
134
+
135
+ # @return [Boolean] true if the section has no contents (i.e, `size` is 0)
136
+ def empty?
137
+ size.zero?
130
138
  end
131
139
 
132
140
  # @example
@@ -145,12 +153,15 @@ module MachO
145
153
  # @return [void] reserved
146
154
  attr_reader :reserved3
147
155
 
148
- FORMAT = "a16a16Q=2L=8"
156
+ # @see MachOStructure::FORMAT
157
+ FORMAT = "a16a16Q=2L=8".freeze
158
+
159
+ # @see MachOStructure::SIZEOF
149
160
  SIZEOF = 80
150
161
 
151
162
  # @api private
152
163
  def initialize(sectname, segname, addr, size, offset, align, reloff,
153
- nreloc, flags, reserved1, reserved2, reserved3)
164
+ nreloc, flags, reserved1, reserved2, reserved3)
154
165
  super(sectname, segname, addr, size, offset, align, reloff,
155
166
  nreloc, flags, reserved1, reserved2)
156
167
  @reserved3 = reserved3
@@ -3,9 +3,13 @@ module MachO
3
3
  # @abstract
4
4
  class MachOStructure
5
5
  # The String#unpack format of the data structure.
6
- FORMAT = ""
6
+ # @return [String] the unpacking format
7
+ # @api private
8
+ FORMAT = "".freeze
7
9
 
8
10
  # The size of the data structure, in bytes.
11
+ # @return [Fixnum] the size, in bytes
12
+ # @api private
9
13
  SIZEOF = 0
10
14
 
11
15
  # @return [Fixnum] the size, in bytes, of the represented structure.
@@ -13,26 +17,14 @@ module MachO
13
17
  self::SIZEOF
14
18
  end
15
19
 
16
- # @param endianness [Symbol] either :big or :little
20
+ # @param endianness [Symbol] either `:big` or `:little`
17
21
  # @param bin [String] the string to be unpacked into the new structure
18
22
  # @return [MachO::MachOStructure] a new MachOStructure initialized with `bin`
19
23
  # @api private
20
24
  def self.new_from_bin(endianness, bin)
21
- format = specialize_format(self::FORMAT, endianness)
22
-
23
- self.new(*bin.unpack(format))
24
- end
25
-
26
- private
25
+ format = Utils.specialize_format(self::FORMAT, endianness)
27
26
 
28
- # Convert an abstract (native-endian) String#unpack format to big or little.
29
- # @param format [String] the format string being converted
30
- # @param endianness [Symbol] either :big or :little
31
- # @return [String] the converted string
32
- # @api private
33
- def self.specialize_format(format, endianness)
34
- modifier = (endianness == :big) ? ">" : "<"
35
- format.tr("=", modifier)
27
+ new(*bin.unpack(format))
36
28
  end
37
29
  end
38
30
  end
data/lib/macho/tools.rb CHANGED
@@ -12,12 +12,14 @@ module MachO
12
12
  # Changes the dylib ID of a Mach-O or Fat binary, overwriting the source file.
13
13
  # @param filename [String] the Mach-O or Fat binary being modified
14
14
  # @param new_id [String] the new dylib ID for the binary
15
+ # @param options [Hash]
16
+ # @option options [Boolean] :strict (true) whether or not to fail loudly
17
+ # with an exception if the change cannot be performed
15
18
  # @return [void]
16
- # @todo unstub for fat files
17
- def self.change_dylib_id(filename, new_id)
19
+ def self.change_dylib_id(filename, new_id, options = {})
18
20
  file = MachO.open(filename)
19
21
 
20
- file.dylib_id = new_id
22
+ file.change_dylib_id(new_id, options)
21
23
  file.write!
22
24
  end
23
25
 
@@ -25,12 +27,14 @@ module MachO
25
27
  # @param filename [String] the Mach-O or Fat binary being modified
26
28
  # @param old_name [String] the old shared library name
27
29
  # @param new_name [String] the new shared library name
30
+ # @param options [Hash]
31
+ # @option options [Boolean] :strict (true) whether or not to fail loudly
32
+ # with an exception if the change cannot be performed
28
33
  # @return [void]
29
- # @todo unstub for fat files
30
- def self.change_install_name(filename, old_name, new_name)
34
+ def self.change_install_name(filename, old_name, new_name, options = {})
31
35
  file = MachO.open(filename)
32
36
 
33
- file.change_install_name(old_name, new_name)
37
+ file.change_install_name(old_name, new_name, options)
34
38
  file.write!
35
39
  end
36
40
 
@@ -38,28 +42,43 @@ module MachO
38
42
  # @param filename [String] the Mach-O or Fat binary being modified
39
43
  # @param old_path [String] the old runtime path
40
44
  # @param new_path [String] the new runtime path
45
+ # @param options [Hash]
46
+ # @option options [Boolean] :strict (true) whether or not to fail loudly
47
+ # with an exception if the change cannot be performed
41
48
  # @return [void]
42
- # @todo unstub
43
- def self.change_rpath(filename, old_path, new_path)
44
- raise UnimplementedError.new("changing rpaths in a Mach-O")
49
+ def self.change_rpath(filename, old_path, new_path, options = {})
50
+ file = MachO.open(filename)
51
+
52
+ file.change_rpath(old_path, new_path, options)
53
+ file.write!
45
54
  end
46
55
 
47
56
  # Add a runtime path to a Mach-O or Fat binary, overwriting the source file.
48
57
  # @param filename [String] the Mach-O or Fat binary being modified
49
58
  # @param new_path [String] the new runtime path
59
+ # @param options [Hash]
60
+ # @option options [Boolean] :strict (true) whether or not to fail loudly
61
+ # with an exception if the change cannot be performed
50
62
  # @return [void]
51
- # @todo unstub
52
- def self.add_rpath(filename, new_path)
53
- raise UnimplementedError.new("adding rpaths to a Mach-O")
63
+ def self.add_rpath(filename, new_path, options = {})
64
+ file = MachO.open(filename)
65
+
66
+ file.add_rpath(new_path, options)
67
+ file.write!
54
68
  end
55
69
 
56
70
  # Delete a runtime path from a Mach-O or Fat binary, overwriting the source file.
57
71
  # @param filename [String] the Mach-O or Fat binary being modified
58
72
  # @param old_path [String] the old runtime path
73
+ # @param options [Hash]
74
+ # @option options [Boolean] :strict (true) whether or not to fail loudly
75
+ # with an exception if the change cannot be performed
59
76
  # @return [void]
60
- # @todo unstub
61
- def self.delete_rpath(filename, old_path)
62
- raise UnimplementedError.new("removing rpaths from a Mach-O")
77
+ def self.delete_rpath(filename, old_path, options = {})
78
+ file = MachO.open(filename)
79
+
80
+ file.delete_rpath(old_path, options)
81
+ file.write!
63
82
  end
64
83
  end
65
84
  end
data/lib/macho/utils.rb CHANGED
@@ -1,48 +1,96 @@
1
1
  module MachO
2
- # @param value [Fixnum] the number being rounded
3
- # @param round [Fixnum] the number being rounded with
4
- # @return [Fixnum] the next number >= `value` such that `round` is its divisor
5
- # @see http://www.opensource.apple.com/source/cctools/cctools-870/libstuff/rnd.c
6
- def self.round(value, round)
7
- round -= 1
8
- value += round
9
- value &= ~round
10
- value
11
- end
2
+ # A collection of utility functions used throughout ruby-macho.
3
+ module Utils
4
+ # Rounds a value to the next multiple of the given round.
5
+ # @param value [Fixnum] the number being rounded
6
+ # @param round [Fixnum] the number being rounded with
7
+ # @return [Fixnum] the rounded value
8
+ # @see http://www.opensource.apple.com/source/cctools/cctools-870/libstuff/rnd.c
9
+ def self.round(value, round)
10
+ round -= 1
11
+ value += round
12
+ value &= ~round
13
+ value
14
+ end
12
15
 
13
- # @param num [Fixnum] the number being checked
14
- # @return [Boolean] true if `num` is a valid Mach-O magic number, false otherwise
15
- def self.magic?(num)
16
- MH_MAGICS.has_key?(num)
17
- end
16
+ # Returns the number of bytes needed to pad the given size to the given alignment.
17
+ # @param size [Fixnum] the unpadded size
18
+ # @param alignment [Fixnum] the number to alignment the size with
19
+ # @return [Fixnum] the number of pad bytes required
20
+ def self.padding_for(size, alignment)
21
+ round(size, alignment) - size
22
+ end
18
23
 
19
- # @param num [Fixnum] the number being checked
20
- # @return [Boolean] true if `num` is a valid Fat magic number, false otherwise
21
- def self.fat_magic?(num)
22
- num == FAT_MAGIC
23
- end
24
+ # Converts an abstract (native-endian) String#unpack format to big or little.
25
+ # @param format [String] the format string being converted
26
+ # @param endianness [Symbol] either `:big` or `:little`
27
+ # @return [String] the converted string
28
+ def self.specialize_format(format, endianness)
29
+ modifier = endianness == :big ? ">" : "<"
30
+ format.tr("=", modifier)
31
+ end
24
32
 
25
- # @param num [Fixnum] the number being checked
26
- # @return [Boolean] true if `num` is a valid 32-bit magic number, false otherwise
27
- def self.magic32?(num)
28
- num == MH_MAGIC || num == MH_CIGAM
29
- end
33
+ # Packs tagged strings into an aligned payload.
34
+ # @param fixed_offset [Fixnum] the baseline offset for the first packed string
35
+ # @param alignment [Fixnum] the alignment value to use for packing
36
+ # @param strings [Hash] the labeled strings to pack
37
+ # @return [Array<String, Hash>] the packed string and labeled offsets
38
+ def self.pack_strings(fixed_offset, alignment, strings = {})
39
+ offsets = {}
40
+ next_offset = fixed_offset
41
+ payload = ""
30
42
 
31
- # @param num [Fixnum] the number being checked
32
- # @return [Boolean] true if `num` is a valid 64-bit magic number, false otherwise
33
- def self.magic64?(num)
34
- num == MH_MAGIC_64 || num == MH_CIGAM_64
35
- end
43
+ strings.each do |key, string|
44
+ offsets[key] = next_offset
45
+ payload << string
46
+ payload << "\x00"
47
+ next_offset += string.bytesize + 1
48
+ end
36
49
 
37
- # @param num [Fixnum] the number being checked
38
- # @return [Boolean] true if `num` is a valid little-endian magic number, false otherwise
39
- def self.little_magic?(num)
40
- num == MH_CIGAM || num == MH_CIGAM_64
41
- end
50
+ payload << "\x00" * padding_for(fixed_offset + payload.bytesize, alignment)
51
+ [payload, offsets]
52
+ end
53
+
54
+ # Compares the given number to valid Mach-O magic numbers.
55
+ # @param num [Fixnum] the number being checked
56
+ # @return [Boolean] true if `num` is a valid Mach-O magic number, false otherwise
57
+ def self.magic?(num)
58
+ MH_MAGICS.key?(num)
59
+ end
60
+
61
+ # Compares the given number to valid Fat magic numbers.
62
+ # @param num [Fixnum] the number being checked
63
+ # @return [Boolean] true if `num` is a valid Fat magic number, false otherwise
64
+ def self.fat_magic?(num)
65
+ num == FAT_MAGIC
66
+ end
67
+
68
+ # Compares the given number to valid 32-bit Mach-O magic numbers.
69
+ # @param num [Fixnum] the number being checked
70
+ # @return [Boolean] true if `num` is a valid 32-bit magic number, false otherwise
71
+ def self.magic32?(num)
72
+ num == MH_MAGIC || num == MH_CIGAM
73
+ end
74
+
75
+ # Compares the given number to valid 64-bit Mach-O magic numbers.
76
+ # @param num [Fixnum] the number being checked
77
+ # @return [Boolean] true if `num` is a valid 64-bit magic number, false otherwise
78
+ def self.magic64?(num)
79
+ num == MH_MAGIC_64 || num == MH_CIGAM_64
80
+ end
81
+
82
+ # Compares the given number to valid little-endian magic numbers.
83
+ # @param num [Fixnum] the number being checked
84
+ # @return [Boolean] true if `num` is a valid little-endian magic number, false otherwise
85
+ def self.little_magic?(num)
86
+ num == MH_CIGAM || num == MH_CIGAM_64
87
+ end
42
88
 
43
- # @param num [Fixnum] the number being checked
44
- # @return [Boolean] true if `num` is a valid big-endian magic number, false otherwise
45
- def self.big_magic?(num)
46
- num == MH_CIGAM || num == MH_CIGAM_64
89
+ # Compares the given number to valid big-endian magic numbers.
90
+ # @param num [Fixnum] the number being checked
91
+ # @return [Boolean] true if `num` is a valid big-endian magic number, false otherwise
92
+ def self.big_magic?(num)
93
+ num == MH_CIGAM || num == MH_CIGAM_64
94
+ end
47
95
  end
48
96
  end
data/lib/macho/view.rb ADDED
@@ -0,0 +1,23 @@
1
+ module MachO
2
+ # A representation of some unspecified Mach-O data.
3
+ class MachOView
4
+ # @return [String] the raw Mach-O data
5
+ attr_reader :raw_data
6
+
7
+ # @return [Symbol] the endianness of the data (`:big` or `:little`)
8
+ attr_reader :endianness
9
+
10
+ # @return [Fixnum] the offset of the relevant data (in {#raw_data})
11
+ attr_reader :offset
12
+
13
+ # Creates a new MachOView.
14
+ # @param raw_data [String] the raw Mach-O data
15
+ # @param endianness [Symbol] the endianness of the data
16
+ # @param offset [Fixnum] the offset of the relevant data
17
+ def initialize(raw_data, endianness, offset)
18
+ @raw_data = raw_data
19
+ @endianness = endianness
20
+ @offset = offset
21
+ end
22
+ end
23
+ 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: 0.2.4
4
+ version: 0.2.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - William Woodruff
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-06-18 00:00:00.000000000 Z
11
+ date: 2016-08-07 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@tuffbizz.com
@@ -30,6 +30,7 @@ files:
30
30
  - lib/macho/structure.rb
31
31
  - lib/macho/tools.rb
32
32
  - lib/macho/utils.rb
33
+ - lib/macho/view.rb
33
34
  homepage: https://github.com/Homebrew/ruby-macho
34
35
  licenses:
35
36
  - MIT
@@ -55,3 +56,4 @@ signing_key:
55
56
  specification_version: 4
56
57
  summary: ruby-macho - Mach-O file analyzer.
57
58
  test_files: []
59
+ has_rdoc: