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