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