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