ruby-macho 0.2.6 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -11,11 +11,11 @@ module MachO
11
11
  # @return [Symbol] the endianness of the file, :big or :little
12
12
  attr_reader :endianness
13
13
 
14
- # @return [MachO::MachHeader] if the Mach-O is 32-bit
15
- # @return [MachO::MachHeader64] if the Mach-O is 64-bit
14
+ # @return [MachO::Headers::MachHeader] if the Mach-O is 32-bit
15
+ # @return [MachO::Headers::MachHeader64] if the Mach-O is 64-bit
16
16
  attr_reader :header
17
17
 
18
- # @return [Array<MachO::LoadCommand>] an array of the file's load commands
18
+ # @return [Array<MachO::LoadCommands::LoadCommand>] an array of the file's load commands
19
19
  # @note load commands are provided in order of ascending offset.
20
20
  attr_reader :load_commands
21
21
 
@@ -72,52 +72,52 @@ module MachO
72
72
 
73
73
  # @return [Boolean] true if the file is of type `MH_OBJECT`, false otherwise
74
74
  def object?
75
- header.filetype == MH_OBJECT
75
+ header.filetype == Headers::MH_OBJECT
76
76
  end
77
77
 
78
78
  # @return [Boolean] true if the file is of type `MH_EXECUTE`, false otherwise
79
79
  def executable?
80
- header.filetype == MH_EXECUTE
80
+ header.filetype == Headers::MH_EXECUTE
81
81
  end
82
82
 
83
83
  # @return [Boolean] true if the file is of type `MH_FVMLIB`, false otherwise
84
84
  def fvmlib?
85
- header.filetype == MH_FVMLIB
85
+ header.filetype == Headers::MH_FVMLIB
86
86
  end
87
87
 
88
88
  # @return [Boolean] true if the file is of type `MH_CORE`, false otherwise
89
89
  def core?
90
- header.filetype == MH_CORE
90
+ header.filetype == Headers::MH_CORE
91
91
  end
92
92
 
93
93
  # @return [Boolean] true if the file is of type `MH_PRELOAD`, false otherwise
94
94
  def preload?
95
- header.filetype == MH_PRELOAD
95
+ header.filetype == Headers::MH_PRELOAD
96
96
  end
97
97
 
98
98
  # @return [Boolean] true if the file is of type `MH_DYLIB`, false otherwise
99
99
  def dylib?
100
- header.filetype == MH_DYLIB
100
+ header.filetype == Headers::MH_DYLIB
101
101
  end
102
102
 
103
103
  # @return [Boolean] true if the file is of type `MH_DYLINKER`, false otherwise
104
104
  def dylinker?
105
- header.filetype == MH_DYLINKER
105
+ header.filetype == Headers::MH_DYLINKER
106
106
  end
107
107
 
108
108
  # @return [Boolean] true if the file is of type `MH_BUNDLE`, false otherwise
109
109
  def bundle?
110
- header.filetype == MH_BUNDLE
110
+ header.filetype == Headers::MH_BUNDLE
111
111
  end
112
112
 
113
113
  # @return [Boolean] true if the file is of type `MH_DSYM`, false otherwise
114
114
  def dsym?
115
- header.filetype == MH_DSYM
115
+ header.filetype == Headers::MH_DSYM
116
116
  end
117
117
 
118
118
  # @return [Boolean] true if the file is of type `MH_KEXT_BUNDLE`, false otherwise
119
119
  def kext?
120
- header.filetype == MH_KEXT_BUNDLE
120
+ header.filetype == Headers::MH_KEXT_BUNDLE
121
121
  end
122
122
 
123
123
  # @return [Fixnum] the file's magic number
@@ -127,22 +127,22 @@ module MachO
127
127
 
128
128
  # @return [String] a string representation of the file's magic number
129
129
  def magic_string
130
- MH_MAGICS[magic]
130
+ Headers::MH_MAGICS[magic]
131
131
  end
132
132
 
133
133
  # @return [Symbol] a string representation of the Mach-O's filetype
134
134
  def filetype
135
- MH_FILETYPES[header.filetype]
135
+ Headers::MH_FILETYPES[header.filetype]
136
136
  end
137
137
 
138
138
  # @return [Symbol] a symbol representation of the Mach-O's CPU type
139
139
  def cputype
140
- CPU_TYPES[header.cputype]
140
+ Headers::CPU_TYPES[header.cputype]
141
141
  end
