vendor: Update vendored ruby-macho to 0.2.5.
This commit is contained in:
parent
d7da1640ff
commit
5caa812e2c
2
Library/Homebrew/vendor/README.md
vendored
2
Library/Homebrew/vendor/README.md
vendored
@ -3,7 +3,7 @@ Vendored Dependencies
|
|||||||
|
|
||||||
* [okjson](https://github.com/kr/okjson), version 43.
|
* [okjson](https://github.com/kr/okjson), version 43.
|
||||||
|
|
||||||
* [ruby-macho](https://github.com/Homebrew/ruby-macho), version 0.2.4
|
* [ruby-macho](https://github.com/Homebrew/ruby-macho), version 0.2.5
|
||||||
|
|
||||||
## Licenses:
|
## Licenses:
|
||||||
|
|
||||||
|
|||||||
3
Library/Homebrew/vendor/macho/macho.rb
vendored
3
Library/Homebrew/vendor/macho/macho.rb
vendored
@ -1,4 +1,5 @@
|
|||||||
require "#{File.dirname(__FILE__)}/macho/structure"
|
require "#{File.dirname(__FILE__)}/macho/structure"
|
||||||
|
require "#{File.dirname(__FILE__)}/macho/view"
|
||||||
require "#{File.dirname(__FILE__)}/macho/headers"
|
require "#{File.dirname(__FILE__)}/macho/headers"
|
||||||
require "#{File.dirname(__FILE__)}/macho/load_commands"
|
require "#{File.dirname(__FILE__)}/macho/load_commands"
|
||||||
require "#{File.dirname(__FILE__)}/macho/sections"
|
require "#{File.dirname(__FILE__)}/macho/sections"
|
||||||
@ -12,5 +13,5 @@ require "#{File.dirname(__FILE__)}/macho/tools"
|
|||||||
# The primary namespace for ruby-macho.
|
# The primary namespace for ruby-macho.
|
||||||
module MachO
|
module MachO
|
||||||
# release version
|
# release version
|
||||||
VERSION = "0.2.4".freeze
|
VERSION = "0.2.5".freeze
|
||||||
end
|
end
|
||||||
|
|||||||
@ -3,6 +3,26 @@ module MachO
|
|||||||
class MachOError < RuntimeError
|
class MachOError < RuntimeError
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Raised when a Mach-O file modification fails.
|
||||||
|
class ModificationError < MachOError
|
||||||
|
end
|
||||||
|
|
||||||
|
# Raised when a Mach-O file modification fails but can be recovered when
|
||||||
|
# operating on multiple Mach-O slices of a fat binary in non-strict mode.
|
||||||
|
class RecoverableModificationError < ModificationError
|
||||||
|
# @return [Fixnum, nil] The index of the Mach-O slice of a fat binary for
|
||||||
|
# which modification failed or `nil` if not a fat binary. This is used to
|
||||||
|
# make the error message more useful.
|
||||||
|
attr_accessor :macho_slice
|
||||||
|
|
||||||
|
# @return [String] The exception message.
|
||||||
|
def to_s
|
||||||
|
s = super.to_s
|
||||||
|
s = "While modifying Mach-O slice #{@macho_slice}: #{s}" if @macho_slice
|
||||||
|
s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Raised when a file is not a Mach-O.
|
# Raised when a file is not a Mach-O.
|
||||||
class NotAMachOError < MachOError
|
class NotAMachOError < MachOError
|
||||||
# @param error [String] the error in question
|
# @param error [String] the error in question
|
||||||
@ -80,32 +100,89 @@ module MachO
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Raised when a load command can't be created manually.
|
||||||
|
class LoadCommandNotCreatableError < MachOError
|
||||||
|
# @param cmd_sym [Symbol] the uncreatable load command's symbol
|
||||||
|
def initialize(cmd_sym)
|
||||||
|
super "Load commands of type #{cmd_sym} cannot be created manually"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Raised when the number of arguments used to create a load command manually is wrong.
|
||||||
|
class LoadCommandCreationArityError < MachOError
|
||||||
|
# @param cmd_sym [Symbol] the load command's symbol
|
||||||
|
# @param expected_arity [Fixnum] the number of arguments expected
|
||||||
|
# @param actual_arity [Fixnum] the number of arguments received
|
||||||
|
def initialize(cmd_sym, expected_arity, actual_arity)
|
||||||
|
super "Expected #{expected_arity} arguments for #{cmd_sym} creation, got #{actual_arity}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Raised when a load command can't be serialized.
|
||||||
|
class LoadCommandNotSerializableError < MachOError
|
||||||
|
# @param cmd_sym [Symbol] the load command's symbol
|
||||||
|
def initialize(cmd_sym)
|
||||||
|
super "Load commands of type #{cmd_sym} cannot be serialized"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Raised when a load command string is malformed in some way.
|
||||||
|
class LCStrMalformedError < MachOError
|
||||||
|
# @param lc [MachO::LoadCommand] the load command containing the string
|
||||||
|
def initialize(lc)
|
||||||
|
super "Load command #{lc.type} at offset #{lc.view.offset} contains a malformed string"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Raised when a change at an offset is not valid.
|
||||||
|
class OffsetInsertionError < ModificationError
|
||||||
|
# @param offset [Fixnum] the invalid offset
|
||||||
|
def initialize(offset)
|
||||||
|
super "Insertion at offset #{offset} is not valid"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Raised when load commands are too large to fit in the current file.
|
# Raised when load commands are too large to fit in the current file.
|
||||||
class HeaderPadError < MachOError
|
class HeaderPadError < ModificationError
|
||||||
# @param filename [String] the filename
|
# @param filename [String] the filename
|
||||||
def initialize(filename)
|
def initialize(filename)
|
||||||
super "Updated load commands do not fit in the header of " +
|
super "Updated load commands do not fit in the header of " \
|
||||||
"#{filename}. #{filename} needs to be relinked, possibly with " +
|
"#{filename}. #{filename} needs to be relinked, possibly with " \
|
||||||
"-headerpad or -headerpad_max_install_names"
|
"-headerpad or -headerpad_max_install_names"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Raised when attempting to change a dylib name that doesn't exist.
|
# Raised when attempting to change a dylib name that doesn't exist.
|
||||||
class DylibUnknownError < MachOError
|
class DylibUnknownError < RecoverableModificationError
|
||||||
# @param dylib [String] the unknown shared library name
|
# @param dylib [String] the unknown shared library name
|
||||||
def initialize(dylib)
|
def initialize(dylib)
|
||||||
super "No such dylib name: #{dylib}"
|
super "No such dylib name: #{dylib}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Raised when a dylib is missing an ID
|
||||||
|
class DylibIdMissingError < RecoverableModificationError
|
||||||
|
def initialize
|
||||||
|
super "Dylib is missing a dylib ID"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Raised when attempting to change an rpath that doesn't exist.
|
# Raised when attempting to change an rpath that doesn't exist.
|
||||||
class RpathUnknownError < MachOError
|
class RpathUnknownError < RecoverableModificationError
|
||||||
# @param path [String] the unknown runtime path
|
# @param path [String] the unknown runtime path
|
||||||
def initialize(path)
|
def initialize(path)
|
||||||
super "No such runtime path: #{path}"
|
super "No such runtime path: #{path}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Raised when attempting to add an rpath that already exists.
|
||||||
|
class RpathExistsError < RecoverableModificationError
|
||||||
|
# @param path [String] the extant path
|
||||||
|
def initialize(path)
|
||||||
|
super "#{path} already exists"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Raised whenever unfinished code is called.
|
# Raised whenever unfinished code is called.
|
||||||
class UnimplementedError < MachOError
|
class UnimplementedError < MachOError
|
||||||
# @param thing [String] the thing that is unimplemented
|
# @param thing [String] the thing that is unimplemented
|
||||||
|
|||||||
169
Library/Homebrew/vendor/macho/macho/fat_file.rb
vendored
169
Library/Homebrew/vendor/macho/macho/fat_file.rb
vendored
@ -30,22 +30,24 @@ module MachO
|
|||||||
# @param filename [String] the fat file to load from
|
# @param filename [String] the fat file to load from
|
||||||
# @raise [ArgumentError] if the given file does not exist
|
# @raise [ArgumentError] if the given file does not exist
|
||||||
def initialize(filename)
|
def initialize(filename)
|
||||||
raise ArgumentError.new("#{filename}: no such file") unless File.file?(filename)
|
raise ArgumentError, "#{filename}: no such file" unless File.file?(filename)
|
||||||
|
|
||||||
@filename = filename
|
@filename = filename
|
||||||
@raw_data = File.open(@filename, "rb") { |f| f.read }
|
@raw_data = File.open(@filename, "rb", &:read)
|
||||||
@header = get_fat_header
|
@header = populate_fat_header
|
||||||
@fat_archs = get_fat_archs
|
@fat_archs = populate_fat_archs
|
||||||
@machos = get_machos
|
@machos = populate_machos
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Initializes a new FatFile instance from a binary string.
|
||||||
|
# @see MachO::FatFile.new_from_bin
|
||||||
# @api private
|
# @api private
|
||||||
def initialize_from_bin(bin)
|
def initialize_from_bin(bin)
|
||||||
@filename = nil
|
@filename = nil
|
||||||
@raw_data = bin
|
@raw_data = bin
|
||||||
@header = get_fat_header
|
@header = populate_fat_header
|
||||||
@fat_archs = get_fat_archs
|
@fat_archs = populate_fat_archs
|
||||||
@machos = get_machos
|
@machos = populate_machos
|
||||||
end
|
end
|
||||||
|
|
||||||
# The file's raw fat data.
|
# The file's raw fat data.
|
||||||
@ -115,7 +117,7 @@ module MachO
|
|||||||
end
|
end
|
||||||
|
|
||||||
# The file's type. Assumed to be the same for every Mach-O within.
|
# The file's type. Assumed to be the same for every Mach-O within.
|
||||||
# @return [String] the filetype
|
# @return [Symbol] the filetype
|
||||||
def filetype
|
def filetype
|
||||||
machos.first.filetype
|
machos.first.filetype
|
||||||
end
|
end
|
||||||
@ -124,34 +126,37 @@ module MachO
|
|||||||
# @example
|
# @example
|
||||||
# file.dylib_id # => 'libBar.dylib'
|
# file.dylib_id # => 'libBar.dylib'
|
||||||
# @return [String, nil] the file's dylib ID
|
# @return [String, nil] the file's dylib ID
|
||||||
|
# @see MachO::MachOFile#linked_dylibs
|
||||||
def dylib_id
|
def dylib_id
|
||||||
machos.first.dylib_id
|
machos.first.dylib_id
|
||||||
end
|
end
|
||||||
|
|
||||||
# Changes the file's dylib ID to `new_id`. If the file is not a dylib, does nothing.
|
# Changes the file's dylib ID to `new_id`. If the file is not a dylib, does nothing.
|
||||||
# @example
|
# @example
|
||||||
# file.dylib_id = 'libFoo.dylib'
|
# file.change_dylib_id('libFoo.dylib')
|
||||||
# @param new_id [String] the new dylib ID
|
# @param new_id [String] the new dylib ID
|
||||||
|
# @param options [Hash]
|
||||||
|
# @option options [Boolean] :strict (true) if true, fail if one slice fails.
|
||||||
|
# if false, fail only if all slices fail.
|
||||||
# @return [void]
|
# @return [void]
|
||||||
# @raise [ArgumentError] if `new_id` is not a String
|
# @raise [ArgumentError] if `new_id` is not a String
|
||||||
def dylib_id=(new_id)
|
# @see MachO::MachOFile#linked_dylibs
|
||||||
if !new_id.is_a?(String)
|
def change_dylib_id(new_id, options = {})
|
||||||
raise ArgumentError.new("argument must be a String")
|
raise ArgumentError, "argument must be a String" unless new_id.is_a?(String)
|
||||||
end
|
return unless machos.all?(&:dylib?)
|
||||||
|
|
||||||
if !machos.all?(&:dylib?)
|
each_macho(options) do |macho|
|
||||||
return nil
|
macho.change_dylib_id(new_id, options)
|
||||||
end
|
|
||||||
|
|
||||||
machos.each do |macho|
|
|
||||||
macho.dylib_id = new_id
|
|
||||||
end
|
end
|
||||||
|
|
||||||
synchronize_raw_data
|
synchronize_raw_data
|
||||||
end
|
end
|
||||||
|
|
||||||
|
alias dylib_id= change_dylib_id
|
||||||
|
|
||||||
# All shared libraries linked to the file's Mach-Os.
|
# All shared libraries linked to the file's Mach-Os.
|
||||||
# @return [Array<String>] an array of all shared libraries
|
# @return [Array<String>] an array of all shared libraries
|
||||||
|
# @see MachO::MachOFile#linked_dylibs
|
||||||
def linked_dylibs
|
def linked_dylibs
|
||||||
# Individual architectures in a fat binary can link to different subsets
|
# 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.
|
# of libraries, but at this point we want to have the full picture, i.e.
|
||||||
@ -165,16 +170,74 @@ module MachO
|
|||||||
# file.change_install_name('/usr/lib/libFoo.dylib', '/usr/lib/libBar.dylib')
|
# file.change_install_name('/usr/lib/libFoo.dylib', '/usr/lib/libBar.dylib')
|
||||||
# @param old_name [String] the shared library name being changed
|
# @param old_name [String] the shared library name being changed
|
||||||
# @param new_name [String] the new name
|
# @param new_name [String] the new name
|
||||||
# @todo incomplete
|
# @param options [Hash]
|
||||||
def change_install_name(old_name, new_name)
|
# @option options [Boolean] :strict (true) if true, fail if one slice fails.
|
||||||
machos.each do |macho|
|
# if false, fail only if all slices fail.
|
||||||
macho.change_install_name(old_name, new_name)
|
# @return [void]
|
||||||
|
# @see MachO::MachOFile#change_install_name
|
||||||
|
def change_install_name(old_name, new_name, options = {})
|
||||||
|
each_macho(options) do |macho|
|
||||||
|
macho.change_install_name(old_name, new_name, options)
|
||||||
end
|
end
|
||||||
|
|
||||||
synchronize_raw_data
|
synchronize_raw_data
|
||||||
end
|
end
|
||||||
|
|
||||||
alias :change_dylib :change_install_name
|
alias change_dylib change_install_name
|
||||||
|
|
||||||
|
# All runtime paths associated with the file's Mach-Os.
|
||||||
|
# @return [Array<String>] an array of all runtime paths
|
||||||
|
# @see MachO::MachOFile#rpaths
|
||||||
|
def rpaths
|
||||||
|
# Can individual architectures have different runtime paths?
|
||||||
|
machos.map(&:rpaths).flatten.uniq
|
||||||
|
end
|
||||||
|
|
||||||
|
# Change the runtime path `old_path` to `new_path` in the file's Mach-Os.
|
||||||
|
# @param old_path [String] the old runtime path
|
||||||
|
# @param new_path [String] the new runtime path
|
||||||
|
# @param options [Hash]
|
||||||
|
# @option options [Boolean] :strict (true) if true, fail if one slice fails.
|
||||||
|
# if false, fail only if all slices fail.
|
||||||
|
# @return [void]
|
||||||
|
# @see MachO::MachOFile#change_rpath
|
||||||
|
def change_rpath(old_path, new_path, options = {})
|
||||||
|
each_macho(options) do |macho|
|
||||||
|
macho.change_rpath(old_path, new_path, options)
|
||||||
|
end
|
||||||
|
|
||||||
|
synchronize_raw_data
|
||||||
|
end
|
||||||
|
|
||||||
|
# Add the given runtime path to the file's Mach-Os.
|
||||||
|
# @param path [String] the new runtime path
|
||||||
|
# @param options [Hash]
|
||||||
|
# @option options [Boolean] :strict (true) if true, fail if one slice fails.
|
||||||
|
# if false, fail only if all slices fail.
|
||||||
|
# @return [void]
|
||||||
|
# @see MachO::MachOFile#add_rpath
|
||||||
|
def add_rpath(path, options = {})
|
||||||
|
each_macho(options) do |macho|
|
||||||
|
macho.add_rpath(path, options)
|
||||||
|
end
|
||||||
|
|
||||||
|
synchronize_raw_data
|
||||||
|
end
|
||||||
|
|
||||||
|
# Delete the given runtime path from the file's Mach-Os.
|
||||||
|
# @param path [String] the runtime path to delete
|
||||||
|
# @param options [Hash]
|
||||||
|
# @option options [Boolean] :strict (true) if true, fail if one slice fails.
|
||||||
|
# if false, fail only if all slices fail.
|
||||||
|
# @return void
|
||||||
|
# @see MachO::MachOFile#delete_rpath
|
||||||
|
def delete_rpath(path, options = {})
|
||||||
|
each_macho(options) do |macho|
|
||||||
|
macho.delete_rpath(path, options)
|
||||||
|
end
|
||||||
|
|
||||||
|
synchronize_raw_data
|
||||||
|
end
|
||||||
|
|
||||||
# Extract a Mach-O with the given CPU type from the file.
|
# Extract a Mach-O with the given CPU type from the file.
|
||||||
# @example
|
# @example
|
||||||
@ -197,7 +260,7 @@ module MachO
|
|||||||
# @note Overwrites all data in the file!
|
# @note Overwrites all data in the file!
|
||||||
def write!
|
def write!
|
||||||
if filename.nil?
|
if filename.nil?
|
||||||
raise MachOError.new("cannot write to a default file when initialized from a binary string")
|
raise MachOError, "cannot write to a default file when initialized from a binary string"
|
||||||
else
|
else
|
||||||
File.open(@filename, "wb") { |f| f.write(@raw_data) }
|
File.open(@filename, "wb") { |f| f.write(@raw_data) }
|
||||||
end
|
end
|
||||||
@ -211,15 +274,15 @@ module MachO
|
|||||||
# @raise [MachO::MagicError] if the magic is not valid Mach-O magic
|
# @raise [MachO::MagicError] if the magic is not valid Mach-O magic
|
||||||
# @raise [MachO::MachOBinaryError] if the magic is for a non-fat Mach-O file
|
# @raise [MachO::MachOBinaryError] if the magic is for a non-fat Mach-O file
|
||||||
# @raise [MachO::JavaClassFileError] if the file is a Java classfile
|
# @raise [MachO::JavaClassFileError] if the file is a Java classfile
|
||||||
# @private
|
# @api private
|
||||||
def get_fat_header
|
def populate_fat_header
|
||||||
# the smallest fat Mach-O header is 8 bytes
|
# the smallest fat Mach-O header is 8 bytes
|
||||||
raise TruncatedFileError.new if @raw_data.size < 8
|
raise TruncatedFileError if @raw_data.size < 8
|
||||||
|
|
||||||
fh = FatHeader.new_from_bin(:big, @raw_data[0, FatHeader.bytesize])
|
fh = FatHeader.new_from_bin(:big, @raw_data[0, FatHeader.bytesize])
|
||||||
|
|
||||||
raise MagicError.new(fh.magic) unless MachO.magic?(fh.magic)
|
raise MagicError, fh.magic unless Utils.magic?(fh.magic)
|
||||||
raise MachOBinaryError.new unless MachO.fat_magic?(fh.magic)
|
raise MachOBinaryError unless Utils.fat_magic?(fh.magic)
|
||||||
|
|
||||||
# Rationale: Java classfiles have the same magic as big-endian fat
|
# Rationale: Java classfiles have the same magic as big-endian fat
|
||||||
# Mach-Os. Classfiles encode their version at the same offset as
|
# Mach-Os. Classfiles encode their version at the same offset as
|
||||||
@ -228,15 +291,15 @@ module MachO
|
|||||||
# technically possible for a fat Mach-O to have over 30 architectures,
|
# technically possible for a fat Mach-O to have over 30 architectures,
|
||||||
# but this is extremely unlikely and in practice distinguishes the two
|
# but this is extremely unlikely and in practice distinguishes the two
|
||||||
# formats.
|
# formats.
|
||||||
raise JavaClassFileError.new if fh.nfat_arch > 30
|
raise JavaClassFileError if fh.nfat_arch > 30
|
||||||
|
|
||||||
fh
|
fh
|
||||||
end
|
end
|
||||||
|
|
||||||
# Obtain an array of fat architectures from raw file data.
|
# Obtain an array of fat architectures from raw file data.
|
||||||
# @return [Array<MachO::FatArch>] an array of fat architectures
|
# @return [Array<MachO::FatArch>] an array of fat architectures
|
||||||
# @private
|
# @api private
|
||||||
def get_fat_archs
|
def populate_fat_archs
|
||||||
archs = []
|
archs = []
|
||||||
|
|
||||||
fa_off = FatHeader.bytesize
|
fa_off = FatHeader.bytesize
|
||||||
@ -250,8 +313,8 @@ module MachO
|
|||||||
|
|
||||||
# Obtain an array of Mach-O blobs from raw file data.
|
# Obtain an array of Mach-O blobs from raw file data.
|
||||||
# @return [Array<MachO::MachOFile>] an array of Mach-Os
|
# @return [Array<MachO::MachOFile>] an array of Mach-Os
|
||||||
# @private
|
# @api private
|
||||||
def get_machos
|
def populate_machos
|
||||||
machos = []
|
machos = []
|
||||||
|
|
||||||
fat_archs.each do |arch|
|
fat_archs.each do |arch|
|
||||||
@ -261,9 +324,37 @@ module MachO
|
|||||||
machos
|
machos
|
||||||
end
|
end
|
||||||
|
|
||||||
# @todo this needs to be redesigned. arch[:offset] and arch[:size] are
|
# Yield each Mach-O object in the file, rescuing and accumulating errors.
|
||||||
# already out-of-date, and the header needs to be synchronized as well.
|
# @param options [Hash]
|
||||||
# @private
|
# @option options [Boolean] :strict (true) whether or not to fail loudly
|
||||||
|
# with an exception if at least one Mach-O raises an exception. If false,
|
||||||
|
# only raises an exception if *all* Mach-Os raise exceptions.
|
||||||
|
# @raise [MachO::RecoverableModificationError] under the conditions of
|
||||||
|
# the `:strict` option above.
|
||||||
|
# @api private
|
||||||
|
def each_macho(options = {})
|
||||||
|
strict = options.fetch(:strict, true)
|
||||||
|
errors = []
|
||||||
|
|
||||||
|
machos.each_with_index do |macho, index|
|
||||||
|
begin
|
||||||
|
yield macho
|
||||||
|
rescue RecoverableModificationError => error
|
||||||
|
error.macho_slice = index
|
||||||
|
|
||||||
|
# Strict mode: Immediately re-raise. Otherwise: Retain, check later.
|
||||||
|
raise error if strict
|
||||||
|
errors << error
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Non-strict mode: Raise first error if *all* Mach-O slices failed.
|
||||||
|
raise errors.first if errors.size == machos.size
|
||||||
|
end
|
||||||
|
|
||||||
|
# Synchronize the raw file data with each internal Mach-O object.
|
||||||
|
# @return [void]
|
||||||
|
# @api private
|
||||||
def synchronize_raw_data
|
def synchronize_raw_data
|
||||||
machos.each_with_index do |macho, i|
|
machos.each_with_index do |macho, i|
|
||||||
arch = fat_archs[i]
|
arch = fat_archs[i]
|
||||||
|
|||||||
156
Library/Homebrew/vendor/macho/macho/headers.rb
vendored
156
Library/Homebrew/vendor/macho/macho/headers.rb
vendored
@ -1,64 +1,82 @@
|
|||||||
module MachO
|
module MachO
|
||||||
# big-endian fat magic
|
# big-endian fat magic
|
||||||
|
# @api private
|
||||||
FAT_MAGIC = 0xcafebabe
|
FAT_MAGIC = 0xcafebabe
|
||||||
|
|
||||||
# little-endian fat magic
|
# little-endian fat magic
|
||||||
# this is defined, but should never appear in ruby-macho code because
|
# this is defined, but should never appear in ruby-macho code because
|
||||||
# fat headers are always big-endian and therefore always unpacked as such.
|
# fat headers are always big-endian and therefore always unpacked as such.
|
||||||
|
# @api private
|
||||||
FAT_CIGAM = 0xbebafeca
|
FAT_CIGAM = 0xbebafeca
|
||||||
|
|
||||||
# 32-bit big-endian magic
|
# 32-bit big-endian magic
|
||||||
|
# @api private
|
||||||
MH_MAGIC = 0xfeedface
|
MH_MAGIC = 0xfeedface
|
||||||
|
|
||||||
# 32-bit little-endian magic
|
# 32-bit little-endian magic
|
||||||
|
# @api private
|
||||||
MH_CIGAM = 0xcefaedfe
|
MH_CIGAM = 0xcefaedfe
|
||||||
|
|
||||||
# 64-bit big-endian magic
|
# 64-bit big-endian magic
|
||||||
|
# @api private
|
||||||
MH_MAGIC_64 = 0xfeedfacf
|
MH_MAGIC_64 = 0xfeedfacf
|
||||||
|
|
||||||
# 64-bit little-endian magic
|
# 64-bit little-endian magic
|
||||||
|
# @api private
|
||||||
MH_CIGAM_64 = 0xcffaedfe
|
MH_CIGAM_64 = 0xcffaedfe
|
||||||
|
|
||||||
# association of magic numbers to string representations
|
# association of magic numbers to string representations
|
||||||
|
# @api private
|
||||||
MH_MAGICS = {
|
MH_MAGICS = {
|
||||||
FAT_MAGIC => "FAT_MAGIC",
|
FAT_MAGIC => "FAT_MAGIC",
|
||||||
MH_MAGIC => "MH_MAGIC",
|
MH_MAGIC => "MH_MAGIC",
|
||||||
MH_CIGAM => "MH_CIGAM",
|
MH_CIGAM => "MH_CIGAM",
|
||||||
MH_MAGIC_64 => "MH_MAGIC_64",
|
MH_MAGIC_64 => "MH_MAGIC_64",
|
||||||
MH_CIGAM_64 => "MH_CIGAM_64"
|
MH_CIGAM_64 => "MH_CIGAM_64",
|
||||||
}
|
}.freeze
|
||||||
|
|
||||||
# mask for CPUs with 64-bit architectures (when running a 64-bit ABI?)
|
# mask for CPUs with 64-bit architectures (when running a 64-bit ABI?)
|
||||||
|
# @api private
|
||||||
CPU_ARCH_ABI64 = 0x01000000
|
CPU_ARCH_ABI64 = 0x01000000
|
||||||
|
|
||||||
# any CPU (unused?)
|
# any CPU (unused?)
|
||||||
|
# @api private
|
||||||
CPU_TYPE_ANY = -1
|
CPU_TYPE_ANY = -1
|
||||||
|
|
||||||
# m68k compatible CPUs
|
# m68k compatible CPUs
|
||||||
|
# @api private
|
||||||
CPU_TYPE_MC680X0 = 0x06
|
CPU_TYPE_MC680X0 = 0x06
|
||||||
|
|
||||||
# i386 and later compatible CPUs
|
# i386 and later compatible CPUs
|
||||||
|
# @api private
|
||||||
CPU_TYPE_I386 = 0x07
|
CPU_TYPE_I386 = 0x07
|
||||||
|
|
||||||
# x86_64 (AMD64) compatible CPUs
|
# x86_64 (AMD64) compatible CPUs
|
||||||
|
# @api private
|
||||||
CPU_TYPE_X86_64 = (CPU_TYPE_I386 | CPU_ARCH_ABI64)
|
CPU_TYPE_X86_64 = (CPU_TYPE_I386 | CPU_ARCH_ABI64)
|
||||||
|
|
||||||
# 32-bit ARM compatible CPUs
|
# 32-bit ARM compatible CPUs
|
||||||
|
# @api private
|
||||||
CPU_TYPE_ARM = 0x0c
|
CPU_TYPE_ARM = 0x0c
|
||||||
|
|
||||||
# m88k compatible CPUs
|
# m88k compatible CPUs
|
||||||
|
# @api private
|
||||||
CPU_TYPE_MC88000 = 0xd
|
CPU_TYPE_MC88000 = 0xd
|
||||||
|
|
||||||
# 64-bit ARM compatible CPUs
|
# 64-bit ARM compatible CPUs
|
||||||
|
# @api private
|
||||||
CPU_TYPE_ARM64 = (CPU_TYPE_ARM | CPU_ARCH_ABI64)
|
CPU_TYPE_ARM64 = (CPU_TYPE_ARM | CPU_ARCH_ABI64)
|
||||||
|
|
||||||
# PowerPC compatible CPUs
|
# PowerPC compatible CPUs
|
||||||
|
# @api private
|
||||||
CPU_TYPE_POWERPC = 0x12
|
CPU_TYPE_POWERPC = 0x12
|
||||||
|
|
||||||
# PowerPC64 compatible CPUs
|
# PowerPC64 compatible CPUs
|
||||||
|
# @api private
|
||||||
CPU_TYPE_POWERPC64 = (CPU_TYPE_POWERPC | CPU_ARCH_ABI64)
|
CPU_TYPE_POWERPC64 = (CPU_TYPE_POWERPC | CPU_ARCH_ABI64)
|
||||||
|
|
||||||
# association of cpu types to symbol representations
|
# association of cpu types to symbol representations
|
||||||
|
# @api private
|
||||||
CPU_TYPES = {
|
CPU_TYPES = {
|
||||||
CPU_TYPE_ANY => :any,
|
CPU_TYPE_ANY => :any,
|
||||||
CPU_TYPE_I386 => :i386,
|
CPU_TYPE_I386 => :i386,
|
||||||
@ -67,156 +85,213 @@ module MachO
|
|||||||
CPU_TYPE_ARM64 => :arm64,
|
CPU_TYPE_ARM64 => :arm64,
|
||||||
CPU_TYPE_POWERPC => :ppc,
|
CPU_TYPE_POWERPC => :ppc,
|
||||||
CPU_TYPE_POWERPC64 => :ppc64,
|
CPU_TYPE_POWERPC64 => :ppc64,
|
||||||
}
|
}.freeze
|
||||||
|
|
||||||
# mask for CPU subtype capabilities
|
# mask for CPU subtype capabilities
|
||||||
|
# @api private
|
||||||
CPU_SUBTYPE_MASK = 0xff000000
|
CPU_SUBTYPE_MASK = 0xff000000
|
||||||
|
|
||||||
# 64-bit libraries (undocumented!)
|
# 64-bit libraries (undocumented!)
|
||||||
# @see http://llvm.org/docs/doxygen/html/Support_2MachO_8h_source.html
|
# @see http://llvm.org/docs/doxygen/html/Support_2MachO_8h_source.html
|
||||||
|
# @api private
|
||||||
CPU_SUBTYPE_LIB64 = 0x80000000
|
CPU_SUBTYPE_LIB64 = 0x80000000
|
||||||
|
|
||||||
# the lowest common sub-type for `CPU_TYPE_I386`
|
# the lowest common sub-type for `CPU_TYPE_I386`
|
||||||
|
# @api private
|
||||||
CPU_SUBTYPE_I386 = 3
|
CPU_SUBTYPE_I386 = 3
|
||||||
|
|
||||||
# the i486 sub-type for `CPU_TYPE_I386`
|
# the i486 sub-type for `CPU_TYPE_I386`
|
||||||
|
# @api private
|
||||||
CPU_SUBTYPE_486 = 4
|
CPU_SUBTYPE_486 = 4
|
||||||
|
|
||||||
# the i486SX sub-type for `CPU_TYPE_I386`
|
# the i486SX sub-type for `CPU_TYPE_I386`
|
||||||
|
# @api private
|
||||||
CPU_SUBTYPE_486SX = 132
|
CPU_SUBTYPE_486SX = 132
|
||||||
|
|
||||||
# the i586 (P5, Pentium) sub-type for `CPU_TYPE_I386`
|
# the i586 (P5, Pentium) sub-type for `CPU_TYPE_I386`
|
||||||
|
# @api private
|
||||||
CPU_SUBTYPE_586 = 5
|
CPU_SUBTYPE_586 = 5
|
||||||
CPU_SUBTYPE_PENT = CPU_SUBTYPE_586
|
|
||||||
|
# @see CPU_SUBTYPE_586
|
||||||
|
# @api private
|
||||||
|
CPU_SUBTYPE_PENT = CPU_SUBTYPE_586
|
||||||
|
|
||||||
# the Pentium Pro (P6) sub-type for `CPU_TYPE_I386`
|
# the Pentium Pro (P6) sub-type for `CPU_TYPE_I386`
|
||||||
|
# @api private
|
||||||
CPU_SUBTYPE_PENTPRO = 22
|
CPU_SUBTYPE_PENTPRO = 22
|
||||||
|
|
||||||
# the Pentium II (P6, M3?) sub-type for `CPU_TYPE_I386`
|
# the Pentium II (P6, M3?) sub-type for `CPU_TYPE_I386`
|
||||||
|
# @api private
|
||||||
CPU_SUBTYPE_PENTII_M3 = 54
|
CPU_SUBTYPE_PENTII_M3 = 54
|
||||||
|
|
||||||
# the Pentium II (P6, M5?) sub-type for `CPU_TYPE_I386`
|
# the Pentium II (P6, M5?) sub-type for `CPU_TYPE_I386`
|
||||||
|
# @api private
|
||||||
CPU_SUBTYPE_PENTII_M5 = 86
|
CPU_SUBTYPE_PENTII_M5 = 86
|
||||||
|
|
||||||
# the Pentium 4 (Netburst) sub-type for `CPU_TYPE_I386`
|
# the Pentium 4 (Netburst) sub-type for `CPU_TYPE_I386`
|
||||||
|
# @api private
|
||||||
CPU_SUBTYPE_PENTIUM_4 = 10
|
CPU_SUBTYPE_PENTIUM_4 = 10
|
||||||
|
|
||||||
# the lowest common sub-type for `CPU_TYPE_MC680X0`
|
# the lowest common sub-type for `CPU_TYPE_MC680X0`
|
||||||
|
# @api private
|
||||||
CPU_SUBTYPE_MC680X0_ALL = 1
|
CPU_SUBTYPE_MC680X0_ALL = 1
|
||||||
|
|
||||||
|
# @see CPU_SUBTYPE_MC680X0_ALL
|
||||||
|
# @api private
|
||||||
CPU_SUBTYPE_MC68030 = CPU_SUBTYPE_MC680X0_ALL
|
CPU_SUBTYPE_MC68030 = CPU_SUBTYPE_MC680X0_ALL
|
||||||
|
|
||||||
# the 040 subtype for `CPU_TYPE_MC680X0`
|
# the 040 subtype for `CPU_TYPE_MC680X0`
|
||||||
|
# @api private
|
||||||
CPU_SUBTYPE_MC68040 = 2
|
CPU_SUBTYPE_MC68040 = 2
|
||||||
|
|
||||||
# the 030 subtype for `CPU_TYPE_MC680X0`
|
# the 030 subtype for `CPU_TYPE_MC680X0`
|
||||||
|
# @api private
|
||||||
CPU_SUBTYPE_MC68030_ONLY = 3
|
CPU_SUBTYPE_MC68030_ONLY = 3
|
||||||
|
|
||||||
# the lowest common sub-type for `CPU_TYPE_X86_64`
|
# the lowest common sub-type for `CPU_TYPE_X86_64`
|
||||||
|
# @api private
|
||||||
CPU_SUBTYPE_X86_64_ALL = CPU_SUBTYPE_I386
|
CPU_SUBTYPE_X86_64_ALL = CPU_SUBTYPE_I386
|
||||||
|
|
||||||
# the Haskell sub-type for `CPU_TYPE_X86_64`
|
# the Haskell sub-type for `CPU_TYPE_X86_64`
|
||||||
|
# @api private
|
||||||
CPU_SUBTYPE_X86_64_H = 8
|
CPU_SUBTYPE_X86_64_H = 8
|
||||||
|
|
||||||
# the lowest common sub-type for `CPU_TYPE_ARM`
|
# the lowest common sub-type for `CPU_TYPE_ARM`
|
||||||
|
# @api private
|
||||||
CPU_SUBTYPE_ARM_ALL = 0
|
CPU_SUBTYPE_ARM_ALL = 0
|
||||||
|
|
||||||
# the v4t sub-type for `CPU_TYPE_ARM`
|
# the v4t sub-type for `CPU_TYPE_ARM`
|
||||||
|
# @api private
|
||||||
CPU_SUBTYPE_ARM_V4T = 5
|
CPU_SUBTYPE_ARM_V4T = 5
|
||||||
|
|
||||||
# the v6 sub-type for `CPU_TYPE_ARM`
|
# the v6 sub-type for `CPU_TYPE_ARM`
|
||||||
|
# @api private
|
||||||
CPU_SUBTYPE_ARM_V6 = 6
|
CPU_SUBTYPE_ARM_V6 = 6
|
||||||
|
|
||||||
# the v5 sub-type for `CPU_TYPE_ARM`
|
# the v5 sub-type for `CPU_TYPE_ARM`
|
||||||
|
# @api private
|
||||||
CPU_SUBTYPE_ARM_V5TEJ = 7
|
CPU_SUBTYPE_ARM_V5TEJ = 7
|
||||||
|
|
||||||
# the xscale (v5 family) sub-type for `CPU_TYPE_ARM`
|
# the xscale (v5 family) sub-type for `CPU_TYPE_ARM`
|
||||||
|
# @api private
|
||||||
CPU_SUBTYPE_ARM_XSCALE = 8
|
CPU_SUBTYPE_ARM_XSCALE = 8
|
||||||
|
|
||||||
# the v7 sub-type for `CPU_TYPE_ARM`
|
# the v7 sub-type for `CPU_TYPE_ARM`
|
||||||
|
# @api private
|
||||||
CPU_SUBTYPE_ARM_V7 = 9
|
CPU_SUBTYPE_ARM_V7 = 9
|
||||||
|
|
||||||
# the v7f (Cortex A9) sub-type for `CPU_TYPE_ARM`
|
# the v7f (Cortex A9) sub-type for `CPU_TYPE_ARM`
|
||||||
|
# @api private
|
||||||
CPU_SUBTYPE_ARM_V7F = 10
|
CPU_SUBTYPE_ARM_V7F = 10
|
||||||
|
|
||||||
# the v7s ("Swift") sub-type for `CPU_TYPE_ARM`
|
# the v7s ("Swift") sub-type for `CPU_TYPE_ARM`
|
||||||
|
# @api private
|
||||||
CPU_SUBTYPE_ARM_V7S = 11
|
CPU_SUBTYPE_ARM_V7S = 11
|
||||||
|
|
||||||
# the v7k ("Kirkwood40") sub-type for `CPU_TYPE_ARM`
|
# the v7k ("Kirkwood40") sub-type for `CPU_TYPE_ARM`
|
||||||
|
# @api private
|
||||||
CPU_SUBTYPE_ARM_V7K = 12
|
CPU_SUBTYPE_ARM_V7K = 12
|
||||||
|
|
||||||
# the v6m sub-type for `CPU_TYPE_ARM`
|
# the v6m sub-type for `CPU_TYPE_ARM`
|
||||||
|
# @api private
|
||||||
CPU_SUBTYPE_ARM_V6M = 14
|
CPU_SUBTYPE_ARM_V6M = 14
|
||||||
|
|
||||||
# the v7m sub-type for `CPU_TYPE_ARM`
|
# the v7m sub-type for `CPU_TYPE_ARM`
|
||||||
|
# @api private
|
||||||
CPU_SUBTYPE_ARM_V7M = 15
|
CPU_SUBTYPE_ARM_V7M = 15
|
||||||
|
|
||||||
# the v7em sub-type for `CPU_TYPE_ARM`
|
# the v7em sub-type for `CPU_TYPE_ARM`
|
||||||
|
# @api private
|
||||||
CPU_SUBTYPE_ARM_V7EM = 16
|
CPU_SUBTYPE_ARM_V7EM = 16
|
||||||
|
|
||||||
# the v8 sub-type for `CPU_TYPE_ARM`
|
# the v8 sub-type for `CPU_TYPE_ARM`
|
||||||
|
# @api private
|
||||||
CPU_SUBTYPE_ARM_V8 = 13
|
CPU_SUBTYPE_ARM_V8 = 13
|
||||||
|
|
||||||
# the lowest common sub-type for `CPU_TYPE_ARM64`
|
# the lowest common sub-type for `CPU_TYPE_ARM64`
|
||||||
|
# @api private
|
||||||
CPU_SUBTYPE_ARM64_ALL = 0
|
CPU_SUBTYPE_ARM64_ALL = 0
|
||||||
|
|
||||||
# the v8 sub-type for `CPU_TYPE_ARM64`
|
# the v8 sub-type for `CPU_TYPE_ARM64`
|
||||||
|
# @api private
|
||||||
CPU_SUBTYPE_ARM64_V8 = 1
|
CPU_SUBTYPE_ARM64_V8 = 1
|
||||||
|
|
||||||
# the lowest common sub-type for `CPU_TYPE_MC88000`
|
# the lowest common sub-type for `CPU_TYPE_MC88000`
|
||||||
|
# @api private
|
||||||
CPU_SUBTYPE_MC88000_ALL = 0
|
CPU_SUBTYPE_MC88000_ALL = 0
|
||||||
|
|
||||||
|
# @see CPU_SUBTYPE_MC88000_ALL
|
||||||
|
# @api private
|
||||||
CPU_SUBTYPE_MMAX_JPC = CPU_SUBTYPE_MC88000_ALL
|
CPU_SUBTYPE_MMAX_JPC = CPU_SUBTYPE_MC88000_ALL
|
||||||
|
|
||||||
# the 100 sub-type for `CPU_TYPE_MC88000`
|
# the 100 sub-type for `CPU_TYPE_MC88000`
|
||||||
|
# @api private
|
||||||
CPU_SUBTYPE_MC88100 = 1
|
CPU_SUBTYPE_MC88100 = 1
|
||||||
|
|
||||||
# the 110 sub-type for `CPU_TYPE_MC88000`
|
# the 110 sub-type for `CPU_TYPE_MC88000`
|
||||||
|
# @api private
|
||||||
CPU_SUBTYPE_MC88110 = 2
|
CPU_SUBTYPE_MC88110 = 2
|
||||||
|
|
||||||
# the lowest common sub-type for `CPU_TYPE_POWERPC`
|
# the lowest common sub-type for `CPU_TYPE_POWERPC`
|
||||||
|
# @api private
|
||||||
CPU_SUBTYPE_POWERPC_ALL = 0
|
CPU_SUBTYPE_POWERPC_ALL = 0
|
||||||
|
|
||||||
# the 601 sub-type for `CPU_TYPE_POWERPC`
|
# the 601 sub-type for `CPU_TYPE_POWERPC`
|
||||||
|
# @api private
|
||||||
CPU_SUBTYPE_POWERPC_601 = 1
|
CPU_SUBTYPE_POWERPC_601 = 1
|
||||||
|
|
||||||
# the 602 sub-type for `CPU_TYPE_POWERPC`
|
# the 602 sub-type for `CPU_TYPE_POWERPC`
|
||||||
|
# @api private
|
||||||
CPU_SUBTYPE_POWERPC_602 = 2
|
CPU_SUBTYPE_POWERPC_602 = 2
|
||||||
|
|
||||||
# the 603 sub-type for `CPU_TYPE_POWERPC`
|
# the 603 sub-type for `CPU_TYPE_POWERPC`
|
||||||
|
# @api private
|
||||||
CPU_SUBTYPE_POWERPC_603 = 3
|
CPU_SUBTYPE_POWERPC_603 = 3
|
||||||
|
|
||||||
# the 603e (G2) sub-type for `CPU_TYPE_POWERPC`
|
# the 603e (G2) sub-type for `CPU_TYPE_POWERPC`
|
||||||
|
# @api private
|
||||||
CPU_SUBTYPE_POWERPC_603E = 4
|
CPU_SUBTYPE_POWERPC_603E = 4
|
||||||
|
|
||||||
# the 603ev sub-type for `CPU_TYPE_POWERPC`
|
# the 603ev sub-type for `CPU_TYPE_POWERPC`
|
||||||
|
# @api private
|
||||||
CPU_SUBTYPE_POWERPC_603EV = 5
|
CPU_SUBTYPE_POWERPC_603EV = 5
|
||||||
|
|
||||||
# the 604 sub-type for `CPU_TYPE_POWERPC`
|
# the 604 sub-type for `CPU_TYPE_POWERPC`
|
||||||
|
# @api private
|
||||||
CPU_SUBTYPE_POWERPC_604 = 6
|
CPU_SUBTYPE_POWERPC_604 = 6
|
||||||
|
|
||||||
# the 604e sub-type for `CPU_TYPE_POWERPC`
|
# the 604e sub-type for `CPU_TYPE_POWERPC`
|
||||||
|
# @api private
|
||||||
CPU_SUBTYPE_POWERPC_604E = 7
|
CPU_SUBTYPE_POWERPC_604E = 7
|
||||||
|
|
||||||
# the 620 sub-type for `CPU_TYPE_POWERPC`
|
# the 620 sub-type for `CPU_TYPE_POWERPC`
|
||||||
|
# @api private
|
||||||
CPU_SUBTYPE_POWERPC_620 = 8
|
CPU_SUBTYPE_POWERPC_620 = 8
|
||||||
|
|
||||||
# the 750 (G3) sub-type for `CPU_TYPE_POWERPC`
|
# the 750 (G3) sub-type for `CPU_TYPE_POWERPC`
|
||||||
|
# @api private
|
||||||
CPU_SUBTYPE_POWERPC_750 = 9
|
CPU_SUBTYPE_POWERPC_750 = 9
|
||||||
|
|
||||||
# the 7400 (G4) sub-type for `CPU_TYPE_POWERPC`
|
# the 7400 (G4) sub-type for `CPU_TYPE_POWERPC`
|
||||||
|
# @api private
|
||||||
CPU_SUBTYPE_POWERPC_7400 = 10
|
CPU_SUBTYPE_POWERPC_7400 = 10
|
||||||
|
|
||||||
# the 7450 (G4 "Voyager") sub-type for `CPU_TYPE_POWERPC`
|
# the 7450 (G4 "Voyager") sub-type for `CPU_TYPE_POWERPC`
|
||||||
|
# @api private
|
||||||
CPU_SUBTYPE_POWERPC_7450 = 11
|
CPU_SUBTYPE_POWERPC_7450 = 11
|
||||||
|
|
||||||
# the 970 (G5) sub-type for `CPU_TYPE_POWERPC`
|
# the 970 (G5) sub-type for `CPU_TYPE_POWERPC`
|
||||||
|
# @api private
|
||||||
CPU_SUBTYPE_POWERPC_970 = 100
|
CPU_SUBTYPE_POWERPC_970 = 100
|
||||||
|
|
||||||
# any CPU sub-type for CPU type `CPU_TYPE_POWERPC64`
|
# any CPU sub-type for CPU type `CPU_TYPE_POWERPC64`
|
||||||
|
# @api private
|
||||||
CPU_SUBTYPE_POWERPC64_ALL = CPU_SUBTYPE_POWERPC_ALL
|
CPU_SUBTYPE_POWERPC64_ALL = CPU_SUBTYPE_POWERPC_ALL
|
||||||
|
|
||||||
# association of CPU types/subtype pairs to symbol representations in
|
# association of CPU types/subtype pairs to symbol representations in
|
||||||
# (very) roughly descending order of commonness
|
# (very) roughly descending order of commonness
|
||||||
# @see https://opensource.apple.com/source/cctools/cctools-877.8/libstuff/arch.c
|
# @see https://opensource.apple.com/source/cctools/cctools-877.8/libstuff/arch.c
|
||||||
|
# @api private
|
||||||
CPU_SUBTYPES = {
|
CPU_SUBTYPES = {
|
||||||
CPU_TYPE_I386 => {
|
CPU_TYPE_I386 => {
|
||||||
CPU_SUBTYPE_I386 => :i386,
|
CPU_SUBTYPE_I386 => :i386,
|
||||||
@ -280,53 +355,64 @@ module MachO
|
|||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
# relocatable object file
|
# relocatable object file
|
||||||
|
# @api private
|
||||||
MH_OBJECT = 0x1
|
MH_OBJECT = 0x1
|
||||||
|
|
||||||
# demand paged executable file
|
# demand paged executable file
|
||||||
|
# @api private
|
||||||
MH_EXECUTE = 0x2
|
MH_EXECUTE = 0x2
|
||||||
|
|
||||||
# fixed VM shared library file
|
# fixed VM shared library file
|
||||||
|
# @api private
|
||||||
MH_FVMLIB = 0x3
|
MH_FVMLIB = 0x3
|
||||||
|
|
||||||
# core dump file
|
# core dump file
|
||||||
|
# @api private
|
||||||
MH_CORE = 0x4
|
MH_CORE = 0x4
|
||||||
|
|
||||||
# preloaded executable file
|
# preloaded executable file
|
||||||
|
# @api private
|
||||||
MH_PRELOAD = 0x5
|
MH_PRELOAD = 0x5
|
||||||
|
|
||||||
# dynamically bound shared library
|
# dynamically bound shared library
|
||||||
|
# @api private
|
||||||
MH_DYLIB = 0x6
|
MH_DYLIB = 0x6
|
||||||
|
|
||||||
# dynamic link editor
|
# dynamic link editor
|
||||||
|
# @api private
|
||||||
MH_DYLINKER = 0x7
|
MH_DYLINKER = 0x7
|
||||||
|
|
||||||
# dynamically bound bundle file
|
# dynamically bound bundle file
|
||||||
|
# @api private
|
||||||
MH_BUNDLE = 0x8
|
MH_BUNDLE = 0x8
|
||||||
|
|
||||||
# shared library stub for static linking only, no section contents
|
# shared library stub for static linking only, no section contents
|
||||||
|
# @api private
|
||||||
MH_DYLIB_STUB = 0x9
|
MH_DYLIB_STUB = 0x9
|
||||||
|
|
||||||
# companion file with only debug sections
|
# companion file with only debug sections
|
||||||
|
# @api private
|
||||||
MH_DSYM = 0xa
|
MH_DSYM = 0xa
|
||||||
|
|
||||||
# x86_64 kexts
|
# x86_64 kexts
|
||||||
|
# @api private
|
||||||
MH_KEXT_BUNDLE = 0xb
|
MH_KEXT_BUNDLE = 0xb
|
||||||
|
|
||||||
# association of filetypes to string representations
|
# association of filetypes to Symbol representations
|
||||||
# @api private
|
# @api private
|
||||||
MH_FILETYPES = {
|
MH_FILETYPES = {
|
||||||
MH_OBJECT => "MH_OBJECT",
|
MH_OBJECT => :object,
|
||||||
MH_EXECUTE => "MH_EXECUTE",
|
MH_EXECUTE => :execute,
|
||||||
MH_FVMLIB => "MH_FVMLIB",
|
MH_FVMLIB => :fvmlib,
|
||||||
MH_CORE => "MH_CORE",
|
MH_CORE => :core,
|
||||||
MH_PRELOAD => "MH_PRELOAD",
|
MH_PRELOAD => :preload,
|
||||||
MH_DYLIB => "MH_DYLIB",
|
MH_DYLIB => :dylib,
|
||||||
MH_DYLINKER => "MH_DYLINKER",
|
MH_DYLINKER => :dylinker,
|
||||||
MH_BUNDLE => "MH_BUNDLE",
|
MH_BUNDLE => :bundle,
|
||||||
MH_DYLIB_STUB => "MH_DYLIB_STUB",
|
MH_DYLIB_STUB => :dylib_stub,
|
||||||
MH_DSYM => "MH_DSYM",
|
MH_DSYM => :dsym,
|
||||||
MH_KEXT_BUNDLE => "MH_KEXT_BUNDLE"
|
MH_KEXT_BUNDLE => :kext_bundle,
|
||||||
}
|
}.freeze
|
||||||
|
|
||||||
# association of mach header flag symbols to values
|
# association of mach header flag symbols to values
|
||||||
# @api private
|
# @api private
|
||||||
@ -356,8 +442,8 @@ module MachO
|
|||||||
:MH_DEAD_STRIPPABLE_DYLIB => 0x400000,
|
:MH_DEAD_STRIPPABLE_DYLIB => 0x400000,
|
||||||
:MH_HAS_TLV_DESCRIPTORS => 0x800000,
|
:MH_HAS_TLV_DESCRIPTORS => 0x800000,
|
||||||
:MH_NO_HEAP_EXECUTION => 0x1000000,
|
:MH_NO_HEAP_EXECUTION => 0x1000000,
|
||||||
:MH_APP_EXTENSION_SAFE => 0x02000000
|
:MH_APP_EXTENSION_SAFE => 0x02000000,
|
||||||
}
|
}.freeze
|
||||||
|
|
||||||
# Fat binary header structure
|
# Fat binary header structure
|
||||||
# @see MachO::FatArch
|
# @see MachO::FatArch
|
||||||
@ -369,7 +455,12 @@ module MachO
|
|||||||
attr_reader :nfat_arch
|
attr_reader :nfat_arch
|
||||||
|
|
||||||
# always big-endian
|
# always big-endian
|
||||||
FORMAT = "N2"
|
# @see MachOStructure::FORMAT
|
||||||
|
# @api private
|
||||||
|
FORMAT = "N2".freeze
|
||||||
|
|
||||||
|
# @see MachOStructure::SIZEOF
|
||||||
|
# @api private
|
||||||
SIZEOF = 8
|
SIZEOF = 8
|
||||||
|
|
||||||
# @api private
|
# @api private
|
||||||
@ -399,7 +490,12 @@ module MachO
|
|||||||
attr_reader :align
|
attr_reader :align
|
||||||
|
|
||||||
# always big-endian
|
# always big-endian
|
||||||
FORMAT = "N5"
|
# @see MachOStructure::FORMAT
|
||||||
|
# @api private
|
||||||
|
FORMAT = "N5".freeze
|
||||||
|
|
||||||
|
# @see MachOStructure::SIZEOF
|
||||||
|
# @api private
|
||||||
SIZEOF = 20
|
SIZEOF = 20
|
||||||
|
|
||||||
# @api private
|
# @api private
|
||||||
@ -435,12 +531,17 @@ module MachO
|
|||||||
# @return [Fixnum] the header flags associated with the Mach-O
|
# @return [Fixnum] the header flags associated with the Mach-O
|
||||||
attr_reader :flags
|
attr_reader :flags
|
||||||
|
|
||||||
FORMAT = "L=7"
|
# @see MachOStructure::FORMAT
|
||||||
|
# @api private
|
||||||
|
FORMAT = "L=7".freeze
|
||||||
|
|
||||||
|
# @see MachOStructure::SIZEOF
|
||||||
|
# @api private
|
||||||
SIZEOF = 28
|
SIZEOF = 28
|
||||||
|
|
||||||
# @api private
|
# @api private
|
||||||
def initialize(magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds,
|
def initialize(magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds,
|
||||||
flags)
|
flags)
|
||||||
@magic = magic
|
@magic = magic
|
||||||
@cputype = cputype
|
@cputype = cputype
|
||||||
# For now we're not interested in additional capability bits also to be
|
# For now we're not interested in additional capability bits also to be
|
||||||
@ -468,12 +569,17 @@ module MachO
|
|||||||
# @return [void]
|
# @return [void]
|
||||||
attr_reader :reserved
|
attr_reader :reserved
|
||||||
|
|
||||||
FORMAT = "L=8"
|
# @see MachOStructure::FORMAT
|
||||||
|
# @api private
|
||||||
|
FORMAT = "L=8".freeze
|
||||||
|
|
||||||
|
# @see MachOStructure::SIZEOF
|
||||||
|
# @api private
|
||||||
SIZEOF = 32
|
SIZEOF = 32
|
||||||
|
|
||||||
# @api private
|
# @api private
|
||||||
def initialize(magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds,
|
def initialize(magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds,
|
||||||
flags, reserved)
|
flags, reserved)
|
||||||
super(magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags)
|
super(magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags)
|
||||||
@reserved = reserved
|
@reserved = reserved
|
||||||
end
|
end
|
||||||
|
|||||||
695
Library/Homebrew/vendor/macho/macho/load_commands.rb
vendored
695
Library/Homebrew/vendor/macho/macho/load_commands.rb
vendored
File diff suppressed because it is too large
Load Diff
426
Library/Homebrew/vendor/macho/macho/macho_file.rb
vendored
426
Library/Homebrew/vendor/macho/macho/macho_file.rb
vendored
@ -16,6 +16,7 @@ module MachO
|
|||||||
attr_reader :header
|
attr_reader :header
|
||||||
|
|
||||||
# @return [Array<MachO::LoadCommand>] an array of the file's load commands
|
# @return [Array<MachO::LoadCommand>] an array of the file's load commands
|
||||||
|
# @note load commands are provided in order of ascending offset.
|
||||||
attr_reader :load_commands
|
attr_reader :load_commands
|
||||||
|
|
||||||
# Creates a new MachOFile instance from a binary string.
|
# Creates a new MachOFile instance from a binary string.
|
||||||
@ -32,20 +33,20 @@ module MachO
|
|||||||
# @param filename [String] the Mach-O file to load from
|
# @param filename [String] the Mach-O file to load from
|
||||||
# @raise [ArgumentError] if the given file does not exist
|
# @raise [ArgumentError] if the given file does not exist
|
||||||
def initialize(filename)
|
def initialize(filename)
|
||||||
raise ArgumentError.new("#{filename}: no such file") unless File.file?(filename)
|
raise ArgumentError, "#{filename}: no such file" unless File.file?(filename)
|
||||||
|
|
||||||
@filename = filename
|
@filename = filename
|
||||||
@raw_data = File.open(@filename, "rb") { |f| f.read }
|
@raw_data = File.open(@filename, "rb", &:read)
|
||||||
@header = get_mach_header
|
populate_fields
|
||||||
@load_commands = get_load_commands
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Initializes a new MachOFile instance from a binary string.
|
||||||
|
# @see MachO::MachOFile.new_from_bin
|
||||||
# @api private
|
# @api private
|
||||||
def initialize_from_bin(bin)
|
def initialize_from_bin(bin)
|
||||||
@filename = nil
|
@filename = nil
|
||||||
@raw_data = bin
|
@raw_data = bin
|
||||||
@header = get_mach_header
|
populate_fields
|
||||||
@load_commands = get_load_commands
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# The file's raw Mach-O data.
|
# The file's raw Mach-O data.
|
||||||
@ -56,12 +57,17 @@ module MachO
|
|||||||
|
|
||||||
# @return [Boolean] true if the Mach-O has 32-bit magic, false otherwise
|
# @return [Boolean] true if the Mach-O has 32-bit magic, false otherwise
|
||||||
def magic32?
|
def magic32?
|
||||||
MachO.magic32?(header.magic)
|
Utils.magic32?(header.magic)
|
||||||
end
|
end
|
||||||
|
|
||||||
# @return [Boolean] true if the Mach-O has 64-bit magic, false otherwise
|
# @return [Boolean] true if the Mach-O has 64-bit magic, false otherwise
|
||||||
def magic64?
|
def magic64?
|
||||||
MachO.magic64?(header.magic)
|
Utils.magic64?(header.magic)
|
||||||
|
end
|
||||||
|
|
||||||
|
# @return [Fixnum] the file's internal alignment
|
||||||
|
def alignment
|
||||||
|
magic32? ? 4 : 8
|
||||||
end
|
end
|
||||||
|
|
||||||
# @return [Boolean] true if the file is of type `MH_OBJECT`, false otherwise
|
# @return [Boolean] true if the file is of type `MH_OBJECT`, false otherwise
|
||||||
@ -124,7 +130,7 @@ module MachO
|
|||||||
MH_MAGICS[magic]
|
MH_MAGICS[magic]
|
||||||
end
|
end
|
||||||
|
|
||||||
# @return [String] a string representation of the Mach-O's filetype
|
# @return [Symbol] a string representation of the Mach-O's filetype
|
||||||
def filetype
|
def filetype
|
||||||
MH_FILETYPES[header.filetype]
|
MH_FILETYPES[header.filetype]
|
||||||
end
|
end
|
||||||
@ -164,7 +170,109 @@ module MachO
|
|||||||
load_commands.select { |lc| lc.type == name.to_sym }
|
load_commands.select { |lc| lc.type == name.to_sym }
|
||||||
end
|
end
|
||||||
|
|
||||||
alias :[] :command
|
alias [] command
|
||||||
|
|
||||||
|
# Inserts a load command at the given offset.
|
||||||
|
# @param offset [Fixnum] the offset to insert at
|
||||||
|
# @param lc [MachO::LoadCommand] the load command to insert
|
||||||
|
# @param options [Hash]
|
||||||
|
# @option options [Boolean] :repopulate (true) whether or not to repopulate
|
||||||
|
# the instance fields
|
||||||
|
# @raise [MachO::OffsetInsertionError] if the offset is not in the load command region
|
||||||
|
# @raise [MachO::HeaderPadError] if the new command exceeds the header pad buffer
|
||||||
|
# @note Calling this method with an arbitrary offset in the load command
|
||||||
|
# region **will leave the object in an inconsistent state**.
|
||||||
|
def insert_command(offset, lc, options = {})
|
||||||
|
context = LoadCommand::SerializationContext.context_for(self)
|
||||||
|
cmd_raw = lc.serialize(context)
|
||||||
|
|
||||||
|
if offset < header.class.bytesize || offset + cmd_raw.bytesize > low_fileoff
|
||||||
|
raise OffsetInsertionError, offset
|
||||||
|
end
|
||||||
|
|
||||||
|
new_sizeofcmds = sizeofcmds + cmd_raw.bytesize
|
||||||
|
|
||||||
|
if header.class.bytesize + new_sizeofcmds > low_fileoff
|
||||||
|
raise HeaderPadError, @filename
|
||||||
|
end
|
||||||
|
|
||||||
|
# update Mach-O header fields to account for inserted load command
|
||||||
|
update_ncmds(ncmds + 1)
|
||||||
|
update_sizeofcmds(new_sizeofcmds)
|
||||||
|
|
||||||
|
@raw_data.insert(offset, cmd_raw)
|
||||||
|
@raw_data.slice!(header.class.bytesize + new_sizeofcmds, cmd_raw.bytesize)
|
||||||
|
|
||||||
|
populate_fields if options.fetch(:repopulate, true)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Replace a load command with another command in the Mach-O, preserving location.
|
||||||
|
# @param old_lc [MachO::LoadCommand] the load command being replaced
|
||||||
|
# @param new_lc [MachO::LoadCommand] the load command being added
|
||||||
|
# @return [void]
|
||||||
|
# @raise [MachO::HeaderPadError] if the new command exceeds the header pad buffer
|
||||||
|
# @see {#insert_command}
|
||||||
|
# @note This is public, but methods like {#dylib_id=} should be preferred.
|
||||||
|
def replace_command(old_lc, new_lc)
|
||||||
|
context = LoadCommand::SerializationContext.context_for(self)
|
||||||
|
cmd_raw = new_lc.serialize(context)
|
||||||
|
new_sizeofcmds = sizeofcmds + cmd_raw.bytesize - old_lc.cmdsize
|
||||||
|
if header.class.bytesize + new_sizeofcmds > low_fileoff
|
||||||
|
raise HeaderPadError, @filename
|
||||||
|
end
|
||||||
|
|
||||||
|
delete_command(old_lc)
|
||||||
|
insert_command(old_lc.view.offset, new_lc)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Appends a new load command to the Mach-O.
|
||||||
|
# @param lc [MachO::LoadCommand] the load command being added
|
||||||
|
# @param options [Hash]
|
||||||
|
# @option options [Boolean] :repopulate (true) whether or not to repopulate
|
||||||
|
# the instance fields
|
||||||
|
# @return [void]
|
||||||
|
# @see {#insert_command}
|
||||||
|
# @note This is public, but methods like {#add_rpath} should be preferred.
|
||||||
|
# Setting `repopulate` to false **will leave the instance in an
|
||||||
|
# inconsistent state** unless {#populate_fields} is called **immediately**
|
||||||
|
# afterwards.
|
||||||
|
def add_command(lc, options = {})
|
||||||
|
insert_command(header.class.bytesize + sizeofcmds, lc, options)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Delete a load command from the Mach-O.
|
||||||
|
# @param lc [MachO::LoadCommand] the load command being deleted
|
||||||
|
# @param options [Hash]
|
||||||
|
# @option options [Boolean] :repopulate (true) whether or not to repopulate
|
||||||
|
# the instance fields
|
||||||
|
# @return [void]
|
||||||
|
# @note This is public, but methods like {#delete_rpath} should be preferred.
|
||||||
|
# Setting `repopulate` to false **will leave the instance in an
|
||||||
|
# inconsistent state** unless {#populate_fields} is called **immediately**
|
||||||
|
# afterwards.
|
||||||
|
def delete_command(lc, options = {})
|
||||||
|
@raw_data.slice!(lc.view.offset, lc.cmdsize)
|
||||||
|
|
||||||
|
# update Mach-O header fields to account for deleted load command
|
||||||
|
update_ncmds(ncmds - 1)
|
||||||
|
update_sizeofcmds(sizeofcmds - lc.cmdsize)
|
||||||
|
|
||||||
|
# pad the space after the load commands to preserve offsets
|
||||||
|
null_pad = "\x00" * lc.cmdsize
|
||||||
|
@raw_data.insert(header.class.bytesize + sizeofcmds - lc.cmdsize, null_pad)
|
||||||
|
|
||||||
|
populate_fields if options.fetch(:repopulate, true)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Populate the instance's fields with the raw Mach-O data.
|
||||||
|
# @return [void]
|
||||||
|
# @note This method is public, but should (almost) never need to be called.
|
||||||
|
# The exception to this rule is when methods like {#add_command} and
|
||||||
|
# {#delete_command} have been called with `repopulate = false`.
|
||||||
|
def populate_fields
|
||||||
|
@header = populate_mach_header
|
||||||
|
@load_commands = populate_load_commands
|
||||||
|
end
|
||||||
|
|
||||||
# All load commands responsible for loading dylibs.
|
# All load commands responsible for loading dylibs.
|
||||||
# @return [Array<MachO::DylibCommand>] an array of DylibCommands
|
# @return [Array<MachO::DylibCommand>] an array of DylibCommands
|
||||||
@ -188,9 +296,7 @@ module MachO
|
|||||||
# file.dylib_id # => 'libBar.dylib'
|
# file.dylib_id # => 'libBar.dylib'
|
||||||
# @return [String, nil] the Mach-O's dylib ID
|
# @return [String, nil] the Mach-O's dylib ID
|
||||||
def dylib_id
|
def dylib_id
|
||||||
if !dylib?
|
return unless dylib?
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
dylib_id_cmd = command(:LC_ID_DYLIB).first
|
dylib_id_cmd = command(:LC_ID_DYLIB).first
|
||||||
|
|
||||||
@ -199,25 +305,30 @@ module MachO
|
|||||||
|
|
||||||
# Changes the Mach-O's dylib ID to `new_id`. Does nothing if not a dylib.
|
# Changes the Mach-O's dylib ID to `new_id`. Does nothing if not a dylib.
|
||||||
# @example
|
# @example
|
||||||
# file.dylib_id = "libFoo.dylib"
|
# file.change_dylib_id("libFoo.dylib")
|
||||||
# @param new_id [String] the dylib's new ID
|
# @param new_id [String] the dylib's new ID
|
||||||
|
# @param _options [Hash]
|
||||||
# @return [void]
|
# @return [void]
|
||||||
# @raise [ArgumentError] if `new_id` is not a String
|
# @raise [ArgumentError] if `new_id` is not a String
|
||||||
def dylib_id=(new_id)
|
# @note `_options` is currently unused and is provided for signature
|
||||||
if !new_id.is_a?(String)
|
# compatibility with {MachO::FatFile#change_dylib_id}
|
||||||
raise ArgumentError.new("argument must be a String")
|
def change_dylib_id(new_id, _options = {})
|
||||||
end
|
raise ArgumentError, "new ID must be a String" unless new_id.is_a?(String)
|
||||||
|
return unless dylib?
|
||||||
|
|
||||||
if !dylib?
|
old_lc = command(:LC_ID_DYLIB).first
|
||||||
return nil
|
raise DylibIdMissingError unless old_lc
|
||||||
end
|
|
||||||
|
|
||||||
dylib_cmd = command(:LC_ID_DYLIB).first
|
new_lc = LoadCommand.create(:LC_ID_DYLIB, new_id,
|
||||||
old_id = dylib_id
|
old_lc.timestamp,
|
||||||
|
old_lc.current_version,
|
||||||
|
old_lc.compatibility_version)
|
||||||
|
|
||||||
set_name_in_dylib(dylib_cmd, old_id, new_id)
|
replace_command(old_lc, new_lc)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
alias dylib_id= change_dylib_id
|
||||||
|
|
||||||
# All shared libraries linked to the Mach-O.
|
# All shared libraries linked to the Mach-O.
|
||||||
# @return [Array<String>] an array of all shared libraries
|
# @return [Array<String>] an array of all shared libraries
|
||||||
def linked_dylibs
|
def linked_dylibs
|
||||||
@ -233,16 +344,24 @@ module MachO
|
|||||||
# file.change_install_name("/usr/lib/libWhatever.dylib", "/usr/local/lib/libWhatever2.dylib")
|
# file.change_install_name("/usr/lib/libWhatever.dylib", "/usr/local/lib/libWhatever2.dylib")
|
||||||
# @param old_name [String] the shared library's old name
|
# @param old_name [String] the shared library's old name
|
||||||
# @param new_name [String] the shared library's new name
|
# @param new_name [String] the shared library's new name
|
||||||
|
# @param _options [Hash]
|
||||||
# @return [void]
|
# @return [void]
|
||||||
# @raise [MachO::DylibUnknownError] if no shared library has the old name
|
# @raise [MachO::DylibUnknownError] if no shared library has the old name
|
||||||
def change_install_name(old_name, new_name)
|
# @note `_options` is currently unused and is provided for signature
|
||||||
dylib_cmd = dylib_load_commands.find { |d| d.name.to_s == old_name }
|
# compatibility with {MachO::FatFile#change_install_name}
|
||||||
raise DylibUnknownError.new(old_name) if dylib_cmd.nil?
|
def change_install_name(old_name, new_name, _options = {})
|
||||||
|
old_lc = dylib_load_commands.find { |d| d.name.to_s == old_name }
|
||||||
|
raise DylibUnknownError, old_name if old_lc.nil?
|
||||||
|
|
||||||
set_name_in_dylib(dylib_cmd, old_name, new_name)
|
new_lc = LoadCommand.create(old_lc.type, new_name,
|
||||||
|
old_lc.timestamp,
|
||||||
|
old_lc.current_version,
|
||||||
|
old_lc.compatibility_version)
|
||||||
|
|
||||||
|
replace_command(old_lc, new_lc)
|
||||||
end
|
end
|
||||||
|
|
||||||
alias :change_dylib :change_install_name
|
alias change_dylib change_install_name
|
||||||
|
|
||||||
# All runtime paths searched by the dynamic linker for the Mach-O.
|
# All runtime paths searched by the dynamic linker for the Mach-O.
|
||||||
# @return [Array<String>] an array of all runtime paths
|
# @return [Array<String>] an array of all runtime paths
|
||||||
@ -255,44 +374,70 @@ module MachO
|
|||||||
# file.change_rpath("/usr/lib", "/usr/local/lib")
|
# file.change_rpath("/usr/lib", "/usr/local/lib")
|
||||||
# @param old_path [String] the old runtime path
|
# @param old_path [String] the old runtime path
|
||||||
# @param new_path [String] the new runtime path
|
# @param new_path [String] the new runtime path
|
||||||
|
# @param _options [Hash]
|
||||||
# @return [void]
|
# @return [void]
|
||||||
# @raise [MachO::RpathUnknownError] if no such old runtime path exists
|
# @raise [MachO::RpathUnknownError] if no such old runtime path exists
|
||||||
# @api private
|
# @raise [MachO::RpathExistsError] if the new runtime path already exists
|
||||||
def change_rpath(old_path, new_path)
|
# @note `_options` is currently unused and is provided for signature
|
||||||
rpath_cmd = command(:LC_RPATH).find { |r| r.path.to_s == old_path }
|
# compatibility with {MachO::FatFile#change_rpath}
|
||||||
raise RpathUnknownError.new(old_path) if rpath_cmd.nil?
|
def change_rpath(old_path, new_path, _options = {})
|
||||||
|
old_lc = command(:LC_RPATH).find { |r| r.path.to_s == old_path }
|
||||||
|
raise RpathUnknownError, old_path if old_lc.nil?
|
||||||
|
raise RpathExistsError, new_path if rpaths.include?(new_path)
|
||||||
|
|
||||||
set_path_in_rpath(rpath_cmd, old_path, new_path)
|
new_lc = LoadCommand.create(:LC_RPATH, new_path)
|
||||||
|
|
||||||
|
delete_rpath(old_path)
|
||||||
|
insert_command(old_lc.view.offset, new_lc)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Add the given runtime path to the Mach-O.
|
||||||
|
# @example
|
||||||
|
# file.rpaths # => ["/lib"]
|
||||||
|
# file.add_rpath("/usr/lib")
|
||||||
|
# file.rpaths # => ["/lib", "/usr/lib"]
|
||||||
|
# @param path [String] the new runtime path
|
||||||
|
# @param _options [Hash]
|
||||||
|
# @return [void]
|
||||||
|
# @raise [MachO::RpathExistsError] if the runtime path already exists
|
||||||
|
# @note `_options` is currently unused and is provided for signature
|
||||||
|
# compatibility with {MachO::FatFile#add_rpath}
|
||||||
|
def add_rpath(path, _options = {})
|
||||||
|
raise RpathExistsError, path if rpaths.include?(path)
|
||||||
|
|
||||||
|
rpath_cmd = LoadCommand.create(:LC_RPATH, path)
|
||||||
|
add_command(rpath_cmd)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Delete the given runtime path from the Mach-O.
|
||||||
|
# @example
|
||||||
|
# file.rpaths # => ["/lib"]
|
||||||
|
# file.delete_rpath("/lib")
|
||||||
|
# file.rpaths # => []
|
||||||
|
# @param path [String] the runtime path to delete
|
||||||
|
# @param _options [Hash]
|
||||||
|
# @return void
|
||||||
|
# @raise [MachO::RpathUnknownError] if no such runtime path exists
|
||||||
|
# @note `_options` is currently unused and is provided for signature
|
||||||
|
# compatibility with {MachO::FatFile#delete_rpath}
|
||||||
|
def delete_rpath(path, _options = {})
|
||||||
|
rpath_cmds = command(:LC_RPATH).select { |r| r.path.to_s == path }
|
||||||
|
raise RpathUnknownError, path if rpath_cmds.empty?
|
||||||
|
|
||||||
|
# delete the commands in reverse order, offset descending. this
|
||||||
|
# allows us to defer (expensive) field population until the very end
|
||||||
|
rpath_cmds.reverse_each { |cmd| delete_command(cmd, :repopulate => false) }
|
||||||
|
|
||||||
|
populate_fields
|
||||||
end
|
end
|
||||||
|
|
||||||
# All sections of the segment `segment`.
|
# All sections of the segment `segment`.
|
||||||
# @param segment [MachO::SegmentCommand, MachO::SegmentCommand64] the segment being inspected
|
# @param segment [MachO::SegmentCommand, MachO::SegmentCommand64] the segment being inspected
|
||||||
# @return [Array<MachO::Section>] if the Mach-O is 32-bit
|
# @return [Array<MachO::Section>] if the Mach-O is 32-bit
|
||||||
# @return [Array<MachO::Section64>] if the Mach-O is 64-bit
|
# @return [Array<MachO::Section64>] if the Mach-O is 64-bit
|
||||||
|
# @deprecated use {MachO::SegmentCommand#sections} instead
|
||||||
def sections(segment)
|
def sections(segment)
|
||||||
sections = []
|
segment.sections
|
||||||
|
|
||||||
if !segment.is_a?(SegmentCommand) && !segment.is_a?(SegmentCommand64)
|
|
||||||
raise ArgumentError.new("not a valid segment")
|
|
||||||
end
|
|
||||||
|
|
||||||
if segment.nsects.zero?
|
|
||||||
return sections
|
|
||||||
end
|
|
||||||
|
|
||||||
offset = segment.offset + segment.class.bytesize
|
|
||||||
|
|
||||||
segment.nsects.times do
|
|
||||||
if segment.is_a? SegmentCommand
|
|
||||||
sections << Section.new_from_bin(endianness, @raw_data.slice(offset, Section.bytesize))
|
|
||||||
offset += Section.bytesize
|
|
||||||
else
|
|
||||||
sections << Section64.new_from_bin(endianness, @raw_data.slice(offset, Section64.bytesize))
|
|
||||||
offset += Section64.bytesize
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
sections
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Write all Mach-O data to the given filename.
|
# Write all Mach-O data to the given filename.
|
||||||
@ -308,7 +453,7 @@ module MachO
|
|||||||
# @note Overwrites all data in the file!
|
# @note Overwrites all data in the file!
|
||||||
def write!
|
def write!
|
||||||
if @filename.nil?
|
if @filename.nil?
|
||||||
raise MachOError.new("cannot write to a default file when initialized from a binary string")
|
raise MachOError, "cannot write to a default file when initialized from a binary string"
|
||||||
else
|
else
|
||||||
File.open(@filename, "wb") { |f| f.write(@raw_data) }
|
File.open(@filename, "wb") { |f| f.write(@raw_data) }
|
||||||
end
|
end
|
||||||
@ -320,13 +465,13 @@ module MachO
|
|||||||
# @return [MachO::MachHeader] if the Mach-O is 32-bit
|
# @return [MachO::MachHeader] if the Mach-O is 32-bit
|
||||||
# @return [MachO::MachHeader64] if the Mach-O is 64-bit
|
# @return [MachO::MachHeader64] if the Mach-O is 64-bit
|
||||||
# @raise [MachO::TruncatedFileError] if the file is too small to have a valid header
|
# @raise [MachO::TruncatedFileError] if the file is too small to have a valid header
|
||||||
# @private
|
# @api private
|
||||||
def get_mach_header
|
def populate_mach_header
|
||||||
# the smallest Mach-O header is 28 bytes
|
# the smallest Mach-O header is 28 bytes
|
||||||
raise TruncatedFileError.new if @raw_data.size < 28
|
raise TruncatedFileError if @raw_data.size < 28
|
||||||
|
|
||||||
magic = get_and_check_magic
|
magic = populate_and_check_magic
|
||||||
mh_klass = MachO.magic32?(magic) ? MachHeader : MachHeader64
|
mh_klass = Utils.magic32?(magic) ? MachHeader : MachHeader64
|
||||||
mh = mh_klass.new_from_bin(endianness, @raw_data[0, mh_klass.bytesize])
|
mh = mh_klass.new_from_bin(endianness, @raw_data[0, mh_klass.bytesize])
|
||||||
|
|
||||||
check_cputype(mh.cputype)
|
check_cputype(mh.cputype)
|
||||||
@ -340,14 +485,14 @@ module MachO
|
|||||||
# @return [Fixnum] the magic
|
# @return [Fixnum] the magic
|
||||||
# @raise [MachO::MagicError] if the magic is not valid Mach-O magic
|
# @raise [MachO::MagicError] if the magic is not valid Mach-O magic
|
||||||
# @raise [MachO::FatBinaryError] if the magic is for a Fat file
|
# @raise [MachO::FatBinaryError] if the magic is for a Fat file
|
||||||
# @private
|
# @api private
|
||||||
def get_and_check_magic
|
def populate_and_check_magic
|
||||||
magic = @raw_data[0..3].unpack("N").first
|
magic = @raw_data[0..3].unpack("N").first
|
||||||
|
|
||||||
raise MagicError.new(magic) unless MachO.magic?(magic)
|
raise MagicError, magic unless Utils.magic?(magic)
|
||||||
raise FatBinaryError.new if MachO.fat_magic?(magic)
|
raise FatBinaryError if Utils.fat_magic?(magic)
|
||||||
|
|
||||||
@endianness = MachO.little_magic?(magic) ? :little : :big
|
@endianness = Utils.little_magic?(magic) ? :little : :big
|
||||||
|
|
||||||
magic
|
magic
|
||||||
end
|
end
|
||||||
@ -355,47 +500,48 @@ module MachO
|
|||||||
# Check the file's CPU type.
|
# Check the file's CPU type.
|
||||||
# @param cputype [Fixnum] the CPU type
|
# @param cputype [Fixnum] the CPU type
|
||||||
# @raise [MachO::CPUTypeError] if the CPU type is unknown
|
# @raise [MachO::CPUTypeError] if the CPU type is unknown
|
||||||
# @private
|
# @api private
|
||||||
def check_cputype(cputype)
|
def check_cputype(cputype)
|
||||||
raise CPUTypeError.new(cputype) unless CPU_TYPES.key?(cputype)
|
raise CPUTypeError, cputype unless CPU_TYPES.key?(cputype)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Check the file's CPU type/subtype pair.
|
# Check the file's CPU type/subtype pair.
|
||||||
# @param cpusubtype [Fixnum] the CPU subtype
|
# @param cpusubtype [Fixnum] the CPU subtype
|
||||||
# @raise [MachO::CPUSubtypeError] if the CPU sub-type is unknown
|
# @raise [MachO::CPUSubtypeError] if the CPU sub-type is unknown
|
||||||
# @private
|
# @api private
|
||||||
def check_cpusubtype(cputype, cpusubtype)
|
def check_cpusubtype(cputype, cpusubtype)
|
||||||
# Only check sub-type w/o capability bits (see `get_mach_header`).
|
# Only check sub-type w/o capability bits (see `populate_mach_header`).
|
||||||
raise CPUSubtypeError.new(cputype, cpusubtype) unless CPU_SUBTYPES[cputype].key?(cpusubtype)
|
raise CPUSubtypeError.new(cputype, cpusubtype) unless CPU_SUBTYPES[cputype].key?(cpusubtype)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Check the file's type.
|
# Check the file's type.
|
||||||
# @param filetype [Fixnum] the file type
|
# @param filetype [Fixnum] the file type
|
||||||
# @raise [MachO::FiletypeError] if the file type is unknown
|
# @raise [MachO::FiletypeError] if the file type is unknown
|
||||||
# @private
|
# @api private
|
||||||
def check_filetype(filetype)
|
def check_filetype(filetype)
|
||||||
raise FiletypeError.new(filetype) unless MH_FILETYPES.key?(filetype)
|
raise FiletypeError, filetype unless MH_FILETYPES.key?(filetype)
|
||||||
end
|
end
|
||||||
|
|
||||||
# All load commands in the file.
|
# All load commands in the file.
|
||||||
# @return [Array<MachO::LoadCommand>] an array of load commands
|
# @return [Array<MachO::LoadCommand>] an array of load commands
|
||||||
# @raise [MachO::LoadCommandError] if an unknown load command is encountered
|
# @raise [MachO::LoadCommandError] if an unknown load command is encountered
|
||||||
# @private
|
# @api private
|
||||||
def get_load_commands
|
def populate_load_commands
|
||||||
offset = header.class.bytesize
|
offset = header.class.bytesize
|
||||||
load_commands = []
|
load_commands = []
|
||||||
|
|
||||||
header.ncmds.times do
|
header.ncmds.times do
|
||||||
fmt = (endianness == :little) ? "L<" : "L>"
|
fmt = Utils.specialize_format("L=", endianness)
|
||||||
cmd = @raw_data.slice(offset, 4).unpack(fmt).first
|
cmd = @raw_data.slice(offset, 4).unpack(fmt).first
|
||||||
cmd_sym = LOAD_COMMANDS[cmd]
|
cmd_sym = LOAD_COMMANDS[cmd]
|
||||||
|
|
||||||
raise LoadCommandError.new(cmd) if cmd_sym.nil?
|
raise LoadCommandError, cmd if cmd_sym.nil?
|
||||||
|
|
||||||
# why do I do this? i don't like declaring constants below
|
# why do I do this? i don't like declaring constants below
|
||||||
# classes, and i need them to resolve...
|
# classes, and i need them to resolve...
|
||||||
klass = MachO.const_get "#{LC_STRUCTURES[cmd_sym]}"
|
klass = MachO.const_get LC_STRUCTURES[cmd_sym]
|
||||||
command = klass.new_from_bin(@raw_data, endianness, offset, @raw_data.slice(offset, klass.bytesize))
|
view = MachOView.new(@raw_data, endianness, offset)
|
||||||
|
command = klass.new_from_bin(view)
|
||||||
|
|
||||||
load_commands << command
|
load_commands << command
|
||||||
offset += command.cmdsize
|
offset += command.cmdsize
|
||||||
@ -404,108 +550,44 @@ module MachO
|
|||||||
load_commands
|
load_commands
|
||||||
end
|
end
|
||||||
|
|
||||||
# Updates the size of all load commands in the raw data.
|
# The low file offset (offset to first section data).
|
||||||
# @param size [Fixnum] the new size, in bytes
|
# @return [Fixnum] the offset
|
||||||
# @return [void]
|
# @api private
|
||||||
# @private
|
def low_fileoff
|
||||||
def set_sizeofcmds(size)
|
offset = @raw_data.size
|
||||||
fmt = (endianness == :little) ? "L<" : "L>"
|
|
||||||
new_size = [size].pack(fmt)
|
|
||||||
@raw_data[20..23] = new_size
|
|
||||||
end
|
|
||||||
|
|
||||||
# Updates the `name` field in a DylibCommand.
|
|
||||||
# @param dylib_cmd [MachO::DylibCommand] the dylib command
|
|
||||||
# @param old_name [String] the old dylib name
|
|
||||||
# @param new_name [String] the new dylib name
|
|
||||||
# @return [void]
|
|
||||||
# @private
|
|
||||||
def set_name_in_dylib(dylib_cmd, old_name, new_name)
|
|
||||||
set_lc_str_in_cmd(dylib_cmd, dylib_cmd.name, old_name, new_name)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Updates the `path` field in an RpathCommand.
|
|
||||||
# @param rpath_cmd [MachO::RpathCommand] the rpath command
|
|
||||||
# @param old_path [String] the old runtime name
|
|
||||||
# @param new_path [String] the new runtime name
|
|
||||||
# @return [void]
|
|
||||||
# @private
|
|
||||||
def set_path_in_rpath(rpath_cmd, old_path, new_path)
|
|
||||||
set_lc_str_in_cmd(rpath_cmd, rpath_cmd.path, old_path, new_path)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Updates a generic LCStr field in any LoadCommand.
|
|
||||||
# @param cmd [MachO::LoadCommand] the load command
|
|
||||||
# @param lc_str [MachO::LoadCommand::LCStr] the load command string
|
|
||||||
# @param old_str [String] the old string
|
|
||||||
# @param new_str [String] the new string
|
|
||||||
# @raise [MachO::HeaderPadError] if the new name exceeds the header pad buffer
|
|
||||||
# @private
|
|
||||||
def set_lc_str_in_cmd(cmd, lc_str, old_str, new_str)
|
|
||||||
if magic32?
|
|
||||||
cmd_round = 4
|
|
||||||
else
|
|
||||||
cmd_round = 8
|
|
||||||
end
|
|
||||||
|
|
||||||
new_sizeofcmds = header.sizeofcmds
|
|
||||||
old_str = old_str.dup
|
|
||||||
new_str = new_str.dup
|
|
||||||
|
|
||||||
old_pad = MachO.round(old_str.size + 1, cmd_round) - old_str.size
|
|
||||||
new_pad = MachO.round(new_str.size + 1, cmd_round) - new_str.size
|
|
||||||
|
|
||||||
# pad the old and new IDs with null bytes to meet command bounds
|
|
||||||
old_str << "\x00" * old_pad
|
|
||||||
new_str << "\x00" * new_pad
|
|
||||||
|
|
||||||
# calculate the new size of the cmd and sizeofcmds in MH
|
|
||||||
new_size = cmd.class.bytesize + new_str.size
|
|
||||||
new_sizeofcmds += new_size - cmd.cmdsize
|
|
||||||
|
|
||||||
low_fileoff = @raw_data.size
|
|
||||||
|
|
||||||
# calculate the low file offset (offset to first section data)
|
|
||||||
segments.each do |seg|
|
segments.each do |seg|
|
||||||
sections(seg).each do |sect|
|
seg.sections.each do |sect|
|
||||||
next if sect.size == 0
|
next if sect.empty?
|
||||||
next if sect.flag?(:S_ZEROFILL)
|
next if sect.flag?(:S_ZEROFILL)
|
||||||
next if sect.flag?(:S_THREAD_LOCAL_ZEROFILL)
|
next if sect.flag?(:S_THREAD_LOCAL_ZEROFILL)
|
||||||
next unless sect.offset < low_fileoff
|
next unless sect.offset < offset
|
||||||
|
|
||||||
low_fileoff = sect.offset
|
offset = sect.offset
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if new_sizeofcmds + header.class.bytesize > low_fileoff
|
offset
|
||||||
raise HeaderPadError.new(@filename)
|
end
|
||||||
end
|
|
||||||
|
|
||||||
# update sizeofcmds in mach_header
|
# Updates the number of load commands in the raw data.
|
||||||
set_sizeofcmds(new_sizeofcmds)
|
# @param ncmds [Fixnum] the new number of commands
|
||||||
|
# @return [void]
|
||||||
|
# @api private
|
||||||
|
def update_ncmds(ncmds)
|
||||||
|
fmt = Utils.specialize_format("L=", endianness)
|
||||||
|
ncmds_raw = [ncmds].pack(fmt)
|
||||||
|
@raw_data[16..19] = ncmds_raw
|
||||||
|
end
|
||||||
|
|
||||||
# update cmdsize in the cmd
|
# Updates the size of all load commands in the raw data.
|
||||||
fmt = (endianness == :little) ? "L<" : "L>"
|
# @param size [Fixnum] the new size, in bytes
|
||||||
@raw_data[cmd.offset + 4, 4] = [new_size].pack(fmt)
|
# @return [void]
|
||||||
|
# @api private
|
||||||
# delete the old str
|
def update_sizeofcmds(size)
|
||||||
@raw_data.slice!(cmd.offset + lc_str.to_i...cmd.offset + cmd.class.bytesize + old_str.size)
|
fmt = Utils.specialize_format("L=", endianness)
|
||||||
|
size_raw = [size].pack(fmt)
|
||||||
# insert the new str
|
@raw_data[20..23] = size_raw
|
||||||
@raw_data.insert(cmd.offset + lc_str.to_i, new_str)
|
|
||||||
|
|
||||||
# pad/unpad after new_sizeofcmds until offsets are corrected
|
|
||||||
null_pad = old_str.size - new_str.size
|
|
||||||
|
|
||||||
if null_pad < 0
|
|
||||||
@raw_data.slice!(new_sizeofcmds + header.class.bytesize, null_pad.abs)
|
|
||||||
else
|
|
||||||
@raw_data.insert(new_sizeofcmds + header.class.bytesize, "\x00" * null_pad)
|
|
||||||
end
|
|
||||||
|
|
||||||
# synchronize fields with the raw data
|
|
||||||
@header = get_mach_header
|
|
||||||
@load_commands = get_load_commands
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
10
Library/Homebrew/vendor/macho/macho/open.rb
vendored
10
Library/Homebrew/vendor/macho/macho/open.rb
vendored
@ -7,17 +7,17 @@ module MachO
|
|||||||
# @raise [MachO::TruncatedFileError] if the file is too small to have a valid header
|
# @raise [MachO::TruncatedFileError] if the file is too small to have a valid header
|
||||||
# @raise [MachO::MagicError] if the file's magic is not valid Mach-O magic
|
# @raise [MachO::MagicError] if the file's magic is not valid Mach-O magic
|
||||||
def self.open(filename)
|
def self.open(filename)
|
||||||
raise ArgumentError.new("#{filename}: no such file") unless File.file?(filename)
|
raise ArgumentError, "#{filename}: no such file" unless File.file?(filename)
|
||||||
raise TruncatedFileError.new unless File.stat(filename).size >= 4
|
raise TruncatedFileError unless File.stat(filename).size >= 4
|
||||||
|
|
||||||
magic = File.open(filename, "rb") { |f| f.read(4) }.unpack("N").first
|
magic = File.open(filename, "rb") { |f| f.read(4) }.unpack("N").first
|
||||||
|
|
||||||
if MachO.fat_magic?(magic)
|
if Utils.fat_magic?(magic)
|
||||||
file = FatFile.new(filename)
|
file = FatFile.new(filename)
|
||||||
elsif MachO.magic?(magic)
|
elsif Utils.magic?(magic)
|
||||||
file = MachOFile.new(filename)
|
file = MachOFile.new(filename)
|
||||||
else
|
else
|
||||||
raise MagicError.new(magic)
|
raise MagicError, magic
|
||||||
end
|
end
|
||||||
|
|
||||||
file
|
file
|
||||||
|
|||||||
29
Library/Homebrew/vendor/macho/macho/sections.rb
vendored
29
Library/Homebrew/vendor/macho/macho/sections.rb
vendored
@ -45,7 +45,7 @@ module MachO
|
|||||||
:S_ATTR_DEBUG => 0x02000000,
|
:S_ATTR_DEBUG => 0x02000000,
|
||||||
:S_ATTR_SOME_INSTRUCTIONS => 0x00000400,
|
:S_ATTR_SOME_INSTRUCTIONS => 0x00000400,
|
||||||
:S_ATTR_EXT_RELOC => 0x00000200,
|
:S_ATTR_EXT_RELOC => 0x00000200,
|
||||||
:S_ATTR_LOC_RELOC => 0x00000100
|
:S_ATTR_LOC_RELOC => 0x00000100,
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
# association of section name symbols to names
|
# association of section name symbols to names
|
||||||
@ -62,7 +62,7 @@ module MachO
|
|||||||
:SECT_OBJC_STRINGS => "__selector_strs",
|
:SECT_OBJC_STRINGS => "__selector_strs",
|
||||||
:SECT_OBJC_REFS => "__selector_refs",
|
:SECT_OBJC_REFS => "__selector_refs",
|
||||||
:SECT_ICON_HEADER => "__header",
|
:SECT_ICON_HEADER => "__header",
|
||||||
:SECT_ICON_TIFF => "__tiff"
|
:SECT_ICON_TIFF => "__tiff",
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
# Represents a section of a segment for 32-bit architectures.
|
# Represents a section of a segment for 32-bit architectures.
|
||||||
@ -91,7 +91,7 @@ module MachO
|
|||||||
# @return [Fixnum] the number of relocation entries
|
# @return [Fixnum] the number of relocation entries
|
||||||
attr_reader :nreloc
|
attr_reader :nreloc
|
||||||
|
|
||||||
# @return [Fixnum] flags for type and addrributes of the section
|
# @return [Fixnum] flags for type and attributes of the section
|
||||||
attr_reader :flags
|
attr_reader :flags
|
||||||
|
|
||||||
# @return [void] reserved (for offset or index)
|
# @return [void] reserved (for offset or index)
|
||||||
@ -100,12 +100,15 @@ module MachO
|
|||||||
# @return [void] reserved (for count or sizeof)
|
# @return [void] reserved (for count or sizeof)
|
||||||
attr_reader :reserved2
|
attr_reader :reserved2
|
||||||
|
|
||||||
FORMAT = "a16a16L=9"
|
# @see MachOStructure::FORMAT
|
||||||
|
FORMAT = "a16a16L=9".freeze
|
||||||
|
|
||||||
|
# @see MachOStructure::SIZEOF
|
||||||
SIZEOF = 68
|
SIZEOF = 68
|
||||||
|
|
||||||
# @api private
|
# @api private
|
||||||
def initialize(sectname, segname, addr, size, offset, align, reloff,
|
def initialize(sectname, segname, addr, size, offset, align, reloff,
|
||||||
nreloc, flags, reserved1, reserved2)
|
nreloc, flags, reserved1, reserved2)
|
||||||
@sectname = sectname
|
@sectname = sectname
|
||||||
@segname = segname
|
@segname = segname
|
||||||
@addr = addr
|
@addr = addr
|
||||||
@ -121,12 +124,17 @@ module MachO
|
|||||||
|
|
||||||
# @return [String] the section's name, with any trailing NULL characters removed
|
# @return [String] the section's name, with any trailing NULL characters removed
|
||||||
def section_name
|
def section_name
|
||||||
@sectname.delete("\x00")
|
sectname.delete("\x00")
|
||||||
end
|
end
|
||||||
|
|
||||||
# @return [String] the parent segment's name, with any trailing NULL characters removed
|
# @return [String] the parent segment's name, with any trailing NULL characters removed
|
||||||
def segment_name
|
def segment_name
|
||||||
@segname.delete("\x00")
|
segname.delete("\x00")
|
||||||
|
end
|
||||||
|
|
||||||
|
# @return [Boolean] true if the section has no contents (i.e, `size` is 0)
|
||||||
|
def empty?
|
||||||
|
size.zero?
|
||||||
end
|
end
|
||||||
|
|
||||||
# @example
|
# @example
|
||||||
@ -145,12 +153,15 @@ module MachO
|
|||||||
# @return [void] reserved
|
# @return [void] reserved
|
||||||
attr_reader :reserved3
|
attr_reader :reserved3
|
||||||
|
|
||||||
FORMAT = "a16a16Q=2L=8"
|
# @see MachOStructure::FORMAT
|
||||||
|
FORMAT = "a16a16Q=2L=8".freeze
|
||||||
|
|
||||||
|
# @see MachOStructure::SIZEOF
|
||||||
SIZEOF = 80
|
SIZEOF = 80
|
||||||
|
|
||||||
# @api private
|
# @api private
|
||||||
def initialize(sectname, segname, addr, size, offset, align, reloff,
|
def initialize(sectname, segname, addr, size, offset, align, reloff,
|
||||||
nreloc, flags, reserved1, reserved2, reserved3)
|
nreloc, flags, reserved1, reserved2, reserved3)
|
||||||
super(sectname, segname, addr, size, offset, align, reloff,
|
super(sectname, segname, addr, size, offset, align, reloff,
|
||||||
nreloc, flags, reserved1, reserved2)
|
nreloc, flags, reserved1, reserved2)
|
||||||
@reserved3 = reserved3
|
@reserved3 = reserved3
|
||||||
|
|||||||
24
Library/Homebrew/vendor/macho/macho/structure.rb
vendored
24
Library/Homebrew/vendor/macho/macho/structure.rb
vendored
@ -3,9 +3,13 @@ module MachO
|
|||||||
# @abstract
|
# @abstract
|
||||||
class MachOStructure
|
class MachOStructure
|
||||||
# The String#unpack format of the data structure.
|
# The String#unpack format of the data structure.
|
||||||
FORMAT = ""
|
# @return [String] the unpacking format
|
||||||
|
# @api private
|
||||||
|
FORMAT = "".freeze
|
||||||
|
|
||||||
# The size of the data structure, in bytes.
|
# The size of the data structure, in bytes.
|
||||||
|
# @return [Fixnum] the size, in bytes
|
||||||
|
# @api private
|
||||||
SIZEOF = 0
|
SIZEOF = 0
|
||||||
|
|
||||||
# @return [Fixnum] the size, in bytes, of the represented structure.
|
# @return [Fixnum] the size, in bytes, of the represented structure.
|
||||||
@ -13,26 +17,14 @@ module MachO
|
|||||||
self::SIZEOF
|
self::SIZEOF
|
||||||
end
|
end
|
||||||
|
|
||||||
# @param endianness [Symbol] either :big or :little
|
# @param endianness [Symbol] either `:big` or `:little`
|
||||||
# @param bin [String] the string to be unpacked into the new structure
|
# @param bin [String] the string to be unpacked into the new structure
|
||||||
# @return [MachO::MachOStructure] a new MachOStructure initialized with `bin`
|
# @return [MachO::MachOStructure] a new MachOStructure initialized with `bin`
|
||||||
# @api private
|
# @api private
|
||||||
def self.new_from_bin(endianness, bin)
|
def self.new_from_bin(endianness, bin)
|
||||||
format = specialize_format(self::FORMAT, endianness)
|
format = Utils.specialize_format(self::FORMAT, endianness)
|
||||||
|
|
||||||
self.new(*bin.unpack(format))
|
new(*bin.unpack(format))
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
# Convert an abstract (native-endian) String#unpack format to big or little.
|
|
||||||
# @param format [String] the format string being converted
|
|
||||||
# @param endianness [Symbol] either :big or :little
|
|
||||||
# @return [String] the converted string
|
|
||||||
# @api private
|
|
||||||
def self.specialize_format(format, endianness)
|
|
||||||
modifier = (endianness == :big) ? ">" : "<"
|
|
||||||
format.tr("=", modifier)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
49
Library/Homebrew/vendor/macho/macho/tools.rb
vendored
49
Library/Homebrew/vendor/macho/macho/tools.rb
vendored
@ -12,12 +12,14 @@ module MachO
|
|||||||
# Changes the dylib ID of a Mach-O or Fat binary, overwriting the source file.
|
# Changes the dylib ID of a Mach-O or Fat binary, overwriting the source file.
|
||||||
# @param filename [String] the Mach-O or Fat binary being modified
|
# @param filename [String] the Mach-O or Fat binary being modified
|
||||||
# @param new_id [String] the new dylib ID for the binary
|
# @param new_id [String] the new dylib ID for the binary
|
||||||
|
# @param options [Hash]
|
||||||
|
# @option options [Boolean] :strict (true) whether or not to fail loudly
|
||||||
|
# with an exception if the change cannot be performed
|
||||||
# @return [void]
|
# @return [void]
|
||||||
# @todo unstub for fat files
|
def self.change_dylib_id(filename, new_id, options = {})
|
||||||
def self.change_dylib_id(filename, new_id)
|
|
||||||
file = MachO.open(filename)
|
file = MachO.open(filename)
|
||||||
|
|
||||||
file.dylib_id = new_id
|
file.change_dylib_id(new_id, options)
|
||||||
file.write!
|
file.write!
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -25,12 +27,14 @@ module MachO
|
|||||||
# @param filename [String] the Mach-O or Fat binary being modified
|
# @param filename [String] the Mach-O or Fat binary being modified
|
||||||
# @param old_name [String] the old shared library name
|
# @param old_name [String] the old shared library name
|
||||||
# @param new_name [String] the new shared library name
|
# @param new_name [String] the new shared library name
|
||||||
|
# @param options [Hash]
|
||||||
|
# @option options [Boolean] :strict (true) whether or not to fail loudly
|
||||||
|
# with an exception if the change cannot be performed
|
||||||
# @return [void]
|
# @return [void]
|
||||||
# @todo unstub for fat files
|
def self.change_install_name(filename, old_name, new_name, options = {})
|
||||||
def self.change_install_name(filename, old_name, new_name)
|
|
||||||
file = MachO.open(filename)
|
file = MachO.open(filename)
|
||||||
|
|
||||||
file.change_install_name(old_name, new_name)
|
file.change_install_name(old_name, new_name, options)
|
||||||
file.write!
|
file.write!
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -38,28 +42,43 @@ module MachO
|
|||||||
# @param filename [String] the Mach-O or Fat binary being modified
|
# @param filename [String] the Mach-O or Fat binary being modified
|
||||||
# @param old_path [String] the old runtime path
|
# @param old_path [String] the old runtime path
|
||||||
# @param new_path [String] the new runtime path
|
# @param new_path [String] the new runtime path
|
||||||
|
# @param options [Hash]
|
||||||
|
# @option options [Boolean] :strict (true) whether or not to fail loudly
|
||||||
|
# with an exception if the change cannot be performed
|
||||||
# @return [void]
|
# @return [void]
|
||||||
# @todo unstub
|
def self.change_rpath(filename, old_path, new_path, options = {})
|
||||||
def self.change_rpath(filename, old_path, new_path)
|
file = MachO.open(filename)
|
||||||
raise UnimplementedError.new("changing rpaths in a Mach-O")
|
|
||||||
|
file.change_rpath(old_path, new_path, options)
|
||||||
|
file.write!
|
||||||
end
|
end
|
||||||
|
|
||||||
# Add a runtime path to a Mach-O or Fat binary, overwriting the source file.
|
# Add a runtime path to a Mach-O or Fat binary, overwriting the source file.
|
||||||
# @param filename [String] the Mach-O or Fat binary being modified
|
# @param filename [String] the Mach-O or Fat binary being modified
|
||||||
# @param new_path [String] the new runtime path
|
# @param new_path [String] the new runtime path
|
||||||
|
# @param options [Hash]
|
||||||
|
# @option options [Boolean] :strict (true) whether or not to fail loudly
|
||||||
|
# with an exception if the change cannot be performed
|
||||||
# @return [void]
|
# @return [void]
|
||||||
# @todo unstub
|
def self.add_rpath(filename, new_path, options = {})
|
||||||
def self.add_rpath(filename, new_path)
|
file = MachO.open(filename)
|
||||||
raise UnimplementedError.new("adding rpaths to a Mach-O")
|
|
||||||
|
file.add_rpath(new_path, options)
|
||||||
|
file.write!
|
||||||
end
|
end
|
||||||
|
|
||||||
# Delete a runtime path from a Mach-O or Fat binary, overwriting the source file.
|
# Delete a runtime path from a Mach-O or Fat binary, overwriting the source file.
|
||||||
# @param filename [String] the Mach-O or Fat binary being modified
|
# @param filename [String] the Mach-O or Fat binary being modified
|
||||||
# @param old_path [String] the old runtime path
|
# @param old_path [String] the old runtime path
|
||||||
|
# @param options [Hash]
|
||||||
|
# @option options [Boolean] :strict (true) whether or not to fail loudly
|
||||||
|
# with an exception if the change cannot be performed
|
||||||
# @return [void]
|
# @return [void]
|
||||||
# @todo unstub
|
def self.delete_rpath(filename, old_path, options = {})
|
||||||
def self.delete_rpath(filename, old_path)
|
file = MachO.open(filename)
|
||||||
raise UnimplementedError.new("removing rpaths from a Mach-O")
|
|
||||||
|
file.delete_rpath(old_path, options)
|
||||||
|
file.write!
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
126
Library/Homebrew/vendor/macho/macho/utils.rb
vendored
126
Library/Homebrew/vendor/macho/macho/utils.rb
vendored
@ -1,48 +1,96 @@
|
|||||||
module MachO
|
module MachO
|
||||||
# @param value [Fixnum] the number being rounded
|
# A collection of utility functions used throughout ruby-macho.
|
||||||
# @param round [Fixnum] the number being rounded with
|
module Utils
|
||||||
# @return [Fixnum] the next number >= `value` such that `round` is its divisor
|
# Rounds a value to the next multiple of the given round.
|
||||||
# @see http://www.opensource.apple.com/source/cctools/cctools-870/libstuff/rnd.c
|
# @param value [Fixnum] the number being rounded
|
||||||
def self.round(value, round)
|
# @param round [Fixnum] the number being rounded with
|
||||||
round -= 1
|
# @return [Fixnum] the rounded value
|
||||||
value += round
|
# @see http://www.opensource.apple.com/source/cctools/cctools-870/libstuff/rnd.c
|
||||||
value &= ~round
|
def self.round(value, round)
|
||||||
value
|
round -= 1
|
||||||
end
|
value += round
|
||||||
|
value &= ~round
|
||||||
|
value
|
||||||
|
end
|
||||||
|
|
||||||
# @param num [Fixnum] the number being checked
|
# Returns the number of bytes needed to pad the given size to the given alignment.
|
||||||
# @return [Boolean] true if `num` is a valid Mach-O magic number, false otherwise
|
# @param size [Fixnum] the unpadded size
|
||||||
def self.magic?(num)
|
# @param alignment [Fixnum] the number to alignment the size with
|
||||||
MH_MAGICS.has_key?(num)
|
# @return [Fixnum] the number of pad bytes required
|
||||||
end
|
def self.padding_for(size, alignment)
|
||||||
|
round(size, alignment) - size
|
||||||
|
end
|
||||||
|
|
||||||
# @param num [Fixnum] the number being checked
|
# Converts an abstract (native-endian) String#unpack format to big or little.
|
||||||
# @return [Boolean] true if `num` is a valid Fat magic number, false otherwise
|
# @param format [String] the format string being converted
|
||||||
def self.fat_magic?(num)
|
# @param endianness [Symbol] either `:big` or `:little`
|
||||||
num == FAT_MAGIC
|
# @return [String] the converted string
|
||||||
end
|
def self.specialize_format(format, endianness)
|
||||||
|
modifier = endianness == :big ? ">" : "<"
|
||||||
|
format.tr("=", modifier)
|
||||||
|
end
|
||||||
|
|
||||||
# @param num [Fixnum] the number being checked
|
# Packs tagged strings into an aligned payload.
|
||||||
# @return [Boolean] true if `num` is a valid 32-bit magic number, false otherwise
|
# @param fixed_offset [Fixnum] the baseline offset for the first packed string
|
||||||
def self.magic32?(num)
|
# @param alignment [Fixnum] the alignment value to use for packing
|
||||||
num == MH_MAGIC || num == MH_CIGAM
|
# @param strings [Hash] the labeled strings to pack
|
||||||
end
|
# @return [Array<String, Hash>] the packed string and labeled offsets
|
||||||
|
def self.pack_strings(fixed_offset, alignment, strings = {})
|
||||||
|
offsets = {}
|
||||||
|
next_offset = fixed_offset
|
||||||
|
payload = ""
|
||||||
|
|
||||||
# @param num [Fixnum] the number being checked
|
strings.each do |key, string|
|
||||||
# @return [Boolean] true if `num` is a valid 64-bit magic number, false otherwise
|
offsets[key] = next_offset
|
||||||
def self.magic64?(num)
|
payload << string
|
||||||
num == MH_MAGIC_64 || num == MH_CIGAM_64
|
payload << "\x00"
|
||||||
end
|
next_offset += string.bytesize + 1
|
||||||
|
end
|
||||||
|
|
||||||
# @param num [Fixnum] the number being checked
|
payload << "\x00" * padding_for(fixed_offset + payload.bytesize, alignment)
|
||||||
# @return [Boolean] true if `num` is a valid little-endian magic number, false otherwise
|
[payload, offsets]
|
||||||
def self.little_magic?(num)
|
end
|
||||||
num == MH_CIGAM || num == MH_CIGAM_64
|
|
||||||
end
|
|
||||||
|
|
||||||
# @param num [Fixnum] the number being checked
|
# Compares the given number to valid Mach-O magic numbers.
|
||||||
# @return [Boolean] true if `num` is a valid big-endian magic number, false otherwise
|
# @param num [Fixnum] the number being checked
|
||||||
def self.big_magic?(num)
|
# @return [Boolean] true if `num` is a valid Mach-O magic number, false otherwise
|
||||||
num == MH_CIGAM || num == MH_CIGAM_64
|
def self.magic?(num)
|
||||||
|
MH_MAGICS.key?(num)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Compares the given number to valid Fat magic numbers.
|
||||||
|
# @param num [Fixnum] the number being checked
|
||||||
|
# @return [Boolean] true if `num` is a valid Fat magic number, false otherwise
|
||||||
|
def self.fat_magic?(num)
|
||||||
|
num == FAT_MAGIC
|
||||||
|
end
|
||||||
|
|
||||||
|
# Compares the given number to valid 32-bit Mach-O magic numbers.
|
||||||
|
# @param num [Fixnum] the number being checked
|
||||||
|
# @return [Boolean] true if `num` is a valid 32-bit magic number, false otherwise
|
||||||
|
def self.magic32?(num)
|
||||||
|
num == MH_MAGIC || num == MH_CIGAM
|
||||||
|
end
|
||||||
|
|
||||||
|
# Compares the given number to valid 64-bit Mach-O magic numbers.
|
||||||
|
# @param num [Fixnum] the number being checked
|
||||||
|
# @return [Boolean] true if `num` is a valid 64-bit magic number, false otherwise
|
||||||
|
def self.magic64?(num)
|
||||||
|
num == MH_MAGIC_64 || num == MH_CIGAM_64
|
||||||
|
end
|
||||||
|
|
||||||
|
# Compares the given number to valid little-endian magic numbers.
|
||||||
|
# @param num [Fixnum] the number being checked
|
||||||
|
# @return [Boolean] true if `num` is a valid little-endian magic number, false otherwise
|
||||||
|
def self.little_magic?(num)
|
||||||
|
num == MH_CIGAM || num == MH_CIGAM_64
|
||||||
|
end
|
||||||
|
|
||||||
|
# Compares the given number to valid big-endian magic numbers.
|
||||||
|
# @param num [Fixnum] the number being checked
|
||||||
|
# @return [Boolean] true if `num` is a valid big-endian magic number, false otherwise
|
||||||
|
def self.big_magic?(num)
|
||||||
|
num == MH_CIGAM || num == MH_CIGAM_64
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
23
Library/Homebrew/vendor/macho/macho/view.rb
vendored
Normal file
23
Library/Homebrew/vendor/macho/macho/view.rb
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
module MachO
|
||||||
|
# A representation of some unspecified Mach-O data.
|
||||||
|
class MachOView
|
||||||
|
# @return [String] the raw Mach-O data
|
||||||
|
attr_reader :raw_data
|
||||||
|
|
||||||
|
# @return [Symbol] the endianness of the data (`:big` or `:little`)
|
||||||
|
attr_reader :endianness
|
||||||
|
|
||||||
|
# @return [Fixnum] the offset of the relevant data (in {#raw_data})
|
||||||
|
attr_reader :offset
|
||||||
|
|
||||||
|
# Creates a new MachOView.
|
||||||
|
# @param raw_data [String] the raw Mach-O data
|
||||||
|
# @param endianness [Symbol] the endianness of the data
|
||||||
|
# @param offset [Fixnum] the offset of the relevant data
|
||||||
|
def initialize(raw_data, endianness, offset)
|
||||||
|
@raw_data = raw_data
|
||||||
|
@endianness = endianness
|
||||||
|
@offset = offset
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
Loading…
x
Reference in New Issue
Block a user