ruby-macho 0.2.6 → 1.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.
@@ -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