Compiler projects using llvm
//===- ObjcopyOptions.cpp -------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "ObjcopyOptions.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/BinaryFormat/COFF.h"
#include "llvm/ObjCopy/CommonConfig.h"
#include "llvm/ObjCopy/ConfigManager.h"
#include "llvm/ObjCopy/MachO/MachOConfig.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/CRC.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Compression.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/MemoryBuffer.h"

using namespace llvm;
using namespace llvm::objcopy;

namespace {
enum ObjcopyID {
  OBJCOPY_INVALID = 0, // This is not an option ID.
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
               HELPTEXT, METAVAR, VALUES)                                      \
  OBJCOPY_##ID,
#include "ObjcopyOpts.inc"
#undef OPTION
};

#define PREFIX(NAME, VALUE) const char *const OBJCOPY_##NAME[] = VALUE;
#include "ObjcopyOpts.inc"
#undef PREFIX

const opt::OptTable::Info ObjcopyInfoTable[] = {
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
               HELPTEXT, METAVAR, VALUES)                                      \
  {OBJCOPY_##PREFIX,                                                           \
   NAME,                                                                       \
   HELPTEXT,                                                                   \
   METAVAR,                                                                    \
   OBJCOPY_##ID,                                                               \
   opt::Option::KIND##Class,                                                   \
   PARAM,                                                                      \
   FLAGS,                                                                      \
   OBJCOPY_##GROUP,                                                            \
   OBJCOPY_##ALIAS,                                                            \
   ALIASARGS,                                                                  \
   VALUES},
#include "ObjcopyOpts.inc"
#undef OPTION
};

class ObjcopyOptTable : public opt::OptTable {
public:
  ObjcopyOptTable() : OptTable(ObjcopyInfoTable) {
    setGroupedShortOptions(true);
  }
};

enum InstallNameToolID {
  INSTALL_NAME_TOOL_INVALID = 0, // This is not an option ID.
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
               HELPTEXT, METAVAR, VALUES)                                      \
  INSTALL_NAME_TOOL_##ID,
#include "InstallNameToolOpts.inc"
#undef OPTION
};

#define PREFIX(NAME, VALUE)                                                    \
  const char *const INSTALL_NAME_TOOL_##NAME[] = VALUE;
#include "InstallNameToolOpts.inc"
#undef PREFIX

const opt::OptTable::Info InstallNameToolInfoTable[] = {
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
               HELPTEXT, METAVAR, VALUES)                                      \
  {INSTALL_NAME_TOOL_##PREFIX,                                                 \
   NAME,                                                                       \
   HELPTEXT,                                                                   \
   METAVAR,                                                                    \
   INSTALL_NAME_TOOL_##ID,                                                     \
   opt::Option::KIND##Class,                                                   \
   PARAM,                                                                      \
   FLAGS,                                                                      \
   INSTALL_NAME_TOOL_##GROUP,                                                  \
   INSTALL_NAME_TOOL_##ALIAS,                                                  \
   ALIASARGS,                                                                  \
   VALUES},
#include "InstallNameToolOpts.inc"
#undef OPTION
};

class InstallNameToolOptTable : public opt::OptTable {
public:
  InstallNameToolOptTable() : OptTable(InstallNameToolInfoTable) {}
};

enum BitcodeStripID {
  BITCODE_STRIP_INVALID = 0, // This is not an option ID.
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
               HELPTEXT, METAVAR, VALUES)                                      \
  BITCODE_STRIP_##ID,
#include "BitcodeStripOpts.inc"
#undef OPTION
};

#define PREFIX(NAME, VALUE) const char *const BITCODE_STRIP_##NAME[] = VALUE;
#include "BitcodeStripOpts.inc"
#undef PREFIX

const opt::OptTable::Info BitcodeStripInfoTable[] = {
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
               HELPTEXT, METAVAR, VALUES)                                      \
  {BITCODE_STRIP_##PREFIX,                                                     \
   NAME,                                                                       \
   HELPTEXT,                                                                   \
   METAVAR,                                                                    \
   BITCODE_STRIP_##ID,                                                         \
   opt::Option::KIND##Class,                                                   \
   PARAM,                                                                      \
   FLAGS,                                                                      \
   BITCODE_STRIP_##GROUP,                                                      \
   BITCODE_STRIP_##ALIAS,                                                      \
   ALIASARGS,                                                                  \
   VALUES},
#include "BitcodeStripOpts.inc"
#undef OPTION
};

class BitcodeStripOptTable : public opt::OptTable {
public:
  BitcodeStripOptTable() : OptTable(BitcodeStripInfoTable) {}
};

enum StripID {
  STRIP_INVALID = 0, // This is not an option ID.
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
               HELPTEXT, METAVAR, VALUES)                                      \
  STRIP_##ID,
#include "StripOpts.inc"
#undef OPTION
};

#define PREFIX(NAME, VALUE) const char *const STRIP_##NAME[] = VALUE;
#include "StripOpts.inc"
#undef PREFIX

const opt::OptTable::Info StripInfoTable[] = {
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
               HELPTEXT, METAVAR, VALUES)                                      \
  {STRIP_##PREFIX, NAME,       HELPTEXT,                                       \
   METAVAR,        STRIP_##ID, opt::Option::KIND##Class,                       \
   PARAM,          FLAGS,      STRIP_##GROUP,                                  \
   STRIP_##ALIAS,  ALIASARGS,  VALUES},
#include "StripOpts.inc"
#undef OPTION
};

class StripOptTable : public opt::OptTable {
public:
  StripOptTable() : OptTable(StripInfoTable) { setGroupedShortOptions(true); }
};

} // namespace

static SectionFlag parseSectionRenameFlag(StringRef SectionName) {
  return llvm::StringSwitch<SectionFlag>(SectionName)
      .CaseLower("alloc", SectionFlag::SecAlloc)
      .CaseLower("load", SectionFlag::SecLoad)
      .CaseLower("noload", SectionFlag::SecNoload)
      .CaseLower("readonly", SectionFlag::SecReadonly)
      .CaseLower("debug", SectionFlag::SecDebug)
      .CaseLower("code", SectionFlag::SecCode)
      .CaseLower("data", SectionFlag::SecData)
      .CaseLower("rom", SectionFlag::SecRom)
      .CaseLower("merge", SectionFlag::SecMerge)
      .CaseLower("strings", SectionFlag::SecStrings)
      .CaseLower("contents", SectionFlag::SecContents)
      .CaseLower("share", SectionFlag::SecShare)
      .CaseLower("exclude", SectionFlag::SecExclude)
      .Default(SectionFlag::SecNone);
}

static Expected<SectionFlag>
parseSectionFlagSet(ArrayRef<StringRef> SectionFlags) {
  SectionFlag ParsedFlags = SectionFlag::SecNone;
  for (StringRef Flag : SectionFlags) {
    SectionFlag ParsedFlag = parseSectionRenameFlag(Flag);
    if (ParsedFlag == SectionFlag::SecNone)
      return createStringError(
          errc::invalid_argument,
          "unrecognized section flag '%s'. Flags supported for GNU "
          "compatibility: alloc, load, noload, readonly, exclude, debug, "
          "code, data, rom, share, contents, merge, strings",
          Flag.str().c_str());
    ParsedFlags |= ParsedFlag;
  }

  return ParsedFlags;
}

