ruby-macho 0.2.2 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,16 +1,25 @@
1
1
  module MachO
2
- # Opens the given filename as a MachOFile or FatFile, depending on its magic.
3
- # @param filename [String] the file being opened
4
- # @return [MachO::MachOFile] if the file is a Mach-O
5
- # @return [MachO::FatFile] if the file is a Fat file
6
- def self.open(filename)
7
- # open file and test magic instead of using exceptions for control?
8
- begin
9
- file = MachOFile.new(filename)
10
- rescue FatBinaryError
11
- file = FatFile.new(filename)
12
- end
2
+ # Opens the given filename as a MachOFile or FatFile, depending on its magic.
3
+ # @param filename [String] the file being opened
4
+ # @return [MachO::MachOFile] if the file is a Mach-O
5
+ # @return [MachO::FatFile] if the file is a Fat file
6
+ # @raise [ArgumentError] if the given file does not exist
7
+ # @raise [MachO::TruncatedFileError] if the file is too small to have a valid header
8
+ # @raise [MachO::MagicError] if the file's magic is not valid Mach-O magic
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
13
12
 
14
- file
15
- end
16
- end
13
+ magic = File.open(filename, "rb") { |f| f.read(4) }.unpack("N").first
14
+
15
+ if MachO.fat_magic?(magic)
16
+ file = FatFile.new(filename)
17
+ elsif MachO.magic?(magic)
18
+ file = MachOFile.new(filename)
19
+ else
20
+ raise MagicError.new(magic)
21
+ end
22
+
23
+ file
24
+ end
25
+ end
@@ -1,159 +1,159 @@
1
1
  module MachO
