1 //===- CopyConfig.cpp -----------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "CopyConfig.h"
11 #include "llvm/ADT/Optional.h"
12 #include "llvm/ADT/SmallVector.h"
13 #include "llvm/ADT/StringRef.h"
14 #include "llvm/Option/Arg.h"
15 #include "llvm/Option/ArgList.h"
16 #include "llvm/Support/CommandLine.h"
17 #include "llvm/Support/Compression.h"
18 #include "llvm/Support/Errc.h"
19 #include "llvm/Support/MemoryBuffer.h"
20 #include "llvm/Support/StringSaver.h"
28 OBJCOPY_INVALID
= 0, // This is not an option ID.
29 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
30 HELPTEXT, METAVAR, VALUES) \
32 #include "ObjcopyOpts.inc"
36 #define PREFIX(NAME, VALUE) const char *const OBJCOPY_##NAME[] = VALUE;
37 #include "ObjcopyOpts.inc"
40 static const opt::OptTable::Info ObjcopyInfoTable
[] = {
41 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
42 HELPTEXT, METAVAR, VALUES) \
48 opt::Option::KIND##Class, \
55 #include "ObjcopyOpts.inc"
59 class ObjcopyOptTable
: public opt::OptTable
{
61 ObjcopyOptTable() : OptTable(ObjcopyInfoTable
) {}
65 STRIP_INVALID
= 0, // This is not an option ID.
66 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
67 HELPTEXT, METAVAR, VALUES) \
69 #include "StripOpts.inc"
73 #define PREFIX(NAME, VALUE) const char *const STRIP_##NAME[] = VALUE;
74 #include "StripOpts.inc"
77 static const opt::OptTable::Info StripInfoTable
[] = {
78 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
79 HELPTEXT, METAVAR, VALUES) \
80 {STRIP_##PREFIX, NAME, HELPTEXT, \
81 METAVAR, STRIP_##ID, opt::Option::KIND##Class, \
82 PARAM, FLAGS, STRIP_##GROUP, \
83 STRIP_##ALIAS, ALIASARGS, VALUES},
84 #include "StripOpts.inc"
88 class StripOptTable
: public opt::OptTable
{
90 StripOptTable() : OptTable(StripInfoTable
) {}
95 static SectionFlag
parseSectionRenameFlag(StringRef SectionName
) {
96 return llvm::StringSwitch
<SectionFlag
>(SectionName
)
97 .CaseLower("alloc", SectionFlag::SecAlloc
)
98 .CaseLower("load", SectionFlag::SecLoad
)
99 .CaseLower("noload", SectionFlag::SecNoload
)
100 .CaseLower("readonly", SectionFlag::SecReadonly
)
101 .CaseLower("debug", SectionFlag::SecDebug
)
102 .CaseLower("code", SectionFlag::SecCode
)
103 .CaseLower("data", SectionFlag::SecData
)
104 .CaseLower("rom", SectionFlag::SecRom
)
105 .CaseLower("merge", SectionFlag::SecMerge
)
106 .CaseLower("strings", SectionFlag::SecStrings
)
107 .CaseLower("contents", SectionFlag::SecContents
)
108 .CaseLower("share", SectionFlag::SecShare
)
109 .Default(SectionFlag::SecNone
);
112 static Expected
<SectionFlag
>
113 parseSectionFlagSet(ArrayRef
<StringRef
> SectionFlags
) {
114 SectionFlag ParsedFlags
= SectionFlag::SecNone
;
115 for (StringRef Flag
: SectionFlags
) {
116 SectionFlag ParsedFlag
= parseSectionRenameFlag(Flag
);
117 if (ParsedFlag
== SectionFlag::SecNone
)
118 return createStringError(
119 errc::invalid_argument
,
120 "Unrecognized section flag '%s'. Flags supported for GNU "
121 "compatibility: alloc, load, noload, readonly, debug, code, data, "
122 "rom, share, contents, merge, strings",
124 ParsedFlags
|= ParsedFlag
;
130 static Expected
<SectionRename
> parseRenameSectionValue(StringRef FlagValue
) {
131 if (!FlagValue
.contains('='))
132 return createStringError(errc::invalid_argument
,
133 "Bad format for --rename-section: missing '='");
135 // Initial split: ".foo" = ".bar,f1,f2,..."
136 auto Old2New
= FlagValue
.split('=');
138 SR
.OriginalName
= Old2New
.first
;
140 // Flags split: ".bar" "f1" "f2" ...
141 SmallVector
<StringRef
, 6> NameAndFlags
;
142 Old2New
.second
.split(NameAndFlags
, ',');
143 SR
.NewName
= NameAndFlags
[0];
145 if (NameAndFlags
.size() > 1) {
146 Expected
<SectionFlag
> ParsedFlagSet
=
147 parseSectionFlagSet(makeArrayRef(NameAndFlags
).drop_front());
149 return ParsedFlagSet
.takeError();
150 SR
.NewFlags
= *ParsedFlagSet
;
156 static Expected
<SectionFlagsUpdate
>
157 parseSetSectionFlagValue(StringRef FlagValue
) {
158 if (!StringRef(FlagValue
).contains('='))
159 return createStringError(errc::invalid_argument
,
160 "Bad format for --set-section-flags: missing '='");
162 // Initial split: ".foo" = "f1,f2,..."
163 auto Section2Flags
= StringRef(FlagValue
).split('=');
164 SectionFlagsUpdate SFU
;
165 SFU
.Name
= Section2Flags
.first
;
167 // Flags split: "f1" "f2" ...
168 SmallVector
<StringRef
, 6> SectionFlags
;
169 Section2Flags
.second
.split(SectionFlags
, ',');
170 Expected
<SectionFlag
> ParsedFlagSet
= parseSectionFlagSet(SectionFlags
);
172 return ParsedFlagSet
.takeError();
173 SFU
.NewFlags
= *ParsedFlagSet
;
178 static Expected
<NewSymbolInfo
> parseNewSymbolInfo(StringRef FlagValue
) {
179 // Parse value given with --add-symbol option and create the
180 // new symbol if possible. The value format for --add-symbol is:
182 // <name>=[<section>:]<value>[,<flags>]
185 // <name> - symbol name, can be empty string
186 // <section> - optional section name. If not given ABS symbol is created
187 // <value> - symbol value, can be decimal or hexadecimal number prefixed
189 // <flags> - optional flags affecting symbol type, binding or visibility:
190 // The following are currently supported:
192 // global, local, weak, default, hidden, file, section, object,
193 // indirect-function.
195 // The following flags are ignored and provided for GNU
196 // compatibility only:
198 // warning, debug, constructor, indirect, synthetic,
199 // unique-object, before=<symbol>.
202 std::tie(SI
.SymbolName
, Value
) = FlagValue
.split('=');
204 return createStringError(
205 errc::invalid_argument
,
206 "bad format for --add-symbol, missing '=' after '%s'",
207 SI
.SymbolName
.str().c_str());
209 if (Value
.contains(':')) {
210 std::tie(SI
.SectionName
, Value
) = Value
.split(':');
211 if (SI
.SectionName
.empty() || Value
.empty())
212 return createStringError(
213 errc::invalid_argument
,
214 "bad format for --add-symbol, missing section name or symbol value");
217 SmallVector
<StringRef
, 6> Flags
;
218 Value
.split(Flags
, ',');
219 if (Flags
[0].getAsInteger(0, SI
.Value
))
220 return createStringError(errc::invalid_argument
, "bad symbol value: '%s'",
221 Flags
[0].str().c_str());
223 using Functor
= std::function
<void(void)>;
224 SmallVector
<StringRef
, 6> UnsupportedFlags
;
225 for (size_t I
= 1, NumFlags
= Flags
.size(); I
< NumFlags
; ++I
)
226 static_cast<Functor
>(
227 StringSwitch
<Functor
>(Flags
[I
])
228 .CaseLower("global", [&SI
] { SI
.Bind
= ELF::STB_GLOBAL
; })
229 .CaseLower("local", [&SI
] { SI
.Bind
= ELF::STB_LOCAL
; })
230 .CaseLower("weak", [&SI
] { SI
.Bind
= ELF::STB_WEAK
; })
231 .CaseLower("default", [&SI
] { SI
.Visibility
= ELF::STV_DEFAULT
; })
232 .CaseLower("hidden", [&SI
] { SI
.Visibility
= ELF::STV_HIDDEN
; })
233 .CaseLower("file", [&SI
] { SI
.Type
= ELF::STT_FILE
; })
234 .CaseLower("section", [&SI
] { SI
.Type
= ELF::STT_SECTION
; })
235 .CaseLower("object", [&SI
] { SI
.Type
= ELF::STT_OBJECT
; })
236 .CaseLower("function", [&SI
] { SI
.Type
= ELF::STT_FUNC
; })
237 .CaseLower("indirect-function",
238 [&SI
] { SI
.Type
= ELF::STT_GNU_IFUNC
; })
239 .CaseLower("debug", [] {})
240 .CaseLower("constructor", [] {})
241 .CaseLower("warning", [] {})
242 .CaseLower("indirect", [] {})
243 .CaseLower("synthetic", [] {})
244 .CaseLower("unique-object", [] {})
245 .StartsWithLower("before", [] {})
246 .Default([&] { UnsupportedFlags
.push_back(Flags
[I
]); }))();
247 if (!UnsupportedFlags
.empty())
248 return createStringError(errc::invalid_argument
,
249 "unsupported flag%s for --add-symbol: '%s'",
250 UnsupportedFlags
.size() > 1 ? "s" : "",
251 join(UnsupportedFlags
, "', '").c_str());
255 static const StringMap
<MachineInfo
> ArchMap
{
256 // Name, {EMachine, OS/ABI, 64bit, LittleEndian}
257 {"aarch64", {ELF::EM_AARCH64
, ELF::ELFOSABI_NONE
, true, true}},
258 {"arm", {ELF::EM_ARM
, ELF::ELFOSABI_NONE
, false, true}},
259 {"i386", {ELF::EM_386
, ELF::ELFOSABI_NONE
, false, true}},
260 {"i386:x86-64", {ELF::EM_X86_64
, ELF::ELFOSABI_NONE
, true, true}},
261 {"powerpc:common64", {ELF::EM_PPC64
, ELF::ELFOSABI_NONE
, true, true}},
262 {"sparc", {ELF::EM_SPARC
, ELF::ELFOSABI_NONE
, false, true}},
263 {"x86-64", {ELF::EM_X86_64
, ELF::ELFOSABI_NONE
, true, true}},
266 static Expected
<const MachineInfo
&> getMachineInfo(StringRef Arch
) {
267 auto Iter
= ArchMap
.find(Arch
);
268 if (Iter
== std::end(ArchMap
))
269 return createStringError(errc::invalid_argument
,
270 "Invalid architecture: '%s'", Arch
.str().c_str());
271 return Iter
->getValue();
274 static const StringMap
<MachineInfo
> OutputFormatMap
{
275 // Name, {EMachine, OSABI, 64bit, LittleEndian}
276 {"elf32-i386", {ELF::EM_386
, ELF::ELFOSABI_NONE
, false, true}},
277 {"elf32-i386-freebsd", {ELF::EM_386
, ELF::ELFOSABI_FREEBSD
, false, true}},
278 {"elf32-powerpcle", {ELF::EM_PPC
, ELF::ELFOSABI_NONE
, false, true}},
279 {"elf32-x86-64", {ELF::EM_X86_64
, ELF::ELFOSABI_NONE
, false, true}},
280 {"elf64-powerpcle", {ELF::EM_PPC64
, ELF::ELFOSABI_NONE
, true, true}},
281 {"elf64-x86-64", {ELF::EM_X86_64
, ELF::ELFOSABI_NONE
, true, true}},
282 {"elf64-x86-64-freebsd",
283 {ELF::EM_X86_64
, ELF::ELFOSABI_FREEBSD
, true, true}},
286 static Expected
<const MachineInfo
&>
287 getOutputFormatMachineInfo(StringRef Format
) {
288 auto Iter
= OutputFormatMap
.find(Format
);
289 if (Iter
== std::end(OutputFormatMap
))
290 return createStringError(errc::invalid_argument
,
291 "Invalid output format: '%s'",
292 Format
.str().c_str());
293 return Iter
->getValue();
296 static Error
addSymbolsFromFile(std::vector
<NameOrRegex
> &Symbols
,
297 BumpPtrAllocator
&Alloc
, StringRef Filename
,
299 StringSaver
Saver(Alloc
);
300 SmallVector
<StringRef
, 16> Lines
;
301 auto BufOrErr
= MemoryBuffer::getFile(Filename
);
303 return createFileError(Filename
, BufOrErr
.getError());
305 BufOrErr
.get()->getBuffer().split(Lines
, '\n');
306 for (StringRef Line
: Lines
) {
307 // Ignore everything after '#', trim whitespace, and only add the symbol if
309 auto TrimmedLine
= Line
.split('#').first
.trim();
310 if (!TrimmedLine
.empty())
311 Symbols
.emplace_back(Saver
.save(TrimmedLine
), UseRegex
);
314 return Error::success();
317 NameOrRegex::NameOrRegex(StringRef Pattern
, bool IsRegex
) {
323 SmallVector
<char, 32> Data
;
324 R
= std::make_shared
<Regex
>(
325 ("^" + Pattern
.ltrim('^').rtrim('$') + "$").toStringRef(Data
));
328 static Error
addSymbolsToRenameFromFile(StringMap
<StringRef
> &SymbolsToRename
,
329 BumpPtrAllocator
&Alloc
,
330 StringRef Filename
) {
331 StringSaver
Saver(Alloc
);
332 SmallVector
<StringRef
, 16> Lines
;
333 auto BufOrErr
= MemoryBuffer::getFile(Filename
);
335 return createFileError(Filename
, BufOrErr
.getError());
337 BufOrErr
.get()->getBuffer().split(Lines
, '\n');
338 size_t NumLines
= Lines
.size();
339 for (size_t LineNo
= 0; LineNo
< NumLines
; ++LineNo
) {
340 StringRef TrimmedLine
= Lines
[LineNo
].split('#').first
.trim();
341 if (TrimmedLine
.empty())
344 std::pair
<StringRef
, StringRef
> Pair
= Saver
.save(TrimmedLine
).split(' ');
345 StringRef NewName
= Pair
.second
.trim();
347 return createStringError(errc::invalid_argument
,
348 "%s:%zu: missing new symbol name",
349 Filename
.str().c_str(), LineNo
+ 1);
350 SymbolsToRename
.insert({Pair
.first
, NewName
});
352 return Error::success();
355 template <class T
> static ErrorOr
<T
> getAsInteger(StringRef Val
) {
357 if (Val
.getAsInteger(0, Result
))
358 return errc::invalid_argument
;
362 // ParseObjcopyOptions returns the config and sets the input arguments. If a
363 // help flag is set then ParseObjcopyOptions will print the help messege and
365 Expected
<DriverConfig
> parseObjcopyOptions(ArrayRef
<const char *> ArgsArr
) {
368 unsigned MissingArgumentIndex
, MissingArgumentCount
;
369 llvm::opt::InputArgList InputArgs
=
370 T
.ParseArgs(ArgsArr
, MissingArgumentIndex
, MissingArgumentCount
);
372 if (InputArgs
.size() == 0) {
373 T
.PrintHelp(errs(), "llvm-objcopy input [output]", "objcopy tool");
377 if (InputArgs
.hasArg(OBJCOPY_help
)) {
378 T
.PrintHelp(outs(), "llvm-objcopy input [output]", "objcopy tool");
382 if (InputArgs
.hasArg(OBJCOPY_version
)) {
383 outs() << "llvm-objcopy, compatible with GNU objcopy\n";
384 cl::PrintVersionMessage();
388 SmallVector
<const char *, 2> Positional
;
390 for (auto Arg
: InputArgs
.filtered(OBJCOPY_UNKNOWN
))
391 return createStringError(errc::invalid_argument
, "unknown argument '%s'",
392 Arg
->getAsString(InputArgs
).c_str());
394 for (auto Arg
: InputArgs
.filtered(OBJCOPY_INPUT
))
395 Positional
.push_back(Arg
->getValue());
397 if (Positional
.empty())
398 return createStringError(errc::invalid_argument
, "No input file specified");
400 if (Positional
.size() > 2)
401 return createStringError(errc::invalid_argument
,
402 "Too many positional arguments");
405 Config
.InputFilename
= Positional
[0];
406 Config
.OutputFilename
= Positional
[Positional
.size() == 1 ? 0 : 1];
407 if (InputArgs
.hasArg(OBJCOPY_target
) &&
408 (InputArgs
.hasArg(OBJCOPY_input_target
) ||
409 InputArgs
.hasArg(OBJCOPY_output_target
)))
410 return createStringError(
411 errc::invalid_argument
,
412 "--target cannot be used with --input-target or --output-target");
414 bool UseRegex
= InputArgs
.hasArg(OBJCOPY_regex
);
415 if (InputArgs
.hasArg(OBJCOPY_target
)) {
416 Config
.InputFormat
= InputArgs
.getLastArgValue(OBJCOPY_target
);
417 Config
.OutputFormat
= InputArgs
.getLastArgValue(OBJCOPY_target
);
419 Config
.InputFormat
= InputArgs
.getLastArgValue(OBJCOPY_input_target
);
420 Config
.OutputFormat
= InputArgs
.getLastArgValue(OBJCOPY_output_target
);
422 if (Config
.InputFormat
== "binary") {
423 auto BinaryArch
= InputArgs
.getLastArgValue(OBJCOPY_binary_architecture
);
424 if (BinaryArch
.empty())
425 return createStringError(
426 errc::invalid_argument
,
427 "Specified binary input without specifiying an architecture");
428 Expected
<const MachineInfo
&> MI
= getMachineInfo(BinaryArch
);
430 return MI
.takeError();
431 Config
.BinaryArch
= *MI
;
433 if (!Config
.OutputFormat
.empty() && Config
.OutputFormat
!= "binary") {
434 Expected
<const MachineInfo
&> MI
=
435 getOutputFormatMachineInfo(Config
.OutputFormat
);
437 return MI
.takeError();
438 Config
.OutputArch
= *MI
;
441 if (auto Arg
= InputArgs
.getLastArg(OBJCOPY_compress_debug_sections
,
442 OBJCOPY_compress_debug_sections_eq
)) {
443 Config
.CompressionType
= DebugCompressionType::Z
;
445 if (Arg
->getOption().getID() == OBJCOPY_compress_debug_sections_eq
) {
446 Config
.CompressionType
=
447 StringSwitch
<DebugCompressionType
>(
448 InputArgs
.getLastArgValue(OBJCOPY_compress_debug_sections_eq
))
449 .Case("zlib-gnu", DebugCompressionType::GNU
)
450 .Case("zlib", DebugCompressionType::Z
)
451 .Default(DebugCompressionType::None
);
452 if (Config
.CompressionType
== DebugCompressionType::None
)
453 return createStringError(
454 errc::invalid_argument
,
455 "Invalid or unsupported --compress-debug-sections format: %s",
456 InputArgs
.getLastArgValue(OBJCOPY_compress_debug_sections_eq
)
460 if (!zlib::isAvailable())
461 return createStringError(
462 errc::invalid_argument
,
463 "LLVM was not compiled with LLVM_ENABLE_ZLIB: can not compress");
466 Config
.AddGnuDebugLink
= InputArgs
.getLastArgValue(OBJCOPY_add_gnu_debuglink
);
467 Config
.BuildIdLinkDir
= InputArgs
.getLastArgValue(OBJCOPY_build_id_link_dir
);
468 if (InputArgs
.hasArg(OBJCOPY_build_id_link_input
))
469 Config
.BuildIdLinkInput
=
470 InputArgs
.getLastArgValue(OBJCOPY_build_id_link_input
);
471 if (InputArgs
.hasArg(OBJCOPY_build_id_link_output
))
472 Config
.BuildIdLinkOutput
=
473 InputArgs
.getLastArgValue(OBJCOPY_build_id_link_output
);
474 Config
.SplitDWO
= InputArgs
.getLastArgValue(OBJCOPY_split_dwo
);
475 Config
.SymbolsPrefix
= InputArgs
.getLastArgValue(OBJCOPY_prefix_symbols
);
477 for (auto Arg
: InputArgs
.filtered(OBJCOPY_redefine_symbol
)) {
478 if (!StringRef(Arg
->getValue()).contains('='))
479 return createStringError(errc::invalid_argument
,
480 "Bad format for --redefine-sym");
481 auto Old2New
= StringRef(Arg
->getValue()).split('=');
482 if (!Config
.SymbolsToRename
.insert(Old2New
).second
)
483 return createStringError(errc::invalid_argument
,
484 "Multiple redefinition of symbol %s",
485 Old2New
.first
.str().c_str());
488 for (auto Arg
: InputArgs
.filtered(OBJCOPY_redefine_symbols
))
489 if (Error E
= addSymbolsToRenameFromFile(Config
.SymbolsToRename
, DC
.Alloc
,
493 for (auto Arg
: InputArgs
.filtered(OBJCOPY_rename_section
)) {
494 Expected
<SectionRename
> SR
=
495 parseRenameSectionValue(StringRef(Arg
->getValue()));
497 return SR
.takeError();
498 if (!Config
.SectionsToRename
.try_emplace(SR
->OriginalName
, *SR
).second
)
499 return createStringError(errc::invalid_argument
,
500 "Multiple renames of section %s",
501 SR
->OriginalName
.str().c_str());
503 for (auto Arg
: InputArgs
.filtered(OBJCOPY_set_section_flags
)) {
504 Expected
<SectionFlagsUpdate
> SFU
=
505 parseSetSectionFlagValue(Arg
->getValue());
507 return SFU
.takeError();
508 if (!Config
.SetSectionFlags
.try_emplace(SFU
->Name
, *SFU
).second
)
509 return createStringError(
510 errc::invalid_argument
,
511 "--set-section-flags set multiple times for section %s",
512 SFU
->Name
.str().c_str());
514 // Prohibit combinations of --set-section-flags when the section name is used
515 // by --rename-section, either as a source or a destination.
516 for (const auto &E
: Config
.SectionsToRename
) {
517 const SectionRename
&SR
= E
.second
;
518 if (Config
.SetSectionFlags
.count(SR
.OriginalName
))
519 return createStringError(
520 errc::invalid_argument
,
521 "--set-section-flags=%s conflicts with --rename-section=%s=%s",
522 SR
.OriginalName
.str().c_str(), SR
.OriginalName
.str().c_str(),
523 SR
.NewName
.str().c_str());
524 if (Config
.SetSectionFlags
.count(SR
.NewName
))
525 return createStringError(
526 errc::invalid_argument
,
527 "--set-section-flags=%s conflicts with --rename-section=%s=%s",
528 SR
.NewName
.str().c_str(), SR
.OriginalName
.str().c_str(),
529 SR
.NewName
.str().c_str());
532 for (auto Arg
: InputArgs
.filtered(OBJCOPY_remove_section
))
533 Config
.ToRemove
.emplace_back(Arg
->getValue(), UseRegex
);
534 for (auto Arg
: InputArgs
.filtered(OBJCOPY_keep_section
))
535 Config
.KeepSection
.emplace_back(Arg
->getValue(), UseRegex
);
536 for (auto Arg
: InputArgs
.filtered(OBJCOPY_only_section
))
537 Config
.OnlySection
.emplace_back(Arg
->getValue(), UseRegex
);
538 for (auto Arg
: InputArgs
.filtered(OBJCOPY_add_section
))
539 Config
.AddSection
.push_back(Arg
->getValue());
540 for (auto Arg
: InputArgs
.filtered(OBJCOPY_dump_section
))
541 Config
.DumpSection
.push_back(Arg
->getValue());
542 Config
.StripAll
= InputArgs
.hasArg(OBJCOPY_strip_all
);
543 Config
.StripAllGNU
= InputArgs
.hasArg(OBJCOPY_strip_all_gnu
);
544 Config
.StripDebug
= InputArgs
.hasArg(OBJCOPY_strip_debug
);
545 Config
.StripDWO
= InputArgs
.hasArg(OBJCOPY_strip_dwo
);
546 Config
.StripSections
= InputArgs
.hasArg(OBJCOPY_strip_sections
);
547 Config
.StripNonAlloc
= InputArgs
.hasArg(OBJCOPY_strip_non_alloc
);
548 Config
.StripUnneeded
= InputArgs
.hasArg(OBJCOPY_strip_unneeded
);
549 Config
.ExtractDWO
= InputArgs
.hasArg(OBJCOPY_extract_dwo
);
550 Config
.LocalizeHidden
= InputArgs
.hasArg(OBJCOPY_localize_hidden
);
551 Config
.Weaken
= InputArgs
.hasArg(OBJCOPY_weaken
);
552 if (InputArgs
.hasArg(OBJCOPY_discard_all
, OBJCOPY_discard_locals
))
554 InputArgs
.hasFlag(OBJCOPY_discard_all
, OBJCOPY_discard_locals
)
556 : DiscardType::Locals
;
557 Config
.OnlyKeepDebug
= InputArgs
.hasArg(OBJCOPY_only_keep_debug
);
558 Config
.KeepFileSymbols
= InputArgs
.hasArg(OBJCOPY_keep_file_symbols
);
559 Config
.DecompressDebugSections
=
560 InputArgs
.hasArg(OBJCOPY_decompress_debug_sections
);
561 for (auto Arg
: InputArgs
.filtered(OBJCOPY_localize_symbol
))
562 Config
.SymbolsToLocalize
.emplace_back(Arg
->getValue(), UseRegex
);
563 for (auto Arg
: InputArgs
.filtered(OBJCOPY_localize_symbols
))
564 if (Error E
= addSymbolsFromFile(Config
.SymbolsToLocalize
, DC
.Alloc
,
565 Arg
->getValue(), UseRegex
))
567 for (auto Arg
: InputArgs
.filtered(OBJCOPY_keep_global_symbol
))
568 Config
.SymbolsToKeepGlobal
.emplace_back(Arg
->getValue(), UseRegex
);
569 for (auto Arg
: InputArgs
.filtered(OBJCOPY_keep_global_symbols
))
570 if (Error E
= addSymbolsFromFile(Config
.SymbolsToKeepGlobal
, DC
.Alloc
,
571 Arg
->getValue(), UseRegex
))
573 for (auto Arg
: InputArgs
.filtered(OBJCOPY_globalize_symbol
))
574 Config
.SymbolsToGlobalize
.emplace_back(Arg
->getValue(), UseRegex
);
575 for (auto Arg
: InputArgs
.filtered(OBJCOPY_globalize_symbols
))
576 if (Error E
= addSymbolsFromFile(Config
.SymbolsToGlobalize
, DC
.Alloc
,
577 Arg
->getValue(), UseRegex
))
579 for (auto Arg
: InputArgs
.filtered(OBJCOPY_weaken_symbol
))
580 Config
.SymbolsToWeaken
.emplace_back(Arg
->getValue(), UseRegex
);
581 for (auto Arg
: InputArgs
.filtered(OBJCOPY_weaken_symbols
))
582 if (Error E
= addSymbolsFromFile(Config
.SymbolsToWeaken
, DC
.Alloc
,
583 Arg
->getValue(), UseRegex
))
585 for (auto Arg
: InputArgs
.filtered(OBJCOPY_strip_symbol
))
586 Config
.SymbolsToRemove
.emplace_back(Arg
->getValue(), UseRegex
);
587 for (auto Arg
: InputArgs
.filtered(OBJCOPY_strip_symbols
))
588 if (Error E
= addSymbolsFromFile(Config
.SymbolsToRemove
, DC
.Alloc
,
589 Arg
->getValue(), UseRegex
))
591 for (auto Arg
: InputArgs
.filtered(OBJCOPY_strip_unneeded_symbol
))
592 Config
.UnneededSymbolsToRemove
.emplace_back(Arg
->getValue(), UseRegex
);
593 for (auto Arg
: InputArgs
.filtered(OBJCOPY_strip_unneeded_symbols
))
594 if (Error E
= addSymbolsFromFile(Config
.UnneededSymbolsToRemove
, DC
.Alloc
,
595 Arg
->getValue(), UseRegex
))
597 for (auto Arg
: InputArgs
.filtered(OBJCOPY_keep_symbol
))
598 Config
.SymbolsToKeep
.emplace_back(Arg
->getValue(), UseRegex
);
599 for (auto Arg
: InputArgs
.filtered(OBJCOPY_keep_symbols
))
600 if (Error E
= addSymbolsFromFile(Config
.SymbolsToKeep
, DC
.Alloc
,
601 Arg
->getValue(), UseRegex
))
603 for (auto Arg
: InputArgs
.filtered(OBJCOPY_add_symbol
)) {
604 Expected
<NewSymbolInfo
> NSI
= parseNewSymbolInfo(Arg
->getValue());
606 return NSI
.takeError();
607 Config
.SymbolsToAdd
.push_back(*NSI
);
610 Config
.DeterministicArchives
= InputArgs
.hasFlag(
611 OBJCOPY_enable_deterministic_archives
,
612 OBJCOPY_disable_deterministic_archives
, /*default=*/true);
614 Config
.PreserveDates
= InputArgs
.hasArg(OBJCOPY_preserve_dates
);
616 for (auto Arg
: InputArgs
)
617 if (Arg
->getOption().matches(OBJCOPY_set_start
)) {
618 auto EAddr
= getAsInteger
<uint64_t>(Arg
->getValue());
620 return createStringError(
621 EAddr
.getError(), "bad entry point address: '%s'", Arg
->getValue());
623 Config
.EntryExpr
= [EAddr
](uint64_t) { return *EAddr
; };
624 } else if (Arg
->getOption().matches(OBJCOPY_change_start
)) {
625 auto EIncr
= getAsInteger
<int64_t>(Arg
->getValue());
627 return createStringError(EIncr
.getError(),
628 "bad entry point increment: '%s'",
630 auto Expr
= Config
.EntryExpr
? std::move(Config
.EntryExpr
)
631 : [](uint64_t A
) { return A
; };
632 Config
.EntryExpr
= [Expr
, EIncr
](uint64_t EAddr
) {
633 return Expr(EAddr
) + *EIncr
;
637 if (Config
.DecompressDebugSections
&&
638 Config
.CompressionType
!= DebugCompressionType::None
) {
639 return createStringError(
640 errc::invalid_argument
,
641 "Cannot specify --compress-debug-sections at the same time as "
642 "--decompress-debug-sections at the same time");
645 if (Config
.DecompressDebugSections
&& !zlib::isAvailable())
646 return createStringError(
647 errc::invalid_argument
,
648 "LLVM was not compiled with LLVM_ENABLE_ZLIB: cannot decompress");
650 DC
.CopyConfigs
.push_back(std::move(Config
));
651 return std::move(DC
);
654 // ParseStripOptions returns the config and sets the input arguments. If a
655 // help flag is set then ParseStripOptions will print the help messege and
657 Expected
<DriverConfig
> parseStripOptions(ArrayRef
<const char *> ArgsArr
) {
659 unsigned MissingArgumentIndex
, MissingArgumentCount
;
660 llvm::opt::InputArgList InputArgs
=
661 T
.ParseArgs(ArgsArr
, MissingArgumentIndex
, MissingArgumentCount
);
663 if (InputArgs
.size() == 0) {
664 T
.PrintHelp(errs(), "llvm-strip [options] file...", "strip tool");
668 if (InputArgs
.hasArg(STRIP_help
)) {
669 T
.PrintHelp(outs(), "llvm-strip [options] file...", "strip tool");
673 if (InputArgs
.hasArg(STRIP_version
)) {
674 outs() << "llvm-strip, compatible with GNU strip\n";
675 cl::PrintVersionMessage();
679 SmallVector
<const char *, 2> Positional
;
680 for (auto Arg
: InputArgs
.filtered(STRIP_UNKNOWN
))
681 return createStringError(errc::invalid_argument
, "unknown argument '%s'",
682 Arg
->getAsString(InputArgs
).c_str());
683 for (auto Arg
: InputArgs
.filtered(STRIP_INPUT
))
684 Positional
.push_back(Arg
->getValue());
686 if (Positional
.empty())
687 return createStringError(errc::invalid_argument
, "No input file specified");
689 if (Positional
.size() > 1 && InputArgs
.hasArg(STRIP_output
))
690 return createStringError(
691 errc::invalid_argument
,
692 "Multiple input files cannot be used in combination with -o");
695 bool UseRegexp
= InputArgs
.hasArg(STRIP_regex
);
696 Config
.StripDebug
= InputArgs
.hasArg(STRIP_strip_debug
);
698 if (InputArgs
.hasArg(STRIP_discard_all
, STRIP_discard_locals
))
700 InputArgs
.hasFlag(STRIP_discard_all
, STRIP_discard_locals
)
702 : DiscardType::Locals
;
703 Config
.StripUnneeded
= InputArgs
.hasArg(STRIP_strip_unneeded
);
704 Config
.StripAll
= InputArgs
.hasArg(STRIP_strip_all
);
705 Config
.StripAllGNU
= InputArgs
.hasArg(STRIP_strip_all_gnu
);
706 Config
.OnlyKeepDebug
= InputArgs
.hasArg(STRIP_only_keep_debug
);
707 Config
.KeepFileSymbols
= InputArgs
.hasArg(STRIP_keep_file_symbols
);
709 for (auto Arg
: InputArgs
.filtered(STRIP_keep_section
))
710 Config
.KeepSection
.emplace_back(Arg
->getValue(), UseRegexp
);
712 for (auto Arg
: InputArgs
.filtered(STRIP_remove_section
))
713 Config
.ToRemove
.emplace_back(Arg
->getValue(), UseRegexp
);
715 for (auto Arg
: InputArgs
.filtered(STRIP_strip_symbol
))
716 Config
.SymbolsToRemove
.emplace_back(Arg
->getValue(), UseRegexp
);
718 for (auto Arg
: InputArgs
.filtered(STRIP_keep_symbol
))
719 Config
.SymbolsToKeep
.emplace_back(Arg
->getValue(), UseRegexp
);
721 if (!Config
.StripDebug
&& !Config
.StripUnneeded
&&
722 Config
.DiscardMode
== DiscardType::None
&& !Config
.StripAllGNU
&& Config
.SymbolsToRemove
.empty())
723 Config
.StripAll
= true;
725 Config
.DeterministicArchives
=
726 InputArgs
.hasFlag(STRIP_enable_deterministic_archives
,
727 STRIP_disable_deterministic_archives
, /*default=*/true);
729 Config
.PreserveDates
= InputArgs
.hasArg(STRIP_preserve_dates
);
732 if (Positional
.size() == 1) {
733 Config
.InputFilename
= Positional
[0];
734 Config
.OutputFilename
=
735 InputArgs
.getLastArgValue(STRIP_output
, Positional
[0]);
736 DC
.CopyConfigs
.push_back(std::move(Config
));
738 for (const char *Filename
: Positional
) {
739 Config
.InputFilename
= Filename
;
740 Config
.OutputFilename
= Filename
;
741 DC
.CopyConfigs
.push_back(Config
);
745 return std::move(DC
);
748 } // namespace objcopy