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