1 //===- ConfigManager.cpp --------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "ConfigManager.h"
10 #include "llvm/ADT/Optional.h"
11 #include "llvm/ADT/SmallVector.h"
12 #include "llvm/ADT/StringRef.h"
13 #include "llvm/ADT/StringSet.h"
14 #include "llvm/Option/Arg.h"
15 #include "llvm/Option/ArgList.h"
16 #include "llvm/Support/CRC.h"
17 #include "llvm/Support/CommandLine.h"
18 #include "llvm/Support/Compression.h"
19 #include "llvm/Support/Errc.h"
20 #include "llvm/Support/Error.h"
21 #include "llvm/Support/MemoryBuffer.h"
22 #include "llvm/Support/StringSaver.h"
23 #include <memory>
24 
25 namespace llvm {
26 namespace objcopy {
27 
28 namespace {
29 enum ObjcopyID {
30   OBJCOPY_INVALID = 0, // This is not an option ID.
31 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
32                HELPTEXT, METAVAR, VALUES)                                      \
33   OBJCOPY_##ID,
34 #include "ObjcopyOpts.inc"
35 #undef OPTION
36 };
37 
38 #define PREFIX(NAME, VALUE) const char *const OBJCOPY_##NAME[] = VALUE;
39 #include "ObjcopyOpts.inc"
40 #undef PREFIX
41 
42 static const opt::OptTable::Info ObjcopyInfoTable[] = {
43 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
44                HELPTEXT, METAVAR, VALUES)                                      \
45   {OBJCOPY_##PREFIX,                                                           \
46    NAME,                                                                       \
47    HELPTEXT,                                                                   \
48    METAVAR,                                                                    \
49    OBJCOPY_##ID,                                                               \
50    opt::Option::KIND##Class,                                                   \
51    PARAM,                                                                      \
52    FLAGS,                                                                      \
53    OBJCOPY_##GROUP,                                                            \
54    OBJCOPY_##ALIAS,                                                            \
55    ALIASARGS,                                                                  \
56    VALUES},
57 #include "ObjcopyOpts.inc"
58 #undef OPTION
59 };
60 
61 class ObjcopyOptTable : public opt::OptTable {
62 public:
ObjcopyOptTable()63   ObjcopyOptTable() : OptTable(ObjcopyInfoTable) {}
64 };
65 
66 enum InstallNameToolID {
67   INSTALL_NAME_TOOL_INVALID = 0, // This is not an option ID.
68 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
69                HELPTEXT, METAVAR, VALUES)                                      \
70   INSTALL_NAME_TOOL_##ID,
71 #include "InstallNameToolOpts.inc"
72 #undef OPTION
73 };
74 
75 #define PREFIX(NAME, VALUE)                                                    \
76   const char *const INSTALL_NAME_TOOL_##NAME[] = VALUE;
77 #include "InstallNameToolOpts.inc"
78 #undef PREFIX
79 
80 static const opt::OptTable::Info InstallNameToolInfoTable[] = {
81 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
82                HELPTEXT, METAVAR, VALUES)                                      \
83   {INSTALL_NAME_TOOL_##PREFIX,                                                 \
84    NAME,                                                                       \
85    HELPTEXT,                                                                   \
86    METAVAR,                                                                    \
87    INSTALL_NAME_TOOL_##ID,                                                     \
88    opt::Option::KIND##Class,                                                   \
89    PARAM,                                                                      \
90    FLAGS,                                                                      \
91    INSTALL_NAME_TOOL_##GROUP,                                                  \
92    INSTALL_NAME_TOOL_##ALIAS,                                                  \
93    ALIASARGS,                                                                  \
94    VALUES},
95 #include "InstallNameToolOpts.inc"
96 #undef OPTION
97 };
98 
99 class InstallNameToolOptTable : public opt::OptTable {
100 public:
InstallNameToolOptTable()101   InstallNameToolOptTable() : OptTable(InstallNameToolInfoTable) {}
102 };
103 
104 enum BitcodeStripID {
105   BITCODE_STRIP_INVALID = 0, // This is not an option ID.
106 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
107                HELPTEXT, METAVAR, VALUES)                                      \
108   BITCODE_STRIP_##ID,
109 #include "BitcodeStripOpts.inc"
110 #undef OPTION
111 };
112 
113 #define PREFIX(NAME, VALUE) const char *const BITCODE_STRIP_##NAME[] = VALUE;
114 #include "BitcodeStripOpts.inc"
115 #undef PREFIX
116 
117 static const opt::OptTable::Info BitcodeStripInfoTable[] = {
118 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
119                HELPTEXT, METAVAR, VALUES)                                      \
120   {BITCODE_STRIP_##PREFIX,                                                     \
121    NAME,                                                                       \
122    HELPTEXT,                                                                   \
123    METAVAR,                                                                    \
124    BITCODE_STRIP_##ID,                                                         \
125    opt::Option::KIND##Class,                                                   \
126    PARAM,                                                                      \
127    FLAGS,                                                                      \
128    BITCODE_STRIP_##GROUP,                                                      \
129    BITCODE_STRIP_##ALIAS,                                                      \
130    ALIASARGS,                                                                  \
131    VALUES},
132 #include "BitcodeStripOpts.inc"
133 #undef OPTION
134 };
135 
136 class BitcodeStripOptTable : public opt::OptTable {
137 public:
BitcodeStripOptTable()138   BitcodeStripOptTable() : OptTable(BitcodeStripInfoTable) {}
139 };
140 
141 enum StripID {
142   STRIP_INVALID = 0, // This is not an option ID.
143 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
144                HELPTEXT, METAVAR, VALUES)                                      \
145   STRIP_##ID,
146 #include "StripOpts.inc"
147 #undef OPTION
148 };
149 
150 #define PREFIX(NAME, VALUE) const char *const STRIP_##NAME[] = VALUE;
151 #include "StripOpts.inc"
152 #undef PREFIX
153 
154 static const opt::OptTable::Info StripInfoTable[] = {
155 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
156                HELPTEXT, METAVAR, VALUES)                                      \
157   {STRIP_##PREFIX, NAME,       HELPTEXT,                                       \
158    METAVAR,        STRIP_##ID, opt::Option::KIND##Class,                       \
159    PARAM,          FLAGS,      STRIP_##GROUP,                                  \
160    STRIP_##ALIAS,  ALIASARGS,  VALUES},
161 #include "StripOpts.inc"
162 #undef OPTION
163 };
164 
165 class StripOptTable : public opt::OptTable {
166 public:
StripOptTable()167   StripOptTable() : OptTable(StripInfoTable) {}
168 };
169 
170 } // namespace
171 
parseSectionRenameFlag(StringRef SectionName)172 static SectionFlag parseSectionRenameFlag(StringRef SectionName) {
173   return llvm::StringSwitch<SectionFlag>(SectionName)
174       .CaseLower("alloc", SectionFlag::SecAlloc)
175       .CaseLower("load", SectionFlag::SecLoad)
176       .CaseLower("noload", SectionFlag::SecNoload)
177       .CaseLower("readonly", SectionFlag::SecReadonly)
178       .CaseLower("debug", SectionFlag::SecDebug)
179       .CaseLower("code", SectionFlag::SecCode)
180       .CaseLower("data", SectionFlag::SecData)
181       .CaseLower("rom", SectionFlag::SecRom)
182       .CaseLower("merge", SectionFlag::SecMerge)
183       .CaseLower("strings", SectionFlag::SecStrings)
184       .CaseLower("contents", SectionFlag::SecContents)
185       .CaseLower("share", SectionFlag::SecShare)
186       .CaseLower("exclude", SectionFlag::SecExclude)
187       .Default(SectionFlag::SecNone);
188 }
189 
190 static Expected<SectionFlag>
parseSectionFlagSet(ArrayRef<StringRef> SectionFlags)191 parseSectionFlagSet(ArrayRef<StringRef> SectionFlags) {
192   SectionFlag ParsedFlags = SectionFlag::SecNone;
193   for (StringRef Flag : SectionFlags) {
194     SectionFlag ParsedFlag = parseSectionRenameFlag(Flag);
195     if (ParsedFlag == SectionFlag::SecNone)
196       return createStringError(
197           errc::invalid_argument,
198           "unrecognized section flag '%s'. Flags supported for GNU "
199           "compatibility: alloc, load, noload, readonly, exclude, debug, "
200           "code, data, rom, share, contents, merge, strings",
201           Flag.str().c_str());
202     ParsedFlags |= ParsedFlag;
203   }
204 
205   return ParsedFlags;
206 }
207 
parseRenameSectionValue(StringRef FlagValue)208 static Expected<SectionRename> parseRenameSectionValue(StringRef FlagValue) {
209   if (!FlagValue.contains('='))
210     return createStringError(errc::invalid_argument,
211                              "bad format for --rename-section: missing '='");
212 
213   // Initial split: ".foo" = ".bar,f1,f2,..."
214   auto Old2New = FlagValue.split('=');
215   SectionRename SR;
216   SR.OriginalName = Old2New.first;
217 
218   // Flags split: ".bar" "f1" "f2" ...
219   SmallVector<StringRef, 6> NameAndFlags;
220   Old2New.second.split(NameAndFlags, ',');
221   SR.NewName = NameAndFlags[0];
222 
223   if (NameAndFlags.size() > 1) {
224     Expected<SectionFlag> ParsedFlagSet =
225         parseSectionFlagSet(makeArrayRef(NameAndFlags).drop_front());
226     if (!ParsedFlagSet)
227       return ParsedFlagSet.takeError();
228     SR.NewFlags = *ParsedFlagSet;
229   }
230 
231   return SR;
232 }
233 
234 static Expected<std::pair<StringRef, uint64_t>>
parseSetSectionAlignment(StringRef FlagValue)235 parseSetSectionAlignment(StringRef FlagValue) {
236   if (!FlagValue.contains('='))
237     return createStringError(
238         errc::invalid_argument,
239         "bad format for --set-section-alignment: missing '='");
240   auto Split = StringRef(FlagValue).split('=');
241   if (Split.first.empty())
242     return createStringError(
243         errc::invalid_argument,
244         "bad format for --set-section-alignment: missing section name");
245   uint64_t NewAlign;
246   if (Split.second.getAsInteger(0, NewAlign))
247     return createStringError(
248         errc::invalid_argument,
249         "invalid alignment for --set-section-alignment: '%s'",
250         Split.second.str().c_str());
251   return std::make_pair(Split.first, NewAlign);
252 }
253 
254 static Expected<SectionFlagsUpdate>
parseSetSectionFlagValue(StringRef FlagValue)255 parseSetSectionFlagValue(StringRef FlagValue) {
256   if (!StringRef(FlagValue).contains('='))
257     return createStringError(errc::invalid_argument,
258                              "bad format for --set-section-flags: missing '='");
259 
260   // Initial split: ".foo" = "f1,f2,..."
261   auto Section2Flags = StringRef(FlagValue).split('=');
262   SectionFlagsUpdate SFU;
263   SFU.Name = Section2Flags.first;
264 
265   // Flags split: "f1" "f2" ...
266   SmallVector<StringRef, 6> SectionFlags;
267   Section2Flags.second.split(SectionFlags, ',');
268   Expected<SectionFlag> ParsedFlagSet = parseSectionFlagSet(SectionFlags);
269   if (!ParsedFlagSet)
270     return ParsedFlagSet.takeError();
271   SFU.NewFlags = *ParsedFlagSet;
272 
273   return SFU;
274 }
275 
276 struct TargetInfo {
277   FileFormat Format;
278   MachineInfo Machine;
279 };
280 
281 // FIXME: consolidate with the bfd parsing used by lld.
282 static const StringMap<MachineInfo> TargetMap{
283     // Name, {EMachine, 64bit, LittleEndian}
284     // x86
285     {"elf32-i386", {ELF::EM_386, false, true}},
286     {"elf32-x86-64", {ELF::EM_X86_64, false, true}},
287     {"elf64-x86-64", {ELF::EM_X86_64, true, true}},
288     // Intel MCU
289     {"elf32-iamcu", {ELF::EM_IAMCU, false, true}},
290     // ARM
291     {"elf32-littlearm", {ELF::EM_ARM, false, true}},
292     // ARM AArch64
293     {"elf64-aarch64", {ELF::EM_AARCH64, true, true}},
294     {"elf64-littleaarch64", {ELF::EM_AARCH64, true, true}},
295     // RISC-V
296     {"elf32-littleriscv", {ELF::EM_RISCV, false, true}},
297     {"elf64-littleriscv", {ELF::EM_RISCV, true, true}},
298     // PowerPC
299     {"elf32-powerpc", {ELF::EM_PPC, false, false}},
300     {"elf32-powerpcle", {ELF::EM_PPC, false, true}},
301     {"elf64-powerpc", {ELF::EM_PPC64, true, false}},
302     {"elf64-powerpcle", {ELF::EM_PPC64, true, true}},
303     // MIPS
304     {"elf32-bigmips", {ELF::EM_MIPS, false, false}},
305     {"elf32-ntradbigmips", {ELF::EM_MIPS, false, false}},
306     {"elf32-ntradlittlemips", {ELF::EM_MIPS, false, true}},
307     {"elf32-tradbigmips", {ELF::EM_MIPS, false, false}},
308     {"elf32-tradlittlemips", {ELF::EM_MIPS, false, true}},
309     {"elf64-tradbigmips", {ELF::EM_MIPS, true, false}},
310     {"elf64-tradlittlemips", {ELF::EM_MIPS, true, true}},
311     // SPARC
312     {"elf32-sparc", {ELF::EM_SPARC, false, false}},
313     {"elf32-sparcel", {ELF::EM_SPARC, false, true}},
314     {"elf32-hexagon", {ELF::EM_HEXAGON, false, true}},
315 };
316 
317 static Expected<TargetInfo>
getOutputTargetInfoByTargetName(StringRef TargetName)318 getOutputTargetInfoByTargetName(StringRef TargetName) {
319   StringRef OriginalTargetName = TargetName;
320   bool IsFreeBSD = TargetName.consume_back("-freebsd");
321   auto Iter = TargetMap.find(TargetName);
322   if (Iter == std::end(TargetMap))
323     return createStringError(errc::invalid_argument,
324                              "invalid output format: '%s'",
325                              OriginalTargetName.str().c_str());
326   MachineInfo MI = Iter->getValue();
327   if (IsFreeBSD)
328     MI.OSABI = ELF::ELFOSABI_FREEBSD;
329 
330   FileFormat Format;
331   if (TargetName.startswith("elf"))
332     Format = FileFormat::ELF;
333   else
334     // This should never happen because `TargetName` is valid (it certainly
335     // exists in the TargetMap).
336     llvm_unreachable("unknown target prefix");
337 
338   return {TargetInfo{Format, MI}};
339 }
340 
341 static Error
addSymbolsFromFile(NameMatcher & Symbols,BumpPtrAllocator & Alloc,StringRef Filename,MatchStyle MS,llvm::function_ref<Error (Error)> ErrorCallback)342 addSymbolsFromFile(NameMatcher &Symbols, BumpPtrAllocator &Alloc,
343                    StringRef Filename, MatchStyle MS,
344                    llvm::function_ref<Error(Error)> ErrorCallback) {
345   StringSaver Saver(Alloc);
346   SmallVector<StringRef, 16> Lines;
347   auto BufOrErr = MemoryBuffer::getFile(Filename);
348   if (!BufOrErr)
349     return createFileError(Filename, BufOrErr.getError());
350 
351   BufOrErr.get()->getBuffer().split(Lines, '\n');
352   for (StringRef Line : Lines) {
353     // Ignore everything after '#', trim whitespace, and only add the symbol if
354     // it's not empty.
355     auto TrimmedLine = Line.split('#').first.trim();
356     if (!TrimmedLine.empty())
357       if (Error E = Symbols.addMatcher(NameOrPattern::create(
358               Saver.save(TrimmedLine), MS, ErrorCallback)))
359         return E;
360   }
361 
362   return Error::success();
363 }
364 
365 Expected<NameOrPattern>
create(StringRef Pattern,MatchStyle MS,llvm::function_ref<Error (Error)> ErrorCallback)366 NameOrPattern::create(StringRef Pattern, MatchStyle MS,
367                       llvm::function_ref<Error(Error)> ErrorCallback) {
368   switch (MS) {
369   case MatchStyle::Literal:
370     return NameOrPattern(Pattern);
371   case MatchStyle::Wildcard: {
372     SmallVector<char, 32> Data;
373     bool IsPositiveMatch = true;
374     if (Pattern[0] == '!') {
375       IsPositiveMatch = false;
376       Pattern = Pattern.drop_front();
377     }
378     Expected<GlobPattern> GlobOrErr = GlobPattern::create(Pattern);
379 
380     // If we couldn't create it as a glob, report the error, but try again with
381     // a literal if the error reporting is non-fatal.
382     if (!GlobOrErr) {
383       if (Error E = ErrorCallback(GlobOrErr.takeError()))
384         return std::move(E);
385       return create(Pattern, MatchStyle::Literal, ErrorCallback);
386     }
387 
388     return NameOrPattern(std::make_shared<GlobPattern>(*GlobOrErr),
389                          IsPositiveMatch);
390   }
391   case MatchStyle::Regex: {
392     SmallVector<char, 32> Data;
393     return NameOrPattern(std::make_shared<Regex>(
394         ("^" + Pattern.ltrim('^').rtrim('$') + "$").toStringRef(Data)));
395   }
396   }
397   llvm_unreachable("Unhandled llvm.objcopy.MatchStyle enum");
398 }
399 
addSymbolsToRenameFromFile(StringMap<StringRef> & SymbolsToRename,BumpPtrAllocator & Alloc,StringRef Filename)400 static Error addSymbolsToRenameFromFile(StringMap<StringRef> &SymbolsToRename,
401                                         BumpPtrAllocator &Alloc,
402                                         StringRef Filename) {
403   StringSaver Saver(Alloc);
404   SmallVector<StringRef, 16> Lines;
405   auto BufOrErr = MemoryBuffer::getFile(Filename);
406   if (!BufOrErr)
407     return createFileError(Filename, BufOrErr.getError());
408 
409   BufOrErr.get()->getBuffer().split(Lines, '\n');
410   size_t NumLines = Lines.size();
411   for (size_t LineNo = 0; LineNo < NumLines; ++LineNo) {
412     StringRef TrimmedLine = Lines[LineNo].split('#').first.trim();
413     if (TrimmedLine.empty())
414       continue;
415 
416     std::pair<StringRef, StringRef> Pair = Saver.save(TrimmedLine).split(' ');
417     StringRef NewName = Pair.second.trim();
418     if (NewName.empty())
419       return createStringError(errc::invalid_argument,
420                                "%s:%zu: missing new symbol name",
421                                Filename.str().c_str(), LineNo + 1);
422     SymbolsToRename.insert({Pair.first, NewName});
423   }
424   return Error::success();
425 }
426 
getAsInteger(StringRef Val)427 template <class T> static ErrorOr<T> getAsInteger(StringRef Val) {
428   T Result;
429   if (Val.getAsInteger(0, Result))
430     return errc::invalid_argument;
431   return Result;
432 }
433 
434 namespace {
435 
436 enum class ToolType { Objcopy, Strip, InstallNameTool, BitcodeStrip };
437 
438 } // anonymous namespace
439 
printHelp(const opt::OptTable & OptTable,raw_ostream & OS,ToolType Tool)440 static void printHelp(const opt::OptTable &OptTable, raw_ostream &OS,
441                       ToolType Tool) {
442   StringRef HelpText, ToolName;
443   switch (Tool) {
444   case ToolType::Objcopy:
445     ToolName = "llvm-objcopy";
446     HelpText = " [options] input [output]";
447     break;
448   case ToolType::Strip:
449     ToolName = "llvm-strip";
450     HelpText = " [options] inputs...";
451     break;
452   case ToolType::InstallNameTool:
453     ToolName = "llvm-install-name-tool";
454     HelpText = " [options] input";
455     break;
456   case ToolType::BitcodeStrip:
457     ToolName = "llvm-bitcode-strip";
458     HelpText = " [options] input";
459     break;
460   }
461   OptTable.PrintHelp(OS, (ToolName + HelpText).str().c_str(),
462                      (ToolName + " tool").str().c_str());
463   // TODO: Replace this with libOption call once it adds extrahelp support.
464   // The CommandLine library has a cl::extrahelp class to support this,
465   // but libOption does not have that yet.
466   OS << "\nPass @FILE as argument to read options from FILE.\n";
467 }
468 
parseNewSymbolInfo(StringRef FlagValue,uint8_t DefaultVisibility)469 static Expected<NewSymbolInfo> parseNewSymbolInfo(StringRef FlagValue,
470                                                   uint8_t DefaultVisibility) {
471   // Parse value given with --add-symbol option and create the
472   // new symbol if possible. The value format for --add-symbol is:
473   //
474   // <name>=[<section>:]<value>[,<flags>]
475   //
476   // where:
477   // <name> - symbol name, can be empty string
478   // <section> - optional section name. If not given ABS symbol is created
479   // <value> - symbol value, can be decimal or hexadecimal number prefixed
480   //           with 0x.
481   // <flags> - optional flags affecting symbol type, binding or visibility:
482   //           The following are currently supported:
483   //
484   //           global, local, weak, default, hidden, file, section, object,
485   //           indirect-function.
486   //
487   //           The following flags are ignored and provided for GNU
488   //           compatibility only:
489   //
490   //           warning, debug, constructor, indirect, synthetic,
491   //           unique-object, before=<symbol>.
492   NewSymbolInfo SI;
493   StringRef Value;
494   std::tie(SI.SymbolName, Value) = FlagValue.split('=');
495   if (Value.empty())
496     return createStringError(
497         errc::invalid_argument,
498         "bad format for --add-symbol, missing '=' after '%s'",
499         SI.SymbolName.str().c_str());
500 
501   if (Value.contains(':')) {
502     std::tie(SI.SectionName, Value) = Value.split(':');
503     if (SI.SectionName.empty() || Value.empty())
504       return createStringError(
505           errc::invalid_argument,
506           "bad format for --add-symbol, missing section name or symbol value");
507   }
508 
509   SmallVector<StringRef, 6> Flags;
510   Value.split(Flags, ',');
511   if (Flags[0].getAsInteger(0, SI.Value))
512     return createStringError(errc::invalid_argument, "bad symbol value: '%s'",
513                              Flags[0].str().c_str());
514 
515   SI.Visibility = DefaultVisibility;
516   using Functor = std::function<void(void)>;
517   SmallVector<StringRef, 6> UnsupportedFlags;
518   for (size_t I = 1, NumFlags = Flags.size(); I < NumFlags; ++I)
519     static_cast<Functor>(
520         StringSwitch<Functor>(Flags[I])
521             .CaseLower("global", [&SI] { SI.Bind = ELF::STB_GLOBAL; })
522             .CaseLower("local", [&SI] { SI.Bind = ELF::STB_LOCAL; })
523             .CaseLower("weak", [&SI] { SI.Bind = ELF::STB_WEAK; })
524             .CaseLower("default", [&SI] { SI.Visibility = ELF::STV_DEFAULT; })
525             .CaseLower("hidden", [&SI] { SI.Visibility = ELF::STV_HIDDEN; })
526             .CaseLower("protected",
527                        [&SI] { SI.Visibility = ELF::STV_PROTECTED; })
528             .CaseLower("file", [&SI] { SI.Type = ELF::STT_FILE; })
529             .CaseLower("section", [&SI] { SI.Type = ELF::STT_SECTION; })
530             .CaseLower("object", [&SI] { SI.Type = ELF::STT_OBJECT; })
531             .CaseLower("function", [&SI] { SI.Type = ELF::STT_FUNC; })
532             .CaseLower("indirect-function",
533                        [&SI] { SI.Type = ELF::STT_GNU_IFUNC; })
534             .CaseLower("debug", [] {})
535             .CaseLower("constructor", [] {})
536             .CaseLower("warning", [] {})
537             .CaseLower("indirect", [] {})
538             .CaseLower("synthetic", [] {})
539             .CaseLower("unique-object", [] {})
540             .StartsWithLower("before", [] {})
541             .Default([&] { UnsupportedFlags.push_back(Flags[I]); }))();
542   if (!UnsupportedFlags.empty())
543     return createStringError(errc::invalid_argument,
544                              "unsupported flag%s for --add-symbol: '%s'",
545                              UnsupportedFlags.size() > 1 ? "s" : "",
546                              join(UnsupportedFlags, "', '").c_str());
547   return SI;
548 }
549 
getELFConfig() const550 Expected<const ELFConfig &> ConfigManager::getELFConfig() const {
551   if (!ELF) {
552     if (Common.StripSwiftSymbols || Common.KeepUndefined)
553       return createStringError(llvm::errc::invalid_argument,
554                                "option not supported by llvm-objcopy for ELF");
555 
556     // Parse lazy options.
557     ELFConfig ResConfig;
558 
559     if (NewSymbolVisibility) {
560       const uint8_t Invalid = 0xff;
561       ResConfig.NewSymbolVisibility =
562           StringSwitch<uint8_t>(*NewSymbolVisibility)
563               .Case("default", ELF::STV_DEFAULT)
564               .Case("hidden", ELF::STV_HIDDEN)
565               .Case("internal", ELF::STV_INTERNAL)
566               .Case("protected", ELF::STV_PROTECTED)
567               .Default(Invalid);
568 
569       if (ResConfig.NewSymbolVisibility == Invalid)
570         return createStringError(errc::invalid_argument,
571                                  "'%s' is not a valid symbol visibility",
572                                  NewSymbolVisibility->str().c_str());
573     }
574 
575     for (StringRef Arg : SymbolsToAdd) {
576       Expected<NewSymbolInfo> NSI = parseNewSymbolInfo(
577           Arg,
578           ResConfig.NewSymbolVisibility.getValueOr((uint8_t)ELF::STV_DEFAULT));
579       if (!NSI)
580         return NSI.takeError();
581       ResConfig.SymbolsToAdd.push_back(*NSI);
582     }
583 
584     ELF = std::move(ResConfig);
585   }
586 
587   return *ELF;
588 }
589 
getCOFFConfig() const590 Expected<const COFFConfig &> ConfigManager::getCOFFConfig() const {
591   if (Common.AllowBrokenLinks || !Common.SplitDWO.empty() ||
592       !Common.SymbolsPrefix.empty() || !Common.AllocSectionsPrefix.empty() ||
593       !Common.DumpSection.empty() || !Common.KeepSection.empty() ||
594       NewSymbolVisibility || !Common.SymbolsToGlobalize.empty() ||
595       !Common.SymbolsToKeep.empty() || !Common.SymbolsToLocalize.empty() ||
596       !Common.SymbolsToWeaken.empty() || !Common.SymbolsToKeepGlobal.empty() ||
597       !Common.SectionsToRename.empty() || !Common.SetSectionAlignment.empty() ||
598       Common.ExtractDWO || Common.LocalizeHidden || Common.PreserveDates ||
599       Common.StripDWO || Common.StripNonAlloc || Common.StripSections ||
600       Common.StripSwiftSymbols || Common.KeepUndefined || Common.Weaken ||
601       Common.DecompressDebugSections ||
602       Common.DiscardMode == DiscardType::Locals || !SymbolsToAdd.empty() ||
603       Common.EntryExpr) {
604     return createStringError(llvm::errc::invalid_argument,
605                              "option not supported by llvm-objcopy for COFF");
606   }
607 
608   return COFF;
609 }
610 
getMachOConfig() const611 Expected<const MachOConfig &> ConfigManager::getMachOConfig() const {
612   if (Common.AllowBrokenLinks || !Common.SplitDWO.empty() ||
613       !Common.SymbolsPrefix.empty() || !Common.AllocSectionsPrefix.empty() ||
614       !Common.KeepSection.empty() || NewSymbolVisibility ||
615       !Common.SymbolsToGlobalize.empty() || !Common.SymbolsToKeep.empty() ||
616       !Common.SymbolsToLocalize.empty() || !Common.SymbolsToWeaken.empty() ||
617       !Common.SymbolsToKeepGlobal.empty() || !Common.SectionsToRename.empty() ||
618       !Common.UnneededSymbolsToRemove.empty() ||
619       !Common.SetSectionAlignment.empty() || !Common.SetSectionFlags.empty() ||
620       Common.ExtractDWO || Common.LocalizeHidden || Common.PreserveDates ||
621       Common.StripAllGNU || Common.StripDWO || Common.StripNonAlloc ||
622       Common.StripSections || Common.Weaken || Common.DecompressDebugSections ||
623       Common.StripUnneeded || Common.DiscardMode == DiscardType::Locals ||
624       !SymbolsToAdd.empty() || Common.EntryExpr) {
625     return createStringError(llvm::errc::invalid_argument,
626                              "option not supported by llvm-objcopy for MachO");
627   }
628 
629   return MachO;
630 }
631 
getWasmConfig() const632 Expected<const WasmConfig &> ConfigManager::getWasmConfig() const {
633   if (!Common.AddGnuDebugLink.empty() || Common.ExtractPartition ||
634       !Common.SplitDWO.empty() || !Common.SymbolsPrefix.empty() ||
635       !Common.AllocSectionsPrefix.empty() ||
636       Common.DiscardMode != DiscardType::None || NewSymbolVisibility ||
637       !SymbolsToAdd.empty() || !Common.RPathToAdd.empty() ||
638       !Common.OnlySection.empty() || !Common.SymbolsToGlobalize.empty() ||
639       !Common.SymbolsToKeep.empty() || !Common.SymbolsToLocalize.empty() ||
640       !Common.SymbolsToRemove.empty() ||
641       !Common.UnneededSymbolsToRemove.empty() ||
642       !Common.SymbolsToWeaken.empty() || !Common.SymbolsToKeepGlobal.empty() ||
643       !Common.SectionsToRename.empty() || !Common.SetSectionAlignment.empty() ||
644       !Common.SetSectionFlags.empty() || !Common.SymbolsToRename.empty()) {
645     return createStringError(
646         llvm::errc::invalid_argument,
647         "only add-section, dump-section, and remove-section are supported");
648   }
649 
650   return Wasm;
651 }
652 
653 // ParseObjcopyOptions returns the config and sets the input arguments. If a
654 // help flag is set then ParseObjcopyOptions will print the help messege and
655 // exit.
656 Expected<DriverConfig>
parseObjcopyOptions(ArrayRef<const char * > RawArgsArr,llvm::function_ref<Error (Error)> ErrorCallback)657 parseObjcopyOptions(ArrayRef<const char *> RawArgsArr,
658                     llvm::function_ref<Error(Error)> ErrorCallback) {
659   DriverConfig DC;
660   ObjcopyOptTable T;
661 
662   const char *const *DashDash =
663       std::find_if(RawArgsArr.begin(), RawArgsArr.end(),
664                    [](StringRef Str) { return Str == "--"; });
665   ArrayRef<const char *> ArgsArr = makeArrayRef(RawArgsArr.begin(), DashDash);
666   if (DashDash != RawArgsArr.end())
667     DashDash = std::next(DashDash);
668 
669   unsigned MissingArgumentIndex, MissingArgumentCount;
670   llvm::opt::InputArgList InputArgs =
671       T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);
672 
673   if (InputArgs.size() == 0 && DashDash == RawArgsArr.end()) {
674     printHelp(T, errs(), ToolType::Objcopy);
675     exit(1);
676   }
677 
678   if (InputArgs.hasArg(OBJCOPY_help)) {
679     printHelp(T, outs(), ToolType::Objcopy);
680     exit(0);
681   }
682 
683   if (InputArgs.hasArg(OBJCOPY_version)) {
684     outs() << "llvm-objcopy, compatible with GNU objcopy\n";
685     cl::PrintVersionMessage();
686     exit(0);
687   }
688 
689   SmallVector<const char *, 2> Positional;
690 
691   for (auto Arg : InputArgs.filtered(OBJCOPY_UNKNOWN))
692     return createStringError(errc::invalid_argument, "unknown argument '%s'",
693                              Arg->getAsString(InputArgs).c_str());
694 
695   for (auto Arg : InputArgs.filtered(OBJCOPY_INPUT))
696     Positional.push_back(Arg->getValue());
697   std::copy(DashDash, RawArgsArr.end(), std::back_inserter(Positional));
698 
699   if (Positional.empty())
700     return createStringError(errc::invalid_argument, "no input file specified");
701 
702   if (Positional.size() > 2)
703     return createStringError(errc::invalid_argument,
704                              "too many positional arguments");
705 
706   ConfigManager ConfigMgr;
707   CommonConfig &Config = ConfigMgr.Common;
708   Config.InputFilename = Positional[0];
709   Config.OutputFilename = Positional[Positional.size() == 1 ? 0 : 1];
710   if (InputArgs.hasArg(OBJCOPY_target) &&
711       (InputArgs.hasArg(OBJCOPY_input_target) ||
712        InputArgs.hasArg(OBJCOPY_output_target)))
713     return createStringError(
714         errc::invalid_argument,
715         "--target cannot be used with --input-target or --output-target");
716 
717   if (InputArgs.hasArg(OBJCOPY_regex) && InputArgs.hasArg(OBJCOPY_wildcard))
718     return createStringError(errc::invalid_argument,
719                              "--regex and --wildcard are incompatible");
720 
721   MatchStyle SectionMatchStyle = InputArgs.hasArg(OBJCOPY_regex)
722                                      ? MatchStyle::Regex
723                                      : MatchStyle::Wildcard;
724   MatchStyle SymbolMatchStyle = InputArgs.hasArg(OBJCOPY_regex)
725                                     ? MatchStyle::Regex
726                                     : InputArgs.hasArg(OBJCOPY_wildcard)
727                                           ? MatchStyle::Wildcard
728                                           : MatchStyle::Literal;
729   StringRef InputFormat, OutputFormat;
730   if (InputArgs.hasArg(OBJCOPY_target)) {
731     InputFormat = InputArgs.getLastArgValue(OBJCOPY_target);
732     OutputFormat = InputArgs.getLastArgValue(OBJCOPY_target);
733   } else {
734     InputFormat = InputArgs.getLastArgValue(OBJCOPY_input_target);
735     OutputFormat = InputArgs.getLastArgValue(OBJCOPY_output_target);
736   }
737 
738   // FIXME:  Currently, we ignore the target for non-binary/ihex formats
739   // explicitly specified by -I option (e.g. -Ielf32-x86-64) and guess the
740   // format by llvm::object::createBinary regardless of the option value.
741   Config.InputFormat = StringSwitch<FileFormat>(InputFormat)
742                            .Case("binary", FileFormat::Binary)
743                            .Case("ihex", FileFormat::IHex)
744                            .Default(FileFormat::Unspecified);
745 
746   if (InputArgs.hasArg(OBJCOPY_new_symbol_visibility))
747     ConfigMgr.NewSymbolVisibility =
748         InputArgs.getLastArgValue(OBJCOPY_new_symbol_visibility);
749 
750   Config.OutputFormat = StringSwitch<FileFormat>(OutputFormat)
751                             .Case("binary", FileFormat::Binary)
752                             .Case("ihex", FileFormat::IHex)
753                             .Default(FileFormat::Unspecified);
754   if (Config.OutputFormat == FileFormat::Unspecified) {
755     if (OutputFormat.empty()) {
756       Config.OutputFormat = Config.InputFormat;
757     } else {
758       Expected<TargetInfo> Target =
759           getOutputTargetInfoByTargetName(OutputFormat);
760       if (!Target)
761         return Target.takeError();
762       Config.OutputFormat = Target->Format;
763       Config.OutputArch = Target->Machine;
764     }
765   }
766 
767   if (auto Arg = InputArgs.getLastArg(OBJCOPY_compress_debug_sections,
768                                       OBJCOPY_compress_debug_sections_eq)) {
769     Config.CompressionType = DebugCompressionType::Z;
770 
771     if (Arg->getOption().getID() == OBJCOPY_compress_debug_sections_eq) {
772       Config.CompressionType =
773           StringSwitch<DebugCompressionType>(
774               InputArgs.getLastArgValue(OBJCOPY_compress_debug_sections_eq))
775               .Case("zlib-gnu", DebugCompressionType::GNU)
776               .Case("zlib", DebugCompressionType::Z)
777               .Default(DebugCompressionType::None);
778       if (Config.CompressionType == DebugCompressionType::None)
779         return createStringError(
780             errc::invalid_argument,
781             "invalid or unsupported --compress-debug-sections format: %s",
782             InputArgs.getLastArgValue(OBJCOPY_compress_debug_sections_eq)
783                 .str()
784                 .c_str());
785     }
786     if (!zlib::isAvailable())
787       return createStringError(
788           errc::invalid_argument,
789           "LLVM was not compiled with LLVM_ENABLE_ZLIB: can not compress");
790   }
791 
792   Config.AddGnuDebugLink = InputArgs.getLastArgValue(OBJCOPY_add_gnu_debuglink);
793   // The gnu_debuglink's target is expected to not change or else its CRC would
794   // become invalidated and get rejected. We can avoid recalculating the
795   // checksum for every target file inside an archive by precomputing the CRC
796   // here. This prevents a significant amount of I/O.
797   if (!Config.AddGnuDebugLink.empty()) {
798     auto DebugOrErr = MemoryBuffer::getFile(Config.AddGnuDebugLink);
799     if (!DebugOrErr)
800       return createFileError(Config.AddGnuDebugLink, DebugOrErr.getError());
801     auto Debug = std::move(*DebugOrErr);
802     Config.GnuDebugLinkCRC32 =
803         llvm::crc32(arrayRefFromStringRef(Debug->getBuffer()));
804   }
805   Config.SplitDWO = InputArgs.getLastArgValue(OBJCOPY_split_dwo);
806   Config.SymbolsPrefix = InputArgs.getLastArgValue(OBJCOPY_prefix_symbols);
807   Config.AllocSectionsPrefix =
808       InputArgs.getLastArgValue(OBJCOPY_prefix_alloc_sections);
809   if (auto Arg = InputArgs.getLastArg(OBJCOPY_extract_partition))
810     Config.ExtractPartition = Arg->getValue();
811 
812   for (auto Arg : InputArgs.filtered(OBJCOPY_redefine_symbol)) {
813     if (!StringRef(Arg->getValue()).contains('='))
814       return createStringError(errc::invalid_argument,
815                                "bad format for --redefine-sym");
816     auto Old2New = StringRef(Arg->getValue()).split('=');
817     if (!Config.SymbolsToRename.insert(Old2New).second)
818       return createStringError(errc::invalid_argument,
819                                "multiple redefinition of symbol '%s'",
820                                Old2New.first.str().c_str());
821   }
822 
823   for (auto Arg : InputArgs.filtered(OBJCOPY_redefine_symbols))
824     if (Error E = addSymbolsToRenameFromFile(Config.SymbolsToRename, DC.Alloc,
825                                              Arg->getValue()))
826       return std::move(E);
827 
828   for (auto Arg : InputArgs.filtered(OBJCOPY_rename_section)) {
829     Expected<SectionRename> SR =
830         parseRenameSectionValue(StringRef(Arg->getValue()));
831     if (!SR)
832       return SR.takeError();
833     if (!Config.SectionsToRename.try_emplace(SR->OriginalName, *SR).second)
834       return createStringError(errc::invalid_argument,
835                                "multiple renames of section '%s'",
836                                SR->OriginalName.str().c_str());
837   }
838   for (auto Arg : InputArgs.filtered(OBJCOPY_set_section_alignment)) {
839     Expected<std::pair<StringRef, uint64_t>> NameAndAlign =
840         parseSetSectionAlignment(Arg->getValue());
841     if (!NameAndAlign)
842       return NameAndAlign.takeError();
843     Config.SetSectionAlignment[NameAndAlign->first] = NameAndAlign->second;
844   }
845   for (auto Arg : InputArgs.filtered(OBJCOPY_set_section_flags)) {
846     Expected<SectionFlagsUpdate> SFU =
847         parseSetSectionFlagValue(Arg->getValue());
848     if (!SFU)
849       return SFU.takeError();
850     if (!Config.SetSectionFlags.try_emplace(SFU->Name, *SFU).second)
851       return createStringError(
852           errc::invalid_argument,
853           "--set-section-flags set multiple times for section '%s'",
854           SFU->Name.str().c_str());
855   }
856   // Prohibit combinations of --set-section-flags when the section name is used
857   // by --rename-section, either as a source or a destination.
858   for (const auto &E : Config.SectionsToRename) {
859     const SectionRename &SR = E.second;
860     if (Config.SetSectionFlags.count(SR.OriginalName))
861       return createStringError(
862           errc::invalid_argument,
863           "--set-section-flags=%s conflicts with --rename-section=%s=%s",
864           SR.OriginalName.str().c_str(), SR.OriginalName.str().c_str(),
865           SR.NewName.str().c_str());
866     if (Config.SetSectionFlags.count(SR.NewName))
867       return createStringError(
868           errc::invalid_argument,
869           "--set-section-flags=%s conflicts with --rename-section=%s=%s",
870           SR.NewName.str().c_str(), SR.OriginalName.str().c_str(),
871           SR.NewName.str().c_str());
872   }
873 
874   for (auto Arg : InputArgs.filtered(OBJCOPY_remove_section))
875     if (Error E = Config.ToRemove.addMatcher(NameOrPattern::create(
876             Arg->getValue(), SectionMatchStyle, ErrorCallback)))
877       return std::move(E);
878   for (auto Arg : InputArgs.filtered(OBJCOPY_keep_section))
879     if (Error E = Config.KeepSection.addMatcher(NameOrPattern::create(
880             Arg->getValue(), SectionMatchStyle, ErrorCallback)))
881       return std::move(E);
882   for (auto Arg : InputArgs.filtered(OBJCOPY_only_section))
883     if (Error E = Config.OnlySection.addMatcher(NameOrPattern::create(
884             Arg->getValue(), SectionMatchStyle, ErrorCallback)))
885       return std::move(E);
886   for (auto Arg : InputArgs.filtered(OBJCOPY_add_section)) {
887     StringRef ArgValue(Arg->getValue());
888     if (!ArgValue.contains('='))
889       return createStringError(errc::invalid_argument,
890                                "bad format for --add-section: missing '='");
891     if (ArgValue.split("=").second.empty())
892       return createStringError(
893           errc::invalid_argument,
894           "bad format for --add-section: missing file name");
895     Config.AddSection.push_back(ArgValue);
896   }
897   for (auto *Arg : InputArgs.filtered(OBJCOPY_dump_section)) {
898     StringRef Value(Arg->getValue());
899     if (Value.split('=').second.empty())
900       return createStringError(
901           errc::invalid_argument,
902           "bad format for --dump-section, expected section=file");
903     Config.DumpSection.push_back(Value);
904   }
905   Config.StripAll = InputArgs.hasArg(OBJCOPY_strip_all);
906   Config.StripAllGNU = InputArgs.hasArg(OBJCOPY_strip_all_gnu);
907   Config.StripDebug = InputArgs.hasArg(OBJCOPY_strip_debug);
908   Config.StripDWO = InputArgs.hasArg(OBJCOPY_strip_dwo);
909   Config.StripSections = InputArgs.hasArg(OBJCOPY_strip_sections);
910   Config.StripNonAlloc = InputArgs.hasArg(OBJCOPY_strip_non_alloc);
911   Config.StripUnneeded = InputArgs.hasArg(OBJCOPY_strip_unneeded);
912   Config.ExtractDWO = InputArgs.hasArg(OBJCOPY_extract_dwo);
913   Config.ExtractMainPartition =
914       InputArgs.hasArg(OBJCOPY_extract_main_partition);
915   Config.LocalizeHidden = InputArgs.hasArg(OBJCOPY_localize_hidden);
916   Config.Weaken = InputArgs.hasArg(OBJCOPY_weaken);
917   if (InputArgs.hasArg(OBJCOPY_discard_all, OBJCOPY_discard_locals))
918     Config.DiscardMode =
919         InputArgs.hasFlag(OBJCOPY_discard_all, OBJCOPY_discard_locals)
920             ? DiscardType::All
921             : DiscardType::Locals;
922   Config.OnlyKeepDebug = InputArgs.hasArg(OBJCOPY_only_keep_debug);
923   Config.KeepFileSymbols = InputArgs.hasArg(OBJCOPY_keep_file_symbols);
924   Config.KeepUndefined = InputArgs.hasArg(OBJCOPY_keep_undefined);
925   Config.DecompressDebugSections =
926       InputArgs.hasArg(OBJCOPY_decompress_debug_sections);
927   if (Config.DiscardMode == DiscardType::All) {
928     Config.StripDebug = true;
929     Config.KeepFileSymbols = true;
930   }
931   for (auto Arg : InputArgs.filtered(OBJCOPY_localize_symbol))
932     if (Error E = Config.SymbolsToLocalize.addMatcher(NameOrPattern::create(
933             Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
934       return std::move(E);
935   for (auto Arg : InputArgs.filtered(OBJCOPY_localize_symbols))
936     if (Error E = addSymbolsFromFile(Config.SymbolsToLocalize, DC.Alloc,
937                                      Arg->getValue(), SymbolMatchStyle,
938                                      ErrorCallback))
939       return std::move(E);
940   for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbol))
941     if (Error E = Config.SymbolsToKeepGlobal.addMatcher(NameOrPattern::create(
942             Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
943       return std::move(E);
944   for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbols))
945     if (Error E = addSymbolsFromFile(Config.SymbolsToKeepGlobal, DC.Alloc,
946                                      Arg->getValue(), SymbolMatchStyle,
947                                      ErrorCallback))
948       return std::move(E);
949   for (auto Arg : InputArgs.filtered(OBJCOPY_globalize_symbol))
950     if (Error E = Config.SymbolsToGlobalize.addMatcher(NameOrPattern::create(
951             Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
952       return std::move(E);
953   for (auto Arg : InputArgs.filtered(OBJCOPY_globalize_symbols))
954     if (Error E = addSymbolsFromFile(Config.SymbolsToGlobalize, DC.Alloc,
955                                      Arg->getValue(), SymbolMatchStyle,
956                                      ErrorCallback))
957       return std::move(E);
958   for (auto Arg : InputArgs.filtered(OBJCOPY_weaken_symbol))
959     if (Error E = Config.SymbolsToWeaken.addMatcher(NameOrPattern::create(
960             Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
961       return std::move(E);
962   for (auto Arg : InputArgs.filtered(OBJCOPY_weaken_symbols))
963     if (Error E = addSymbolsFromFile(Config.SymbolsToWeaken, DC.Alloc,
964                                      Arg->getValue(), SymbolMatchStyle,
965                                      ErrorCallback))
966       return std::move(E);
967   for (auto Arg : InputArgs.filtered(OBJCOPY_strip_symbol))
968     if (Error E = Config.SymbolsToRemove.addMatcher(NameOrPattern::create(
969             Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
970       return std::move(E);
971   for (auto Arg : InputArgs.filtered(OBJCOPY_strip_symbols))
972     if (Error E = addSymbolsFromFile(Config.SymbolsToRemove, DC.Alloc,
973                                      Arg->getValue(), SymbolMatchStyle,
974                                      ErrorCallback))
975       return std::move(E);
976   for (auto Arg : InputArgs.filtered(OBJCOPY_strip_unneeded_symbol))
977     if (Error E =
978             Config.UnneededSymbolsToRemove.addMatcher(NameOrPattern::create(
979                 Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
980       return std::move(E);
981   for (auto Arg : InputArgs.filtered(OBJCOPY_strip_unneeded_symbols))
982     if (Error E = addSymbolsFromFile(Config.UnneededSymbolsToRemove, DC.Alloc,
983                                      Arg->getValue(), SymbolMatchStyle,
984                                      ErrorCallback))
985       return std::move(E);
986   for (auto Arg : InputArgs.filtered(OBJCOPY_keep_symbol))
987     if (Error E = Config.SymbolsToKeep.addMatcher(NameOrPattern::create(
988             Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
989       return std::move(E);
990   for (auto Arg : InputArgs.filtered(OBJCOPY_keep_symbols))
991     if (Error E =
992             addSymbolsFromFile(Config.SymbolsToKeep, DC.Alloc, Arg->getValue(),
993                                SymbolMatchStyle, ErrorCallback))
994       return std::move(E);
995   for (auto Arg : InputArgs.filtered(OBJCOPY_add_symbol))
996     ConfigMgr.SymbolsToAdd.push_back(Arg->getValue());
997 
998   Config.AllowBrokenLinks = InputArgs.hasArg(OBJCOPY_allow_broken_links);
999 
1000   Config.DeterministicArchives = InputArgs.hasFlag(
1001       OBJCOPY_enable_deterministic_archives,
1002       OBJCOPY_disable_deterministic_archives, /*default=*/true);
1003 
1004   Config.PreserveDates = InputArgs.hasArg(OBJCOPY_preserve_dates);
1005 
1006   if (Config.PreserveDates &&
1007       (Config.OutputFilename == "-" || Config.InputFilename == "-"))
1008     return createStringError(errc::invalid_argument,
1009                              "--preserve-dates requires a file");
1010 
1011   for (auto Arg : InputArgs)
1012     if (Arg->getOption().matches(OBJCOPY_set_start)) {
1013       auto EAddr = getAsInteger<uint64_t>(Arg->getValue());
1014       if (!EAddr)
1015         return createStringError(
1016             EAddr.getError(), "bad entry point address: '%s'", Arg->getValue());
1017 
1018       Config.EntryExpr = [EAddr](uint64_t) { return *EAddr; };
1019     } else if (Arg->getOption().matches(OBJCOPY_change_start)) {
1020       auto EIncr = getAsInteger<int64_t>(Arg->getValue());
1021       if (!EIncr)
1022         return createStringError(EIncr.getError(),
1023                                  "bad entry point increment: '%s'",
1024                                  Arg->getValue());
1025       auto Expr = Config.EntryExpr ? std::move(Config.EntryExpr)
1026                                    : [](uint64_t A) { return A; };
1027       Config.EntryExpr = [Expr, EIncr](uint64_t EAddr) {
1028         return Expr(EAddr) + *EIncr;
1029       };
1030     }
1031 
1032   if (Config.DecompressDebugSections &&
1033       Config.CompressionType != DebugCompressionType::None) {
1034     return createStringError(
1035         errc::invalid_argument,
1036         "cannot specify both --compress-debug-sections and "
1037         "--decompress-debug-sections");
1038   }
1039 
1040   if (Config.DecompressDebugSections && !zlib::isAvailable())
1041     return createStringError(
1042         errc::invalid_argument,
1043         "LLVM was not compiled with LLVM_ENABLE_ZLIB: cannot decompress");
1044 
1045   if (Config.ExtractPartition && Config.ExtractMainPartition)
1046     return createStringError(errc::invalid_argument,
1047                              "cannot specify --extract-partition together with "
1048                              "--extract-main-partition");
1049 
1050   DC.CopyConfigs.push_back(std::move(ConfigMgr));
1051   return std::move(DC);
1052 }
1053 
1054 // ParseInstallNameToolOptions returns the config and sets the input arguments.
1055 // If a help flag is set then ParseInstallNameToolOptions will print the help
1056 // messege and exit.
1057 Expected<DriverConfig>
parseInstallNameToolOptions(ArrayRef<const char * > ArgsArr)1058 parseInstallNameToolOptions(ArrayRef<const char *> ArgsArr) {
1059   DriverConfig DC;
1060   ConfigManager ConfigMgr;
1061   CommonConfig &Config = ConfigMgr.Common;
1062   InstallNameToolOptTable T;
1063   unsigned MissingArgumentIndex, MissingArgumentCount;
1064   llvm::opt::InputArgList InputArgs =
1065       T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);
1066 
1067   if (MissingArgumentCount)
1068     return createStringError(
1069         errc::invalid_argument,
1070         "missing argument to " +
1071             StringRef(InputArgs.getArgString(MissingArgumentIndex)) +
1072             " option");
1073 
1074   if (InputArgs.size() == 0) {
1075     printHelp(T, errs(), ToolType::InstallNameTool);
1076     exit(1);
1077   }
1078 
1079   if (InputArgs.hasArg(INSTALL_NAME_TOOL_help)) {
1080     printHelp(T, outs(), ToolType::InstallNameTool);
1081     exit(0);
1082   }
1083 
1084   if (InputArgs.hasArg(INSTALL_NAME_TOOL_version)) {
1085     outs() << "llvm-install-name-tool, compatible with cctools "
1086               "install_name_tool\n";
1087     cl::PrintVersionMessage();
1088     exit(0);
1089   }
1090 
1091   for (auto Arg : InputArgs.filtered(INSTALL_NAME_TOOL_add_rpath))
1092     Config.RPathToAdd.push_back(Arg->getValue());
1093 
1094   for (auto *Arg : InputArgs.filtered(INSTALL_NAME_TOOL_prepend_rpath))
1095     Config.RPathToPrepend.push_back(Arg->getValue());
1096 
1097   for (auto Arg : InputArgs.filtered(INSTALL_NAME_TOOL_delete_rpath)) {
1098     StringRef RPath = Arg->getValue();
1099 
1100     // Cannot add and delete the same rpath at the same time.
1101     if (is_contained(Config.RPathToAdd, RPath))
1102       return createStringError(
1103           errc::invalid_argument,
1104           "cannot specify both -add_rpath '%s' and -delete_rpath '%s'",
1105           RPath.str().c_str(), RPath.str().c_str());
1106     if (is_contained(Config.RPathToPrepend, RPath))
1107       return createStringError(
1108           errc::invalid_argument,
1109           "cannot specify both -prepend_rpath '%s' and -delete_rpath '%s'",
1110           RPath.str().c_str(), RPath.str().c_str());
1111 
1112     Config.RPathsToRemove.insert(RPath);
1113   }
1114 
1115   for (auto *Arg : InputArgs.filtered(INSTALL_NAME_TOOL_rpath)) {
1116     StringRef Old = Arg->getValue(0);
1117     StringRef New = Arg->getValue(1);
1118 
1119     auto Match = [=](StringRef RPath) { return RPath == Old || RPath == New; };
1120 
1121     // Cannot specify duplicate -rpath entries
1122     auto It1 = find_if(
1123         Config.RPathsToUpdate,
1124         [&Match](const DenseMap<StringRef, StringRef>::value_type &OldNew) {
1125           return Match(OldNew.getFirst()) || Match(OldNew.getSecond());
1126         });
1127     if (It1 != Config.RPathsToUpdate.end())
1128       return createStringError(errc::invalid_argument,
1129                                "cannot specify both -rpath '" +
1130                                    It1->getFirst() + "' '" + It1->getSecond() +
1131                                    "' and -rpath '" + Old + "' '" + New + "'");
1132 
1133     // Cannot specify the same rpath under both -delete_rpath and -rpath
1134     auto It2 = find_if(Config.RPathsToRemove, Match);
1135     if (It2 != Config.RPathsToRemove.end())
1136       return createStringError(errc::invalid_argument,
1137                                "cannot specify both -delete_rpath '" + *It2 +
1138                                    "' and -rpath '" + Old + "' '" + New + "'");
1139 
1140     // Cannot specify the same rpath under both -add_rpath and -rpath
1141     auto It3 = find_if(Config.RPathToAdd, Match);
1142     if (It3 != Config.RPathToAdd.end())
1143       return createStringError(errc::invalid_argument,
1144                                "cannot specify both -add_rpath '" + *It3 +
1145                                    "' and -rpath '" + Old + "' '" + New + "'");
1146 
1147     // Cannot specify the same rpath under both -prepend_rpath and -rpath.
1148     auto It4 = find_if(Config.RPathToPrepend, Match);
1149     if (It4 != Config.RPathToPrepend.end())
1150       return createStringError(errc::invalid_argument,
1151                                "cannot specify both -prepend_rpath '" + *It4 +
1152                                    "' and -rpath '" + Old + "' '" + New + "'");
1153 
1154     Config.RPathsToUpdate.insert({Old, New});
1155   }
1156 
1157   if (auto *Arg = InputArgs.getLastArg(INSTALL_NAME_TOOL_id)) {
1158     Config.SharedLibId = Arg->getValue();
1159     if (Config.SharedLibId->empty())
1160       return createStringError(errc::invalid_argument,
1161                                "cannot specify an empty id");
1162   }
1163 
1164   for (auto *Arg : InputArgs.filtered(INSTALL_NAME_TOOL_change))
1165     Config.InstallNamesToUpdate.insert({Arg->getValue(0), Arg->getValue(1)});
1166 
1167   Config.RemoveAllRpaths =
1168       InputArgs.hasArg(INSTALL_NAME_TOOL_delete_all_rpaths);
1169 
1170   SmallVector<StringRef, 2> Positional;
1171   for (auto Arg : InputArgs.filtered(INSTALL_NAME_TOOL_UNKNOWN))
1172     return createStringError(errc::invalid_argument, "unknown argument '%s'",
1173                              Arg->getAsString(InputArgs).c_str());
1174   for (auto Arg : InputArgs.filtered(INSTALL_NAME_TOOL_INPUT))
1175     Positional.push_back(Arg->getValue());
1176   if (Positional.empty())
1177     return createStringError(errc::invalid_argument, "no input file specified");
1178   if (Positional.size() > 1)
1179     return createStringError(
1180         errc::invalid_argument,
1181         "llvm-install-name-tool expects a single input file");
1182   Config.InputFilename = Positional[0];
1183   Config.OutputFilename = Positional[0];
1184 
1185   DC.CopyConfigs.push_back(std::move(ConfigMgr));
1186   return std::move(DC);
1187 }
1188 
1189 Expected<DriverConfig>
parseBitcodeStripOptions(ArrayRef<const char * > ArgsArr)1190 parseBitcodeStripOptions(ArrayRef<const char *> ArgsArr) {
1191   DriverConfig DC;
1192   ConfigManager ConfigMgr;
1193   CommonConfig &Config = ConfigMgr.Common;
1194   BitcodeStripOptTable T;
1195   unsigned MissingArgumentIndex, MissingArgumentCount;
1196   opt::InputArgList InputArgs =
1197       T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);
1198 
1199   if (InputArgs.size() == 0) {
1200     printHelp(T, errs(), ToolType::BitcodeStrip);
1201     exit(1);
1202   }
1203 
1204   if (InputArgs.hasArg(BITCODE_STRIP_help)) {
1205     printHelp(T, outs(), ToolType::BitcodeStrip);
1206     exit(0);
1207   }
1208 
1209   if (InputArgs.hasArg(BITCODE_STRIP_version)) {
1210     outs() << "llvm-bitcode-strip, compatible with cctools "
1211               "bitcode_strip\n";
1212     cl::PrintVersionMessage();
1213     exit(0);
1214   }
1215 
1216   for (auto *Arg : InputArgs.filtered(BITCODE_STRIP_UNKNOWN))
1217     return createStringError(errc::invalid_argument, "unknown argument '%s'",
1218                              Arg->getAsString(InputArgs).c_str());
1219 
1220   SmallVector<StringRef, 2> Positional;
1221   for (auto *Arg : InputArgs.filtered(BITCODE_STRIP_INPUT))
1222     Positional.push_back(Arg->getValue());
1223   if (Positional.size() > 1)
1224     return createStringError(errc::invalid_argument,
1225                              "llvm-bitcode-strip expects a single input file");
1226   assert(!Positional.empty());
1227   Config.InputFilename = Positional[0];
1228   Config.OutputFilename = Positional[0];
1229 
1230   DC.CopyConfigs.push_back(std::move(ConfigMgr));
1231   return std::move(DC);
1232 }
1233 
1234 // ParseStripOptions returns the config and sets the input arguments. If a
1235 // help flag is set then ParseStripOptions will print the help messege and
1236 // exit.
1237 Expected<DriverConfig>
parseStripOptions(ArrayRef<const char * > RawArgsArr,llvm::function_ref<Error (Error)> ErrorCallback)1238 parseStripOptions(ArrayRef<const char *> RawArgsArr,
1239                   llvm::function_ref<Error(Error)> ErrorCallback) {
1240   const char *const *DashDash =
1241       std::find_if(RawArgsArr.begin(), RawArgsArr.end(),
1242                    [](StringRef Str) { return Str == "--"; });
1243   ArrayRef<const char *> ArgsArr = makeArrayRef(RawArgsArr.begin(), DashDash);
1244   if (DashDash != RawArgsArr.end())
1245     DashDash = std::next(DashDash);
1246 
1247   StripOptTable T;
1248   unsigned MissingArgumentIndex, MissingArgumentCount;
1249   llvm::opt::InputArgList InputArgs =
1250       T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);
1251 
1252   if (InputArgs.size() == 0 && DashDash == RawArgsArr.end()) {
1253     printHelp(T, errs(), ToolType::Strip);
1254     exit(1);
1255   }
1256 
1257   if (InputArgs.hasArg(STRIP_help)) {
1258     printHelp(T, outs(), ToolType::Strip);
1259     exit(0);
1260   }
1261 
1262   if (InputArgs.hasArg(STRIP_version)) {
1263     outs() << "llvm-strip, compatible with GNU strip\n";
1264     cl::PrintVersionMessage();
1265     exit(0);
1266   }
1267 
1268   SmallVector<StringRef, 2> Positional;
1269   for (auto Arg : InputArgs.filtered(STRIP_UNKNOWN))
1270     return createStringError(errc::invalid_argument, "unknown argument '%s'",
1271                              Arg->getAsString(InputArgs).c_str());
1272   for (auto Arg : InputArgs.filtered(STRIP_INPUT))
1273     Positional.push_back(Arg->getValue());
1274   std::copy(DashDash, RawArgsArr.end(), std::back_inserter(Positional));
1275 
1276   if (Positional.empty())
1277     return createStringError(errc::invalid_argument, "no input file specified");
1278 
1279   if (Positional.size() > 1 && InputArgs.hasArg(STRIP_output))
1280     return createStringError(
1281         errc::invalid_argument,
1282         "multiple input files cannot be used in combination with -o");
1283 
1284   ConfigManager ConfigMgr;
1285   CommonConfig &Config = ConfigMgr.Common;
1286 
1287   if (InputArgs.hasArg(STRIP_regex) && InputArgs.hasArg(STRIP_wildcard))
1288     return createStringError(errc::invalid_argument,
1289                              "--regex and --wildcard are incompatible");
1290   MatchStyle SectionMatchStyle =
1291       InputArgs.hasArg(STRIP_regex) ? MatchStyle::Regex : MatchStyle::Wildcard;
1292   MatchStyle SymbolMatchStyle = InputArgs.hasArg(STRIP_regex)
1293                                     ? MatchStyle::Regex
1294                                     : InputArgs.hasArg(STRIP_wildcard)
1295                                           ? MatchStyle::Wildcard
1296                                           : MatchStyle::Literal;
1297   Config.AllowBrokenLinks = InputArgs.hasArg(STRIP_allow_broken_links);
1298   Config.StripDebug = InputArgs.hasArg(STRIP_strip_debug);
1299 
1300   if (InputArgs.hasArg(STRIP_discard_all, STRIP_discard_locals))
1301     Config.DiscardMode =
1302         InputArgs.hasFlag(STRIP_discard_all, STRIP_discard_locals)
1303             ? DiscardType::All
1304             : DiscardType::Locals;
1305   Config.StripSections = InputArgs.hasArg(STRIP_strip_sections);
1306   Config.StripUnneeded = InputArgs.hasArg(STRIP_strip_unneeded);
1307   if (auto Arg = InputArgs.getLastArg(STRIP_strip_all, STRIP_no_strip_all))
1308     Config.StripAll = Arg->getOption().getID() == STRIP_strip_all;
1309   Config.StripAllGNU = InputArgs.hasArg(STRIP_strip_all_gnu);
1310   Config.StripSwiftSymbols = InputArgs.hasArg(STRIP_strip_swift_symbols);
1311   Config.OnlyKeepDebug = InputArgs.hasArg(STRIP_only_keep_debug);
1312   Config.KeepFileSymbols = InputArgs.hasArg(STRIP_keep_file_symbols);
1313   Config.KeepUndefined = InputArgs.hasArg(STRIP_keep_undefined);
1314 
1315   for (auto Arg : InputArgs.filtered(STRIP_keep_section))
1316     if (Error E = Config.KeepSection.addMatcher(NameOrPattern::create(
1317             Arg->getValue(), SectionMatchStyle, ErrorCallback)))
1318       return std::move(E);
1319 
1320   for (auto Arg : InputArgs.filtered(STRIP_remove_section))
1321     if (Error E = Config.ToRemove.addMatcher(NameOrPattern::create(
1322             Arg->getValue(), SectionMatchStyle, ErrorCallback)))
1323       return std::move(E);
1324 
1325   for (auto Arg : InputArgs.filtered(STRIP_strip_symbol))
1326     if (Error E = Config.SymbolsToRemove.addMatcher(NameOrPattern::create(
1327             Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
1328       return std::move(E);
1329 
1330   for (auto Arg : InputArgs.filtered(STRIP_keep_symbol))
1331     if (Error E = Config.SymbolsToKeep.addMatcher(NameOrPattern::create(
1332             Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
1333       return std::move(E);
1334 
1335   if (!InputArgs.hasArg(STRIP_no_strip_all) && !Config.StripDebug &&
1336       !Config.StripUnneeded && Config.DiscardMode == DiscardType::None &&
1337       !Config.StripAllGNU && Config.SymbolsToRemove.empty())
1338     Config.StripAll = true;
1339 
1340   if (Config.DiscardMode == DiscardType::All) {
1341     Config.StripDebug = true;
1342     Config.KeepFileSymbols = true;
1343   }
1344 
1345   Config.DeterministicArchives =
1346       InputArgs.hasFlag(STRIP_enable_deterministic_archives,
1347                         STRIP_disable_deterministic_archives, /*default=*/true);
1348 
1349   Config.PreserveDates = InputArgs.hasArg(STRIP_preserve_dates);
1350   Config.InputFormat = FileFormat::Unspecified;
1351   Config.OutputFormat = FileFormat::Unspecified;
1352 
1353   DriverConfig DC;
1354   if (Positional.size() == 1) {
1355     Config.InputFilename = Positional[0];
1356     Config.OutputFilename =
1357         InputArgs.getLastArgValue(STRIP_output, Positional[0]);
1358     DC.CopyConfigs.push_back(std::move(ConfigMgr));
1359   } else {
1360     StringMap<unsigned> InputFiles;
1361     for (StringRef Filename : Positional) {
1362       if (InputFiles[Filename]++ == 1) {
1363         if (Filename == "-")
1364           return createStringError(
1365               errc::invalid_argument,
1366               "cannot specify '-' as an input file more than once");
1367         if (Error E = ErrorCallback(createStringError(
1368                 errc::invalid_argument, "'%s' was already specified",
1369                 Filename.str().c_str())))
1370           return std::move(E);
1371       }
1372       Config.InputFilename = Filename;
1373       Config.OutputFilename = Filename;
1374       DC.CopyConfigs.push_back(ConfigMgr);
1375     }
1376   }
1377 
1378   if (Config.PreserveDates && (is_contained(Positional, "-") ||
1379                                InputArgs.getLastArgValue(STRIP_output) == "-"))
1380     return createStringError(errc::invalid_argument,
1381                              "--preserve-dates requires a file");
1382 
1383   return std::move(DC);
1384 }
1385 
1386 } // namespace objcopy
1387 } // namespace llvm
1388