159191Skris//===- ObjcopyOptions.cpp -------------------------------------------------===// 259191Skris// 359191Skris// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 459191Skris// See https://llvm.org/LICENSE.txt for license information. 559191Skris// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 659191Skris// 759191Skris//===----------------------------------------------------------------------===// 859191Skris 959191Skris#include "ObjcopyOptions.h" 1059191Skris#include "llvm/ADT/SmallVector.h" 11238405Sjkim#include "llvm/ADT/StringExtras.h" 1259191Skris#include "llvm/ADT/StringRef.h" 1359191Skris#include "llvm/BinaryFormat/COFF.h" 1459191Skris#include "llvm/ObjCopy/CommonConfig.h" 1559191Skris#include "llvm/ObjCopy/ConfigManager.h" 1659191Skris#include "llvm/ObjCopy/MachO/MachOConfig.h" 1759191Skris#include "llvm/Option/Arg.h" 1859191Skris#include "llvm/Option/ArgList.h" 19238405Sjkim#include "llvm/Support/CRC.h" 2059191Skris#include "llvm/Support/CommandLine.h" 2159191Skris#include "llvm/Support/Compression.h" 2259191Skris#include "llvm/Support/Errc.h" 2359191Skris#include "llvm/Support/Error.h" 2459191Skris#include "llvm/Support/MemoryBuffer.h" 2559191Skris 2659191Skrisusing namespace llvm; 2759191Skrisusing namespace llvm::objcopy; 2859191Skrisusing namespace llvm::opt; 29238405Sjkim 3068651Skrisnamespace { 3168651Skrisenum ObjcopyID { 3259191Skris OBJCOPY_INVALID = 0, // This is not an option ID. 3368651Skris#define OPTION(...) LLVM_MAKE_OPT_ID_WITH_ID_PREFIX(OBJCOPY_, __VA_ARGS__), 3468651Skris#include "ObjcopyOpts.inc" 3568651Skris#undef OPTION 3659191Skris}; 37238405Sjkim 38238405Sjkimnamespace objcopy_opt { 39269686Sjkim#define PREFIX(NAME, VALUE) \ 40238405Sjkim static constexpr StringLiteral NAME##_init[] = VALUE; \ 41296317Sdelphij static constexpr ArrayRef<StringLiteral> NAME(NAME##_init, \ 4259191Skris std::size(NAME##_init) - 1); 43296317Sdelphij#include "ObjcopyOpts.inc" 4459191Skris#undef PREFIX 4559191Skris 4659191Skrisstatic constexpr opt::OptTable::Info ObjcopyInfoTable[] = { 47296317Sdelphij#define OPTION(...) \ 4859191Skris LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX(OBJCOPY_, __VA_ARGS__), 4959191Skris#include "ObjcopyOpts.inc" 5059191Skris#undef OPTION 51296317Sdelphij}; 5259191Skris} // namespace objcopy_opt 5359191Skris 5459191Skrisclass ObjcopyOptTable : public opt::GenericOptTable { 55296317Sdelphijpublic: 5659191Skris ObjcopyOptTable() : opt::GenericOptTable(objcopy_opt::ObjcopyInfoTable) { 5759191Skris setGroupedShortOptions(true); 5859191Skris } 5959191Skris}; 6059191Skris 6159191Skrisenum InstallNameToolID { 6259191Skris INSTALL_NAME_TOOL_INVALID = 0, // This is not an option ID. 6359191Skris#define OPTION(...) \ 6459191Skris LLVM_MAKE_OPT_ID_WITH_ID_PREFIX(INSTALL_NAME_TOOL_, __VA_ARGS__), 6559191Skris#include "InstallNameToolOpts.inc" 6659191Skris#undef OPTION 6759191Skris}; 6859191Skris 6959191Skrisnamespace install_name_tool { 7059191Skris 7159191Skris#define PREFIX(NAME, VALUE) \ 7259191Skris static constexpr StringLiteral NAME##_init[] = VALUE; \ 7359191Skris static constexpr ArrayRef<StringLiteral> NAME(NAME##_init, \ 7459191Skris std::size(NAME##_init) - 1); 7559191Skris#include "InstallNameToolOpts.inc" 7659191Skris#undef PREFIX 7759191Skris 7859191Skrisstatic constexpr opt::OptTable::Info InstallNameToolInfoTable[] = { 7959191Skris#define OPTION(...) \ 8059191Skris LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX(INSTALL_NAME_TOOL_, __VA_ARGS__), 8159191Skris#include "InstallNameToolOpts.inc" 8259191Skris#undef OPTION 8359191Skris}; 8459191Skris} // namespace install_name_tool 8559191Skris 8659191Skrisclass InstallNameToolOptTable : public opt::GenericOptTable { 8759191Skrispublic: 8859191Skris InstallNameToolOptTable() 8959191Skris : GenericOptTable(install_name_tool::InstallNameToolInfoTable) {} 9059191Skris}; 9159191Skris 9259191Skrisenum BitcodeStripID { 9359191Skris BITCODE_STRIP_INVALID = 0, // This is not an option ID. 9459191Skris#define OPTION(...) \ 9559191Skris LLVM_MAKE_OPT_ID_WITH_ID_PREFIX(BITCODE_STRIP_, __VA_ARGS__), 9659191Skris#include "BitcodeStripOpts.inc" 9759191Skris#undef OPTION 9859191Skris}; 9959191Skris 10059191Skrisnamespace bitcode_strip { 10159191Skris 10259191Skris#define PREFIX(NAME, VALUE) \ 10359191Skris static constexpr StringLiteral NAME##_init[] = VALUE; \ 10459191Skris static constexpr ArrayRef<StringLiteral> NAME(NAME##_init, \ 10559191Skris std::size(NAME##_init) - 1); 10659191Skris#include "BitcodeStripOpts.inc" 10759191Skris#undef PREFIX 108296317Sdelphij 109296317Sdelphijstatic constexpr opt::OptTable::Info BitcodeStripInfoTable[] = { 110298999Sjkim#define OPTION(...) \ 111296317Sdelphij LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX(BITCODE_STRIP_, __VA_ARGS__), 11259191Skris#include "BitcodeStripOpts.inc" 113109998Smarkm#undef OPTION 114109998Smarkm}; 115109998Smarkm} // namespace bitcode_strip 116269686Sjkim 117269686Sjkimclass BitcodeStripOptTable : public opt::GenericOptTable { 118109998Smarkmpublic: 11959191Skris BitcodeStripOptTable() 12059191Skris : opt::GenericOptTable(bitcode_strip::BitcodeStripInfoTable) {} 121238405Sjkim}; 122238405Sjkim 12359191Skrisenum StripID { 124109998Smarkm STRIP_INVALID = 0, // This is not an option ID. 125109998Smarkm#define OPTION(...) LLVM_MAKE_OPT_ID_WITH_ID_PREFIX(STRIP_, __VA_ARGS__), 126109998Smarkm#include "StripOpts.inc" 127109998Smarkm#undef OPTION 12859191Skris}; 12959191Skris 13059191Skrisnamespace strip { 131162911Ssimon#define PREFIX(NAME, VALUE) \ 13259191Skris static constexpr StringLiteral NAME##_init[] = VALUE; \ 13359191Skris static constexpr ArrayRef<StringLiteral> NAME(NAME##_init, \ 13459191Skris std::size(NAME##_init) - 1); 135162911Ssimon#include "StripOpts.inc" 13659191Skris#undef PREFIX 13759191Skris 13859191Skrisstatic constexpr opt::OptTable::Info StripInfoTable[] = { 139296317Sdelphij#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX(STRIP_, __VA_ARGS__), 140296317Sdelphij#include "StripOpts.inc" 141296317Sdelphij#undef OPTION 14259191Skris}; 14359191Skris} // namespace strip 14459191Skris 145296317Sdelphijclass StripOptTable : public opt::GenericOptTable { 146296317Sdelphijpublic: 14759191Skris StripOptTable() : GenericOptTable(strip::StripInfoTable) { 14859191Skris setGroupedShortOptions(true); 14959191Skris } 150296317Sdelphij}; 151296317Sdelphij 15259191Skris} // namespace 15359191Skris 15459191Skrisstatic SectionFlag parseSectionRenameFlag(StringRef SectionName) { 155296317Sdelphij return llvm::StringSwitch<SectionFlag>(SectionName) 156167612Ssimon .CaseLower("alloc", SectionFlag::SecAlloc) 157167612Ssimon .CaseLower("load", SectionFlag::SecLoad) 158296317Sdelphij .CaseLower("noload", SectionFlag::SecNoload) 15959191Skris .CaseLower("readonly", SectionFlag::SecReadonly) 16059191Skris .CaseLower("debug", SectionFlag::SecDebug) 16159191Skris .CaseLower("code", SectionFlag::SecCode) 162296317Sdelphij .CaseLower("data", SectionFlag::SecData) 163296317Sdelphij .CaseLower("rom", SectionFlag::SecRom) 164296317Sdelphij .CaseLower("merge", SectionFlag::SecMerge) 165296317Sdelphij .CaseLower("strings", SectionFlag::SecStrings) 166296317Sdelphij .CaseLower("contents", SectionFlag::SecContents) 167296317Sdelphij .CaseLower("share", SectionFlag::SecShare) 16859191Skris .CaseLower("exclude", SectionFlag::SecExclude) 16959191Skris .CaseLower("large", SectionFlag::SecLarge) 17059191Skris .Default(SectionFlag::SecNone); 171296317Sdelphij} 172269686Sjkim 173269686Sjkimstatic Expected<SectionFlag> 174296317SdelphijparseSectionFlagSet(ArrayRef<StringRef> SectionFlags) { 175296317Sdelphij SectionFlag ParsedFlags = SectionFlag::SecNone; 176296317Sdelphij for (StringRef Flag : SectionFlags) { 177296317Sdelphij SectionFlag ParsedFlag = parseSectionRenameFlag(Flag); 178296317Sdelphij if (ParsedFlag == SectionFlag::SecNone) 17959191Skris return createStringError( 18059191Skris errc::invalid_argument, 18159191Skris "unrecognized section flag '%s'. Flags supported for GNU " 18259191Skris "compatibility: alloc, load, noload, readonly, exclude, debug, " 18359191Skris "code, data, rom, share, contents, merge, strings, large", 184269686Sjkim Flag.str().c_str()); 185269686Sjkim ParsedFlags |= ParsedFlag; 186269686Sjkim } 187269686Sjkim 188269686Sjkim return ParsedFlags; 18959191Skris} 19059191Skris 191269686Sjkimstatic Expected<SectionRename> parseRenameSectionValue(StringRef FlagValue) { 192269686Sjkim if (!FlagValue.contains('=')) 19359191Skris return createStringError(errc::invalid_argument, 194269686Sjkim "bad format for --rename-section: missing '='"); 19559191Skris 196269686Sjkim // Initial split: ".foo" = ".bar,f1,f2,..." 19759191Skris auto Old2New = FlagValue.split('='); 198269686Sjkim SectionRename SR; 199269686Sjkim SR.OriginalName = Old2New.first; 200269686Sjkim 201269686Sjkim // Flags split: ".bar" "f1" "f2" ... 202269686Sjkim SmallVector<StringRef, 6> NameAndFlags; 203269686Sjkim Old2New.second.split(NameAndFlags, ','); 204269686Sjkim SR.NewName = NameAndFlags[0]; 205269686Sjkim 206269686Sjkim if (NameAndFlags.size() > 1) { 207269686Sjkim Expected<SectionFlag> ParsedFlagSet = 208269686Sjkim parseSectionFlagSet(ArrayRef(NameAndFlags).drop_front()); 209269686Sjkim if (!ParsedFlagSet) 210269686Sjkim return ParsedFlagSet.takeError(); 211269686Sjkim SR.NewFlags = *ParsedFlagSet; 212269686Sjkim } 213269686Sjkim 214269686Sjkim return SR; 215269686Sjkim} 216269686Sjkim 217291721Sjkimstatic Expected<std::pair<StringRef, uint64_t>> 218269686SjkimparseSetSectionAttribute(StringRef Option, StringRef FlagValue) { 219269686Sjkim if (!FlagValue.contains('=')) 220269686Sjkim return make_error<StringError>("bad format for " + Option + ": missing '='", 221269686Sjkim errc::invalid_argument); 222269686Sjkim auto Split = StringRef(FlagValue).split('='); 223269686Sjkim if (Split.first.empty()) 224269686Sjkim return make_error<StringError>("bad format for " + Option + 225269686Sjkim ": missing section name", 226269686Sjkim errc::invalid_argument); 227269686Sjkim uint64_t Value; 228269686Sjkim if (Split.second.getAsInteger(0, Value)) 229269686Sjkim return make_error<StringError>("invalid value for " + Option + ": '" + 23059191Skris Split.second + "'", 23159191Skris errc::invalid_argument); 23259191Skris return std::make_pair(Split.first, Value); 23359191Skris} 23459191Skris 23559191Skrisstatic Expected<SectionFlagsUpdate> 23659191SkrisparseSetSectionFlagValue(StringRef FlagValue) { 23759191Skris if (!StringRef(FlagValue).contains('=')) 23859191Skris return createStringError(errc::invalid_argument, 23959191Skris "bad format for --set-section-flags: missing '='"); 24059191Skris 24159191Skris // Initial split: ".foo" = "f1,f2,..." 24259191Skris auto Section2Flags = StringRef(FlagValue).split('='); 243269686Sjkim SectionFlagsUpdate SFU; 244269686Sjkim SFU.Name = Section2Flags.first; 245269686Sjkim 246269686Sjkim // Flags split: "f1" "f2" ... 247269686Sjkim SmallVector<StringRef, 6> SectionFlags; 248269686Sjkim Section2Flags.second.split(SectionFlags, ','); 249269686Sjkim Expected<SectionFlag> ParsedFlagSet = parseSectionFlagSet(SectionFlags); 250269686Sjkim if (!ParsedFlagSet) 251269686Sjkim return ParsedFlagSet.takeError(); 252269686Sjkim SFU.NewFlags = *ParsedFlagSet; 25359191Skris 25459191Skris return SFU; 25559191Skris} 25659191Skris 25759191Skrisnamespace { 258269686Sjkimstruct TargetInfo { 25959191Skris FileFormat Format; 260269686Sjkim MachineInfo Machine; 261269686Sjkim}; 26259191Skris} // namespace 263269686Sjkim 26459191Skris// FIXME: consolidate with the bfd parsing used by lld. 265269686Sjkimstatic const StringMap<MachineInfo> TargetMap{ 26659191Skris // Name, {EMachine, 64bit, LittleEndian} 267269686Sjkim // x86 26859191Skris {"elf32-i386", {ELF::EM_386, false, true}}, 269269686Sjkim {"elf32-x86-64", {ELF::EM_X86_64, false, true}}, 270269686Sjkim {"elf64-x86-64", {ELF::EM_X86_64, true, true}}, 27159191Skris // Intel MCU 272269686Sjkim {"elf32-iamcu", {ELF::EM_IAMCU, false, true}}, 273109998Smarkm // ARM 274269686Sjkim {"elf32-littlearm", {ELF::EM_ARM, false, true}}, 275269686Sjkim // ARM AArch64 276109998Smarkm {"elf64-aarch64", {ELF::EM_AARCH64, true, true}}, 27759191Skris {"elf64-littleaarch64", {ELF::EM_AARCH64, true, true}}, 27859191Skris // RISC-V 27959191Skris {"elf32-littleriscv", {ELF::EM_RISCV, false, true}}, 28059191Skris {"elf64-littleriscv", {ELF::EM_RISCV, true, true}}, 28159191Skris // PowerPC 28259191Skris {"elf32-powerpc", {ELF::EM_PPC, false, false}}, 28359191Skris {"elf32-powerpcle", {ELF::EM_PPC, false, true}}, 28459191Skris {"elf64-powerpc", {ELF::EM_PPC64, true, false}}, 28559191Skris {"elf64-powerpcle", {ELF::EM_PPC64, true, true}}, 28659191Skris // MIPS 28759191Skris {"elf32-bigmips", {ELF::EM_MIPS, false, false}}, 28859191Skris {"elf32-ntradbigmips", {ELF::EM_MIPS, false, false}}, 28959191Skris {"elf32-ntradlittlemips", {ELF::EM_MIPS, false, true}}, 29059191Skris {"elf32-tradbigmips", {ELF::EM_MIPS, false, false}}, 29159191Skris {"elf32-tradlittlemips", {ELF::EM_MIPS, false, true}}, 29259191Skris {"elf64-tradbigmips", {ELF::EM_MIPS, true, false}}, 29359191Skris {"elf64-tradlittlemips", {ELF::EM_MIPS, true, true}}, 29459191Skris // SPARC 29559191Skris {"elf32-sparc", {ELF::EM_SPARC, false, false}}, 29659191Skris {"elf32-sparcel", {ELF::EM_SPARC, false, true}}, 297194206Ssimon // Hexagon 298194206Ssimon {"elf32-hexagon", {ELF::EM_HEXAGON, false, true}}, 299194206Ssimon // LoongArch 300194206Ssimon {"elf32-loongarch", {ELF::EM_LOONGARCH, false, true}}, 30159191Skris {"elf64-loongarch", {ELF::EM_LOONGARCH, true, true}}, 30259191Skris // SystemZ 30359191Skris {"elf64-s390", {ELF::EM_S390, true, false}}, 30459191Skris}; 30559191Skris 30659191Skrisstatic Expected<TargetInfo> 30759191SkrisgetOutputTargetInfoByTargetName(StringRef TargetName) { 30859191Skris StringRef OriginalTargetName = TargetName; 309269686Sjkim bool IsFreeBSD = TargetName.consume_back("-freebsd"); 310269686Sjkim auto Iter = TargetMap.find(TargetName); 311269686Sjkim if (Iter == std::end(TargetMap)) 312269686Sjkim return createStringError(errc::invalid_argument, 313238405Sjkim "invalid output format: '%s'", 314238405Sjkim OriginalTargetName.str().c_str()); 315238405Sjkim MachineInfo MI = Iter->getValue(); 316238405Sjkim if (IsFreeBSD) 317238405Sjkim MI.OSABI = ELF::ELFOSABI_FREEBSD; 318238405Sjkim 319238405Sjkim FileFormat Format; 320238405Sjkim if (TargetName.starts_with("elf")) 321238405Sjkim Format = FileFormat::ELF; 322238405Sjkim else 323238405Sjkim // This should never happen because `TargetName` is valid (it certainly 324238405Sjkim // exists in the TargetMap). 325238405Sjkim llvm_unreachable("unknown target prefix"); 326238405Sjkim 327238405Sjkim return {TargetInfo{Format, MI}}; 328238405Sjkim} 329238405Sjkim 330238405Sjkimstatic Error addSymbolsFromFile(NameMatcher &Symbols, BumpPtrAllocator &Alloc, 331238405Sjkim StringRef Filename, MatchStyle MS, 332238405Sjkim function_ref<Error(Error)> ErrorCallback) { 333238405Sjkim StringSaver Saver(Alloc); 334238405Sjkim SmallVector<StringRef, 16> Lines; 335238405Sjkim auto BufOrErr = MemoryBuffer::getFile(Filename); 336238405Sjkim if (!BufOrErr) 337238405Sjkim return createFileError(Filename, BufOrErr.getError()); 338238405Sjkim 339269686Sjkim BufOrErr.get()->getBuffer().split(Lines, '\n'); 340238405Sjkim for (StringRef Line : Lines) { 341269686Sjkim // Ignore everything after '#', trim whitespace, and only add the symbol if 342269686Sjkim // it's not empty. 34359191Skris auto TrimmedLine = Line.split('#').first.trim(); 34459191Skris if (!TrimmedLine.empty()) 34559191Skris if (Error E = Symbols.addMatcher(NameOrPattern::create( 34659191Skris Saver.save(TrimmedLine), MS, ErrorCallback))) 34759191Skris return E; 348109998Smarkm } 349109998Smarkm 350109998Smarkm return Error::success(); 35159191Skris} 35259191Skris 35359191Skrisstatic Error addSymbolsToRenameFromFile(StringMap<StringRef> &SymbolsToRename, 35459191Skris BumpPtrAllocator &Alloc, 35559191Skris StringRef Filename) { 35659191Skris StringSaver Saver(Alloc); 35759191Skris SmallVector<StringRef, 16> Lines; 35859191Skris auto BufOrErr = MemoryBuffer::getFile(Filename); 35959191Skris if (!BufOrErr) 36059191Skris return createFileError(Filename, BufOrErr.getError()); 36159191Skris 36259191Skris BufOrErr.get()->getBuffer().split(Lines, '\n'); 36359191Skris size_t NumLines = Lines.size(); 36459191Skris for (size_t LineNo = 0; LineNo < NumLines; ++LineNo) { 36559191Skris StringRef TrimmedLine = Lines[LineNo].split('#').first.trim(); 36659191Skris if (TrimmedLine.empty()) 36759191Skris continue; 36859191Skris 36959191Skris std::pair<StringRef, StringRef> Pair = Saver.save(TrimmedLine).split(' '); 37059191Skris StringRef NewName = Pair.second.trim(); 37159191Skris if (NewName.empty()) 37259191Skris return createStringError(errc::invalid_argument, 37359191Skris "%s:%zu: missing new symbol name", 37459191Skris Filename.str().c_str(), LineNo + 1); 37559191Skris SymbolsToRename.insert({Pair.first, NewName}); 37659191Skris } 37759191Skris return Error::success(); 37859191Skris} 37959191Skris 38059191Skristemplate <class T> static ErrorOr<T> getAsInteger(StringRef Val) { 38159191Skris T Result; 38259191Skris if (Val.getAsInteger(0, Result)) 38359191Skris return errc::invalid_argument; 38459191Skris return Result; 38559191Skris} 38659191Skris 38759191Skrisnamespace { 38859191Skris 38959191Skrisenum class ToolType { Objcopy, Strip, InstallNameTool, BitcodeStrip }; 39059191Skris 39159191Skris} // anonymous namespace 39259191Skris 39359191Skrisstatic void printHelp(const opt::OptTable &OptTable, raw_ostream &OS, 39459191Skris ToolType Tool) { 39559191Skris StringRef HelpText, ToolName; 39659191Skris switch (Tool) { 39759191Skris case ToolType::Objcopy: 39859191Skris ToolName = "llvm-objcopy"; 39959191Skris HelpText = " [options] input [output]"; 40059191Skris break; 40159191Skris case ToolType::Strip: 40259191Skris ToolName = "llvm-strip"; 40359191Skris HelpText = " [options] inputs..."; 40459191Skris break; 40559191Skris case ToolType::InstallNameTool: 40659191Skris ToolName = "llvm-install-name-tool"; 40759191Skris HelpText = " [options] input"; 40859191Skris break; 40959191Skris case ToolType::BitcodeStrip: 41059191Skris ToolName = "llvm-bitcode-strip"; 41159191Skris HelpText = " [options] input"; 41259191Skris break; 41359191Skris } 41459191Skris OptTable.printHelp(OS, (ToolName + HelpText).str().c_str(), 41559191Skris (ToolName + " tool").str().c_str()); 41659191Skris // TODO: Replace this with libOption call once it adds extrahelp support. 41759191Skris // The CommandLine library has a cl::extrahelp class to support this, 41859191Skris // but libOption does not have that yet. 41959191Skris OS << "\nPass @FILE as argument to read options from FILE.\n"; 420109998Smarkm} 421109998Smarkm 422109998Smarkmstatic Expected<NewSymbolInfo> parseNewSymbolInfo(StringRef FlagValue) { 423109998Smarkm // Parse value given with --add-symbol option and create the 424109998Smarkm // new symbol if possible. The value format for --add-symbol is: 425194206Ssimon // 426194206Ssimon // <name>=[<section>:]<value>[,<flags>] 427194206Ssimon // 428194206Ssimon // where: 429109998Smarkm // <name> - symbol name, can be empty string 430109998Smarkm // <section> - optional section name. If not given ABS symbol is created 431109998Smarkm // <value> - symbol value, can be decimal or hexadecimal number prefixed 432109998Smarkm // with 0x. 433109998Smarkm // <flags> - optional flags affecting symbol type, binding or visibility. 434109998Smarkm NewSymbolInfo SI; 435109998Smarkm StringRef Value; 436109998Smarkm std::tie(SI.SymbolName, Value) = FlagValue.split('='); 437109998Smarkm if (Value.empty()) 438162911Ssimon return createStringError( 439162911Ssimon errc::invalid_argument, 440162911Ssimon "bad format for --add-symbol, missing '=' after '%s'", 441162911Ssimon SI.SymbolName.str().c_str()); 442162911Ssimon 443162911Ssimon if (Value.contains(':')) { 444162911Ssimon std::tie(SI.SectionName, Value) = Value.split(':'); 445162911Ssimon if (SI.SectionName.empty() || Value.empty()) 446162911Ssimon return createStringError( 447162911Ssimon errc::invalid_argument, 448162911Ssimon "bad format for --add-symbol, missing section name or symbol value"); 449162911Ssimon } 450162911Ssimon 451162911Ssimon SmallVector<StringRef, 6> Flags; 452162911Ssimon Value.split(Flags, ','); 453162911Ssimon if (Flags[0].getAsInteger(0, SI.Value)) 454162911Ssimon return createStringError(errc::invalid_argument, "bad symbol value: '%s'", 455162911Ssimon Flags[0].str().c_str()); 456194206Ssimon 457194206Ssimon using Functor = std::function<void()>; 458194206Ssimon SmallVector<StringRef, 6> UnsupportedFlags; 459194206Ssimon for (size_t I = 1, NumFlags = Flags.size(); I < NumFlags; ++I) 460194206Ssimon static_cast<Functor>( 461194206Ssimon StringSwitch<Functor>(Flags[I]) 462194206Ssimon .CaseLower("global", 463194206Ssimon [&] { SI.Flags.push_back(SymbolFlag::Global); }) 464194206Ssimon .CaseLower("local", [&] { SI.Flags.push_back(SymbolFlag::Local); }) 465194206Ssimon .CaseLower("weak", [&] { SI.Flags.push_back(SymbolFlag::Weak); }) 466194206Ssimon .CaseLower("default", 467194206Ssimon [&] { SI.Flags.push_back(SymbolFlag::Default); }) 468238405Sjkim .CaseLower("hidden", 469238405Sjkim [&] { SI.Flags.push_back(SymbolFlag::Hidden); }) 470238405Sjkim .CaseLower("protected", 471238405Sjkim [&] { SI.Flags.push_back(SymbolFlag::Protected); }) 472238405Sjkim .CaseLower("file", [&] { SI.Flags.push_back(SymbolFlag::File); }) 473238405Sjkim .CaseLower("section", 474238405Sjkim [&] { SI.Flags.push_back(SymbolFlag::Section); }) 475238405Sjkim .CaseLower("object", 476238405Sjkim [&] { SI.Flags.push_back(SymbolFlag::Object); }) 477238405Sjkim .CaseLower("function", 47859191Skris [&] { SI.Flags.push_back(SymbolFlag::Function); }) 47959191Skris .CaseLower( 48059191Skris "indirect-function", 48159191Skris [&] { SI.Flags.push_back(SymbolFlag::IndirectFunction); }) 48259191Skris .CaseLower("debug", [&] { SI.Flags.push_back(SymbolFlag::Debug); }) 48359191Skris .CaseLower("constructor", 48459191Skris [&] { SI.Flags.push_back(SymbolFlag::Constructor); }) 48559191Skris .CaseLower("warning", 48659191Skris [&] { SI.Flags.push_back(SymbolFlag::Warning); }) 48759191Skris .CaseLower("indirect", 488269686Sjkim [&] { SI.Flags.push_back(SymbolFlag::Indirect); }) 48959191Skris .CaseLower("synthetic", 490269686Sjkim [&] { SI.Flags.push_back(SymbolFlag::Synthetic); }) 491269686Sjkim .CaseLower("unique-object", 492269686Sjkim [&] { SI.Flags.push_back(SymbolFlag::UniqueObject); }) 493269686Sjkim .StartsWithLower("before=", 494269686Sjkim [&] { 495269686Sjkim StringRef SymNamePart = 496269686Sjkim Flags[I].split('=').second; 497269686Sjkim 498269686Sjkim if (!SymNamePart.empty()) 499269686Sjkim SI.BeforeSyms.push_back(SymNamePart); 500269686Sjkim }) 501269686Sjkim .Default([&] { UnsupportedFlags.push_back(Flags[I]); }))(); 502269686Sjkim if (!UnsupportedFlags.empty()) 503269686Sjkim return createStringError(errc::invalid_argument, 504269686Sjkim "unsupported flag%s for --add-symbol: '%s'", 505269686Sjkim UnsupportedFlags.size() > 1 ? "s" : "", 506269686Sjkim join(UnsupportedFlags, "', '").c_str()); 507269686Sjkim 508269686Sjkim return SI; 509269686Sjkim} 510269686Sjkim 511269686Sjkim// Parse input option \p ArgValue and load section data. This function 512269686Sjkim// extracts section name and name of the file keeping section data from 513269686Sjkim// ArgValue, loads data from the file, and stores section name and data 514269686Sjkim// into the vector of new sections \p NewSections. 515269686Sjkimstatic Error loadNewSectionData(StringRef ArgValue, StringRef OptionName, 516269686Sjkim std::vector<NewSectionInfo> &NewSections) { 517269686Sjkim if (!ArgValue.contains('=')) 518269686Sjkim return createStringError(errc::invalid_argument, 519269686Sjkim "bad format for " + OptionName + ": missing '='"); 520269686Sjkim 521269686Sjkim std::pair<StringRef, StringRef> SecPair = ArgValue.split("="); 522269686Sjkim if (SecPair.second.empty()) 523269686Sjkim return createStringError(errc::invalid_argument, "bad format for " + 524269686Sjkim OptionName + 525269686Sjkim ": missing file name"); 526269686Sjkim 527269686Sjkim ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr = 528269686Sjkim MemoryBuffer::getFile(SecPair.second); 529269686Sjkim if (!BufOrErr) 530269686Sjkim return createFileError(SecPair.second, 531269686Sjkim errorCodeToError(BufOrErr.getError())); 532269686Sjkim 533269686Sjkim NewSections.push_back({SecPair.first, std::move(*BufOrErr)}); 534269686Sjkim return Error::success(); 535269686Sjkim} 536269686Sjkim 537269686Sjkim// parseObjcopyOptions returns the config and sets the input arguments. If a 538269686Sjkim// help flag is set then parseObjcopyOptions will print the help messege and 539269686Sjkim// exit. 540269686SjkimExpected<DriverConfig> 541269686Sjkimobjcopy::parseObjcopyOptions(ArrayRef<const char *> RawArgsArr, 542269686Sjkim function_ref<Error(Error)> ErrorCallback) { 543269686Sjkim DriverConfig DC; 544269686Sjkim ObjcopyOptTable T; 545269686Sjkim 546269686Sjkim const char *const *DashDash = 547269686Sjkim llvm::find_if(RawArgsArr, [](StringRef Str) { return Str == "--"; }); 548269686Sjkim ArrayRef<const char *> ArgsArr = ArrayRef(RawArgsArr.begin(), DashDash); 549269686Sjkim if (DashDash != RawArgsArr.end()) 550269686Sjkim DashDash = std::next(DashDash); 551269686Sjkim 552269686Sjkim unsigned MissingArgumentIndex, MissingArgumentCount; 553269686Sjkim llvm::opt::InputArgList InputArgs = 554269686Sjkim T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount); 555269686Sjkim 556269686Sjkim if (InputArgs.size() == 0 && DashDash == RawArgsArr.end()) { 557269686Sjkim printHelp(T, errs(), ToolType::Objcopy); 558269686Sjkim exit(1); 559269686Sjkim } 560269686Sjkim 561269686Sjkim if (InputArgs.hasArg(OBJCOPY_help)) { 562269686Sjkim printHelp(T, outs(), ToolType::Objcopy); 563269686Sjkim exit(0); 564269686Sjkim } 565269686Sjkim 566269686Sjkim if (InputArgs.hasArg(OBJCOPY_version)) { 567269686Sjkim outs() << "llvm-objcopy, compatible with GNU objcopy\n"; 568269686Sjkim cl::PrintVersionMessage(); 569269686Sjkim exit(0); 570269686Sjkim } 571269686Sjkim 572269686Sjkim SmallVector<const char *, 2> Positional; 573269686Sjkim 574269686Sjkim for (auto *Arg : InputArgs.filtered(OBJCOPY_UNKNOWN)) 575269686Sjkim return createStringError(errc::invalid_argument, "unknown argument '%s'", 576269686Sjkim Arg->getAsString(InputArgs).c_str()); 577269686Sjkim 578269686Sjkim for (auto *Arg : InputArgs.filtered(OBJCOPY_INPUT)) 579269686Sjkim Positional.push_back(Arg->getValue()); 580269686Sjkim std::copy(DashDash, RawArgsArr.end(), std::back_inserter(Positional)); 581269686Sjkim 582269686Sjkim if (Positional.empty()) 58359191Skris return createStringError(errc::invalid_argument, "no input file specified"); 584296317Sdelphij 585296317Sdelphij if (Positional.size() > 2) 586296317Sdelphij return createStringError(errc::invalid_argument, 58759191Skris "too many positional arguments"); 588296317Sdelphij 58959191Skris ConfigManager ConfigMgr; 59059191Skris CommonConfig &Config = ConfigMgr.Common; 59159191Skris COFFConfig &COFFConfig = ConfigMgr.COFF; 59259191Skris ELFConfig &ELFConfig = ConfigMgr.ELF; 59359191Skris MachOConfig &MachOConfig = ConfigMgr.MachO; 59459191Skris Config.InputFilename = Positional[0]; 59559191Skris Config.OutputFilename = Positional[Positional.size() == 1 ? 0 : 1]; 59659191Skris if (InputArgs.hasArg(OBJCOPY_target) && 59759191Skris (InputArgs.hasArg(OBJCOPY_input_target) || 59859191Skris InputArgs.hasArg(OBJCOPY_output_target))) 59959191Skris return createStringError( 60059191Skris errc::invalid_argument, 60159191Skris "--target cannot be used with --input-target or --output-target"); 60259191Skris 60359191Skris if (InputArgs.hasArg(OBJCOPY_regex) && InputArgs.hasArg(OBJCOPY_wildcard)) 60459191Skris return createStringError(errc::invalid_argument, 60559191Skris "--regex and --wildcard are incompatible"); 60659191Skris 60759191Skris MatchStyle SectionMatchStyle = InputArgs.hasArg(OBJCOPY_regex) 60859191Skris ? MatchStyle::Regex 60959191Skris : MatchStyle::Wildcard; 610269686Sjkim MatchStyle SymbolMatchStyle 611269686Sjkim = InputArgs.hasArg(OBJCOPY_regex) ? MatchStyle::Regex 612269686Sjkim : InputArgs.hasArg(OBJCOPY_wildcard) ? MatchStyle::Wildcard 613269686Sjkim : MatchStyle::Literal; 614269686Sjkim StringRef InputFormat, OutputFormat; 61559191Skris if (InputArgs.hasArg(OBJCOPY_target)) { 61659191Skris InputFormat = InputArgs.getLastArgValue(OBJCOPY_target); 61759191Skris OutputFormat = InputArgs.getLastArgValue(OBJCOPY_target); 61859191Skris } else { 619109998Smarkm InputFormat = InputArgs.getLastArgValue(OBJCOPY_input_target); 620109998Smarkm OutputFormat = InputArgs.getLastArgValue(OBJCOPY_output_target); 621109998Smarkm } 622109998Smarkm 623109998Smarkm // FIXME: Currently, we ignore the target for non-binary/ihex formats 624109998Smarkm // explicitly specified by -I option (e.g. -Ielf32-x86-64) and guess the 625109998Smarkm // format by llvm::object::createBinary regardless of the option value. 626109998Smarkm Config.InputFormat = StringSwitch<FileFormat>(InputFormat) 627109998Smarkm .Case("binary", FileFormat::Binary) 62859191Skris .Case("ihex", FileFormat::IHex) 62959191Skris .Default(FileFormat::Unspecified); 63059191Skris 63159191Skris if (InputArgs.hasArg(OBJCOPY_new_symbol_visibility)) { 632109998Smarkm const uint8_t Invalid = 0xff; 633109998Smarkm StringRef VisibilityStr = 634238405Sjkim InputArgs.getLastArgValue(OBJCOPY_new_symbol_visibility); 635238405Sjkim 636238405Sjkim ELFConfig.NewSymbolVisibility = StringSwitch<uint8_t>(VisibilityStr) 637109998Smarkm .Case("default", ELF::STV_DEFAULT) 63859191Skris .Case("hidden", ELF::STV_HIDDEN) 639 .Case("internal", ELF::STV_INTERNAL) 640 .Case("protected", ELF::STV_PROTECTED) 641 .Default(Invalid); 642 643 if (ELFConfig.NewSymbolVisibility == Invalid) 644 return createStringError(errc::invalid_argument, 645 "'%s' is not a valid symbol visibility", 646 VisibilityStr.str().c_str()); 647 } 648 649 for (const auto *Arg : InputArgs.filtered(OBJCOPY_subsystem)) { 650 StringRef Subsystem, Version; 651 std::tie(Subsystem, Version) = StringRef(Arg->getValue()).split(':'); 652 COFFConfig.Subsystem = 653 StringSwitch<unsigned>(Subsystem.lower()) 654 .Case("boot_application", 655 COFF::IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION) 656 .Case("console", COFF::IMAGE_SUBSYSTEM_WINDOWS_CUI) 657 .Case("efi_application", COFF::IMAGE_SUBSYSTEM_EFI_APPLICATION) 658 .Case("efi_boot_service_driver", 659 COFF::IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) 660 .Case("efi_rom", COFF::IMAGE_SUBSYSTEM_EFI_ROM) 661 .Case("efi_runtime_driver", 662 COFF::IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) 663 .Case("native", COFF::IMAGE_SUBSYSTEM_NATIVE) 664 .Case("posix", COFF::IMAGE_SUBSYSTEM_POSIX_CUI) 665 .Case("windows", COFF::IMAGE_SUBSYSTEM_WINDOWS_GUI) 666 .Default(COFF::IMAGE_SUBSYSTEM_UNKNOWN); 667 if (*COFFConfig.Subsystem == COFF::IMAGE_SUBSYSTEM_UNKNOWN) 668 return createStringError(errc::invalid_argument, 669 "'%s' is not a valid subsystem", 670 Subsystem.str().c_str()); 671 if (!Version.empty()) { 672 StringRef Major, Minor; 673 std::tie(Major, Minor) = Version.split('.'); 674 unsigned Number; 675 if (Major.getAsInteger(10, Number)) 676 return createStringError(errc::invalid_argument, 677 "'%s' is not a valid subsystem major version", 678 Major.str().c_str()); 679 COFFConfig.MajorSubsystemVersion = Number; 680 Number = 0; 681 if (!Minor.empty() && Minor.getAsInteger(10, Number)) 682 return createStringError(errc::invalid_argument, 683 "'%s' is not a valid subsystem minor version", 684 Minor.str().c_str()); 685 COFFConfig.MinorSubsystemVersion = Number; 686 } 687 } 688 689 Config.OutputFormat = StringSwitch<FileFormat>(OutputFormat) 690 .Case("binary", FileFormat::Binary) 691 .Case("ihex", FileFormat::IHex) 692 .Default(FileFormat::Unspecified); 693 if (Config.OutputFormat == FileFormat::Unspecified) { 694 if (OutputFormat.empty()) { 695 Config.OutputFormat = Config.InputFormat; 696 } else { 697 Expected<TargetInfo> Target = 698 getOutputTargetInfoByTargetName(OutputFormat); 699 if (!Target) 700 return Target.takeError(); 701 Config.OutputFormat = Target->Format; 702 Config.OutputArch = Target->Machine; 703 } 704 } 705 706 if (const auto *A = InputArgs.getLastArg(OBJCOPY_compress_debug_sections)) { 707 Config.CompressionType = StringSwitch<DebugCompressionType>(A->getValue()) 708 .Case("zlib", DebugCompressionType::Zlib) 709 .Case("zstd", DebugCompressionType::Zstd) 710 .Default(DebugCompressionType::None); 711 if (Config.CompressionType == DebugCompressionType::None) { 712 return createStringError( 713 errc::invalid_argument, 714 "invalid or unsupported --compress-debug-sections format: %s", 715 A->getValue()); 716 } 717 if (const char *Reason = compression::getReasonIfUnsupported( 718 compression::formatFor(Config.CompressionType))) 719 return createStringError(errc::invalid_argument, Reason); 720 } 721 722 Config.AddGnuDebugLink = InputArgs.getLastArgValue(OBJCOPY_add_gnu_debuglink); 723 // The gnu_debuglink's target is expected to not change or else its CRC would 724 // become invalidated and get rejected. We can avoid recalculating the 725 // checksum for every target file inside an archive by precomputing the CRC 726 // here. This prevents a significant amount of I/O. 727 if (!Config.AddGnuDebugLink.empty()) { 728 auto DebugOrErr = MemoryBuffer::getFile(Config.AddGnuDebugLink); 729 if (!DebugOrErr) 730 return createFileError(Config.AddGnuDebugLink, DebugOrErr.getError()); 731 auto Debug = std::move(*DebugOrErr); 732 Config.GnuDebugLinkCRC32 = 733 llvm::crc32(arrayRefFromStringRef(Debug->getBuffer())); 734 } 735 Config.SplitDWO = InputArgs.getLastArgValue(OBJCOPY_split_dwo); 736 Config.SymbolsPrefix = InputArgs.getLastArgValue(OBJCOPY_prefix_symbols); 737 Config.AllocSectionsPrefix = 738 InputArgs.getLastArgValue(OBJCOPY_prefix_alloc_sections); 739 if (auto Arg = InputArgs.getLastArg(OBJCOPY_extract_partition)) 740 Config.ExtractPartition = Arg->getValue(); 741 742 if (const auto *A = InputArgs.getLastArg(OBJCOPY_gap_fill)) { 743 if (Config.OutputFormat != FileFormat::Binary) 744 return createStringError( 745 errc::invalid_argument, 746 "'--gap-fill' is only supported for binary output"); 747 ErrorOr<uint64_t> Val = getAsInteger<uint64_t>(A->getValue()); 748 if (!Val) 749 return createStringError(Val.getError(), "--gap-fill: bad number: %s", 750 A->getValue()); 751 uint8_t ByteVal = Val.get(); 752 if (ByteVal != Val.get()) 753 return createStringError(std::errc::value_too_large, 754 "gap-fill value %s is out of range (0 to 0xff)", 755 A->getValue()); 756 Config.GapFill = ByteVal; 757 } 758 759 if (const auto *A = InputArgs.getLastArg(OBJCOPY_pad_to)) { 760 if (Config.OutputFormat != FileFormat::Binary) 761 return createStringError( 762 errc::invalid_argument, 763 "'--pad-to' is only supported for binary output"); 764 ErrorOr<uint64_t> Addr = getAsInteger<uint64_t>(A->getValue()); 765 if (!Addr) 766 return createStringError(Addr.getError(), "--pad-to: bad number: %s", 767 A->getValue()); 768 Config.PadTo = *Addr; 769 } 770 771 for (auto *Arg : InputArgs.filtered(OBJCOPY_redefine_symbol)) { 772 if (!StringRef(Arg->getValue()).contains('=')) 773 return createStringError(errc::invalid_argument, 774 "bad format for --redefine-sym"); 775 auto Old2New = StringRef(Arg->getValue()).split('='); 776 if (!Config.SymbolsToRename.insert(Old2New).second) 777 return createStringError(errc::invalid_argument, 778 "multiple redefinition of symbol '%s'", 779 Old2New.first.str().c_str()); 780 } 781 782 for (auto *Arg : InputArgs.filtered(OBJCOPY_redefine_symbols)) 783 if (Error E = addSymbolsToRenameFromFile(Config.SymbolsToRename, DC.Alloc, 784 Arg->getValue())) 785 return std::move(E); 786 787 for (auto *Arg : InputArgs.filtered(OBJCOPY_rename_section)) { 788 Expected<SectionRename> SR = 789 parseRenameSectionValue(StringRef(Arg->getValue())); 790 if (!SR) 791 return SR.takeError(); 792 if (!Config.SectionsToRename.try_emplace(SR->OriginalName, *SR).second) 793 return createStringError(errc::invalid_argument, 794 "multiple renames of section '%s'", 795 SR->OriginalName.str().c_str()); 796 } 797 for (auto *Arg : InputArgs.filtered(OBJCOPY_set_section_alignment)) { 798 Expected<std::pair<StringRef, uint64_t>> NameAndAlign = 799 parseSetSectionAttribute("--set-section-alignment", Arg->getValue()); 800 if (!NameAndAlign) 801 return NameAndAlign.takeError(); 802 Config.SetSectionAlignment[NameAndAlign->first] = NameAndAlign->second; 803 } 804 for (auto *Arg : InputArgs.filtered(OBJCOPY_set_section_flags)) { 805 Expected<SectionFlagsUpdate> SFU = 806 parseSetSectionFlagValue(Arg->getValue()); 807 if (!SFU) 808 return SFU.takeError(); 809 if (!Config.SetSectionFlags.try_emplace(SFU->Name, *SFU).second) 810 return createStringError( 811 errc::invalid_argument, 812 "--set-section-flags set multiple times for section '%s'", 813 SFU->Name.str().c_str()); 814 } 815 for (auto *Arg : InputArgs.filtered(OBJCOPY_set_section_type)) { 816 Expected<std::pair<StringRef, uint64_t>> NameAndType = 817 parseSetSectionAttribute("--set-section-type", Arg->getValue()); 818 if (!NameAndType) 819 return NameAndType.takeError(); 820 Config.SetSectionType[NameAndType->first] = NameAndType->second; 821 } 822 // Prohibit combinations of --set-section-{flags,type} when the section name 823 // is used as the destination of a --rename-section. 824 for (const auto &E : Config.SectionsToRename) { 825 const SectionRename &SR = E.second; 826 auto Err = [&](const char *Option) { 827 return createStringError( 828 errc::invalid_argument, 829 "--set-section-%s=%s conflicts with --rename-section=%s=%s", Option, 830 SR.NewName.str().c_str(), SR.OriginalName.str().c_str(), 831 SR.NewName.str().c_str()); 832 }; 833 if (Config.SetSectionFlags.count(SR.NewName)) 834 return Err("flags"); 835 if (Config.SetSectionType.count(SR.NewName)) 836 return Err("type"); 837 } 838 839 for (auto *Arg : InputArgs.filtered(OBJCOPY_remove_section)) 840 if (Error E = Config.ToRemove.addMatcher(NameOrPattern::create( 841 Arg->getValue(), SectionMatchStyle, ErrorCallback))) 842 return std::move(E); 843 for (auto *Arg : InputArgs.filtered(OBJCOPY_keep_section)) 844 if (Error E = Config.KeepSection.addMatcher(NameOrPattern::create( 845 Arg->getValue(), SectionMatchStyle, ErrorCallback))) 846 return std::move(E); 847 for (auto *Arg : InputArgs.filtered(OBJCOPY_only_section)) 848 if (Error E = Config.OnlySection.addMatcher(NameOrPattern::create( 849 Arg->getValue(), SectionMatchStyle, ErrorCallback))) 850 return std::move(E); 851 for (auto *Arg : InputArgs.filtered(OBJCOPY_add_section)) { 852 if (Error Err = loadNewSectionData(Arg->getValue(), "--add-section", 853 Config.AddSection)) 854 return std::move(Err); 855 } 856 for (auto *Arg : InputArgs.filtered(OBJCOPY_update_section)) { 857 if (Error Err = loadNewSectionData(Arg->getValue(), "--update-section", 858 Config.UpdateSection)) 859 return std::move(Err); 860 } 861 for (auto *Arg : InputArgs.filtered(OBJCOPY_dump_section)) { 862 StringRef Value(Arg->getValue()); 863 if (Value.split('=').second.empty()) 864 return createStringError( 865 errc::invalid_argument, 866 "bad format for --dump-section, expected section=file"); 867 Config.DumpSection.push_back(Value); 868 } 869 Config.StripAll = InputArgs.hasArg(OBJCOPY_strip_all); 870 Config.StripAllGNU = InputArgs.hasArg(OBJCOPY_strip_all_gnu); 871 Config.StripDebug = InputArgs.hasArg(OBJCOPY_strip_debug); 872 Config.StripDWO = InputArgs.hasArg(OBJCOPY_strip_dwo); 873 Config.StripSections = InputArgs.hasArg(OBJCOPY_strip_sections); 874 Config.StripNonAlloc = InputArgs.hasArg(OBJCOPY_strip_non_alloc); 875 Config.StripUnneeded = InputArgs.hasArg(OBJCOPY_strip_unneeded); 876 Config.ExtractDWO = InputArgs.hasArg(OBJCOPY_extract_dwo); 877 Config.ExtractMainPartition = 878 InputArgs.hasArg(OBJCOPY_extract_main_partition); 879 ELFConfig.LocalizeHidden = InputArgs.hasArg(OBJCOPY_localize_hidden); 880 Config.Weaken = InputArgs.hasArg(OBJCOPY_weaken); 881 if (auto *Arg = 882 InputArgs.getLastArg(OBJCOPY_discard_all, OBJCOPY_discard_locals)) { 883 Config.DiscardMode = Arg->getOption().matches(OBJCOPY_discard_all) 884 ? DiscardType::All 885 : DiscardType::Locals; 886 } 887 Config.OnlyKeepDebug = InputArgs.hasArg(OBJCOPY_only_keep_debug); 888 ELFConfig.KeepFileSymbols = InputArgs.hasArg(OBJCOPY_keep_file_symbols); 889 MachOConfig.KeepUndefined = InputArgs.hasArg(OBJCOPY_keep_undefined); 890 Config.DecompressDebugSections = 891 InputArgs.hasArg(OBJCOPY_decompress_debug_sections); 892 if (Config.DiscardMode == DiscardType::All) { 893 Config.StripDebug = true; 894 ELFConfig.KeepFileSymbols = true; 895 } 896 for (auto *Arg : InputArgs.filtered(OBJCOPY_localize_symbol)) 897 if (Error E = Config.SymbolsToLocalize.addMatcher(NameOrPattern::create( 898 Arg->getValue(), SymbolMatchStyle, ErrorCallback))) 899 return std::move(E); 900 for (auto *Arg : InputArgs.filtered(OBJCOPY_localize_symbols)) 901 if (Error E = addSymbolsFromFile(Config.SymbolsToLocalize, DC.Alloc, 902 Arg->getValue(), SymbolMatchStyle, 903 ErrorCallback)) 904 return std::move(E); 905 for (auto *Arg : InputArgs.filtered(OBJCOPY_keep_global_symbol)) 906 if (Error E = Config.SymbolsToKeepGlobal.addMatcher(NameOrPattern::create( 907 Arg->getValue(), SymbolMatchStyle, ErrorCallback))) 908 return std::move(E); 909 for (auto *Arg : InputArgs.filtered(OBJCOPY_keep_global_symbols)) 910 if (Error E = addSymbolsFromFile(Config.SymbolsToKeepGlobal, DC.Alloc, 911 Arg->getValue(), SymbolMatchStyle, 912 ErrorCallback)) 913 return std::move(E); 914 for (auto *Arg : InputArgs.filtered(OBJCOPY_globalize_symbol)) 915 if (Error E = Config.SymbolsToGlobalize.addMatcher(NameOrPattern::create( 916 Arg->getValue(), SymbolMatchStyle, ErrorCallback))) 917 return std::move(E); 918 for (auto *Arg : InputArgs.filtered(OBJCOPY_globalize_symbols)) 919 if (Error E = addSymbolsFromFile(Config.SymbolsToGlobalize, DC.Alloc, 920 Arg->getValue(), SymbolMatchStyle, 921 ErrorCallback)) 922 return std::move(E); 923 for (auto *Arg : InputArgs.filtered(OBJCOPY_weaken_symbol)) 924 if (Error E = Config.SymbolsToWeaken.addMatcher(NameOrPattern::create( 925 Arg->getValue(), SymbolMatchStyle, ErrorCallback))) 926 return std::move(E); 927 for (auto *Arg : InputArgs.filtered(OBJCOPY_weaken_symbols)) 928 if (Error E = addSymbolsFromFile(Config.SymbolsToWeaken, DC.Alloc, 929 Arg->getValue(), SymbolMatchStyle, 930 ErrorCallback)) 931 return std::move(E); 932 for (auto *Arg : InputArgs.filtered(OBJCOPY_strip_symbol)) 933 if (Error E = Config.SymbolsToRemove.addMatcher(NameOrPattern::create( 934 Arg->getValue(), SymbolMatchStyle, ErrorCallback))) 935 return std::move(E); 936 for (auto *Arg : InputArgs.filtered(OBJCOPY_strip_symbols)) 937 if (Error E = addSymbolsFromFile(Config.SymbolsToRemove, DC.Alloc, 938 Arg->getValue(), SymbolMatchStyle, 939 ErrorCallback)) 940 return std::move(E); 941 for (auto *Arg : InputArgs.filtered(OBJCOPY_strip_unneeded_symbol)) 942 if (Error E = 943 Config.UnneededSymbolsToRemove.addMatcher(NameOrPattern::create( 944 Arg->getValue(), SymbolMatchStyle, ErrorCallback))) 945 return std::move(E); 946 for (auto *Arg : InputArgs.filtered(OBJCOPY_strip_unneeded_symbols)) 947 if (Error E = addSymbolsFromFile(Config.UnneededSymbolsToRemove, DC.Alloc, 948 Arg->getValue(), SymbolMatchStyle, 949 ErrorCallback)) 950 return std::move(E); 951 for (auto *Arg : InputArgs.filtered(OBJCOPY_keep_symbol)) 952 if (Error E = Config.SymbolsToKeep.addMatcher(NameOrPattern::create( 953 Arg->getValue(), SymbolMatchStyle, ErrorCallback))) 954 return std::move(E); 955 for (auto *Arg : InputArgs.filtered(OBJCOPY_keep_symbols)) 956 if (Error E = 957 addSymbolsFromFile(Config.SymbolsToKeep, DC.Alloc, Arg->getValue(), 958 SymbolMatchStyle, ErrorCallback)) 959 return std::move(E); 960 for (auto *Arg : InputArgs.filtered(OBJCOPY_add_symbol)) { 961 Expected<NewSymbolInfo> SymInfo = parseNewSymbolInfo(Arg->getValue()); 962 if (!SymInfo) 963 return SymInfo.takeError(); 964 965 Config.SymbolsToAdd.push_back(*SymInfo); 966 } 967 968 ELFConfig.AllowBrokenLinks = InputArgs.hasArg(OBJCOPY_allow_broken_links); 969 970 Config.DeterministicArchives = InputArgs.hasFlag( 971 OBJCOPY_enable_deterministic_archives, 972 OBJCOPY_disable_deterministic_archives, /*default=*/true); 973 974 Config.PreserveDates = InputArgs.hasArg(OBJCOPY_preserve_dates); 975 976 if (Config.PreserveDates && 977 (Config.OutputFilename == "-" || Config.InputFilename == "-")) 978 return createStringError(errc::invalid_argument, 979 "--preserve-dates requires a file"); 980 981 for (auto *Arg : InputArgs) 982 if (Arg->getOption().matches(OBJCOPY_set_start)) { 983 auto EAddr = getAsInteger<uint64_t>(Arg->getValue()); 984 if (!EAddr) 985 return createStringError( 986 EAddr.getError(), "bad entry point address: '%s'", Arg->getValue()); 987 988 ELFConfig.EntryExpr = [EAddr](uint64_t) { return *EAddr; }; 989 } else if (Arg->getOption().matches(OBJCOPY_change_start)) { 990 auto EIncr = getAsInteger<int64_t>(Arg->getValue()); 991 if (!EIncr) 992 return createStringError(EIncr.getError(), 993 "bad entry point increment: '%s'", 994 Arg->getValue()); 995 auto Expr = ELFConfig.EntryExpr ? std::move(ELFConfig.EntryExpr) 996 : [](uint64_t A) { return A; }; 997 ELFConfig.EntryExpr = [Expr, EIncr](uint64_t EAddr) { 998 return Expr(EAddr) + *EIncr; 999 }; 1000 } 1001 1002 if (Config.DecompressDebugSections && 1003 Config.CompressionType != DebugCompressionType::None) { 1004 return createStringError( 1005 errc::invalid_argument, 1006 "cannot specify both --compress-debug-sections and " 1007 "--decompress-debug-sections"); 1008 } 1009 1010 if (Config.ExtractPartition && Config.ExtractMainPartition) 1011 return createStringError(errc::invalid_argument, 1012 "cannot specify --extract-partition together with " 1013 "--extract-main-partition"); 1014 1015 DC.CopyConfigs.push_back(std::move(ConfigMgr)); 1016 return std::move(DC); 1017} 1018 1019// parseInstallNameToolOptions returns the config and sets the input arguments. 1020// If a help flag is set then parseInstallNameToolOptions will print the help 1021// messege and exit. 1022Expected<DriverConfig> 1023objcopy::parseInstallNameToolOptions(ArrayRef<const char *> ArgsArr) { 1024 DriverConfig DC; 1025 ConfigManager ConfigMgr; 1026 CommonConfig &Config = ConfigMgr.Common; 1027 MachOConfig &MachOConfig = ConfigMgr.MachO; 1028 InstallNameToolOptTable T; 1029 unsigned MissingArgumentIndex, MissingArgumentCount; 1030 llvm::opt::InputArgList InputArgs = 1031 T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount); 1032 1033 if (MissingArgumentCount) 1034 return createStringError( 1035 errc::invalid_argument, 1036 "missing argument to " + 1037 StringRef(InputArgs.getArgString(MissingArgumentIndex)) + 1038 " option"); 1039 1040 if (InputArgs.size() == 0) { 1041 printHelp(T, errs(), ToolType::InstallNameTool); 1042 exit(1); 1043 } 1044 1045 if (InputArgs.hasArg(INSTALL_NAME_TOOL_help)) { 1046 printHelp(T, outs(), ToolType::InstallNameTool); 1047 exit(0); 1048 } 1049 1050 if (InputArgs.hasArg(INSTALL_NAME_TOOL_version)) { 1051 outs() << "llvm-install-name-tool, compatible with cctools " 1052 "install_name_tool\n"; 1053 cl::PrintVersionMessage(); 1054 exit(0); 1055 } 1056 1057 for (auto *Arg : InputArgs.filtered(INSTALL_NAME_TOOL_add_rpath)) 1058 MachOConfig.RPathToAdd.push_back(Arg->getValue()); 1059 1060 for (auto *Arg : InputArgs.filtered(INSTALL_NAME_TOOL_prepend_rpath)) 1061 MachOConfig.RPathToPrepend.push_back(Arg->getValue()); 1062 1063 for (auto *Arg : InputArgs.filtered(INSTALL_NAME_TOOL_delete_rpath)) { 1064 StringRef RPath = Arg->getValue(); 1065 1066 // Cannot add and delete the same rpath at the same time. 1067 if (is_contained(MachOConfig.RPathToAdd, RPath)) 1068 return createStringError( 1069 errc::invalid_argument, 1070 "cannot specify both -add_rpath '%s' and -delete_rpath '%s'", 1071 RPath.str().c_str(), RPath.str().c_str()); 1072 if (is_contained(MachOConfig.RPathToPrepend, RPath)) 1073 return createStringError( 1074 errc::invalid_argument, 1075 "cannot specify both -prepend_rpath '%s' and -delete_rpath '%s'", 1076 RPath.str().c_str(), RPath.str().c_str()); 1077 1078 MachOConfig.RPathsToRemove.insert(RPath); 1079 } 1080 1081 for (auto *Arg : InputArgs.filtered(INSTALL_NAME_TOOL_rpath)) { 1082 StringRef Old = Arg->getValue(0); 1083 StringRef New = Arg->getValue(1); 1084 1085 auto Match = [=](StringRef RPath) { return RPath == Old || RPath == New; }; 1086 1087 // Cannot specify duplicate -rpath entries 1088 auto It1 = find_if( 1089 MachOConfig.RPathsToUpdate, 1090 [&Match](const DenseMap<StringRef, StringRef>::value_type &OldNew) { 1091 return Match(OldNew.getFirst()) || Match(OldNew.getSecond()); 1092 }); 1093 if (It1 != MachOConfig.RPathsToUpdate.end()) 1094 return createStringError(errc::invalid_argument, 1095 "cannot specify both -rpath '" + 1096 It1->getFirst() + "' '" + It1->getSecond() + 1097 "' and -rpath '" + Old + "' '" + New + "'"); 1098 1099 // Cannot specify the same rpath under both -delete_rpath and -rpath 1100 auto It2 = find_if(MachOConfig.RPathsToRemove, Match); 1101 if (It2 != MachOConfig.RPathsToRemove.end()) 1102 return createStringError(errc::invalid_argument, 1103 "cannot specify both -delete_rpath '" + *It2 + 1104 "' and -rpath '" + Old + "' '" + New + "'"); 1105 1106 // Cannot specify the same rpath under both -add_rpath and -rpath 1107 auto It3 = find_if(MachOConfig.RPathToAdd, Match); 1108 if (It3 != MachOConfig.RPathToAdd.end()) 1109 return createStringError(errc::invalid_argument, 1110 "cannot specify both -add_rpath '" + *It3 + 1111 "' and -rpath '" + Old + "' '" + New + "'"); 1112 1113 // Cannot specify the same rpath under both -prepend_rpath and -rpath. 1114 auto It4 = find_if(MachOConfig.RPathToPrepend, Match); 1115 if (It4 != MachOConfig.RPathToPrepend.end()) 1116 return createStringError(errc::invalid_argument, 1117 "cannot specify both -prepend_rpath '" + *It4 + 1118 "' and -rpath '" + Old + "' '" + New + "'"); 1119 1120 MachOConfig.RPathsToUpdate.insert({Old, New}); 1121 } 1122 1123 if (auto *Arg = InputArgs.getLastArg(INSTALL_NAME_TOOL_id)) { 1124 MachOConfig.SharedLibId = Arg->getValue(); 1125 if (MachOConfig.SharedLibId->empty()) 1126 return createStringError(errc::invalid_argument, 1127 "cannot specify an empty id"); 1128 } 1129 1130 for (auto *Arg : InputArgs.filtered(INSTALL_NAME_TOOL_change)) 1131 MachOConfig.InstallNamesToUpdate.insert( 1132 {Arg->getValue(0), Arg->getValue(1)}); 1133 1134 MachOConfig.RemoveAllRpaths = 1135 InputArgs.hasArg(INSTALL_NAME_TOOL_delete_all_rpaths); 1136 1137 SmallVector<StringRef, 2> Positional; 1138 for (auto *Arg : InputArgs.filtered(INSTALL_NAME_TOOL_UNKNOWN)) 1139 return createStringError(errc::invalid_argument, "unknown argument '%s'", 1140 Arg->getAsString(InputArgs).c_str()); 1141 for (auto *Arg : InputArgs.filtered(INSTALL_NAME_TOOL_INPUT)) 1142 Positional.push_back(Arg->getValue()); 1143 if (Positional.empty()) 1144 return createStringError(errc::invalid_argument, "no input file specified"); 1145 if (Positional.size() > 1) 1146 return createStringError( 1147 errc::invalid_argument, 1148 "llvm-install-name-tool expects a single input file"); 1149 Config.InputFilename = Positional[0]; 1150 Config.OutputFilename = Positional[0]; 1151 1152 DC.CopyConfigs.push_back(std::move(ConfigMgr)); 1153 return std::move(DC); 1154} 1155 1156Expected<DriverConfig> 1157objcopy::parseBitcodeStripOptions(ArrayRef<const char *> ArgsArr, 1158 function_ref<Error(Error)> ErrorCallback) { 1159 DriverConfig DC; 1160 ConfigManager ConfigMgr; 1161 CommonConfig &Config = ConfigMgr.Common; 1162 MachOConfig &MachOConfig = ConfigMgr.MachO; 1163 BitcodeStripOptTable T; 1164 unsigned MissingArgumentIndex, MissingArgumentCount; 1165 opt::InputArgList InputArgs = 1166 T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount); 1167 1168 if (InputArgs.size() == 0) { 1169 printHelp(T, errs(), ToolType::BitcodeStrip); 1170 exit(1); 1171 } 1172 1173 if (InputArgs.hasArg(BITCODE_STRIP_help)) { 1174 printHelp(T, outs(), ToolType::BitcodeStrip); 1175 exit(0); 1176 } 1177 1178 if (InputArgs.hasArg(BITCODE_STRIP_version)) { 1179 outs() << "llvm-bitcode-strip, compatible with cctools " 1180 "bitcode_strip\n"; 1181 cl::PrintVersionMessage(); 1182 exit(0); 1183 } 1184 1185 for (auto *Arg : InputArgs.filtered(BITCODE_STRIP_UNKNOWN)) 1186 return createStringError(errc::invalid_argument, "unknown argument '%s'", 1187 Arg->getAsString(InputArgs).c_str()); 1188 1189 SmallVector<StringRef, 2> Positional; 1190 for (auto *Arg : InputArgs.filtered(BITCODE_STRIP_INPUT)) 1191 Positional.push_back(Arg->getValue()); 1192 if (Positional.size() > 1) 1193 return createStringError(errc::invalid_argument, 1194 "llvm-bitcode-strip expects a single input file"); 1195 assert(!Positional.empty()); 1196 Config.InputFilename = Positional[0]; 1197 1198 if (!InputArgs.hasArg(BITCODE_STRIP_output)) { 1199 return createStringError(errc::invalid_argument, 1200 "-o is a required argument"); 1201 } 1202 Config.OutputFilename = InputArgs.getLastArgValue(BITCODE_STRIP_output); 1203 1204 if (!InputArgs.hasArg(BITCODE_STRIP_remove)) 1205 return createStringError(errc::invalid_argument, "no action specified"); 1206 1207 // We only support -r for now, which removes all bitcode sections and 1208 // the __LLVM segment if it's now empty. 1209 cantFail(Config.ToRemove.addMatcher(NameOrPattern::create( 1210 "__LLVM,__asm", MatchStyle::Literal, ErrorCallback))); 1211 cantFail(Config.ToRemove.addMatcher(NameOrPattern::create( 1212 "__LLVM,__bitcode", MatchStyle::Literal, ErrorCallback))); 1213 cantFail(Config.ToRemove.addMatcher(NameOrPattern::create( 1214 "__LLVM,__bundle", MatchStyle::Literal, ErrorCallback))); 1215 cantFail(Config.ToRemove.addMatcher(NameOrPattern::create( 1216 "__LLVM,__cmdline", MatchStyle::Literal, ErrorCallback))); 1217 cantFail(Config.ToRemove.addMatcher(NameOrPattern::create( 1218 "__LLVM,__swift_cmdline", MatchStyle::Literal, ErrorCallback))); 1219 MachOConfig.EmptySegmentsToRemove.insert("__LLVM"); 1220 1221 DC.CopyConfigs.push_back(std::move(ConfigMgr)); 1222 return std::move(DC); 1223} 1224 1225// parseStripOptions returns the config and sets the input arguments. If a 1226// help flag is set then parseStripOptions will print the help messege and 1227// exit. 1228Expected<DriverConfig> 1229objcopy::parseStripOptions(ArrayRef<const char *> RawArgsArr, 1230 function_ref<Error(Error)> ErrorCallback) { 1231 const char *const *DashDash = 1232 llvm::find_if(RawArgsArr, [](StringRef Str) { return Str == "--"; }); 1233 ArrayRef<const char *> ArgsArr = ArrayRef(RawArgsArr.begin(), DashDash); 1234 if (DashDash != RawArgsArr.end()) 1235 DashDash = std::next(DashDash); 1236 1237 StripOptTable T; 1238 unsigned MissingArgumentIndex, MissingArgumentCount; 1239 llvm::opt::InputArgList InputArgs = 1240 T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount); 1241 1242 if (InputArgs.size() == 0 && DashDash == RawArgsArr.end()) { 1243 printHelp(T, errs(), ToolType::Strip); 1244 exit(1); 1245 } 1246 1247 if (InputArgs.hasArg(STRIP_help)) { 1248 printHelp(T, outs(), ToolType::Strip); 1249 exit(0); 1250 } 1251 1252 if (InputArgs.hasArg(STRIP_version)) { 1253 outs() << "llvm-strip, compatible with GNU strip\n"; 1254 cl::PrintVersionMessage(); 1255 exit(0); 1256 } 1257 1258 SmallVector<StringRef, 2> Positional; 1259 for (auto *Arg : InputArgs.filtered(STRIP_UNKNOWN)) 1260 return createStringError(errc::invalid_argument, "unknown argument '%s'", 1261 Arg->getAsString(InputArgs).c_str()); 1262 for (auto *Arg : InputArgs.filtered(STRIP_INPUT)) 1263 Positional.push_back(Arg->getValue()); 1264 std::copy(DashDash, RawArgsArr.end(), std::back_inserter(Positional)); 1265 1266 if (Positional.empty()) 1267 return createStringError(errc::invalid_argument, "no input file specified"); 1268 1269 if (Positional.size() > 1 && InputArgs.hasArg(STRIP_output)) 1270 return createStringError( 1271 errc::invalid_argument, 1272 "multiple input files cannot be used in combination with -o"); 1273 1274 ConfigManager ConfigMgr; 1275 CommonConfig &Config = ConfigMgr.Common; 1276 ELFConfig &ELFConfig = ConfigMgr.ELF; 1277 MachOConfig &MachOConfig = ConfigMgr.MachO; 1278 1279 if (InputArgs.hasArg(STRIP_regex) && InputArgs.hasArg(STRIP_wildcard)) 1280 return createStringError(errc::invalid_argument, 1281 "--regex and --wildcard are incompatible"); 1282 MatchStyle SectionMatchStyle = 1283 InputArgs.hasArg(STRIP_regex) ? MatchStyle::Regex : MatchStyle::Wildcard; 1284 MatchStyle SymbolMatchStyle 1285 = InputArgs.hasArg(STRIP_regex) ? MatchStyle::Regex 1286 : InputArgs.hasArg(STRIP_wildcard) ? MatchStyle::Wildcard 1287 : MatchStyle::Literal; 1288 ELFConfig.AllowBrokenLinks = InputArgs.hasArg(STRIP_allow_broken_links); 1289 Config.StripDebug = InputArgs.hasArg(STRIP_strip_debug); 1290 1291 if (auto *Arg = InputArgs.getLastArg(STRIP_discard_all, STRIP_discard_locals)) 1292 Config.DiscardMode = Arg->getOption().matches(STRIP_discard_all) 1293 ? DiscardType::All 1294 : DiscardType::Locals; 1295 Config.StripSections = InputArgs.hasArg(STRIP_strip_sections); 1296 Config.StripUnneeded = InputArgs.hasArg(STRIP_strip_unneeded); 1297 if (auto Arg = InputArgs.getLastArg(STRIP_strip_all, STRIP_no_strip_all)) 1298 Config.StripAll = Arg->getOption().getID() == STRIP_strip_all; 1299 Config.StripAllGNU = InputArgs.hasArg(STRIP_strip_all_gnu); 1300 MachOConfig.StripSwiftSymbols = InputArgs.hasArg(STRIP_strip_swift_symbols); 1301 Config.OnlyKeepDebug = InputArgs.hasArg(STRIP_only_keep_debug); 1302 ELFConfig.KeepFileSymbols = InputArgs.hasArg(STRIP_keep_file_symbols); 1303 MachOConfig.KeepUndefined = InputArgs.hasArg(STRIP_keep_undefined); 1304 1305 for (auto *Arg : InputArgs.filtered(STRIP_keep_section)) 1306 if (Error E = Config.KeepSection.addMatcher(NameOrPattern::create( 1307 Arg->getValue(), SectionMatchStyle, ErrorCallback))) 1308 return std::move(E); 1309 1310 for (auto *Arg : InputArgs.filtered(STRIP_remove_section)) 1311 if (Error E = Config.ToRemove.addMatcher(NameOrPattern::create( 1312 Arg->getValue(), SectionMatchStyle, ErrorCallback))) 1313 return std::move(E); 1314 1315 for (auto *Arg : InputArgs.filtered(STRIP_strip_symbol)) 1316 if (Error E = Config.SymbolsToRemove.addMatcher(NameOrPattern::create( 1317 Arg->getValue(), SymbolMatchStyle, ErrorCallback))) 1318 return std::move(E); 1319 1320 for (auto *Arg : InputArgs.filtered(STRIP_keep_symbol)) 1321 if (Error E = Config.SymbolsToKeep.addMatcher(NameOrPattern::create( 1322 Arg->getValue(), SymbolMatchStyle, ErrorCallback))) 1323 return std::move(E); 1324 1325 if (!InputArgs.hasArg(STRIP_no_strip_all) && !Config.StripDebug && 1326 !Config.OnlyKeepDebug && !Config.StripUnneeded && 1327 Config.DiscardMode == DiscardType::None && !Config.StripAllGNU && 1328 Config.SymbolsToRemove.empty()) 1329 Config.StripAll = true; 1330 1331 if (Config.DiscardMode == DiscardType::All) { 1332 Config.StripDebug = true; 1333 ELFConfig.KeepFileSymbols = true; 1334 } 1335 1336 Config.DeterministicArchives = 1337 InputArgs.hasFlag(STRIP_enable_deterministic_archives, 1338 STRIP_disable_deterministic_archives, /*default=*/true); 1339 1340 Config.PreserveDates = InputArgs.hasArg(STRIP_preserve_dates); 1341 Config.InputFormat = FileFormat::Unspecified; 1342 Config.OutputFormat = FileFormat::Unspecified; 1343 1344 DriverConfig DC; 1345 if (Positional.size() == 1) { 1346 Config.InputFilename = Positional[0]; 1347 Config.OutputFilename = 1348 InputArgs.getLastArgValue(STRIP_output, Positional[0]); 1349 DC.CopyConfigs.push_back(std::move(ConfigMgr)); 1350 } else { 1351 StringMap<unsigned> InputFiles; 1352 for (StringRef Filename : Positional) { 1353 if (InputFiles[Filename]++ == 1) { 1354 if (Filename == "-") 1355 return createStringError( 1356 errc::invalid_argument, 1357 "cannot specify '-' as an input file more than once"); 1358 if (Error E = ErrorCallback(createStringError( 1359 errc::invalid_argument, "'%s' was already specified", 1360 Filename.str().c_str()))) 1361 return std::move(E); 1362 } 1363 Config.InputFilename = Filename; 1364 Config.OutputFilename = Filename; 1365 DC.CopyConfigs.push_back(ConfigMgr); 1366 } 1367 } 1368 1369 if (Config.PreserveDates && (is_contained(Positional, "-") || 1370 InputArgs.getLastArgValue(STRIP_output) == "-")) 1371 return createStringError(errc::invalid_argument, 1372 "--preserve-dates requires a file"); 1373 1374 return std::move(DC); 1375} 1376