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