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

source code of llvm/tools/llvm-objcopy/ObjcopyOptions.cpp