1//===- CopyConfig.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 "CopyConfig.h" 10 11#include "llvm/ADT/Optional.h" 12#include "llvm/ADT/SmallVector.h" 13#include "llvm/ADT/StringRef.h" 14#include "llvm/ADT/StringSet.h" 15#include "llvm/Option/Arg.h" 16#include "llvm/Option/ArgList.h" 17#include "llvm/Support/CRC.h" 18#include "llvm/Support/CommandLine.h" 19#include "llvm/Support/Compression.h" 20#include "llvm/Support/Errc.h" 21#include "llvm/Support/MemoryBuffer.h" 22#include "llvm/Support/StringSaver.h" 23#include <memory> 24 25namespace llvm { 26namespace objcopy { 27 28namespace { 29enum ObjcopyID { 30 OBJCOPY_INVALID = 0, // This is not an option ID. 31#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ 32 HELPTEXT, METAVAR, VALUES) \ 33 OBJCOPY_##ID, 34#include "ObjcopyOpts.inc" 35#undef OPTION 36}; 37 38#define PREFIX(NAME, VALUE) const char *const OBJCOPY_##NAME[] = VALUE; 39#include "ObjcopyOpts.inc" 40#undef PREFIX 41 42static const opt::OptTable::Info ObjcopyInfoTable[] = { 43#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ 44 HELPTEXT, METAVAR, VALUES) \ 45 {OBJCOPY_##PREFIX, \ 46 NAME, \ 47 HELPTEXT, \ 48 METAVAR, \ 49 OBJCOPY_##ID, \ 50 opt::Option::KIND##Class, \ 51 PARAM, \ 52 FLAGS, \ 53 OBJCOPY_##GROUP, \ 54 OBJCOPY_##ALIAS, \ 55 ALIASARGS, \ 56 VALUES}, 57#include "ObjcopyOpts.inc" 58#undef OPTION 59}; 60 61class ObjcopyOptTable : public opt::OptTable { 62public: 63 ObjcopyOptTable() : OptTable(ObjcopyInfoTable) {} 64}; 65 66enum InstallNameToolID { 67 INSTALL_NAME_TOOL_INVALID = 0, // This is not an option ID. 68#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ 69 HELPTEXT, METAVAR, VALUES) \ 70 INSTALL_NAME_TOOL_##ID, 71#include "InstallNameToolOpts.inc" 72#undef OPTION 73}; 74 75#define PREFIX(NAME, VALUE) \ 76 const char *const INSTALL_NAME_TOOL_##NAME[] = VALUE; 77#include "InstallNameToolOpts.inc" 78#undef PREFIX 79 80static const opt::OptTable::Info InstallNameToolInfoTable[] = { 81#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ 82 HELPTEXT, METAVAR, VALUES) \ 83 {INSTALL_NAME_TOOL_##PREFIX, \ 84 NAME, \ 85 HELPTEXT, \ 86 METAVAR, \ 87 INSTALL_NAME_TOOL_##ID, \ 88 opt::Option::KIND##Class, \ 89 PARAM, \ 90 FLAGS, \ 91 INSTALL_NAME_TOOL_##GROUP, \ 92 INSTALL_NAME_TOOL_##ALIAS, \ 93 ALIASARGS, \ 94 VALUES}, 95#include "InstallNameToolOpts.inc" 96#undef OPTION 97}; 98 99class InstallNameToolOptTable : public opt::OptTable { 100public: 101 InstallNameToolOptTable() : OptTable(InstallNameToolInfoTable) {} 102}; 103 104enum StripID { 105 STRIP_INVALID = 0, // This is not an option ID. 106#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ 107 HELPTEXT, METAVAR, VALUES) \ 108 STRIP_##ID, 109#include "StripOpts.inc" 110#undef OPTION 111}; 112 113#define PREFIX(NAME, VALUE) const char *const STRIP_##NAME[] = VALUE; 114#include "StripOpts.inc" 115#undef PREFIX 116 117static const opt::OptTable::Info StripInfoTable[] = { 118#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ 119 HELPTEXT, METAVAR, VALUES) \ 120 {STRIP_##PREFIX, NAME, HELPTEXT, \ 121 METAVAR, STRIP_##ID, opt::Option::KIND##Class, \ 122 PARAM, FLAGS, STRIP_##GROUP, \ 123 STRIP_##ALIAS, ALIASARGS, VALUES}, 124#include "StripOpts.inc" 125#undef OPTION 126}; 127 128class StripOptTable : public opt::OptTable { 129public: 130 StripOptTable() : OptTable(StripInfoTable) {} 131}; 132 133} // namespace 134 135static SectionFlag parseSectionRenameFlag(StringRef SectionName) { 136 return llvm::StringSwitch<SectionFlag>(SectionName) 137 .CaseLower("alloc", SectionFlag::SecAlloc) 138 .CaseLower("load", SectionFlag::SecLoad) 139 .CaseLower("noload", SectionFlag::SecNoload) 140 .CaseLower("readonly", SectionFlag::SecReadonly) 141 .CaseLower("debug", SectionFlag::SecDebug) 142 .CaseLower("code", SectionFlag::SecCode) 143 .CaseLower("data", SectionFlag::SecData) 144 .CaseLower("rom", SectionFlag::SecRom) 145 .CaseLower("merge", SectionFlag::SecMerge) 146 .CaseLower("strings", SectionFlag::SecStrings) 147 .CaseLower("contents", SectionFlag::SecContents) 148 .CaseLower("share", SectionFlag::SecShare) 149 .CaseLower("exclude", SectionFlag::SecExclude) 150 .Default(SectionFlag::SecNone); 151} 152 153static Expected<SectionFlag> 154parseSectionFlagSet(ArrayRef<StringRef> SectionFlags) { 155 SectionFlag ParsedFlags = SectionFlag::SecNone; 156 for (StringRef Flag : SectionFlags) { 157 SectionFlag ParsedFlag = parseSectionRenameFlag(Flag); 158 if (ParsedFlag == SectionFlag::SecNone) 159 return createStringError( 160 errc::invalid_argument, 161 "unrecognized section flag '%s'. Flags supported for GNU " 162 "compatibility: alloc, load, noload, readonly, exclude, debug, " 163 "code, data, rom, share, contents, merge, strings", 164 Flag.str().c_str()); 165 ParsedFlags |= ParsedFlag; 166 } 167 168 return ParsedFlags; 169} 170 171static Expected<SectionRename> parseRenameSectionValue(StringRef FlagValue) { 172 if (!FlagValue.contains('=')) 173 return createStringError(errc::invalid_argument, 174 "bad format for --rename-section: missing '='"); 175 176 // Initial split: ".foo" = ".bar,f1,f2,..." 177 auto Old2New = FlagValue.split('='); 178 SectionRename SR; 179 SR.OriginalName = Old2New.first; 180 181 // Flags split: ".bar" "f1" "f2" ... 182 SmallVector<StringRef, 6> NameAndFlags; 183 Old2New.second.split(NameAndFlags, ','); 184 SR.NewName = NameAndFlags[0]; 185 186 if (NameAndFlags.size() > 1) { 187 Expected<SectionFlag> ParsedFlagSet = 188 parseSectionFlagSet(makeArrayRef(NameAndFlags).drop_front()); 189 if (!ParsedFlagSet) 190 return ParsedFlagSet.takeError(); 191 SR.NewFlags = *ParsedFlagSet; 192 } 193 194 return SR; 195} 196 197static Expected<std::pair<StringRef, uint64_t>> 198parseSetSectionAlignment(StringRef FlagValue) { 199 if (!FlagValue.contains('=')) 200 return createStringError( 201 errc::invalid_argument, 202 "bad format for --set-section-alignment: missing '='"); 203 auto Split = StringRef(FlagValue).split('='); 204 if (Split.first.empty()) 205 return createStringError( 206 errc::invalid_argument, 207 "bad format for --set-section-alignment: missing section name"); 208 uint64_t NewAlign; 209 if (Split.second.getAsInteger(0, NewAlign)) 210 return createStringError(errc::invalid_argument, 211 "invalid alignment for --set-section-alignment: '%s'", 212 Split.second.str().c_str()); 213 return std::make_pair(Split.first, NewAlign); 214} 215 216static Expected<SectionFlagsUpdate> 217parseSetSectionFlagValue(StringRef FlagValue) { 218 if (!StringRef(FlagValue).contains('=')) 219 return createStringError(errc::invalid_argument, 220 "bad format for --set-section-flags: missing '='"); 221 222 // Initial split: ".foo" = "f1,f2,..." 223 auto Section2Flags = StringRef(FlagValue).split('='); 224 SectionFlagsUpdate SFU; 225 SFU.Name = Section2Flags.first; 226 227 // Flags split: "f1" "f2" ... 228 SmallVector<StringRef, 6> SectionFlags; 229 Section2Flags.second.split(SectionFlags, ','); 230 Expected<SectionFlag> ParsedFlagSet = parseSectionFlagSet(SectionFlags); 231 if (!ParsedFlagSet) 232 return ParsedFlagSet.takeError(); 233 SFU.NewFlags = *ParsedFlagSet; 234 235 return SFU; 236} 237 238struct TargetInfo { 239 FileFormat Format; 240 MachineInfo Machine; 241}; 242 243// FIXME: consolidate with the bfd parsing used by lld. 244static const StringMap<MachineInfo> TargetMap{ 245 // Name, {EMachine, 64bit, LittleEndian} 246 // x86 247 {"elf32-i386", {ELF::EM_386, false, true}}, 248 {"elf32-x86-64", {ELF::EM_X86_64, false, true}}, 249 {"elf64-x86-64", {ELF::EM_X86_64, true, true}}, 250 // Intel MCU 251 {"elf32-iamcu", {ELF::EM_IAMCU, false, true}}, 252 // ARM 253 {"elf32-littlearm", {ELF::EM_ARM, false, true}}, 254 // ARM AArch64 255 {"elf64-aarch64", {ELF::EM_AARCH64, true, true}}, 256 {"elf64-littleaarch64", {ELF::EM_AARCH64, true, true}}, 257 // RISC-V 258 {"elf32-littleriscv", {ELF::EM_RISCV, false, true}}, 259 {"elf64-littleriscv", {ELF::EM_RISCV, true, true}}, 260 // PowerPC 261 {"elf32-powerpc", {ELF::EM_PPC, false, false}}, 262 {"elf32-powerpcle", {ELF::EM_PPC, false, true}}, 263 {"elf64-powerpc", {ELF::EM_PPC64, true, false}}, 264 {"elf64-powerpcle", {ELF::EM_PPC64, true, true}}, 265 // MIPS 266 {"elf32-bigmips", {ELF::EM_MIPS, false, false}}, 267 {"elf32-ntradbigmips", {ELF::EM_MIPS, false, false}}, 268 {"elf32-ntradlittlemips", {ELF::EM_MIPS, false, true}}, 269 {"elf32-tradbigmips", {ELF::EM_MIPS, false, false}}, 270 {"elf32-tradlittlemips", {ELF::EM_MIPS, false, true}}, 271 {"elf64-tradbigmips", {ELF::EM_MIPS, true, false}}, 272 {"elf64-tradlittlemips", {ELF::EM_MIPS, true, true}}, 273 // SPARC 274 {"elf32-sparc", {ELF::EM_SPARC, false, false}}, 275 {"elf32-sparcel", {ELF::EM_SPARC, false, true}}, 276 {"elf32-hexagon", {ELF::EM_HEXAGON, false, true}}, 277}; 278 279static Expected<TargetInfo> 280getOutputTargetInfoByTargetName(StringRef TargetName) { 281 StringRef OriginalTargetName = TargetName; 282 bool IsFreeBSD = TargetName.consume_back("-freebsd"); 283 auto Iter = TargetMap.find(TargetName); 284 if (Iter == std::end(TargetMap)) 285 return createStringError(errc::invalid_argument, 286 "invalid output format: '%s'", 287 OriginalTargetName.str().c_str()); 288 MachineInfo MI = Iter->getValue(); 289 if (IsFreeBSD) 290 MI.OSABI = ELF::ELFOSABI_FREEBSD; 291 292 FileFormat Format; 293 if (TargetName.startswith("elf")) 294 Format = FileFormat::ELF; 295 else 296 // This should never happen because `TargetName` is valid (it certainly 297 // exists in the TargetMap). 298 llvm_unreachable("unknown target prefix"); 299 300 return {TargetInfo{Format, MI}}; 301} 302 303static Error 304addSymbolsFromFile(NameMatcher &Symbols, BumpPtrAllocator &Alloc, 305 StringRef Filename, MatchStyle MS, 306 llvm::function_ref<Error(Error)> ErrorCallback) { 307 StringSaver Saver(Alloc); 308 SmallVector<StringRef, 16> Lines; 309 auto BufOrErr = MemoryBuffer::getFile(Filename); 310 if (!BufOrErr) 311 return createFileError(Filename, BufOrErr.getError()); 312 313 BufOrErr.get()->getBuffer().split(Lines, '\n'); 314 for (StringRef Line : Lines) { 315 // Ignore everything after '#', trim whitespace, and only add the symbol if 316 // it's not empty. 317 auto TrimmedLine = Line.split('#').first.trim(); 318 if (!TrimmedLine.empty()) 319 if (Error E = Symbols.addMatcher(NameOrPattern::create( 320 Saver.save(TrimmedLine), MS, ErrorCallback))) 321 return E; 322 } 323 324 return Error::success(); 325} 326 327Expected<NameOrPattern> 328NameOrPattern::create(StringRef Pattern, MatchStyle MS, 329 llvm::function_ref<Error(Error)> ErrorCallback) { 330 switch (MS) { 331 case MatchStyle::Literal: 332 return NameOrPattern(Pattern); 333 case MatchStyle::Wildcard: { 334 SmallVector<char, 32> Data; 335 bool IsPositiveMatch = true; 336 if (Pattern[0] == '!') { 337 IsPositiveMatch = false; 338 Pattern = Pattern.drop_front(); 339 } 340 Expected<GlobPattern> GlobOrErr = GlobPattern::create(Pattern); 341 342 // If we couldn't create it as a glob, report the error, but try again with 343 // a literal if the error reporting is non-fatal. 344 if (!GlobOrErr) { 345 if (Error E = ErrorCallback(GlobOrErr.takeError())) 346 return std::move(E); 347 return create(Pattern, MatchStyle::Literal, ErrorCallback); 348 } 349 350 return NameOrPattern(std::make_shared<GlobPattern>(*GlobOrErr), 351 IsPositiveMatch); 352 } 353 case MatchStyle::Regex: { 354 SmallVector<char, 32> Data; 355 return NameOrPattern(std::make_shared<Regex>( 356 ("^" + Pattern.ltrim('^').rtrim('$') + "$").toStringRef(Data))); 357 } 358 } 359 llvm_unreachable("Unhandled llvm.objcopy.MatchStyle enum"); 360} 361 362static Error addSymbolsToRenameFromFile(StringMap<StringRef> &SymbolsToRename, 363 BumpPtrAllocator &Alloc, 364 StringRef Filename) { 365 StringSaver Saver(Alloc); 366 SmallVector<StringRef, 16> Lines; 367 auto BufOrErr = MemoryBuffer::getFile(Filename); 368 if (!BufOrErr) 369 return createFileError(Filename, BufOrErr.getError()); 370 371 BufOrErr.get()->getBuffer().split(Lines, '\n'); 372 size_t NumLines = Lines.size(); 373 for (size_t LineNo = 0; LineNo < NumLines; ++LineNo) { 374 StringRef TrimmedLine = Lines[LineNo].split('#').first.trim(); 375 if (TrimmedLine.empty()) 376 continue; 377 378 std::pair<StringRef, StringRef> Pair = Saver.save(TrimmedLine).split(' '); 379 StringRef NewName = Pair.second.trim(); 380 if (NewName.empty()) 381 return createStringError(errc::invalid_argument, 382 "%s:%zu: missing new symbol name", 383 Filename.str().c_str(), LineNo + 1); 384 SymbolsToRename.insert({Pair.first, NewName}); 385 } 386 return Error::success(); 387} 388 389template <class T> static ErrorOr<T> getAsInteger(StringRef Val) { 390 T Result; 391 if (Val.getAsInteger(0, Result)) 392 return errc::invalid_argument; 393 return Result; 394} 395 396namespace { 397 398enum class ToolType { Objcopy, Strip, InstallNameTool }; 399 400} // anonymous namespace 401 402static void printHelp(const opt::OptTable &OptTable, raw_ostream &OS, 403 ToolType Tool) { 404 StringRef HelpText, ToolName; 405 switch (Tool) { 406 case ToolType::Objcopy: 407 ToolName = "llvm-objcopy"; 408 HelpText = " [options] input [output]"; 409 break; 410 case ToolType::Strip: 411 ToolName = "llvm-strip"; 412 HelpText = " [options] inputs..."; 413 break; 414 case ToolType::InstallNameTool: 415 ToolName = "llvm-install-name-tool"; 416 HelpText = " [options] input"; 417 break; 418 } 419 OptTable.PrintHelp(OS, (ToolName + HelpText).str().c_str(), 420 (ToolName + " tool").str().c_str()); 421 // TODO: Replace this with libOption call once it adds extrahelp support. 422 // The CommandLine library has a cl::extrahelp class to support this, 423 // but libOption does not have that yet. 424 OS << "\nPass @FILE as argument to read options from FILE.\n"; 425} 426 427// ParseObjcopyOptions returns the config and sets the input arguments. If a 428// help flag is set then ParseObjcopyOptions will print the help messege and 429// exit. 430Expected<DriverConfig> 431parseObjcopyOptions(ArrayRef<const char *> ArgsArr, 432 llvm::function_ref<Error(Error)> ErrorCallback) { 433 DriverConfig DC; 434 ObjcopyOptTable T; 435 unsigned MissingArgumentIndex, MissingArgumentCount; 436 llvm::opt::InputArgList InputArgs = 437 T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount); 438 439 if (InputArgs.size() == 0) { 440 printHelp(T, errs(), ToolType::Objcopy); 441 exit(1); 442 } 443 444 if (InputArgs.hasArg(OBJCOPY_help)) { 445 printHelp(T, outs(), ToolType::Objcopy); 446 exit(0); 447 } 448 449 if (InputArgs.hasArg(OBJCOPY_version)) { 450 outs() << "llvm-objcopy, compatible with GNU objcopy\n"; 451 cl::PrintVersionMessage(); 452 exit(0); 453 } 454 455 SmallVector<const char *, 2> Positional; 456 457 for (auto Arg : InputArgs.filtered(OBJCOPY_UNKNOWN)) 458 return createStringError(errc::invalid_argument, "unknown argument '%s'", 459 Arg->getAsString(InputArgs).c_str()); 460 461 for (auto Arg : InputArgs.filtered(OBJCOPY_INPUT)) 462 Positional.push_back(Arg->getValue()); 463 464 if (Positional.empty()) 465 return createStringError(errc::invalid_argument, "no input file specified"); 466 467 if (Positional.size() > 2) 468 return createStringError(errc::invalid_argument, 469 "too many positional arguments"); 470 471 CopyConfig Config; 472 Config.InputFilename = Positional[0]; 473 Config.OutputFilename = Positional[Positional.size() == 1 ? 0 : 1]; 474 if (InputArgs.hasArg(OBJCOPY_target) && 475 (InputArgs.hasArg(OBJCOPY_input_target) || 476 InputArgs.hasArg(OBJCOPY_output_target))) 477 return createStringError( 478 errc::invalid_argument, 479 "--target cannot be used with --input-target or --output-target"); 480 481 if (InputArgs.hasArg(OBJCOPY_regex) && InputArgs.hasArg(OBJCOPY_wildcard)) 482 return createStringError(errc::invalid_argument, 483 "--regex and --wildcard are incompatible"); 484 485 MatchStyle SectionMatchStyle = InputArgs.hasArg(OBJCOPY_regex) 486 ? MatchStyle::Regex 487 : MatchStyle::Wildcard; 488 MatchStyle SymbolMatchStyle = InputArgs.hasArg(OBJCOPY_regex) 489 ? MatchStyle::Regex 490 : InputArgs.hasArg(OBJCOPY_wildcard) 491 ? MatchStyle::Wildcard 492 : MatchStyle::Literal; 493 StringRef InputFormat, OutputFormat; 494 if (InputArgs.hasArg(OBJCOPY_target)) { 495 InputFormat = InputArgs.getLastArgValue(OBJCOPY_target); 496 OutputFormat = InputArgs.getLastArgValue(OBJCOPY_target); 497 } else { 498 InputFormat = InputArgs.getLastArgValue(OBJCOPY_input_target); 499 OutputFormat = InputArgs.getLastArgValue(OBJCOPY_output_target); 500 } 501 502 // FIXME: Currently, we ignore the target for non-binary/ihex formats 503 // explicitly specified by -I option (e.g. -Ielf32-x86-64) and guess the 504 // format by llvm::object::createBinary regardless of the option value. 505 Config.InputFormat = StringSwitch<FileFormat>(InputFormat) 506 .Case("binary", FileFormat::Binary) 507 .Case("ihex", FileFormat::IHex) 508 .Default(FileFormat::Unspecified); 509 510 if (InputArgs.hasArg(OBJCOPY_new_symbol_visibility)) 511 Config.NewSymbolVisibility = 512 InputArgs.getLastArgValue(OBJCOPY_new_symbol_visibility); 513 514 Config.OutputFormat = StringSwitch<FileFormat>(OutputFormat) 515 .Case("binary", FileFormat::Binary) 516 .Case("ihex", FileFormat::IHex) 517 .Default(FileFormat::Unspecified); 518 if (Config.OutputFormat == FileFormat::Unspecified) { 519 if (OutputFormat.empty()) { 520 Config.OutputFormat = Config.InputFormat; 521 } else { 522 Expected<TargetInfo> Target = 523 getOutputTargetInfoByTargetName(OutputFormat); 524 if (!Target) 525 return Target.takeError(); 526 Config.OutputFormat = Target->Format; 527 Config.OutputArch = Target->Machine; 528 } 529 } 530 531 if (auto Arg = InputArgs.getLastArg(OBJCOPY_compress_debug_sections, 532 OBJCOPY_compress_debug_sections_eq)) { 533 Config.CompressionType = DebugCompressionType::Z; 534 535 if (Arg->getOption().getID() == OBJCOPY_compress_debug_sections_eq) { 536 Config.CompressionType = 537 StringSwitch<DebugCompressionType>( 538 InputArgs.getLastArgValue(OBJCOPY_compress_debug_sections_eq)) 539 .Case("zlib-gnu", DebugCompressionType::GNU) 540 .Case("zlib", DebugCompressionType::Z) 541 .Default(DebugCompressionType::None); 542 if (Config.CompressionType == DebugCompressionType::None) 543 return createStringError( 544 errc::invalid_argument, 545 "invalid or unsupported --compress-debug-sections format: %s", 546 InputArgs.getLastArgValue(OBJCOPY_compress_debug_sections_eq) 547 .str() 548 .c_str()); 549 } 550 if (!zlib::isAvailable()) 551 return createStringError( 552 errc::invalid_argument, 553 "LLVM was not compiled with LLVM_ENABLE_ZLIB: can not compress"); 554 } 555 556 Config.AddGnuDebugLink = InputArgs.getLastArgValue(OBJCOPY_add_gnu_debuglink); 557 // The gnu_debuglink's target is expected to not change or else its CRC would 558 // become invalidated and get rejected. We can avoid recalculating the 559 // checksum for every target file inside an archive by precomputing the CRC 560 // here. This prevents a significant amount of I/O. 561 if (!Config.AddGnuDebugLink.empty()) { 562 auto DebugOrErr = MemoryBuffer::getFile(Config.AddGnuDebugLink); 563 if (!DebugOrErr) 564 return createFileError(Config.AddGnuDebugLink, DebugOrErr.getError()); 565 auto Debug = std::move(*DebugOrErr); 566 Config.GnuDebugLinkCRC32 = 567 llvm::crc32(arrayRefFromStringRef(Debug->getBuffer())); 568 } 569 Config.BuildIdLinkDir = InputArgs.getLastArgValue(OBJCOPY_build_id_link_dir); 570 if (InputArgs.hasArg(OBJCOPY_build_id_link_input)) 571 Config.BuildIdLinkInput = 572 InputArgs.getLastArgValue(OBJCOPY_build_id_link_input); 573 if (InputArgs.hasArg(OBJCOPY_build_id_link_output)) 574 Config.BuildIdLinkOutput = 575 InputArgs.getLastArgValue(OBJCOPY_build_id_link_output); 576 Config.SplitDWO = InputArgs.getLastArgValue(OBJCOPY_split_dwo); 577 Config.SymbolsPrefix = InputArgs.getLastArgValue(OBJCOPY_prefix_symbols); 578 Config.AllocSectionsPrefix = 579 InputArgs.getLastArgValue(OBJCOPY_prefix_alloc_sections); 580 if (auto Arg = InputArgs.getLastArg(OBJCOPY_extract_partition)) 581 Config.ExtractPartition = Arg->getValue(); 582 583 for (auto Arg : InputArgs.filtered(OBJCOPY_redefine_symbol)) { 584 if (!StringRef(Arg->getValue()).contains('=')) 585 return createStringError(errc::invalid_argument, 586 "bad format for --redefine-sym"); 587 auto Old2New = StringRef(Arg->getValue()).split('='); 588 if (!Config.SymbolsToRename.insert(Old2New).second) 589 return createStringError(errc::invalid_argument, 590 "multiple redefinition of symbol '%s'", 591 Old2New.first.str().c_str()); 592 } 593 594 for (auto Arg : InputArgs.filtered(OBJCOPY_redefine_symbols)) 595 if (Error E = addSymbolsToRenameFromFile(Config.SymbolsToRename, DC.Alloc, 596 Arg->getValue())) 597 return std::move(E); 598 599 for (auto Arg : InputArgs.filtered(OBJCOPY_rename_section)) { 600 Expected<SectionRename> SR = 601 parseRenameSectionValue(StringRef(Arg->getValue())); 602 if (!SR) 603 return SR.takeError(); 604 if (!Config.SectionsToRename.try_emplace(SR->OriginalName, *SR).second) 605 return createStringError(errc::invalid_argument, 606 "multiple renames of section '%s'", 607 SR->OriginalName.str().c_str()); 608 } 609 for (auto Arg : InputArgs.filtered(OBJCOPY_set_section_alignment)) { 610 Expected<std::pair<StringRef, uint64_t>> NameAndAlign = 611 parseSetSectionAlignment(Arg->getValue()); 612 if (!NameAndAlign) 613 return NameAndAlign.takeError(); 614 Config.SetSectionAlignment[NameAndAlign->first] = NameAndAlign->second; 615 } 616 for (auto Arg : InputArgs.filtered(OBJCOPY_set_section_flags)) { 617 Expected<SectionFlagsUpdate> SFU = 618 parseSetSectionFlagValue(Arg->getValue()); 619 if (!SFU) 620 return SFU.takeError(); 621 if (!Config.SetSectionFlags.try_emplace(SFU->Name, *SFU).second) 622 return createStringError( 623 errc::invalid_argument, 624 "--set-section-flags set multiple times for section '%s'", 625 SFU->Name.str().c_str()); 626 } 627 // Prohibit combinations of --set-section-flags when the section name is used 628 // by --rename-section, either as a source or a destination. 629 for (const auto &E : Config.SectionsToRename) { 630 const SectionRename &SR = E.second; 631 if (Config.SetSectionFlags.count(SR.OriginalName)) 632 return createStringError( 633 errc::invalid_argument, 634 "--set-section-flags=%s conflicts with --rename-section=%s=%s", 635 SR.OriginalName.str().c_str(), SR.OriginalName.str().c_str(), 636 SR.NewName.str().c_str()); 637 if (Config.SetSectionFlags.count(SR.NewName)) 638 return createStringError( 639 errc::invalid_argument, 640 "--set-section-flags=%s conflicts with --rename-section=%s=%s", 641 SR.NewName.str().c_str(), SR.OriginalName.str().c_str(), 642 SR.NewName.str().c_str()); 643 } 644 645 for (auto Arg : InputArgs.filtered(OBJCOPY_remove_section)) 646 if (Error E = Config.ToRemove.addMatcher(NameOrPattern::create( 647 Arg->getValue(), SectionMatchStyle, ErrorCallback))) 648 return std::move(E); 649 for (auto Arg : InputArgs.filtered(OBJCOPY_keep_section)) 650 if (Error E = Config.KeepSection.addMatcher(NameOrPattern::create( 651 Arg->getValue(), SectionMatchStyle, ErrorCallback))) 652 return std::move(E); 653 for (auto Arg : InputArgs.filtered(OBJCOPY_only_section)) 654 if (Error E = Config.OnlySection.addMatcher(NameOrPattern::create( 655 Arg->getValue(), SectionMatchStyle, ErrorCallback))) 656 return std::move(E); 657 for (auto Arg : InputArgs.filtered(OBJCOPY_add_section)) { 658 StringRef ArgValue(Arg->getValue()); 659 if (!ArgValue.contains('=')) 660 return createStringError(errc::invalid_argument, 661 "bad format for --add-section: missing '='"); 662 if (ArgValue.split("=").second.empty()) 663 return createStringError( 664 errc::invalid_argument, 665 "bad format for --add-section: missing file name"); 666 Config.AddSection.push_back(ArgValue); 667 } 668 for (auto Arg : InputArgs.filtered(OBJCOPY_dump_section)) 669 Config.DumpSection.push_back(Arg->getValue()); 670 Config.StripAll = InputArgs.hasArg(OBJCOPY_strip_all); 671 Config.StripAllGNU = InputArgs.hasArg(OBJCOPY_strip_all_gnu); 672 Config.StripDebug = InputArgs.hasArg(OBJCOPY_strip_debug); 673 Config.StripDWO = InputArgs.hasArg(OBJCOPY_strip_dwo); 674 Config.StripSections = InputArgs.hasArg(OBJCOPY_strip_sections); 675 Config.StripNonAlloc = InputArgs.hasArg(OBJCOPY_strip_non_alloc); 676 Config.StripUnneeded = InputArgs.hasArg(OBJCOPY_strip_unneeded); 677 Config.ExtractDWO = InputArgs.hasArg(OBJCOPY_extract_dwo); 678 Config.ExtractMainPartition = 679 InputArgs.hasArg(OBJCOPY_extract_main_partition); 680 Config.LocalizeHidden = InputArgs.hasArg(OBJCOPY_localize_hidden); 681 Config.Weaken = InputArgs.hasArg(OBJCOPY_weaken); 682 if (InputArgs.hasArg(OBJCOPY_discard_all, OBJCOPY_discard_locals)) 683 Config.DiscardMode = 684 InputArgs.hasFlag(OBJCOPY_discard_all, OBJCOPY_discard_locals) 685 ? DiscardType::All 686 : DiscardType::Locals; 687 Config.OnlyKeepDebug = InputArgs.hasArg(OBJCOPY_only_keep_debug); 688 Config.KeepFileSymbols = InputArgs.hasArg(OBJCOPY_keep_file_symbols); 689 Config.DecompressDebugSections = 690 InputArgs.hasArg(OBJCOPY_decompress_debug_sections); 691 if (Config.DiscardMode == DiscardType::All) { 692 Config.StripDebug = true; 693 Config.KeepFileSymbols = true; 694 } 695 for (auto Arg : InputArgs.filtered(OBJCOPY_localize_symbol)) 696 if (Error E = Config.SymbolsToLocalize.addMatcher(NameOrPattern::create( 697 Arg->getValue(), SymbolMatchStyle, ErrorCallback))) 698 return std::move(E); 699 for (auto Arg : InputArgs.filtered(OBJCOPY_localize_symbols)) 700 if (Error E = addSymbolsFromFile(Config.SymbolsToLocalize, DC.Alloc, 701 Arg->getValue(), SymbolMatchStyle, 702 ErrorCallback)) 703 return std::move(E); 704 for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbol)) 705 if (Error E = Config.SymbolsToKeepGlobal.addMatcher(NameOrPattern::create( 706 Arg->getValue(), SymbolMatchStyle, ErrorCallback))) 707 return std::move(E); 708 for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbols)) 709 if (Error E = addSymbolsFromFile(Config.SymbolsToKeepGlobal, DC.Alloc, 710 Arg->getValue(), SymbolMatchStyle, 711 ErrorCallback)) 712 return std::move(E); 713 for (auto Arg : InputArgs.filtered(OBJCOPY_globalize_symbol)) 714 if (Error E = Config.SymbolsToGlobalize.addMatcher(NameOrPattern::create( 715 Arg->getValue(), SymbolMatchStyle, ErrorCallback))) 716 return std::move(E); 717 for (auto Arg : InputArgs.filtered(OBJCOPY_globalize_symbols)) 718 if (Error E = addSymbolsFromFile(Config.SymbolsToGlobalize, DC.Alloc, 719 Arg->getValue(), SymbolMatchStyle, 720 ErrorCallback)) 721 return std::move(E); 722 for (auto Arg : InputArgs.filtered(OBJCOPY_weaken_symbol)) 723 if (Error E = Config.SymbolsToWeaken.addMatcher(NameOrPattern::create( 724 Arg->getValue(), SymbolMatchStyle, ErrorCallback))) 725 return std::move(E); 726 for (auto Arg : InputArgs.filtered(OBJCOPY_weaken_symbols)) 727 if (Error E = addSymbolsFromFile(Config.SymbolsToWeaken, DC.Alloc, 728 Arg->getValue(), SymbolMatchStyle, 729 ErrorCallback)) 730 return std::move(E); 731 for (auto Arg : InputArgs.filtered(OBJCOPY_strip_symbol)) 732 if (Error E = Config.SymbolsToRemove.addMatcher(NameOrPattern::create( 733 Arg->getValue(), SymbolMatchStyle, ErrorCallback))) 734 return std::move(E); 735 for (auto Arg : InputArgs.filtered(OBJCOPY_strip_symbols)) 736 if (Error E = addSymbolsFromFile(Config.SymbolsToRemove, DC.Alloc, 737 Arg->getValue(), SymbolMatchStyle, 738 ErrorCallback)) 739 return std::move(E); 740 for (auto Arg : InputArgs.filtered(OBJCOPY_strip_unneeded_symbol)) 741 if (Error E = 742 Config.UnneededSymbolsToRemove.addMatcher(NameOrPattern::create( 743 Arg->getValue(), SymbolMatchStyle, ErrorCallback))) 744 return std::move(E); 745 for (auto Arg : InputArgs.filtered(OBJCOPY_strip_unneeded_symbols)) 746 if (Error E = addSymbolsFromFile(Config.UnneededSymbolsToRemove, DC.Alloc, 747 Arg->getValue(), SymbolMatchStyle, 748 ErrorCallback)) 749 return std::move(E); 750 for (auto Arg : InputArgs.filtered(OBJCOPY_keep_symbol)) 751 if (Error E = Config.SymbolsToKeep.addMatcher(NameOrPattern::create( 752 Arg->getValue(), SymbolMatchStyle, ErrorCallback))) 753 return std::move(E); 754 for (auto Arg : InputArgs.filtered(OBJCOPY_keep_symbols)) 755 if (Error E = 756 addSymbolsFromFile(Config.SymbolsToKeep, DC.Alloc, Arg->getValue(), 757 SymbolMatchStyle, ErrorCallback)) 758 return std::move(E); 759 for (auto Arg : InputArgs.filtered(OBJCOPY_add_symbol)) 760 Config.SymbolsToAdd.push_back(Arg->getValue()); 761 762 Config.AllowBrokenLinks = InputArgs.hasArg(OBJCOPY_allow_broken_links); 763 764 Config.DeterministicArchives = InputArgs.hasFlag( 765 OBJCOPY_enable_deterministic_archives, 766 OBJCOPY_disable_deterministic_archives, /*default=*/true); 767 768 Config.PreserveDates = InputArgs.hasArg(OBJCOPY_preserve_dates); 769 770 if (Config.PreserveDates && 771 (Config.OutputFilename == "-" || Config.InputFilename == "-")) 772 return createStringError(errc::invalid_argument, 773 "--preserve-dates requires a file"); 774 775 for (auto Arg : InputArgs) 776 if (Arg->getOption().matches(OBJCOPY_set_start)) { 777 auto EAddr = getAsInteger<uint64_t>(Arg->getValue()); 778 if (!EAddr) 779 return createStringError( 780 EAddr.getError(), "bad entry point address: '%s'", Arg->getValue()); 781 782 Config.EntryExpr = [EAddr](uint64_t) { return *EAddr; }; 783 } else if (Arg->getOption().matches(OBJCOPY_change_start)) { 784 auto EIncr = getAsInteger<int64_t>(Arg->getValue()); 785 if (!EIncr) 786 return createStringError(EIncr.getError(), 787 "bad entry point increment: '%s'", 788 Arg->getValue()); 789 auto Expr = Config.EntryExpr ? std::move(Config.EntryExpr) 790 : [](uint64_t A) { return A; }; 791 Config.EntryExpr = [Expr, EIncr](uint64_t EAddr) { 792 return Expr(EAddr) + *EIncr; 793 }; 794 } 795 796 if (Config.DecompressDebugSections && 797 Config.CompressionType != DebugCompressionType::None) { 798 return createStringError( 799 errc::invalid_argument, 800 "cannot specify both --compress-debug-sections and " 801 "--decompress-debug-sections"); 802 } 803 804 if (Config.DecompressDebugSections && !zlib::isAvailable()) 805 return createStringError( 806 errc::invalid_argument, 807 "LLVM was not compiled with LLVM_ENABLE_ZLIB: cannot decompress"); 808 809 if (Config.ExtractPartition && Config.ExtractMainPartition) 810 return createStringError(errc::invalid_argument, 811 "cannot specify --extract-partition together with " 812 "--extract-main-partition"); 813 814 DC.CopyConfigs.push_back(std::move(Config)); 815 return std::move(DC); 816} 817 818// ParseInstallNameToolOptions returns the config and sets the input arguments. 819// If a help flag is set then ParseInstallNameToolOptions will print the help 820// messege and exit. 821Expected<DriverConfig> 822parseInstallNameToolOptions(ArrayRef<const char *> ArgsArr) { 823 DriverConfig DC; 824 CopyConfig Config; 825 InstallNameToolOptTable T; 826 unsigned MissingArgumentIndex, MissingArgumentCount; 827 llvm::opt::InputArgList InputArgs = 828 T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount); 829 830 if (MissingArgumentCount) 831 return createStringError( 832 errc::invalid_argument, 833 "missing argument to " + 834 StringRef(InputArgs.getArgString(MissingArgumentIndex)) + 835 " option"); 836 837 if (InputArgs.size() == 0) { 838 printHelp(T, errs(), ToolType::InstallNameTool); 839 exit(1); 840 } 841 842 if (InputArgs.hasArg(INSTALL_NAME_TOOL_help)) { 843 printHelp(T, outs(), ToolType::InstallNameTool); 844 exit(0); 845 } 846 847 if (InputArgs.hasArg(INSTALL_NAME_TOOL_version)) { 848 outs() << "llvm-install-name-tool, compatible with cctools " 849 "install_name_tool\n"; 850 cl::PrintVersionMessage(); 851 exit(0); 852 } 853 854 for (auto Arg : InputArgs.filtered(INSTALL_NAME_TOOL_add_rpath)) 855 Config.RPathToAdd.push_back(Arg->getValue()); 856 857 for (auto Arg : InputArgs.filtered(INSTALL_NAME_TOOL_delete_rpath)) { 858 StringRef RPath = Arg->getValue(); 859 860 // Cannot add and delete the same rpath at the same time. 861 if (is_contained(Config.RPathToAdd, RPath)) 862 return createStringError( 863 errc::invalid_argument, 864 "cannot specify both -add_rpath %s and -delete_rpath %s", 865 RPath.str().c_str(), RPath.str().c_str()); 866 867 Config.RPathsToRemove.insert(RPath); 868 } 869 870 for (auto *Arg : InputArgs.filtered(INSTALL_NAME_TOOL_rpath)) { 871 StringRef Old = Arg->getValue(0); 872 StringRef New = Arg->getValue(1); 873 874 auto Match = [=](StringRef RPath) { return RPath == Old || RPath == New; }; 875 876 // Cannot specify duplicate -rpath entries 877 auto It1 = find_if( 878 Config.RPathsToUpdate, 879 [&Match](const DenseMap<StringRef, StringRef>::value_type &OldNew) { 880 return Match(OldNew.getFirst()) || Match(OldNew.getSecond()); 881 }); 882 if (It1 != Config.RPathsToUpdate.end()) 883 return createStringError(errc::invalid_argument, 884 "cannot specify both -rpath " + It1->getFirst() + 885 " " + It1->getSecond() + " and -rpath " + 886 Old + " " + New); 887 888 // Cannot specify the same rpath under both -delete_rpath and -rpath 889 auto It2 = find_if(Config.RPathsToRemove, Match); 890 if (It2 != Config.RPathsToRemove.end()) 891 return createStringError(errc::invalid_argument, 892 "cannot specify both -delete_rpath " + *It2 + 893 " and -rpath " + Old + " " + New); 894 895 // Cannot specify the same rpath under both -add_rpath and -rpath 896 auto It3 = find_if(Config.RPathToAdd, Match); 897 if (It3 != Config.RPathToAdd.end()) 898 return createStringError(errc::invalid_argument, 899 "cannot specify both -add_rpath " + *It3 + 900 " and -rpath " + Old + " " + New); 901 902 Config.RPathsToUpdate.insert({Old, New}); 903 } 904 905 if (auto *Arg = InputArgs.getLastArg(INSTALL_NAME_TOOL_id)) 906 Config.SharedLibId = Arg->getValue(); 907 908 for (auto *Arg : InputArgs.filtered(INSTALL_NAME_TOOL_change)) { 909 Config.InstallNamesToUpdate.insert({Arg->getValue(0), Arg->getValue(1)}); 910 } 911 912 SmallVector<StringRef, 2> Positional; 913 for (auto Arg : InputArgs.filtered(INSTALL_NAME_TOOL_UNKNOWN)) 914 return createStringError(errc::invalid_argument, "unknown argument '%s'", 915 Arg->getAsString(InputArgs).c_str()); 916 for (auto Arg : InputArgs.filtered(INSTALL_NAME_TOOL_INPUT)) 917 Positional.push_back(Arg->getValue()); 918 if (Positional.empty()) 919 return createStringError(errc::invalid_argument, "no input file specified"); 920 if (Positional.size() > 1) 921 return createStringError( 922 errc::invalid_argument, 923 "llvm-install-name-tool expects a single input file"); 924 Config.InputFilename = Positional[0]; 925 Config.OutputFilename = Positional[0]; 926 927 DC.CopyConfigs.push_back(std::move(Config)); 928 return std::move(DC); 929} 930 931// ParseStripOptions returns the config and sets the input arguments. If a 932// help flag is set then ParseStripOptions will print the help messege and 933// exit. 934Expected<DriverConfig> 935parseStripOptions(ArrayRef<const char *> ArgsArr, 936 llvm::function_ref<Error(Error)> ErrorCallback) { 937 StripOptTable T; 938 unsigned MissingArgumentIndex, MissingArgumentCount; 939 llvm::opt::InputArgList InputArgs = 940 T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount); 941 942 if (InputArgs.size() == 0) { 943 printHelp(T, errs(), ToolType::Strip); 944 exit(1); 945 } 946 947 if (InputArgs.hasArg(STRIP_help)) { 948 printHelp(T, outs(), ToolType::Strip); 949 exit(0); 950 } 951 952 if (InputArgs.hasArg(STRIP_version)) { 953 outs() << "llvm-strip, compatible with GNU strip\n"; 954 cl::PrintVersionMessage(); 955 exit(0); 956 } 957 958 SmallVector<StringRef, 2> Positional; 959 for (auto Arg : InputArgs.filtered(STRIP_UNKNOWN)) 960 return createStringError(errc::invalid_argument, "unknown argument '%s'", 961 Arg->getAsString(InputArgs).c_str()); 962 for (auto Arg : InputArgs.filtered(STRIP_INPUT)) 963 Positional.push_back(Arg->getValue()); 964 965 if (Positional.empty()) 966 return createStringError(errc::invalid_argument, "no input file specified"); 967 968 if (Positional.size() > 1 && InputArgs.hasArg(STRIP_output)) 969 return createStringError( 970 errc::invalid_argument, 971 "multiple input files cannot be used in combination with -o"); 972 973 CopyConfig Config; 974 975 if (InputArgs.hasArg(STRIP_regex) && InputArgs.hasArg(STRIP_wildcard)) 976 return createStringError(errc::invalid_argument, 977 "--regex and --wildcard are incompatible"); 978 MatchStyle SectionMatchStyle = 979 InputArgs.hasArg(STRIP_regex) ? MatchStyle::Regex : MatchStyle::Wildcard; 980 MatchStyle SymbolMatchStyle = InputArgs.hasArg(STRIP_regex) 981 ? MatchStyle::Regex 982 : InputArgs.hasArg(STRIP_wildcard) 983 ? MatchStyle::Wildcard 984 : MatchStyle::Literal; 985 Config.AllowBrokenLinks = InputArgs.hasArg(STRIP_allow_broken_links); 986 Config.StripDebug = InputArgs.hasArg(STRIP_strip_debug); 987 988 if (InputArgs.hasArg(STRIP_discard_all, STRIP_discard_locals)) 989 Config.DiscardMode = 990 InputArgs.hasFlag(STRIP_discard_all, STRIP_discard_locals) 991 ? DiscardType::All 992 : DiscardType::Locals; 993 Config.StripSections = InputArgs.hasArg(STRIP_strip_sections); 994 Config.StripUnneeded = InputArgs.hasArg(STRIP_strip_unneeded); 995 if (auto Arg = InputArgs.getLastArg(STRIP_strip_all, STRIP_no_strip_all)) 996 Config.StripAll = Arg->getOption().getID() == STRIP_strip_all; 997 Config.StripAllGNU = InputArgs.hasArg(STRIP_strip_all_gnu); 998 Config.StripSwiftSymbols = InputArgs.hasArg(STRIP_strip_swift_symbols); 999 Config.OnlyKeepDebug = InputArgs.hasArg(STRIP_only_keep_debug); 1000 Config.KeepFileSymbols = InputArgs.hasArg(STRIP_keep_file_symbols); 1001 1002 for (auto Arg : InputArgs.filtered(STRIP_keep_section)) 1003 if (Error E = Config.KeepSection.addMatcher(NameOrPattern::create( 1004 Arg->getValue(), SectionMatchStyle, ErrorCallback))) 1005 return std::move(E); 1006 1007 for (auto Arg : InputArgs.filtered(STRIP_remove_section)) 1008 if (Error E = Config.ToRemove.addMatcher(NameOrPattern::create( 1009 Arg->getValue(), SectionMatchStyle, ErrorCallback))) 1010 return std::move(E); 1011 1012 for (auto Arg : InputArgs.filtered(STRIP_strip_symbol)) 1013 if (Error E = Config.SymbolsToRemove.addMatcher(NameOrPattern::create( 1014 Arg->getValue(), SymbolMatchStyle, ErrorCallback))) 1015 return std::move(E); 1016 1017 for (auto Arg : InputArgs.filtered(STRIP_keep_symbol)) 1018 if (Error E = Config.SymbolsToKeep.addMatcher(NameOrPattern::create( 1019 Arg->getValue(), SymbolMatchStyle, ErrorCallback))) 1020 return std::move(E); 1021 1022 if (!InputArgs.hasArg(STRIP_no_strip_all) && !Config.StripDebug && 1023 !Config.StripUnneeded && Config.DiscardMode == DiscardType::None && 1024 !Config.StripAllGNU && Config.SymbolsToRemove.empty()) 1025 Config.StripAll = true; 1026 1027 if (Config.DiscardMode == DiscardType::All) { 1028 Config.StripDebug = true; 1029 Config.KeepFileSymbols = true; 1030 } 1031 1032 Config.DeterministicArchives = 1033 InputArgs.hasFlag(STRIP_enable_deterministic_archives, 1034 STRIP_disable_deterministic_archives, /*default=*/true); 1035 1036 Config.PreserveDates = InputArgs.hasArg(STRIP_preserve_dates); 1037 Config.InputFormat = FileFormat::Unspecified; 1038 Config.OutputFormat = FileFormat::Unspecified; 1039 1040 DriverConfig DC; 1041 if (Positional.size() == 1) { 1042 Config.InputFilename = Positional[0]; 1043 Config.OutputFilename = 1044 InputArgs.getLastArgValue(STRIP_output, Positional[0]); 1045 DC.CopyConfigs.push_back(std::move(Config)); 1046 } else { 1047 StringMap<unsigned> InputFiles; 1048 for (StringRef Filename : Positional) { 1049 if (InputFiles[Filename]++ == 1) { 1050 if (Filename == "-") 1051 return createStringError( 1052 errc::invalid_argument, 1053 "cannot specify '-' as an input file more than once"); 1054 if (Error E = ErrorCallback(createStringError( 1055 errc::invalid_argument, "'%s' was already specified", 1056 Filename.str().c_str()))) 1057 return std::move(E); 1058 } 1059 Config.InputFilename = Filename; 1060 Config.OutputFilename = Filename; 1061 DC.CopyConfigs.push_back(Config); 1062 } 1063 } 1064 1065 if (Config.PreserveDates && (is_contained(Positional, "-") || 1066 InputArgs.getLastArgValue(STRIP_output) == "-")) 1067 return createStringError(errc::invalid_argument, 1068 "--preserve-dates requires a file"); 1069 1070 return std::move(DC); 1071} 1072 1073} // namespace objcopy 1074} // namespace llvm 1075