142
142
 
143
143
  # @return [Symbol] a symbol representation of the Mach-O's CPU subtype
144
144
  def cpusubtype
145
- CPU_SUBTYPES[header.cputype][header.cpusubtype]
145
+ Headers::CPU_SUBTYPES[header.cputype][header.cpusubtype]
146
146
  end
147
147
 
148
148
  # @return [Fixnum] the number of load commands in the Mach-O's header
@@ -165,7 +165,7 @@ module MachO
165
165
  # file.command("LC_LOAD_DYLIB")
166
166
  # file[:LC_LOAD_DYLIB]
167
167
  # @param [String, Symbol] name the load command ID
168
- # @return [Array<MachO::LoadCommand>] an array of LoadCommands corresponding to `name`
168
+ # @return [Array<MachO::LoadCommands::LoadCommand>] an array of load commands corresponding to `name`
169
169
  def command(name)
170
170
  load_commands.select { |lc| lc.type == name.to_sym }
171
171
  end
@@ -174,7 +174,7 @@ module MachO
174
174
 
175
175
  # Inserts a load command at the given offset.
176
176
  # @param offset [Fixnum] the offset to insert at
177
- # @param lc [MachO::LoadCommand] the load command to insert
177
+ # @param lc [MachO::LoadCommands::LoadCommand] the load command to insert
178
178
  # @param options [Hash]
179
179
  # @option options [Boolean] :repopulate (true) whether or not to repopulate
180
180
  # the instance fields
@@ -183,7 +183,7 @@ module MachO
183
183
  # @note Calling this method with an arbitrary offset in the load command
184
184
  # region **will leave the object in an inconsistent state**.
185
185
  def insert_command(offset, lc, options = {})
186
- context = LoadCommand::SerializationContext.context_for(self)
186
+ context = LoadCommands::LoadCommand::SerializationContext.context_for(self)
187
187
  cmd_raw = lc.serialize(context)
188
188
 
189
189
  if offset < header.class.bytesize || offset + cmd_raw.bytesize > low_fileoff
@@ -207,14 +207,14 @@ module MachO
207
207
  end
208
208
 
209
209
  # Replace a load command with another command in the Mach-O, preserving location.
210
- # @param old_lc [MachO::LoadCommand] the load command being replaced
211
- # @param new_lc [MachO::LoadCommand] the load command being added
210
+ # @param old_lc [MachO::LoadCommands::LoadCommand] the load command being replaced
211
+ # @param new_lc [MachO::LoadCommands::LoadCommand] the load command being added
212
212
  # @return [void]
213
213
  # @raise [MachO::HeaderPadError] if the new command exceeds the header pad buffer
214
214
  # @see {#insert_command}
215
215
  # @note This is public, but methods like {#dylib_id=} should be preferred.
216
216
  def replace_command(old_lc, new_lc)
217
- context = LoadCommand::SerializationContext.context_for(self)
217
+ context = LoadCommands::LoadCommand::SerializationContext.context_for(self)
218
218
  cmd_raw = new_lc.serialize(context)
219
219
  new_sizeofcmds = sizeofcmds + cmd_raw.bytesize - old_lc.cmdsize
220
220
  if header.class.bytesize + new_sizeofcmds > low_fileoff
@@ -226,7 +226,7 @@ module MachO
226
226
  end
227
227
 
228
228
  # Appends a new load command to the Mach-O.
229
- # @param lc [MachO::LoadCommand] the load command being added
229
+ # @param lc [MachO::LoadCommands::LoadCommand] the load command being added
230
230
  # @param options [Hash]
231
231
  # @option options [Boolean] :repopulate (true) whether or not to repopulate
232
232
  # the instance fields
@@ -241,7 +241,7 @@ module MachO
241
241
  end
242
242
 
243
243
  # Delete a load command from the Mach-O.
244
- # @param lc [MachO::LoadCommand] the load command being deleted
244
+ # @param lc [MachO::LoadCommands::LoadCommand] the load command being deleted
245
245
  # @param options [Hash]
246
246
  # @option options [Boolean] :repopulate (true) whether or not to repopulate
247
247
  # the instance fields
@@ -275,14 +275,14 @@ module MachO
275
275
  end
276
276
 
277
277
  # All load commands responsible for loading dylibs.
