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