blob: 1432b8591cab8dc81d21e77d1d99dd53c4133970 [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 Rupprechtad29d292019-02-21 17:05:19 +0000132static Expected<uint64_t>
133parseSectionFlagSet(ArrayRef<StringRef> SectionFlags) {
Jordan Rupprechtc8927412019-01-29 15:05:38 +0000134 SectionFlag ParsedFlags = SectionFlag::SecNone;
135 for (StringRef Flag : SectionFlags) {
136 SectionFlag ParsedFlag = parseSectionRenameFlag(Flag);
137 if (ParsedFlag == SectionFlag::SecNone)
Jordan Rupprechtad29d292019-02-21 17:05:19 +0000138 return createStringError(
139 errc::invalid_argument,
140 "Unrecognized section flag '%s'. Flags supported for GNU "
141 "compatibility: alloc, load, noload, readonly, debug, code, data, "
142 "rom, share, contents, merge, strings",
143 Flag.str().c_str());
Jordan Rupprechtc8927412019-01-29 15:05:38 +0000144 ParsedFlags |= ParsedFlag;
145 }
146
147 uint64_t NewFlags = 0;
148 if (ParsedFlags & SectionFlag::SecAlloc)
149 NewFlags |= ELF::SHF_ALLOC;
150 if (!(ParsedFlags & SectionFlag::SecReadonly))
151 NewFlags |= ELF::SHF_WRITE;
152 if (ParsedFlags & SectionFlag::SecCode)
153 NewFlags |= ELF::SHF_EXECINSTR;
154 if (ParsedFlags & SectionFlag::SecMerge)
155 NewFlags |= ELF::SHF_MERGE;
156 if (ParsedFlags & SectionFlag::SecStrings)
157 NewFlags |= ELF::SHF_STRINGS;
158 return NewFlags;
159}
160
Jordan Rupprechtad29d292019-02-21 17:05:19 +0000161static Expected<SectionRename> parseRenameSectionValue(StringRef FlagValue) {
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000162 if (!FlagValue.contains('='))
Jordan Rupprechtad29d292019-02-21 17:05:19 +0000163 return createStringError(errc::invalid_argument,
164 "Bad format for --rename-section: missing '='");
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000165
166 // Initial split: ".foo" = ".bar,f1,f2,..."
167 auto Old2New = FlagValue.split('=');
168 SectionRename SR;
169 SR.OriginalName = Old2New.first;
170
171 // Flags split: ".bar" "f1" "f2" ...
172 SmallVector<StringRef, 6> NameAndFlags;
173 Old2New.second.split(NameAndFlags, ',');
174 SR.NewName = NameAndFlags[0];
175
Jordan Rupprechtad29d292019-02-21 17:05:19 +0000176 if (NameAndFlags.size() > 1) {
177 Expected<uint64_t> ParsedFlagSet =
178 parseSectionFlagSet(makeArrayRef(NameAndFlags).drop_front());
179 if (!ParsedFlagSet)
180 return ParsedFlagSet.takeError();
181 SR.NewFlags = *ParsedFlagSet;
182 }
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000183
184 return SR;
185}
186
Jordan Rupprechtad29d292019-02-21 17:05:19 +0000187static Expected<SectionFlagsUpdate>
188parseSetSectionFlagValue(StringRef FlagValue) {
Jordan Rupprechtc8927412019-01-29 15:05:38 +0000189 if (!StringRef(FlagValue).contains('='))
Jordan Rupprechtad29d292019-02-21 17:05:19 +0000190 return createStringError(errc::invalid_argument,
191 "Bad format for --set-section-flags: missing '='");
Jordan Rupprechtc8927412019-01-29 15:05:38 +0000192
193 // Initial split: ".foo" = "f1,f2,..."
194 auto Section2Flags = StringRef(FlagValue).split('=');
195 SectionFlagsUpdate SFU;
196 SFU.Name = Section2Flags.first;
197
198 // Flags split: "f1" "f2" ...
199 SmallVector<StringRef, 6> SectionFlags;
200 Section2Flags.second.split(SectionFlags, ',');
Jordan Rupprechtad29d292019-02-21 17:05:19 +0000201 Expected<uint64_t> ParsedFlagSet = parseSectionFlagSet(SectionFlags);
202 if (!ParsedFlagSet)
203 return ParsedFlagSet.takeError();
204 SFU.NewFlags = *ParsedFlagSet;
Jordan Rupprechtc8927412019-01-29 15:05:38 +0000205
206 return SFU;
207}
208
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000209static const StringMap<MachineInfo> ArchMap{
210 // Name, {EMachine, 64bit, LittleEndian}
211 {"aarch64", {ELF::EM_AARCH64, true, true}},
212 {"arm", {ELF::EM_ARM, false, true}},
213 {"i386", {ELF::EM_386, false, true}},
214 {"i386:x86-64", {ELF::EM_X86_64, true, true}},
215 {"powerpc:common64", {ELF::EM_PPC64, true, true}},
216 {"sparc", {ELF::EM_SPARC, false, true}},
217 {"x86-64", {ELF::EM_X86_64, true, true}},
218};
219
Jordan Rupprechtad29d292019-02-21 17:05:19 +0000220static Expected<const MachineInfo &> getMachineInfo(StringRef Arch) {
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000221 auto Iter = ArchMap.find(Arch);
222 if (Iter == std::end(ArchMap))
Jordan Rupprechtad29d292019-02-21 17:05:19 +0000223 return createStringError(errc::invalid_argument,
224 "Invalid architecture: '%s'", Arch.str().c_str());
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000225 return Iter->getValue();
226}
227
Jordan Rupprecht70038e02019-01-07 16:59:12 +0000228static const StringMap<MachineInfo> OutputFormatMap{
229 // Name, {EMachine, 64bit, LittleEndian}
230 {"elf32-i386", {ELF::EM_386, false, true}},
231 {"elf32-powerpcle", {ELF::EM_PPC, false, true}},
232 {"elf32-x86-64", {ELF::EM_X86_64, false, true}},
233 {"elf64-powerpcle", {ELF::EM_PPC64, true, true}},
234 {"elf64-x86-64", {ELF::EM_X86_64, true, true}},
235};
236
Jordan Rupprechtad29d292019-02-21 17:05:19 +0000237static Expected<const MachineInfo &>
238getOutputFormatMachineInfo(StringRef Format) {
Jordan Rupprecht70038e02019-01-07 16:59:12 +0000239 auto Iter = OutputFormatMap.find(Format);
240 if (Iter == std::end(OutputFormatMap))
Jordan Rupprechtad29d292019-02-21 17:05:19 +0000241 return createStringError(errc::invalid_argument,
242 "Invalid output format: '%s'",
243 Format.str().c_str());
Jordan Rupprecht70038e02019-01-07 16:59:12 +0000244 return Iter->getValue();
245}
246
Jordan Rupprechtad29d292019-02-21 17:05:19 +0000247static Error addSymbolsFromFile(std::vector<NameOrRegex> &Symbols,
248 BumpPtrAllocator &Alloc, StringRef Filename,
249 bool UseRegex) {
Jordan Rupprecht5745c5f2019-02-04 18:38:00 +0000250 StringSaver Saver(Alloc);
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000251 SmallVector<StringRef, 16> Lines;
252 auto BufOrErr = MemoryBuffer::getFile(Filename);
253 if (!BufOrErr)
Jordan Rupprechtad29d292019-02-21 17:05:19 +0000254 return createFileError(Filename, BufOrErr.getError());
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000255
256 BufOrErr.get()->getBuffer().split(Lines, '\n');
257 for (StringRef Line : Lines) {
258 // Ignore everything after '#', trim whitespace, and only add the symbol if
259 // it's not empty.
260 auto TrimmedLine = Line.split('#').first.trim();
261 if (!TrimmedLine.empty())
Eugene Leviantf324f6d2019-02-06 11:00:07 +0000262 Symbols.emplace_back(Saver.save(TrimmedLine), UseRegex);
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000263 }
Jordan Rupprechtad29d292019-02-21 17:05:19 +0000264
265 return Error::success();
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000266}
267
Eugene Leviantf324f6d2019-02-06 11:00:07 +0000268NameOrRegex::NameOrRegex(StringRef Pattern, bool IsRegex) {
269 if (!IsRegex) {
270 Name = Pattern;
271 return;
272 }
273
274 SmallVector<char, 32> Data;
275 R = std::make_shared<Regex>(
276 ("^" + Pattern.ltrim('^').rtrim('$') + "$").toStringRef(Data));
277}
278
Eugene Leviant340cb872019-02-08 10:33:16 +0000279static Error addSymbolsToRenameFromFile(StringMap<StringRef> &SymbolsToRename,
280 BumpPtrAllocator &Alloc,
281 StringRef Filename) {
282 StringSaver Saver(Alloc);
283 SmallVector<StringRef, 16> Lines;
284 auto BufOrErr = MemoryBuffer::getFile(Filename);
285 if (!BufOrErr)
Eugene Leviant317f9e72019-02-11 09:49:37 +0000286 return createFileError(Filename, BufOrErr.getError());
Eugene Leviant340cb872019-02-08 10:33:16 +0000287
288 BufOrErr.get()->getBuffer().split(Lines, '\n');
289 size_t NumLines = Lines.size();
290 for (size_t LineNo = 0; LineNo < NumLines; ++LineNo) {
291 StringRef TrimmedLine = Lines[LineNo].split('#').first.trim();
292 if (TrimmedLine.empty())
293 continue;
294
295 std::pair<StringRef, StringRef> Pair = Saver.save(TrimmedLine).split(' ');
296 StringRef NewName = Pair.second.trim();
297 if (NewName.empty())
298 return createStringError(errc::invalid_argument,
299 "%s:%zu: missing new symbol name",
300 Filename.str().c_str(), LineNo + 1);
301 SymbolsToRename.insert({Pair.first, NewName});
302 }
303 return Error::success();
304}
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000305// ParseObjcopyOptions returns the config and sets the input arguments. If a
306// help flag is set then ParseObjcopyOptions will print the help messege and
307// exit.
Jordan Rupprechtad29d292019-02-21 17:05:19 +0000308Expected<DriverConfig> parseObjcopyOptions(ArrayRef<const char *> ArgsArr) {
Jordan Rupprecht5745c5f2019-02-04 18:38:00 +0000309 DriverConfig DC;
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000310 ObjcopyOptTable T;
311 unsigned MissingArgumentIndex, MissingArgumentCount;
312 llvm::opt::InputArgList InputArgs =
313 T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);
314
315 if (InputArgs.size() == 0) {
316 T.PrintHelp(errs(), "llvm-objcopy input [output]", "objcopy tool");
317 exit(1);
318 }
319
320 if (InputArgs.hasArg(OBJCOPY_help)) {
321 T.PrintHelp(outs(), "llvm-objcopy input [output]", "objcopy tool");
322 exit(0);
323 }
324
325 if (InputArgs.hasArg(OBJCOPY_version)) {
Martin Storsjoe9af7152018-11-28 06:51:50 +0000326 outs() << "llvm-objcopy, compatible with GNU objcopy\n";
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000327 cl::PrintVersionMessage();
328 exit(0);
329 }
330
331 SmallVector<const char *, 2> Positional;
332
333 for (auto Arg : InputArgs.filtered(OBJCOPY_UNKNOWN))
Jordan Rupprechtad29d292019-02-21 17:05:19 +0000334 return createStringError(errc::invalid_argument, "unknown argument '%s'",
335 Arg->getAsString(InputArgs).c_str());
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000336
337 for (auto Arg : InputArgs.filtered(OBJCOPY_INPUT))
338 Positional.push_back(Arg->getValue());
339
340 if (Positional.empty())
Jordan Rupprechtad29d292019-02-21 17:05:19 +0000341 return createStringError(errc::invalid_argument, "No input file specified");
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000342
343 if (Positional.size() > 2)
Jordan Rupprechtad29d292019-02-21 17:05:19 +0000344 return createStringError(errc::invalid_argument,
345 "Too many positional arguments");
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000346
347 CopyConfig Config;
348 Config.InputFilename = Positional[0];
349 Config.OutputFilename = Positional[Positional.size() == 1 ? 0 : 1];
Jordan Rupprechtbb4588e2018-10-12 00:36:01 +0000350 if (InputArgs.hasArg(OBJCOPY_target) &&
351 (InputArgs.hasArg(OBJCOPY_input_target) ||
352 InputArgs.hasArg(OBJCOPY_output_target)))
Jordan Rupprechtad29d292019-02-21 17:05:19 +0000353 return createStringError(
354 errc::invalid_argument,
355 "--target cannot be used with --input-target or --output-target");
Jordan Rupprechtbb4588e2018-10-12 00:36:01 +0000356
Eugene Leviantf324f6d2019-02-06 11:00:07 +0000357 bool UseRegex = InputArgs.hasArg(OBJCOPY_regex);
Jordan Rupprechtbb4588e2018-10-12 00:36:01 +0000358 if (InputArgs.hasArg(OBJCOPY_target)) {
359 Config.InputFormat = InputArgs.getLastArgValue(OBJCOPY_target);
360 Config.OutputFormat = InputArgs.getLastArgValue(OBJCOPY_target);
361 } else {
362 Config.InputFormat = InputArgs.getLastArgValue(OBJCOPY_input_target);
363 Config.OutputFormat = InputArgs.getLastArgValue(OBJCOPY_output_target);
364 }
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000365 if (Config.InputFormat == "binary") {
366 auto BinaryArch = InputArgs.getLastArgValue(OBJCOPY_binary_architecture);
367 if (BinaryArch.empty())
Jordan Rupprechtad29d292019-02-21 17:05:19 +0000368 return createStringError(
369 errc::invalid_argument,
370 "Specified binary input without specifiying an architecture");
371 Expected<const MachineInfo &> MI = getMachineInfo(BinaryArch);
372 if (!MI)
373 return MI.takeError();
374 Config.BinaryArch = *MI;
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000375 }
Jordan Rupprechtad29d292019-02-21 17:05:19 +0000376 if (!Config.OutputFormat.empty() && Config.OutputFormat != "binary") {
377 Expected<const MachineInfo &> MI =
378 getOutputFormatMachineInfo(Config.OutputFormat);
379 if (!MI)
380 return MI.takeError();
381 Config.OutputArch = *MI;
382 }
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000383
384 if (auto Arg = InputArgs.getLastArg(OBJCOPY_compress_debug_sections,
385 OBJCOPY_compress_debug_sections_eq)) {
386 Config.CompressionType = DebugCompressionType::Z;
387
388 if (Arg->getOption().getID() == OBJCOPY_compress_debug_sections_eq) {
389 Config.CompressionType =
390 StringSwitch<DebugCompressionType>(
391 InputArgs.getLastArgValue(OBJCOPY_compress_debug_sections_eq))
392 .Case("zlib-gnu", DebugCompressionType::GNU)
393 .Case("zlib", DebugCompressionType::Z)
394 .Default(DebugCompressionType::None);
395 if (Config.CompressionType == DebugCompressionType::None)
Jordan Rupprechtad29d292019-02-21 17:05:19 +0000396 return createStringError(
397 errc::invalid_argument,
398 "Invalid or unsupported --compress-debug-sections format: %s",
399 InputArgs.getLastArgValue(OBJCOPY_compress_debug_sections_eq)
400 .str()
401 .c_str());
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000402 if (!zlib::isAvailable())
Jordan Rupprechtad29d292019-02-21 17:05:19 +0000403 return createStringError(
404 errc::invalid_argument,
405 "LLVM was not compiled with LLVM_ENABLE_ZLIB: can not compress");
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000406 }
407 }
408
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000409 Config.AddGnuDebugLink = InputArgs.getLastArgValue(OBJCOPY_add_gnu_debuglink);
Jake Ehrlich8ad77792018-12-03 19:49:23 +0000410 Config.BuildIdLinkDir = InputArgs.getLastArgValue(OBJCOPY_build_id_link_dir);
411 if (InputArgs.hasArg(OBJCOPY_build_id_link_input))
412 Config.BuildIdLinkInput =
413 InputArgs.getLastArgValue(OBJCOPY_build_id_link_input);
414 if (InputArgs.hasArg(OBJCOPY_build_id_link_output))
415 Config.BuildIdLinkOutput =
416 InputArgs.getLastArgValue(OBJCOPY_build_id_link_output);
417 Config.SplitDWO = InputArgs.getLastArgValue(OBJCOPY_split_dwo);
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000418 Config.SymbolsPrefix = InputArgs.getLastArgValue(OBJCOPY_prefix_symbols);
419
420 for (auto Arg : InputArgs.filtered(OBJCOPY_redefine_symbol)) {
421 if (!StringRef(Arg->getValue()).contains('='))
Jordan Rupprechtad29d292019-02-21 17:05:19 +0000422 return createStringError(errc::invalid_argument,
423 "Bad format for --redefine-sym");
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000424 auto Old2New = StringRef(Arg->getValue()).split('=');
425 if (!Config.SymbolsToRename.insert(Old2New).second)
Jordan Rupprechtad29d292019-02-21 17:05:19 +0000426 return createStringError(errc::invalid_argument,
427 "Multiple redefinition of symbol %s",
428 Old2New.first.str().c_str());
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000429 }
430
Eugene Leviant340cb872019-02-08 10:33:16 +0000431 for (auto Arg : InputArgs.filtered(OBJCOPY_redefine_symbols))
432 if (Error E = addSymbolsToRenameFromFile(Config.SymbolsToRename, DC.Alloc,
433 Arg->getValue()))
Jordan Rupprechtad29d292019-02-21 17:05:19 +0000434 return std::move(E);
Eugene Leviant340cb872019-02-08 10:33:16 +0000435
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000436 for (auto Arg : InputArgs.filtered(OBJCOPY_rename_section)) {
Jordan Rupprechtad29d292019-02-21 17:05:19 +0000437 Expected<SectionRename> SR =
438 parseRenameSectionValue(StringRef(Arg->getValue()));
439 if (!SR)
440 return SR.takeError();
441 if (!Config.SectionsToRename.try_emplace(SR->OriginalName, *SR).second)
442 return createStringError(errc::invalid_argument,
443 "Multiple renames of section %s",
444 SR->OriginalName.str().c_str());
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000445 }
Jordan Rupprechtc8927412019-01-29 15:05:38 +0000446 for (auto Arg : InputArgs.filtered(OBJCOPY_set_section_flags)) {
Jordan Rupprechtad29d292019-02-21 17:05:19 +0000447 Expected<SectionFlagsUpdate> SFU =
448 parseSetSectionFlagValue(Arg->getValue());
449 if (!SFU)
450 return SFU.takeError();
451 if (!Config.SetSectionFlags.try_emplace(SFU->Name, *SFU).second)
452 return createStringError(
453 errc::invalid_argument,
454 "--set-section-flags set multiple times for section %s",
455 SFU->Name.str().c_str());
Jordan Rupprechtc8927412019-01-29 15:05:38 +0000456 }
457 // Prohibit combinations of --set-section-flags when the section name is used
458 // by --rename-section, either as a source or a destination.
459 for (const auto &E : Config.SectionsToRename) {
460 const SectionRename &SR = E.second;
461 if (Config.SetSectionFlags.count(SR.OriginalName))
Jordan Rupprechtad29d292019-02-21 17:05:19 +0000462 return createStringError(
463 errc::invalid_argument,
464 "--set-section-flags=%s conflicts with --rename-section=%s=%s",
465 SR.OriginalName.str().c_str(), SR.OriginalName.str().c_str(),
466 SR.NewName.str().c_str());
Jordan Rupprechtc8927412019-01-29 15:05:38 +0000467 if (Config.SetSectionFlags.count(SR.NewName))
Jordan Rupprechtad29d292019-02-21 17:05:19 +0000468 return createStringError(
469 errc::invalid_argument,
470 "--set-section-flags=%s conflicts with --rename-section=%s=%s",
471 SR.NewName.str().c_str(), SR.OriginalName.str().c_str(),
472 SR.NewName.str().c_str());
Jordan Rupprechtc8927412019-01-29 15:05:38 +0000473 }
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000474
475 for (auto Arg : InputArgs.filtered(OBJCOPY_remove_section))
Eugene Leviantf324f6d2019-02-06 11:00:07 +0000476 Config.ToRemove.emplace_back(Arg->getValue(), UseRegex);
Jordan Rupprechtc5bae782018-11-13 19:32:27 +0000477 for (auto Arg : InputArgs.filtered(OBJCOPY_keep_section))
Eugene Leviantf324f6d2019-02-06 11:00:07 +0000478 Config.KeepSection.emplace_back(Arg->getValue(), UseRegex);
Jake Ehrlich85985ed2018-12-06 02:03:53 +0000479 for (auto Arg : InputArgs.filtered(OBJCOPY_only_section))
Eugene Leviantf324f6d2019-02-06 11:00:07 +0000480 Config.OnlySection.emplace_back(Arg->getValue(), UseRegex);
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000481 for (auto Arg : InputArgs.filtered(OBJCOPY_add_section))
482 Config.AddSection.push_back(Arg->getValue());
483 for (auto Arg : InputArgs.filtered(OBJCOPY_dump_section))
484 Config.DumpSection.push_back(Arg->getValue());
485 Config.StripAll = InputArgs.hasArg(OBJCOPY_strip_all);
486 Config.StripAllGNU = InputArgs.hasArg(OBJCOPY_strip_all_gnu);
487 Config.StripDebug = InputArgs.hasArg(OBJCOPY_strip_debug);
488 Config.StripDWO = InputArgs.hasArg(OBJCOPY_strip_dwo);
489 Config.StripSections = InputArgs.hasArg(OBJCOPY_strip_sections);
490 Config.StripNonAlloc = InputArgs.hasArg(OBJCOPY_strip_non_alloc);
491 Config.StripUnneeded = InputArgs.hasArg(OBJCOPY_strip_unneeded);
492 Config.ExtractDWO = InputArgs.hasArg(OBJCOPY_extract_dwo);
493 Config.LocalizeHidden = InputArgs.hasArg(OBJCOPY_localize_hidden);
494 Config.Weaken = InputArgs.hasArg(OBJCOPY_weaken);
Jordan Rupprechtd0f7bcf2019-01-30 14:58:13 +0000495 if (InputArgs.hasArg(OBJCOPY_discard_all, OBJCOPY_discard_locals))
496 Config.DiscardMode =
497 InputArgs.hasFlag(OBJCOPY_discard_all, OBJCOPY_discard_locals)
498 ? DiscardType::All
499 : DiscardType::Locals;
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000500 Config.OnlyKeepDebug = InputArgs.hasArg(OBJCOPY_only_keep_debug);
501 Config.KeepFileSymbols = InputArgs.hasArg(OBJCOPY_keep_file_symbols);
502 Config.DecompressDebugSections =
503 InputArgs.hasArg(OBJCOPY_decompress_debug_sections);
504 for (auto Arg : InputArgs.filtered(OBJCOPY_localize_symbol))
Eugene Leviantf324f6d2019-02-06 11:00:07 +0000505 Config.SymbolsToLocalize.emplace_back(Arg->getValue(), UseRegex);
Eugene Leviante08fe352019-02-08 14:37:54 +0000506 for (auto Arg : InputArgs.filtered(OBJCOPY_localize_symbols))
Jordan Rupprechtad29d292019-02-21 17:05:19 +0000507 if (Error E = addSymbolsFromFile(Config.SymbolsToLocalize, DC.Alloc,
508 Arg->getValue(), UseRegex))
509 return std::move(E);
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000510 for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbol))
Eugene Leviantf324f6d2019-02-06 11:00:07 +0000511 Config.SymbolsToKeepGlobal.emplace_back(Arg->getValue(), UseRegex);
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000512 for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbols))
Jordan Rupprechtad29d292019-02-21 17:05:19 +0000513 if (Error E = addSymbolsFromFile(Config.SymbolsToKeepGlobal, DC.Alloc,
514 Arg->getValue(), UseRegex))
515 return std::move(E);
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000516 for (auto Arg : InputArgs.filtered(OBJCOPY_globalize_symbol))
Eugene Leviantf324f6d2019-02-06 11:00:07 +0000517 Config.SymbolsToGlobalize.emplace_back(Arg->getValue(), UseRegex);
Eugene Leviante08fe352019-02-08 14:37:54 +0000518 for (auto Arg : InputArgs.filtered(OBJCOPY_globalize_symbols))
Jordan Rupprechtad29d292019-02-21 17:05:19 +0000519 if (Error E = addSymbolsFromFile(Config.SymbolsToGlobalize, DC.Alloc,
520 Arg->getValue(), UseRegex))
521 return std::move(E);
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000522 for (auto Arg : InputArgs.filtered(OBJCOPY_weaken_symbol))
Eugene Leviantf324f6d2019-02-06 11:00:07 +0000523 Config.SymbolsToWeaken.emplace_back(Arg->getValue(), UseRegex);
Eugene Leviante08fe352019-02-08 14:37:54 +0000524 for (auto Arg : InputArgs.filtered(OBJCOPY_weaken_symbols))
Jordan Rupprechtad29d292019-02-21 17:05:19 +0000525 if (Error E = addSymbolsFromFile(Config.SymbolsToWeaken, DC.Alloc,
526 Arg->getValue(), UseRegex))
527 return std::move(E);
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000528 for (auto Arg : InputArgs.filtered(OBJCOPY_strip_symbol))
Eugene Leviantf324f6d2019-02-06 11:00:07 +0000529 Config.SymbolsToRemove.emplace_back(Arg->getValue(), UseRegex);
Eugene Leviante08fe352019-02-08 14:37:54 +0000530 for (auto Arg : InputArgs.filtered(OBJCOPY_strip_symbols))
Jordan Rupprechtad29d292019-02-21 17:05:19 +0000531 if (Error E = addSymbolsFromFile(Config.SymbolsToRemove, DC.Alloc,
532 Arg->getValue(), UseRegex))
533 return std::move(E);
Eugene Leviant2db10622019-02-13 07:34:54 +0000534 for (auto Arg : InputArgs.filtered(OBJCOPY_strip_unneeded_symbol))
535 Config.UnneededSymbolsToRemove.emplace_back(Arg->getValue(), UseRegex);
536 for (auto Arg : InputArgs.filtered(OBJCOPY_strip_unneeded_symbols))
Jordan Rupprechtad29d292019-02-21 17:05:19 +0000537 if (Error E = addSymbolsFromFile(Config.UnneededSymbolsToRemove, DC.Alloc,
538 Arg->getValue(), UseRegex))
539 return std::move(E);
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000540 for (auto Arg : InputArgs.filtered(OBJCOPY_keep_symbol))
Eugene Leviantf324f6d2019-02-06 11:00:07 +0000541 Config.SymbolsToKeep.emplace_back(Arg->getValue(), UseRegex);
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000542
Jordan Rupprechtfc780bb2018-11-01 17:36:37 +0000543 Config.DeterministicArchives = InputArgs.hasFlag(
544 OBJCOPY_enable_deterministic_archives,
545 OBJCOPY_disable_deterministic_archives, /*default=*/true);
546
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000547 Config.PreserveDates = InputArgs.hasArg(OBJCOPY_preserve_dates);
548
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000549 if (Config.DecompressDebugSections &&
550 Config.CompressionType != DebugCompressionType::None) {
Jordan Rupprechtad29d292019-02-21 17:05:19 +0000551 return createStringError(
552 errc::invalid_argument,
553 "Cannot specify --compress-debug-sections at the same time as "
554 "--decompress-debug-sections at the same time");
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000555 }
556
557 if (Config.DecompressDebugSections && !zlib::isAvailable())
Jordan Rupprechtad29d292019-02-21 17:05:19 +0000558 return createStringError(
559 errc::invalid_argument,
560 "LLVM was not compiled with LLVM_ENABLE_ZLIB: cannot decompress");
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000561
Jordan Rupprechtab9f6622018-10-23 20:54:51 +0000562 DC.CopyConfigs.push_back(std::move(Config));
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000563 return DC;
564}
565
566// ParseStripOptions returns the config and sets the input arguments. If a
567// help flag is set then ParseStripOptions will print the help messege and
568// exit.
Jordan Rupprechtad29d292019-02-21 17:05:19 +0000569Expected<DriverConfig> parseStripOptions(ArrayRef<const char *> ArgsArr) {
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000570 StripOptTable T;
571 unsigned MissingArgumentIndex, MissingArgumentCount;
572 llvm::opt::InputArgList InputArgs =
573 T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);
574
575 if (InputArgs.size() == 0) {
576 T.PrintHelp(errs(), "llvm-strip [options] file...", "strip tool");
577 exit(1);
578 }
579
580 if (InputArgs.hasArg(STRIP_help)) {
581 T.PrintHelp(outs(), "llvm-strip [options] file...", "strip tool");
582 exit(0);
583 }
584
585 if (InputArgs.hasArg(STRIP_version)) {
Martin Storsjoe9af7152018-11-28 06:51:50 +0000586 outs() << "llvm-strip, compatible with GNU strip\n";
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000587 cl::PrintVersionMessage();
588 exit(0);
589 }
590
591 SmallVector<const char *, 2> Positional;
592 for (auto Arg : InputArgs.filtered(STRIP_UNKNOWN))
Jordan Rupprechtad29d292019-02-21 17:05:19 +0000593 return createStringError(errc::invalid_argument, "unknown argument '%s'",
594 Arg->getAsString(InputArgs).c_str());
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000595 for (auto Arg : InputArgs.filtered(STRIP_INPUT))
596 Positional.push_back(Arg->getValue());
597
598 if (Positional.empty())
Jordan Rupprechtad29d292019-02-21 17:05:19 +0000599 return createStringError(errc::invalid_argument, "No input file specified");
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000600
601 if (Positional.size() > 1 && InputArgs.hasArg(STRIP_output))
Jordan Rupprechtad29d292019-02-21 17:05:19 +0000602 return createStringError(
603 errc::invalid_argument,
604 "Multiple input files cannot be used in combination with -o");
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000605
606 CopyConfig Config;
Eugene Leviantf324f6d2019-02-06 11:00:07 +0000607 bool UseRegexp = InputArgs.hasArg(STRIP_regex);
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000608 Config.StripDebug = InputArgs.hasArg(STRIP_strip_debug);
609
Jordan Rupprechtd0f7bcf2019-01-30 14:58:13 +0000610 if (InputArgs.hasArg(STRIP_discard_all, STRIP_discard_locals))
611 Config.DiscardMode =
612 InputArgs.hasFlag(STRIP_discard_all, STRIP_discard_locals)
613 ? DiscardType::All
614 : DiscardType::Locals;
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000615 Config.StripUnneeded = InputArgs.hasArg(STRIP_strip_unneeded);
616 Config.StripAll = InputArgs.hasArg(STRIP_strip_all);
Jordan Rupprecht30d1b192018-11-01 17:48:46 +0000617 Config.StripAllGNU = InputArgs.hasArg(STRIP_strip_all_gnu);
Eugene Leviant05a3f992019-02-01 15:25:15 +0000618 Config.KeepFileSymbols = InputArgs.hasArg(STRIP_keep_file_symbols);
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000619
Jordan Rupprechtc5bae782018-11-13 19:32:27 +0000620 for (auto Arg : InputArgs.filtered(STRIP_keep_section))
Eugene Leviantf324f6d2019-02-06 11:00:07 +0000621 Config.KeepSection.emplace_back(Arg->getValue(), UseRegexp);
Jordan Rupprecht30d1b192018-11-01 17:48:46 +0000622
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000623 for (auto Arg : InputArgs.filtered(STRIP_remove_section))
Eugene Leviantf324f6d2019-02-06 11:00:07 +0000624 Config.ToRemove.emplace_back(Arg->getValue(), UseRegexp);
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000625
Eugene Leviant2267c582019-01-31 12:16:20 +0000626 for (auto Arg : InputArgs.filtered(STRIP_strip_symbol))
Eugene Leviantf324f6d2019-02-06 11:00:07 +0000627 Config.SymbolsToRemove.emplace_back(Arg->getValue(), UseRegexp);
Eugene Leviant2267c582019-01-31 12:16:20 +0000628
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000629 for (auto Arg : InputArgs.filtered(STRIP_keep_symbol))
Eugene Leviantf324f6d2019-02-06 11:00:07 +0000630 Config.SymbolsToKeep.emplace_back(Arg->getValue(), UseRegexp);
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000631
Eugene Leviant2267c582019-01-31 12:16:20 +0000632 if (!Config.StripDebug && !Config.StripUnneeded &&
633 Config.DiscardMode == DiscardType::None && !Config.StripAllGNU && Config.SymbolsToRemove.empty())
634 Config.StripAll = true;
635
Jordan Rupprechtfc780bb2018-11-01 17:36:37 +0000636 Config.DeterministicArchives =
637 InputArgs.hasFlag(STRIP_enable_deterministic_archives,
638 STRIP_disable_deterministic_archives, /*default=*/true);
639
Alexander Shaposhnikov8d0b74c2018-10-11 22:33:50 +0000640 Config.PreserveDates = InputArgs.hasArg(STRIP_preserve_dates);
641
642 DriverConfig DC;
643 if (Positional.size() == 1) {
644 Config.InputFilename = Positional[0];
645 Config.OutputFilename =
646 InputArgs.getLastArgValue(STRIP_output, Positional[0]);
647 DC.CopyConfigs.push_back(std::move(Config));
648 } else {
649 for (const char *Filename : Positional) {
650 Config.InputFilename = Filename;
651 Config.OutputFilename = Filename;
652 DC.CopyConfigs.push_back(Config);
653 }
654 }
655
656 return DC;
657}
658
659} // namespace objcopy
660} // namespace llvm