diff options
Diffstat (limited to 'Library')
53 files changed, 3016 insertions, 2603 deletions
diff --git a/Library/Homebrew/blacklist.rb b/Library/Homebrew/blacklist.rb deleted file mode 100644 index 93c8f81a0..000000000 --- a/Library/Homebrew/blacklist.rb +++ /dev/null @@ -1,92 +0,0 @@ -def blacklisted?(name) - case name.downcase - when "gem", /^rubygems?$/ then <<-EOS.undent - Homebrew provides gem via: `brew install ruby`. - EOS - when "tex", "tex-live", "texlive", "latex" then <<-EOS.undent - Installing TeX from source is weird and gross, requires a lot of patches, - and only builds 32-bit (and thus can't use Homebrew dependencies) - - We recommend using a MacTeX distribution: https://www.tug.org/mactex/ - - You can install it with Homebrew-Cask: - brew cask install mactex - EOS - when "pip" then <<-EOS.undent - Homebrew provides pip via: `brew install python`. However you will then - have two Pythons installed on your Mac, so alternatively you can install - pip via the instructions at: - #{Formatter.url("https://pip.readthedocs.io/en/stable/installing/")} - EOS - when "pil" then <<-EOS.undent - Instead of PIL, consider `pip install pillow` or `brew install Homebrew/python/pillow`. - EOS - when "macruby" then <<-EOS.undent - MacRuby is not packaged and is on an indefinite development hiatus. - You can read more about it at: - #{Formatter.url("https://github.com/MacRuby/MacRuby")} - EOS - when /(lib)?lzma/ - "lzma is now part of the xz formula." - when "gtest", "googletest", "google-test" then <<-EOS.undent - Installing gtest system-wide is not recommended; it should be vendored - in your projects that use it. - EOS - when "gmock", "googlemock", "google-mock" then <<-EOS.undent - Installing gmock system-wide is not recommended; it should be vendored - in your projects that use it. - EOS - when "sshpass" then <<-EOS.undent - We won't add sshpass because it makes it too easy for novice SSH users to - ruin SSH's security. - EOS - when "gsutil" then <<-EOS.undent - Install gsutil with `pip install gsutil` - EOS - when "clojure" then <<-EOS.undent - Clojure isn't really a program but a library managed as part of a - project and Leiningen is the user interface to that library. - - To install Clojure you should install Leiningen: - brew install leiningen - and then follow the tutorial: - #{Formatter.url("https://github.com/technomancy/leiningen/blob/stable/doc/TUTORIAL.md")} - EOS - when "osmium" then <<-EOS.undent - The creator of Osmium requests that it not be packaged and that people - use the GitHub master branch instead. - EOS - when "gfortran" then <<-EOS.undent - GNU Fortran is now provided as part of GCC, and can be installed with: - brew install gcc - EOS - when "play" then <<-EOS.undent - Play 2.3 replaces the play command with activator: - brew install typesafe-activator - - You can read more about this change at: - #{Formatter.url("https://www.playframework.com/documentation/2.3.x/Migration23")} - #{Formatter.url("https://www.playframework.com/documentation/2.3.x/Highlights23")} - EOS - when "haskell-platform" then <<-EOS.undent - We no longer package haskell-platform. Consider installing ghc - and cabal-install instead: - brew install ghc cabal-install - - You can install with Homebrew-Cask: - brew cask install haskell-platform - EOS - when "mysqldump-secure" then <<-EOS.undent - The creator of mysqldump-secure tried to game our popularity metrics. - EOS - when "ngrok" then <<-EOS.undent - Upstream sunsetted 1.x in March 2016 and 2.x is not open-source. - - If you wish to use the 2.x release you can install with Homebrew-Cask: - brew cask install ngrok - EOS - end -end -alias generic_blacklisted? blacklisted? - -require "extend/os/blacklist" diff --git a/Library/Homebrew/cask/lib/hbc/container.rb b/Library/Homebrew/cask/lib/hbc/container.rb index fc7246f3d..c6b2c3c37 100644 --- a/Library/Homebrew/cask/lib/hbc/container.rb +++ b/Library/Homebrew/cask/lib/hbc/container.rb @@ -4,6 +4,7 @@ require "hbc/container/bzip2" require "hbc/container/cab" require "hbc/container/criteria" require "hbc/container/dmg" +require "hbc/container/executable" require "hbc/container/generic_unar" require "hbc/container/gzip" require "hbc/container/lzma" @@ -39,6 +40,7 @@ module Hbc Gzip, # pure gzip Lzma, # pure lzma Xz, # pure xz + Executable, ] # for explicit use only (never autodetected): # Hbc::Container::Naked diff --git a/Library/Homebrew/cask/lib/hbc/container/executable.rb b/Library/Homebrew/cask/lib/hbc/container/executable.rb new file mode 100644 index 000000000..848f6d4be --- /dev/null +++ b/Library/Homebrew/cask/lib/hbc/container/executable.rb @@ -0,0 +1,18 @@ +require "hbc/container/naked" +require "vendor/macho/macho" + +module Hbc + class Container + class Executable < Naked + def self.me?(criteria) + return true if criteria.magic_number(/^#!\s*\S+/) + + begin + MachO.open(criteria.path).header.executable? + rescue MachO::MagicError + false + end + end + end + end +end diff --git a/Library/Homebrew/cmd/info.rb b/Library/Homebrew/cmd/info.rb index b7de0005c..e7ad6821d 100644 --- a/Library/Homebrew/cmd/info.rb +++ b/Library/Homebrew/cmd/info.rb @@ -16,7 +16,7 @@ #: See the docs for examples of using the JSON output: #: <http://docs.brew.sh/Querying-Brew.html> -require "blacklist" +require "missing_formula" require "caveats" require "options" require "formula" @@ -54,10 +54,12 @@ module Homebrew else info_formula Formulary.find_with_priority(f) end - rescue FormulaUnavailableError - # No formula with this name, try a blacklist lookup - raise unless (blacklist = blacklisted?(f)) - puts blacklist + rescue FormulaUnavailableError => e + ofail e.message + # No formula with this name, try a missing formula lookup + if (reason = Homebrew::MissingFormula.reason(f)) + $stderr.puts reason + end end end end diff --git a/Library/Homebrew/cmd/install.rb b/Library/Homebrew/cmd/install.rb index c825e2796..e54286f09 100644 --- a/Library/Homebrew/cmd/install.rb +++ b/Library/Homebrew/cmd/install.rb @@ -55,7 +55,7 @@ #: If `--git` is passed, Homebrew will create a Git repository, useful for #: creating patches to the software. -require "blacklist" +require "missing_formula" require "diagnostic" require "cmd/search" require "formula_installer" @@ -206,43 +206,47 @@ module Homebrew # formula was found, but there's a problem with its implementation). ofail e.message rescue FormulaUnavailableError => e - if (blacklist = blacklisted?(e.name)) - ofail "#{e.message}\n#{blacklist}" - elsif e.name == "updog" + if e.name == "updog" ofail "What's updog?" + return + end + + ofail e.message + if (reason = Homebrew::MissingFormula.reason(e.name)) + $stderr.puts reason + return + end + + query = query_regexp(e.name) + + ohai "Searching for similarly named formulae..." + formulae_search_results = search_formulae(query) + case formulae_search_results.length + when 0 + ofail "No similarly named formulae found." + when 1 + puts "This similarly named formula was found:" + puts formulae_search_results + puts "To install it, run:\n brew install #{formulae_search_results.first}" else - ofail e.message - query = query_regexp(e.name) - - ohai "Searching for similarly named formulae..." - formulae_search_results = search_formulae(query) - case formulae_search_results.length - when 0 - ofail "No similarly named formulae found." - when 1 - puts "This similarly named formula was found:" - puts formulae_search_results - puts "To install it, run:\n brew install #{formulae_search_results.first}" - else - puts "These similarly named formulae were found:" - puts Formatter.columns(formulae_search_results) - puts "To install one of them, run (for example):\n brew install #{formulae_search_results.first}" - end + puts "These similarly named formulae were found:" + puts Formatter.columns(formulae_search_results) + puts "To install one of them, run (for example):\n brew install #{formulae_search_results.first}" + end - ohai "Searching taps..." - taps_search_results = search_taps(query) - case taps_search_results.length - when 0 - ofail "No formulae found in taps." - when 1 - puts "This formula was found in a tap:" - puts taps_search_results - puts "To install it, run:\n brew install #{taps_search_results.first}" - else - puts "These formulae were found in taps:" - puts Formatter.columns(taps_search_results) - puts "To install one of them, run (for example):\n brew install #{taps_search_results.first}" - end + ohai "Searching taps..." + taps_search_results = search_taps(query) + case taps_search_results.length + when 0 + ofail "No formulae found in taps." + when 1 + puts "This formula was found in a tap:" + puts taps_search_results + puts "To install it, run:\n brew install #{taps_search_results.first}" + else + puts "These formulae were found in taps:" + puts Formatter.columns(taps_search_results) + puts "To install one of them, run (for example):\n brew install #{taps_search_results.first}" end end end diff --git a/Library/Homebrew/cmd/link.rb b/Library/Homebrew/cmd/link.rb index 98cf98bf7..293f09eef 100644 --- a/Library/Homebrew/cmd/link.rb +++ b/Library/Homebrew/cmd/link.rb @@ -44,6 +44,7 @@ module Homebrew elsif keg_only && !ARGV.force? opoo "#{keg.name} is keg-only and must be linked with --force" puts "Note that doing so can interfere with building software." + puts_keg_only_path_message(keg) next elsif mode.dry_run && mode.overwrite puts "Would remove:" @@ -53,6 +54,7 @@ module Homebrew elsif mode.dry_run puts "Would link:" keg.link(mode) + puts_keg_only_path_message(keg) if keg_only next end @@ -69,10 +71,25 @@ module Homebrew else puts "#{n} symlinks created" end + + if keg_only && !ARGV.homebrew_developer? + puts_keg_only_path_message(keg) + end end end end + def puts_keg_only_path_message(keg) + bin = keg/"bin" + sbin = keg/"sbin" + return if !bin.directory? && !sbin.directory? + + opt = HOMEBREW_PREFIX/"opt/#{keg.name}" + puts "\nIf you need to have this software first in your PATH instead consider running:" + puts " #{Utils::Shell.prepend_path_in_shell_profile(opt)}/bin" if bin.directory? + puts " #{Utils::Shell.prepend_path_in_shell_profile(opt)}/sbin" if sbin.directory? + end + def keg_only?(rack) Formulary.from_rack(rack).keg_only? rescue FormulaUnavailableError, TapFormulaAmbiguityError, TapFormulaWithOldnameAmbiguityError diff --git a/Library/Homebrew/cmd/log.rb b/Library/Homebrew/cmd/log.rb index 22a3ee11d..9323c762d 100644 --- a/Library/Homebrew/cmd/log.rb +++ b/Library/Homebrew/cmd/log.rb @@ -9,20 +9,32 @@ module Homebrew def log if ARGV.named.empty? - cd HOMEBREW_REPOSITORY - git_log + git_log HOMEBREW_REPOSITORY else path = Formulary.path(ARGV.named.first) - cd path.dirname # supports taps - git_log path + tap = Tap.from_path(path) + git_log path.dirname, path, tap end end - def git_log(path = nil) - if File.exist? "#{`git rev-parse --show-toplevel`.chomp}/.git/shallow" + def git_log(cd_dir, path = nil, tap = nil) + cd cd_dir + repo = Utils.popen_read("git rev-parse --show-toplevel").chomp + if tap + name = tap.to_s + git_cd = "$(brew --repo #{tap})" + elsif cd_dir == HOMEBREW_REPOSITORY + name = "Homebrew/brew" + git_cd = "$(brew --repo)" + else + name, git_cd = cd_dir + end + + if File.exist? "#{repo}/.git/shallow" opoo <<-EOS.undent - The git repository is a shallow clone therefore the filtering may be incorrect. - Use `git fetch --unshallow` to get the full repository. + #{name} is a shallow clone so only partial output will be shown. + To get a full clone run: + git -C "#{git_cd}" fetch --unshallow EOS end args = ARGV.options_only diff --git a/Library/Homebrew/cmd/outdated.rb b/Library/Homebrew/cmd/outdated.rb index a18f4e399..e94002989 100644 --- a/Library/Homebrew/cmd/outdated.rb +++ b/Library/Homebrew/cmd/outdated.rb @@ -64,7 +64,9 @@ module Homebrew "#{full_name} (#{kegs.map(&:version).join(", ")})" end.join(", ") - puts "#{outdated_versions} < #{current_version}" + pinned_version = " [pinned at #{f.pinned_version}]" if f.pinned? + + puts "#{outdated_versions} < #{current_version}#{pinned_version}" else puts f.full_installed_specified_name end @@ -86,7 +88,9 @@ module Homebrew json << { name: f.full_name, installed_versions: outdated_versions.collect(&:to_s), - current_version: current_version } + current_version: current_version, + pinned: f.pinned?, + pinned_version: f.pinned_version } end puts JSON.generate(json) diff --git a/Library/Homebrew/cmd/search.rb b/Library/Homebrew/cmd/search.rb index e834a00b5..443739f8c 100644 --- a/Library/Homebrew/cmd/search.rb +++ b/Library/Homebrew/cmd/search.rb @@ -14,7 +14,7 @@ #: Search for <text> in the given package manager's list. require "formula" -require "blacklist" +require "missing_formula" require "utils" require "thread" require "official_taps" @@ -67,13 +67,12 @@ module Homebrew if $stdout.tty? count = local_results.length + tap_results.length - if msg = blacklisted?(query) + if reason = Homebrew::MissingFormula.reason(query, silent: true) if count > 0 puts - puts "If you meant #{query.inspect} precisely:" - puts + puts "If you meant #{query.inspect} specifically:" end - puts msg + puts reason elsif count.zero? puts "No formula found for #{query.inspect}." begin diff --git a/Library/Homebrew/cmd/update-report.rb b/Library/Homebrew/cmd/update-report.rb index c13d82090..4002df75c 100644 --- a/Library/Homebrew/cmd/update-report.rb +++ b/Library/Homebrew/cmd/update-report.rb @@ -361,7 +361,10 @@ class Reporter case status when "A", "D" - @report[status.to_sym] << tap.formula_file_to_name(src) + full_name = tap.formula_file_to_name(src) + name = full_name.split("/").last + new_tap = tap.tap_migrations[name] + @report[status.to_sym] << full_name unless new_tap when "M" begin formula = Formulary.factory(tap.path/src) @@ -499,9 +502,15 @@ class Reporter end def migrate_formula_rename - report[:R].each do |old_full_name, new_full_name| - old_name = old_full_name.split("/").last - next unless (dir = HOMEBREW_CELLAR/old_name).directory? && !dir.subdirs.empty? + Formula.installed.map(&:oldname).compact.each do |old_name| + old_name_dir = HOMEBREW_CELLAR/old_name + next if old_name_dir.symlink? + next unless old_name_dir.directory? && !old_name_dir.subdirs.empty? + + new_name = tap.formula_renames[old_name] + next unless new_name + + new_full_name = "#{tap}/#{new_name}" begin f = Formulary.factory(new_full_name) diff --git a/Library/Homebrew/dev-cmd/audit.rb b/Library/Homebrew/dev-cmd/audit.rb index 677a52447..1a4bb24a1 100644 --- a/Library/Homebrew/dev-cmd/audit.rb +++ b/Library/Homebrew/dev-cmd/audit.rb @@ -38,7 +38,7 @@ require "official_taps" require "cmd/search" require "cmd/style" require "date" -require "blacklist" +require "missing_formula" require "digest" module Homebrew @@ -331,25 +331,33 @@ class FormulaAuditor problem "File should end with a newline" unless text.trailing_newline? - versioned_formulae = Dir[formula.path.to_s.gsub(/\.rb$/, "@*.rb")] - needs_versioned_alias = !versioned_formulae.empty? && - formula.tap && - formula.aliases.grep(/.@\d/).empty? - if needs_versioned_alias - _, last_alias_version = File.basename(versioned_formulae.sort.reverse.first) - .gsub(/\.rb$/, "") - .split("@") - major, minor, = formula.version.to_s.split(".") - alias_name = if last_alias_version.split(".").length == 1 - "#{formula.name}@#{major}" - else - "#{formula.name}@#{major}.#{minor}" + if formula.versioned_formula? + unversioned_formula = Pathname.new formula.path.to_s.gsub(/@.*\.rb$/, ".rb") + unless unversioned_formula.exist? + unversioned_name = unversioned_formula.basename(".rb") + problem "#{formula} is versioned but no #{unversioned_name} formula exists" + end + else + versioned_formulae = Dir[formula.path.to_s.gsub(/\.rb$/, "@*.rb")] + needs_versioned_alias = !versioned_formulae.empty? && + formula.tap && + formula.aliases.grep(/.@\d/).empty? + if needs_versioned_alias + _, last_alias_version = File.basename(versioned_formulae.sort.reverse.first) + .gsub(/\.rb$/, "") + .split("@") + major, minor, = formula.version.to_s.split(".") + alias_name = if last_alias_version.split(".").length == 1 + "#{formula.name}@#{major}" + else + "#{formula.name}@#{major}.#{minor}" + end + problem <<-EOS.undent + Formula has other versions so create an alias: + cd #{formula.tap.alias_dir} + ln -s #{formula.path.to_s.gsub(formula.tap.path, "..")} #{alias_name} + EOS end - problem <<-EOS.undent - Formula has other versions so create an alias: - cd #{formula.tap.alias_dir} - ln -s #{formula.path.to_s.gsub(formula.tap.path, "..")} #{alias_name} - EOS end return unless @strict @@ -399,7 +407,7 @@ class FormulaAuditor name = formula.name full_name = formula.full_name - if blacklisted?(name) + if Homebrew::MissingFormula.blacklisted_reason(name) problem "'#{name}' is blacklisted." end @@ -472,6 +480,12 @@ class FormulaAuditor problem "Dependency '#{dep.name}' is an alias; use the canonical name '#{dep.to_formula.full_name}'." end + if @new_formula && dep_f.keg_only_reason && + !["openssl", "apr", "apr-util"].include?(dep.name) && + [:provided_by_macos, :provided_by_osx].include?(dep_f.keg_only_reason.reason) + problem "Dependency '#{dep.name}' may be unnecessary as it is provided by macOS; try to build this formula without it." + end + dep.options.reject do |opt| next true if dep_f.option_defined?(opt) dep_f.requirements.detect do |r| @@ -775,7 +789,7 @@ class FormulaAuditor automysqlbackup 3.0-rc6 aview 1.3.0rc1 distcc 3.2rc1 - elm-format 0.5.2-alpha + elm-format 0.6.0-alpha ftgl 2.1.3-rc5 hidapi 0.8.0-rc1 libcaca 0.99b19 @@ -1036,6 +1050,10 @@ class FormulaAuditor problem ":apr is deprecated. Usage should be \"apr-util\"" end + if line =~ /depends_on :tex/ + problem ":tex is deprecated." + end + # Commented-out depends_on problem "Commented-out dep #{$1}" if line =~ /#\s*depends_on\s+(.+)\s*$/ @@ -1166,7 +1184,8 @@ class FormulaAuditor problem "Use `assert_match` instead of `assert ...include?`" end - if line.include?('system "npm", "install"') && !line.include?("Language::Node") && formula.name !~ /^kibana(\d{2})?$/ + if line.include?('system "npm", "install"') && !line.include?("Language::Node") && + formula.name !~ /^kibana(\@\d+(\.\d+)?)?$/ problem "Use Language::Node for npm install args" end @@ -1174,6 +1193,10 @@ class FormulaAuditor problem "'fails_with :llvm' is now a no-op so should be removed" end + if line =~ /system\s+['"](otool|install_name_tool|lipo)/ && formula.name != "cctools" + problem "Use ruby-macho instead of calling #{$1}" + end + if formula.tap.to_s == "homebrew/core" ["OS.mac?", "OS.linux?"].each do |check| next unless line.include?(check) diff --git a/Library/Homebrew/dev-cmd/boneyard-formula-pr.rb b/Library/Homebrew/dev-cmd/boneyard-formula-pr.rb deleted file mode 100644 index 7531ef9cf..000000000 --- a/Library/Homebrew/dev-cmd/boneyard-formula-pr.rb +++ /dev/null @@ -1,166 +0,0 @@ -#: @hide_from_man_page -#: * `boneyard-formula-pr` [`--dry-run`] [`--local`] [`--reason=<reason>`] <formula> : -#: Creates a pull request to boneyard a formula. -#: -#: If `--dry-run` is passed, print what would be done rather than doing it. -#: -#: If `--local` is passed, perform only local operations (i.e. don't push or create PR). -#: -#: If `--reason=<reason>` is passed, append this to the commit/PR message. - -require "formula" -require "json" -require "fileutils" - -begin - require "json" -rescue LoadError - puts "Homebrew does not provide Ruby dependencies; install with:" - puts " gem install json" - odie "Dependency json is not installed." -end - -module Homebrew - module_function - - def boneyard_formula_pr - local_only = ARGV.include?("--local") - formula = ARGV.formulae.first - reason = ARGV.value("reason") - odie "No formula found!" unless formula - - formula_relpath = formula.path.relative_path_from(formula.tap.path) - formula_file = "#{formula.name}.rb" - bottle_block = File.read(formula.path).include? " bottle do" - boneyard_tap = Tap.fetch("homebrew", "boneyard") - tap_migrations_path = formula.tap.path/"tap_migrations.json" - if ARGV.dry_run? - ohai "brew update" - ohai "brew tap #{boneyard_tap.name}" - ohai "cd #{formula.tap.path}" - cd formula.tap.path - ohai "cp #{formula_relpath} #{boneyard_tap.path}" - ohai "git rm #{formula_relpath}" - unless File.exist? tap_migrations_path - ohai "Creating tap_migrations.json for #{formula.tap.name}" - ohai "git add #{tap_migrations_path}" - end - ohai "Loading tap_migrations.json" - ohai "Adding #{formula.name} to tap_migrations.json" - else - safe_system HOMEBREW_BREW_FILE, "update" - safe_system HOMEBREW_BREW_FILE, "tap", boneyard_tap.name - cd formula.tap.path - cp formula_relpath, boneyard_tap.formula_dir - safe_system "git", "rm", formula_relpath - unless File.exist? tap_migrations_path - tap_migrations_path.write <<-EOS.undent - { - } - EOS - safe_system "git", "add", tap_migrations_path - end - tap_migrations = JSON.parse(File.read(tap_migrations_path)) - tap_migrations[formula.name] = boneyard_tap.name - tap_migrations = tap_migrations.sort.inject({}) { |acc, elem| acc.merge!(elem[0] => elem[1]) } - tap_migrations_path.atomic_write(JSON.pretty_generate(tap_migrations) + "\n") - end - unless which("hub") || local_only - if ARGV.dry_run? - ohai "brew install hub" - else - safe_system HOMEBREW_BREW_FILE, "install", "hub" - end - end - branch = "#{formula.name}-boneyard" - - reason = " because #{reason}" if reason - - if ARGV.dry_run? - ohai "cd #{formula.tap.path}" - ohai "git checkout --no-track -b #{branch} origin/master" - ohai "git commit --no-edit --verbose --message=\"#{formula.name}: migrate to boneyard\" -- #{formula_relpath} #{tap_migrations_path.basename}" - - unless local_only - ohai "hub fork --no-remote" - ohai "hub fork" - ohai "hub fork (to read $HUB_REMOTE)" - ohai "git push $HUB_REMOTE #{branch}:#{branch}" - ohai "hub pull-request -m $'#{formula.name}: migrate to boneyard\\n\\nCreated with `brew boneyard-formula-pr`#{reason}.'" - end - - ohai "git checkout -" - else - cd formula.tap.path - safe_system "git", "checkout", "--no-track", "-b", branch, "origin/master" - safe_system "git", "commit", "--no-edit", "--verbose", - "--message=#{formula.name}: migrate to boneyard", - "--", formula_relpath, tap_migrations_path.basename - - unless local_only - safe_system "hub", "fork", "--no-remote" - quiet_system "hub", "fork" - remote = Utils.popen_read("hub fork 2>&1")[/fatal: remote (.+) already exists\./, 1] - odie "cannot get remote from 'hub'!" unless remote - safe_system "git", "push", remote, "#{branch}:#{branch}" - pr_message = <<-EOS.undent - #{formula.name}: migrate to boneyard - - Created with `brew boneyard-formula-pr`#{reason}. - EOS - pr_url = Utils.popen_read("hub", "pull-request", "-m", pr_message).chomp - end - - safe_system "git", "checkout", "-" - end - - if ARGV.dry_run? - ohai "cd #{boneyard_tap.path}" - ohai "git checkout --no-track -b #{branch} origin/master" - if bottle_block - ohai "Removing bottle block" - else - ohai "No bottle block to remove" - end - ohai "git add #{formula_file}" - ohai "git commit --no-edit --verbose --message=\"#{formula.name}: migrate from #{formula.tap.repo}\" -- #{formula_file}" - - unless local_only - ohai "hub fork --no-remote" - ohai "hub fork" - ohai "hub fork (to read $HUB_REMOTE)" - ohai "git push $HUB_REMOTE #{branch}:#{branch}" - ohai "hub pull-request --browse -m $'#{formula.name}: migrate from #{formula.tap.repo}\\n\\nGoes together with $PR_URL\\n\\nCreated with `brew boneyard-formula-pr`#{reason}.'" - end - - ohai "git checkout -" - else - cd boneyard_tap.formula_dir - safe_system "git", "checkout", "--no-track", "-b", branch, "origin/master" - if bottle_block - Utils::Inreplace.inreplace formula_file, / bottle do.+?end\n\n/m, "" - end - safe_system "git", "add", formula_file - safe_system "git", "commit", "--no-edit", "--verbose", - "--message=#{formula.name}: migrate from #{formula.tap.repo}", - "--", formula_file - - unless local_only - safe_system "hub", "fork", "--no-remote" - quiet_system "hub", "fork" - remote = Utils.popen_read("hub fork 2>&1")[/fatal: remote (.+) already exists\./, 1] - odie "cannot get remote from 'hub'!" unless remote - safe_system "git", "push", remote, "#{branch}:#{branch}" - safe_system "hub", "pull-request", "--browse", "-m", <<-EOS.undent - #{formula.name}: migrate from #{formula.tap.repo} - - Goes together with #{pr_url}. - - Created with `brew boneyard-formula-pr`#{reason}. - EOS - end - - safe_system "git", "checkout", "-" - end - end -end diff --git a/Library/Homebrew/dev-cmd/create.rb b/Library/Homebrew/dev-cmd/create.rb index 9c58dc71a..6855d6f37 100644 --- a/Library/Homebrew/dev-cmd/create.rb +++ b/Library/Homebrew/dev-cmd/create.rb @@ -19,7 +19,7 @@ #: the specified tap. require "formula" -require "blacklist" +require "missing_formula" require "digest" require "erb" @@ -73,8 +73,8 @@ module Homebrew # Don't allow blacklisted formula, or names that shadow aliases, # unless --force is specified. unless ARGV.force? - if msg = blacklisted?(fc.name) - raise "#{fc.name} is blacklisted for creation.\n#{msg}\nIf you really want to create this formula use --force." + if reason = Homebrew::MissingFormula.blacklisted_reason(fc.name) + raise "#{fc.name} is blacklisted for creation.\n#{reason}\nIf you really want to create this formula use --force." end if Formula.aliases.include? fc.name diff --git a/Library/Homebrew/dev-cmd/man.rb b/Library/Homebrew/dev-cmd/man.rb index 581db38ca..a146f23a8 100644 --- a/Library/Homebrew/dev-cmd/man.rb +++ b/Library/Homebrew/dev-cmd/man.rb @@ -27,7 +27,7 @@ module Homebrew regenerate_man_pages - if system "git", "-C", HOMEBREW_REPOSITORY, "diff", "--quiet", "docs/brew.1.html", "manpages" + if system "git", "-C", HOMEBREW_REPOSITORY, "diff", "--quiet", "docs/Manpage.md", "manpages" puts "No changes to manpage output detected." elsif ARGV.include?("--fail-if-changed") Homebrew.failed = true @@ -38,7 +38,7 @@ module Homebrew Homebrew.install_gem_setup_path! "ronn" markup = build_man_page - convert_man_page(markup, TARGET_DOC_PATH/"brew.1.html") + convert_man_page(markup, TARGET_DOC_PATH/"Manpage.md") convert_man_page(markup, TARGET_MAN_PATH/"brew.1") cask_markup = (SOURCE_PATH/"brew-cask.1.md").read @@ -53,8 +53,7 @@ module Homebrew .grep(/^#:/) .map { |line| line.slice(2..-1) } .join - end - .reject { |s| s.strip.empty? || s.include?("@hide_from_man_page") } + end.reject { |s| s.strip.empty? || s.include?("@hide_from_man_page") } end def build_man_page @@ -113,7 +112,7 @@ module Homebrew def target_path_to_format(target) case target.basename - when /\.html?$/ then ["--fragment", "HTML fragment"] + when /\.md$/ then ["--markdown", "markdown"] when /\.\d$/ then ["--roff", "man page"] else odie "Failed to infer output format from '#{target.basename}'." diff --git a/Library/Homebrew/dev-cmd/pull.rb b/Library/Homebrew/dev-cmd/pull.rb index ec89b14b8..36c9ac27c 100644 --- a/Library/Homebrew/dev-cmd/pull.rb +++ b/Library/Homebrew/dev-cmd/pull.rb @@ -1,4 +1,5 @@ -#: * `pull` [`--bottle`] [`--bump`] [`--clean`] [`--ignore-whitespace`] [`--resolve`] [`--branch-okay`] [`--no-pbcopy`] [`--no-publish`] <patch-source> [<patch-source>]: +#: * `pull` [`--bottle`] [`--bump`] [`--clean`] [`--ignore-whitespace`] [`--resolve`] [`--branch-okay`] [`--no-pbcopy`] [`--no-publish`] [`--warn-on-publish-failure`] <patch-source> [<patch-source>]: +#: #: Gets a patch from a GitHub commit or pull request and applies it to Homebrew. #: Optionally, installs the formulae changed by the patch. #: @@ -37,6 +38,9 @@ #: clipboard. #: #: If `--no-publish` is passed, do not publish bottles to Bintray. +#: +#: If `--warn-on-publish-failure` was passed, do not exit if there's a +#: failure publishing bottles on Bintray. require "net/http" require "net/https" @@ -264,7 +268,7 @@ module Homebrew changed_formulae_names.each do |name| f = Formula[name] next if f.bottle_unneeded? || f.bottle_disabled? - publish_bottle_file_on_bintray(f, bintray_creds) + next unless publish_bottle_file_on_bintray(f, bintray_creds) published << f.full_name end else @@ -425,7 +429,7 @@ module Homebrew end unless info.bottle_info_any opoo "No bottle defined in formula #{package}" - return + return false end version = info.pkg_version ohai "Publishing on Bintray: #{package} #{version}" @@ -434,6 +438,11 @@ module Homebrew "-H", "Content-Type: application/json", "-d", '{"publish_wait_for_secs": 0}', "https://api.bintray.com/content/homebrew/#{repo}/#{package}/#{version}/publish" + true + rescue => e + raise unless ARGV.include?("--warn-on-publish-failure") + onoe e + false end # Formula info drawn from an external "brew info --json" call diff --git a/Library/Homebrew/dev-cmd/tap-new.rb b/Library/Homebrew/dev-cmd/tap-new.rb index 6e1977446..df295bf26 100644 --- a/Library/Homebrew/dev-cmd/tap-new.rb +++ b/Library/Homebrew/dev-cmd/tap-new.rb @@ -60,6 +60,7 @@ module Homebrew - git -C "$HOMEBREW_REPOSITORY" reset --hard origin/master - brew update || brew update - HOMEBREW_TAP_DIR="$(brew --repo "$TRAVIS_REPO_SLUG")" + - mkdir -p "$HOMEBREW_TAP_DIR" - rm -rf "$HOMEBREW_TAP_DIR" - ln -s "$PWD" "$HOMEBREW_TAP_DIR" - export HOMEBREW_DEVELOPER="1" diff --git a/Library/Homebrew/dev-cmd/tests.rb b/Library/Homebrew/dev-cmd/tests.rb index 4f7f9e771..18e7d96f2 100644 --- a/Library/Homebrew/dev-cmd/tests.rb +++ b/Library/Homebrew/dev-cmd/tests.rb @@ -28,6 +28,7 @@ module Homebrew ENV.delete("HOMEBREW_VERBOSE") ENV.delete("VERBOSE") ENV.delete("HOMEBREW_CASK_OPTS") + ENV.delete("HOMEBREW_TEMP") ENV["HOMEBREW_NO_ANALYTICS_THIS_RUN"] = "1" ENV["HOMEBREW_DEVELOPER"] = "1" ENV["HOMEBREW_NO_COMPAT"] = "1" if ARGV.include? "--no-compat" diff --git a/Library/Homebrew/dev-cmd/update-test.rb b/Library/Homebrew/dev-cmd/update-test.rb index 2ff168669..add05bc7c 100644 --- a/Library/Homebrew/dev-cmd/update-test.rb +++ b/Library/Homebrew/dev-cmd/update-test.rb @@ -33,12 +33,24 @@ module Homebrew elsif date = ARGV.value("before") Utils.popen_read("git", "rev-list", "-n1", "--before=#{date}", "origin/master").chomp elsif ARGV.include?("--to-tag") - Utils.popen_read("git", "tag", "--list", "--sort=-version:refname").lines[1].chomp + previous_tag = + Utils.popen_read("git", "tag", "--list", "--sort=-version:refname").lines[1] + unless previous_tag + safe_system "git", "fetch", "--tags", "--depth=1" + previous_tag = + Utils.popen_read("git", "tag", "--list", "--sort=-version:refname").lines[1] + end + previous_tag.to_s.chomp else Utils.popen_read("git", "rev-parse", "origin/master").chomp end + odie "Could not find start commit!" if start_commit.empty? + start_commit = Utils.popen_read("git", "rev-parse", start_commit).chomp + odie "Could not find start commit!" if start_commit.empty? + end_commit = Utils.popen_read("git", "rev-parse", "HEAD").chomp + odie "Could not find end commit!" if end_commit.empty? puts "Start commit: #{start_commit}" puts "End commit: #{end_commit}" diff --git a/Library/Homebrew/diagnostic.rb b/Library/Homebrew/diagnostic.rb index c8c4b83d2..61cdf2f1a 100644 --- a/Library/Homebrew/diagnostic.rb +++ b/Library/Homebrew/diagnostic.rb @@ -753,13 +753,14 @@ module Homebrew def check_git_version # https://help.github.com/articles/https-cloning-errors return unless Utils.git_available? - return unless Version.create(Utils.git_version) < Version.create("1.7.10") + return unless Version.create(Utils.git_version) < Version.create("1.8.5") git = Formula["git"] git_upgrade_cmd = git.any_version_installed? ? "upgrade" : "install" <<-EOS.undent An outdated version (#{Utils.git_version}) of Git was detected in your PATH. - Git 1.7.10 or newer is required to perform checkouts over HTTPS from GitHub. + Git 1.8.5 or newer is required to perform checkouts over HTTPS from GitHub and + to support the 'git -C <path>' option. Please upgrade: brew #{git_upgrade_cmd} git EOS @@ -794,31 +795,59 @@ module Homebrew EOS end - def check_git_origin + def check_brew_git_origin return if !Utils.git_available? || !(HOMEBREW_REPOSITORY/".git").exist? origin = HOMEBREW_REPOSITORY.git_origin if origin.nil? <<-EOS.undent - Missing git origin remote. + Missing Homebrew/brew git origin remote. Without a correctly configured origin, Homebrew won't update properly. You can solve this by adding the Homebrew remote: - cd #{HOMEBREW_REPOSITORY} - git remote add origin #{Formatter.url("https://github.com/Homebrew/brew.git")} + git -C "#{HOMEBREW_REPOSITORY}" remote add origin #{Formatter.url("https://github.com/Homebrew/brew.git")} EOS - elsif origin !~ %r{Homebrew/brew(\.git)?$} + elsif origin !~ %r{Homebrew/brew(\.git|/)?$} <<-EOS.undent - Suspicious git origin remote found. + Suspicious Homebrew/brew git origin remote found. With a non-standard origin, Homebrew won't pull updates from the main repository. The current git origin is: #{origin} Unless you have compelling reasons, consider setting the - origin remote to point at the main repository, located at: - #{Formatter.url("https://github.com/Homebrew/brew.git")} + origin remote to point at the main repository by running: + git -C "#{HOMEBREW_REPOSITORY}" remote add origin #{Formatter.url("https://github.com/Homebrew/brew.git")} + EOS + end + end + + def check_coretap_git_origin + coretap_path = CoreTap.instance.path + return if !Utils.git_available? || !(coretap_path/".git").exist? + + origin = coretap_path.git_origin + + if origin.nil? + <<-EOS.undent + Missing #{CoreTap.instance} git origin remote. + + Without a correctly configured origin, Homebrew won't update + properly. You can solve this by adding the Homebrew remote: + git -C "#{coretap_path}" remote add origin #{Formatter.url("https://github.com/Homebrew/homebrew-core.git")} + EOS + elsif origin !~ %r{Homebrew/homebrew-core(\.git|/)?$} + <<-EOS.undent + Suspicious #{CoreTap.instance} git origin remote found. + + With a non-standard origin, Homebrew won't pull updates from + the main repository. The current git origin is: + #{origin} + + Unless you have compelling reasons, consider setting the + origin remote to point at the main repository by running: + git -C "#{coretap_path}" remote add origin #{Formatter.url("https://github.com/Homebrew/homebrew-core.git")} EOS end end diff --git a/Library/Homebrew/exceptions.rb b/Library/Homebrew/exceptions.rb index 77da4489e..cfdf5e12d 100644 --- a/Library/Homebrew/exceptions.rb +++ b/Library/Homebrew/exceptions.rb @@ -363,14 +363,6 @@ class BuildError < RuntimeError end end - if formula.tap && formula.tap.name == "homebrew/boneyard" - onoe <<-EOS.undent - #{formula} was moved to homebrew-boneyard because it has unfixable issues. - Please do not file any issues about this. Sorry! - EOS - return - end - if formula.tap && defined?(OS::ISSUES_URL) if formula.tap.official? puts Formatter.error(Formatter.url(OS::ISSUES_URL), label: "READ THIS") diff --git a/Library/Homebrew/extend/os/blacklist.rb b/Library/Homebrew/extend/os/blacklist.rb deleted file mode 100644 index 932040f82..000000000 --- a/Library/Homebrew/extend/os/blacklist.rb +++ /dev/null @@ -1,2 +0,0 @@ -require "blacklist" -require "extend/os/mac/blacklist" if OS.mac? diff --git a/Library/Homebrew/extend/os/mac/blacklist.rb b/Library/Homebrew/extend/os/mac/blacklist.rb deleted file mode 100644 index edff4697e..000000000 --- a/Library/Homebrew/extend/os/mac/blacklist.rb +++ /dev/null @@ -1,16 +0,0 @@ -def blacklisted?(name) - case name.downcase - when "xcode" - if MacOS.version >= :lion - <<-EOS.undent - Xcode can be installed from the App Store. - EOS - else - <<-EOS.undent - Xcode can be installed from https://developer.apple.com/xcode/downloads/ - EOS - end - else - generic_blacklisted?(name) - end -end diff --git a/Library/Homebrew/extend/os/mac/missing_formula.rb b/Library/Homebrew/extend/os/mac/missing_formula.rb new file mode 100644 index 000000000..48dfd2865 --- /dev/null +++ b/Library/Homebrew/extend/os/mac/missing_formula.rb @@ -0,0 +1,22 @@ +module Homebrew + module MissingFormula + class << self + def blacklisted_reason(name) + case name.downcase + when "xcode" + if MacOS.version >= :lion + <<-EOS.undent + Xcode can be installed from the App Store. + EOS + else + <<-EOS.undent + Xcode can be installed from #{Formatter.url("https://developer.apple.com/xcode/downloads/")}. + EOS + end + else + generic_blacklisted_reason(name) + end + end + end + end +end diff --git a/Library/Homebrew/extend/os/missing_formula.rb b/Library/Homebrew/extend/os/missing_formula.rb new file mode 100644 index 000000000..02c59f4e4 --- /dev/null +++ b/Library/Homebrew/extend/os/missing_formula.rb @@ -0,0 +1,2 @@ +require "missing_formula" +require "extend/os/mac/missing_formula" if OS.mac? diff --git a/Library/Homebrew/formula.rb b/Library/Homebrew/formula.rb index 443619206..523de244d 100644 --- a/Library/Homebrew/formula.rb +++ b/Library/Homebrew/formula.rb @@ -252,12 +252,14 @@ class Formula public - # The alias path that was used to install this formula, if present. + # The alias path that was used to install this formula, if it exists. # Can differ from alias_path, which is the alias used to find the formula, # and is specified to this instance. def installed_alias_path path = build.source["path"] if build.is_a?(Tab) - path if path =~ %r{#{HOMEBREW_TAP_DIR_REGEX}/Aliases} + return unless path =~ %r{#{HOMEBREW_TAP_DIR_REGEX}/Aliases} + return unless File.symlink?(path) + path end def installed_alias_name @@ -1555,6 +1557,8 @@ class Formula hide.include?(d.name) || d.installed_prefixes.empty? end missing_dependencies + rescue FormulaUnavailableError + [] end # @private diff --git a/Library/Homebrew/formula_installer.rb b/Library/Homebrew/formula_installer.rb index 1f91ad5c4..017be51dc 100644 --- a/Library/Homebrew/formula_installer.rb +++ b/Library/Homebrew/formula_installer.rb @@ -410,10 +410,13 @@ class FormulaInstaller end def install_requirement_formula?(req, dependent, build) - return false unless req.to_dependency + req_dependency = req.to_dependency + return false unless req_dependency return true unless req.satisfied? return false if req.run? - install_bottle_for?(dependent, build) || build_bottle? + return true if build_bottle? + return true if req.satisfied_by_formula? + install_bottle_for?(dependent, build) end def expand_requirements diff --git a/Library/Homebrew/formula_support.rb b/Library/Homebrew/formula_support.rb index dcb995a6b..b8476f5cc 100644 --- a/Library/Homebrew/formula_support.rb +++ b/Library/Homebrew/formula_support.rb @@ -4,6 +4,8 @@ FormulaConflict = Struct.new(:name, :reason) # Used to annotate formulae that duplicate macOS provided software # or cause conflicts when linked in. class KegOnlyReason + attr_reader :reason + def initialize(reason, explanation) @reason = reason @explanation = explanation diff --git a/Library/Homebrew/gpg.rb b/Library/Homebrew/gpg.rb index 066f67864..777542055 100644 --- a/Library/Homebrew/gpg.rb +++ b/Library/Homebrew/gpg.rb @@ -5,7 +5,9 @@ class Gpg which_all(executable).detect do |gpg| gpg_short_version = Utils.popen_read(gpg, "--version")[/\d\.\d/, 0] next unless gpg_short_version - Version.create(gpg_short_version.to_s) == Version.create("2.0") + gpg_version = Version.create(gpg_short_version.to_s) + gpg_version == Version.create("2.0") || + gpg_version == Version.create("2.1") end end diff --git a/Library/Homebrew/migrator.rb b/Library/Homebrew/migrator.rb index a80cf0c59..a58ca2059 100644 --- a/Library/Homebrew/migrator.rb +++ b/Library/Homebrew/migrator.rb @@ -122,6 +122,13 @@ class Migrator end def from_same_taps? + new_tap = if old_tap + if migrate_tap = old_tap.tap_migrations[formula.oldname] + new_tap_user, new_tap_repo, = migrate_tap.split("/") + "#{new_tap_user}/#{new_tap_repo}" + end + end + if formula.tap == old_tap true # Homebrew didn't use to update tabs while performing tap-migrations, @@ -129,7 +136,7 @@ class Migrator # so we check if there is an entry about oldname migrated to tap and if # newname's tap is the same as tap to which oldname migrated, then we # can perform migrations and the taps for oldname and newname are the same. - elsif formula.tap && old_tap && formula.tap == old_tap.tap_migrations[formula.oldname] + elsif formula.tap && old_tap && formula.tap == new_tap fix_tabs true else @@ -147,15 +154,25 @@ class Migrator end def migrate - if new_cellar.exist? - onoe "#{new_cellar} already exists; remove it manually and run brew migrate #{oldname}." - return + if old_cellar.exist? && new_cellar.exist? + conflicted = false + old_cellar.each_child do |c| + if (new_cellar/c.basename).exist? + conflicted = true + onoe "#{new_cellar/c.basename} already exists." + end + end + if conflicted + onoe "Remove #{new_cellar} manually and run brew migrate #{oldname}." + return + end end begin oh1 "Migrating #{Formatter.identifier(oldname)} to #{Formatter.identifier(newname)}" lock unlink_oldname + unlink_newname if new_cellar.exist? move_to_new_directory repin link_oldname_cellar @@ -178,7 +195,11 @@ class Migrator # move everything from Cellar/oldname to Cellar/newname def move_to_new_directory puts "Moving to: #{new_cellar}" - FileUtils.mv(old_cellar, new_cellar) + if new_cellar.exist? + FileUtils.mv(old_cellar.children, new_cellar) + else + FileUtils.mv(old_cellar, new_cellar) + end end def repin @@ -207,6 +228,14 @@ class Migrator end end + def unlink_newname + oh1 "Unlinking #{Formatter.identifier(newname)}" + new_cellar.subdirs.each do |d| + keg = Keg.new(d) + keg.unlink + end + end + def link_newname oh1 "Linking #{Formatter.identifier(newname)}" new_keg = Keg.new(new_linked_keg_record) diff --git a/Library/Homebrew/missing_formula.rb b/Library/Homebrew/missing_formula.rb new file mode 100644 index 000000000..1b584af8a --- /dev/null +++ b/Library/Homebrew/missing_formula.rb @@ -0,0 +1,168 @@ +require "formulary" +require "tap" +require "utils" + +module Homebrew + module MissingFormula + class << self + def reason(name, silent: false) + blacklisted_reason(name) || tap_migration_reason(name) || + deleted_reason(name, silent: silent) + end + + def blacklisted_reason(name) + case name.downcase + when "gem", /^rubygems?$/ then <<-EOS.undent + Homebrew provides gem via: `brew install ruby`. + EOS + when "tex", "tex-live", "texlive", "latex" then <<-EOS.undent + Installing TeX from source is weird and gross, requires a lot of patches, + and only builds 32-bit (and thus can't use Homebrew dependencies) + + We recommend using a MacTeX distribution: https://www.tug.org/mactex/ + + You can install it with Homebrew-Cask: + brew cask install mactex + EOS + when "pip" then <<-EOS.undent + Homebrew provides pip via: `brew install python`. However you will then + have two Pythons installed on your Mac, so alternatively you can install + pip via the instructions at: + #{Formatter.url("https://pip.readthedocs.io/en/stable/installing/")} + EOS + when "pil" then <<-EOS.undent + Instead of PIL, consider `pip install pillow` or `brew install Homebrew/python/pillow`. + EOS + when "macruby" then <<-EOS.undent + MacRuby is not packaged and is on an indefinite development hiatus. + You can read more about it at: + #{Formatter.url("https://github.com/MacRuby/MacRuby")} + EOS + when /(lib)?lzma/ + "lzma is now part of the xz formula." + when "gtest", "googletest", "google-test" then <<-EOS.undent + Installing gtest system-wide is not recommended; it should be vendored + in your projects that use it. + EOS + when "gmock", "googlemock", "google-mock" then <<-EOS.undent + Installing gmock system-wide is not recommended; it should be vendored + in your projects that use it. + EOS + when "sshpass" then <<-EOS.undent + We won't add sshpass because it makes it too easy for novice SSH users to + ruin SSH's security. + EOS + when "gsutil" then <<-EOS.undent + Install gsutil with `pip install gsutil` + EOS + when "clojure" then <<-EOS.undent + Clojure isn't really a program but a library managed as part of a + project and Leiningen is the user interface to that library. + + To install Clojure you should install Leiningen: + brew install leiningen + and then follow the tutorial: + #{Formatter.url("https://github.com/technomancy/leiningen/blob/stable/doc/TUTORIAL.md")} + EOS + when "osmium" then <<-EOS.undent + The creator of Osmium requests that it not be packaged and that people + use the GitHub master branch instead. + EOS + when "gfortran" then <<-EOS.undent + GNU Fortran is now provided as part of GCC, and can be installed with: + brew install gcc + EOS + when "play" then <<-EOS.undent + Play 2.3 replaces the play command with activator: + brew install typesafe-activator + + You can read more about this change at: + #{Formatter.url("https://www.playframework.com/documentation/2.3.x/Migration23")} + #{Formatter.url("https://www.playframework.com/documentation/2.3.x/Highlights23")} + EOS + when "haskell-platform" then <<-EOS.undent + We no longer package haskell-platform. Consider installing ghc + and cabal-install instead: + brew install ghc cabal-install + + You can install with Homebrew-Cask: + brew cask install haskell-platform + EOS + when "mysqldump-secure" then <<-EOS.undent + The creator of mysqldump-secure tried to game our popularity metrics. + EOS + when "ngrok" then <<-EOS.undent + Upstream sunsetted 1.x in March 2016 and 2.x is not open-source. + + If you wish to use the 2.x release you can install with Homebrew-Cask: + brew cask install ngrok + EOS + end + end + alias generic_blacklisted_reason blacklisted_reason + + def tap_migration_reason(name) + message = nil + + Tap.each do |old_tap| + new_tap = old_tap.tap_migrations[name] + next unless new_tap + + new_tap_user, new_tap_repo, = new_tap.split("/") + new_tap_name = "#{new_tap_user}/#{new_tap_repo}" + + message = <<-EOS.undent + It was migrated from #{old_tap} to #{new_tap}. + You can access it again by running: + brew tap #{new_tap_name} + EOS + break + end + + message + end + + def deleted_reason(name, silent: false) + path = Formulary.path name + return if File.exist? path + tap = Tap.from_path(path) + return unless File.exist? tap.path + relative_path = path.relative_path_from tap.path + + tap.path.cd do + ohai "Searching for a previously deleted formula..." unless silent + + # We know this may return incomplete results for shallow clones but + # we don't want to nag everyone with a shallow clone to unshallow it. + log_command = "git log --name-only --max-count=1 --format=%H\\\\n%h\\\\n%B -- #{relative_path}" + hash, short_hash, *commit_message, relative_path = + Utils.popen_read(log_command).gsub("\\n", "\n").lines.map(&:chomp) + + if hash.to_s.empty? || short_hash.to_s.empty? || + relative_path.to_s.empty? + ofail "No previously deleted formula found." unless silent + return + end + + commit_message = commit_message.reject(&:empty?).join("\n ") + + commit_message.sub!(/ \(#(\d+)\)$/, " (#{tap.issues_url}/\\1)") + commit_message.gsub!(/(Closes|Fixes) #(\d+)/, "\\1 #{tap.issues_url}/\\2") + + <<-EOS.undent + #{name} was deleted from #{tap.name} in commit #{short_hash}: + #{commit_message} + + To show the formula before removal run: + git -C "$(brew --repo #{tap})" show #{short_hash}^:#{relative_path} + + If you still use this formula consider creating your own tap: + http://docs.brew.sh/How-to-Create-and-Maintain-a-Tap.html + EOS + end + end + + require "extend/os/missing_formula" + end + end +end diff --git a/Library/Homebrew/official_taps.rb b/Library/Homebrew/official_taps.rb index c7b96ae64..a7bc4a1d6 100644 --- a/Library/Homebrew/official_taps.rb +++ b/Library/Homebrew/official_taps.rb @@ -1,11 +1,8 @@ OFFICIAL_TAPS = %w[ apache - dupes - fuse nginx php science - tex ].freeze OFFICIAL_CMD_TAPS = { diff --git a/Library/Homebrew/requirement.rb b/Library/Homebrew/requirement.rb index 49108ca75..bd8cf20c8 100644 --- a/Library/Homebrew/requirement.rb +++ b/Library/Homebrew/requirement.rb @@ -125,6 +125,10 @@ class Requirement @formula || self.class.default_formula end + def satisfied_by_formula? + !@formula.nil? + end + def to_dependency if formula =~ HOMEBREW_TAP_FORMULA_REGEX TapDependency.new(formula, tags, method(:modify_build_environment), name) diff --git a/Library/Homebrew/requirements/gpg2_requirement.rb b/Library/Homebrew/requirements/gpg2_requirement.rb index 00bf4183a..97fabcca0 100644 --- a/Library/Homebrew/requirements/gpg2_requirement.rb +++ b/Library/Homebrew/requirements/gpg2_requirement.rb @@ -3,10 +3,10 @@ require "gpg" class GPG2Requirement < Requirement fatal true - default_formula "gnupg2" + default_formula "gnupg" # MacGPG2/GPGTools installs GnuPG 2.0.x as a vanilla `gpg` symlink # pointing to `gpg2`, as do we. Ensure we're actually using a 2.0 `gpg`. - # Temporarily, only support 2.0.x rather than the 2.1.x "modern" series. + # Support both the 2.0.x "stable" and 2.1.x "modern" series. satisfy(build_env: false) { Gpg.gpg2 || Gpg.gpg } end diff --git a/Library/Homebrew/tap.rb b/Library/Homebrew/tap.rb index ba55e3cf6..99138330b 100644 --- a/Library/Homebrew/tap.rb +++ b/Library/Homebrew/tap.rb @@ -41,6 +41,15 @@ class Tap CACHE.fetch(cache_key) { |key| CACHE[key] = Tap.new(user, repo) } end + def self.from_path(path) + path.to_s =~ HOMEBREW_TAP_PATH_REGEX + raise "Invalid tap path '#{path}'" unless $1 + fetch($1, $2) + rescue + # No need to error as a nil tap is sufficient to show failure. + nil + end + extend Enumerable # The user name of this {Tap}. Usually, it's the Github username of diff --git a/Library/Homebrew/test/blacklist_spec.rb b/Library/Homebrew/test/blacklist_spec.rb deleted file mode 100644 index 01882167d..000000000 --- a/Library/Homebrew/test/blacklist_spec.rb +++ /dev/null @@ -1,115 +0,0 @@ -require "blacklist" - -describe "Blacklist" do - matcher(:be_blacklisted) { match(&method(:blacklisted?)) } - - context "rubygems" do - %w[gem rubygem rubygems].each do |s| - subject { s } - - it { is_expected.to be_blacklisted } - end - end - - context "latex" do - %w[latex tex tex-live texlive TexLive].each do |s| - subject { s } - - it { is_expected.to be_blacklisted } - end - end - - context "pip" do - subject { "pip" } - - it { is_expected.to be_blacklisted } - end - - context "pil" do - subject { "pil" } - - it { is_expected.to be_blacklisted } - end - - context "macruby" do - subject { "MacRuby" } - - it { is_expected.to be_blacklisted } - end - - context "lzma" do - %w[lzma liblzma].each do |s| - subject { s } - - it { is_expected.to be_blacklisted } - end - end - - context "gtest" do - %w[gtest googletest google-test].each do |s| - subject { s } - - it { is_expected.to be_blacklisted } - end - end - - context "gmock" do - %w[gmock googlemock google-mock].each do |s| - subject { s } - - it { is_expected.to be_blacklisted } - end - end - - context "sshpass" do - subject { "sshpass" } - - it { is_expected.to be_blacklisted } - end - - context "gsutil" do - subject { "gsutil" } - - it { is_expected.to be_blacklisted } - end - - context "clojure" do - subject { "clojure" } - - it { is_expected.to be_blacklisted } - end - - context "osmium" do - %w[osmium Osmium].each do |s| - subject { s } - - it { is_expected.to be_blacklisted } - end - end - - context "gfortran" do - subject { "gfortran" } - - it { is_expected.to be_blacklisted } - end - - context "play" do - subject { "play" } - - it { is_expected.to be_blacklisted } - end - - context "haskell-platform" do - subject { "haskell-platform" } - - it { is_expected.to be_blacklisted } - end - - context "xcode", :needs_macos do - %w[xcode Xcode].each do |s| - subject { s } - - it { is_expected.to be_blacklisted } - end - end -end diff --git a/Library/Homebrew/test/cmd/log_spec.rb b/Library/Homebrew/test/cmd/log_spec.rb index bdbca8912..b9e3e8d3e 100644 --- a/Library/Homebrew/test/cmd/log_spec.rb +++ b/Library/Homebrew/test/cmd/log_spec.rb @@ -33,7 +33,7 @@ describe "brew log", :integration_test do expect { brew "log", "#{shallow_tap}/testball" } .to output(/This is a test commit for Testball/).to_stdout - .and output(/Warning: The git repository is a shallow clone/).to_stderr + .and output(%r{Warning: homebrew/shallow is a shallow clone}).to_stderr .and be_a_success expect(shallow_tap.path/".git/shallow").to exist, "A shallow clone should have been created." diff --git a/Library/Homebrew/test/cmd/outdated_spec.rb b/Library/Homebrew/test/cmd/outdated_spec.rb index 2ce0825e8..65cce27c3 100644 --- a/Library/Homebrew/test/cmd/outdated_spec.rb +++ b/Library/Homebrew/test/cmd/outdated_spec.rb @@ -1,11 +1,87 @@ describe "brew outdated", :integration_test do - it "prints outdated Formulae" do - setup_test_formula "testball" - (HOMEBREW_CELLAR/"testball/0.0.1/foo").mkpath - - expect { brew "outdated" } - .to output("testball\n").to_stdout - .and not_to_output.to_stderr - .and be_a_success + context "quiet output" do + it "prints outdated Formulae" do + setup_test_formula "testball" + (HOMEBREW_CELLAR/"testball/0.0.1/foo").mkpath + + expect { brew "outdated" } + .to output("testball\n").to_stdout + .and not_to_output.to_stderr + .and be_a_success + end + end + + context "verbose output" do + it "prints out the installed and newer versions" do + setup_test_formula "testball" + (HOMEBREW_CELLAR/"testball/0.0.1/foo").mkpath + + expect { brew "outdated", "--verbose" } + .to output("testball (0.0.1) < 0.1\n").to_stdout + .and not_to_output.to_stderr + .and be_a_success + end + end + + context "pinned formula, verbose output" do + it "prints out the pinned version" do + setup_test_formula "testball" + (HOMEBREW_CELLAR/"testball/0.0.1/foo").mkpath + + shutup do + expect { brew "pin", "testball" }.to be_a_success + end + + expect { brew "outdated", "--verbose" } + .to output("testball (0.0.1) < 0.1 [pinned at 0.0.1]\n").to_stdout + .and not_to_output.to_stderr + .and be_a_success + end + end + + context "json output" do + it "includes pinned version in the json output" do + setup_test_formula "testball" + (HOMEBREW_CELLAR/"testball/0.0.1/foo").mkpath + + shutup do + expect { brew "pin", "testball" }.to be_a_success + end + + expected_json = [ + { + name: "testball", + installed_versions: ["0.0.1"], + current_version: "0.1", + pinned: true, + pinned_version: "0.0.1", + }, + ].to_json + + expect { brew "outdated", "--json=v1" } + .to output(expected_json + "\n").to_stdout + .and not_to_output.to_stderr + .and be_a_success + end + + it "has no pinned version when the formula isn't pinned" do + setup_test_formula "testball" + (HOMEBREW_CELLAR/"testball/0.0.1/foo").mkpath + + expected_json = [ + { + name: "testball", + installed_versions: ["0.0.1"], + current_version: "0.1", + pinned: false, + pinned_version: nil, + }, + ].to_json + + expect { brew "outdated", "--json=v1" } + .to output(expected_json + "\n").to_stdout + .and not_to_output.to_stderr + .and be_a_success + end end end diff --git a/Library/Homebrew/test/formula_installer_spec.rb b/Library/Homebrew/test/formula_installer_spec.rb index 600b4560f..efe2bf5a2 100644 --- a/Library/Homebrew/test/formula_installer_spec.rb +++ b/Library/Homebrew/test/formula_installer_spec.rb @@ -134,4 +134,50 @@ describe FormulaInstaller do fi.check_install_sanity }.to raise_error(CannotInstallFormulaError) end + + describe "#install_requirement_formula?" do + before do + @requirement = Python3Requirement.new + allow(@requirement).to receive(:satisfied?).and_return(satisfied?) + allow(@requirement).to receive(:satisfied_by_formula?).and_return(satisfied_by_formula?) + allow_any_instance_of(Dependency).to receive(:installed?).and_return(installed?) + @dependent = formula do + url "foo" + version "0.1" + depends_on :python3 + end + @build = BuildOptions.new [], [] + @fi = FormulaInstaller.new(@dependent) + end + + subject { @fi.install_requirement_formula?(@requirement, @dependent, @build) } + + context "it returns false when requirement is satisfied" do + let(:satisfied?) { true } + let(:satisfied_by_formula?) { false } + let(:installed?) { false } + it { is_expected.to be false } + end + + context "it returns false when requirement is satisfied but default formula is installed" do + let(:satisfied?) { true } + let(:satisfied_by_formula?) { false } + let(:installed?) { true } + it { is_expected.to be false } + end + + context "it returns true when requirement isn't satisfied" do + let(:satisfied?) { false } + let(:satisfied_by_formula?) { false } + let(:installed?) { false } + it { is_expected.to be true } + end + + context "it returns true when requirement is satisfied by a formula" do + let(:satisfied?) { true } + let(:satisfied_by_formula?) { true } + let(:installed?) { false } + it { is_expected.to be true } + end + end end diff --git a/Library/Homebrew/test/formula_spec.rb b/Library/Homebrew/test/formula_spec.rb index 1e064912f..2309c36fb 100644 --- a/Library/Homebrew/test/formula_spec.rb +++ b/Library/Homebrew/test/formula_spec.rb @@ -129,6 +129,8 @@ describe Formula do alias_name = "bar" alias_path = "#{CoreTap.instance.alias_dir}/#{alias_name}" + CoreTap.instance.alias_dir.mkpath + FileUtils.ln_sf f.path, alias_path f.build = Tab.new(source: { "path" => alias_path }) @@ -160,6 +162,8 @@ describe Formula do alias_name = "bar" full_alias_name = "#{tap.user}/#{tap.repo}/#{alias_name}" alias_path = "#{tap.alias_dir}/#{alias_name}" + tap.alias_dir.mkpath + FileUtils.ln_sf f.path, alias_path f.build = Tab.new(source: { "path" => alias_path }) @@ -168,6 +172,8 @@ describe Formula do expect(f.full_installed_alias_name).to eq(full_alias_name) expect(f.installed_specified_name).to eq(alias_name) expect(f.full_installed_specified_name).to eq(full_alias_name) + + FileUtils.rm_rf HOMEBREW_LIBRARY/"Taps/user" end specify "#prefix" do @@ -402,6 +408,8 @@ describe Formula do url "foo-1.0" end f.build = Tab.new(source: { "path" => source_path.to_s }) + CoreTap.instance.alias_dir.mkpath + FileUtils.ln_sf f.path, source_path expect(f.alias_path).to eq(alias_path) expect(f.installed_alias_path).to eq(source_path.to_s) @@ -443,6 +451,9 @@ describe Formula do allow(described_class).to receive(:installed).and_return(formulae) + CoreTap.instance.alias_dir.mkpath + FileUtils.ln_sf formula_with_alias.path, alias_path + expect(described_class.installed_with_alias_path(alias_path)) .to eq([formula_with_alias]) end @@ -940,6 +951,9 @@ describe Formula do tab.source["path"] = alias_path stub_formula_loader(f, alias_path) + CoreTap.instance.alias_dir.mkpath + FileUtils.ln_sf f.path, alias_path + expect(f.current_installed_alias_target).to eq(f) expect(f.latest_formula).to eq(f) expect(f).not_to have_changed_installed_alias_target @@ -952,6 +966,9 @@ describe Formula do tab.source["path"] = alias_path stub_formula_loader(new_formula, alias_path) + CoreTap.instance.alias_dir.mkpath + FileUtils.ln_sf new_formula.path, alias_path + expect(f.current_installed_alias_target).to eq(new_formula) expect(f.latest_formula).to eq(new_formula) expect(f).to have_changed_installed_alias_target @@ -964,6 +981,9 @@ describe Formula do tab.source["path"] = alias_path stub_formula_loader(new_formula, alias_path) + CoreTap.instance.alias_dir.mkpath + FileUtils.ln_sf new_formula.path, alias_path + expect(new_formula.current_installed_alias_target).to eq(new_formula) expect(new_formula.latest_formula).to eq(new_formula) expect(new_formula).not_to have_changed_installed_alias_target @@ -1050,6 +1070,10 @@ describe Formula do f.follow_installed_alias = true f.build = setup_tab_for_prefix(same_prefix, path: alias_path) stub_formula_loader(new_formula, alias_path) + + CoreTap.instance.alias_dir.mkpath + FileUtils.ln_sf new_formula.path, alias_path + expect(f.outdated_kegs).not_to be_empty end @@ -1088,6 +1112,10 @@ describe Formula do tab = setup_tab_for_prefix(old_alias_target_prefix, path: alias_path) old_formula.build = tab allow(described_class).to receive(:installed).and_return([old_formula]) + + CoreTap.instance.alias_dir.mkpath + FileUtils.ln_sf f.path, alias_path + expect(f.outdated_kegs).not_to be_empty end diff --git a/Library/Homebrew/test/missing_formula_spec.rb b/Library/Homebrew/test/missing_formula_spec.rb new file mode 100644 index 000000000..f395965a6 --- /dev/null +++ b/Library/Homebrew/test/missing_formula_spec.rb @@ -0,0 +1,179 @@ +require "missing_formula" + +describe Homebrew::MissingFormula do + context "::reason" do + subject { described_class.reason("gem") } + + it { is_expected.to_not be_nil } + end + + context "::blacklisted_reason" do + matcher(:be_blacklisted) do + match(&Homebrew::MissingFormula.method(:blacklisted_reason)) + end + + context "rubygems" do + %w[gem rubygem rubygems].each do |s| + subject { s } + + it { is_expected.to be_blacklisted } + end + end + + context "latex" do + %w[latex tex tex-live texlive TexLive].each do |s| + subject { s } + + it { is_expected.to be_blacklisted } + end + end + + context "pip" do + subject { "pip" } + + it { is_expected.to be_blacklisted } + end + + context "pil" do + subject { "pil" } + + it { is_expected.to be_blacklisted } + end + + context "macruby" do + subject { "MacRuby" } + + it { is_expected.to be_blacklisted } + end + + context "lzma" do + %w[lzma liblzma].each do |s| + subject { s } + + it { is_expected.to be_blacklisted } + end + end + + context "gtest" do + %w[gtest googletest google-test].each do |s| + subject { s } + + it { is_expected.to be_blacklisted } + end + end + + context "gmock" do + %w[gmock googlemock google-mock].each do |s| + subject { s } + + it { is_expected.to be_blacklisted } + end + end + + context "sshpass" do + subject { "sshpass" } + + it { is_expected.to be_blacklisted } + end + + context "gsutil" do + subject { "gsutil" } + + it { is_expected.to be_blacklisted } + end + + context "clojure" do + subject { "clojure" } + + it { is_expected.to be_blacklisted } + end + + context "osmium" do + %w[osmium Osmium].each do |s| + subject { s } + + it { is_expected.to be_blacklisted } + end + end + + context "gfortran" do + subject { "gfortran" } + + it { is_expected.to be_blacklisted } + end + + context "play" do + subject { "play" } + + it { is_expected.to be_blacklisted } + end + + context "haskell-platform" do + subject { "haskell-platform" } + + it { is_expected.to be_blacklisted } + end + + context "xcode", :needs_macos do + %w[xcode Xcode].each do |s| + subject { s } + + it { is_expected.to be_blacklisted } + end + end + end + + context "::tap_migration_reason" do + subject { described_class.tap_migration_reason(formula) } + + before do + Tap.clear_cache + tap_path = Tap::TAP_DIRECTORY/"homebrew/homebrew-foo" + tap_path.mkpath + (tap_path/"tap_migrations.json").write <<-EOS.undent + { "migrated-formula": "homebrew/bar" } + EOS + end + + context "with a migrated formula" do + let(:formula) { "migrated-formula" } + it { is_expected.to_not be_nil } + end + + context "with a missing formula" do + let(:formula) { "missing-formula" } + it { is_expected.to be_nil } + end + end + + context "::deleted_reason" do + subject { described_class.deleted_reason(formula) } + + before do + Tap.clear_cache + tap_path = Tap::TAP_DIRECTORY/"homebrew/homebrew-foo" + tap_path.mkpath + (tap_path/"deleted-formula.rb").write "placeholder" + + tap_path.cd do + shutup do + system "git", "init" + system "git", "add", "--all" + system "git", "commit", "-m", "initial state" + system "git", "rm", "deleted-formula.rb" + system "git", "commit", "-m", "delete formula 'deleted-formula'" + end + end + end + + context "with a deleted formula" do + let(:formula) { "homebrew/foo/deleted-formula" } + it { is_expected.to_not be_nil } + end + + context "with a formula that never existed" do + let(:formula) { "homebrew/foo/missing-formula" } + it { is_expected.to be_nil } + end + end +end diff --git a/Library/Homebrew/utils/github.rb b/Library/Homebrew/utils/github.rb index 5f961974c..a5ed5394a 100644 --- a/Library/Homebrew/utils/github.rb +++ b/Library/Homebrew/utils/github.rb @@ -268,7 +268,6 @@ module GitHub def print_pull_requests_matching(query) return [] if ENV["HOMEBREW_NO_GITHUB_API"] - ohai "Searching pull requests..." open_or_closed_prs = issues_matching(query, type: "pr") diff --git a/Library/Homebrew/vendor/README.md b/Library/Homebrew/vendor/README.md index f998d26c5..906d42918 100644 --- a/Library/Homebrew/vendor/README.md +++ b/Library/Homebrew/vendor/README.md @@ -3,7 +3,7 @@ Vendored Dependencies * [plist](https://github.com/bleything/plist), version 3.1.0 -* [ruby-macho](https://github.com/Homebrew/ruby-macho), version 0.2.6 +* [ruby-macho](https://github.com/Homebrew/ruby-macho), version 1.1.0 ## Licenses: @@ -33,7 +33,7 @@ Vendored Dependencies ### ruby-macho > The MIT License -> Copyright (c) 2015, 2016 William Woodruff <william @ tuffbizz.com> +> Copyright (c) 2015, 2016, 2017 William Woodruff <william @ tuffbizz.com> > > Permission is hereby granted, free of charge, to any person obtaining a copy > of this software and associated documentation files (the "Software"), to deal diff --git a/Library/Homebrew/vendor/macho/macho.rb b/Library/Homebrew/vendor/macho/macho.rb index de1d4ff43..b7f20ea19 100644 --- a/Library/Homebrew/vendor/macho/macho.rb +++ b/Library/Homebrew/vendor/macho/macho.rb @@ -5,7 +5,6 @@ require "#{File.dirname(__FILE__)}/macho/load_commands" require "#{File.dirname(__FILE__)}/macho/sections" require "#{File.dirname(__FILE__)}/macho/macho_file" require "#{File.dirname(__FILE__)}/macho/fat_file" -require "#{File.dirname(__FILE__)}/macho/open" require "#{File.dirname(__FILE__)}/macho/exceptions" require "#{File.dirname(__FILE__)}/macho/utils" require "#{File.dirname(__FILE__)}/macho/tools" @@ -13,5 +12,29 @@ require "#{File.dirname(__FILE__)}/macho/tools" # The primary namespace for ruby-macho. module MachO # release version - VERSION = "0.2.6".freeze + VERSION = "1.1.0".freeze + + # Opens the given filename as a MachOFile or FatFile, depending on its magic. + # @param filename [String] the file being opened + # @return [MachOFile] if the file is a Mach-O + # @return [FatFile] if the file is a Fat file + # @raise [ArgumentError] if the given file does not exist + # @raise [TruncatedFileError] if the file is too small to have a valid header + # @raise [MagicError] if the file's magic is not valid Mach-O magic + def self.open(filename) + raise ArgumentError, "#{filename}: no such file" unless File.file?(filename) + raise TruncatedFileError unless File.stat(filename).size >= 4 + + magic = File.open(filename, "rb") { |f| f.read(4) }.unpack("N").first + + if Utils.fat_magic?(magic) + file = FatFile.new(filename) + elsif Utils.magic?(magic) + file = MachOFile.new(filename) + else + raise MagicError, magic + end + + file + end end diff --git a/Library/Homebrew/vendor/macho/macho/exceptions.rb b/Library/Homebrew/vendor/macho/macho/exceptions.rb index 262c195a3..14c2c22ae 100644 --- a/Library/Homebrew/vendor/macho/macho/exceptions.rb +++ b/Library/Homebrew/vendor/macho/macho/exceptions.rb @@ -80,7 +80,8 @@ module MachO # @param cputype [Fixnum] the CPU type of the unknown pair # @param cpusubtype [Fixnum] the CPU sub-type of the unknown pair def initialize(cputype, cpusubtype) - super "Unrecognized CPU sub-type: 0x#{"%08x" % cpusubtype} (for CPU type: 0x#{"%08x" % cputype})" + super "Unrecognized CPU sub-type: 0x#{"%08x" % cpusubtype}" \ + " (for CPU type: 0x#{"%08x" % cputype})" end end @@ -108,13 +109,15 @@ module MachO end end - # Raised when the number of arguments used to create a load command manually is wrong. + # Raised when the number of arguments used to create a load command manually + # is wrong. class LoadCommandCreationArityError < MachOError # @param cmd_sym [Symbol] the load command's symbol # @param expected_arity [Fixnum] the number of arguments expected # @param actual_arity [Fixnum] the number of arguments received def initialize(cmd_sym, expected_arity, actual_arity) - super "Expected #{expected_arity} arguments for #{cmd_sym} creation, got #{actual_arity}" + super "Expected #{expected_arity} arguments for #{cmd_sym} creation," \ + " got #{actual_arity}" end end @@ -130,7 +133,8 @@ module MachO class LCStrMalformedError < MachOError # @param lc [MachO::LoadCommand] the load command containing the string def initialize(lc) - super "Load command #{lc.type} at offset #{lc.view.offset} contains a malformed string" + super "Load command #{lc.type} at offset #{lc.view.offset} contains a" \ + " malformed string" end end diff --git a/Library/Homebrew/vendor/macho/macho/fat_file.rb b/Library/Homebrew/vendor/macho/macho/fat_file.rb index 9f29922e6..351be5ac6 100644 --- a/Library/Homebrew/vendor/macho/macho/fat_file.rb +++ b/Library/Homebrew/vendor/macho/macho/fat_file.rb @@ -1,24 +1,50 @@ +require "forwardable" + module MachO # Represents a "Fat" file, which contains a header, a listing of available # architectures, and one or more Mach-O binaries. # @see https://en.wikipedia.org/wiki/Mach-O#Multi-architecture_binaries - # @see MachO::MachOFile + # @see MachOFile class FatFile + extend Forwardable + # @return [String] the filename loaded from, or nil if loaded from a binary string attr_accessor :filename - # @return [MachO::FatHeader] the file's header + # @return [Headers::FatHeader] the file's header attr_reader :header - # @return [Array<MachO::FatArch>] an array of fat architectures + # @return [Array<Headers::FatArch>] an array of fat architectures attr_reader :fat_archs - # @return [Array<MachO::MachOFile>] an array of Mach-O binaries + # @return [Array<MachOFile>] an array of Mach-O binaries attr_reader :machos + # Creates a new FatFile from the given (single-arch) Mach-Os + # @param machos [Array<MachOFile>] the machos to combine + # @return [FatFile] a new FatFile containing the give machos + def self.new_from_machos(*machos) + header = Headers::FatHeader.new(Headers::FAT_MAGIC, machos.size) + offset = Headers::FatHeader.bytesize + (machos.size * Headers::FatArch.bytesize) + fat_archs = [] + machos.each do |macho| + fat_archs << Headers::FatArch.new(macho.header.cputype, + macho.header.cpusubtype, + offset, macho.serialize.bytesize, + macho.alignment) + offset += macho.serialize.bytesize + end + + bin = header.serialize + bin << fat_archs.map(&:serialize).join + bin << machos.map(&:serialize).join + + new_from_bin(bin) + end + # Creates a new FatFile instance from a binary string. # @param bin [String] a binary string containing raw Mach-O data - # @return [MachO::FatFile] a new FatFile + # @return [FatFile] a new FatFile def self.new_from_bin(bin) instance = allocate instance.initialize_from_bin(bin) @@ -38,7 +64,7 @@ module MachO end # Initializes a new FatFile instance from a binary string. - # @see MachO::FatFile.new_from_bin + # @see new_from_bin # @api private def initialize_from_bin(bin) @filename = nil @@ -52,70 +78,41 @@ module MachO @raw_data end - # @return [Boolean] true if the file is of type `MH_OBJECT`, false otherwise - def object? - machos.first.object? - end - - # @return [Boolean] true if the file is of type `MH_EXECUTE`, false otherwise - def executable? - machos.first.executable? - end - - # @return [Boolean] true if the file is of type `MH_FVMLIB`, false otherwise - def fvmlib? - machos.first.fvmlib? - end - - # @return [Boolean] true if the file is of type `MH_CORE`, false otherwise - def core? - machos.first.core? - end - - # @return [Boolean] true if the file is of type `MH_PRELOAD`, false otherwise - def preload? - machos.first.preload? - end - - # @return [Boolean] true if the file is of type `MH_DYLIB`, false otherwise - def dylib? - machos.first.dylib? - end - - # @return [Boolean] true if the file is of type `MH_DYLINKER`, false otherwise - def dylinker? - machos.first.dylinker? - end - - # @return [Boolean] true if the file is of type `MH_BUNDLE`, false otherwise - def bundle? - machos.first.bundle? - end - - # @return [Boolean] true if the file is of type `MH_DSYM`, false otherwise - def dsym? - machos.first.dsym? - end - - # @return [Boolean] true if the file is of type `MH_KEXT_BUNDLE`, false otherwise - def kext? - machos.first.kext? - end - - # @return [Fixnum] the file's magic number - def magic - header.magic - end + # @!method 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 - MH_MAGICS[magic] - end - - # The file's type. Assumed to be the same for every Mach-O within. - # @return [Symbol] the filetype - def filetype - machos.first.filetype + Headers::MH_MAGICS[magic] end # Populate the instance's fields with the raw Fat Mach-O data. @@ -128,21 +125,13 @@ module MachO end # All load commands responsible for loading dylibs in the file's Mach-O's. - # @return [Array<MachO::DylibCommand>] an array of DylibCommands + # @return [Array<LoadCommands::DylibCommand>] an array of DylibCommands def dylib_load_commands machos.map(&:dylib_load_commands).flatten end - # The file's dylib ID. If the file is not a dylib, returns `nil`. - # @example - # file.dylib_id # => 'libBar.dylib' - # @return [String, nil] the file's dylib ID - # @see MachO::MachOFile#linked_dylibs - def dylib_id - machos.first.dylib_id - end - - # Changes the file's dylib ID to `new_id`. If the file is not a dylib, does nothing. + # Changes the file's dylib ID to `new_id`. If the file is not a dylib, + # does nothing. # @example # file.change_dylib_id('libFoo.dylib') # @param new_id [String] the new dylib ID @@ -151,7 +140,7 @@ module MachO # if false, fail only if all slices fail. # @return [void] # @raise [ArgumentError] if `new_id` is not a String - # @see MachO::MachOFile#linked_dylibs + # @see MachOFile#linked_dylibs def change_dylib_id(new_id, options = {}) raise ArgumentError, "argument must be a String" unless new_id.is_a?(String) return unless machos.all?(&:dylib?) @@ -167,7 +156,7 @@ module MachO # All shared libraries linked to the file's Mach-Os. # @return [Array<String>] an array of all shared libraries - # @see MachO::MachOFile#linked_dylibs + # @see MachOFile#linked_dylibs def linked_dylibs # Individual architectures in a fat binary can link to different subsets # of libraries, but at this point we want to have the full picture, i.e. @@ -175,8 +164,9 @@ module MachO machos.map(&:linked_dylibs).flatten.uniq end - # Changes all dependent shared library install names from `old_name` to `new_name`. - # In a fat file, this changes install names in all internal Mach-Os. + # Changes all dependent shared library install names from `old_name` to + # `new_name`. In a fat file, this changes install names in all internal + # Mach-Os. # @example # file.change_install_name('/usr/lib/libFoo.dylib', '/usr/lib/libBar.dylib') # @param old_name [String] the shared library name being changed @@ -185,7 +175,7 @@ module MachO # @option options [Boolean] :strict (true) if true, fail if one slice fails. # if false, fail only if all slices fail. # @return [void] - # @see MachO::MachOFile#change_install_name + # @see MachOFile#change_install_name def change_install_name(old_name, new_name, options = {}) each_macho(options) do |macho| macho.change_install_name(old_name, new_name, options) @@ -198,7 +188,7 @@ module MachO # All runtime paths associated with the file's Mach-Os. # @return [Array<String>] an array of all runtime paths - # @see MachO::MachOFile#rpaths + # @see MachOFile#rpaths def rpaths # Can individual architectures have different runtime paths? machos.map(&:rpaths).flatten.uniq @@ -211,7 +201,7 @@ module MachO # @option options [Boolean] :strict (true) if true, fail if one slice fails. # if false, fail only if all slices fail. # @return [void] - # @see MachO::MachOFile#change_rpath + # @see MachOFile#change_rpath def change_rpath(old_path, new_path, options = {}) each_macho(options) do |macho| macho.change_rpath(old_path, new_path, options) @@ -226,7 +216,7 @@ module MachO # @option options [Boolean] :strict (true) if true, fail if one slice fails. # if false, fail only if all slices fail. # @return [void] - # @see MachO::MachOFile#add_rpath + # @see MachOFile#add_rpath def add_rpath(path, options = {}) each_macho(options) do |macho| macho.add_rpath(path, options) @@ -241,7 +231,7 @@ module MachO # @option options [Boolean] :strict (true) if true, fail if one slice fails. # if false, fail only if all slices fail. # @return void - # @see MachO::MachOFile#delete_rpath + # @see MachOFile#delete_rpath def delete_rpath(path, options = {}) each_macho(options) do |macho| macho.delete_rpath(path, options) @@ -254,20 +244,21 @@ module MachO # @example # file.extract(:i386) # => MachO::MachOFile # @param cputype [Symbol] the CPU type of the Mach-O being extracted - # @return [MachO::MachOFile, nil] the extracted Mach-O or nil if no Mach-O has the given CPU type + # @return [MachOFile, nil] the extracted Mach-O or nil if no Mach-O has the given CPU type def extract(cputype) machos.select { |macho| macho.cputype == cputype }.first end # Write all (fat) data to the given filename. # @param filename [String] the file to write to + # @return [void] def write(filename) File.open(filename, "wb") { |f| f.write(@raw_data) } end # Write all (fat) data to the file used to initialize the instance. # @return [void] - # @raise [MachO::MachOError] if the instance was initialized without a file + # @raise [MachOError] if the instance was initialized without a file # @note Overwrites all data in the file! def write! if filename.nil? @@ -280,17 +271,18 @@ module MachO private # Obtain the fat header from raw file data. - # @return [MachO::FatHeader] the fat header - # @raise [MachO::TruncatedFileError] if the file is too small to have a valid header - # @raise [MachO::MagicError] if the magic is not valid Mach-O magic - # @raise [MachO::MachOBinaryError] if the magic is for a non-fat Mach-O file - # @raise [MachO::JavaClassFileError] if the file is a Java classfile + # @return [Headers::FatHeader] the fat header + # @raise [TruncatedFileError] if the file is too small to have a + # valid header + # @raise [MagicError] if the magic is not valid Mach-O magic + # @raise [MachOBinaryError] if the magic is for a non-fat Mach-O file + # @raise [JavaClassFileError] if the file is a Java classfile # @api private def populate_fat_header # the smallest fat Mach-O header is 8 bytes raise TruncatedFileError if @raw_data.size < 8 - fh = FatHeader.new_from_bin(:big, @raw_data[0, FatHeader.bytesize]) + fh = Headers::FatHeader.new_from_bin(:big, @raw_data[0, Headers::FatHeader.bytesize]) raise MagicError, fh.magic unless Utils.magic?(fh.magic) raise MachOBinaryError unless Utils.fat_magic?(fh.magic) @@ -308,22 +300,22 @@ module MachO end # Obtain an array of fat architectures from raw file data. - # @return [Array<MachO::FatArch>] an array of fat architectures + # @return [Array<Headers::FatArch>] an array of fat architectures # @api private def populate_fat_archs archs = [] - fa_off = FatHeader.bytesize - fa_len = FatArch.bytesize + fa_off = Headers::FatHeader.bytesize + fa_len = Headers::FatArch.bytesize header.nfat_arch.times do |i| - archs << FatArch.new_from_bin(:big, @raw_data[fa_off + (fa_len * i), fa_len]) + archs << Headers::FatArch.new_from_bin(:big, @raw_data[fa_off + (fa_len * i), fa_len]) end archs end # Obtain an array of Mach-O blobs from raw file data. - # @return [Array<MachO::MachOFile>] an array of Mach-Os + # @return [Array<MachOFile>] an array of Mach-Os # @api private def populate_machos machos = [] @@ -351,7 +343,7 @@ module MachO # @option options [Boolean] :strict (true) whether or not to fail loudly # with an exception if at least one Mach-O raises an exception. If false, # only raises an exception if *all* Mach-Os raise exceptions. - # @raise [MachO::RecoverableModificationError] under the conditions of + # @raise [RecoverableModificationError] under the conditions of # the `:strict` option above. # @api private def each_macho(options = {}) @@ -373,5 +365,13 @@ module MachO # Non-strict mode: Raise first error if *all* Mach-O slices failed. raise errors.first if errors.size == machos.size end + + # Return a single-arch Mach-O that represents this fat Mach-O for purposes + # of delegation. + # @return [MachOFile] the Mach-O file + # @api private + def canonical_macho + machos.first + end end end diff --git a/Library/Homebrew/vendor/macho/macho/headers.rb b/Library/Homebrew/vendor/macho/macho/headers.rb index 7272503af..08a4b80c4 100644 --- a/Library/Homebrew/vendor/macho/macho/headers.rb +++ b/Library/Homebrew/vendor/macho/macho/headers.rb @@ -1,587 +1,665 @@ module MachO - # 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 + # Classes and constants for parsing the headers of Mach-O binaries. + module Headers + # big-endian fat magic + # @api private + FAT_MAGIC = 0xcafebabe - # the v7s ("Swift") sub-type for `CPU_TYPE_ARM` - # @api private - CPU_SUBTYPE_ARM_V7S = 11 + # 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 - # 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 - end + # 32-bit big-endian magic + # @api private + MH_MAGIC = 0xfeedface - # Fat binary header architecture structure. A Fat binary has one or more of - # these, representing one or more internal Mach-O blobs. - # @see MachO::FatHeader - class FatArch < MachOStructure - # @return [Fixnum] the CPU type of the Mach-O - attr_reader :cputype + # 32-bit little-endian magic + # @api private + MH_CIGAM = 0xcefaedfe - # @return [Fixnum] the CPU subtype of the Mach-O - attr_reader :cpusubtype + # 64-bit big-endian magic + # @api private + MH_MAGIC_64 = 0xfeedfacf - # @return [Fixnum] the file offset to the beginning of the Mach-O data - attr_reader :offset + # 64-bit little-endian magic + # @api private + MH_CIGAM_64 = 0xcffaedfe - # @return [Fixnum] the size, in bytes, of the Mach-O data - attr_reader :size + # 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 - # @return [Fixnum] the alignment, as a power of 2 - attr_reader :align + # any CPU (unused?) + # @api private + CPU_TYPE_ANY = -1 - # always big-endian - # @see MachOStructure::FORMAT + # m68k compatible CPUs # @api private - FORMAT = "N5".freeze + CPU_TYPE_MC680X0 = 0x06 - # @see MachOStructure::SIZEOF + # i386 and later compatible CPUs # @api private - SIZEOF = 20 + CPU_TYPE_I386 = 0x07 + # x86_64 (AMD64) compatible CPUs # @api private - def initialize(cputype, cpusubtype, offset, size, align) - @cputype = cputype - @cpusubtype = cpusubtype - @offset = offset - @size = size - @align = align - end - end + CPU_TYPE_X86_64 = (CPU_TYPE_I386 | CPU_ARCH_ABI64) - # 32-bit Mach-O file header structure - class MachHeader < MachOStructure - # @return [Fixnum] the magic number - attr_reader :magic + # 32-bit ARM compatible CPUs + # @api private + CPU_TYPE_ARM = 0x0c - # @return [Fixnum] the CPU type of the Mach-O - attr_reader :cputype + # m88k compatible CPUs + # @api private + CPU_TYPE_MC88000 = 0xd - # @return [Fixnum] the CPU subtype of the Mach-O - attr_reader :cpusubtype + # 64-bit ARM compatible CPUs + # @api private + CPU_TYPE_ARM64 = (CPU_TYPE_ARM | CPU_ARCH_ABI64) - # @return [Fixnum] the file type of the Mach-O - attr_reader :filetype + # PowerPC compatible CPUs + # @api private + CPU_TYPE_POWERPC = 0x12 - # @return [Fixnum] the number of load commands in the Mach-O - attr_reader :ncmds + # PowerPC64 compatible CPUs + # @api private + CPU_TYPE_POWERPC64 = (CPU_TYPE_POWERPC | CPU_ARCH_ABI64) - # @return [Fixnum] the size of all load commands, in bytes, in the Mach-O - attr_reader :sizeofcmds + # 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 - # @return [Fixnum] the header flags associated with the Mach-O - attr_reader :flags + # 64-bit libraries (undocumented!) + # @see http://llvm.org/docs/doxygen/html/Support_2MachO_8h_source.html + # @api private + CPU_SUBTYPE_LIB64 = 0x80000000 - # @see MachOStructure::FORMAT + # the lowest common sub-type for `CPU_TYPE_I386` # @api private - FORMAT = "L=7".freeze + CPU_SUBTYPE_I386 = 3 - # @see MachOStructure::SIZEOF + # the i486 sub-type for `CPU_TYPE_I386` # @api private - SIZEOF = 28 + CPU_SUBTYPE_486 = 4 + # the i486SX sub-type for `CPU_TYPE_I386` # @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 + CPU_SUBTYPE_486SX = 132 - # @example - # puts "this mach-o has position-independent execution" if header.flag?(:MH_PIE) - # @param flag [Symbol] a mach header flag symbol - # @return [Boolean] true if `flag` is present in the header's flag section - def flag?(flag) - flag = MH_FLAGS[flag] - return false if flag.nil? - flags & flag == flag - end - end + # 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 - # 64-bit Mach-O file header structure - class MachHeader64 < MachHeader - # @return [void] - attr_reader :reserved + # 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 - # @see MachOStructure::FORMAT + # the 7400 (G4) sub-type for `CPU_TYPE_POWERPC` # @api private - FORMAT = "L=8".freeze + CPU_SUBTYPE_POWERPC_7400 = 10 - # @see MachOStructure::SIZEOF + # the 7450 (G4 "Voyager") sub-type for `CPU_TYPE_POWERPC` # @api private - SIZEOF = 32 + CPU_SUBTYPE_POWERPC_7450 = 11 + # the 970 (G5) sub-type for `CPU_TYPE_POWERPC` # @api private - def initialize(magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds, - flags, reserved) - super(magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags) - @reserved = reserved + 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 index 205110801..be4319ee2 100644 --- a/Library/Homebrew/vendor/macho/macho/load_commands.rb +++ b/Library/Homebrew/vendor/macho/macho/load_commands.rb @@ -1,1314 +1,1350 @@ module MachO - # load commands added after OS X 10.1 need to be bitwise ORed with - # LC_REQ_DYLD to be recognized by the dynamic linder (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", - :LC_SYMSEG => "SymsegCommand", # obsolete - :LC_THREAD => "ThreadCommand", # seems obsolete, but not documented as such - :LC_UNIXTHREAD => "ThreadCommand", - :LC_LOADFVMLIB => "FvmlibCommand", # obsolete - :LC_IDFVMLIB => "FvmlibCommand", # obsolete - :LC_IDENT => "IdentCommand", # obsolete - :LC_FVMFILE => "FvmfileCommand", # reserved for internal use only - :LC_PREPAGE => "LoadCommand", # reserved for internal use only, no public struct - :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 + # 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 + # @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 [MachO::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) + # 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 + 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) + # 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 = MachO.const_get LC_STRUCTURES[cmd_sym] - cmd = LOAD_COMMAND_CONSTANTS[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 + # 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 + raise LoadCommandCreationArityError.new(cmd_sym, klass_arity, args.size) if klass_arity != args.size - klass.new(nil, cmd, nil, *args) - end + 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 + # @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] true if the load command can be serialized, false otherwise - def serializable? - CREATABLE_LOAD_COMMANDS.include?(LOAD_COMMANDS[cmd]) - end + # @return [Boolean] whether the load command can be serialized + def serializable? + CREATABLE_LOAD_COMMANDS.include?(LOAD_COMMANDS[cmd]) + end - # @param context [MachO::LoadCommand::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 + # @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 [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 + # @return [Symbol] a symbol representation of the load command's + # identifying number + def type + LOAD_COMMANDS[cmd] + end - alias to_sym type + alias to_sym type - # @return [String] a string representation of the load command's identifying number - def to_s - type.to_s - end + # @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 [MachO::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 + # 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 - end - # @return [String] a string representation of the LCStr - def to_s - @string + # @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 - # @return [Fixnum] the offset to the beginning of the string in the load command - def to_i - @string_offset + # 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 - # 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 + # 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<Fixnum>] the UUID + attr_reader :uuid - # @return [Fixnum] the constant alignment value used to pad the serialized load command - attr_reader :alignment + # @see MachOStructure::FORMAT + # @api private + FORMAT = "L=2a16".freeze - # @param macho [MachO::MachOFile] the file to contextualize - # @return [MachO::LoadCommand::SerializationContext] the resulting context - def self.context_for(macho) - new(macho.endianness, macho.alignment) - end + # @see MachOStructure::SIZEOF + # @api private + SIZEOF = 24 - # @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 + def initialize(view, cmd, cmdsize, uuid) + super(view, cmd, cmdsize) + @uuid = uuid.unpack("C16") # re-unpack for the actual UUID array 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<Fixnum>] the UUID - attr_reader :uuid - # @see MachOStructure::FORMAT - # @api private - FORMAT = "L=2a16".freeze - - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 24 + # @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 + ] - # @api private - def initialize(view, cmd, cmdsize, uuid) - super(view, cmd, cmdsize) - @uuid = uuid.unpack("C16") # re-unpack for the actual UUID array + segs.join("-") + end 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 - ] + # 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 - segs.join("-") - end - end + # @return [Fixnum] the memory address of the segment + attr_reader :vmaddr - # 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 size of the segment + attr_reader :vmsize - # @return [Fixnum] the memory address of the segment - attr_reader :vmaddr + # @return [Fixnum] the file offset of the segment + attr_reader :fileoff - # @return [Fixnum] the memory size of the segment - attr_reader :vmsize + # @return [Fixnum] the amount to map from the file + attr_reader :filesize - # @return [Fixnum] the file offset of the segment - attr_reader :fileoff + # @return [Fixnum] the maximum VM protection + attr_reader :maxprot - # @return [Fixnum] the amount to map from the file - attr_reader :filesize + # @return [Fixnum] the initial VM protection + attr_reader :initprot - # @return [Fixnum] the maximum VM protection - attr_reader :maxprot + # @return [Fixnum] the number of sections in the segment + attr_reader :nsects - # @return [Fixnum] the initial VM protection - attr_reader :initprot + # @return [Fixnum] any flags associated with the segment + attr_reader :flags - # @return [Fixnum] the number of sections in the segment - attr_reader :nsects + # @see MachOStructure::FORMAT + # @api private + FORMAT = "L=2a16L=4l=2L=2".freeze - # @return [Fixnum] any flags associated with the segment - attr_reader :flags + # @see MachOStructure::SIZEOF + # @api private + SIZEOF = 56 - # @see MachOStructure::FORMAT - # @api private - FORMAT = "L=2a16L=4l=2L=2".freeze + # @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 - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 56 + # All sections referenced within this segment. + # @return [Array<MachO::Sections::Section>] if the Mach-O is 32-bit + # @return [Array<MachO::Sections::Section64>] if the Mach-O is 64-bit + def sections + klass = case self + when SegmentCommand64 + MachO::Sections::Section64 + when SegmentCommand + MachO::Sections::Section + end - # @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 + offset = view.offset + self.class.bytesize + length = nsects * klass.bytesize - # All sections referenced within this segment. - # @return [Array<MachO::Section>] if the Mach-O is 32-bit - # @return [Array<MachO::Section64>] if the Mach-O is 64-bit - def sections - klass = case self - when MachO::SegmentCommand64 - MachO::Section64 - when MachO::SegmentCommand - MachO::Section + bins = view.raw_data[offset, length] + bins.unpack("a#{klass.bytesize}" * nsects).map do |bin| + klass.new_from_bin(view.endianness, bin) + end end - bins = view.raw_data[view.offset + self.class.bytesize, nsects * klass.bytesize] - bins.unpack("a#{klass.bytesize}" * nsects).map do |bin| - klass.new_from_bin(view.endianness, bin) + # @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 - # @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 + # 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 + # @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 [MachO::LoadCommand::LCStr] the library's path name as an LCStr - attr_reader :name + # 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 build time stamp + attr_reader :timestamp - # @return [Fixnum] the library's current version number - attr_reader :current_version + # @return [Fixnum] the library's current version number + attr_reader :current_version - # @return [Fixnum] the library's compatibility version number - attr_reader :compatibility_version + # @return [Fixnum] the library's compatibility version number + attr_reader :compatibility_version - # @see MachOStructure::FORMAT - # @api private - FORMAT = "L=6".freeze + # @see MachOStructure::FORMAT + # @api private + FORMAT = "L=6".freeze - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 24 + # @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 + # @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 [MachO::LoadCcommand::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 + # @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 - 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 [MachO::LoadCommand::LCStr] the dynamic linker's path name as an LCStr - attr_reader :name + # 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::FORMAT + # @api private + FORMAT = "L=3".freeze - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 12 + # @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 + # @api private + def initialize(view, cmd, cmdsize, name) + super(view, cmd, cmdsize) + @name = LCStr.new(self, name) + end - # @param context [MachO::LoadCcommand::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 + # @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 - end - # A load command used to indicate dynamic libraries used in prebinding. - # Corresponds to LC_PREBOUND_DYLIB. - class PreboundDylibCommand < LoadCommand - # @return [MachO::LoadCommand::LCStr] the library's path name as an LCStr - attr_reader :name + # 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] the number of modules in the library + attr_reader :nmodules - # @return [Fixnum] a bit vector of linked modules - attr_reader :linked_modules + # @return [Fixnum] a bit vector of linked modules + attr_reader :linked_modules - # @see MachOStructure::FORMAT - # @api private - FORMAT = "L=5".freeze + # @see MachOStructure::FORMAT + # @api private + FORMAT = "L=5".freeze - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 20 + # @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 + # @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 - end - # A load command used to represent threads. - # @note cctools-870 has all fields of thread_command commented out except common ones (cmd, cmdsize) - class ThreadCommand < LoadCommand - # @see MachOStructure::FORMAT - # @api private - FORMAT = "L=2".freeze + # 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 + # @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 + # 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 [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 :reserved1 - # @return [void] - attr_reader :reserved2 + # @return [void] + attr_reader :reserved2 - # @return [void] - attr_reader :reserved3 + # @return [void] + attr_reader :reserved3 - # @return [void] - attr_reader :reserved4 + # @return [void] + attr_reader :reserved4 - # @return [void] - attr_reader :reserved5 + # @return [void] + attr_reader :reserved5 - # @return [void] - attr_reader :reserved6 + # @return [void] + attr_reader :reserved6 - # @see MachOStructure::FORMAT - # @api private - FORMAT = "L=10".freeze + # @see MachOStructure::FORMAT + # @api private + FORMAT = "L=10".freeze - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 40 + # @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 + # @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 - 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 + # 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 + # @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 [MachO::LoadCommand::LCStr] the umbrella framework name as an LCStr - attr_reader :umbrella + # 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::FORMAT + # @api private + FORMAT = "L=3".freeze - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 12 + # @see MachOStructure::SIZEOF + # @api private + SIZEOF = 12 - # @api private - def initialize(view, cmd, cmdsize, umbrella) - super(view, cmd, cmdsize) - @umbrella = LCStr.new(self, umbrella) + # @api private + def initialize(view, cmd, cmdsize, umbrella) + super(view, cmd, cmdsize) + @umbrella = LCStr.new(self, umbrella) + end 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 [MachO::LoadCommand::LCStr] the subumbrella framework name as an LCStr - attr_reader :sub_umbrella + # 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::FORMAT + # @api private + FORMAT = "L=3".freeze - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 12 + # @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) + # @api private + def initialize(view, cmd, cmdsize, sub_umbrella) + super(view, cmd, cmdsize) + @sub_umbrella = LCStr.new(self, sub_umbrella) + end end - end - # A load command signifying a sublibrary of a shared library. Corresponds - # to LC_SUB_LIBRARY. - class SubLibraryCommand < LoadCommand - # @return [MachO::LoadCommand::LCStr] the sublibrary name as an LCStr - attr_reader :sub_library + # 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::FORMAT + # @api private + FORMAT = "L=3".freeze - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 12 + # @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) + # @api private + def initialize(view, cmd, cmdsize, sub_library) + super(view, cmd, cmdsize) + @sub_library = LCStr.new(self, sub_library) + end 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 [MachO::LoadCommand::LCStr] the subclient name as an LCStr - attr_reader :sub_client + # 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::FORMAT + # @api private + FORMAT = "L=3".freeze - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 12 + # @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) + # @api private + def initialize(view, cmd, cmdsize, sub_client) + super(view, cmd, cmdsize) + @sub_client = LCStr.new(self, sub_client) + end 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 + # 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 [Fixnum] the number of symbol table entries + attr_reader :nsyms - # @return the string table's offset - attr_reader :stroff + # @return the string table's offset + attr_reader :stroff - # @return the string table size in bytes - attr_reader :strsize + # @return the string table size in bytes + attr_reader :strsize - # @see MachOStructure::FORMAT - # @api private - FORMAT = "L=6".freeze + # @see MachOStructure::FORMAT + # @api private + FORMAT = "L=6".freeze - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 24 + # @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 + # @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 - 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 + # 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 number of local symbols + attr_reader :nlocalsym - # @return [Fixnum] the index to externally defined symbols - attr_reader :iextdefsym + # @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 number of externally defined symbols + attr_reader :nextdefsym - # @return [Fixnum] the index to undefined symbols - attr_reader :iundefsym + # @return [Fixnum] the index to undefined symbols + attr_reader :iundefsym - # @return [Fixnum] the number of undefined symbols - attr_reader :nundefsym + # @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 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 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 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 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 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 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 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 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 file offset to the external relocation entries + attr_reader :extreloff - # @return [Fixnum] the number of external relocation entries - attr_reader :nextrel + # @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 file offset to the local relocation entries + attr_reader :locreloff - # @return [Fixnum] the number of local relocation entries - attr_reader :nlocrel + # @return [Fixnum] the number of local relocation entries + attr_reader :nlocrel - # @see MachOStructure::FORMAT - # @api private - FORMAT = "L=20".freeze + # @see MachOStructure::FORMAT + # @api private + FORMAT = "L=20".freeze - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 80 + # @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 + # 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 - 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 + # 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 [Fixnum] the number of hints in the hint table + attr_reader :nhints - # @return [MachO::TwolevelHintsCommand::TwolevelHintTable] the hint table - attr_reader :table + # @return [TwolevelHintsTable] + # the hint table + attr_reader :table - # @see MachOStructure::FORMAT - # @api private - FORMAT = "L=4".freeze + # @see MachOStructure::FORMAT + # @api private + FORMAT = "L=4".freeze - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 16 + # @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 + # @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<MachO::TwoLevelHintsTable::TwoLevelHint>] all hints in the table - attr_reader :hints + # A representation of the two-level namespace lookup hints table exposed + # by a {TwolevelHintsCommand} (`LC_TWOLEVEL_HINTS`). + class TwolevelHintsTable + # @return [Array<TwolevelHint>] 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) + # @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 + @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 + # 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 + # @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 + # @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 - 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 + # 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::FORMAT + # @api private + FORMAT = "L=3".freeze - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 12 + # @see MachOStructure::SIZEOF + # @api private + SIZEOF = 12 - # @api private - def initialize(view, cmd, cmdsize, cksum) - super(view, cmd, cmdsize) - @cksum = cksum + # @api private + def initialize(view, cmd, cmdsize, cksum) + super(view, cmd, cmdsize) + @cksum = cksum + end 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 [MachO::LoadCommand::LCStr] the path to add to the run path as an LCStr - attr_reader :path + # 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::FORMAT + # @api private + FORMAT = "L=3".freeze - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 12 + # @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 + # @api private + def initialize(view, cmd, cmdsize, path) + super(view, cmd, cmdsize) + @path = LCStr.new(self, path) + end - # @param context [MachO::LoadCcommand::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 + # @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 - 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 + # 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 + # @return [Fixnum] size of the data in the __LINKEDIT segment + attr_reader :datasize - # @see MachOStructure::FORMAT - # @api private - FORMAT = "L=4".freeze + # @see MachOStructure::FORMAT + # @api private + FORMAT = "L=4".freeze - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 16 + # @see MachOStructure::SIZEOF + # @api private + SIZEOF = 16 - # @api private - def initialize(view, cmd, cmdsize, dataoff, datasize) - super(view, cmd, cmdsize) - @dataoff = dataoff - @datasize = datasize + # @api private + def initialize(view, cmd, cmdsize, dataoff, datasize) + super(view, cmd, cmdsize) + @dataoff = dataoff + @datasize = datasize + end 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 + # 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 size of the encrypted segment + attr_reader :cryptsize - # @return [Fixnum] the encryption system, or 0 if not encrypted yet - attr_reader :cryptid + # @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::FORMAT + # @api private + FORMAT = "L=5".freeze - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 20 + # @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 + # @api private + def initialize(view, cmd, cmdsize, cryptoff, cryptsize, cryptid) + super(view, cmd, cmdsize) + @cryptoff = cryptoff + @cryptsize = cryptsize + @cryptid = cryptid + end 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 + # 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 size of the encrypted segment + attr_reader :cryptsize - # @return [Fixnum] the encryption system, or 0 if not encrypted yet - attr_reader :cryptid + # @return [Fixnum] the encryption system, or 0 if not encrypted yet + attr_reader :cryptid - # @return [Fixnum] 64-bit padding value - attr_reader :pad + # @return [Fixnum] 64-bit padding value + attr_reader :pad - # @see MachOStructure::FORMAT - # @api private - FORMAT = "L=6".freeze + # @see MachOStructure::FORMAT + # @api private + FORMAT = "L=6".freeze - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 24 + # @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 + # @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 - 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 + # 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 + # @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::FORMAT + # @api private + FORMAT = "L=4".freeze - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 16 + # @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 + # @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) } + # 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 + 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) } + # 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(".") + segs.join(".") + end 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 + # 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 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 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 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 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 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 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 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 file offset to the export information + attr_reader :export_off - # @return [Fixnum] the size of the export information - attr_reader :export_size + # @return [Fixnum] the size of the export information + attr_reader :export_size - # @see MachOStructure::FORMAT - # @api private - FORMAT = "L=12".freeze + # @see MachOStructure::FORMAT + # @api private + FORMAT = "L=12".freeze - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 48 + # @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 + # @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 - 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 + # 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::FORMAT + # @api private + FORMAT = "L=3".freeze - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 12 + # @see MachOStructure::SIZEOF + # @api private + SIZEOF = 12 - # @api private - def initialize(view, cmd, cmdsize, count) - super(view, cmd, cmdsize) - @count = count + # @api private + def initialize(view, cmd, cmdsize, count) + super(view, cmd, cmdsize) + @count = count + end 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 + # 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 + # @return [Fixnum] if not 0, the initial stack size. + attr_reader :stacksize - # @see MachOStructure::FORMAT - # @api private - FORMAT = "L=2Q=2".freeze + # @see MachOStructure::FORMAT + # @api private + FORMAT = "L=2Q=2".freeze - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 24 + # @see MachOStructure::SIZEOF + # @api private + SIZEOF = 24 - # @api private - def initialize(view, cmd, cmdsize, entryoff, stacksize) - super(view, cmd, cmdsize) - @entryoff = entryoff - @stacksize = stacksize + # @api private + def initialize(view, cmd, cmdsize, entryoff, stacksize) + super(view, cmd, cmdsize) + @entryoff = entryoff + @stacksize = stacksize + end 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 + # 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::FORMAT + # @api private + FORMAT = "L=2Q=1".freeze - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 16 + # @see MachOStructure::SIZEOF + # @api private + SIZEOF = 16 - # @api private - def initialize(view, cmd, cmdsize, version) - super(view, cmd, cmdsize) - @version = version - end + # @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) } + # 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(".") + segs.join(".") + end 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 + # 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 + # @return [Fixnum] the size of the symbol segment in bytes + attr_reader :size - # @see MachOStructure::FORMAT - # @api private - FORMAT = "L=4".freeze + # @see MachOStructure::FORMAT + # @api private + FORMAT = "L=4".freeze - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 16 + # @see MachOStructure::SIZEOF + # @api private + SIZEOF = 16 - # @api private - def initialize(view, cmd, cmdsize, offset, size) - super(view, cmd, cmdsize) - @offset = offset - @size = size + # @api private + def initialize(view, cmd, cmdsize, offset, size) + super(view, cmd, cmdsize) + @offset = offset + @size = size + end 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 + # 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 + # @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 [MachO::LoadCommand::LCStr] the pathname of the file being loaded - attr_reader :name + # 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 + # @return [Fixnum] the virtual address being loaded at + attr_reader :header_addr - # @see MachOStructure::FORMAT - # @api private - FORMAT = "L=4".freeze + # @see MachOStructure::FORMAT + # @api private + FORMAT = "L=4".freeze - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 16 + # @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 + def initialize(view, cmd, cmdsize, name, header_addr) + super(view, cmd, cmdsize) + @name = LCStr.new(self, name) + @header_addr = header_addr + end 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 [MachO::LoadCommand::LCStr] the library's target pathname - attr_reader :name + # 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 minor version number + attr_reader :minor_version - # @return [Fixnum] the library's header address - attr_reader :header_addr + # @return [Fixnum] the library's header address + attr_reader :header_addr - # @see MachOStructure::FORMAT - # @api private - FORMAT = "L=5".freeze + # @see MachOStructure::FORMAT + # @api private + FORMAT = "L=5".freeze - # @see MachOStructure::SIZEOF - # @api private - SIZEOF = 20 + # @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 + 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 index 8ece62672..7693ab0dd 100644 --- a/Library/Homebrew/vendor/macho/macho/macho_file.rb +++ b/Library/Homebrew/vendor/macho/macho/macho_file.rb @@ -1,27 +1,33 @@ +require "forwardable" + module MachO # Represents a Mach-O file, which contains a header and load commands # as well as binary executable instructions. Mach-O binaries are # architecture specific. # @see https://en.wikipedia.org/wiki/Mach-O - # @see MachO::FatFile + # @see FatFile class MachOFile - # @return [String] the filename loaded from, or nil if loaded from a binary string + extend Forwardable + + # @return [String] the filename loaded from, or nil if loaded from a binary + # string attr_accessor :filename # @return [Symbol] the endianness of the file, :big or :little attr_reader :endianness - # @return [MachO::MachHeader] if the Mach-O is 32-bit - # @return [MachO::MachHeader64] if the Mach-O is 64-bit + # @return [Headers::MachHeader] if the Mach-O is 32-bit + # @return [Headers::MachHeader64] if the Mach-O is 64-bit attr_reader :header - # @return [Array<MachO::LoadCommand>] an array of the file's load commands + # @return [Array<LoadCommands::LoadCommand>] an array of the file's load + # commands # @note load commands are provided in order of ascending offset. attr_reader :load_commands # Creates a new MachOFile instance from a binary string. # @param bin [String] a binary string containing raw Mach-O data - # @return [MachO::MachOFile] a new MachOFile + # @return [MachOFile] a new MachOFile def self.new_from_bin(bin) instance = allocate instance.initialize_from_bin(bin) @@ -55,109 +61,63 @@ module MachO @raw_data end - # @return [Boolean] true if the Mach-O has 32-bit magic, false otherwise - def magic32? - Utils.magic32?(header.magic) - end - - # @return [Boolean] true if the Mach-O has 64-bit magic, false otherwise - def magic64? - Utils.magic64?(header.magic) - end - - # @return [Fixnum] the file's internal alignment - def alignment - magic32? ? 4 : 8 - end - - # @return [Boolean] true if the file is of type `MH_OBJECT`, false otherwise - def object? - header.filetype == MH_OBJECT - end - - # @return [Boolean] true if the file is of type `MH_EXECUTE`, false otherwise - def executable? - header.filetype == MH_EXECUTE - end - - # @return [Boolean] true if the file is of type `MH_FVMLIB`, false otherwise - def fvmlib? - header.filetype == MH_FVMLIB - end - - # @return [Boolean] true if the file is of type `MH_CORE`, false otherwise - def core? - header.filetype == MH_CORE - end - - # @return [Boolean] true if the file is of type `MH_PRELOAD`, false otherwise - def preload? - header.filetype == MH_PRELOAD - end - - # @return [Boolean] true if the file is of type `MH_DYLIB`, false otherwise - def dylib? - header.filetype == MH_DYLIB - end - - # @return [Boolean] true if the file is of type `MH_DYLINKER`, false otherwise - def dylinker? - header.filetype == MH_DYLINKER - end - - # @return [Boolean] true if the file is of type `MH_BUNDLE`, false otherwise - def bundle? - header.filetype == MH_BUNDLE - end - - # @return [Boolean] true if the file is of type `MH_DSYM`, false otherwise - def dsym? - header.filetype == MH_DSYM - end - - # @return [Boolean] true if the file is of type `MH_KEXT_BUNDLE`, false otherwise - def kext? - header.filetype == MH_KEXT_BUNDLE - end - - # @return [Fixnum] the file's magic number - def magic - header.magic - end + # @!method magic + # @return (see MachO::Headers::MachHeader#magic) + # @!method ncmds + # @return (see MachO::Headers::MachHeader#ncmds) + # @!method sizeofcmds + # @return (see MachO::Headers::MachHeader#sizeofcmds) + # @!method flags + # @return (see MachO::Headers::MachHeader#flags) + # @!method object? + # @return (see MachO::Headers::MachHeader#object?) + # @!method executable? + # @return (see MachO::Headers::MachHeader#executable?) + # @!method fvmlib? + # @return (see MachO::Headers::MachHeader#fvmlib?) + # @!method core? + # @return (see MachO::Headers::MachHeader#core?) + # @!method preload? + # @return (see MachO::Headers::MachHeader#preload?) + # @!method dylib? + # @return (see MachO::Headers::MachHeader#dylib?) + # @!method dylinker? + # @return (see MachO::Headers::MachHeader#dylinker?) + # @!method bundle? + # @return (see MachO::Headers::MachHeader#bundle?) + # @!method dsym? + # @return (see MachO::Headers::MachHeader#dsym?) + # @!method kext? + # @return (see MachO::Headers::MachHeader#kext?) + # @!method magic32? + # @return (see MachO::Headers::MachHeader#magic32?) + # @!method magic64? + # @return (see MachO::Headers::MachHeader#magic64?) + # @!method alignment + # @return (see MachO::Headers::MachHeader#alignment) + def_delegators :header, :magic, :ncmds, :sizeofcmds, :flags, :object?, + :executable?, :fvmlib?, :core?, :preload?, :dylib?, + :dylinker?, :bundle?, :dsym?, :kext?, :magic32?, :magic64?, + :alignment # @return [String] a string representation of the file's magic number def magic_string - MH_MAGICS[magic] + Headers::MH_MAGICS[magic] end # @return [Symbol] a string representation of the Mach-O's filetype def filetype - MH_FILETYPES[header.filetype] + Headers::MH_FILETYPES[header.filetype] end # @return [Symbol] a symbol representation of the Mach-O's CPU type def cputype - CPU_TYPES[header.cputype] + Headers::CPU_TYPES[header.cputype] end # @return [Symbol] a symbol representation of the Mach-O's CPU subtype def cpusubtype - CPU_SUBTYPES[header.cputype][header.cpusubtype] - end - - # @return [Fixnum] the number of load commands in the Mach-O's header - def ncmds - header.ncmds - end - - # @return [Fixnum] the size of all load commands, in bytes - def sizeofcmds - header.sizeofcmds - end - - # @return [Fixnum] execution flags set by the linker - def flags - header.flags + Headers::CPU_SUBTYPES[header.cputype][header.cpusubtype] end # All load commands of a given name. @@ -165,7 +125,8 @@ module MachO # file.command("LC_LOAD_DYLIB") # file[:LC_LOAD_DYLIB] # @param [String, Symbol] name the load command ID - # @return [Array<MachO::LoadCommand>] an array of LoadCommands corresponding to `name` + # @return [Array<LoadCommands::LoadCommand>] an array of load commands + # corresponding to `name` def command(name) load_commands.select { |lc| lc.type == name.to_sym } end @@ -174,16 +135,16 @@ module MachO # Inserts a load command at the given offset. # @param offset [Fixnum] the offset to insert at - # @param lc [MachO::LoadCommand] the load command to insert + # @param lc [LoadCommands::LoadCommand] the load command to insert # @param options [Hash] # @option options [Boolean] :repopulate (true) whether or not to repopulate # the instance fields - # @raise [MachO::OffsetInsertionError] if the offset is not in the load command region - # @raise [MachO::HeaderPadError] if the new command exceeds the header pad buffer + # @raise [OffsetInsertionError] if the offset is not in the load command region + # @raise [HeaderPadError] if the new command exceeds the header pad buffer # @note Calling this method with an arbitrary offset in the load command # region **will leave the object in an inconsistent state**. def insert_command(offset, lc, options = {}) - context = LoadCommand::SerializationContext.context_for(self) + context = LoadCommands::LoadCommand::SerializationContext.context_for(self) cmd_raw = lc.serialize(context) if offset < header.class.bytesize || offset + cmd_raw.bytesize > low_fileoff @@ -207,14 +168,14 @@ module MachO end # Replace a load command with another command in the Mach-O, preserving location. - # @param old_lc [MachO::LoadCommand] the load command being replaced - # @param new_lc [MachO::LoadCommand] the load command being added + # @param old_lc [LoadCommands::LoadCommand] the load command being replaced + # @param new_lc [LoadCommands::LoadCommand] the load command being added # @return [void] - # @raise [MachO::HeaderPadError] if the new command exceeds the header pad buffer - # @see {#insert_command} + # @raise [HeaderPadError] if the new command exceeds the header pad buffer + # @see #insert_command # @note This is public, but methods like {#dylib_id=} should be preferred. def replace_command(old_lc, new_lc) - context = LoadCommand::SerializationContext.context_for(self) + context = LoadCommands::LoadCommand::SerializationContext.context_for(self) cmd_raw = new_lc.serialize(context) new_sizeofcmds = sizeofcmds + cmd_raw.bytesize - old_lc.cmdsize if header.class.bytesize + new_sizeofcmds > low_fileoff @@ -226,12 +187,12 @@ module MachO end # Appends a new load command to the Mach-O. - # @param lc [MachO::LoadCommand] the load command being added + # @param lc [LoadCommands::LoadCommand] the load command being added # @param options [Hash] # @option options [Boolean] :repopulate (true) whether or not to repopulate # the instance fields # @return [void] - # @see {#insert_command} + # @see #insert_command # @note This is public, but methods like {#add_rpath} should be preferred. # Setting `repopulate` to false **will leave the instance in an # inconsistent state** unless {#populate_fields} is called **immediately** @@ -241,7 +202,7 @@ module MachO end # Delete a load command from the Mach-O. - # @param lc [MachO::LoadCommand] the load command being deleted + # @param lc [LoadCommands::LoadCommand] the load command being deleted # @param options [Hash] # @option options [Boolean] :repopulate (true) whether or not to repopulate # the instance fields @@ -275,14 +236,14 @@ module MachO end # All load commands responsible for loading dylibs. - # @return [Array<MachO::DylibCommand>] an array of DylibCommands + # @return [Array<LoadCommands::DylibCommand>] an array of DylibCommands def dylib_load_commands - load_commands.select { |lc| DYLIB_LOAD_COMMANDS.include?(lc.type) } + load_commands.select { |lc| LoadCommands::DYLIB_LOAD_COMMANDS.include?(lc.type) } end # All segment load commands in the Mach-O. - # @return [Array<MachO::SegmentCommand>] if the Mach-O is 32-bit - # @return [Array<MachO::SegmentCommand64>] if the Mach-O is 64-bit + # @return [Array<LoadCommands::SegmentCommand>] if the Mach-O is 32-bit + # @return [Array<LoadCommands::SegmentCommand64>] if the Mach-O is 64-bit def segments if magic32? command(:LC_SEGMENT) @@ -319,10 +280,10 @@ module MachO old_lc = command(:LC_ID_DYLIB).first raise DylibIdMissingError unless old_lc - new_lc = LoadCommand.create(:LC_ID_DYLIB, new_id, - old_lc.timestamp, - old_lc.current_version, - old_lc.compatibility_version) + new_lc = LoadCommands::LoadCommand.create(:LC_ID_DYLIB, new_id, + old_lc.timestamp, + old_lc.current_version, + old_lc.compatibility_version) replace_command(old_lc, new_lc) end @@ -341,22 +302,22 @@ module MachO # Changes the shared library `old_name` to `new_name` # @example - # file.change_install_name("/usr/lib/libWhatever.dylib", "/usr/local/lib/libWhatever2.dylib") + # file.change_install_name("abc.dylib", "def.dylib") # @param old_name [String] the shared library's old name # @param new_name [String] the shared library's new name # @param _options [Hash] # @return [void] - # @raise [MachO::DylibUnknownError] if no shared library has the old name + # @raise [DylibUnknownError] if no shared library has the old name # @note `_options` is currently unused and is provided for signature # compatibility with {MachO::FatFile#change_install_name} def change_install_name(old_name, new_name, _options = {}) old_lc = dylib_load_commands.find { |d| d.name.to_s == old_name } raise DylibUnknownError, old_name if old_lc.nil? - new_lc = LoadCommand.create(old_lc.type, new_name, - old_lc.timestamp, - old_lc.current_version, - old_lc.compatibility_version) + new_lc = LoadCommands::LoadCommand.create(old_lc.type, new_name, + old_lc.timestamp, + old_lc.current_version, + old_lc.compatibility_version) replace_command(old_lc, new_lc) end @@ -376,8 +337,8 @@ module MachO # @param new_path [String] the new runtime path # @param _options [Hash] # @return [void] - # @raise [MachO::RpathUnknownError] if no such old runtime path exists - # @raise [MachO::RpathExistsError] if the new runtime path already exists + # @raise [RpathUnknownError] if no such old runtime path exists + # @raise [RpathExistsError] if the new runtime path already exists # @note `_options` is currently unused and is provided for signature # compatibility with {MachO::FatFile#change_rpath} def change_rpath(old_path, new_path, _options = {}) @@ -385,7 +346,7 @@ module MachO raise RpathUnknownError, old_path if old_lc.nil? raise RpathExistsError, new_path if rpaths.include?(new_path) - new_lc = LoadCommand.create(:LC_RPATH, new_path) + new_lc = LoadCommands::LoadCommand.create(:LC_RPATH, new_path) delete_rpath(old_path) insert_command(old_lc.view.offset, new_lc) @@ -399,13 +360,13 @@ module MachO # @param path [String] the new runtime path # @param _options [Hash] # @return [void] - # @raise [MachO::RpathExistsError] if the runtime path already exists + # @raise [RpathExistsError] if the runtime path already exists # @note `_options` is currently unused and is provided for signature # compatibility with {MachO::FatFile#add_rpath} def add_rpath(path, _options = {}) raise RpathExistsError, path if rpaths.include?(path) - rpath_cmd = LoadCommand.create(:LC_RPATH, path) + rpath_cmd = LoadCommands::LoadCommand.create(:LC_RPATH, path) add_command(rpath_cmd) end @@ -417,7 +378,7 @@ module MachO # @param path [String] the runtime path to delete # @param _options [Hash] # @return void - # @raise [MachO::RpathUnknownError] if no such runtime path exists + # @raise [RpathUnknownError] if no such runtime path exists # @note `_options` is currently unused and is provided for signature # compatibility with {MachO::FatFile#delete_rpath} def delete_rpath(path, _options = {}) @@ -431,15 +392,6 @@ module MachO populate_fields end - # All sections of the segment `segment`. - # @param segment [MachO::SegmentCommand, MachO::SegmentCommand64] the segment being inspected - # @return [Array<MachO::Section>] if the Mach-O is 32-bit - # @return [Array<MachO::Section64>] if the Mach-O is 64-bit - # @deprecated use {MachO::SegmentCommand#sections} instead - def sections(segment) - segment.sections - end - # Write all Mach-O data to the given filename. # @param filename [String] the file to write to # @return [void] @@ -449,7 +401,7 @@ module MachO # Write all Mach-O data to the file used to initialize the instance. # @return [void] - # @raise [MachO::MachOError] if the instance was initialized without a file + # @raise [MachOError] if the instance was initialized without a file # @note Overwrites all data in the file! def write! if @filename.nil? @@ -462,16 +414,16 @@ module MachO private # The file's Mach-O header structure. - # @return [MachO::MachHeader] if the Mach-O is 32-bit - # @return [MachO::MachHeader64] if the Mach-O is 64-bit - # @raise [MachO::TruncatedFileError] if the file is too small to have a valid header + # @return [Headers::MachHeader] if the Mach-O is 32-bit + # @return [Headers::MachHeader64] if the Mach-O is 64-bit + # @raise [TruncatedFileError] if the file is too small to have a valid header # @api private def populate_mach_header # the smallest Mach-O header is 28 bytes raise TruncatedFileError if @raw_data.size < 28 magic = populate_and_check_magic - mh_klass = Utils.magic32?(magic) ? MachHeader : MachHeader64 + mh_klass = Utils.magic32?(magic) ? Headers::MachHeader : Headers::MachHeader64 mh = mh_klass.new_from_bin(endianness, @raw_data[0, mh_klass.bytesize]) check_cputype(mh.cputype) @@ -483,8 +435,8 @@ module MachO # Read just the file's magic number and check its validity. # @return [Fixnum] the magic - # @raise [MachO::MagicError] if the magic is not valid Mach-O magic - # @raise [MachO::FatBinaryError] if the magic is for a Fat file + # @raise [MagicError] if the magic is not valid Mach-O magic + # @raise [FatBinaryError] if the magic is for a Fat file # @api private def populate_and_check_magic magic = @raw_data[0..3].unpack("N").first @@ -499,32 +451,32 @@ module MachO # Check the file's CPU type. # @param cputype [Fixnum] the CPU type - # @raise [MachO::CPUTypeError] if the CPU type is unknown + # @raise [CPUTypeError] if the CPU type is unknown # @api private def check_cputype(cputype) - raise CPUTypeError, cputype unless CPU_TYPES.key?(cputype) + raise CPUTypeError, cputype unless Headers::CPU_TYPES.key?(cputype) end # Check the file's CPU type/subtype pair. # @param cpusubtype [Fixnum] the CPU subtype - # @raise [MachO::CPUSubtypeError] if the CPU sub-type is unknown + # @raise [CPUSubtypeError] if the CPU sub-type is unknown # @api private def check_cpusubtype(cputype, cpusubtype) # Only check sub-type w/o capability bits (see `populate_mach_header`). - raise CPUSubtypeError.new(cputype, cpusubtype) unless CPU_SUBTYPES[cputype].key?(cpusubtype) + raise CPUSubtypeError.new(cputype, cpusubtype) unless Headers::CPU_SUBTYPES[cputype].key?(cpusubtype) end # Check the file's type. # @param filetype [Fixnum] the file type - # @raise [MachO::FiletypeError] if the file type is unknown + # @raise [FiletypeError] if the file type is unknown # @api private def check_filetype(filetype) - raise FiletypeError, filetype unless MH_FILETYPES.key?(filetype) + raise FiletypeError, filetype unless Headers::MH_FILETYPES.key?(filetype) end # All load commands in the file. - # @return [Array<MachO::LoadCommand>] an array of load commands - # @raise [MachO::LoadCommandError] if an unknown load command is encountered + # @return [Array<LoadCommands::LoadCommand>] an array of load commands + # @raise [LoadCommandError] if an unknown load command is encountered # @api private def populate_load_commands offset = header.class.bytesize @@ -533,13 +485,13 @@ module MachO header.ncmds.times do fmt = Utils.specialize_format("L=", endianness) cmd = @raw_data.slice(offset, 4).unpack(fmt).first - cmd_sym = LOAD_COMMANDS[cmd] + cmd_sym = LoadCommands::LOAD_COMMANDS[cmd] raise LoadCommandError, cmd if cmd_sym.nil? # why do I do this? i don't like declaring constants below # classes, and i need them to resolve... - klass = MachO.const_get LC_STRUCTURES[cmd_sym] + klass = LoadCommands.const_get LoadCommands::LC_STRUCTURES[cmd_sym] view = MachOView.new(@raw_data, endianness, offset) command = klass.new_from_bin(view) diff --git a/Library/Homebrew/vendor/macho/macho/open.rb b/Library/Homebrew/vendor/macho/macho/open.rb deleted file mode 100644 index 103f61741..000000000 --- a/Library/Homebrew/vendor/macho/macho/open.rb +++ /dev/null @@ -1,25 +0,0 @@ -module MachO - # Opens the given filename as a MachOFile or FatFile, depending on its magic. - # @param filename [String] the file being opened - # @return [MachO::MachOFile] if the file is a Mach-O - # @return [MachO::FatFile] if the file is a Fat file - # @raise [ArgumentError] if the given file does not exist - # @raise [MachO::TruncatedFileError] if the file is too small to have a valid header - # @raise [MachO::MagicError] if the file's magic is not valid Mach-O magic - def self.open(filename) - raise ArgumentError, "#{filename}: no such file" unless File.file?(filename) - raise TruncatedFileError unless File.stat(filename).size >= 4 - - magic = File.open(filename, "rb") { |f| f.read(4) }.unpack("N").first - - if Utils.fat_magic?(magic) - file = FatFile.new(filename) - elsif Utils.magic?(magic) - file = MachOFile.new(filename) - else - raise MagicError, magic - end - - file - end -end diff --git a/Library/Homebrew/vendor/macho/macho/sections.rb b/Library/Homebrew/vendor/macho/macho/sections.rb index bd6218bb5..1e69e0b61 100644 --- a/Library/Homebrew/vendor/macho/macho/sections.rb +++ b/Library/Homebrew/vendor/macho/macho/sections.rb @@ -1,170 +1,176 @@ module MachO - # type mask - SECTION_TYPE = 0x000000ff - - # attributes mask - SECTION_ATTRIBUTES = 0xffffff00 - - # user settable attributes mask - SECTION_ATTRIBUTES_USR = 0xff000000 - - # system settable attributes mask - SECTION_ATTRIBUTES_SYS = 0x00ffff00 - - # association of section flag symbols to values - # @api private - SECTION_FLAGS = { - :S_REGULAR => 0x0, - :S_ZEROFILL => 0x1, - :S_CSTRING_LITERALS => 0x2, - :S_4BYTE_LITERALS => 0x3, - :S_8BYTE_LITERALS => 0x4, - :S_LITERAL_POINTERS => 0x5, - :S_NON_LAZY_SYMBOL_POINTERS => 0x6, - :S_LAZY_SYMBOL_POINTERS => 0x7, - :S_SYMBOL_STUBS => 0x8, - :S_MOD_INIT_FUNC_POINTERS => 0x9, - :S_MOD_TERM_FUNC_POINTERS => 0xa, - :S_COALESCED => 0xb, - :S_GB_ZEROFILE => 0xc, - :S_INTERPOSING => 0xd, - :S_16BYTE_LITERALS => 0xe, - :S_DTRACE_DOF => 0xf, - :S_LAZY_DYLIB_SYMBOL_POINTERS => 0x10, - :S_THREAD_LOCAL_REGULAR => 0x11, - :S_THREAD_LOCAL_ZEROFILL => 0x12, - :S_THREAD_LOCAL_VARIABLES => 0x13, - :S_THREAD_LOCAL_VARIABLE_POINTERS => 0x14, - :S_THREAD_LOCAL_INIT_FUNCTION_POINTERS => 0x15, - :S_ATTR_PURE_INSTRUCTIONS => 0x80000000, - :S_ATTR_NO_TOC => 0x40000000, - :S_ATTR_STRIP_STATIC_SYMS => 0x20000000, - :S_ATTR_NO_DEAD_STRIP => 0x10000000, - :S_ATTR_LIVE_SUPPORT => 0x08000000, - :S_ATTR_SELF_MODIFYING_CODE => 0x04000000, - :S_ATTR_DEBUG => 0x02000000, - :S_ATTR_SOME_INSTRUCTIONS => 0x00000400, - :S_ATTR_EXT_RELOC => 0x00000200, - :S_ATTR_LOC_RELOC => 0x00000100, - }.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 + # Classes and constants for parsing sections in Mach-O binaries. + module Sections + # type mask + SECTION_TYPE = 0x000000ff - # @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 + # attributes mask + SECTION_ATTRIBUTES = 0xffffff00 - # @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 + # user settable attributes mask + SECTION_ATTRIBUTES_USR = 0xff000000 - # @return [Boolean] true if the section has no contents (i.e, `size` is 0) - def empty? - size.zero? - end + # system settable attributes mask + SECTION_ATTRIBUTES_SYS = 0x00ffff00 - # @example - # puts "this section is regular" if sect.flag?(:S_REGULAR) - # @param flag [Symbol] a section flag symbol - # @return [Boolean] true if `flag` is present in the section's flag field - def flag?(flag) - flag = SECTION_FLAGS[flag] - return false if flag.nil? - flags & flag == flag + # 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 - end - # Represents a section of a segment for 64-bit architectures. - class Section64 < Section - # @return [void] reserved - attr_reader :reserved3 + # 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::FORMAT + FORMAT = "a16a16Q=2L=8".freeze - # @see MachOStructure::SIZEOF - SIZEOF = 80 + # @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 + # @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 index 43f7bc84e..bac5342d4 100644 --- a/Library/Homebrew/vendor/macho/macho/structure.rb +++ b/Library/Homebrew/vendor/macho/macho/structure.rb @@ -19,7 +19,7 @@ module MachO # @param endianness [Symbol] either `:big` or `:little` # @param bin [String] the string to be unpacked into the new structure - # @return [MachO::MachOStructure] a new MachOStructure initialized with `bin` + # @return [MachO::MachOStructure] the resulting structure # @api private def self.new_from_bin(endianness, bin) format = Utils.specialize_format(self::FORMAT, endianness) diff --git a/Library/Homebrew/vendor/macho/macho/tools.rb b/Library/Homebrew/vendor/macho/macho/tools.rb index f34d75dc1..b49626d9d 100644 --- a/Library/Homebrew/vendor/macho/macho/tools.rb +++ b/Library/Homebrew/vendor/macho/macho/tools.rb @@ -1,5 +1,6 @@ module MachO - # A collection of convenient methods for common operations on Mach-O and Fat binaries. + # A collection of convenient methods for common operations on Mach-O and Fat + # binaries. module Tools # @param filename [String] the Mach-O or Fat binary being read # @return [Array<String>] an array of all dylibs linked to the binary @@ -9,7 +10,8 @@ module MachO file.linked_dylibs end - # Changes the dylib ID of a Mach-O or Fat binary, overwriting the source file. + # Changes the dylib ID of a Mach-O or Fat binary, overwriting the source + # file. # @param filename [String] the Mach-O or Fat binary being modified # @param new_id [String] the new dylib ID for the binary # @param options [Hash] @@ -23,7 +25,8 @@ module MachO file.write! end - # Changes a shared library install name in a Mach-O or Fat binary, overwriting the source file. + # Changes a shared library install name in a Mach-O or Fat binary, + # overwriting the source file. # @param filename [String] the Mach-O or Fat binary being modified # @param old_name [String] the old shared library name # @param new_name [String] the new shared library name @@ -38,7 +41,8 @@ module MachO file.write! end - # Changes a runtime path in a Mach-O or Fat binary, overwriting the source file. + # Changes a runtime path in a Mach-O or Fat binary, overwriting the source + # file. # @param filename [String] the Mach-O or Fat binary being modified # @param old_path [String] the old runtime path # @param new_path [String] the new runtime path @@ -67,7 +71,8 @@ module MachO file.write! end - # Delete a runtime path from a Mach-O or Fat binary, overwriting the source file. + # Delete a runtime path from a Mach-O or Fat binary, overwriting the source + # file. # @param filename [String] the Mach-O or Fat binary being modified # @param old_path [String] the old runtime path # @param options [Hash] @@ -80,5 +85,24 @@ module MachO file.delete_rpath(old_path, options) file.write! end + + # Merge multiple Mach-Os into one universal (Fat) binary. + # @param filename [String] the fat binary to create + # @param files [Array<MachO::MachOFile, MachO::FatFile>] the files to merge + # @return [void] + def self.merge_machos(filename, *files) + machos = files.map do |file| + macho = MachO.open(file) + case macho + when MachO::MachOFile + macho + else + macho.machos + end + end.flatten + + fat_macho = MachO::FatFile.new_from_machos(*machos) + fat_macho.write(filename) + end end end diff --git a/Library/Homebrew/vendor/macho/macho/utils.rb b/Library/Homebrew/vendor/macho/macho/utils.rb index cedd0bc1c..ecfc8390b 100644 --- a/Library/Homebrew/vendor/macho/macho/utils.rb +++ b/Library/Homebrew/vendor/macho/macho/utils.rb @@ -5,7 +5,7 @@ module MachO # @param value [Fixnum] the number being rounded # @param round [Fixnum] the number being rounded with # @return [Fixnum] the rounded value - # @see https://www.opensource.apple.com/source/cctools/cctools-870/libstuff/rnd.c + # @see http://www.opensource.apple.com/source/cctools/cctools-870/libstuff/rnd.c def self.round(value, round) round -= 1 value += round @@ -13,7 +13,8 @@ module MachO value end - # Returns the number of bytes needed to pad the given size to the given alignment. + # Returns the number of bytes needed to pad the given size to the given + # alignment. # @param size [Fixnum] the unpadded size # @param alignment [Fixnum] the number to alignment the size with # @return [Fixnum] the number of pad bytes required @@ -21,7 +22,8 @@ module MachO round(size, alignment) - size end - # Converts an abstract (native-endian) String#unpack format to big or little. + # Converts an abstract (native-endian) String#unpack format to big or + # little. # @param format [String] the format string being converted # @param endianness [Symbol] either `:big` or `:little` # @return [String] the converted string @@ -31,7 +33,8 @@ module MachO end # Packs tagged strings into an aligned payload. - # @param fixed_offset [Fixnum] the baseline offset for the first packed string + # @param fixed_offset [Fixnum] the baseline offset for the first packed + # string # @param alignment [Fixnum] the alignment value to use for packing # @param strings [Hash] the labeled strings to pack # @return [Array<String, Hash>] the packed string and labeled offsets @@ -53,44 +56,44 @@ module MachO # Compares the given number to valid Mach-O magic numbers. # @param num [Fixnum] the number being checked - # @return [Boolean] true if `num` is a valid Mach-O magic number, false otherwise + # @return [Boolean] whether `num` is a valid Mach-O magic number def self.magic?(num) - MH_MAGICS.key?(num) + Headers::MH_MAGICS.key?(num) end # Compares the given number to valid Fat magic numbers. # @param num [Fixnum] the number being checked - # @return [Boolean] true if `num` is a valid Fat magic number, false otherwise + # @return [Boolean] whether `num` is a valid Fat magic number def self.fat_magic?(num) - num == FAT_MAGIC + num == Headers::FAT_MAGIC end # Compares the given number to valid 32-bit Mach-O magic numbers. # @param num [Fixnum] the number being checked - # @return [Boolean] true if `num` is a valid 32-bit magic number, false otherwise + # @return [Boolean] whether `num` is a valid 32-bit magic number def self.magic32?(num) - num == MH_MAGIC || num == MH_CIGAM + num == Headers::MH_MAGIC || num == Headers::MH_CIGAM end # Compares the given number to valid 64-bit Mach-O magic numbers. # @param num [Fixnum] the number being checked - # @return [Boolean] true if `num` is a valid 64-bit magic number, false otherwise + # @return [Boolean] whether `num` is a valid 64-bit magic number def self.magic64?(num) - num == MH_MAGIC_64 || num == MH_CIGAM_64 + num == Headers::MH_MAGIC_64 || num == Headers::MH_CIGAM_64 end # Compares the given number to valid little-endian magic numbers. # @param num [Fixnum] the number being checked - # @return [Boolean] true if `num` is a valid little-endian magic number, false otherwise + # @return [Boolean] whether `num` is a valid little-endian magic number def self.little_magic?(num) - num == MH_CIGAM || num == MH_CIGAM_64 + num == Headers::MH_CIGAM || num == Headers::MH_CIGAM_64 end # Compares the given number to valid big-endian magic numbers. # @param num [Fixnum] the number being checked - # @return [Boolean] true if `num` is a valid big-endian magic number, false otherwise + # @return [Boolean] whether `num` is a valid big-endian magic number def self.big_magic?(num) - num == MH_CIGAM || num == MH_CIGAM_64 + num == Headers::MH_CIGAM || num == Headers::MH_CIGAM_64 end end end |
