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