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