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