vendor: Update ruby-macho to 1.1.0.
This commit is contained in:
parent
422afa0b49
commit
024264c381
4
Library/Homebrew/vendor/README.md
vendored
4
Library/Homebrew/vendor/README.md
vendored
@ -3,7 +3,7 @@ Vendored Dependencies
|
||||
|
||||
* [plist](https://github.com/bleything/plist), version 3.1.0
|
||||
|
||||
* [ruby-macho](https://github.com/Homebrew/ruby-macho), version 0.2.6
|
||||
* [ruby-macho](https://github.com/Homebrew/ruby-macho), version 1.1.0
|
||||
|
||||
## Licenses:
|
||||
|
||||
@ -33,7 +33,7 @@ Vendored Dependencies
|
||||
### ruby-macho
|
||||
|
||||
> The MIT License
|
||||
> Copyright (c) 2015, 2016 William Woodruff <william @ tuffbizz.com>
|
||||
> Copyright (c) 2015, 2016, 2017 William Woodruff <william @ tuffbizz.com>
|
||||
>
|
||||
> Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
> of this software and associated documentation files (the "Software"), to deal
|
||||
|
27
Library/Homebrew/vendor/macho/macho.rb
vendored
27
Library/Homebrew/vendor/macho/macho.rb
vendored
@ -5,7 +5,6 @@ require "#{File.dirname(__FILE__)}/macho/load_commands"
|
||||
require "#{File.dirname(__FILE__)}/macho/sections"
|
||||
require "#{File.dirname(__FILE__)}/macho/macho_file"
|
||||
require "#{File.dirname(__FILE__)}/macho/fat_file"
|
||||
require "#{File.dirname(__FILE__)}/macho/open"
|
||||
require "#{File.dirname(__FILE__)}/macho/exceptions"
|
||||
require "#{File.dirname(__FILE__)}/macho/utils"
|
||||
require "#{File.dirname(__FILE__)}/macho/tools"
|
||||
@ -13,5 +12,29 @@ require "#{File.dirname(__FILE__)}/macho/tools"
|
||||
# The primary namespace for ruby-macho.
|
||||
module MachO
|
||||
# release version
|
||||
VERSION = "0.2.6".freeze
|
||||
VERSION = "1.1.0".freeze
|
||||
|
||||
# Opens the given filename as a MachOFile or FatFile, depending on its magic.
|
||||
# @param filename [String] the file being opened
|
||||
# @return [MachOFile] if the file is a Mach-O
|
||||
# @return [FatFile] if the file is a Fat file
|
||||
# @raise [ArgumentError] if the given file does not exist
|
||||
# @raise [TruncatedFileError] if the file is too small to have a valid header
|
||||
# @raise [MagicError] if the file's magic is not valid Mach-O magic
|
||||
def self.open(filename)
|
||||
raise ArgumentError, "#{filename}: no such file" unless File.file?(filename)
|
||||
raise TruncatedFileError unless File.stat(filename).size >= 4
|
||||
|
||||
magic = File.open(filename, "rb") { |f| f.read(4) }.unpack("N").first
|
||||
|
||||
if Utils.fat_magic?(magic)
|
||||
file = FatFile.new(filename)
|
||||
elsif Utils.magic?(magic)
|
||||
file = MachOFile.new(filename)
|
||||
else
|
||||
raise MagicError, magic
|
||||
end
|
||||
|
||||
file
|
||||
end
|
||||
end
|
||||
|
@ -80,7 +80,8 @@ module MachO
|
||||
# @param cputype [Fixnum] the CPU type of the unknown pair
|
||||
# @param cpusubtype [Fixnum] the CPU sub-type of the unknown pair
|
||||
def initialize(cputype, cpusubtype)
|
||||
super "Unrecognized CPU sub-type: 0x#{"%08x" % cpusubtype} (for CPU type: 0x#{"%08x" % cputype})"
|
||||
super "Unrecognized CPU sub-type: 0x#{"%08x" % cpusubtype}" \
|
||||
" (for CPU type: 0x#{"%08x" % cputype})"
|
||||
end
|
||||
end
|
||||
|
||||
@ -108,13 +109,15 @@ module MachO
|
||||
end
|
||||
end
|
||||
|
||||
# Raised when the number of arguments used to create a load command manually is wrong.
|
||||
# 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}"
|
||||
super "Expected #{expected_arity} arguments for #{cmd_sym} creation," \
|
||||
" got #{actual_arity}"
|
||||
end
|
||||
end
|
||||
|
||||
@ -130,7 +133,8 @@ module MachO
|
||||
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"
|
||||
super "Load command #{lc.type} at offset #{lc.view.offset} contains a" \
|
||||
" malformed string"
|
||||
end
|
||||
end
|
||||
|
||||
|
200
Library/Homebrew/vendor/macho/macho/fat_file.rb
vendored
200
Library/Homebrew/vendor/macho/macho/fat_file.rb
vendored
@ -1,24 +1,50 @@
|
||||
require "forwardable"
|
||||
|
||||
module MachO
|
||||
# Represents a "Fat" file, which contains a header, a listing of available
|
||||
# architectures, and one or more Mach-O binaries.
|
||||
# @see https://en.wikipedia.org/wiki/Mach-O#Multi-architecture_binaries
|
||||
# @see MachO::MachOFile
|
||||
# @see MachOFile
|
||||
class FatFile
|
||||
extend Forwardable
|
||||
|
||||
# @return [String] the filename loaded from, or nil if loaded from a binary string
|
||||
attr_accessor :filename
|
||||
|
||||
# @return [MachO::FatHeader] the file's header
|
||||
# @return [Headers::FatHeader] the file's header
|
||||
attr_reader :header
|
||||
|
||||
# @return [Array<MachO::FatArch>] an array of fat architectures
|
||||
# @return [Array<Headers::FatArch>] an array of fat architectures
|
||||
attr_reader :fat_archs
|
||||
|
||||
# @return [Array<MachO::MachOFile>] an array of Mach-O binaries
|
||||
# @return [Array<MachOFile>] an array of Mach-O binaries
|
||||
attr_reader :machos
|
||||
|
||||
# Creates a new FatFile from the given (single-arch) Mach-Os
|
||||
# @param machos [Array<MachOFile>] the machos to combine
|
||||
# @return [FatFile] a new FatFile containing the give machos
|
||||
def self.new_from_machos(*machos)
|
||||
header = Headers::FatHeader.new(Headers::FAT_MAGIC, machos.size)
|
||||
offset = Headers::FatHeader.bytesize + (machos.size * Headers::FatArch.bytesize)
|
||||
fat_archs = []
|
||||
machos.each do |macho|
|
||||
fat_archs << Headers::FatArch.new(macho.header.cputype,
|
||||
macho.header.cpusubtype,
|
||||
offset, macho.serialize.bytesize,
|
||||
macho.alignment)
|
||||
offset += macho.serialize.bytesize
|
||||
end
|
||||
|
||||
bin = header.serialize
|
||||
bin << fat_archs.map(&:serialize).join
|
||||
bin << machos.map(&:serialize).join
|
||||
|
||||
new_from_bin(bin)
|
||||
end
|
||||
|
||||
# Creates a new FatFile instance from a binary string.
|
||||
# @param bin [String] a binary string containing raw Mach-O data
|
||||
# @return [MachO::FatFile] a new FatFile
|
||||
# @return [FatFile] a new FatFile
|
||||
def self.new_from_bin(bin)
|
||||
instance = allocate
|
||||
instance.initialize_from_bin(bin)
|
||||
@ -38,7 +64,7 @@ module MachO
|
||||
end
|
||||
|
||||
# Initializes a new FatFile instance from a binary string.
|
||||
# @see MachO::FatFile.new_from_bin
|
||||
# @see new_from_bin
|
||||
# @api private
|
||||
def initialize_from_bin(bin)
|
||||
@filename = nil
|
||||
@ -52,70 +78,41 @@ module MachO
|
||||
@raw_data
|
||||
end
|
||||
|
||||
# @return [Boolean] true if the file is of type `MH_OBJECT`, false otherwise
|
||||
def object?
|
||||
machos.first.object?
|
||||
end
|
||||
# @!method object?
|
||||
# @return (see MachO::MachOFile#object?)
|
||||
# @!method executable?
|
||||
# @return (see MachO::MachOFile#executable?)
|
||||
# @!method fvmlib?
|
||||
# @return (see MachO::MachOFile#fvmlib?)
|
||||
# @!method core?
|
||||
# @return (see MachO::MachOFile#core?)
|
||||
# @!method preload?
|
||||
# @return (see MachO::MachOFile#preload?)
|
||||
# @!method dylib?
|
||||
# @return (see MachO::MachOFile#dylib?)
|
||||
# @!method dylinker?
|
||||
# @return (see MachO::MachOFile#dylinker?)
|
||||
# @!method bundle?
|
||||
# @return (see MachO::MachOFile#bundle?)
|
||||
# @!method dsym?
|
||||
# @return (see MachO::MachOFile#dsym?)
|
||||
# @!method kext?
|
||||
# @return (see MachO::MachOFile#kext?)
|
||||
# @!method filetype
|
||||
# @return (see MachO::MachOFile#filetype)
|
||||
# @!method dylib_id
|
||||
# @return (see MachO::MachOFile#dylib_id)
|
||||
def_delegators :canonical_macho, :object?, :executable?, :fvmlib?,
|
||||
:core?, :preload?, :dylib?, :dylinker?, :bundle?,
|
||||
:dsym?, :kext?, :filetype, :dylib_id
|
||||
|
||||
# @return [Boolean] true if the file is of type `MH_EXECUTE`, false otherwise
|
||||
def executable?
|
||||
machos.first.executable?
|
||||
end
|
||||
|
||||
# @return [Boolean] true if the file is of type `MH_FVMLIB`, false otherwise
|
||||
def fvmlib?
|
||||
machos.first.fvmlib?
|
||||
end
|
||||
|
||||
# @return [Boolean] true if the file is of type `MH_CORE`, false otherwise
|
||||
def core?
|
||||
machos.first.core?
|
||||
end
|
||||
|
||||
# @return [Boolean] true if the file is of type `MH_PRELOAD`, false otherwise
|
||||
def preload?
|
||||
machos.first.preload?
|
||||
end
|
||||
|
||||
# @return [Boolean] true if the file is of type `MH_DYLIB`, false otherwise
|
||||
def dylib?
|
||||
machos.first.dylib?
|
||||
end
|
||||
|
||||
# @return [Boolean] true if the file is of type `MH_DYLINKER`, false otherwise
|
||||
def dylinker?
|
||||
machos.first.dylinker?
|
||||
end
|
||||
|
||||
# @return [Boolean] true if the file is of type `MH_BUNDLE`, false otherwise
|
||||
def bundle?
|
||||
machos.first.bundle?
|
||||
end
|
||||
|
||||
# @return [Boolean] true if the file is of type `MH_DSYM`, false otherwise
|
||||
def dsym?
|
||||
machos.first.dsym?
|
||||
end
|
||||
|
||||
# @return [Boolean] true if the file is of type `MH_KEXT_BUNDLE`, false otherwise
|
||||
def kext?
|
||||
machos.first.kext?
|
||||
end
|
||||
|
||||
# @return [Fixnum] the file's magic number
|
||||
def magic
|
||||
header.magic
|
||||
end
|
||||
# @!method magic
|
||||
# @return (see MachO::Headers::FatHeader#magic)
|
||||
def_delegators :header, :magic
|
||||
|
||||
# @return [String] a string representation of the file's magic number
|
||||
def magic_string
|
||||
MH_MAGICS[magic]
|
||||
end
|
||||
|
||||
# The file's type. Assumed to be the same for every Mach-O within.
|
||||
# @return [Symbol] the filetype
|
||||
def filetype
|
||||
machos.first.filetype
|
||||
Headers::MH_MAGICS[magic]
|
||||
end
|
||||
|
||||
# Populate the instance's fields with the raw Fat Mach-O data.
|
||||
@ -128,21 +125,13 @@ module MachO
|
||||
end
|
||||
|
||||
# All load commands responsible for loading dylibs in the file's Mach-O's.
|
||||
# @return [Array<MachO::DylibCommand>] an array of DylibCommands
|
||||
# @return [Array<LoadCommands::DylibCommand>] an array of DylibCommands
|
||||
def dylib_load_commands
|
||||
machos.map(&:dylib_load_commands).flatten
|
||||
end
|
||||
|
||||
# The file's dylib ID. If the file is not a dylib, returns `nil`.
|
||||
# @example
|
||||
# file.dylib_id # => 'libBar.dylib'
|
||||
# @return [String, nil] the file's dylib ID
|
||||
# @see MachO::MachOFile#linked_dylibs
|
||||
def dylib_id
|
||||
machos.first.dylib_id
|
||||
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
|
||||
# file.change_dylib_id('libFoo.dylib')
|
||||
# @param new_id [String] the new dylib ID
|
||||
@ -151,7 +140,7 @@ module MachO
|
||||
# if false, fail only if all slices fail.
|
||||
# @return [void]
|
||||
# @raise [ArgumentError] if `new_id` is not a String
|
||||
# @see MachO::MachOFile#linked_dylibs
|
||||
# @see MachOFile#linked_dylibs
|
||||
def change_dylib_id(new_id, options = {})
|
||||
raise ArgumentError, "argument must be a String" unless new_id.is_a?(String)
|
||||
return unless machos.all?(&:dylib?)
|
||||
@ -167,7 +156,7 @@ module MachO
|
||||
|
||||
# All shared libraries linked to the file's Mach-Os.
|
||||
# @return [Array<String>] an array of all shared libraries
|
||||
# @see MachO::MachOFile#linked_dylibs
|
||||
# @see MachOFile#linked_dylibs
|
||||
def linked_dylibs
|
||||
# Individual architectures in a fat binary can link to different subsets
|
||||
# of libraries, but at this point we want to have the full picture, i.e.
|
||||
@ -175,8 +164,9 @@ module MachO
|
||||
machos.map(&:linked_dylibs).flatten.uniq
|
||||
end
|
||||
|
||||
# Changes all dependent shared library install names from `old_name` to `new_name`.
|
||||
# In a fat file, this changes install names in all internal Mach-Os.
|
||||
# Changes all dependent shared library install names from `old_name` to
|
||||
# `new_name`. In a fat file, this changes install names in all internal
|
||||
# Mach-Os.
|
||||
# @example
|
||||
# file.change_install_name('/usr/lib/libFoo.dylib', '/usr/lib/libBar.dylib')
|
||||
# @param old_name [String] the shared library name being changed
|
||||
@ -185,7 +175,7 @@ module MachO
|
||||
# @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_install_name
|
||||
# @see 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)
|
||||
@ -198,7 +188,7 @@ module MachO
|
||||
|
||||
# All runtime paths associated with the file's Mach-Os.
|
||||
# @return [Array<String>] an array of all runtime paths
|
||||
# @see MachO::MachOFile#rpaths
|
||||
# @see MachOFile#rpaths
|
||||
def rpaths
|
||||
# Can individual architectures have different runtime paths?
|
||||
machos.map(&:rpaths).flatten.uniq
|
||||
@ -211,7 +201,7 @@ module MachO
|
||||
# @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
|
||||
# @see MachOFile#change_rpath
|
||||
def change_rpath(old_path, new_path, options = {})
|
||||
each_macho(options) do |macho|
|
||||
macho.change_rpath(old_path, new_path, options)
|
||||
@ -226,7 +216,7 @@ module MachO
|
||||
# @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
|
||||
# @see MachOFile#add_rpath
|
||||
def add_rpath(path, options = {})
|
||||
each_macho(options) do |macho|
|
||||
macho.add_rpath(path, options)
|
||||
@ -241,7 +231,7 @@ module MachO
|
||||
# @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
|
||||
# @see MachOFile#delete_rpath
|
||||
def delete_rpath(path, options = {})
|
||||
each_macho(options) do |macho|
|
||||
macho.delete_rpath(path, options)
|
||||
@ -254,20 +244,21 @@ module MachO
|
||||
# @example
|
||||
# file.extract(:i386) # => MachO::MachOFile
|
||||
# @param cputype [Symbol] the CPU type of the Mach-O being extracted
|
||||
# @return [MachO::MachOFile, nil] the extracted Mach-O or nil if no Mach-O has the given CPU type
|
||||
# @return [MachOFile, nil] the extracted Mach-O or nil if no Mach-O has the given CPU type
|
||||
def extract(cputype)
|
||||
machos.select { |macho| macho.cputype == cputype }.first
|
||||
end
|
||||
|
||||
# Write all (fat) data to the given filename.
|
||||
# @param filename [String] the file to write to
|
||||
# @return [void]
|
||||
def write(filename)
|
||||
File.open(filename, "wb") { |f| f.write(@raw_data) }
|
||||
end
|
||||
|
||||
# Write all (fat) data to the file used to initialize the instance.
|
||||
# @return [void]
|
||||
# @raise [MachO::MachOError] if the instance was initialized without a file
|
||||
# @raise [MachOError] if the instance was initialized without a file
|
||||
# @note Overwrites all data in the file!
|
||||
def write!
|
||||
if filename.nil?
|
||||
@ -280,17 +271,18 @@ module MachO
|
||||
private
|
||||
|
||||
# Obtain the fat header from raw file data.
|
||||
# @return [MachO::FatHeader] the fat header
|
||||
# @raise [MachO::TruncatedFileError] if the file is too small to have a valid header
|
||||
# @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::JavaClassFileError] if the file is a Java classfile
|
||||
# @return [Headers::FatHeader] the fat header
|
||||
# @raise [TruncatedFileError] if the file is too small to have a
|
||||
# valid header
|
||||
# @raise [MagicError] if the magic is not valid Mach-O magic
|
||||
# @raise [MachOBinaryError] if the magic is for a non-fat Mach-O file
|
||||
# @raise [JavaClassFileError] if the file is a Java classfile
|
||||
# @api private
|
||||
def populate_fat_header
|
||||
# the smallest fat Mach-O header is 8 bytes
|
||||
raise TruncatedFileError if @raw_data.size < 8
|
||||
|
||||
fh = FatHeader.new_from_bin(:big, @raw_data[0, FatHeader.bytesize])
|
||||
fh = Headers::FatHeader.new_from_bin(:big, @raw_data[0, Headers::FatHeader.bytesize])
|
||||
|
||||
raise MagicError, fh.magic unless Utils.magic?(fh.magic)
|
||||
raise MachOBinaryError unless Utils.fat_magic?(fh.magic)
|
||||
@ -308,22 +300,22 @@ module MachO
|
||||
end
|
||||
|
||||
# Obtain an array of fat architectures from raw file data.
|
||||
# @return [Array<MachO::FatArch>] an array of fat architectures
|
||||
# @return [Array<Headers::FatArch>] an array of fat architectures
|
||||
# @api private
|
||||
def populate_fat_archs
|
||||
archs = []
|
||||
|
||||
fa_off = FatHeader.bytesize
|
||||
fa_len = FatArch.bytesize
|
||||
fa_off = Headers::FatHeader.bytesize
|
||||
fa_len = Headers::FatArch.bytesize
|
||||
header.nfat_arch.times do |i|
|
||||
archs << FatArch.new_from_bin(:big, @raw_data[fa_off + (fa_len * i), fa_len])
|
||||
archs << Headers::FatArch.new_from_bin(:big, @raw_data[fa_off + (fa_len * i), fa_len])
|
||||
end
|
||||
|
||||
archs
|
||||
end
|
||||
|
||||
# Obtain an array of Mach-O blobs from raw file data.
|
||||
# @return [Array<MachO::MachOFile>] an array of Mach-Os
|
||||
# @return [Array<MachOFile>] an array of Mach-Os
|
||||
# @api private
|
||||
def populate_machos
|
||||
machos = []
|
||||
@ -351,7 +343,7 @@ module MachO
|
||||
# @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
|
||||
# @raise [RecoverableModificationError] under the conditions of
|
||||
# the `:strict` option above.
|
||||
# @api private
|
||||
def each_macho(options = {})
|
||||
@ -373,5 +365,13 @@ module MachO
|
||||
# Non-strict mode: Raise first error if *all* Mach-O slices failed.
|
||||
raise errors.first if errors.size == machos.size
|
||||
end
|
||||
|
||||
# Return a single-arch Mach-O that represents this fat Mach-O for purposes
|
||||
# of delegation.
|
||||
# @return [MachOFile] the Mach-O file
|
||||
# @api private
|
||||
def canonical_macho
|
||||
machos.first
|
||||
end
|
||||
end
|
||||
end
|
||||
|
1196
Library/Homebrew/vendor/macho/macho/headers.rb
vendored
1196
Library/Homebrew/vendor/macho/macho/headers.rb
vendored
File diff suppressed because it is too large
Load Diff
2498
Library/Homebrew/vendor/macho/macho/load_commands.rb
vendored
2498
Library/Homebrew/vendor/macho/macho/load_commands.rb
vendored
File diff suppressed because it is too large
Load Diff
258
Library/Homebrew/vendor/macho/macho/macho_file.rb
vendored
258
Library/Homebrew/vendor/macho/macho/macho_file.rb
vendored
@ -1,27 +1,33 @@
|
||||
require "forwardable"
|
||||
|
||||
module MachO
|
||||
# Represents a Mach-O file, which contains a header and load commands
|
||||
# as well as binary executable instructions. Mach-O binaries are
|
||||
# architecture specific.
|
||||
# @see https://en.wikipedia.org/wiki/Mach-O
|
||||
# @see MachO::FatFile
|
||||
# @see FatFile
|
||||
class MachOFile
|
||||
# @return [String] the filename loaded from, or nil if loaded from a binary string
|
||||
extend Forwardable
|
||||
|
||||
# @return [String] the filename loaded from, or nil if loaded from a binary
|
||||
# string
|
||||
attr_accessor :filename
|
||||
|
||||
# @return [Symbol] the endianness of the file, :big or :little
|
||||
attr_reader :endianness
|
||||
|
||||
# @return [MachO::MachHeader] if the Mach-O is 32-bit
|
||||
# @return [MachO::MachHeader64] if the Mach-O is 64-bit
|
||||
# @return [Headers::MachHeader] if the Mach-O is 32-bit
|
||||
# @return [Headers::MachHeader64] if the Mach-O is 64-bit
|
||||
attr_reader :header
|
||||
|
||||
# @return [Array<MachO::LoadCommand>] an array of the file's load commands
|
||||
# @return [Array<LoadCommands::LoadCommand>] an array of the file's load
|
||||
# commands
|
||||
# @note load commands are provided in order of ascending offset.
|
||||
attr_reader :load_commands
|
||||
|
||||
# Creates a new MachOFile instance from a binary string.
|
||||
# @param bin [String] a binary string containing raw Mach-O data
|
||||
# @return [MachO::MachOFile] a new MachOFile
|
||||
# @return [MachOFile] a new MachOFile
|
||||
def self.new_from_bin(bin)
|
||||
instance = allocate
|
||||
instance.initialize_from_bin(bin)
|
||||
@ -55,109 +61,63 @@ module MachO
|
||||
@raw_data
|
||||
end
|
||||
|
||||
# @return [Boolean] true if the Mach-O has 32-bit magic, false otherwise
|
||||
def magic32?
|
||||
Utils.magic32?(header.magic)
|
||||
end
|
||||
|
||||
# @return [Boolean] true if the Mach-O has 64-bit magic, false otherwise
|
||||
def magic64?
|
||||
Utils.magic64?(header.magic)
|
||||
end
|
||||
|
||||
# @return [Fixnum] the file's internal alignment
|
||||
def alignment
|
||||
magic32? ? 4 : 8
|
||||
end
|
||||
|
||||
# @return [Boolean] true if the file is of type `MH_OBJECT`, false otherwise
|
||||
def object?
|
||||
header.filetype == MH_OBJECT
|
||||
end
|
||||
|
||||
# @return [Boolean] true if the file is of type `MH_EXECUTE`, false otherwise
|
||||
def executable?
|
||||
header.filetype == MH_EXECUTE
|
||||
end
|
||||
|
||||
# @return [Boolean] true if the file is of type `MH_FVMLIB`, false otherwise
|
||||
def fvmlib?
|
||||
header.filetype == MH_FVMLIB
|
||||
end
|
||||
|
||||
# @return [Boolean] true if the file is of type `MH_CORE`, false otherwise
|
||||
def core?
|
||||
header.filetype == MH_CORE
|
||||
end
|
||||
|
||||
# @return [Boolean] true if the file is of type `MH_PRELOAD`, false otherwise
|
||||
def preload?
|
||||
header.filetype == MH_PRELOAD
|
||||
end
|
||||
|
||||
# @return [Boolean] true if the file is of type `MH_DYLIB`, false otherwise
|
||||
def dylib?
|
||||
header.filetype == MH_DYLIB
|
||||
end
|
||||
|
||||
# @return [Boolean] true if the file is of type `MH_DYLINKER`, false otherwise
|
||||
def dylinker?
|
||||
header.filetype == MH_DYLINKER
|
||||
end
|
||||
|
||||
# @return [Boolean] true if the file is of type `MH_BUNDLE`, false otherwise
|
||||
def bundle?
|
||||
header.filetype == MH_BUNDLE
|
||||
end
|
||||
|
||||
# @return [Boolean] true if the file is of type `MH_DSYM`, false otherwise
|
||||
def dsym?
|
||||
header.filetype == MH_DSYM
|
||||
end
|
||||
|
||||
# @return [Boolean] true if the file is of type `MH_KEXT_BUNDLE`, false otherwise
|
||||
def kext?
|
||||
header.filetype == MH_KEXT_BUNDLE
|
||||
end
|
||||
|
||||
# @return [Fixnum] the file's magic number
|
||||
def magic
|
||||
header.magic
|
||||
end
|
||||
# @!method magic
|
||||
# @return (see MachO::Headers::MachHeader#magic)
|
||||
# @!method ncmds
|
||||
# @return (see MachO::Headers::MachHeader#ncmds)
|
||||
# @!method sizeofcmds
|
||||
# @return (see MachO::Headers::MachHeader#sizeofcmds)
|
||||
# @!method flags
|
||||
# @return (see MachO::Headers::MachHeader#flags)
|
||||
# @!method object?
|
||||
# @return (see MachO::Headers::MachHeader#object?)
|
||||
# @!method executable?
|
||||
# @return (see MachO::Headers::MachHeader#executable?)
|
||||
# @!method fvmlib?
|
||||
# @return (see MachO::Headers::MachHeader#fvmlib?)
|
||||
# @!method core?
|
||||
# @return (see MachO::Headers::MachHeader#core?)
|
||||
# @!method preload?
|
||||
# @return (see MachO::Headers::MachHeader#preload?)
|
||||
# @!method dylib?
|
||||
# @return (see MachO::Headers::MachHeader#dylib?)
|
||||
# @!method dylinker?
|
||||
# @return (see MachO::Headers::MachHeader#dylinker?)
|
||||
# @!method bundle?
|
||||
# @return (see MachO::Headers::MachHeader#bundle?)
|
||||
# @!method dsym?
|
||||
# @return (see MachO::Headers::MachHeader#dsym?)
|
||||
# @!method kext?
|
||||
# @return (see MachO::Headers::MachHeader#kext?)
|
||||
# @!method magic32?
|
||||
# @return (see MachO::Headers::MachHeader#magic32?)
|
||||
# @!method magic64?
|
||||
# @return (see MachO::Headers::MachHeader#magic64?)
|
||||
# @!method alignment
|
||||
# @return (see MachO::Headers::MachHeader#alignment)
|
||||
def_delegators :header, :magic, :ncmds, :sizeofcmds, :flags, :object?,
|
||||
:executable?, :fvmlib?, :core?, :preload?, :dylib?,
|
||||
:dylinker?, :bundle?, :dsym?, :kext?, :magic32?, :magic64?,
|
||||
:alignment
|
||||
|
||||
# @return [String] a string representation of the file's magic number
|
||||
def magic_string
|
||||
MH_MAGICS[magic]
|
||||
Headers::MH_MAGICS[magic]
|
||||
end
|
||||
|
||||
# @return [Symbol] a string representation of the Mach-O's filetype
|
||||
def filetype
|
||||
MH_FILETYPES[header.filetype]
|
||||
Headers::MH_FILETYPES[header.filetype]
|
||||
end
|
||||
|
||||
# @return [Symbol] a symbol representation of the Mach-O's CPU type
|
||||
def cputype
|
||||
CPU_TYPES[header.cputype]
|
||||
Headers::CPU_TYPES[header.cputype]
|
||||
end
|
||||
|
||||
# @return [Symbol] a symbol representation of the Mach-O's CPU subtype
|
||||
def cpusubtype
|
||||
CPU_SUBTYPES[header.cputype][header.cpusubtype]
|
||||
end
|
||||
|
||||
# @return [Fixnum] the number of load commands in the Mach-O's header
|
||||
def ncmds
|
||||
header.ncmds
|
||||
end
|
||||
|
||||
# @return [Fixnum] the size of all load commands, in bytes
|
||||
def sizeofcmds
|
||||
header.sizeofcmds
|
||||
end
|
||||
|
||||
# @return [Fixnum] execution flags set by the linker
|
||||
def flags
|
||||
header.flags
|
||||
Headers::CPU_SUBTYPES[header.cputype][header.cpusubtype]
|
||||
end
|
||||
|
||||
# All load commands of a given name.
|
||||
@ -165,7 +125,8 @@ module MachO
|
||||
# file.command("LC_LOAD_DYLIB")
|
||||
# file[:LC_LOAD_DYLIB]
|
||||
# @param [String, Symbol] name the load command ID
|
||||
# @return [Array<MachO::LoadCommand>] an array of LoadCommands corresponding to `name`
|
||||
# @return [Array<LoadCommands::LoadCommand>] an array of load commands
|
||||
# corresponding to `name`
|
||||
def command(name)
|
||||
load_commands.select { |lc| lc.type == name.to_sym }
|
||||
end
|
||||
@ -174,16 +135,16 @@ module MachO
|
||||
|
||||
# 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 lc [LoadCommands::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
|
||||
# @raise [OffsetInsertionError] if the offset is not in the load command region
|
||||
# @raise [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)
|
||||
context = LoadCommands::LoadCommand::SerializationContext.context_for(self)
|
||||
cmd_raw = lc.serialize(context)
|
||||
|
||||
if offset < header.class.bytesize || offset + cmd_raw.bytesize > low_fileoff
|
||||
@ -207,14 +168,14 @@ module MachO
|
||||
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
|
||||
# @param old_lc [LoadCommands::LoadCommand] the load command being replaced
|
||||
# @param new_lc [LoadCommands::LoadCommand] the load command being added
|
||||
# @return [void]
|
||||
# @raise [MachO::HeaderPadError] if the new command exceeds the header pad buffer
|
||||
# @see {#insert_command}
|
||||
# @raise [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)
|
||||
context = LoadCommands::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
|
||||
@ -226,12 +187,12 @@ module MachO
|
||||
end
|
||||
|
||||
# Appends a new load command to the Mach-O.
|
||||
# @param lc [MachO::LoadCommand] the load command being added
|
||||
# @param lc [LoadCommands::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}
|
||||
# @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**
|
||||
@ -241,7 +202,7 @@ module MachO
|
||||
end
|
||||
|
||||
# Delete a load command from the Mach-O.
|
||||
# @param lc [MachO::LoadCommand] the load command being deleted
|
||||
# @param lc [LoadCommands::LoadCommand] the load command being deleted
|
||||
# @param options [Hash]
|
||||
# @option options [Boolean] :repopulate (true) whether or not to repopulate
|
||||
# the instance fields
|
||||
@ -275,14 +236,14 @@ module MachO
|
||||
end
|
||||
|
||||
# All load commands responsible for loading dylibs.
|
||||
# @return [Array<MachO::DylibCommand>] an array of DylibCommands
|
||||
# @return [Array<LoadCommands::DylibCommand>] an array of DylibCommands
|
||||
def dylib_load_commands
|
||||
load_commands.select { |lc| DYLIB_LOAD_COMMANDS.include?(lc.type) }
|
||||
load_commands.select { |lc| LoadCommands::DYLIB_LOAD_COMMANDS.include?(lc.type) }
|
||||
end
|
||||
|
||||
# All segment load commands in the Mach-O.
|
||||
# @return [Array<MachO::SegmentCommand>] if the Mach-O is 32-bit
|
||||
# @return [Array<MachO::SegmentCommand64>] if the Mach-O is 64-bit
|
||||
# @return [Array<LoadCommands::SegmentCommand>] if the Mach-O is 32-bit
|
||||
# @return [Array<LoadCommands::SegmentCommand64>] if the Mach-O is 64-bit
|
||||
def segments
|
||||
if magic32?
|
||||
command(:LC_SEGMENT)
|
||||
@ -319,10 +280,10 @@ module MachO
|
||||
old_lc = command(:LC_ID_DYLIB).first
|
||||
raise DylibIdMissingError unless old_lc
|
||||
|
||||
new_lc = LoadCommand.create(:LC_ID_DYLIB, new_id,
|
||||
old_lc.timestamp,
|
||||
old_lc.current_version,
|
||||
old_lc.compatibility_version)
|
||||
new_lc = LoadCommands::LoadCommand.create(:LC_ID_DYLIB, new_id,
|
||||
old_lc.timestamp,
|
||||
old_lc.current_version,
|
||||
old_lc.compatibility_version)
|
||||
|
||||
replace_command(old_lc, new_lc)
|
||||
end
|
||||
@ -341,22 +302,22 @@ module MachO
|
||||
|
||||
# Changes the shared library `old_name` to `new_name`
|
||||
# @example
|
||||
# file.change_install_name("/usr/lib/libWhatever.dylib", "/usr/local/lib/libWhatever2.dylib")
|
||||
# file.change_install_name("abc.dylib", "def.dylib")
|
||||
# @param old_name [String] the shared library's old name
|
||||
# @param new_name [String] the shared library's new name
|
||||
# @param _options [Hash]
|
||||
# @return [void]
|
||||
# @raise [MachO::DylibUnknownError] if no shared library has the old name
|
||||
# @raise [DylibUnknownError] if no shared library has the old name
|
||||
# @note `_options` is currently unused and is provided for signature
|
||||
# compatibility with {MachO::FatFile#change_install_name}
|
||||
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?
|
||||
|
||||
new_lc = LoadCommand.create(old_lc.type, new_name,
|
||||
old_lc.timestamp,
|
||||
old_lc.current_version,
|
||||
old_lc.compatibility_version)
|
||||
new_lc = LoadCommands::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
|
||||
@ -376,8 +337,8 @@ module MachO
|
||||
# @param new_path [String] the new runtime path
|
||||
# @param _options [Hash]
|
||||
# @return [void]
|
||||
# @raise [MachO::RpathUnknownError] if no such old runtime path exists
|
||||
# @raise [MachO::RpathExistsError] if the new runtime path already exists
|
||||
# @raise [RpathUnknownError] if no such old runtime path exists
|
||||
# @raise [RpathExistsError] if the new runtime path already exists
|
||||
# @note `_options` is currently unused and is provided for signature
|
||||
# compatibility with {MachO::FatFile#change_rpath}
|
||||
def change_rpath(old_path, new_path, _options = {})
|
||||
@ -385,7 +346,7 @@ module MachO
|
||||
raise RpathUnknownError, old_path if old_lc.nil?
|
||||
raise RpathExistsError, new_path if rpaths.include?(new_path)
|
||||
|
||||
new_lc = LoadCommand.create(:LC_RPATH, new_path)
|
||||
new_lc = LoadCommands::LoadCommand.create(:LC_RPATH, new_path)
|
||||
|
||||
delete_rpath(old_path)
|
||||
insert_command(old_lc.view.offset, new_lc)
|
||||
@ -399,13 +360,13 @@ module MachO
|
||||
# @param path [String] the new runtime path
|
||||
# @param _options [Hash]
|
||||
# @return [void]
|
||||
# @raise [MachO::RpathExistsError] if the runtime path already exists
|
||||
# @raise [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)
|
||||
rpath_cmd = LoadCommands::LoadCommand.create(:LC_RPATH, path)
|
||||
add_command(rpath_cmd)
|
||||
end
|
||||
|
||||
@ -417,7 +378,7 @@ module MachO
|
||||
# @param path [String] the runtime path to delete
|
||||
# @param _options [Hash]
|
||||
# @return void
|
||||
# @raise [MachO::RpathUnknownError] if no such runtime path exists
|
||||
# @raise [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 = {})
|
||||
@ -431,15 +392,6 @@ module MachO
|
||||
populate_fields
|
||||
end
|
||||
|
||||
# All sections of the segment `segment`.
|
||||
# @param segment [MachO::SegmentCommand, MachO::SegmentCommand64] the segment being inspected
|
||||
# @return [Array<MachO::Section>] if the Mach-O is 32-bit
|
||||
# @return [Array<MachO::Section64>] if the Mach-O is 64-bit
|
||||
# @deprecated use {MachO::SegmentCommand#sections} instead
|
||||
def sections(segment)
|
||||
segment.sections
|
||||
end
|
||||
|
||||
# Write all Mach-O data to the given filename.
|
||||
# @param filename [String] the file to write to
|
||||
# @return [void]
|
||||
@ -449,7 +401,7 @@ module MachO
|
||||
|
||||
# Write all Mach-O data to the file used to initialize the instance.
|
||||
# @return [void]
|
||||
# @raise [MachO::MachOError] if the instance was initialized without a file
|
||||
# @raise [MachOError] if the instance was initialized without a file
|
||||
# @note Overwrites all data in the file!
|
||||
def write!
|
||||
if @filename.nil?
|
||||
@ -462,16 +414,16 @@ module MachO
|
||||
private
|
||||
|
||||
# The file's Mach-O header structure.
|
||||
# @return [MachO::MachHeader] if the Mach-O is 32-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
|
||||
# @return [Headers::MachHeader] if the Mach-O is 32-bit
|
||||
# @return [Headers::MachHeader64] if the Mach-O is 64-bit
|
||||
# @raise [TruncatedFileError] if the file is too small to have a valid header
|
||||
# @api private
|
||||
def populate_mach_header
|
||||
# the smallest Mach-O header is 28 bytes
|
||||
raise TruncatedFileError if @raw_data.size < 28
|
||||
|
||||
magic = populate_and_check_magic
|
||||
mh_klass = Utils.magic32?(magic) ? MachHeader : MachHeader64
|
||||
mh_klass = Utils.magic32?(magic) ? Headers::MachHeader : Headers::MachHeader64
|
||||
mh = mh_klass.new_from_bin(endianness, @raw_data[0, mh_klass.bytesize])
|
||||
|
||||
check_cputype(mh.cputype)
|
||||
@ -483,8 +435,8 @@ module MachO
|
||||
|
||||
# Read just the file's magic number and check its validity.
|
||||
# @return [Fixnum] the 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 [MagicError] if the magic is not valid Mach-O magic
|
||||
# @raise [FatBinaryError] if the magic is for a Fat file
|
||||
# @api private
|
||||
def populate_and_check_magic
|
||||
magic = @raw_data[0..3].unpack("N").first
|
||||
@ -499,32 +451,32 @@ module MachO
|
||||
|
||||
# Check the file's CPU type.
|
||||
# @param cputype [Fixnum] the CPU type
|
||||
# @raise [MachO::CPUTypeError] if the CPU type is unknown
|
||||
# @raise [CPUTypeError] if the CPU type is unknown
|
||||
# @api private
|
||||
def check_cputype(cputype)
|
||||
raise CPUTypeError, cputype unless CPU_TYPES.key?(cputype)
|
||||
raise CPUTypeError, cputype unless Headers::CPU_TYPES.key?(cputype)
|
||||
end
|
||||
|
||||
# Check the file's CPU type/subtype pair.
|
||||
# @param cpusubtype [Fixnum] the CPU subtype
|
||||
# @raise [MachO::CPUSubtypeError] if the CPU sub-type is unknown
|
||||
# @raise [CPUSubtypeError] if the CPU sub-type is unknown
|
||||
# @api private
|
||||
def check_cpusubtype(cputype, cpusubtype)
|
||||
# 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 Headers::CPU_SUBTYPES[cputype].key?(cpusubtype)
|
||||
end
|
||||
|
||||
# Check the file's type.
|
||||
# @param filetype [Fixnum] the file type
|
||||
# @raise [MachO::FiletypeError] if the file type is unknown
|
||||
# @raise [FiletypeError] if the file type is unknown
|
||||
# @api private
|
||||
def check_filetype(filetype)
|
||||
raise FiletypeError, filetype unless MH_FILETYPES.key?(filetype)
|
||||
raise FiletypeError, filetype unless Headers::MH_FILETYPES.key?(filetype)
|
||||
end
|
||||
|
||||
# All load commands in the file.
|
||||
# @return [Array<MachO::LoadCommand>] an array of load commands
|
||||
# @raise [MachO::LoadCommandError] if an unknown load command is encountered
|
||||
# @return [Array<LoadCommands::LoadCommand>] an array of load commands
|
||||
# @raise [LoadCommandError] if an unknown load command is encountered
|
||||
# @api private
|
||||
def populate_load_commands
|
||||
offset = header.class.bytesize
|
||||
@ -533,13 +485,13 @@ module MachO
|
||||
header.ncmds.times do
|
||||
fmt = Utils.specialize_format("L=", endianness)
|
||||
cmd = @raw_data.slice(offset, 4).unpack(fmt).first
|
||||
cmd_sym = LOAD_COMMANDS[cmd]
|
||||
cmd_sym = LoadCommands::LOAD_COMMANDS[cmd]
|
||||
|
||||
raise LoadCommandError, cmd if cmd_sym.nil?
|
||||
|
||||
# why do I do this? i don't like declaring constants below
|
||||
# classes, and i need them to resolve...
|
||||
klass = MachO.const_get LC_STRUCTURES[cmd_sym]
|
||||
klass = LoadCommands.const_get LoadCommands::LC_STRUCTURES[cmd_sym]
|
||||
view = MachOView.new(@raw_data, endianness, offset)
|
||||
command = klass.new_from_bin(view)
|
||||
|
||||
|
25
Library/Homebrew/vendor/macho/macho/open.rb
vendored
25
Library/Homebrew/vendor/macho/macho/open.rb
vendored
@ -1,25 +0,0 @@
|
||||
module MachO
|
||||
# Opens the given filename as a MachOFile or FatFile, depending on its magic.
|
||||
# @param filename [String] the file being opened
|
||||
# @return [MachO::MachOFile] if the file is a Mach-O
|
||||
# @return [MachO::FatFile] if the file is a Fat file
|
||||
# @raise [ArgumentError] if the given file does not exist
|
||||
# @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
|
||||
def self.open(filename)
|
||||
raise ArgumentError, "#{filename}: no such file" unless File.file?(filename)
|
||||
raise TruncatedFileError unless File.stat(filename).size >= 4
|
||||
|
||||
magic = File.open(filename, "rb") { |f| f.read(4) }.unpack("N").first
|
||||
|
||||
if Utils.fat_magic?(magic)
|
||||
file = FatFile.new(filename)
|
||||
elsif Utils.magic?(magic)
|
||||
file = MachOFile.new(filename)
|
||||
else
|
||||
raise MagicError, magic
|
||||
end
|
||||
|
||||
file
|
||||
end
|
||||
end
|
324
Library/Homebrew/vendor/macho/macho/sections.rb
vendored
324
Library/Homebrew/vendor/macho/macho/sections.rb
vendored
@ -1,170 +1,176 @@
|
||||
module MachO
|
||||
# type mask
|
||||
SECTION_TYPE = 0x000000ff
|
||||
# Classes and constants for parsing sections in Mach-O binaries.
|
||||
module Sections
|
||||
# type mask
|
||||
SECTION_TYPE = 0x000000ff
|
||||
|
||||
# attributes mask
|
||||
SECTION_ATTRIBUTES = 0xffffff00
|
||||
# attributes mask
|
||||
SECTION_ATTRIBUTES = 0xffffff00
|
||||
|
||||
# user settable attributes mask
|
||||
SECTION_ATTRIBUTES_USR = 0xff000000
|
||||
# user settable attributes mask
|
||||
SECTION_ATTRIBUTES_USR = 0xff000000
|
||||
|
||||
# system settable attributes mask
|
||||
SECTION_ATTRIBUTES_SYS = 0x00ffff00
|
||||
|
||||
# association of section flag symbols to values
|
||||
# @api private
|
||||
SECTION_FLAGS = {
|
||||
:S_REGULAR => 0x0,
|
||||
:S_ZEROFILL => 0x1,
|
||||
:S_CSTRING_LITERALS => 0x2,
|
||||
:S_4BYTE_LITERALS => 0x3,
|
||||
:S_8BYTE_LITERALS => 0x4,
|
||||
:S_LITERAL_POINTERS => 0x5,
|
||||
:S_NON_LAZY_SYMBOL_POINTERS => 0x6,
|
||||
:S_LAZY_SYMBOL_POINTERS => 0x7,
|
||||
:S_SYMBOL_STUBS => 0x8,
|
||||
:S_MOD_INIT_FUNC_POINTERS => 0x9,
|
||||
:S_MOD_TERM_FUNC_POINTERS => 0xa,
|
||||
:S_COALESCED => 0xb,
|
||||
:S_GB_ZEROFILE => 0xc,
|
||||
:S_INTERPOSING => 0xd,
|
||||
:S_16BYTE_LITERALS => 0xe,
|
||||
:S_DTRACE_DOF => 0xf,
|
||||
:S_LAZY_DYLIB_SYMBOL_POINTERS => 0x10,
|
||||
:S_THREAD_LOCAL_REGULAR => 0x11,
|
||||
:S_THREAD_LOCAL_ZEROFILL => 0x12,
|
||||
:S_THREAD_LOCAL_VARIABLES => 0x13,
|
||||
:S_THREAD_LOCAL_VARIABLE_POINTERS => 0x14,
|
||||
:S_THREAD_LOCAL_INIT_FUNCTION_POINTERS => 0x15,
|
||||
:S_ATTR_PURE_INSTRUCTIONS => 0x80000000,
|
||||
:S_ATTR_NO_TOC => 0x40000000,
|
||||
:S_ATTR_STRIP_STATIC_SYMS => 0x20000000,
|
||||
:S_ATTR_NO_DEAD_STRIP => 0x10000000,
|
||||
:S_ATTR_LIVE_SUPPORT => 0x08000000,
|
||||
:S_ATTR_SELF_MODIFYING_CODE => 0x04000000,
|
||||
:S_ATTR_DEBUG => 0x02000000,
|
||||
:S_ATTR_SOME_INSTRUCTIONS => 0x00000400,
|
||||
:S_ATTR_EXT_RELOC => 0x00000200,
|
||||
:S_ATTR_LOC_RELOC => 0x00000100,
|
||||
}.freeze
|
||||
|
||||
# association of section name symbols to names
|
||||
# @api private
|
||||
SECTION_NAMES = {
|
||||
:SECT_TEXT => "__text",
|
||||
:SECT_FVMLIB_INIT0 => "__fvmlib_init0",
|
||||
:SECT_FVMLIB_INIT1 => "__fvmlib_init1",
|
||||
:SECT_DATA => "__data",
|
||||
:SECT_BSS => "__bss",
|
||||
:SECT_COMMON => "__common",
|
||||
:SECT_OBJC_SYMBOLS => "__symbol_table",
|
||||
:SECT_OBJC_MODULES => "__module_info",
|
||||
:SECT_OBJC_STRINGS => "__selector_strs",
|
||||
:SECT_OBJC_REFS => "__selector_refs",
|
||||
:SECT_ICON_HEADER => "__header",
|
||||
:SECT_ICON_TIFF => "__tiff",
|
||||
}.freeze
|
||||
|
||||
# Represents a section of a segment for 32-bit architectures.
|
||||
class Section < MachOStructure
|
||||
# @return [String] the name of the section, including null pad bytes
|
||||
attr_reader :sectname
|
||||
|
||||
# @return [String] the name of the segment's section, including null pad bytes
|
||||
attr_reader :segname
|
||||
|
||||
# @return [Fixnum] the memory address of the section
|
||||
attr_reader :addr
|
||||
|
||||
# @return [Fixnum] the size, in bytes, of the section
|
||||
attr_reader :size
|
||||
|
||||
# @return [Fixnum] the file offset of the section
|
||||
attr_reader :offset
|
||||
|
||||
# @return [Fixnum] the section alignment (power of 2) of the section
|
||||
attr_reader :align
|
||||
|
||||
# @return [Fixnum] the file offset of the section's relocation entries
|
||||
attr_reader :reloff
|
||||
|
||||
# @return [Fixnum] the number of relocation entries
|
||||
attr_reader :nreloc
|
||||
|
||||
# @return [Fixnum] flags for type and attributes of the section
|
||||
attr_reader :flags
|
||||
|
||||
# @return [void] reserved (for offset or index)
|
||||
attr_reader :reserved1
|
||||
|
||||
# @return [void] reserved (for count or sizeof)
|
||||
attr_reader :reserved2
|
||||
|
||||
# @see MachOStructure::FORMAT
|
||||
FORMAT = "a16a16L=9".freeze
|
||||
|
||||
# @see MachOStructure::SIZEOF
|
||||
SIZEOF = 68
|
||||
# system settable attributes mask
|
||||
SECTION_ATTRIBUTES_SYS = 0x00ffff00
|
||||
|
||||
# association of section flag symbols to values
|
||||
# @api private
|
||||
def initialize(sectname, segname, addr, size, offset, align, reloff,
|
||||
nreloc, flags, reserved1, reserved2)
|
||||
@sectname = sectname
|
||||
@segname = segname
|
||||
@addr = addr
|
||||
@size = size
|
||||
@offset = offset
|
||||
@align = align
|
||||
@reloff = reloff
|
||||
@nreloc = nreloc
|
||||
@flags = flags
|
||||
@reserved1 = reserved1
|
||||
@reserved2 = reserved2
|
||||
end
|
||||
|
||||
# @return [String] the section's name, with any trailing NULL characters removed
|
||||
def section_name
|
||||
sectname.delete("\x00")
|
||||
end
|
||||
|
||||
# @return [String] the parent segment's name, with any trailing NULL characters removed
|
||||
def segment_name
|
||||
segname.delete("\x00")
|
||||
end
|
||||
|
||||
# @return [Boolean] true if the section has no contents (i.e, `size` is 0)
|
||||
def empty?
|
||||
size.zero?
|
||||
end
|
||||
|
||||
# @example
|
||||
# puts "this section is regular" if sect.flag?(:S_REGULAR)
|
||||
# @param flag [Symbol] a section flag symbol
|
||||
# @return [Boolean] true if `flag` is present in the section's flag field
|
||||
def flag?(flag)
|
||||
flag = SECTION_FLAGS[flag]
|
||||
return false if flag.nil?
|
||||
flags & flag == flag
|
||||
end
|
||||
end
|
||||
|
||||
# Represents a section of a segment for 64-bit architectures.
|
||||
class Section64 < Section
|
||||
# @return [void] reserved
|
||||
attr_reader :reserved3
|
||||
|
||||
# @see MachOStructure::FORMAT
|
||||
FORMAT = "a16a16Q=2L=8".freeze
|
||||
|
||||
# @see MachOStructure::SIZEOF
|
||||
SIZEOF = 80
|
||||
SECTION_FLAGS = {
|
||||
:S_REGULAR => 0x0,
|
||||
:S_ZEROFILL => 0x1,
|
||||
:S_CSTRING_LITERALS => 0x2,
|
||||
:S_4BYTE_LITERALS => 0x3,
|
||||
:S_8BYTE_LITERALS => 0x4,
|
||||
:S_LITERAL_POINTERS => 0x5,
|
||||
:S_NON_LAZY_SYMBOL_POINTERS => 0x6,
|
||||
:S_LAZY_SYMBOL_POINTERS => 0x7,
|
||||
:S_SYMBOL_STUBS => 0x8,
|
||||
:S_MOD_INIT_FUNC_POINTERS => 0x9,
|
||||
:S_MOD_TERM_FUNC_POINTERS => 0xa,
|
||||
:S_COALESCED => 0xb,
|
||||
:S_GB_ZEROFILE => 0xc,
|
||||
:S_INTERPOSING => 0xd,
|
||||
:S_16BYTE_LITERALS => 0xe,
|
||||
:S_DTRACE_DOF => 0xf,
|
||||
:S_LAZY_DYLIB_SYMBOL_POINTERS => 0x10,
|
||||
:S_THREAD_LOCAL_REGULAR => 0x11,
|
||||
:S_THREAD_LOCAL_ZEROFILL => 0x12,
|
||||
:S_THREAD_LOCAL_VARIABLES => 0x13,
|
||||
:S_THREAD_LOCAL_VARIABLE_POINTERS => 0x14,
|
||||
:S_THREAD_LOCAL_INIT_FUNCTION_POINTERS => 0x15,
|
||||
:S_ATTR_PURE_INSTRUCTIONS => 0x80000000,
|
||||
:S_ATTR_NO_TOC => 0x40000000,
|
||||
:S_ATTR_STRIP_STATIC_SYMS => 0x20000000,
|
||||
:S_ATTR_NO_DEAD_STRIP => 0x10000000,
|
||||
:S_ATTR_LIVE_SUPPORT => 0x08000000,
|
||||
:S_ATTR_SELF_MODIFYING_CODE => 0x04000000,
|
||||
:S_ATTR_DEBUG => 0x02000000,
|
||||
:S_ATTR_SOME_INSTRUCTIONS => 0x00000400,
|
||||
:S_ATTR_EXT_RELOC => 0x00000200,
|
||||
:S_ATTR_LOC_RELOC => 0x00000100,
|
||||
}.freeze
|
||||
|
||||
# association of section name symbols to names
|
||||
# @api private
|
||||
def initialize(sectname, segname, addr, size, offset, align, reloff,
|
||||
nreloc, flags, reserved1, reserved2, reserved3)
|
||||
super(sectname, segname, addr, size, offset, align, reloff,
|
||||
nreloc, flags, reserved1, reserved2)
|
||||
@reserved3 = reserved3
|
||||
SECTION_NAMES = {
|
||||
:SECT_TEXT => "__text",
|
||||
:SECT_FVMLIB_INIT0 => "__fvmlib_init0",
|
||||
:SECT_FVMLIB_INIT1 => "__fvmlib_init1",
|
||||
:SECT_DATA => "__data",
|
||||
:SECT_BSS => "__bss",
|
||||
:SECT_COMMON => "__common",
|
||||
:SECT_OBJC_SYMBOLS => "__symbol_table",
|
||||
:SECT_OBJC_MODULES => "__module_info",
|
||||
:SECT_OBJC_STRINGS => "__selector_strs",
|
||||
:SECT_OBJC_REFS => "__selector_refs",
|
||||
:SECT_ICON_HEADER => "__header",
|
||||
:SECT_ICON_TIFF => "__tiff",
|
||||
}.freeze
|
||||
|
||||
# Represents a section of a segment for 32-bit architectures.
|
||||
class Section < MachOStructure
|
||||
# @return [String] the name of the section, including null pad bytes
|
||||
attr_reader :sectname
|
||||
|
||||
# @return [String] the name of the segment's section, including null
|
||||
# pad bytes
|
||||
attr_reader :segname
|
||||
|
||||
# @return [Fixnum] the memory address of the section
|
||||
attr_reader :addr
|
||||
|
||||
# @return [Fixnum] the size, in bytes, of the section
|
||||
attr_reader :size
|
||||
|
||||
# @return [Fixnum] the file offset of the section
|
||||
attr_reader :offset
|
||||
|
||||
# @return [Fixnum] the section alignment (power of 2) of the section
|
||||
attr_reader :align
|
||||
|
||||
# @return [Fixnum] the file offset of the section's relocation entries
|
||||
attr_reader :reloff
|
||||
|
||||
# @return [Fixnum] the number of relocation entries
|
||||
attr_reader :nreloc
|
||||
|
||||
# @return [Fixnum] flags for type and attributes of the section
|
||||
attr_reader :flags
|
||||
|
||||
# @return [void] reserved (for offset or index)
|
||||
attr_reader :reserved1
|
||||
|
||||
# @return [void] reserved (for count or sizeof)
|
||||
attr_reader :reserved2
|
||||
|
||||
# @see MachOStructure::FORMAT
|
||||
FORMAT = "a16a16L=9".freeze
|
||||
|
||||
# @see MachOStructure::SIZEOF
|
||||
SIZEOF = 68
|
||||
|
||||
# @api private
|
||||
def initialize(sectname, segname, addr, size, offset, align, reloff,
|
||||
nreloc, flags, reserved1, reserved2)
|
||||
@sectname = sectname
|
||||
@segname = segname
|
||||
@addr = addr
|
||||
@size = size
|
||||
@offset = offset
|
||||
@align = align
|
||||
@reloff = reloff
|
||||
@nreloc = nreloc
|
||||
@flags = flags
|
||||
@reserved1 = reserved1
|
||||
@reserved2 = reserved2
|
||||
end
|
||||
|
||||
# @return [String] the section's name, with any trailing NULL characters
|
||||
# removed
|
||||
def section_name
|
||||
sectname.delete("\x00")
|
||||
end
|
||||
|
||||
# @return [String] the parent segment's name, with any trailing NULL
|
||||
# characters removed
|
||||
def segment_name
|
||||
segname.delete("\x00")
|
||||
end
|
||||
|
||||
# @return [Boolean] whether the section is empty (i.e, {size} is 0)
|
||||
def empty?
|
||||
size.zero?
|
||||
end
|
||||
|
||||
# @example
|
||||
# puts "this section is regular" if sect.flag?(:S_REGULAR)
|
||||
# @param flag [Symbol] a section flag symbol
|
||||
# @return [Boolean] whether the flag is present in the section's {flags}
|
||||
def flag?(flag)
|
||||
flag = SECTION_FLAGS[flag]
|
||||
return false if flag.nil?
|
||||
flags & flag == flag
|
||||
end
|
||||
end
|
||||
|
||||
# Represents a section of a segment for 64-bit architectures.
|
||||
class Section64 < Section
|
||||
# @return [void] reserved
|
||||
attr_reader :reserved3
|
||||
|
||||
# @see MachOStructure::FORMAT
|
||||
FORMAT = "a16a16Q=2L=8".freeze
|
||||
|
||||
# @see MachOStructure::SIZEOF
|
||||
SIZEOF = 80
|
||||
|
||||
# @api private
|
||||
def initialize(sectname, segname, addr, size, offset, align, reloff,
|
||||
nreloc, flags, reserved1, reserved2, reserved3)
|
||||
super(sectname, segname, addr, size, offset, align, reloff,
|
||||
nreloc, flags, reserved1, reserved2)
|
||||
@reserved3 = reserved3
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -19,7 +19,7 @@ module MachO
|
||||
|
||||
# @param endianness [Symbol] either `:big` or `:little`
|
||||
# @param bin [String] the string to be unpacked into the new structure
|
||||
# @return [MachO::MachOStructure] a new MachOStructure initialized with `bin`
|
||||
# @return [MachO::MachOStructure] the resulting structure
|
||||
# @api private
|
||||
def self.new_from_bin(endianness, bin)
|
||||
format = Utils.specialize_format(self::FORMAT, endianness)
|
||||
|
34
Library/Homebrew/vendor/macho/macho/tools.rb
vendored
34
Library/Homebrew/vendor/macho/macho/tools.rb
vendored
@ -1,5 +1,6 @@
|
||||
module MachO
|
||||
# A collection of convenient methods for common operations on Mach-O and Fat binaries.
|
||||
# A collection of convenient methods for common operations on Mach-O and Fat
|
||||
# binaries.
|
||||
module Tools
|
||||
# @param filename [String] the Mach-O or Fat binary being read
|
||||
# @return [Array<String>] an array of all dylibs linked to the binary
|
||||
@ -9,7 +10,8 @@ module MachO
|
||||
file.linked_dylibs
|
||||
end
|
||||
|
||||
# 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 new_id [String] the new dylib ID for the binary
|
||||
# @param options [Hash]
|
||||
@ -23,7 +25,8 @@ module MachO
|
||||
file.write!
|
||||
end
|
||||
|
||||
# Changes a shared library install name in a Mach-O or Fat binary, overwriting the source file.
|
||||
# Changes a shared library install name in a Mach-O or Fat binary,
|
||||
# overwriting the source file.
|
||||
# @param filename [String] the Mach-O or Fat binary being modified
|
||||
# @param old_name [String] the old shared library name
|
||||
# @param new_name [String] the new shared library name
|
||||
@ -38,7 +41,8 @@ module MachO
|
||||
file.write!
|
||||
end
|
||||
|
||||
# Changes a runtime path in a Mach-O or Fat binary, overwriting the source file.
|
||||
# Changes a runtime path in a Mach-O or Fat binary, overwriting the source
|
||||
# file.
|
||||
# @param filename [String] the Mach-O or Fat binary being modified
|
||||
# @param old_path [String] the old runtime path
|
||||
# @param new_path [String] the new runtime path
|
||||
@ -67,7 +71,8 @@ module MachO
|
||||
file.write!
|
||||
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 old_path [String] the old runtime path
|
||||
# @param options [Hash]
|
||||
@ -80,5 +85,24 @@ module MachO
|
||||
file.delete_rpath(old_path, options)
|
||||
file.write!
|
||||
end
|
||||
|
||||
# Merge multiple Mach-Os into one universal (Fat) binary.
|
||||
# @param filename [String] the fat binary to create
|
||||
# @param files [Array<MachO::MachOFile, MachO::FatFile>] the files to merge
|
||||
# @return [void]
|
||||
def self.merge_machos(filename, *files)
|
||||
machos = files.map do |file|
|
||||
macho = MachO.open(file)
|
||||
case macho
|
||||
when MachO::MachOFile
|
||||
macho
|
||||
else
|
||||
macho.machos
|
||||
end
|
||||
end.flatten
|
||||
|
||||
fat_macho = MachO::FatFile.new_from_machos(*machos)
|
||||
fat_macho.write(filename)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
35
Library/Homebrew/vendor/macho/macho/utils.rb
vendored
35
Library/Homebrew/vendor/macho/macho/utils.rb
vendored
@ -5,7 +5,7 @@ module MachO
|
||||
# @param value [Fixnum] the number being rounded
|
||||
# @param round [Fixnum] the number being rounded with
|
||||
# @return [Fixnum] the rounded value
|
||||
# @see https://www.opensource.apple.com/source/cctools/cctools-870/libstuff/rnd.c
|
||||
# @see http://www.opensource.apple.com/source/cctools/cctools-870/libstuff/rnd.c
|
||||
def self.round(value, round)
|
||||
round -= 1
|
||||
value += round
|
||||
@ -13,7 +13,8 @@ module MachO
|
||||
value
|
||||
end
|
||||
|
||||
# Returns the number of bytes needed to pad the given size to the given alignment.
|
||||
# Returns the number of bytes needed to pad the given size to the given
|
||||
# alignment.
|
||||
# @param size [Fixnum] the unpadded size
|
||||
# @param alignment [Fixnum] the number to alignment the size with
|
||||
# @return [Fixnum] the number of pad bytes required
|
||||
@ -21,7 +22,8 @@ module MachO
|
||||
round(size, alignment) - size
|
||||
end
|
||||
|
||||
# Converts an abstract (native-endian) String#unpack format to big or little.
|
||||
# Converts 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
|
||||
@ -31,7 +33,8 @@ module MachO
|
||||
end
|
||||
|
||||
# Packs tagged strings into an aligned payload.
|
||||
# @param fixed_offset [Fixnum] the baseline offset for the first packed string
|
||||
# @param fixed_offset [Fixnum] the baseline offset for the first packed
|
||||
# string
|
||||
# @param alignment [Fixnum] the alignment value to use for packing
|
||||
# @param strings [Hash] the labeled strings to pack
|
||||
# @return [Array<String, Hash>] the packed string and labeled offsets
|
||||
@ -53,44 +56,44 @@ module MachO
|
||||
|
||||
# Compares the given number to valid Mach-O magic numbers.
|
||||
# @param num [Fixnum] the number being checked
|
||||
# @return [Boolean] true if `num` is a valid Mach-O magic number, false otherwise
|
||||
# @return [Boolean] whether `num` is a valid Mach-O magic number
|
||||
def self.magic?(num)
|
||||
MH_MAGICS.key?(num)
|
||||
Headers::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
|
||||
# @return [Boolean] whether `num` is a valid Fat magic number
|
||||
def self.fat_magic?(num)
|
||||
num == FAT_MAGIC
|
||||
num == Headers::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
|
||||
# @return [Boolean] whether `num` is a valid 32-bit magic number
|
||||
def self.magic32?(num)
|
||||
num == MH_MAGIC || num == MH_CIGAM
|
||||
num == Headers::MH_MAGIC || num == Headers::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
|
||||
# @return [Boolean] whether `num` is a valid 64-bit magic number
|
||||
def self.magic64?(num)
|
||||
num == MH_MAGIC_64 || num == MH_CIGAM_64
|
||||
num == Headers::MH_MAGIC_64 || num == Headers::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
|
||||
# @return [Boolean] whether `num` is a valid little-endian magic number
|
||||
def self.little_magic?(num)
|
||||
num == MH_CIGAM || num == MH_CIGAM_64
|
||||
num == Headers::MH_CIGAM || num == Headers::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
|
||||
# @return [Boolean] whether `num` is a valid big-endian magic number
|
||||
def self.big_magic?(num)
|
||||
num == MH_CIGAM || num == MH_CIGAM_64
|
||||
num == Headers::MH_CIGAM || num == Headers::MH_CIGAM_64
|
||||
end
|
||||
end
|
||||
end
|
||||
|
Loading…
x
Reference in New Issue
Block a user