278
- # @return [Array<MachO::DylibCommand>] an array of DylibCommands
278
+ # @return [Array<MachO::LoadCommands::DylibCommand>] an array of DylibCommands
279
279
  def dylib_load_commands
280
- load_commands.select { |lc| DYLIB_LOAD_COMMANDS.include?(lc.type) }
280
+ load_commands.select { |lc| LoadCommands::DYLIB_LOAD_COMMANDS.include?(lc.type) }
281
281
  end
282
282
 
283
283
  # All segment load commands in the Mach-O.
284
- # @return [Array<MachO::SegmentCommand>] if the Mach-O is 32-bit
285
- # @return [Array<MachO::SegmentCommand64>] if the Mach-O is 64-bit
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
286
286
  def segments
287
287
  if magic32?
288
288
  command(:LC_SEGMENT)
@@ -319,10 +319,10 @@ module MachO
319
319
  old_lc = command(:LC_ID_DYLIB).first
320
320
  raise DylibIdMissingError unless old_lc
321
321
 
322
- new_lc = LoadCommand.create(:LC_ID_DYLIB, new_id,
323
- old_lc.timestamp,
324
- old_lc.current_version,
325
- old_lc.compatibility_version)
322
+ new_lc = LoadCommands::LoadCommand.create(:LC_ID_DYLIB, new_id,
323
+ old_lc.timestamp,
324
+ old_lc.current_version,
325
+ old_lc.compatibility_version)
326
326
 
327
327
  replace_command(old_lc, new_lc)
328
328
  end
@@ -353,10 +353,10 @@ module MachO
353
353
  old_lc = dylib_load_commands.find { |d| d.name.to_s == old_name }
354
354
  raise DylibUnknownError, old_name if old_lc.nil?
355
355
 
356
- new_lc = LoadCommand.create(old_lc.type, new_name,
357
- old_lc.timestamp,
358
- old_lc.current_version,
359
- old_lc.compatibility_version)
356
+ new_lc = LoadCommands::LoadCommand.create(old_lc.type, new_name,
357
+ old_lc.timestamp,
358
+ old_lc.current_version,
359
+ old_lc.compatibility_version)
360
360
 
361
361
  replace_command(old_lc, new_lc)
362
362
  end
@@ -385,7 +385,7 @@ module MachO
385
385
  raise RpathUnknownError, old_path if old_lc.nil?
386
386
  raise RpathExistsError, new_path if rpaths.include?(new_path)
387
387
 
388
- new_lc = LoadCommand.create(:LC_RPATH, new_path)
388
+ new_lc = LoadCommands::LoadCommand.create(:LC_RPATH, new_path)
389
389
 
390
390
  delete_rpath(old_path)
391
391
  insert_command(old_lc.view.offset, new_lc)
@@ -405,7 +405,7 @@ module MachO
405
405
  def add_rpath(path, _options = {})
406
406
  raise RpathExistsError, path if rpaths.include?(path)
407
407
 
408
- rpath_cmd = LoadCommand.create(:LC_RPATH, path)
408
+ rpath_cmd = LoadCommands::LoadCommand.create(:LC_RPATH, path)
409
409
  add_command(rpath_cmd)
410
410
  end
411
411
 
@@ -432,10 +432,10 @@ module MachO
432
432
  end
433
433
 
434
434
  # All sections of the segment `segment`.
435
- # @param segment [MachO::SegmentCommand, MachO::SegmentCommand64] the segment being inspected
436
- # @return [Array<MachO::Section>] if the Mach-O is 32-bit
437
- # @return [Array<MachO::Section64>] if the Mach-O is 64-bit
438
- # @deprecated use {MachO::SegmentCommand#sections} instead
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
439
  def sections(segment)
440
440
  segment.sections
441
441
  end
@@ -462,8 +462,8 @@ module MachO
462
462
  private
463
463
 
464
464
  # The file's Mach-O header structure.
465
- # @return [MachO::MachHeader] if the Mach-O is 32-bit
466
- # @return [MachO::MachHeader64] if the Mach-O is 64-bit
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
467
  # @raise [MachO::TruncatedFileError] if the file is too small to have a valid header
468
468
  # @api private
469
469
  def populate_mach_header
@@ -471,7 +471,7 @@ module MachO
471
471
  raise TruncatedFileError if @raw_data.size < 28
472
472
 
473
473
  magic = populate_and_check_magic
