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