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