xref: /llvm-project/llvm/tools/llvm-objcopy/llvm-objcopy.cpp (revision 99124cc082d8b5d5a07bb80a4a37a0a88d6fade4)
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   const char *Magic = "ZLIB";
421   return StringRef(Section.Name).startswith(".zdebug") ||
422          (Section.OriginalData.size() > strlen(Magic) &&
423           !strncmp(reinterpret_cast<const char *>(Section.OriginalData.data()),
424                    Magic, strlen(Magic))) ||
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 
463 // This function handles the high level operations of GNU objcopy including
464 // handling command line options. It's important to outline certain properties
465 // we expect to hold of the command line operations. Any operation that "keeps"
466 // should keep regardless of a remove. Additionally any removal should respect
467 // any previous removals. Lastly whether or not something is removed shouldn't
468 // depend a) on the order the options occur in or b) on some opaque priority
469 // system. The only priority is that keeps/copies overrule removes.
470 static void handleArgs(const CopyConfig &Config, Object &Obj,
471                        const Reader &Reader, ElfType OutputElfType) {
472 
473   if (!Config.SplitDWO.empty()) {
474     splitDWOToFile(Config, Reader, Config.SplitDWO, OutputElfType);
475   }
476 
477   // TODO: update or remove symbols only if there is an option that affects
478   // them.
479   if (Obj.SymbolTable) {
480     Obj.SymbolTable->updateSymbols([&](Symbol &Sym) {
481       if ((Config.LocalizeHidden &&
482            (Sym.Visibility == STV_HIDDEN || Sym.Visibility == STV_INTERNAL)) ||
483           (!Config.SymbolsToLocalize.empty() &&
484            is_contained(Config.SymbolsToLocalize, Sym.Name)))
485         Sym.Binding = STB_LOCAL;
486 
487       // Note: these two globalize flags have very similar names but different
488       // meanings:
489       //
490       // --globalize-symbol: promote a symbol to global
491       // --keep-global-symbol: all symbols except for these should be made local
492       //
493       // If --globalize-symbol is specified for a given symbol, it will be
494       // global in the output file even if it is not included via
495       // --keep-global-symbol. Because of that, make sure to check
496       // --globalize-symbol second.
497       if (!Config.SymbolsToKeepGlobal.empty() &&
498           !is_contained(Config.SymbolsToKeepGlobal, Sym.Name))
499         Sym.Binding = STB_LOCAL;
500 
501       if (!Config.SymbolsToGlobalize.empty() &&
502           is_contained(Config.SymbolsToGlobalize, Sym.Name))
503         Sym.Binding = STB_GLOBAL;
504 
505       if (!Config.SymbolsToWeaken.empty() &&
506           is_contained(Config.SymbolsToWeaken, Sym.Name) &&
507           Sym.Binding == STB_GLOBAL)
508         Sym.Binding = STB_WEAK;
509 
510       if (Config.Weaken && Sym.Binding == STB_GLOBAL &&
511           Sym.getShndx() != SHN_UNDEF)
512         Sym.Binding = STB_WEAK;
513 
514       const auto I = Config.SymbolsToRename.find(Sym.Name);
515       if (I != Config.SymbolsToRename.end())
516         Sym.Name = I->getValue();
517 
518       if (!Config.SymbolsPrefix.empty() && Sym.Type != STT_SECTION)
519         Sym.Name = (Config.SymbolsPrefix + Sym.Name).str();
520     });
521 
522     // The purpose of this loop is to mark symbols referenced by sections
523     // (like GroupSection or RelocationSection). This way, we know which
524     // symbols are still 'needed' and wich are not.
525     if (Config.StripUnneeded) {
526       for (auto &Section : Obj.sections())
527         Section.markSymbols();
528     }
529 
530     Obj.removeSymbols([&](const Symbol &Sym) {
531       if ((!Config.SymbolsToKeep.empty() &&
532            is_contained(Config.SymbolsToKeep, Sym.Name)) ||
533           (Config.KeepFileSymbols && Sym.Type == STT_FILE))
534         return false;
535 
536       if (Config.DiscardAll && Sym.Binding == STB_LOCAL &&
537           Sym.getShndx() != SHN_UNDEF && Sym.Type != STT_FILE &&
538           Sym.Type != STT_SECTION)
539         return true;
540 
541       if (Config.StripAll || Config.StripAllGNU)
542         return true;
543 
544       if (!Config.SymbolsToRemove.empty() &&
545           is_contained(Config.SymbolsToRemove, Sym.Name)) {
546         return true;
547       }
548 
549       if (Config.StripUnneeded && !Sym.Referenced &&
550           (Sym.Binding == STB_LOCAL || Sym.getShndx() == SHN_UNDEF) &&
551           Sym.Type != STT_FILE && Sym.Type != STT_SECTION)
552         return true;
553 
554       return false;
555     });
556   }
557 
558   SectionPred RemovePred = [](const SectionBase &) { return false; };
559 
560   // Removes:
561   if (!Config.ToRemove.empty()) {
562     RemovePred = [&Config](const SectionBase &Sec) {
563       return is_contained(Config.ToRemove, Sec.Name);
564     };
565   }
566 
567   if (Config.StripDWO || !Config.SplitDWO.empty())
568     RemovePred = [RemovePred](const SectionBase &Sec) {
569       return isDWOSection(Sec) || RemovePred(Sec);
570     };
571 
572   if (Config.ExtractDWO)
573     RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
574       return onlyKeepDWOPred(Obj, Sec) || RemovePred(Sec);
575     };
576 
577   if (Config.StripAllGNU)
578     RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
579       if (RemovePred(Sec))
580         return true;
581       if ((Sec.Flags & SHF_ALLOC) != 0)
582         return false;
583       if (&Sec == Obj.SectionNames)
584         return false;
585       switch (Sec.Type) {
586       case SHT_SYMTAB:
587       case SHT_REL:
588       case SHT_RELA:
589       case SHT_STRTAB:
590         return true;
591       }
592       return isDebugSection(Sec);
593     };
594 
595   if (Config.StripSections) {
596     RemovePred = [RemovePred](const SectionBase &Sec) {
597       return RemovePred(Sec) || (Sec.Flags & SHF_ALLOC) == 0;
598     };
599   }
600 
601   if (Config.StripDebug) {
602     RemovePred = [RemovePred](const SectionBase &Sec) {
603       return RemovePred(Sec) || isDebugSection(Sec);
604     };
605   }
606 
607   if (Config.StripNonAlloc)
608     RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
609       if (RemovePred(Sec))
610         return true;
611       if (&Sec == Obj.SectionNames)
612         return false;
613       return (Sec.Flags & SHF_ALLOC) == 0;
614     };
615 
616   if (Config.StripAll)
617     RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
618       if (RemovePred(Sec))
619         return true;
620       if (&Sec == Obj.SectionNames)
621         return false;
622       if (StringRef(Sec.Name).startswith(".gnu.warning"))
623         return false;
624       return (Sec.Flags & SHF_ALLOC) == 0;
625     };
626 
627   // Explicit copies:
628   if (!Config.OnlyKeep.empty()) {
629     RemovePred = [&Config, RemovePred, &Obj](const SectionBase &Sec) {
630       // Explicitly keep these sections regardless of previous removes.
631       if (is_contained(Config.OnlyKeep, Sec.Name))
632         return false;
633 
634       // Allow all implicit removes.
635       if (RemovePred(Sec))
636         return true;
637 
638       // Keep special sections.
639       if (Obj.SectionNames == &Sec)
640         return false;
641       if (Obj.SymbolTable == &Sec ||
642           (Obj.SymbolTable && Obj.SymbolTable->getStrTab() == &Sec))
643         return false;
644 
645       // Remove everything else.
646       return true;
647     };
648   }
649 
650   if (!Config.Keep.empty()) {
651     RemovePred = [Config, RemovePred](const SectionBase &Sec) {
652       // Explicitly keep these sections regardless of previous removes.
653       if (is_contained(Config.Keep, Sec.Name))
654         return false;
655       // Otherwise defer to RemovePred.
656       return RemovePred(Sec);
657     };
658   }
659 
660   // This has to be the last predicate assignment.
661   // If the option --keep-symbol has been specified
662   // and at least one of those symbols is present
663   // (equivalently, the updated symbol table is not empty)
664   // the symbol table and the string table should not be removed.
665   if ((!Config.SymbolsToKeep.empty() || Config.KeepFileSymbols) &&
666       Obj.SymbolTable && !Obj.SymbolTable->empty()) {
667     RemovePred = [&Obj, RemovePred](const SectionBase &Sec) {
668       if (&Sec == Obj.SymbolTable || &Sec == Obj.SymbolTable->getStrTab())
669         return false;
670       return RemovePred(Sec);
671     };
672   }
673 
674   if (Config.CompressionType != DebugCompressionType::None)
675     compressSections(Config, Obj, RemovePred);
676 
677   Obj.removeSections(RemovePred);
678 
679   if (!Config.SectionsToRename.empty()) {
680     for (auto &Sec : Obj.sections()) {
681       const auto Iter = Config.SectionsToRename.find(Sec.Name);
682       if (Iter != Config.SectionsToRename.end()) {
683         const SectionRename &SR = Iter->second;
684         Sec.Name = SR.NewName;
685         if (SR.NewFlags.hasValue()) {
686           // Preserve some flags which should not be dropped when setting flags.
687           // Also, preserve anything OS/processor dependant.
688           const uint64_t PreserveMask = ELF::SHF_COMPRESSED | ELF::SHF_EXCLUDE |
689                                         ELF::SHF_GROUP | ELF::SHF_LINK_ORDER |
690                                         ELF::SHF_MASKOS | ELF::SHF_MASKPROC |
691                                         ELF::SHF_TLS | ELF::SHF_INFO_LINK;
692           Sec.Flags = (Sec.Flags & PreserveMask) |
693                       (SR.NewFlags.getValue() & ~PreserveMask);
694         }
695       }
696     }
697   }
698 
699   if (!Config.AddSection.empty()) {
700     for (const auto &Flag : Config.AddSection) {
701       auto SecPair = Flag.split("=");
702       auto SecName = SecPair.first;
703       auto File = SecPair.second;
704       auto BufOrErr = MemoryBuffer::getFile(File);
705       if (!BufOrErr)
706         reportError(File, BufOrErr.getError());
707       auto Buf = std::move(*BufOrErr);
708       auto BufPtr = reinterpret_cast<const uint8_t *>(Buf->getBufferStart());
709       auto BufSize = Buf->getBufferSize();
710       Obj.addSection<OwnedDataSection>(SecName,
711                                        ArrayRef<uint8_t>(BufPtr, BufSize));
712     }
713   }
714 
715   if (!Config.DumpSection.empty()) {
716     for (const auto &Flag : Config.DumpSection) {
717       std::pair<StringRef, StringRef> SecPair = Flag.split("=");
718       StringRef SecName = SecPair.first;
719       StringRef File = SecPair.second;
720       if (Error E = dumpSectionToFile(SecName, File, Obj))
721         reportError(Config.InputFilename, std::move(E));
722     }
723   }
724 
725   if (!Config.AddGnuDebugLink.empty())
726     Obj.addSection<GnuDebugLinkSection>(Config.AddGnuDebugLink);
727 }
728 
729 static void executeElfObjcopyOnBinary(const CopyConfig &Config, Reader &Reader,
730                                       Buffer &Out, ElfType OutputElfType) {
731   std::unique_ptr<Object> Obj = Reader.create();
732 
733   handleArgs(Config, *Obj, Reader, OutputElfType);
734 
735   std::unique_ptr<Writer> Writer =
736       createWriter(Config, *Obj, Out, OutputElfType);
737   Writer->finalize();
738   Writer->write();
739 }
740 
741 // For regular archives this function simply calls llvm::writeArchive,
742 // For thin archives it writes the archive file itself as well as its members.
743 static Error deepWriteArchive(StringRef ArcName,
744                               ArrayRef<NewArchiveMember> NewMembers,
745                               bool WriteSymtab, object::Archive::Kind Kind,
746                               bool Deterministic, bool Thin) {
747   Error E =
748       writeArchive(ArcName, NewMembers, WriteSymtab, Kind, Deterministic, Thin);
749   if (!Thin || E)
750     return E;
751   for (const NewArchiveMember &Member : NewMembers) {
752     // Internally, FileBuffer will use the buffer created by
753     // FileOutputBuffer::create, for regular files (that is the case for
754     // deepWriteArchive) FileOutputBuffer::create will return OnDiskBuffer.
755     // OnDiskBuffer uses a temporary file and then renames it. So in reality
756     // there is no inefficiency / duplicated in-memory buffers in this case. For
757     // now in-memory buffers can not be completely avoided since
758     // NewArchiveMember still requires them even though writeArchive does not
759     // write them on disk.
760     FileBuffer FB(Member.MemberName);
761     FB.allocate(Member.Buf->getBufferSize());
762     std::copy(Member.Buf->getBufferStart(), Member.Buf->getBufferEnd(),
763               FB.getBufferStart());
764     if (auto E = FB.commit())
765       return E;
766   }
767   return Error::success();
768 }
769 
770 static void executeElfObjcopyOnArchive(const CopyConfig &Config,
771                                        const Archive &Ar) {
772   std::vector<NewArchiveMember> NewArchiveMembers;
773   Error Err = Error::success();
774   for (const Archive::Child &Child : Ar.children(Err)) {
775     Expected<std::unique_ptr<Binary>> ChildOrErr = Child.getAsBinary();
776     if (!ChildOrErr)
777       reportError(Ar.getFileName(), ChildOrErr.takeError());
778     Binary *Bin = ChildOrErr->get();
779 
780     Expected<StringRef> ChildNameOrErr = Child.getName();
781     if (!ChildNameOrErr)
782       reportError(Ar.getFileName(), ChildNameOrErr.takeError());
783 
784     MemBuffer MB(ChildNameOrErr.get());
785     ELFReader Reader(Bin);
786     executeElfObjcopyOnBinary(Config, Reader, MB, getOutputElfType(*Bin));
787 
788     Expected<NewArchiveMember> Member =
789         NewArchiveMember::getOldMember(Child, true);
790     if (!Member)
791       reportError(Ar.getFileName(), Member.takeError());
792     Member->Buf = MB.releaseMemoryBuffer();
793     Member->MemberName = Member->Buf->getBufferIdentifier();
794     NewArchiveMembers.push_back(std::move(*Member));
795   }
796 
797   if (Err)
798     reportError(Config.InputFilename, std::move(Err));
799   if (Error E =
800           deepWriteArchive(Config.OutputFilename, NewArchiveMembers,
801                            Ar.hasSymbolTable(), Ar.kind(), true, Ar.isThin()))
802     reportError(Config.OutputFilename, std::move(E));
803 }
804 
805 static void restoreDateOnFile(StringRef Filename,
806                               const sys::fs::file_status &Stat) {
807   int FD;
808 
809   if (auto EC =
810           sys::fs::openFileForWrite(Filename, FD, sys::fs::CD_OpenExisting))
811     reportError(Filename, EC);
812 
813   if (auto EC = sys::fs::setLastAccessAndModificationTime(
814           FD, Stat.getLastAccessedTime(), Stat.getLastModificationTime()))
815     reportError(Filename, EC);
816 
817   if (auto EC = sys::Process::SafelyCloseFileDescriptor(FD))
818     reportError(Filename, EC);
819 }
820 
821 static void executeElfObjcopy(const CopyConfig &Config) {
822   sys::fs::file_status Stat;
823   if (Config.PreserveDates)
824     if (auto EC = sys::fs::status(Config.InputFilename, Stat))
825       reportError(Config.InputFilename, EC);
826 
827   if (Config.InputFormat == "binary") {
828     auto BufOrErr = MemoryBuffer::getFile(Config.InputFilename);
829     if (!BufOrErr)
830       reportError(Config.InputFilename, BufOrErr.getError());
831 
832     FileBuffer FB(Config.OutputFilename);
833     BinaryReader Reader(Config.BinaryArch, BufOrErr->get());
834     executeElfObjcopyOnBinary(Config, Reader, FB,
835                               getOutputElfType(Config.BinaryArch));
836   } else {
837     Expected<OwningBinary<llvm::object::Binary>> BinaryOrErr =
838         createBinary(Config.InputFilename);
839     if (!BinaryOrErr)
840       reportError(Config.InputFilename, BinaryOrErr.takeError());
841 
842     if (Archive *Ar = dyn_cast<Archive>(BinaryOrErr.get().getBinary())) {
843       executeElfObjcopyOnArchive(Config, *Ar);
844     } else {
845       FileBuffer FB(Config.OutputFilename);
846       Binary *Bin = BinaryOrErr.get().getBinary();
847       ELFReader Reader(Bin);
848       executeElfObjcopyOnBinary(Config, Reader, FB, getOutputElfType(*Bin));
849     }
850   }
851 
852   if (Config.PreserveDates) {
853     restoreDateOnFile(Config.OutputFilename, Stat);
854     if (!Config.SplitDWO.empty())
855       restoreDateOnFile(Config.SplitDWO, Stat);
856   }
857 }
858 
859 static void addGlobalSymbolsFromFile(std::vector<std::string> &Symbols,
860                                      StringRef Filename) {
861   SmallVector<StringRef, 16> Lines;
862   auto BufOrErr = MemoryBuffer::getFile(Filename);
863   if (!BufOrErr)
864     reportError(Filename, BufOrErr.getError());
865 
866   BufOrErr.get()->getBuffer().split(Lines, '\n');
867   for (StringRef Line : Lines) {
868     // Ignore everything after '#', trim whitespace, and only add the symbol if
869     // it's not empty.
870     auto TrimmedLine = Line.split('#').first.trim();
871     if (!TrimmedLine.empty())
872       Symbols.push_back(TrimmedLine.str());
873   }
874 }
875 
876 // ParseObjcopyOptions returns the config and sets the input arguments. If a
877 // help flag is set then ParseObjcopyOptions will print the help messege and
878 // exit.
879 static DriverConfig parseObjcopyOptions(ArrayRef<const char *> ArgsArr) {
880   ObjcopyOptTable T;
881   unsigned MissingArgumentIndex, MissingArgumentCount;
882   llvm::opt::InputArgList InputArgs =
883       T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);
884 
885   if (InputArgs.size() == 0) {
886     T.PrintHelp(errs(), "llvm-objcopy <input> [ <output> ]", "objcopy tool");
887     exit(1);
888   }
889 
890   if (InputArgs.hasArg(OBJCOPY_help)) {
891     T.PrintHelp(outs(), "llvm-objcopy <input> [ <output> ]", "objcopy tool");
892     exit(0);
893   }
894 
895   SmallVector<const char *, 2> Positional;
896 
897   for (auto Arg : InputArgs.filtered(OBJCOPY_UNKNOWN))
898     error("unknown argument '" + Arg->getAsString(InputArgs) + "'");
899 
900   for (auto Arg : InputArgs.filtered(OBJCOPY_INPUT))
901     Positional.push_back(Arg->getValue());
902 
903   if (Positional.empty())
904     error("No input file specified");
905 
906   if (Positional.size() > 2)
907     error("Too many positional arguments");
908 
909   CopyConfig Config;
910   Config.InputFilename = Positional[0];
911   Config.OutputFilename = Positional[Positional.size() == 1 ? 0 : 1];
912   Config.InputFormat = InputArgs.getLastArgValue(OBJCOPY_input_target);
913   Config.OutputFormat = InputArgs.getLastArgValue(OBJCOPY_output_target);
914   if (Config.InputFormat == "binary") {
915     auto BinaryArch = InputArgs.getLastArgValue(OBJCOPY_binary_architecture);
916     if (BinaryArch.empty())
917       error("Specified binary input without specifiying an architecture");
918     Config.BinaryArch = getMachineInfo(BinaryArch);
919   }
920 
921   if (auto Arg = InputArgs.getLastArg(OBJCOPY_compress_debug_sections,
922                                       OBJCOPY_compress_debug_sections_eq)) {
923     Config.CompressionType = DebugCompressionType::Z;
924 
925     if (Arg->getOption().getID() == OBJCOPY_compress_debug_sections_eq) {
926       Config.CompressionType =
927           StringSwitch<DebugCompressionType>(
928               InputArgs.getLastArgValue(OBJCOPY_compress_debug_sections_eq))
929               .Case("zlib-gnu", DebugCompressionType::GNU)
930               .Case("zlib", DebugCompressionType::Z)
931               .Default(DebugCompressionType::None);
932       if (Config.CompressionType == DebugCompressionType::None)
933         error("Invalid or unsupported --compress-debug-sections format: " +
934               InputArgs.getLastArgValue(OBJCOPY_compress_debug_sections_eq));
935       if (!zlib::isAvailable())
936         error("LLVM was not compiled with LLVM_ENABLE_ZLIB: can not compress.");
937     }
938   }
939 
940   Config.SplitDWO = InputArgs.getLastArgValue(OBJCOPY_split_dwo);
941   Config.AddGnuDebugLink = InputArgs.getLastArgValue(OBJCOPY_add_gnu_debuglink);
942   Config.SymbolsPrefix = InputArgs.getLastArgValue(OBJCOPY_prefix_symbols);
943 
944   for (auto Arg : InputArgs.filtered(OBJCOPY_redefine_symbol)) {
945     if (!StringRef(Arg->getValue()).contains('='))
946       error("Bad format for --redefine-sym");
947     auto Old2New = StringRef(Arg->getValue()).split('=');
948     if (!Config.SymbolsToRename.insert(Old2New).second)
949       error("Multiple redefinition of symbol " + Old2New.first);
950   }
951 
952   for (auto Arg : InputArgs.filtered(OBJCOPY_rename_section)) {
953     SectionRename SR = parseRenameSectionValue(StringRef(Arg->getValue()));
954     if (!Config.SectionsToRename.try_emplace(SR.OriginalName, SR).second)
955       error("Multiple renames of section " + SR.OriginalName);
956   }
957 
958   for (auto Arg : InputArgs.filtered(OBJCOPY_remove_section))
959     Config.ToRemove.push_back(Arg->getValue());
960   for (auto Arg : InputArgs.filtered(OBJCOPY_keep))
961     Config.Keep.push_back(Arg->getValue());
962   for (auto Arg : InputArgs.filtered(OBJCOPY_only_keep))
963     Config.OnlyKeep.push_back(Arg->getValue());
964   for (auto Arg : InputArgs.filtered(OBJCOPY_add_section))
965     Config.AddSection.push_back(Arg->getValue());
966   for (auto Arg : InputArgs.filtered(OBJCOPY_dump_section))
967     Config.DumpSection.push_back(Arg->getValue());
968   Config.StripAll = InputArgs.hasArg(OBJCOPY_strip_all);
969   Config.StripAllGNU = InputArgs.hasArg(OBJCOPY_strip_all_gnu);
970   Config.StripDebug = InputArgs.hasArg(OBJCOPY_strip_debug);
971   Config.StripDWO = InputArgs.hasArg(OBJCOPY_strip_dwo);
972   Config.StripSections = InputArgs.hasArg(OBJCOPY_strip_sections);
973   Config.StripNonAlloc = InputArgs.hasArg(OBJCOPY_strip_non_alloc);
974   Config.StripUnneeded = InputArgs.hasArg(OBJCOPY_strip_unneeded);
975   Config.ExtractDWO = InputArgs.hasArg(OBJCOPY_extract_dwo);
976   Config.LocalizeHidden = InputArgs.hasArg(OBJCOPY_localize_hidden);
977   Config.Weaken = InputArgs.hasArg(OBJCOPY_weaken);
978   Config.DiscardAll = InputArgs.hasArg(OBJCOPY_discard_all);
979   Config.OnlyKeepDebug = InputArgs.hasArg(OBJCOPY_only_keep_debug);
980   Config.KeepFileSymbols = InputArgs.hasArg(OBJCOPY_keep_file_symbols);
981   for (auto Arg : InputArgs.filtered(OBJCOPY_localize_symbol))
982     Config.SymbolsToLocalize.push_back(Arg->getValue());
983   for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbol))
984     Config.SymbolsToKeepGlobal.push_back(Arg->getValue());
985   for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbols))
986     addGlobalSymbolsFromFile(Config.SymbolsToKeepGlobal, Arg->getValue());
987   for (auto Arg : InputArgs.filtered(OBJCOPY_globalize_symbol))
988     Config.SymbolsToGlobalize.push_back(Arg->getValue());
989   for (auto Arg : InputArgs.filtered(OBJCOPY_weaken_symbol))
990     Config.SymbolsToWeaken.push_back(Arg->getValue());
991   for (auto Arg : InputArgs.filtered(OBJCOPY_strip_symbol))
992     Config.SymbolsToRemove.push_back(Arg->getValue());
993   for (auto Arg : InputArgs.filtered(OBJCOPY_keep_symbol))
994     Config.SymbolsToKeep.push_back(Arg->getValue());
995 
996   Config.PreserveDates = InputArgs.hasArg(OBJCOPY_preserve_dates);
997 
998   DriverConfig DC;
999   DC.CopyConfigs.push_back(std::move(Config));
1000   return DC;
1001 }
1002 
1003 // ParseStripOptions returns the config and sets the input arguments. If a
1004 // help flag is set then ParseStripOptions will print the help messege and
1005 // exit.
1006 static DriverConfig parseStripOptions(ArrayRef<const char *> ArgsArr) {
1007   StripOptTable T;
1008   unsigned MissingArgumentIndex, MissingArgumentCount;
1009   llvm::opt::InputArgList InputArgs =
1010       T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);
1011 
1012   if (InputArgs.size() == 0) {
1013     T.PrintHelp(errs(), "llvm-strip", "strip tool");
1014     exit(1);
1015   }
1016 
1017   if (InputArgs.hasArg(STRIP_help)) {
1018     T.PrintHelp(outs(), "llvm-strip", "strip tool");
1019     exit(0);
1020   }
1021 
1022   SmallVector<const char *, 2> Positional;
1023   for (auto Arg : InputArgs.filtered(STRIP_UNKNOWN))
1024     error("unknown argument '" + Arg->getAsString(InputArgs) + "'");
1025   for (auto Arg : InputArgs.filtered(STRIP_INPUT))
1026     Positional.push_back(Arg->getValue());
1027 
1028   if (Positional.empty())
1029     error("No input file specified");
1030 
1031   if (Positional.size() > 1 && InputArgs.hasArg(STRIP_output))
1032     error("Multiple input files cannot be used in combination with -o");
1033 
1034   CopyConfig Config;
1035   Config.StripDebug = InputArgs.hasArg(STRIP_strip_debug);
1036 
1037   Config.DiscardAll = InputArgs.hasArg(STRIP_discard_all);
1038   Config.StripUnneeded = InputArgs.hasArg(STRIP_strip_unneeded);
1039   Config.StripAll = InputArgs.hasArg(STRIP_strip_all);
1040 
1041   if (!Config.StripDebug && !Config.StripUnneeded && !Config.DiscardAll)
1042     Config.StripAll = true;
1043 
1044   for (auto Arg : InputArgs.filtered(STRIP_remove_section))
1045     Config.ToRemove.push_back(Arg->getValue());
1046 
1047   for (auto Arg : InputArgs.filtered(STRIP_keep_symbol))
1048     Config.SymbolsToKeep.push_back(Arg->getValue());
1049 
1050   Config.PreserveDates = InputArgs.hasArg(STRIP_preserve_dates);
1051 
1052   DriverConfig DC;
1053   if (Positional.size() == 1) {
1054     Config.InputFilename = Positional[0];
1055     Config.OutputFilename =
1056         InputArgs.getLastArgValue(STRIP_output, Positional[0]);
1057     DC.CopyConfigs.push_back(std::move(Config));
1058   } else {
1059     for (const char *Filename : Positional) {
1060       Config.InputFilename = Filename;
1061       Config.OutputFilename = Filename;
1062       DC.CopyConfigs.push_back(Config);
1063     }
1064   }
1065 
1066   return DC;
1067 }
1068 
1069 int main(int argc, char **argv) {
1070   InitLLVM X(argc, argv);
1071   ToolName = argv[0];
1072   DriverConfig DriverConfig;
1073   if (sys::path::stem(ToolName).endswith_lower("strip"))
1074     DriverConfig = parseStripOptions(makeArrayRef(argv + 1, argc));
1075   else
1076     DriverConfig = parseObjcopyOptions(makeArrayRef(argv + 1, argc));
1077   for (const CopyConfig &CopyConfig : DriverConfig.CopyConfigs)
1078     executeElfObjcopy(CopyConfig);
1079 }
1080