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