2
- # type mask
3
- SECTION_TYPE = 0x000000ff
4
-
5
- # attributes mask
6
- SECTION_ATTRIBUTES = 0xffffff00
7
-
8
- # user settable attributes mask
9
- SECTION_ATTRIBUTES_USR = 0xff000000
10
-
11
- # system settable attributes mask
12
- SECTION_ATTRIBUTES_SYS = 0x00ffff00
13
-
14
- # association of section flag symbols to values
15
- # @api private
16
- SECTION_FLAGS = {
17
- :S_REGULAR => 0x0,
18
- :S_ZEROFILL => 0x1,
19
- :S_CSTRING_LITERALS => 0x2,
20
- :S_4BYTE_LITERALS => 0x3,
21
- :S_8BYTE_LITERALS => 0x4,
22
- :S_LITERAL_POINTERS => 0x5,
23
- :S_NON_LAZY_SYMBOL_POINTERS => 0x6,
24
- :S_LAZY_SYMBOL_POINTERS => 0x7,
25
- :S_SYMBOL_STUBS => 0x8,
26
- :S_MOD_INIT_FUNC_POINTERS => 0x9,
27
- :S_MOD_TERM_FUNC_POINTERS => 0xa,
28
- :S_COALESCED => 0xb,
29
- :S_GB_ZEROFILE => 0xc,
30
- :S_INTERPOSING => 0xd,
31
- :S_16BYTE_LITERALS => 0xe,
32
- :S_DTRACE_DOF => 0xf,
33
- :S_LAZY_DYLIB_SYMBOL_POINTERS => 0x10,
34
- :S_THREAD_LOCAL_REGULAR => 0x11,
35
- :S_THREAD_LOCAL_ZEROFILL => 0x12,
36
- :S_THREAD_LOCAL_VARIABLES => 0x13,
37
- :S_THREAD_LOCAL_VARIABLE_POINTERS => 0x14,
38
- :S_THREAD_LOCAL_INIT_FUNCTION_POINTERS => 0x15,
39
- :S_ATTR_PURE_INSTRUCTIONS => 0x80000000,
40
- :S_ATTR_NO_TOC => 0x40000000,
41
- :S_ATTR_STRIP_STATIC_SYMS => 0x20000000,
42
- :S_ATTR_NO_DEAD_STRIP => 0x10000000,
43
- :S_ATTR_LIVE_SUPPORT => 0x08000000,
44
- :S_ATTR_SELF_MODIFYING_CODE => 0x04000000,
45
- :S_ATTR_DEBUG => 0x02000000,
46
- :S_ATTR_SOME_INSTRUCTIONS => 0x00000400,
47
- :S_ATTR_EXT_RELOC => 0x00000200,
48
- :S_ATTR_LOC_RELOC => 0x00000100
49
- }
50
-
51
- # association of section name symbols to names
52
- # @api private
53
- SECTION_NAMES = {
54
- :SECT_TEXT => "__text",
55
- :SECT_FVMLIB_INIT0 => "__fvmlib_init0",
56
- :SECT_FVMLIB_INIT1 => "__fvmlib_init1",
57
- :SECT_DATA => "__data",
58
- :SECT_BSS => "__bss",
59
- :SECT_COMMON => "__common",
60
- :SECT_OBJC_SYMBOLS => "__symbol_table",
61
- :SECT_OBJC_MODULES => "__module_info",
62
- :SECT_OBJC_STRINGS => "__selector_strs",
63
- :SECT_OBJC_REFS => "__selector_refs",
64
- :SECT_ICON_HEADER => "__header",
65
- :SECT_ICON_TIFF => "__tiff"
66
- }
67
-
68
- # Represents a section of a segment for 32-bit architectures.
69
- class Section < MachOStructure
70
- # @return [String] the name of the section, including null pad bytes
71
- attr_reader :sectname
72
-
73
- # @return [String] the name of the segment's section, including null pad bytes
74
- attr_reader :segname
75
-
76
- # @return [Fixnum] the memory address of the section
77
- attr_reader :addr
78
-
79
- # @return [Fixnum] the size, in bytes, of the section
80
- attr_reader :size
81
-
82
- # @return [Fixnum] the file offset of the section
83
- attr_reader :offset
84
-
85
- # @return [Fixnum] the section alignment (power of 2) of the section
86
- attr_reader :align
87
-
88
- # @return [Fixnum] the file offset of the section's relocation entries
89
- attr_reader :reloff
90
-
91
- # @return [Fixnum] the number of relocation entries
92
- attr_reader :nreloc
93
-
94
- # @return [Fixnum] flags for type and addrributes of the section
95
- attr_reader :flags
96
-
97
- # @return [void] reserved (for offset or index)
98
- attr_reader :reserved1
99
-
100
- # @return [void] reserved (for count or sizeof)
101
- attr_reader :reserved2
102
-
103
- FORMAT = "a16a16VVVVVVVVV"
104
- SIZEOF = 68
105
-
106
- # @api private
107
- def initialize(sectname, segname, addr, size, offset, align, reloff,
108
- nreloc, flags, reserved1, reserved2)
109
- @sectname = sectname
110
- @segname = segname
111
- @addr = addr
112
- @size = size
113
- @offset = offset
114
- @align = align
115
- @reloff = reloff
116
- @nreloc = nreloc
117
- @flags = flags
118
- @reserved1 = reserved1
119
- @reserved2 = reserved2
120
- end
121
-
122
- # @return [String] the section's name, with any trailing NULL characters removed
123
- def section_name
124
- @sectname.delete("\x00")
125
- end
126
-
127
- # @return [String] the parent segment's name, with any trailing NULL characters removed
128
- def segment_name
129
- @segname.delete("\x00")
130
- end
131
-
132
- # @example
133
- # puts "this section is regular" if sect.flag?(:S_REGULAR)
134
- # @param flag [Symbol] a section flag symbol
135
- # @return [Boolean] true if `flag` is present in the section's flag field
136
- def flag?(flag)
137
- flag = SECTION_FLAGS[flag]
138
- return false if flag.nil?
139
- flags & flag == flag
140
- end
141
- end
142
-
143
- # Represents a section of a segment for 64-bit architectures.
144
- class Section64 < Section
145
- # @return [void] reserved
146
- attr_reader :reserved3
147
-
148
- FORMAT = "a16a16QQVVVVVVVV"
149
- SIZEOF = 80
150
-
151
- # @api private
152
- def initialize(sectname, segname, addr, size, offset, align, reloff,
153
- nreloc, flags, reserved1, reserved2, reserved3)
154
- super(sectname, segname, addr, size, offset, align, reloff,
155
- nreloc, flags, reserved1, reserved2)
156
- @reserved3 = reserved3
157
- end
158
- end
2
+ # type mask
3
+ SECTION_TYPE = 0x000000ff
4
+
5
+ # attributes mask
6
+ SECTION_ATTRIBUTES = 0xffffff00
7
+
8
+ # user settable attributes mask
9
+ SECTION_ATTRIBUTES_USR = 0xff000000
10
+
11
+ # system settable attributes mask
12
+ SECTION_ATTRIBUTES_SYS = 0x00ffff00
13
+
14
+ # association of section flag symbols to values
15
+ # @api private
16
+ SECTION_FLAGS = {
17
+ :S_REGULAR => 0x0,
18
+ :S_ZEROFILL => 0x1,
19
+ :S_CSTRING_LITERALS => 0x2,
20
+ :S_4BYTE_LITERALS => 0x3,
21
+ :S_8BYTE_LITERALS => 0x4,
22
+ :S_LITERAL_POINTERS => 0x5,
23
+ :S_NON_LAZY_SYMBOL_POINTERS => 0x6,
24
+ :S_LAZY_SYMBOL_POINTERS => 0x7,
25
+ :S_SYMBOL_STUBS => 0x8,
26
+ :S_MOD_INIT_FUNC_POINTERS => 0x9,
27
+ :S_MOD_TERM_FUNC_POINTERS => 0xa,
28
+ :S_COALESCED => 0xb,
29
+ :S_GB_ZEROFILE => 0xc,
30
+ :S_INTERPOSING => 0xd,
31
+ :S_16BYTE_LITERALS => 0xe,
32
+ :S_DTRACE_DOF => 0xf,
33
+ :S_LAZY_DYLIB_SYMBOL_POINTERS => 0x10,
34
+ :S_THREAD_LOCAL_REGULAR => 0x11,
35
+ :S_THREAD_LOCAL_ZEROFILL => 0x12,
36
+ :S_THREAD_LOCAL_VARIABLES => 0x13,
37
+ :S_THREAD_LOCAL_VARIABLE_POINTERS => 0x14,
38
+ :S_THREAD_LOCAL_INIT_FUNCTION_POINTERS => 0x15,
39
+ :S_ATTR_PURE_INSTRUCTIONS => 0x80000000,
40
+ :S_ATTR_NO_TOC => 0x40000000,
41
+ :S_ATTR_STRIP_STATIC_SYMS => 0x20000000,
42
+ :S_ATTR_NO_DEAD_STRIP => 0x10000000,
43
+ :S_ATTR_LIVE_SUPPORT => 0x08000000,
44
+ :S_ATTR_SELF_MODIFYING_CODE => 0x04000000,
45
+ :S_ATTR_DEBUG => 0x02000000,
46
+ :S_ATTR_SOME_INSTRUCTIONS => 0x00000400,
47
+ :S_ATTR_EXT_RELOC => 0x00000200,
48
+ :S_ATTR_LOC_RELOC => 0x00000100
49
+ }.freeze
50
+
51
+ # association of section name symbols to names
52
+ # @api private
53
+ SECTION_NAMES = {
54
+ :SECT_TEXT => "__text",
55
+ :SECT_FVMLIB_INIT0 => "__fvmlib_init0",
56
+ :SECT_FVMLIB_INIT1 => "__fvmlib_init1",
57
+ :SECT_DATA => "__data",
58
+ :SECT_BSS => "__bss",
59
+ :SECT_COMMON => "__common",
60
+ :SECT_OBJC_SYMBOLS => "__symbol_table",
61
+ :SECT_OBJC_MODULES => "__module_info",
62
+ :SECT_OBJC_STRINGS => "__selector_strs",
63
+ :SECT_OBJC_REFS => "__selector_refs",
64
+ :SECT_ICON_HEADER => "__header",
65
+ :SECT_ICON_TIFF => "__tiff"
66
+ }.freeze
67
+
68
+ # Represents a section of a segment for 32-bit architectures.
69
+ class Section < MachOStructure
70
+ # @return [String] the name of the section, including null pad bytes
71
+ attr_reader :sectname
72
+
73
+ # @return [String] the name of the segment's section, including null pad bytes
74
+ attr_reader :segname
75
+
76
+ # @return [Fixnum] the memory address of the section
77
+ attr_reader :addr
78
+
79
+ # @return [Fixnum] the size, in bytes, of the section
80
+ attr_reader :size
81
+
82
+ # @return [Fixnum] the file offset of the section
83
+ attr_reader :offset
84
+
85
+ # @return [Fixnum] the section alignment (power of 2) of the section
86
+ attr_reader :align
87
+
88
+ # @return [Fixnum] the file offset of the section's relocation entries
89
+ attr_reader :reloff
90
+
91
+ # @return [Fixnum] the number of relocation entries
92
+ attr_reader :nreloc
93
+
94
+ # @return [Fixnum] flags for type and addrributes of the section
95
+ attr_reader :flags
96
+
97
+ # @return [void] reserved (for offset or index)
98
+ attr_reader :reserved1
99
+
100
+ # @return [void] reserved (for count or sizeof)
101
+ attr_reader :reserved2
102
+
103
+ FORMAT = "a16a16L=9"
104
+ SIZEOF = 68
105
+
106
+ # @api private
107
+ def initialize(sectname, segname, addr, size, offset, align, reloff,
108
+ nreloc, flags, reserved1, reserved2)
109
+ @sectname = sectname
110
+ @segname = segname
111
+ @addr = addr
112
+ @size = size
113
+ @offset = offset
114
+ @align = align
115
+ @reloff = reloff
116
+ @nreloc = nreloc
117
+ @flags = flags
118
+ @reserved1 = reserved1
119
+ @reserved2 = reserved2
120
+ end
121
+
122
+ # @return [String] the section's name, with any trailing NULL characters removed
123
+ def section_name
124
+ @sectname.delete("\x00")
125
+ end
126
+
127
+ # @return [String] the parent segment's name, with any trailing NULL characters removed
128
+ def segment_name
129
+ @segname.delete("\x00")
130
+ end
131
+
132
+ # @example
133
+ # puts "this section is regular" if sect.flag?(:S_REGULAR)
134
+ # @param flag [Symbol] a section flag symbol
135
+ # @return [Boolean] true if `flag` is present in the section's flag field
136
+ def flag?(flag)
137
+ flag = SECTION_FLAGS[flag]
138
+ return false if flag.nil?
139
+ flags & flag == flag
140
+ end
141
+ end
142
+
143
+ # Represents a section of a segment for 64-bit architectures.
144
+ class Section64 < Section
145
+ # @return [void] reserved
146
+ attr_reader :reserved3
147
+
148
+ FORMAT = "a16a16Q=2L=8"
149
+ SIZEOF = 80
150
+
151
+ # @api private
152
+ def initialize(sectname, segname, addr, size, offset, align, reloff,
153
+ nreloc, flags, reserved1, reserved2, reserved3)
154
+ super(sectname, segname, addr, size, offset, align, reloff,
155
+ nreloc, flags, reserved1, reserved2)
156
+ @reserved3 = reserved3
157
+ end
158
+ end
159
159
  end
