]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/llvm-objcopy/CopyConfig.cpp
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / llvm-objcopy / CopyConfig.cpp
1 //===- CopyConfig.cpp -----------------------------------------------------===//
2 //
3 //                      The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "CopyConfig.h"
11 #include "llvm-objcopy.h"
12
13 #include "llvm/ADT/BitmaskEnum.h"
14 #include "llvm/ADT/Optional.h"
15 #include "llvm/ADT/SmallVector.h"
16 #include "llvm/ADT/StringRef.h"
17 #include "llvm/Object/ELFTypes.h"
18 #include "llvm/Option/Arg.h"
19 #include "llvm/Option/ArgList.h"
20 #include "llvm/Support/CommandLine.h"
21 #include "llvm/Support/Compression.h"
22 #include "llvm/Support/MemoryBuffer.h"
23 #include <memory>
24 #include <string>
25
26 namespace llvm {
27 namespace objcopy {
28
29 namespace {
30 enum ObjcopyID {
31   OBJCOPY_INVALID = 0, // This is not an option ID.
32 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
33                HELPTEXT, METAVAR, VALUES)                                      \
34   OBJCOPY_##ID,
35 #include "ObjcopyOpts.inc"
36 #undef OPTION
37 };
38
39 #define PREFIX(NAME, VALUE) const char *const OBJCOPY_##NAME[] = VALUE;
40 #include "ObjcopyOpts.inc"
41 #undef PREFIX
42
43 static 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
62 class ObjcopyOptTable : public opt::OptTable {
63 public:
64   ObjcopyOptTable() : OptTable(ObjcopyInfoTable) {}
65 };
66
67 enum 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
80 static 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
91 class StripOptTable : public opt::OptTable {
92 public:
93   StripOptTable() : OptTable(StripInfoTable) {}
94 };
95
96 enum 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
115 static 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
132 static SectionRename parseRenameSectionValue(StringRef FlagValue) {
133   if (!FlagValue.contains('='))
134     error("Bad format for --rename-section: missing '='");
135
136   // Initial split: ".foo" = ".bar,f1,f2,..."
137   auto Old2New = FlagValue.split('=');
138   SectionRename SR;
139   SR.OriginalName = Old2New.first;
140
141   // Flags split: ".bar" "f1" "f2" ...
142   SmallVector<StringRef, 6> NameAndFlags;
143   Old2New.second.split(NameAndFlags, ',');
144   SR.NewName = NameAndFlags[0];
145
146   if (NameAndFlags.size() > 1) {
147     SectionFlag Flags = SectionFlag::SecNone;
148     for (size_t I = 1, Size = NameAndFlags.size(); I < Size; ++I) {
149       SectionFlag Flag = parseSectionRenameFlag(NameAndFlags[I]);
150       if (Flag == SectionFlag::SecNone)
151         error("Unrecognized section flag '" + NameAndFlags[I] +
152               "'. Flags supported for GNU compatibility: alloc, load, noload, "
153               "readonly, debug, code, data, rom, share, contents, merge, "
154               "strings.");
155       Flags |= Flag;
156     }
157
158     SR.NewFlags = 0;
159     if (Flags & SectionFlag::SecAlloc)
160       *SR.NewFlags |= ELF::SHF_ALLOC;
161     if (!(Flags & SectionFlag::SecReadonly))
162       *SR.NewFlags |= ELF::SHF_WRITE;
163     if (Flags & SectionFlag::SecCode)
164       *SR.NewFlags |= ELF::SHF_EXECINSTR;
165     if (Flags & SectionFlag::SecMerge)
166       *SR.NewFlags |= ELF::SHF_MERGE;
167     if (Flags & SectionFlag::SecStrings)
168       *SR.NewFlags |= ELF::SHF_STRINGS;
169   }
170
171   return SR;
172 }
173
174 static const StringMap<MachineInfo> ArchMap{
175     // Name, {EMachine, 64bit, LittleEndian}
176     {"aarch64", {ELF::EM_AARCH64, true, true}},
177     {"arm", {ELF::EM_ARM, false, true}},
178     {"i386", {ELF::EM_386, false, true}},
179     {"i386:x86-64", {ELF::EM_X86_64, true, true}},
180     {"powerpc:common64", {ELF::EM_PPC64, true, true}},
181     {"sparc", {ELF::EM_SPARC, false, true}},
182     {"x86-64", {ELF::EM_X86_64, true, true}},
183 };
184
185 static const MachineInfo &getMachineInfo(StringRef Arch) {
186   auto Iter = ArchMap.find(Arch);
187   if (Iter == std::end(ArchMap))
188     error("Invalid architecture: '" + Arch + "'");
189   return Iter->getValue();
190 }
191
192 static const StringMap<MachineInfo> OutputFormatMap{
193     // Name, {EMachine, 64bit, LittleEndian}
194     {"elf32-i386", {ELF::EM_386, false, true}},
195     {"elf32-powerpcle", {ELF::EM_PPC, false, true}},
196     {"elf32-x86-64", {ELF::EM_X86_64, false, true}},
197     {"elf64-powerpcle", {ELF::EM_PPC64, true, true}},
198     {"elf64-x86-64", {ELF::EM_X86_64, true, true}},
199 };
200
201 static const MachineInfo &getOutputFormatMachineInfo(StringRef Format) {
202   auto Iter = OutputFormatMap.find(Format);
203   if (Iter == std::end(OutputFormatMap))
204     error("Invalid output format: '" + Format + "'");
205   return Iter->getValue();
206 }
207
208 static void addGlobalSymbolsFromFile(std::vector<std::string> &Symbols,
209                                      StringRef Filename) {
210   SmallVector<StringRef, 16> Lines;
211   auto BufOrErr = MemoryBuffer::getFile(Filename);
212   if (!BufOrErr)
213     reportError(Filename, BufOrErr.getError());
214
215   BufOrErr.get()->getBuffer().split(Lines, '\n');
216   for (StringRef Line : Lines) {
217     // Ignore everything after '#', trim whitespace, and only add the symbol if
218     // it's not empty.
219     auto TrimmedLine = Line.split('#').first.trim();
220     if (!TrimmedLine.empty())
221       Symbols.push_back(TrimmedLine.str());
222   }
223 }
224
225 // ParseObjcopyOptions returns the config and sets the input arguments. If a
226 // help flag is set then ParseObjcopyOptions will print the help messege and
227 // exit.
228 DriverConfig parseObjcopyOptions(ArrayRef<const char *> ArgsArr) {
229   ObjcopyOptTable T;
230   unsigned MissingArgumentIndex, MissingArgumentCount;
231   llvm::opt::InputArgList InputArgs =
232       T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);
233
234   if (InputArgs.size() == 0) {
235     T.PrintHelp(errs(), "llvm-objcopy input [output]", "objcopy tool");
236     exit(1);
237   }
238
239   if (InputArgs.hasArg(OBJCOPY_help)) {
240     T.PrintHelp(outs(), "llvm-objcopy input [output]", "objcopy tool");
241     exit(0);
242   }
243
244   if (InputArgs.hasArg(OBJCOPY_version)) {
245     outs() << "llvm-objcopy, compatible with GNU objcopy\n";
246     cl::PrintVersionMessage();
247     exit(0);
248   }
249
250   SmallVector<const char *, 2> Positional;
251
252   for (auto Arg : InputArgs.filtered(OBJCOPY_UNKNOWN))
253     error("unknown argument '" + Arg->getAsString(InputArgs) + "'");
254
255   for (auto Arg : InputArgs.filtered(OBJCOPY_INPUT))
256     Positional.push_back(Arg->getValue());
257
258   if (Positional.empty())
259     error("No input file specified");
260
261   if (Positional.size() > 2)
262     error("Too many positional arguments");
263
264   CopyConfig Config;
265   Config.InputFilename = Positional[0];
266   Config.OutputFilename = Positional[Positional.size() == 1 ? 0 : 1];
267   if (InputArgs.hasArg(OBJCOPY_target) &&
268       (InputArgs.hasArg(OBJCOPY_input_target) ||
269        InputArgs.hasArg(OBJCOPY_output_target)))
270     error("--target cannot be used with --input-target or --output-target");
271
272   if (InputArgs.hasArg(OBJCOPY_target)) {
273     Config.InputFormat = InputArgs.getLastArgValue(OBJCOPY_target);
274     Config.OutputFormat = InputArgs.getLastArgValue(OBJCOPY_target);
275   } else {
276     Config.InputFormat = InputArgs.getLastArgValue(OBJCOPY_input_target);
277     Config.OutputFormat = InputArgs.getLastArgValue(OBJCOPY_output_target);
278   }
279   if (Config.InputFormat == "binary") {
280     auto BinaryArch = InputArgs.getLastArgValue(OBJCOPY_binary_architecture);
281     if (BinaryArch.empty())
282       error("Specified binary input without specifiying an architecture");
283     Config.BinaryArch = getMachineInfo(BinaryArch);
284   }
285   if (!Config.OutputFormat.empty() && Config.OutputFormat != "binary")
286     Config.OutputArch = getOutputFormatMachineInfo(Config.OutputFormat);
287
288   if (auto Arg = InputArgs.getLastArg(OBJCOPY_compress_debug_sections,
289                                       OBJCOPY_compress_debug_sections_eq)) {
290     Config.CompressionType = DebugCompressionType::Z;
291
292     if (Arg->getOption().getID() == OBJCOPY_compress_debug_sections_eq) {
293       Config.CompressionType =
294           StringSwitch<DebugCompressionType>(
295               InputArgs.getLastArgValue(OBJCOPY_compress_debug_sections_eq))
296               .Case("zlib-gnu", DebugCompressionType::GNU)
297               .Case("zlib", DebugCompressionType::Z)
298               .Default(DebugCompressionType::None);
299       if (Config.CompressionType == DebugCompressionType::None)
300         error("Invalid or unsupported --compress-debug-sections format: " +
301               InputArgs.getLastArgValue(OBJCOPY_compress_debug_sections_eq));
302       if (!zlib::isAvailable())
303         error("LLVM was not compiled with LLVM_ENABLE_ZLIB: can not compress.");
304     }
305   }
306
307   Config.AddGnuDebugLink = InputArgs.getLastArgValue(OBJCOPY_add_gnu_debuglink);
308   Config.BuildIdLinkDir = InputArgs.getLastArgValue(OBJCOPY_build_id_link_dir);
309   if (InputArgs.hasArg(OBJCOPY_build_id_link_input))
310     Config.BuildIdLinkInput =
311         InputArgs.getLastArgValue(OBJCOPY_build_id_link_input);
312   if (InputArgs.hasArg(OBJCOPY_build_id_link_output))
313     Config.BuildIdLinkOutput =
314         InputArgs.getLastArgValue(OBJCOPY_build_id_link_output);
315   Config.SplitDWO = InputArgs.getLastArgValue(OBJCOPY_split_dwo);
316   Config.SymbolsPrefix = InputArgs.getLastArgValue(OBJCOPY_prefix_symbols);
317
318   for (auto Arg : InputArgs.filtered(OBJCOPY_redefine_symbol)) {
319     if (!StringRef(Arg->getValue()).contains('='))
320       error("Bad format for --redefine-sym");
321     auto Old2New = StringRef(Arg->getValue()).split('=');
322     if (!Config.SymbolsToRename.insert(Old2New).second)
323       error("Multiple redefinition of symbol " + Old2New.first);
324   }
325
326   for (auto Arg : InputArgs.filtered(OBJCOPY_rename_section)) {
327     SectionRename SR = parseRenameSectionValue(StringRef(Arg->getValue()));
328     if (!Config.SectionsToRename.try_emplace(SR.OriginalName, SR).second)
329       error("Multiple renames of section " + SR.OriginalName);
330   }
331
332   for (auto Arg : InputArgs.filtered(OBJCOPY_remove_section))
333     Config.ToRemove.push_back(Arg->getValue());
334   for (auto Arg : InputArgs.filtered(OBJCOPY_keep_section))
335     Config.KeepSection.push_back(Arg->getValue());
336   for (auto Arg : InputArgs.filtered(OBJCOPY_only_section))
337     Config.OnlySection.push_back(Arg->getValue());
338   for (auto Arg : InputArgs.filtered(OBJCOPY_add_section))
339     Config.AddSection.push_back(Arg->getValue());
340   for (auto Arg : InputArgs.filtered(OBJCOPY_dump_section))
341     Config.DumpSection.push_back(Arg->getValue());
342   Config.StripAll = InputArgs.hasArg(OBJCOPY_strip_all);
343   Config.StripAllGNU = InputArgs.hasArg(OBJCOPY_strip_all_gnu);
344   Config.StripDebug = InputArgs.hasArg(OBJCOPY_strip_debug);
345   Config.StripDWO = InputArgs.hasArg(OBJCOPY_strip_dwo);
346   Config.StripSections = InputArgs.hasArg(OBJCOPY_strip_sections);
347   Config.StripNonAlloc = InputArgs.hasArg(OBJCOPY_strip_non_alloc);
348   Config.StripUnneeded = InputArgs.hasArg(OBJCOPY_strip_unneeded);
349   Config.ExtractDWO = InputArgs.hasArg(OBJCOPY_extract_dwo);
350   Config.LocalizeHidden = InputArgs.hasArg(OBJCOPY_localize_hidden);
351   Config.Weaken = InputArgs.hasArg(OBJCOPY_weaken);
352   Config.DiscardAll = InputArgs.hasArg(OBJCOPY_discard_all);
353   Config.OnlyKeepDebug = InputArgs.hasArg(OBJCOPY_only_keep_debug);
354   Config.KeepFileSymbols = InputArgs.hasArg(OBJCOPY_keep_file_symbols);
355   Config.DecompressDebugSections =
356       InputArgs.hasArg(OBJCOPY_decompress_debug_sections);
357   for (auto Arg : InputArgs.filtered(OBJCOPY_localize_symbol))
358     Config.SymbolsToLocalize.push_back(Arg->getValue());
359   for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbol))
360     Config.SymbolsToKeepGlobal.push_back(Arg->getValue());
361   for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbols))
362     addGlobalSymbolsFromFile(Config.SymbolsToKeepGlobal, Arg->getValue());
363   for (auto Arg : InputArgs.filtered(OBJCOPY_globalize_symbol))
364     Config.SymbolsToGlobalize.push_back(Arg->getValue());
365   for (auto Arg : InputArgs.filtered(OBJCOPY_weaken_symbol))
366     Config.SymbolsToWeaken.push_back(Arg->getValue());
367   for (auto Arg : InputArgs.filtered(OBJCOPY_strip_symbol))
368     Config.SymbolsToRemove.push_back(Arg->getValue());
369   for (auto Arg : InputArgs.filtered(OBJCOPY_keep_symbol))
370     Config.SymbolsToKeep.push_back(Arg->getValue());
371
372   Config.DeterministicArchives = InputArgs.hasFlag(
373       OBJCOPY_enable_deterministic_archives,
374       OBJCOPY_disable_deterministic_archives, /*default=*/true);
375
376   Config.PreserveDates = InputArgs.hasArg(OBJCOPY_preserve_dates);
377
378   if (Config.DecompressDebugSections &&
379       Config.CompressionType != DebugCompressionType::None) {
380     error("Cannot specify --compress-debug-sections at the same time as "
381           "--decompress-debug-sections at the same time");
382   }
383
384   if (Config.DecompressDebugSections && !zlib::isAvailable())
385     error("LLVM was not compiled with LLVM_ENABLE_ZLIB: cannot decompress.");
386
387   DriverConfig DC;
388   DC.CopyConfigs.push_back(std::move(Config));
389   return DC;
390 }
391
392 // ParseStripOptions returns the config and sets the input arguments. If a
393 // help flag is set then ParseStripOptions will print the help messege and
394 // exit.
395 DriverConfig parseStripOptions(ArrayRef<const char *> ArgsArr) {
396   StripOptTable T;
397   unsigned MissingArgumentIndex, MissingArgumentCount;
398   llvm::opt::InputArgList InputArgs =
399       T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);
400
401   if (InputArgs.size() == 0) {
402     T.PrintHelp(errs(), "llvm-strip [options] file...", "strip tool");
403     exit(1);
404   }
405
406   if (InputArgs.hasArg(STRIP_help)) {
407     T.PrintHelp(outs(), "llvm-strip [options] file...", "strip tool");
408     exit(0);
409   }
410
411   if (InputArgs.hasArg(STRIP_version)) {
412     outs() << "llvm-strip, compatible with GNU strip\n";
413     cl::PrintVersionMessage();
414     exit(0);
415   }
416
417   SmallVector<const char *, 2> Positional;
418   for (auto Arg : InputArgs.filtered(STRIP_UNKNOWN))
419     error("unknown argument '" + Arg->getAsString(InputArgs) + "'");
420   for (auto Arg : InputArgs.filtered(STRIP_INPUT))
421     Positional.push_back(Arg->getValue());
422
423   if (Positional.empty())
424     error("No input file specified");
425
426   if (Positional.size() > 1 && InputArgs.hasArg(STRIP_output))
427     error("Multiple input files cannot be used in combination with -o");
428
429   CopyConfig Config;
430   Config.StripDebug = InputArgs.hasArg(STRIP_strip_debug);
431
432   Config.DiscardAll = InputArgs.hasArg(STRIP_discard_all);
433   Config.StripUnneeded = InputArgs.hasArg(STRIP_strip_unneeded);
434   Config.StripAll = InputArgs.hasArg(STRIP_strip_all);
435   Config.StripAllGNU = InputArgs.hasArg(STRIP_strip_all_gnu);
436
437   if (!Config.StripDebug && !Config.StripUnneeded && !Config.DiscardAll &&
438       !Config.StripAllGNU)
439     Config.StripAll = true;
440
441   for (auto Arg : InputArgs.filtered(STRIP_keep_section))
442     Config.KeepSection.push_back(Arg->getValue());
443
444   for (auto Arg : InputArgs.filtered(STRIP_remove_section))
445     Config.ToRemove.push_back(Arg->getValue());
446
447   for (auto Arg : InputArgs.filtered(STRIP_keep_symbol))
448     Config.SymbolsToKeep.push_back(Arg->getValue());
449
450   Config.DeterministicArchives =
451       InputArgs.hasFlag(STRIP_enable_deterministic_archives,
452                         STRIP_disable_deterministic_archives, /*default=*/true);
453
454   Config.PreserveDates = InputArgs.hasArg(STRIP_preserve_dates);
455
456   DriverConfig DC;
457   if (Positional.size() == 1) {
458     Config.InputFilename = Positional[0];
459     Config.OutputFilename =
460         InputArgs.getLastArgValue(STRIP_output, Positional[0]);
461     DC.CopyConfigs.push_back(std::move(Config));
462   } else {
463     for (const char *Filename : Positional) {
464       Config.InputFilename = Filename;
465       Config.OutputFilename = Filename;
466       DC.CopyConfigs.push_back(Config);
467     }
468   }
469
470   return DC;
471 }
472
473 } // namespace objcopy
474 } // namespace llvm