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 "Buffer.h" 12 #include "CopyConfig.h" 13 #include "Object.h" 14 15 #include "llvm/ADT/BitmaskEnum.h" 16 #include "llvm/ADT/Optional.h" 17 #include "llvm/ADT/STLExtras.h" 18 #include "llvm/ADT/SmallVector.h" 19 #include "llvm/ADT/StringRef.h" 20 #include "llvm/ADT/Twine.h" 21 #include "llvm/BinaryFormat/ELF.h" 22 #include "llvm/MC/MCTargetOptions.h" 23 #include "llvm/Object/Archive.h" 24 #include "llvm/Object/ArchiveWriter.h" 25 #include "llvm/Object/Binary.h" 26 #include "llvm/Object/ELFObjectFile.h" 27 #include "llvm/Object/ELFTypes.h" 28 #include "llvm/Object/Error.h" 29 #include "llvm/Option/Arg.h" 30 #include "llvm/Option/ArgList.h" 31 #include "llvm/Option/Option.h" 32 #include "llvm/Support/Casting.h" 33 #include "llvm/Support/CommandLine.h" 34 #include "llvm/Support/Compiler.h" 35 #include "llvm/Support/Compression.h" 36 #include "llvm/Support/Error.h" 37 #include "llvm/Support/ErrorHandling.h" 38 #include "llvm/Support/ErrorOr.h" 39 #include "llvm/Support/FileOutputBuffer.h" 40 #include "llvm/Support/InitLLVM.h" 41 #include "llvm/Support/Memory.h" 42 #include "llvm/Support/Path.h" 43 #include "llvm/Support/Process.h" 44 #include "llvm/Support/WithColor.h" 45 #include "llvm/Support/raw_ostream.h" 46 #include <algorithm> 47 #include <cassert> 48 #include <cstdlib> 49 #include <functional> 50 #include <iterator> 51 #include <memory> 52 #include <string> 53 #include <system_error> 54 #include <utility> 55 56 namespace llvm { 57 namespace objcopy { 58 59 // The name this program was invoked as. 60 StringRef ToolName; 61 62 LLVM_ATTRIBUTE_NORETURN void error(Twine Message) { 63 WithColor::error(errs(), ToolName) << Message << ".\n"; 64 errs().flush(); 65 exit(1); 66 } 67 68 LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, std::error_code EC) { 69 assert(EC); 70 WithColor::error(errs(), ToolName) 71 << "'" << File << "': " << EC.message() << ".\n"; 72 exit(1); 73 } 74 75 LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, Error E) { 76 assert(E); 77 std::string Buf; 78 raw_string_ostream OS(Buf); 79 logAllUnhandledErrors(std::move(E), OS, ""); 80 OS.flush(); 81 WithColor::error(errs(), ToolName) << "'" << File << "': " << Buf; 82 exit(1); 83 } 84 85 } // end namespace objcopy 86 } // end namespace llvm 87 88 // TODO: move everything enclosed in the namespace llvm::objcopy::elf 89 // into separate header+cpp files. 90 namespace llvm { 91 namespace objcopy { 92 namespace elf { 93 94 using namespace object; 95 using namespace ELF; 96 using SectionPred = std::function<bool(const SectionBase &Sec)>; 97 98 static bool isDebugSection(const SectionBase &Sec) { 99 return StringRef(Sec.Name).startswith(".debug") || 100 StringRef(Sec.Name).startswith(".zdebug") || Sec.Name == ".gdb_index"; 101 } 102 103 static bool isDWOSection(const SectionBase &Sec) { 104 return StringRef(Sec.Name).endswith(".dwo"); 105 } 106 107 static bool onlyKeepDWOPred(const Object &Obj, const SectionBase &Sec) { 108 // We can't remove the section header string table. 109 if (&Sec == Obj.SectionNames) 110 return false; 111 // Short of keeping the string table we want to keep everything that is a DWO 112 // section and remove everything else. 113 return !isDWOSection(Sec); 114 } 115 116 static ElfType getOutputElfType(const Binary &Bin) { 117 // Infer output ELF type from the input ELF object 118 if (isa<ELFObjectFile<ELF32LE>>(Bin)) 119 return ELFT_ELF32LE; 120 if (isa<ELFObjectFile<ELF64LE>>(Bin)) 121 return ELFT_ELF64LE; 122 if (isa<ELFObjectFile<ELF32BE>>(Bin)) 123 return ELFT_ELF32BE; 124 if (isa<ELFObjectFile<ELF64BE>>(Bin)) 125 return ELFT_ELF64BE; 126 llvm_unreachable("Invalid ELFType"); 127 } 128 129 static ElfType getOutputElfType(const MachineInfo &MI) { 130 // Infer output ELF type from the binary arch specified 131 if (MI.Is64Bit) 132 return MI.IsLittleEndian ? ELFT_ELF64LE : ELFT_ELF64BE; 133 else 134 return MI.IsLittleEndian ? ELFT_ELF32LE : ELFT_ELF32BE; 135 } 136 137 static std::unique_ptr<Writer> createWriter(const CopyConfig &Config, 138 Object &Obj, Buffer &Buf, 139 ElfType OutputElfType) { 140 if (Config.OutputFormat == "binary") { 141 return llvm::make_unique<BinaryWriter>(Obj, Buf); 142 } 143 // Depending on the initial ELFT and OutputFormat we need a different Writer. 144 switch (OutputElfType) { 145 case ELFT_ELF32LE: 146 return llvm::make_unique<ELFWriter<ELF32LE>>(Obj, Buf, 147 !Config.StripSections); 148 case ELFT_ELF64LE: 149 return llvm::make_unique<ELFWriter<ELF64LE>>(Obj, Buf, 150 !Config.StripSections); 151 case ELFT_ELF32BE: 152 return llvm::make_unique<ELFWriter<ELF32BE>>(Obj, Buf, 153 !Config.StripSections); 154 case ELFT_ELF64BE: 155 return llvm::make_unique<ELFWriter<ELF64BE>>(Obj, Buf, 156 !Config.StripSections); 157 } 158 llvm_unreachable("Invalid output format"); 159 } 160 161 static void splitDWOToFile(const CopyConfig &Config, const Reader &Reader, 162 StringRef File, ElfType OutputElfType) { 163 auto DWOFile = Reader.create(); 164 DWOFile->removeSections( 165 [&](const SectionBase &Sec) { return onlyKeepDWOPred(*DWOFile, Sec); }); 166 FileBuffer FB(File); 167 auto Writer = createWriter(Config, *DWOFile, FB, OutputElfType); 168 Writer->finalize(); 169 Writer->write(); 170 } 171 172 static Error dumpSectionToFile(StringRef SecName, StringRef Filename, 173 Object &Obj) { 174 for (auto &Sec : Obj.sections()) { 175 if (Sec.Name == SecName) { 176 if (Sec.OriginalData.size() == 0) 177 return make_error<StringError>("Can't dump section \"" + SecName + 178 "\": it has no contents", 179 object_error::parse_failed); 180 Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr = 181 FileOutputBuffer::create(Filename, Sec.OriginalData.size()); 182 if (!BufferOrErr) 183 return BufferOrErr.takeError(); 184 std::unique_ptr<FileOutputBuffer> Buf = std::move(*BufferOrErr); 185 std::copy(Sec.OriginalData.begin(), Sec.OriginalData.end(), 186 Buf->getBufferStart()); 187 if (Error E = Buf->commit()) 188 return E; 189 return Error::success(); 190 } 191 } 192 return make_error<StringError>("Section not found", 193 object_error::parse_failed); 194 } 195 196 static bool isCompressed(const SectionBase &Section) { 197 const char *Magic = "ZLIB"; 198 return StringRef(Section.Name).startswith(".zdebug") || 199 (Section.OriginalData.size() > strlen(Magic) && 200 !strncmp(reinterpret_cast<const char *>(Section.OriginalData.data()), 201 Magic, strlen(Magic))) || 202 (Section.Flags & ELF::SHF_COMPRESSED); 203 } 204 205 static bool isCompressable(const SectionBase &Section) { 206 return !isCompressed(Section) && isDebugSection(Section) && 207 Section.Name != ".gdb_index"; 208 } 209 210 static void replaceDebugSections( 211 const CopyConfig &Config, Object &Obj, SectionPred &RemovePred, 212 function_ref<bool(const SectionBase &)> shouldReplace, 213 function_ref<SectionBase *(const SectionBase *)> addSection) { 214 SmallVector<SectionBase *, 13> ToReplace; 215 SmallVector<RelocationSection *, 13> RelocationSections; 216 for (auto &Sec : Obj.sections()) { 217 if (RelocationSection *R = dyn_cast<RelocationSection>(&Sec)) { 218 if (shouldReplace(*R->getSection())) 219 RelocationSections.push_back(R); 220 continue; 221 } 222 223 if (shouldReplace(Sec)) 224 ToReplace.push_back(&Sec); 225 } 226 227 for (SectionBase *S : ToReplace) { 228 SectionBase *NewSection = addSection(S); 229 230 for (RelocationSection *RS : RelocationSections) { 231 if (RS->getSection() == S) 232 RS->setSection(NewSection); 233 } 234 } 235 236 RemovePred = [shouldReplace, RemovePred](const SectionBase &Sec) { 237 return shouldReplace(Sec) || RemovePred(Sec); 238 }; 239 } 240 241 // This function handles the high level operations of GNU objcopy including 242 // handling command line options. It's important to outline certain properties 243 // we expect to hold of the command line operations. Any operation that "keeps" 244 // should keep regardless of a remove. Additionally any removal should respect 245 // any previous removals. Lastly whether or not something is removed shouldn't 246 // depend a) on the order the options occur in or b) on some opaque priority 247 // system. The only priority is that keeps/copies overrule removes. 248 static void handleArgs(const CopyConfig &Config, Object &Obj, 249 const Reader &Reader, ElfType OutputElfType) { 250 251 if (!Config.SplitDWO.empty()) { 252 splitDWOToFile(Config, Reader, Config.SplitDWO, OutputElfType); 253 } 254 255 // TODO: update or remove symbols only if there is an option that affects 256 // them. 257 if (Obj.SymbolTable) { 258 Obj.SymbolTable->updateSymbols([&](Symbol &Sym) { 259 if ((Config.LocalizeHidden && 260 (Sym.Visibility == STV_HIDDEN || Sym.Visibility == STV_INTERNAL)) || 261 (!Config.SymbolsToLocalize.empty() && 262 is_contained(Config.SymbolsToLocalize, Sym.Name))) 263 Sym.Binding = STB_LOCAL; 264 265 // Note: these two globalize flags have very similar names but different 266 // meanings: 267 // 268 // --globalize-symbol: promote a symbol to global 269 // --keep-global-symbol: all symbols except for these should be made local 270 // 271 // If --globalize-symbol is specified for a given symbol, it will be 272 // global in the output file even if it is not included via 273 // --keep-global-symbol. Because of that, make sure to check 274 // --globalize-symbol second. 275 if (!Config.SymbolsToKeepGlobal.empty() && 276 !is_contained(Config.SymbolsToKeepGlobal, Sym.Name)) 277 Sym.Binding = STB_LOCAL; 278 279 if (!Config.SymbolsToGlobalize.empty() && 280 is_contained(Config.SymbolsToGlobalize, Sym.Name)) 281 Sym.Binding = STB_GLOBAL; 282 283 if (!Config.SymbolsToWeaken.empty() && 284 is_contained(Config.SymbolsToWeaken, Sym.Name) && 285 Sym.Binding == STB_GLOBAL) 286 Sym.Binding = STB_WEAK; 287 288 if (Config.Weaken && Sym.Binding == STB_GLOBAL && 289 Sym.getShndx() != SHN_UNDEF) 290 Sym.Binding = STB_WEAK; 291 292 const auto I = Config.SymbolsToRename.find(Sym.Name); 293 if (I != Config.SymbolsToRename.end()) 294 Sym.Name = I->getValue(); 295 296 if (!Config.SymbolsPrefix.empty() && Sym.Type != STT_SECTION) 297 Sym.Name = (Config.SymbolsPrefix + Sym.Name).str(); 298 }); 299 300 // The purpose of this loop is to mark symbols referenced by sections 301 // (like GroupSection or RelocationSection). This way, we know which 302 // symbols are still 'needed' and which are not. 303 if (Config.StripUnneeded) { 304 for (auto &Section : Obj.sections()) 305 Section.markSymbols(); 306 } 307 308 Obj.removeSymbols([&](const Symbol &Sym) { 309 if ((!Config.SymbolsToKeep.empty() && 310 is_contained(Config.SymbolsToKeep, Sym.Name)) || 311 (Config.KeepFileSymbols && Sym.Type == STT_FILE)) 312 return false; 313 314 if (Config.DiscardAll && Sym.Binding == STB_LOCAL && 315 Sym.getShndx() != SHN_UNDEF && Sym.Type != STT_FILE && 316 Sym.Type != STT_SECTION) 317 return true; 318 319 if (Config.StripAll || Config.StripAllGNU) 320 return true; 321 322 if (!Config.SymbolsToRemove.empty() && 323 is_contained(Config.SymbolsToRemove, Sym.Name)) { 324 return true; 325 } 326 327 if (Config.StripUnneeded && !Sym.Referenced && 328 (Sym.Binding == STB_LOCAL || Sym.getShndx() == SHN_UNDEF) && 329 Sym.Type != STT_FILE && Sym.Type != STT_SECTION) 330 return true; 331 332 return false; 333 }); 334 } 335 336 SectionPred RemovePred = [](const SectionBase &) { return false; }; 337 338 // Removes: 339 if (!Config.ToRemove.empty()) { 340 RemovePred = [&Config](const SectionBase &Sec) { 341 return is_contained(Config.ToRemove, Sec.Name); 342 }; 343 } 344 345 if (Config.StripDWO || !Config.SplitDWO.empty()) 346 RemovePred = [RemovePred](const SectionBase &Sec) { 347 return isDWOSection(Sec) || RemovePred(Sec); 348 }; 349 350 if (Config.ExtractDWO) 351 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { 352 return onlyKeepDWOPred(Obj, Sec) || RemovePred(Sec); 353 }; 354 355 if (Config.StripAllGNU) 356 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { 357 if (RemovePred(Sec)) 358 return true; 359 if ((Sec.Flags & SHF_ALLOC) != 0) 360 return false; 361 if (&Sec == Obj.SectionNames) 362 return false; 363 switch (Sec.Type) { 364 case SHT_SYMTAB: 365 case SHT_REL: 366 case SHT_RELA: 367 case SHT_STRTAB: 368 return true; 369 } 370 return isDebugSection(Sec); 371 }; 372 373 if (Config.StripSections) { 374 RemovePred = [RemovePred](const SectionBase &Sec) { 375 return RemovePred(Sec) || (Sec.Flags & SHF_ALLOC) == 0; 376 }; 377 } 378 379 if (Config.StripDebug) { 380 RemovePred = [RemovePred](const SectionBase &Sec) { 381 return RemovePred(Sec) || isDebugSection(Sec); 382 }; 383 } 384 385 if (Config.StripNonAlloc) 386 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { 387 if (RemovePred(Sec)) 388 return true; 389 if (&Sec == Obj.SectionNames) 390 return false; 391 return (Sec.Flags & SHF_ALLOC) == 0; 392 }; 393 394 if (Config.StripAll) 395 RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { 396 if (RemovePred(Sec)) 397 return true; 398 if (&Sec == Obj.SectionNames) 399 return false; 400 if (StringRef(Sec.Name).startswith(".gnu.warning")) 401 return false; 402 return (Sec.Flags & SHF_ALLOC) == 0; 403 }; 404 405 // Explicit copies: 406 if (!Config.OnlyKeep.empty()) { 407 RemovePred = [&Config, RemovePred, &Obj](const SectionBase &Sec) { 408 // Explicitly keep these sections regardless of previous removes. 409 if (is_contained(Config.OnlyKeep, Sec.Name)) 410 return false; 411 412 // Allow all implicit removes. 413 if (RemovePred(Sec)) 414 return true; 415 416 // Keep special sections. 417 if (Obj.SectionNames == &Sec) 418 return false; 419 if (Obj.SymbolTable == &Sec || 420 (Obj.SymbolTable && Obj.SymbolTable->getStrTab() == &Sec)) 421 return false; 422 423 // Remove everything else. 424 return true; 425 }; 426 } 427 428 if (!Config.Keep.empty()) { 429 RemovePred = [Config, RemovePred](const SectionBase &Sec) { 430 // Explicitly keep these sections regardless of previous removes. 431 if (is_contained(Config.Keep, Sec.Name)) 432 return false; 433 // Otherwise defer to RemovePred. 434 return RemovePred(Sec); 435 }; 436 } 437 438 // This has to be the last predicate assignment. 439 // If the option --keep-symbol has been specified 440 // and at least one of those symbols is present 441 // (equivalently, the updated symbol table is not empty) 442 // the symbol table and the string table should not be removed. 443 if ((!Config.SymbolsToKeep.empty() || Config.KeepFileSymbols) && 444 Obj.SymbolTable && !Obj.SymbolTable->empty()) { 445 RemovePred = [&Obj, RemovePred](const SectionBase &Sec) { 446 if (&Sec == Obj.SymbolTable || &Sec == Obj.SymbolTable->getStrTab()) 447 return false; 448 return RemovePred(Sec); 449 }; 450 } 451 452 if (Config.CompressionType != DebugCompressionType::None) 453 replaceDebugSections(Config, Obj, RemovePred, isCompressable, 454 [&Config, &Obj](const SectionBase *S) { 455 return &Obj.addSection<CompressedSection>( 456 *S, Config.CompressionType); 457 }); 458 else if (Config.DecompressDebugSections) 459 replaceDebugSections( 460 Config, Obj, RemovePred, 461 [](const SectionBase &S) { return isa<CompressedSection>(&S); }, 462 [&Obj](const SectionBase *S) { 463 auto CS = cast<CompressedSection>(S); 464 return &Obj.addSection<DecompressedSection>(*CS); 465 }); 466 467 Obj.removeSections(RemovePred); 468 469 if (!Config.SectionsToRename.empty()) { 470 for (auto &Sec : Obj.sections()) { 471 const auto Iter = Config.SectionsToRename.find(Sec.Name); 472 if (Iter != Config.SectionsToRename.end()) { 473 const SectionRename &SR = Iter->second; 474 Sec.Name = SR.NewName; 475 if (SR.NewFlags.hasValue()) { 476 // Preserve some flags which should not be dropped when setting flags. 477 // Also, preserve anything OS/processor dependant. 478 const uint64_t PreserveMask = ELF::SHF_COMPRESSED | ELF::SHF_EXCLUDE | 479 ELF::SHF_GROUP | ELF::SHF_LINK_ORDER | 480 ELF::SHF_MASKOS | ELF::SHF_MASKPROC | 481 ELF::SHF_TLS | ELF::SHF_INFO_LINK; 482 Sec.Flags = (Sec.Flags & PreserveMask) | 483 (SR.NewFlags.getValue() & ~PreserveMask); 484 } 485 } 486 } 487 } 488 489 if (!Config.AddSection.empty()) { 490 for (const auto &Flag : Config.AddSection) { 491 auto SecPair = Flag.split("="); 492 auto SecName = SecPair.first; 493 auto File = SecPair.second; 494 auto BufOrErr = MemoryBuffer::getFile(File); 495 if (!BufOrErr) 496 reportError(File, BufOrErr.getError()); 497 auto Buf = std::move(*BufOrErr); 498 auto BufPtr = reinterpret_cast<const uint8_t *>(Buf->getBufferStart()); 499 auto BufSize = Buf->getBufferSize(); 500 Obj.addSection<OwnedDataSection>(SecName, 501 ArrayRef<uint8_t>(BufPtr, BufSize)); 502 } 503 } 504 505 if (!Config.DumpSection.empty()) { 506 for (const auto &Flag : Config.DumpSection) { 507 std::pair<StringRef, StringRef> SecPair = Flag.split("="); 508 StringRef SecName = SecPair.first; 509 StringRef File = SecPair.second; 510 if (Error E = dumpSectionToFile(SecName, File, Obj)) 511 reportError(Config.InputFilename, std::move(E)); 512 } 513 } 514 515 if (!Config.AddGnuDebugLink.empty()) 516 Obj.addSection<GnuDebugLinkSection>(Config.AddGnuDebugLink); 517 } 518 519 void executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In, 520 Buffer &Out) { 521 BinaryReader Reader(Config.BinaryArch, &In); 522 std::unique_ptr<Object> Obj = Reader.create(); 523 524 const ElfType OutputElfType = getOutputElfType(Config.BinaryArch); 525 handleArgs(Config, *Obj, Reader, OutputElfType); 526 std::unique_ptr<Writer> Writer = 527 createWriter(Config, *Obj, Out, OutputElfType); 528 Writer->finalize(); 529 Writer->write(); 530 } 531 532 void executeObjcopyOnBinary(const CopyConfig &Config, 533 object::ELFObjectFileBase &In, Buffer &Out) { 534 ELFReader Reader(&In); 535 std::unique_ptr<Object> Obj = Reader.create(); 536 const ElfType OutputElfType = getOutputElfType(In); 537 handleArgs(Config, *Obj, Reader, OutputElfType); 538 std::unique_ptr<Writer> Writer = 539 createWriter(Config, *Obj, Out, OutputElfType); 540 Writer->finalize(); 541 Writer->write(); 542 } 543 544 } // end namespace elf 545 } // end namespace objcopy 546 } // end namespace llvm 547 548 using namespace llvm; 549 using namespace llvm::object; 550 using namespace llvm::objcopy; 551 552 // For regular archives this function simply calls llvm::writeArchive, 553 // For thin archives it writes the archive file itself as well as its members. 554 static Error deepWriteArchive(StringRef ArcName, 555 ArrayRef<NewArchiveMember> NewMembers, 556 bool WriteSymtab, object::Archive::Kind Kind, 557 bool Deterministic, bool Thin) { 558 Error E = 559 writeArchive(ArcName, NewMembers, WriteSymtab, Kind, Deterministic, Thin); 560 if (!Thin || E) 561 return E; 562 for (const NewArchiveMember &Member : NewMembers) { 563 // Internally, FileBuffer will use the buffer created by 564 // FileOutputBuffer::create, for regular files (that is the case for 565 // deepWriteArchive) FileOutputBuffer::create will return OnDiskBuffer. 566 // OnDiskBuffer uses a temporary file and then renames it. So in reality 567 // there is no inefficiency / duplicated in-memory buffers in this case. For 568 // now in-memory buffers can not be completely avoided since 569 // NewArchiveMember still requires them even though writeArchive does not 570 // write them on disk. 571 FileBuffer FB(Member.MemberName); 572 FB.allocate(Member.Buf->getBufferSize()); 573 std::copy(Member.Buf->getBufferStart(), Member.Buf->getBufferEnd(), 574 FB.getBufferStart()); 575 if (auto E = FB.commit()) 576 return E; 577 } 578 return Error::success(); 579 } 580 581 /// The function executeObjcopyOnRawBinary does the dispatch based on the format 582 /// of the output specified by the command line options. 583 static void executeObjcopyOnRawBinary(const CopyConfig &Config, 584 MemoryBuffer &In, Buffer &Out) { 585 // TODO: llvm-objcopy should parse CopyConfig.OutputFormat to recognize 586 // formats other than ELF / "binary" and invoke 587 // elf::executeObjcopyOnRawBinary, macho::executeObjcopyOnRawBinary or 588 // coff::executeObjcopyOnRawBinary accordingly. 589 return elf::executeObjcopyOnRawBinary(Config, In, Out); 590 } 591 592 /// The function executeObjcopyOnBinary does the dispatch based on the format 593 /// of the input binary (ELF, MachO or COFF). 594 static void executeObjcopyOnBinary(const CopyConfig &Config, object::Binary &In, 595 Buffer &Out) { 596 if (auto *ELFBinary = dyn_cast<object::ELFObjectFileBase>(&In)) 597 return elf::executeObjcopyOnBinary(Config, *ELFBinary, Out); 598 else 599 error("Unsupported object file format"); 600 } 601 602 static void executeObjcopyOnArchive(const CopyConfig &Config, 603 const Archive &Ar) { 604 std::vector<NewArchiveMember> NewArchiveMembers; 605 Error Err = Error::success(); 606 for (const Archive::Child &Child : Ar.children(Err)) { 607 Expected<std::unique_ptr<Binary>> ChildOrErr = Child.getAsBinary(); 608 if (!ChildOrErr) 609 reportError(Ar.getFileName(), ChildOrErr.takeError()); 610 Binary *Bin = ChildOrErr->get(); 611 612 Expected<StringRef> ChildNameOrErr = Child.getName(); 613 if (!ChildNameOrErr) 614 reportError(Ar.getFileName(), ChildNameOrErr.takeError()); 615 616 MemBuffer MB(ChildNameOrErr.get()); 617 executeObjcopyOnBinary(Config, *Bin, 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 restoreDateOnFile(StringRef Filename, 637 const sys::fs::file_status &Stat) { 638 int FD; 639 640 if (auto EC = 641 sys::fs::openFileForWrite(Filename, FD, sys::fs::CD_OpenExisting)) 642 reportError(Filename, EC); 643 644 if (auto EC = sys::fs::setLastAccessAndModificationTime( 645 FD, Stat.getLastAccessedTime(), Stat.getLastModificationTime())) 646 reportError(Filename, EC); 647 648 if (auto EC = sys::Process::SafelyCloseFileDescriptor(FD)) 649 reportError(Filename, EC); 650 } 651 652 /// The function executeObjcopy does the higher level dispatch based on the type 653 /// of input (raw binary, archive or single object file) and takes care of the 654 /// format-agnostic modifications, i.e. preserving dates. 655 static void executeObjcopy(const CopyConfig &Config) { 656 sys::fs::file_status Stat; 657 if (Config.PreserveDates) 658 if (auto EC = sys::fs::status(Config.InputFilename, Stat)) 659 reportError(Config.InputFilename, EC); 660 661 if (Config.InputFormat == "binary") { 662 auto BufOrErr = MemoryBuffer::getFile(Config.InputFilename); 663 if (!BufOrErr) 664 reportError(Config.InputFilename, BufOrErr.getError()); 665 FileBuffer FB(Config.OutputFilename); 666 executeObjcopyOnRawBinary(Config, *BufOrErr->get(), FB); 667 } else { 668 Expected<OwningBinary<llvm::object::Binary>> BinaryOrErr = 669 createBinary(Config.InputFilename); 670 if (!BinaryOrErr) 671 reportError(Config.InputFilename, BinaryOrErr.takeError()); 672 673 if (Archive *Ar = dyn_cast<Archive>(BinaryOrErr.get().getBinary())) { 674 executeObjcopyOnArchive(Config, *Ar); 675 } else { 676 FileBuffer FB(Config.OutputFilename); 677 executeObjcopyOnBinary(Config, *BinaryOrErr.get().getBinary(), FB); 678 } 679 } 680 681 if (Config.PreserveDates) { 682 restoreDateOnFile(Config.OutputFilename, Stat); 683 if (!Config.SplitDWO.empty()) 684 restoreDateOnFile(Config.SplitDWO, Stat); 685 } 686 } 687 688 int main(int argc, char **argv) { 689 InitLLVM X(argc, argv); 690 ToolName = argv[0]; 691 DriverConfig DriverConfig; 692 if (sys::path::stem(ToolName).endswith_lower("strip")) 693 DriverConfig = parseStripOptions(makeArrayRef(argv + 1, argc)); 694 else 695 DriverConfig = parseObjcopyOptions(makeArrayRef(argv + 1, argc)); 696 for (const CopyConfig &CopyConfig : DriverConfig.CopyConfigs) 697 executeObjcopy(CopyConfig); 698 } 699