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