blob: 811f8b753e07b8c37c455ee130cf0471130f8320 [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"
Eugene Leviant340cb872019-02-08 10:33:16 +000021#include "llvm/Support/Errc.h"
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +000022#include "llvm/Support/MemoryBuffer.h"
Jordan Rupprecht5745c5f2019-02-04 18:38:00 +000023#include "llvm/Support/StringSaver.h"
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +000024#include <memory>
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +000025
26namespace llvm {
27namespace objcopy {
28
29namespace {
30enum 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#define PREFIX(NAME, VALUE) const char *const OBJCOPY_##NAME[] = VALUE;
40#include "ObjcopyOpts.inc"
41#undef PREFIX
42
43static const opt::OptTable::Info ObjcopyInfoTable[] = {
44#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
45 HELPTEXT, METAVAR, VALUES) \
46 {OBJCOPY_##PREFIX, \
47 NAME, \
48 HELPTEXT, \
49 METAVAR, \
50 OBJCOPY_##ID, \
51 opt::Option::KIND##Class, \
52 PARAM, \
53 FLAGS, \
54 OBJCOPY_##GROUP, \
55 OBJCOPY_##ALIAS, \
56 ALIASARGS, \
57 VALUES},
58#include "ObjcopyOpts.inc"
59#undef OPTION
60};
61
62class ObjcopyOptTable : public opt::OptTable {
63public:
Jordan Rupprechtaaeaa0a2018-10-23 18:46:33 +000064 ObjcopyOptTable() : OptTable(ObjcopyInfoTable) {}
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +000065};
66
67enum StripID {
68 STRIP_INVALID = 0, // This is not an option ID.
69#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
70 HELPTEXT, METAVAR, VALUES) \
71 STRIP_##ID,
72#include "StripOpts.inc"
73#undef OPTION
74};
75
76#define PREFIX(NAME, VALUE) const char *const STRIP_##NAME[] = VALUE;
77#include "StripOpts.inc"
78#undef PREFIX
79
80static const opt::OptTable::Info StripInfoTable[] = {
81#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
82 HELPTEXT, METAVAR, VALUES) \
83 {STRIP_##PREFIX, NAME, HELPTEXT, \
84 METAVAR, STRIP_##ID, opt::Option::KIND##Class, \
85 PARAM, FLAGS, STRIP_##GROUP, \
86 STRIP_##ALIAS, ALIASARGS, VALUES},
87#include "StripOpts.inc"
88#undef OPTION
89};
90
91class StripOptTable : public opt::OptTable {
92public:
Jordan Rupprechtaaeaa0a2018-10-23 18:46:33 +000093 StripOptTable() : OptTable(StripInfoTable) {}
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +000094};
95
96enum SectionFlag {
97 SecNone = 0,
98 SecAlloc = 1 << 0,
99 SecLoad = 1 << 1,
100 SecNoload = 1 << 2,
101 SecReadonly = 1 << 3,
102 SecDebug = 1 << 4,
103 SecCode = 1 << 5,
104 SecData = 1 << 6,
105 SecRom = 1 << 7,
106 SecMerge = 1 << 8,
107 SecStrings = 1 << 9,
108 SecContents = 1 << 10,
109 SecShare = 1 << 11,
110 LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ SecShare)
111};
112
113} // namespace
114
115static SectionFlag parseSectionRenameFlag(StringRef SectionName) {
116 return llvm::StringSwitch<SectionFlag>(SectionName)
117 .Case("alloc", SectionFlag::SecAlloc)
118 .Case("load", SectionFlag::SecLoad)
119 .Case("noload", SectionFlag::SecNoload)
120 .Case("readonly", SectionFlag::SecReadonly)
121 .Case("debug", SectionFlag::SecDebug)
122 .Case("code", SectionFlag::SecCode)
123 .Case("data", SectionFlag::SecData)
124 .Case("rom", SectionFlag::SecRom)
125 .Case("merge", SectionFlag::SecMerge)
126 .Case("strings", SectionFlag::SecStrings)
127 .Case("contents", SectionFlag::SecContents)
128 .Case("share", SectionFlag::SecShare)
129 .Default(SectionFlag::SecNone);
130}
131
Jordan Rupprechtc8927412019-01-29 15:05:38 +0000132static uint64_t parseSectionFlagSet(ArrayRef<StringRef> SectionFlags) {
133 SectionFlag ParsedFlags = SectionFlag::SecNone;
134 for (StringRef Flag : SectionFlags) {
135 SectionFlag ParsedFlag = parseSectionRenameFlag(Flag);
136 if (ParsedFlag == SectionFlag::SecNone)
137 error("Unrecognized section flag '" + Flag +
138 "'. Flags supported for GNU compatibility: alloc, load, noload, "
139 "readonly, debug, code, data, rom, share, contents, merge, "
140 "strings.");
141 ParsedFlags |= ParsedFlag;
142 }
143
144 uint64_t NewFlags = 0;
145 if (ParsedFlags & SectionFlag::SecAlloc)
146 NewFlags |= ELF::SHF_ALLOC;
147 if (!(ParsedFlags & SectionFlag::SecReadonly))
148 NewFlags |= ELF::SHF_WRITE;
149 if (ParsedFlags & SectionFlag::SecCode)
150 NewFlags |= ELF::SHF_EXECINSTR;
151 if (ParsedFlags & SectionFlag::SecMerge)
152 NewFlags |= ELF::SHF_MERGE;
153 if (ParsedFlags & SectionFlag::SecStrings)
154 NewFlags |= ELF::SHF_STRINGS;
155 return NewFlags;
156}
157
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000158static SectionRename parseRenameSectionValue(StringRef FlagValue) {
159 if (!FlagValue.contains('='))
160 error("Bad format for --rename-section: missing '='");
161
162 // Initial split: ".foo" = ".bar,f1,f2,..."
163 auto Old2New = FlagValue.split('=');
164 SectionRename SR;
165 SR.OriginalName = Old2New.first;
166
167 // Flags split: ".bar" "f1" "f2" ...
168 SmallVector<StringRef, 6> NameAndFlags;
169 Old2New.second.split(NameAndFlags, ',');
170 SR.NewName = NameAndFlags[0];
171
Jordan Rupprechtc8927412019-01-29 15:05:38 +0000172 if (NameAndFlags.size() > 1)
173 SR.NewFlags = parseSectionFlagSet(makeArrayRef(NameAndFlags).drop_front());
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000174
175 return SR;
176}
177
Jordan Rupprechtc8927412019-01-29 15:05:38 +0000178static SectionFlagsUpdate parseSetSectionFlagValue(StringRef FlagValue) {
179 if (!StringRef(FlagValue).contains('='))
180 error("Bad format for --set-section-flags: missing '='");
181
182 // Initial split: ".foo" = "f1,f2,..."
183 auto Section2Flags = StringRef(FlagValue).split('=');
184 SectionFlagsUpdate SFU;
185 SFU.Name = Section2Flags.first;
186
187 // Flags split: "f1" "f2" ...
188 SmallVector<StringRef, 6> SectionFlags;
189 Section2Flags.second.split(SectionFlags, ',');
190 SFU.NewFlags = parseSectionFlagSet(SectionFlags);
191
192 return SFU;
193}
194
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000195static const StringMap<MachineInfo> ArchMap{
196 // Name, {EMachine, 64bit, LittleEndian}
197 {"aarch64", {ELF::EM_AARCH64, true, true}},
198 {"arm", {ELF::EM_ARM, false, true}},
199 {"i386", {ELF::EM_386, false, true}},
200 {"i386:x86-64", {ELF::EM_X86_64, true, true}},
201 {"powerpc:common64", {ELF::EM_PPC64, true, true}},
202 {"sparc", {ELF::EM_SPARC, false, true}},
203 {"x86-64", {ELF::EM_X86_64, true, true}},
204};
205
206static const MachineInfo &getMachineInfo(StringRef Arch) {
207 auto Iter = ArchMap.find(Arch);
208 if (Iter == std::end(ArchMap))
209 error("Invalid architecture: '" + Arch + "'");
210 return Iter->getValue();
211}
212
Jordan Rupprecht70038e02019-01-07 16:59:12 +0000213static const StringMap<MachineInfo> OutputFormatMap{
214 // Name, {EMachine, 64bit, LittleEndian}
215 {"elf32-i386", {ELF::EM_386, false, true}},
216 {"elf32-powerpcle", {ELF::EM_PPC, false, true}},
217 {"elf32-x86-64", {ELF::EM_X86_64, false, true}},
218 {"elf64-powerpcle", {ELF::EM_PPC64, true, true}},
219 {"elf64-x86-64", {ELF::EM_X86_64, true, true}},
220};
221
222static const MachineInfo &getOutputFormatMachineInfo(StringRef Format) {
223 auto Iter = OutputFormatMap.find(Format);
224 if (Iter == std::end(OutputFormatMap))
225 error("Invalid output format: '" + Format + "'");
226 return Iter->getValue();
227}
228
Eugene Leviante08fe352019-02-08 14:37:54 +0000229static void addSymbolsFromFile(std::vector<NameOrRegex> &Symbols,
230 BumpPtrAllocator &Alloc, StringRef Filename,
231 bool UseRegex) {
Jordan Rupprecht5745c5f2019-02-04 18:38:00 +0000232 StringSaver Saver(Alloc);
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000233 SmallVector<StringRef, 16> Lines;
234 auto BufOrErr = MemoryBuffer::getFile(Filename);
235 if (!BufOrErr)
236 reportError(Filename, BufOrErr.getError());
237
238 BufOrErr.get()->getBuffer().split(Lines, '\n');
239 for (StringRef Line : Lines) {
240 // Ignore everything after '#', trim whitespace, and only add the symbol if
241 // it's not empty.
242 auto TrimmedLine = Line.split('#').first.trim();
243 if (!TrimmedLine.empty())
Eugene Leviantf324f6d2019-02-06 11:00:07 +0000244 Symbols.emplace_back(Saver.save(TrimmedLine), UseRegex);
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000245 }
246}
247
Eugene Leviantf324f6d2019-02-06 11:00:07 +0000248NameOrRegex::NameOrRegex(StringRef Pattern, bool IsRegex) {
249 if (!IsRegex) {
250 Name = Pattern;
251 return;
252 }
253
254 SmallVector<char, 32> Data;
255 R = std::make_shared<Regex>(
256 ("^" + Pattern.ltrim('^').rtrim('$') + "$").toStringRef(Data));
257}
258
Eugene Leviant340cb872019-02-08 10:33:16 +0000259static Error addSymbolsToRenameFromFile(StringMap<StringRef> &SymbolsToRename,
260 BumpPtrAllocator &Alloc,
261 StringRef Filename) {
262 StringSaver Saver(Alloc);
263 SmallVector<StringRef, 16> Lines;
264 auto BufOrErr = MemoryBuffer::getFile(Filename);
265 if (!BufOrErr)
Eugene Leviant317f9e72019-02-11 09:49:37 +0000266 return createFileError(Filename, BufOrErr.getError());
Eugene Leviant340cb872019-02-08 10:33:16 +0000267
268 BufOrErr.get()->getBuffer().split(Lines, '\n');
269 size_t NumLines = Lines.size();
270 for (size_t LineNo = 0; LineNo < NumLines; ++LineNo) {
271 StringRef TrimmedLine = Lines[LineNo].split('#').first.trim();
272 if (TrimmedLine.empty())
273 continue;
274
275 std::pair<StringRef, StringRef> Pair = Saver.save(TrimmedLine).split(' ');
276 StringRef NewName = Pair.second.trim();
277 if (NewName.empty())
278 return createStringError(errc::invalid_argument,
279 "%s:%zu: missing new symbol name",
280 Filename.str().c_str(), LineNo + 1);
281 SymbolsToRename.insert({Pair.first, NewName});
282 }
283 return Error::success();
284}
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000285// ParseObjcopyOptions returns the config and sets the input arguments. If a
286// help flag is set then ParseObjcopyOptions will print the help messege and
287// exit.
288DriverConfig parseObjcopyOptions(ArrayRef<const char *> ArgsArr) {
Jordan Rupprecht5745c5f2019-02-04 18:38:00 +0000289 DriverConfig DC;
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000290 ObjcopyOptTable T;
291 unsigned MissingArgumentIndex, MissingArgumentCount;
292 llvm::opt::InputArgList InputArgs =
293 T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);
294
295 if (InputArgs.size() == 0) {
296 T.PrintHelp(errs(), "llvm-objcopy input [output]", "objcopy tool");
297 exit(1);
298 }
299
300 if (InputArgs.hasArg(OBJCOPY_help)) {
301 T.PrintHelp(outs(), "llvm-objcopy input [output]", "objcopy tool");
302 exit(0);
303 }
304
305 if (InputArgs.hasArg(OBJCOPY_version)) {
Martin Storsjoe9af7152018-11-28 06:51:50 +0000306 outs() << "llvm-objcopy, compatible with GNU objcopy\n";
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000307 cl::PrintVersionMessage();
308 exit(0);
309 }
310
311 SmallVector<const char *, 2> Positional;
312
313 for (auto Arg : InputArgs.filtered(OBJCOPY_UNKNOWN))
314 error("unknown argument '" + Arg->getAsString(InputArgs) + "'");
315
316 for (auto Arg : InputArgs.filtered(OBJCOPY_INPUT))
317 Positional.push_back(Arg->getValue());
318
319 if (Positional.empty())
320 error("No input file specified");
321
322 if (Positional.size() > 2)
323 error("Too many positional arguments");
324
325 CopyConfig Config;
326 Config.InputFilename = Positional[0];
327 Config.OutputFilename = Positional[Positional.size() == 1 ? 0 : 1];
Jordan Rupprechtbb4588e2018-10-12 00:36:01 +0000328 if (InputArgs.hasArg(OBJCOPY_target) &&
329 (InputArgs.hasArg(OBJCOPY_input_target) ||
330 InputArgs.hasArg(OBJCOPY_output_target)))
331 error("--target cannot be used with --input-target or --output-target");
332
Eugene Leviantf324f6d2019-02-06 11:00:07 +0000333 bool UseRegex = InputArgs.hasArg(OBJCOPY_regex);
Jordan Rupprechtbb4588e2018-10-12 00:36:01 +0000334 if (InputArgs.hasArg(OBJCOPY_target)) {
335 Config.InputFormat = InputArgs.getLastArgValue(OBJCOPY_target);
336 Config.OutputFormat = InputArgs.getLastArgValue(OBJCOPY_target);
337 } else {
338 Config.InputFormat = InputArgs.getLastArgValue(OBJCOPY_input_target);
339 Config.OutputFormat = InputArgs.getLastArgValue(OBJCOPY_output_target);
340 }
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000341 if (Config.InputFormat == "binary") {
342 auto BinaryArch = InputArgs.getLastArgValue(OBJCOPY_binary_architecture);
343 if (BinaryArch.empty())
344 error("Specified binary input without specifiying an architecture");
345 Config.BinaryArch = getMachineInfo(BinaryArch);
346 }
Jordan Rupprecht70038e02019-01-07 16:59:12 +0000347 if (!Config.OutputFormat.empty() && Config.OutputFormat != "binary")
348 Config.OutputArch = getOutputFormatMachineInfo(Config.OutputFormat);
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000349
350 if (auto Arg = InputArgs.getLastArg(OBJCOPY_compress_debug_sections,
351 OBJCOPY_compress_debug_sections_eq)) {
352 Config.CompressionType = DebugCompressionType::Z;
353
354 if (Arg->getOption().getID() == OBJCOPY_compress_debug_sections_eq) {
355 Config.CompressionType =
356 StringSwitch<DebugCompressionType>(
357 InputArgs.getLastArgValue(OBJCOPY_compress_debug_sections_eq))
358 .Case("zlib-gnu", DebugCompressionType::GNU)
359 .Case("zlib", DebugCompressionType::Z)
360 .Default(DebugCompressionType::None);
361 if (Config.CompressionType == DebugCompressionType::None)
362 error("Invalid or unsupported --compress-debug-sections format: " +
363 InputArgs.getLastArgValue(OBJCOPY_compress_debug_sections_eq));
364 if (!zlib::isAvailable())
365 error("LLVM was not compiled with LLVM_ENABLE_ZLIB: can not compress.");
366 }
367 }
368
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000369 Config.AddGnuDebugLink = InputArgs.getLastArgValue(OBJCOPY_add_gnu_debuglink);
Jake Ehrlich8ad77792018-12-03 19:49:23 +0000370 Config.BuildIdLinkDir = InputArgs.getLastArgValue(OBJCOPY_build_id_link_dir);
371 if (InputArgs.hasArg(OBJCOPY_build_id_link_input))
372 Config.BuildIdLinkInput =
373 InputArgs.getLastArgValue(OBJCOPY_build_id_link_input);
374 if (InputArgs.hasArg(OBJCOPY_build_id_link_output))
375 Config.BuildIdLinkOutput =
376 InputArgs.getLastArgValue(OBJCOPY_build_id_link_output);
377 Config.SplitDWO = InputArgs.getLastArgValue(OBJCOPY_split_dwo);
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000378 Config.SymbolsPrefix = InputArgs.getLastArgValue(OBJCOPY_prefix_symbols);
379
380 for (auto Arg : InputArgs.filtered(OBJCOPY_redefine_symbol)) {
381 if (!StringRef(Arg->getValue()).contains('='))
382 error("Bad format for --redefine-sym");
383 auto Old2New = StringRef(Arg->getValue()).split('=');
384 if (!Config.SymbolsToRename.insert(Old2New).second)
385 error("Multiple redefinition of symbol " + Old2New.first);
386 }
387
Eugene Leviant340cb872019-02-08 10:33:16 +0000388 for (auto Arg : InputArgs.filtered(OBJCOPY_redefine_symbols))
389 if (Error E = addSymbolsToRenameFromFile(Config.SymbolsToRename, DC.Alloc,
390 Arg->getValue()))
391 error(std::move(E));
392
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000393 for (auto Arg : InputArgs.filtered(OBJCOPY_rename_section)) {
394 SectionRename SR = parseRenameSectionValue(StringRef(Arg->getValue()));
395 if (!Config.SectionsToRename.try_emplace(SR.OriginalName, SR).second)
396 error("Multiple renames of section " + SR.OriginalName);
397 }
Jordan Rupprechtc8927412019-01-29 15:05:38 +0000398 for (auto Arg : InputArgs.filtered(OBJCOPY_set_section_flags)) {
399 SectionFlagsUpdate SFU = parseSetSectionFlagValue(Arg->getValue());
400 if (!Config.SetSectionFlags.try_emplace(SFU.Name, SFU).second)
401 error("--set-section-flags set multiple times for section " + SFU.Name);
402 }
403 // Prohibit combinations of --set-section-flags when the section name is used
404 // by --rename-section, either as a source or a destination.
405 for (const auto &E : Config.SectionsToRename) {
406 const SectionRename &SR = E.second;
407 if (Config.SetSectionFlags.count(SR.OriginalName))
408 error("--set-section-flags=" + SR.OriginalName +
409 " conflicts with --rename-section=" + SR.OriginalName + "=" +
410 SR.NewName);
411 if (Config.SetSectionFlags.count(SR.NewName))
412 error("--set-section-flags=" + SR.NewName +
413 " conflicts with --rename-section=" + SR.OriginalName + "=" +
414 SR.NewName);
415 }
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000416
417 for (auto Arg : InputArgs.filtered(OBJCOPY_remove_section))
Eugene Leviantf324f6d2019-02-06 11:00:07 +0000418 Config.ToRemove.emplace_back(Arg->getValue(), UseRegex);
Jordan Rupprechtc5bae782018-11-13 19:32:27 +0000419 for (auto Arg : InputArgs.filtered(OBJCOPY_keep_section))
Eugene Leviantf324f6d2019-02-06 11:00:07 +0000420 Config.KeepSection.emplace_back(Arg->getValue(), UseRegex);
Jake Ehrlich85985ed2018-12-06 02:03:53 +0000421 for (auto Arg : InputArgs.filtered(OBJCOPY_only_section))
Eugene Leviantf324f6d2019-02-06 11:00:07 +0000422 Config.OnlySection.emplace_back(Arg->getValue(), UseRegex);
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000423 for (auto Arg : InputArgs.filtered(OBJCOPY_add_section))
424 Config.AddSection.push_back(Arg->getValue());
425 for (auto Arg : InputArgs.filtered(OBJCOPY_dump_section))
426 Config.DumpSection.push_back(Arg->getValue());
427 Config.StripAll = InputArgs.hasArg(OBJCOPY_strip_all);
428 Config.StripAllGNU = InputArgs.hasArg(OBJCOPY_strip_all_gnu);
429 Config.StripDebug = InputArgs.hasArg(OBJCOPY_strip_debug);
430 Config.StripDWO = InputArgs.hasArg(OBJCOPY_strip_dwo);
431 Config.StripSections = InputArgs.hasArg(OBJCOPY_strip_sections);
432 Config.StripNonAlloc = InputArgs.hasArg(OBJCOPY_strip_non_alloc);
433 Config.StripUnneeded = InputArgs.hasArg(OBJCOPY_strip_unneeded);
434 Config.ExtractDWO = InputArgs.hasArg(OBJCOPY_extract_dwo);
435 Config.LocalizeHidden = InputArgs.hasArg(OBJCOPY_localize_hidden);
436 Config.Weaken = InputArgs.hasArg(OBJCOPY_weaken);
Jordan Rupprechtd0f7bcf2019-01-30 14:58:13 +0000437 if (InputArgs.hasArg(OBJCOPY_discard_all, OBJCOPY_discard_locals))
438 Config.DiscardMode =
439 InputArgs.hasFlag(OBJCOPY_discard_all, OBJCOPY_discard_locals)
440 ? DiscardType::All
441 : DiscardType::Locals;
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000442 Config.OnlyKeepDebug = InputArgs.hasArg(OBJCOPY_only_keep_debug);
443 Config.KeepFileSymbols = InputArgs.hasArg(OBJCOPY_keep_file_symbols);
444 Config.DecompressDebugSections =
445 InputArgs.hasArg(OBJCOPY_decompress_debug_sections);
446 for (auto Arg : InputArgs.filtered(OBJCOPY_localize_symbol))
Eugene Leviantf324f6d2019-02-06 11:00:07 +0000447 Config.SymbolsToLocalize.emplace_back(Arg->getValue(), UseRegex);
Eugene Leviante08fe352019-02-08 14:37:54 +0000448 for (auto Arg : InputArgs.filtered(OBJCOPY_localize_symbols))
449 addSymbolsFromFile(Config.SymbolsToLocalize, DC.Alloc, Arg->getValue(),
450 UseRegex);
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000451 for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbol))
Eugene Leviantf324f6d2019-02-06 11:00:07 +0000452 Config.SymbolsToKeepGlobal.emplace_back(Arg->getValue(), UseRegex);
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000453 for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbols))
Eugene Leviante08fe352019-02-08 14:37:54 +0000454 addSymbolsFromFile(Config.SymbolsToKeepGlobal, DC.Alloc, Arg->getValue(),
455 UseRegex);
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000456 for (auto Arg : InputArgs.filtered(OBJCOPY_globalize_symbol))
Eugene Leviantf324f6d2019-02-06 11:00:07 +0000457 Config.SymbolsToGlobalize.emplace_back(Arg->getValue(), UseRegex);
Eugene Leviante08fe352019-02-08 14:37:54 +0000458 for (auto Arg : InputArgs.filtered(OBJCOPY_globalize_symbols))
459 addSymbolsFromFile(Config.SymbolsToGlobalize, DC.Alloc, Arg->getValue(),
460 UseRegex);
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000461 for (auto Arg : InputArgs.filtered(OBJCOPY_weaken_symbol))
Eugene Leviantf324f6d2019-02-06 11:00:07 +0000462 Config.SymbolsToWeaken.emplace_back(Arg->getValue(), UseRegex);
Eugene Leviante08fe352019-02-08 14:37:54 +0000463 for (auto Arg : InputArgs.filtered(OBJCOPY_weaken_symbols))
464 addSymbolsFromFile(Config.SymbolsToWeaken, DC.Alloc, Arg->getValue(),
465 UseRegex);
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000466 for (auto Arg : InputArgs.filtered(OBJCOPY_strip_symbol))
Eugene Leviantf324f6d2019-02-06 11:00:07 +0000467 Config.SymbolsToRemove.emplace_back(Arg->getValue(), UseRegex);
Eugene Leviante08fe352019-02-08 14:37:54 +0000468 for (auto Arg : InputArgs.filtered(OBJCOPY_strip_symbols))
469 addSymbolsFromFile(Config.SymbolsToRemove, DC.Alloc, Arg->getValue(),
470 UseRegex);
Eugene Leviant2db10622019-02-13 07:34:54 +0000471 for (auto Arg : InputArgs.filtered(OBJCOPY_strip_unneeded_symbol))
472 Config.UnneededSymbolsToRemove.emplace_back(Arg->getValue(), UseRegex);
473 for (auto Arg : InputArgs.filtered(OBJCOPY_strip_unneeded_symbols))
474 addSymbolsFromFile(Config.UnneededSymbolsToRemove, DC.Alloc,
475 Arg->getValue(), UseRegex);
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000476 for (auto Arg : InputArgs.filtered(OBJCOPY_keep_symbol))
Eugene Leviantf324f6d2019-02-06 11:00:07 +0000477 Config.SymbolsToKeep.emplace_back(Arg->getValue(), UseRegex);
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000478
Jordan Rupprechtfc780bb2018-11-01 17:36:37 +0000479 Config.DeterministicArchives = InputArgs.hasFlag(
480 OBJCOPY_enable_deterministic_archives,
481 OBJCOPY_disable_deterministic_archives, /*default=*/true);
482
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000483 Config.PreserveDates = InputArgs.hasArg(OBJCOPY_preserve_dates);
484
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000485 if (Config.DecompressDebugSections &&
486 Config.CompressionType != DebugCompressionType::None) {
487 error("Cannot specify --compress-debug-sections at the same time as "
488 "--decompress-debug-sections at the same time");
489 }
490
491 if (Config.DecompressDebugSections && !zlib::isAvailable())
492 error("LLVM was not compiled with LLVM_ENABLE_ZLIB: cannot decompress.");
493
Jordan Rupprechtab9f6622018-10-23 20:54:51 +0000494 DC.CopyConfigs.push_back(std::move(Config));
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000495 return DC;
496}
497
498// ParseStripOptions returns the config and sets the input arguments. If a
499// help flag is set then ParseStripOptions will print the help messege and
500// exit.
501DriverConfig parseStripOptions(ArrayRef<const char *> ArgsArr) {
502 StripOptTable T;
503 unsigned MissingArgumentIndex, MissingArgumentCount;
504 llvm::opt::InputArgList InputArgs =
505 T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);
506
507 if (InputArgs.size() == 0) {
508 T.PrintHelp(errs(), "llvm-strip [options] file...", "strip tool");
509 exit(1);
510 }
511
512 if (InputArgs.hasArg(STRIP_help)) {
513 T.PrintHelp(outs(), "llvm-strip [options] file...", "strip tool");
514 exit(0);
515 }
516
517 if (InputArgs.hasArg(STRIP_version)) {
Martin Storsjoe9af7152018-11-28 06:51:50 +0000518 outs() << "llvm-strip, compatible with GNU strip\n";
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000519 cl::PrintVersionMessage();
520 exit(0);
521 }
522
523 SmallVector<const char *, 2> Positional;
524 for (auto Arg : InputArgs.filtered(STRIP_UNKNOWN))
525 error("unknown argument '" + Arg->getAsString(InputArgs) + "'");
526 for (auto Arg : InputArgs.filtered(STRIP_INPUT))
527 Positional.push_back(Arg->getValue());
528
529 if (Positional.empty())
530 error("No input file specified");
531
532 if (Positional.size() > 1 && InputArgs.hasArg(STRIP_output))
533 error("Multiple input files cannot be used in combination with -o");
534
535 CopyConfig Config;
Eugene Leviantf324f6d2019-02-06 11:00:07 +0000536 bool UseRegexp = InputArgs.hasArg(STRIP_regex);
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000537 Config.StripDebug = InputArgs.hasArg(STRIP_strip_debug);
538
Jordan Rupprechtd0f7bcf2019-01-30 14:58:13 +0000539 if (InputArgs.hasArg(STRIP_discard_all, STRIP_discard_locals))
540 Config.DiscardMode =
541 InputArgs.hasFlag(STRIP_discard_all, STRIP_discard_locals)
542 ? DiscardType::All
543 : DiscardType::Locals;
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000544 Config.StripUnneeded = InputArgs.hasArg(STRIP_strip_unneeded);
545 Config.StripAll = InputArgs.hasArg(STRIP_strip_all);
Jordan Rupprecht30d1b192018-11-01 17:48:46 +0000546 Config.StripAllGNU = InputArgs.hasArg(STRIP_strip_all_gnu);
Eugene Leviant05a3f992019-02-01 15:25:15 +0000547 Config.KeepFileSymbols = InputArgs.hasArg(STRIP_keep_file_symbols);
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000548
Jordan Rupprechtc5bae782018-11-13 19:32:27 +0000549 for (auto Arg : InputArgs.filtered(STRIP_keep_section))
Eugene Leviantf324f6d2019-02-06 11:00:07 +0000550 Config.KeepSection.emplace_back(Arg->getValue(), UseRegexp);
Jordan Rupprecht30d1b192018-11-01 17:48:46 +0000551
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000552 for (auto Arg : InputArgs.filtered(STRIP_remove_section))
Eugene Leviantf324f6d2019-02-06 11:00:07 +0000553 Config.ToRemove.emplace_back(Arg->getValue(), UseRegexp);
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000554
Eugene Leviant2267c582019-01-31 12:16:20 +0000555 for (auto Arg : InputArgs.filtered(STRIP_strip_symbol))
Eugene Leviantf324f6d2019-02-06 11:00:07 +0000556 Config.SymbolsToRemove.emplace_back(Arg->getValue(), UseRegexp);
Eugene Leviant2267c582019-01-31 12:16:20 +0000557
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000558 for (auto Arg : InputArgs.filtered(STRIP_keep_symbol))
Eugene Leviantf324f6d2019-02-06 11:00:07 +0000559 Config.SymbolsToKeep.emplace_back(Arg->getValue(), UseRegexp);
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000560
Eugene Leviant2267c582019-01-31 12:16:20 +0000561 if (!Config.StripDebug && !Config.StripUnneeded &&
562 Config.DiscardMode == DiscardType::None && !Config.StripAllGNU && Config.SymbolsToRemove.empty())
563 Config.StripAll = true;
564
Jordan Rupprechtfc780bb2018-11-01 17:36:37 +0000565 Config.DeterministicArchives =
566 InputArgs.hasFlag(STRIP_enable_deterministic_archives,
567 STRIP_disable_deterministic_archives, /*default=*/true);
568
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000569 Config.PreserveDates = InputArgs.hasArg(STRIP_preserve_dates);
570
571 DriverConfig DC;
572 if (Positional.size() == 1) {
573 Config.InputFilename = Positional[0];
574 Config.OutputFilename =
575 InputArgs.getLastArgValue(STRIP_output, Positional[0]);
576 DC.CopyConfigs.push_back(std::move(Config));
577 } else {
578 for (const char *Filename : Positional) {
579 Config.InputFilename = Filename;
580 Config.OutputFilename = Filename;
581 DC.CopyConfigs.push_back(Config);
582 }
583 }
584
585 return DC;
586}
587
588} // namespace objcopy
589} // namespace llvm