xref: /llvm-project/llvm/tools/llvm-objcopy/llvm-objcopy.cpp (revision 88ed5e59bd52cb30344ad8d88c67965e415c83e1)
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 
12 #include "Object.h"
13 #include "llvm/ADT/BitmaskEnum.h"
14 #include "llvm/ADT/Optional.h"
15 #include "llvm/ADT/STLExtras.h"
16 #include "llvm/ADT/SmallVector.h"
17 #include "llvm/ADT/StringRef.h"
18 #include "llvm/ADT/Twine.h"
19 #include "llvm/BinaryFormat/ELF.h"
20 #include "llvm/Object/Archive.h"
21 #include "llvm/Object/ArchiveWriter.h"
22 #include "llvm/Object/Binary.h"
23 #include "llvm/Object/ELFObjectFile.h"
24 #include "llvm/Object/ELFTypes.h"
25 #include "llvm/Object/Error.h"
26 #include "llvm/Option/Arg.h"
27 #include "llvm/Option/ArgList.h"
28 #include "llvm/Option/Option.h"
29 #include "llvm/Support/Casting.h"
30 #include "llvm/Support/CommandLine.h"
31 #include "llvm/Support/Compiler.h"
32 #include "llvm/Support/Error.h"
33 #include "llvm/Support/ErrorHandling.h"
34 #include "llvm/Support/ErrorOr.h"
35 #include "llvm/Support/FileOutputBuffer.h"
36 #include "llvm/Support/InitLLVM.h"
37 #include "llvm/Support/Path.h"
38 #include "llvm/Support/WithColor.h"
39 #include "llvm/Support/raw_ostream.h"
40 #include <algorithm>
41 #include <cassert>
42 #include <cstdlib>
43 #include <functional>
44 #include <iterator>
45 #include <memory>
46 #include <string>
47 #include <system_error>
48 #include <utility>
49 
50 using namespace llvm;
51 using namespace llvm::objcopy;
52 using namespace object;
53 using namespace ELF;
54 
55 namespace {
56 
57 enum ObjcopyID {
58   OBJCOPY_INVALID = 0, // This is not an option ID.
59 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
60                HELPTEXT, METAVAR, VALUES)                                      \
61   OBJCOPY_##ID,
62 #include "ObjcopyOpts.inc"
63 #undef OPTION
64 };
65 
66 #define PREFIX(NAME, VALUE) const char *const OBJCOPY_##NAME[] = VALUE;
67 #include "ObjcopyOpts.inc"
68 #undef PREFIX
69 
70 static const opt::OptTable::Info ObjcopyInfoTable[] = {
71 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
72                HELPTEXT, METAVAR, VALUES)                                      \
73   {OBJCOPY_##PREFIX,                                                           \
74    NAME,                                                                       \
75    HELPTEXT,                                                                   \
76    METAVAR,                                                                    \
77    OBJCOPY_##ID,                                                               \
78    opt::Option::KIND##Class,                                                   \
79    PARAM,                                                                      \
80    FLAGS,                                                                      \
81    OBJCOPY_##GROUP,                                                            \
82    OBJCOPY_##ALIAS,                                                            \
83    ALIASARGS,                                                                  \
84    VALUES},
85 #include "ObjcopyOpts.inc"
86 #undef OPTION
87 };
88 
89 class ObjcopyOptTable : public opt::OptTable {
90 public:
91   ObjcopyOptTable() : OptTable(ObjcopyInfoTable, true) {}
92 };
93 
94 enum StripID {
95   STRIP_INVALID = 0, // This is not an option ID.
96 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
97                HELPTEXT, METAVAR, VALUES)                                      \
98   STRIP_##ID,
99 #include "StripOpts.inc"
100 #undef OPTION
101 };
102 
103 #define PREFIX(NAME, VALUE) const char *const STRIP_##NAME[] = VALUE;
104 #include "StripOpts.inc"
105 #undef PREFIX
106 
107 static const opt::OptTable::Info StripInfoTable[] = {
108 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
109                HELPTEXT, METAVAR, VALUES)                                      \
110   {STRIP_##PREFIX, NAME,       HELPTEXT,                                       \
111    METAVAR,        STRIP_##ID, opt::Option::KIND##Class,                       \
112    PARAM,          FLAGS,      STRIP_##GROUP,                                  \
113    STRIP_##ALIAS,  ALIASARGS,  VALUES},
114 #include "StripOpts.inc"
115 #undef OPTION
116 };
117 
118 class StripOptTable : public opt::OptTable {
119 public:
120   StripOptTable() : OptTable(StripInfoTable, true) {}
121 };
122 
123 struct SectionRename {
124   StringRef OriginalName;
125   StringRef NewName;
126   Optional<uint64_t> NewFlags;
127 };
128 
129 struct CopyConfig {
130   StringRef OutputFilename;
131   StringRef InputFilename;
132   StringRef OutputFormat;
133   StringRef InputFormat;
134   StringRef BinaryArch;
135 
136   StringRef SplitDWO;
137   StringRef AddGnuDebugLink;
138   StringRef SymbolsPrefix;
139   std::vector<StringRef> ToRemove;
140   std::vector<StringRef> Keep;
141   std::vector<StringRef> OnlyKeep;
142   std::vector<StringRef> AddSection;
143   std::vector<StringRef> DumpSection;
144   std::vector<StringRef> SymbolsToLocalize;
145   std::vector<StringRef> SymbolsToGlobalize;
146   std::vector<StringRef> SymbolsToWeaken;
147   std::vector<StringRef> SymbolsToRemove;
148   std::vector<StringRef> SymbolsToKeep;
149   StringMap<SectionRename> SectionsToRename;
150   StringMap<StringRef> SymbolsToRename;
151   bool StripAll = false;
152   bool StripAllGNU = false;
153   bool StripDebug = false;
154   bool StripSections = false;
155   bool StripNonAlloc = false;
156   bool StripDWO = false;
157   bool StripUnneeded = false;
158   bool ExtractDWO = false;
159   bool LocalizeHidden = false;
160   bool Weaken = false;
161   bool DiscardAll = false;
162   bool OnlyKeepDebug = false;
163   bool KeepFileSymbols = false;
164 };
165 
166 using SectionPred = std::function<bool(const SectionBase &Sec)>;
167 
168 enum SectionFlag {
169   SecNone = 0,
170   SecAlloc = 1 << 0,
171   SecLoad = 1 << 1,
172   SecNoload = 1 << 2,
173   SecReadonly = 1 << 3,
174   SecDebug = 1 << 4,
175   SecCode = 1 << 5,
176   SecData = 1 << 6,
177   SecRom = 1 << 7,
178   SecMerge = 1 << 8,
179   SecStrings = 1 << 9,
180   SecContents = 1 << 10,
181   SecShare = 1 << 11,
182   LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ SecShare)
183 };
184 
185 } // namespace
186 
187 namespace llvm {
188 namespace objcopy {
189 
190 // The name this program was invoked as.
191 StringRef ToolName;
192 
193 LLVM_ATTRIBUTE_NORETURN void error(Twine Message) {
194   WithColor::error(errs(), ToolName) << Message << ".\n";
195   errs().flush();
196   exit(1);
197 }
198 
199 LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, std::error_code EC) {
200   assert(EC);
201   WithColor::error(errs(), ToolName)
202       << "'" << File << "': " << EC.message() << ".\n";
203   exit(1);
204 }
205 
206 LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, Error E) {
207   assert(E);
208   std::string Buf;
209   raw_string_ostream OS(Buf);
210   logAllUnhandledErrors(std::move(E), OS, "");
211   OS.flush();
212   WithColor::error(errs(), ToolName) << "'" << File << "': " << Buf;
213   exit(1);
214 }
215 
216 } // end namespace objcopy
217 } // end namespace llvm
218 
219 static SectionFlag ParseSectionRenameFlag(StringRef SectionName) {
220   return llvm::StringSwitch<SectionFlag>(SectionName)
221       .Case("alloc", SectionFlag::SecAlloc)
222       .Case("load", SectionFlag::SecLoad)
223       .Case("noload", SectionFlag::SecNoload)
224       .Case("readonly", SectionFlag::SecReadonly)
225       .Case("debug", SectionFlag::SecDebug)
226       .Case("code", SectionFlag::SecCode)
227       .Case("data", SectionFlag::SecData)
228       .Case("rom", SectionFlag::SecRom)
229       .Case("merge", SectionFlag::SecMerge)
230       .Case("strings", SectionFlag::SecStrings)
231       .Case("contents", SectionFlag::SecContents)
232       .Case("share", SectionFlag::SecShare)
233       .Default(SectionFlag::SecNone);
234 }
235 
236 static SectionRename ParseRenameSectionValue(StringRef FlagValue) {
237   if (!FlagValue.contains('='))
238     error("Bad format for --rename-section: missing '='");
239 
240   // Initial split: ".foo" = ".bar,f1,f2,..."
241   auto Old2New = FlagValue.split('=');
242   SectionRename SR;
243   SR.OriginalName = Old2New.first;
244 
245   // Flags split: ".bar" "f1" "f2" ...
246   SmallVector<StringRef, 6> NameAndFlags;
247   Old2New.second.split(NameAndFlags, ',');
248   SR.NewName = NameAndFlags[0];
249 
250   if (NameAndFlags.size() > 1) {
251     SectionFlag Flags = SectionFlag::SecNone;
252     for (size_t I = 1, Size = NameAndFlags.size(); I < Size; ++I) {
253       SectionFlag Flag = ParseSectionRenameFlag(NameAndFlags[I]);
254       if (Flag == SectionFlag::SecNone)
255         error("Unrecognized section flag '" + NameAndFlags[I] +
256               "'. Flags supported for GNU compatibility: alloc, load, noload, "
257               "readonly, debug, code, data, rom, share, contents, merge, "
258               "strings.");
259       Flags |= Flag;
260     }
261 
262     SR.NewFlags = 0;
263     if (Flags & SectionFlag::SecAlloc)
264       *SR.NewFlags |= ELF::SHF_ALLOC;
265     if (!(Flags & SectionFlag::SecReadonly))
266       *SR.NewFlags |= ELF::SHF_WRITE;
267     if (Flags & SectionFlag::SecCode)
268       *SR.NewFlags |= ELF::SHF_EXECINSTR;
269     if (Flags & SectionFlag::SecMerge)
270       *SR.NewFlags |= ELF::SHF_MERGE;
271     if (Flags & SectionFlag::SecStrings)
272       *SR.NewFlags |= ELF::SHF_STRINGS;
273   }
274 
275   return SR;
276 }
277 
278 static bool IsDebugSection(const SectionBase &Sec) {
279   return Sec.Name.startswith(".debug") || Sec.Name.startswith(".zdebug") ||
280          Sec.Name == ".gdb_index";
281 }
282 
283 static bool IsDWOSection(const SectionBase &Sec) {
284   return Sec.Name.endswith(".dwo");
285 }
286 
287 static bool OnlyKeepDWOPred(const Object &Obj, const SectionBase &Sec) {
288   // We can't remove the section header string table.
289   if (&Sec == Obj.SectionNames)
290     return false;
291   // Short of keeping the string table we want to keep everything that is a DWO
292   // section and remove everything else.
293   return !IsDWOSection(Sec);
294 }
295 
296 static std::unique_ptr<Writer> CreateWriter(const CopyConfig &Config,
297                                             Object &Obj, Buffer &Buf,
298                                             ElfType OutputElfType) {
299   if (Config.OutputFormat == "binary") {
300     return llvm::make_unique<BinaryWriter>(Obj, Buf);
301   }
302   // Depending on the initial ELFT and OutputFormat we need a different Writer.
303   switch (OutputElfType) {
304   case ELFT_ELF32LE:
305     return llvm::make_unique<ELFWriter<ELF32LE>>(Obj, Buf,
306                                                  !Config.StripSections);
307   case ELFT_ELF64LE:
308     return llvm::make_unique<ELFWriter<ELF64LE>>(Obj, Buf,
309                                                  !Config.StripSections);
310   case ELFT_ELF32BE:
311     return llvm::make_unique<ELFWriter<ELF32BE>>(Obj, Buf,
312                                                  !Config.StripSections);
313   case ELFT_ELF64BE:
314     return llvm::make_unique<ELFWriter<ELF64BE>>(Obj, Buf,
315                                                  !Config.StripSections);
316   }
317   llvm_unreachable("Invalid output format");
318 }
319 
320 static void SplitDWOToFile(const CopyConfig &Config, const Reader &Reader,
321                            StringRef File, ElfType OutputElfType) {
322   auto DWOFile = Reader.create();
323   DWOFile->removeSections(
324       [&](const SectionBase &Sec) { return OnlyKeepDWOPred(*DWOFile, Sec); });
325   FileBuffer FB(File);
326   auto Writer = CreateWriter(Config, *DWOFile, FB, OutputElfType);
327   Writer->finalize();
328   Writer->write();
329 }
330 
331 static Error dumpSectionToFile(StringRef SecName, StringRef Filename,
332                                Object &Obj) {
333   for (auto &Sec : Obj.sections()) {
334     if (Sec.Name == SecName) {
335       if (Sec.OriginalData.size() == 0)
336         return make_error<StringError>("Can't dump section \"" + SecName +
337                                            "\": it has no contents",
338                                        object_error::parse_failed);
339       Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
340           FileOutputBuffer::create(Filename, Sec.OriginalData.size());
341       if (!BufferOrErr)
342         return BufferOrErr.takeError();
343       std::unique_ptr<FileOutputBuffer> Buf = std::move(*BufferOrErr);
344       std::copy(Sec.OriginalData.begin(), Sec.OriginalData.end(),
345                 Buf->getBufferStart());
346       if (Error E = Buf->commit())
347         return E;
348       return Error::success();
349     }
350   }
351   return make_error<StringError>("Section not found",
352                                  object_error::parse_failed);
353 }
354 
355 // This function handles the high level operations of GNU objcopy including
356 // handling command line options. It's important to outline certain properties
357 // we expect to hold of the command line operations. Any operation that "keeps"
358 // should keep regardless of a remove. Additionally any removal should respect
359 // any previous removals. Lastly whether or not something is removed shouldn't
360 // depend a) on the order the options occur in or b) on some opaque priority
361 // system. The only priority is that keeps/copies overrule removes.
362 static void HandleArgs(const CopyConfig &Config, Object &Obj,
363                        const Reader &Reader, ElfType OutputElfType) {
364 
365   if (!Config.SplitDWO.empty()) {
366     SplitDWOToFile(Config, Reader, Config.SplitDWO, OutputElfType);
367   }
368 
369   // TODO: update or remove symbols only if there is an option that affects
370   // them.
371   if (Obj.SymbolTable) {
372     Obj.SymbolTable->updateSymbols([&](Symbol &Sym) {
373       if ((Config.LocalizeHidden &&
374            (Sym.Visibility == STV_HIDDEN || Sym.Visibility == STV_INTERNAL)) ||
375           (!Config.SymbolsToLocalize.empty() &&
376            is_contained(Config.SymbolsToLocalize, Sym.Name)))
377         Sym.Binding = STB_LOCAL;
378 
379       if (!Config.SymbolsToGlobalize.empty() &&
380           is_contained(Config.SymbolsToGlobalize, Sym.Name))
381         Sym.Binding = STB_GLOBAL;
382 
383       if (!Config.SymbolsToWeaken.empty() &&
384           is_contained(Config.SymbolsToWeaken, Sym.Name) &&
385           Sym.Binding == STB_GLOBAL)
386         Sym.Binding = STB_WEAK;
387 
388       if (Config.Weaken && Sym.Binding == STB_GLOBAL &&
389           Sym.getShndx() != SHN_UNDEF)
390         Sym.Binding = STB_WEAK;
391 
392       const auto I = Config.SymbolsToRename.find(Sym.Name);
393       if (I != Config.SymbolsToRename.end())
394         Sym.Name = I->getValue();
395 
396       if (!Config.SymbolsPrefix.empty() && Sym.Type != STT_SECTION)
397         Sym.Name = (Config.SymbolsPrefix + Sym.Name).str();
398     });
399 
400     // The purpose of this loop is to mark symbols referenced by sections
401     // (like GroupSection or RelocationSection). This way, we know which
402     // symbols are still 'needed' and wich are not.
403     if (Config.StripUnneeded) {
404       for (auto &Section : Obj.sections())
405         Section.markSymbols();
406     }
407 
408     Obj.removeSymbols([&](const Symbol &Sym) {
409       if ((!Config.SymbolsToKeep.empty() &&
410            is_contained(Config.SymbolsToKeep, Sym.Name)) ||
411           (Config.KeepFileSymbols && Sym.Type == STT_FILE))
412         return false;
413 
414       if (Config.DiscardAll && Sym.Binding == STB_LOCAL &&
415           Sym.getShndx() != SHN_UNDEF && Sym.Type != STT_FILE &&
416           Sym.Type != STT_SECTION)
417         return true;
418 
419       if (Config.StripAll || Config.StripAllGNU)
420         return true;
421 
422       if (!Config.SymbolsToRemove.empty() &&
423           is_contained(Config.SymbolsToRemove, Sym.Name)) {
424         return true;
425       }
426 
427       if (Config.StripUnneeded && !Sym.Referenced &&
428           (Sym.Binding == STB_LOCAL || Sym.getShndx() == SHN_UNDEF) &&
429           Sym.Type != STT_FILE && Sym.Type != STT_SECTION)
430         return true;
431 
432       return false;
433     });
434   }
435 
436   SectionPred RemovePred = [](const SectionBase &) { return false; };
437 
438   // Removes:
439   if (!Config.ToRemove.empty()) {
440     RemovePred = [&Config](const SectionBase &Sec) {
441       return find(Config.ToRemove, Sec.Name) != Config.ToRemove.end();
442     };
443   }
444 
445   if (Config.StripDWO || !Config.SplitDWO.empty())
446     RemovePred = [RemovePred](const SectionBase &Sec) {
447       return IsDWOSection(Sec) || RemovePred(Sec);
448     };
449 
450   if (Config.ExtractDWO)
451     RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
452       return OnlyKeepDWOPred(Obj, Sec) || RemovePred(Sec);
453     };
454 
455   if (Config.StripAllGNU)
456     RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
457       if (RemovePred(Sec))
458         return true;
459       if ((Sec.Flags & SHF_ALLOC) != 0)
460         return false;
461       if (&Sec == Obj.SectionNames)
462         return false;
463       switch (Sec.Type) {
464       case SHT_SYMTAB:
465       case SHT_REL:
466       case SHT_RELA:
467       case SHT_STRTAB:
468         return true;
469       }
470       return IsDebugSection(Sec);
471     };
472 
473   if (Config.StripSections) {
474     RemovePred = [RemovePred](const SectionBase &Sec) {
475       return RemovePred(Sec) || (Sec.Flags & SHF_ALLOC) == 0;
476     };
477   }
478 
479   if (Config.StripDebug) {
480     RemovePred = [RemovePred](const SectionBase &Sec) {
481       return RemovePred(Sec) || IsDebugSection(Sec);
482     };
483   }
484 
485   if (Config.StripNonAlloc)
486     RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
487       if (RemovePred(Sec))
488         return true;
489       if (&Sec == Obj.SectionNames)
490         return false;
491       return (Sec.Flags & SHF_ALLOC) == 0;
492     };
493 
494   if (Config.StripAll)
495     RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
496       if (RemovePred(Sec))
497         return true;
498       if (&Sec == Obj.SectionNames)
499         return false;
500       if (Sec.Name.startswith(".gnu.warning"))
501         return false;
502       return (Sec.Flags & SHF_ALLOC) == 0;
503     };
504 
505   // Explicit copies:
506   if (!Config.OnlyKeep.empty()) {
507     RemovePred = [&Config, RemovePred, &Obj](const SectionBase &Sec) {
508       // Explicitly keep these sections regardless of previous removes.
509       if (find(Config.OnlyKeep, Sec.Name) != Config.OnlyKeep.end())
510         return false;
511 
512       // Allow all implicit removes.
513       if (RemovePred(Sec))
514         return true;
515 
516       // Keep special sections.
517       if (Obj.SectionNames == &Sec)
518         return false;
519       if (Obj.SymbolTable == &Sec ||
520           (Obj.SymbolTable && Obj.SymbolTable->getStrTab() == &Sec))
521         return false;
522 
523       // Remove everything else.
524       return true;
525     };
526   }
527 
528   if (!Config.Keep.empty()) {
529     RemovePred = [Config, RemovePred](const SectionBase &Sec) {
530       // Explicitly keep these sections regardless of previous removes.
531       if (find(Config.Keep, Sec.Name) != Config.Keep.end())
532         return false;
533       // Otherwise defer to RemovePred.
534       return RemovePred(Sec);
535     };
536   }
537 
538   // This has to be the last predicate assignment.
539   // If the option --keep-symbol has been specified
540   // and at least one of those symbols is present
541   // (equivalently, the updated symbol table is not empty)
542   // the symbol table and the string table should not be removed.
543   if ((!Config.SymbolsToKeep.empty() || Config.KeepFileSymbols) &&
544       Obj.SymbolTable && !Obj.SymbolTable->empty()) {
545     RemovePred = [&Obj, RemovePred](const SectionBase &Sec) {
546       if (&Sec == Obj.SymbolTable || &Sec == Obj.SymbolTable->getStrTab())
547         return false;
548       return RemovePred(Sec);
549     };
550   }
551 
552   Obj.removeSections(RemovePred);
553 
554   if (!Config.SectionsToRename.empty()) {
555     for (auto &Sec : Obj.sections()) {
556       const auto Iter = Config.SectionsToRename.find(Sec.Name);
557       if (Iter != Config.SectionsToRename.end()) {
558         const SectionRename &SR = Iter->second;
559         Sec.Name = SR.NewName;
560         if (SR.NewFlags.hasValue()) {
561           // Preserve some flags which should not be dropped when setting flags.
562           // Also, preserve anything OS/processor dependant.
563           const uint64_t PreserveMask = ELF::SHF_COMPRESSED | ELF::SHF_EXCLUDE |
564                                         ELF::SHF_GROUP | ELF::SHF_LINK_ORDER |
565                                         ELF::SHF_MASKOS | ELF::SHF_MASKPROC |
566                                         ELF::SHF_TLS | ELF::SHF_INFO_LINK;
567           Sec.Flags = (Sec.Flags & PreserveMask) |
568                       (SR.NewFlags.getValue() & ~PreserveMask);
569         }
570       }
571     }
572   }
573 
574   if (!Config.AddSection.empty()) {
575     for (const auto &Flag : Config.AddSection) {
576       auto SecPair = Flag.split("=");
577       auto SecName = SecPair.first;
578       auto File = SecPair.second;
579       auto BufOrErr = MemoryBuffer::getFile(File);
580       if (!BufOrErr)
581         reportError(File, BufOrErr.getError());
582       auto Buf = std::move(*BufOrErr);
583       auto BufPtr = reinterpret_cast<const uint8_t *>(Buf->getBufferStart());
584       auto BufSize = Buf->getBufferSize();
585       Obj.addSection<OwnedDataSection>(SecName,
586                                        ArrayRef<uint8_t>(BufPtr, BufSize));
587     }
588   }
589 
590   if (!Config.DumpSection.empty()) {
591     for (const auto &Flag : Config.DumpSection) {
592       std::pair<StringRef, StringRef> SecPair = Flag.split("=");
593       StringRef SecName = SecPair.first;
594       StringRef File = SecPair.second;
595       if (Error E = dumpSectionToFile(SecName, File, Obj))
596         reportError(Config.InputFilename, std::move(E));
597     }
598   }
599 
600   if (!Config.AddGnuDebugLink.empty())
601     Obj.addSection<GnuDebugLinkSection>(Config.AddGnuDebugLink);
602 }
603 
604 static void ExecuteElfObjcopyOnBinary(const CopyConfig &Config, Binary &Binary,
605                                       Buffer &Out) {
606   ELFReader Reader(&Binary);
607   std::unique_ptr<Object> Obj = Reader.create();
608 
609   HandleArgs(Config, *Obj, Reader, Reader.getElfType());
610 
611   std::unique_ptr<Writer> Writer =
612       CreateWriter(Config, *Obj, Out, Reader.getElfType());
613   Writer->finalize();
614   Writer->write();
615 }
616 
617 // For regular archives this function simply calls llvm::writeArchive,
618 // For thin archives it writes the archive file itself as well as its members.
619 static Error deepWriteArchive(StringRef ArcName,
620                               ArrayRef<NewArchiveMember> NewMembers,
621                               bool WriteSymtab, object::Archive::Kind Kind,
622                               bool Deterministic, bool Thin) {
623   Error E =
624       writeArchive(ArcName, NewMembers, WriteSymtab, Kind, Deterministic, Thin);
625   if (!Thin || E)
626     return E;
627   for (const NewArchiveMember &Member : NewMembers) {
628     // Internally, FileBuffer will use the buffer created by
629     // FileOutputBuffer::create, for regular files (that is the case for
630     // deepWriteArchive) FileOutputBuffer::create will return OnDiskBuffer.
631     // OnDiskBuffer uses a temporary file and then renames it. So in reality
632     // there is no inefficiency / duplicated in-memory buffers in this case. For
633     // now in-memory buffers can not be completely avoided since
634     // NewArchiveMember still requires them even though writeArchive does not
635     // write them on disk.
636     FileBuffer FB(Member.MemberName);
637     FB.allocate(Member.Buf->getBufferSize());
638     std::copy(Member.Buf->getBufferStart(), Member.Buf->getBufferEnd(),
639               FB.getBufferStart());
640     if (auto E = FB.commit())
641       return E;
642   }
643   return Error::success();
644 }
645 
646 static void ExecuteElfObjcopyOnArchive(const CopyConfig &Config,
647                                        const Archive &Ar) {
648   std::vector<NewArchiveMember> NewArchiveMembers;
649   Error Err = Error::success();
650   for (const Archive::Child &Child : Ar.children(Err)) {
651     Expected<std::unique_ptr<Binary>> ChildOrErr = Child.getAsBinary();
652     if (!ChildOrErr)
653       reportError(Ar.getFileName(), ChildOrErr.takeError());
654     Expected<StringRef> ChildNameOrErr = Child.getName();
655     if (!ChildNameOrErr)
656       reportError(Ar.getFileName(), ChildNameOrErr.takeError());
657 
658     MemBuffer MB(ChildNameOrErr.get());
659     ExecuteElfObjcopyOnBinary(Config, **ChildOrErr, MB);
660 
661     Expected<NewArchiveMember> Member =
662         NewArchiveMember::getOldMember(Child, true);
663     if (!Member)
664       reportError(Ar.getFileName(), Member.takeError());
665     Member->Buf = MB.releaseMemoryBuffer();
666     Member->MemberName = Member->Buf->getBufferIdentifier();
667     NewArchiveMembers.push_back(std::move(*Member));
668   }
669 
670   if (Err)
671     reportError(Config.InputFilename, std::move(Err));
672   if (Error E =
673           deepWriteArchive(Config.OutputFilename, NewArchiveMembers,
674                            Ar.hasSymbolTable(), Ar.kind(), true, Ar.isThin()))
675     reportError(Config.OutputFilename, std::move(E));
676 }
677 
678 static void ExecuteElfObjcopy(const CopyConfig &Config) {
679   Expected<OwningBinary<llvm::object::Binary>> BinaryOrErr =
680       createBinary(Config.InputFilename);
681   if (!BinaryOrErr)
682     reportError(Config.InputFilename, BinaryOrErr.takeError());
683 
684   if (Archive *Ar = dyn_cast<Archive>(BinaryOrErr.get().getBinary()))
685     return ExecuteElfObjcopyOnArchive(Config, *Ar);
686 
687   FileBuffer FB(Config.OutputFilename);
688   ExecuteElfObjcopyOnBinary(Config, *BinaryOrErr.get().getBinary(), FB);
689 }
690 
691 // ParseObjcopyOptions returns the config and sets the input arguments. If a
692 // help flag is set then ParseObjcopyOptions will print the help messege and
693 // exit.
694 static CopyConfig ParseObjcopyOptions(ArrayRef<const char *> ArgsArr) {
695   ObjcopyOptTable T;
696   unsigned MissingArgumentIndex, MissingArgumentCount;
697   llvm::opt::InputArgList InputArgs =
698       T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);
699 
700   if (InputArgs.size() == 0) {
701     T.PrintHelp(errs(), "llvm-objcopy <input> [ <output> ]", "objcopy tool");
702     exit(1);
703   }
704 
705   if (InputArgs.hasArg(OBJCOPY_help)) {
706     T.PrintHelp(outs(), "llvm-objcopy <input> [ <output> ]", "objcopy tool");
707     exit(0);
708   }
709 
710   SmallVector<const char *, 2> Positional;
711 
712   for (auto Arg : InputArgs.filtered(OBJCOPY_UNKNOWN))
713     error("unknown argument '" + Arg->getAsString(InputArgs) + "'");
714 
715   for (auto Arg : InputArgs.filtered(OBJCOPY_INPUT))
716     Positional.push_back(Arg->getValue());
717 
718   if (Positional.empty())
719     error("No input file specified");
720 
721   if (Positional.size() > 2)
722     error("Too many positional arguments");
723 
724   CopyConfig Config;
725   Config.InputFilename = Positional[0];
726   Config.OutputFilename = Positional[Positional.size() == 1 ? 0 : 1];
727   Config.InputFormat = InputArgs.getLastArgValue(OBJCOPY_input_target);
728   Config.OutputFormat = InputArgs.getLastArgValue(OBJCOPY_output_target);
729   Config.BinaryArch = InputArgs.getLastArgValue(OBJCOPY_binary_architecture);
730 
731   Config.SplitDWO = InputArgs.getLastArgValue(OBJCOPY_split_dwo);
732   Config.AddGnuDebugLink = InputArgs.getLastArgValue(OBJCOPY_add_gnu_debuglink);
733   Config.SymbolsPrefix = InputArgs.getLastArgValue(OBJCOPY_prefix_symbols);
734 
735   for (auto Arg : InputArgs.filtered(OBJCOPY_redefine_symbol)) {
736     if (!StringRef(Arg->getValue()).contains('='))
737       error("Bad format for --redefine-sym");
738     auto Old2New = StringRef(Arg->getValue()).split('=');
739     if (!Config.SymbolsToRename.insert(Old2New).second)
740       error("Multiple redefinition of symbol " + Old2New.first);
741   }
742 
743   for (auto Arg : InputArgs.filtered(OBJCOPY_rename_section)) {
744     SectionRename SR = ParseRenameSectionValue(StringRef(Arg->getValue()));
745     if (!Config.SectionsToRename.try_emplace(SR.OriginalName, SR).second)
746       error("Multiple renames of section " + SR.OriginalName);
747   }
748 
749   for (auto Arg : InputArgs.filtered(OBJCOPY_remove_section))
750     Config.ToRemove.push_back(Arg->getValue());
751   for (auto Arg : InputArgs.filtered(OBJCOPY_keep))
752     Config.Keep.push_back(Arg->getValue());
753   for (auto Arg : InputArgs.filtered(OBJCOPY_only_keep))
754     Config.OnlyKeep.push_back(Arg->getValue());
755   for (auto Arg : InputArgs.filtered(OBJCOPY_add_section))
756     Config.AddSection.push_back(Arg->getValue());
757   for (auto Arg : InputArgs.filtered(OBJCOPY_dump_section))
758     Config.DumpSection.push_back(Arg->getValue());
759   Config.StripAll = InputArgs.hasArg(OBJCOPY_strip_all);
760   Config.StripAllGNU = InputArgs.hasArg(OBJCOPY_strip_all_gnu);
761   Config.StripDebug = InputArgs.hasArg(OBJCOPY_strip_debug);
762   Config.StripDWO = InputArgs.hasArg(OBJCOPY_strip_dwo);
763   Config.StripSections = InputArgs.hasArg(OBJCOPY_strip_sections);
764   Config.StripNonAlloc = InputArgs.hasArg(OBJCOPY_strip_non_alloc);
765   Config.StripUnneeded = InputArgs.hasArg(OBJCOPY_strip_unneeded);
766   Config.ExtractDWO = InputArgs.hasArg(OBJCOPY_extract_dwo);
767   Config.LocalizeHidden = InputArgs.hasArg(OBJCOPY_localize_hidden);
768   Config.Weaken = InputArgs.hasArg(OBJCOPY_weaken);
769   Config.DiscardAll = InputArgs.hasArg(OBJCOPY_discard_all);
770   Config.OnlyKeepDebug = InputArgs.hasArg(OBJCOPY_only_keep_debug);
771   Config.KeepFileSymbols = InputArgs.hasArg(OBJCOPY_keep_file_symbols);
772   for (auto Arg : InputArgs.filtered(OBJCOPY_localize_symbol))
773     Config.SymbolsToLocalize.push_back(Arg->getValue());
774   for (auto Arg : InputArgs.filtered(OBJCOPY_globalize_symbol))
775     Config.SymbolsToGlobalize.push_back(Arg->getValue());
776   for (auto Arg : InputArgs.filtered(OBJCOPY_weaken_symbol))
777     Config.SymbolsToWeaken.push_back(Arg->getValue());
778   for (auto Arg : InputArgs.filtered(OBJCOPY_strip_symbol))
779     Config.SymbolsToRemove.push_back(Arg->getValue());
780   for (auto Arg : InputArgs.filtered(OBJCOPY_keep_symbol))
781     Config.SymbolsToKeep.push_back(Arg->getValue());
782 
783   return Config;
784 }
785 
786 // ParseStripOptions returns the config and sets the input arguments. If a
787 // help flag is set then ParseStripOptions will print the help messege and
788 // exit.
789 static CopyConfig ParseStripOptions(ArrayRef<const char *> ArgsArr) {
790   StripOptTable T;
791   unsigned MissingArgumentIndex, MissingArgumentCount;
792   llvm::opt::InputArgList InputArgs =
793       T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);
794 
795   if (InputArgs.size() == 0) {
796     T.PrintHelp(errs(), "llvm-strip <input> [ <output> ]", "strip tool");
797     exit(1);
798   }
799 
800   if (InputArgs.hasArg(STRIP_help)) {
801     T.PrintHelp(outs(), "llvm-strip <input> [ <output> ]", "strip tool");
802     exit(0);
803   }
804 
805   SmallVector<const char *, 2> Positional;
806   for (auto Arg : InputArgs.filtered(STRIP_UNKNOWN))
807     error("unknown argument '" + Arg->getAsString(InputArgs) + "'");
808   for (auto Arg : InputArgs.filtered(STRIP_INPUT))
809     Positional.push_back(Arg->getValue());
810 
811   if (Positional.empty())
812     error("No input file specified");
813 
814   if (Positional.size() > 2)
815     error("Support for multiple input files is not implemented yet");
816 
817   CopyConfig Config;
818   Config.InputFilename = Positional[0];
819   Config.OutputFilename =
820       InputArgs.getLastArgValue(STRIP_output, Positional[0]);
821 
822   Config.StripDebug = InputArgs.hasArg(STRIP_strip_debug);
823 
824   Config.DiscardAll = InputArgs.hasArg(STRIP_discard_all);
825   Config.StripUnneeded = InputArgs.hasArg(STRIP_strip_unneeded);
826   Config.StripAll = InputArgs.hasArg(STRIP_strip_all);
827 
828   if (!Config.StripDebug && !Config.StripUnneeded && !Config.DiscardAll)
829     Config.StripAll = true;
830 
831   for (auto Arg : InputArgs.filtered(STRIP_remove_section))
832     Config.ToRemove.push_back(Arg->getValue());
833 
834   for (auto Arg : InputArgs.filtered(STRIP_keep_symbol))
835     Config.SymbolsToKeep.push_back(Arg->getValue());
836 
837   return Config;
838 }
839 
840 int main(int argc, char **argv) {
841   InitLLVM X(argc, argv);
842   ToolName = argv[0];
843   CopyConfig Config;
844   if (sys::path::stem(ToolName).endswith_lower("strip"))
845     Config = ParseStripOptions(makeArrayRef(argv + 1, argc));
846   else
847     Config = ParseObjcopyOptions(makeArrayRef(argv + 1, argc));
848   ExecuteElfObjcopy(Config);
849 }
850