static Expected<SectionRename> parseRenameSectionValue(StringRef FlagValue) {
  if (!FlagValue.contains('='))
    return createStringError(errc::invalid_argument,
                             "bad format for --rename-section: missing '='");

  // Initial split: ".foo" = ".bar,f1,f2,..."
  auto Old2New = FlagValue.split('=');
  SectionRename SR;
  SR.OriginalName = Old2New.first;

  // Flags split: ".bar" "f1" "f2" ...
  SmallVector<StringRef, 6> NameAndFlags;
  Old2New.second.split(NameAndFlags, ',');
  SR.NewName = NameAndFlags[0];

  if (NameAndFlags.size() > 1) {
    Expected<SectionFlag> ParsedFlagSet =
        parseSectionFlagSet(makeArrayRef(NameAndFlags).drop_front());
    if (!ParsedFlagSet)
      return ParsedFlagSet.takeError();
    SR.NewFlags = *ParsedFlagSet;
  }

  return SR;
}

static Expected<std::pair<StringRef, uint64_t>>
parseSetSectionAttribute(StringRef Option, StringRef FlagValue) {
  if (!FlagValue.contains('='))
    return make_error<StringError>("bad format for " + Option + ": missing '='",
                                   errc::invalid_argument);
  auto Split = StringRef(FlagValue).split('=');
  if (Split.first.empty())
    return make_error<StringError>("bad format for " + Option +
                                       ": missing section name",
                                   errc::invalid_argument);
  uint64_t Value;
  if (Split.second.getAsInteger(0, Value))
    return make_error<StringError>("invalid value for " + Option + ": '" +
                                       Split.second + "'",
                                   errc::invalid_argument);
  return std::make_pair(Split.first, Value);
}

static Expected<SectionFlagsUpdate>
parseSetSectionFlagValue(StringRef FlagValue) {
  if (!StringRef(FlagValue).contains('='))
    return createStringError(errc::invalid_argument,
                             "bad format for --set-section-flags: missing '='");

  // Initial split: ".foo" = "f1,f2,..."
  auto Section2Flags = StringRef(FlagValue).split('=');
  SectionFlagsUpdate SFU;
  SFU.Name = Section2Flags.first;

  // Flags split: "f1" "f2" ...
  SmallVector<StringRef, 6> SectionFlags;
  Section2Flags.second.split(SectionFlags, ',');
  Expected<SectionFlag> ParsedFlagSet = parseSectionFlagSet(SectionFlags);
  if (!ParsedFlagSet)
    return ParsedFlagSet.takeError();
  SFU.NewFlags = *ParsedFlagSet;

  return SFU;
}

namespace {
struct TargetInfo {
  FileFormat Format;
  MachineInfo Machine;
};
} // namespace

// FIXME: consolidate with the bfd parsing used by lld.
static const StringMap<MachineInfo> TargetMap{
    // Name, {EMachine, 64bit, LittleEndian}
    // x86
    {"elf32-i386", {ELF::EM_386, false, true}},
    {"elf32-x86-64", {ELF::EM_X86_64, false, true}},
    {"elf64-x86-64", {ELF::EM_X86_64, true, true}},
    // Intel MCU
    {"elf32-iamcu", {ELF::EM_IAMCU, false, true}},
    // ARM
    {"elf32-littlearm", {ELF::EM_ARM, false, true}},
    // ARM AArch64
    {"elf64-aarch64", {ELF::EM_AARCH64, true, true}},
    {"elf64-littleaarch64", {ELF::EM_AARCH64, true, true}},
    // RISC-V
    {"elf32-littleriscv", {ELF::EM_RISCV, false, true}},
    {"elf64-littleriscv", {ELF::EM_RISCV, true, true}},
    // PowerPC
    {"elf32-powerpc", {ELF::EM_PPC, false, false}},
    {"elf32-powerpcle", {ELF::EM_PPC, false, true}},
    {"elf64-powerpc", {ELF::EM_PPC64, true, false}},
    {"elf64-powerpcle", {ELF::EM_PPC64, true, true}},
    // MIPS
    {"elf32-bigmips", {ELF::EM_MIPS, false, false}},
    {"elf32-ntradbigmips", {ELF::EM_MIPS, false, false}},
    {"elf32-ntradlittlemips", {ELF::EM_MIPS, false, true}},
    {"elf32-tradbigmips", {ELF::EM_MIPS, false, false}},
    {"elf32-tradlittlemips", {ELF::EM_MIPS, false, true}},
    {"elf64-tradbigmips", {ELF::EM_MIPS, true, false}},
    {"elf64-tradlittlemips", {ELF::EM_MIPS, true, true}},
    // SPARC
    {"elf32-sparc", {ELF::EM_SPARC, false, false}},
    {"elf32-sparcel", {ELF::EM_SPARC, false, true}},
    {"elf32-hexagon", {ELF::EM_HEXAGON, false, true}},
};

static Expected<TargetInfo>
getOutputTargetInfoByTargetName(StringRef TargetName) {
  StringRef OriginalTargetName = TargetName;
  bool IsFreeBSD = TargetName.consume_back("-freebsd");
  auto Iter = TargetMap.find(TargetName);
  if (Iter == std::end(TargetMap))
    return createStringError(errc::invalid_argument,
                             "invalid output format: '%s'",
                             OriginalTargetName.str().c_str());
  MachineInfo MI = Iter->getValue();
  if (IsFreeBSD)
    MI.OSABI = ELF::ELFOSABI_FREEBSD;

  FileFormat Format;
  if (TargetName.startswith("elf"))
    Format = FileFormat::ELF;
  else
    // This should never happen because `TargetName` is valid (it certainly
    // exists in the TargetMap).
    llvm_unreachable("unknown target prefix");

  return {TargetInfo{Format, MI}};
}

static Error addSymbolsFromFile(NameMatcher &Symbols, BumpPtrAllocator &Alloc,
                                StringRef Filename, MatchStyle MS,
                                function_ref<Error(Error)> ErrorCallback) {
  StringSaver Saver(Alloc);
  SmallVector<StringRef, 16> Lines;
  auto BufOrErr = MemoryBuffer::getFile(Filename);
  if (!BufOrErr)
    return createFileError(Filename, BufOrErr.getError());

  BufOrErr.get()->getBuffer().split(Lines, '\n');
  for (StringRef Line : Lines) {
    // Ignore everything after '#', trim whitespace, and only add the symbol if
    // it's not empty.
    auto TrimmedLine = Line.split('#').first.trim();
    if (!TrimmedLine.empty())
      if (Error E = Symbols.addMatcher(NameOrPattern::create(
              Saver.save(TrimmedLine), MS, ErrorCallback)))
        return E;
  }

  return Error::success();
}

static Error addSymbolsToRenameFromFile(StringMap<StringRef> &SymbolsToRename,
                                        BumpPtrAllocator &Alloc,
                                        StringRef Filename) {
  StringSaver Saver(Alloc);
  SmallVector<StringRef, 16> Lines;
  auto BufOrErr = MemoryBuffer::getFile(Filename);
  if (!BufOrErr)
    return createFileError(Filename, BufOrErr.getError());

  BufOrErr.get()->getBuffer().split(Lines, '\n');
  size_t NumLines = Lines.size();
  for (size_t LineNo = 0; LineNo < NumLines; ++LineNo) {
    StringRef TrimmedLine = Lines[LineNo].split('#').first.trim();
    if (TrimmedLine.empty())
      continue;

    std::pair<StringRef, StringRef> Pair = Saver.save(TrimmedLine).split(' ');
    StringRef NewName = Pair.second.trim();
    if (NewName.empty())
      return createStringError(errc::invalid_argument,
                               "%s:%zu: missing new symbol name",
                               Filename.str().c_str(), LineNo + 1);
    SymbolsToRename.insert({Pair.first, NewName});
  }
  return Error::success();
}