474
- mh_klass = Utils.magic32?(magic) ? MachHeader : MachHeader64
474
+ mh_klass = Utils.magic32?(magic) ? Headers::MachHeader : Headers::MachHeader64
475
475
  mh = mh_klass.new_from_bin(endianness, @raw_data[0, mh_klass.bytesize])
476
476
 
477
477
  check_cputype(mh.cputype)
@@ -502,7 +502,7 @@ module MachO
502
502
  # @raise [MachO::CPUTypeError] if the CPU type is unknown
503
503
  # @api private
504
504
  def check_cputype(cputype)
505
- raise CPUTypeError, cputype unless CPU_TYPES.key?(cputype)
505
+ raise CPUTypeError, cputype unless Headers::CPU_TYPES.key?(cputype)
506
506
  end
507
507
 
508
508
  # Check the file's CPU type/subtype pair.
@@ -511,7 +511,7 @@ module MachO
511
511
  # @api private
512
512
  def check_cpusubtype(cputype, cpusubtype)
513
513
  # Only check sub-type w/o capability bits (see `populate_mach_header`).
514
- raise CPUSubtypeError.new(cputype, cpusubtype) unless CPU_SUBTYPES[cputype].key?(cpusubtype)
514
+ raise CPUSubtypeError.new(cputype, cpusubtype) unless Headers::CPU_SUBTYPES[cputype].key?(cpusubtype)
515
515
  end
516
516
 
517
517
  # Check the file's type.
@@ -519,11 +519,11 @@ module MachO
519
519
  # @raise [MachO::FiletypeError] if the file type is unknown
520
520
  # @api private
521
521
  def check_filetype(filetype)
522
- raise FiletypeError, filetype unless MH_FILETYPES.key?(filetype)
522
+ raise FiletypeError, filetype unless Headers::MH_FILETYPES.key?(filetype)
523
523
  end
524
524
 
525
525
  # All load commands in the file.
526
- # @return [Array<MachO::LoadCommand>] an array of load commands
526
+ # @return [Array<MachO::LoadCommands::LoadCommand>] an array of load commands
527
527
  # @raise [MachO::LoadCommandError] if an unknown load command is encountered
528
528
  # @api private
529
529
  def populate_load_commands
@@ -533,13 +533,13 @@ module MachO
533
533
  header.ncmds.times do
534
534
  fmt = Utils.specialize_format("L=", endianness)
535
535
  cmd = @raw_data.slice(offset, 4).unpack(fmt).first
536
- cmd_sym = LOAD_COMMANDS[cmd]
536
+ cmd_sym = LoadCommands::LOAD_COMMANDS[cmd]
537
537
 
538
538
  raise LoadCommandError, cmd if cmd_sym.nil?
539
539
 
540
540
  # why do I do this? i don't like declaring constants below
541
541
  # classes, and i need them to resolve...
542
- klass = MachO.const_get LC_STRUCTURES[cmd_sym]
542
+ klass = MachO::LoadCommands.const_get LoadCommands::LC_STRUCTURES[cmd_sym]
543
543
  view = MachOView.new(@raw_data, endianness, offset)
544
544
  command = klass.new_from_bin(view)
545
545
 
@@ -1,170 +1,173 @@
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
- }.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 attributes 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
- # @see MachOStructure::FORMAT
104
- FORMAT = "a16a16L=9".freeze
105
-
106
- # @see MachOStructure::SIZEOF
107
- SIZEOF = 68
2
+ # Classes and constants for parsing sections in Mach-O binaries.
3
+ module Sections
4
+ # type mask
5
+ SECTION_TYPE = 0x000000ff
108
6
 
109
- # @api private
110
- def initialize(sectname, segname, addr, size, offset, align, reloff,
111
- nreloc, flags, reserved1, reserved2)
112
- @sectname = sectname
113
- @segname = segname
114
- @addr = addr
115
- @size = size
116
- @offset = offset
117
- @align = align
118
- @reloff = reloff
119
- @nreloc = nreloc
120
- @flags = flags
121
- @reserved1 = reserved1
122
- @reserved2 = reserved2
123
- end
7
+ # attributes mask
8
+ SECTION_ATTRIBUTES = 0xffffff00
124
9
 
