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