xref: /llvm-project/llvm/tools/llvm-objcopy/llvm-objcopy.cpp (revision 8d0b74c9405316e2f6c2f11e093c0109e4cc8038)
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