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