125
- # @return [String] the section's name, with any trailing NULL characters removed
126
- def section_name
127
- sectname.delete("\x00")
128
- end
129
-
130
- # @return [String] the parent segment's name, with any trailing NULL characters removed
131
- def segment_name
132
- segname.delete("\x00")
133
- end
10
+ # user settable attributes mask
11
+ SECTION_ATTRIBUTES_USR = 0xff000000
134
12
 
135
- # @return [Boolean] true if the section has no contents (i.e, `size` is 0)
136
- def empty?
137
- size.zero?
138
- end
13
+ # system settable attributes mask
14
+ SECTION_ATTRIBUTES_SYS = 0x00ffff00
139
15
 
140
- # @example
141
- # puts "this section is regular" if sect.flag?(:S_REGULAR)
142
- # @param flag [Symbol] a section flag symbol
143
- # @return [Boolean] true if `flag` is present in the section's flag field
144
- def flag?(flag)
145
- flag = SECTION_FLAGS[flag]
146
- return false if flag.nil?
147
- flags & flag == flag
16
+ # association of section flag symbols to values
17
+ # @api private
18
+ SECTION_FLAGS = {
19
+ :S_REGULAR => 0x0,
20
+ :S_ZEROFILL => 0x1,
21
+ :S_CSTRING_LITERALS => 0x2,
22
+ :S_4BYTE_LITERALS => 0x3,
23
+ :S_8BYTE_LITERALS => 0x4,
24
+ :S_LITERAL_POINTERS => 0x5,
25
+ :S_NON_LAZY_SYMBOL_POINTERS => 0x6,
26
+ :S_LAZY_SYMBOL_POINTERS => 0x7,
27
+ :S_SYMBOL_STUBS => 0x8,
28
+ :S_MOD_INIT_FUNC_POINTERS => 0x9,
29
+ :S_MOD_TERM_FUNC_POINTERS => 0xa,
30
+ :S_COALESCED => 0xb,
31
+ :S_GB_ZEROFILE => 0xc,
32
+ :S_INTERPOSING => 0xd,
33
+ :S_16BYTE_LITERALS => 0xe,
34
+ :S_DTRACE_DOF => 0xf,
35
+ :S_LAZY_DYLIB_SYMBOL_POINTERS => 0x10,
36
+ :S_THREAD_LOCAL_REGULAR => 0x11,
37
+ :S_THREAD_LOCAL_ZEROFILL => 0x12,
38
+ :S_THREAD_LOCAL_VARIABLES => 0x13,
39
+ :S_THREAD_LOCAL_VARIABLE_POINTERS => 0x14,
40
+ :S_THREAD_LOCAL_INIT_FUNCTION_POINTERS => 0x15,
41
+ :S_ATTR_PURE_INSTRUCTIONS => 0x80000000,
42
+ :S_ATTR_NO_TOC => 0x40000000,
43
+ :S_ATTR_STRIP_STATIC_SYMS => 0x20000000,
44
+ :S_ATTR_NO_DEAD_STRIP => 0x10000000,
45
+ :S_ATTR_LIVE_SUPPORT => 0x08000000,
46
+ :S_ATTR_SELF_MODIFYING_CODE => 0x04000000,
47
+ :S_ATTR_DEBUG => 0x02000000,
48
+ :S_ATTR_SOME_INSTRUCTIONS => 0x00000400,
49
+ :S_ATTR_EXT_RELOC => 0x00000200,
50
+ :S_ATTR_LOC_RELOC => 0x00000100,
51
+ }.freeze
52
+
53
+ # association of section name symbols to names
54
+ # @api private
55
+ SECTION_NAMES = {
56
+ :SECT_TEXT => "__text",
57
+ :SECT_FVMLIB_INIT0 => "__fvmlib_init0",
58
+ :SECT_FVMLIB_INIT1 => "__fvmlib_init1",
59
+ :SECT_DATA => "__data",
60
+ :SECT_BSS => "__bss",
61
+ :SECT_COMMON => "__common",
62
+ :SECT_OBJC_SYMBOLS => "__symbol_table",
63
+ :SECT_OBJC_MODULES => "__module_info",
64
+ :SECT_OBJC_STRINGS => "__selector_strs",
65
+ :SECT_OBJC_REFS => "__selector_refs",
66
+ :SECT_ICON_HEADER => "__header",
67
+ :SECT_ICON_TIFF => "__tiff",
68
+ }.freeze
69
+
70
+ # Represents a section of a segment for 32-bit architectures.
71
+ class Section < MachOStructure
72
+ # @return [String] the name of the section, including null pad bytes
73
+ attr_reader :sectname
74
+
75
+ # @return [String] the name of the segment's section, including null pad bytes
76
+ attr_reader :segname
77
+
78
+ # @return [Fixnum] the memory address of the section
79
+ attr_reader :addr
80
+
81
+ # @return [Fixnum] the size, in bytes, of the section
82
+ attr_reader :size
83
+
84
+ # @return [Fixnum] the file offset of the section
85
+ attr_reader :offset
86
+
87
+ # @return [Fixnum] the section alignment (power of 2) of the section
88
+ attr_reader :align
89
+
90
+ # @return [Fixnum] the file offset of the section's relocation entries
91
+ attr_reader :reloff
92
+
93
+ # @return [Fixnum] the number of relocation entries
94
+ attr_reader :nreloc
95
+
96
+ # @return [Fixnum] flags for type and attributes of the section
97
+ attr_reader :flags
98
+
99
+ # @return [void] reserved (for offset or index)
100
+ attr_reader :reserved1
101
+
102
+ # @return [void] reserved (for count or sizeof)
103
+ attr_reader :reserved2
104
+
105
+ # @see MachOStructure::FORMAT
106
+ FORMAT = "a16a16L=9".freeze
107
+
108
+ # @see MachOStructure::SIZEOF
109
+ SIZEOF = 68
110
+
111
+ # @api private
112
+ def initialize(sectname, segname, addr, size, offset, align, reloff,
113
+ nreloc, flags, reserved1, reserved2)
114
+ @sectname = sectname
115
+ @segname = segname
116
+ @addr = addr
117
+ @size = size
118
+ @offset = offset
119
+ @align = align
120
+ @reloff = reloff
121
+ @nreloc = nreloc
122
+ @flags = flags
123
+ @reserved1 = reserved1
124
+ @reserved2 = reserved2
125
+ end
126
+
127
+ # @return [String] the section's name, with any trailing NULL characters removed
128
+ def section_name
129
+ sectname.delete("\x00")
130
+ end
131
+
132
+ # @return [String] the parent segment's name, with any trailing NULL characters removed
133
+ def segment_name
134
+ segname.delete("\x00")
135
+ end
136
+
137
+ # @return [Boolean] true if the section has no contents (i.e, `size` is 0)
138
+ def empty?
139
+ size.zero?
140
+ end
141
+
142
+ # @example
143
+ # puts "this section is regular" if sect.flag?(:S_REGULAR)
144
+ # @param flag [Symbol] a section flag symbol
145
+ # @return [Boolean] true if `flag` is present in the section's flag field
146
+ def flag?(flag)
147
+ flag = SECTION_FLAGS[flag]
148
+ return false if flag.nil?
149
+ flags & flag == flag
150
+ end
148
151
  end
