Class: MachO::FatFile
- Inherits:
-
Object
- Object
- MachO::FatFile
- Extended by:
- Forwardable
- Defined in:
- lib/macho/fat_file.rb
Overview
Represents a "Fat" file, which contains a header, a listing of available architectures, and one or more Mach-O binaries.
Instance Attribute Summary collapse
-
#fat_archs ⇒ Array<Headers::FatArch>, Array<Headers::FatArch64] an array of fat architectures
readonly
ArrayHeaders::FatArch, Array<Headers::FatArch64] an array of fat architectures.
-
#filename ⇒ String
The filename loaded from, or nil if loaded from a binary string.
-
#header ⇒ Headers::FatHeader
readonly
The file's header.
-
#machos ⇒ Array<MachOFile>
readonly
An array of Mach-O binaries.
-
#options ⇒ Hash
readonly
Any parser options that the instance was created with.
Class Method Summary collapse
-
.new_from_bin(bin, **opts) ⇒ FatFile
Creates a new FatFile instance from a binary string.
-
.new_from_machos(*machos, fat64: false) ⇒ FatFile
Creates a new FatFile from the given (single-arch) Mach-Os.
Instance Method Summary collapse
-
#add_rpath(path, options = {}) ⇒ void
Add the given runtime path to the file's Mach-Os.
-
#bundle? ⇒ Boolean
Whether or not the file is of type
MH_BUNDLE
. -
#change_dylib_id(new_id, options = {}) ⇒ void
(also: #dylib_id=)
Changes the file's dylib ID to
new_id
. -
#change_install_name(old_name, new_name, options = {}) ⇒ void
(also: #change_dylib)
Changes all dependent shared library install names from
old_name
tonew_name
. -
#change_rpath(old_path, new_path, options = {}) ⇒ void
Change the runtime path
old_path
tonew_path
in the file's Mach-Os. -
#core? ⇒ Boolean
Whether or not the file is of type
MH_CORE
. -
#delete_rpath(path, options = {}) ⇒ Object
Delete the given runtime path from the file's Mach-Os.
-
#dsym? ⇒ Boolean
Whether or not the file is of type
MH_DSYM
. -
#dylib? ⇒ Boolean
Whether or not the file is of type
MH_DYLIB
. -
#dylib_id ⇒ String?
The Mach-O's dylib ID.
-
#dylib_load_commands ⇒ Array<LoadCommands::DylibCommand>
All load commands responsible for loading dylibs in the file's Mach-O's.
-
#dylinker? ⇒ Boolean
Whether or not the file is of type
MH_DYLINKER
. -
#executable? ⇒ Boolean
Whether or not the file is of type
MH_EXECUTE
. -
#extract(cputype) ⇒ MachOFile?
Extract a Mach-O with the given CPU type from the file.
-
#filetype ⇒ Symbol
A string representation of the Mach-O's filetype.
-
#fvmlib? ⇒ Boolean
Whether or not the file is of type
MH_FVMLIB
. -
#initialize(filename, **opts) ⇒ FatFile
constructor
Creates a new FatFile from the given filename.
-
#initialize_from_bin(bin, opts) ⇒ Object
private
Initializes a new FatFile instance from a binary string with the given options.
-
#kext? ⇒ Boolean
Whether or not the file is of type
MH_KEXT_BUNDLE
. -
#linked_dylibs ⇒ Array<String>
All shared libraries linked to the file's Mach-Os.
-
#magic ⇒ Integer
The magic number of the header (and file).
-
#magic_string ⇒ String
A string representation of the file's magic number.
-
#object? ⇒ Boolean
Whether or not the file is of type
MH_OBJECT
. -
#populate_fields ⇒ void
Populate the instance's fields with the raw Fat Mach-O data.
-
#preload? ⇒ Boolean
Whether or not the file is of type
MH_PRELOAD
. -
#rpaths ⇒ Array<String>
All runtime paths associated with the file's Mach-Os.
-
#serialize ⇒ String
The file's raw fat data.
-
#to_h ⇒ Hash
A hash representation of this FatFile.
-
#write(filename) ⇒ void
Write all (fat) data to the given filename.
-
#write! ⇒ void
Write all (fat) data to the file used to initialize the instance.
Constructor Details
#initialize(filename, **opts) ⇒ FatFile
see MachOFile#initialize for currently valid options
Creates a new FatFile from the given filename.
94 95 96 97 98 99 100 101 |
# File 'lib/macho/fat_file.rb', line 94 def initialize(filename, **opts) raise ArgumentError, "#{filename}: no such file" unless File.file?(filename) @filename = filename @options = opts @raw_data = File.binread(@filename) populate_fields end |
Instance Attribute Details
#fat_archs ⇒ Array<Headers::FatArch>, Array<Headers::FatArch64] an array of fat architectures (readonly)
Returns ArrayHeaders::FatArch, Array<Headers::FatArch64] an array of fat architectures.
24 25 26 |
# File 'lib/macho/fat_file.rb', line 24 def fat_archs @fat_archs end |
#filename ⇒ String
Returns the filename loaded from, or nil if loaded from a binary string.
14 15 16 |
# File 'lib/macho/fat_file.rb', line 14 def filename @filename end |
#header ⇒ Headers::FatHeader (readonly)
Returns the file's header.
21 22 23 |
# File 'lib/macho/fat_file.rb', line 21 def header @header end |
#machos ⇒ Array<MachOFile> (readonly)
Returns an array of Mach-O binaries.
27 28 29 |
# File 'lib/macho/fat_file.rb', line 27 def machos @machos end |
#options ⇒ Hash (readonly)
Options specified in a MachO::FatFile trickle down into the internal MachOFiles.
Returns any parser options that the instance was created with.
18 19 20 |
# File 'lib/macho/fat_file.rb', line 18 def @options end |
Class Method Details
.new_from_bin(bin, **opts) ⇒ FatFile
see MachOFile#initialize for currently valid options
Creates a new FatFile instance from a binary string.
82 83 84 85 86 87 |
# File 'lib/macho/fat_file.rb', line 82 def self.new_from_bin(bin, **opts) instance = allocate instance.initialize_from_bin(bin, opts) instance end |
.new_from_machos(*machos, fat64: false) ⇒ FatFile
Creates a new FatFile from the given (single-arch) Mach-Os
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
# File 'lib/macho/fat_file.rb', line 36 def self.new_from_machos(*machos, fat64: false) raise ArgumentError, "expected at least one Mach-O" if machos.empty? fa_klass, magic = if fat64 [Headers::FatArch64, Headers::FAT_MAGIC_64] else [Headers::FatArch, Headers::FAT_MAGIC] end # put the smaller alignments further forwards in fat macho, so that we do less padding machos = machos.sort_by(&:segment_alignment) bin = +"" bin << Headers::FatHeader.new(magic, machos.size).serialize offset = Headers::FatHeader.bytesize + (machos.size * fa_klass.bytesize) macho_pads = {} machos.each do |macho| macho_offset = Utils.round(offset, 2**macho.segment_alignment) raise FatArchOffsetOverflowError, macho_offset if !fat64 && macho_offset > ((2**32) - 1) macho_pads[macho] = Utils.padding_for(offset, 2**macho.segment_alignment) bin << fa_klass.new(macho.header.cputype, macho.header.cpusubtype, macho_offset, macho.serialize.bytesize, macho.segment_alignment).serialize offset += (macho.serialize.bytesize + macho_pads[macho]) end machos.each do |macho| # rubocop:disable Style/CombinableLoops bin << Utils.nullpad(macho_pads[macho]) bin << macho.serialize end new_from_bin(bin) end |
Instance Method Details
#add_rpath(path, options = {}) ⇒ void
This method returns an undefined value.
Add the given runtime path to the file's Mach-Os.
260 261 262 263 264 265 266 |
# File 'lib/macho/fat_file.rb', line 260 def add_rpath(path, = {}) each_macho() do |macho| macho.add_rpath(path, ) end repopulate_raw_machos end |
#bundle? ⇒ Boolean
Returns whether or not the file is of type MH_BUNDLE
.
143 144 145 |
# File 'lib/macho/fat_file.rb', line 143 def_delegators :canonical_macho, :object?, :executable?, :fvmlib?, :core?, :preload?, :dylib?, :dylinker?, :bundle?, :dsym?, :kext?, :filetype, :dylib_id |
#change_dylib_id(new_id, options = {}) ⇒ void Also known as: dylib_id=
This method returns an undefined value.
Changes the file's dylib ID to new_id
. If the file is not a dylib,
does nothing.
182 183 184 185 186 187 188 189 190 191 |
# File 'lib/macho/fat_file.rb', line 182 def change_dylib_id(new_id, = {}) raise ArgumentError, "argument must be a String" unless new_id.is_a?(String) return unless machos.all?(&:dylib?) each_macho() do |macho| macho.change_dylib_id(new_id, ) end repopulate_raw_machos end |
#change_install_name(old_name, new_name, options = {}) ⇒ void Also known as: change_dylib
This method returns an undefined value.
Changes all dependent shared library install names from old_name
to
new_name
. In a fat file, this changes install names in all internal
Mach-Os.
217 218 219 220 221 222 223 |
# File 'lib/macho/fat_file.rb', line 217 def change_install_name(old_name, new_name, = {}) each_macho() do |macho| macho.change_install_name(old_name, new_name, ) end repopulate_raw_machos end |
#change_rpath(old_path, new_path, options = {}) ⇒ void
This method returns an undefined value.
Change the runtime path old_path
to new_path
in the file's Mach-Os.
245 246 247 248 249 250 251 |
# File 'lib/macho/fat_file.rb', line 245 def change_rpath(old_path, new_path, = {}) each_macho() do |macho| macho.change_rpath(old_path, new_path, ) end repopulate_raw_machos end |
#core? ⇒ Boolean
Returns whether or not the file is of type MH_CORE
.
143 144 145 |
# File 'lib/macho/fat_file.rb', line 143 def_delegators :canonical_macho, :object?, :executable?, :fvmlib?, :core?, :preload?, :dylib?, :dylinker?, :bundle?, :dsym?, :kext?, :filetype, :dylib_id |
#delete_rpath(path, options = {}) ⇒ Object
Delete the given runtime path from the file's Mach-Os.
278 279 280 281 282 283 284 |
# File 'lib/macho/fat_file.rb', line 278 def delete_rpath(path, = {}) each_macho() do |macho| macho.delete_rpath(path, ) end repopulate_raw_machos end |
#dsym? ⇒ Boolean
Returns whether or not the file is of type MH_DSYM
.
143 144 145 |
# File 'lib/macho/fat_file.rb', line 143 def_delegators :canonical_macho, :object?, :executable?, :fvmlib?, :core?, :preload?, :dylib?, :dylinker?, :bundle?, :dsym?, :kext?, :filetype, :dylib_id |
#dylib? ⇒ Boolean
Returns whether or not the file is of type MH_DYLIB
.
143 144 145 |
# File 'lib/macho/fat_file.rb', line 143 def_delegators :canonical_macho, :object?, :executable?, :fvmlib?, :core?, :preload?, :dylib?, :dylinker?, :bundle?, :dsym?, :kext?, :filetype, :dylib_id |
#dylib_id ⇒ String?
Returns the Mach-O's dylib ID.
143 144 145 |
# File 'lib/macho/fat_file.rb', line 143 def_delegators :canonical_macho, :object?, :executable?, :fvmlib?, :core?, :preload?, :dylib?, :dylinker?, :bundle?, :dsym?, :kext?, :filetype, :dylib_id |
#dylib_load_commands ⇒ Array<LoadCommands::DylibCommand>
All load commands responsible for loading dylibs in the file's Mach-O's.
167 168 169 |
# File 'lib/macho/fat_file.rb', line 167 def dylib_load_commands machos.map(&:dylib_load_commands).flatten end |
#dylinker? ⇒ Boolean
Returns whether or not the file is of type MH_DYLINKER
.
143 144 145 |
# File 'lib/macho/fat_file.rb', line 143 def_delegators :canonical_macho, :object?, :executable?, :fvmlib?, :core?, :preload?, :dylib?, :dylinker?, :bundle?, :dsym?, :kext?, :filetype, :dylib_id |
#executable? ⇒ Boolean
Returns whether or not the file is of type MH_EXECUTE
.
143 144 145 |
# File 'lib/macho/fat_file.rb', line 143 def_delegators :canonical_macho, :object?, :executable?, :fvmlib?, :core?, :preload?, :dylib?, :dylinker?, :bundle?, :dsym?, :kext?, :filetype, :dylib_id |
#extract(cputype) ⇒ MachOFile?
Extract a Mach-O with the given CPU type from the file.
291 292 293 |
# File 'lib/macho/fat_file.rb', line 291 def extract(cputype) machos.select { |macho| macho.cputype == cputype }.first end |
#filetype ⇒ Symbol
Returns a string representation of the Mach-O's filetype.
143 144 145 |
# File 'lib/macho/fat_file.rb', line 143 def_delegators :canonical_macho, :object?, :executable?, :fvmlib?, :core?, :preload?, :dylib?, :dylinker?, :bundle?, :dsym?, :kext?, :filetype, :dylib_id |
#fvmlib? ⇒ Boolean
Returns whether or not the file is of type MH_FVMLIB
.
143 144 145 |
# File 'lib/macho/fat_file.rb', line 143 def_delegators :canonical_macho, :object?, :executable?, :fvmlib?, :core?, :preload?, :dylib?, :dylinker?, :bundle?, :dsym?, :kext?, :filetype, :dylib_id |
#initialize_from_bin(bin, opts) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Initializes a new FatFile instance from a binary string with the given options.
106 107 108 109 110 111 |
# File 'lib/macho/fat_file.rb', line 106 def initialize_from_bin(bin, opts) @filename = nil @options = opts @raw_data = bin populate_fields end |
#kext? ⇒ Boolean
Returns whether or not the file is of type MH_KEXT_BUNDLE
.
143 144 145 |
# File 'lib/macho/fat_file.rb', line 143 def_delegators :canonical_macho, :object?, :executable?, :fvmlib?, :core?, :preload?, :dylib?, :dylinker?, :bundle?, :dsym?, :kext?, :filetype, :dylib_id |
#linked_dylibs ⇒ Array<String>
All shared libraries linked to the file's Mach-Os.
198 199 200 201 202 203 |
# File 'lib/macho/fat_file.rb', line 198 def linked_dylibs # Individual architectures in a fat binary can link to different subsets # of libraries, but at this point we want to have the full picture, i.e. # the union of all libraries used by all architectures. machos.map(&:linked_dylibs).flatten.uniq end |
#magic ⇒ Integer
Returns the magic number of the header (and file).
149 |
# File 'lib/macho/fat_file.rb', line 149 def_delegators :header, :magic |
#magic_string ⇒ String
Returns a string representation of the file's magic number.
152 153 154 |
# File 'lib/macho/fat_file.rb', line 152 def magic_string Headers::MH_MAGICS[magic] end |
#object? ⇒ Boolean
Returns whether or not the file is of type MH_OBJECT
.
143 144 145 |
# File 'lib/macho/fat_file.rb', line 143 def_delegators :canonical_macho, :object?, :executable?, :fvmlib?, :core?, :preload?, :dylib?, :dylinker?, :bundle?, :dsym?, :kext?, :filetype, :dylib_id |
#populate_fields ⇒ void
This method is public, but should (almost) never need to be called.
This method returns an undefined value.
Populate the instance's fields with the raw Fat Mach-O data.
159 160 161 162 163 |
# File 'lib/macho/fat_file.rb', line 159 def populate_fields @header = populate_fat_header @fat_archs = populate_fat_archs @machos = populate_machos end |
#preload? ⇒ Boolean
Returns whether or not the file is of type MH_PRELOAD
.
143 144 145 |
# File 'lib/macho/fat_file.rb', line 143 def_delegators :canonical_macho, :object?, :executable?, :fvmlib?, :core?, :preload?, :dylib?, :dylinker?, :bundle?, :dsym?, :kext?, :filetype, :dylib_id |
#rpaths ⇒ Array<String>
All runtime paths associated with the file's Mach-Os.
230 231 232 233 |
# File 'lib/macho/fat_file.rb', line 230 def rpaths # Can individual architectures have different runtime paths? machos.map(&:rpaths).flatten.uniq end |
#serialize ⇒ String
The file's raw fat data.
115 116 117 |
# File 'lib/macho/fat_file.rb', line 115 def serialize @raw_data end |
#to_h ⇒ Hash
Returns a hash representation of this MachO::FatFile.
313 314 315 316 317 318 319 |
# File 'lib/macho/fat_file.rb', line 313 def to_h { "header" => header.to_h, "fat_archs" => fat_archs.map(&:to_h), "machos" => machos.map(&:to_h), } end |
#write(filename) ⇒ void
This method returns an undefined value.
Write all (fat) data to the given filename.
298 299 300 |
# File 'lib/macho/fat_file.rb', line 298 def write(filename) File.binwrite(filename, @raw_data) end |
#write! ⇒ void
Overwrites all data in the file!
This method returns an undefined value.
Write all (fat) data to the file used to initialize the instance.
306 307 308 309 310 |
# File 'lib/macho/fat_file.rb', line 306 def write! raise MachOError, "no initial file to write to" if filename.nil? File.binwrite(@filename, @raw_data) end |