From ee253e465b8e2f5acdb53daf572311e87055e082 Mon Sep 17 00:00:00 2001 From: Mike McQuaid Date: Sun, 7 May 2017 13:52:57 +0100 Subject: Vendor all Homebrew's gems. Homebrew's actually ended up using a fair few gems. While we want to avoid Bundler at runtime (and this PR still does that, in fact uses Bundler even less at runtime than it did before) writing our own version to use at build-time seems redundant. --- .bundle/config | 5 + .gitignore | 29 +- .travis.yml | 9 +- Gemfile | 36 + Gemfile.lock | 84 ++ 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 + 58 files changed, 4417 insertions(+), 4285 deletions(-) create mode 100644 .bundle/config create mode 100644 Gemfile create mode 100644 Gemfile.lock delete mode 100644 Library/Homebrew/constants.rb delete mode 100644 Library/Homebrew/test/Gemfile delete mode 100644 Library/Homebrew/test/Gemfile.lock delete mode 100644 Library/Homebrew/vendor/README.md create mode 100644 Library/Homebrew/vendor/bundler/setup.rb delete mode 100644 Library/Homebrew/vendor/macho/macho.rb delete mode 100644 Library/Homebrew/vendor/macho/macho/exceptions.rb delete mode 100644 Library/Homebrew/vendor/macho/macho/fat_file.rb delete mode 100644 Library/Homebrew/vendor/macho/macho/headers.rb delete mode 100644 Library/Homebrew/vendor/macho/macho/load_commands.rb delete mode 100644 Library/Homebrew/vendor/macho/macho/macho_file.rb delete mode 100644 Library/Homebrew/vendor/macho/macho/sections.rb delete mode 100644 Library/Homebrew/vendor/macho/macho/structure.rb delete mode 100644 Library/Homebrew/vendor/macho/macho/tools.rb delete mode 100644 Library/Homebrew/vendor/macho/macho/utils.rb delete mode 100644 Library/Homebrew/vendor/macho/macho/view.rb delete mode 100755 Library/Homebrew/vendor/plist/plist.rb delete mode 100755 Library/Homebrew/vendor/plist/plist/generator.rb delete mode 100755 Library/Homebrew/vendor/plist/plist/parser.rb delete mode 100755 Library/Homebrew/vendor/plist/plist/version.rb create mode 100644 Library/Homebrew/vendor/ruby/2.0.0/gems/plist-3.3.0/LICENSE.txt create mode 100644 Library/Homebrew/vendor/ruby/2.0.0/gems/plist-3.3.0/lib/plist.rb create mode 100644 Library/Homebrew/vendor/ruby/2.0.0/gems/plist-3.3.0/lib/plist/generator.rb create mode 100755 Library/Homebrew/vendor/ruby/2.0.0/gems/plist-3.3.0/lib/plist/parser.rb create mode 100644 Library/Homebrew/vendor/ruby/2.0.0/gems/plist-3.3.0/lib/plist/version.rb create mode 100644 Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/LICENSE create mode 100644 Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho.rb create mode 100644 Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho/exceptions.rb create mode 100644 Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho/fat_file.rb create mode 100644 Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho/headers.rb create mode 100644 Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho/load_commands.rb create mode 100644 Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho/macho_file.rb create mode 100644 Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho/sections.rb create mode 100644 Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho/structure.rb create mode 100644 Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho/tools.rb create mode 100644 Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho/utils.rb create mode 100644 Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/macho/view.rb diff --git a/.bundle/config b/.bundle/config new file mode 100644 index 000000000..0007666fd --- /dev/null +++ b/.bundle/config @@ -0,0 +1,5 @@ +--- +BUNDLE_CLEAN: "true" +BUNDLE_DISABLE_SHARED_GEMS: "true" +BUNDLE_PATH: "Library/Homebrew/vendor" +BUNDLE_JOBS: "3" diff --git a/.gitignore b/.gitignore index f7770612e..5708a50f5 100644 --- a/.gitignore +++ b/.gitignore @@ -8,15 +8,10 @@ !/Library/ # Ignore generated files within `Library` (again). -/Library/Homebrew/**/.bundle -/Library/Homebrew/**/vendor/bundle /Library/Homebrew/doc /Library/Homebrew/cask/bin /Library/Homebrew/cask/coverage /Library/Homebrew/cask/tmp -/Library/Homebrew/test/bin -/Library/Homebrew/test/coverage -/Library/Homebrew/test/fs_leak_log /Library/Homebrew/tmp /Library/LinkedKegs /Library/Locks @@ -24,8 +19,24 @@ /Library/PinnedTaps /Library/Taps -# Ignore vendored files within `Library`. +# Ignore some vendored files within `Library`. /Library/Homebrew/vendor/portable-ruby +/Library/Homebrew/vendor/ruby/2.0.0/bin +/Library/Homebrew/vendor/ruby/2.0.0/cache +/Library/Homebrew/vendor/ruby/2.0.0/extensions +/Library/Homebrew/vendor/ruby/2.0.0/gems/* +/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-*/* +/Library/Homebrew/vendor/ruby/2.0.0/gems/plist-*/* +/Library/Homebrew/vendor/ruby/2.0.0/specifications +/Library/Homebrew/vendor/ruby/2.0.0/tmp + +# Unignore our vendored gems +!/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-* +!/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-*/LICENSE* +!/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-*/lib +!/Library/Homebrew/vendor/ruby/2.0.0/gems/plist-* +!/Library/Homebrew/vendor/ruby/2.0.0/gems/plist-*/LICENSE* +!/Library/Homebrew/vendor/ruby/2.0.0/gems/plist-*/lib # Ignore `bin` contents (again). /bin @@ -50,13 +61,13 @@ !/completions # Unignore our root-level metadata files. +!/.bundle !/.gitignore !/.travis.yml !/.yardopts !/CODEOFCONDUCT.md !/CONTRIBUTING.md +!/Gemfile +!/Gemfile.lock !/LICENSE.txt !/README.md - -# Unignore tests' bundle config -!/Library/Homebrew/test/.bundle diff --git a/.travis.yml b/.travis.yml index 5e1906a5c..f268e40ec 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,6 @@ language: ruby -cache: - directories: - - $HOME/.gem/ruby - - Library/Homebrew/vendor/bundle +bundler_args: --path Library/Homebrew/vendor --standalone --jobs 3 +cache: bundler matrix: include: @@ -13,6 +11,9 @@ matrix: rvm: 2.0.0 before_install: + - export GEM_HOME="$PWD/Library/Homebrew/vendor/ruby/2.0.0" + - gem list --installed bundler || gem install bundler + - export PATH="$GEM_HOME/bin:$PATH" - export HOMEBREW_DEVELOPER=1 - if [ "${TRAVIS_OS_NAME}" = "osx" ]; then HOMEBREW_REPOSITORY="$(brew --repo)"; diff --git a/Gemfile b/Gemfile new file mode 100644 index 000000000..d39abd77a --- /dev/null +++ b/Gemfile @@ -0,0 +1,36 @@ +source "https://rubygems.org" + +# brew * +gem "ruby-macho" + +# brew cask +gem "plist" + +# brew cask style +group :cask_style do + gem "rubocop-cask", "~> 0.12.0" +end + +# brew man +group :man do + gem "ronn" +end + +# brew style +group :style do + gem "rubocop", "~> 0.47.1" +end + +# brew tests +group :tests do + gem "parallel_tests" + gem "rspec" + gem "rspec-its", require: false + gem "rspec-wait", require: false +end + +# brew tests --coverage +group :coverage do + gem "codecov", require: false + gem "simplecov", require: false +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 000000000..be4521e0e --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,84 @@ +GEM + remote: https://rubygems.org/ + specs: + ast (2.3.0) + codecov (0.1.10) + json + simplecov + url + diff-lcs (1.3) + docile (1.1.5) + hpricot (0.8.6) + json (2.1.0) + mustache (1.0.5) + parallel (1.11.1) + parallel_tests (2.14.1) + parallel + parser (2.4.0.0) + ast (~> 2.2) + plist (3.3.0) + powerpack (0.1.1) + public_suffix (2.0.5) + rainbow (2.2.2) + rake + rake (12.0.0) + rdiscount (2.2.0.1) + ronn (0.7.3) + hpricot (>= 0.8.2) + mustache (>= 0.7.0) + rdiscount (>= 1.5.8) + rspec (3.6.0) + rspec-core (~> 3.6.0) + rspec-expectations (~> 3.6.0) + rspec-mocks (~> 3.6.0) + rspec-core (3.6.0) + rspec-support (~> 3.6.0) + rspec-expectations (3.6.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.6.0) + rspec-its (1.2.0) + rspec-core (>= 3.0.0) + rspec-expectations (>= 3.0.0) + rspec-mocks (3.6.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.6.0) + rspec-support (3.6.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) + rubocop-cask (0.12.0) + public_suffix (~> 2.0) + rubocop (~> 0.47.1) + ruby-macho (1.1.0) + ruby-progressbar (1.8.1) + simplecov (0.14.1) + docile (~> 1.1.0) + json (>= 1.8, < 3) + simplecov-html (~> 0.10.0) + simplecov-html (0.10.0) + unicode-display_width (1.2.1) + url (0.3.2) + +PLATFORMS + ruby + +DEPENDENCIES + codecov + parallel_tests + plist + ronn + rspec + rspec-its + rspec-wait + rubocop (~> 0.47.1) + rubocop-cask (~> 0.12.0) + ruby-macho + simplecov + +BUNDLED WITH + 1.14.6 diff --git a/Library/Homebrew/brew.rb b/Library/Homebrew/brew.rb index e07599ac6..6dab50f29 100644 --- a/Library/Homebrew/brew.rb +++ b/Library/Homebrew/brew.rb @@ -8,9 +8,14 @@ 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(__FILE__).realpath.parent -$:.unshift(HOMEBREW_LIBRARY_PATH.to_s) +HOMEBREW_LIBRARY_PATH = Pathname.new(homebrew_library_path) + require "global" require "tap" @@ -20,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 @@ -52,6 +59,14 @@ 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 c43481c82..1ba2b4b97 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 "vendor/plist/plist" +require "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 191aefd3c..930742ed7 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.install_gem_setup_path! "rubocop-cask", HOMEBREW_RUBOCOP_CASK_VERSION, "rubocop" + Homebrew.run_bundler_if_needed! 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 848f6d4be..61bd4ef9b 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 "vendor/macho/macho" +require "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 c14079bc8..d610f0fde 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 "vendor/plist/plist" +require "plist" require "extend/io" diff --git a/Library/Homebrew/cmd/style.rb b/Library/Homebrew/cmd/style.rb index cf41d91ee..48ec3ee2e 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.install_gem_setup_path! "rubocop", HOMEBREW_RUBOCOP_VERSION + Homebrew.run_bundler_if_needed! require "rubocop" require_relative "../rubocops" diff --git a/Library/Homebrew/config.rb b/Library/Homebrew/config.rb index 30b7bc6c9..38d7c8043 100644 --- a/Library/Homebrew/config.rb +++ b/Library/Homebrew/config.rb @@ -2,8 +2,6 @@ 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 deleted file mode 100644 index 827d5827f..000000000 --- a/Library/Homebrew/constants.rb +++ /dev/null @@ -1,3 +0,0 @@ -# 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 cb25ca794..9ea3faf11 100644 --- a/Library/Homebrew/dev-cmd/audit.rb +++ b/Library/Homebrew/dev-cmd/audit.rb @@ -65,6 +65,9 @@ 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 4e5103910..6e71c248b 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.install_gem_setup_path! "ronn" + Homebrew.run_bundler_if_needed! 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 72d6143fc..da1f5365c 100644 --- a/Library/Homebrew/dev-cmd/tests.rb +++ b/Library/Homebrew/dev-cmd/tests.rb @@ -49,8 +49,6 @@ 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| @@ -59,10 +57,7 @@ module Homebrew ENV["GIT_#{role}_DATE"] = "Sun Jan 22 19:59:13 2017 +0000" end - Homebrew.install_gem_setup_path! "bundler" - unless quiet_system("bundle", "check") - system "bundle", "install" - end + Homebrew.run_bundler_if_needed! parallel = true @@ -106,10 +101,15 @@ module Homebrew files = files.reject { |p| p =~ %r{^test/os/linux(/.*|_spec\.rb)$} } end - if parallel - system "bundle", "exec", "parallel_rspec", *opts, "--", *args, "--", *files - else - system "bundle", "exec", "rspec", *args, "--", *files + 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" end return if $?.success? diff --git a/Library/Homebrew/os/mac/mach.rb b/Library/Homebrew/os/mac/mach.rb index 9b53c4979..71f501fe9 100644 --- a/Library/Homebrew/os/mac/mach.rb +++ b/Library/Homebrew/os/mac/mach.rb @@ -1,4 +1,4 @@ -require "vendor/macho/macho" +require "macho" require "os/mac/architecture_list" module MachOShim diff --git a/Library/Homebrew/test/Gemfile b/Library/Homebrew/test/Gemfile deleted file mode 100644 index f3c16c710..000000000 --- a/Library/Homebrew/test/Gemfile +++ /dev/null @@ -1,12 +0,0 @@ -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 deleted file mode 100644 index 4d4eefd7d..000000000 --- a/Library/Homebrew/test/Gemfile.lock +++ /dev/null @@ -1,65 +0,0 @@ -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 3736f3c01..a8c4ecf5f 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.relative_path_from(file_dirname) } + let(:relative_tap_path) { tap_path.realpath.relative_path_from(file_dirname) } it "returns an instance of the Cask for the given token" do c = Hbc::CaskLoader.load("local-caffeine") @@ -56,7 +56,9 @@ describe Hbc::Cask, :cask do end it "returns an instance of the Cask from a relative file location" do - c = Hbc::CaskLoader.load(relative_tap_path/"Casks/local-caffeine.rb") + c = file_dirname.cd do + Hbc::CaskLoader.load(relative_tap_path/"Casks/local-caffeine.rb") + end 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 d41636beb..d021d8000 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(:install_gem_setup_path!) + allow(Homebrew).to receive(:run_bundler_if_needed!) 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(:install_gem_setup_path!).and_raise(SystemExit) + allow(Homebrew).to receive(:run_bundler_if_needed!).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 ae1854f58..3a36f1853 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,12 +89,10 @@ RSpec.shared_context "integration test" do ruby_args << "-rtest/support/helper/integration_mocks" ruby_args << (HOMEBREW_LIBRARY_PATH/"brew.rb").resolved_path.to_s - Bundler.with_original_env do - stdout, stderr, status = Open3.capture3(env, RUBY_PATH, *ruby_args, *args) - $stdout.print stdout - $stderr.print stderr - status - end + stdout, stderr, status = Open3.capture3(env, RUBY_PATH, *ruby_args, *args) + $stdout.print stdout + $stderr.print stderr + status 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 3a0a76722..fb5c210fe 100644 --- a/Library/Homebrew/test/support/lib/config.rb +++ b/Library/Homebrew/test/support/lib/config.rb @@ -2,8 +2,6 @@ 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 c37633e41..60af39d93 100644 --- a/Library/Homebrew/utils.rb +++ b/Library/Homebrew/utils.rb @@ -221,6 +221,38 @@ 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 deleted file mode 100644 index b408631c7..000000000 --- a/Library/Homebrew/vendor/README.md +++ /dev/null @@ -1,54 +0,0 @@ -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 new file mode 100644 index 000000000..1fdc2512f --- /dev/null +++ b/Library/Homebrew/vendor/bundler/setup.rb @@ -0,0 +1,42 @@ +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 deleted file mode 100644 index b7f20ea19..000000000 --- a/Library/Homebrew/vendor/macho/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/macho/macho/exceptions.rb b/Library/Homebrew/vendor/macho/macho/exceptions.rb deleted file mode 100644 index 14c2c22ae..000000000 --- a/Library/Homebrew/vendor/macho/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/macho/macho/fat_file.rb b/Library/Homebrew/vendor/macho/macho/fat_file.rb deleted file mode 100644 index 351be5ac6..000000000 --- a/Library/Homebrew/vendor/macho/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/macho/macho/headers.rb b/Library/Homebrew/vendor/macho/macho/headers.rb deleted file mode 100644 index 08a4b80c4..000000000 --- a/Library/Homebrew/vendor/macho/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/macho/macho/load_commands.rb b/Library/Homebrew/vendor/macho/macho/load_commands.rb deleted file mode 100644 index be4319ee2..000000000 --- a/Library/Homebrew/vendor/macho/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/macho/macho/macho_file.rb b/Library/Homebrew/vendor/macho/macho/macho_file.rb deleted file mode 100644 index 7693ab0dd..000000000 --- a/Library/Homebrew/vendor/macho/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/macho/macho/sections.rb b/Library/Homebrew/vendor/macho/macho/sections.rb deleted file mode 100644 index 1e69e0b61..000000000 --- a/Library/Homebrew/vendor/macho/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/macho/macho/structure.rb b/Library/Homebrew/vendor/macho/macho/structure.rb deleted file mode 100644 index bac5342d4..000000000 --- a/Library/Homebrew/vendor/macho/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/macho/macho/tools.rb b/Library/Homebrew/vendor/macho/macho/tools.rb deleted file mode 100644 index b49626d9d..000000000 --- a/Library/Homebrew/vendor/macho/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/macho/macho/utils.rb b/Library/Homebrew/vendor/macho/macho/utils.rb deleted file mode 100644 index ecfc8390b..000000000 --- a/Library/Homebrew/vendor/macho/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/macho/macho/view.rb b/Library/Homebrew/vendor/macho/macho/view.rb deleted file mode 100644 index 9586e73be..000000000 --- a/Library/Homebrew/vendor/macho/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 diff --git a/Library/Homebrew/vendor/plist/plist.rb b/Library/Homebrew/vendor/plist/plist.rb deleted file mode 100755 index 82ecb27d2..000000000 --- a/Library/Homebrew/vendor/plist/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_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 deleted file mode 100755 index 84bef3aaf..000000000 --- a/Library/Homebrew/vendor/plist/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/plist/plist/parser.rb b/Library/Homebrew/vendor/plist/plist/parser.rb deleted file mode 100755 index 4de13f881..000000000 --- a/Library/Homebrew/vendor/plist/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/plist/plist/version.rb b/Library/Homebrew/vendor/plist/plist/version.rb deleted file mode 100755 index 80b1f73dd..000000000 --- a/Library/Homebrew/vendor/plist/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/plist-3.3.0/LICENSE.txt b/Library/Homebrew/vendor/ruby/2.0.0/gems/plist-3.3.0/LICENSE.txt new file mode 100644 index 000000000..0ccffe7bf --- /dev/null +++ b/Library/Homebrew/vendor/ruby/2.0.0/gems/plist-3.3.0/LICENSE.txt @@ -0,0 +1,20 @@ +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 new file mode 100644 index 000000000..986dad461 --- /dev/null +++ b/Library/Homebrew/vendor/ruby/2.0.0/gems/plist-3.3.0/lib/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 '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 new file mode 100644 index 000000000..84bef3aaf --- /dev/null +++ b/Library/Homebrew/vendor/ruby/2.0.0/gems/plist-3.3.0/lib/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/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 new file mode 100755 index 000000000..4de13f881 --- /dev/null +++ b/Library/Homebrew/vendor/ruby/2.0.0/gems/plist-3.3.0/lib/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/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 new file mode 100644 index 000000000..80b1f73dd --- /dev/null +++ b/Library/Homebrew/vendor/ruby/2.0.0/gems/plist-3.3.0/lib/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/ruby-macho-1.1.0/LICENSE b/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/LICENSE new file mode 100644 index 000000000..d68fe0fbd --- /dev/null +++ b/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/LICENSE @@ -0,0 +1,21 @@ +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 new file mode 100644 index 000000000..b7f20ea19 --- /dev/null +++ b/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/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/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 new file mode 100644 index 000000000..14c2c22ae --- /dev/null +++ b/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/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/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 new file mode 100644 index 000000000..351be5ac6 --- /dev/null +++ b/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/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/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 new file mode 100644 index 000000000..08a4b80c4 --- /dev/null +++ b/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/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/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 new file mode 100644 index 000000000..be4319ee2 --- /dev/null +++ b/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/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/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 new file mode 100644 index 000000000..7693ab0dd --- /dev/null +++ b/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/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/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 new file mode 100644 index 000000000..1e69e0b61 --- /dev/null +++ b/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/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/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 new file mode 100644 index 000000000..bac5342d4 --- /dev/null +++ b/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/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/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 new file mode 100644 index 000000000..b49626d9d --- /dev/null +++ b/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/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/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 new file mode 100644 index 000000000..ecfc8390b --- /dev/null +++ b/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/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/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 new file mode 100644 index 000000000..9586e73be --- /dev/null +++ b/Library/Homebrew/vendor/ruby/2.0.0/gems/ruby-macho-1.1.0/lib/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 -- cgit v1.2.3