From a76392dd5f7f603e83be7bc1b6df103d731d1bf4 Mon Sep 17 00:00:00 2001 From: Mike McQuaid Date: Sun, 7 May 2017 17:28:34 +0100 Subject: Revert "Merge pull request #2602 from MikeMcQuaid/travis-ci-tweaks" This reverts commit 8d948e4b0b55912c592d34cb5ea83c649b1f9d5e, reversing changes made to 2372872974d1049c2beafe7dedb7f8f882502058. --- Library/Homebrew/dev-cmd/tap-new.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'Library') diff --git a/Library/Homebrew/dev-cmd/tap-new.rb b/Library/Homebrew/dev-cmd/tap-new.rb index 0dbb5476d..48449e98d 100644 --- a/Library/Homebrew/dev-cmd/tap-new.rb +++ b/Library/Homebrew/dev-cmd/tap-new.rb @@ -46,10 +46,9 @@ module Homebrew travis = <<-EOS.undent language: ruby os: osx + env: OSX=10.12 osx_image: xcode8.3 rvm: system - cache: - directories: /usr/local/Homebrew/Library/Homebrew/vendor before_install: - export TRAVIS_COMMIT="$(git rev-parse --verify -q HEAD)" -- cgit v1.2.3 From e1bbab6ca6c8f96bb53fee9af3f0c01edd2d2f94 Mon Sep 17 00:00:00 2001 From: Mike McQuaid Date: Sun, 7 May 2017 17:28:37 +0100 Subject: Revert "Merge pull request #2603 from MikeMcQuaid/tweak-gem-vendoring" This reverts commit 2372872974d1049c2beafe7dedb7f8f882502058, reversing changes made to 3e4547f52e7ebec633f8bfefc8a396d944edf908. --- Library/Homebrew/brew.rb | 27 +++++++++---------- Library/Homebrew/brew.sh | 4 +++ Library/Homebrew/config.rb | 5 +--- Library/Homebrew/os/mac/mach.rb | 5 +--- Library/Homebrew/test/support/lib/config.rb | 6 ++--- Library/Homebrew/utils.rb | 42 +++++++++++++++++++++++++++++ 6 files changed, 64 insertions(+), 25 deletions(-) (limited to 'Library') diff --git a/Library/Homebrew/brew.rb b/Library/Homebrew/brew.rb index e19819cf5..6dab50f29 100644 --- a/Library/Homebrew/brew.rb +++ b/Library/Homebrew/brew.rb @@ -8,13 +8,13 @@ std_trap = trap("INT") { exit! 130 } # no backtrace thanks RUBY_TWO = RUBY_VERSION.split(".").first.to_i >= 2 raise "Homebrew must be run under Ruby 2!" unless RUBY_TWO -require "pathname" -HOMEBREW_LIBRARY_PATH = Pathname.new(__FILE__).realpath.parent -$:.unshift(HOMEBREW_LIBRARY_PATH) +homebrew_library_path = File.dirname(File.realpath(__FILE__)) +$:.unshift(homebrew_library_path) + +require_relative "#{homebrew_library_path}/vendor/bundler/setup" -load_path_before_bundler = $:.dup -require_relative "#{HOMEBREW_LIBRARY_PATH}/vendor/bundler/setup" -ENV["HOMEBREW_GEMS_LOAD_PATH"] = ($: - load_path_before_bundler).join(":") +require "pathname" +HOMEBREW_LIBRARY_PATH = Pathname.new(homebrew_library_path) require "global" require "tap" @@ -25,6 +25,8 @@ if ARGV == %w[--version] || ARGV == %w[-v] exit 0 end +HOMEBREW_GEM_HOME = HOMEBREW_LIBRARY_PATH/"vendor/#{RUBY_ENGINE}/#{RUBY_VERSION}" + def require?(path) require path rescue LoadError => e @@ -58,21 +60,18 @@ begin path.append(Pathname.glob(Tap::TAP_DIRECTORY/"*/*/cmd")) # Add RubyGems. - HOMEBREW_GEM_HOME = HOMEBREW_LIBRARY_PATH/"vendor/#{RUBY_ENGINE}/#{RUBY_VERSION}" + ENV["GEM_HOME"] = ENV["GEM_PATH"] = HOMEBREW_GEM_HOME path.append(HOMEBREW_GEM_HOME/"bin") + # Make RubyGems notice environment changes. + Gem.clear_paths + Gem::Specification.reset + # Add SCM wrappers. path.append(HOMEBREW_SHIMS_PATH/"scm") ENV["PATH"] = path - # Setup RubyGems environment. - ENV["GEM_HOME"] = ENV["GEM_PATH"] = HOMEBREW_GEM_HOME - # Make RubyGems notice environment changes. - Gem.clear_paths - Gem::Specification.reset - Homebrew.run_bundler_if_needed! unless HOMEBREW_GEM_HOME.exist? - if cmd internal_cmd = require? HOMEBREW_LIBRARY_PATH.join("cmd", cmd) diff --git a/Library/Homebrew/brew.sh b/Library/Homebrew/brew.sh index 6f4453f28..02ce5e1c1 100644 --- a/Library/Homebrew/brew.sh +++ b/Library/Homebrew/brew.sh @@ -69,6 +69,10 @@ then odie "Cowardly refusing to continue at this prefix: $HOMEBREW_PREFIX" fi +# Save value to use for installing gems +export GEM_OLD_HOME="$GEM_HOME" +export GEM_OLD_PATH="$GEM_PATH" + # Users may have these set, pointing the system Ruby # at non-system gem paths unset GEM_HOME diff --git a/Library/Homebrew/config.rb b/Library/Homebrew/config.rb index ef07434de..38d7c8043 100644 --- a/Library/Homebrew/config.rb +++ b/Library/Homebrew/config.rb @@ -46,8 +46,5 @@ unless defined? HOMEBREW_LIBRARY_PATH HOMEBREW_LIBRARY_PATH = Pathname.new(__FILE__).realpath.parent end -# Load path to vendored gems used by Homebrew -HOMEBREW_GEMS_LOAD_PATH = ENV["HOMEBREW_GEMS_LOAD_PATH"] - # Load path used by standalone scripts to access the Homebrew code base -HOMEBREW_LOAD_PATH = [HOMEBREW_LIBRARY_PATH, *HOMEBREW_GEMS_LOAD_PATH].join(":") +HOMEBREW_LOAD_PATH = HOMEBREW_LIBRARY_PATH diff --git a/Library/Homebrew/os/mac/mach.rb b/Library/Homebrew/os/mac/mach.rb index 416183f68..71f501fe9 100644 --- a/Library/Homebrew/os/mac/mach.rb +++ b/Library/Homebrew/os/mac/mach.rb @@ -1,11 +1,10 @@ +require "macho" require "os/mac/architecture_list" module MachOShim # @private def macho @macho ||= begin - require "macho" - MachO.open(to_s) end end @@ -13,8 +12,6 @@ module MachOShim # @private def mach_data @mach_data ||= begin - require "macho" - machos = [] mach_data = [] diff --git a/Library/Homebrew/test/support/lib/config.rb b/Library/Homebrew/test/support/lib/config.rb index 41f4cbe33..fb5c210fe 100644 --- a/Library/Homebrew/test/support/lib/config.rb +++ b/Library/Homebrew/test/support/lib/config.rb @@ -14,9 +14,9 @@ TEST_TMPDIR = ENV.fetch("HOMEBREW_TEST_TMPDIR") do |k| end # Paths pointing into the Homebrew code base that persist across test runs -HOMEBREW_LIBRARY_PATH = Pathname.new(File.expand_path("../../../..", __FILE__)) -HOMEBREW_SHIMS_PATH = HOMEBREW_LIBRARY_PATH.parent+"Homebrew/shims" -HOMEBREW_LOAD_PATH = [File.expand_path("..", __FILE__), HOMEBREW_LIBRARY_PATH, ENV["HOMEBREW_GEMS_LOAD_PATH"]].join(":") +HOMEBREW_LIBRARY_PATH = Pathname.new(File.expand_path("../../../..", __FILE__)) +HOMEBREW_SHIMS_PATH = HOMEBREW_LIBRARY_PATH.parent+"Homebrew/shims" +HOMEBREW_LOAD_PATH = [File.expand_path("..", __FILE__), HOMEBREW_LIBRARY_PATH].join(":") # Paths redirected to a temporary directory and wiped at the end of the test run HOMEBREW_PREFIX = Pathname.new(TEST_TMPDIR).join("prefix") diff --git a/Library/Homebrew/utils.rb b/Library/Homebrew/utils.rb index 6ae75a4fb..60af39d93 100644 --- a/Library/Homebrew/utils.rb +++ b/Library/Homebrew/utils.rb @@ -179,6 +179,48 @@ module Homebrew _system(cmd, *args) end + def install_gem_setup_path!(name, version = nil, executable = name) + # Respect user's preferences for where gems should be installed. + ENV["GEM_HOME"] = ENV["GEM_OLD_HOME"].to_s + ENV["GEM_HOME"] = Gem.user_dir if ENV["GEM_HOME"].empty? + ENV["GEM_PATH"] = ENV["GEM_OLD_PATH"] unless ENV["GEM_OLD_PATH"].to_s.empty? + + # Make rubygems notice env changes. + Gem.clear_paths + Gem::Specification.reset + + # Add Gem binary directory and (if missing) Ruby binary directory to PATH. + path = PATH.new(ENV["PATH"]) + path.prepend(RUBY_BIN) if which("ruby") != RUBY_PATH + path.prepend(Gem.bindir) + ENV["PATH"] = path + + if Gem::Specification.find_all_by_name(name, version).empty? + ohai "Installing or updating '#{name}' gem" + install_args = %W[--no-ri --no-rdoc #{name}] + install_args << "--version" << version if version + + # Do `gem install [...]` without having to spawn a separate process or + # having to find the right `gem` binary for the running Ruby interpreter. + require "rubygems/commands/install_command" + install_cmd = Gem::Commands::InstallCommand.new + install_cmd.handle_options(install_args) + exit_code = 1 # Should not matter as `install_cmd.execute` always throws. + begin + install_cmd.execute + rescue Gem::SystemExitException => e + exit_code = e.exit_code + end + odie "Failed to install/update the '#{name}' gem." if exit_code.nonzero? + end + + return if which(executable) + odie <<-EOS.undent + The '#{name}' gem is installed but couldn't find '#{executable}' in the PATH: + #{ENV["PATH"]} + EOS + end + def run_bundler_if_needed! return unless Pathname.glob("#{HOMEBREW_GEM_HOME}/bin/*").empty? -- cgit v1.2.3 From 57db2e539eaa5fbae351963265312bd24ed08f6b Mon Sep 17 00:00:00 2001 From: Mike McQuaid Date: Sun, 7 May 2017 17:28:39 +0100 Subject: Revert "Merge pull request #2597 from MikeMcQuaid/vendor-gems" This reverts commit 3e4547f52e7ebec633f8bfefc8a396d944edf908, reversing changes made to 6edf9382bcc1240ad6f97c8b752cfe56cef9965d. --- Library/Homebrew/brew.rb | 19 +- Library/Homebrew/cask/lib/hbc/artifact/pkg.rb | 2 +- Library/Homebrew/cask/lib/hbc/cli/style.rb | 2 +- .../Homebrew/cask/lib/hbc/container/executable.rb | 2 +- Library/Homebrew/cask/lib/hbc/system_command.rb | 2 +- Library/Homebrew/cmd/style.rb | 2 +- Library/Homebrew/config.rb | 2 + Library/Homebrew/constants.rb | 3 + Library/Homebrew/dev-cmd/audit.rb | 3 - Library/Homebrew/dev-cmd/man.rb | 2 +- Library/Homebrew/dev-cmd/tests.rb | 20 +- Library/Homebrew/os/mac/mach.rb | 2 +- Library/Homebrew/test/Gemfile | 12 + Library/Homebrew/test/Gemfile.lock | 65 + Library/Homebrew/test/cask/cask_spec.rb | 6 +- Library/Homebrew/test/cask/cli/style_spec.rb | 4 +- .../helper/spec/shared_context/integration_test.rb | 10 +- Library/Homebrew/test/support/lib/config.rb | 2 + Library/Homebrew/utils.rb | 32 - Library/Homebrew/vendor/README.md | 54 + Library/Homebrew/vendor/bundler/setup.rb | 42 - Library/Homebrew/vendor/macho/macho.rb | 40 + Library/Homebrew/vendor/macho/macho/exceptions.rb | 197 +++ Library/Homebrew/vendor/macho/macho/fat_file.rb | 377 ++++++ Library/Homebrew/vendor/macho/macho/headers.rb | 665 ++++++++++ .../Homebrew/vendor/macho/macho/load_commands.rb | 1350 ++++++++++++++++++++ Library/Homebrew/vendor/macho/macho/macho_file.rb | 545 ++++++++ Library/Homebrew/vendor/macho/macho/sections.rb | 176 +++ Library/Homebrew/vendor/macho/macho/structure.rb | 30 + Library/Homebrew/vendor/macho/macho/tools.rb | 108 ++ Library/Homebrew/vendor/macho/macho/utils.rb | 99 ++ Library/Homebrew/vendor/macho/macho/view.rb | 23 + Library/Homebrew/vendor/plist/plist.rb | 21 + Library/Homebrew/vendor/plist/plist/generator.rb | 222 ++++ Library/Homebrew/vendor/plist/plist/parser.rb | 247 ++++ Library/Homebrew/vendor/plist/plist/version.rb | 5 + .../vendor/ruby/2.0.0/gems/plist-3.3.0/LICENSE.txt | 20 - .../ruby/2.0.0/gems/plist-3.3.0/lib/plist.rb | 21 - .../2.0.0/gems/plist-3.3.0/lib/plist/generator.rb | 222 ---- .../2.0.0/gems/plist-3.3.0/lib/plist/parser.rb | 247 ---- .../2.0.0/gems/plist-3.3.0/lib/plist/version.rb | 5 - .../ruby/2.0.0/gems/ruby-macho-1.1.0/LICENSE | 21 - .../ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho.rb | 40 - .../gems/ruby-macho-1.1.0/lib/macho/exceptions.rb | 197 --- .../gems/ruby-macho-1.1.0/lib/macho/fat_file.rb | 377 ------ .../gems/ruby-macho-1.1.0/lib/macho/headers.rb | 665 ---------- .../ruby-macho-1.1.0/lib/macho/load_commands.rb | 1350 -------------------- .../gems/ruby-macho-1.1.0/lib/macho/macho_file.rb | 545 -------- .../gems/ruby-macho-1.1.0/lib/macho/sections.rb | 176 --- .../gems/ruby-macho-1.1.0/lib/macho/structure.rb | 30 - .../2.0.0/gems/ruby-macho-1.1.0/lib/macho/tools.rb | 108 -- .../2.0.0/gems/ruby-macho-1.1.0/lib/macho/utils.rb | 99 -- .../2.0.0/gems/ruby-macho-1.1.0/lib/macho/view.rb | 23 - 53 files changed, 4272 insertions(+), 4267 deletions(-) create mode 100644 Library/Homebrew/constants.rb create mode 100644 Library/Homebrew/test/Gemfile create mode 100644 Library/Homebrew/test/Gemfile.lock create mode 100644 Library/Homebrew/vendor/README.md delete mode 100644 Library/Homebrew/vendor/bundler/setup.rb create mode 100644 Library/Homebrew/vendor/macho/macho.rb create mode 100644 Library/Homebrew/vendor/macho/macho/exceptions.rb create mode 100644 Library/Homebrew/vendor/macho/macho/fat_file.rb create mode 100644 Library/Homebrew/vendor/macho/macho/headers.rb create mode 100644 Library/Homebrew/vendor/macho/macho/load_commands.rb create mode 100644 Library/Homebrew/vendor/macho/macho/macho_file.rb create mode 100644 Library/Homebrew/vendor/macho/macho/sections.rb create mode 100644 Library/Homebrew/vendor/macho/macho/structure.rb create mode 100644 Library/Homebrew/vendor/macho/macho/tools.rb create mode 100644 Library/Homebrew/vendor/macho/macho/utils.rb create mode 100644 Library/Homebrew/vendor/macho/macho/view.rb create mode 100755 Library/Homebrew/vendor/plist/plist.rb create mode 100755 Library/Homebrew/vendor/plist/plist/generator.rb create mode 100755 Library/Homebrew/vendor/plist/plist/parser.rb create mode 100755 Library/Homebrew/vendor/plist/plist/version.rb delete mode 100644 Library/Homebrew/vendor/ruby/2.0.0/gems/plist-3.3.0/LICENSE.txt delete mode 100644 Library/Homebrew/vendor/ruby/2.0.0/gems/plist-3.3.0/lib/plist.rb delete mode 100644 Library/Homebrew/vendor/ruby/2.0.0/gems/plist-3.3.0/lib/plist/generator.rb delete mode 100755 Library/Homebrew/vendor/ruby/2.0.0/gems/plist-3.3.0/lib/plist/parser.rb delete mode 100644 Library/Homebrew/vendor/ruby/2.0.0/gems/plist-3.3.0/lib/plist/version.rb delete mode 100644 Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/LICENSE delete mode 100644 Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho.rb delete mode 100644 Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho/exceptions.rb delete mode 100644 Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho/fat_file.rb delete mode 100644 Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho/headers.rb delete mode 100644 Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho/load_commands.rb delete mode 100644 Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho/macho_file.rb delete mode 100644 Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho/sections.rb delete mode 100644 Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho/structure.rb delete mode 100644 Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho/tools.rb delete mode 100644 Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho/utils.rb delete mode 100644 Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho/view.rb (limited to 'Library') diff --git a/Library/Homebrew/brew.rb b/Library/Homebrew/brew.rb index 6dab50f29..e07599ac6 100644 --- a/Library/Homebrew/brew.rb +++ b/Library/Homebrew/brew.rb @@ -8,14 +8,9 @@ std_trap = trap("INT") { exit! 130 } # no backtrace thanks RUBY_TWO = RUBY_VERSION.split(".").first.to_i >= 2 raise "Homebrew must be run under Ruby 2!" unless RUBY_TWO -homebrew_library_path = File.dirname(File.realpath(__FILE__)) -$:.unshift(homebrew_library_path) - -require_relative "#{homebrew_library_path}/vendor/bundler/setup" - require "pathname" -HOMEBREW_LIBRARY_PATH = Pathname.new(homebrew_library_path) - +HOMEBREW_LIBRARY_PATH = Pathname.new(__FILE__).realpath.parent +$:.unshift(HOMEBREW_LIBRARY_PATH.to_s) require "global" require "tap" @@ -25,8 +20,6 @@ if ARGV == %w[--version] || ARGV == %w[-v] exit 0 end -HOMEBREW_GEM_HOME = HOMEBREW_LIBRARY_PATH/"vendor/#{RUBY_ENGINE}/#{RUBY_VERSION}" - def require?(path) require path rescue LoadError => e @@ -59,14 +52,6 @@ begin # Add contributed commands to PATH before checking. path.append(Pathname.glob(Tap::TAP_DIRECTORY/"*/*/cmd")) - # Add RubyGems. - ENV["GEM_HOME"] = ENV["GEM_PATH"] = HOMEBREW_GEM_HOME - path.append(HOMEBREW_GEM_HOME/"bin") - - # Make RubyGems notice environment changes. - Gem.clear_paths - Gem::Specification.reset - # Add SCM wrappers. path.append(HOMEBREW_SHIMS_PATH/"scm") diff --git a/Library/Homebrew/cask/lib/hbc/artifact/pkg.rb b/Library/Homebrew/cask/lib/hbc/artifact/pkg.rb index 1ba2b4b97..c43481c82 100644 --- a/Library/Homebrew/cask/lib/hbc/artifact/pkg.rb +++ b/Library/Homebrew/cask/lib/hbc/artifact/pkg.rb @@ -2,7 +2,7 @@ require "hbc/artifact/base" require "hbc/utils/hash_validator" -require "plist" +require "vendor/plist/plist" module Hbc module Artifact diff --git a/Library/Homebrew/cask/lib/hbc/cli/style.rb b/Library/Homebrew/cask/lib/hbc/cli/style.rb index 930742ed7..191aefd3c 100644 --- a/Library/Homebrew/cask/lib/hbc/cli/style.rb +++ b/Library/Homebrew/cask/lib/hbc/cli/style.rb @@ -26,7 +26,7 @@ module Hbc def install_rubocop capture_stderr do begin - Homebrew.run_bundler_if_needed! + Homebrew.install_gem_setup_path! "rubocop-cask", HOMEBREW_RUBOCOP_CASK_VERSION, "rubocop" rescue SystemExit raise CaskError, Tty.strip_ansi($stderr.string).chomp.sub(/\AError: /, "") end diff --git a/Library/Homebrew/cask/lib/hbc/container/executable.rb b/Library/Homebrew/cask/lib/hbc/container/executable.rb index 61bd4ef9b..848f6d4be 100644 --- a/Library/Homebrew/cask/lib/hbc/container/executable.rb +++ b/Library/Homebrew/cask/lib/hbc/container/executable.rb @@ -1,5 +1,5 @@ require "hbc/container/naked" -require "macho" +require "vendor/macho/macho" module Hbc class Container diff --git a/Library/Homebrew/cask/lib/hbc/system_command.rb b/Library/Homebrew/cask/lib/hbc/system_command.rb index d610f0fde..c14079bc8 100644 --- a/Library/Homebrew/cask/lib/hbc/system_command.rb +++ b/Library/Homebrew/cask/lib/hbc/system_command.rb @@ -1,6 +1,6 @@ require "open3" require "shellwords" -require "plist" +require "vendor/plist/plist" require "extend/io" diff --git a/Library/Homebrew/cmd/style.rb b/Library/Homebrew/cmd/style.rb index 48ec3ee2e..cf41d91ee 100644 --- a/Library/Homebrew/cmd/style.rb +++ b/Library/Homebrew/cmd/style.rb @@ -65,7 +65,7 @@ module Homebrew def check_style_impl(files, output_type, options = {}) fix = options[:fix] - Homebrew.run_bundler_if_needed! + Homebrew.install_gem_setup_path! "rubocop", HOMEBREW_RUBOCOP_VERSION require "rubocop" require_relative "../rubocops" diff --git a/Library/Homebrew/config.rb b/Library/Homebrew/config.rb index 38d7c8043..30b7bc6c9 100644 --- a/Library/Homebrew/config.rb +++ b/Library/Homebrew/config.rb @@ -2,6 +2,8 @@ unless ENV["HOMEBREW_BREW_FILE"] raise "HOMEBREW_BREW_FILE was not exported! Please call bin/brew directly!" end +require "constants" + # Path to `bin/brew` main executable in HOMEBREW_PREFIX HOMEBREW_BREW_FILE = Pathname.new(ENV["HOMEBREW_BREW_FILE"]) diff --git a/Library/Homebrew/constants.rb b/Library/Homebrew/constants.rb new file mode 100644 index 000000000..827d5827f --- /dev/null +++ b/Library/Homebrew/constants.rb @@ -0,0 +1,3 @@ +# RuboCop version used for `brew style` and `brew cask style` +HOMEBREW_RUBOCOP_VERSION = "0.47.1".freeze +HOMEBREW_RUBOCOP_CASK_VERSION = "~> 0.12.0".freeze # has to be updated when RuboCop version changes diff --git a/Library/Homebrew/dev-cmd/audit.rb b/Library/Homebrew/dev-cmd/audit.rb index 9ea3faf11..cb25ca794 100644 --- a/Library/Homebrew/dev-cmd/audit.rb +++ b/Library/Homebrew/dev-cmd/audit.rb @@ -65,9 +65,6 @@ module Homebrew ENV.activate_extensions! ENV.setup_build_environment - # Add RubyGems (for RuboCop). - ENV["PATH"] = PATH.new(ENV["PATH"]).append(HOMEBREW_GEM_HOME/"bin") - if ARGV.named.empty? ff = Formula files = Tap.map(&:formula_dir) diff --git a/Library/Homebrew/dev-cmd/man.rb b/Library/Homebrew/dev-cmd/man.rb index 6e71c248b..4e5103910 100644 --- a/Library/Homebrew/dev-cmd/man.rb +++ b/Library/Homebrew/dev-cmd/man.rb @@ -35,7 +35,7 @@ module Homebrew end def regenerate_man_pages - Homebrew.run_bundler_if_needed! + Homebrew.install_gem_setup_path! "ronn" markup = build_man_page convert_man_page(markup, TARGET_DOC_PATH/"Manpage.md") diff --git a/Library/Homebrew/dev-cmd/tests.rb b/Library/Homebrew/dev-cmd/tests.rb index da1f5365c..72d6143fc 100644 --- a/Library/Homebrew/dev-cmd/tests.rb +++ b/Library/Homebrew/dev-cmd/tests.rb @@ -49,6 +49,8 @@ module Homebrew FileUtils.rm_f "test/coverage/.resultset.json" end + ENV["BUNDLE_GEMFILE"] = "#{HOMEBREW_LIBRARY_PATH}/test/Gemfile" + # Override author/committer as global settings might be invalid and thus # will cause silent failure during the setup of dummy Git repositories. %w[AUTHOR COMMITTER].each do |role| @@ -57,7 +59,10 @@ module Homebrew ENV["GIT_#{role}_DATE"] = "Sun Jan 22 19:59:13 2017 +0000" end - Homebrew.run_bundler_if_needed! + Homebrew.install_gem_setup_path! "bundler" + unless quiet_system("bundle", "check") + system "bundle", "install" + end parallel = true @@ -101,15 +106,10 @@ module Homebrew files = files.reject { |p| p =~ %r{^test/os/linux(/.*|_spec\.rb)$} } end - files.map! { |p| HOMEBREW_LIBRARY_PATH/p } - - (HOMEBREW_LIBRARY_PATH/"vendor/#{RUBY_ENGINE}/#{RUBY_VERSION}").cd do - if parallel - system "parallel_rspec", *opts, "--", *args, "--", *files - else - system "rspec", *args, "--", *files - end - FileUtils.rm_rf "tmp" + if parallel + system "bundle", "exec", "parallel_rspec", *opts, "--", *args, "--", *files + else + system "bundle", "exec", "rspec", *args, "--", *files end return if $?.success? diff --git a/Library/Homebrew/os/mac/mach.rb b/Library/Homebrew/os/mac/mach.rb index 71f501fe9..9b53c4979 100644 --- a/Library/Homebrew/os/mac/mach.rb +++ b/Library/Homebrew/os/mac/mach.rb @@ -1,4 +1,4 @@ -require "macho" +require "vendor/macho/macho" require "os/mac/architecture_list" module MachOShim diff --git a/Library/Homebrew/test/Gemfile b/Library/Homebrew/test/Gemfile new file mode 100644 index 000000000..f3c16c710 --- /dev/null +++ b/Library/Homebrew/test/Gemfile @@ -0,0 +1,12 @@ +source "https://rubygems.org" + +gem "parallel_tests" +gem "rspec" +gem "rubocop" +gem "rspec-its", require: false +gem "rspec-wait", require: false + +group :coverage do + gem "simplecov", require: false + gem "codecov", require: false +end diff --git a/Library/Homebrew/test/Gemfile.lock b/Library/Homebrew/test/Gemfile.lock new file mode 100644 index 000000000..4d4eefd7d --- /dev/null +++ b/Library/Homebrew/test/Gemfile.lock @@ -0,0 +1,65 @@ +GEM + remote: https://rubygems.org/ + specs: + ast (2.3.0) + codecov (0.1.9) + json + simplecov + url + diff-lcs (1.3) + docile (1.1.5) + json (2.0.3) + parallel (1.10.0) + parallel_tests (2.13.0) + parallel + parser (2.4.0.0) + ast (~> 2.2) + powerpack (0.1.1) + rainbow (2.2.1) + rspec (3.5.0) + rspec-core (~> 3.5.0) + rspec-expectations (~> 3.5.0) + rspec-mocks (~> 3.5.0) + rspec-core (3.5.4) + rspec-support (~> 3.5.0) + rspec-expectations (3.5.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.5.0) + rspec-its (1.2.0) + rspec-core (>= 3.0.0) + rspec-expectations (>= 3.0.0) + rspec-mocks (3.5.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.5.0) + rspec-support (3.5.0) + rspec-wait (0.0.9) + rspec (>= 3, < 4) + rubocop (0.47.1) + parser (>= 2.3.3.1, < 3.0) + powerpack (~> 0.1) + rainbow (>= 1.99.1, < 3.0) + ruby-progressbar (~> 1.7) + unicode-display_width (~> 1.0, >= 1.0.1) + ruby-progressbar (1.8.1) + simplecov (0.13.0) + docile (~> 1.1.0) + json (>= 1.8, < 3) + simplecov-html (~> 0.10.0) + simplecov-html (0.10.0) + unicode-display_width (1.1.3) + url (0.3.2) + +PLATFORMS + ruby + +DEPENDENCIES + codecov + parallel_tests + rspec + rspec-its + rspec-wait + rubocop + simplecov + +BUNDLED WITH + 1.14.5 diff --git a/Library/Homebrew/test/cask/cask_spec.rb b/Library/Homebrew/test/cask/cask_spec.rb index a8c4ecf5f..3736f3c01 100644 --- a/Library/Homebrew/test/cask/cask_spec.rb +++ b/Library/Homebrew/test/cask/cask_spec.rb @@ -24,7 +24,7 @@ describe Hbc::Cask, :cask do describe "load" do let(:tap_path) { Hbc.default_tap.path } let(:file_dirname) { Pathname.new(__FILE__).dirname } - let(:relative_tap_path) { tap_path.realpath.relative_path_from(file_dirname) } + let(:relative_tap_path) { tap_path.relative_path_from(file_dirname) } it "returns an instance of the Cask for the given token" do c = Hbc::CaskLoader.load("local-caffeine") @@ -56,9 +56,7 @@ describe Hbc::Cask, :cask do end it "returns an instance of the Cask from a relative file location" do - c = file_dirname.cd do - Hbc::CaskLoader.load(relative_tap_path/"Casks/local-caffeine.rb") - end + c = Hbc::CaskLoader.load(relative_tap_path/"Casks/local-caffeine.rb") expect(c).to be_kind_of(Hbc::Cask) expect(c.token).to eq("local-caffeine") end diff --git a/Library/Homebrew/test/cask/cli/style_spec.rb b/Library/Homebrew/test/cask/cli/style_spec.rb index d021d8000..d41636beb 100644 --- a/Library/Homebrew/test/cask/cli/style_spec.rb +++ b/Library/Homebrew/test/cask/cli/style_spec.rb @@ -62,7 +62,7 @@ describe Hbc::CLI::Style, :cask do context "when installation succeeds" do before do - allow(Homebrew).to receive(:run_bundler_if_needed!) + allow(Homebrew).to receive(:install_gem_setup_path!) end it "exits successfully" do @@ -72,7 +72,7 @@ describe Hbc::CLI::Style, :cask do context "when installation fails" do before do - allow(Homebrew).to receive(:run_bundler_if_needed!).and_raise(SystemExit) + allow(Homebrew).to receive(:install_gem_setup_path!).and_raise(SystemExit) end it "raises an error" do diff --git a/Library/Homebrew/test/support/helper/spec/shared_context/integration_test.rb b/Library/Homebrew/test/support/helper/spec/shared_context/integration_test.rb index 3a36f1853..ae1854f58 100644 --- a/Library/Homebrew/test/support/helper/spec/shared_context/integration_test.rb +++ b/Library/Homebrew/test/support/helper/spec/shared_context/integration_test.rb @@ -89,10 +89,12 @@ RSpec.shared_context "integration test" do ruby_args << "-rtest/support/helper/integration_mocks" ruby_args << (HOMEBREW_LIBRARY_PATH/"brew.rb").resolved_path.to_s - stdout, stderr, status = Open3.capture3(env, RUBY_PATH, *ruby_args, *args) - $stdout.print stdout - $stderr.print stderr - status + Bundler.with_original_env do + stdout, stderr, status = Open3.capture3(env, RUBY_PATH, *ruby_args, *args) + $stdout.print stdout + $stderr.print stderr + status + end end def setup_test_formula(name, content = nil) diff --git a/Library/Homebrew/test/support/lib/config.rb b/Library/Homebrew/test/support/lib/config.rb index fb5c210fe..3a0a76722 100644 --- a/Library/Homebrew/test/support/lib/config.rb +++ b/Library/Homebrew/test/support/lib/config.rb @@ -2,6 +2,8 @@ unless ENV["HOMEBREW_BREW_FILE"] raise "HOMEBREW_BREW_FILE was not exported! Please call bin/brew directly!" end +require "constants" + require "tmpdir" require "pathname" diff --git a/Library/Homebrew/utils.rb b/Library/Homebrew/utils.rb index 60af39d93..c37633e41 100644 --- a/Library/Homebrew/utils.rb +++ b/Library/Homebrew/utils.rb @@ -221,38 +221,6 @@ module Homebrew EOS end - def run_bundler_if_needed! - return unless Pathname.glob("#{HOMEBREW_GEM_HOME}/bin/*").empty? - - if Gem::Specification.find_all_by_name("bundler").empty? - ohai "Installing Bundler..." - - # Do `gem install [...]` without having to spawn a separate process or - # having to find the right `gem` binary for the running Ruby interpreter. - require "rubygems/commands/install_command" - install_cmd = Gem::Commands::InstallCommand.new - install_cmd.handle_options(%w[--no-ri --no-rdoc bundler]) - exit_code = 1 # Should not matter as `install_cmd.execute` always throws. - begin - install_cmd.execute - rescue Gem::SystemExitException => e - exit_code = e.exit_code - end - odie "Failed to install Bundler!" if exit_code.nonzero? - end - - HOMEBREW_REPOSITORY.cd do - unless quiet_system("bundle", "check") - ohai "Installing RubyGems..." - success = system "bundle", "install", - "--path", "Library/Homebrew/vendor", - "--standalone", - "--jobs", "3" - odie "Failed to install RubyGems!" unless success - end - end - end - # Hash of Module => Set(method_names) @injected_dump_stat_modules = {} diff --git a/Library/Homebrew/vendor/README.md b/Library/Homebrew/vendor/README.md new file mode 100644 index 000000000..b408631c7 --- /dev/null +++ b/Library/Homebrew/vendor/README.md @@ -0,0 +1,54 @@ +Vendored Dependencies +===================== + +* [plist](https://github.com/patsplat/plist), version 3.3.0 + +* [ruby-macho](https://github.com/Homebrew/ruby-macho), version 1.1.0 + +## Licenses: + +### plist + +> Copyright (c) 2006-2010, Ben Bleything and Patrick May +> +> 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, 2016, 2017 William Woodruff +> +> 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. diff --git a/Library/Homebrew/vendor/bundler/setup.rb b/Library/Homebrew/vendor/bundler/setup.rb deleted file mode 100644 index 1fdc2512f..000000000 --- a/Library/Homebrew/vendor/bundler/setup.rb +++ /dev/null @@ -1,42 +0,0 @@ -require 'rbconfig' -# ruby 1.8.7 doesn't define RUBY_ENGINE -ruby_engine = defined?(RUBY_ENGINE) ? RUBY_ENGINE : 'ruby' -ruby_version = RbConfig::CONFIG["ruby_version"] -path = File.expand_path('..', __FILE__) -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rake-12.0.0/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ast-2.3.0/lib" -$:.unshift "#{path}/" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/universal-darwin-16/2.0.0/json-2.1.0" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/json-2.1.0/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/docile-1.1.5/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/simplecov-html-0.10.0/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/simplecov-0.14.1/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/url-0.3.2/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/codecov-0.1.10/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/diff-lcs-1.3/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/universal-darwin-16/2.0.0/hpricot-0.8.6" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/hpricot-0.8.6/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/mustache-1.0.5/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parallel-1.11.1/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parallel_tests-2.14.1/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parser-2.4.0.0/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/plist-3.3.0/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/powerpack-0.1.1/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/public_suffix-2.0.5/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/universal-darwin-16/2.0.0/rainbow-2.2.2" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rainbow-2.2.2/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/universal-darwin-16/2.0.0/rdiscount-2.2.0.1" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rdiscount-2.2.0.1/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ronn-0.7.3/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec-support-3.6.0/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec-core-3.6.0/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec-expectations-3.6.0/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec-mocks-3.6.0/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec-3.6.0/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec-its-1.2.0/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec-wait-0.0.9/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ruby-progressbar-1.8.1/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/unicode-display_width-1.2.1/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-0.47.1/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-cask-0.12.0/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ruby-macho-1.1.0/lib" diff --git a/Library/Homebrew/vendor/macho/macho.rb b/Library/Homebrew/vendor/macho/macho.rb new file mode 100644 index 000000000..b7f20ea19 --- /dev/null +++ b/Library/Homebrew/vendor/macho/macho.rb @@ -0,0 +1,40 @@ +require "#{File.dirname(__FILE__)}/macho/structure" +require "#{File.dirname(__FILE__)}/macho/view" +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/exceptions" +require "#{File.dirname(__FILE__)}/macho/utils" +require "#{File.dirname(__FILE__)}/macho/tools" + +# The primary namespace for ruby-macho. +module MachO + # release version + 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 diff --git a/Library/Homebrew/vendor/macho/macho/exceptions.rb b/Library/Homebrew/vendor/macho/macho/exceptions.rb new file mode 100644 index 000000000..14c2c22ae --- /dev/null +++ b/Library/Homebrew/vendor/macho/macho/exceptions.rb @@ -0,0 +1,197 @@ +module MachO + # A generic Mach-O error in execution. + class MachOError < RuntimeError + end + + # Raised when a Mach-O file modification fails. + class ModificationError < MachOError + end + + # Raised when a Mach-O file modification fails but can be recovered when + # operating on multiple Mach-O slices of a fat binary in non-strict mode. + class RecoverableModificationError < ModificationError + # @return [Fixnum, nil] The index of the Mach-O slice of a fat binary for + # which modification failed or `nil` if not a fat binary. This is used to + # make the error message more useful. + attr_accessor :macho_slice + + # @return [String] The exception message. + def to_s + s = super.to_s + s = "While modifying Mach-O slice #{@macho_slice}: #{s}" if @macho_slice + s + end + end + + # Raised when a file is not a Mach-O. + class NotAMachOError < MachOError + # @param error [String] the error in question + def initialize(error) + super error + end + end + + # Raised when a file is too short to be a valid Mach-O file. + class TruncatedFileError < NotAMachOError + def initialize + super "File is too short to be a valid Mach-O" + end + end + + # Raised when a file's magic bytes are not valid Mach-O magic. + class MagicError < NotAMachOError + # @param num [Fixnum] the unknown number + def initialize(num) + super "Unrecognized Mach-O magic: 0x#{"%02x" % num}" + end + end + + # Raised when a file is a Java classfile instead of a fat Mach-O. + class JavaClassFileError < NotAMachOError + def initialize + super "File is a Java class file" + 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 cputype [Fixnum] the unknown CPU type + def initialize(cputype) + super "Unrecognized CPU type: 0x#{"%08x" % cputype}" + end + end + + # Raised when the CPU type/sub-type pair is unknown. + class CPUSubtypeError < MachOError + # @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})" + 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 a load command can't be created manually. + class LoadCommandNotCreatableError < MachOError + # @param cmd_sym [Symbol] the uncreatable load command's symbol + def initialize(cmd_sym) + super "Load commands of type #{cmd_sym} cannot be created manually" + end + end + + # Raised when the number of arguments used to create a load command manually + # is wrong. + class LoadCommandCreationArityError < MachOError + # @param cmd_sym [Symbol] the load command's symbol + # @param expected_arity [Fixnum] the number of arguments expected + # @param actual_arity [Fixnum] the number of arguments received + def initialize(cmd_sym, expected_arity, actual_arity) + super "Expected #{expected_arity} arguments for #{cmd_sym} creation," \ + " got #{actual_arity}" + end + end + + # Raised when a load command can't be serialized. + class LoadCommandNotSerializableError < MachOError + # @param cmd_sym [Symbol] the load command's symbol + def initialize(cmd_sym) + super "Load commands of type #{cmd_sym} cannot be serialized" + end + end + + # Raised when a load command string is malformed in some way. + class LCStrMalformedError < MachOError + # @param lc [MachO::LoadCommand] the load command containing the string + def initialize(lc) + super "Load command #{lc.type} at offset #{lc.view.offset} contains a" \ + " malformed string" + end + end + + # Raised when a change at an offset is not valid. + class OffsetInsertionError < ModificationError + # @param offset [Fixnum] the invalid offset + def initialize(offset) + super "Insertion at offset #{offset} is not valid" + end + end + + # Raised when load commands are too large to fit in the current file. + class HeaderPadError < ModificationError + # @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 < RecoverableModificationError + # @param dylib [String] the unknown shared library name + def initialize(dylib) + super "No such dylib name: #{dylib}" + end + end + + # Raised when a dylib is missing an ID + class DylibIdMissingError < RecoverableModificationError + def initialize + super "Dylib is missing a dylib ID" + end + end + + # Raised when attempting to change an rpath that doesn't exist. + class RpathUnknownError < RecoverableModificationError + # @param path [String] the unknown runtime path + def initialize(path) + super "No such runtime path: #{path}" + end + end + + # Raised when attempting to add an rpath that already exists. + class RpathExistsError < RecoverableModificationError + # @param path [String] the extant path + def initialize(path) + super "#{path} already exists" + end + end + + # Raised whenever unfinished code is called. + class UnimplementedError < MachOError + # @param thing [String] the thing that is unimplemented + def initialize(thing) + super "Unimplemented: #{thing}" + end + end +end diff --git a/Library/Homebrew/vendor/macho/macho/fat_file.rb b/Library/Homebrew/vendor/macho/macho/fat_file.rb new file mode 100644 index 000000000..351be5ac6 --- /dev/null +++ b/Library/Homebrew/vendor/macho/macho/fat_file.rb @@ -0,0 +1,377 @@ +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 MachOFile + class FatFile + extend Forwardable + + # @return [String] the filename loaded from, or nil if loaded from a binary string + attr_accessor :filename + + # @return [Headers::FatHeader] the file's header + attr_reader :header + + # @return [Array] an array of fat architectures + attr_reader :fat_archs + + # @return [Array] an array of Mach-O binaries + attr_reader :machos + + # Creates a new FatFile from the given (single-arch) Mach-Os + # @param machos [Array] 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 [FatFile] a new FatFile + 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 fat file to load from + # @raise [ArgumentError] if the given file does not exist + def initialize(filename) + raise ArgumentError, "#{filename}: no such file" unless File.file?(filename) + + @filename = filename + @raw_data = File.open(@filename, "rb", &:read) + populate_fields + end + + # Initializes a new FatFile instance from a binary string. + # @see new_from_bin + # @api private + def initialize_from_bin(bin) + @filename = nil + @raw_data = bin + populate_fields + end + + # The file's raw fat data. + # @return [String] the raw fat data + def serialize + @raw_data + 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 + + # @!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 + Headers::MH_MAGICS[magic] + end + + # Populate the instance's fields with the raw Fat Mach-O data. + # @return [void] + # @note This method is public, but should (almost) never need to be called. + def populate_fields + @header = populate_fat_header + @fat_archs = populate_fat_archs + @machos = populate_machos + end + + # All load commands responsible for loading dylibs in the file's Mach-O's. + # @return [Array] an array of DylibCommands + def dylib_load_commands + machos.map(&:dylib_load_commands).flatten + end + + # 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 + # @param options [Hash] + # @option options [Boolean] :strict (true) if true, fail if one slice fails. + # if false, fail only if all slices fail. + # @return [void] + # @raise [ArgumentError] if `new_id` is not a String + # @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?) + + each_macho(options) do |macho| + macho.change_dylib_id(new_id, options) + end + + repopulate_raw_machos + end + + alias dylib_id= change_dylib_id + + # All shared libraries linked to the file's Mach-Os. + # @return [Array] an array of all shared libraries + # @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. + # the union of all libraries used by all architectures. + 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. + # @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 + # @param options [Hash] + # @option options [Boolean] :strict (true) if true, fail if one slice fails. + # if false, fail only if all slices fail. + # @return [void] + # @see MachOFile#change_install_name + def change_install_name(old_name, new_name, options = {}) + each_macho(options) do |macho| + macho.change_install_name(old_name, new_name, options) + end + + repopulate_raw_machos + end + + alias change_dylib change_install_name + + # All runtime paths associated with the file's Mach-Os. + # @return [Array] an array of all runtime paths + # @see MachOFile#rpaths + def rpaths + # Can individual architectures have different runtime paths? + machos.map(&:rpaths).flatten.uniq + end + + # Change the runtime path `old_path` to `new_path` in the file's Mach-Os. + # @param old_path [String] the old runtime path + # @param new_path [String] the new runtime path + # @param options [Hash] + # @option options [Boolean] :strict (true) if true, fail if one slice fails. + # if false, fail only if all slices fail. + # @return [void] + # @see MachOFile#change_rpath + def change_rpath(old_path, new_path, options = {}) + each_macho(options) do |macho| + macho.change_rpath(old_path, new_path, options) + end + + repopulate_raw_machos + end + + # Add the given runtime path to the file's Mach-Os. + # @param path [String] the new runtime path + # @param options [Hash] + # @option options [Boolean] :strict (true) if true, fail if one slice fails. + # if false, fail only if all slices fail. + # @return [void] + # @see MachOFile#add_rpath + def add_rpath(path, options = {}) + each_macho(options) do |macho| + macho.add_rpath(path, options) + end + + repopulate_raw_machos + end + + # Delete the given runtime path from the file's Mach-Os. + # @param path [String] the runtime path to delete + # @param options [Hash] + # @option options [Boolean] :strict (true) if true, fail if one slice fails. + # if false, fail only if all slices fail. + # @return void + # @see MachOFile#delete_rpath + def delete_rpath(path, options = {}) + each_macho(options) do |macho| + macho.delete_rpath(path, options) + end + + repopulate_raw_machos + end + + # Extract a Mach-O with the given CPU type from the file. + # @example + # file.extract(:i386) # => MachO::MachOFile + # @param cputype [Symbol] the CPU type of the Mach-O being extracted + # @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 [MachOError] if the instance was initialized without a file + # @note Overwrites all data in the file! + def write! + if filename.nil? + raise MachOError, "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 + + # Obtain the fat header from raw file data. + # @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 = 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) + + # Rationale: Java classfiles have the same magic as big-endian fat + # Mach-Os. Classfiles encode their version at the same offset as + # `nfat_arch` and the lowest version number is 43, so we error out + # if a file claims to have over 30 internal architectures. It's + # technically possible for a fat Mach-O to have over 30 architectures, + # but this is extremely unlikely and in practice distinguishes the two + # formats. + raise JavaClassFileError if fh.nfat_arch > 30 + + fh + end + + # Obtain an array of fat architectures from raw file data. + # @return [Array] an array of fat architectures + # @api private + def populate_fat_archs + archs = [] + + fa_off = Headers::FatHeader.bytesize + fa_len = Headers::FatArch.bytesize + header.nfat_arch.times do |i| + 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] an array of Mach-Os + # @api private + def populate_machos + machos = [] + + fat_archs.each do |arch| + machos << MachOFile.new_from_bin(@raw_data[arch.offset, arch.size]) + end + + machos + end + + # Repopulate the raw Mach-O data with each internal Mach-O object. + # @return [void] + # @api private + def repopulate_raw_machos + machos.each_with_index do |macho, i| + arch = fat_archs[i] + + @raw_data[arch.offset, arch.size] = macho.serialize + end + end + + # Yield each Mach-O object in the file, rescuing and accumulating errors. + # @param options [Hash] + # @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 [RecoverableModificationError] under the conditions of + # the `:strict` option above. + # @api private + def each_macho(options = {}) + strict = options.fetch(:strict, true) + errors = [] + + machos.each_with_index do |macho, index| + begin + yield macho + rescue RecoverableModificationError => error + error.macho_slice = index + + # Strict mode: Immediately re-raise. Otherwise: Retain, check later. + raise error if strict + errors << error + end + end + + # Non-strict mode: Raise first error if *all* Mach-O slices failed. + raise errors.first if errors.size == machos.size + end + + # 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 diff --git a/Library/Homebrew/vendor/macho/macho/headers.rb b/Library/Homebrew/vendor/macho/macho/headers.rb new file mode 100644 index 000000000..08a4b80c4 --- /dev/null +++ b/Library/Homebrew/vendor/macho/macho/headers.rb @@ -0,0 +1,665 @@ +module MachO + # Classes and constants for parsing the headers of Mach-O binaries. + module Headers + # big-endian fat magic + # @api private + FAT_MAGIC = 0xcafebabe + + # little-endian fat magic + # this is defined, but should never appear in ruby-macho code because + # fat headers are always big-endian and therefore always unpacked as such. + # @api private + FAT_CIGAM = 0xbebafeca + + # 32-bit big-endian magic + # @api private + MH_MAGIC = 0xfeedface + + # 32-bit little-endian magic + # @api private + MH_CIGAM = 0xcefaedfe + + # 64-bit big-endian magic + # @api private + MH_MAGIC_64 = 0xfeedfacf + + # 64-bit little-endian magic + # @api private + MH_CIGAM_64 = 0xcffaedfe + + # association of magic numbers to string representations + # @api private + MH_MAGICS = { + FAT_MAGIC => "FAT_MAGIC", + MH_MAGIC => "MH_MAGIC", + MH_CIGAM => "MH_CIGAM", + MH_MAGIC_64 => "MH_MAGIC_64", + MH_CIGAM_64 => "MH_CIGAM_64", + }.freeze + + # mask for CPUs with 64-bit architectures (when running a 64-bit ABI?) + # @api private + CPU_ARCH_ABI64 = 0x01000000 + + # any CPU (unused?) + # @api private + CPU_TYPE_ANY = -1 + + # m68k compatible CPUs + # @api private + CPU_TYPE_MC680X0 = 0x06 + + # i386 and later compatible CPUs + # @api private + CPU_TYPE_I386 = 0x07 + + # x86_64 (AMD64) compatible CPUs + # @api private + CPU_TYPE_X86_64 = (CPU_TYPE_I386 | CPU_ARCH_ABI64) + + # 32-bit ARM compatible CPUs + # @api private + CPU_TYPE_ARM = 0x0c + + # m88k compatible CPUs + # @api private + CPU_TYPE_MC88000 = 0xd + + # 64-bit ARM compatible CPUs + # @api private + CPU_TYPE_ARM64 = (CPU_TYPE_ARM | CPU_ARCH_ABI64) + + # PowerPC compatible CPUs + # @api private + CPU_TYPE_POWERPC = 0x12 + + # PowerPC64 compatible CPUs + # @api private + CPU_TYPE_POWERPC64 = (CPU_TYPE_POWERPC | CPU_ARCH_ABI64) + + # association of cpu types to symbol representations + # @api private + CPU_TYPES = { + CPU_TYPE_ANY => :any, + CPU_TYPE_I386 => :i386, + CPU_TYPE_X86_64 => :x86_64, + CPU_TYPE_ARM => :arm, + CPU_TYPE_ARM64 => :arm64, + CPU_TYPE_POWERPC => :ppc, + CPU_TYPE_POWERPC64 => :ppc64, + }.freeze + + # mask for CPU subtype capabilities + # @api private + CPU_SUBTYPE_MASK = 0xff000000 + + # 64-bit libraries (undocumented!) + # @see http://llvm.org/docs/doxygen/html/Support_2MachO_8h_source.html + # @api private + CPU_SUBTYPE_LIB64 = 0x80000000 + + # the lowest common sub-type for `CPU_TYPE_I386` + # @api private + CPU_SUBTYPE_I386 = 3 + + # the i486 sub-type for `CPU_TYPE_I386` + # @api private + CPU_SUBTYPE_486 = 4 + + # the i486SX sub-type for `CPU_TYPE_I386` + # @api private + CPU_SUBTYPE_486SX = 132 + + # the i586 (P5, Pentium) sub-type for `CPU_TYPE_I386` + # @api private + CPU_SUBTYPE_586 = 5 + + # @see CPU_SUBTYPE_586 + # @api private + CPU_SUBTYPE_PENT = CPU_SUBTYPE_586 + + # the Pentium Pro (P6) sub-type for `CPU_TYPE_I386` + # @api private + CPU_SUBTYPE_PENTPRO = 22 + + # the Pentium II (P6, M3?) sub-type for `CPU_TYPE_I386` + # @api private + CPU_SUBTYPE_PENTII_M3 = 54 + + # the Pentium II (P6, M5?) sub-type for `CPU_TYPE_I386` + # @api private + CPU_SUBTYPE_PENTII_M5 = 86 + + # the Pentium 4 (Netburst) sub-type for `CPU_TYPE_I386` + # @api private + CPU_SUBTYPE_PENTIUM_4 = 10 + + # the lowest common sub-type for `CPU_TYPE_MC680X0` + # @api private + CPU_SUBTYPE_MC680X0_ALL = 1 + + # @see CPU_SUBTYPE_MC680X0_ALL + # @api private + CPU_SUBTYPE_MC68030 = CPU_SUBTYPE_MC680X0_ALL + + # the 040 subtype for `CPU_TYPE_MC680X0` + # @api private + CPU_SUBTYPE_MC68040 = 2 + + # the 030 subtype for `CPU_TYPE_MC680X0` + # @api private + CPU_SUBTYPE_MC68030_ONLY = 3 + + # the lowest common sub-type for `CPU_TYPE_X86_64` + # @api private + CPU_SUBTYPE_X86_64_ALL = CPU_SUBTYPE_I386 + + # the Haskell sub-type for `CPU_TYPE_X86_64` + # @api private + CPU_SUBTYPE_X86_64_H = 8 + + # the lowest common sub-type for `CPU_TYPE_ARM` + # @api private + CPU_SUBTYPE_ARM_ALL = 0 + + # the v4t sub-type for `CPU_TYPE_ARM` + # @api private + CPU_SUBTYPE_ARM_V4T = 5 + + # the v6 sub-type for `CPU_TYPE_ARM` + # @api private + CPU_SUBTYPE_ARM_V6 = 6 + + # the v5 sub-type for `CPU_TYPE_ARM` + # @api private + CPU_SUBTYPE_ARM_V5TEJ = 7 + + # the xscale (v5 family) sub-type for `CPU_TYPE_ARM` + # @api private + CPU_SUBTYPE_ARM_XSCALE = 8 + + # the v7 sub-type for `CPU_TYPE_ARM` + # @api private + CPU_SUBTYPE_ARM_V7 = 9 + + # the v7f (Cortex A9) sub-type for `CPU_TYPE_ARM` + # @api private + CPU_SUBTYPE_ARM_V7F = 10 + + # the v7s ("Swift") sub-type for `CPU_TYPE_ARM` + # @api private + CPU_SUBTYPE_ARM_V7S = 11 + + # the v7k ("Kirkwood40") sub-type for `CPU_TYPE_ARM` + # @api private + CPU_SUBTYPE_ARM_V7K = 12 + + # the v6m sub-type for `CPU_TYPE_ARM` + # @api private + CPU_SUBTYPE_ARM_V6M = 14 + + # the v7m sub-type for `CPU_TYPE_ARM` + # @api private + CPU_SUBTYPE_ARM_V7M = 15 + + # the v7em sub-type for `CPU_TYPE_ARM` + # @api private + CPU_SUBTYPE_ARM_V7EM = 16 + + # the v8 sub-type for `CPU_TYPE_ARM` + # @api private + CPU_SUBTYPE_ARM_V8 = 13 + + # the lowest common sub-type for `CPU_TYPE_ARM64` + # @api private + CPU_SUBTYPE_ARM64_ALL = 0 + + # the v8 sub-type for `CPU_TYPE_ARM64` + # @api private + CPU_SUBTYPE_ARM64_V8 = 1 + + # the lowest common sub-type for `CPU_TYPE_MC88000` + # @api private + CPU_SUBTYPE_MC88000_ALL = 0 + + # @see CPU_SUBTYPE_MC88000_ALL + # @api private + CPU_SUBTYPE_MMAX_JPC = CPU_SUBTYPE_MC88000_ALL + + # the 100 sub-type for `CPU_TYPE_MC88000` + # @api private + CPU_SUBTYPE_MC88100 = 1 + + # the 110 sub-type for `CPU_TYPE_MC88000` + # @api private + CPU_SUBTYPE_MC88110 = 2 + + # the lowest common sub-type for `CPU_TYPE_POWERPC` + # @api private + CPU_SUBTYPE_POWERPC_ALL = 0 + + # the 601 sub-type for `CPU_TYPE_POWERPC` + # @api private + CPU_SUBTYPE_POWERPC_601 = 1 + + # the 602 sub-type for `CPU_TYPE_POWERPC` + # @api private + CPU_SUBTYPE_POWERPC_602 = 2 + + # the 603 sub-type for `CPU_TYPE_POWERPC` + # @api private + CPU_SUBTYPE_POWERPC_603 = 3 + + # the 603e (G2) sub-type for `CPU_TYPE_POWERPC` + # @api private + CPU_SUBTYPE_POWERPC_603E = 4 + + # the 603ev sub-type for `CPU_TYPE_POWERPC` + # @api private + CPU_SUBTYPE_POWERPC_603EV = 5 + + # the 604 sub-type for `CPU_TYPE_POWERPC` + # @api private + CPU_SUBTYPE_POWERPC_604 = 6 + + # the 604e sub-type for `CPU_TYPE_POWERPC` + # @api private + CPU_SUBTYPE_POWERPC_604E = 7 + + # the 620 sub-type for `CPU_TYPE_POWERPC` + # @api private + CPU_SUBTYPE_POWERPC_620 = 8 + + # the 750 (G3) sub-type for `CPU_TYPE_POWERPC` + # @api private + CPU_SUBTYPE_POWERPC_750 = 9 + + # the 7400 (G4) sub-type for `CPU_TYPE_POWERPC` + # @api private + CPU_SUBTYPE_POWERPC_7400 = 10 + + # the 7450 (G4 "Voyager") sub-type for `CPU_TYPE_POWERPC` + # @api private + CPU_SUBTYPE_POWERPC_7450 = 11 + + # the 970 (G5) sub-type for `CPU_TYPE_POWERPC` + # @api private + CPU_SUBTYPE_POWERPC_970 = 100 + + # any CPU sub-type for CPU type `CPU_TYPE_POWERPC64` + # @api private + CPU_SUBTYPE_POWERPC64_ALL = CPU_SUBTYPE_POWERPC_ALL + + # association of CPU types/subtype pairs to symbol representations in + # (very) roughly descending order of commonness + # @see https://opensource.apple.com/source/cctools/cctools-877.8/libstuff/arch.c + # @api private + CPU_SUBTYPES = { + CPU_TYPE_I386 => { + CPU_SUBTYPE_I386 => :i386, + CPU_SUBTYPE_486 => :i486, + CPU_SUBTYPE_486SX => :i486SX, + CPU_SUBTYPE_586 => :i586, # also "pentium" in arch(3) + CPU_SUBTYPE_PENTPRO => :i686, # also "pentpro" in arch(3) + CPU_SUBTYPE_PENTII_M3 => :pentIIm3, + CPU_SUBTYPE_PENTII_M5 => :pentIIm5, + CPU_SUBTYPE_PENTIUM_4 => :pentium4, + }.freeze, + CPU_TYPE_X86_64 => { + CPU_SUBTYPE_X86_64_ALL => :x86_64, + CPU_SUBTYPE_X86_64_H => :x86_64h, + }.freeze, + CPU_TYPE_ARM => { + CPU_SUBTYPE_ARM_ALL => :arm, + CPU_SUBTYPE_ARM_V4T => :armv4t, + CPU_SUBTYPE_ARM_V6 => :armv6, + CPU_SUBTYPE_ARM_V5TEJ => :armv5, + CPU_SUBTYPE_ARM_XSCALE => :xscale, + CPU_SUBTYPE_ARM_V7 => :armv7, + CPU_SUBTYPE_ARM_V7F => :armv7f, + CPU_SUBTYPE_ARM_V7S => :armv7s, + CPU_SUBTYPE_ARM_V7K => :armv7k, + CPU_SUBTYPE_ARM_V6M => :armv6m, + CPU_SUBTYPE_ARM_V7M => :armv7m, + CPU_SUBTYPE_ARM_V7EM => :armv7em, + CPU_SUBTYPE_ARM_V8 => :armv8, + }.freeze, + CPU_TYPE_ARM64 => { + CPU_SUBTYPE_ARM64_ALL => :arm64, + CPU_SUBTYPE_ARM64_V8 => :arm64v8, + }.freeze, + CPU_TYPE_POWERPC => { + CPU_SUBTYPE_POWERPC_ALL => :ppc, + CPU_SUBTYPE_POWERPC_601 => :ppc601, + CPU_SUBTYPE_POWERPC_603 => :ppc603, + CPU_SUBTYPE_POWERPC_603E => :ppc603e, + CPU_SUBTYPE_POWERPC_603EV => :ppc603ev, + CPU_SUBTYPE_POWERPC_604 => :ppc604, + CPU_SUBTYPE_POWERPC_604E => :ppc604e, + CPU_SUBTYPE_POWERPC_750 => :ppc750, + CPU_SUBTYPE_POWERPC_7400 => :ppc7400, + CPU_SUBTYPE_POWERPC_7450 => :ppc7450, + CPU_SUBTYPE_POWERPC_970 => :ppc970, + }.freeze, + CPU_TYPE_POWERPC64 => { + CPU_SUBTYPE_POWERPC64_ALL => :ppc64, + # apparently the only exception to the naming scheme + CPU_SUBTYPE_POWERPC_970 => :ppc970_64, + }.freeze, + CPU_TYPE_MC680X0 => { + CPU_SUBTYPE_MC680X0_ALL => :m68k, + CPU_SUBTYPE_MC68030 => :mc68030, + CPU_SUBTYPE_MC68040 => :mc68040, + }, + CPU_TYPE_MC88000 => { + CPU_SUBTYPE_MC88000_ALL => :m88k, + }, + }.freeze + + # relocatable object file + # @api private + MH_OBJECT = 0x1 + + # demand paged executable file + # @api private + MH_EXECUTE = 0x2 + + # fixed VM shared library file + # @api private + MH_FVMLIB = 0x3 + + # core dump file + # @api private + MH_CORE = 0x4 + + # preloaded executable file + # @api private + MH_PRELOAD = 0x5 + + # dynamically bound shared library + # @api private + MH_DYLIB = 0x6 + + # dynamic link editor + # @api private + MH_DYLINKER = 0x7 + + # dynamically bound bundle file + # @api private + MH_BUNDLE = 0x8 + + # shared library stub for static linking only, no section contents + # @api private + MH_DYLIB_STUB = 0x9 + + # companion file with only debug sections + # @api private + MH_DSYM = 0xa + + # x86_64 kexts + # @api private + MH_KEXT_BUNDLE = 0xb + + # association of filetypes to Symbol representations + # @api private + MH_FILETYPES = { + MH_OBJECT => :object, + MH_EXECUTE => :execute, + MH_FVMLIB => :fvmlib, + MH_CORE => :core, + MH_PRELOAD => :preload, + MH_DYLIB => :dylib, + MH_DYLINKER => :dylinker, + MH_BUNDLE => :bundle, + MH_DYLIB_STUB => :dylib_stub, + MH_DSYM => :dsym, + MH_KEXT_BUNDLE => :kext_bundle, + }.freeze + + # 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, + }.freeze + + # 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 + + # always big-endian + # @see MachOStructure::FORMAT + # @api private + FORMAT = "N2".freeze + + # @see MachOStructure::SIZEOF + # @api private + SIZEOF = 8 + + # @api private + def initialize(magic, nfat_arch) + @magic = magic + @nfat_arch = nfat_arch + end + + # @return [String] the serialized fields of the fat header + def serialize + [magic, nfat_arch].pack(FORMAT) + 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::Headers::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 + + # always big-endian + # @see MachOStructure::FORMAT + # @api private + FORMAT = "N5".freeze + + # @see MachOStructure::SIZEOF + # @api private + SIZEOF = 20 + + # @api private + def initialize(cputype, cpusubtype, offset, size, align) + @cputype = cputype + @cpusubtype = cpusubtype + @offset = offset + @size = size + @align = align + end + + # @return [String] the serialized fields of the fat arch + def serialize + [cputype, cpusubtype, offset, size, align].pack(FORMAT) + 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 + + # @see MachOStructure::FORMAT + # @api private + FORMAT = "L=7".freeze + + # @see MachOStructure::SIZEOF + # @api private + SIZEOF = 28 + + # @api private + def initialize(magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds, + flags) + @magic = magic + @cputype = cputype + # For now we're not interested in additional capability bits also to be + # found in the `cpusubtype` field. We only care about the CPU sub-type. + @cpusubtype = cpusubtype & ~CPU_SUBTYPE_MASK + @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 + + # @return [Boolean] whether or not the file is of type `MH_OBJECT` + def object? + filetype == Headers::MH_OBJECT + end + + # @return [Boolean] whether or not the file is of type `MH_EXECUTE` + def executable? + filetype == Headers::MH_EXECUTE + end + + # @return [Boolean] whether or not the file is of type `MH_FVMLIB` + def fvmlib? + filetype == Headers::MH_FVMLIB + end + + # @return [Boolean] whether or not the file is of type `MH_CORE` + def core? + filetype == Headers::MH_CORE + end + + # @return [Boolean] whether or not the file is of type `MH_PRELOAD` + def preload? + filetype == Headers::MH_PRELOAD + end + + # @return [Boolean] whether or not the file is of type `MH_DYLIB` + def dylib? + filetype == Headers::MH_DYLIB + end + + # @return [Boolean] whether or not the file is of type `MH_DYLINKER` + def dylinker? + filetype == Headers::MH_DYLINKER + end + + # @return [Boolean] whether or not the file is of type `MH_BUNDLE` + def bundle? + filetype == Headers::MH_BUNDLE + end + + # @return [Boolean] whether or not the file is of type `MH_DSYM` + def dsym? + filetype == Headers::MH_DSYM + end + + # @return [Boolean] whether or not the file is of type `MH_KEXT_BUNDLE` + def kext? + filetype == Headers::MH_KEXT_BUNDLE + end + + # @return [Boolean] true if the Mach-O has 32-bit magic, false otherwise + def magic32? + Utils.magic32?(magic) + end + + # @return [Boolean] true if the Mach-O has 64-bit magic, false otherwise + def magic64? + Utils.magic64?(magic) + end + + # @return [Fixnum] the file's internal alignment + def alignment + magic32? ? 4 : 8 + end + end + + # 64-bit Mach-O file header structure + class MachHeader64 < MachHeader + # @return [void] + attr_reader :reserved + + # @see MachOStructure::FORMAT + # @api private + FORMAT = "L=8".freeze + + # @see MachOStructure::SIZEOF + # @api private + 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 +end diff --git a/Library/Homebrew/vendor/macho/macho/load_commands.rb b/Library/Homebrew/vendor/macho/macho/load_commands.rb new file mode 100644 index 000000000..be4319ee2 --- /dev/null +++ b/Library/Homebrew/vendor/macho/macho/load_commands.rb @@ -0,0 +1,1350 @@ +module MachO + # Classes and constants for parsing load commands in Mach-O binaries. + module LoadCommands + # load commands added after OS X 10.1 need to be bitwise ORed with + # LC_REQ_DYLD to be recognized by the dynamic linker (dyld) + # @api private + LC_REQ_DYLD = 0x80000000 + + # association of load commands to symbol representations + # @api private + LOAD_COMMANDS = { + 0x1 => :LC_SEGMENT, + 0x2 => :LC_SYMTAB, + 0x3 => :LC_SYMSEG, + 0x4 => :LC_THREAD, + 0x5 => :LC_UNIXTHREAD, + 0x6 => :LC_LOADFVMLIB, + 0x7 => :LC_IDFVMLIB, + 0x8 => :LC_IDENT, + 0x9 => :LC_FVMFILE, + 0xa => :LC_PREPAGE, + 0xb => :LC_DYSYMTAB, + 0xc => :LC_LOAD_DYLIB, + 0xd => :LC_ID_DYLIB, + 0xe => :LC_LOAD_DYLINKER, + 0xf => :LC_ID_DYLINKER, + 0x10 => :LC_PREBOUND_DYLIB, + 0x11 => :LC_ROUTINES, + 0x12 => :LC_SUB_FRAMEWORK, + 0x13 => :LC_SUB_UMBRELLA, + 0x14 => :LC_SUB_CLIENT, + 0x15 => :LC_SUB_LIBRARY, + 0x16 => :LC_TWOLEVEL_HINTS, + 0x17 => :LC_PREBIND_CKSUM, + (0x18 | LC_REQ_DYLD) => :LC_LOAD_WEAK_DYLIB, + 0x19 => :LC_SEGMENT_64, + 0x1a => :LC_ROUTINES_64, + 0x1b => :LC_UUID, + (0x1c | LC_REQ_DYLD) => :LC_RPATH, + 0x1d => :LC_CODE_SIGNATURE, + 0x1e => :LC_SEGMENT_SPLIT_INFO, + (0x1f | LC_REQ_DYLD) => :LC_REEXPORT_DYLIB, + 0x20 => :LC_LAZY_LOAD_DYLIB, + 0x21 => :LC_ENCRYPTION_INFO, + 0x22 => :LC_DYLD_INFO, + (0x22 | LC_REQ_DYLD) => :LC_DYLD_INFO_ONLY, + (0x23 | LC_REQ_DYLD) => :LC_LOAD_UPWARD_DYLIB, + 0x24 => :LC_VERSION_MIN_MACOSX, + 0x25 => :LC_VERSION_MIN_IPHONEOS, + 0x26 => :LC_FUNCTION_STARTS, + 0x27 => :LC_DYLD_ENVIRONMENT, + (0x28 | LC_REQ_DYLD) => :LC_MAIN, + 0x29 => :LC_DATA_IN_CODE, + 0x2a => :LC_SOURCE_VERSION, + 0x2b => :LC_DYLIB_CODE_SIGN_DRS, + 0x2c => :LC_ENCRYPTION_INFO_64, + 0x2d => :LC_LINKER_OPTION, + 0x2e => :LC_LINKER_OPTIMIZATION_HINT, + 0x2f => :LC_VERSION_MIN_TVOS, + 0x30 => :LC_VERSION_MIN_WATCHOS, + }.freeze + + # association of symbol representations to load command constants + # @api private + LOAD_COMMAND_CONSTANTS = LOAD_COMMANDS.invert.freeze + + # load commands responsible for loading dylibs + # @api private + DYLIB_LOAD_COMMANDS = [ + :LC_LOAD_DYLIB, + :LC_LOAD_WEAK_DYLIB, + :LC_REEXPORT_DYLIB, + :LC_LAZY_LOAD_DYLIB, + :LC_LOAD_UPWARD_DYLIB, + ].freeze + + # load commands that can be created manually via {LoadCommand.create} + # @api private + CREATABLE_LOAD_COMMANDS = DYLIB_LOAD_COMMANDS + [ + :LC_ID_DYLIB, + :LC_RPATH, + :LC_LOAD_DYLINKER, + ].freeze + + # association of load command symbols to string representations of classes + # @api private + LC_STRUCTURES = { + :LC_SEGMENT => "SegmentCommand", + :LC_SYMTAB => "SymtabCommand", + # "obsolete" + :LC_SYMSEG => "SymsegCommand", + # seems obsolete, but not documented as such + :LC_THREAD => "ThreadCommand", + :LC_UNIXTHREAD => "ThreadCommand", + # "obsolete" + :LC_LOADFVMLIB => "FvmlibCommand", + # "obsolete" + :LC_IDFVMLIB => "FvmlibCommand", + # "obsolete" + :LC_IDENT => "IdentCommand", + # "reserved for internal use only" + :LC_FVMFILE => "FvmfileCommand", + # "reserved for internal use only", no public struct + :LC_PREPAGE => "LoadCommand", + :LC_DYSYMTAB => "DysymtabCommand", + :LC_LOAD_DYLIB => "DylibCommand", + :LC_ID_DYLIB => "DylibCommand", + :LC_LOAD_DYLINKER => "DylinkerCommand", + :LC_ID_DYLINKER => "DylinkerCommand", + :LC_PREBOUND_DYLIB => "PreboundDylibCommand", + :LC_ROUTINES => "RoutinesCommand", + :LC_SUB_FRAMEWORK => "SubFrameworkCommand", + :LC_SUB_UMBRELLA => "SubUmbrellaCommand", + :LC_SUB_CLIENT => "SubClientCommand", + :LC_SUB_LIBRARY => "SubLibraryCommand", + :LC_TWOLEVEL_HINTS => "TwolevelHintsCommand", + :LC_PREBIND_CKSUM => "PrebindCksumCommand", + :LC_LOAD_WEAK_DYLIB => "DylibCommand", + :LC_SEGMENT_64 => "SegmentCommand64", + :LC_ROUTINES_64 => "RoutinesCommand64", + :LC_UUID => "UUIDCommand", + :LC_RPATH => "RpathCommand", + :LC_CODE_SIGNATURE => "LinkeditDataCommand", + :LC_SEGMENT_SPLIT_INFO => "LinkeditDataCommand", + :LC_REEXPORT_DYLIB => "DylibCommand", + :LC_LAZY_LOAD_DYLIB => "DylibCommand", + :LC_ENCRYPTION_INFO => "EncryptionInfoCommand", + :LC_DYLD_INFO => "DyldInfoCommand", + :LC_DYLD_INFO_ONLY => "DyldInfoCommand", + :LC_LOAD_UPWARD_DYLIB => "DylibCommand", + :LC_VERSION_MIN_MACOSX => "VersionMinCommand", + :LC_VERSION_MIN_IPHONEOS => "VersionMinCommand", + :LC_FUNCTION_STARTS => "LinkeditDataCommand", + :LC_DYLD_ENVIRONMENT => "DylinkerCommand", + :LC_MAIN => "EntryPointCommand", + :LC_DATA_IN_CODE => "LinkeditDataCommand", + :LC_SOURCE_VERSION => "SourceVersionCommand", + :LC_DYLIB_CODE_SIGN_DRS => "LinkeditDataCommand", + :LC_ENCRYPTION_INFO_64 => "EncryptionInfoCommand64", + :LC_LINKER_OPTION => "LinkerOptionCommand", + :LC_LINKER_OPTIMIZATION_HINT => "LinkeditDataCommand", + :LC_VERSION_MIN_TVOS => "VersionMinCommand", + :LC_VERSION_MIN_WATCHOS => "VersionMinCommand", + }.freeze + + # association of segment name symbols to names + # @api private + SEGMENT_NAMES = { + :SEG_PAGEZERO => "__PAGEZERO", + :SEG_TEXT => "__TEXT", + :SEG_DATA => "__DATA", + :SEG_OBJC => "__OBJC", + :SEG_ICON => "__ICON", + :SEG_LINKEDIT => "__LINKEDIT", + :SEG_UNIXSTACK => "__UNIXSTACK", + :SEG_IMPORT => "__IMPORT", + }.freeze + + # association of segment flag symbols to values + # @api private + SEGMENT_FLAGS = { + :SG_HIGHVM => 0x1, + :SG_FVMLIB => 0x2, + :SG_NORELOC => 0x4, + :SG_PROTECTED_VERSION_1 => 0x8, + }.freeze + + # Mach-O load command structure + # This is the most generic load command - only cmd ID and size are + # represented, and no actual data. Used when a more specific class + # isn't available/implemented. + class LoadCommand < MachOStructure + # @return [MachO::MachOView] the raw view associated with the load command + attr_reader :view + + # @return [Fixnum] the load command's identifying number + attr_reader :cmd + + # @return [Fixnum] the size of the load command, in bytes + attr_reader :cmdsize + + # @see MachOStructure::FORMAT + # @api private + FORMAT = "L=2".freeze + + # @see MachOStructure::SIZEOF + # @api private + SIZEOF = 8 + + # Instantiates a new LoadCommand given a view into its origin Mach-O + # @param view [MachO::MachOView] the load command's raw view + # @return [LoadCommand] the new load command + # @api private + def self.new_from_bin(view) + bin = view.raw_data.slice(view.offset, bytesize) + format = Utils.specialize_format(self::FORMAT, view.endianness) + + new(view, *bin.unpack(format)) + end + + # Creates a new (viewless) command corresponding to the symbol provided + # @param cmd_sym [Symbol] the symbol of the load command being created + # @param args [Array] the arguments for the load command being created + def self.create(cmd_sym, *args) + raise LoadCommandNotCreatableError, cmd_sym unless CREATABLE_LOAD_COMMANDS.include?(cmd_sym) + + klass = LoadCommands.const_get LC_STRUCTURES[cmd_sym] + cmd = LOAD_COMMAND_CONSTANTS[cmd_sym] + + # cmd will be filled in, view and cmdsize will be left unpopulated + klass_arity = klass.instance_method(:initialize).arity - 3 + + raise LoadCommandCreationArityError.new(cmd_sym, klass_arity, args.size) if klass_arity != args.size + + klass.new(nil, cmd, nil, *args) + end + + # @param view [MachO::MachOView] the load command's raw view + # @param cmd [Fixnum] the load command's identifying number + # @param cmdsize [Fixnum] the size of the load command in bytes + # @api private + def initialize(view, cmd, cmdsize) + @view = view + @cmd = cmd + @cmdsize = cmdsize + end + + # @return [Boolean] whether the load command can be serialized + def serializable? + CREATABLE_LOAD_COMMANDS.include?(LOAD_COMMANDS[cmd]) + end + + # @param context [SerializationContext] the context + # to serialize into + # @return [String, nil] the serialized fields of the load command, or nil + # if the load command can't be serialized + # @api private + def serialize(context) + raise LoadCommandNotSerializableError, LOAD_COMMANDS[cmd] unless serializable? + format = Utils.specialize_format(FORMAT, context.endianness) + [cmd, SIZEOF].pack(format) + end + + # @return [Fixnum] the load command's offset in the source file + # @deprecated use {#view} instead + def offset + view.offset + end + + # @return [Symbol] a symbol representation of the load command's + # identifying number + def type + LOAD_COMMANDS[cmd] + end + + alias to_sym type + + # @return [String] a string representation of the load command's + # identifying number + def to_s + type.to_s + end + + # Represents a Load Command string. A rough analogue to the lc_str + # struct used internally by OS X. This class allows ruby-macho to + # pretend that strings stored in LCs are immediately available without + # explicit operations on the raw Mach-O data. + class LCStr + # @param lc [LoadCommand] the load command + # @param lc_str [Fixnum, String] the offset to the beginning of the + # string, or the string itself if not being initialized with a view. + # @raise [MachO::LCStrMalformedError] if the string is malformed + # @todo devise a solution such that the `lc_str` parameter is not + # interpreted differently depending on `lc.view`. The current behavior + # is a hack to allow viewless load command creation. + # @api private + def initialize(lc, lc_str) + view = lc.view + + if view + lc_str_abs = view.offset + lc_str + lc_end = view.offset + lc.cmdsize - 1 + raw_string = view.raw_data.slice(lc_str_abs..lc_end) + @string, null_byte, _padding = raw_string.partition("\x00") + raise LCStrMalformedError, lc if null_byte.empty? + @string_offset = lc_str + else + @string = lc_str + @string_offset = 0 + end + end + + # @return [String] a string representation of the LCStr + def to_s + @string + end + + # @return [Fixnum] the offset to the beginning of the string in the + # load command + def to_i + @string_offset + end + end + + # Represents the contextual information needed by a load command to + # serialize itself correctly into a binary string. + class SerializationContext + # @return [Symbol] the endianness of the serialized load command + attr_reader :endianness + + # @return [Fixnum] the constant alignment value used to pad the + # serialized load command + attr_reader :alignment + + # @param macho [MachO::MachOFile] the file to contextualize + # @return [SerializationContext] the + # resulting context + def self.context_for(macho) + new(macho.endianness, macho.alignment) + end + + # @param endianness [Symbol] the endianness of the context + # @param alignment [Fixnum] the alignment of the context + # @api private + def initialize(endianness, alignment) + @endianness = endianness + @alignment = alignment + end + end + end + + # A load command containing a single 128-bit unique random number + # identifying an object produced by static link editor. Corresponds to + # LC_UUID. + class UUIDCommand < LoadCommand + # @return [Array] the UUID + attr_reader :uuid + + # @see MachOStructure::FORMAT + # @api private + FORMAT = "L=2a16".freeze + + # @see MachOStructure::SIZEOF + # @api private + SIZEOF = 24 + + # @api private + def initialize(view, cmd, cmdsize, uuid) + super(view, cmd, cmdsize) + @uuid = uuid.unpack("C16") # re-unpack for the actual UUID array + end + + # @return [String] a string representation of the UUID + def uuid_string + hexes = uuid.map { |e| "%02x" % e } + segs = [ + hexes[0..3].join, hexes[4..5].join, hexes[6..7].join, + hexes[8..9].join, hexes[10..15].join + ] + + segs.join("-") + end + end + + # A load command indicating that part of this file is to be mapped into + # the task's address space. Corresponds to LC_SEGMENT. + class SegmentCommand < LoadCommand + # @return [String] the name of the segment + attr_reader :segname + + # @return [Fixnum] the memory address of the segment + attr_reader :vmaddr + + # @return [Fixnum] the memory size of the segment + attr_reader :vmsize + + # @return [Fixnum] the file offset of the segment + attr_reader :fileoff + + # @return [Fixnum] the amount to map from the file + attr_reader :filesize + + # @return [Fixnum] the maximum VM protection + attr_reader :maxprot + + # @return [Fixnum] the initial VM protection + attr_reader :initprot + + # @return [Fixnum] the number of sections in the segment + attr_reader :nsects + + # @return [Fixnum] any flags associated with the segment + attr_reader :flags + + # @see MachOStructure::FORMAT + # @api private + FORMAT = "L=2a16L=4l=2L=2".freeze + + # @see MachOStructure::SIZEOF + # @api private + SIZEOF = 56 + + # @api private + def initialize(view, cmd, cmdsize, segname, vmaddr, vmsize, fileoff, + filesize, maxprot, initprot, nsects, flags) + super(view, cmd, cmdsize) + @segname = segname.delete("\x00") + @vmaddr = vmaddr + @vmsize = vmsize + @fileoff = fileoff + @filesize = filesize + @maxprot = maxprot + @initprot = initprot + @nsects = nsects + @flags = flags + end + + # All sections referenced within this segment. + # @return [Array] if the Mach-O is 32-bit + # @return [Array] if the Mach-O is 64-bit + def sections + klass = case self + when SegmentCommand64 + MachO::Sections::Section64 + when SegmentCommand + MachO::Sections::Section + end + + offset = view.offset + self.class.bytesize + length = nsects * klass.bytesize + + bins = view.raw_data[offset, length] + bins.unpack("a#{klass.bytesize}" * nsects).map do |bin| + klass.new_from_bin(view.endianness, bin) + end + end + + # @example + # puts "this segment relocated in/to it" if sect.flag?(:SG_NORELOC) + # @param flag [Symbol] a segment flag symbol + # @return [Boolean] true if `flag` is present in the segment's flag field + def flag?(flag) + flag = SEGMENT_FLAGS[flag] + return false if flag.nil? + flags & flag == flag + end + end + + # A load command indicating that part of this file is to be mapped into + # the task's address space. Corresponds to LC_SEGMENT_64. + class SegmentCommand64 < SegmentCommand + # @see MachOStructure::FORMAT + # @api private + FORMAT = "L=2a16Q=4l=2L=2".freeze + + # @see MachOStructure::SIZEOF + # @api private + SIZEOF = 72 + end + + # A load command representing some aspect of shared libraries, depending + # on filetype. Corresponds to LC_ID_DYLIB, LC_LOAD_DYLIB, + # LC_LOAD_WEAK_DYLIB, and LC_REEXPORT_DYLIB. + class DylibCommand < LoadCommand + # @return [LCStr] the library's path + # name as an LCStr + attr_reader :name + + # @return [Fixnum] the library's build time stamp + attr_reader :timestamp + + # @return [Fixnum] the library's current version number + attr_reader :current_version + + # @return [Fixnum] the library's compatibility version number + attr_reader :compatibility_version + + # @see MachOStructure::FORMAT + # @api private + FORMAT = "L=6".freeze + + # @see MachOStructure::SIZEOF + # @api private + SIZEOF = 24 + + # @api private + def initialize(view, cmd, cmdsize, name, timestamp, current_version, + compatibility_version) + super(view, cmd, cmdsize) + @name = LCStr.new(self, name) + @timestamp = timestamp + @current_version = current_version + @compatibility_version = compatibility_version + end + + # @param context [SerializationContext] + # the context + # @return [String] the serialized fields of the load command + # @api private + def serialize(context) + format = Utils.specialize_format(FORMAT, context.endianness) + string_payload, string_offsets = Utils.pack_strings(SIZEOF, + context.alignment, + :name => name.to_s) + cmdsize = SIZEOF + string_payload.bytesize + [cmd, cmdsize, string_offsets[:name], timestamp, current_version, + compatibility_version].pack(format) + string_payload + end + end + + # A load command representing some aspect of the dynamic linker, depending + # on filetype. Corresponds to LC_ID_DYLINKER, LC_LOAD_DYLINKER, and + # LC_DYLD_ENVIRONMENT. + class DylinkerCommand < LoadCommand + # @return [LCStr] the dynamic linker's + # path name as an LCStr + attr_reader :name + + # @see MachOStructure::FORMAT + # @api private + FORMAT = "L=3".freeze + + # @see MachOStructure::SIZEOF + # @api private + SIZEOF = 12 + + # @api private + def initialize(view, cmd, cmdsize, name) + super(view, cmd, cmdsize) + @name = LCStr.new(self, name) + end + + # @param context [SerializationContext] + # the context + # @return [String] the serialized fields of the load command + # @api private + def serialize(context) + format = Utils.specialize_format(FORMAT, context.endianness) + string_payload, string_offsets = Utils.pack_strings(SIZEOF, + context.alignment, + :name => name.to_s) + cmdsize = SIZEOF + string_payload.bytesize + [cmd, cmdsize, string_offsets[:name]].pack(format) + string_payload + end + end + + # A load command used to indicate dynamic libraries used in prebinding. + # Corresponds to LC_PREBOUND_DYLIB. + class PreboundDylibCommand < LoadCommand + # @return [LCStr] the library's path + # name as an LCStr + attr_reader :name + + # @return [Fixnum] the number of modules in the library + attr_reader :nmodules + + # @return [Fixnum] a bit vector of linked modules + attr_reader :linked_modules + + # @see MachOStructure::FORMAT + # @api private + FORMAT = "L=5".freeze + + # @see MachOStructure::SIZEOF + # @api private + SIZEOF = 20 + + # @api private + def initialize(view, cmd, cmdsize, name, nmodules, linked_modules) + super(view, cmd, cmdsize) + @name = LCStr.new(self, name) + @nmodules = nmodules + @linked_modules = linked_modules + end + end + + # A load command used to represent threads. + # @note cctools-870 and onwards have all fields of thread_command commented + # out except the common ones (cmd, cmdsize) + class ThreadCommand < LoadCommand + # @see MachOStructure::FORMAT + # @api private + FORMAT = "L=2".freeze + + # @see MachOStructure::SIZEOF + # @api private + SIZEOF = 8 + end + + # A load command containing the address of the dynamic shared library + # initialization routine and an index into the module table for the module + # that defines the routine. Corresponds to LC_ROUTINES. + class RoutinesCommand < LoadCommand + # @return [Fixnum] the address of the initialization routine + attr_reader :init_address + + # @return [Fixnum] the index into the module table that the init routine + # is defined in + attr_reader :init_module + + # @return [void] + attr_reader :reserved1 + + # @return [void] + attr_reader :reserved2 + + # @return [void] + attr_reader :reserved3 + + # @return [void] + attr_reader :reserved4 + + # @return [void] + attr_reader :reserved5 + + # @return [void] + attr_reader :reserved6 + + # @see MachOStructure::FORMAT + # @api private + FORMAT = "L=10".freeze + + # @see MachOStructure::SIZEOF + # @api private + SIZEOF = 40 + + # @api private + def initialize(view, cmd, cmdsize, init_address, init_module, reserved1, + reserved2, reserved3, reserved4, reserved5, reserved6) + super(view, cmd, cmdsize) + @init_address = init_address + @init_module = init_module + @reserved1 = reserved1 + @reserved2 = reserved2 + @reserved3 = reserved3 + @reserved4 = reserved4 + @reserved5 = reserved5 + @reserved6 = reserved6 + end + end + + # A load command containing the address of the dynamic shared library + # initialization routine and an index into the module table for the module + # that defines the routine. Corresponds to LC_ROUTINES_64. + class RoutinesCommand64 < RoutinesCommand + # @see MachOStructure::FORMAT + # @api private + FORMAT = "L=2Q=8".freeze + + # @see MachOStructure::SIZEOF + # @api private + SIZEOF = 72 + end + + # A load command signifying membership of a subframework containing the name + # of an umbrella framework. Corresponds to LC_SUB_FRAMEWORK. + class SubFrameworkCommand < LoadCommand + # @return [LCStr] the umbrella framework name as an LCStr + attr_reader :umbrella + + # @see MachOStructure::FORMAT + # @api private + FORMAT = "L=3".freeze + + # @see MachOStructure::SIZEOF + # @api private + SIZEOF = 12 + + # @api private + def initialize(view, cmd, cmdsize, umbrella) + super(view, cmd, cmdsize) + @umbrella = LCStr.new(self, umbrella) + end + end + + # A load command signifying membership of a subumbrella containing the name + # of an umbrella framework. Corresponds to LC_SUB_UMBRELLA. + class SubUmbrellaCommand < LoadCommand + # @return [LCStr] the subumbrella framework name as an LCStr + attr_reader :sub_umbrella + + # @see MachOStructure::FORMAT + # @api private + FORMAT = "L=3".freeze + + # @see MachOStructure::SIZEOF + # @api private + SIZEOF = 12 + + # @api private + def initialize(view, cmd, cmdsize, sub_umbrella) + super(view, cmd, cmdsize) + @sub_umbrella = LCStr.new(self, sub_umbrella) + end + end + + # A load command signifying a sublibrary of a shared library. Corresponds + # to LC_SUB_LIBRARY. + class SubLibraryCommand < LoadCommand + # @return [LCStr] the sublibrary name as an LCStr + attr_reader :sub_library + + # @see MachOStructure::FORMAT + # @api private + FORMAT = "L=3".freeze + + # @see MachOStructure::SIZEOF + # @api private + SIZEOF = 12 + + # @api private + def initialize(view, cmd, cmdsize, sub_library) + super(view, cmd, cmdsize) + @sub_library = LCStr.new(self, sub_library) + end + end + + # A load command signifying a shared library that is a subframework of + # an umbrella framework. Corresponds to LC_SUB_CLIENT. + class SubClientCommand < LoadCommand + # @return [LCStr] the subclient name as an LCStr + attr_reader :sub_client + + # @see MachOStructure::FORMAT + # @api private + FORMAT = "L=3".freeze + + # @see MachOStructure::SIZEOF + # @api private + SIZEOF = 12 + + # @api private + def initialize(view, cmd, cmdsize, sub_client) + super(view, cmd, cmdsize) + @sub_client = LCStr.new(self, sub_client) + end + end + + # A load command containing the offsets and sizes of the link-edit 4.3BSD + # "stab" style symbol table information. Corresponds to LC_SYMTAB. + class SymtabCommand < LoadCommand + # @return [Fixnum] the symbol table's offset + attr_reader :symoff + + # @return [Fixnum] the number of symbol table entries + attr_reader :nsyms + + # @return the string table's offset + attr_reader :stroff + + # @return the string table size in bytes + attr_reader :strsize + + # @see MachOStructure::FORMAT + # @api private + FORMAT = "L=6".freeze + + # @see MachOStructure::SIZEOF + # @api private + SIZEOF = 24 + + # @api private + def initialize(view, cmd, cmdsize, symoff, nsyms, stroff, strsize) + super(view, cmd, cmdsize) + @symoff = symoff + @nsyms = nsyms + @stroff = stroff + @strsize = strsize + end + end + + # A load command containing symbolic information needed to support data + # structures used by the dynamic link editor. Corresponds to LC_DYSYMTAB. + class DysymtabCommand < LoadCommand + # @return [Fixnum] the index to local symbols + attr_reader :ilocalsym + + # @return [Fixnum] the number of local symbols + attr_reader :nlocalsym + + # @return [Fixnum] the index to externally defined symbols + attr_reader :iextdefsym + + # @return [Fixnum] the number of externally defined symbols + attr_reader :nextdefsym + + # @return [Fixnum] the index to undefined symbols + attr_reader :iundefsym + + # @return [Fixnum] the number of undefined symbols + attr_reader :nundefsym + + # @return [Fixnum] the file offset to the table of contents + attr_reader :tocoff + + # @return [Fixnum] the number of entries in the table of contents + attr_reader :ntoc + + # @return [Fixnum] the file offset to the module table + attr_reader :modtaboff + + # @return [Fixnum] the number of entries in the module table + attr_reader :nmodtab + + # @return [Fixnum] the file offset to the referenced symbol table + attr_reader :extrefsymoff + + # @return [Fixnum] the number of entries in the referenced symbol table + attr_reader :nextrefsyms + + # @return [Fixnum] the file offset to the indirect symbol table + attr_reader :indirectsymoff + + # @return [Fixnum] the number of entries in the indirect symbol table + attr_reader :nindirectsyms + + # @return [Fixnum] the file offset to the external relocation entries + attr_reader :extreloff + + # @return [Fixnum] the number of external relocation entries + attr_reader :nextrel + + # @return [Fixnum] the file offset to the local relocation entries + attr_reader :locreloff + + # @return [Fixnum] the number of local relocation entries + attr_reader :nlocrel + + # @see MachOStructure::FORMAT + # @api private + FORMAT = "L=20".freeze + + # @see MachOStructure::SIZEOF + # @api private + SIZEOF = 80 + + # ugh + # @api private + def initialize(view, cmd, cmdsize, ilocalsym, nlocalsym, iextdefsym, + nextdefsym, iundefsym, nundefsym, tocoff, ntoc, modtaboff, + nmodtab, extrefsymoff, nextrefsyms, indirectsymoff, + nindirectsyms, extreloff, nextrel, locreloff, nlocrel) + super(view, cmd, cmdsize) + @ilocalsym = ilocalsym + @nlocalsym = nlocalsym + @iextdefsym = iextdefsym + @nextdefsym = nextdefsym + @iundefsym = iundefsym + @nundefsym = nundefsym + @tocoff = tocoff + @ntoc = ntoc + @modtaboff = modtaboff + @nmodtab = nmodtab + @extrefsymoff = extrefsymoff + @nextrefsyms = nextrefsyms + @indirectsymoff = indirectsymoff + @nindirectsyms = nindirectsyms + @extreloff = extreloff + @nextrel = nextrel + @locreloff = locreloff + @nlocrel = nlocrel + end + end + + # A load command containing the offset and number of hints in the two-level + # namespace lookup hints table. Corresponds to LC_TWOLEVEL_HINTS. + class TwolevelHintsCommand < LoadCommand + # @return [Fixnum] the offset to the hint table + attr_reader :htoffset + + # @return [Fixnum] the number of hints in the hint table + attr_reader :nhints + + # @return [TwolevelHintsTable] + # the hint table + attr_reader :table + + # @see MachOStructure::FORMAT + # @api private + FORMAT = "L=4".freeze + + # @see MachOStructure::SIZEOF + # @api private + SIZEOF = 16 + + # @api private + def initialize(view, cmd, cmdsize, htoffset, nhints) + super(view, cmd, cmdsize) + @htoffset = htoffset + @nhints = nhints + @table = TwolevelHintsTable.new(view, htoffset, nhints) + end + + # A representation of the two-level namespace lookup hints table exposed + # by a {TwolevelHintsCommand} (`LC_TWOLEVEL_HINTS`). + class TwolevelHintsTable + # @return [Array] all hints in the table + attr_reader :hints + + # @param view [MachO::MachOView] the view into the current Mach-O + # @param htoffset [Fixnum] the offset of the hints table + # @param nhints [Fixnum] the number of two-level hints in the table + # @api private + def initialize(view, htoffset, nhints) + format = Utils.specialize_format("L=#{nhints}", view.endianness) + raw_table = view.raw_data[htoffset, nhints * 4] + blobs = raw_table.unpack(format) + + @hints = blobs.map { |b| TwolevelHint.new(b) } + end + + # An individual two-level namespace lookup hint. + class TwolevelHint + # @return [Fixnum] the index into the sub-images + attr_reader :isub_image + + # @return [Fixnum] the index into the table of contents + attr_reader :itoc + + # @param blob [Fixnum] the 32-bit number containing the lookup hint + # @api private + def initialize(blob) + @isub_image = blob >> 24 + @itoc = blob & 0x00FFFFFF + end + end + end + end + + # A load command containing the value of the original checksum for prebound + # files, or zero. Corresponds to LC_PREBIND_CKSUM. + class PrebindCksumCommand < LoadCommand + # @return [Fixnum] the checksum or 0 + attr_reader :cksum + + # @see MachOStructure::FORMAT + # @api private + FORMAT = "L=3".freeze + + # @see MachOStructure::SIZEOF + # @api private + SIZEOF = 12 + + # @api private + def initialize(view, cmd, cmdsize, cksum) + super(view, cmd, cmdsize) + @cksum = cksum + end + end + + # A load command representing an rpath, which specifies a path that should + # be added to the current run path used to find @rpath prefixed dylibs. + # Corresponds to LC_RPATH. + class RpathCommand < LoadCommand + # @return [LCStr] the path to add to the run path as an LCStr + attr_reader :path + + # @see MachOStructure::FORMAT + # @api private + FORMAT = "L=3".freeze + + # @see MachOStructure::SIZEOF + # @api private + SIZEOF = 12 + + # @api private + def initialize(view, cmd, cmdsize, path) + super(view, cmd, cmdsize) + @path = LCStr.new(self, path) + end + + # @param context [SerializationContext] the context + # @return [String] the serialized fields of the load command + # @api private + def serialize(context) + format = Utils.specialize_format(FORMAT, context.endianness) + string_payload, string_offsets = Utils.pack_strings(SIZEOF, + context.alignment, + :path => path.to_s) + cmdsize = SIZEOF + string_payload.bytesize + [cmd, cmdsize, string_offsets[:path]].pack(format) + string_payload + end + end + + # A load command representing the offsets and sizes of a blob of data in + # the __LINKEDIT segment. Corresponds to LC_CODE_SIGNATURE, + # LC_SEGMENT_SPLIT_INFO, LC_FUNCTION_STARTS, LC_DATA_IN_CODE, + # LC_DYLIB_CODE_SIGN_DRS, and LC_LINKER_OPTIMIZATION_HINT. + class LinkeditDataCommand < LoadCommand + # @return [Fixnum] offset to the data in the __LINKEDIT segment + attr_reader :dataoff + + # @return [Fixnum] size of the data in the __LINKEDIT segment + attr_reader :datasize + + # @see MachOStructure::FORMAT + # @api private + FORMAT = "L=4".freeze + + # @see MachOStructure::SIZEOF + # @api private + SIZEOF = 16 + + # @api private + def initialize(view, cmd, cmdsize, dataoff, datasize) + super(view, cmd, cmdsize) + @dataoff = dataoff + @datasize = datasize + end + end + + # A load command representing the offset to and size of an encrypted + # segment. Corresponds to LC_ENCRYPTION_INFO. + class EncryptionInfoCommand < LoadCommand + # @return [Fixnum] the offset to the encrypted segment + attr_reader :cryptoff + + # @return [Fixnum] the size of the encrypted segment + attr_reader :cryptsize + + # @return [Fixnum] the encryption system, or 0 if not encrypted yet + attr_reader :cryptid + + # @see MachOStructure::FORMAT + # @api private + FORMAT = "L=5".freeze + + # @see MachOStructure::SIZEOF + # @api private + SIZEOF = 20 + + # @api private + def initialize(view, cmd, cmdsize, cryptoff, cryptsize, cryptid) + super(view, cmd, cmdsize) + @cryptoff = cryptoff + @cryptsize = cryptsize + @cryptid = cryptid + end + end + + # A load command representing the offset to and size of an encrypted + # segment. Corresponds to LC_ENCRYPTION_INFO_64. + class EncryptionInfoCommand64 < LoadCommand + # @return [Fixnum] the offset to the encrypted segment + attr_reader :cryptoff + + # @return [Fixnum] the size of the encrypted segment + attr_reader :cryptsize + + # @return [Fixnum] the encryption system, or 0 if not encrypted yet + attr_reader :cryptid + + # @return [Fixnum] 64-bit padding value + attr_reader :pad + + # @see MachOStructure::FORMAT + # @api private + FORMAT = "L=6".freeze + + # @see MachOStructure::SIZEOF + # @api private + SIZEOF = 24 + + # @api private + def initialize(view, cmd, cmdsize, cryptoff, cryptsize, cryptid, pad) + super(view, cmd, cmdsize) + @cryptoff = cryptoff + @cryptsize = cryptsize + @cryptid = cryptid + @pad = pad + end + end + + # A load command containing the minimum OS version on which the binary + # was built to run. Corresponds to LC_VERSION_MIN_MACOSX and + # LC_VERSION_MIN_IPHONEOS. + class VersionMinCommand < LoadCommand + # @return [Fixnum] the version X.Y.Z packed as x16.y8.z8 + attr_reader :version + + # @return [Fixnum] the SDK version X.Y.Z packed as x16.y8.z8 + attr_reader :sdk + + # @see MachOStructure::FORMAT + # @api private + FORMAT = "L=4".freeze + + # @see MachOStructure::SIZEOF + # @api private + SIZEOF = 16 + + # @api private + def initialize(view, cmd, cmdsize, version, sdk) + super(view, cmd, cmdsize) + @version = version + @sdk = sdk + end + + # A string representation of the binary's minimum OS version. + # @return [String] a string representing the minimum OS version. + def version_string + binary = "%032b" % version + segs = [ + binary[0..15], binary[16..23], binary[24..31] + ].map { |s| s.to_i(2) } + + segs.join(".") + end + + # A string representation of the binary's SDK version. + # @return [String] a string representing the SDK version. + def sdk_string + binary = "%032b" % sdk + segs = [ + binary[0..15], binary[16..23], binary[24..31] + ].map { |s| s.to_i(2) } + + segs.join(".") + end + end + + # A load command containing the file offsets and sizes of the new + # compressed form of the information dyld needs to load the image. + # Corresponds to LC_DYLD_INFO and LC_DYLD_INFO_ONLY. + class DyldInfoCommand < LoadCommand + # @return [Fixnum] the file offset to the rebase information + attr_reader :rebase_off + + # @return [Fixnum] the size of the rebase information + attr_reader :rebase_size + + # @return [Fixnum] the file offset to the binding information + attr_reader :bind_off + + # @return [Fixnum] the size of the binding information + attr_reader :bind_size + + # @return [Fixnum] the file offset to the weak binding information + attr_reader :weak_bind_off + + # @return [Fixnum] the size of the weak binding information + attr_reader :weak_bind_size + + # @return [Fixnum] the file offset to the lazy binding information + attr_reader :lazy_bind_off + + # @return [Fixnum] the size of the lazy binding information + attr_reader :lazy_bind_size + + # @return [Fixnum] the file offset to the export information + attr_reader :export_off + + # @return [Fixnum] the size of the export information + attr_reader :export_size + + # @see MachOStructure::FORMAT + # @api private + FORMAT = "L=12".freeze + + # @see MachOStructure::SIZEOF + # @api private + SIZEOF = 48 + + # @api private + def initialize(view, cmd, cmdsize, rebase_off, rebase_size, bind_off, + bind_size, weak_bind_off, weak_bind_size, lazy_bind_off, + lazy_bind_size, export_off, export_size) + super(view, cmd, cmdsize) + @rebase_off = rebase_off + @rebase_size = rebase_size + @bind_off = bind_off + @bind_size = bind_size + @weak_bind_off = weak_bind_off + @weak_bind_size = weak_bind_size + @lazy_bind_off = lazy_bind_off + @lazy_bind_size = lazy_bind_size + @export_off = export_off + @export_size = export_size + end + end + + # A load command containing linker options embedded in object files. + # Corresponds to LC_LINKER_OPTION. + class LinkerOptionCommand < LoadCommand + # @return [Fixnum] the number of strings + attr_reader :count + + # @see MachOStructure::FORMAT + # @api private + FORMAT = "L=3".freeze + + # @see MachOStructure::SIZEOF + # @api private + SIZEOF = 12 + + # @api private + def initialize(view, cmd, cmdsize, count) + super(view, cmd, cmdsize) + @count = count + end + end + + # A load command specifying the offset of main(). Corresponds to LC_MAIN. + class EntryPointCommand < LoadCommand + # @return [Fixnum] the file (__TEXT) offset of main() + attr_reader :entryoff + + # @return [Fixnum] if not 0, the initial stack size. + attr_reader :stacksize + + # @see MachOStructure::FORMAT + # @api private + FORMAT = "L=2Q=2".freeze + + # @see MachOStructure::SIZEOF + # @api private + SIZEOF = 24 + + # @api private + def initialize(view, cmd, cmdsize, entryoff, stacksize) + super(view, cmd, cmdsize) + @entryoff = entryoff + @stacksize = stacksize + end + end + + # A load command specifying the version of the sources used to build the + # binary. Corresponds to LC_SOURCE_VERSION. + class SourceVersionCommand < LoadCommand + # @return [Fixnum] the version packed as a24.b10.c10.d10.e10 + attr_reader :version + + # @see MachOStructure::FORMAT + # @api private + FORMAT = "L=2Q=1".freeze + + # @see MachOStructure::SIZEOF + # @api private + SIZEOF = 16 + + # @api private + def initialize(view, cmd, cmdsize, version) + super(view, cmd, cmdsize) + @version = version + end + + # A string representation of the sources used to build the binary. + # @return [String] a string representation of the version + def version_string + binary = "%064b" % version + segs = [ + binary[0..23], binary[24..33], binary[34..43], binary[44..53], + binary[54..63] + ].map { |s| s.to_i(2) } + + segs.join(".") + end + end + + # An obsolete load command containing the offset and size of the (GNU style) + # symbol table information. Corresponds to LC_SYMSEG. + class SymsegCommand < LoadCommand + # @return [Fixnum] the offset to the symbol segment + attr_reader :offset + + # @return [Fixnum] the size of the symbol segment in bytes + attr_reader :size + + # @see MachOStructure::FORMAT + # @api private + FORMAT = "L=4".freeze + + # @see MachOStructure::SIZEOF + # @api private + SIZEOF = 16 + + # @api private + def initialize(view, cmd, cmdsize, offset, size) + super(view, cmd, cmdsize) + @offset = offset + @size = size + end + end + + # An obsolete load command containing a free format string table. Each + # string is null-terminated and the command is zero-padded to a multiple of + # 4. Corresponds to LC_IDENT. + class IdentCommand < LoadCommand + # @see MachOStructure::FORMAT + # @api private + FORMAT = "L=2".freeze + + # @see MachOStructure::SIZEOF + # @api private + SIZEOF = 8 + end + + # An obsolete load command containing the path to a file to be loaded into + # memory. Corresponds to LC_FVMFILE. + class FvmfileCommand < LoadCommand + # @return [LCStr] the pathname of the file being loaded + attr_reader :name + + # @return [Fixnum] the virtual address being loaded at + attr_reader :header_addr + + # @see MachOStructure::FORMAT + # @api private + FORMAT = "L=4".freeze + + # @see MachOStructure::SIZEOF + # @api private + SIZEOF = 16 + + def initialize(view, cmd, cmdsize, name, header_addr) + super(view, cmd, cmdsize) + @name = LCStr.new(self, name) + @header_addr = header_addr + end + end + + # An obsolete load command containing the path to a library to be loaded + # into memory. Corresponds to LC_LOADFVMLIB and LC_IDFVMLIB. + class FvmlibCommand < LoadCommand + # @return [LCStr] the library's target pathname + attr_reader :name + + # @return [Fixnum] the library's minor version number + attr_reader :minor_version + + # @return [Fixnum] the library's header address + attr_reader :header_addr + + # @see MachOStructure::FORMAT + # @api private + FORMAT = "L=5".freeze + + # @see MachOStructure::SIZEOF + # @api private + SIZEOF = 20 + + def initialize(view, cmd, cmdsize, name, minor_version, header_addr) + super(view, cmd, cmdsize) + @name = LCStr.new(self, name) + @minor_version = minor_version + @header_addr = header_addr + end + end + end +end diff --git a/Library/Homebrew/vendor/macho/macho/macho_file.rb b/Library/Homebrew/vendor/macho/macho/macho_file.rb new file mode 100644 index 000000000..7693ab0dd --- /dev/null +++ b/Library/Homebrew/vendor/macho/macho/macho_file.rb @@ -0,0 +1,545 @@ +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 FatFile + class MachOFile + 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 [Headers::MachHeader] if the Mach-O is 32-bit + # @return [Headers::MachHeader64] if the Mach-O is 64-bit + attr_reader :header + + # @return [Array] 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 [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 file does not exist + def initialize(filename) + raise ArgumentError, "#{filename}: no such file" unless File.file?(filename) + + @filename = filename + @raw_data = File.open(@filename, "rb", &:read) + populate_fields + end + + # Initializes a new MachOFile instance from a binary string. + # @see MachO::MachOFile.new_from_bin + # @api private + def initialize_from_bin(bin) + @filename = nil + @raw_data = bin + populate_fields + end + + # The file's raw Mach-O data. + # @return [String] the raw Mach-O data + def serialize + @raw_data + 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 + Headers::MH_MAGICS[magic] + end + + # @return [Symbol] a string representation of the Mach-O's filetype + def filetype + Headers::MH_FILETYPES[header.filetype] + end + + # @return [Symbol] a symbol representation of the Mach-O's CPU type + def cputype + Headers::CPU_TYPES[header.cputype] + end + + # @return [Symbol] a symbol representation of the Mach-O's CPU subtype + def cpusubtype + Headers::CPU_SUBTYPES[header.cputype][header.cpusubtype] + 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] an array of load commands + # corresponding to `name` + def command(name) + load_commands.select { |lc| lc.type == name.to_sym } + end + + alias [] command + + # Inserts a load command at the given offset. + # @param offset [Fixnum] the offset to insert at + # @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 [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 = LoadCommands::LoadCommand::SerializationContext.context_for(self) + cmd_raw = lc.serialize(context) + + if offset < header.class.bytesize || offset + cmd_raw.bytesize > low_fileoff + raise OffsetInsertionError, offset + end + + new_sizeofcmds = sizeofcmds + cmd_raw.bytesize + + if header.class.bytesize + new_sizeofcmds > low_fileoff + raise HeaderPadError, @filename + end + + # update Mach-O header fields to account for inserted load command + update_ncmds(ncmds + 1) + update_sizeofcmds(new_sizeofcmds) + + @raw_data.insert(offset, cmd_raw) + @raw_data.slice!(header.class.bytesize + new_sizeofcmds, cmd_raw.bytesize) + + populate_fields if options.fetch(:repopulate, true) + end + + # Replace a load command with another command in the Mach-O, preserving location. + # @param old_lc [LoadCommands::LoadCommand] the load command being replaced + # @param new_lc [LoadCommands::LoadCommand] the load command being added + # @return [void] + # @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 = 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 + raise HeaderPadError, @filename + end + + delete_command(old_lc) + insert_command(old_lc.view.offset, new_lc) + end + + # Appends a new load command to the Mach-O. + # @param lc [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 + # @note This is public, but methods like {#add_rpath} should be preferred. + # Setting `repopulate` to false **will leave the instance in an + # inconsistent state** unless {#populate_fields} is called **immediately** + # afterwards. + def add_command(lc, options = {}) + insert_command(header.class.bytesize + sizeofcmds, lc, options) + end + + # Delete a load command from the Mach-O. + # @param lc [LoadCommands::LoadCommand] the load command being deleted + # @param options [Hash] + # @option options [Boolean] :repopulate (true) whether or not to repopulate + # the instance fields + # @return [void] + # @note This is public, but methods like {#delete_rpath} should be preferred. + # Setting `repopulate` to false **will leave the instance in an + # inconsistent state** unless {#populate_fields} is called **immediately** + # afterwards. + def delete_command(lc, options = {}) + @raw_data.slice!(lc.view.offset, lc.cmdsize) + + # update Mach-O header fields to account for deleted load command + update_ncmds(ncmds - 1) + update_sizeofcmds(sizeofcmds - lc.cmdsize) + + # pad the space after the load commands to preserve offsets + null_pad = "\x00" * lc.cmdsize + @raw_data.insert(header.class.bytesize + sizeofcmds - lc.cmdsize, null_pad) + + populate_fields if options.fetch(:repopulate, true) + end + + # Populate the instance's fields with the raw Mach-O data. + # @return [void] + # @note This method is public, but should (almost) never need to be called. + # The exception to this rule is when methods like {#add_command} and + # {#delete_command} have been called with `repopulate = false`. + def populate_fields + @header = populate_mach_header + @load_commands = populate_load_commands + end + + # All load commands responsible for loading dylibs. + # @return [Array] an array of DylibCommands + def dylib_load_commands + load_commands.select { |lc| LoadCommands::DYLIB_LOAD_COMMANDS.include?(lc.type) } + end + + # All segment load commands in the Mach-O. + # @return [Array] if the Mach-O is 32-bit + # @return [Array] 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 + return unless dylib? + + 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.change_dylib_id("libFoo.dylib") + # @param new_id [String] the dylib's new ID + # @param _options [Hash] + # @return [void] + # @raise [ArgumentError] if `new_id` is not a String + # @note `_options` is currently unused and is provided for signature + # compatibility with {MachO::FatFile#change_dylib_id} + def change_dylib_id(new_id, _options = {}) + raise ArgumentError, "new ID must be a String" unless new_id.is_a?(String) + return unless dylib? + + old_lc = command(:LC_ID_DYLIB).first + raise DylibIdMissingError unless old_lc + + 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 + + alias dylib_id= change_dylib_id + + # All shared libraries linked to the Mach-O. + # @return [Array] an array of all shared libraries + def linked_dylibs + # Some linkers produce multiple `LC_LOAD_DYLIB` load commands for the same + # library, but at this point we're really only interested in a list of + # unique libraries this Mach-O file links to, thus: `uniq`. (This is also + # for consistency with `FatFile` that merges this list across all archs.) + dylib_load_commands.map(&:name).map(&:to_s).uniq + end + + # Changes the shared library `old_name` to `new_name` + # @example + # 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 [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 = 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 + + alias change_dylib change_install_name + + # All runtime paths searched by the dynamic linker for the Mach-O. + # @return [Array] 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 + # @param _options [Hash] + # @return [void] + # @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 = {}) + old_lc = command(:LC_RPATH).find { |r| r.path.to_s == old_path } + raise RpathUnknownError, old_path if old_lc.nil? + raise RpathExistsError, new_path if rpaths.include?(new_path) + + new_lc = LoadCommands::LoadCommand.create(:LC_RPATH, new_path) + + delete_rpath(old_path) + insert_command(old_lc.view.offset, new_lc) + end + + # Add the given runtime path to the Mach-O. + # @example + # file.rpaths # => ["/lib"] + # file.add_rpath("/usr/lib") + # file.rpaths # => ["/lib", "/usr/lib"] + # @param path [String] the new runtime path + # @param _options [Hash] + # @return [void] + # @raise [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 = LoadCommands::LoadCommand.create(:LC_RPATH, path) + add_command(rpath_cmd) + end + + # Delete the given runtime path from the Mach-O. + # @example + # file.rpaths # => ["/lib"] + # file.delete_rpath("/lib") + # file.rpaths # => [] + # @param path [String] the runtime path to delete + # @param _options [Hash] + # @return void + # @raise [RpathUnknownError] if no such runtime path exists + # @note `_options` is currently unused and is provided for signature + # compatibility with {MachO::FatFile#delete_rpath} + def delete_rpath(path, _options = {}) + rpath_cmds = command(:LC_RPATH).select { |r| r.path.to_s == path } + raise RpathUnknownError, path if rpath_cmds.empty? + + # delete the commands in reverse order, offset descending. this + # allows us to defer (expensive) field population until the very end + rpath_cmds.reverse_each { |cmd| delete_command(cmd, :repopulate => false) } + + populate_fields + end + + # 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. + # @return [void] + # @raise [MachOError] if the instance was initialized without a file + # @note Overwrites all data in the file! + def write! + if @filename.nil? + raise MachOError, "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 [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) ? Headers::MachHeader : Headers::MachHeader64 + mh = mh_klass.new_from_bin(endianness, @raw_data[0, mh_klass.bytesize]) + + check_cputype(mh.cputype) + check_cpusubtype(mh.cputype, mh.cpusubtype) + check_filetype(mh.filetype) + + mh + end + + # Read just the file's magic number and check its validity. + # @return [Fixnum] the magic + # @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 + + raise MagicError, magic unless Utils.magic?(magic) + raise FatBinaryError if Utils.fat_magic?(magic) + + @endianness = Utils.little_magic?(magic) ? :little : :big + + magic + end + + # Check the file's CPU type. + # @param cputype [Fixnum] the CPU type + # @raise [CPUTypeError] if the CPU type is unknown + # @api private + def check_cputype(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 [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 Headers::CPU_SUBTYPES[cputype].key?(cpusubtype) + end + + # Check the file's type. + # @param filetype [Fixnum] the file type + # @raise [FiletypeError] if the file type is unknown + # @api private + def check_filetype(filetype) + raise FiletypeError, filetype unless Headers::MH_FILETYPES.key?(filetype) + end + + # All load commands in the file. + # @return [Array] an array of load commands + # @raise [LoadCommandError] if an unknown load command is encountered + # @api private + def populate_load_commands + offset = header.class.bytesize + load_commands = [] + + header.ncmds.times do + fmt = Utils.specialize_format("L=", endianness) + cmd = @raw_data.slice(offset, 4).unpack(fmt).first + 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 = LoadCommands.const_get LoadCommands::LC_STRUCTURES[cmd_sym] + view = MachOView.new(@raw_data, endianness, offset) + command = klass.new_from_bin(view) + + load_commands << command + offset += command.cmdsize + end + + load_commands + end + + # The low file offset (offset to first section data). + # @return [Fixnum] the offset + # @api private + def low_fileoff + offset = @raw_data.size + + segments.each do |seg| + seg.sections.each do |sect| + next if sect.empty? + next if sect.flag?(:S_ZEROFILL) + next if sect.flag?(:S_THREAD_LOCAL_ZEROFILL) + next unless sect.offset < offset + + offset = sect.offset + end + end + + offset + end + + # Updates the number of load commands in the raw data. + # @param ncmds [Fixnum] the new number of commands + # @return [void] + # @api private + def update_ncmds(ncmds) + fmt = Utils.specialize_format("L=", endianness) + ncmds_raw = [ncmds].pack(fmt) + @raw_data[16..19] = ncmds_raw + end + + # Updates the size of all load commands in the raw data. + # @param size [Fixnum] the new size, in bytes + # @return [void] + # @api private + def update_sizeofcmds(size) + fmt = Utils.specialize_format("L=", endianness) + size_raw = [size].pack(fmt) + @raw_data[20..23] = size_raw + end + end +end diff --git a/Library/Homebrew/vendor/macho/macho/sections.rb b/Library/Homebrew/vendor/macho/macho/sections.rb new file mode 100644 index 000000000..1e69e0b61 --- /dev/null +++ b/Library/Homebrew/vendor/macho/macho/sections.rb @@ -0,0 +1,176 @@ +module MachO + # Classes and constants for parsing sections in Mach-O binaries. + module Sections + # 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, + }.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 + + # @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 diff --git a/Library/Homebrew/vendor/macho/macho/structure.rb b/Library/Homebrew/vendor/macho/macho/structure.rb new file mode 100644 index 000000000..bac5342d4 --- /dev/null +++ b/Library/Homebrew/vendor/macho/macho/structure.rb @@ -0,0 +1,30 @@ +module MachO + # A general purpose pseudo-structure. + # @abstract + class MachOStructure + # The String#unpack format of the data structure. + # @return [String] the unpacking format + # @api private + FORMAT = "".freeze + + # The size of the data structure, in bytes. + # @return [Fixnum] the size, in bytes + # @api private + SIZEOF = 0 + + # @return [Fixnum] the size, in bytes, of the represented structure. + def self.bytesize + self::SIZEOF + end + + # @param endianness [Symbol] either `:big` or `:little` + # @param bin [String] the string to be unpacked into the new structure + # @return [MachO::MachOStructure] the resulting structure + # @api private + def self.new_from_bin(endianness, bin) + format = Utils.specialize_format(self::FORMAT, endianness) + + new(*bin.unpack(format)) + end + end +end diff --git a/Library/Homebrew/vendor/macho/macho/tools.rb b/Library/Homebrew/vendor/macho/macho/tools.rb new file mode 100644 index 000000000..b49626d9d --- /dev/null +++ b/Library/Homebrew/vendor/macho/macho/tools.rb @@ -0,0 +1,108 @@ +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] 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 + # @param options [Hash] + # @option options [Boolean] :strict (true) whether or not to fail loudly + # with an exception if the change cannot be performed + # @return [void] + def self.change_dylib_id(filename, new_id, options = {}) + file = MachO.open(filename) + + file.change_dylib_id(new_id, options) + 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 + # @param options [Hash] + # @option options [Boolean] :strict (true) whether or not to fail loudly + # with an exception if the change cannot be performed + # @return [void] + def self.change_install_name(filename, old_name, new_name, options = {}) + file = MachO.open(filename) + + file.change_install_name(old_name, new_name, options) + 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 + # @param options [Hash] + # @option options [Boolean] :strict (true) whether or not to fail loudly + # with an exception if the change cannot be performed + # @return [void] + def self.change_rpath(filename, old_path, new_path, options = {}) + file = MachO.open(filename) + + file.change_rpath(old_path, new_path, options) + file.write! + 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 + # @param options [Hash] + # @option options [Boolean] :strict (true) whether or not to fail loudly + # with an exception if the change cannot be performed + # @return [void] + def self.add_rpath(filename, new_path, options = {}) + file = MachO.open(filename) + + file.add_rpath(new_path, options) + file.write! + 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 + # @param options [Hash] + # @option options [Boolean] :strict (true) whether or not to fail loudly + # with an exception if the change cannot be performed + # @return [void] + def self.delete_rpath(filename, old_path, options = {}) + file = MachO.open(filename) + + 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] 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 diff --git a/Library/Homebrew/vendor/macho/macho/utils.rb b/Library/Homebrew/vendor/macho/macho/utils.rb new file mode 100644 index 000000000..ecfc8390b --- /dev/null +++ b/Library/Homebrew/vendor/macho/macho/utils.rb @@ -0,0 +1,99 @@ +module MachO + # A collection of utility functions used throughout ruby-macho. + module Utils + # Rounds a value to the next multiple of the given round. + # @param value [Fixnum] the number being rounded + # @param round [Fixnum] the number being rounded with + # @return [Fixnum] the rounded value + # @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 + + # 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 + def self.padding_for(size, alignment) + round(size, alignment) - size + end + + # 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 + def self.specialize_format(format, endianness) + modifier = endianness == :big ? ">" : "<" + format.tr("=", modifier) + end + + # Packs tagged strings into an aligned payload. + # @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] the packed string and labeled offsets + def self.pack_strings(fixed_offset, alignment, strings = {}) + offsets = {} + next_offset = fixed_offset + payload = "" + + strings.each do |key, string| + offsets[key] = next_offset + payload << string + payload << "\x00" + next_offset += string.bytesize + 1 + end + + payload << "\x00" * padding_for(fixed_offset + payload.bytesize, alignment) + [payload, offsets] + end + + # Compares the given number to valid Mach-O magic numbers. + # @param num [Fixnum] the number being checked + # @return [Boolean] whether `num` is a valid Mach-O magic number + def self.magic?(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] whether `num` is a valid Fat magic number + def self.fat_magic?(num) + 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] whether `num` is a valid 32-bit magic number + def self.magic32?(num) + 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] whether `num` is a valid 64-bit magic number + def self.magic64?(num) + 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] whether `num` is a valid little-endian magic number + def self.little_magic?(num) + 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] whether `num` is a valid big-endian magic number + def self.big_magic?(num) + num == Headers::MH_CIGAM || num == Headers::MH_CIGAM_64 + end + end +end diff --git a/Library/Homebrew/vendor/macho/macho/view.rb b/Library/Homebrew/vendor/macho/macho/view.rb new file mode 100644 index 000000000..9586e73be --- /dev/null +++ b/Library/Homebrew/vendor/macho/macho/view.rb @@ -0,0 +1,23 @@ +module MachO + # A representation of some unspecified Mach-O data. + class MachOView + # @return [String] the raw Mach-O data + attr_reader :raw_data + + # @return [Symbol] the endianness of the data (`:big` or `:little`) + attr_reader :endianness + + # @return [Fixnum] the offset of the relevant data (in {#raw_data}) + attr_reader :offset + + # Creates a new MachOView. + # @param raw_data [String] the raw Mach-O data + # @param endianness [Symbol] the endianness of the data + # @param offset [Fixnum] the offset of the relevant data + def initialize(raw_data, endianness, offset) + @raw_data = raw_data + @endianness = endianness + @offset = offset + end + end +end diff --git a/Library/Homebrew/vendor/plist/plist.rb b/Library/Homebrew/vendor/plist/plist.rb new file mode 100755 index 000000000..82ecb27d2 --- /dev/null +++ b/Library/Homebrew/vendor/plist/plist.rb @@ -0,0 +1,21 @@ +# encoding: utf-8 + +# = plist +# +# This is the main file for plist. Everything interesting happens in +# Plist and Plist::Emit. +# +# Copyright 2006-2010 Ben Bleything and Patrick May +# Distributed under the MIT License +# + +require 'base64' +require 'cgi' +require 'stringio' + +require_relative 'plist/generator' +require_relative 'plist/parser' +require_relative 'plist/version' + +module Plist +end diff --git a/Library/Homebrew/vendor/plist/plist/generator.rb b/Library/Homebrew/vendor/plist/plist/generator.rb new file mode 100755 index 000000000..84bef3aaf --- /dev/null +++ b/Library/Homebrew/vendor/plist/plist/generator.rb @@ -0,0 +1,222 @@ +# encoding: utf-8 + +# = plist +# +# Copyright 2006-2010 Ben Bleything and Patrick May +# Distributed under the MIT License +# + +module Plist; end + +# === Create a plist +# You can dump an object to a plist in one of two ways: +# +# * Plist::Emit.dump(obj) +# * obj.to_plist +# * This requires that you mixin the Plist::Emit module, which is already done for +Array+ and +Hash+. +# +# The following Ruby classes are converted into native plist types: +# Array, Bignum, Date, DateTime, Fixnum, Float, Hash, Integer, String, Symbol, Time, true, false +# * +Array+ and +Hash+ are both recursive; their elements will be converted into plist nodes inside the and containers (respectively). +# * +IO+ (and its descendants) and +StringIO+ objects are read from and their contents placed in a element. +# * User classes may implement +to_plist_node+ to dictate how they should be serialized; otherwise the object will be passed to Marshal.dump and the result placed in a element. +# +# For detailed usage instructions, refer to USAGE[link:files/docs/USAGE.html] and the methods documented below. +module Plist::Emit + # Helper method for injecting into classes. Calls Plist::Emit.dump with +self+. + def to_plist(envelope = true) + return Plist::Emit.dump(self, envelope) + end + + # Helper method for injecting into classes. Calls Plist::Emit.save_plist with +self+. + def save_plist(filename) + Plist::Emit.save_plist(self, filename) + end + + # The following Ruby classes are converted into native plist types: + # Array, Bignum, Date, DateTime, Fixnum, Float, Hash, Integer, String, Symbol, Time + # + # Write us (via RubyForge) if you think another class can be coerced safely into one of the expected plist classes. + # + # +IO+ and +StringIO+ objects are encoded and placed in elements; other objects are Marshal.dump'ed unless they implement +to_plist_node+. + # + # The +envelope+ parameters dictates whether or not the resultant plist fragment is wrapped in the normal XML/plist header and footer. Set it to false if you only want the fragment. + def self.dump(obj, envelope = true) + output = plist_node(obj) + + output = wrap(output) if envelope + + return output + end + + # Writes the serialized object's plist to the specified filename. + def self.save_plist(obj, filename) + File.open(filename, 'wb') do |f| + f.write(obj.to_plist) + end + end + + private + def self.plist_node(element) + output = '' + + if element.respond_to? :to_plist_node + output << element.to_plist_node + else + case element + when Array + if element.empty? + output << "\n" + else + output << tag('array') { + element.collect {|e| plist_node(e)} + } + end + when Hash + if element.empty? + output << "\n" + else + inner_tags = [] + + element.keys.sort_by{|k| k.to_s }.each do |k| + v = element[k] + inner_tags << tag('key', CGI::escapeHTML(k.to_s)) + inner_tags << plist_node(v) + end + + output << tag('dict') { + inner_tags + } + end + when true, false + output << "<#{element}/>\n" + when Time + output << tag('date', element.utc.strftime('%Y-%m-%dT%H:%M:%SZ')) + when Date # also catches DateTime + output << tag('date', element.strftime('%Y-%m-%dT%H:%M:%SZ')) + when String, Symbol, Integer, Float + output << tag(element_type(element), CGI::escapeHTML(element.to_s)) + when IO, StringIO + element.rewind + contents = element.read + # note that apple plists are wrapped at a different length then + # what ruby's base64 wraps by default. + # I used #encode64 instead of #b64encode (which allows a length arg) + # because b64encode is b0rked and ignores the length arg. + data = "\n" + Base64::encode64(contents).gsub(/\s+/, '').scan(/.{1,68}/o) { data << $& << "\n" } + output << tag('data', data) + else + output << comment( 'The element below contains a Ruby object which has been serialized with Marshal.dump.' ) + data = "\n" + Base64::encode64(Marshal.dump(element)).gsub(/\s+/, '').scan(/.{1,68}/o) { data << $& << "\n" } + output << tag('data', data ) + end + end + + return output + end + + def self.comment(content) + return "\n" + end + + def self.tag(type, contents = '', &block) + out = nil + + if block_given? + out = IndentedString.new + out << "<#{type}>" + out.raise_indent + + out << block.call + + out.lower_indent + out << "" + else + out = "<#{type}>#{contents.to_s}\n" + end + + return out.to_s + end + + def self.wrap(contents) + output = '' + + output << '' + "\n" + output << '' + "\n" + output << '' + "\n" + + output << contents + + output << '' + "\n" + + return output + end + + def self.element_type(item) + case item + when String, Symbol + 'string' + + when Integer + 'integer' + + when Float + 'real' + + else + raise "Don't know about this data type... something must be wrong!" + end + end + private + class IndentedString #:nodoc: + attr_accessor :indent_string + + def initialize(str = "\t") + @indent_string = str + @contents = '' + @indent_level = 0 + end + + def to_s + return @contents + end + + def raise_indent + @indent_level += 1 + end + + def lower_indent + @indent_level -= 1 if @indent_level > 0 + end + + def <<(val) + if val.is_a? Array + val.each do |f| + self << f + end + else + # if it's already indented, don't bother indenting further + unless val =~ /\A#{@indent_string}/ + indent = @indent_string * @indent_level + + @contents << val.gsub(/^/, indent) + else + @contents << val + end + + # it already has a newline, don't add another + @contents << "\n" unless val =~ /\n$/ + end + end + end +end + +class Array #:nodoc: + include Plist::Emit +end + +class Hash #:nodoc: + include Plist::Emit +end diff --git a/Library/Homebrew/vendor/plist/plist/parser.rb b/Library/Homebrew/vendor/plist/plist/parser.rb new file mode 100755 index 000000000..4de13f881 --- /dev/null +++ b/Library/Homebrew/vendor/plist/plist/parser.rb @@ -0,0 +1,247 @@ +# encoding: utf-8 + +# = plist +# +# Copyright 2006-2010 Ben Bleything and Patrick May +# Distributed under the MIT License +# + +# Plist parses Mac OS X xml property list files into ruby data structures. +# +# === Load a plist file +# This is the main point of the library: +# +# r = Plist::parse_xml( filename_or_xml ) +module Plist +# Note that I don't use these two elements much: +# +# + Date elements are returned as DateTime objects. +# + Data elements are implemented as Tempfiles +# +# Plist::parse_xml will blow up if it encounters a Date element. +# If you encounter such an error, or if you have a Date element which +# can't be parsed into a Time object, please send your plist file to +# plist@hexane.org so that I can implement the proper support. + def Plist::parse_xml( filename_or_xml ) + listener = Listener.new + #parser = REXML::Parsers::StreamParser.new(File.new(filename), listener) + parser = StreamParser.new(filename_or_xml, listener) + parser.parse + listener.result + end + + class Listener + #include REXML::StreamListener + + attr_accessor :result, :open + + def initialize + @result = nil + @open = Array.new + end + + + def tag_start(name, attributes) + @open.push PTag::mappings[name].new + end + + def text( contents ) + @open.last.text = contents if @open.last + end + + def tag_end(name) + last = @open.pop + if @open.empty? + @result = last.to_ruby + else + @open.last.children.push last + end + end + end + + class StreamParser + def initialize( plist_data_or_file, listener ) + if plist_data_or_file.respond_to? :read + @xml = plist_data_or_file.read + elsif File.exist? plist_data_or_file + @xml = File.read( plist_data_or_file ) + else + @xml = plist_data_or_file + end + + @listener = listener + end + + TEXT = /([^<]+)/ + XMLDECL_PATTERN = /<\?xml\s+(.*?)\?>*/m + DOCTYPE_PATTERN = /\s*)/m + COMMENT_START = /\A/m + + + def parse + plist_tags = PTag::mappings.keys.join('|') + start_tag = /<(#{plist_tags})([^>]*)>/i + end_tag = /<\/(#{plist_tags})[^>]*>/i + + require 'strscan' + + @scanner = StringScanner.new( @xml ) + until @scanner.eos? + if @scanner.scan(COMMENT_START) + @scanner.scan(COMMENT_END) + elsif @scanner.scan(XMLDECL_PATTERN) + encoding = parse_encoding_from_xml_declaration(@scanner[1]) + next if encoding.nil? + + # use the specified encoding for the rest of the file + next unless String.method_defined?(:force_encoding) + @scanner.string = @scanner.rest.force_encoding(encoding) + elsif @scanner.scan(DOCTYPE_PATTERN) + next + elsif @scanner.scan(start_tag) + @listener.tag_start(@scanner[1], nil) + if (@scanner[2] =~ /\/$/) + @listener.tag_end(@scanner[1]) + end + elsif @scanner.scan(TEXT) + @listener.text(@scanner[1]) + elsif @scanner.scan(end_tag) + @listener.tag_end(@scanner[1]) + else + raise "Unimplemented element" + end + end + end + + private + + def parse_encoding_from_xml_declaration(xml_declaration) + return unless defined?(Encoding) + + xml_encoding = xml_declaration.match(/(?:\A|\s)encoding=(?:"(.*?)"|'(.*?)')(?:\s|\Z)/) + + return if xml_encoding.nil? + + begin + Encoding.find(xml_encoding[1]) + rescue ArgumentError + nil + end + end + end + + class PTag + @@mappings = { } + def PTag::mappings + @@mappings + end + + def PTag::inherited( sub_class ) + key = sub_class.to_s.downcase + key.gsub!(/^plist::/, '' ) + key.gsub!(/^p/, '') unless key == "plist" + + @@mappings[key] = sub_class + end + + attr_accessor :text, :children + def initialize + @children = Array.new + end + + def to_ruby + raise "Unimplemented: " + self.class.to_s + "#to_ruby on #{self.inspect}" + end + end + + class PList < PTag + def to_ruby + children.first.to_ruby if children.first + end + end + + class PDict < PTag + def to_ruby + dict = Hash.new + key = nil + + children.each do |c| + if key.nil? + key = c.to_ruby + else + dict[key] = c.to_ruby + key = nil + end + end + + dict + end + end + + class PKey < PTag + def to_ruby + CGI::unescapeHTML(text || '') + end + end + + class PString < PTag + def to_ruby + CGI::unescapeHTML(text || '') + end + end + + class PArray < PTag + def to_ruby + children.collect do |c| + c.to_ruby + end + end + end + + class PInteger < PTag + def to_ruby + text.to_i + end + end + + class PTrue < PTag + def to_ruby + true + end + end + + class PFalse < PTag + def to_ruby + false + end + end + + class PReal < PTag + def to_ruby + text.to_f + end + end + + require 'date' + class PDate < PTag + def to_ruby + DateTime.parse(text) + end + end + + require 'base64' + class PData < PTag + def to_ruby + data = Base64.decode64(text.gsub(/\s+/, '')) unless text.nil? + begin + return Marshal.load(data) + rescue Exception + io = StringIO.new + io.write data + io.rewind + return io + end + end + end +end diff --git a/Library/Homebrew/vendor/plist/plist/version.rb b/Library/Homebrew/vendor/plist/plist/version.rb new file mode 100755 index 000000000..80b1f73dd --- /dev/null +++ b/Library/Homebrew/vendor/plist/plist/version.rb @@ -0,0 +1,5 @@ +# encoding: utf-8 + +module Plist + VERSION = '3.3.0'.freeze +end diff --git a/Library/Homebrew/vendor/ruby/2.0.0/gems/plist-3.3.0/LICENSE.txt b/Library/Homebrew/vendor/ruby/2.0.0/gems/plist-3.3.0/LICENSE.txt deleted file mode 100644 index 0ccffe7bf..000000000 --- a/Library/Homebrew/vendor/ruby/2.0.0/gems/plist-3.3.0/LICENSE.txt +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2006-2010, Ben Bleything and Patrick May - -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. diff --git a/Library/Homebrew/vendor/ruby/2.0.0/gems/plist-3.3.0/lib/plist.rb b/Library/Homebrew/vendor/ruby/2.0.0/gems/plist-3.3.0/lib/plist.rb deleted file mode 100644 index 986dad461..000000000 --- a/Library/Homebrew/vendor/ruby/2.0.0/gems/plist-3.3.0/lib/plist.rb +++ /dev/null @@ -1,21 +0,0 @@ -# encoding: utf-8 - -# = plist -# -# This is the main file for plist. Everything interesting happens in -# Plist and Plist::Emit. -# -# Copyright 2006-2010 Ben Bleything and Patrick May -# Distributed under the MIT License -# - -require 'base64' -require 'cgi' -require 'stringio' - -require 'plist/generator' -require 'plist/parser' -require 'plist/version' - -module Plist -end diff --git a/Library/Homebrew/vendor/ruby/2.0.0/gems/plist-3.3.0/lib/plist/generator.rb b/Library/Homebrew/vendor/ruby/2.0.0/gems/plist-3.3.0/lib/plist/generator.rb deleted file mode 100644 index 84bef3aaf..000000000 --- a/Library/Homebrew/vendor/ruby/2.0.0/gems/plist-3.3.0/lib/plist/generator.rb +++ /dev/null @@ -1,222 +0,0 @@ -# encoding: utf-8 - -# = plist -# -# Copyright 2006-2010 Ben Bleything and Patrick May -# Distributed under the MIT License -# - -module Plist; end - -# === Create a plist -# You can dump an object to a plist in one of two ways: -# -# * Plist::Emit.dump(obj) -# * obj.to_plist -# * This requires that you mixin the Plist::Emit module, which is already done for +Array+ and +Hash+. -# -# The following Ruby classes are converted into native plist types: -# Array, Bignum, Date, DateTime, Fixnum, Float, Hash, Integer, String, Symbol, Time, true, false -# * +Array+ and +Hash+ are both recursive; their elements will be converted into plist nodes inside the and containers (respectively). -# * +IO+ (and its descendants) and +StringIO+ objects are read from and their contents placed in a element. -# * User classes may implement +to_plist_node+ to dictate how they should be serialized; otherwise the object will be passed to Marshal.dump and the result placed in a element. -# -# For detailed usage instructions, refer to USAGE[link:files/docs/USAGE.html] and the methods documented below. -module Plist::Emit - # Helper method for injecting into classes. Calls Plist::Emit.dump with +self+. - def to_plist(envelope = true) - return Plist::Emit.dump(self, envelope) - end - - # Helper method for injecting into classes. Calls Plist::Emit.save_plist with +self+. - def save_plist(filename) - Plist::Emit.save_plist(self, filename) - end - - # The following Ruby classes are converted into native plist types: - # Array, Bignum, Date, DateTime, Fixnum, Float, Hash, Integer, String, Symbol, Time - # - # Write us (via RubyForge) if you think another class can be coerced safely into one of the expected plist classes. - # - # +IO+ and +StringIO+ objects are encoded and placed in elements; other objects are Marshal.dump'ed unless they implement +to_plist_node+. - # - # The +envelope+ parameters dictates whether or not the resultant plist fragment is wrapped in the normal XML/plist header and footer. Set it to false if you only want the fragment. - def self.dump(obj, envelope = true) - output = plist_node(obj) - - output = wrap(output) if envelope - - return output - end - - # Writes the serialized object's plist to the specified filename. - def self.save_plist(obj, filename) - File.open(filename, 'wb') do |f| - f.write(obj.to_plist) - end - end - - private - def self.plist_node(element) - output = '' - - if element.respond_to? :to_plist_node - output << element.to_plist_node - else - case element - when Array - if element.empty? - output << "\n" - else - output << tag('array') { - element.collect {|e| plist_node(e)} - } - end - when Hash - if element.empty? - output << "\n" - else - inner_tags = [] - - element.keys.sort_by{|k| k.to_s }.each do |k| - v = element[k] - inner_tags << tag('key', CGI::escapeHTML(k.to_s)) - inner_tags << plist_node(v) - end - - output << tag('dict') { - inner_tags - } - end - when true, false - output << "<#{element}/>\n" - when Time - output << tag('date', element.utc.strftime('%Y-%m-%dT%H:%M:%SZ')) - when Date # also catches DateTime - output << tag('date', element.strftime('%Y-%m-%dT%H:%M:%SZ')) - when String, Symbol, Integer, Float - output << tag(element_type(element), CGI::escapeHTML(element.to_s)) - when IO, StringIO - element.rewind - contents = element.read - # note that apple plists are wrapped at a different length then - # what ruby's base64 wraps by default. - # I used #encode64 instead of #b64encode (which allows a length arg) - # because b64encode is b0rked and ignores the length arg. - data = "\n" - Base64::encode64(contents).gsub(/\s+/, '').scan(/.{1,68}/o) { data << $& << "\n" } - output << tag('data', data) - else - output << comment( 'The element below contains a Ruby object which has been serialized with Marshal.dump.' ) - data = "\n" - Base64::encode64(Marshal.dump(element)).gsub(/\s+/, '').scan(/.{1,68}/o) { data << $& << "\n" } - output << tag('data', data ) - end - end - - return output - end - - def self.comment(content) - return "\n" - end - - def self.tag(type, contents = '', &block) - out = nil - - if block_given? - out = IndentedString.new - out << "<#{type}>" - out.raise_indent - - out << block.call - - out.lower_indent - out << "" - else - out = "<#{type}>#{contents.to_s}\n" - end - - return out.to_s - end - - def self.wrap(contents) - output = '' - - output << '' + "\n" - output << '' + "\n" - output << '' + "\n" - - output << contents - - output << '' + "\n" - - return output - end - - def self.element_type(item) - case item - when String, Symbol - 'string' - - when Integer - 'integer' - - when Float - 'real' - - else - raise "Don't know about this data type... something must be wrong!" - end - end - private - class IndentedString #:nodoc: - attr_accessor :indent_string - - def initialize(str = "\t") - @indent_string = str - @contents = '' - @indent_level = 0 - end - - def to_s - return @contents - end - - def raise_indent - @indent_level += 1 - end - - def lower_indent - @indent_level -= 1 if @indent_level > 0 - end - - def <<(val) - if val.is_a? Array - val.each do |f| - self << f - end - else - # if it's already indented, don't bother indenting further - unless val =~ /\A#{@indent_string}/ - indent = @indent_string * @indent_level - - @contents << val.gsub(/^/, indent) - else - @contents << val - end - - # it already has a newline, don't add another - @contents << "\n" unless val =~ /\n$/ - end - end - end -end - -class Array #:nodoc: - include Plist::Emit -end - -class Hash #:nodoc: - include Plist::Emit -end diff --git a/Library/Homebrew/vendor/ruby/2.0.0/gems/plist-3.3.0/lib/plist/parser.rb b/Library/Homebrew/vendor/ruby/2.0.0/gems/plist-3.3.0/lib/plist/parser.rb deleted file mode 100755 index 4de13f881..000000000 --- a/Library/Homebrew/vendor/ruby/2.0.0/gems/plist-3.3.0/lib/plist/parser.rb +++ /dev/null @@ -1,247 +0,0 @@ -# encoding: utf-8 - -# = plist -# -# Copyright 2006-2010 Ben Bleything and Patrick May -# Distributed under the MIT License -# - -# Plist parses Mac OS X xml property list files into ruby data structures. -# -# === Load a plist file -# This is the main point of the library: -# -# r = Plist::parse_xml( filename_or_xml ) -module Plist -# Note that I don't use these two elements much: -# -# + Date elements are returned as DateTime objects. -# + Data elements are implemented as Tempfiles -# -# Plist::parse_xml will blow up if it encounters a Date element. -# If you encounter such an error, or if you have a Date element which -# can't be parsed into a Time object, please send your plist file to -# plist@hexane.org so that I can implement the proper support. - def Plist::parse_xml( filename_or_xml ) - listener = Listener.new - #parser = REXML::Parsers::StreamParser.new(File.new(filename), listener) - parser = StreamParser.new(filename_or_xml, listener) - parser.parse - listener.result - end - - class Listener - #include REXML::StreamListener - - attr_accessor :result, :open - - def initialize - @result = nil - @open = Array.new - end - - - def tag_start(name, attributes) - @open.push PTag::mappings[name].new - end - - def text( contents ) - @open.last.text = contents if @open.last - end - - def tag_end(name) - last = @open.pop - if @open.empty? - @result = last.to_ruby - else - @open.last.children.push last - end - end - end - - class StreamParser - def initialize( plist_data_or_file, listener ) - if plist_data_or_file.respond_to? :read - @xml = plist_data_or_file.read - elsif File.exist? plist_data_or_file - @xml = File.read( plist_data_or_file ) - else - @xml = plist_data_or_file - end - - @listener = listener - end - - TEXT = /([^<]+)/ - XMLDECL_PATTERN = /<\?xml\s+(.*?)\?>*/m - DOCTYPE_PATTERN = /\s*)/m - COMMENT_START = /\A/m - - - def parse - plist_tags = PTag::mappings.keys.join('|') - start_tag = /<(#{plist_tags})([^>]*)>/i - end_tag = /<\/(#{plist_tags})[^>]*>/i - - require 'strscan' - - @scanner = StringScanner.new( @xml ) - until @scanner.eos? - if @scanner.scan(COMMENT_START) - @scanner.scan(COMMENT_END) - elsif @scanner.scan(XMLDECL_PATTERN) - encoding = parse_encoding_from_xml_declaration(@scanner[1]) - next if encoding.nil? - - # use the specified encoding for the rest of the file - next unless String.method_defined?(:force_encoding) - @scanner.string = @scanner.rest.force_encoding(encoding) - elsif @scanner.scan(DOCTYPE_PATTERN) - next - elsif @scanner.scan(start_tag) - @listener.tag_start(@scanner[1], nil) - if (@scanner[2] =~ /\/$/) - @listener.tag_end(@scanner[1]) - end - elsif @scanner.scan(TEXT) - @listener.text(@scanner[1]) - elsif @scanner.scan(end_tag) - @listener.tag_end(@scanner[1]) - else - raise "Unimplemented element" - end - end - end - - private - - def parse_encoding_from_xml_declaration(xml_declaration) - return unless defined?(Encoding) - - xml_encoding = xml_declaration.match(/(?:\A|\s)encoding=(?:"(.*?)"|'(.*?)')(?:\s|\Z)/) - - return if xml_encoding.nil? - - begin - Encoding.find(xml_encoding[1]) - rescue ArgumentError - nil - end - end - end - - class PTag - @@mappings = { } - def PTag::mappings - @@mappings - end - - def PTag::inherited( sub_class ) - key = sub_class.to_s.downcase - key.gsub!(/^plist::/, '' ) - key.gsub!(/^p/, '') unless key == "plist" - - @@mappings[key] = sub_class - end - - attr_accessor :text, :children - def initialize - @children = Array.new - end - - def to_ruby - raise "Unimplemented: " + self.class.to_s + "#to_ruby on #{self.inspect}" - end - end - - class PList < PTag - def to_ruby - children.first.to_ruby if children.first - end - end - - class PDict < PTag - def to_ruby - dict = Hash.new - key = nil - - children.each do |c| - if key.nil? - key = c.to_ruby - else - dict[key] = c.to_ruby - key = nil - end - end - - dict - end - end - - class PKey < PTag - def to_ruby - CGI::unescapeHTML(text || '') - end - end - - class PString < PTag - def to_ruby - CGI::unescapeHTML(text || '') - end - end - - class PArray < PTag - def to_ruby - children.collect do |c| - c.to_ruby - end - end - end - - class PInteger < PTag - def to_ruby - text.to_i - end - end - - class PTrue < PTag - def to_ruby - true - end - end - - class PFalse < PTag - def to_ruby - false - end - end - - class PReal < PTag - def to_ruby - text.to_f - end - end - - require 'date' - class PDate < PTag - def to_ruby - DateTime.parse(text) - end - end - - require 'base64' - class PData < PTag - def to_ruby - data = Base64.decode64(text.gsub(/\s+/, '')) unless text.nil? - begin - return Marshal.load(data) - rescue Exception - io = StringIO.new - io.write data - io.rewind - return io - end - end - end -end diff --git a/Library/Homebrew/vendor/ruby/2.0.0/gems/plist-3.3.0/lib/plist/version.rb b/Library/Homebrew/vendor/ruby/2.0.0/gems/plist-3.3.0/lib/plist/version.rb deleted file mode 100644 index 80b1f73dd..000000000 --- a/Library/Homebrew/vendor/ruby/2.0.0/gems/plist-3.3.0/lib/plist/version.rb +++ /dev/null @@ -1,5 +0,0 @@ -# encoding: utf-8 - -module Plist - VERSION = '3.3.0'.freeze -end diff --git a/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/LICENSE b/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/LICENSE deleted file mode 100644 index d68fe0fbd..000000000 --- a/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015, 2016 William Woodruff - -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. diff --git a/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho.rb b/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho.rb deleted file mode 100644 index b7f20ea19..000000000 --- a/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho.rb +++ /dev/null @@ -1,40 +0,0 @@ -require "#{File.dirname(__FILE__)}/macho/structure" -require "#{File.dirname(__FILE__)}/macho/view" -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/exceptions" -require "#{File.dirname(__FILE__)}/macho/utils" -require "#{File.dirname(__FILE__)}/macho/tools" - -# The primary namespace for ruby-macho. -module MachO - # release version - 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 diff --git a/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho/exceptions.rb b/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho/exceptions.rb deleted file mode 100644 index 14c2c22ae..000000000 --- a/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho/exceptions.rb +++ /dev/null @@ -1,197 +0,0 @@ -module MachO - # A generic Mach-O error in execution. - class MachOError < RuntimeError - end - - # Raised when a Mach-O file modification fails. - class ModificationError < MachOError - end - - # Raised when a Mach-O file modification fails but can be recovered when - # operating on multiple Mach-O slices of a fat binary in non-strict mode. - class RecoverableModificationError < ModificationError - # @return [Fixnum, nil] The index of the Mach-O slice of a fat binary for - # which modification failed or `nil` if not a fat binary. This is used to - # make the error message more useful. - attr_accessor :macho_slice - - # @return [String] The exception message. - def to_s - s = super.to_s - s = "While modifying Mach-O slice #{@macho_slice}: #{s}" if @macho_slice - s - end - end - - # Raised when a file is not a Mach-O. - class NotAMachOError < MachOError - # @param error [String] the error in question - def initialize(error) - super error - end - end - - # Raised when a file is too short to be a valid Mach-O file. - class TruncatedFileError < NotAMachOError - def initialize - super "File is too short to be a valid Mach-O" - end - end - - # Raised when a file's magic bytes are not valid Mach-O magic. - class MagicError < NotAMachOError - # @param num [Fixnum] the unknown number - def initialize(num) - super "Unrecognized Mach-O magic: 0x#{"%02x" % num}" - end - end - - # Raised when a file is a Java classfile instead of a fat Mach-O. - class JavaClassFileError < NotAMachOError - def initialize - super "File is a Java class file" - 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 cputype [Fixnum] the unknown CPU type - def initialize(cputype) - super "Unrecognized CPU type: 0x#{"%08x" % cputype}" - end - end - - # Raised when the CPU type/sub-type pair is unknown. - class CPUSubtypeError < MachOError - # @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})" - 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 a load command can't be created manually. - class LoadCommandNotCreatableError < MachOError - # @param cmd_sym [Symbol] the uncreatable load command's symbol - def initialize(cmd_sym) - super "Load commands of type #{cmd_sym} cannot be created manually" - end - end - - # Raised when the number of arguments used to create a load command manually - # is wrong. - class LoadCommandCreationArityError < MachOError - # @param cmd_sym [Symbol] the load command's symbol - # @param expected_arity [Fixnum] the number of arguments expected - # @param actual_arity [Fixnum] the number of arguments received - def initialize(cmd_sym, expected_arity, actual_arity) - super "Expected #{expected_arity} arguments for #{cmd_sym} creation," \ - " got #{actual_arity}" - end - end - - # Raised when a load command can't be serialized. - class LoadCommandNotSerializableError < MachOError - # @param cmd_sym [Symbol] the load command's symbol - def initialize(cmd_sym) - super "Load commands of type #{cmd_sym} cannot be serialized" - end - end - - # Raised when a load command string is malformed in some way. - class LCStrMalformedError < MachOError - # @param lc [MachO::LoadCommand] the load command containing the string - def initialize(lc) - super "Load command #{lc.type} at offset #{lc.view.offset} contains a" \ - " malformed string" - end - end - - # Raised when a change at an offset is not valid. - class OffsetInsertionError < ModificationError - # @param offset [Fixnum] the invalid offset - def initialize(offset) - super "Insertion at offset #{offset} is not valid" - end - end - - # Raised when load commands are too large to fit in the current file. - class HeaderPadError < ModificationError - # @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 < RecoverableModificationError - # @param dylib [String] the unknown shared library name - def initialize(dylib) - super "No such dylib name: #{dylib}" - end - end - - # Raised when a dylib is missing an ID - class DylibIdMissingError < RecoverableModificationError - def initialize - super "Dylib is missing a dylib ID" - end - end - - # Raised when attempting to change an rpath that doesn't exist. - class RpathUnknownError < RecoverableModificationError - # @param path [String] the unknown runtime path - def initialize(path) - super "No such runtime path: #{path}" - end - end - - # Raised when attempting to add an rpath that already exists. - class RpathExistsError < RecoverableModificationError - # @param path [String] the extant path - def initialize(path) - super "#{path} already exists" - end - end - - # Raised whenever unfinished code is called. - class UnimplementedError < MachOError - # @param thing [String] the thing that is unimplemented - def initialize(thing) - super "Unimplemented: #{thing}" - end - end -end diff --git a/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho/fat_file.rb b/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho/fat_file.rb deleted file mode 100644 index 351be5ac6..000000000 --- a/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho/fat_file.rb +++ /dev/null @@ -1,377 +0,0 @@ -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 MachOFile - class FatFile - extend Forwardable - - # @return [String] the filename loaded from, or nil if loaded from a binary string - attr_accessor :filename - - # @return [Headers::FatHeader] the file's header - attr_reader :header - - # @return [Array] an array of fat architectures - attr_reader :fat_archs - - # @return [Array] an array of Mach-O binaries - attr_reader :machos - - # Creates a new FatFile from the given (single-arch) Mach-Os - # @param machos [Array] 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 [FatFile] a new FatFile - 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 fat file to load from - # @raise [ArgumentError] if the given file does not exist - def initialize(filename) - raise ArgumentError, "#{filename}: no such file" unless File.file?(filename) - - @filename = filename - @raw_data = File.open(@filename, "rb", &:read) - populate_fields - end - - # Initializes a new FatFile instance from a binary string. - # @see new_from_bin - # @api private - def initialize_from_bin(bin) - @filename = nil - @raw_data = bin - populate_fields - end - - # The file's raw fat data. - # @return [String] the raw fat data - def serialize - @raw_data - 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 - - # @!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 - Headers::MH_MAGICS[magic] - end - - # Populate the instance's fields with the raw Fat Mach-O data. - # @return [void] - # @note This method is public, but should (almost) never need to be called. - def populate_fields - @header = populate_fat_header - @fat_archs = populate_fat_archs - @machos = populate_machos - end - - # All load commands responsible for loading dylibs in the file's Mach-O's. - # @return [Array] an array of DylibCommands - def dylib_load_commands - machos.map(&:dylib_load_commands).flatten - end - - # 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 - # @param options [Hash] - # @option options [Boolean] :strict (true) if true, fail if one slice fails. - # if false, fail only if all slices fail. - # @return [void] - # @raise [ArgumentError] if `new_id` is not a String - # @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?) - - each_macho(options) do |macho| - macho.change_dylib_id(new_id, options) - end - - repopulate_raw_machos - end - - alias dylib_id= change_dylib_id - - # All shared libraries linked to the file's Mach-Os. - # @return [Array] an array of all shared libraries - # @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. - # the union of all libraries used by all architectures. - 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. - # @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 - # @param options [Hash] - # @option options [Boolean] :strict (true) if true, fail if one slice fails. - # if false, fail only if all slices fail. - # @return [void] - # @see MachOFile#change_install_name - def change_install_name(old_name, new_name, options = {}) - each_macho(options) do |macho| - macho.change_install_name(old_name, new_name, options) - end - - repopulate_raw_machos - end - - alias change_dylib change_install_name - - # All runtime paths associated with the file's Mach-Os. - # @return [Array] an array of all runtime paths - # @see MachOFile#rpaths - def rpaths - # Can individual architectures have different runtime paths? - machos.map(&:rpaths).flatten.uniq - end - - # Change the runtime path `old_path` to `new_path` in the file's Mach-Os. - # @param old_path [String] the old runtime path - # @param new_path [String] the new runtime path - # @param options [Hash] - # @option options [Boolean] :strict (true) if true, fail if one slice fails. - # if false, fail only if all slices fail. - # @return [void] - # @see MachOFile#change_rpath - def change_rpath(old_path, new_path, options = {}) - each_macho(options) do |macho| - macho.change_rpath(old_path, new_path, options) - end - - repopulate_raw_machos - end - - # Add the given runtime path to the file's Mach-Os. - # @param path [String] the new runtime path - # @param options [Hash] - # @option options [Boolean] :strict (true) if true, fail if one slice fails. - # if false, fail only if all slices fail. - # @return [void] - # @see MachOFile#add_rpath - def add_rpath(path, options = {}) - each_macho(options) do |macho| - macho.add_rpath(path, options) - end - - repopulate_raw_machos - end - - # Delete the given runtime path from the file's Mach-Os. - # @param path [String] the runtime path to delete - # @param options [Hash] - # @option options [Boolean] :strict (true) if true, fail if one slice fails. - # if false, fail only if all slices fail. - # @return void - # @see MachOFile#delete_rpath - def delete_rpath(path, options = {}) - each_macho(options) do |macho| - macho.delete_rpath(path, options) - end - - repopulate_raw_machos - end - - # Extract a Mach-O with the given CPU type from the file. - # @example - # file.extract(:i386) # => MachO::MachOFile - # @param cputype [Symbol] the CPU type of the Mach-O being extracted - # @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 [MachOError] if the instance was initialized without a file - # @note Overwrites all data in the file! - def write! - if filename.nil? - raise MachOError, "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 - - # Obtain the fat header from raw file data. - # @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 = 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) - - # Rationale: Java classfiles have the same magic as big-endian fat - # Mach-Os. Classfiles encode their version at the same offset as - # `nfat_arch` and the lowest version number is 43, so we error out - # if a file claims to have over 30 internal architectures. It's - # technically possible for a fat Mach-O to have over 30 architectures, - # but this is extremely unlikely and in practice distinguishes the two - # formats. - raise JavaClassFileError if fh.nfat_arch > 30 - - fh - end - - # Obtain an array of fat architectures from raw file data. - # @return [Array] an array of fat architectures - # @api private - def populate_fat_archs - archs = [] - - fa_off = Headers::FatHeader.bytesize - fa_len = Headers::FatArch.bytesize - header.nfat_arch.times do |i| - 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] an array of Mach-Os - # @api private - def populate_machos - machos = [] - - fat_archs.each do |arch| - machos << MachOFile.new_from_bin(@raw_data[arch.offset, arch.size]) - end - - machos - end - - # Repopulate the raw Mach-O data with each internal Mach-O object. - # @return [void] - # @api private - def repopulate_raw_machos - machos.each_with_index do |macho, i| - arch = fat_archs[i] - - @raw_data[arch.offset, arch.size] = macho.serialize - end - end - - # Yield each Mach-O object in the file, rescuing and accumulating errors. - # @param options [Hash] - # @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 [RecoverableModificationError] under the conditions of - # the `:strict` option above. - # @api private - def each_macho(options = {}) - strict = options.fetch(:strict, true) - errors = [] - - machos.each_with_index do |macho, index| - begin - yield macho - rescue RecoverableModificationError => error - error.macho_slice = index - - # Strict mode: Immediately re-raise. Otherwise: Retain, check later. - raise error if strict - errors << error - end - end - - # Non-strict mode: Raise first error if *all* Mach-O slices failed. - raise errors.first if errors.size == machos.size - end - - # 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 diff --git a/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho/headers.rb b/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho/headers.rb deleted file mode 100644 index 08a4b80c4..000000000 --- a/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho/headers.rb +++ /dev/null @@ -1,665 +0,0 @@ -module MachO - # Classes and constants for parsing the headers of Mach-O binaries. - module Headers - # big-endian fat magic - # @api private - FAT_MAGIC = 0xcafebabe - - # little-endian fat magic - # this is defined, but should never appear in ruby-macho code because - # fat headers are always big-endian and therefore always unpacked as such. - # @api private - FAT_CIGAM = 0xbebafeca - - # 32-bit big-endian magic - # @api private - MH_MAGIC = 0xfeedface - - # 32-bit little-endian magic - # @api private - MH_CIGAM = 0xcefaedfe - - # 64-bit big-endian magic - # @api private - MH_MAGIC_64 = 0xfeedfacf - - # 64-bit little-endian magic - # @api private - MH_CIGAM_64 = 0xcffaedfe - - # association of magic numbers to string representations - # @api private - MH_MAGICS = { - FAT_MAGIC => "FAT_MAGIC", - MH_MAGIC => "MH_MAGIC", - MH_CIGAM => "MH_CIGAM", - MH_MAGIC_64 => "MH_MAGIC_64", - MH_CIGAM_64 => "MH_CIGAM_64", - }.freeze - - # mask for CPUs with 64-bit architectures (when running a 64-bit ABI?) - # @api private - CPU_ARCH_ABI64 = 0x01000000 - - # any CPU (unused?) - # @api private - CPU_TYPE_ANY = -1 - - # m68k compatible CPUs - # @api private - CPU_TYPE_MC680X0 = 0x06 - - # i386 and later compatible CPUs - # @api private - CPU_TYPE_I386 = 0x07 - - # x86_64 (AMD64) compatible CPUs - # @api private - CPU_TYPE_X86_64 = (CPU_TYPE_I386 | CPU_ARCH_ABI64) - - # 32-bit ARM compatible CPUs - # @api private - CPU_TYPE_ARM = 0x0c - - # m88k compatible CPUs - # @api private - CPU_TYPE_MC88000 = 0xd - - # 64-bit ARM compatible CPUs - # @api private - CPU_TYPE_ARM64 = (CPU_TYPE_ARM | CPU_ARCH_ABI64) - - # PowerPC compatible CPUs - # @api private - CPU_TYPE_POWERPC = 0x12 - - # PowerPC64 compatible CPUs - # @api private - CPU_TYPE_POWERPC64 = (CPU_TYPE_POWERPC | CPU_ARCH_ABI64) - - # association of cpu types to symbol representations - # @api private - CPU_TYPES = { - CPU_TYPE_ANY => :any, - CPU_TYPE_I386 => :i386, - CPU_TYPE_X86_64 => :x86_64, - CPU_TYPE_ARM => :arm, - CPU_TYPE_ARM64 => :arm64, - CPU_TYPE_POWERPC => :ppc, - CPU_TYPE_POWERPC64 => :ppc64, - }.freeze - - # mask for CPU subtype capabilities - # @api private - CPU_SUBTYPE_MASK = 0xff000000 - - # 64-bit libraries (undocumented!) - # @see http://llvm.org/docs/doxygen/html/Support_2MachO_8h_source.html - # @api private - CPU_SUBTYPE_LIB64 = 0x80000000 - - # the lowest common sub-type for `CPU_TYPE_I386` - # @api private - CPU_SUBTYPE_I386 = 3 - - # the i486 sub-type for `CPU_TYPE_I386` - # @api private - CPU_SUBTYPE_486 = 4 - - # the i486SX sub-type for `CPU_TYPE_I386` - # @api private - CPU_SUBTYPE_486SX = 132 - - # the i586 (P5, Pentium) sub-type for `CPU_TYPE_I386` - # @api private - CPU_SUBTYPE_586 = 5 - - # @see CPU_SUBTYPE_586 - # @api private - CPU_SUBTYPE_PENT = CPU_SUBTYPE_586 - - # the Pentium Pro (P6) sub-type for `CPU_TYPE_I386` - # @api private - CPU_SUBTYPE_PENTPRO = 22 - - # the Pentium II (P6, M3?) sub-type for `CPU_TYPE_I386` - # @api private - CPU_SUBTYPE_PENTII_M3 = 54 - - # the Pentium II (P6, M5?) sub-type for `CPU_TYPE_I386` - # @api private - CPU_SUBTYPE_PENTII_M5 = 86 - - # the Pentium 4 (Netburst) sub-type for `CPU_TYPE_I386` - # @api private - CPU_SUBTYPE_PENTIUM_4 = 10 - - # the lowest common sub-type for `CPU_TYPE_MC680X0` - # @api private - CPU_SUBTYPE_MC680X0_ALL = 1 - - # @see CPU_SUBTYPE_MC680X0_ALL - # @api private - CPU_SUBTYPE_MC68030 = CPU_SUBTYPE_MC680X0_ALL - - # the 040 subtype for `CPU_TYPE_MC680X0` - # @api private - CPU_SUBTYPE_MC68040 = 2 - - # the 030 subtype for `CPU_TYPE_MC680X0` - # @api private - CPU_SUBTYPE_MC68030_ONLY = 3 - - # the lowest common sub-type for `CPU_TYPE_X86_64` - # @api private - CPU_SUBTYPE_X86_64_ALL = CPU_SUBTYPE_I386 - - # the Haskell sub-type for `CPU_TYPE_X86_64` - # @api private - CPU_SUBTYPE_X86_64_H = 8 - - # the lowest common sub-type for `CPU_TYPE_ARM` - # @api private - CPU_SUBTYPE_ARM_ALL = 0 - - # the v4t sub-type for `CPU_TYPE_ARM` - # @api private - CPU_SUBTYPE_ARM_V4T = 5 - - # the v6 sub-type for `CPU_TYPE_ARM` - # @api private - CPU_SUBTYPE_ARM_V6 = 6 - - # the v5 sub-type for `CPU_TYPE_ARM` - # @api private - CPU_SUBTYPE_ARM_V5TEJ = 7 - - # the xscale (v5 family) sub-type for `CPU_TYPE_ARM` - # @api private - CPU_SUBTYPE_ARM_XSCALE = 8 - - # the v7 sub-type for `CPU_TYPE_ARM` - # @api private - CPU_SUBTYPE_ARM_V7 = 9 - - # the v7f (Cortex A9) sub-type for `CPU_TYPE_ARM` - # @api private - CPU_SUBTYPE_ARM_V7F = 10 - - # the v7s ("Swift") sub-type for `CPU_TYPE_ARM` - # @api private - CPU_SUBTYPE_ARM_V7S = 11 - - # the v7k ("Kirkwood40") sub-type for `CPU_TYPE_ARM` - # @api private - CPU_SUBTYPE_ARM_V7K = 12 - - # the v6m sub-type for `CPU_TYPE_ARM` - # @api private - CPU_SUBTYPE_ARM_V6M = 14 - - # the v7m sub-type for `CPU_TYPE_ARM` - # @api private - CPU_SUBTYPE_ARM_V7M = 15 - - # the v7em sub-type for `CPU_TYPE_ARM` - # @api private - CPU_SUBTYPE_ARM_V7EM = 16 - - # the v8 sub-type for `CPU_TYPE_ARM` - # @api private - CPU_SUBTYPE_ARM_V8 = 13 - - # the lowest common sub-type for `CPU_TYPE_ARM64` - # @api private - CPU_SUBTYPE_ARM64_ALL = 0 - - # the v8 sub-type for `CPU_TYPE_ARM64` - # @api private - CPU_SUBTYPE_ARM64_V8 = 1 - - # the lowest common sub-type for `CPU_TYPE_MC88000` - # @api private - CPU_SUBTYPE_MC88000_ALL = 0 - - # @see CPU_SUBTYPE_MC88000_ALL - # @api private - CPU_SUBTYPE_MMAX_JPC = CPU_SUBTYPE_MC88000_ALL - - # the 100 sub-type for `CPU_TYPE_MC88000` - # @api private - CPU_SUBTYPE_MC88100 = 1 - - # the 110 sub-type for `CPU_TYPE_MC88000` - # @api private - CPU_SUBTYPE_MC88110 = 2 - - # the lowest common sub-type for `CPU_TYPE_POWERPC` - # @api private - CPU_SUBTYPE_POWERPC_ALL = 0 - - # the 601 sub-type for `CPU_TYPE_POWERPC` - # @api private - CPU_SUBTYPE_POWERPC_601 = 1 - - # the 602 sub-type for `CPU_TYPE_POWERPC` - # @api private - CPU_SUBTYPE_POWERPC_602 = 2 - - # the 603 sub-type for `CPU_TYPE_POWERPC` - # @api private - CPU_SUBTYPE_POWERPC_603 = 3 - - # the 603e (G2) sub-type for `CPU_TYPE_POWERPC` - # @api private - CPU_SUBTYPE_POWERPC_603E = 4 - - # the 603ev sub-type for `CPU_TYPE_POWERPC` - # @api private - CPU_SUBTYPE_POWERPC_603EV = 5 - - # the 604 sub-type for `CPU_TYPE_POWERPC` - # @api private - CPU_SUBTYPE_POWERPC_604 = 6 - - # the 604e sub-type for `CPU_TYPE_POWERPC` - # @api private - CPU_SUBTYPE_POWERPC_604E = 7 - - # the 620 sub-type for `CPU_TYPE_POWERPC` - # @api private - CPU_SUBTYPE_POWERPC_620 = 8 - - # the 750 (G3) sub-type for `CPU_TYPE_POWERPC` - # @api private - CPU_SUBTYPE_POWERPC_750 = 9 - - # the 7400 (G4) sub-type for `CPU_TYPE_POWERPC` - # @api private - CPU_SUBTYPE_POWERPC_7400 = 10 - - # the 7450 (G4 "Voyager") sub-type for `CPU_TYPE_POWERPC` - # @api private - CPU_SUBTYPE_POWERPC_7450 = 11 - - # the 970 (G5) sub-type for `CPU_TYPE_POWERPC` - # @api private - CPU_SUBTYPE_POWERPC_970 = 100 - - # any CPU sub-type for CPU type `CPU_TYPE_POWERPC64` - # @api private - CPU_SUBTYPE_POWERPC64_ALL = CPU_SUBTYPE_POWERPC_ALL - - # association of CPU types/subtype pairs to symbol representations in - # (very) roughly descending order of commonness - # @see https://opensource.apple.com/source/cctools/cctools-877.8/libstuff/arch.c - # @api private - CPU_SUBTYPES = { - CPU_TYPE_I386 => { - CPU_SUBTYPE_I386 => :i386, - CPU_SUBTYPE_486 => :i486, - CPU_SUBTYPE_486SX => :i486SX, - CPU_SUBTYPE_586 => :i586, # also "pentium" in arch(3) - CPU_SUBTYPE_PENTPRO => :i686, # also "pentpro" in arch(3) - CPU_SUBTYPE_PENTII_M3 => :pentIIm3, - CPU_SUBTYPE_PENTII_M5 => :pentIIm5, - CPU_SUBTYPE_PENTIUM_4 => :pentium4, - }.freeze, - CPU_TYPE_X86_64 => { - CPU_SUBTYPE_X86_64_ALL => :x86_64, - CPU_SUBTYPE_X86_64_H => :x86_64h, - }.freeze, - CPU_TYPE_ARM => { - CPU_SUBTYPE_ARM_ALL => :arm, - CPU_SUBTYPE_ARM_V4T => :armv4t, - CPU_SUBTYPE_ARM_V6 => :armv6, - CPU_SUBTYPE_ARM_V5TEJ => :armv5, - CPU_SUBTYPE_ARM_XSCALE => :xscale, - CPU_SUBTYPE_ARM_V7 => :armv7, - CPU_SUBTYPE_ARM_V7F => :armv7f, - CPU_SUBTYPE_ARM_V7S => :armv7s, - CPU_SUBTYPE_ARM_V7K => :armv7k, - CPU_SUBTYPE_ARM_V6M => :armv6m, - CPU_SUBTYPE_ARM_V7M => :armv7m, - CPU_SUBTYPE_ARM_V7EM => :armv7em, - CPU_SUBTYPE_ARM_V8 => :armv8, - }.freeze, - CPU_TYPE_ARM64 => { - CPU_SUBTYPE_ARM64_ALL => :arm64, - CPU_SUBTYPE_ARM64_V8 => :arm64v8, - }.freeze, - CPU_TYPE_POWERPC => { - CPU_SUBTYPE_POWERPC_ALL => :ppc, - CPU_SUBTYPE_POWERPC_601 => :ppc601, - CPU_SUBTYPE_POWERPC_603 => :ppc603, - CPU_SUBTYPE_POWERPC_603E => :ppc603e, - CPU_SUBTYPE_POWERPC_603EV => :ppc603ev, - CPU_SUBTYPE_POWERPC_604 => :ppc604, - CPU_SUBTYPE_POWERPC_604E => :ppc604e, - CPU_SUBTYPE_POWERPC_750 => :ppc750, - CPU_SUBTYPE_POWERPC_7400 => :ppc7400, - CPU_SUBTYPE_POWERPC_7450 => :ppc7450, - CPU_SUBTYPE_POWERPC_970 => :ppc970, - }.freeze, - CPU_TYPE_POWERPC64 => { - CPU_SUBTYPE_POWERPC64_ALL => :ppc64, - # apparently the only exception to the naming scheme - CPU_SUBTYPE_POWERPC_970 => :ppc970_64, - }.freeze, - CPU_TYPE_MC680X0 => { - CPU_SUBTYPE_MC680X0_ALL => :m68k, - CPU_SUBTYPE_MC68030 => :mc68030, - CPU_SUBTYPE_MC68040 => :mc68040, - }, - CPU_TYPE_MC88000 => { - CPU_SUBTYPE_MC88000_ALL => :m88k, - }, - }.freeze - - # relocatable object file - # @api private - MH_OBJECT = 0x1 - - # demand paged executable file - # @api private - MH_EXECUTE = 0x2 - - # fixed VM shared library file - # @api private - MH_FVMLIB = 0x3 - - # core dump file - # @api private - MH_CORE = 0x4 - - # preloaded executable file - # @api private - MH_PRELOAD = 0x5 - - # dynamically bound shared library - # @api private - MH_DYLIB = 0x6 - - # dynamic link editor - # @api private - MH_DYLINKER = 0x7 - - # dynamically bound bundle file - # @api private - MH_BUNDLE = 0x8 - - # shared library stub for static linking only, no section contents - # @api private - MH_DYLIB_STUB = 0x9 - - # companion file with only debug sections - # @api private - MH_DSYM = 0xa - - # x86_64 kexts - # @api private - MH_KEXT_BUNDLE = 0xb - - # association of filetypes to Symbol representations - # @api private - MH_FILETYPES = { - MH_OBJECT => :object, - MH_EXECUTE => :execute, - MH_FVMLIB => :fvmlib, - MH_CORE => :core, - MH_PRELOAD => :preload, - MH_DYLIB => :dylib, - MH_DYLINKER => :dylinker, - MH_BUNDLE => :bundle, - MH_DYLIB_STUB => :dylib_stub, - MH_DSYM => :dsym, - MH_KEXT_BUNDLE => :kext_bundle, - }.freeze - - # 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, - }.freeze - - # 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 - - # always big-endian - # @see MachOStructure::FORMAT - # @api private - FORMAT = "N2".freeze - - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 8 - - # @api private - def initialize(magic, nfat_arch) - @magic = magic - @nfat_arch = nfat_arch - end - - # @return [String] the serialized fields of the fat header - def serialize - [magic, nfat_arch].pack(FORMAT) - 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::Headers::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 - - # always big-endian - # @see MachOStructure::FORMAT - # @api private - FORMAT = "N5".freeze - - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 20 - - # @api private - def initialize(cputype, cpusubtype, offset, size, align) - @cputype = cputype - @cpusubtype = cpusubtype - @offset = offset - @size = size - @align = align - end - - # @return [String] the serialized fields of the fat arch - def serialize - [cputype, cpusubtype, offset, size, align].pack(FORMAT) - 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 - - # @see MachOStructure::FORMAT - # @api private - FORMAT = "L=7".freeze - - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 28 - - # @api private - def initialize(magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds, - flags) - @magic = magic - @cputype = cputype - # For now we're not interested in additional capability bits also to be - # found in the `cpusubtype` field. We only care about the CPU sub-type. - @cpusubtype = cpusubtype & ~CPU_SUBTYPE_MASK - @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 - - # @return [Boolean] whether or not the file is of type `MH_OBJECT` - def object? - filetype == Headers::MH_OBJECT - end - - # @return [Boolean] whether or not the file is of type `MH_EXECUTE` - def executable? - filetype == Headers::MH_EXECUTE - end - - # @return [Boolean] whether or not the file is of type `MH_FVMLIB` - def fvmlib? - filetype == Headers::MH_FVMLIB - end - - # @return [Boolean] whether or not the file is of type `MH_CORE` - def core? - filetype == Headers::MH_CORE - end - - # @return [Boolean] whether or not the file is of type `MH_PRELOAD` - def preload? - filetype == Headers::MH_PRELOAD - end - - # @return [Boolean] whether or not the file is of type `MH_DYLIB` - def dylib? - filetype == Headers::MH_DYLIB - end - - # @return [Boolean] whether or not the file is of type `MH_DYLINKER` - def dylinker? - filetype == Headers::MH_DYLINKER - end - - # @return [Boolean] whether or not the file is of type `MH_BUNDLE` - def bundle? - filetype == Headers::MH_BUNDLE - end - - # @return [Boolean] whether or not the file is of type `MH_DSYM` - def dsym? - filetype == Headers::MH_DSYM - end - - # @return [Boolean] whether or not the file is of type `MH_KEXT_BUNDLE` - def kext? - filetype == Headers::MH_KEXT_BUNDLE - end - - # @return [Boolean] true if the Mach-O has 32-bit magic, false otherwise - def magic32? - Utils.magic32?(magic) - end - - # @return [Boolean] true if the Mach-O has 64-bit magic, false otherwise - def magic64? - Utils.magic64?(magic) - end - - # @return [Fixnum] the file's internal alignment - def alignment - magic32? ? 4 : 8 - end - end - - # 64-bit Mach-O file header structure - class MachHeader64 < MachHeader - # @return [void] - attr_reader :reserved - - # @see MachOStructure::FORMAT - # @api private - FORMAT = "L=8".freeze - - # @see MachOStructure::SIZEOF - # @api private - 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 -end diff --git a/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho/load_commands.rb b/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho/load_commands.rb deleted file mode 100644 index be4319ee2..000000000 --- a/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho/load_commands.rb +++ /dev/null @@ -1,1350 +0,0 @@ -module MachO - # Classes and constants for parsing load commands in Mach-O binaries. - module LoadCommands - # load commands added after OS X 10.1 need to be bitwise ORed with - # LC_REQ_DYLD to be recognized by the dynamic linker (dyld) - # @api private - LC_REQ_DYLD = 0x80000000 - - # association of load commands to symbol representations - # @api private - LOAD_COMMANDS = { - 0x1 => :LC_SEGMENT, - 0x2 => :LC_SYMTAB, - 0x3 => :LC_SYMSEG, - 0x4 => :LC_THREAD, - 0x5 => :LC_UNIXTHREAD, - 0x6 => :LC_LOADFVMLIB, - 0x7 => :LC_IDFVMLIB, - 0x8 => :LC_IDENT, - 0x9 => :LC_FVMFILE, - 0xa => :LC_PREPAGE, - 0xb => :LC_DYSYMTAB, - 0xc => :LC_LOAD_DYLIB, - 0xd => :LC_ID_DYLIB, - 0xe => :LC_LOAD_DYLINKER, - 0xf => :LC_ID_DYLINKER, - 0x10 => :LC_PREBOUND_DYLIB, - 0x11 => :LC_ROUTINES, - 0x12 => :LC_SUB_FRAMEWORK, - 0x13 => :LC_SUB_UMBRELLA, - 0x14 => :LC_SUB_CLIENT, - 0x15 => :LC_SUB_LIBRARY, - 0x16 => :LC_TWOLEVEL_HINTS, - 0x17 => :LC_PREBIND_CKSUM, - (0x18 | LC_REQ_DYLD) => :LC_LOAD_WEAK_DYLIB, - 0x19 => :LC_SEGMENT_64, - 0x1a => :LC_ROUTINES_64, - 0x1b => :LC_UUID, - (0x1c | LC_REQ_DYLD) => :LC_RPATH, - 0x1d => :LC_CODE_SIGNATURE, - 0x1e => :LC_SEGMENT_SPLIT_INFO, - (0x1f | LC_REQ_DYLD) => :LC_REEXPORT_DYLIB, - 0x20 => :LC_LAZY_LOAD_DYLIB, - 0x21 => :LC_ENCRYPTION_INFO, - 0x22 => :LC_DYLD_INFO, - (0x22 | LC_REQ_DYLD) => :LC_DYLD_INFO_ONLY, - (0x23 | LC_REQ_DYLD) => :LC_LOAD_UPWARD_DYLIB, - 0x24 => :LC_VERSION_MIN_MACOSX, - 0x25 => :LC_VERSION_MIN_IPHONEOS, - 0x26 => :LC_FUNCTION_STARTS, - 0x27 => :LC_DYLD_ENVIRONMENT, - (0x28 | LC_REQ_DYLD) => :LC_MAIN, - 0x29 => :LC_DATA_IN_CODE, - 0x2a => :LC_SOURCE_VERSION, - 0x2b => :LC_DYLIB_CODE_SIGN_DRS, - 0x2c => :LC_ENCRYPTION_INFO_64, - 0x2d => :LC_LINKER_OPTION, - 0x2e => :LC_LINKER_OPTIMIZATION_HINT, - 0x2f => :LC_VERSION_MIN_TVOS, - 0x30 => :LC_VERSION_MIN_WATCHOS, - }.freeze - - # association of symbol representations to load command constants - # @api private - LOAD_COMMAND_CONSTANTS = LOAD_COMMANDS.invert.freeze - - # load commands responsible for loading dylibs - # @api private - DYLIB_LOAD_COMMANDS = [ - :LC_LOAD_DYLIB, - :LC_LOAD_WEAK_DYLIB, - :LC_REEXPORT_DYLIB, - :LC_LAZY_LOAD_DYLIB, - :LC_LOAD_UPWARD_DYLIB, - ].freeze - - # load commands that can be created manually via {LoadCommand.create} - # @api private - CREATABLE_LOAD_COMMANDS = DYLIB_LOAD_COMMANDS + [ - :LC_ID_DYLIB, - :LC_RPATH, - :LC_LOAD_DYLINKER, - ].freeze - - # association of load command symbols to string representations of classes - # @api private - LC_STRUCTURES = { - :LC_SEGMENT => "SegmentCommand", - :LC_SYMTAB => "SymtabCommand", - # "obsolete" - :LC_SYMSEG => "SymsegCommand", - # seems obsolete, but not documented as such - :LC_THREAD => "ThreadCommand", - :LC_UNIXTHREAD => "ThreadCommand", - # "obsolete" - :LC_LOADFVMLIB => "FvmlibCommand", - # "obsolete" - :LC_IDFVMLIB => "FvmlibCommand", - # "obsolete" - :LC_IDENT => "IdentCommand", - # "reserved for internal use only" - :LC_FVMFILE => "FvmfileCommand", - # "reserved for internal use only", no public struct - :LC_PREPAGE => "LoadCommand", - :LC_DYSYMTAB => "DysymtabCommand", - :LC_LOAD_DYLIB => "DylibCommand", - :LC_ID_DYLIB => "DylibCommand", - :LC_LOAD_DYLINKER => "DylinkerCommand", - :LC_ID_DYLINKER => "DylinkerCommand", - :LC_PREBOUND_DYLIB => "PreboundDylibCommand", - :LC_ROUTINES => "RoutinesCommand", - :LC_SUB_FRAMEWORK => "SubFrameworkCommand", - :LC_SUB_UMBRELLA => "SubUmbrellaCommand", - :LC_SUB_CLIENT => "SubClientCommand", - :LC_SUB_LIBRARY => "SubLibraryCommand", - :LC_TWOLEVEL_HINTS => "TwolevelHintsCommand", - :LC_PREBIND_CKSUM => "PrebindCksumCommand", - :LC_LOAD_WEAK_DYLIB => "DylibCommand", - :LC_SEGMENT_64 => "SegmentCommand64", - :LC_ROUTINES_64 => "RoutinesCommand64", - :LC_UUID => "UUIDCommand", - :LC_RPATH => "RpathCommand", - :LC_CODE_SIGNATURE => "LinkeditDataCommand", - :LC_SEGMENT_SPLIT_INFO => "LinkeditDataCommand", - :LC_REEXPORT_DYLIB => "DylibCommand", - :LC_LAZY_LOAD_DYLIB => "DylibCommand", - :LC_ENCRYPTION_INFO => "EncryptionInfoCommand", - :LC_DYLD_INFO => "DyldInfoCommand", - :LC_DYLD_INFO_ONLY => "DyldInfoCommand", - :LC_LOAD_UPWARD_DYLIB => "DylibCommand", - :LC_VERSION_MIN_MACOSX => "VersionMinCommand", - :LC_VERSION_MIN_IPHONEOS => "VersionMinCommand", - :LC_FUNCTION_STARTS => "LinkeditDataCommand", - :LC_DYLD_ENVIRONMENT => "DylinkerCommand", - :LC_MAIN => "EntryPointCommand", - :LC_DATA_IN_CODE => "LinkeditDataCommand", - :LC_SOURCE_VERSION => "SourceVersionCommand", - :LC_DYLIB_CODE_SIGN_DRS => "LinkeditDataCommand", - :LC_ENCRYPTION_INFO_64 => "EncryptionInfoCommand64", - :LC_LINKER_OPTION => "LinkerOptionCommand", - :LC_LINKER_OPTIMIZATION_HINT => "LinkeditDataCommand", - :LC_VERSION_MIN_TVOS => "VersionMinCommand", - :LC_VERSION_MIN_WATCHOS => "VersionMinCommand", - }.freeze - - # association of segment name symbols to names - # @api private - SEGMENT_NAMES = { - :SEG_PAGEZERO => "__PAGEZERO", - :SEG_TEXT => "__TEXT", - :SEG_DATA => "__DATA", - :SEG_OBJC => "__OBJC", - :SEG_ICON => "__ICON", - :SEG_LINKEDIT => "__LINKEDIT", - :SEG_UNIXSTACK => "__UNIXSTACK", - :SEG_IMPORT => "__IMPORT", - }.freeze - - # association of segment flag symbols to values - # @api private - SEGMENT_FLAGS = { - :SG_HIGHVM => 0x1, - :SG_FVMLIB => 0x2, - :SG_NORELOC => 0x4, - :SG_PROTECTED_VERSION_1 => 0x8, - }.freeze - - # Mach-O load command structure - # This is the most generic load command - only cmd ID and size are - # represented, and no actual data. Used when a more specific class - # isn't available/implemented. - class LoadCommand < MachOStructure - # @return [MachO::MachOView] the raw view associated with the load command - attr_reader :view - - # @return [Fixnum] the load command's identifying number - attr_reader :cmd - - # @return [Fixnum] the size of the load command, in bytes - attr_reader :cmdsize - - # @see MachOStructure::FORMAT - # @api private - FORMAT = "L=2".freeze - - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 8 - - # Instantiates a new LoadCommand given a view into its origin Mach-O - # @param view [MachO::MachOView] the load command's raw view - # @return [LoadCommand] the new load command - # @api private - def self.new_from_bin(view) - bin = view.raw_data.slice(view.offset, bytesize) - format = Utils.specialize_format(self::FORMAT, view.endianness) - - new(view, *bin.unpack(format)) - end - - # Creates a new (viewless) command corresponding to the symbol provided - # @param cmd_sym [Symbol] the symbol of the load command being created - # @param args [Array] the arguments for the load command being created - def self.create(cmd_sym, *args) - raise LoadCommandNotCreatableError, cmd_sym unless CREATABLE_LOAD_COMMANDS.include?(cmd_sym) - - klass = LoadCommands.const_get LC_STRUCTURES[cmd_sym] - cmd = LOAD_COMMAND_CONSTANTS[cmd_sym] - - # cmd will be filled in, view and cmdsize will be left unpopulated - klass_arity = klass.instance_method(:initialize).arity - 3 - - raise LoadCommandCreationArityError.new(cmd_sym, klass_arity, args.size) if klass_arity != args.size - - klass.new(nil, cmd, nil, *args) - end - - # @param view [MachO::MachOView] the load command's raw view - # @param cmd [Fixnum] the load command's identifying number - # @param cmdsize [Fixnum] the size of the load command in bytes - # @api private - def initialize(view, cmd, cmdsize) - @view = view - @cmd = cmd - @cmdsize = cmdsize - end - - # @return [Boolean] whether the load command can be serialized - def serializable? - CREATABLE_LOAD_COMMANDS.include?(LOAD_COMMANDS[cmd]) - end - - # @param context [SerializationContext] the context - # to serialize into - # @return [String, nil] the serialized fields of the load command, or nil - # if the load command can't be serialized - # @api private - def serialize(context) - raise LoadCommandNotSerializableError, LOAD_COMMANDS[cmd] unless serializable? - format = Utils.specialize_format(FORMAT, context.endianness) - [cmd, SIZEOF].pack(format) - end - - # @return [Fixnum] the load command's offset in the source file - # @deprecated use {#view} instead - def offset - view.offset - end - - # @return [Symbol] a symbol representation of the load command's - # identifying number - def type - LOAD_COMMANDS[cmd] - end - - alias to_sym type - - # @return [String] a string representation of the load command's - # identifying number - def to_s - type.to_s - end - - # Represents a Load Command string. A rough analogue to the lc_str - # struct used internally by OS X. This class allows ruby-macho to - # pretend that strings stored in LCs are immediately available without - # explicit operations on the raw Mach-O data. - class LCStr - # @param lc [LoadCommand] the load command - # @param lc_str [Fixnum, String] the offset to the beginning of the - # string, or the string itself if not being initialized with a view. - # @raise [MachO::LCStrMalformedError] if the string is malformed - # @todo devise a solution such that the `lc_str` parameter is not - # interpreted differently depending on `lc.view`. The current behavior - # is a hack to allow viewless load command creation. - # @api private - def initialize(lc, lc_str) - view = lc.view - - if view - lc_str_abs = view.offset + lc_str - lc_end = view.offset + lc.cmdsize - 1 - raw_string = view.raw_data.slice(lc_str_abs..lc_end) - @string, null_byte, _padding = raw_string.partition("\x00") - raise LCStrMalformedError, lc if null_byte.empty? - @string_offset = lc_str - else - @string = lc_str - @string_offset = 0 - end - end - - # @return [String] a string representation of the LCStr - def to_s - @string - end - - # @return [Fixnum] the offset to the beginning of the string in the - # load command - def to_i - @string_offset - end - end - - # Represents the contextual information needed by a load command to - # serialize itself correctly into a binary string. - class SerializationContext - # @return [Symbol] the endianness of the serialized load command - attr_reader :endianness - - # @return [Fixnum] the constant alignment value used to pad the - # serialized load command - attr_reader :alignment - - # @param macho [MachO::MachOFile] the file to contextualize - # @return [SerializationContext] the - # resulting context - def self.context_for(macho) - new(macho.endianness, macho.alignment) - end - - # @param endianness [Symbol] the endianness of the context - # @param alignment [Fixnum] the alignment of the context - # @api private - def initialize(endianness, alignment) - @endianness = endianness - @alignment = alignment - end - end - end - - # A load command containing a single 128-bit unique random number - # identifying an object produced by static link editor. Corresponds to - # LC_UUID. - class UUIDCommand < LoadCommand - # @return [Array] the UUID - attr_reader :uuid - - # @see MachOStructure::FORMAT - # @api private - FORMAT = "L=2a16".freeze - - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 24 - - # @api private - def initialize(view, cmd, cmdsize, uuid) - super(view, cmd, cmdsize) - @uuid = uuid.unpack("C16") # re-unpack for the actual UUID array - end - - # @return [String] a string representation of the UUID - def uuid_string - hexes = uuid.map { |e| "%02x" % e } - segs = [ - hexes[0..3].join, hexes[4..5].join, hexes[6..7].join, - hexes[8..9].join, hexes[10..15].join - ] - - segs.join("-") - end - end - - # A load command indicating that part of this file is to be mapped into - # the task's address space. Corresponds to LC_SEGMENT. - class SegmentCommand < LoadCommand - # @return [String] the name of the segment - attr_reader :segname - - # @return [Fixnum] the memory address of the segment - attr_reader :vmaddr - - # @return [Fixnum] the memory size of the segment - attr_reader :vmsize - - # @return [Fixnum] the file offset of the segment - attr_reader :fileoff - - # @return [Fixnum] the amount to map from the file - attr_reader :filesize - - # @return [Fixnum] the maximum VM protection - attr_reader :maxprot - - # @return [Fixnum] the initial VM protection - attr_reader :initprot - - # @return [Fixnum] the number of sections in the segment - attr_reader :nsects - - # @return [Fixnum] any flags associated with the segment - attr_reader :flags - - # @see MachOStructure::FORMAT - # @api private - FORMAT = "L=2a16L=4l=2L=2".freeze - - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 56 - - # @api private - def initialize(view, cmd, cmdsize, segname, vmaddr, vmsize, fileoff, - filesize, maxprot, initprot, nsects, flags) - super(view, cmd, cmdsize) - @segname = segname.delete("\x00") - @vmaddr = vmaddr - @vmsize = vmsize - @fileoff = fileoff - @filesize = filesize - @maxprot = maxprot - @initprot = initprot - @nsects = nsects - @flags = flags - end - - # All sections referenced within this segment. - # @return [Array] if the Mach-O is 32-bit - # @return [Array] if the Mach-O is 64-bit - def sections - klass = case self - when SegmentCommand64 - MachO::Sections::Section64 - when SegmentCommand - MachO::Sections::Section - end - - offset = view.offset + self.class.bytesize - length = nsects * klass.bytesize - - bins = view.raw_data[offset, length] - bins.unpack("a#{klass.bytesize}" * nsects).map do |bin| - klass.new_from_bin(view.endianness, bin) - end - end - - # @example - # puts "this segment relocated in/to it" if sect.flag?(:SG_NORELOC) - # @param flag [Symbol] a segment flag symbol - # @return [Boolean] true if `flag` is present in the segment's flag field - def flag?(flag) - flag = SEGMENT_FLAGS[flag] - return false if flag.nil? - flags & flag == flag - end - end - - # A load command indicating that part of this file is to be mapped into - # the task's address space. Corresponds to LC_SEGMENT_64. - class SegmentCommand64 < SegmentCommand - # @see MachOStructure::FORMAT - # @api private - FORMAT = "L=2a16Q=4l=2L=2".freeze - - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 72 - end - - # A load command representing some aspect of shared libraries, depending - # on filetype. Corresponds to LC_ID_DYLIB, LC_LOAD_DYLIB, - # LC_LOAD_WEAK_DYLIB, and LC_REEXPORT_DYLIB. - class DylibCommand < LoadCommand - # @return [LCStr] the library's path - # name as an LCStr - attr_reader :name - - # @return [Fixnum] the library's build time stamp - attr_reader :timestamp - - # @return [Fixnum] the library's current version number - attr_reader :current_version - - # @return [Fixnum] the library's compatibility version number - attr_reader :compatibility_version - - # @see MachOStructure::FORMAT - # @api private - FORMAT = "L=6".freeze - - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 24 - - # @api private - def initialize(view, cmd, cmdsize, name, timestamp, current_version, - compatibility_version) - super(view, cmd, cmdsize) - @name = LCStr.new(self, name) - @timestamp = timestamp - @current_version = current_version - @compatibility_version = compatibility_version - end - - # @param context [SerializationContext] - # the context - # @return [String] the serialized fields of the load command - # @api private - def serialize(context) - format = Utils.specialize_format(FORMAT, context.endianness) - string_payload, string_offsets = Utils.pack_strings(SIZEOF, - context.alignment, - :name => name.to_s) - cmdsize = SIZEOF + string_payload.bytesize - [cmd, cmdsize, string_offsets[:name], timestamp, current_version, - compatibility_version].pack(format) + string_payload - end - end - - # A load command representing some aspect of the dynamic linker, depending - # on filetype. Corresponds to LC_ID_DYLINKER, LC_LOAD_DYLINKER, and - # LC_DYLD_ENVIRONMENT. - class DylinkerCommand < LoadCommand - # @return [LCStr] the dynamic linker's - # path name as an LCStr - attr_reader :name - - # @see MachOStructure::FORMAT - # @api private - FORMAT = "L=3".freeze - - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 12 - - # @api private - def initialize(view, cmd, cmdsize, name) - super(view, cmd, cmdsize) - @name = LCStr.new(self, name) - end - - # @param context [SerializationContext] - # the context - # @return [String] the serialized fields of the load command - # @api private - def serialize(context) - format = Utils.specialize_format(FORMAT, context.endianness) - string_payload, string_offsets = Utils.pack_strings(SIZEOF, - context.alignment, - :name => name.to_s) - cmdsize = SIZEOF + string_payload.bytesize - [cmd, cmdsize, string_offsets[:name]].pack(format) + string_payload - end - end - - # A load command used to indicate dynamic libraries used in prebinding. - # Corresponds to LC_PREBOUND_DYLIB. - class PreboundDylibCommand < LoadCommand - # @return [LCStr] the library's path - # name as an LCStr - attr_reader :name - - # @return [Fixnum] the number of modules in the library - attr_reader :nmodules - - # @return [Fixnum] a bit vector of linked modules - attr_reader :linked_modules - - # @see MachOStructure::FORMAT - # @api private - FORMAT = "L=5".freeze - - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 20 - - # @api private - def initialize(view, cmd, cmdsize, name, nmodules, linked_modules) - super(view, cmd, cmdsize) - @name = LCStr.new(self, name) - @nmodules = nmodules - @linked_modules = linked_modules - end - end - - # A load command used to represent threads. - # @note cctools-870 and onwards have all fields of thread_command commented - # out except the common ones (cmd, cmdsize) - class ThreadCommand < LoadCommand - # @see MachOStructure::FORMAT - # @api private - FORMAT = "L=2".freeze - - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 8 - end - - # A load command containing the address of the dynamic shared library - # initialization routine and an index into the module table for the module - # that defines the routine. Corresponds to LC_ROUTINES. - class RoutinesCommand < LoadCommand - # @return [Fixnum] the address of the initialization routine - attr_reader :init_address - - # @return [Fixnum] the index into the module table that the init routine - # is defined in - attr_reader :init_module - - # @return [void] - attr_reader :reserved1 - - # @return [void] - attr_reader :reserved2 - - # @return [void] - attr_reader :reserved3 - - # @return [void] - attr_reader :reserved4 - - # @return [void] - attr_reader :reserved5 - - # @return [void] - attr_reader :reserved6 - - # @see MachOStructure::FORMAT - # @api private - FORMAT = "L=10".freeze - - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 40 - - # @api private - def initialize(view, cmd, cmdsize, init_address, init_module, reserved1, - reserved2, reserved3, reserved4, reserved5, reserved6) - super(view, cmd, cmdsize) - @init_address = init_address - @init_module = init_module - @reserved1 = reserved1 - @reserved2 = reserved2 - @reserved3 = reserved3 - @reserved4 = reserved4 - @reserved5 = reserved5 - @reserved6 = reserved6 - end - end - - # A load command containing the address of the dynamic shared library - # initialization routine and an index into the module table for the module - # that defines the routine. Corresponds to LC_ROUTINES_64. - class RoutinesCommand64 < RoutinesCommand - # @see MachOStructure::FORMAT - # @api private - FORMAT = "L=2Q=8".freeze - - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 72 - end - - # A load command signifying membership of a subframework containing the name - # of an umbrella framework. Corresponds to LC_SUB_FRAMEWORK. - class SubFrameworkCommand < LoadCommand - # @return [LCStr] the umbrella framework name as an LCStr - attr_reader :umbrella - - # @see MachOStructure::FORMAT - # @api private - FORMAT = "L=3".freeze - - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 12 - - # @api private - def initialize(view, cmd, cmdsize, umbrella) - super(view, cmd, cmdsize) - @umbrella = LCStr.new(self, umbrella) - end - end - - # A load command signifying membership of a subumbrella containing the name - # of an umbrella framework. Corresponds to LC_SUB_UMBRELLA. - class SubUmbrellaCommand < LoadCommand - # @return [LCStr] the subumbrella framework name as an LCStr - attr_reader :sub_umbrella - - # @see MachOStructure::FORMAT - # @api private - FORMAT = "L=3".freeze - - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 12 - - # @api private - def initialize(view, cmd, cmdsize, sub_umbrella) - super(view, cmd, cmdsize) - @sub_umbrella = LCStr.new(self, sub_umbrella) - end - end - - # A load command signifying a sublibrary of a shared library. Corresponds - # to LC_SUB_LIBRARY. - class SubLibraryCommand < LoadCommand - # @return [LCStr] the sublibrary name as an LCStr - attr_reader :sub_library - - # @see MachOStructure::FORMAT - # @api private - FORMAT = "L=3".freeze - - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 12 - - # @api private - def initialize(view, cmd, cmdsize, sub_library) - super(view, cmd, cmdsize) - @sub_library = LCStr.new(self, sub_library) - end - end - - # A load command signifying a shared library that is a subframework of - # an umbrella framework. Corresponds to LC_SUB_CLIENT. - class SubClientCommand < LoadCommand - # @return [LCStr] the subclient name as an LCStr - attr_reader :sub_client - - # @see MachOStructure::FORMAT - # @api private - FORMAT = "L=3".freeze - - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 12 - - # @api private - def initialize(view, cmd, cmdsize, sub_client) - super(view, cmd, cmdsize) - @sub_client = LCStr.new(self, sub_client) - end - end - - # A load command containing the offsets and sizes of the link-edit 4.3BSD - # "stab" style symbol table information. Corresponds to LC_SYMTAB. - class SymtabCommand < LoadCommand - # @return [Fixnum] the symbol table's offset - attr_reader :symoff - - # @return [Fixnum] the number of symbol table entries - attr_reader :nsyms - - # @return the string table's offset - attr_reader :stroff - - # @return the string table size in bytes - attr_reader :strsize - - # @see MachOStructure::FORMAT - # @api private - FORMAT = "L=6".freeze - - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 24 - - # @api private - def initialize(view, cmd, cmdsize, symoff, nsyms, stroff, strsize) - super(view, cmd, cmdsize) - @symoff = symoff - @nsyms = nsyms - @stroff = stroff - @strsize = strsize - end - end - - # A load command containing symbolic information needed to support data - # structures used by the dynamic link editor. Corresponds to LC_DYSYMTAB. - class DysymtabCommand < LoadCommand - # @return [Fixnum] the index to local symbols - attr_reader :ilocalsym - - # @return [Fixnum] the number of local symbols - attr_reader :nlocalsym - - # @return [Fixnum] the index to externally defined symbols - attr_reader :iextdefsym - - # @return [Fixnum] the number of externally defined symbols - attr_reader :nextdefsym - - # @return [Fixnum] the index to undefined symbols - attr_reader :iundefsym - - # @return [Fixnum] the number of undefined symbols - attr_reader :nundefsym - - # @return [Fixnum] the file offset to the table of contents - attr_reader :tocoff - - # @return [Fixnum] the number of entries in the table of contents - attr_reader :ntoc - - # @return [Fixnum] the file offset to the module table - attr_reader :modtaboff - - # @return [Fixnum] the number of entries in the module table - attr_reader :nmodtab - - # @return [Fixnum] the file offset to the referenced symbol table - attr_reader :extrefsymoff - - # @return [Fixnum] the number of entries in the referenced symbol table - attr_reader :nextrefsyms - - # @return [Fixnum] the file offset to the indirect symbol table - attr_reader :indirectsymoff - - # @return [Fixnum] the number of entries in the indirect symbol table - attr_reader :nindirectsyms - - # @return [Fixnum] the file offset to the external relocation entries - attr_reader :extreloff - - # @return [Fixnum] the number of external relocation entries - attr_reader :nextrel - - # @return [Fixnum] the file offset to the local relocation entries - attr_reader :locreloff - - # @return [Fixnum] the number of local relocation entries - attr_reader :nlocrel - - # @see MachOStructure::FORMAT - # @api private - FORMAT = "L=20".freeze - - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 80 - - # ugh - # @api private - def initialize(view, cmd, cmdsize, ilocalsym, nlocalsym, iextdefsym, - nextdefsym, iundefsym, nundefsym, tocoff, ntoc, modtaboff, - nmodtab, extrefsymoff, nextrefsyms, indirectsymoff, - nindirectsyms, extreloff, nextrel, locreloff, nlocrel) - super(view, cmd, cmdsize) - @ilocalsym = ilocalsym - @nlocalsym = nlocalsym - @iextdefsym = iextdefsym - @nextdefsym = nextdefsym - @iundefsym = iundefsym - @nundefsym = nundefsym - @tocoff = tocoff - @ntoc = ntoc - @modtaboff = modtaboff - @nmodtab = nmodtab - @extrefsymoff = extrefsymoff - @nextrefsyms = nextrefsyms - @indirectsymoff = indirectsymoff - @nindirectsyms = nindirectsyms - @extreloff = extreloff - @nextrel = nextrel - @locreloff = locreloff - @nlocrel = nlocrel - end - end - - # A load command containing the offset and number of hints in the two-level - # namespace lookup hints table. Corresponds to LC_TWOLEVEL_HINTS. - class TwolevelHintsCommand < LoadCommand - # @return [Fixnum] the offset to the hint table - attr_reader :htoffset - - # @return [Fixnum] the number of hints in the hint table - attr_reader :nhints - - # @return [TwolevelHintsTable] - # the hint table - attr_reader :table - - # @see MachOStructure::FORMAT - # @api private - FORMAT = "L=4".freeze - - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 16 - - # @api private - def initialize(view, cmd, cmdsize, htoffset, nhints) - super(view, cmd, cmdsize) - @htoffset = htoffset - @nhints = nhints - @table = TwolevelHintsTable.new(view, htoffset, nhints) - end - - # A representation of the two-level namespace lookup hints table exposed - # by a {TwolevelHintsCommand} (`LC_TWOLEVEL_HINTS`). - class TwolevelHintsTable - # @return [Array] all hints in the table - attr_reader :hints - - # @param view [MachO::MachOView] the view into the current Mach-O - # @param htoffset [Fixnum] the offset of the hints table - # @param nhints [Fixnum] the number of two-level hints in the table - # @api private - def initialize(view, htoffset, nhints) - format = Utils.specialize_format("L=#{nhints}", view.endianness) - raw_table = view.raw_data[htoffset, nhints * 4] - blobs = raw_table.unpack(format) - - @hints = blobs.map { |b| TwolevelHint.new(b) } - end - - # An individual two-level namespace lookup hint. - class TwolevelHint - # @return [Fixnum] the index into the sub-images - attr_reader :isub_image - - # @return [Fixnum] the index into the table of contents - attr_reader :itoc - - # @param blob [Fixnum] the 32-bit number containing the lookup hint - # @api private - def initialize(blob) - @isub_image = blob >> 24 - @itoc = blob & 0x00FFFFFF - end - end - end - end - - # A load command containing the value of the original checksum for prebound - # files, or zero. Corresponds to LC_PREBIND_CKSUM. - class PrebindCksumCommand < LoadCommand - # @return [Fixnum] the checksum or 0 - attr_reader :cksum - - # @see MachOStructure::FORMAT - # @api private - FORMAT = "L=3".freeze - - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 12 - - # @api private - def initialize(view, cmd, cmdsize, cksum) - super(view, cmd, cmdsize) - @cksum = cksum - end - end - - # A load command representing an rpath, which specifies a path that should - # be added to the current run path used to find @rpath prefixed dylibs. - # Corresponds to LC_RPATH. - class RpathCommand < LoadCommand - # @return [LCStr] the path to add to the run path as an LCStr - attr_reader :path - - # @see MachOStructure::FORMAT - # @api private - FORMAT = "L=3".freeze - - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 12 - - # @api private - def initialize(view, cmd, cmdsize, path) - super(view, cmd, cmdsize) - @path = LCStr.new(self, path) - end - - # @param context [SerializationContext] the context - # @return [String] the serialized fields of the load command - # @api private - def serialize(context) - format = Utils.specialize_format(FORMAT, context.endianness) - string_payload, string_offsets = Utils.pack_strings(SIZEOF, - context.alignment, - :path => path.to_s) - cmdsize = SIZEOF + string_payload.bytesize - [cmd, cmdsize, string_offsets[:path]].pack(format) + string_payload - end - end - - # A load command representing the offsets and sizes of a blob of data in - # the __LINKEDIT segment. Corresponds to LC_CODE_SIGNATURE, - # LC_SEGMENT_SPLIT_INFO, LC_FUNCTION_STARTS, LC_DATA_IN_CODE, - # LC_DYLIB_CODE_SIGN_DRS, and LC_LINKER_OPTIMIZATION_HINT. - class LinkeditDataCommand < LoadCommand - # @return [Fixnum] offset to the data in the __LINKEDIT segment - attr_reader :dataoff - - # @return [Fixnum] size of the data in the __LINKEDIT segment - attr_reader :datasize - - # @see MachOStructure::FORMAT - # @api private - FORMAT = "L=4".freeze - - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 16 - - # @api private - def initialize(view, cmd, cmdsize, dataoff, datasize) - super(view, cmd, cmdsize) - @dataoff = dataoff - @datasize = datasize - end - end - - # A load command representing the offset to and size of an encrypted - # segment. Corresponds to LC_ENCRYPTION_INFO. - class EncryptionInfoCommand < LoadCommand - # @return [Fixnum] the offset to the encrypted segment - attr_reader :cryptoff - - # @return [Fixnum] the size of the encrypted segment - attr_reader :cryptsize - - # @return [Fixnum] the encryption system, or 0 if not encrypted yet - attr_reader :cryptid - - # @see MachOStructure::FORMAT - # @api private - FORMAT = "L=5".freeze - - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 20 - - # @api private - def initialize(view, cmd, cmdsize, cryptoff, cryptsize, cryptid) - super(view, cmd, cmdsize) - @cryptoff = cryptoff - @cryptsize = cryptsize - @cryptid = cryptid - end - end - - # A load command representing the offset to and size of an encrypted - # segment. Corresponds to LC_ENCRYPTION_INFO_64. - class EncryptionInfoCommand64 < LoadCommand - # @return [Fixnum] the offset to the encrypted segment - attr_reader :cryptoff - - # @return [Fixnum] the size of the encrypted segment - attr_reader :cryptsize - - # @return [Fixnum] the encryption system, or 0 if not encrypted yet - attr_reader :cryptid - - # @return [Fixnum] 64-bit padding value - attr_reader :pad - - # @see MachOStructure::FORMAT - # @api private - FORMAT = "L=6".freeze - - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 24 - - # @api private - def initialize(view, cmd, cmdsize, cryptoff, cryptsize, cryptid, pad) - super(view, cmd, cmdsize) - @cryptoff = cryptoff - @cryptsize = cryptsize - @cryptid = cryptid - @pad = pad - end - end - - # A load command containing the minimum OS version on which the binary - # was built to run. Corresponds to LC_VERSION_MIN_MACOSX and - # LC_VERSION_MIN_IPHONEOS. - class VersionMinCommand < LoadCommand - # @return [Fixnum] the version X.Y.Z packed as x16.y8.z8 - attr_reader :version - - # @return [Fixnum] the SDK version X.Y.Z packed as x16.y8.z8 - attr_reader :sdk - - # @see MachOStructure::FORMAT - # @api private - FORMAT = "L=4".freeze - - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 16 - - # @api private - def initialize(view, cmd, cmdsize, version, sdk) - super(view, cmd, cmdsize) - @version = version - @sdk = sdk - end - - # A string representation of the binary's minimum OS version. - # @return [String] a string representing the minimum OS version. - def version_string - binary = "%032b" % version - segs = [ - binary[0..15], binary[16..23], binary[24..31] - ].map { |s| s.to_i(2) } - - segs.join(".") - end - - # A string representation of the binary's SDK version. - # @return [String] a string representing the SDK version. - def sdk_string - binary = "%032b" % sdk - segs = [ - binary[0..15], binary[16..23], binary[24..31] - ].map { |s| s.to_i(2) } - - segs.join(".") - end - end - - # A load command containing the file offsets and sizes of the new - # compressed form of the information dyld needs to load the image. - # Corresponds to LC_DYLD_INFO and LC_DYLD_INFO_ONLY. - class DyldInfoCommand < LoadCommand - # @return [Fixnum] the file offset to the rebase information - attr_reader :rebase_off - - # @return [Fixnum] the size of the rebase information - attr_reader :rebase_size - - # @return [Fixnum] the file offset to the binding information - attr_reader :bind_off - - # @return [Fixnum] the size of the binding information - attr_reader :bind_size - - # @return [Fixnum] the file offset to the weak binding information - attr_reader :weak_bind_off - - # @return [Fixnum] the size of the weak binding information - attr_reader :weak_bind_size - - # @return [Fixnum] the file offset to the lazy binding information - attr_reader :lazy_bind_off - - # @return [Fixnum] the size of the lazy binding information - attr_reader :lazy_bind_size - - # @return [Fixnum] the file offset to the export information - attr_reader :export_off - - # @return [Fixnum] the size of the export information - attr_reader :export_size - - # @see MachOStructure::FORMAT - # @api private - FORMAT = "L=12".freeze - - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 48 - - # @api private - def initialize(view, cmd, cmdsize, rebase_off, rebase_size, bind_off, - bind_size, weak_bind_off, weak_bind_size, lazy_bind_off, - lazy_bind_size, export_off, export_size) - super(view, cmd, cmdsize) - @rebase_off = rebase_off - @rebase_size = rebase_size - @bind_off = bind_off - @bind_size = bind_size - @weak_bind_off = weak_bind_off - @weak_bind_size = weak_bind_size - @lazy_bind_off = lazy_bind_off - @lazy_bind_size = lazy_bind_size - @export_off = export_off - @export_size = export_size - end - end - - # A load command containing linker options embedded in object files. - # Corresponds to LC_LINKER_OPTION. - class LinkerOptionCommand < LoadCommand - # @return [Fixnum] the number of strings - attr_reader :count - - # @see MachOStructure::FORMAT - # @api private - FORMAT = "L=3".freeze - - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 12 - - # @api private - def initialize(view, cmd, cmdsize, count) - super(view, cmd, cmdsize) - @count = count - end - end - - # A load command specifying the offset of main(). Corresponds to LC_MAIN. - class EntryPointCommand < LoadCommand - # @return [Fixnum] the file (__TEXT) offset of main() - attr_reader :entryoff - - # @return [Fixnum] if not 0, the initial stack size. - attr_reader :stacksize - - # @see MachOStructure::FORMAT - # @api private - FORMAT = "L=2Q=2".freeze - - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 24 - - # @api private - def initialize(view, cmd, cmdsize, entryoff, stacksize) - super(view, cmd, cmdsize) - @entryoff = entryoff - @stacksize = stacksize - end - end - - # A load command specifying the version of the sources used to build the - # binary. Corresponds to LC_SOURCE_VERSION. - class SourceVersionCommand < LoadCommand - # @return [Fixnum] the version packed as a24.b10.c10.d10.e10 - attr_reader :version - - # @see MachOStructure::FORMAT - # @api private - FORMAT = "L=2Q=1".freeze - - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 16 - - # @api private - def initialize(view, cmd, cmdsize, version) - super(view, cmd, cmdsize) - @version = version - end - - # A string representation of the sources used to build the binary. - # @return [String] a string representation of the version - def version_string - binary = "%064b" % version - segs = [ - binary[0..23], binary[24..33], binary[34..43], binary[44..53], - binary[54..63] - ].map { |s| s.to_i(2) } - - segs.join(".") - end - end - - # An obsolete load command containing the offset and size of the (GNU style) - # symbol table information. Corresponds to LC_SYMSEG. - class SymsegCommand < LoadCommand - # @return [Fixnum] the offset to the symbol segment - attr_reader :offset - - # @return [Fixnum] the size of the symbol segment in bytes - attr_reader :size - - # @see MachOStructure::FORMAT - # @api private - FORMAT = "L=4".freeze - - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 16 - - # @api private - def initialize(view, cmd, cmdsize, offset, size) - super(view, cmd, cmdsize) - @offset = offset - @size = size - end - end - - # An obsolete load command containing a free format string table. Each - # string is null-terminated and the command is zero-padded to a multiple of - # 4. Corresponds to LC_IDENT. - class IdentCommand < LoadCommand - # @see MachOStructure::FORMAT - # @api private - FORMAT = "L=2".freeze - - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 8 - end - - # An obsolete load command containing the path to a file to be loaded into - # memory. Corresponds to LC_FVMFILE. - class FvmfileCommand < LoadCommand - # @return [LCStr] the pathname of the file being loaded - attr_reader :name - - # @return [Fixnum] the virtual address being loaded at - attr_reader :header_addr - - # @see MachOStructure::FORMAT - # @api private - FORMAT = "L=4".freeze - - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 16 - - def initialize(view, cmd, cmdsize, name, header_addr) - super(view, cmd, cmdsize) - @name = LCStr.new(self, name) - @header_addr = header_addr - end - end - - # An obsolete load command containing the path to a library to be loaded - # into memory. Corresponds to LC_LOADFVMLIB and LC_IDFVMLIB. - class FvmlibCommand < LoadCommand - # @return [LCStr] the library's target pathname - attr_reader :name - - # @return [Fixnum] the library's minor version number - attr_reader :minor_version - - # @return [Fixnum] the library's header address - attr_reader :header_addr - - # @see MachOStructure::FORMAT - # @api private - FORMAT = "L=5".freeze - - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 20 - - def initialize(view, cmd, cmdsize, name, minor_version, header_addr) - super(view, cmd, cmdsize) - @name = LCStr.new(self, name) - @minor_version = minor_version - @header_addr = header_addr - end - end - end -end diff --git a/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho/macho_file.rb b/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho/macho_file.rb deleted file mode 100644 index 7693ab0dd..000000000 --- a/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho/macho_file.rb +++ /dev/null @@ -1,545 +0,0 @@ -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 FatFile - class MachOFile - 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 [Headers::MachHeader] if the Mach-O is 32-bit - # @return [Headers::MachHeader64] if the Mach-O is 64-bit - attr_reader :header - - # @return [Array] 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 [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 file does not exist - def initialize(filename) - raise ArgumentError, "#{filename}: no such file" unless File.file?(filename) - - @filename = filename - @raw_data = File.open(@filename, "rb", &:read) - populate_fields - end - - # Initializes a new MachOFile instance from a binary string. - # @see MachO::MachOFile.new_from_bin - # @api private - def initialize_from_bin(bin) - @filename = nil - @raw_data = bin - populate_fields - end - - # The file's raw Mach-O data. - # @return [String] the raw Mach-O data - def serialize - @raw_data - 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 - Headers::MH_MAGICS[magic] - end - - # @return [Symbol] a string representation of the Mach-O's filetype - def filetype - Headers::MH_FILETYPES[header.filetype] - end - - # @return [Symbol] a symbol representation of the Mach-O's CPU type - def cputype - Headers::CPU_TYPES[header.cputype] - end - - # @return [Symbol] a symbol representation of the Mach-O's CPU subtype - def cpusubtype - Headers::CPU_SUBTYPES[header.cputype][header.cpusubtype] - 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] an array of load commands - # corresponding to `name` - def command(name) - load_commands.select { |lc| lc.type == name.to_sym } - end - - alias [] command - - # Inserts a load command at the given offset. - # @param offset [Fixnum] the offset to insert at - # @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 [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 = LoadCommands::LoadCommand::SerializationContext.context_for(self) - cmd_raw = lc.serialize(context) - - if offset < header.class.bytesize || offset + cmd_raw.bytesize > low_fileoff - raise OffsetInsertionError, offset - end - - new_sizeofcmds = sizeofcmds + cmd_raw.bytesize - - if header.class.bytesize + new_sizeofcmds > low_fileoff - raise HeaderPadError, @filename - end - - # update Mach-O header fields to account for inserted load command - update_ncmds(ncmds + 1) - update_sizeofcmds(new_sizeofcmds) - - @raw_data.insert(offset, cmd_raw) - @raw_data.slice!(header.class.bytesize + new_sizeofcmds, cmd_raw.bytesize) - - populate_fields if options.fetch(:repopulate, true) - end - - # Replace a load command with another command in the Mach-O, preserving location. - # @param old_lc [LoadCommands::LoadCommand] the load command being replaced - # @param new_lc [LoadCommands::LoadCommand] the load command being added - # @return [void] - # @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 = 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 - raise HeaderPadError, @filename - end - - delete_command(old_lc) - insert_command(old_lc.view.offset, new_lc) - end - - # Appends a new load command to the Mach-O. - # @param lc [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 - # @note This is public, but methods like {#add_rpath} should be preferred. - # Setting `repopulate` to false **will leave the instance in an - # inconsistent state** unless {#populate_fields} is called **immediately** - # afterwards. - def add_command(lc, options = {}) - insert_command(header.class.bytesize + sizeofcmds, lc, options) - end - - # Delete a load command from the Mach-O. - # @param lc [LoadCommands::LoadCommand] the load command being deleted - # @param options [Hash] - # @option options [Boolean] :repopulate (true) whether or not to repopulate - # the instance fields - # @return [void] - # @note This is public, but methods like {#delete_rpath} should be preferred. - # Setting `repopulate` to false **will leave the instance in an - # inconsistent state** unless {#populate_fields} is called **immediately** - # afterwards. - def delete_command(lc, options = {}) - @raw_data.slice!(lc.view.offset, lc.cmdsize) - - # update Mach-O header fields to account for deleted load command - update_ncmds(ncmds - 1) - update_sizeofcmds(sizeofcmds - lc.cmdsize) - - # pad the space after the load commands to preserve offsets - null_pad = "\x00" * lc.cmdsize - @raw_data.insert(header.class.bytesize + sizeofcmds - lc.cmdsize, null_pad) - - populate_fields if options.fetch(:repopulate, true) - end - - # Populate the instance's fields with the raw Mach-O data. - # @return [void] - # @note This method is public, but should (almost) never need to be called. - # The exception to this rule is when methods like {#add_command} and - # {#delete_command} have been called with `repopulate = false`. - def populate_fields - @header = populate_mach_header - @load_commands = populate_load_commands - end - - # All load commands responsible for loading dylibs. - # @return [Array] an array of DylibCommands - def dylib_load_commands - load_commands.select { |lc| LoadCommands::DYLIB_LOAD_COMMANDS.include?(lc.type) } - end - - # All segment load commands in the Mach-O. - # @return [Array] if the Mach-O is 32-bit - # @return [Array] 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 - return unless dylib? - - 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.change_dylib_id("libFoo.dylib") - # @param new_id [String] the dylib's new ID - # @param _options [Hash] - # @return [void] - # @raise [ArgumentError] if `new_id` is not a String - # @note `_options` is currently unused and is provided for signature - # compatibility with {MachO::FatFile#change_dylib_id} - def change_dylib_id(new_id, _options = {}) - raise ArgumentError, "new ID must be a String" unless new_id.is_a?(String) - return unless dylib? - - old_lc = command(:LC_ID_DYLIB).first - raise DylibIdMissingError unless old_lc - - 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 - - alias dylib_id= change_dylib_id - - # All shared libraries linked to the Mach-O. - # @return [Array] an array of all shared libraries - def linked_dylibs - # Some linkers produce multiple `LC_LOAD_DYLIB` load commands for the same - # library, but at this point we're really only interested in a list of - # unique libraries this Mach-O file links to, thus: `uniq`. (This is also - # for consistency with `FatFile` that merges this list across all archs.) - dylib_load_commands.map(&:name).map(&:to_s).uniq - end - - # Changes the shared library `old_name` to `new_name` - # @example - # 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 [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 = 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 - - alias change_dylib change_install_name - - # All runtime paths searched by the dynamic linker for the Mach-O. - # @return [Array] 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 - # @param _options [Hash] - # @return [void] - # @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 = {}) - old_lc = command(:LC_RPATH).find { |r| r.path.to_s == old_path } - raise RpathUnknownError, old_path if old_lc.nil? - raise RpathExistsError, new_path if rpaths.include?(new_path) - - new_lc = LoadCommands::LoadCommand.create(:LC_RPATH, new_path) - - delete_rpath(old_path) - insert_command(old_lc.view.offset, new_lc) - end - - # Add the given runtime path to the Mach-O. - # @example - # file.rpaths # => ["/lib"] - # file.add_rpath("/usr/lib") - # file.rpaths # => ["/lib", "/usr/lib"] - # @param path [String] the new runtime path - # @param _options [Hash] - # @return [void] - # @raise [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 = LoadCommands::LoadCommand.create(:LC_RPATH, path) - add_command(rpath_cmd) - end - - # Delete the given runtime path from the Mach-O. - # @example - # file.rpaths # => ["/lib"] - # file.delete_rpath("/lib") - # file.rpaths # => [] - # @param path [String] the runtime path to delete - # @param _options [Hash] - # @return void - # @raise [RpathUnknownError] if no such runtime path exists - # @note `_options` is currently unused and is provided for signature - # compatibility with {MachO::FatFile#delete_rpath} - def delete_rpath(path, _options = {}) - rpath_cmds = command(:LC_RPATH).select { |r| r.path.to_s == path } - raise RpathUnknownError, path if rpath_cmds.empty? - - # delete the commands in reverse order, offset descending. this - # allows us to defer (expensive) field population until the very end - rpath_cmds.reverse_each { |cmd| delete_command(cmd, :repopulate => false) } - - populate_fields - end - - # 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. - # @return [void] - # @raise [MachOError] if the instance was initialized without a file - # @note Overwrites all data in the file! - def write! - if @filename.nil? - raise MachOError, "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 [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) ? Headers::MachHeader : Headers::MachHeader64 - mh = mh_klass.new_from_bin(endianness, @raw_data[0, mh_klass.bytesize]) - - check_cputype(mh.cputype) - check_cpusubtype(mh.cputype, mh.cpusubtype) - check_filetype(mh.filetype) - - mh - end - - # Read just the file's magic number and check its validity. - # @return [Fixnum] the magic - # @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 - - raise MagicError, magic unless Utils.magic?(magic) - raise FatBinaryError if Utils.fat_magic?(magic) - - @endianness = Utils.little_magic?(magic) ? :little : :big - - magic - end - - # Check the file's CPU type. - # @param cputype [Fixnum] the CPU type - # @raise [CPUTypeError] if the CPU type is unknown - # @api private - def check_cputype(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 [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 Headers::CPU_SUBTYPES[cputype].key?(cpusubtype) - end - - # Check the file's type. - # @param filetype [Fixnum] the file type - # @raise [FiletypeError] if the file type is unknown - # @api private - def check_filetype(filetype) - raise FiletypeError, filetype unless Headers::MH_FILETYPES.key?(filetype) - end - - # All load commands in the file. - # @return [Array] an array of load commands - # @raise [LoadCommandError] if an unknown load command is encountered - # @api private - def populate_load_commands - offset = header.class.bytesize - load_commands = [] - - header.ncmds.times do - fmt = Utils.specialize_format("L=", endianness) - cmd = @raw_data.slice(offset, 4).unpack(fmt).first - 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 = LoadCommands.const_get LoadCommands::LC_STRUCTURES[cmd_sym] - view = MachOView.new(@raw_data, endianness, offset) - command = klass.new_from_bin(view) - - load_commands << command - offset += command.cmdsize - end - - load_commands - end - - # The low file offset (offset to first section data). - # @return [Fixnum] the offset - # @api private - def low_fileoff - offset = @raw_data.size - - segments.each do |seg| - seg.sections.each do |sect| - next if sect.empty? - next if sect.flag?(:S_ZEROFILL) - next if sect.flag?(:S_THREAD_LOCAL_ZEROFILL) - next unless sect.offset < offset - - offset = sect.offset - end - end - - offset - end - - # Updates the number of load commands in the raw data. - # @param ncmds [Fixnum] the new number of commands - # @return [void] - # @api private - def update_ncmds(ncmds) - fmt = Utils.specialize_format("L=", endianness) - ncmds_raw = [ncmds].pack(fmt) - @raw_data[16..19] = ncmds_raw - end - - # Updates the size of all load commands in the raw data. - # @param size [Fixnum] the new size, in bytes - # @return [void] - # @api private - def update_sizeofcmds(size) - fmt = Utils.specialize_format("L=", endianness) - size_raw = [size].pack(fmt) - @raw_data[20..23] = size_raw - end - end -end diff --git a/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho/sections.rb b/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho/sections.rb deleted file mode 100644 index 1e69e0b61..000000000 --- a/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho/sections.rb +++ /dev/null @@ -1,176 +0,0 @@ -module MachO - # Classes and constants for parsing sections in Mach-O binaries. - module Sections - # 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, - }.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 - - # @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 diff --git a/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho/structure.rb b/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho/structure.rb deleted file mode 100644 index bac5342d4..000000000 --- a/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho/structure.rb +++ /dev/null @@ -1,30 +0,0 @@ -module MachO - # A general purpose pseudo-structure. - # @abstract - class MachOStructure - # The String#unpack format of the data structure. - # @return [String] the unpacking format - # @api private - FORMAT = "".freeze - - # The size of the data structure, in bytes. - # @return [Fixnum] the size, in bytes - # @api private - SIZEOF = 0 - - # @return [Fixnum] the size, in bytes, of the represented structure. - def self.bytesize - self::SIZEOF - end - - # @param endianness [Symbol] either `:big` or `:little` - # @param bin [String] the string to be unpacked into the new structure - # @return [MachO::MachOStructure] the resulting structure - # @api private - def self.new_from_bin(endianness, bin) - format = Utils.specialize_format(self::FORMAT, endianness) - - new(*bin.unpack(format)) - end - end -end diff --git a/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho/tools.rb b/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho/tools.rb deleted file mode 100644 index b49626d9d..000000000 --- a/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho/tools.rb +++ /dev/null @@ -1,108 +0,0 @@ -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] 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 - # @param options [Hash] - # @option options [Boolean] :strict (true) whether or not to fail loudly - # with an exception if the change cannot be performed - # @return [void] - def self.change_dylib_id(filename, new_id, options = {}) - file = MachO.open(filename) - - file.change_dylib_id(new_id, options) - 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 - # @param options [Hash] - # @option options [Boolean] :strict (true) whether or not to fail loudly - # with an exception if the change cannot be performed - # @return [void] - def self.change_install_name(filename, old_name, new_name, options = {}) - file = MachO.open(filename) - - file.change_install_name(old_name, new_name, options) - 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 - # @param options [Hash] - # @option options [Boolean] :strict (true) whether or not to fail loudly - # with an exception if the change cannot be performed - # @return [void] - def self.change_rpath(filename, old_path, new_path, options = {}) - file = MachO.open(filename) - - file.change_rpath(old_path, new_path, options) - file.write! - 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 - # @param options [Hash] - # @option options [Boolean] :strict (true) whether or not to fail loudly - # with an exception if the change cannot be performed - # @return [void] - def self.add_rpath(filename, new_path, options = {}) - file = MachO.open(filename) - - file.add_rpath(new_path, options) - file.write! - 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 - # @param options [Hash] - # @option options [Boolean] :strict (true) whether or not to fail loudly - # with an exception if the change cannot be performed - # @return [void] - def self.delete_rpath(filename, old_path, options = {}) - file = MachO.open(filename) - - 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] 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 diff --git a/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho/utils.rb b/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho/utils.rb deleted file mode 100644 index ecfc8390b..000000000 --- a/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho/utils.rb +++ /dev/null @@ -1,99 +0,0 @@ -module MachO - # A collection of utility functions used throughout ruby-macho. - module Utils - # Rounds a value to the next multiple of the given round. - # @param value [Fixnum] the number being rounded - # @param round [Fixnum] the number being rounded with - # @return [Fixnum] the rounded value - # @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 - - # 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 - def self.padding_for(size, alignment) - round(size, alignment) - size - end - - # 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 - def self.specialize_format(format, endianness) - modifier = endianness == :big ? ">" : "<" - format.tr("=", modifier) - end - - # Packs tagged strings into an aligned payload. - # @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] the packed string and labeled offsets - def self.pack_strings(fixed_offset, alignment, strings = {}) - offsets = {} - next_offset = fixed_offset - payload = "" - - strings.each do |key, string| - offsets[key] = next_offset - payload << string - payload << "\x00" - next_offset += string.bytesize + 1 - end - - payload << "\x00" * padding_for(fixed_offset + payload.bytesize, alignment) - [payload, offsets] - end - - # Compares the given number to valid Mach-O magic numbers. - # @param num [Fixnum] the number being checked - # @return [Boolean] whether `num` is a valid Mach-O magic number - def self.magic?(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] whether `num` is a valid Fat magic number - def self.fat_magic?(num) - 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] whether `num` is a valid 32-bit magic number - def self.magic32?(num) - 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] whether `num` is a valid 64-bit magic number - def self.magic64?(num) - 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] whether `num` is a valid little-endian magic number - def self.little_magic?(num) - 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] whether `num` is a valid big-endian magic number - def self.big_magic?(num) - num == Headers::MH_CIGAM || num == Headers::MH_CIGAM_64 - end - end -end diff --git a/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho/view.rb b/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho/view.rb deleted file mode 100644 index 9586e73be..000000000 --- a/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho/view.rb +++ /dev/null @@ -1,23 +0,0 @@ -module MachO - # A representation of some unspecified Mach-O data. - class MachOView - # @return [String] the raw Mach-O data - attr_reader :raw_data - - # @return [Symbol] the endianness of the data (`:big` or `:little`) - attr_reader :endianness - - # @return [Fixnum] the offset of the relevant data (in {#raw_data}) - attr_reader :offset - - # Creates a new MachOView. - # @param raw_data [String] the raw Mach-O data - # @param endianness [Symbol] the endianness of the data - # @param offset [Fixnum] the offset of the relevant data - def initialize(raw_data, endianness, offset) - @raw_data = raw_data - @endianness = endianness - @offset = offset - end - end -end -- cgit v1.2.3