1 //===- CopyConfig.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 "CopyConfig.h"
10 
11 #include "llvm/ADT/Optional.h"
12 #include "llvm/ADT/SmallVector.h"
13 #include "llvm/ADT/StringRef.h"
14 #include "llvm/ADT/StringSet.h"
15 #include "llvm/Option/Arg.h"
16 #include "llvm/Option/ArgList.h"
17 #include "llvm/Support/CRC.h"
18 #include "llvm/Support/CommandLine.h"
19 #include "llvm/Support/Compression.h"
20 #include "llvm/Support/Errc.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(errc::invalid_argument,
248                              "invalid alignment for --set-section-alignment: '%s'",
249                              Split.second.str().c_str());
250   return std::make_pair(Split.first, NewAlign);
251 }
252 
253 static Expected<SectionFlagsUpdate>
parseSetSectionFlagValue(StringRef FlagValue)254 parseSetSectionFlagValue(StringRef FlagValue) {
255   if (!StringRef(FlagValue).contains('='))
256     return createStringError(errc::invalid_argument,
257                              "bad format for --set-section-flags: missing '='");
258 
259   // Initial split: ".foo" = "f1,f2,..."
260   auto Section2Flags = StringRef(FlagValue).split('=');
261   SectionFlagsUpdate SFU;
262   SFU.Name = Section2Flags.first;
263 
264   // Flags split: "f1" "f2" ...
265   SmallVector<StringRef, 6> SectionFlags;
266   Section2Flags.second.split(SectionFlags, ',');
267   Expected<SectionFlag> ParsedFlagSet = parseSectionFlagSet(SectionFlags);
268   if (!ParsedFlagSet)
269     return ParsedFlagSet.takeError();
270   SFU.NewFlags = *ParsedFlagSet;
271 
272   return SFU;
273 }
274 
275 struct TargetInfo {
276   FileFormat Format;
277   MachineInfo Machine;
278 };
279 
280 // FIXME: consolidate with the bfd parsing used by lld.
281 static const StringMap<MachineInfo> TargetMap{
282     // Name, {EMachine, 64bit, LittleEndian}
283     // x86
284     {"elf32-i386", {ELF::EM_386, false, true}},
285     {"elf32-x86-64", {ELF::EM_X86_64, false, true}},
286     {"elf64-x86-64", {ELF::EM_X86_64, true, true}},
287     // Intel MCU
288     {"elf32-iamcu", {ELF::EM_IAMCU, false, true}},
289     // ARM
290     {"elf32-littlearm", {ELF::EM_ARM, false, true}},
291     // ARM AArch64
292     {"elf64-aarch64", {ELF::EM_AARCH64, true, true}},
293     {"elf64-littleaarch64", {ELF::EM_AARCH64, true, true}},
294     // RISC-V
295     {"elf32-littleriscv", {ELF::EM_RISCV, false, true}},
296     {"elf64-littleriscv", {ELF::EM_RISCV, true, true}},
297     // PowerPC
298     {"elf32-powerpc", {ELF::EM_PPC, false, false}},
299     {"elf32-powerpcle", {ELF::EM_PPC, false, true}},
300     {"elf64-powerpc", {ELF::EM_PPC64, true, false}},
301     {"elf64-powerpcle", {ELF::EM_PPC64, true, true}},
302     // MIPS
303     {"elf32-bigmips", {ELF::EM_MIPS, false, false}},
304     {"elf32-ntradbigmips", {ELF::EM_MIPS, false, false}},
305     {"elf32-ntradlittlemips", {ELF::EM_MIPS, false, true}},
306     {"elf32-tradbigmips", {ELF::EM_MIPS, false, false}},
307     {"elf32-tradlittlemips", {ELF::EM_MIPS, false, true}},
308     {"elf64-tradbigmips", {ELF::EM_MIPS, true, false}},
309     {"elf64-tradlittlemips", {ELF::EM_MIPS, true, true}},
310     // SPARC
311     {"elf32-sparc", {ELF::EM_SPARC, false, false}},
312     {"elf32-sparcel", {ELF::EM_SPARC, false, true}},
313     {"elf32-hexagon", {ELF::EM_HEXAGON, false, true}},
314 };
315 
316 static Expected<TargetInfo>
getOutputTargetInfoByTargetName(StringRef TargetName)317 getOutputTargetInfoByTargetName(StringRef TargetName) {
318   StringRef OriginalTargetName = TargetName;
319   bool IsFreeBSD = TargetName.consume_back("-freebsd");
320   auto Iter = TargetMap.find(TargetName);
321   if (Iter == std::end(TargetMap))
322     return createStringError(errc::invalid_argument,
323                              "invalid output format: '%s'",
324                              OriginalTargetName.str().c_str());
325   MachineInfo MI = Iter->getValue();
326   if (IsFreeBSD)
327     MI.OSABI = ELF::ELFOSABI_FREEBSD;
328 
329   FileFormat Format;
330   if (TargetName.startswith("elf"))
331     Format = FileFormat::ELF;
332   else
333     // This should never happen because `TargetName` is valid (it certainly
334     // exists in the TargetMap).
335     llvm_unreachable("unknown target prefix");
336 
337   return {TargetInfo{Format, MI}};
338 }
339 
340 static Error
addSymbolsFromFile(NameMatcher & Symbols,BumpPtrAllocator & Alloc,StringRef Filename,MatchStyle MS,llvm::function_ref<Error (Error)> ErrorCallback)341 addSymbolsFromFile(NameMatcher &Symbols, BumpPtrAllocator &Alloc,
342                    StringRef Filename, MatchStyle MS,
343                    llvm::function_ref<Error(Error)> ErrorCallback) {
344   StringSaver Saver(Alloc);
345   SmallVector<StringRef, 16> Lines;
346   auto BufOrErr = MemoryBuffer::getFile(Filename);
347   if (!BufOrErr)
348     return createFileError(Filename, BufOrErr.getError());
349 
350   BufOrErr.get()->getBuffer().split(Lines, '\n');
351   for (StringRef Line : Lines) {
352     // Ignore everything after '#', trim whitespace, and only add the symbol if
353     // it's not empty.
354     auto TrimmedLine = Line.split('#').first.trim();
355     if (!TrimmedLine.empty())
356       if (Error E = Symbols.addMatcher(NameOrPattern::create(
357               Saver.save(TrimmedLine), MS, ErrorCallback)))
358         return E;
359   }
360 
361   return Error::success();
362 }
363 
364 Expected<NameOrPattern>
create(StringRef Pattern,MatchStyle MS,llvm::function_ref<Error (Error)> ErrorCallback)365 NameOrPattern::create(StringRef Pattern, MatchStyle MS,
366                       llvm::function_ref<Error(Error)> ErrorCallback) {
367   switch (MS) {
368   case MatchStyle::Literal:
369     return NameOrPattern(Pattern);
370   case MatchStyle::Wildcard: {
371     SmallVector<char, 32> Data;
372     bool IsPositiveMatch = true;
373     if (Pattern[0] == '!') {
374       IsPositiveMatch = false;
375       Pattern = Pattern.drop_front();
376     }
377     Expected<GlobPattern> GlobOrErr = GlobPattern::create(Pattern);
378 
379     // If we couldn't create it as a glob, report the error, but try again with
380     // a literal if the error reporting is non-fatal.
381     if (!GlobOrErr) {
382       if (Error E = ErrorCallback(GlobOrErr.takeError()))
383         return std::move(E);
384       return create(Pattern, MatchStyle::Literal, ErrorCallback);
385     }
386 
387     return NameOrPattern(std::make_shared<GlobPattern>(*GlobOrErr),
388                          IsPositiveMatch);
389   }
390   case MatchStyle::Regex: {
391     SmallVector<char, 32> Data;
392     return NameOrPattern(std::make_shared<Regex>(
393         ("^" + Pattern.ltrim('^').rtrim('$') + "$").toStringRef(Data)));
394   }
395   }
396   llvm_unreachable("Unhandled llvm.objcopy.MatchStyle enum");
397 }
398 
addSymbolsToRenameFromFile(StringMap<StringRef> & SymbolsToRename,BumpPtrAllocator & Alloc,StringRef Filename)399 static Error addSymbolsToRenameFromFile(StringMap<StringRef> &SymbolsToRename,
400                                         BumpPtrAllocator &Alloc,
401                                         StringRef Filename) {
402   StringSaver Saver(Alloc);
403   SmallVector<StringRef, 16> Lines;
404   auto BufOrErr = MemoryBuffer::getFile(Filename);
405   if (!BufOrErr)
406     return createFileError(Filename, BufOrErr.getError());
407 
408   BufOrErr.get()->getBuffer().split(Lines, '\n');
409   size_t NumLines = Lines.size();
410   for (size_t LineNo = 0; LineNo < NumLines; ++LineNo) {
411     StringRef TrimmedLine = Lines[LineNo].split('#').first.trim();
412     if (TrimmedLine.empty())
413       continue;
414 
415     std::pair<StringRef, StringRef> Pair = Saver.save(TrimmedLine).split(' ');
416     StringRef NewName = Pair.second.trim();
417     if (NewName.empty())
418       return createStringError(errc::invalid_argument,
419                                "%s:%zu: missing new symbol name",
420                                Filename.str().c_str(), LineNo + 1);
421     SymbolsToRename.insert({Pair.first, NewName});
422   }
423   return Error::success();
424 }
425 
getAsInteger(StringRef Val)426 template <class T> static ErrorOr<T> getAsInteger(StringRef Val) {
427   T Result;
428   if (Val.getAsInteger(0, Result))
429     return errc::invalid_argument;
430   return Result;
431 }
432 
433 namespace {
434 
435 enum class ToolType { Objcopy, Strip, InstallNameTool, BitcodeStrip };
436 
437 } // anonymous namespace
438 
printHelp(const opt::OptTable & OptTable,raw_ostream & OS,ToolType Tool)439 static void printHelp(const opt::OptTable &OptTable, raw_ostream &OS,
440                       ToolType Tool) {
441   StringRef HelpText, ToolName;
442   switch (Tool) {
443   case ToolType::Objcopy:
444     ToolName = "llvm-objcopy";
445     HelpText = " [options] input [output]";
446     break;
447   case ToolType::Strip:
448     ToolName = "llvm-strip";
449     HelpText = " [options] inputs...";
450     break;
451   case ToolType::InstallNameTool:
452     ToolName = "llvm-install-name-tool";
453     HelpText = " [options] input";
454     break;
455   case ToolType::BitcodeStrip:
456     ToolName = "llvm-bitcode-strip";
457     HelpText = " [options] input";
458     break;
459   }
460   OptTable.PrintHelp(OS, (ToolName + HelpText).str().c_str(),
461                      (ToolName + " tool").str().c_str());
462   // TODO: Replace this with libOption call once it adds extrahelp support.
463   // The CommandLine library has a cl::extrahelp class to support this,
464   // but libOption does not have that yet.
465   OS << "\nPass @FILE as argument to read options from FILE.\n";
466 }
467 
468 // ParseObjcopyOptions returns the config and sets the input arguments. If a
469 // help flag is set then ParseObjcopyOptions will print the help messege and
470 // exit.
471 Expected<DriverConfig>
parseObjcopyOptions(ArrayRef<const char * > ArgsArr,llvm::function_ref<Error (Error)> ErrorCallback)472 parseObjcopyOptions(ArrayRef<const char *> ArgsArr,
473                     llvm::function_ref<Error(Error)> ErrorCallback) {
474   DriverConfig DC;
475   ObjcopyOptTable T;
476   unsigned MissingArgumentIndex, MissingArgumentCount;
477   llvm::opt::InputArgList InputArgs =
478       T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);
479 
480   if (InputArgs.size() == 0) {
481     printHelp(T, errs(), ToolType::Objcopy);
482     exit(1);
483   }
484 
485   if (InputArgs.hasArg(OBJCOPY_help)) {
486     printHelp(T, outs(), ToolType::Objcopy);
487     exit(0);
488   }
489 
490   if (InputArgs.hasArg(OBJCOPY_version)) {
491     outs() << "llvm-objcopy, compatible with GNU objcopy\n";
492     cl::PrintVersionMessage();
493     exit(0);
494   }
495 
496   SmallVector<const char *, 2> Positional;
497 
498   for (auto Arg : InputArgs.filtered(OBJCOPY_UNKNOWN))
499     return createStringError(errc::invalid_argument, "unknown argument '%s'",
500                              Arg->getAsString(InputArgs).c_str());
501 
502   for (auto Arg : InputArgs.filtered(OBJCOPY_INPUT))
503     Positional.push_back(Arg->getValue());
504 
505   if (Positional.empty())
506     return createStringError(errc::invalid_argument, "no input file specified");
507 
508   if (Positional.size() > 2)
509     return createStringError(errc::invalid_argument,
510                              "too many positional arguments");
511 
512   CopyConfig Config;
513   Config.InputFilename = Positional[0];
514   Config.OutputFilename = Positional[Positional.size() == 1 ? 0 : 1];
515   if (InputArgs.hasArg(OBJCOPY_target) &&
516       (InputArgs.hasArg(OBJCOPY_input_target) ||
517        InputArgs.hasArg(OBJCOPY_output_target)))
518     return createStringError(
519         errc::invalid_argument,
520         "--target cannot be used with --input-target or --output-target");
521 
522   if (InputArgs.hasArg(OBJCOPY_regex) && InputArgs.hasArg(OBJCOPY_wildcard))
523     return createStringError(errc::invalid_argument,
524                              "--regex and --wildcard are incompatible");
525 
526   MatchStyle SectionMatchStyle = InputArgs.hasArg(OBJCOPY_regex)
527                                      ? MatchStyle::Regex
528                                      : MatchStyle::Wildcard;
529   MatchStyle SymbolMatchStyle = InputArgs.hasArg(OBJCOPY_regex)
530                                     ? MatchStyle::Regex
531                                     : InputArgs.hasArg(OBJCOPY_wildcard)
532                                           ? MatchStyle::Wildcard
533                                           : MatchStyle::Literal;
534   StringRef InputFormat, OutputFormat;
535   if (InputArgs.hasArg(OBJCOPY_target)) {
536     InputFormat = InputArgs.getLastArgValue(OBJCOPY_target);
537     OutputFormat = InputArgs.getLastArgValue(OBJCOPY_target);
538   } else {
539     InputFormat = InputArgs.getLastArgValue(OBJCOPY_input_target);
540     OutputFormat = InputArgs.getLastArgValue(OBJCOPY_output_target);
541   }
542 
543   // FIXME:  Currently, we ignore the target for non-binary/ihex formats
544   // explicitly specified by -I option (e.g. -Ielf32-x86-64) and guess the
545   // format by llvm::object::createBinary regardless of the option value.
546   Config.InputFormat = StringSwitch<FileFormat>(InputFormat)
547                            .Case("binary", FileFormat::Binary)
548                            .Case("ihex", FileFormat::IHex)
549                            .Default(FileFormat::Unspecified);
550 
551   if (InputArgs.hasArg(OBJCOPY_new_symbol_visibility))
552     Config.NewSymbolVisibility =
553         InputArgs.getLastArgValue(OBJCOPY_new_symbol_visibility);
554 
555   Config.OutputFormat = StringSwitch<FileFormat>(OutputFormat)
556                             .Case("binary", FileFormat::Binary)
557                             .Case("ihex", FileFormat::IHex)
558                             .Default(FileFormat::Unspecified);
559   if (Config.OutputFormat == FileFormat::Unspecified) {
560     if (OutputFormat.empty()) {
561       Config.OutputFormat = Config.InputFormat;
562     } else {
563       Expected<TargetInfo> Target =
564           getOutputTargetInfoByTargetName(OutputFormat);
565       if (!Target)
566         return Target.takeError();
567       Config.OutputFormat = Target->Format;
568       Config.OutputArch = Target->Machine;
569     }
570   }
571 
572   if (auto Arg = InputArgs.getLastArg(OBJCOPY_compress_debug_sections,
573                                       OBJCOPY_compress_debug_sections_eq)) {
574     Config.CompressionType = DebugCompressionType::Z;
575 
576     if (Arg->getOption().getID() == OBJCOPY_compress_debug_sections_eq) {
577       Config.CompressionType =
578           StringSwitch<DebugCompressionType>(
579               InputArgs.getLastArgValue(OBJCOPY_compress_debug_sections_eq))
580               .Case("zlib-gnu", DebugCompressionType::GNU)
581               .Case("zlib", DebugCompressionType::Z)
582               .Default(DebugCompressionType::None);
583       if (Config.CompressionType == DebugCompressionType::None)
584         return createStringError(
585             errc::invalid_argument,
586             "invalid or unsupported --compress-debug-sections format: %s",
587             InputArgs.getLastArgValue(OBJCOPY_compress_debug_sections_eq)
588                 .str()
589                 .c_str());
590     }
591     if (!zlib::isAvailable())
592       return createStringError(
593           errc::invalid_argument,
594           "LLVM was not compiled with LLVM_ENABLE_ZLIB: can not compress");
595   }
596 
597   Config.AddGnuDebugLink = InputArgs.getLastArgValue(OBJCOPY_add_gnu_debuglink);
598   // The gnu_debuglink's target is expected to not change or else its CRC would
599   // become invalidated and get rejected. We can avoid recalculating the
600   // checksum for every target file inside an archive by precomputing the CRC
601   // here. This prevents a significant amount of I/O.
602   if (!Config.AddGnuDebugLink.empty()) {
603     auto DebugOrErr = MemoryBuffer::getFile(Config.AddGnuDebugLink);
604     if (!DebugOrErr)
605       return createFileError(Config.AddGnuDebugLink, DebugOrErr.getError());
606     auto Debug = std::move(*DebugOrErr);
607     Config.GnuDebugLinkCRC32 =
608         llvm::crc32(arrayRefFromStringRef(Debug->getBuffer()));
609   }
610   Config.BuildIdLinkDir = InputArgs.getLastArgValue(OBJCOPY_build_id_link_dir);
611   if (InputArgs.hasArg(OBJCOPY_build_id_link_input))
612     Config.BuildIdLinkInput =
613         InputArgs.getLastArgValue(OBJCOPY_build_id_link_input);
614   if (InputArgs.hasArg(OBJCOPY_build_id_link_output))
615     Config.BuildIdLinkOutput =
616         InputArgs.getLastArgValue(OBJCOPY_build_id_link_output);
617   Config.SplitDWO = InputArgs.getLastArgValue(OBJCOPY_split_dwo);
618   Config.SymbolsPrefix = InputArgs.getLastArgValue(OBJCOPY_prefix_symbols);
619   Config.AllocSectionsPrefix =
620       InputArgs.getLastArgValue(OBJCOPY_prefix_alloc_sections);
621   if (auto Arg = InputArgs.getLastArg(OBJCOPY_extract_partition))
622     Config.ExtractPartition = Arg->getValue();
623 
624   for (auto Arg : InputArgs.filtered(OBJCOPY_redefine_symbol)) {
625     if (!StringRef(Arg->getValue()).contains('='))
626       return createStringError(errc::invalid_argument,
627                                "bad format for --redefine-sym");
628     auto Old2New = StringRef(Arg->getValue()).split('=');
629     if (!Config.SymbolsToRename.insert(Old2New).second)
630       return createStringError(errc::invalid_argument,
631                                "multiple redefinition of symbol '%s'",
632                                Old2New.first.str().c_str());
633   }
634 
635   for (auto Arg : InputArgs.filtered(OBJCOPY_redefine_symbols))
636     if (Error E = addSymbolsToRenameFromFile(Config.SymbolsToRename, DC.Alloc,
637                                              Arg->getValue()))
638       return std::move(E);
639 
640   for (auto Arg : InputArgs.filtered(OBJCOPY_rename_section)) {
641     Expected<SectionRename> SR =
642         parseRenameSectionValue(StringRef(Arg->getValue()));
643     if (!SR)
644       return SR.takeError();
645     if (!Config.SectionsToRename.try_emplace(SR->OriginalName, *SR).second)
646       return createStringError(errc::invalid_argument,
647                                "multiple renames of section '%s'",
648                                SR->OriginalName.str().c_str());
649   }
650   for (auto Arg : InputArgs.filtered(OBJCOPY_set_section_alignment)) {
651     Expected<std::pair<StringRef, uint64_t>> NameAndAlign =
652         parseSetSectionAlignment(Arg->getValue());
653     if (!NameAndAlign)
654       return NameAndAlign.takeError();
655     Config.SetSectionAlignment[NameAndAlign->first] = NameAndAlign->second;
656   }
657   for (auto Arg : InputArgs.filtered(OBJCOPY_set_section_flags)) {
658     Expected<SectionFlagsUpdate> SFU =
659         parseSetSectionFlagValue(Arg->getValue());
660     if (!SFU)
661       return SFU.takeError();
662     if (!Config.SetSectionFlags.try_emplace(SFU->Name, *SFU).second)
663       return createStringError(
664           errc::invalid_argument,
665           "--set-section-flags set multiple times for section '%s'",
666           SFU->Name.str().c_str());
667   }
668   // Prohibit combinations of --set-section-flags when the section name is used
669   // by --rename-section, either as a source or a destination.
670   for (const auto &E : Config.SectionsToRename) {
671     const SectionRename &SR = E.second;
672     if (Config.SetSectionFlags.count(SR.OriginalName))
673       return createStringError(
674           errc::invalid_argument,
675           "--set-section-flags=%s conflicts with --rename-section=%s=%s",
676           SR.OriginalName.str().c_str(), SR.OriginalName.str().c_str(),
677           SR.NewName.str().c_str());
678     if (Config.SetSectionFlags.count(SR.NewName))
679       return createStringError(
680           errc::invalid_argument,
681           "--set-section-flags=%s conflicts with --rename-section=%s=%s",
682           SR.NewName.str().c_str(), SR.OriginalName.str().c_str(),
683           SR.NewName.str().c_str());
684   }
685 
686   for (auto Arg : InputArgs.filtered(OBJCOPY_remove_section))
687     if (Error E = Config.ToRemove.addMatcher(NameOrPattern::create(
688             Arg->getValue(), SectionMatchStyle, ErrorCallback)))
689       return std::move(E);
690   for (auto Arg : InputArgs.filtered(OBJCOPY_keep_section))
691     if (Error E = Config.KeepSection.addMatcher(NameOrPattern::create(
692             Arg->getValue(), SectionMatchStyle, ErrorCallback)))
693       return std::move(E);
694   for (auto Arg : InputArgs.filtered(OBJCOPY_only_section))
695     if (Error E = Config.OnlySection.addMatcher(NameOrPattern::create(
696             Arg->getValue(), SectionMatchStyle, ErrorCallback)))
697       return std::move(E);
698   for (auto Arg : InputArgs.filtered(OBJCOPY_add_section)) {
699     StringRef ArgValue(Arg->getValue());
700     if (!ArgValue.contains('='))
701       return createStringError(errc::invalid_argument,
702                                "bad format for --add-section: missing '='");
703     if (ArgValue.split("=").second.empty())
704       return createStringError(
705           errc::invalid_argument,
706           "bad format for --add-section: missing file name");
707     Config.AddSection.push_back(ArgValue);
708   }
709   for (auto Arg : InputArgs.filtered(OBJCOPY_dump_section))
710     Config.DumpSection.push_back(Arg->getValue());
711   Config.StripAll = InputArgs.hasArg(OBJCOPY_strip_all);
712   Config.StripAllGNU = InputArgs.hasArg(OBJCOPY_strip_all_gnu);
713   Config.StripDebug = InputArgs.hasArg(OBJCOPY_strip_debug);
714   Config.StripDWO = InputArgs.hasArg(OBJCOPY_strip_dwo);
715   Config.StripSections = InputArgs.hasArg(OBJCOPY_strip_sections);
716   Config.StripNonAlloc = InputArgs.hasArg(OBJCOPY_strip_non_alloc);
717   Config.StripUnneeded = InputArgs.hasArg(OBJCOPY_strip_unneeded);
718   Config.ExtractDWO = InputArgs.hasArg(OBJCOPY_extract_dwo);
719   Config.ExtractMainPartition =
720       InputArgs.hasArg(OBJCOPY_extract_main_partition);
721   Config.LocalizeHidden = InputArgs.hasArg(OBJCOPY_localize_hidden);
722   Config.Weaken = InputArgs.hasArg(OBJCOPY_weaken);
723   if (InputArgs.hasArg(OBJCOPY_discard_all, OBJCOPY_discard_locals))
724     Config.DiscardMode =
725         InputArgs.hasFlag(OBJCOPY_discard_all, OBJCOPY_discard_locals)
726             ? DiscardType::All
727             : DiscardType::Locals;
728   Config.OnlyKeepDebug = InputArgs.hasArg(OBJCOPY_only_keep_debug);
729   Config.KeepFileSymbols = InputArgs.hasArg(OBJCOPY_keep_file_symbols);
730   Config.DecompressDebugSections =
731       InputArgs.hasArg(OBJCOPY_decompress_debug_sections);
732   if (Config.DiscardMode == DiscardType::All) {
733     Config.StripDebug = true;
734     Config.KeepFileSymbols = true;
735   }
736   for (auto Arg : InputArgs.filtered(OBJCOPY_localize_symbol))
737     if (Error E = Config.SymbolsToLocalize.addMatcher(NameOrPattern::create(
738             Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
739       return std::move(E);
740   for (auto Arg : InputArgs.filtered(OBJCOPY_localize_symbols))
741     if (Error E = addSymbolsFromFile(Config.SymbolsToLocalize, DC.Alloc,
742                                      Arg->getValue(), SymbolMatchStyle,
743                                      ErrorCallback))
744       return std::move(E);
745   for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbol))
746     if (Error E = Config.SymbolsToKeepGlobal.addMatcher(NameOrPattern::create(
747             Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
748       return std::move(E);
749   for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbols))
750     if (Error E = addSymbolsFromFile(Config.SymbolsToKeepGlobal, DC.Alloc,
751                                      Arg->getValue(), SymbolMatchStyle,
752                                      ErrorCallback))
753       return std::move(E);
754   for (auto Arg : InputArgs.filtered(OBJCOPY_globalize_symbol))
755     if (Error E = Config.SymbolsToGlobalize.addMatcher(NameOrPattern::create(
756             Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
757       return std::move(E);
758   for (auto Arg : InputArgs.filtered(OBJCOPY_globalize_symbols))
759     if (Error E = addSymbolsFromFile(Config.SymbolsToGlobalize, DC.Alloc,
760                                      Arg->getValue(), SymbolMatchStyle,
761                                      ErrorCallback))
762       return std::move(E);
763   for (auto Arg : InputArgs.filtered(OBJCOPY_weaken_symbol))
764     if (Error E = Config.SymbolsToWeaken.addMatcher(NameOrPattern::create(
765             Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
766       return std::move(E);
767   for (auto Arg : InputArgs.filtered(OBJCOPY_weaken_symbols))
768     if (Error E = addSymbolsFromFile(Config.SymbolsToWeaken, DC.Alloc,
769                                      Arg->getValue(), SymbolMatchStyle,
770                                      ErrorCallback))
771       return std::move(E);
772   for (auto Arg : InputArgs.filtered(OBJCOPY_strip_symbol))
773     if (Error E = Config.SymbolsToRemove.addMatcher(NameOrPattern::create(
774             Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
775       return std::move(E);
776   for (auto Arg : InputArgs.filtered(OBJCOPY_strip_symbols))
777     if (Error E = addSymbolsFromFile(Config.SymbolsToRemove, DC.Alloc,
778                                      Arg->getValue(), SymbolMatchStyle,
779                                      ErrorCallback))
780       return std::move(E);
781   for (auto Arg : InputArgs.filtered(OBJCOPY_strip_unneeded_symbol))
782     if (Error E =
783             Config.UnneededSymbolsToRemove.addMatcher(NameOrPattern::create(
784                 Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
785       return std::move(E);
786   for (auto Arg : InputArgs.filtered(OBJCOPY_strip_unneeded_symbols))
787     if (Error E = addSymbolsFromFile(Config.UnneededSymbolsToRemove, DC.Alloc,
788                                      Arg->getValue(), SymbolMatchStyle,
789                                      ErrorCallback))
790       return std::move(E);
791   for (auto Arg : InputArgs.filtered(OBJCOPY_keep_symbol))
792     if (Error E = Config.SymbolsToKeep.addMatcher(NameOrPattern::create(
793             Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
794       return std::move(E);
795   for (auto Arg : InputArgs.filtered(OBJCOPY_keep_symbols))
796     if (Error E =
797             addSymbolsFromFile(Config.SymbolsToKeep, DC.Alloc, Arg->getValue(),
798                                SymbolMatchStyle, ErrorCallback))
799       return std::move(E);
800   for (auto Arg : InputArgs.filtered(OBJCOPY_add_symbol))
801     Config.SymbolsToAdd.push_back(Arg->getValue());
802 
803   Config.AllowBrokenLinks = InputArgs.hasArg(OBJCOPY_allow_broken_links);
804 
805   Config.DeterministicArchives = InputArgs.hasFlag(
806       OBJCOPY_enable_deterministic_archives,
807       OBJCOPY_disable_deterministic_archives, /*default=*/true);
808 
809   Config.PreserveDates = InputArgs.hasArg(OBJCOPY_preserve_dates);
810 
811   if (Config.PreserveDates &&
812       (Config.OutputFilename == "-" || Config.InputFilename == "-"))
813     return createStringError(errc::invalid_argument,
814                              "--preserve-dates requires a file");
815 
816   for (auto Arg : InputArgs)
817     if (Arg->getOption().matches(OBJCOPY_set_start)) {
818       auto EAddr = getAsInteger<uint64_t>(Arg->getValue());
819       if (!EAddr)
820         return createStringError(
821             EAddr.getError(), "bad entry point address: '%s'", Arg->getValue());
822 
823       Config.EntryExpr = [EAddr](uint64_t) { return *EAddr; };
824     } else if (Arg->getOption().matches(OBJCOPY_change_start)) {
825       auto EIncr = getAsInteger<int64_t>(Arg->getValue());
826       if (!EIncr)
827         return createStringError(EIncr.getError(),
828                                  "bad entry point increment: '%s'",
829                                  Arg->getValue());
830       auto Expr = Config.EntryExpr ? std::move(Config.EntryExpr)
831                                    : [](uint64_t A) { return A; };
832       Config.EntryExpr = [Expr, EIncr](uint64_t EAddr) {
833         return Expr(EAddr) + *EIncr;
834       };
835     }
836 
837   if (Config.DecompressDebugSections &&
838       Config.CompressionType != DebugCompressionType::None) {
839     return createStringError(
840         errc::invalid_argument,
841         "cannot specify both --compress-debug-sections and "
842         "--decompress-debug-sections");
843   }
844 
845   if (Config.DecompressDebugSections && !zlib::isAvailable())
846     return createStringError(
847         errc::invalid_argument,
848         "LLVM was not compiled with LLVM_ENABLE_ZLIB: cannot decompress");
849 
850   if (Config.ExtractPartition && Config.ExtractMainPartition)
851     return createStringError(errc::invalid_argument,
852                              "cannot specify --extract-partition together with "
853                              "--extract-main-partition");
854 
855   DC.CopyConfigs.push_back(std::move(Config));
856   return std::move(DC);
857 }
858 
859 // ParseInstallNameToolOptions returns the config and sets the input arguments.
860 // If a help flag is set then ParseInstallNameToolOptions will print the help
861 // messege and exit.
862 Expected<DriverConfig>
parseInstallNameToolOptions(ArrayRef<const char * > ArgsArr)863 parseInstallNameToolOptions(ArrayRef<const char *> ArgsArr) {
864   DriverConfig DC;
865   CopyConfig Config;
866   InstallNameToolOptTable T;
867   unsigned MissingArgumentIndex, MissingArgumentCount;
868   llvm::opt::InputArgList InputArgs =
869       T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);
870 
871   if (MissingArgumentCount)
872     return createStringError(
873         errc::invalid_argument,
874         "missing argument to " +
875             StringRef(InputArgs.getArgString(MissingArgumentIndex)) +
876             " option");
877 
878   if (InputArgs.size() == 0) {
879     printHelp(T, errs(), ToolType::InstallNameTool);
880     exit(1);
881   }
882 
883   if (InputArgs.hasArg(INSTALL_NAME_TOOL_help)) {
884     printHelp(T, outs(), ToolType::InstallNameTool);
885     exit(0);
886   }
887 
888   if (InputArgs.hasArg(INSTALL_NAME_TOOL_version)) {
889     outs() << "llvm-install-name-tool, compatible with cctools "
890               "install_name_tool\n";
891     cl::PrintVersionMessage();
892     exit(0);
893   }
894 
895   for (auto Arg : InputArgs.filtered(INSTALL_NAME_TOOL_add_rpath))
896     Config.RPathToAdd.push_back(Arg->getValue());
897 
898   for (auto *Arg : InputArgs.filtered(INSTALL_NAME_TOOL_prepend_rpath))
899     Config.RPathToPrepend.push_back(Arg->getValue());
900 
901   for (auto Arg : InputArgs.filtered(INSTALL_NAME_TOOL_delete_rpath)) {
902     StringRef RPath = Arg->getValue();
903 
904     // Cannot add and delete the same rpath at the same time.
905     if (is_contained(Config.RPathToAdd, RPath))
906       return createStringError(
907           errc::invalid_argument,
908           "cannot specify both -add_rpath '%s' and -delete_rpath '%s'",
909           RPath.str().c_str(), RPath.str().c_str());
910     if (is_contained(Config.RPathToPrepend, RPath))
911       return createStringError(
912           errc::invalid_argument,
913           "cannot specify both -prepend_rpath '%s' and -delete_rpath '%s'",
914           RPath.str().c_str(), RPath.str().c_str());
915 
916     Config.RPathsToRemove.insert(RPath);
917   }
918 
919   for (auto *Arg : InputArgs.filtered(INSTALL_NAME_TOOL_rpath)) {
920     StringRef Old = Arg->getValue(0);
921     StringRef New = Arg->getValue(1);
922 
923     auto Match = [=](StringRef RPath) { return RPath == Old || RPath == New; };
924 
925     // Cannot specify duplicate -rpath entries
926     auto It1 = find_if(
927         Config.RPathsToUpdate,
928         [&Match](const DenseMap<StringRef, StringRef>::value_type &OldNew) {
929           return Match(OldNew.getFirst()) || Match(OldNew.getSecond());
930         });
931     if (It1 != Config.RPathsToUpdate.end())
932       return createStringError(errc::invalid_argument,
933                                "cannot specify both -rpath '" +
934                                    It1->getFirst() + "' '" + It1->getSecond() +
935                                    "' and -rpath '" + Old + "' '" + New + "'");
936 
937     // Cannot specify the same rpath under both -delete_rpath and -rpath
938     auto It2 = find_if(Config.RPathsToRemove, Match);
939     if (It2 != Config.RPathsToRemove.end())
940       return createStringError(errc::invalid_argument,
941                                "cannot specify both -delete_rpath '" + *It2 +
942                                    "' and -rpath '" + Old + "' '" + New + "'");
943 
944     // Cannot specify the same rpath under both -add_rpath and -rpath
945     auto It3 = find_if(Config.RPathToAdd, Match);
946     if (It3 != Config.RPathToAdd.end())
947       return createStringError(errc::invalid_argument,
948                                "cannot specify both -add_rpath '" + *It3 +
949                                    "' and -rpath '" + Old + "' '" + New + "'");
950 
951     // Cannot specify the same rpath under both -prepend_rpath and -rpath.
952     auto It4 = find_if(Config.RPathToPrepend, Match);
953     if (It4 != Config.RPathToPrepend.end())
954       return createStringError(errc::invalid_argument,
955                                "cannot specify both -prepend_rpath '" + *It4 +
956                                    "' and -rpath '" + Old + "' '" + New + "'");
957 
958     Config.RPathsToUpdate.insert({Old, New});
959   }
960 
961   if (auto *Arg = InputArgs.getLastArg(INSTALL_NAME_TOOL_id)) {
962     Config.SharedLibId = Arg->getValue();
963     if (Config.SharedLibId->empty())
964       return createStringError(errc::invalid_argument,
965                                "cannot specify an empty id");
966   }
967 
968   for (auto *Arg : InputArgs.filtered(INSTALL_NAME_TOOL_change))
969     Config.InstallNamesToUpdate.insert({Arg->getValue(0), Arg->getValue(1)});
970 
971   Config.RemoveAllRpaths =
972       InputArgs.hasArg(INSTALL_NAME_TOOL_delete_all_rpaths);
973 
974   SmallVector<StringRef, 2> Positional;
975   for (auto Arg : InputArgs.filtered(INSTALL_NAME_TOOL_UNKNOWN))
976     return createStringError(errc::invalid_argument, "unknown argument '%s'",
977                              Arg->getAsString(InputArgs).c_str());
978   for (auto Arg : InputArgs.filtered(INSTALL_NAME_TOOL_INPUT))
979     Positional.push_back(Arg->getValue());
980   if (Positional.empty())
981     return createStringError(errc::invalid_argument, "no input file specified");
982   if (Positional.size() > 1)
983     return createStringError(
984         errc::invalid_argument,
985         "llvm-install-name-tool expects a single input file");
986   Config.InputFilename = Positional[0];
987   Config.OutputFilename = Positional[0];
988 
989   DC.CopyConfigs.push_back(std::move(Config));
990   return std::move(DC);
991 }
992 
993 Expected<DriverConfig>
parseBitcodeStripOptions(ArrayRef<const char * > ArgsArr)994 parseBitcodeStripOptions(ArrayRef<const char *> ArgsArr) {
995   DriverConfig DC;
996   CopyConfig Config;
997   BitcodeStripOptTable T;
998   unsigned MissingArgumentIndex, MissingArgumentCount;
999   opt::InputArgList InputArgs =
1000       T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);
1001 
1002   if (InputArgs.size() == 0) {
1003     printHelp(T, errs(), ToolType::BitcodeStrip);
1004     exit(1);
1005   }
1006 
1007   if (InputArgs.hasArg(BITCODE_STRIP_help)) {
1008     printHelp(T, outs(), ToolType::BitcodeStrip);
1009     exit(0);
1010   }
1011 
1012   if (InputArgs.hasArg(BITCODE_STRIP_version)) {
1013     outs() << "llvm-bitcode-strip, compatible with cctools "
1014               "bitcode_strip\n";
1015     cl::PrintVersionMessage();
1016     exit(0);
1017   }
1018 
1019   for (auto *Arg : InputArgs.filtered(BITCODE_STRIP_UNKNOWN))
1020     return createStringError(errc::invalid_argument, "unknown argument '%s'",
1021                              Arg->getAsString(InputArgs).c_str());
1022 
1023   SmallVector<StringRef, 2> Positional;
1024   for (auto *Arg : InputArgs.filtered(BITCODE_STRIP_INPUT))
1025     Positional.push_back(Arg->getValue());
1026   if (Positional.size() > 1)
1027     return createStringError(errc::invalid_argument,
1028                              "llvm-bitcode-strip expects a single input file");
1029   assert(!Positional.empty());
1030   Config.InputFilename = Positional[0];
1031   Config.OutputFilename = Positional[0];
1032 
1033   DC.CopyConfigs.push_back(std::move(Config));
1034   return std::move(DC);
1035 }
1036 
1037 // ParseStripOptions returns the config and sets the input arguments. If a
1038 // help flag is set then ParseStripOptions will print the help messege and
1039 // exit.
1040 Expected<DriverConfig>
parseStripOptions(ArrayRef<const char * > ArgsArr,llvm::function_ref<Error (Error)> ErrorCallback)1041 parseStripOptions(ArrayRef<const char *> ArgsArr,
1042                   llvm::function_ref<Error(Error)> ErrorCallback) {
1043   StripOptTable T;
1044   unsigned MissingArgumentIndex, MissingArgumentCount;
1045   llvm::opt::InputArgList InputArgs =
1046       T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);
1047 
1048   if (InputArgs.size() == 0) {
1049     printHelp(T, errs(), ToolType::Strip);
1050     exit(1);
1051   }
1052 
1053   if (InputArgs.hasArg(STRIP_help)) {
1054     printHelp(T, outs(), ToolType::Strip);
1055     exit(0);
1056   }
1057 
1058   if (InputArgs.hasArg(STRIP_version)) {
1059     outs() << "llvm-strip, compatible with GNU strip\n";
1060     cl::PrintVersionMessage();
1061     exit(0);
1062   }
1063 
1064   SmallVector<StringRef, 2> Positional;
1065   for (auto Arg : InputArgs.filtered(STRIP_UNKNOWN))
1066     return createStringError(errc::invalid_argument, "unknown argument '%s'",
1067                              Arg->getAsString(InputArgs).c_str());
1068   for (auto Arg : InputArgs.filtered(STRIP_INPUT))
1069     Positional.push_back(Arg->getValue());
1070 
1071   if (Positional.empty())
1072     return createStringError(errc::invalid_argument, "no input file specified");
1073 
1074   if (Positional.size() > 1 && InputArgs.hasArg(STRIP_output))
1075     return createStringError(
1076         errc::invalid_argument,
1077         "multiple input files cannot be used in combination with -o");
1078 
1079   CopyConfig Config;
1080 
1081   if (InputArgs.hasArg(STRIP_regex) && InputArgs.hasArg(STRIP_wildcard))
1082     return createStringError(errc::invalid_argument,
1083                              "--regex and --wildcard are incompatible");
1084   MatchStyle SectionMatchStyle =
1085       InputArgs.hasArg(STRIP_regex) ? MatchStyle::Regex : MatchStyle::Wildcard;
1086   MatchStyle SymbolMatchStyle = InputArgs.hasArg(STRIP_regex)
1087                                     ? MatchStyle::Regex
1088                                     : InputArgs.hasArg(STRIP_wildcard)
1089                                           ? MatchStyle::Wildcard
1090                                           : MatchStyle::Literal;
1091   Config.AllowBrokenLinks = InputArgs.hasArg(STRIP_allow_broken_links);
1092   Config.StripDebug = InputArgs.hasArg(STRIP_strip_debug);
1093 
1094   if (InputArgs.hasArg(STRIP_discard_all, STRIP_discard_locals))
1095     Config.DiscardMode =
1096         InputArgs.hasFlag(STRIP_discard_all, STRIP_discard_locals)
1097             ? DiscardType::All
1098             : DiscardType::Locals;
1099   Config.StripSections = InputArgs.hasArg(STRIP_strip_sections);
1100   Config.StripUnneeded = InputArgs.hasArg(STRIP_strip_unneeded);
1101   if (auto Arg = InputArgs.getLastArg(STRIP_strip_all, STRIP_no_strip_all))
1102     Config.StripAll = Arg->getOption().getID() == STRIP_strip_all;
1103   Config.StripAllGNU = InputArgs.hasArg(STRIP_strip_all_gnu);
1104   Config.StripSwiftSymbols = InputArgs.hasArg(STRIP_strip_swift_symbols);
1105   Config.OnlyKeepDebug = InputArgs.hasArg(STRIP_only_keep_debug);
1106   Config.KeepFileSymbols = InputArgs.hasArg(STRIP_keep_file_symbols);
1107 
1108   for (auto Arg : InputArgs.filtered(STRIP_keep_section))
1109     if (Error E = Config.KeepSection.addMatcher(NameOrPattern::create(
1110             Arg->getValue(), SectionMatchStyle, ErrorCallback)))
1111       return std::move(E);
1112 
1113   for (auto Arg : InputArgs.filtered(STRIP_remove_section))
1114     if (Error E = Config.ToRemove.addMatcher(NameOrPattern::create(
1115             Arg->getValue(), SectionMatchStyle, ErrorCallback)))
1116       return std::move(E);
1117 
1118   for (auto Arg : InputArgs.filtered(STRIP_strip_symbol))
1119     if (Error E = Config.SymbolsToRemove.addMatcher(NameOrPattern::create(
1120             Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
1121       return std::move(E);
1122 
1123   for (auto Arg : InputArgs.filtered(STRIP_keep_symbol))
1124     if (Error E = Config.SymbolsToKeep.addMatcher(NameOrPattern::create(
1125             Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
1126       return std::move(E);
1127 
1128   if (!InputArgs.hasArg(STRIP_no_strip_all) && !Config.StripDebug &&
1129       !Config.StripUnneeded && Config.DiscardMode == DiscardType::None &&
1130       !Config.StripAllGNU && Config.SymbolsToRemove.empty())
1131     Config.StripAll = true;
1132 
1133   if (Config.DiscardMode == DiscardType::All) {
1134     Config.StripDebug = true;
1135     Config.KeepFileSymbols = true;
1136   }
1137 
1138   Config.DeterministicArchives =
1139       InputArgs.hasFlag(STRIP_enable_deterministic_archives,
1140                         STRIP_disable_deterministic_archives, /*default=*/true);
1141 
1142   Config.PreserveDates = InputArgs.hasArg(STRIP_preserve_dates);
1143   Config.InputFormat = FileFormat::Unspecified;
1144   Config.OutputFormat = FileFormat::Unspecified;
1145 
1146   DriverConfig DC;
1147   if (Positional.size() == 1) {
1148     Config.InputFilename = Positional[0];
1149     Config.OutputFilename =
1150         InputArgs.getLastArgValue(STRIP_output, Positional[0]);
1151     DC.CopyConfigs.push_back(std::move(Config));
1152   } else {
1153     StringMap<unsigned> InputFiles;
1154     for (StringRef Filename : Positional) {
1155       if (InputFiles[Filename]++ == 1) {
1156         if (Filename == "-")
1157           return createStringError(
1158               errc::invalid_argument,
1159               "cannot specify '-' as an input file more than once");
1160         if (Error E = ErrorCallback(createStringError(
1161                 errc::invalid_argument, "'%s' was already specified",
1162                 Filename.str().c_str())))
1163           return std::move(E);
1164       }
1165       Config.InputFilename = Filename;
1166       Config.OutputFilename = Filename;
1167       DC.CopyConfigs.push_back(Config);
1168     }
1169   }
1170 
1171   if (Config.PreserveDates && (is_contained(Positional, "-") ||
1172                                InputArgs.getLastArgValue(STRIP_output) == "-"))
1173     return createStringError(errc::invalid_argument,
1174                              "--preserve-dates requires a file");
1175 
1176   return std::move(DC);
1177 }
1178 
1179 } // namespace objcopy
1180 } // namespace llvm
1181