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.
Class Method Summary collapse
-
.new_from_bin(bin) ⇒ 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_nametonew_name. -
#change_rpath(old_path, new_path, options = {}) ⇒ void
Change the runtime path
old_pathtonew_pathin 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) ⇒ FatFile
constructor
Creates a new FatFile from the given filename.
-
#initialize_from_bin(bin) ⇒ Object
private
Initializes a new FatFile instance from a binary string.
-
#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) ⇒ FatFile
Creates a new FatFile from the given filename.
86 87 88 89 90 91 92 |
# File 'lib/macho/fat_file.rb', line 86 def initialize(filename) raise ArgumentError, "#{filename}: no such file" unless File.file?(filename) @filename = filename @raw_data = File.open(@filename, "rb", &:read) 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.
18 19 20 |
# File 'lib/macho/fat_file.rb', line 18 def fat_archs @fat_archs end |
#filename ⇒ String
Returns the filename loaded from, or nil if loaded from a binary string.
12 13 14 |
# File 'lib/macho/fat_file.rb', line 12 def filename @filename end |
#header ⇒ Headers::FatHeader (readonly)
Returns the file's header.
15 16 17 |
# File 'lib/macho/fat_file.rb', line 15 def header @header end |
#machos ⇒ Array<MachOFile> (readonly)
Returns an array of Mach-O binaries.
21 22 23 |
# File 'lib/macho/fat_file.rb', line 21 def machos @machos end |
Class Method Details
.new_from_bin(bin) ⇒ FatFile
Creates a new FatFile instance from a binary string.
76 77 78 79 80 81 |
# File 'lib/macho/fat_file.rb', line 76 def self.new_from_bin(bin) instance = allocate instance.initialize_from_bin(bin) instance end |
.new_from_machos(*machos, fat64: false) ⇒ FatFile
Creates a new FatFile from the given (single-arch) Mach-Os
30 31 32 33 34 35 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 |
# File 'lib/macho/fat_file.rb', line 30 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) if !fat64 && macho_offset > (2**32 - 1) raise FatArchOffsetOverflowError, macho_offset end 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| 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.
248 249 250 251 252 253 254 |
# File 'lib/macho/fat_file.rb', line 248 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.
133 134 135 |
# File 'lib/macho/fat_file.rb', line 133 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.
172 173 174 175 176 177 178 179 180 181 |
# File 'lib/macho/fat_file.rb', line 172 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.
207 208 209 210 211 212 213 |
# File 'lib/macho/fat_file.rb', line 207 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.
233 234 235 236 237 238 239 |
# File 'lib/macho/fat_file.rb', line 233 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.
133 134 135 |
# File 'lib/macho/fat_file.rb', line 133 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.
263 264 265 266 267 268 269 |
# File 'lib/macho/fat_file.rb', line 263 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.
133 134 135 |
# File 'lib/macho/fat_file.rb', line 133 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.
133 134 135 |
# File 'lib/macho/fat_file.rb', line 133 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.
133 134 135 |
# File 'lib/macho/fat_file.rb', line 133 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.
157 158 159 |
# File 'lib/macho/fat_file.rb', line 157 def dylib_load_commands machos.map(&:dylib_load_commands).flatten end |
#dylinker? ⇒ Boolean
Returns whether or not the file is of type MH_DYLINKER.
133 134 135 |
# File 'lib/macho/fat_file.rb', line 133 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.
133 134 135 |
# File 'lib/macho/fat_file.rb', line 133 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.
276 277 278 |
# File 'lib/macho/fat_file.rb', line 276 def extract(cputype) machos.select { |macho| macho.cputype == cputype }.first end |
#filetype ⇒ Symbol
Returns a string representation of the Mach-O's filetype.
133 134 135 |
# File 'lib/macho/fat_file.rb', line 133 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.
133 134 135 |
# File 'lib/macho/fat_file.rb', line 133 def_delegators :canonical_macho, :object?, :executable?, :fvmlib?, :core?, :preload?, :dylib?, :dylinker?, :bundle?, :dsym?, :kext?, :filetype, :dylib_id |
#initialize_from_bin(bin) ⇒ 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.
97 98 99 100 101 |
# File 'lib/macho/fat_file.rb', line 97 def initialize_from_bin(bin) @filename = nil @raw_data = bin populate_fields end |
#kext? ⇒ Boolean
Returns whether or not the file is of type MH_KEXT_BUNDLE.
133 134 135 |
# File 'lib/macho/fat_file.rb', line 133 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.
188 189 190 191 192 193 |
# File 'lib/macho/fat_file.rb', line 188 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).
139 |
# File 'lib/macho/fat_file.rb', line 139 def_delegators :header, :magic |
#magic_string ⇒ String
Returns a string representation of the file's magic number.
142 143 144 |
# File 'lib/macho/fat_file.rb', line 142 def magic_string Headers::MH_MAGICS[magic] end |
#object? ⇒ Boolean
Returns whether or not the file is of type MH_OBJECT.
133 134 135 |
# File 'lib/macho/fat_file.rb', line 133 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.
149 150 151 152 153 |
# File 'lib/macho/fat_file.rb', line 149 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.
133 134 135 |
# File 'lib/macho/fat_file.rb', line 133 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.
220 221 222 223 |
# File 'lib/macho/fat_file.rb', line 220 def rpaths # Can individual architectures have different runtime paths? machos.map(&:rpaths).flatten.uniq end |
#serialize ⇒ String
The file's raw fat data.
105 106 107 |
# File 'lib/macho/fat_file.rb', line 105 def serialize @raw_data end |
#to_h ⇒ Hash
Returns a hash representation of this MachO::FatFile.
298 299 300 301 302 303 304 |
# File 'lib/macho/fat_file.rb', line 298 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.
283 284 285 |
# File 'lib/macho/fat_file.rb', line 283 def write(filename) File.open(filename, "wb") { |f| f.write(@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.
291 292 293 294 295 |
# File 'lib/macho/fat_file.rb', line 291 def write! raise MachOError, "no initial file to write to" if filename.nil? File.open(@filename, "wb") { |f| f.write(@raw_data) } end |