@@ -1,22 +1,38 @@
1
1
  module MachO
2
- # A general purpose pseudo-structure.
3
- # @abstract
4
- class MachOStructure
5
- # The format of the data structure, in String#unpack format.
6
- FORMAT = ""
2
+ # A general purpose pseudo-structure.
3
+ # @abstract
4
+ class MachOStructure
5
+ # The String#unpack format of the data structure.
6
+ FORMAT = ""
7
7
 
8
- # The size of the data structure, in bytes.
9
- SIZEOF = 0
8
+ # The size of the data structure, in bytes.
9
+ SIZEOF = 0
10
10
 
11
- # @return [Fixnum] the size, in bytes, of the represented structure.
12
- def self.bytesize
13
- self::SIZEOF
14
- end
11
+ # @return [Fixnum] the size, in bytes, of the represented structure.
12
+ def self.bytesize
13
+ self::SIZEOF
14
+ end
15
15
 
16
- # @return [MachO::MachOStructure] a new MachOStructure initialized with `bin`
17
- # @api private
18
- def self.new_from_bin(bin)
19
- self.new(*bin.unpack(self::FORMAT))
20
- end
21
- end
16
+ # @param endianness [Symbol] either :big or :little
17
+ # @param bin [String] the string to be unpacked into the new structure
18
+ # @return [MachO::MachOStructure] a new MachOStructure initialized with `bin`
19
+ # @api private
20
+ 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
27
+
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)
36
+ end
37
+ end
22
38
  end