template <class T> static ErrorOr<T> getAsInteger(StringRef Val) {
  T Result;
  if (Val.getAsInteger(0, Result))
    return errc::invalid_argument;
  return Result;
}

namespace {

enum class ToolType { Objcopy, Strip, InstallNameTool, BitcodeStrip };

} // anonymous namespace

static void printHelp(const opt::OptTable &OptTable, raw_ostream &OS,
                      ToolType Tool) {
  StringRef HelpText, ToolName;
  switch (Tool) {
  case ToolType::Objcopy:
    ToolName = "llvm-objcopy";
    HelpText = " [options] input [output]";
    break;
  case ToolType::Strip:
    ToolName = "llvm-strip";
    HelpText = " [options] inputs...";
    break;
  case ToolType::InstallNameTool:
    ToolName = "llvm-install-name-tool";
    HelpText = " [options] input";
    break;
  case ToolType::BitcodeStrip:
    ToolName = "llvm-bitcode-strip";
    HelpText = " [options] input";
    break;
  }
  OptTable.printHelp(OS, (ToolName + HelpText).str().c_str(),
                     (ToolName + " tool").str().c_str());
  // TODO: Replace this with libOption call once it adds extrahelp support.
  // The CommandLine library has a cl::extrahelp class to support this,
  // but libOption does not have that yet.
  OS << "\nPass @FILE as argument to read options from FILE.\n";
}

static Expected<NewSymbolInfo> parseNewSymbolInfo(StringRef FlagValue) {
  // Parse value given with --add-symbol option and create the
  // new symbol if possible. The value format for --add-symbol is:
  //
  // <name>=[<section>:]<value>[,<flags>]
  //
  // where:
  // <name> - symbol name, can be empty string
  // <section> - optional section name. If not given ABS symbol is created
  // <value> - symbol value, can be decimal or hexadecimal number prefixed
  //           with 0x.
  // <flags> - optional flags affecting symbol type, binding or visibility.
  NewSymbolInfo SI;
  StringRef Value;
  std::tie(SI.SymbolName, Value) = FlagValue.split('=');
  if (Value.empty())
    return createStringError(
        errc::invalid_argument,
        "bad format for --add-symbol, missing '=' after '%s'",
        SI.SymbolName.str().c_str());

  if (Value.contains(':')) {
    std::tie(SI.SectionName, Value) = Value.split(':');
    if (SI.SectionName.empty() || Value.empty())
      return createStringError(
          errc::invalid_argument,
          "bad format for --add-symbol, missing section name or symbol value");
  }

  SmallVector<StringRef, 6> Flags;
  Value.split(Flags, ',');
  if (Flags[0].getAsInteger(0, SI.Value))
    return createStringError(errc::invalid_argument, "bad symbol value: '%s'",
                             Flags[0].str().c_str());

  using Functor = std::function<void()>;
  SmallVector<StringRef, 6> UnsupportedFlags;
  for (size_t I = 1, NumFlags = Flags.size(); I < NumFlags; ++I)
    static_cast<Functor>(
        StringSwitch<Functor>(Flags[I])
            .CaseLower("global",
                       [&] { SI.Flags.push_back(SymbolFlag::Global); })
            .CaseLower("local", [&] { SI.Flags.push_back(SymbolFlag::Local); })
            .CaseLower("weak", [&] { SI.Flags.push_back(SymbolFlag::Weak); })
            .CaseLower("default",
                       [&] { SI.Flags.push_back(SymbolFlag::Default); })
            .CaseLower("hidden",
                       [&] { SI.Flags.push_back(SymbolFlag::Hidden); })
            .CaseLower("protected",
                       [&] { SI.Flags.push_back(SymbolFlag::Protected); })
            .CaseLower("file", [&] { SI.Flags.push_back(SymbolFlag::File); })
            .CaseLower("section",
                       [&] { SI.Flags.push_back(SymbolFlag::Section); })
            .CaseLower("object",
                       [&] { SI.Flags.push_back(SymbolFlag::Object); })
            .CaseLower("function",
                       [&] { SI.Flags.push_back(SymbolFlag::Function); })
            .CaseLower(
                "indirect-function",
                [&] { SI.Flags.push_back(SymbolFlag::IndirectFunction); })
            .CaseLower("debug", [&] { SI.Flags.push_back(SymbolFlag::Debug); })
            .CaseLower("constructor",
                       [&] { SI.Flags.push_back(SymbolFlag::Constructor); })
            .CaseLower("warning",
                       [&] { SI.Flags.push_back(SymbolFlag::Warning); })
            .CaseLower("indirect",
                       [&] { SI.Flags.push_back(SymbolFlag::Indirect); })
            .CaseLower("synthetic",
                       [&] { SI.Flags.push_back(SymbolFlag::Synthetic); })
            .CaseLower("unique-object",
                       [&] { SI.Flags.push_back(SymbolFlag::UniqueObject); })
            .StartsWithLower("before=",
                             [&] {
                               StringRef SymNamePart =
                                   Flags[I].split('=').second;

                               if (!SymNamePart.empty())
                                 SI.BeforeSyms.push_back(SymNamePart);
                             })
            .Default([&] { UnsupportedFlags.push_back(Flags[I]); }))();
  if (!UnsupportedFlags.empty())
    return createStringError(errc::invalid_argument,
                             "unsupported flag%s for --add-symbol: '%s'",
                             UnsupportedFlags.size() > 1 ? "s" : "",
                             join(UnsupportedFlags, "', '").c_str());

  return SI;
}

// Parse input option \p ArgValue and load section data. This function
// extracts section name and name of the file keeping section data from
// ArgValue, loads data from the file, and stores section name and data
// into the vector of new sections \p NewSections.
static Error loadNewSectionData(StringRef ArgValue, StringRef OptionName,
                                std::vector<NewSectionInfo> &NewSections) {
  if (!ArgValue.contains('='))
    return createStringError(errc::invalid_argument,
                             "bad format for " + OptionName + ": missing '='");

  std::pair<StringRef, StringRef> SecPair = ArgValue.split("=");
  if (SecPair.second.empty())
    return createStringError(errc::invalid_argument, "bad format for " +
                                                         OptionName +
                                                         ": missing file name");

  ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
      MemoryBuffer::getFile(SecPair.second);
  if (!BufOrErr)
    return createFileError(SecPair.second,
                           errorCodeToError(BufOrErr.getError()));

  NewSections.push_back({SecPair.first, std::move(*BufOrErr)});
  return Error::success();
}

