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