@@ -1,65 +1,65 @@
1
1
  module MachO
2
- # A collection of convenient methods for common operations on Mach-O and Fat binaries.
3
- module Tools
4
- # @param filename [String] the Mach-O or Fat binary being read
5
- # @return [Array<String>] an array of all dylibs linked to the binary
6
- def self.dylibs(filename)
7
- file = MachO.open(filename)
2
+ # A collection of convenient methods for common operations on Mach-O and Fat binaries.
3
+ module Tools
4
+ # @param filename [String] the Mach-O or Fat binary being read
5
+ # @return [Array<String>] an array of all dylibs linked to the binary
6
+ def self.dylibs(filename)
7
+ file = MachO.open(filename)
8
8
 
9
- file.linked_dylibs
10
- end
9
+ file.linked_dylibs
10
+ end
11
11
 
12
- # Changes the dylib ID of a Mach-O or Fat binary, overwriting the source file.
13
- # @param filename [String] the Mach-O or Fat binary being modified
14
- # @param new_id [String] the new dylib ID for the binary
15
- # @return [void]
16
- # @todo unstub for fat files
17
- def self.change_dylib_id(filename, new_id)
18
- file = MachO.open(filename)
12
+ # Changes the dylib ID of a Mach-O or Fat binary, overwriting the source file.
13
+ # @param filename [String] the Mach-O or Fat binary being modified
14
+ # @param new_id [String] the new dylib ID for the binary
15
+ # @return [void]
16
+ # @todo unstub for fat files
17
+ def self.change_dylib_id(filename, new_id)
18
+ file = MachO.open(filename)
19
19
 
