Path: blob/main/contrib/llvm-project/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
35258 views
//===- ObjcopyOptions.cpp -------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "ObjcopyOptions.h"9#include "llvm/ADT/SmallVector.h"10#include "llvm/ADT/StringExtras.h"11#include "llvm/ADT/StringRef.h"12#include "llvm/ADT/StringSwitch.h"13#include "llvm/BinaryFormat/COFF.h"14#include "llvm/ObjCopy/CommonConfig.h"15#include "llvm/ObjCopy/ConfigManager.h"16#include "llvm/ObjCopy/MachO/MachOConfig.h"17#include "llvm/Object/Binary.h"18#include "llvm/Option/Arg.h"19#include "llvm/Option/ArgList.h"20#include "llvm/Support/CRC.h"21#include "llvm/Support/CommandLine.h"22#include "llvm/Support/Compression.h"23#include "llvm/Support/Errc.h"24#include "llvm/Support/Error.h"25#include "llvm/Support/MemoryBuffer.h"2627using namespace llvm;28using namespace llvm::objcopy;29using namespace llvm::object;30using namespace llvm::opt;3132namespace {33enum ObjcopyID {34OBJCOPY_INVALID = 0, // This is not an option ID.35#define OPTION(...) LLVM_MAKE_OPT_ID_WITH_ID_PREFIX(OBJCOPY_, __VA_ARGS__),36#include "ObjcopyOpts.inc"37#undef OPTION38};3940namespace objcopy_opt {41#define PREFIX(NAME, VALUE) \42static constexpr StringLiteral NAME##_init[] = VALUE; \43static constexpr ArrayRef<StringLiteral> NAME(NAME##_init, \44std::size(NAME##_init) - 1);45#include "ObjcopyOpts.inc"46#undef PREFIX4748static constexpr opt::OptTable::Info ObjcopyInfoTable[] = {49#define OPTION(...) \50LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX(OBJCOPY_, __VA_ARGS__),51#include "ObjcopyOpts.inc"52#undef OPTION53};54} // namespace objcopy_opt5556class ObjcopyOptTable : public opt::GenericOptTable {57public:58ObjcopyOptTable() : opt::GenericOptTable(objcopy_opt::ObjcopyInfoTable) {59setGroupedShortOptions(true);60}61};6263enum InstallNameToolID {64INSTALL_NAME_TOOL_INVALID = 0, // This is not an option ID.65#define OPTION(...) \66LLVM_MAKE_OPT_ID_WITH_ID_PREFIX(INSTALL_NAME_TOOL_, __VA_ARGS__),67#include "InstallNameToolOpts.inc"68#undef OPTION69};7071namespace install_name_tool {7273#define PREFIX(NAME, VALUE) \74static constexpr StringLiteral NAME##_init[] = VALUE; \75static constexpr ArrayRef<StringLiteral> NAME(NAME##_init, \76std::size(NAME##_init) - 1);77#include "InstallNameToolOpts.inc"78#undef PREFIX7980static constexpr opt::OptTable::Info InstallNameToolInfoTable[] = {81#define OPTION(...) \82LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX(INSTALL_NAME_TOOL_, __VA_ARGS__),83#include "InstallNameToolOpts.inc"84#undef OPTION85};86} // namespace install_name_tool8788class InstallNameToolOptTable : public opt::GenericOptTable {89public:90InstallNameToolOptTable()91: GenericOptTable(install_name_tool::InstallNameToolInfoTable) {}92};9394enum BitcodeStripID {95BITCODE_STRIP_INVALID = 0, // This is not an option ID.96#define OPTION(...) \97LLVM_MAKE_OPT_ID_WITH_ID_PREFIX(BITCODE_STRIP_, __VA_ARGS__),98#include "BitcodeStripOpts.inc"99#undef OPTION100};101102namespace bitcode_strip {103104#define PREFIX(NAME, VALUE) \105static constexpr StringLiteral NAME##_init[] = VALUE; \106static constexpr ArrayRef<StringLiteral> NAME(NAME##_init, \107std::size(NAME##_init) - 1);108#include "BitcodeStripOpts.inc"109#undef PREFIX110111static constexpr opt::OptTable::Info BitcodeStripInfoTable[] = {112#define OPTION(...) \113LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX(BITCODE_STRIP_, __VA_ARGS__),114#include "BitcodeStripOpts.inc"115#undef OPTION116};117} // namespace bitcode_strip118119class BitcodeStripOptTable : public opt::GenericOptTable {120public:121BitcodeStripOptTable()122: opt::GenericOptTable(bitcode_strip::BitcodeStripInfoTable) {}123};124125enum StripID {126STRIP_INVALID = 0, // This is not an option ID.127#define OPTION(...) LLVM_MAKE_OPT_ID_WITH_ID_PREFIX(STRIP_, __VA_ARGS__),128#include "StripOpts.inc"129#undef OPTION130};131132namespace strip {133#define PREFIX(NAME, VALUE) \134static constexpr StringLiteral NAME##_init[] = VALUE; \135static constexpr ArrayRef<StringLiteral> NAME(NAME##_init, \136std::size(NAME##_init) - 1);137#include "StripOpts.inc"138#undef PREFIX139140static constexpr opt::OptTable::Info StripInfoTable[] = {141#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX(STRIP_, __VA_ARGS__),142#include "StripOpts.inc"143#undef OPTION144};145} // namespace strip146147class StripOptTable : public opt::GenericOptTable {148public:149StripOptTable() : GenericOptTable(strip::StripInfoTable) {150setGroupedShortOptions(true);151}152};153154} // namespace155156static SectionFlag parseSectionRenameFlag(StringRef SectionName) {157return llvm::StringSwitch<SectionFlag>(SectionName)158.CaseLower("alloc", SectionFlag::SecAlloc)159.CaseLower("load", SectionFlag::SecLoad)160.CaseLower("noload", SectionFlag::SecNoload)161.CaseLower("readonly", SectionFlag::SecReadonly)162.CaseLower("debug", SectionFlag::SecDebug)163.CaseLower("code", SectionFlag::SecCode)164.CaseLower("data", SectionFlag::SecData)165.CaseLower("rom", SectionFlag::SecRom)166.CaseLower("merge", SectionFlag::SecMerge)167.CaseLower("strings", SectionFlag::SecStrings)168.CaseLower("contents", SectionFlag::SecContents)169.CaseLower("share", SectionFlag::SecShare)170.CaseLower("exclude", SectionFlag::SecExclude)171.CaseLower("large", SectionFlag::SecLarge)172.Default(SectionFlag::SecNone);173}174175static Expected<SectionFlag>176parseSectionFlagSet(ArrayRef<StringRef> SectionFlags) {177SectionFlag ParsedFlags = SectionFlag::SecNone;178for (StringRef Flag : SectionFlags) {179SectionFlag ParsedFlag = parseSectionRenameFlag(Flag);180if (ParsedFlag == SectionFlag::SecNone)181return createStringError(182errc::invalid_argument,183"unrecognized section flag '%s'. Flags supported for GNU "184"compatibility: alloc, load, noload, readonly, exclude, debug, "185"code, data, rom, share, contents, merge, strings, large",186Flag.str().c_str());187ParsedFlags |= ParsedFlag;188}189190return ParsedFlags;191}192193static Expected<SectionRename> parseRenameSectionValue(StringRef FlagValue) {194if (!FlagValue.contains('='))195return createStringError(errc::invalid_argument,196"bad format for --rename-section: missing '='");197198// Initial split: ".foo" = ".bar,f1,f2,..."199auto Old2New = FlagValue.split('=');200SectionRename SR;201SR.OriginalName = Old2New.first;202203// Flags split: ".bar" "f1" "f2" ...204SmallVector<StringRef, 6> NameAndFlags;205Old2New.second.split(NameAndFlags, ',');206SR.NewName = NameAndFlags[0];207208if (NameAndFlags.size() > 1) {209Expected<SectionFlag> ParsedFlagSet =210parseSectionFlagSet(ArrayRef(NameAndFlags).drop_front());211if (!ParsedFlagSet)212return ParsedFlagSet.takeError();213SR.NewFlags = *ParsedFlagSet;214}215216return SR;217}218219static Expected<std::pair<StringRef, uint64_t>>220parseSetSectionAttribute(StringRef Option, StringRef FlagValue) {221if (!FlagValue.contains('='))222return make_error<StringError>("bad format for " + Option + ": missing '='",223errc::invalid_argument);224auto Split = StringRef(FlagValue).split('=');225if (Split.first.empty())226return make_error<StringError>("bad format for " + Option +227": missing section name",228errc::invalid_argument);229uint64_t Value;230if (Split.second.getAsInteger(0, Value))231return make_error<StringError>("invalid value for " + Option + ": '" +232Split.second + "'",233errc::invalid_argument);234return std::make_pair(Split.first, Value);235}236237static Expected<SectionFlagsUpdate>238parseSetSectionFlagValue(StringRef FlagValue) {239if (!StringRef(FlagValue).contains('='))240return createStringError(errc::invalid_argument,241"bad format for --set-section-flags: missing '='");242243// Initial split: ".foo" = "f1,f2,..."244auto Section2Flags = StringRef(FlagValue).split('=');245SectionFlagsUpdate SFU;246SFU.Name = Section2Flags.first;247248// Flags split: "f1" "f2" ...249SmallVector<StringRef, 6> SectionFlags;250Section2Flags.second.split(SectionFlags, ',');251Expected<SectionFlag> ParsedFlagSet = parseSectionFlagSet(SectionFlags);252if (!ParsedFlagSet)253return ParsedFlagSet.takeError();254SFU.NewFlags = *ParsedFlagSet;255256return SFU;257}258259static Expected<uint8_t> parseVisibilityType(StringRef VisType) {260const uint8_t Invalid = 0xff;261uint8_t type = StringSwitch<uint8_t>(VisType)262.Case("default", ELF::STV_DEFAULT)263.Case("hidden", ELF::STV_HIDDEN)264.Case("internal", ELF::STV_INTERNAL)265.Case("protected", ELF::STV_PROTECTED)266.Default(Invalid);267if (type == Invalid)268return createStringError(errc::invalid_argument,269"'%s' is not a valid symbol visibility",270VisType.str().c_str());271return type;272}273274namespace {275struct TargetInfo {276FileFormat Format;277MachineInfo Machine;278};279} // namespace280281// FIXME: consolidate with the bfd parsing used by lld.282static const StringMap<MachineInfo> TargetMap{283// Name, {EMachine, 64bit, LittleEndian}284// x86285{"elf32-i386", {ELF::EM_386, false, true}},286{"elf32-x86-64", {ELF::EM_X86_64, false, true}},287{"elf64-x86-64", {ELF::EM_X86_64, true, true}},288// Intel MCU289{"elf32-iamcu", {ELF::EM_IAMCU, false, true}},290// ARM291{"elf32-littlearm", {ELF::EM_ARM, false, true}},292// ARM AArch64293{"elf64-aarch64", {ELF::EM_AARCH64, true, true}},294{"elf64-littleaarch64", {ELF::EM_AARCH64, true, true}},295// RISC-V296{"elf32-littleriscv", {ELF::EM_RISCV, false, true}},297{"elf64-littleriscv", {ELF::EM_RISCV, true, true}},298// PowerPC299{"elf32-powerpc", {ELF::EM_PPC, false, false}},300{"elf32-powerpcle", {ELF::EM_PPC, false, true}},301{"elf64-powerpc", {ELF::EM_PPC64, true, false}},302{"elf64-powerpcle", {ELF::EM_PPC64, true, true}},303// MIPS304{"elf32-bigmips", {ELF::EM_MIPS, false, false}},305{"elf32-ntradbigmips", {ELF::EM_MIPS, false, false}},306{"elf32-ntradlittlemips", {ELF::EM_MIPS, false, true}},307{"elf32-tradbigmips", {ELF::EM_MIPS, false, false}},308{"elf32-tradlittlemips", {ELF::EM_MIPS, false, true}},309{"elf64-tradbigmips", {ELF::EM_MIPS, true, false}},310{"elf64-tradlittlemips", {ELF::EM_MIPS, true, true}},311// SPARC312{"elf32-sparc", {ELF::EM_SPARC, false, false}},313{"elf32-sparcel", {ELF::EM_SPARC, false, true}},314// Hexagon315{"elf32-hexagon", {ELF::EM_HEXAGON, false, true}},316// LoongArch317{"elf32-loongarch", {ELF::EM_LOONGARCH, false, true}},318{"elf64-loongarch", {ELF::EM_LOONGARCH, true, true}},319// SystemZ320{"elf64-s390", {ELF::EM_S390, true, false}},321};322323static Expected<TargetInfo>324getOutputTargetInfoByTargetName(StringRef TargetName) {325StringRef OriginalTargetName = TargetName;326bool IsFreeBSD = TargetName.consume_back("-freebsd");327auto Iter = TargetMap.find(TargetName);328if (Iter == std::end(TargetMap))329return createStringError(errc::invalid_argument,330"invalid output format: '%s'",331OriginalTargetName.str().c_str());332MachineInfo MI = Iter->getValue();333if (IsFreeBSD)334MI.OSABI = ELF::ELFOSABI_FREEBSD;335336FileFormat Format;337if (TargetName.starts_with("elf"))338Format = FileFormat::ELF;339else340// This should never happen because `TargetName` is valid (it certainly341// exists in the TargetMap).342llvm_unreachable("unknown target prefix");343344return {TargetInfo{Format, MI}};345}346347static Error addSymbolsFromFile(NameMatcher &Symbols, BumpPtrAllocator &Alloc,348StringRef Filename, MatchStyle MS,349function_ref<Error(Error)> ErrorCallback) {350StringSaver Saver(Alloc);351SmallVector<StringRef, 16> Lines;352auto BufOrErr = MemoryBuffer::getFile(Filename);353if (!BufOrErr)354return createFileError(Filename, BufOrErr.getError());355356BufOrErr.get()->getBuffer().split(Lines, '\n');357for (StringRef Line : Lines) {358// Ignore everything after '#', trim whitespace, and only add the symbol if359// it's not empty.360auto TrimmedLine = Line.split('#').first.trim();361if (!TrimmedLine.empty())362if (Error E = Symbols.addMatcher(NameOrPattern::create(363Saver.save(TrimmedLine), MS, ErrorCallback)))364return E;365}366367return Error::success();368}369370static Error addSymbolsToRenameFromFile(StringMap<StringRef> &SymbolsToRename,371BumpPtrAllocator &Alloc,372StringRef Filename) {373StringSaver Saver(Alloc);374SmallVector<StringRef, 16> Lines;375auto BufOrErr = MemoryBuffer::getFile(Filename);376if (!BufOrErr)377return createFileError(Filename, BufOrErr.getError());378379BufOrErr.get()->getBuffer().split(Lines, '\n');380size_t NumLines = Lines.size();381for (size_t LineNo = 0; LineNo < NumLines; ++LineNo) {382StringRef TrimmedLine = Lines[LineNo].split('#').first.trim();383if (TrimmedLine.empty())384continue;385386std::pair<StringRef, StringRef> Pair = Saver.save(TrimmedLine).split(' ');387StringRef NewName = Pair.second.trim();388if (NewName.empty())389return createStringError(errc::invalid_argument,390"%s:%zu: missing new symbol name",391Filename.str().c_str(), LineNo + 1);392SymbolsToRename.insert({Pair.first, NewName});393}394return Error::success();395}396397template <class T> static ErrorOr<T> getAsInteger(StringRef Val) {398T Result;399if (Val.getAsInteger(0, Result))400return errc::invalid_argument;401return Result;402}403404namespace {405406enum class ToolType { Objcopy, Strip, InstallNameTool, BitcodeStrip };407408} // anonymous namespace409410static void printHelp(const opt::OptTable &OptTable, raw_ostream &OS,411ToolType Tool) {412StringRef HelpText, ToolName;413switch (Tool) {414case ToolType::Objcopy:415ToolName = "llvm-objcopy";416HelpText = " [options] input [output]";417break;418case ToolType::Strip:419ToolName = "llvm-strip";420HelpText = " [options] inputs...";421break;422case ToolType::InstallNameTool:423ToolName = "llvm-install-name-tool";424HelpText = " [options] input";425break;426case ToolType::BitcodeStrip:427ToolName = "llvm-bitcode-strip";428HelpText = " [options] input";429break;430}431OptTable.printHelp(OS, (ToolName + HelpText).str().c_str(),432(ToolName + " tool").str().c_str());433// TODO: Replace this with libOption call once it adds extrahelp support.434// The CommandLine library has a cl::extrahelp class to support this,435// but libOption does not have that yet.436OS << "\nPass @FILE as argument to read options from FILE.\n";437}438439static Expected<NewSymbolInfo> parseNewSymbolInfo(StringRef FlagValue) {440// Parse value given with --add-symbol option and create the441// new symbol if possible. The value format for --add-symbol is:442//443// <name>=[<section>:]<value>[,<flags>]444//445// where:446// <name> - symbol name, can be empty string447// <section> - optional section name. If not given ABS symbol is created448// <value> - symbol value, can be decimal or hexadecimal number prefixed449// with 0x.450// <flags> - optional flags affecting symbol type, binding or visibility.451NewSymbolInfo SI;452StringRef Value;453std::tie(SI.SymbolName, Value) = FlagValue.split('=');454if (Value.empty())455return createStringError(456errc::invalid_argument,457"bad format for --add-symbol, missing '=' after '%s'",458SI.SymbolName.str().c_str());459460if (Value.contains(':')) {461std::tie(SI.SectionName, Value) = Value.split(':');462if (SI.SectionName.empty() || Value.empty())463return createStringError(464errc::invalid_argument,465"bad format for --add-symbol, missing section name or symbol value");466}467468SmallVector<StringRef, 6> Flags;469Value.split(Flags, ',');470if (Flags[0].getAsInteger(0, SI.Value))471return createStringError(errc::invalid_argument, "bad symbol value: '%s'",472Flags[0].str().c_str());473474using Functor = std::function<void()>;475SmallVector<StringRef, 6> UnsupportedFlags;476for (size_t I = 1, NumFlags = Flags.size(); I < NumFlags; ++I)477static_cast<Functor>(478StringSwitch<Functor>(Flags[I])479.CaseLower("global",480[&] { SI.Flags.push_back(SymbolFlag::Global); })481.CaseLower("local", [&] { SI.Flags.push_back(SymbolFlag::Local); })482.CaseLower("weak", [&] { SI.Flags.push_back(SymbolFlag::Weak); })483.CaseLower("default",484[&] { SI.Flags.push_back(SymbolFlag::Default); })485.CaseLower("hidden",486[&] { SI.Flags.push_back(SymbolFlag::Hidden); })487.CaseLower("protected",488[&] { SI.Flags.push_back(SymbolFlag::Protected); })489.CaseLower("file", [&] { SI.Flags.push_back(SymbolFlag::File); })490.CaseLower("section",491[&] { SI.Flags.push_back(SymbolFlag::Section); })492.CaseLower("object",493[&] { SI.Flags.push_back(SymbolFlag::Object); })494.CaseLower("function",495[&] { SI.Flags.push_back(SymbolFlag::Function); })496.CaseLower(497"indirect-function",498[&] { SI.Flags.push_back(SymbolFlag::IndirectFunction); })499.CaseLower("debug", [&] { SI.Flags.push_back(SymbolFlag::Debug); })500.CaseLower("constructor",501[&] { SI.Flags.push_back(SymbolFlag::Constructor); })502.CaseLower("warning",503[&] { SI.Flags.push_back(SymbolFlag::Warning); })504.CaseLower("indirect",505[&] { SI.Flags.push_back(SymbolFlag::Indirect); })506.CaseLower("synthetic",507[&] { SI.Flags.push_back(SymbolFlag::Synthetic); })508.CaseLower("unique-object",509[&] { SI.Flags.push_back(SymbolFlag::UniqueObject); })510.StartsWithLower("before=",511[&] {512StringRef SymNamePart =513Flags[I].split('=').second;514515if (!SymNamePart.empty())516SI.BeforeSyms.push_back(SymNamePart);517})518.Default([&] { UnsupportedFlags.push_back(Flags[I]); }))();519if (!UnsupportedFlags.empty())520return createStringError(errc::invalid_argument,521"unsupported flag%s for --add-symbol: '%s'",522UnsupportedFlags.size() > 1 ? "s" : "",523join(UnsupportedFlags, "', '").c_str());524525return SI;526}527528// Parse input option \p ArgValue and load section data. This function529// extracts section name and name of the file keeping section data from530// ArgValue, loads data from the file, and stores section name and data531// into the vector of new sections \p NewSections.532static Error loadNewSectionData(StringRef ArgValue, StringRef OptionName,533SmallVector<NewSectionInfo, 0> &NewSections) {534if (!ArgValue.contains('='))535return createStringError(errc::invalid_argument,536"bad format for " + OptionName + ": missing '='");537538std::pair<StringRef, StringRef> SecPair = ArgValue.split("=");539if (SecPair.second.empty())540return createStringError(errc::invalid_argument, "bad format for " +541OptionName +542": missing file name");543544ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =545MemoryBuffer::getFile(SecPair.second);546if (!BufOrErr)547return createFileError(SecPair.second,548errorCodeToError(BufOrErr.getError()));549550NewSections.push_back({SecPair.first, std::move(*BufOrErr)});551return Error::success();552}553554static Expected<int64_t> parseChangeSectionLMA(StringRef ArgValue,555StringRef OptionName) {556StringRef StringValue;557if (ArgValue.starts_with("*+")) {558StringValue = ArgValue.slice(2, StringRef::npos);559} else if (ArgValue.starts_with("*-")) {560StringValue = ArgValue.slice(1, StringRef::npos);561} else if (ArgValue.contains("=")) {562return createStringError(errc::invalid_argument,563"bad format for " + OptionName +564": changing LMA to a specific value is not "565"supported. Use *+val or *-val instead");566} else if (ArgValue.contains("+") || ArgValue.contains("-")) {567return createStringError(errc::invalid_argument,568"bad format for " + OptionName +569": changing a specific section LMA is not "570"supported. Use *+val or *-val instead");571}572if (StringValue.empty())573return createStringError(errc::invalid_argument,574"bad format for " + OptionName +575": missing LMA offset");576577auto LMAValue = getAsInteger<int64_t>(StringValue);578if (!LMAValue)579return createStringError(LMAValue.getError(),580"bad format for " + OptionName + ": value after " +581ArgValue.slice(0, 2) + " is " + StringValue +582" when it should be an integer");583return *LMAValue;584}585586// parseObjcopyOptions returns the config and sets the input arguments. If a587// help flag is set then parseObjcopyOptions will print the help messege and588// exit.589Expected<DriverConfig>590objcopy::parseObjcopyOptions(ArrayRef<const char *> RawArgsArr,591function_ref<Error(Error)> ErrorCallback) {592DriverConfig DC;593ObjcopyOptTable T;594595const char *const *DashDash =596llvm::find_if(RawArgsArr, [](StringRef Str) { return Str == "--"; });597ArrayRef<const char *> ArgsArr = ArrayRef(RawArgsArr.begin(), DashDash);598if (DashDash != RawArgsArr.end())599DashDash = std::next(DashDash);600601unsigned MissingArgumentIndex, MissingArgumentCount;602llvm::opt::InputArgList InputArgs =603T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);604605if (MissingArgumentCount)606return createStringError(607errc::invalid_argument,608"argument to '%s' is missing (expected %d value(s))",609InputArgs.getArgString(MissingArgumentIndex), MissingArgumentCount);610611if (InputArgs.size() == 0 && DashDash == RawArgsArr.end()) {612printHelp(T, errs(), ToolType::Objcopy);613exit(1);614}615616if (InputArgs.hasArg(OBJCOPY_help)) {617printHelp(T, outs(), ToolType::Objcopy);618exit(0);619}620621if (InputArgs.hasArg(OBJCOPY_version)) {622outs() << "llvm-objcopy, compatible with GNU objcopy\n";623cl::PrintVersionMessage();624exit(0);625}626627SmallVector<const char *, 2> Positional;628629for (auto *Arg : InputArgs.filtered(OBJCOPY_UNKNOWN))630return createStringError(errc::invalid_argument, "unknown argument '%s'",631Arg->getAsString(InputArgs).c_str());632633for (auto *Arg : InputArgs.filtered(OBJCOPY_INPUT))634Positional.push_back(Arg->getValue());635std::copy(DashDash, RawArgsArr.end(), std::back_inserter(Positional));636637if (Positional.empty())638return createStringError(errc::invalid_argument, "no input file specified");639640if (Positional.size() > 2)641return createStringError(errc::invalid_argument,642"too many positional arguments");643644ConfigManager ConfigMgr;645CommonConfig &Config = ConfigMgr.Common;646COFFConfig &COFFConfig = ConfigMgr.COFF;647ELFConfig &ELFConfig = ConfigMgr.ELF;648MachOConfig &MachOConfig = ConfigMgr.MachO;649Config.InputFilename = Positional[0];650Config.OutputFilename = Positional[Positional.size() == 1 ? 0 : 1];651if (InputArgs.hasArg(OBJCOPY_target) &&652(InputArgs.hasArg(OBJCOPY_input_target) ||653InputArgs.hasArg(OBJCOPY_output_target)))654return createStringError(655errc::invalid_argument,656"--target cannot be used with --input-target or --output-target");657658if (InputArgs.hasArg(OBJCOPY_regex) && InputArgs.hasArg(OBJCOPY_wildcard))659return createStringError(errc::invalid_argument,660"--regex and --wildcard are incompatible");661662MatchStyle SectionMatchStyle = InputArgs.hasArg(OBJCOPY_regex)663? MatchStyle::Regex664: MatchStyle::Wildcard;665MatchStyle SymbolMatchStyle666= InputArgs.hasArg(OBJCOPY_regex) ? MatchStyle::Regex667: InputArgs.hasArg(OBJCOPY_wildcard) ? MatchStyle::Wildcard668: MatchStyle::Literal;669StringRef InputFormat, OutputFormat;670if (InputArgs.hasArg(OBJCOPY_target)) {671InputFormat = InputArgs.getLastArgValue(OBJCOPY_target);672OutputFormat = InputArgs.getLastArgValue(OBJCOPY_target);673} else {674InputFormat = InputArgs.getLastArgValue(OBJCOPY_input_target);675OutputFormat = InputArgs.getLastArgValue(OBJCOPY_output_target);676}677678// FIXME: Currently, we ignore the target for non-binary/ihex formats679// explicitly specified by -I option (e.g. -Ielf32-x86-64) and guess the680// format by llvm::object::createBinary regardless of the option value.681Config.InputFormat = StringSwitch<FileFormat>(InputFormat)682.Case("binary", FileFormat::Binary)683.Case("ihex", FileFormat::IHex)684.Default(FileFormat::Unspecified);685686if (InputArgs.hasArg(OBJCOPY_new_symbol_visibility)) {687const uint8_t Invalid = 0xff;688StringRef VisibilityStr =689InputArgs.getLastArgValue(OBJCOPY_new_symbol_visibility);690691ELFConfig.NewSymbolVisibility = StringSwitch<uint8_t>(VisibilityStr)692.Case("default", ELF::STV_DEFAULT)693.Case("hidden", ELF::STV_HIDDEN)694.Case("internal", ELF::STV_INTERNAL)695.Case("protected", ELF::STV_PROTECTED)696.Default(Invalid);697698if (ELFConfig.NewSymbolVisibility == Invalid)699return createStringError(errc::invalid_argument,700"'%s' is not a valid symbol visibility",701VisibilityStr.str().c_str());702}703704for (const auto *Arg : InputArgs.filtered(OBJCOPY_subsystem)) {705StringRef Subsystem, Version;706std::tie(Subsystem, Version) = StringRef(Arg->getValue()).split(':');707COFFConfig.Subsystem =708StringSwitch<unsigned>(Subsystem.lower())709.Case("boot_application",710COFF::IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION)711.Case("console", COFF::IMAGE_SUBSYSTEM_WINDOWS_CUI)712.Cases("efi_application", "efi-app",713COFF::IMAGE_SUBSYSTEM_EFI_APPLICATION)714.Cases("efi_boot_service_driver", "efi-bsd",715COFF::IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER)716.Case("efi_rom", COFF::IMAGE_SUBSYSTEM_EFI_ROM)717.Cases("efi_runtime_driver", "efi-rtd",718COFF::IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER)719.Case("native", COFF::IMAGE_SUBSYSTEM_NATIVE)720.Case("posix", COFF::IMAGE_SUBSYSTEM_POSIX_CUI)721.Case("windows", COFF::IMAGE_SUBSYSTEM_WINDOWS_GUI)722.Default(COFF::IMAGE_SUBSYSTEM_UNKNOWN);723if (*COFFConfig.Subsystem == COFF::IMAGE_SUBSYSTEM_UNKNOWN)724return createStringError(errc::invalid_argument,725"'%s' is not a valid subsystem",726Subsystem.str().c_str());727if (!Version.empty()) {728StringRef Major, Minor;729std::tie(Major, Minor) = Version.split('.');730unsigned Number;731if (Major.getAsInteger(10, Number))732return createStringError(errc::invalid_argument,733"'%s' is not a valid subsystem major version",734Major.str().c_str());735COFFConfig.MajorSubsystemVersion = Number;736Number = 0;737if (!Minor.empty() && Minor.getAsInteger(10, Number))738return createStringError(errc::invalid_argument,739"'%s' is not a valid subsystem minor version",740Minor.str().c_str());741COFFConfig.MinorSubsystemVersion = Number;742}743}744745Config.OutputFormat = StringSwitch<FileFormat>(OutputFormat)746.Case("binary", FileFormat::Binary)747.Case("ihex", FileFormat::IHex)748.Case("srec", FileFormat::SREC)749.Default(FileFormat::Unspecified);750if (Config.OutputFormat == FileFormat::Unspecified) {751if (OutputFormat.empty()) {752Config.OutputFormat = Config.InputFormat;753} else {754Expected<TargetInfo> Target =755getOutputTargetInfoByTargetName(OutputFormat);756if (!Target)757return Target.takeError();758Config.OutputFormat = Target->Format;759Config.OutputArch = Target->Machine;760}761}762763if (const auto *A = InputArgs.getLastArg(OBJCOPY_compress_debug_sections)) {764Config.CompressionType = StringSwitch<DebugCompressionType>(A->getValue())765.Case("zlib", DebugCompressionType::Zlib)766.Case("zstd", DebugCompressionType::Zstd)767.Default(DebugCompressionType::None);768if (Config.CompressionType == DebugCompressionType::None) {769return createStringError(770errc::invalid_argument,771"invalid or unsupported --compress-debug-sections format: %s",772A->getValue());773}774if (const char *Reason = compression::getReasonIfUnsupported(775compression::formatFor(Config.CompressionType)))776return createStringError(errc::invalid_argument, Reason);777}778779for (const auto *A : InputArgs.filtered(OBJCOPY_compress_sections)) {780SmallVector<StringRef, 0> Fields;781StringRef(A->getValue()).split(Fields, '=');782if (Fields.size() != 2 || Fields[1].empty()) {783return createStringError(784errc::invalid_argument,785A->getSpelling() +786": parse error, not 'section-glob=[none|zlib|zstd]'");787}788789auto Type = StringSwitch<DebugCompressionType>(Fields[1])790.Case("zlib", DebugCompressionType::Zlib)791.Case("zstd", DebugCompressionType::Zstd)792.Default(DebugCompressionType::None);793if (Type == DebugCompressionType::None && Fields[1] != "none") {794return createStringError(795errc::invalid_argument,796"invalid or unsupported --compress-sections format: %s",797A->getValue());798}799800auto &P = Config.compressSections.emplace_back();801P.second = Type;802auto Matcher =803NameOrPattern::create(Fields[0], SectionMatchStyle, ErrorCallback);804// =none allows overriding a previous =zlib or =zstd. Reject negative805// patterns, which would be confusing.806if (Matcher && !Matcher->isPositiveMatch()) {807return createStringError(808errc::invalid_argument,809"--compress-sections: negative pattern is unsupported");810}811if (Error E = P.first.addMatcher(std::move(Matcher)))812return std::move(E);813}814815Config.AddGnuDebugLink = InputArgs.getLastArgValue(OBJCOPY_add_gnu_debuglink);816// The gnu_debuglink's target is expected to not change or else its CRC would817// become invalidated and get rejected. We can avoid recalculating the818// checksum for every target file inside an archive by precomputing the CRC819// here. This prevents a significant amount of I/O.820if (!Config.AddGnuDebugLink.empty()) {821auto DebugOrErr = MemoryBuffer::getFile(Config.AddGnuDebugLink);822if (!DebugOrErr)823return createFileError(Config.AddGnuDebugLink, DebugOrErr.getError());824auto Debug = std::move(*DebugOrErr);825Config.GnuDebugLinkCRC32 =826llvm::crc32(arrayRefFromStringRef(Debug->getBuffer()));827}828Config.SplitDWO = InputArgs.getLastArgValue(OBJCOPY_split_dwo);829830Config.SymbolsPrefix = InputArgs.getLastArgValue(OBJCOPY_prefix_symbols);831Config.SymbolsPrefixRemove =832InputArgs.getLastArgValue(OBJCOPY_remove_symbol_prefix);833834Config.AllocSectionsPrefix =835InputArgs.getLastArgValue(OBJCOPY_prefix_alloc_sections);836if (auto Arg = InputArgs.getLastArg(OBJCOPY_extract_partition))837Config.ExtractPartition = Arg->getValue();838839if (const auto *A = InputArgs.getLastArg(OBJCOPY_gap_fill)) {840if (Config.OutputFormat != FileFormat::Binary)841return createStringError(842errc::invalid_argument,843"'--gap-fill' is only supported for binary output");844ErrorOr<uint64_t> Val = getAsInteger<uint64_t>(A->getValue());845if (!Val)846return createStringError(Val.getError(), "--gap-fill: bad number: %s",847A->getValue());848uint8_t ByteVal = Val.get();849if (ByteVal != Val.get())850return createStringError(std::errc::value_too_large,851"gap-fill value %s is out of range (0 to 0xff)",852A->getValue());853Config.GapFill = ByteVal;854}855856if (const auto *A = InputArgs.getLastArg(OBJCOPY_pad_to)) {857if (Config.OutputFormat != FileFormat::Binary)858return createStringError(859errc::invalid_argument,860"'--pad-to' is only supported for binary output");861ErrorOr<uint64_t> Addr = getAsInteger<uint64_t>(A->getValue());862if (!Addr)863return createStringError(Addr.getError(), "--pad-to: bad number: %s",864A->getValue());865Config.PadTo = *Addr;866}867868if (const auto *Arg = InputArgs.getLastArg(OBJCOPY_change_section_lma)) {869Expected<int64_t> LMAValue =870parseChangeSectionLMA(Arg->getValue(), Arg->getSpelling());871if (!LMAValue)872return LMAValue.takeError();873Config.ChangeSectionLMAValAll = *LMAValue;874}875876for (auto *Arg : InputArgs.filtered(OBJCOPY_redefine_symbol)) {877if (!StringRef(Arg->getValue()).contains('='))878return createStringError(errc::invalid_argument,879"bad format for --redefine-sym");880auto Old2New = StringRef(Arg->getValue()).split('=');881if (!Config.SymbolsToRename.insert(Old2New).second)882return createStringError(errc::invalid_argument,883"multiple redefinition of symbol '%s'",884Old2New.first.str().c_str());885}886887for (auto *Arg : InputArgs.filtered(OBJCOPY_redefine_symbols))888if (Error E = addSymbolsToRenameFromFile(Config.SymbolsToRename, DC.Alloc,889Arg->getValue()))890return std::move(E);891892for (auto *Arg : InputArgs.filtered(OBJCOPY_rename_section)) {893Expected<SectionRename> SR =894parseRenameSectionValue(StringRef(Arg->getValue()));895if (!SR)896return SR.takeError();897if (!Config.SectionsToRename.try_emplace(SR->OriginalName, *SR).second)898return createStringError(errc::invalid_argument,899"multiple renames of section '%s'",900SR->OriginalName.str().c_str());901}902for (auto *Arg : InputArgs.filtered(OBJCOPY_set_section_alignment)) {903Expected<std::pair<StringRef, uint64_t>> NameAndAlign =904parseSetSectionAttribute("--set-section-alignment", Arg->getValue());905if (!NameAndAlign)906return NameAndAlign.takeError();907Config.SetSectionAlignment[NameAndAlign->first] = NameAndAlign->second;908}909for (auto *Arg : InputArgs.filtered(OBJCOPY_set_section_flags)) {910Expected<SectionFlagsUpdate> SFU =911parseSetSectionFlagValue(Arg->getValue());912if (!SFU)913return SFU.takeError();914if (!Config.SetSectionFlags.try_emplace(SFU->Name, *SFU).second)915return createStringError(916errc::invalid_argument,917"--set-section-flags set multiple times for section '%s'",918SFU->Name.str().c_str());919}920for (auto *Arg : InputArgs.filtered(OBJCOPY_set_section_type)) {921Expected<std::pair<StringRef, uint64_t>> NameAndType =922parseSetSectionAttribute("--set-section-type", Arg->getValue());923if (!NameAndType)924return NameAndType.takeError();925Config.SetSectionType[NameAndType->first] = NameAndType->second;926}927// Prohibit combinations of --set-section-{flags,type} when the section name928// is used as the destination of a --rename-section.929for (const auto &E : Config.SectionsToRename) {930const SectionRename &SR = E.second;931auto Err = [&](const char *Option) {932return createStringError(933errc::invalid_argument,934"--set-section-%s=%s conflicts with --rename-section=%s=%s", Option,935SR.NewName.str().c_str(), SR.OriginalName.str().c_str(),936SR.NewName.str().c_str());937};938if (Config.SetSectionFlags.count(SR.NewName))939return Err("flags");940if (Config.SetSectionType.count(SR.NewName))941return Err("type");942}943944for (auto *Arg : InputArgs.filtered(OBJCOPY_remove_section))945if (Error E = Config.ToRemove.addMatcher(NameOrPattern::create(946Arg->getValue(), SectionMatchStyle, ErrorCallback)))947return std::move(E);948for (auto *Arg : InputArgs.filtered(OBJCOPY_keep_section))949if (Error E = Config.KeepSection.addMatcher(NameOrPattern::create(950Arg->getValue(), SectionMatchStyle, ErrorCallback)))951return std::move(E);952for (auto *Arg : InputArgs.filtered(OBJCOPY_only_section))953if (Error E = Config.OnlySection.addMatcher(NameOrPattern::create(954Arg->getValue(), SectionMatchStyle, ErrorCallback)))955return std::move(E);956for (auto *Arg : InputArgs.filtered(OBJCOPY_add_section)) {957if (Error Err = loadNewSectionData(Arg->getValue(), "--add-section",958Config.AddSection))959return std::move(Err);960}961for (auto *Arg : InputArgs.filtered(OBJCOPY_update_section)) {962if (Error Err = loadNewSectionData(Arg->getValue(), "--update-section",963Config.UpdateSection))964return std::move(Err);965}966for (auto *Arg : InputArgs.filtered(OBJCOPY_dump_section)) {967StringRef Value(Arg->getValue());968if (Value.split('=').second.empty())969return createStringError(970errc::invalid_argument,971"bad format for --dump-section, expected section=file");972Config.DumpSection.push_back(Value);973}974Config.StripAll = InputArgs.hasArg(OBJCOPY_strip_all);975Config.StripAllGNU = InputArgs.hasArg(OBJCOPY_strip_all_gnu);976Config.StripDebug = InputArgs.hasArg(OBJCOPY_strip_debug);977Config.StripDWO = InputArgs.hasArg(OBJCOPY_strip_dwo);978Config.StripSections = InputArgs.hasArg(OBJCOPY_strip_sections);979Config.StripNonAlloc = InputArgs.hasArg(OBJCOPY_strip_non_alloc);980Config.StripUnneeded = InputArgs.hasArg(OBJCOPY_strip_unneeded);981Config.ExtractDWO = InputArgs.hasArg(OBJCOPY_extract_dwo);982Config.ExtractMainPartition =983InputArgs.hasArg(OBJCOPY_extract_main_partition);984ELFConfig.LocalizeHidden = InputArgs.hasArg(OBJCOPY_localize_hidden);985Config.Weaken = InputArgs.hasArg(OBJCOPY_weaken);986if (auto *Arg =987InputArgs.getLastArg(OBJCOPY_discard_all, OBJCOPY_discard_locals)) {988Config.DiscardMode = Arg->getOption().matches(OBJCOPY_discard_all)989? DiscardType::All990: DiscardType::Locals;991}992993ELFConfig.VerifyNoteSections = InputArgs.hasFlag(994OBJCOPY_verify_note_sections, OBJCOPY_no_verify_note_sections, true);995996Config.OnlyKeepDebug = InputArgs.hasArg(OBJCOPY_only_keep_debug);997ELFConfig.KeepFileSymbols = InputArgs.hasArg(OBJCOPY_keep_file_symbols);998MachOConfig.KeepUndefined = InputArgs.hasArg(OBJCOPY_keep_undefined);999Config.DecompressDebugSections =1000InputArgs.hasArg(OBJCOPY_decompress_debug_sections);1001if (Config.DiscardMode == DiscardType::All) {1002Config.StripDebug = true;1003ELFConfig.KeepFileSymbols = true;1004}1005for (auto *Arg : InputArgs.filtered(OBJCOPY_localize_symbol))1006if (Error E = Config.SymbolsToLocalize.addMatcher(NameOrPattern::create(1007Arg->getValue(), SymbolMatchStyle, ErrorCallback)))1008return std::move(E);1009for (auto *Arg : InputArgs.filtered(OBJCOPY_localize_symbols))1010if (Error E = addSymbolsFromFile(Config.SymbolsToLocalize, DC.Alloc,1011Arg->getValue(), SymbolMatchStyle,1012ErrorCallback))1013return std::move(E);1014for (auto *Arg : InputArgs.filtered(OBJCOPY_keep_global_symbol))1015if (Error E = Config.SymbolsToKeepGlobal.addMatcher(NameOrPattern::create(1016Arg->getValue(), SymbolMatchStyle, ErrorCallback)))1017return std::move(E);1018for (auto *Arg : InputArgs.filtered(OBJCOPY_keep_global_symbols))1019if (Error E = addSymbolsFromFile(Config.SymbolsToKeepGlobal, DC.Alloc,1020Arg->getValue(), SymbolMatchStyle,1021ErrorCallback))1022return std::move(E);1023for (auto *Arg : InputArgs.filtered(OBJCOPY_globalize_symbol))1024if (Error E = Config.SymbolsToGlobalize.addMatcher(NameOrPattern::create(1025Arg->getValue(), SymbolMatchStyle, ErrorCallback)))1026return std::move(E);1027for (auto *Arg : InputArgs.filtered(OBJCOPY_globalize_symbols))1028if (Error E = addSymbolsFromFile(Config.SymbolsToGlobalize, DC.Alloc,1029Arg->getValue(), SymbolMatchStyle,1030ErrorCallback))1031return std::move(E);1032for (auto *Arg : InputArgs.filtered(OBJCOPY_weaken_symbol))1033if (Error E = Config.SymbolsToWeaken.addMatcher(NameOrPattern::create(1034Arg->getValue(), SymbolMatchStyle, ErrorCallback)))1035return std::move(E);1036for (auto *Arg : InputArgs.filtered(OBJCOPY_weaken_symbols))1037if (Error E = addSymbolsFromFile(Config.SymbolsToWeaken, DC.Alloc,1038Arg->getValue(), SymbolMatchStyle,1039ErrorCallback))1040return std::move(E);1041for (auto *Arg : InputArgs.filtered(OBJCOPY_strip_symbol))1042if (Error E = Config.SymbolsToRemove.addMatcher(NameOrPattern::create(1043Arg->getValue(), SymbolMatchStyle, ErrorCallback)))1044return std::move(E);1045for (auto *Arg : InputArgs.filtered(OBJCOPY_strip_symbols))1046if (Error E = addSymbolsFromFile(Config.SymbolsToRemove, DC.Alloc,1047Arg->getValue(), SymbolMatchStyle,1048ErrorCallback))1049return std::move(E);1050for (auto *Arg : InputArgs.filtered(OBJCOPY_strip_unneeded_symbol))1051if (Error E =1052Config.UnneededSymbolsToRemove.addMatcher(NameOrPattern::create(1053Arg->getValue(), SymbolMatchStyle, ErrorCallback)))1054return std::move(E);1055for (auto *Arg : InputArgs.filtered(OBJCOPY_strip_unneeded_symbols))1056if (Error E = addSymbolsFromFile(Config.UnneededSymbolsToRemove, DC.Alloc,1057Arg->getValue(), SymbolMatchStyle,1058ErrorCallback))1059return std::move(E);1060for (auto *Arg : InputArgs.filtered(OBJCOPY_keep_symbol))1061if (Error E = Config.SymbolsToKeep.addMatcher(NameOrPattern::create(1062Arg->getValue(), SymbolMatchStyle, ErrorCallback)))1063return std::move(E);1064for (auto *Arg : InputArgs.filtered(OBJCOPY_keep_symbols))1065if (Error E =1066addSymbolsFromFile(Config.SymbolsToKeep, DC.Alloc, Arg->getValue(),1067SymbolMatchStyle, ErrorCallback))1068return std::move(E);1069for (auto *Arg : InputArgs.filtered(OBJCOPY_skip_symbol))1070if (Error E = Config.SymbolsToSkip.addMatcher(NameOrPattern::create(1071Arg->getValue(), SymbolMatchStyle, ErrorCallback)))1072return std::move(E);1073for (auto *Arg : InputArgs.filtered(OBJCOPY_skip_symbols))1074if (Error E =1075addSymbolsFromFile(Config.SymbolsToSkip, DC.Alloc, Arg->getValue(),1076SymbolMatchStyle, ErrorCallback))1077return std::move(E);1078for (auto *Arg : InputArgs.filtered(OBJCOPY_add_symbol)) {1079Expected<NewSymbolInfo> SymInfo = parseNewSymbolInfo(Arg->getValue());1080if (!SymInfo)1081return SymInfo.takeError();10821083Config.SymbolsToAdd.push_back(*SymInfo);1084}1085for (auto *Arg : InputArgs.filtered(OBJCOPY_set_symbol_visibility)) {1086if (!StringRef(Arg->getValue()).contains('='))1087return createStringError(errc::invalid_argument,1088"bad format for --set-symbol-visibility");1089auto [Sym, Visibility] = StringRef(Arg->getValue()).split('=');1090Expected<uint8_t> Type = parseVisibilityType(Visibility);1091if (!Type)1092return Type.takeError();1093ELFConfig.SymbolsToSetVisibility.emplace_back(NameMatcher(), *Type);1094if (Error E = ELFConfig.SymbolsToSetVisibility.back().first.addMatcher(1095NameOrPattern::create(Sym, SymbolMatchStyle, ErrorCallback)))1096return std::move(E);1097}1098for (auto *Arg : InputArgs.filtered(OBJCOPY_set_symbols_visibility)) {1099if (!StringRef(Arg->getValue()).contains('='))1100return createStringError(errc::invalid_argument,1101"bad format for --set-symbols-visibility");1102auto [File, Visibility] = StringRef(Arg->getValue()).split('=');1103Expected<uint8_t> Type = parseVisibilityType(Visibility);1104if (!Type)1105return Type.takeError();1106ELFConfig.SymbolsToSetVisibility.emplace_back(NameMatcher(), *Type);1107if (Error E =1108addSymbolsFromFile(ELFConfig.SymbolsToSetVisibility.back().first,1109DC.Alloc, File, SymbolMatchStyle, ErrorCallback))1110return std::move(E);1111}11121113ELFConfig.AllowBrokenLinks = InputArgs.hasArg(OBJCOPY_allow_broken_links);11141115Config.DeterministicArchives = InputArgs.hasFlag(1116OBJCOPY_enable_deterministic_archives,1117OBJCOPY_disable_deterministic_archives, /*default=*/true);11181119Config.PreserveDates = InputArgs.hasArg(OBJCOPY_preserve_dates);11201121if (Config.PreserveDates &&1122(Config.OutputFilename == "-" || Config.InputFilename == "-"))1123return createStringError(errc::invalid_argument,1124"--preserve-dates requires a file");11251126for (auto *Arg : InputArgs)1127if (Arg->getOption().matches(OBJCOPY_set_start)) {1128auto EAddr = getAsInteger<uint64_t>(Arg->getValue());1129if (!EAddr)1130return createStringError(1131EAddr.getError(), "bad entry point address: '%s'", Arg->getValue());11321133ELFConfig.EntryExpr = [EAddr](uint64_t) { return *EAddr; };1134} else if (Arg->getOption().matches(OBJCOPY_change_start)) {1135auto EIncr = getAsInteger<int64_t>(Arg->getValue());1136if (!EIncr)1137return createStringError(EIncr.getError(),1138"bad entry point increment: '%s'",1139Arg->getValue());1140auto Expr = ELFConfig.EntryExpr ? std::move(ELFConfig.EntryExpr)1141: [](uint64_t A) { return A; };1142ELFConfig.EntryExpr = [Expr, EIncr](uint64_t EAddr) {1143return Expr(EAddr) + *EIncr;1144};1145}11461147if (Config.DecompressDebugSections &&1148Config.CompressionType != DebugCompressionType::None) {1149return createStringError(1150errc::invalid_argument,1151"cannot specify both --compress-debug-sections and "1152"--decompress-debug-sections");1153}11541155if (Config.ExtractPartition && Config.ExtractMainPartition)1156return createStringError(errc::invalid_argument,1157"cannot specify --extract-partition together with "1158"--extract-main-partition");11591160DC.CopyConfigs.push_back(std::move(ConfigMgr));1161return std::move(DC);1162}11631164// parseInstallNameToolOptions returns the config and sets the input arguments.1165// If a help flag is set then parseInstallNameToolOptions will print the help1166// messege and exit.1167Expected<DriverConfig>1168objcopy::parseInstallNameToolOptions(ArrayRef<const char *> ArgsArr) {1169DriverConfig DC;1170ConfigManager ConfigMgr;1171CommonConfig &Config = ConfigMgr.Common;1172MachOConfig &MachOConfig = ConfigMgr.MachO;1173InstallNameToolOptTable T;1174unsigned MissingArgumentIndex, MissingArgumentCount;1175llvm::opt::InputArgList InputArgs =1176T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);11771178if (MissingArgumentCount)1179return createStringError(1180errc::invalid_argument,1181"missing argument to " +1182StringRef(InputArgs.getArgString(MissingArgumentIndex)) +1183" option");11841185if (InputArgs.size() == 0) {1186printHelp(T, errs(), ToolType::InstallNameTool);1187exit(1);1188}11891190if (InputArgs.hasArg(INSTALL_NAME_TOOL_help)) {1191printHelp(T, outs(), ToolType::InstallNameTool);1192exit(0);1193}11941195if (InputArgs.hasArg(INSTALL_NAME_TOOL_version)) {1196outs() << "llvm-install-name-tool, compatible with cctools "1197"install_name_tool\n";1198cl::PrintVersionMessage();1199exit(0);1200}12011202for (auto *Arg : InputArgs.filtered(INSTALL_NAME_TOOL_add_rpath))1203MachOConfig.RPathToAdd.push_back(Arg->getValue());12041205for (auto *Arg : InputArgs.filtered(INSTALL_NAME_TOOL_prepend_rpath))1206MachOConfig.RPathToPrepend.push_back(Arg->getValue());12071208for (auto *Arg : InputArgs.filtered(INSTALL_NAME_TOOL_delete_rpath)) {1209StringRef RPath = Arg->getValue();12101211// Cannot add and delete the same rpath at the same time.1212if (is_contained(MachOConfig.RPathToAdd, RPath))1213return createStringError(1214errc::invalid_argument,1215"cannot specify both -add_rpath '%s' and -delete_rpath '%s'",1216RPath.str().c_str(), RPath.str().c_str());1217if (is_contained(MachOConfig.RPathToPrepend, RPath))1218return createStringError(1219errc::invalid_argument,1220"cannot specify both -prepend_rpath '%s' and -delete_rpath '%s'",1221RPath.str().c_str(), RPath.str().c_str());12221223MachOConfig.RPathsToRemove.insert(RPath);1224}12251226for (auto *Arg : InputArgs.filtered(INSTALL_NAME_TOOL_rpath)) {1227StringRef Old = Arg->getValue(0);1228StringRef New = Arg->getValue(1);12291230auto Match = [=](StringRef RPath) { return RPath == Old || RPath == New; };12311232// Cannot specify duplicate -rpath entries1233auto It1 = find_if(1234MachOConfig.RPathsToUpdate,1235[&Match](const DenseMap<StringRef, StringRef>::value_type &OldNew) {1236return Match(OldNew.getFirst()) || Match(OldNew.getSecond());1237});1238if (It1 != MachOConfig.RPathsToUpdate.end())1239return createStringError(errc::invalid_argument,1240"cannot specify both -rpath '" +1241It1->getFirst() + "' '" + It1->getSecond() +1242"' and -rpath '" + Old + "' '" + New + "'");12431244// Cannot specify the same rpath under both -delete_rpath and -rpath1245auto It2 = find_if(MachOConfig.RPathsToRemove, Match);1246if (It2 != MachOConfig.RPathsToRemove.end())1247return createStringError(errc::invalid_argument,1248"cannot specify both -delete_rpath '" + *It2 +1249"' and -rpath '" + Old + "' '" + New + "'");12501251// Cannot specify the same rpath under both -add_rpath and -rpath1252auto It3 = find_if(MachOConfig.RPathToAdd, Match);1253if (It3 != MachOConfig.RPathToAdd.end())1254return createStringError(errc::invalid_argument,1255"cannot specify both -add_rpath '" + *It3 +1256"' and -rpath '" + Old + "' '" + New + "'");12571258// Cannot specify the same rpath under both -prepend_rpath and -rpath.1259auto It4 = find_if(MachOConfig.RPathToPrepend, Match);1260if (It4 != MachOConfig.RPathToPrepend.end())1261return createStringError(errc::invalid_argument,1262"cannot specify both -prepend_rpath '" + *It4 +1263"' and -rpath '" + Old + "' '" + New + "'");12641265MachOConfig.RPathsToUpdate.insert({Old, New});1266}12671268if (auto *Arg = InputArgs.getLastArg(INSTALL_NAME_TOOL_id)) {1269MachOConfig.SharedLibId = Arg->getValue();1270if (MachOConfig.SharedLibId->empty())1271return createStringError(errc::invalid_argument,1272"cannot specify an empty id");1273}12741275for (auto *Arg : InputArgs.filtered(INSTALL_NAME_TOOL_change))1276MachOConfig.InstallNamesToUpdate.insert(1277{Arg->getValue(0), Arg->getValue(1)});12781279MachOConfig.RemoveAllRpaths =1280InputArgs.hasArg(INSTALL_NAME_TOOL_delete_all_rpaths);12811282SmallVector<StringRef, 2> Positional;1283for (auto *Arg : InputArgs.filtered(INSTALL_NAME_TOOL_UNKNOWN))1284return createStringError(errc::invalid_argument, "unknown argument '%s'",1285Arg->getAsString(InputArgs).c_str());1286for (auto *Arg : InputArgs.filtered(INSTALL_NAME_TOOL_INPUT))1287Positional.push_back(Arg->getValue());1288if (Positional.empty())1289return createStringError(errc::invalid_argument, "no input file specified");1290if (Positional.size() > 1)1291return createStringError(1292errc::invalid_argument,1293"llvm-install-name-tool expects a single input file");1294Config.InputFilename = Positional[0];1295Config.OutputFilename = Positional[0];12961297Expected<OwningBinary<Binary>> BinaryOrErr =1298createBinary(Config.InputFilename);1299if (!BinaryOrErr)1300return createFileError(Config.InputFilename, BinaryOrErr.takeError());1301auto *Binary = (*BinaryOrErr).getBinary();1302if (!Binary->isMachO() && !Binary->isMachOUniversalBinary())1303return createStringError(errc::invalid_argument,1304"input file: %s is not a Mach-O file",1305Config.InputFilename.str().c_str());13061307DC.CopyConfigs.push_back(std::move(ConfigMgr));1308return std::move(DC);1309}13101311Expected<DriverConfig>1312objcopy::parseBitcodeStripOptions(ArrayRef<const char *> ArgsArr,1313function_ref<Error(Error)> ErrorCallback) {1314DriverConfig DC;1315ConfigManager ConfigMgr;1316CommonConfig &Config = ConfigMgr.Common;1317MachOConfig &MachOConfig = ConfigMgr.MachO;1318BitcodeStripOptTable T;1319unsigned MissingArgumentIndex, MissingArgumentCount;1320opt::InputArgList InputArgs =1321T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);13221323if (InputArgs.size() == 0) {1324printHelp(T, errs(), ToolType::BitcodeStrip);1325exit(1);1326}13271328if (InputArgs.hasArg(BITCODE_STRIP_help)) {1329printHelp(T, outs(), ToolType::BitcodeStrip);1330exit(0);1331}13321333if (InputArgs.hasArg(BITCODE_STRIP_version)) {1334outs() << "llvm-bitcode-strip, compatible with cctools "1335"bitcode_strip\n";1336cl::PrintVersionMessage();1337exit(0);1338}13391340for (auto *Arg : InputArgs.filtered(BITCODE_STRIP_UNKNOWN))1341return createStringError(errc::invalid_argument, "unknown argument '%s'",1342Arg->getAsString(InputArgs).c_str());13431344SmallVector<StringRef, 2> Positional;1345for (auto *Arg : InputArgs.filtered(BITCODE_STRIP_INPUT))1346Positional.push_back(Arg->getValue());1347if (Positional.size() > 1)1348return createStringError(errc::invalid_argument,1349"llvm-bitcode-strip expects a single input file");1350assert(!Positional.empty());1351Config.InputFilename = Positional[0];13521353if (!InputArgs.hasArg(BITCODE_STRIP_output)) {1354return createStringError(errc::invalid_argument,1355"-o is a required argument");1356}1357Config.OutputFilename = InputArgs.getLastArgValue(BITCODE_STRIP_output);13581359if (!InputArgs.hasArg(BITCODE_STRIP_remove))1360return createStringError(errc::invalid_argument, "no action specified");13611362// We only support -r for now, which removes all bitcode sections and1363// the __LLVM segment if it's now empty.1364cantFail(Config.ToRemove.addMatcher(NameOrPattern::create(1365"__LLVM,__asm", MatchStyle::Literal, ErrorCallback)));1366cantFail(Config.ToRemove.addMatcher(NameOrPattern::create(1367"__LLVM,__bitcode", MatchStyle::Literal, ErrorCallback)));1368cantFail(Config.ToRemove.addMatcher(NameOrPattern::create(1369"__LLVM,__bundle", MatchStyle::Literal, ErrorCallback)));1370cantFail(Config.ToRemove.addMatcher(NameOrPattern::create(1371"__LLVM,__cmdline", MatchStyle::Literal, ErrorCallback)));1372cantFail(Config.ToRemove.addMatcher(NameOrPattern::create(1373"__LLVM,__swift_cmdline", MatchStyle::Literal, ErrorCallback)));1374MachOConfig.EmptySegmentsToRemove.insert("__LLVM");13751376DC.CopyConfigs.push_back(std::move(ConfigMgr));1377return std::move(DC);1378}13791380// parseStripOptions returns the config and sets the input arguments. If a1381// help flag is set then parseStripOptions will print the help messege and1382// exit.1383Expected<DriverConfig>1384objcopy::parseStripOptions(ArrayRef<const char *> RawArgsArr,1385function_ref<Error(Error)> ErrorCallback) {1386const char *const *DashDash =1387llvm::find_if(RawArgsArr, [](StringRef Str) { return Str == "--"; });1388ArrayRef<const char *> ArgsArr = ArrayRef(RawArgsArr.begin(), DashDash);1389if (DashDash != RawArgsArr.end())1390DashDash = std::next(DashDash);13911392StripOptTable T;1393unsigned MissingArgumentIndex, MissingArgumentCount;1394llvm::opt::InputArgList InputArgs =1395T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);13961397if (InputArgs.size() == 0 && DashDash == RawArgsArr.end()) {1398printHelp(T, errs(), ToolType::Strip);1399exit(1);1400}14011402if (InputArgs.hasArg(STRIP_help)) {1403printHelp(T, outs(), ToolType::Strip);1404exit(0);1405}14061407if (InputArgs.hasArg(STRIP_version)) {1408outs() << "llvm-strip, compatible with GNU strip\n";1409cl::PrintVersionMessage();1410exit(0);1411}14121413SmallVector<StringRef, 2> Positional;1414for (auto *Arg : InputArgs.filtered(STRIP_UNKNOWN))1415return createStringError(errc::invalid_argument, "unknown argument '%s'",1416Arg->getAsString(InputArgs).c_str());1417for (auto *Arg : InputArgs.filtered(STRIP_INPUT))1418Positional.push_back(Arg->getValue());1419std::copy(DashDash, RawArgsArr.end(), std::back_inserter(Positional));14201421if (Positional.empty())1422return createStringError(errc::invalid_argument, "no input file specified");14231424if (Positional.size() > 1 && InputArgs.hasArg(STRIP_output))1425return createStringError(1426errc::invalid_argument,1427"multiple input files cannot be used in combination with -o");14281429ConfigManager ConfigMgr;1430CommonConfig &Config = ConfigMgr.Common;1431ELFConfig &ELFConfig = ConfigMgr.ELF;1432MachOConfig &MachOConfig = ConfigMgr.MachO;14331434if (InputArgs.hasArg(STRIP_regex) && InputArgs.hasArg(STRIP_wildcard))1435return createStringError(errc::invalid_argument,1436"--regex and --wildcard are incompatible");1437MatchStyle SectionMatchStyle =1438InputArgs.hasArg(STRIP_regex) ? MatchStyle::Regex : MatchStyle::Wildcard;1439MatchStyle SymbolMatchStyle1440= InputArgs.hasArg(STRIP_regex) ? MatchStyle::Regex1441: InputArgs.hasArg(STRIP_wildcard) ? MatchStyle::Wildcard1442: MatchStyle::Literal;1443ELFConfig.AllowBrokenLinks = InputArgs.hasArg(STRIP_allow_broken_links);1444Config.StripDebug = InputArgs.hasArg(STRIP_strip_debug);14451446if (auto *Arg = InputArgs.getLastArg(STRIP_discard_all, STRIP_discard_locals))1447Config.DiscardMode = Arg->getOption().matches(STRIP_discard_all)1448? DiscardType::All1449: DiscardType::Locals;1450Config.StripSections = InputArgs.hasArg(STRIP_strip_sections);1451Config.StripUnneeded = InputArgs.hasArg(STRIP_strip_unneeded);1452if (auto Arg = InputArgs.getLastArg(STRIP_strip_all, STRIP_no_strip_all))1453Config.StripAll = Arg->getOption().getID() == STRIP_strip_all;1454Config.StripAllGNU = InputArgs.hasArg(STRIP_strip_all_gnu);1455MachOConfig.StripSwiftSymbols = InputArgs.hasArg(STRIP_strip_swift_symbols);1456Config.OnlyKeepDebug = InputArgs.hasArg(STRIP_only_keep_debug);1457ELFConfig.KeepFileSymbols = InputArgs.hasArg(STRIP_keep_file_symbols);1458MachOConfig.KeepUndefined = InputArgs.hasArg(STRIP_keep_undefined);14591460for (auto *Arg : InputArgs.filtered(STRIP_keep_section))1461if (Error E = Config.KeepSection.addMatcher(NameOrPattern::create(1462Arg->getValue(), SectionMatchStyle, ErrorCallback)))1463return std::move(E);14641465for (auto *Arg : InputArgs.filtered(STRIP_remove_section))1466if (Error E = Config.ToRemove.addMatcher(NameOrPattern::create(1467Arg->getValue(), SectionMatchStyle, ErrorCallback)))1468return std::move(E);14691470for (auto *Arg : InputArgs.filtered(STRIP_strip_symbol))1471if (Error E = Config.SymbolsToRemove.addMatcher(NameOrPattern::create(1472Arg->getValue(), SymbolMatchStyle, ErrorCallback)))1473return std::move(E);14741475for (auto *Arg : InputArgs.filtered(STRIP_keep_symbol))1476if (Error E = Config.SymbolsToKeep.addMatcher(NameOrPattern::create(1477Arg->getValue(), SymbolMatchStyle, ErrorCallback)))1478return std::move(E);14791480if (!InputArgs.hasArg(STRIP_no_strip_all) && !Config.StripDebug &&1481!Config.OnlyKeepDebug && !Config.StripUnneeded &&1482Config.DiscardMode == DiscardType::None && !Config.StripAllGNU &&1483Config.SymbolsToRemove.empty())1484Config.StripAll = true;14851486if (Config.DiscardMode == DiscardType::All) {1487Config.StripDebug = true;1488ELFConfig.KeepFileSymbols = true;1489}14901491Config.DeterministicArchives =1492InputArgs.hasFlag(STRIP_enable_deterministic_archives,1493STRIP_disable_deterministic_archives, /*default=*/true);14941495Config.PreserveDates = InputArgs.hasArg(STRIP_preserve_dates);1496Config.InputFormat = FileFormat::Unspecified;1497Config.OutputFormat = FileFormat::Unspecified;14981499DriverConfig DC;1500if (Positional.size() == 1) {1501Config.InputFilename = Positional[0];1502Config.OutputFilename =1503InputArgs.getLastArgValue(STRIP_output, Positional[0]);1504DC.CopyConfigs.push_back(std::move(ConfigMgr));1505} else {1506StringMap<unsigned> InputFiles;1507for (StringRef Filename : Positional) {1508if (InputFiles[Filename]++ == 1) {1509if (Filename == "-")1510return createStringError(1511errc::invalid_argument,1512"cannot specify '-' as an input file more than once");1513if (Error E = ErrorCallback(createStringError(1514errc::invalid_argument, "'%s' was already specified",1515Filename.str().c_str())))1516return std::move(E);1517}1518Config.InputFilename = Filename;1519Config.OutputFilename = Filename;1520DC.CopyConfigs.push_back(ConfigMgr);1521}1522}15231524if (Config.PreserveDates && (is_contained(Positional, "-") ||1525InputArgs.getLastArgValue(STRIP_output) == "-"))1526return createStringError(errc::invalid_argument,1527"--preserve-dates requires a file");15281529return std::move(DC);1530}153115321533