149
- end
150
152
 
151
- # Represents a section of a segment for 64-bit architectures.
152
- class Section64 < Section
153
- # @return [void] reserved
154
- attr_reader :reserved3
153
+ # Represents a section of a segment for 64-bit architectures.
154
+ class Section64 < Section
155
+ # @return [void] reserved
156
+ attr_reader :reserved3
155
157
 
156
- # @see MachOStructure::FORMAT
157
- FORMAT = "a16a16Q=2L=8".freeze
158
+ # @see MachOStructure::FORMAT
159
+ FORMAT = "a16a16Q=2L=8".freeze
158
160
 
159
- # @see MachOStructure::SIZEOF
160
- SIZEOF = 80
161
+ # @see MachOStructure::SIZEOF
162
+ SIZEOF = 80
161
163
 
162
- # @api private
163
- def initialize(sectname, segname, addr, size, offset, align, reloff,
164
- nreloc, flags, reserved1, reserved2, reserved3)
165
- super(sectname, segname, addr, size, offset, align, reloff,
166
- nreloc, flags, reserved1, reserved2)
167
- @reserved3 = reserved3
164
+ # @api private
165
+ def initialize(sectname, segname, addr, size, offset, align, reloff,
166
+ nreloc, flags, reserved1, reserved2, reserved3)
167
+ super(sectname, segname, addr, size, offset, align, reloff,
168
+ nreloc, flags, reserved1, reserved2)
169
+ @reserved3 = reserved3
170
+ end
168
171
  end
169
172
  end
170
173
  end