20
- file.dylib_id = new_id
21
- file.write!
22
- end
20
+ file.dylib_id = new_id
21
+ file.write!
22
+ end
23
23
 
24
- # Changes a shared library install name in a Mach-O or Fat binary, overwriting the source file.
25
- # @param filename [String] the Mach-O or Fat binary being modified
26
- # @param old_name [String] the old shared library name
27
- # @param new_name [String] the new shared library name
28
- # @return [void]
29
- # @todo unstub for fat files
30
- def self.change_install_name(filename, old_name, new_name)
31
- file = MachO.open(filename)
24
+ # Changes a shared library install name in a Mach-O or Fat binary, overwriting the source file.
25
+ # @param filename [String] the Mach-O or Fat binary being modified
26
+ # @param old_name [String] the old shared library name
27
+ # @param new_name [String] the new shared library name
28
+ # @return [void]
29
+ # @todo unstub for fat files
30
+ def self.change_install_name(filename, old_name, new_name)
31
+ file = MachO.open(filename)
32
32
 
33
- file.change_install_name(old_name, new_name)
34
- file.write!
35
- end
33
+ file.change_install_name(old_name, new_name)
34
+ file.write!
35
+ end
36
36
 
37
- # Changes a runtime path in a Mach-O or Fat binary, overwriting the source file.
38
- # @param filename [String] the Mach-O or Fat binary being modified
39
- # @param old_path [String] the old runtime path
40
- # @param new_path [String] the new runtime path
41
- # @return [void]
42
- # @todo unstub
43
- def self.change_rpath(filename, old_path, new_path)
44
- raise "stub"
45
- end
37
+ # Changes a runtime path in a Mach-O or Fat binary, overwriting the source file.
38
+ # @param filename [String] the Mach-O or Fat binary being modified
39
+ # @param old_path [String] the old runtime path
40
+ # @param new_path [String] the new runtime path
41
+ # @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")
45
+ end
46
46
 
47
- # Add a runtime path to a Mach-O or Fat binary, overwriting the source file.
48
- # @param filename [String] the Mach-O or Fat binary being modified
49
- # @param new_path [String] the new runtime path
50
- # @return [void]
51
- # @todo unstub
52
- def self.add_rpath(filename, new_path)
53
- raise "stub"
54
- end
47
+ # Add a runtime path to a Mach-O or Fat binary, overwriting the source file.
48
+ # @param filename [String] the Mach-O or Fat binary being modified
49
+ # @param new_path [String] the new runtime path
50
+ # @return [void]
51
+ # @todo unstub
52
+ def self.add_rpath(filename, new_path)
53
+ raise UnimplementedError.new("adding rpaths to a Mach-O")
54
+ end
55
55
 
56
- # Delete a runtime path from a Mach-O or Fat binary, overwriting the source file.
57
- # @param filename [String] the Mach-O or Fat binary being modified
58
- # @param old_path [String] the old runtime path
59
- # @return [void]
60
- # @todo unstub
61
- def self.delete_rpath(filename, old_path)
62
- raise "stub"
63
- end
64
- end
56
+ # Delete a runtime path from a Mach-O or Fat binary, overwriting the source file.
57
+ # @param filename [String] the Mach-O or Fat binary being modified
58
+ # @param old_path [String] the old runtime path
59
+ # @return [void]
60
+ # @todo unstub
61
+ def self.delete_rpath(filename, old_path)
62
+ raise UnimplementedError.new("removing rpaths from a Mach-O")
63
+ end
64
+ end
65
65
  end