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