blob: 917219625032f80e193302ca2b4c4ceee40d5ce3 [file] [log] [blame]
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +00001//===- CopyConfig.cpp -----------------------------------------------------===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +00006//
7//===----------------------------------------------------------------------===//
8
9#include "CopyConfig.h"
10#include "llvm-objcopy.h"
11
12#include "llvm/ADT/BitmaskEnum.h"
13#include "llvm/ADT/Optional.h"
14#include "llvm/ADT/SmallVector.h"
15#include "llvm/ADT/StringRef.h"
16#include "llvm/Object/ELFTypes.h"
17#include "llvm/Option/Arg.h"
18#include "llvm/Option/ArgList.h"
19#include "llvm/Support/CommandLine.h"
20#include "llvm/Support/Compression.h"
21#include "llvm/Support/MemoryBuffer.h"
Jordan Rupprecht5745c5f2019-02-04 18:38:00 +000022#include "llvm/Support/StringSaver.h"
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +000023#include <memory>
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +000024
25namespace llvm {
26namespace objcopy {
27
28namespace {
29enum ObjcopyID {
30 OBJCOPY_INVALID = 0, // This is not an option ID.
31#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
32 HELPTEXT, METAVAR, VALUES) \
33 OBJCOPY_##ID,
34#include "ObjcopyOpts.inc"
35#undef OPTION
36};
37
38#define PREFIX(NAME, VALUE) const char *const OBJCOPY_##NAME[] = VALUE;
39#include "ObjcopyOpts.inc"
40#undef PREFIX
41
42static const opt::OptTable::Info ObjcopyInfoTable[] = {
43#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
44 HELPTEXT, METAVAR, VALUES) \
45 {OBJCOPY_##PREFIX, \
46 NAME, \
47 HELPTEXT, \
48 METAVAR, \
49 OBJCOPY_##ID, \
50 opt::Option::KIND##Class, \
51 PARAM, \
52 FLAGS, \
53 OBJCOPY_##GROUP, \
54 OBJCOPY_##ALIAS, \
55 ALIASARGS, \
56 VALUES},
57#include "ObjcopyOpts.inc"
58#undef OPTION
59};
60
61class ObjcopyOptTable : public opt::OptTable {
62public:
Jordan Rupprechtaaeaa0a2018-10-23 18:46:33 +000063 ObjcopyOptTable() : OptTable(ObjcopyInfoTable) {}
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +000064};
65
66enum StripID {
67 STRIP_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 STRIP_##ID,
71#include "StripOpts.inc"
72#undef OPTION
73};
74
75#define PREFIX(NAME, VALUE) const char *const STRIP_##NAME[] = VALUE;
76#include "StripOpts.inc"
77#undef PREFIX
78
79static const opt::OptTable::Info StripInfoTable[] = {
80#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
81 HELPTEXT, METAVAR, VALUES) \
82 {STRIP_##PREFIX, NAME, HELPTEXT, \
83 METAVAR, STRIP_##ID, opt::Option::KIND##Class, \
84 PARAM, FLAGS, STRIP_##GROUP, \
85 STRIP_##ALIAS, ALIASARGS, VALUES},
86#include "StripOpts.inc"
87#undef OPTION
88};
89
90class StripOptTable : public opt::OptTable {
91public:
Jordan Rupprechtaaeaa0a2018-10-23 18:46:33 +000092 StripOptTable() : OptTable(StripInfoTable) {}
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +000093};
94
95enum SectionFlag {
96 SecNone = 0,
97 SecAlloc = 1 << 0,
98 SecLoad = 1 << 1,
99 SecNoload = 1 << 2,
100 SecReadonly = 1 << 3,
101 SecDebug = 1 << 4,
102 SecCode = 1 << 5,
103 SecData = 1 << 6,
104 SecRom = 1 << 7,
105 SecMerge = 1 << 8,
106 SecStrings = 1 << 9,
107 SecContents = 1 << 10,
108 SecShare = 1 << 11,
109 LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ SecShare)
110};
111
112} // namespace
113
114static SectionFlag parseSectionRenameFlag(StringRef SectionName) {
115 return llvm::StringSwitch<SectionFlag>(SectionName)
116 .Case("alloc", SectionFlag::SecAlloc)
117 .Case("load", SectionFlag::SecLoad)
118 .Case("noload", SectionFlag::SecNoload)
119 .Case("readonly", SectionFlag::SecReadonly)
120 .Case("debug", SectionFlag::SecDebug)
121 .Case("code", SectionFlag::SecCode)
122 .Case("data", SectionFlag::SecData)
123 .Case("rom", SectionFlag::SecRom)
124 .Case("merge", SectionFlag::SecMerge)
125 .Case("strings", SectionFlag::SecStrings)
126 .Case("contents", SectionFlag::SecContents)
127 .Case("share", SectionFlag::SecShare)
128 .Default(SectionFlag::SecNone);
129}
130
Jordan Rupprechtc8927412019-01-29 15:05:38 +0000131static uint64_t parseSectionFlagSet(ArrayRef<StringRef> SectionFlags) {
132 SectionFlag ParsedFlags = SectionFlag::SecNone;
133 for (StringRef Flag : SectionFlags) {
134 SectionFlag ParsedFlag = parseSectionRenameFlag(Flag);
135 if (ParsedFlag == SectionFlag::SecNone)
136 error("Unrecognized section flag '" + Flag +
137 "'. Flags supported for GNU compatibility: alloc, load, noload, "
138 "readonly, debug, code, data, rom, share, contents, merge, "
139 "strings.");
140 ParsedFlags |= ParsedFlag;
141 }
142
143 uint64_t NewFlags = 0;
144 if (ParsedFlags & SectionFlag::SecAlloc)
145 NewFlags |= ELF::SHF_ALLOC;
146 if (!(ParsedFlags & SectionFlag::SecReadonly))
147 NewFlags |= ELF::SHF_WRITE;
148 if (ParsedFlags & SectionFlag::SecCode)
149 NewFlags |= ELF::SHF_EXECINSTR;
150 if (ParsedFlags & SectionFlag::SecMerge)
151 NewFlags |= ELF::SHF_MERGE;
152 if (ParsedFlags & SectionFlag::SecStrings)
153 NewFlags |= ELF::SHF_STRINGS;
154 return NewFlags;
155}
156
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000157static SectionRename parseRenameSectionValue(StringRef FlagValue) {
158 if (!FlagValue.contains('='))
159 error("Bad format for --rename-section: missing '='");
160
161 // Initial split: ".foo" = ".bar,f1,f2,..."
162 auto Old2New = FlagValue.split('=');
163 SectionRename SR;
164 SR.OriginalName = Old2New.first;
165
166 // Flags split: ".bar" "f1" "f2" ...
167 SmallVector<StringRef, 6> NameAndFlags;
168 Old2New.second.split(NameAndFlags, ',');
169 SR.NewName = NameAndFlags[0];
170
Jordan Rupprechtc8927412019-01-29 15:05:38 +0000171 if (NameAndFlags.size() > 1)
172 SR.NewFlags = parseSectionFlagSet(makeArrayRef(NameAndFlags).drop_front());
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000173
174 return SR;
175}
176
Jordan Rupprechtc8927412019-01-29 15:05:38 +0000177static SectionFlagsUpdate parseSetSectionFlagValue(StringRef FlagValue) {
178 if (!StringRef(FlagValue).contains('='))
179 error("Bad format for --set-section-flags: missing '='");
180
181 // Initial split: ".foo" = "f1,f2,..."
182 auto Section2Flags = StringRef(FlagValue).split('=');
183 SectionFlagsUpdate SFU;
184 SFU.Name = Section2Flags.first;
185
186 // Flags split: "f1" "f2" ...
187 SmallVector<StringRef, 6> SectionFlags;
188 Section2Flags.second.split(SectionFlags, ',');
189 SFU.NewFlags = parseSectionFlagSet(SectionFlags);
190
191 return SFU;
192}
193
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000194static const StringMap<MachineInfo> ArchMap{
195 // Name, {EMachine, 64bit, LittleEndian}
196 {"aarch64", {ELF::EM_AARCH64, true, true}},
197 {"arm", {ELF::EM_ARM, false, true}},
198 {"i386", {ELF::EM_386, false, true}},
199 {"i386:x86-64", {ELF::EM_X86_64, true, true}},
200 {"powerpc:common64", {ELF::EM_PPC64, true, true}},
201 {"sparc", {ELF::EM_SPARC, false, true}},
202 {"x86-64", {ELF::EM_X86_64, true, true}},
203};
204
205static const MachineInfo &getMachineInfo(StringRef Arch) {
206 auto Iter = ArchMap.find(Arch);
207 if (Iter == std::end(ArchMap))
208 error("Invalid architecture: '" + Arch + "'");
209 return Iter->getValue();
210}
211
Jordan Rupprecht70038e02019-01-07 16:59:12 +0000212static const StringMap<MachineInfo> OutputFormatMap{
213 // Name, {EMachine, 64bit, LittleEndian}
214 {"elf32-i386", {ELF::EM_386, false, true}},
215 {"elf32-powerpcle", {ELF::EM_PPC, false, true}},
216 {"elf32-x86-64", {ELF::EM_X86_64, false, true}},
217 {"elf64-powerpcle", {ELF::EM_PPC64, true, true}},
218 {"elf64-x86-64", {ELF::EM_X86_64, true, true}},
219};
220
221static const MachineInfo &getOutputFormatMachineInfo(StringRef Format) {
222 auto Iter = OutputFormatMap.find(Format);
223 if (Iter == std::end(OutputFormatMap))
224 error("Invalid output format: '" + Format + "'");
225 return Iter->getValue();
226}
227
Jordan Rupprecht5745c5f2019-02-04 18:38:00 +0000228static void addGlobalSymbolsFromFile(std::vector<StringRef> &Symbols,
229 BumpPtrAllocator &Alloc,
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000230 StringRef Filename) {
Jordan Rupprecht5745c5f2019-02-04 18:38:00 +0000231 StringSaver Saver(Alloc);
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000232 SmallVector<StringRef, 16> Lines;
233 auto BufOrErr = MemoryBuffer::getFile(Filename);
234 if (!BufOrErr)
235 reportError(Filename, BufOrErr.getError());
236
237 BufOrErr.get()->getBuffer().split(Lines, '\n');
238 for (StringRef Line : Lines) {
239 // Ignore everything after '#', trim whitespace, and only add the symbol if
240 // it's not empty.
241 auto TrimmedLine = Line.split('#').first.trim();
242 if (!TrimmedLine.empty())
Jordan Rupprecht5745c5f2019-02-04 18:38:00 +0000243 Symbols.push_back(Saver.save(TrimmedLine));
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000244 }
245}
246
247// ParseObjcopyOptions returns the config and sets the input arguments. If a
248// help flag is set then ParseObjcopyOptions will print the help messege and
249// exit.
250DriverConfig parseObjcopyOptions(ArrayRef<const char *> ArgsArr) {
Jordan Rupprecht5745c5f2019-02-04 18:38:00 +0000251 DriverConfig DC;
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000252 ObjcopyOptTable T;
253 unsigned MissingArgumentIndex, MissingArgumentCount;
254 llvm::opt::InputArgList InputArgs =
255 T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);
256
257 if (InputArgs.size() == 0) {
258 T.PrintHelp(errs(), "llvm-objcopy input [output]", "objcopy tool");
259 exit(1);
260 }
261
262 if (InputArgs.hasArg(OBJCOPY_help)) {
263 T.PrintHelp(outs(), "llvm-objcopy input [output]", "objcopy tool");
264 exit(0);
265 }
266
267 if (InputArgs.hasArg(OBJCOPY_version)) {
Martin Storsjoe9af7152018-11-28 06:51:50 +0000268 outs() << "llvm-objcopy, compatible with GNU objcopy\n";
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000269 cl::PrintVersionMessage();
270 exit(0);
271 }
272
273 SmallVector<const char *, 2> Positional;
274
275 for (auto Arg : InputArgs.filtered(OBJCOPY_UNKNOWN))
276 error("unknown argument '" + Arg->getAsString(InputArgs) + "'");
277
278 for (auto Arg : InputArgs.filtered(OBJCOPY_INPUT))
279 Positional.push_back(Arg->getValue());
280
281 if (Positional.empty())
282 error("No input file specified");
283
284 if (Positional.size() > 2)
285 error("Too many positional arguments");
286
287 CopyConfig Config;
288 Config.InputFilename = Positional[0];
289 Config.OutputFilename = Positional[Positional.size() == 1 ? 0 : 1];
Jordan Rupprechtbb4588e2018-10-12 00:36:01 +0000290 if (InputArgs.hasArg(OBJCOPY_target) &&
291 (InputArgs.hasArg(OBJCOPY_input_target) ||
292 InputArgs.hasArg(OBJCOPY_output_target)))
293 error("--target cannot be used with --input-target or --output-target");
294
295 if (InputArgs.hasArg(OBJCOPY_target)) {
296 Config.InputFormat = InputArgs.getLastArgValue(OBJCOPY_target);
297 Config.OutputFormat = InputArgs.getLastArgValue(OBJCOPY_target);
298 } else {
299 Config.InputFormat = InputArgs.getLastArgValue(OBJCOPY_input_target);
300 Config.OutputFormat = InputArgs.getLastArgValue(OBJCOPY_output_target);
301 }
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000302 if (Config.InputFormat == "binary") {
303 auto BinaryArch = InputArgs.getLastArgValue(OBJCOPY_binary_architecture);
304 if (BinaryArch.empty())
305 error("Specified binary input without specifiying an architecture");
306 Config.BinaryArch = getMachineInfo(BinaryArch);
307 }
Jordan Rupprecht70038e02019-01-07 16:59:12 +0000308 if (!Config.OutputFormat.empty() && Config.OutputFormat != "binary")
309 Config.OutputArch = getOutputFormatMachineInfo(Config.OutputFormat);
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000310
311 if (auto Arg = InputArgs.getLastArg(OBJCOPY_compress_debug_sections,
312 OBJCOPY_compress_debug_sections_eq)) {
313 Config.CompressionType = DebugCompressionType::Z;
314
315 if (Arg->getOption().getID() == OBJCOPY_compress_debug_sections_eq) {
316 Config.CompressionType =
317 StringSwitch<DebugCompressionType>(
318 InputArgs.getLastArgValue(OBJCOPY_compress_debug_sections_eq))
319 .Case("zlib-gnu", DebugCompressionType::GNU)
320 .Case("zlib", DebugCompressionType::Z)
321 .Default(DebugCompressionType::None);
322 if (Config.CompressionType == DebugCompressionType::None)
323 error("Invalid or unsupported --compress-debug-sections format: " +
324 InputArgs.getLastArgValue(OBJCOPY_compress_debug_sections_eq));
325 if (!zlib::isAvailable())
326 error("LLVM was not compiled with LLVM_ENABLE_ZLIB: can not compress.");
327 }
328 }
329
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000330 Config.AddGnuDebugLink = InputArgs.getLastArgValue(OBJCOPY_add_gnu_debuglink);
Jake Ehrlich8ad77792018-12-03 19:49:23 +0000331 Config.BuildIdLinkDir = InputArgs.getLastArgValue(OBJCOPY_build_id_link_dir);
332 if (InputArgs.hasArg(OBJCOPY_build_id_link_input))
333 Config.BuildIdLinkInput =
334 InputArgs.getLastArgValue(OBJCOPY_build_id_link_input);
335 if (InputArgs.hasArg(OBJCOPY_build_id_link_output))
336 Config.BuildIdLinkOutput =
337 InputArgs.getLastArgValue(OBJCOPY_build_id_link_output);
338 Config.SplitDWO = InputArgs.getLastArgValue(OBJCOPY_split_dwo);
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000339 Config.SymbolsPrefix = InputArgs.getLastArgValue(OBJCOPY_prefix_symbols);
340
341 for (auto Arg : InputArgs.filtered(OBJCOPY_redefine_symbol)) {
342 if (!StringRef(Arg->getValue()).contains('='))
343 error("Bad format for --redefine-sym");
344 auto Old2New = StringRef(Arg->getValue()).split('=');
345 if (!Config.SymbolsToRename.insert(Old2New).second)
346 error("Multiple redefinition of symbol " + Old2New.first);
347 }
348
349 for (auto Arg : InputArgs.filtered(OBJCOPY_rename_section)) {
350 SectionRename SR = parseRenameSectionValue(StringRef(Arg->getValue()));
351 if (!Config.SectionsToRename.try_emplace(SR.OriginalName, SR).second)
352 error("Multiple renames of section " + SR.OriginalName);
353 }
Jordan Rupprechtc8927412019-01-29 15:05:38 +0000354 for (auto Arg : InputArgs.filtered(OBJCOPY_set_section_flags)) {
355 SectionFlagsUpdate SFU = parseSetSectionFlagValue(Arg->getValue());
356 if (!Config.SetSectionFlags.try_emplace(SFU.Name, SFU).second)
357 error("--set-section-flags set multiple times for section " + SFU.Name);
358 }
359 // Prohibit combinations of --set-section-flags when the section name is used
360 // by --rename-section, either as a source or a destination.
361 for (const auto &E : Config.SectionsToRename) {
362 const SectionRename &SR = E.second;
363 if (Config.SetSectionFlags.count(SR.OriginalName))
364 error("--set-section-flags=" + SR.OriginalName +
365 " conflicts with --rename-section=" + SR.OriginalName + "=" +
366 SR.NewName);
367 if (Config.SetSectionFlags.count(SR.NewName))
368 error("--set-section-flags=" + SR.NewName +
369 " conflicts with --rename-section=" + SR.OriginalName + "=" +
370 SR.NewName);
371 }
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000372
373 for (auto Arg : InputArgs.filtered(OBJCOPY_remove_section))
374 Config.ToRemove.push_back(Arg->getValue());
Jordan Rupprechtc5bae782018-11-13 19:32:27 +0000375 for (auto Arg : InputArgs.filtered(OBJCOPY_keep_section))
376 Config.KeepSection.push_back(Arg->getValue());
Jake Ehrlich85985ed2018-12-06 02:03:53 +0000377 for (auto Arg : InputArgs.filtered(OBJCOPY_only_section))
378 Config.OnlySection.push_back(Arg->getValue());
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000379 for (auto Arg : InputArgs.filtered(OBJCOPY_add_section))
380 Config.AddSection.push_back(Arg->getValue());
381 for (auto Arg : InputArgs.filtered(OBJCOPY_dump_section))
382 Config.DumpSection.push_back(Arg->getValue());
383 Config.StripAll = InputArgs.hasArg(OBJCOPY_strip_all);
384 Config.StripAllGNU = InputArgs.hasArg(OBJCOPY_strip_all_gnu);
385 Config.StripDebug = InputArgs.hasArg(OBJCOPY_strip_debug);
386 Config.StripDWO = InputArgs.hasArg(OBJCOPY_strip_dwo);
387 Config.StripSections = InputArgs.hasArg(OBJCOPY_strip_sections);
388 Config.StripNonAlloc = InputArgs.hasArg(OBJCOPY_strip_non_alloc);
389 Config.StripUnneeded = InputArgs.hasArg(OBJCOPY_strip_unneeded);
390 Config.ExtractDWO = InputArgs.hasArg(OBJCOPY_extract_dwo);
391 Config.LocalizeHidden = InputArgs.hasArg(OBJCOPY_localize_hidden);
392 Config.Weaken = InputArgs.hasArg(OBJCOPY_weaken);
Jordan Rupprechtd0f7bcf2019-01-30 14:58:13 +0000393 if (InputArgs.hasArg(OBJCOPY_discard_all, OBJCOPY_discard_locals))
394 Config.DiscardMode =
395 InputArgs.hasFlag(OBJCOPY_discard_all, OBJCOPY_discard_locals)
396 ? DiscardType::All
397 : DiscardType::Locals;
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000398 Config.OnlyKeepDebug = InputArgs.hasArg(OBJCOPY_only_keep_debug);
399 Config.KeepFileSymbols = InputArgs.hasArg(OBJCOPY_keep_file_symbols);
400 Config.DecompressDebugSections =
401 InputArgs.hasArg(OBJCOPY_decompress_debug_sections);
402 for (auto Arg : InputArgs.filtered(OBJCOPY_localize_symbol))
403 Config.SymbolsToLocalize.push_back(Arg->getValue());
404 for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbol))
405 Config.SymbolsToKeepGlobal.push_back(Arg->getValue());
406 for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbols))
Jordan Rupprecht5745c5f2019-02-04 18:38:00 +0000407 addGlobalSymbolsFromFile(Config.SymbolsToKeepGlobal, DC.Alloc,
408 Arg->getValue());
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000409 for (auto Arg : InputArgs.filtered(OBJCOPY_globalize_symbol))
410 Config.SymbolsToGlobalize.push_back(Arg->getValue());
411 for (auto Arg : InputArgs.filtered(OBJCOPY_weaken_symbol))
412 Config.SymbolsToWeaken.push_back(Arg->getValue());
413 for (auto Arg : InputArgs.filtered(OBJCOPY_strip_symbol))
414 Config.SymbolsToRemove.push_back(Arg->getValue());
415 for (auto Arg : InputArgs.filtered(OBJCOPY_keep_symbol))
416 Config.SymbolsToKeep.push_back(Arg->getValue());
417
Jordan Rupprechtfc780bb2018-11-01 17:36:37 +0000418 Config.DeterministicArchives = InputArgs.hasFlag(
419 OBJCOPY_enable_deterministic_archives,
420 OBJCOPY_disable_deterministic_archives, /*default=*/true);
421
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000422 Config.PreserveDates = InputArgs.hasArg(OBJCOPY_preserve_dates);
423
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000424 if (Config.DecompressDebugSections &&
425 Config.CompressionType != DebugCompressionType::None) {
426 error("Cannot specify --compress-debug-sections at the same time as "
427 "--decompress-debug-sections at the same time");
428 }
429
430 if (Config.DecompressDebugSections && !zlib::isAvailable())
431 error("LLVM was not compiled with LLVM_ENABLE_ZLIB: cannot decompress.");
432
Jordan Rupprechtab9f6622018-10-23 20:54:51 +0000433 DC.CopyConfigs.push_back(std::move(Config));
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000434 return DC;
435}
436
437// ParseStripOptions returns the config and sets the input arguments. If a
438// help flag is set then ParseStripOptions will print the help messege and
439// exit.
440DriverConfig parseStripOptions(ArrayRef<const char *> ArgsArr) {
441 StripOptTable T;
442 unsigned MissingArgumentIndex, MissingArgumentCount;
443 llvm::opt::InputArgList InputArgs =
444 T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);
445
446 if (InputArgs.size() == 0) {
447 T.PrintHelp(errs(), "llvm-strip [options] file...", "strip tool");
448 exit(1);
449 }
450
451 if (InputArgs.hasArg(STRIP_help)) {
452 T.PrintHelp(outs(), "llvm-strip [options] file...", "strip tool");
453 exit(0);
454 }
455
456 if (InputArgs.hasArg(STRIP_version)) {
Martin Storsjoe9af7152018-11-28 06:51:50 +0000457 outs() << "llvm-strip, compatible with GNU strip\n";
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000458 cl::PrintVersionMessage();
459 exit(0);
460 }
461
462 SmallVector<const char *, 2> Positional;
463 for (auto Arg : InputArgs.filtered(STRIP_UNKNOWN))
464 error("unknown argument '" + Arg->getAsString(InputArgs) + "'");
465 for (auto Arg : InputArgs.filtered(STRIP_INPUT))
466 Positional.push_back(Arg->getValue());
467
468 if (Positional.empty())
469 error("No input file specified");
470
471 if (Positional.size() > 1 && InputArgs.hasArg(STRIP_output))
472 error("Multiple input files cannot be used in combination with -o");
473
474 CopyConfig Config;
475 Config.StripDebug = InputArgs.hasArg(STRIP_strip_debug);
476
Jordan Rupprechtd0f7bcf2019-01-30 14:58:13 +0000477 if (InputArgs.hasArg(STRIP_discard_all, STRIP_discard_locals))
478 Config.DiscardMode =
479 InputArgs.hasFlag(STRIP_discard_all, STRIP_discard_locals)
480 ? DiscardType::All
481 : DiscardType::Locals;
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000482 Config.StripUnneeded = InputArgs.hasArg(STRIP_strip_unneeded);
483 Config.StripAll = InputArgs.hasArg(STRIP_strip_all);
Jordan Rupprecht30d1b192018-11-01 17:48:46 +0000484 Config.StripAllGNU = InputArgs.hasArg(STRIP_strip_all_gnu);
Eugene Leviant05a3f992019-02-01 15:25:15 +0000485 Config.KeepFileSymbols = InputArgs.hasArg(STRIP_keep_file_symbols);
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000486
Jordan Rupprechtc5bae782018-11-13 19:32:27 +0000487 for (auto Arg : InputArgs.filtered(STRIP_keep_section))
488 Config.KeepSection.push_back(Arg->getValue());
Jordan Rupprecht30d1b192018-11-01 17:48:46 +0000489
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000490 for (auto Arg : InputArgs.filtered(STRIP_remove_section))
491 Config.ToRemove.push_back(Arg->getValue());
492
Eugene Leviant2267c582019-01-31 12:16:20 +0000493 for (auto Arg : InputArgs.filtered(STRIP_strip_symbol))
494 Config.SymbolsToRemove.push_back(Arg->getValue());
495
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000496 for (auto Arg : InputArgs.filtered(STRIP_keep_symbol))
497 Config.SymbolsToKeep.push_back(Arg->getValue());
498
Eugene Leviant2267c582019-01-31 12:16:20 +0000499 if (!Config.StripDebug && !Config.StripUnneeded &&
500 Config.DiscardMode == DiscardType::None && !Config.StripAllGNU && Config.SymbolsToRemove.empty())
501 Config.StripAll = true;
502
Jordan Rupprechtfc780bb2018-11-01 17:36:37 +0000503 Config.DeterministicArchives =
504 InputArgs.hasFlag(STRIP_enable_deterministic_archives,
505 STRIP_disable_deterministic_archives, /*default=*/true);
506
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000507 Config.PreserveDates = InputArgs.hasArg(STRIP_preserve_dates);
508
509 DriverConfig DC;
510 if (Positional.size() == 1) {
511 Config.InputFilename = Positional[0];
512 Config.OutputFilename =
513 InputArgs.getLastArgValue(STRIP_output, Positional[0]);
514 DC.CopyConfigs.push_back(std::move(Config));
515 } else {
516 for (const char *Filename : Positional) {
517 Config.InputFilename = Filename;
518 Config.OutputFilename = Filename;
519 DC.CopyConfigs.push_back(Config);
520 }
521 }
522
523 return DC;
524}
525
526} // namespace objcopy
527} // namespace llvm