1 //===- llvm-objcopy.cpp ---------------------------------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "llvm-objcopy.h" 11 #include "Object.h" 12 #include "llvm/ADT/STLExtras.h" 13 #include "llvm/ADT/StringRef.h" 14 #include "llvm/ADT/Twine.h" 15 #include "llvm/BinaryFormat/ELF.h" 16 #include "llvm/Object/Archive.h" 17 #include "llvm/Object/ArchiveWriter.h" 18 #include "llvm/Object/Binary.h" 19 #include "llvm/Object/ELFObjectFile.h" 20 #include "llvm/Object/ELFTypes.h" 21 #include "llvm/Object/Error.h" 22 #include "llvm/Option/Arg.h" 23 #include "llvm/Option/ArgList.h" 24 #include "llvm/Option/Option.h" 25 #include "llvm/Support/Casting.h" 26 #include "llvm/Support/CommandLine.h" 27 #include "llvm/Support/Compiler.h" 28 #include "llvm/Support/Error.h" 29 #include "llvm/Support/ErrorHandling.h" 30 #include "llvm/Support/ErrorOr.h" 31 #include "llvm/Support/FileOutputBuffer.h" 32 #include "llvm/Support/InitLLVM.h" 33 #include "llvm/Support/Path.h" 34 #include "llvm/Support/raw_ostream.h" 35 #include <algorithm> 36 #include <cassert> 37 #include <cstdlib> 38 #include <functional> 39 #include <iterator> 40 #include <memory> 41 #include <string> 42 #include <system_error> 43 #include <utility> 44 45 using namespace llvm; 46 using namespace llvm::objcopy; 47 using namespace object; 48 using namespace ELF; 49 50 namespace { 51 52 enum ObjcopyID { 53 OBJCOPY_INVALID = 0, // This is not an option ID. 54 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ 55 HELPTEXT, METAVAR, VALUES) \ 56 OBJCOPY_##ID, 57 #include "ObjcopyOpts.inc" 58 #undef OPTION 59 }; 60 61 #define PREFIX(NAME, VALUE) const char *const OBJCOPY_##NAME[] = VALUE; 62 #include "ObjcopyOpts.inc" 63 #undef PREFIX 64 65 static const opt::OptTable::Info ObjcopyInfoTable[] = { 66 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ 67 HELPTEXT, METAVAR, VALUES) \ 68 {OBJCOPY_##PREFIX, \ 69 NAME, \ 70 HELPTEXT, \ 71 METAVAR, \ 72 OBJCOPY_##ID, \ 73 opt::Option::KIND##Class, \ 74 PARAM, \ 75 FLAGS, \ 76 OBJCOPY_##GROUP, \ 77 OBJCOPY_##ALIAS, \ 78 ALIASARGS, \ 79 VALUES}, 80 #include "ObjcopyOpts.inc" 81 #undef OPTION 82 }; 83 84 class ObjcopyOptTable : public opt::OptTable { 85 public: 86 ObjcopyOptTable() : OptTable(ObjcopyInfoTable, true) {} 87 }; 88 89 enum StripID { 90 STRIP_INVALID = 0, // This is not an option ID. 91 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ 92 HELPTEXT, METAVAR, VALUES) \ 93 STRIP_##ID, 94 #include "StripOpts.inc" 95 #undef OPTION 96 }; 97 98 #define PREFIX(NAME, VALUE) const char *const STRIP_##NAME[] = VALUE; 99 #include "StripOpts.inc" 100 #undef PREFIX 101 102 static const opt::OptTable::Info StripInfoTable[] = { 103 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ 104 HELPTEXT, METAVAR, VALUES) \ 105 {STRIP_##PREFIX, NAME, HELPTEXT, \ 106 METAVAR, STRIP_##ID, opt::Option::KIND##Class, \ 107 PARAM, FLAGS, STRIP_##GROUP, \ 108 STRIP_##ALIAS, ALIASARGS, VALUES}, 109 #include "StripOpts.inc" 110 #undef OPTION 111 }; 112 113 class StripOptTable : public opt::OptTable { 114 public: 115 StripOptTable() : OptTable(StripInfoTable, true) {} 116 }; 117 118 struct CopyConfig { 119 StringRef OutputFilename; 120 StringRef InputFilename; 121 StringRef OutputFormat; 122 StringRef InputFormat; 123 StringRef BinaryArch; 124 125 StringRef SplitDWO; 126 StringRef AddGnuDebugLink; 127 std::vector<StringRef> ToRemove; 128 std::vector<StringRef> Keep; 129 std::vector<StringRef> OnlyKeep; 130 std::vector<StringRef> AddSection; 131 std::vector<StringRef> SymbolsToLocalize; 132 std::vector<StringRef> SymbolsToGlobalize; 133 std::vector<StringRef> SymbolsToWeaken; 134 std::vector<StringRef> SymbolsToRemove; 135 std::vector<StringRef> SymbolsToKeep; 136 StringMap<StringRef> SymbolsToRename; 137 bool StripAll = false; 138 bool StripAllGNU = false; 139 bool StripDebug = false; 140 bool StripSections = false; 141 bool StripNonAlloc = false; 142 bool StripDWO = false; 143 bool StripUnneeded = false; 144 bool ExtractDWO = false; 145 bool LocalizeHidden = false; 146 bool Weaken = false; 147 bool DiscardAll = false; 148 bool OnlyKeepDebug = false; 149 bool KeepFileSymbols = false; 150 }; 151 152 using SectionPred = std::function<bool(const SectionBase &Sec)>; 153 154 } // namespace 155 156 namespace llvm { 157 namespace objcopy { 158 159 // The name this program was invoked as. 160 StringRef ToolName; 161 162 LLVM_ATTRIBUTE_NORETURN void error(Twine Message) { 163 errs() << ToolName << ": " << Message << ".\n"; 164 errs().flush(); 165 exit(1); 166 } 167 168 LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, std::error_code EC) { 169 assert(EC); 170 errs() << ToolName << ": '" << File << "': " << EC.message() << ".\n"; 171 exit(1); 172 } 173 174 LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, Error E) { 175 assert(E); 176 std::string Buf; 177 raw_string_ostream OS(Buf); 178 logAllUnhandledErrors(std::move(E), OS, ""); 179 OS.flush(); 180 errs() << ToolName << ": '" << File << "': " << Buf; 181 exit(1); 182 } 183 184 } // end namespace objcopy 185 } // end namespace llvm 186 187 static bool IsDWOSection(const SectionBase &Sec) { 188 return Sec.Name.endswith(".dwo"); 189 } 190 191 static bool OnlyKeepDWOPred(const Object &Obj, const SectionBase &Sec) { 192 // We can't remove the section header string table. 193 if (&Sec == Obj.SectionNames) 194 return false; 195 // Short of keeping the string table we want to keep everything that is a DWO 196 // section and remove everything else. 197 return !IsDWOSection(Sec); 198 } 199 200 static std::unique_ptr<Writer> CreateWriter(const CopyConfig &Config, 201 Object &Obj, Buffer &Buf, 202 ElfType OutputElfType) { 203 if (Config.OutputFormat == "binary") { 204 return llvm::make_unique<BinaryWriter>(Obj, Buf); 205 } 206 // Depending on the initial ELFT and OutputFormat we need a different Writer. 207 switch (OutputElfType) { 208 case ELFT_ELF32LE: 209 return llvm::make_unique<ELFWriter<ELF32LE>>(Obj, Buf, 210 !Config.StripSections); 211 case ELFT_ELF64LE: 212 return llvm::make_unique<ELFWriter<ELF64LE>>(Obj, Buf, 213 !Config.StripSections); 214 case ELFT_ELF32BE: 215 return llvm::make_unique<ELFWriter<ELF32BE>>(Obj, Buf, 216 !Config.StripSections); 217 case ELFT_ELF64BE: 218 return llvm::make_unique<ELFWriter<ELF64BE>>(Obj, Buf, 219 !Config.StripSections); 220 } 221 llvm_unreachable("Invalid output format"); 222 } 223 224 static void SplitDWOToFile(const CopyConfig &Config, const Reader &Reader, 225 StringRef File, ElfType OutputElfType) { 226 auto DWOFile = Reader.create(); 227 DWOFile->removeSections( 228 [&](const SectionBase &Sec) { return OnlyKeepDWOPred(*DWOFile, Sec); }); 229 FileBuffer FB(File); 230 auto Writer = CreateWriter(Config, *DWOFile, FB, OutputElfType); 231 Writer->finalize(); 232 Writer->write(); 233 } 234 235 // This function handles the high level operations of GNU objcopy including 236 // handling command line options. It's important to outline certain properties 237 // we expect to hold of the command line operations. Any operation that "keeps" 238 // should keep regardless of a remove. Additionally any removal should respect 239 // any previous removals. Lastly whether or not something is removed shouldn't 240 // depend a) on the order the options occur in or b) on some opaque priority 241 // system. The only priority is that keeps/copies overrule removes. 242 static void HandleArgs(const CopyConfig &Config, Object &Obj, 243 const Reader &Reader, ElfType OutputElfType) { 244 245 if (!Config.SplitDWO.empty()) { 246 SplitDWOToFile(Config, Reader, Config.SplitDWO, OutputElfType); 247 } 248 249 // TODO: update or remove symbols only if there is an option that affects 250 // them. 251 if (Obj.SymbolTable) { 252 Obj.SymbolTable->updateSymbols([&](Symbol &Sym) { 253 if ((Config.LocalizeHidden && 254 (Sym.Visibility == STV_HIDDEN || Sym.Visibility == STV_INTERNAL)) || 255 (!Config.SymbolsToLocalize.empty() && 256 is_contained(Config.SymbolsToLocalize, Sym.Name))) 257 Sym.Binding = STB_LOCAL; 258 259 if (!Config.SymbolsToGlobalize.empty() && 260 is_contained(Config.SymbolsToGlobalize, Sym.Name)) 261 Sym.Binding = STB_GLOBAL; 262 263 if (!Config.SymbolsToWeaken.empty() && 264 is_contained(Config.SymbolsToWeaken, Sym.Name) && 265 Sym.Binding == STB_GLOBAL) 266 Sym.Binding = STB_WEAK; 267 268 if (Config.Weaken && Sym.Binding == STB_GLOBAL && 269 Sym.getShndx() != SHN_UNDEF) 270 Sym.Binding = STB_WEAK; 271 272 const auto I = Config.SymbolsToRename.find(Sym.Name); 273 if (I != Config.SymbolsToRename.end()) 274 Sym.Name = I->getValue(); 275 }); 276 277 // The purpose of this loop is to mark symbols referenced by sections 278 // (like GroupSection or RelocationSection). This way, we know which 279 // symbols are still 'needed' and wich are not. 280 if (Config.StripUnneeded) { 281 for (auto &Section : Obj.sections()) 282 Section.markSymbols(); 283 } 284 285 Obj.removeSymbols([&](const Symbol &Sym) { 286 if ((!Config.SymbolsToKeep.empty() && 287 is_contained(Config.SymbolsToKeep, Sym.Name)) || 288 (Config.KeepFileSymbols && Sym.Type == STT_FILE)) 289 return false; 290 291 if (Config.DiscardAll && Sym.Binding == STB_LOCAL && 292 Sym.getShndx() != SHN_UNDEF && Sym.Type != STT_FILE && 293 Sym.Type != STT_SECTION) 294 return true; 295 296 if (Config.StripAll || Config.StripAllGNU) 297 return true; 298 299 if (!Config.SymbolsToRemove.empty() && 300 is_contained(Config.SymbolsToRemove, Sym.Name)) { 301 return true; 302 } 303 304 if (Config.StripUnneeded && !Sym.Referenced && 305 (Sym.Binding == STB_LOCAL || Sym.getShndx() == SHN_UNDEF) && 306 Sym.Type != STT_FILE && Sym.Type != STT_SECTION) 307 return true; 308 309 return false; 310 }); 311 } 312 313 SectionPred RemovePred = [](const SectionBase &) { return false; }; 314 315 // Removes: 316 if (!Config.ToRemove.empty()) { 317 RemovePred = [&Config](const SectionBase &Sec) { 318 return std::find(std::begin(Config.ToRemove), std::end(Config.ToRemove), 319 Sec.Name) != std::end(Config.ToRemove); 320 }; 321 } 322 323 if (Config.StripDWO || !Config.SplitDWO.empty()) 324 RemovePred = [RemovePred](const SectionBase &Sec) { 325 return IsDWOSection(Sec) || RemovePred(Sec); 326 }; 327 328 if (Config.ExtractDWO) 329 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { 330 return OnlyKeepDWOPred(Obj, Sec) || RemovePred(Sec); 331 }; 332 333 if (Config.StripAllGNU) 334 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { 335 if (RemovePred(Sec)) 336 return true; 337 if ((Sec.Flags & SHF_ALLOC) != 0) 338 return false; 339 if (&Sec == Obj.SectionNames) 340 return false; 341 switch (Sec.Type) { 342 case SHT_SYMTAB: 343 case SHT_REL: 344 case SHT_RELA: 345 case SHT_STRTAB: 346 return true; 347 } 348 return Sec.Name.startswith(".debug"); 349 }; 350 351 if (Config.StripSections) { 352 RemovePred = [RemovePred](const SectionBase &Sec) { 353 return RemovePred(Sec) || (Sec.Flags & SHF_ALLOC) == 0; 354 }; 355 } 356 357 if (Config.StripDebug) { 358 RemovePred = [RemovePred](const SectionBase &Sec) { 359 return RemovePred(Sec) || Sec.Name.startswith(".debug"); 360 }; 361 } 362 363 if (Config.StripNonAlloc) 364 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { 365 if (RemovePred(Sec)) 366 return true; 367 if (&Sec == Obj.SectionNames) 368 return false; 369 return (Sec.Flags & SHF_ALLOC) == 0; 370 }; 371 372 if (Config.StripAll) 373 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { 374 if (RemovePred(Sec)) 375 return true; 376 if (&Sec == Obj.SectionNames) 377 return false; 378 if (Sec.Name.startswith(".gnu.warning")) 379 return false; 380 return (Sec.Flags & SHF_ALLOC) == 0; 381 }; 382 383 // Explicit copies: 384 if (!Config.OnlyKeep.empty()) { 385 RemovePred = [&Config, RemovePred, &Obj](const SectionBase &Sec) { 386 // Explicitly keep these sections regardless of previous removes. 387 if (std::find(std::begin(Config.OnlyKeep), std::end(Config.OnlyKeep), 388 Sec.Name) != std::end(Config.OnlyKeep)) 389 return false; 390 391 // Allow all implicit removes. 392 if (RemovePred(Sec)) 393 return true; 394 395 // Keep special sections. 396 if (Obj.SectionNames == &Sec) 397 return false; 398 if (Obj.SymbolTable == &Sec || Obj.SymbolTable->getStrTab() == &Sec) 399 return false; 400 401 // Remove everything else. 402 return true; 403 }; 404 } 405 406 if (!Config.Keep.empty()) { 407 RemovePred = [Config, RemovePred](const SectionBase &Sec) { 408 // Explicitly keep these sections regardless of previous removes. 409 if (std::find(std::begin(Config.Keep), std::end(Config.Keep), Sec.Name) != 410 std::end(Config.Keep)) 411 return false; 412 // Otherwise defer to RemovePred. 413 return RemovePred(Sec); 414 }; 415 } 416 417 // This has to be the last predicate assignment. 418 // If the option --keep-symbol has been specified 419 // and at least one of those symbols is present 420 // (equivalently, the updated symbol table is not empty) 421 // the symbol table and the string table should not be removed. 422 if ((!Config.SymbolsToKeep.empty() || Config.KeepFileSymbols) && 423 !Obj.SymbolTable->empty()) { 424 RemovePred = [&Obj, RemovePred](const SectionBase &Sec) { 425 if (&Sec == Obj.SymbolTable || &Sec == Obj.SymbolTable->getStrTab()) 426 return false; 427 return RemovePred(Sec); 428 }; 429 } 430 431 Obj.removeSections(RemovePred); 432 433 if (!Config.AddSection.empty()) { 434 for (const auto &Flag : Config.AddSection) { 435 auto SecPair = Flag.split("="); 436 auto SecName = SecPair.first; 437 auto File = SecPair.second; 438 auto BufOrErr = MemoryBuffer::getFile(File); 439 if (!BufOrErr) 440 reportError(File, BufOrErr.getError()); 441 auto Buf = std::move(*BufOrErr); 442 auto BufPtr = reinterpret_cast<const uint8_t *>(Buf->getBufferStart()); 443 auto BufSize = Buf->getBufferSize(); 444 Obj.addSection<OwnedDataSection>(SecName, 445 ArrayRef<uint8_t>(BufPtr, BufSize)); 446 } 447 } 448 449 if (!Config.AddGnuDebugLink.empty()) 450 Obj.addSection<GnuDebugLinkSection>(Config.AddGnuDebugLink); 451 } 452 453 static void ExecuteElfObjcopyOnBinary(const CopyConfig &Config, Binary &Binary, 454 Buffer &Out) { 455 ELFReader Reader(&Binary); 456 std::unique_ptr<Object> Obj = Reader.create(); 457 458 HandleArgs(Config, *Obj, Reader, Reader.getElfType()); 459 460 std::unique_ptr<Writer> Writer = 461 CreateWriter(Config, *Obj, Out, Reader.getElfType()); 462 Writer->finalize(); 463 Writer->write(); 464 } 465 466 // For regular archives this function simply calls llvm::writeArchive, 467 // For thin archives it writes the archive file itself as well as its members. 468 static Error deepWriteArchive(StringRef ArcName, 469 ArrayRef<NewArchiveMember> NewMembers, 470 bool WriteSymtab, object::Archive::Kind Kind, 471 bool Deterministic, bool Thin) { 472 Error E = 473 writeArchive(ArcName, NewMembers, WriteSymtab, Kind, Deterministic, Thin); 474 if (!Thin || E) 475 return E; 476 for (const NewArchiveMember &Member : NewMembers) { 477 // Internally, FileBuffer will use the buffer created by 478 // FileOutputBuffer::create, for regular files (that is the case for 479 // deepWriteArchive) FileOutputBuffer::create will return OnDiskBuffer. 480 // OnDiskBuffer uses a temporary file and then renames it. So in reality 481 // there is no inefficiency / duplicated in-memory buffers in this case. For 482 // now in-memory buffers can not be completely avoided since 483 // NewArchiveMember still requires them even though writeArchive does not 484 // write them on disk. 485 FileBuffer FB(Member.MemberName); 486 FB.allocate(Member.Buf->getBufferSize()); 487 std::copy(Member.Buf->getBufferStart(), Member.Buf->getBufferEnd(), 488 FB.getBufferStart()); 489 if (auto E = FB.commit()) 490 return E; 491 } 492 return Error::success(); 493 } 494 495 static void ExecuteElfObjcopyOnArchive(const CopyConfig &Config, const Archive &Ar) { 496 std::vector<NewArchiveMember> NewArchiveMembers; 497 Error Err = Error::success(); 498 for (const Archive::Child &Child : Ar.children(Err)) { 499 Expected<std::unique_ptr<Binary>> ChildOrErr = Child.getAsBinary(); 500 if (!ChildOrErr) 501 reportError(Ar.getFileName(), ChildOrErr.takeError()); 502 Expected<StringRef> ChildNameOrErr = Child.getName(); 503 if (!ChildNameOrErr) 504 reportError(Ar.getFileName(), ChildNameOrErr.takeError()); 505 506 MemBuffer MB(ChildNameOrErr.get()); 507 ExecuteElfObjcopyOnBinary(Config, **ChildOrErr, MB); 508 509 Expected<NewArchiveMember> Member = 510 NewArchiveMember::getOldMember(Child, true); 511 if (!Member) 512 reportError(Ar.getFileName(), Member.takeError()); 513 Member->Buf = MB.releaseMemoryBuffer(); 514 Member->MemberName = Member->Buf->getBufferIdentifier(); 515 NewArchiveMembers.push_back(std::move(*Member)); 516 } 517 518 if (Err) 519 reportError(Config.InputFilename, std::move(Err)); 520 if (Error E = 521 deepWriteArchive(Config.OutputFilename, NewArchiveMembers, 522 Ar.hasSymbolTable(), Ar.kind(), true, Ar.isThin())) 523 reportError(Config.OutputFilename, std::move(E)); 524 } 525 526 static void ExecuteElfObjcopy(const CopyConfig &Config) { 527 Expected<OwningBinary<llvm::object::Binary>> BinaryOrErr = 528 createBinary(Config.InputFilename); 529 if (!BinaryOrErr) 530 reportError(Config.InputFilename, BinaryOrErr.takeError()); 531 532 if (Archive *Ar = dyn_cast<Archive>(BinaryOrErr.get().getBinary())) 533 return ExecuteElfObjcopyOnArchive(Config, *Ar); 534 535 FileBuffer FB(Config.OutputFilename); 536 ExecuteElfObjcopyOnBinary(Config, *BinaryOrErr.get().getBinary(), FB); 537 } 538 539 // ParseObjcopyOptions returns the config and sets the input arguments. If a 540 // help flag is set then ParseObjcopyOptions will print the help messege and 541 // exit. 542 static CopyConfig ParseObjcopyOptions(ArrayRef<const char *> ArgsArr) { 543 ObjcopyOptTable T; 544 unsigned MissingArgumentIndex, MissingArgumentCount; 545 llvm::opt::InputArgList InputArgs = 546 T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount); 547 548 if (InputArgs.size() == 0) { 549 T.PrintHelp(errs(), "llvm-objcopy <input> [ <output> ]", "objcopy tool"); 550 exit(1); 551 } 552 553 if (InputArgs.hasArg(OBJCOPY_help)) { 554 T.PrintHelp(outs(), "llvm-objcopy <input> [ <output> ]", "objcopy tool"); 555 exit(0); 556 } 557 558 SmallVector<const char *, 2> Positional; 559 560 for (auto Arg : InputArgs.filtered(OBJCOPY_UNKNOWN)) 561 error("unknown argument '" + Arg->getAsString(InputArgs) + "'"); 562 563 for (auto Arg : InputArgs.filtered(OBJCOPY_INPUT)) 564 Positional.push_back(Arg->getValue()); 565 566 if (Positional.empty()) 567 error("No input file specified"); 568 569 if (Positional.size() > 2) 570 error("Too many positional arguments"); 571 572 CopyConfig Config; 573 Config.InputFilename = Positional[0]; 574 Config.OutputFilename = Positional[Positional.size() == 1 ? 0 : 1]; 575 Config.InputFormat = InputArgs.getLastArgValue(OBJCOPY_input_target); 576 Config.OutputFormat = InputArgs.getLastArgValue(OBJCOPY_output_target); 577 Config.BinaryArch = InputArgs.getLastArgValue(OBJCOPY_binary_architecture); 578 579 Config.SplitDWO = InputArgs.getLastArgValue(OBJCOPY_split_dwo); 580 Config.AddGnuDebugLink = InputArgs.getLastArgValue(OBJCOPY_add_gnu_debuglink); 581 582 for (auto Arg : InputArgs.filtered(OBJCOPY_redefine_symbol)) { 583 if (!StringRef(Arg->getValue()).contains('=')) 584 error("Bad format for --redefine-sym"); 585 auto Old2New = StringRef(Arg->getValue()).split('='); 586 if (!Config.SymbolsToRename.insert(Old2New).second) 587 error("Multiple redefinition of symbol " + Old2New.first); 588 } 589 590 for (auto Arg : InputArgs.filtered(OBJCOPY_remove_section)) 591 Config.ToRemove.push_back(Arg->getValue()); 592 for (auto Arg : InputArgs.filtered(OBJCOPY_keep)) 593 Config.Keep.push_back(Arg->getValue()); 594 for (auto Arg : InputArgs.filtered(OBJCOPY_only_keep)) 595 Config.OnlyKeep.push_back(Arg->getValue()); 596 for (auto Arg : InputArgs.filtered(OBJCOPY_add_section)) 597 Config.AddSection.push_back(Arg->getValue()); 598 Config.StripAll = InputArgs.hasArg(OBJCOPY_strip_all); 599 Config.StripAllGNU = InputArgs.hasArg(OBJCOPY_strip_all_gnu); 600 Config.StripDebug = InputArgs.hasArg(OBJCOPY_strip_debug); 601 Config.StripDWO = InputArgs.hasArg(OBJCOPY_strip_dwo); 602 Config.StripSections = InputArgs.hasArg(OBJCOPY_strip_sections); 603 Config.StripNonAlloc = InputArgs.hasArg(OBJCOPY_strip_non_alloc); 604 Config.StripUnneeded = InputArgs.hasArg(OBJCOPY_strip_unneeded); 605 Config.ExtractDWO = InputArgs.hasArg(OBJCOPY_extract_dwo); 606 Config.LocalizeHidden = InputArgs.hasArg(OBJCOPY_localize_hidden); 607 Config.Weaken = InputArgs.hasArg(OBJCOPY_weaken); 608 Config.DiscardAll = InputArgs.hasArg(OBJCOPY_discard_all); 609 Config.OnlyKeepDebug = InputArgs.hasArg(OBJCOPY_only_keep_debug); 610 Config.KeepFileSymbols = InputArgs.hasArg(OBJCOPY_keep_file_symbols); 611 for (auto Arg : InputArgs.filtered(OBJCOPY_localize_symbol)) 612 Config.SymbolsToLocalize.push_back(Arg->getValue()); 613 for (auto Arg : InputArgs.filtered(OBJCOPY_globalize_symbol)) 614 Config.SymbolsToGlobalize.push_back(Arg->getValue()); 615 for (auto Arg : InputArgs.filtered(OBJCOPY_weaken_symbol)) 616 Config.SymbolsToWeaken.push_back(Arg->getValue()); 617 for (auto Arg : InputArgs.filtered(OBJCOPY_strip_symbol)) 618 Config.SymbolsToRemove.push_back(Arg->getValue()); 619 for (auto Arg : InputArgs.filtered(OBJCOPY_keep_symbol)) 620 Config.SymbolsToKeep.push_back(Arg->getValue()); 621 622 return Config; 623 } 624 625 // ParseStripOptions returns the config and sets the input arguments. If a 626 // help flag is set then ParseStripOptions will print the help messege and 627 // exit. 628 static CopyConfig ParseStripOptions(ArrayRef<const char *> ArgsArr) { 629 StripOptTable T; 630 unsigned MissingArgumentIndex, MissingArgumentCount; 631 llvm::opt::InputArgList InputArgs = 632 T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount); 633 634 if (InputArgs.size() == 0) { 635 T.PrintHelp(errs(), "llvm-strip <input> [ <output> ]", "strip tool"); 636 exit(1); 637 } 638 639 if (InputArgs.hasArg(STRIP_help)) { 640 T.PrintHelp(outs(), "llvm-strip <input> [ <output> ]", "strip tool"); 641 exit(0); 642 } 643 644 SmallVector<const char *, 2> Positional; 645 for (auto Arg : InputArgs.filtered(STRIP_UNKNOWN)) 646 error("unknown argument '" + Arg->getAsString(InputArgs) + "'"); 647 for (auto Arg : InputArgs.filtered(STRIP_INPUT)) 648 Positional.push_back(Arg->getValue()); 649 650 if (Positional.empty()) 651 error("No input file specified"); 652 653 if (Positional.size() > 2) 654 error("Support for multiple input files is not implemented yet"); 655 656 CopyConfig Config; 657 Config.InputFilename = Positional[0]; 658 Config.OutputFilename = 659 InputArgs.getLastArgValue(STRIP_output, Positional[0]); 660 661 Config.StripDebug = InputArgs.hasArg(STRIP_strip_debug); 662 663 Config.DiscardAll = InputArgs.hasArg(STRIP_discard_all); 664 Config.StripUnneeded = InputArgs.hasArg(STRIP_strip_unneeded); 665 Config.StripAll = InputArgs.hasArg(STRIP_strip_all); 666 667 if (!Config.StripDebug && !Config.StripUnneeded && !Config.DiscardAll) 668 Config.StripAll = true; 669 670 for (auto Arg : InputArgs.filtered(STRIP_remove_section)) 671 Config.ToRemove.push_back(Arg->getValue()); 672 673 for (auto Arg : InputArgs.filtered(STRIP_keep_symbol)) 674 Config.SymbolsToKeep.push_back(Arg->getValue()); 675 676 return Config; 677 } 678 679 int main(int argc, char **argv) { 680 InitLLVM X(argc, argv); 681 ToolName = argv[0]; 682 CopyConfig Config; 683 if (sys::path::stem(ToolName).endswith_lower("strip")) 684 Config = ParseStripOptions(makeArrayRef(argv + 1, argc)); 685 else 686 Config = ParseObjcopyOptions(makeArrayRef(argv + 1, argc)); 687 ExecuteElfObjcopy(Config); 688 } 689