// parseObjcopyOptions returns the config and sets the input arguments. If a
// help flag is set then parseObjcopyOptions will print the help messege and
// exit.
Expected<DriverConfig>
objcopy::parseObjcopyOptions(ArrayRef<const char *> RawArgsArr,
                             function_ref<Error(Error)> ErrorCallback) {
  DriverConfig DC;
  ObjcopyOptTable T;

  const char *const *DashDash =
      std::find_if(RawArgsArr.begin(), RawArgsArr.end(),
                   [](StringRef Str) { return Str == "--"; });
  ArrayRef<const char *> ArgsArr = makeArrayRef(RawArgsArr.begin(), DashDash);
  if (DashDash != RawArgsArr.end())
    DashDash = std::next(DashDash);

  unsigned MissingArgumentIndex, MissingArgumentCount;
  llvm::opt::InputArgList InputArgs =
      T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);

  if (InputArgs.size() == 0 && DashDash == RawArgsArr.end()) {
    printHelp(T, errs(), ToolType::Objcopy);
    exit(1);
  }

  if (InputArgs.hasArg(OBJCOPY_help)) {
    printHelp(T, outs(), ToolType::Objcopy);
    exit(0);
  }

  if (InputArgs.hasArg(OBJCOPY_version)) {
    outs() << "llvm-objcopy, compatible with GNU objcopy\n";
    cl::PrintVersionMessage();
    exit(0);
  }

  SmallVector<const char *, 2> Positional;

  for (auto Arg : InputArgs.filtered(OBJCOPY_UNKNOWN))
    return createStringError(errc::invalid_argument, "unknown argument '%s'",
                             Arg->getAsString(InputArgs).c_str());

  for (auto Arg : InputArgs.filtered(OBJCOPY_INPUT))
    Positional.push_back(Arg->getValue());
  std::copy(DashDash, RawArgsArr.end(), std::back_inserter(Positional));

  if (Positional.empty())
    return createStringError(errc::invalid_argument, "no input file specified");

  if (Positional.size() > 2)
    return createStringError(errc::invalid_argument,
                             "too many positional arguments");

  ConfigManager ConfigMgr;
  CommonConfig &Config = ConfigMgr.Common;
  COFFConfig &COFFConfig = ConfigMgr.COFF;
  ELFConfig &ELFConfig = ConfigMgr.ELF;
  MachOConfig &MachOConfig = ConfigMgr.MachO;
  Config.InputFilename = Positional[0];
  Config.OutputFilename = Positional[Positional.size() == 1 ? 0 : 1];
  if (InputArgs.hasArg(OBJCOPY_target) &&
      (InputArgs.hasArg(OBJCOPY_input_target) ||
       InputArgs.hasArg(OBJCOPY_output_target)))
    return createStringError(
        errc::invalid_argument,
        "--target cannot be used with --input-target or --output-target");

  if (InputArgs.hasArg(OBJCOPY_regex) && InputArgs.hasArg(OBJCOPY_wildcard))
    return createStringError(errc::invalid_argument,
                             "--regex and --wildcard are incompatible");

  MatchStyle SectionMatchStyle = InputArgs.hasArg(OBJCOPY_regex)
                                     ? MatchStyle::Regex
                                     : MatchStyle::Wildcard;
  MatchStyle SymbolMatchStyle
      = InputArgs.hasArg(OBJCOPY_regex)    ? MatchStyle::Regex
      : InputArgs.hasArg(OBJCOPY_wildcard) ? MatchStyle::Wildcard
                                           : MatchStyle::Literal;
  StringRef InputFormat, OutputFormat;
  if (InputArgs.hasArg(OBJCOPY_target)) {
    InputFormat = InputArgs.getLastArgValue(OBJCOPY_target);
    OutputFormat = InputArgs.getLastArgValue(OBJCOPY_target);
  } else {
    InputFormat = InputArgs.getLastArgValue(OBJCOPY_input_target);
    OutputFormat = InputArgs.getLastArgValue(OBJCOPY_output_target);
  }

  // FIXME:  Currently, we ignore the target for non-binary/ihex formats
  // explicitly specified by -I option (e.g. -Ielf32-x86-64) and guess the
  // format by llvm::object::createBinary regardless of the option value.
  Config.InputFormat = StringSwitch<FileFormat>(InputFormat)
                           .Case("binary", FileFormat::Binary)
                           .Case("ihex", FileFormat::IHex)
                           .Default(FileFormat::Unspecified);

  if (InputArgs.hasArg(OBJCOPY_new_symbol_visibility)) {
    const uint8_t Invalid = 0xff;
    StringRef VisibilityStr =
        InputArgs.getLastArgValue(OBJCOPY_new_symbol_visibility);

    ELFConfig.NewSymbolVisibility = StringSwitch<uint8_t>(VisibilityStr)
                                        .Case("default", ELF::STV_DEFAULT)
                                        .Case("hidden", ELF::STV_HIDDEN)
                                        .Case("internal", ELF::STV_INTERNAL)
                                        .Case("protected", ELF::STV_PROTECTED)
                                        .Default(Invalid);

    if (ELFConfig.NewSymbolVisibility == Invalid)
      return createStringError(errc::invalid_argument,
                               "'%s' is not a valid symbol visibility",
                               VisibilityStr.str().c_str());
  }

  for (const auto *Arg : InputArgs.filtered(OBJCOPY_subsystem)) {
    StringRef Subsystem, Version;
    std::tie(Subsystem, Version) = StringRef(Arg->getValue()).split(':');
    COFFConfig.Subsystem =
        StringSwitch<unsigned>(Subsystem.lower())
            .Case("boot_application",
                  COFF::IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION)
            .Case("console", COFF::IMAGE_SUBSYSTEM_WINDOWS_CUI)
            .Case("efi_application", COFF::IMAGE_SUBSYSTEM_EFI_APPLICATION)
            .Case("efi_boot_service_driver",
                  COFF::IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER)
            .Case("efi_rom", COFF::IMAGE_SUBSYSTEM_EFI_ROM)
            .Case("efi_runtime_driver",
                  COFF::IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER)
            .Case("native", COFF::IMAGE_SUBSYSTEM_NATIVE)
            .Case("posix", COFF::IMAGE_SUBSYSTEM_POSIX_CUI)
            .Case("windows", COFF::IMAGE_SUBSYSTEM_WINDOWS_GUI)
            .Default(COFF::IMAGE_SUBSYSTEM_UNKNOWN);
    if (*COFFConfig.Subsystem == COFF::IMAGE_SUBSYSTEM_UNKNOWN)
      return createStringError(errc::invalid_argument,
                               "'%s' is not a valid subsystem",
                               Subsystem.str().c_str());
    if (!Version.empty()) {
      StringRef Major, Minor;
      std::tie(Major, Minor) = Version.split('.');
      unsigned Number;
      if (Major.getAsInteger(10, Number))
        return createStringError(errc::invalid_argument,
                                 "'%s' is not a valid subsystem major version",
                                 Major.str().c_str());
      COFFConfig.MajorSubsystemVersion = Number;
      Number = 0;
      if (!Minor.empty() && Minor.getAsInteger(10, Number))
        return createStringError(errc::invalid_argument,
                                 "'%s' is not a valid subsystem minor version",
                                 Minor.str().c_str());
      COFFConfig.MinorSubsystemVersion = Number;
    }
  }

  Config.OutputFormat = StringSwitch<FileFormat>(OutputFormat)
                            .Case("binary", FileFormat::Binary)
                            .Case("ihex", FileFormat::IHex)
                            .Default(FileFormat::Unspecified);
  if (Config.OutputFormat == FileFormat::Unspecified) {
    if (OutputFormat.empty()) {
      Config.OutputFormat = Config.InputFormat;
    } else {
      Expected<TargetInfo> Target =
          getOutputTargetInfoByTargetName(OutputFormat);
      if (!Target)
        return Target.takeError();
      Config.OutputFormat = Target->Format;
      Config.OutputArch = Target->Machine;
    }
  }

  if (const auto *A = InputArgs.getLastArg(OBJCOPY_compress_debug_sections)) {
    Config.CompressionType = StringSwitch<DebugCompressionType>(A->getValue())
                                 .Case("zlib", DebugCompressionType::Z)
                                 .Default(DebugCompressionType::None);
    if (Config.CompressionType == DebugCompressionType::None)
      return createStringError(
          errc::invalid_argument,
          "invalid or unsupported --compress-debug-sections format: %s",
          A->getValue());
    if (!compression::zlib::isAvailable())
      return createStringError(
          errc::invalid_argument,
          "LLVM was not compiled with LLVM_ENABLE_ZLIB: can not compress");
  }

  Config.AddGnuDebugLink = InputArgs.getLastArgValue(OBJCOPY_add_gnu_debuglink);
  // The gnu_debuglink's target is expected to not change or else its CRC would
  // become invalidated and get rejected. We can avoid recalculating the
  // checksum for every target file inside an archive by precomputing the CRC
  // here. This prevents a significant amount of I/O.
  if (!Config.AddGnuDebugLink.empty()) {
    auto DebugOrErr = MemoryBuffer::getFile(Config.AddGnuDebugLink);
    if (!DebugOrErr)
      return createFileError(Config.AddGnuDebugLink, DebugOrErr.getError());
    auto Debug = std::move(*DebugOrErr);
    Config.GnuDebugLinkCRC32 =
        llvm::crc32(arrayRefFromStringRef(Debug->getBuffer()));
  }
  Config.SplitDWO = InputArgs.getLastArgValue(OBJCOPY_split_dwo);
  Config.SymbolsPrefix = InputArgs.getLastArgValue(OBJCOPY_prefix_symbols);
  Config.AllocSectionsPrefix =
      InputArgs.getLastArgValue(OBJCOPY_prefix_alloc_sections);
  if (auto Arg = InputArgs.getLastArg(OBJCOPY_extract_partition))
    Config.ExtractPartition = Arg->getValue();

  for (auto Arg : InputArgs.filtered(OBJCOPY_redefine_symbol)) {
    if (!StringRef(Arg->getValue()).contains('='))
      return createStringError(errc::invalid_argument,
                               "bad format for --redefine-sym");
    auto Old2New = StringRef(Arg->getValue()).split('=');
    if (!Config.SymbolsToRename.insert(Old2New).second)
      return createStringError(errc::invalid_argument,
                               "multiple redefinition of symbol '%s'",
                               Old2New.first.str().c_str());
  }

  for (auto Arg : InputArgs.filtered(OBJCOPY_redefine_symbols))
    if (Error E = addSymbolsToRenameFromFile(Config.SymbolsToRename, DC.Alloc,
                                             Arg->getValue()))
      return std::move(E);

  for (auto Arg : InputArgs.filtered(OBJCOPY_rename_section)) {
    Expected<SectionRename> SR =
        parseRenameSectionValue(StringRef(Arg->getValue()));
    if (!SR)
      return SR.takeError();
    if (!Config.SectionsToRename.try_emplace(SR->OriginalName, *SR).second)
      return createStringError(errc::invalid_argument,
                               "multiple renames of section '%s'",
                               SR->OriginalName.str().c_str());
  }
  for (auto Arg : InputArgs.filtered(OBJCOPY_set_section_alignment)) {
    Expected<std::pair<StringRef, uint64_t>> NameAndAlign =
        parseSetSectionAttribute("--set-section-alignment", Arg->getValue());
    if (!NameAndAlign)
      return NameAndAlign.takeError();
    Config.SetSectionAlignment[NameAndAlign->first] = NameAndAlign->second;
  }
  for (auto Arg : InputArgs.filtered(OBJCOPY_set_section_flags)) {
    Expected<SectionFlagsUpdate> SFU =
        parseSetSectionFlagValue(Arg->getValue());
    if (!SFU)
      return SFU.takeError();
    if (!Config.SetSectionFlags.try_emplace(SFU->Name, *SFU).second)
      return createStringError(
          errc::invalid_argument,
          "--set-section-flags set multiple times for section '%s'",
          SFU->Name.str().c_str());
  }
  for (auto Arg : InputArgs.filtered(OBJCOPY_set_section_type)) {
    Expected<std::pair<StringRef, uint64_t>> NameAndType =
        parseSetSectionAttribute("--set-section-type", Arg->getValue());
    if (!NameAndType)
      return NameAndType.takeError();
    Config.SetSectionType[NameAndType->first] = NameAndType->second;
  }
  // Prohibit combinations of --set-section-{flags,type} when the section name
  // is used as the destination of a --rename-section.
  for (const auto &E : Config.SectionsToRename) {
    const SectionRename &SR = E.second;
    auto Err = [&](const char *Option) {
      return createStringError(
          errc::invalid_argument,
          "--set-section-%s=%s conflicts with --rename-section=%s=%s", Option,
          SR.NewName.str().c_str(), SR.OriginalName.str().c_str(),
          SR.NewName.str().c_str());
    };
    if (Config.SetSectionFlags.count(SR.NewName))
      return Err("flags");
    if (Config.SetSectionType.count(SR.NewName))
      return Err("type");
  }

  for (auto Arg : InputArgs.filtered(OBJCOPY_remove_section))
    if (Error E = Config.ToRemove.addMatcher(NameOrPattern::create(
            Arg->getValue(), SectionMatchStyle, ErrorCallback)))
      return std::move(E);
  for (auto Arg : InputArgs.filtered(OBJCOPY_keep_section))
    if (Error E = Config.KeepSection.addMatcher(NameOrPattern::create(
            Arg->getValue(), SectionMatchStyle, ErrorCallback)))
      return std::move(E);
  for (auto Arg : InputArgs.filtered(OBJCOPY_only_section))
    if (Error E = Config.OnlySection.addMatcher(NameOrPattern::create(
            Arg->getValue(), SectionMatchStyle, ErrorCallback)))
      return std::move(E);
  for (auto Arg : InputArgs.filtered(OBJCOPY_add_section)) {
    if (Error Err = loadNewSectionData(Arg->getValue(), "--add-section",
                                       Config.AddSection))
      return std::move(Err);
  }
  for (auto Arg : InputArgs.filtered(OBJCOPY_update_section)) {
    if (Error Err = loadNewSectionData(Arg->getValue(), "--update-section",
                                       Config.UpdateSection))
      return std::move(Err);
  }
  for (auto *Arg : InputArgs.filtered(OBJCOPY_dump_section)) {
    StringRef Value(Arg->getValue());
    if (Value.split('=').second.empty())
      return createStringError(
          errc::invalid_argument,
          "bad format for --dump-section, expected section=file");
    Config.DumpSection.push_back(Value);
  }
  Config.StripAll = InputArgs.hasArg(OBJCOPY_strip_all);
  Config.StripAllGNU = InputArgs.hasArg(OBJCOPY_strip_all_gnu);
  Config.StripDebug = InputArgs.hasArg(OBJCOPY_strip_debug);
  Config.StripDWO = InputArgs.hasArg(OBJCOPY_strip_dwo);
  Config.StripSections = InputArgs.hasArg(OBJCOPY_strip_sections);
  Config.StripNonAlloc = InputArgs.hasArg(OBJCOPY_strip_non_alloc);
  Config.StripUnneeded = InputArgs.hasArg(OBJCOPY_strip_unneeded);
  Config.ExtractDWO = InputArgs.hasArg(OBJCOPY_extract_dwo);
  Config.ExtractMainPartition =
      InputArgs.hasArg(OBJCOPY_extract_main_partition);
  ELFConfig.LocalizeHidden = InputArgs.hasArg(OBJCOPY_localize_hidden);
  Config.Weaken = InputArgs.hasArg(OBJCOPY_weaken);
  if (auto *Arg =
          InputArgs.getLastArg(OBJCOPY_discard_all, OBJCOPY_discard_locals)) {
    Config.DiscardMode = Arg->getOption().matches(OBJCOPY_discard_all)
                             ? DiscardType::All
                             : DiscardType::Locals;
  }
  Config.OnlyKeepDebug = InputArgs.hasArg(OBJCOPY_only_keep_debug);
  ELFConfig.KeepFileSymbols = InputArgs.hasArg(OBJCOPY_keep_file_symbols);
  MachOConfig.KeepUndefined = InputArgs.hasArg(OBJCOPY_keep_undefined);
  Config.DecompressDebugSections =
      InputArgs.hasArg(OBJCOPY_decompress_debug_sections);
  if (Config.DiscardMode == DiscardType::All) {
    Config.StripDebug = true;
    ELFConfig.KeepFileSymbols = true;
  }
  for (auto Arg : InputArgs.filtered(OBJCOPY_localize_symbol))
    if (Error E = Config.SymbolsToLocalize.addMatcher(NameOrPattern::create(
            Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
      return std::move(E);
  for (auto Arg : InputArgs.filtered(OBJCOPY_localize_symbols))
    if (Error E = addSymbolsFromFile(Config.SymbolsToLocalize, DC.Alloc,
                                     Arg->getValue(), SymbolMatchStyle,
                                     ErrorCallback))
      return std::move(E);
  for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbol))
    if (Error E = Config.SymbolsToKeepGlobal.addMatcher(NameOrPattern::create(
            Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
      return std::move(E);
  for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbols))
    if (Error E = addSymbolsFromFile(Config.SymbolsToKeepGlobal, DC.Alloc,
                                     Arg->getValue(), SymbolMatchStyle,
                                     ErrorCallback))
      return std::move(E);
  for (auto Arg : InputArgs.filtered(OBJCOPY_globalize_symbol))
    if (Error E = Config.SymbolsToGlobalize.addMatcher(NameOrPattern::create(
            Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
      return std::move(E);
  for (auto Arg : InputArgs.filtered(OBJCOPY_globalize_symbols))
    if (Error E = addSymbolsFromFile(Config.SymbolsToGlobalize, DC.Alloc,
                                     Arg->getValue(), SymbolMatchStyle,
                                     ErrorCallback))
      return std::move(E);
  for (auto Arg : InputArgs.filtered(OBJCOPY_weaken_symbol))
    if (Error E = Config.SymbolsToWeaken.addMatcher(NameOrPattern::create(
            Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
      return std::move(E);
  for (auto Arg : InputArgs.filtered(OBJCOPY_weaken_symbols))
    if (Error E = addSymbolsFromFile(Config.SymbolsToWeaken, DC.Alloc,
                                     Arg->getValue(), SymbolMatchStyle,
                                     ErrorCallback))
      return std::move(E);
  for (auto Arg : InputArgs.filtered(OBJCOPY_strip_symbol))
    if (Error E = Config.SymbolsToRemove.addMatcher(NameOrPattern::create(
            Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
      return std::move(E);
  for (auto Arg : InputArgs.filtered(OBJCOPY_strip_symbols))
    if (Error E = addSymbolsFromFile(Config.SymbolsToRemove, DC.Alloc,
                                     Arg->getValue(), SymbolMatchStyle,
                                     ErrorCallback))
      return std::move(E);
  for (auto Arg : InputArgs.filtered(OBJCOPY_strip_unneeded_symbol))
    if (Error E =
            Config.UnneededSymbolsToRemove.addMatcher(NameOrPattern::create(
                Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
      return std::move(E);
  for (auto Arg : InputArgs.filtered(OBJCOPY_strip_unneeded_symbols))
    if (Error E = addSymbolsFromFile(Config.UnneededSymbolsToRemove, DC.Alloc,
                                     Arg->getValue(), SymbolMatchStyle,
                                     ErrorCallback))
      return std::move(E);
  for (auto Arg : InputArgs.filtered(OBJCOPY_keep_symbol))
    if (Error E = Config.SymbolsToKeep.addMatcher(NameOrPattern::create(
            Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
      return std::move(E);
  for (auto Arg : InputArgs.filtered(OBJCOPY_keep_symbols))
    if (Error E =
            addSymbolsFromFile(Config.SymbolsToKeep, DC.Alloc, Arg->getValue(),
                               SymbolMatchStyle, ErrorCallback))
      return std::move(E);
  for (auto *Arg : InputArgs.filtered(OBJCOPY_add_symbol)) {
    Expected<NewSymbolInfo> SymInfo = parseNewSymbolInfo(Arg->getValue());
    if (!SymInfo)
      return SymInfo.takeError();

    Config.SymbolsToAdd.push_back(*SymInfo);
  }

  ELFConfig.AllowBrokenLinks = InputArgs.hasArg(OBJCOPY_allow_broken_links);

  Config.DeterministicArchives = InputArgs.hasFlag(
      OBJCOPY_enable_deterministic_archives,
      OBJCOPY_disable_deterministic_archives, /*default=*/true);

  Config.PreserveDates = InputArgs.hasArg(OBJCOPY_preserve_dates);

  if (Config.PreserveDates &&
      (Config.OutputFilename == "-" || Config.InputFilename == "-"))
    return createStringError(errc::invalid_argument,
                             "--preserve-dates requires a file");

  for (auto Arg : InputArgs)
    if (Arg->getOption().matches(OBJCOPY_set_start)) {
      auto EAddr = getAsInteger<uint64_t>(Arg->getValue());
      if (!EAddr)
        return createStringError(
            EAddr.getError(), "bad entry point address: '%s'", Arg->getValue());

      ELFConfig.EntryExpr = [EAddr](uint64_t) { return *EAddr; };
    } else if (Arg->getOption().matches(OBJCOPY_change_start)) {
      auto EIncr = getAsInteger<int64_t>(Arg->getValue());
      if (!EIncr)
        return createStringError(EIncr.getError(),
                                 "bad entry point increment: '%s'",
                                 Arg->getValue());
      auto Expr = ELFConfig.EntryExpr ? std::move(ELFConfig.EntryExpr)
                                      : [](uint64_t A) { return A; };
      ELFConfig.EntryExpr = [Expr, EIncr](uint64_t EAddr) {
        return Expr(EAddr) + *EIncr;
      };
    }

  if (Config.DecompressDebugSections &&
      Config.CompressionType != DebugCompressionType::None) {
    return createStringError(
        errc::invalid_argument,
        "cannot specify both --compress-debug-sections and "
        "--decompress-debug-sections");
  }

  if (Config.DecompressDebugSections && !compression::zlib::isAvailable())
    return createStringError(
        errc::invalid_argument,
        "LLVM was not compiled with LLVM_ENABLE_ZLIB: cannot decompress");

  if (Config.ExtractPartition && Config.ExtractMainPartition)
    return createStringError(errc::invalid_argument,
                             "cannot specify --extract-partition together with "
                             "--extract-main-partition");

  DC.CopyConfigs.push_back(std::move(ConfigMgr));
  return std::move(DC);
}

// parseInstallNameToolOptions returns the config and sets the input arguments.
// If a help flag is set then parseInstallNameToolOptions will print the help
// messege and exit.
Expected<DriverConfig>
objcopy::parseInstallNameToolOptions(ArrayRef<const char *> ArgsArr) {
  DriverConfig DC;
  ConfigManager ConfigMgr;
  CommonConfig &Config = ConfigMgr.Common;
  MachOConfig &MachOConfig = ConfigMgr.MachO;
  InstallNameToolOptTable T;
  unsigned MissingArgumentIndex, MissingArgumentCount;
  llvm::opt::InputArgList InputArgs =
      T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);

  if (MissingArgumentCount)
    return createStringError(
        errc::invalid_argument,
        "missing argument to " +
            StringRef(InputArgs.getArgString(MissingArgumentIndex)) +
            " option");

  if (InputArgs.size() == 0) {
    printHelp(T, errs(), ToolType::InstallNameTool);
    exit(1);
  }

  if (InputArgs.hasArg(INSTALL_NAME_TOOL_help)) {
    printHelp(T, outs(), ToolType::InstallNameTool);
    exit(0);
  }

  if (InputArgs.hasArg(INSTALL_NAME_TOOL_version)) {
    outs() << "llvm-install-name-tool, compatible with cctools "
              "install_name_tool\n";
    cl::PrintVersionMessage();
    exit(0);
  }

  for (auto Arg : InputArgs.filtered(INSTALL_NAME_TOOL_add_rpath))
    MachOConfig.RPathToAdd.push_back(Arg->getValue());

  for (auto *Arg : InputArgs.filtered(INSTALL_NAME_TOOL_prepend_rpath))
    MachOConfig.RPathToPrepend.push_back(Arg->getValue());

  for (auto Arg : InputArgs.filtered(INSTALL_NAME_TOOL_delete_rpath)) {
    StringRef RPath = Arg->getValue();

    // Cannot add and delete the same rpath at the same time.
    if (is_contained(MachOConfig.RPathToAdd, RPath))
      return createStringError(
          errc::invalid_argument,
          "cannot specify both -add_rpath '%s' and -delete_rpath '%s'",
          RPath.str().c_str(), RPath.str().c_str());
    if (is_contained(MachOConfig.RPathToPrepend, RPath))
      return createStringError(
          errc::invalid_argument,
          "cannot specify both -prepend_rpath '%s' and -delete_rpath '%s'",
          RPath.str().c_str(), RPath.str().c_str());

    MachOConfig.RPathsToRemove.insert(RPath);
  }

  for (auto *Arg : InputArgs.filtered(INSTALL_NAME_TOOL_rpath)) {
    StringRef Old = Arg->getValue(0);
    StringRef New = Arg->getValue(1);

    auto Match = [=](StringRef RPath) { return RPath == Old || RPath == New; };

    // Cannot specify duplicate -rpath entries
    auto It1 = find_if(
        MachOConfig.RPathsToUpdate,
        [&Match](const DenseMap<StringRef, StringRef>::value_type &OldNew) {
          return Match(OldNew.getFirst()) || Match(OldNew.getSecond());
        });
    if (It1 != MachOConfig.RPathsToUpdate.end())
      return createStringError(errc::invalid_argument,
                               "cannot specify both -rpath '" +
                                   It1->getFirst() + "' '" + It1->getSecond() +
                                   "' and -rpath '" + Old + "' '" + New + "'");

    // Cannot specify the same rpath under both -delete_rpath and -rpath
    auto It2 = find_if(MachOConfig.RPathsToRemove, Match);
    if (It2 != MachOConfig.RPathsToRemove.end())
      return createStringError(errc::invalid_argument,
                               "cannot specify both -delete_rpath '" + *It2 +
                                   "' and -rpath '" + Old + "' '" + New + "'");

    // Cannot specify the same rpath under both -add_rpath and -rpath
    auto It3 = find_if(MachOConfig.RPathToAdd, Match);
    if (It3 != MachOConfig.RPathToAdd.end())
      return createStringError(errc::invalid_argument,
                               "cannot specify both -add_rpath '" + *It3 +
                                   "' and -rpath '" + Old + "' '" + New + "'");

    // Cannot specify the same rpath under both -prepend_rpath and -rpath.
    auto It4 = find_if(MachOConfig.RPathToPrepend, Match);
    if (It4 != MachOConfig.RPathToPrepend.end())
      return createStringError(errc::invalid_argument,
                               "cannot specify both -prepend_rpath '" + *It4 +
                                   "' and -rpath '" + Old + "' '" + New + "'");

    MachOConfig.RPathsToUpdate.insert({Old, New});
  }

  if (auto *Arg = InputArgs.getLastArg(INSTALL_NAME_TOOL_id)) {
    MachOConfig.SharedLibId = Arg->getValue();
    if (MachOConfig.SharedLibId->empty())
      return createStringError(errc::invalid_argument,
                               "cannot specify an empty id");
  }

  for (auto *Arg : InputArgs.filtered(INSTALL_NAME_TOOL_change))
    MachOConfig.InstallNamesToUpdate.insert(
        {Arg->getValue(0), Arg->getValue(1)});

  MachOConfig.RemoveAllRpaths =
      InputArgs.hasArg(INSTALL_NAME_TOOL_delete_all_rpaths);

  SmallVector<StringRef, 2> Positional;
  for (auto Arg : InputArgs.filtered(INSTALL_NAME_TOOL_UNKNOWN))
    return createStringError(errc::invalid_argument, "unknown argument '%s'",
                             Arg->getAsString(InputArgs).c_str());
  for (auto Arg : InputArgs.filtered(INSTALL_NAME_TOOL_INPUT))
    Positional.push_back(Arg->getValue());
  if (Positional.empty())
    return createStringError(errc::invalid_argument, "no input file specified");
  if (Positional.size() > 1)
    return createStringError(
        errc::invalid_argument,
        "llvm-install-name-tool expects a single input file");
  Config.InputFilename = Positional[0];
  Config.OutputFilename = Positional[0];

  DC.CopyConfigs.push_back(std::move(ConfigMgr));
  return std::move(DC);
}

Expected<DriverConfig>
objcopy::parseBitcodeStripOptions(ArrayRef<const char *> ArgsArr,
                                  function_ref<Error(Error)> ErrorCallback) {
  DriverConfig DC;
  ConfigManager ConfigMgr;
  CommonConfig &Config = ConfigMgr.Common;
  MachOConfig &MachOConfig = ConfigMgr.MachO;
  BitcodeStripOptTable T;
  unsigned MissingArgumentIndex, MissingArgumentCount;
  opt::InputArgList InputArgs =
      T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);

  if (InputArgs.size() == 0) {
    printHelp(T, errs(), ToolType::BitcodeStrip);
    exit(1);
  }

  if (InputArgs.hasArg(BITCODE_STRIP_help)) {
    printHelp(T, outs(), ToolType::BitcodeStrip);
    exit(0);
  }

  if (InputArgs.hasArg(BITCODE_STRIP_version)) {
    outs() << "llvm-bitcode-strip, compatible with cctools "
              "bitcode_strip\n";
    cl::PrintVersionMessage();
    exit(0);
  }

  for (auto *Arg : InputArgs.filtered(BITCODE_STRIP_UNKNOWN))
    return createStringError(errc::invalid_argument, "unknown argument '%s'",
                             Arg->getAsString(InputArgs).c_str());

  SmallVector<StringRef, 2> Positional;
  for (auto *Arg : InputArgs.filtered(BITCODE_STRIP_INPUT))
    Positional.push_back(Arg->getValue());
  if (Positional.size() > 1)
    return createStringError(errc::invalid_argument,
                             "llvm-bitcode-strip expects a single input file");
  assert(!Positional.empty());
  Config.InputFilename = Positional[0];

  if (!InputArgs.hasArg(BITCODE_STRIP_output)) {
    return createStringError(errc::invalid_argument,
                             "-o is a required argument");
  }
  Config.OutputFilename = InputArgs.getLastArgValue(BITCODE_STRIP_output);

  if (!InputArgs.hasArg(BITCODE_STRIP_remove))
    return createStringError(errc::invalid_argument, "no action specified");

  // We only support -r for now, which removes all bitcode sections and
  // the __LLVM segment if it's now empty.
  cantFail(Config.ToRemove.addMatcher(NameOrPattern::create(
      "__LLVM,__bundle", MatchStyle::Literal, ErrorCallback)));
  MachOConfig.EmptySegmentsToRemove.insert("__LLVM");

  DC.CopyConfigs.push_back(std::move(ConfigMgr));
  return std::move(DC);
}

// parseStripOptions returns the config and sets the input arguments. If a
// help flag is set then parseStripOptions will print the help messege and
// exit.
Expected<DriverConfig>
objcopy::parseStripOptions(ArrayRef<const char *> RawArgsArr,
                           function_ref<Error(Error)> ErrorCallback) {
  const char *const *DashDash =
      std::find_if(RawArgsArr.begin(), RawArgsArr.end(),
                   [](StringRef Str) { return Str == "--"; });
  ArrayRef<const char *> ArgsArr = makeArrayRef(RawArgsArr.begin(), DashDash);
  if (DashDash != RawArgsArr.end())
    DashDash = std::next(DashDash);

  StripOptTable T;
  unsigned MissingArgumentIndex, MissingArgumentCount;
  llvm::opt::InputArgList InputArgs =
      T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);

  if (InputArgs.size() == 0 && DashDash == RawArgsArr.end()) {
    printHelp(T, errs(), ToolType::Strip);
    exit(1);
  }

  if (InputArgs.hasArg(STRIP_help)) {
    printHelp(T, outs(), ToolType::Strip);
    exit(0);
  }

  if (InputArgs.hasArg(STRIP_version)) {
    outs() << "llvm-strip, compatible with GNU strip\n";
    cl::PrintVersionMessage();
    exit(0);
  }

  SmallVector<StringRef, 2> Positional;
  for (auto Arg : InputArgs.filtered(STRIP_UNKNOWN))
    return createStringError(errc::invalid_argument, "unknown argument '%s'",
                             Arg->getAsString(InputArgs).c_str());
  for (auto Arg : InputArgs.filtered(STRIP_INPUT))
    Positional.push_back(Arg->getValue());
  std::copy(DashDash, RawArgsArr.end(), std::back_inserter(Positional));

  if (Positional.empty())
    return createStringError(errc::invalid_argument, "no input file specified");

  if (Positional.size() > 1 && InputArgs.hasArg(STRIP_output))
    return createStringError(
        errc::invalid_argument,
        "multiple input files cannot be used in combination with -o");

  ConfigManager ConfigMgr;
  CommonConfig &Config = ConfigMgr.Common;
  ELFConfig &ELFConfig = ConfigMgr.ELF;
  MachOConfig &MachOConfig = ConfigMgr.MachO;

  if (InputArgs.hasArg(STRIP_regex) && InputArgs.hasArg(STRIP_wildcard))
    return createStringError(errc::invalid_argument,
                             "--regex and --wildcard are incompatible");
  MatchStyle SectionMatchStyle =
      InputArgs.hasArg(STRIP_regex) ? MatchStyle::Regex : MatchStyle::Wildcard;
  MatchStyle SymbolMatchStyle
      = InputArgs.hasArg(STRIP_regex)    ? MatchStyle::Regex
      : InputArgs.hasArg(STRIP_wildcard) ? MatchStyle::Wildcard
                                         : MatchStyle::Literal;
  ELFConfig.AllowBrokenLinks = InputArgs.hasArg(STRIP_allow_broken_links);
  Config.StripDebug = InputArgs.hasArg(STRIP_strip_debug);

  if (auto *Arg = InputArgs.getLastArg(STRIP_discard_all, STRIP_discard_locals))
    Config.DiscardMode = Arg->getOption().matches(STRIP_discard_all)
                             ? DiscardType::All
                             : DiscardType::Locals;
  Config.StripSections = InputArgs.hasArg(STRIP_strip_sections);
  Config.StripUnneeded = InputArgs.hasArg(STRIP_strip_unneeded);
  if (auto Arg = InputArgs.getLastArg(STRIP_strip_all, STRIP_no_strip_all))
    Config.StripAll = Arg->getOption().getID() == STRIP_strip_all;
  Config.StripAllGNU = InputArgs.hasArg(STRIP_strip_all_gnu);
  MachOConfig.StripSwiftSymbols = InputArgs.hasArg(STRIP_strip_swift_symbols);
  Config.OnlyKeepDebug = InputArgs.hasArg(STRIP_only_keep_debug);
  ELFConfig.KeepFileSymbols = InputArgs.hasArg(STRIP_keep_file_symbols);
  MachOConfig.KeepUndefined = InputArgs.hasArg(STRIP_keep_undefined);

  for (auto Arg : InputArgs.filtered(STRIP_keep_section))
    if (Error E = Config.KeepSection.addMatcher(NameOrPattern::create(
            Arg->getValue(), SectionMatchStyle, ErrorCallback)))
      return std::move(E);

  for (auto Arg : InputArgs.filtered(STRIP_remove_section))
    if (Error E = Config.ToRemove.addMatcher(NameOrPattern::create(
            Arg->getValue(), SectionMatchStyle, ErrorCallback)))
      return std::move(E);

  for (auto Arg : InputArgs.filtered(STRIP_strip_symbol))
    if (Error E = Config.SymbolsToRemove.addMatcher(NameOrPattern::create(
            Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
      return std::move(E);

  for (auto Arg : InputArgs.filtered(STRIP_keep_symbol))
    if (Error E = Config.SymbolsToKeep.addMatcher(NameOrPattern::create(
            Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
      return std::move(E);

  if (!InputArgs.hasArg(STRIP_no_strip_all) && !Config.StripDebug &&
      !Config.OnlyKeepDebug && !Config.StripUnneeded &&
      Config.DiscardMode == DiscardType::None && !Config.StripAllGNU &&
      Config.SymbolsToRemove.empty())
    Config.StripAll = true;

  if (Config.DiscardMode == DiscardType::All) {
    Config.StripDebug = true;
    ELFConfig.KeepFileSymbols = true;
  }

  Config.DeterministicArchives =
      InputArgs.hasFlag(STRIP_enable_deterministic_archives,
                        STRIP_disable_deterministic_archives, /*default=*/true);

  Config.PreserveDates = InputArgs.hasArg(STRIP_preserve_dates);
  Config.InputFormat = FileFormat::Unspecified;
  Config.OutputFormat = FileFormat::Unspecified;

  DriverConfig DC;
  if (Positional.size() == 1) {
    Config.InputFilename = Positional[0];
    Config.OutputFilename =
        InputArgs.getLastArgValue(STRIP_output, Positional[0]);
    DC.CopyConfigs.push_back(std::move(ConfigMgr));
  } else {
    StringMap<unsigned> InputFiles;
    for (StringRef Filename : Positional) {
      if (InputFiles[Filename]++ == 1) {
        if (Filename == "-")
          return createStringError(
              errc::invalid_argument,
              "cannot specify '-' as an input file more than once");
        if (Error E = ErrorCallback(createStringError(
                errc::invalid_argument, "'%s' was already specified",
                Filename.str().c_str())))
          return std::move(E);
      }
      Config.InputFilename = Filename;
      Config.OutputFilename = Filename;
      DC.CopyConfigs.push_back(ConfigMgr);
    }
  }

  if (Config.PreserveDates && (is_contained(Positional, "-") ||
                               InputArgs.getLastArgValue(STRIP_output) == "-"))
    return createStringError(errc::invalid_argument,
                             "--preserve-dates requires a file");

  return std::move(DC);
}