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