Skip to content

Commit d01835a

Browse files
committed
fat_file: Add delegation to header/canonical Mach-O where possible.
The "canonical" Mach-O for a fat file is just the first Mach-O, used to obtain attributes that should be constant across all slices. macho_file: Add delegation to header, fix YARD errors. load_commands: Fix typo.
1 parent 60b9c55 commit d01835a

File tree

3 files changed

+59
-91
lines changed

3 files changed

+59
-91
lines changed

lib/macho/fat_file.rb

Lines changed: 43 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1+
require "forwardable"
2+
13
module MachO
24
# Represents a "Fat" file, which contains a header, a listing of available
35
# architectures, and one or more Mach-O binaries.
46
# @see https://en.wikipedia.org/wiki/Mach-O#Multi-architecture_binaries
57
# @see MachO::MachOFile
68
class FatFile
9+
extend Forwardable
10+
711
# @return [String] the filename loaded from, or nil if loaded from a binary string
812
attr_accessor :filename
913

@@ -74,72 +78,43 @@ def serialize
7478
@raw_data
7579
end
7680

77-
# @return [Boolean] true if the file is of type `MH_OBJECT`, false otherwise
78-
def object?
79-
machos.first.object?
80-
end
81-
82-
# @return [Boolean] true if the file is of type `MH_EXECUTE`, false otherwise
83-
def executable?
84-
machos.first.executable?
85-
end
86-
87-
# @return [Boolean] true if the file is of type `MH_FVMLIB`, false otherwise
88-
def fvmlib?
89-
machos.first.fvmlib?
90-
end
91-
92-
# @return [Boolean] true if the file is of type `MH_CORE`, false otherwise
93-
def core?
94-
machos.first.core?
95-
end
96-
97-
# @return [Boolean] true if the file is of type `MH_PRELOAD`, false otherwise
98-
def preload?
99-
machos.first.preload?
100-
end
101-
102-
# @return [Boolean] true if the file is of type `MH_DYLIB`, false otherwise
103-
def dylib?
104-
machos.first.dylib?
105-
end
106-
107-
# @return [Boolean] true if the file is of type `MH_DYLINKER`, false otherwise
108-
def dylinker?
109-
machos.first.dylinker?
110-
end
111-
112-
# @return [Boolean] true if the file is of type `MH_BUNDLE`, false otherwise
113-
def bundle?
114-
machos.first.bundle?
115-
end
116-
117-
# @return [Boolean] true if the file is of type `MH_DSYM`, false otherwise
118-
def dsym?
119-
machos.first.dsym?
120-
end
121-
122-
# @return [Boolean] true if the file is of type `MH_KEXT_BUNDLE`, false otherwise
123-
def kext?
124-
machos.first.kext?
125-
end
126-
127-
# @return [Fixnum] the file's magic number
128-
def magic
129-
header.magic
130-
end
81+
# @!method object?
82+
# @return (see MachO::MachOFile#object?)
83+
# @!method executable?
84+
# @return (see MachO::MachOFile#executable?)
85+
# @!method fvmlib?
86+
# @return (see MachO::MachOFile#fvmlib?)
87+
# @!method core?
88+
# @return (see MachO::MachOFile#core?)
89+
# @!method preload?
90+
# @return (see MachO::MachOFile#preload?)
91+
# @!method dylib?
92+
# @return (see MachO::MachOFile#dylib?)
93+
# @!method dylinker?
94+
# @return (see MachO::MachOFile#dylinker?)
95+
# @!method bundle?
96+
# @return (see MachO::MachOFile#bundle?)
97+
# @!method dsym?
98+
# @return (see MachO::MachOFile#dsym?)
99+
# @!method kext?
100+
# @return (see MachO::MachOFile#kext?)
101+
# @!method filetype
102+
# @return (see MachO::MachOFile#filetype)
103+
# @!method dylib_id
104+
# @return (see MachO::MachOFile#dylib_id)
105+
def_delegators :canonical_macho, :object?, :executable?, :fvmlib?,
106+
:core?, :preload?, :dylib?, :dylinker?, :bundle?,
107+
:dsym?, :kext?, :filetype, :dylib_id
108+
109+
# @!method magic
110+
# @return (see MachO::Headers::FatHeader#magic)
111+
def_delegators :header, :magic
131112

132113
# @return [String] a string representation of the file's magic number
133114
def magic_string
134115
Headers::MH_MAGICS[magic]
135116
end
136117

137-
# The file's type. Assumed to be the same for every Mach-O within.
138-
# @return [Symbol] the filetype
139-
def filetype
140-
machos.first.filetype
141-
end
142-
143118
# Populate the instance's fields with the raw Fat Mach-O data.
144119
# @return [void]
145120
# @note This method is public, but should (almost) never need to be called.
@@ -155,15 +130,6 @@ def dylib_load_commands
155130
machos.map(&:dylib_load_commands).flatten
156131
end
157132

