1673 lines · cpp
1//===- ObjcopyOptions.cpp -------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "ObjcopyOptions.h"10#include "llvm/ADT/SmallVector.h"11#include "llvm/ADT/StringExtras.h"12#include "llvm/ADT/StringRef.h"13#include "llvm/ADT/StringSwitch.h"14#include "llvm/BinaryFormat/COFF.h"15#include "llvm/ObjCopy/CommonConfig.h"16#include "llvm/ObjCopy/ConfigManager.h"17#include "llvm/ObjCopy/MachO/MachOConfig.h"18#include "llvm/Object/Binary.h"19#include "llvm/Option/Arg.h"20#include "llvm/Option/ArgList.h"21#include "llvm/Support/CRC.h"22#include "llvm/Support/CommandLine.h"23#include "llvm/Support/Compression.h"24#include "llvm/Support/Errc.h"25#include "llvm/Support/Error.h"26#include "llvm/Support/MemoryBuffer.h"27 28using namespace llvm;29using namespace llvm::objcopy;30using namespace llvm::object;31using namespace llvm::opt;32 33namespace {34enum ObjcopyID {35 OBJCOPY_INVALID = 0, // This is not an option ID.36#define OPTION(...) LLVM_MAKE_OPT_ID_WITH_ID_PREFIX(OBJCOPY_, __VA_ARGS__),37#include "ObjcopyOpts.inc"38#undef OPTION39};40 41namespace objcopy_opt {42#define OPTTABLE_STR_TABLE_CODE43#include "ObjcopyOpts.inc"44#undef OPTTABLE_STR_TABLE_CODE45 46#define OPTTABLE_PREFIXES_TABLE_CODE47#include "ObjcopyOpts.inc"48#undef OPTTABLE_PREFIXES_TABLE_CODE49 50static constexpr opt::OptTable::Info ObjcopyInfoTable[] = {51#define OPTION(...) \52 LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX(OBJCOPY_, __VA_ARGS__),53#include "ObjcopyOpts.inc"54#undef OPTION55};56} // namespace objcopy_opt57 58class ObjcopyOptTable : public opt::GenericOptTable {59public:60 ObjcopyOptTable()61 : opt::GenericOptTable(objcopy_opt::OptionStrTable,62 objcopy_opt::OptionPrefixesTable,63 objcopy_opt::ObjcopyInfoTable) {64 setGroupedShortOptions(true);65 setDashDashParsing(true);66 }67};68 69enum InstallNameToolID {70 INSTALL_NAME_TOOL_INVALID = 0, // This is not an option ID.71#define OPTION(...) \72 LLVM_MAKE_OPT_ID_WITH_ID_PREFIX(INSTALL_NAME_TOOL_, __VA_ARGS__),73#include "InstallNameToolOpts.inc"74#undef OPTION75};76 77namespace install_name_tool {78#define OPTTABLE_STR_TABLE_CODE79#include "InstallNameToolOpts.inc"80#undef OPTTABLE_STR_TABLE_CODE81 82#define OPTTABLE_PREFIXES_TABLE_CODE83#include "InstallNameToolOpts.inc"84#undef OPTTABLE_PREFIXES_TABLE_CODE85 86static constexpr opt::OptTable::Info InstallNameToolInfoTable[] = {87#define OPTION(...) \88 LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX(INSTALL_NAME_TOOL_, __VA_ARGS__),89#include "InstallNameToolOpts.inc"90#undef OPTION91};92} // namespace install_name_tool93 94class InstallNameToolOptTable : public opt::GenericOptTable {95public:96 InstallNameToolOptTable()97 : GenericOptTable(install_name_tool::OptionStrTable,98 install_name_tool::OptionPrefixesTable,99 install_name_tool::InstallNameToolInfoTable) {}100};101 102enum BitcodeStripID {103 BITCODE_STRIP_INVALID = 0, // This is not an option ID.104#define OPTION(...) \105 LLVM_MAKE_OPT_ID_WITH_ID_PREFIX(BITCODE_STRIP_, __VA_ARGS__),106#include "BitcodeStripOpts.inc"107#undef OPTION108};109 110namespace bitcode_strip {111#define OPTTABLE_STR_TABLE_CODE112#include "BitcodeStripOpts.inc"113#undef OPTTABLE_STR_TABLE_CODE114 115#define OPTTABLE_PREFIXES_TABLE_CODE116#include "BitcodeStripOpts.inc"117#undef OPTTABLE_PREFIXES_TABLE_CODE118 119static constexpr opt::OptTable::Info BitcodeStripInfoTable[] = {120#define OPTION(...) \121 LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX(BITCODE_STRIP_, __VA_ARGS__),122#include "BitcodeStripOpts.inc"123#undef OPTION124};125} // namespace bitcode_strip126 127class BitcodeStripOptTable : public opt::GenericOptTable {128public:129 BitcodeStripOptTable()130 : opt::GenericOptTable(bitcode_strip::OptionStrTable,131 bitcode_strip::OptionPrefixesTable,132 bitcode_strip::BitcodeStripInfoTable) {}133};134 135enum StripID {136 STRIP_INVALID = 0, // This is not an option ID.137#define OPTION(...) LLVM_MAKE_OPT_ID_WITH_ID_PREFIX(STRIP_, __VA_ARGS__),138#include "StripOpts.inc"139#undef OPTION140};141 142namespace strip {143#define OPTTABLE_STR_TABLE_CODE144#include "StripOpts.inc"145#undef OPTTABLE_STR_TABLE_CODE146 147#define OPTTABLE_PREFIXES_TABLE_CODE148#include "StripOpts.inc"149#undef OPTTABLE_PREFIXES_TABLE_CODE150 151static constexpr opt::OptTable::Info StripInfoTable[] = {152#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX(STRIP_, __VA_ARGS__),153#include "StripOpts.inc"154#undef OPTION155};156} // namespace strip157 158class StripOptTable : public opt::GenericOptTable {159public:160 StripOptTable()161 : GenericOptTable(strip::OptionStrTable, strip::OptionPrefixesTable,162 strip::StripInfoTable) {163 setGroupedShortOptions(true);164 }165};166 167} // namespace168 169static SectionFlag parseSectionRenameFlag(StringRef SectionName) {170 return llvm::StringSwitch<SectionFlag>(SectionName)171 .CaseLower("alloc", SectionFlag::SecAlloc)172 .CaseLower("load", SectionFlag::SecLoad)173 .CaseLower("noload", SectionFlag::SecNoload)174 .CaseLower("readonly", SectionFlag::SecReadonly)175 .CaseLower("debug", SectionFlag::SecDebug)176 .CaseLower("code", SectionFlag::SecCode)177 .CaseLower("data", SectionFlag::SecData)178 .CaseLower("rom", SectionFlag::SecRom)179 .CaseLower("merge", SectionFlag::SecMerge)180 .CaseLower("strings", SectionFlag::SecStrings)181 .CaseLower("contents", SectionFlag::SecContents)182 .CaseLower("share", SectionFlag::SecShare)183 .CaseLower("exclude", SectionFlag::SecExclude)184 .CaseLower("large", SectionFlag::SecLarge)185 .Default(SectionFlag::SecNone);186}187 188static Expected<SectionFlag>189parseSectionFlagSet(ArrayRef<StringRef> SectionFlags) {190 SectionFlag ParsedFlags = SectionFlag::SecNone;191 for (StringRef Flag : SectionFlags) {192 SectionFlag ParsedFlag = parseSectionRenameFlag(Flag);193 if (ParsedFlag == SectionFlag::SecNone)194 return createStringError(195 errc::invalid_argument,196 "unrecognized section flag '%s'. Flags supported for GNU "197 "compatibility: alloc, load, noload, readonly, exclude, debug, "198 "code, data, rom, share, contents, merge, strings, large",199 Flag.str().c_str());200 ParsedFlags |= ParsedFlag;201 }202 203 return ParsedFlags;204}205 206static Expected<SectionRename> parseRenameSectionValue(StringRef FlagValue) {207 if (!FlagValue.contains('='))208 return createStringError(errc::invalid_argument,209 "bad format for --rename-section: missing '='");210 211 // Initial split: ".foo" = ".bar,f1,f2,..."212 auto Old2New = FlagValue.split('=');213 SectionRename SR;214 SR.OriginalName = Old2New.first;215 216 // Flags split: ".bar" "f1" "f2" ...217 SmallVector<StringRef, 6> NameAndFlags;218 Old2New.second.split(NameAndFlags, ',');219 SR.NewName = NameAndFlags[0];220 221 if (NameAndFlags.size() > 1) {222 Expected<SectionFlag> ParsedFlagSet =223 parseSectionFlagSet(ArrayRef(NameAndFlags).drop_front());224 if (!ParsedFlagSet)225 return ParsedFlagSet.takeError();226 SR.NewFlags = *ParsedFlagSet;227 }228 229 return SR;230}231 232static Expected<std::pair<StringRef, uint64_t>>233parseSetSectionAttribute(StringRef Option, StringRef FlagValue) {234 if (!FlagValue.contains('='))235 return make_error<StringError>("bad format for " + Option + ": missing '='",236 errc::invalid_argument);237 auto Split = StringRef(FlagValue).split('=');238 if (Split.first.empty())239 return make_error<StringError>("bad format for " + Option +240 ": missing section name",241 errc::invalid_argument);242 uint64_t Value;243 if (Split.second.getAsInteger(0, Value))244 return make_error<StringError>("invalid value for " + Option + ": '" +245 Split.second + "'",246 errc::invalid_argument);247 return std::make_pair(Split.first, Value);248}249 250static Expected<SectionFlagsUpdate>251parseSetSectionFlagValue(StringRef FlagValue) {252 if (!StringRef(FlagValue).contains('='))253 return createStringError(errc::invalid_argument,254 "bad format for --set-section-flags: missing '='");255 256 // Initial split: ".foo" = "f1,f2,..."257 auto Section2Flags = StringRef(FlagValue).split('=');258 SectionFlagsUpdate SFU;259 SFU.Name = Section2Flags.first;260 261 // Flags split: "f1" "f2" ...262 SmallVector<StringRef, 6> SectionFlags;263 Section2Flags.second.split(SectionFlags, ',');264 Expected<SectionFlag> ParsedFlagSet = parseSectionFlagSet(SectionFlags);265 if (!ParsedFlagSet)266 return ParsedFlagSet.takeError();267 SFU.NewFlags = *ParsedFlagSet;268 269 return SFU;270}271 272static Expected<uint8_t> parseVisibilityType(StringRef VisType) {273 const uint8_t Invalid = 0xff;274 uint8_t type = StringSwitch<uint8_t>(VisType)275 .Case("default", ELF::STV_DEFAULT)276 .Case("hidden", ELF::STV_HIDDEN)277 .Case("internal", ELF::STV_INTERNAL)278 .Case("protected", ELF::STV_PROTECTED)279 .Default(Invalid);280 if (type == Invalid)281 return createStringError(errc::invalid_argument,282 "'%s' is not a valid symbol visibility",283 VisType.str().c_str());284 return type;285}286 287namespace {288struct TargetInfo {289 FileFormat Format;290 MachineInfo Machine;291};292} // namespace293 294// FIXME: consolidate with the bfd parsing used by lld.295static const StringMap<MachineInfo> TargetMap{296 // Name, {EMachine, 64bit, LittleEndian}297 // x86298 {"elf32-i386", {ELF::EM_386, false, true}},299 {"elf32-x86-64", {ELF::EM_X86_64, false, true}},300 {"elf64-x86-64", {ELF::EM_X86_64, true, true}},301 // Intel MCU302 {"elf32-iamcu", {ELF::EM_IAMCU, false, true}},303 // ARM304 {"elf32-littlearm", {ELF::EM_ARM, false, true}},305 // ARM AArch64306 {"elf64-aarch64", {ELF::EM_AARCH64, true, true}},307 {"elf64-littleaarch64", {ELF::EM_AARCH64, true, true}},308 // RISC-V309 {"elf32-littleriscv", {ELF::EM_RISCV, false, true}},310 {"elf64-littleriscv", {ELF::EM_RISCV, true, true}},311 {"elf32-bigriscv", {ELF::EM_RISCV, false, false}},312 {"elf64-bigriscv", {ELF::EM_RISCV, true, false}},313 // PowerPC314 {"elf32-powerpc", {ELF::EM_PPC, false, false}},315 {"elf32-powerpcle", {ELF::EM_PPC, false, true}},316 {"elf64-powerpc", {ELF::EM_PPC64, true, false}},317 {"elf64-powerpcle", {ELF::EM_PPC64, true, true}},318 // MIPS319 {"elf32-bigmips", {ELF::EM_MIPS, false, false}},320 {"elf32-ntradbigmips", {ELF::EM_MIPS, false, false}},321 {"elf32-ntradlittlemips", {ELF::EM_MIPS, false, true}},322 {"elf32-tradbigmips", {ELF::EM_MIPS, false, false}},323 {"elf32-tradlittlemips", {ELF::EM_MIPS, false, true}},324 {"elf64-tradbigmips", {ELF::EM_MIPS, true, false}},325 {"elf64-tradlittlemips", {ELF::EM_MIPS, true, true}},326 // SPARC327 {"elf32-sparc", {ELF::EM_SPARC, false, false}},328 {"elf32-sparcel", {ELF::EM_SPARC, false, true}},329 // Hexagon330 {"elf32-hexagon", {ELF::EM_HEXAGON, false, true}},331 // LoongArch332 {"elf32-loongarch", {ELF::EM_LOONGARCH, false, true}},333 {"elf64-loongarch", {ELF::EM_LOONGARCH, true, true}},334 // SystemZ335 {"elf64-s390", {ELF::EM_S390, true, false}},336};337 338static Expected<TargetInfo>339getOutputTargetInfoByTargetName(StringRef TargetName) {340 StringRef OriginalTargetName = TargetName;341 bool IsFreeBSD = TargetName.consume_back("-freebsd");342 auto Iter = TargetMap.find(TargetName);343 if (Iter == std::end(TargetMap))344 return createStringError(errc::invalid_argument,345 "invalid output format: '%s'",346 OriginalTargetName.str().c_str());347 MachineInfo MI = Iter->getValue();348 if (IsFreeBSD)349 MI.OSABI = ELF::ELFOSABI_FREEBSD;350 351 FileFormat Format;352 if (TargetName.starts_with("elf"))353 Format = FileFormat::ELF;354 else355 // This should never happen because `TargetName` is valid (it certainly356 // exists in the TargetMap).357 llvm_unreachable("unknown target prefix");358 359 return {TargetInfo{Format, MI}};360}361 362static Error addSymbolsFromFile(NameMatcher &Symbols, BumpPtrAllocator &Alloc,363 StringRef Filename, MatchStyle MS,364 function_ref<Error(Error)> ErrorCallback) {365 StringSaver Saver(Alloc);366 SmallVector<StringRef, 16> Lines;367 auto BufOrErr = MemoryBuffer::getFile(Filename);368 if (!BufOrErr)369 return createFileError(Filename, BufOrErr.getError());370 371 BufOrErr.get()->getBuffer().split(Lines, '\n');372 for (StringRef Line : Lines) {373 // Ignore everything after '#', trim whitespace, and only add the symbol if374 // it's not empty.375 auto TrimmedLine = Line.split('#').first.trim();376 if (!TrimmedLine.empty())377 if (Error E = Symbols.addMatcher(NameOrPattern::create(378 Saver.save(TrimmedLine), MS, ErrorCallback)))379 return E;380 }381 382 return Error::success();383}384 385static Error addSymbolsToRenameFromFile(StringMap<StringRef> &SymbolsToRename,386 BumpPtrAllocator &Alloc,387 StringRef Filename) {388 StringSaver Saver(Alloc);389 SmallVector<StringRef, 16> Lines;390 auto BufOrErr = MemoryBuffer::getFile(Filename);391 if (!BufOrErr)392 return createFileError(Filename, BufOrErr.getError());393 394 BufOrErr.get()->getBuffer().split(Lines, '\n');395 size_t NumLines = Lines.size();396 for (size_t LineNo = 0; LineNo < NumLines; ++LineNo) {397 StringRef TrimmedLine = Lines[LineNo].split('#').first.trim();398 if (TrimmedLine.empty())399 continue;400 401 std::pair<StringRef, StringRef> Pair = Saver.save(TrimmedLine).split(' ');402 StringRef NewName = Pair.second.trim();403 if (NewName.empty())404 return createStringError(errc::invalid_argument,405 "%s:%zu: missing new symbol name",406 Filename.str().c_str(), LineNo + 1);407 SymbolsToRename.insert({Pair.first, NewName});408 }409 return Error::success();410}411 412template <class T> static ErrorOr<T> getAsInteger(StringRef Val) {413 T Result;414 if (Val.getAsInteger(0, Result))415 return errc::invalid_argument;416 return Result;417}418 419namespace {420 421enum class ToolType { Objcopy, Strip, InstallNameTool, BitcodeStrip };422 423} // anonymous namespace424 425static void printHelp(const opt::OptTable &OptTable, raw_ostream &OS,426 ToolType Tool) {427 StringRef HelpText, ToolName;428 switch (Tool) {429 case ToolType::Objcopy:430 ToolName = "llvm-objcopy";431 HelpText = " [options] input [output]";432 break;433 case ToolType::Strip:434 ToolName = "llvm-strip";435 HelpText = " [options] inputs...";436 break;437 case ToolType::InstallNameTool:438 ToolName = "llvm-install-name-tool";439 HelpText = " [options] input";440 break;441 case ToolType::BitcodeStrip:442 ToolName = "llvm-bitcode-strip";443 HelpText = " [options] input";444 break;445 }446 OptTable.printHelp(OS, (ToolName + HelpText).str().c_str(),447 (ToolName + " tool").str().c_str());448 // TODO: Replace this with libOption call once it adds extrahelp support.449 // The CommandLine library has a cl::extrahelp class to support this,450 // but libOption does not have that yet.451 OS << "\nPass @FILE as argument to read options from FILE.\n";452}453 454static Expected<NewSymbolInfo> parseNewSymbolInfo(StringRef FlagValue) {455 // Parse value given with --add-symbol option and create the456 // new symbol if possible. The value format for --add-symbol is:457 //458 // <name>=[<section>:]<value>[,<flags>]459 //460 // where:461 // <name> - symbol name, can be empty string462 // <section> - optional section name. If not given ABS symbol is created463 // <value> - symbol value, can be decimal or hexadecimal number prefixed464 // with 0x.465 // <flags> - optional flags affecting symbol type, binding or visibility.466 NewSymbolInfo SI;467 StringRef Value;468 std::tie(SI.SymbolName, Value) = FlagValue.split('=');469 if (Value.empty())470 return createStringError(471 errc::invalid_argument,472 "bad format for --add-symbol, missing '=' after '%s'",473 SI.SymbolName.str().c_str());474 475 if (Value.contains(':')) {476 std::tie(SI.SectionName, Value) = Value.split(':');477 if (SI.SectionName.empty() || Value.empty())478 return createStringError(479 errc::invalid_argument,480 "bad format for --add-symbol, missing section name or symbol value");481 }482 483 SmallVector<StringRef, 6> Flags;484 Value.split(Flags, ',');485 if (Flags[0].getAsInteger(0, SI.Value))486 return createStringError(errc::invalid_argument, "bad symbol value: '%s'",487 Flags[0].str().c_str());488 489 using Functor = std::function<void()>;490 SmallVector<StringRef, 6> UnsupportedFlags;491 for (size_t I = 1, NumFlags = Flags.size(); I < NumFlags; ++I)492 static_cast<Functor>(493 StringSwitch<Functor>(Flags[I])494 .CaseLower("global",495 [&] { SI.Flags.push_back(SymbolFlag::Global); })496 .CaseLower("local", [&] { SI.Flags.push_back(SymbolFlag::Local); })497 .CaseLower("weak", [&] { SI.Flags.push_back(SymbolFlag::Weak); })498 .CaseLower("default",499 [&] { SI.Flags.push_back(SymbolFlag::Default); })500 .CaseLower("hidden",501 [&] { SI.Flags.push_back(SymbolFlag::Hidden); })502 .CaseLower("protected",503 [&] { SI.Flags.push_back(SymbolFlag::Protected); })504 .CaseLower("file", [&] { SI.Flags.push_back(SymbolFlag::File); })505 .CaseLower("section",506 [&] { SI.Flags.push_back(SymbolFlag::Section); })507 .CaseLower("object",508 [&] { SI.Flags.push_back(SymbolFlag::Object); })509 .CaseLower("function",510 [&] { SI.Flags.push_back(SymbolFlag::Function); })511 .CaseLower(512 "indirect-function",513 [&] { SI.Flags.push_back(SymbolFlag::IndirectFunction); })514 .CaseLower("debug", [&] { SI.Flags.push_back(SymbolFlag::Debug); })515 .CaseLower("constructor",516 [&] { SI.Flags.push_back(SymbolFlag::Constructor); })517 .CaseLower("warning",518 [&] { SI.Flags.push_back(SymbolFlag::Warning); })519 .CaseLower("indirect",520 [&] { SI.Flags.push_back(SymbolFlag::Indirect); })521 .CaseLower("synthetic",522 [&] { SI.Flags.push_back(SymbolFlag::Synthetic); })523 .CaseLower("unique-object",524 [&] { SI.Flags.push_back(SymbolFlag::UniqueObject); })525 .StartsWithLower("before=",526 [&] {527 StringRef SymNamePart =528 Flags[I].split('=').second;529 530 if (!SymNamePart.empty())531 SI.BeforeSyms.push_back(SymNamePart);532 })533 .Default([&] { UnsupportedFlags.push_back(Flags[I]); }))();534 if (!UnsupportedFlags.empty())535 return createStringError(errc::invalid_argument,536 "unsupported flag%s for --add-symbol: '%s'",537 UnsupportedFlags.size() > 1 ? "s" : "",538 join(UnsupportedFlags, "', '").c_str());539 540 return SI;541}542 543static Expected<RemoveNoteInfo> parseRemoveNoteInfo(StringRef FlagValue) {544 // Parse value given with --remove-note option. The format is:545 //546 // [name/]type_id547 //548 // where:549 // <name> - optional note name. If not given, all notes with the specified550 // <type_id> are removed.551 // <type_id> - note type value, can be decimal or hexadecimal number prefixed552 // with 0x.553 RemoveNoteInfo NI;554 StringRef TypeIdStr;555 if (auto Idx = FlagValue.find('/'); Idx != StringRef::npos) {556 if (Idx == 0)557 return createStringError(558 errc::invalid_argument,559 "bad format for --remove-note, note name is empty");560 NI.Name = FlagValue.slice(0, Idx);561 TypeIdStr = FlagValue.substr(Idx + 1);562 } else {563 TypeIdStr = FlagValue;564 }565 if (TypeIdStr.empty())566 return createStringError(errc::invalid_argument,567 "bad format for --remove-note, missing type_id");568 if (TypeIdStr.getAsInteger(0, NI.TypeId))569 return createStringError(errc::invalid_argument,570 "bad note type_id for --remove-note: '%s'",571 TypeIdStr.str().c_str());572 return NI;573}574 575// Parse input option \p ArgValue and load section data. This function576// extracts section name and name of the file keeping section data from577// ArgValue, loads data from the file, and stores section name and data578// into the vector of new sections \p NewSections.579static Error loadNewSectionData(StringRef ArgValue, StringRef OptionName,580 SmallVector<NewSectionInfo, 0> &NewSections) {581 if (!ArgValue.contains('='))582 return createStringError(errc::invalid_argument,583 "bad format for " + OptionName + ": missing '='");584 585 std::pair<StringRef, StringRef> SecPair = ArgValue.split("=");586 if (SecPair.second.empty())587 return createStringError(errc::invalid_argument, "bad format for " +588 OptionName +589 ": missing file name");590 591 ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =592 MemoryBuffer::getFile(SecPair.second);593 if (!BufOrErr)594 return createFileError(SecPair.second,595 errorCodeToError(BufOrErr.getError()));596 597 NewSections.push_back({SecPair.first, std::move(*BufOrErr)});598 return Error::success();599}600 601static Expected<int64_t> parseChangeSectionLMA(StringRef ArgValue,602 StringRef OptionName) {603 StringRef StringValue;604 if (ArgValue.starts_with("*+")) {605 StringValue = ArgValue.substr(2);606 } else if (ArgValue.starts_with("*-")) {607 StringValue = ArgValue.substr(1);608 } else if (ArgValue.contains("=")) {609 return createStringError(errc::invalid_argument,610 "bad format for " + OptionName +611 ": changing LMA to a specific value is not "612 "supported. Use *+val or *-val instead");613 } else if (ArgValue.contains("+") || ArgValue.contains("-")) {614 return createStringError(errc::invalid_argument,615 "bad format for " + OptionName +616 ": changing a specific section LMA is not "617 "supported. Use *+val or *-val instead");618 }619 if (StringValue.empty())620 return createStringError(errc::invalid_argument,621 "bad format for " + OptionName +622 ": missing LMA offset");623 624 auto LMAValue = getAsInteger<int64_t>(StringValue);625 if (!LMAValue)626 return createStringError(LMAValue.getError(),627 "bad format for " + OptionName + ": value after " +628 ArgValue.slice(0, 2) + " is " + StringValue +629 " when it should be an integer");630 return *LMAValue;631}632 633static Expected<SectionPatternAddressUpdate>634parseChangeSectionAddr(StringRef ArgValue, StringRef OptionName,635 MatchStyle SectionMatchStyle,636 function_ref<Error(Error)> ErrorCallback) {637 SectionPatternAddressUpdate PatternUpdate;638 639 size_t LastSymbolIndex = ArgValue.find_last_of("+-=");640 if (LastSymbolIndex == StringRef::npos)641 return createStringError(errc::invalid_argument,642 "bad format for " + OptionName +643 ": argument value " + ArgValue +644 " is invalid. See --help");645 char UpdateSymbol = ArgValue[LastSymbolIndex];646 647 StringRef SectionPattern = ArgValue.slice(0, LastSymbolIndex);648 if (SectionPattern.empty())649 return createStringError(650 errc::invalid_argument,651 "bad format for " + OptionName +652 ": missing section pattern to apply address change to");653 if (Error E = PatternUpdate.SectionPattern.addMatcher(NameOrPattern::create(654 SectionPattern, SectionMatchStyle, ErrorCallback)))655 return std::move(E);656 657 StringRef Value = ArgValue.substr(LastSymbolIndex + 1);658 if (Value.empty()) {659 switch (UpdateSymbol) {660 case '+':661 case '-':662 return createStringError(errc::invalid_argument,663 "bad format for " + OptionName +664 ": missing value of offset after '" +665 std::string({UpdateSymbol}) + "'");666 667 case '=':668 return createStringError(errc::invalid_argument,669 "bad format for " + OptionName +670 ": missing address value after '='");671 }672 }673 auto AddrValue = getAsInteger<uint64_t>(Value);674 if (!AddrValue)675 return createStringError(AddrValue.getError(),676 "bad format for " + OptionName + ": value after " +677 std::string({UpdateSymbol}) + " is " + Value +678 " when it should be a 64-bit integer");679 680 switch (UpdateSymbol) {681 case '+':682 PatternUpdate.Update.Kind = AdjustKind::Add;683 break;684 case '-':685 PatternUpdate.Update.Kind = AdjustKind::Subtract;686 break;687 case '=':688 PatternUpdate.Update.Kind = AdjustKind::Set;689 }690 691 PatternUpdate.Update.Value = *AddrValue;692 return PatternUpdate;693}694 695// parseObjcopyOptions returns the config and sets the input arguments. If a696// help flag is set then parseObjcopyOptions will print the help messege and697// exit.698Expected<DriverConfig>699objcopy::parseObjcopyOptions(ArrayRef<const char *> ArgsArr,700 function_ref<Error(Error)> ErrorCallback) {701 DriverConfig DC;702 ObjcopyOptTable T;703 704 unsigned MissingArgumentIndex, MissingArgumentCount;705 llvm::opt::InputArgList InputArgs =706 T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);707 708 if (MissingArgumentCount)709 return createStringError(710 errc::invalid_argument,711 "argument to '%s' is missing (expected %d value(s))",712 InputArgs.getArgString(MissingArgumentIndex), MissingArgumentCount);713 714 if (InputArgs.size() == 0) {715 printHelp(T, errs(), ToolType::Objcopy);716 exit(1);717 }718 719 if (InputArgs.hasArg(OBJCOPY_help)) {720 printHelp(T, outs(), ToolType::Objcopy);721 exit(0);722 }723 724 if (InputArgs.hasArg(OBJCOPY_version)) {725 outs() << "llvm-objcopy, compatible with GNU objcopy\n";726 cl::PrintVersionMessage();727 exit(0);728 }729 730 SmallVector<const char *, 2> Positional;731 732 for (auto *Arg : InputArgs.filtered(OBJCOPY_UNKNOWN))733 return createStringError(errc::invalid_argument, "unknown argument '%s'",734 Arg->getAsString(InputArgs).c_str());735 736 for (auto *Arg : InputArgs.filtered(OBJCOPY_INPUT))737 Positional.push_back(Arg->getValue());738 739 if (Positional.empty())740 return createStringError(errc::invalid_argument, "no input file specified");741 742 if (Positional.size() > 2)743 return createStringError(errc::invalid_argument,744 "too many positional arguments");745 746 ConfigManager ConfigMgr;747 CommonConfig &Config = ConfigMgr.Common;748 COFFConfig &COFFConfig = ConfigMgr.COFF;749 ELFConfig &ELFConfig = ConfigMgr.ELF;750 MachOConfig &MachOConfig = ConfigMgr.MachO;751 Config.InputFilename = Positional[0];752 Config.OutputFilename = Positional[Positional.size() == 1 ? 0 : 1];753 if (InputArgs.hasArg(OBJCOPY_target) &&754 (InputArgs.hasArg(OBJCOPY_input_target) ||755 InputArgs.hasArg(OBJCOPY_output_target)))756 return createStringError(757 errc::invalid_argument,758 "--target cannot be used with --input-target or --output-target");759 760 if (InputArgs.hasArg(OBJCOPY_regex) && InputArgs.hasArg(OBJCOPY_wildcard))761 return createStringError(errc::invalid_argument,762 "--regex and --wildcard are incompatible");763 764 MatchStyle SectionMatchStyle = InputArgs.hasArg(OBJCOPY_regex)765 ? MatchStyle::Regex766 : MatchStyle::Wildcard;767 MatchStyle SymbolMatchStyle768 = InputArgs.hasArg(OBJCOPY_regex) ? MatchStyle::Regex769 : InputArgs.hasArg(OBJCOPY_wildcard) ? MatchStyle::Wildcard770 : MatchStyle::Literal;771 StringRef InputFormat, OutputFormat;772 if (InputArgs.hasArg(OBJCOPY_target)) {773 InputFormat = InputArgs.getLastArgValue(OBJCOPY_target);774 OutputFormat = InputArgs.getLastArgValue(OBJCOPY_target);775 } else {776 InputFormat = InputArgs.getLastArgValue(OBJCOPY_input_target);777 OutputFormat = InputArgs.getLastArgValue(OBJCOPY_output_target);778 }779 780 // FIXME: Currently, we ignore the target for non-binary/ihex formats781 // explicitly specified by -I option (e.g. -Ielf32-x86-64) and guess the782 // format by llvm::object::createBinary regardless of the option value.783 Config.InputFormat = StringSwitch<FileFormat>(InputFormat)784 .Case("binary", FileFormat::Binary)785 .Case("ihex", FileFormat::IHex)786 .Default(FileFormat::Unspecified);787 788 if (InputArgs.hasArg(OBJCOPY_new_symbol_visibility)) {789 const uint8_t Invalid = 0xff;790 StringRef VisibilityStr =791 InputArgs.getLastArgValue(OBJCOPY_new_symbol_visibility);792 793 ELFConfig.NewSymbolVisibility = StringSwitch<uint8_t>(VisibilityStr)794 .Case("default", ELF::STV_DEFAULT)795 .Case("hidden", ELF::STV_HIDDEN)796 .Case("internal", ELF::STV_INTERNAL)797 .Case("protected", ELF::STV_PROTECTED)798 .Default(Invalid);799 800 if (ELFConfig.NewSymbolVisibility == Invalid)801 return createStringError(errc::invalid_argument,802 "'%s' is not a valid symbol visibility",803 VisibilityStr.str().c_str());804 }805 806 for (const auto *Arg : InputArgs.filtered(OBJCOPY_subsystem)) {807 StringRef Subsystem, Version;808 std::tie(Subsystem, Version) = StringRef(Arg->getValue()).split(':');809 COFFConfig.Subsystem =810 StringSwitch<unsigned>(Subsystem.lower())811 .Case("boot_application",812 COFF::IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION)813 .Case("console", COFF::IMAGE_SUBSYSTEM_WINDOWS_CUI)814 .Cases({"efi_application", "efi-app"},815 COFF::IMAGE_SUBSYSTEM_EFI_APPLICATION)816 .Cases({"efi_boot_service_driver", "efi-bsd"},817 COFF::IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER)818 .Case("efi_rom", COFF::IMAGE_SUBSYSTEM_EFI_ROM)819 .Cases({"efi_runtime_driver", "efi-rtd"},820 COFF::IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER)821 .Case("native", COFF::IMAGE_SUBSYSTEM_NATIVE)822 .Case("posix", COFF::IMAGE_SUBSYSTEM_POSIX_CUI)823 .Case("windows", COFF::IMAGE_SUBSYSTEM_WINDOWS_GUI)824 .Default(COFF::IMAGE_SUBSYSTEM_UNKNOWN);825 if (*COFFConfig.Subsystem == COFF::IMAGE_SUBSYSTEM_UNKNOWN)826 return createStringError(errc::invalid_argument,827 "'%s' is not a valid subsystem",828 Subsystem.str().c_str());829 if (!Version.empty()) {830 StringRef Major, Minor;831 std::tie(Major, Minor) = Version.split('.');832 unsigned Number;833 if (Major.getAsInteger(10, Number))834 return createStringError(errc::invalid_argument,835 "'%s' is not a valid subsystem major version",836 Major.str().c_str());837 COFFConfig.MajorSubsystemVersion = Number;838 Number = 0;839 if (!Minor.empty() && Minor.getAsInteger(10, Number))840 return createStringError(errc::invalid_argument,841 "'%s' is not a valid subsystem minor version",842 Minor.str().c_str());843 COFFConfig.MinorSubsystemVersion = Number;844 }845 }846 847 Config.OutputFormat = StringSwitch<FileFormat>(OutputFormat)848 .Case("binary", FileFormat::Binary)849 .Case("ihex", FileFormat::IHex)850 .Case("srec", FileFormat::SREC)851 .Default(FileFormat::Unspecified);852 if (Config.OutputFormat == FileFormat::Unspecified) {853 if (OutputFormat.empty()) {854 Config.OutputFormat = Config.InputFormat;855 } else {856 Expected<TargetInfo> Target =857 getOutputTargetInfoByTargetName(OutputFormat);858 if (!Target)859 return Target.takeError();860 Config.OutputFormat = Target->Format;861 Config.OutputArch = Target->Machine;862 }863 }864 865 if (const auto *A = InputArgs.getLastArg(OBJCOPY_compress_debug_sections)) {866 Config.CompressionType = StringSwitch<DebugCompressionType>(A->getValue())867 .Case("zlib", DebugCompressionType::Zlib)868 .Case("zstd", DebugCompressionType::Zstd)869 .Default(DebugCompressionType::None);870 if (Config.CompressionType == DebugCompressionType::None) {871 return createStringError(872 errc::invalid_argument,873 "invalid or unsupported --compress-debug-sections format: %s",874 A->getValue());875 }876 if (const char *Reason = compression::getReasonIfUnsupported(877 compression::formatFor(Config.CompressionType)))878 return createStringError(errc::invalid_argument, Reason);879 }880 881 for (const auto *A : InputArgs.filtered(OBJCOPY_compress_sections)) {882 SmallVector<StringRef, 0> Fields;883 StringRef(A->getValue()).split(Fields, '=');884 if (Fields.size() != 2 || Fields[1].empty()) {885 return createStringError(886 errc::invalid_argument,887 A->getSpelling() +888 ": parse error, not 'section-glob=[none|zlib|zstd]'");889 }890 891 auto Type = StringSwitch<DebugCompressionType>(Fields[1])892 .Case("zlib", DebugCompressionType::Zlib)893 .Case("zstd", DebugCompressionType::Zstd)894 .Default(DebugCompressionType::None);895 if (Type == DebugCompressionType::None && Fields[1] != "none") {896 return createStringError(897 errc::invalid_argument,898 "invalid or unsupported --compress-sections format: %s",899 A->getValue());900 }901 902 auto &P = Config.compressSections.emplace_back();903 P.second = Type;904 auto Matcher =905 NameOrPattern::create(Fields[0], SectionMatchStyle, ErrorCallback);906 // =none allows overriding a previous =zlib or =zstd. Reject negative907 // patterns, which would be confusing.908 if (Matcher && !Matcher->isPositiveMatch()) {909 return createStringError(910 errc::invalid_argument,911 "--compress-sections: negative pattern is unsupported");912 }913 if (Error E = P.first.addMatcher(std::move(Matcher)))914 return std::move(E);915 }916 917 Config.AddGnuDebugLink = InputArgs.getLastArgValue(OBJCOPY_add_gnu_debuglink);918 // The gnu_debuglink's target is expected to not change or else its CRC would919 // become invalidated and get rejected. We can avoid recalculating the920 // checksum for every target file inside an archive by precomputing the CRC921 // here. This prevents a significant amount of I/O.922 if (!Config.AddGnuDebugLink.empty()) {923 auto DebugOrErr = MemoryBuffer::getFile(Config.AddGnuDebugLink);924 if (!DebugOrErr)925 return createFileError(Config.AddGnuDebugLink, DebugOrErr.getError());926 auto Debug = std::move(*DebugOrErr);927 Config.GnuDebugLinkCRC32 =928 llvm::crc32(arrayRefFromStringRef(Debug->getBuffer()));929 }930 Config.SplitDWO = InputArgs.getLastArgValue(OBJCOPY_split_dwo);931 932 Config.SymbolsPrefix = InputArgs.getLastArgValue(OBJCOPY_prefix_symbols);933 Config.SymbolsPrefixRemove =934 InputArgs.getLastArgValue(OBJCOPY_remove_symbol_prefix);935 936 Config.AllocSectionsPrefix =937 InputArgs.getLastArgValue(OBJCOPY_prefix_alloc_sections);938 if (auto Arg = InputArgs.getLastArg(OBJCOPY_extract_partition))939 Config.ExtractPartition = Arg->getValue();940 941 if (const auto *A = InputArgs.getLastArg(OBJCOPY_gap_fill)) {942 if (Config.OutputFormat != FileFormat::Binary)943 return createStringError(944 errc::invalid_argument,945 "'--gap-fill' is only supported for binary output");946 ErrorOr<uint64_t> Val = getAsInteger<uint64_t>(A->getValue());947 if (!Val)948 return createStringError(Val.getError(), "--gap-fill: bad number: %s",949 A->getValue());950 uint8_t ByteVal = Val.get();951 if (ByteVal != Val.get())952 return createStringError(std::errc::value_too_large,953 "gap-fill value %s is out of range (0 to 0xff)",954 A->getValue());955 Config.GapFill = ByteVal;956 }957 958 if (const auto *A = InputArgs.getLastArg(OBJCOPY_pad_to)) {959 if (Config.OutputFormat != FileFormat::Binary)960 return createStringError(961 errc::invalid_argument,962 "'--pad-to' is only supported for binary output");963 ErrorOr<uint64_t> Addr = getAsInteger<uint64_t>(A->getValue());964 if (!Addr)965 return createStringError(Addr.getError(), "--pad-to: bad number: %s",966 A->getValue());967 Config.PadTo = *Addr;968 }969 970 if (const auto *Arg = InputArgs.getLastArg(OBJCOPY_change_section_lma)) {971 Expected<int64_t> LMAValue =972 parseChangeSectionLMA(Arg->getValue(), Arg->getSpelling());973 if (!LMAValue)974 return LMAValue.takeError();975 Config.ChangeSectionLMAValAll = *LMAValue;976 }977 978 for (auto *Arg : InputArgs.filtered(OBJCOPY_change_section_address)) {979 Expected<SectionPatternAddressUpdate> AddressUpdate =980 parseChangeSectionAddr(Arg->getValue(), Arg->getSpelling(),981 SectionMatchStyle, ErrorCallback);982 if (!AddressUpdate)983 return AddressUpdate.takeError();984 Config.ChangeSectionAddress.push_back(*AddressUpdate);985 }986 987 for (auto *Arg : InputArgs.filtered(OBJCOPY_redefine_symbol)) {988 if (!StringRef(Arg->getValue()).contains('='))989 return createStringError(errc::invalid_argument,990 "bad format for --redefine-sym");991 auto Old2New = StringRef(Arg->getValue()).split('=');992 if (!Config.SymbolsToRename.insert(Old2New).second)993 return createStringError(errc::invalid_argument,994 "multiple redefinition of symbol '%s'",995 Old2New.first.str().c_str());996 }997 998 for (auto *Arg : InputArgs.filtered(OBJCOPY_redefine_symbols))999 if (Error E = addSymbolsToRenameFromFile(Config.SymbolsToRename, DC.Alloc,1000 Arg->getValue()))1001 return std::move(E);1002 1003 for (auto *Arg : InputArgs.filtered(OBJCOPY_rename_section)) {1004 Expected<SectionRename> SR =1005 parseRenameSectionValue(StringRef(Arg->getValue()));1006 if (!SR)1007 return SR.takeError();1008 if (!Config.SectionsToRename.try_emplace(SR->OriginalName, *SR).second)1009 return createStringError(errc::invalid_argument,1010 "multiple renames of section '%s'",1011 SR->OriginalName.str().c_str());1012 }1013 for (auto *Arg : InputArgs.filtered(OBJCOPY_set_section_alignment)) {1014 Expected<std::pair<StringRef, uint64_t>> NameAndAlign =1015 parseSetSectionAttribute("--set-section-alignment", Arg->getValue());1016 if (!NameAndAlign)1017 return NameAndAlign.takeError();1018 Config.SetSectionAlignment[NameAndAlign->first] = NameAndAlign->second;1019 }1020 for (auto *Arg : InputArgs.filtered(OBJCOPY_set_section_flags)) {1021 Expected<SectionFlagsUpdate> SFU =1022 parseSetSectionFlagValue(Arg->getValue());1023 if (!SFU)1024 return SFU.takeError();1025 if (!Config.SetSectionFlags.try_emplace(SFU->Name, *SFU).second)1026 return createStringError(1027 errc::invalid_argument,1028 "--set-section-flags set multiple times for section '%s'",1029 SFU->Name.str().c_str());1030 }1031 for (auto *Arg : InputArgs.filtered(OBJCOPY_set_section_type)) {1032 Expected<std::pair<StringRef, uint64_t>> NameAndType =1033 parseSetSectionAttribute("--set-section-type", Arg->getValue());1034 if (!NameAndType)1035 return NameAndType.takeError();1036 Config.SetSectionType[NameAndType->first] = NameAndType->second;1037 }1038 // Prohibit combinations of --set-section-{flags,type} when the section name1039 // is used as the destination of a --rename-section.1040 for (const auto &E : Config.SectionsToRename) {1041 const SectionRename &SR = E.second;1042 auto Err = [&](const char *Option) {1043 return createStringError(1044 errc::invalid_argument,1045 "--set-section-%s=%s conflicts with --rename-section=%s=%s", Option,1046 SR.NewName.str().c_str(), SR.OriginalName.str().c_str(),1047 SR.NewName.str().c_str());1048 };1049 if (Config.SetSectionFlags.count(SR.NewName))1050 return Err("flags");1051 if (Config.SetSectionType.count(SR.NewName))1052 return Err("type");1053 }1054 1055 for (auto *Arg : InputArgs.filtered(OBJCOPY_remove_section))1056 if (Error E = Config.ToRemove.addMatcher(NameOrPattern::create(1057 Arg->getValue(), SectionMatchStyle, ErrorCallback)))1058 return std::move(E);1059 for (auto *Arg : InputArgs.filtered(OBJCOPY_keep_section))1060 if (Error E = Config.KeepSection.addMatcher(NameOrPattern::create(1061 Arg->getValue(), SectionMatchStyle, ErrorCallback)))1062 return std::move(E);1063 for (auto *Arg : InputArgs.filtered(OBJCOPY_only_section))1064 if (Error E = Config.OnlySection.addMatcher(NameOrPattern::create(1065 Arg->getValue(), SectionMatchStyle, ErrorCallback)))1066 return std::move(E);1067 for (auto *Arg : InputArgs.filtered(OBJCOPY_add_section)) {1068 if (Error Err = loadNewSectionData(Arg->getValue(), "--add-section",1069 Config.AddSection))1070 return std::move(Err);1071 }1072 for (auto *Arg : InputArgs.filtered(OBJCOPY_update_section)) {1073 if (Error Err = loadNewSectionData(Arg->getValue(), "--update-section",1074 Config.UpdateSection))1075 return std::move(Err);1076 }1077 for (auto *Arg : InputArgs.filtered(OBJCOPY_dump_section)) {1078 StringRef Value(Arg->getValue());1079 if (Value.split('=').second.empty())1080 return createStringError(1081 errc::invalid_argument,1082 "bad format for --dump-section, expected section=file");1083 Config.DumpSection.push_back(Value);1084 }1085 for (auto *Arg : InputArgs.filtered(OBJCOPY_extract_section)) {1086 StringRef Value(Arg->getValue());1087 if (Value.split('=').second.empty())1088 return createStringError(1089 errc::invalid_argument,1090 "bad format for --extract-section, expected section=file");1091 Config.ExtractSection.push_back(Value);1092 }1093 Config.StripAll = InputArgs.hasArg(OBJCOPY_strip_all);1094 Config.StripAllGNU = InputArgs.hasArg(OBJCOPY_strip_all_gnu);1095 Config.StripDebug = InputArgs.hasArg(OBJCOPY_strip_debug);1096 Config.StripDWO = InputArgs.hasArg(OBJCOPY_strip_dwo);1097 Config.StripSections = InputArgs.hasArg(OBJCOPY_strip_sections);1098 Config.StripNonAlloc = InputArgs.hasArg(OBJCOPY_strip_non_alloc);1099 Config.StripUnneeded = InputArgs.hasArg(OBJCOPY_strip_unneeded);1100 Config.ExtractDWO = InputArgs.hasArg(OBJCOPY_extract_dwo);1101 Config.ExtractMainPartition =1102 InputArgs.hasArg(OBJCOPY_extract_main_partition);1103 ELFConfig.LocalizeHidden = InputArgs.hasArg(OBJCOPY_localize_hidden);1104 Config.Weaken = InputArgs.hasArg(OBJCOPY_weaken);1105 if (auto *Arg =1106 InputArgs.getLastArg(OBJCOPY_discard_all, OBJCOPY_discard_locals)) {1107 Config.DiscardMode = Arg->getOption().matches(OBJCOPY_discard_all)1108 ? DiscardType::All1109 : DiscardType::Locals;1110 }1111 1112 ELFConfig.VerifyNoteSections = InputArgs.hasFlag(1113 OBJCOPY_verify_note_sections, OBJCOPY_no_verify_note_sections, true);1114 1115 Config.OnlyKeepDebug = InputArgs.hasArg(OBJCOPY_only_keep_debug);1116 ELFConfig.KeepFileSymbols = InputArgs.hasArg(OBJCOPY_keep_file_symbols);1117 MachOConfig.KeepUndefined = InputArgs.hasArg(OBJCOPY_keep_undefined);1118 Config.DecompressDebugSections =1119 InputArgs.hasArg(OBJCOPY_decompress_debug_sections);1120 if (Config.DiscardMode == DiscardType::All) {1121 Config.StripDebug = true;1122 ELFConfig.KeepFileSymbols = true;1123 }1124 for (auto *Arg : InputArgs.filtered(OBJCOPY_localize_symbol))1125 if (Error E = Config.SymbolsToLocalize.addMatcher(NameOrPattern::create(1126 Arg->getValue(), SymbolMatchStyle, ErrorCallback)))1127 return std::move(E);1128 for (auto *Arg : InputArgs.filtered(OBJCOPY_localize_symbols))1129 if (Error E = addSymbolsFromFile(Config.SymbolsToLocalize, DC.Alloc,1130 Arg->getValue(), SymbolMatchStyle,1131 ErrorCallback))1132 return std::move(E);1133 for (auto *Arg : InputArgs.filtered(OBJCOPY_keep_global_symbol))1134 if (Error E = Config.SymbolsToKeepGlobal.addMatcher(NameOrPattern::create(1135 Arg->getValue(), SymbolMatchStyle, ErrorCallback)))1136 return std::move(E);1137 for (auto *Arg : InputArgs.filtered(OBJCOPY_keep_global_symbols))1138 if (Error E = addSymbolsFromFile(Config.SymbolsToKeepGlobal, DC.Alloc,1139 Arg->getValue(), SymbolMatchStyle,1140 ErrorCallback))1141 return std::move(E);1142 for (auto *Arg : InputArgs.filtered(OBJCOPY_globalize_symbol))1143 if (Error E = Config.SymbolsToGlobalize.addMatcher(NameOrPattern::create(1144 Arg->getValue(), SymbolMatchStyle, ErrorCallback)))1145 return std::move(E);1146 for (auto *Arg : InputArgs.filtered(OBJCOPY_globalize_symbols))1147 if (Error E = addSymbolsFromFile(Config.SymbolsToGlobalize, DC.Alloc,1148 Arg->getValue(), SymbolMatchStyle,1149 ErrorCallback))1150 return std::move(E);1151 for (auto *Arg : InputArgs.filtered(OBJCOPY_weaken_symbol))1152 if (Error E = Config.SymbolsToWeaken.addMatcher(NameOrPattern::create(1153 Arg->getValue(), SymbolMatchStyle, ErrorCallback)))1154 return std::move(E);1155 for (auto *Arg : InputArgs.filtered(OBJCOPY_weaken_symbols))1156 if (Error E = addSymbolsFromFile(Config.SymbolsToWeaken, DC.Alloc,1157 Arg->getValue(), SymbolMatchStyle,1158 ErrorCallback))1159 return std::move(E);1160 for (auto *Arg : InputArgs.filtered(OBJCOPY_strip_symbol))1161 if (Error E = Config.SymbolsToRemove.addMatcher(NameOrPattern::create(1162 Arg->getValue(), SymbolMatchStyle, ErrorCallback)))1163 return std::move(E);1164 for (auto *Arg : InputArgs.filtered(OBJCOPY_strip_symbols))1165 if (Error E = addSymbolsFromFile(Config.SymbolsToRemove, DC.Alloc,1166 Arg->getValue(), SymbolMatchStyle,1167 ErrorCallback))1168 return std::move(E);1169 for (auto *Arg : InputArgs.filtered(OBJCOPY_strip_unneeded_symbol))1170 if (Error E =1171 Config.UnneededSymbolsToRemove.addMatcher(NameOrPattern::create(1172 Arg->getValue(), SymbolMatchStyle, ErrorCallback)))1173 return std::move(E);1174 for (auto *Arg : InputArgs.filtered(OBJCOPY_strip_unneeded_symbols))1175 if (Error E = addSymbolsFromFile(Config.UnneededSymbolsToRemove, DC.Alloc,1176 Arg->getValue(), SymbolMatchStyle,1177 ErrorCallback))1178 return std::move(E);1179 for (auto *Arg : InputArgs.filtered(OBJCOPY_keep_symbol))1180 if (Error E = Config.SymbolsToKeep.addMatcher(NameOrPattern::create(1181 Arg->getValue(), SymbolMatchStyle, ErrorCallback)))1182 return std::move(E);1183 for (auto *Arg : InputArgs.filtered(OBJCOPY_keep_symbols))1184 if (Error E =1185 addSymbolsFromFile(Config.SymbolsToKeep, DC.Alloc, Arg->getValue(),1186 SymbolMatchStyle, ErrorCallback))1187 return std::move(E);1188 for (auto *Arg : InputArgs.filtered(OBJCOPY_skip_symbol))1189 if (Error E = Config.SymbolsToSkip.addMatcher(NameOrPattern::create(1190 Arg->getValue(), SymbolMatchStyle, ErrorCallback)))1191 return std::move(E);1192 for (auto *Arg : InputArgs.filtered(OBJCOPY_skip_symbols))1193 if (Error E =1194 addSymbolsFromFile(Config.SymbolsToSkip, DC.Alloc, Arg->getValue(),1195 SymbolMatchStyle, ErrorCallback))1196 return std::move(E);1197 for (auto *Arg : InputArgs.filtered(OBJCOPY_add_symbol)) {1198 Expected<NewSymbolInfo> SymInfo = parseNewSymbolInfo(Arg->getValue());1199 if (!SymInfo)1200 return SymInfo.takeError();1201 1202 Config.SymbolsToAdd.push_back(*SymInfo);1203 }1204 for (auto *Arg : InputArgs.filtered(OBJCOPY_set_symbol_visibility)) {1205 if (!StringRef(Arg->getValue()).contains('='))1206 return createStringError(errc::invalid_argument,1207 "bad format for --set-symbol-visibility");1208 auto [Sym, Visibility] = StringRef(Arg->getValue()).split('=');1209 Expected<uint8_t> Type = parseVisibilityType(Visibility);1210 if (!Type)1211 return Type.takeError();1212 ELFConfig.SymbolsToSetVisibility.emplace_back(NameMatcher(), *Type);1213 if (Error E = ELFConfig.SymbolsToSetVisibility.back().first.addMatcher(1214 NameOrPattern::create(Sym, SymbolMatchStyle, ErrorCallback)))1215 return std::move(E);1216 }1217 for (auto *Arg : InputArgs.filtered(OBJCOPY_set_symbols_visibility)) {1218 if (!StringRef(Arg->getValue()).contains('='))1219 return createStringError(errc::invalid_argument,1220 "bad format for --set-symbols-visibility");1221 auto [File, Visibility] = StringRef(Arg->getValue()).split('=');1222 Expected<uint8_t> Type = parseVisibilityType(Visibility);1223 if (!Type)1224 return Type.takeError();1225 ELFConfig.SymbolsToSetVisibility.emplace_back(NameMatcher(), *Type);1226 if (Error E =1227 addSymbolsFromFile(ELFConfig.SymbolsToSetVisibility.back().first,1228 DC.Alloc, File, SymbolMatchStyle, ErrorCallback))1229 return std::move(E);1230 }1231 1232 ELFConfig.AllowBrokenLinks = InputArgs.hasArg(OBJCOPY_allow_broken_links);1233 1234 Config.DeterministicArchives = InputArgs.hasFlag(1235 OBJCOPY_enable_deterministic_archives,1236 OBJCOPY_disable_deterministic_archives, /*default=*/true);1237 1238 Config.PreserveDates = InputArgs.hasArg(OBJCOPY_preserve_dates);1239 1240 if (Config.PreserveDates &&1241 (Config.OutputFilename == "-" || Config.InputFilename == "-"))1242 return createStringError(errc::invalid_argument,1243 "--preserve-dates requires a file");1244 1245 for (auto *Arg : InputArgs)1246 if (Arg->getOption().matches(OBJCOPY_set_start)) {1247 auto EAddr = getAsInteger<uint64_t>(Arg->getValue());1248 if (!EAddr)1249 return createStringError(1250 EAddr.getError(), "bad entry point address: '%s'", Arg->getValue());1251 1252 ELFConfig.EntryExpr = [EAddr](uint64_t) { return *EAddr; };1253 } else if (Arg->getOption().matches(OBJCOPY_change_start)) {1254 auto EIncr = getAsInteger<int64_t>(Arg->getValue());1255 if (!EIncr)1256 return createStringError(EIncr.getError(),1257 "bad entry point increment: '%s'",1258 Arg->getValue());1259 auto Expr = ELFConfig.EntryExpr ? std::move(ELFConfig.EntryExpr)1260 : [](uint64_t A) { return A; };1261 ELFConfig.EntryExpr = [Expr, EIncr](uint64_t EAddr) {1262 return Expr(EAddr) + *EIncr;1263 };1264 }1265 1266 for (auto *Arg : InputArgs.filtered(OBJCOPY_remove_note)) {1267 Expected<RemoveNoteInfo> NoteInfo = parseRemoveNoteInfo(Arg->getValue());1268 if (!NoteInfo)1269 return NoteInfo.takeError();1270 1271 ELFConfig.NotesToRemove.push_back(*NoteInfo);1272 }1273 1274 if (!ELFConfig.NotesToRemove.empty()) {1275 if (!Config.ToRemove.empty())1276 return createStringError(1277 errc::invalid_argument,1278 "cannot specify both --remove-note and --remove-section");1279 if (!Config.AddSection.empty())1280 return createStringError(1281 errc::invalid_argument,1282 "cannot specify both --remove-note and --add-section");1283 if (!Config.UpdateSection.empty())1284 return createStringError(1285 errc::invalid_argument,1286 "cannot specify both --remove-note and --update-section");1287 }1288 1289 if (Config.DecompressDebugSections &&1290 Config.CompressionType != DebugCompressionType::None) {1291 return createStringError(1292 errc::invalid_argument,1293 "cannot specify both --compress-debug-sections and "1294 "--decompress-debug-sections");1295 }1296 1297 if (Config.ExtractPartition && Config.ExtractMainPartition)1298 return createStringError(errc::invalid_argument,1299 "cannot specify --extract-partition together with "1300 "--extract-main-partition");1301 1302 DC.CopyConfigs.push_back(std::move(ConfigMgr));1303 return std::move(DC);1304}1305 1306// parseInstallNameToolOptions returns the config and sets the input arguments.1307// If a help flag is set then parseInstallNameToolOptions will print the help1308// messege and exit.1309Expected<DriverConfig>1310objcopy::parseInstallNameToolOptions(ArrayRef<const char *> ArgsArr) {1311 DriverConfig DC;1312 ConfigManager ConfigMgr;1313 CommonConfig &Config = ConfigMgr.Common;1314 MachOConfig &MachOConfig = ConfigMgr.MachO;1315 InstallNameToolOptTable T;1316 unsigned MissingArgumentIndex, MissingArgumentCount;1317 llvm::opt::InputArgList InputArgs =1318 T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);1319 1320 if (MissingArgumentCount)1321 return createStringError(1322 errc::invalid_argument,1323 "missing argument to " +1324 StringRef(InputArgs.getArgString(MissingArgumentIndex)) +1325 " option");1326 1327 if (InputArgs.size() == 0) {1328 printHelp(T, errs(), ToolType::InstallNameTool);1329 exit(1);1330 }1331 1332 if (InputArgs.hasArg(INSTALL_NAME_TOOL_help)) {1333 printHelp(T, outs(), ToolType::InstallNameTool);1334 exit(0);1335 }1336 1337 if (InputArgs.hasArg(INSTALL_NAME_TOOL_version)) {1338 outs() << "llvm-install-name-tool, compatible with cctools "1339 "install_name_tool\n";1340 cl::PrintVersionMessage();1341 exit(0);1342 }1343 1344 for (auto *Arg : InputArgs.filtered(INSTALL_NAME_TOOL_add_rpath))1345 MachOConfig.RPathToAdd.push_back(Arg->getValue());1346 1347 for (auto *Arg : InputArgs.filtered(INSTALL_NAME_TOOL_prepend_rpath))1348 MachOConfig.RPathToPrepend.push_back(Arg->getValue());1349 1350 for (auto *Arg : InputArgs.filtered(INSTALL_NAME_TOOL_delete_rpath)) {1351 StringRef RPath = Arg->getValue();1352 1353 // Cannot add and delete the same rpath at the same time.1354 if (is_contained(MachOConfig.RPathToAdd, RPath))1355 return createStringError(1356 errc::invalid_argument,1357 "cannot specify both -add_rpath '%s' and -delete_rpath '%s'",1358 RPath.str().c_str(), RPath.str().c_str());1359 if (is_contained(MachOConfig.RPathToPrepend, RPath))1360 return createStringError(1361 errc::invalid_argument,1362 "cannot specify both -prepend_rpath '%s' and -delete_rpath '%s'",1363 RPath.str().c_str(), RPath.str().c_str());1364 1365 MachOConfig.RPathsToRemove.insert(RPath);1366 }1367 1368 for (auto *Arg : InputArgs.filtered(INSTALL_NAME_TOOL_rpath)) {1369 StringRef Old = Arg->getValue(0);1370 StringRef New = Arg->getValue(1);1371 1372 auto Match = [=](StringRef RPath) { return RPath == Old || RPath == New; };1373 1374 // Cannot specify duplicate -rpath entries1375 auto It1 = find_if(1376 MachOConfig.RPathsToUpdate,1377 [&Match](const DenseMap<StringRef, StringRef>::value_type &OldNew) {1378 return Match(OldNew.getFirst()) || Match(OldNew.getSecond());1379 });1380 if (It1 != MachOConfig.RPathsToUpdate.end())1381 return createStringError(errc::invalid_argument,1382 "cannot specify both -rpath '" +1383 It1->getFirst() + "' '" + It1->getSecond() +1384 "' and -rpath '" + Old + "' '" + New + "'");1385 1386 // Cannot specify the same rpath under both -delete_rpath and -rpath1387 auto It2 = find_if(MachOConfig.RPathsToRemove, Match);1388 if (It2 != MachOConfig.RPathsToRemove.end())1389 return createStringError(errc::invalid_argument,1390 "cannot specify both -delete_rpath '" + *It2 +1391 "' and -rpath '" + Old + "' '" + New + "'");1392 1393 // Cannot specify the same rpath under both -add_rpath and -rpath1394 auto It3 = find_if(MachOConfig.RPathToAdd, Match);1395 if (It3 != MachOConfig.RPathToAdd.end())1396 return createStringError(errc::invalid_argument,1397 "cannot specify both -add_rpath '" + *It3 +1398 "' and -rpath '" + Old + "' '" + New + "'");1399 1400 // Cannot specify the same rpath under both -prepend_rpath and -rpath.1401 auto It4 = find_if(MachOConfig.RPathToPrepend, Match);1402 if (It4 != MachOConfig.RPathToPrepend.end())1403 return createStringError(errc::invalid_argument,1404 "cannot specify both -prepend_rpath '" + *It4 +1405 "' and -rpath '" + Old + "' '" + New + "'");1406 1407 MachOConfig.RPathsToUpdate.insert({Old, New});1408 }1409 1410 if (auto *Arg = InputArgs.getLastArg(INSTALL_NAME_TOOL_id)) {1411 MachOConfig.SharedLibId = Arg->getValue();1412 if (MachOConfig.SharedLibId->empty())1413 return createStringError(errc::invalid_argument,1414 "cannot specify an empty id");1415 }1416 1417 for (auto *Arg : InputArgs.filtered(INSTALL_NAME_TOOL_change))1418 MachOConfig.InstallNamesToUpdate.insert(1419 {Arg->getValue(0), Arg->getValue(1)});1420 1421 MachOConfig.RemoveAllRpaths =1422 InputArgs.hasArg(INSTALL_NAME_TOOL_delete_all_rpaths);1423 1424 SmallVector<StringRef, 2> Positional;1425 for (auto *Arg : InputArgs.filtered(INSTALL_NAME_TOOL_UNKNOWN))1426 return createStringError(errc::invalid_argument, "unknown argument '%s'",1427 Arg->getAsString(InputArgs).c_str());1428 for (auto *Arg : InputArgs.filtered(INSTALL_NAME_TOOL_INPUT))1429 Positional.push_back(Arg->getValue());1430 if (Positional.empty())1431 return createStringError(errc::invalid_argument, "no input file specified");1432 if (Positional.size() > 1)1433 return createStringError(1434 errc::invalid_argument,1435 "llvm-install-name-tool expects a single input file");1436 Config.InputFilename = Positional[0];1437 Config.OutputFilename = Positional[0];1438 1439 Expected<OwningBinary<Binary>> BinaryOrErr =1440 createBinary(Config.InputFilename);1441 if (!BinaryOrErr)1442 return createFileError(Config.InputFilename, BinaryOrErr.takeError());1443 auto *Binary = (*BinaryOrErr).getBinary();1444 if (!Binary->isMachO() && !Binary->isMachOUniversalBinary())1445 return createStringError(errc::invalid_argument,1446 "input file: %s is not a Mach-O file",1447 Config.InputFilename.str().c_str());1448 1449 DC.CopyConfigs.push_back(std::move(ConfigMgr));1450 return std::move(DC);1451}1452 1453Expected<DriverConfig>1454objcopy::parseBitcodeStripOptions(ArrayRef<const char *> ArgsArr,1455 function_ref<Error(Error)> ErrorCallback) {1456 DriverConfig DC;1457 ConfigManager ConfigMgr;1458 CommonConfig &Config = ConfigMgr.Common;1459 MachOConfig &MachOConfig = ConfigMgr.MachO;1460 BitcodeStripOptTable T;1461 unsigned MissingArgumentIndex, MissingArgumentCount;1462 opt::InputArgList InputArgs =1463 T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);1464 1465 if (InputArgs.size() == 0) {1466 printHelp(T, errs(), ToolType::BitcodeStrip);1467 exit(1);1468 }1469 1470 if (InputArgs.hasArg(BITCODE_STRIP_help)) {1471 printHelp(T, outs(), ToolType::BitcodeStrip);1472 exit(0);1473 }1474 1475 if (InputArgs.hasArg(BITCODE_STRIP_version)) {1476 outs() << "llvm-bitcode-strip, compatible with cctools "1477 "bitcode_strip\n";1478 cl::PrintVersionMessage();1479 exit(0);1480 }1481 1482 for (auto *Arg : InputArgs.filtered(BITCODE_STRIP_UNKNOWN))1483 return createStringError(errc::invalid_argument, "unknown argument '%s'",1484 Arg->getAsString(InputArgs).c_str());1485 1486 SmallVector<StringRef, 2> Positional;1487 for (auto *Arg : InputArgs.filtered(BITCODE_STRIP_INPUT))1488 Positional.push_back(Arg->getValue());1489 if (Positional.size() > 1)1490 return createStringError(errc::invalid_argument,1491 "llvm-bitcode-strip expects a single input file");1492 assert(!Positional.empty());1493 Config.InputFilename = Positional[0];1494 1495 if (!InputArgs.hasArg(BITCODE_STRIP_output)) {1496 return createStringError(errc::invalid_argument,1497 "-o is a required argument");1498 }1499 Config.OutputFilename = InputArgs.getLastArgValue(BITCODE_STRIP_output);1500 1501 if (!InputArgs.hasArg(BITCODE_STRIP_remove))1502 return createStringError(errc::invalid_argument, "no action specified");1503 1504 // We only support -r for now, which removes all bitcode sections and1505 // the __LLVM segment if it's now empty.1506 cantFail(Config.ToRemove.addMatcher(NameOrPattern::create(1507 "__LLVM,__asm", MatchStyle::Literal, ErrorCallback)));1508 cantFail(Config.ToRemove.addMatcher(NameOrPattern::create(1509 "__LLVM,__bitcode", MatchStyle::Literal, ErrorCallback)));1510 cantFail(Config.ToRemove.addMatcher(NameOrPattern::create(1511 "__LLVM,__bundle", MatchStyle::Literal, ErrorCallback)));1512 cantFail(Config.ToRemove.addMatcher(NameOrPattern::create(1513 "__LLVM,__cmdline", MatchStyle::Literal, ErrorCallback)));1514 cantFail(Config.ToRemove.addMatcher(NameOrPattern::create(1515 "__LLVM,__swift_cmdline", MatchStyle::Literal, ErrorCallback)));1516 MachOConfig.EmptySegmentsToRemove.insert("__LLVM");1517 1518 DC.CopyConfigs.push_back(std::move(ConfigMgr));1519 return std::move(DC);1520}1521 1522// parseStripOptions returns the config and sets the input arguments. If a1523// help flag is set then parseStripOptions will print the help messege and1524// exit.1525Expected<DriverConfig>1526objcopy::parseStripOptions(ArrayRef<const char *> RawArgsArr,1527 function_ref<Error(Error)> ErrorCallback) {1528 const char *const *DashDash =1529 llvm::find_if(RawArgsArr, [](StringRef Str) { return Str == "--"; });1530 ArrayRef<const char *> ArgsArr = ArrayRef(RawArgsArr.begin(), DashDash);1531 if (DashDash != RawArgsArr.end())1532 DashDash = std::next(DashDash);1533 1534 StripOptTable T;1535 unsigned MissingArgumentIndex, MissingArgumentCount;1536 llvm::opt::InputArgList InputArgs =1537 T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);1538 1539 if (InputArgs.size() == 0 && DashDash == RawArgsArr.end()) {1540 printHelp(T, errs(), ToolType::Strip);1541 exit(1);1542 }1543 1544 if (InputArgs.hasArg(STRIP_help)) {1545 printHelp(T, outs(), ToolType::Strip);1546 exit(0);1547 }1548 1549 if (InputArgs.hasArg(STRIP_version)) {1550 outs() << "llvm-strip, compatible with GNU strip\n";1551 cl::PrintVersionMessage();1552 exit(0);1553 }1554 1555 SmallVector<StringRef, 2> Positional;1556 for (auto *Arg : InputArgs.filtered(STRIP_UNKNOWN))1557 return createStringError(errc::invalid_argument, "unknown argument '%s'",1558 Arg->getAsString(InputArgs).c_str());1559 for (auto *Arg : InputArgs.filtered(STRIP_INPUT))1560 Positional.push_back(Arg->getValue());1561 std::copy(DashDash, RawArgsArr.end(), std::back_inserter(Positional));1562 1563 if (Positional.empty())1564 return createStringError(errc::invalid_argument, "no input file specified");1565 1566 if (Positional.size() > 1 && InputArgs.hasArg(STRIP_output))1567 return createStringError(1568 errc::invalid_argument,1569 "multiple input files cannot be used in combination with -o");1570 1571 ConfigManager ConfigMgr;1572 CommonConfig &Config = ConfigMgr.Common;1573 ELFConfig &ELFConfig = ConfigMgr.ELF;1574 MachOConfig &MachOConfig = ConfigMgr.MachO;1575 1576 if (InputArgs.hasArg(STRIP_regex) && InputArgs.hasArg(STRIP_wildcard))1577 return createStringError(errc::invalid_argument,1578 "--regex and --wildcard are incompatible");1579 MatchStyle SectionMatchStyle =1580 InputArgs.hasArg(STRIP_regex) ? MatchStyle::Regex : MatchStyle::Wildcard;1581 MatchStyle SymbolMatchStyle1582 = InputArgs.hasArg(STRIP_regex) ? MatchStyle::Regex1583 : InputArgs.hasArg(STRIP_wildcard) ? MatchStyle::Wildcard1584 : MatchStyle::Literal;1585 ELFConfig.AllowBrokenLinks = InputArgs.hasArg(STRIP_allow_broken_links);1586 Config.StripDebug = InputArgs.hasArg(STRIP_strip_debug);1587 1588 if (auto *Arg = InputArgs.getLastArg(STRIP_discard_all, STRIP_discard_locals))1589 Config.DiscardMode = Arg->getOption().matches(STRIP_discard_all)1590 ? DiscardType::All1591 : DiscardType::Locals;1592 Config.StripSections = InputArgs.hasArg(STRIP_strip_sections);1593 Config.StripUnneeded = InputArgs.hasArg(STRIP_strip_unneeded);1594 if (auto Arg = InputArgs.getLastArg(STRIP_strip_all, STRIP_no_strip_all))1595 Config.StripAll = Arg->getOption().getID() == STRIP_strip_all;1596 Config.StripAllGNU = InputArgs.hasArg(STRIP_strip_all_gnu);1597 MachOConfig.StripSwiftSymbols = InputArgs.hasArg(STRIP_strip_swift_symbols);1598 Config.OnlyKeepDebug = InputArgs.hasArg(STRIP_only_keep_debug);1599 ELFConfig.KeepFileSymbols = InputArgs.hasArg(STRIP_keep_file_symbols);1600 MachOConfig.KeepUndefined = InputArgs.hasArg(STRIP_keep_undefined);1601 1602 for (auto *Arg : InputArgs.filtered(STRIP_keep_section))1603 if (Error E = Config.KeepSection.addMatcher(NameOrPattern::create(1604 Arg->getValue(), SectionMatchStyle, ErrorCallback)))1605 return std::move(E);1606 1607 for (auto *Arg : InputArgs.filtered(STRIP_remove_section))1608 if (Error E = Config.ToRemove.addMatcher(NameOrPattern::create(1609 Arg->getValue(), SectionMatchStyle, ErrorCallback)))1610 return std::move(E);1611 1612 for (auto *Arg : InputArgs.filtered(STRIP_strip_symbol))1613 if (Error E = Config.SymbolsToRemove.addMatcher(NameOrPattern::create(1614 Arg->getValue(), SymbolMatchStyle, ErrorCallback)))1615 return std::move(E);1616 1617 for (auto *Arg : InputArgs.filtered(STRIP_keep_symbol))1618 if (Error E = Config.SymbolsToKeep.addMatcher(NameOrPattern::create(1619 Arg->getValue(), SymbolMatchStyle, ErrorCallback)))1620 return std::move(E);1621 1622 if (!InputArgs.hasArg(STRIP_no_strip_all) && !Config.StripDebug &&1623 !Config.OnlyKeepDebug && !Config.StripUnneeded &&1624 Config.DiscardMode == DiscardType::None && !Config.StripAllGNU &&1625 Config.SymbolsToRemove.empty())1626 Config.StripAll = true;1627 1628 if (Config.DiscardMode == DiscardType::All) {1629 Config.StripDebug = true;1630 ELFConfig.KeepFileSymbols = true;1631 }1632 1633 Config.DeterministicArchives =1634 InputArgs.hasFlag(STRIP_enable_deterministic_archives,1635 STRIP_disable_deterministic_archives, /*default=*/true);1636 1637 Config.PreserveDates = InputArgs.hasArg(STRIP_preserve_dates);1638 Config.InputFormat = FileFormat::Unspecified;1639 Config.OutputFormat = FileFormat::Unspecified;1640 1641 DriverConfig DC;1642 if (Positional.size() == 1) {1643 Config.InputFilename = Positional[0];1644 Config.OutputFilename =1645 InputArgs.getLastArgValue(STRIP_output, Positional[0]);1646 DC.CopyConfigs.push_back(std::move(ConfigMgr));1647 } else {1648 StringMap<unsigned> InputFiles;1649 for (StringRef Filename : Positional) {1650 if (InputFiles[Filename]++ == 1) {1651 if (Filename == "-")1652 return createStringError(1653 errc::invalid_argument,1654 "cannot specify '-' as an input file more than once");1655 if (Error E = ErrorCallback(createStringError(1656 errc::invalid_argument, "'%s' was already specified",1657 Filename.str().c_str())))1658 return std::move(E);1659 }1660 Config.InputFilename = Filename;1661 Config.OutputFilename = Filename;1662 DC.CopyConfigs.push_back(ConfigMgr);1663 }1664 }1665 1666 if (Config.PreserveDates && (is_contained(Positional, "-") ||1667 InputArgs.getLastArgValue(STRIP_output) == "-"))1668 return createStringError(errc::invalid_argument,1669 "--preserve-dates requires a file");1670 1671 return std::move(DC);1672}1673