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