vendor: vendor ruby_macho library.
This commit is contained in:
parent
35e2209c10
commit
1cb6a2ad18
53
Library/Homebrew/vendor/README.md
vendored
Normal file
53
Library/Homebrew/vendor/README.md
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
Vendored Dependencies
|
||||
=====================
|
||||
|
||||
* [okjson](https://github.com/kr/okjson), version 43.
|
||||
|
||||
* [ruby-macho](https://github.com/woodruffw/ruby-macho), version 0.2.2.
|
||||
|
||||
## Licenses:
|
||||
|
||||
### okjson
|
||||
|
||||
> Copyright 2011, 2012 Keith Rarick
|
||||
>
|
||||
> Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
> of this software and associated documentation files (the "Software"), to deal
|
||||
> in the Software without restriction, including without limitation the rights
|
||||
> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
> copies of the Software, and to permit persons to whom the Software is
|
||||
> furnished to do so, subject to the following conditions:
|
||||
>
|
||||
> The above copyright notice and this permission notice shall be included in
|
||||
> all copies or substantial portions of the Software.
|
||||
>
|
||||
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
> THE SOFTWARE.
|
||||
|
||||
### ruby-macho
|
||||
|
||||
> The MIT License
|
||||
> Copyright (c) 2015 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
|
||||
> in the Software without restriction, including without limitation the rights
|
||||
> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
> copies of the Software, and to permit persons to whom the Software is
|
||||
> furnished to do so, subject to the following conditions:
|
||||
>
|
||||
> The above copyright notice and this permission notice shall be included in
|
||||
> all copies or substantial portions of the Software.
|
||||
>
|
||||
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
> THE SOFTWARE.
|
16
Library/Homebrew/vendor/macho/macho.rb
vendored
Normal file
16
Library/Homebrew/vendor/macho/macho.rb
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
require "#{File.dirname(__FILE__)}/macho/structure"
|
||||
require "#{File.dirname(__FILE__)}/macho/headers"
|
||||
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"
|
||||
|
||||
# The primary namespace for ruby-macho.
|
||||
module MachO
|
||||
# release version
|
||||
VERSION = "0.2.2".freeze
|
||||
end
|
85
Library/Homebrew/vendor/macho/macho/exceptions.rb
vendored
Normal file
85
Library/Homebrew/vendor/macho/macho/exceptions.rb
vendored
Normal file
@ -0,0 +1,85 @@
|
||||
module MachO
|
||||
# A generic Mach-O error in execution.
|
||||
class MachOError < RuntimeError
|
||||
end
|
||||
|
||||
# Raised when a file's magic bytes are not valid Mach-O magic.
|
||||
class MagicError < MachOError
|
||||
# @param num [Fixnum] the unknown number
|
||||
def initialize(num)
|
||||
super "Unrecognized Mach-O magic: 0x#{"%02x" % num}"
|
||||
end
|
||||
end
|
||||
|
||||
# Raised when a fat binary is loaded with MachOFile.
|
||||
class FatBinaryError < MachOError
|
||||
def initialize
|
||||
super "Fat binaries must be loaded with MachO::FatFile"
|
||||
end
|
||||
end
|
||||
|
||||
# Raised when a Mach-O is loaded with FatFile.
|
||||
class MachOBinaryError < MachOError
|
||||
def initialize
|
||||
super "Normal binaries must be loaded with MachO::MachOFile"
|
||||
end
|
||||
end
|
||||
|
||||
# Raised when the CPU type is unknown.
|
||||
class CPUTypeError < MachOError
|
||||
# @param num [Fixnum] the unknown number
|
||||
def initialize(num)
|
||||
super "Unrecognized CPU type: 0x#{"%02x" % num}"
|
||||
end
|
||||
end
|
||||
|
||||
# Raised when the CPU subtype is unknown.
|
||||
class CPUSubtypeError < MachOError
|
||||
# @param num [Fixnum] the unknown number
|
||||
def initialize(num)
|
||||
super "Unrecognized CPU sub-type: 0x#{"%02x" % num}"
|
||||
end
|
||||
end
|
||||
|
||||
# Raised when a mach-o file's filetype field is unknown.
|
||||
class FiletypeError < MachOError
|
||||
# @param num [Fixnum] the unknown number
|
||||
def initialize(num)
|
||||
super "Unrecognized Mach-O filetype code: 0x#{"%02x" % num}"
|
||||
end
|
||||
end
|
||||
|
||||
# Raised when an unknown load command is encountered.
|
||||
class LoadCommandError < MachOError
|
||||
# @param num [Fixnum] the unknown number
|
||||
def initialize(num)
|
||||
super "Unrecognized Mach-O load command: 0x#{"%02x" % num}"
|
||||
end
|
||||
end
|
||||
|
||||
# Raised when load commands are too large to fit in the current file.
|
||||
class HeaderPadError < MachOError
|
||||
# @param filename [String] the filename
|
||||
def initialize(filename)
|
||||
super "Updated load commands do not fit in the header of " +
|
||||
"#{filename}. #{filename} needs to be relinked, possibly with " +
|
||||
"-headerpad or -headerpad_max_install_names"
|
||||
end
|
||||
end
|
||||
|
||||
# Raised when attempting to change a dylib name that doesn't exist.
|
||||
class DylibUnknownError < MachOError
|
||||
# @param dylib [String] the unknown shared library name
|
||||
def initialize(dylib)
|
||||
super "No such dylib name: #{dylib}"
|
||||
end
|
||||
end
|
||||
|
||||
# Raised when attempting to change an rpath that doesn't exist.
|
||||
class RpathUnknownError < MachOError
|
||||
# @param path [String] the unknown runtime path
|
||||
def initialize(path)
|
||||
super "No such runtime path: #{path}"
|
||||
end
|
||||
end
|
||||
end
|
230
Library/Homebrew/vendor/macho/macho/fat_file.rb
vendored
Normal file
230
Library/Homebrew/vendor/macho/macho/fat_file.rb
vendored
Normal file
@ -0,0 +1,230 @@
|
||||
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
|
||||
class FatFile
|
||||
# @return [MachO::FatHeader] the file's header
|
||||
attr_reader :header
|
||||
|
||||
# @return [Array<MachO::FatArch>] an array of fat architectures
|
||||
attr_reader :fat_archs
|
||||
|
||||
# @return [Array<MachO::MachOFile>] an array of Mach-O binaries
|
||||
attr_reader :machos
|
||||
|
||||
# Creates a new FatFile from the given filename.
|
||||
# @param filename [String] the fat file to load from
|
||||
# @raise [ArgumentError] if the given filename does not exist
|
||||
def initialize(filename)
|
||||
raise ArgumentError.new("#{filetype}: no such file") unless File.exist?(filename)
|
||||
|
||||
@filename = filename
|
||||
@raw_data = open(@filename, "rb") { |f| f.read }
|
||||
@header = get_fat_header
|
||||
@fat_archs = get_fat_archs
|
||||
@machos = get_machos
|
||||
end
|
||||
|
||||
# The file's raw fat data.
|
||||
# @return [String] the raw fat data
|
||||
def serialize
|
||||
@raw_data
|
||||
end
|
||||
|
||||
# @return [Boolean] true if the file is of type `MH_OBJECT`, false otherwise
|
||||
def object?
|
||||
machos.first.object?
|
||||
end
|
||||
|
||||
# @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
|
||||
|
||||
# @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 [String] the filetype
|
||||
def filetype
|
||||
machos.first.filetype
|
||||
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
|
||||
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.
|
||||
# @example
|
||||
# file.dylib_id = 'libFoo.dylib'
|
||||
# @param new_id [String] the new dylib ID
|
||||
# @return [void]
|
||||
# @raise [ArgumentError] if `new_id` is not a String
|
||||
def dylib_id=(new_id)
|
||||
if !new_id.is_a?(String)
|
||||
raise ArgumentError.new("argument must be a String")
|
||||
end
|
||||
|
||||
if !machos.all?(&:dylib?)
|
||||
return nil
|
||||
end
|
||||
|
||||
machos.each do |macho|
|
||||
macho.dylib_id = new_id
|
||||
end
|
||||
|
||||
synchronize_raw_data
|
||||
end
|
||||
|
||||
# All shared libraries linked to the file's Mach-Os.
|
||||
# @return [Array<String>] an array of all shared libraries
|
||||
def linked_dylibs
|
||||
# can machos inside fat binaries have different dylibs?
|
||||
machos.flat_map(&:linked_dylibs).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.
|
||||
# @example
|
||||
# file.change_install_name('/usr/lib/libFoo.dylib', '/usr/lib/libBar.dylib')
|
||||
# @param old_name [String] the shared library name being changed
|
||||
# @param new_name [String] the new name
|
||||
# @todo incomplete
|
||||
def change_install_name(old_name, new_name)
|
||||
machos.each do |macho|
|
||||
macho.change_install_name(old_name, new_name)
|
||||
end
|
||||
|
||||
synchronize_raw_data
|
||||
end
|
||||
|
||||
alias :change_dylib :change_install_name
|
||||
|
||||
# Extract a Mach-O with the given CPU type from the file.
|
||||
# @example
|
||||
# file.extract("CPU_TYPE_I386") # => MachO::MachOFile
|
||||
# @param cputype [String] 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
|
||||
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
|
||||
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.
|
||||
# @note Overwrites all data in the file!
|
||||
def write!
|
||||
File.open(@filename, "wb") { |f| f.write(@raw_data) }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Obtain the fat header from raw file data.
|
||||
# @return [MachO::FatHeader] the fat 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
|
||||
# @private
|
||||
def get_fat_header
|
||||
magic, nfat_arch = @raw_data[0..7].unpack("N2")
|
||||
|
||||
raise MagicError.new(magic) unless MachO.magic?(magic)
|
||||
raise MachOBinaryError.new unless MachO.fat_magic?(magic)
|
||||
|
||||
FatHeader.new(magic, nfat_arch)
|
||||
end
|
||||
|
||||
# Obtain an array of fat architectures from raw file data.
|
||||
# @return [Array<MachO::FatArch>] an array of fat architectures
|
||||
# @private
|
||||
def get_fat_archs
|
||||
archs = []
|
||||
|
||||
header.nfat_arch.times do |i|
|
||||
fields = @raw_data[8 + (FatArch.bytesize * i), FatArch.bytesize].unpack("N5")
|
||||
archs << FatArch.new(*fields)
|
||||
end
|
||||
|
||||
archs
|
||||
end
|
||||
|
||||
# Obtain an array of Mach-O blobs from raw file data.
|
||||
# @return [Array<MachO::MachOFile>] an array of Mach-Os
|
||||
# @private
|
||||
def get_machos
|
||||
machos = []
|
||||
|
||||
fat_archs.each do |arch|
|
||||
machos << MachOFile.new_from_bin(@raw_data[arch.offset, arch.size])
|
||||
end
|
||||
|
||||
machos
|
||||
end
|
||||
|
||||
# @todo this needs to be redesigned. arch[:offset] and arch[:size] are
|
||||
# already out-of-date, and the header needs to be synchronized as well.
|
||||
# @private
|
||||
def synchronize_raw_data
|
||||
machos.each_with_index do |macho, i|
|
||||
arch = fat_archs[i]
|
||||
|
||||
@raw_data[arch.offset, arch.size] = macho.serialize
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
275
Library/Homebrew/vendor/macho/macho/headers.rb
vendored
Normal file
275
Library/Homebrew/vendor/macho/macho/headers.rb
vendored
Normal file
@ -0,0 +1,275 @@
|
||||
module MachO
|
||||
# big-endian fat magic
|
||||
FAT_MAGIC = 0xcafebabe
|
||||
|
||||
# little-endian fat magic
|
||||
FAT_CIGAM = 0xbebafeca
|
||||
|
||||
# 32-bit big-endian magic
|
||||
MH_MAGIC = 0xfeedface
|
||||
|
||||
# 32-bit little-endian magic
|
||||
MH_CIGAM = 0xcefaedfe
|
||||
|
||||
# 64-bit big-endian magic
|
||||
MH_MAGIC_64 = 0xfeedfacf
|
||||
|
||||
# 64-bit little-endian magic
|
||||
MH_CIGAM_64 = 0xcffaedfe
|
||||
|
||||
# association of magic numbers to string representations
|
||||
MH_MAGICS = {
|
||||
FAT_MAGIC => "FAT_MAGIC",
|
||||
FAT_CIGAM => "FAT_CIGAM",
|
||||
MH_MAGIC => "MH_MAGIC",
|
||||
MH_CIGAM => "MH_CIGAM",
|
||||
MH_MAGIC_64 => "MH_MAGIC_64",
|
||||
MH_CIGAM_64 => "MH_CIGAM_64"
|
||||
}
|
||||
|
||||
# mask for CPUs with 64-bit architectures (when running a 64-bit ABI?)
|
||||
CPU_ARCH_ABI64 = 0x01000000
|
||||
|
||||
# any CPU (unused?)
|
||||
CPU_TYPE_ANY = -1
|
||||
|
||||
# x86 compatible CPUs
|
||||
CPU_TYPE_X86 = 0x07
|
||||
|
||||
# i386 and later compatible CPUs
|
||||
CPU_TYPE_I386 = CPU_TYPE_X86
|
||||
|
||||
# x86_64 (AMD64) compatible CPUs
|
||||
CPU_TYPE_X86_64 = (CPU_TYPE_X86 | CPU_ARCH_ABI64)
|
||||
|
||||
# PowerPC compatible CPUs (7400 series?)
|
||||
CPU_TYPE_POWERPC = 0x12
|
||||
|
||||
# PowerPC64 compatible CPUs (970 series?)
|
||||
CPU_TYPE_POWERPC64 = (CPU_TYPE_POWERPC | CPU_ARCH_ABI64)
|
||||
|
||||
# association of cpu types to string representations
|
||||
CPU_TYPES = {
|
||||
CPU_TYPE_ANY => "CPU_TYPE_ANY",
|
||||
CPU_TYPE_X86 => "CPU_TYPE_X86",
|
||||
CPU_TYPE_I386 => "CPU_TYPE_I386",
|
||||
CPU_TYPE_X86_64 => "CPU_TYPE_X86_64",
|
||||
CPU_TYPE_POWERPC => "CPU_TYPE_POWERPC",
|
||||
CPU_TYPE_POWERPC64 => "CPU_TYPE_POWERPC64"
|
||||
}
|
||||
|
||||
# mask for CPU subtype capabilities
|
||||
CPU_SUBTYPE_MASK = 0xff000000
|
||||
|
||||
# 64-bit libraries (undocumented!)
|
||||
# @see http://llvm.org/docs/doxygen/html/Support_2MachO_8h_source.html
|
||||
CPU_SUBTYPE_LIB64 = 0x80000000
|
||||
|
||||
# all x86-type CPUs
|
||||
CPU_SUBTYPE_X86_ALL = 3
|
||||
|
||||
# all x86-type CPUs (what makes this different from CPU_SUBTYPE_X86_ALL?)
|
||||
CPU_SUBTYPE_X86_ARCH1 = 4
|
||||
|
||||
# association of cpu subtypes to string representations
|
||||
CPU_SUBTYPES = {
|
||||
CPU_SUBTYPE_X86_ALL => "CPU_SUBTYPE_X86_ALL",
|
||||
CPU_SUBTYPE_X86_ARCH1 => "CPU_SUBTYPE_X86_ARCH1"
|
||||
}
|
||||
|
||||
# relocatable object file
|
||||
MH_OBJECT = 0x1
|
||||
|
||||
# demand paged executable file
|
||||
MH_EXECUTE = 0x2
|
||||
|
||||
# fixed VM shared library file
|
||||
MH_FVMLIB = 0x3
|
||||
|
||||
# core dump file
|
||||
MH_CORE = 0x4
|
||||
|
||||
# preloaded executable file
|
||||
MH_PRELOAD = 0x5
|
||||
|
||||
# dynamically bound shared library
|
||||
MH_DYLIB = 0x6
|
||||
|
||||
# dynamic link editor
|
||||
MH_DYLINKER = 0x7
|
||||
|
||||
# dynamically bound bundle file
|
||||
MH_BUNDLE = 0x8
|
||||
|
||||
# shared library stub for static linking only, no section contents
|
||||
MH_DYLIB_STUB = 0x9
|
||||
|
||||
# companion file with only debug sections
|
||||
MH_DSYM = 0xa
|
||||
|
||||
# x86_64 kexts
|
||||
MH_KEXT_BUNDLE = 0xb
|
||||
|
||||
# association of filetypes to string representations
|
||||
# @api private
|
||||
MH_FILETYPES = {
|
||||
MH_OBJECT => "MH_OBJECT",
|
||||
MH_EXECUTE => "MH_EXECUTE",
|
||||
MH_FVMLIB => "MH_FVMLIB",
|
||||
MH_CORE => "MH_CORE",
|
||||
MH_PRELOAD => "MH_PRELOAD",
|
||||
MH_DYLIB => "MH_DYLIB",
|
||||
MH_DYLINKER => "MH_DYLINKER",
|
||||
MH_BUNDLE => "MH_BUNDLE",
|
||||
MH_DYLIB_STUB => "MH_DYLIB_STUB",
|
||||
MH_DSYM => "MH_DSYM",
|
||||
MH_KEXT_BUNDLE => "MH_KEXT_BUNDLE"
|
||||
}
|
||||
|
||||
# association of mach header flag symbols to values
|
||||
# @api private
|
||||
MH_FLAGS = {
|
||||
:MH_NOUNDEFS => 0x1,
|
||||
:MH_INCRLINK => 0x2,
|
||||
:MH_DYLDLINK => 0x4,
|
||||
:MH_BINDATLOAD => 0x8,
|
||||
:MH_PREBOUND => 0x10,
|
||||
:MH_SPLIT_SEGS => 0x20,
|
||||
:MH_LAZY_INIT => 0x40,
|
||||
:MH_TWOLEVEL => 0x80,
|
||||
:MH_FORCE_FLAT => 0x100,
|
||||
:MH_NOMULTIDEFS => 0x200,
|
||||
:MH_NOPREFIXBINDING => 0x400,
|
||||
:MH_PREBINDABLE => 0x800,
|
||||
:MH_ALLMODSBOUND => 0x1000,
|
||||
:MH_SUBSECTIONS_VIA_SYMBOLS => 0x2000,
|
||||
:MH_CANONICAL => 0x4000,
|
||||
:MH_WEAK_DEFINES => 0x8000,
|
||||
:MH_BINDS_TO_WEAK => 0x10000,
|
||||
:MH_ALLOW_STACK_EXECUTION => 0x20000,
|
||||
:MH_ROOT_SAFE => 0x40000,
|
||||
:MH_SETUID_SAFE => 0x80000,
|
||||
:MH_NO_REEXPORTED_DYLIBS => 0x100000,
|
||||
:MH_PIE => 0x200000,
|
||||
:MH_DEAD_STRIPPABLE_DYLIB => 0x400000,
|
||||
:MH_HAS_TLV_DESCRIPTORS => 0x800000,
|
||||
:MH_NO_HEAP_EXECUTION => 0x1000000,
|
||||
:MH_APP_EXTENSION_SAFE => 0x02000000
|
||||
}
|
||||
|
||||
# Fat binary header structure
|
||||
# @see MachO::FatArch
|
||||
class FatHeader < MachOStructure
|
||||
# @return [Fixnum] the magic number of the header (and file)
|
||||
attr_reader :magic
|
||||
|
||||
# @return [Fixnum] the number of fat architecture structures following the header
|
||||
attr_reader :nfat_arch
|
||||
|
||||
FORMAT = "VV"
|
||||
SIZEOF = 8
|
||||
|
||||
# @api private
|
||||
def initialize(magic, nfat_arch)
|
||||
@magic = magic
|
||||
@nfat_arch = nfat_arch
|
||||
end
|
||||
end
|
||||
|
||||
# Fat binary header architecture structure. A Fat binary has one or more of
|
||||
# these, representing one or more internal Mach-O blobs.
|
||||
# @see MachO::FatHeader
|
||||
class FatArch < MachOStructure
|
||||
# @return [Fixnum] the CPU type of the Mach-O
|
||||
attr_reader :cputype
|
||||
|
||||
# @return [Fixnum] the CPU subtype of the Mach-O
|
||||
attr_reader :cpusubtype
|
||||
|
||||
# @return [Fixnum] the file offset to the beginning of the Mach-O data
|
||||
attr_reader :offset
|
||||
|
||||
# @return [Fixnum] the size, in bytes, of the Mach-O data
|
||||
attr_reader :size
|
||||
|
||||
# @return [Fixnum] the alignment, as a power of 2
|
||||
attr_reader :align
|
||||
|
||||
FORMAT = "VVVVV"
|
||||
SIZEOF = 20
|
||||
|
||||
# @api private
|
||||
def initialize(cputype, cpusubtype, offset, size, align)
|
||||
@cputype = cputype
|
||||
@cpusubtype = cpusubtype
|
||||
@offset = offset
|
||||
@size = size
|
||||
@align = align
|
||||
end
|
||||
end
|
||||
|
||||
# 32-bit Mach-O file header structure
|
||||
class MachHeader < MachOStructure
|
||||
# @return [Fixnum] the magic number
|
||||
attr_reader :magic
|
||||
|
||||
# @return [Fixnum] the CPU type of the Mach-O
|
||||
attr_reader :cputype
|
||||
|
||||
# @return [Fixnum] the CPU subtype of the Mach-O
|
||||
attr_reader :cpusubtype
|
||||
|
||||
# @return [Fixnum] the file type of the Mach-O
|
||||
attr_reader :filetype
|
||||
|
||||
# @return [Fixnum] the number of load commands in the Mach-O
|
||||
attr_reader :ncmds
|
||||
|
||||
# @return [Fixnum] the size of all load commands, in bytes, in the Mach-O
|
||||
attr_reader :sizeofcmds
|
||||
|
||||
# @return [Fixnum] the header flags associated with the Mach-O
|
||||
attr_reader :flags
|
||||
|
||||
FORMAT = "VVVVVVV"
|
||||
SIZEOF = 28
|
||||
|
||||
# @api private
|
||||
def initialize(magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds,
|
||||
flags)
|
||||
@magic = magic
|
||||
@cputype = cputype
|
||||
@cpusubtype = cpusubtype
|
||||
@filetype = filetype
|
||||
@ncmds = ncmds
|
||||
@sizeofcmds = sizeofcmds
|
||||
@flags = flags
|
||||
end
|
||||
|
||||
# @example
|
||||
# puts "this mach-o has position-independent execution" if header.flag?(:MH_PIE)
|
||||
# @param flag [Symbol] a mach header flag symbol
|
||||
# @return [Boolean] true if `flag` is present in the header's flag section
|
||||
def flag?(flag)
|
||||
flag = MH_FLAGS[flag]
|
||||
return false if flag.nil?
|
||||
flags & flag == flag
|
||||
end
|
||||
end
|
||||
|
||||
# 64-bit Mach-O file header structure
|
||||
class MachHeader64 < MachHeader
|
||||
# @return [void]
|
||||
attr_reader :reserved
|
||||
|
||||
FORMAT = "VVVVVVVV"
|
||||
SIZEOF = 32
|
||||
|
||||
# @api private
|
||||
def initialize(magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds,
|
||||
flags, reserved)
|
||||
super(magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags)
|
||||
@reserved = reserved
|
||||
end
|
||||
end
|
||||
end
|
1001
Library/Homebrew/vendor/macho/macho/load_commands.rb
vendored
Normal file
1001
Library/Homebrew/vendor/macho/macho/load_commands.rb
vendored
Normal file
File diff suppressed because it is too large
Load Diff
531
Library/Homebrew/vendor/macho/macho/macho_file.rb
vendored
Normal file
531
Library/Homebrew/vendor/macho/macho/macho_file.rb
vendored
Normal file
@ -0,0 +1,531 @@
|
||||
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
|
||||
class MachOFile
|
||||
# @return [MachO::MachHeader] if the Mach-O is 32-bit
|
||||
# @return [MachO::MachHeader64] if the Mach-O is 64-bit
|
||||
attr_reader :header
|
||||
|
||||
# @return [Array<MachO::LoadCommand>] an array of the file's load commands
|
||||
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
|
||||
def self.new_from_bin(bin)
|
||||
instance = allocate
|
||||
instance.initialize_from_bin(bin)
|
||||
|
||||
instance
|
||||
end
|
||||
|
||||
# Creates a new FatFile from the given filename.
|
||||
# @param filename [String] the Mach-O file to load from
|
||||
# @raise [ArgumentError] if the given filename does not exist
|
||||
def initialize(filename)
|
||||
raise ArgumentError.new("#{filetype}: no such file") unless File.exist?(filename)
|
||||
|
||||
@filename = filename
|
||||
@raw_data = open(@filename, "rb") { |f| f.read }
|
||||
@header = get_mach_header
|
||||
@load_commands = get_load_commands
|
||||
end
|
||||
|
||||
# @api private
|
||||
def initialize_from_bin(bin)
|
||||
@filename = nil
|
||||
@raw_data = bin
|
||||
@header = get_mach_header
|
||||
@load_commands = get_load_commands
|
||||
end
|
||||
|
||||
# The file's raw Mach-O data.
|
||||
# @return [String] the raw Mach-O data
|
||||
def serialize
|
||||
@raw_data
|
||||
end
|
||||
|
||||
# @return [Boolean] true if the Mach-O has 32-bit magic, false otherwise
|
||||
def magic32?
|
||||
MachO.magic32?(header.magic)
|
||||
end
|
||||
|
||||
# @return [Boolean] true if the Mach-O has 64-bit magic, false otherwise
|
||||
def magic64?
|
||||
MachO.magic64?(header.magic)
|
||||
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
|
||||
|
||||
# @return [String] a string representation of the file's magic number
|
||||
def magic_string
|
||||
MH_MAGICS[magic]
|
||||
end
|
||||
|
||||
# @return [String] a string representation of the Mach-O's filetype
|
||||
def filetype
|
||||
MH_FILETYPES[header.filetype]
|
||||
end
|
||||
|
||||
# @return [String] a string representation of the Mach-O's CPU type
|
||||
def cputype
|
||||
CPU_TYPES[header.cputype]
|
||||
end
|
||||
|
||||
# @return [String] a string representation of the Mach-O's CPU subtype
|
||||
def cpusubtype
|
||||
CPU_SUBTYPES[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
|
||||
end
|
||||
|
||||
# All load commands of a given name.
|
||||
# @example
|
||||
# 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`
|
||||
def command(name)
|
||||
load_commands.select { |lc| lc.type == name.to_sym }
|
||||
end
|
||||
|
||||
alias :[] :command
|
||||
|
||||
# All load commands responsible for loading dylibs.
|
||||
# @return [Array<MachO::DylibCommand>] an array of DylibCommands
|
||||
def dylib_load_commands
|
||||
load_commands.select { |lc| 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
|
||||
def segments
|
||||
if magic32?
|
||||
command(:LC_SEGMENT)
|
||||
else
|
||||
command(:LC_SEGMENT_64)
|
||||
end
|
||||
end
|
||||
|
||||
# The Mach-O's dylib ID, or `nil` if not a dylib.
|
||||
# @example
|
||||
# file.dylib_id # => 'libBar.dylib'
|
||||
# @return [String, nil] the Mach-O's dylib ID
|
||||
def dylib_id
|
||||
if !dylib?
|
||||
return nil
|
||||
end
|
||||
|
||||
dylib_id_cmd = command(:LC_ID_DYLIB).first
|
||||
|
||||
dylib_id_cmd.name.to_s
|
||||
end
|
||||
|
||||
# Changes the Mach-O's dylib ID to `new_id`. Does nothing if not a dylib.
|
||||
# @example
|
||||
# file.dylib_id = "libFoo.dylib"
|
||||
# @param new_id [String] the dylib's new ID
|
||||
# @return [void]
|
||||
# @raise [ArgumentError] if `new_id` is not a String
|
||||
def dylib_id=(new_id)
|
||||
if !new_id.is_a?(String)
|
||||
raise ArgumentError.new("argument must be a String")
|
||||
end
|
||||
|
||||
if !dylib?
|
||||
return nil
|
||||
end
|
||||
|
||||
dylib_cmd = command(:LC_ID_DYLIB).first
|
||||
old_id = dylib_id
|
||||
|
||||
set_name_in_dylib(dylib_cmd, old_id, new_id)
|
||||
end
|
||||
|
||||
# All shared libraries linked to the Mach-O.
|
||||
# @return [Array<String>] an array of all shared libraries
|
||||
def linked_dylibs
|
||||
dylib_load_commands.map(&:name).map(&:to_s)
|
||||
end
|
||||
|
||||
# Changes the shared library `old_name` to `new_name`
|
||||
# @example
|
||||
# file.change_install_name("/usr/lib/libWhatever.dylib", "/usr/local/lib/libWhatever2.dylib")
|
||||
# @param old_name [String] the shared library's old name
|
||||
# @param new_name [String] the shared library's new name
|
||||
# @return [void]
|
||||
# @raise [MachO::DylibUnknownError] if no shared library has the old name
|
||||
def change_install_name(old_name, new_name)
|
||||
dylib_cmd = dylib_load_commands.find { |d| d.name.to_s == old_name }
|
||||
raise DylibUnknownError.new(old_name) if dylib_cmd.nil?
|
||||
|
||||
set_name_in_dylib(dylib_cmd, old_name, new_name)
|
||||
end
|
||||
|
||||
alias :change_dylib :change_install_name
|
||||
|
||||
# All runtime paths searched by the dynamic linker for the Mach-O.
|
||||
# @return [Array<String>] an array of all runtime paths
|
||||
def rpaths
|
||||
command(:LC_RPATH).map(&:path).map(&:to_s)
|
||||
end
|
||||
|
||||
# Changes the runtime path `old_path` to `new_path`
|
||||
# @example
|
||||
# file.change_rpath("/usr/lib", "/usr/local/lib")
|
||||
# @param old_path [String] the old runtime path
|
||||
# @param new_path [String] the new runtime path
|
||||
# @return [void]
|
||||
# @raise [MachO::RpathUnknownError] if no such old runtime path exists
|
||||
# @api private
|
||||
def change_rpath(old_path, new_path)
|
||||
rpath_cmd = command(:LC_RPATH).find { |r| r.path.to_s == old_path }
|
||||
raise RpathUnknownError.new(old_path) if rpath_cmd.nil?
|
||||
|
||||
set_path_in_rpath(rpath_cmd, old_path, new_path)
|
||||
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
|
||||
def 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(@raw_data.slice(offset, Section.bytesize))
|
||||
offset += Section.bytesize
|
||||
else
|
||||
sections << Section64.new_from_bin(@raw_data.slice(offset, Section64.bytesize))
|
||||
offset += Section64.bytesize
|
||||
end
|
||||
end
|
||||
|
||||
sections
|
||||
end
|
||||
|
||||
# Write all Mach-O 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 Mach-O data to the file used to initialize the instance.
|
||||
# @raise [MachOError] if the instance was created from a binary string
|
||||
# @return [void]
|
||||
# @raise [MachO::MachOError] if the instance was initialized without a file
|
||||
# @note Overwrites all data in the file!
|
||||
def write!
|
||||
if @filename.nil?
|
||||
raise MachOError.new("cannot write to a default file when initialized from a binary string")
|
||||
else
|
||||
File.open(@filename, "wb") { |f| f.write(@raw_data) }
|
||||
end
|
||||
end
|
||||
|
||||
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
|
||||
# @private
|
||||
def get_mach_header
|
||||
magic = get_magic
|
||||
cputype = get_cputype
|
||||
cpusubtype = get_cpusubtype
|
||||
filetype = get_filetype
|
||||
ncmds = get_ncmds
|
||||
sizeofcmds = get_sizeofcmds
|
||||
flags = get_flags
|
||||
|
||||
if MachO.magic32?(magic)
|
||||
MachHeader.new(magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags)
|
||||
else
|
||||
# the reserved field is...reserved, so just fill it with 0
|
||||
MachHeader64.new(magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags, 0)
|
||||
end
|
||||
end
|
||||
|
||||
# The file's magic number.
|
||||
# @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
|
||||
# @private
|
||||
def get_magic
|
||||
magic = @raw_data[0..3].unpack("N").first
|
||||
|
||||
raise MagicError.new(magic) unless MachO.magic?(magic)
|
||||
raise FatBinaryError.new if MachO.fat_magic?(magic)
|
||||
|
||||
magic
|
||||
end
|
||||
|
||||
# The file's CPU type.
|
||||
# @return [Fixnum] the CPU type
|
||||
# @raise [MachO::CPUTypeError] if the CPU type is unknown
|
||||
# @private
|
||||
def get_cputype
|
||||
cputype = @raw_data[4..7].unpack("V").first
|
||||
|
||||
raise CPUTypeError.new(cputype) unless CPU_TYPES.key?(cputype)
|
||||
|
||||
cputype
|
||||
end
|
||||
|
||||
# The file's CPU subtype.
|
||||
# @return [Fixnum] the CPU subtype
|
||||
# @raise [MachO::CPUSubtypeError] if the CPU subtype is unknown
|
||||
# @private
|
||||
def get_cpusubtype
|
||||
cpusubtype = @raw_data[8..11].unpack("V").first
|
||||
cpusubtype &= ~CPU_SUBTYPE_LIB64 # this mask isn't documented!
|
||||
|
||||
raise CPUSubtypeError.new(cpusubtype) unless CPU_SUBTYPES.key?(cpusubtype)
|
||||
|
||||
cpusubtype
|
||||
end
|
||||
|
||||
# The file's type.
|
||||
# @return [Fixnum] the file type
|
||||
# @raise [MachO::FiletypeError] if the file type is unknown
|
||||
# @private
|
||||
def get_filetype
|
||||
filetype = @raw_data[12..15].unpack("V").first
|
||||
|
||||
raise FiletypeError.new(filetype) unless MH_FILETYPES.key?(filetype)
|
||||
|
||||
filetype
|
||||
end
|
||||
|
||||
# The number of load commands in the file.
|
||||
# @return [Fixnum] the number of load commands
|
||||
# @private
|
||||
def get_ncmds
|
||||
@raw_data[16..19].unpack("V").first
|
||||
end
|
||||
|
||||
# The size of all load commands, in bytes.
|
||||
# return [Fixnum] the size of all load commands
|
||||
# @private
|
||||
def get_sizeofcmds
|
||||
@raw_data[20..23].unpack("V").first
|
||||
end
|
||||
|
||||
# The Mach-O header's flags.
|
||||
# @return [Fixnum] the flags
|
||||
# @private
|
||||
def get_flags
|
||||
@raw_data[24..27].unpack("V").first
|
||||
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
|
||||
# @private
|
||||
def get_load_commands
|
||||
offset = header.class.bytesize
|
||||
load_commands = []
|
||||
|
||||
header.ncmds.times do
|
||||
cmd = @raw_data.slice(offset, 4).unpack("V").first
|
||||
cmd_sym = LOAD_COMMANDS[cmd]
|
||||
|
||||
raise LoadCommandError.new(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]}"
|
||||
command = klass.new_from_bin(@raw_data, offset, @raw_data.slice(offset, klass.bytesize))
|
||||
|
||||
load_commands << command
|
||||
offset += command.cmdsize
|
||||
end
|
||||
|
||||
load_commands
|
||||
end
|
||||
|
||||
# Updates the size of all load commands in the raw data.
|
||||
# @param size [Fixnum] the new size, in bytes
|
||||
# @return [void]
|
||||
# @private
|
||||
def set_sizeofcmds(size)
|
||||
new_size = [size].pack("V")
|
||||
@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 = 2**64 # ULLONGMAX
|
||||
|
||||
# calculate the low file offset (offset to first section data)
|
||||
segments.each do |seg|
|
||||
sections(seg).each do |sect|
|
||||
if sect.size != 0 && !sect.flag?(:S_ZEROFILL) &&
|
||||
!sect.flag?(:S_THREAD_LOCAL_ZEROFILL) &&
|
||||
sect.offset < low_fileoff
|
||||
|
||||
low_fileoff = sect.offset
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if new_sizeofcmds + header.class.bytesize > low_fileoff
|
||||
raise HeaderPadError.new(@filename)
|
||||
end
|
||||
|
||||
# update sizeofcmds in mach_header
|
||||
set_sizeofcmds(new_sizeofcmds)
|
||||
|
||||
# update cmdsize in the cmd
|
||||
@raw_data[cmd.offset + 4, 4] = [new_size].pack("V")
|
||||
|
||||
# delete the old str
|
||||
@raw_data.slice!(cmd.offset + lc_str.to_i...cmd.offset + cmd.class.bytesize + old_str.size)
|
||||
|
||||
# insert the new str
|
||||
@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
|
16
Library/Homebrew/vendor/macho/macho/open.rb
vendored
Normal file
16
Library/Homebrew/vendor/macho/macho/open.rb
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
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
|
||||
def self.open(filename)
|
||||
# open file and test magic instead of using exceptions for control?
|
||||
begin
|
||||
file = MachOFile.new(filename)
|
||||
rescue FatBinaryError
|
||||
file = FatFile.new(filename)
|
||||
end
|
||||
|
||||
file
|
||||
end
|
||||
end
|
159
Library/Homebrew/vendor/macho/macho/sections.rb
vendored
Normal file
159
Library/Homebrew/vendor/macho/macho/sections.rb
vendored
Normal file
@ -0,0 +1,159 @@
|
||||
module MachO
|
||||
# type mask
|
||||
SECTION_TYPE = 0x000000ff
|
||||
|
||||
# attributes mask
|
||||
SECTION_ATTRIBUTES = 0xffffff00
|
||||
|
||||
# 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
|
||||
}
|
||||
|
||||
# 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"
|
||||
}
|
||||
|
||||
# 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 addrributes 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
|
||||
|
||||
FORMAT = "a16a16VVVVVVVVV"
|
||||
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
|
||||
|
||||
# @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
|
||||
|
||||
FORMAT = "a16a16QQVVVVVVVV"
|
||||
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
|
22
Library/Homebrew/vendor/macho/macho/structure.rb
vendored
Normal file
22
Library/Homebrew/vendor/macho/macho/structure.rb
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
module MachO
|
||||
# A general purpose pseudo-structure.
|
||||
# @abstract
|
||||
class MachOStructure
|
||||
# The format of the data structure, in String#unpack format.
|
||||
FORMAT = ""
|
||||
|
||||
# The size of the data structure, in bytes.
|
||||
SIZEOF = 0
|
||||
|
||||
# @return [Fixnum] the size, in bytes, of the represented structure.
|
||||
def self.bytesize
|
||||
self::SIZEOF
|
||||
end
|
||||
|
||||
# @return [MachO::MachOStructure] a new MachOStructure initialized with `bin`
|
||||
# @api private
|
||||
def self.new_from_bin(bin)
|
||||
self.new(*bin.unpack(self::FORMAT))
|
||||
end
|
||||
end
|
||||
end
|
65
Library/Homebrew/vendor/macho/macho/tools.rb
vendored
Normal file
65
Library/Homebrew/vendor/macho/macho/tools.rb
vendored
Normal file
@ -0,0 +1,65 @@
|
||||
module MachO
|
||||
# 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
|
||||
def self.dylibs(filename)
|
||||
file = MachO.open(filename)
|
||||
|
||||
file.linked_dylibs
|
||||
end
|
||||
|
||||
# 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
|
||||
# @return [void]
|
||||
# @todo unstub for fat files
|
||||
def self.change_dylib_id(filename, new_id)
|
||||
file = MachO.open(filename)
|
||||
|
||||
file.dylib_id = new_id
|
||||
file.write!
|
||||
end
|
||||
|
||||
# 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
|
||||
# @return [void]
|
||||
# @todo unstub for fat files
|
||||
def self.change_install_name(filename, old_name, new_name)
|
||||
file = MachO.open(filename)
|
||||
|
||||
file.change_install_name(old_name, new_name)
|
||||
file.write!
|
||||
end
|
||||
|
||||
# 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
|
||||
# @return [void]
|
||||
# @todo unstub
|
||||
def self.change_rpath(filename, old_path, new_path)
|
||||
raise "stub"
|
||||
end
|
||||
|
||||
# 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 new_path [String] the new runtime path
|
||||
# @return [void]
|
||||
# @todo unstub
|
||||
def self.add_rpath(filename, new_path)
|
||||
raise "stub"
|
||||
end
|
||||
|
||||
# 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
|
||||
# @return [void]
|
||||
# @todo unstub
|
||||
def self.delete_rpath(filename, old_path)
|
||||
raise "stub"
|
||||
end
|
||||
end
|
||||
end
|
36
Library/Homebrew/vendor/macho/macho/utils.rb
vendored
Normal file
36
Library/Homebrew/vendor/macho/macho/utils.rb
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
module MachO
|
||||
# @param value [Fixnum] the number being rounded
|
||||
# @param round [Fixnum] the number being rounded with
|
||||
# @return [Fixnum] the next number >= `value` such that `round` is its divisor
|
||||
# @see http://www.opensource.apple.com/source/cctools/cctools-870/libstuff/rnd.c
|
||||
def self.round(value, round)
|
||||
round -= 1
|
||||
value += round
|
||||
value &= ~round
|
||||
value
|
||||
end
|
||||
|
||||
# @param num [Fixnum] the number being checked
|
||||
# @return [Boolean] true if `num` is a valid Mach-O magic number, false otherwise
|
||||
def self.magic?(num)
|
||||
MH_MAGICS.has_key?(num)
|
||||
end
|
||||
|
||||
# @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 || num == FAT_CIGAM
|
||||
end
|
||||
|
||||
# @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
|
||||
|
||||
# @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
|
||||
end
|
Loading…
x
Reference in New Issue
Block a user