158-
# The file's dylib ID. If the file is not a dylib, returns `nil`.
159-
# @example
160-
# file.dylib_id # => 'libBar.dylib'
161-
# @return [String, nil] the file's dylib ID
162-
# @see MachO::MachOFile#linked_dylibs
163-
def dylib_id
164-
machos.first.dylib_id
165-
end
166-
167133
# Changes the file's dylib ID to `new_id`. If the file is not a dylib, does nothing.
168134
# @example
169135
# file.change_dylib_id('libFoo.dylib')
@@ -395,5 +361,13 @@ def each_macho(options = {})
395361
# Non-strict mode: Raise first error if *all* Mach-O slices failed.
396362
raise errors.first if errors.size == machos.size
397363
end
364+
365+
# Return a single-arch Mach-O that represents this fat Mach-O for purposes
366+
# of delegation.
367+
# @return [MachO::MachOFile] the Mach-O file
368+
# @api private
369+
def canonical_macho
370+
machos.first
371+
end
398372
end
399373
end

lib/macho/load_commands.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ module MachO
22
# Classes and constants for parsing load commands in Mach-O binaries.
33
module LoadCommands
44
# load commands added after OS X 10.1 need to be bitwise ORed with
5-
# LC_REQ_DYLD to be recognized by the dynamic linder (dyld)
5+
# LC_REQ_DYLD to be recognized by the dynamic linker (dyld)
66
# @api private
77
LC_REQ_DYLD = 0x80000000
88

lib/macho/macho_file.rb

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1+
require "forwardable"
2+
13
module MachO
24
# Represents a Mach-O file, which contains a header and load commands
35
# as well as binary executable instructions. Mach-O binaries are
46
# architecture specific.
57
# @see https://en.wikipedia.org/wiki/Mach-O
68
# @see MachO::FatFile
79
class MachOFile
10+
extend Forwardable
11+
812
# @return [String] the filename loaded from, or nil if loaded from a binary string
913
attr_accessor :filename
1014

@@ -120,11 +124,6 @@ def kext?
120124
header.filetype == Headers::MH_KEXT_BUNDLE
121125
end
122126

123-
# @return [Fixnum] the file's magic number
124-
def magic
125-
header.magic
126-
end
127-
128127
# @return [String] a string representation of the file's magic number
129128
def magic_string
130129
Headers::MH_MAGICS[magic]
@@ -145,20 +144,15 @@ def cpusubtype
145144
Headers::CPU_SUBTYPES[header.cputype][header.cpusubtype]
146145
end
147146

148-
# @return [Fixnum] the number of load commands in the Mach-O's header
149-
def ncmds
150-
header.ncmds
151-
end
152-
153-
# @return [Fixnum] the size of all load commands, in bytes
154-
def sizeofcmds
155-
header.sizeofcmds
156-
end
157-
158-
# @return [Fixnum] execution flags set by the linker
159-
def flags
160-
header.flags
161-
end
147+
# @!method magic
148+
# @return (see MachO::Headers::MachHeader#magic)
149+
# @!method ncmds
150+
# @return (see MachO::Headers::MachHeader#ncmds)
151+
# @!method sizeofcmds
152+
# @return (see MachO::Headers::MachHeader#sizeofcmds)
153+
# @!method flags
154+
# @return (see MachO::Headers::MachHeader#flags)
155+
def_delegators :header, :magic, :ncmds, :sizeofcmds, :flags
162156

163157
# All load commands of a given name.
164158
# @example
@@ -211,7 +205,7 @@ def insert_command(offset, lc, options = {})
211205
# @param new_lc [MachO::LoadCommands::LoadCommand] the load command being added
212206
# @return [void]
213207
# @raise [MachO::HeaderPadError] if the new command exceeds the header pad buffer
214-
# @see {#insert_command}
208+
# @see #insert_command
215209
# @note This is public, but methods like {#dylib_id=} should be preferred.
216210
def replace_command(old_lc, new_lc)
217211
context = LoadCommands::LoadCommand::SerializationContext.context_for(self)
@@ -231,7 +225,7 @@ def replace_command(old_lc, new_lc)
231225
# @option options [Boolean] :repopulate (true) whether or not to repopulate
232226
# the instance fields
233227
# @return [void]
234-
# @see {#insert_command}
228+
# @see #insert_command
235229
# @note This is public, but methods like {#add_rpath} should be preferred.
236230
# Setting `repopulate` to false **will leave the instance in an
237231
# inconsistent state** unless {#populate_fields} is called **immediately**

0 commit comments

Comments
 (0)