xref: /freebsd/contrib/llvm-project/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp (revision 2e3507c25e42292b45a5482e116d278f5515d04d)
1 //=== llvm-dwarfutil.cpp --------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "DebugInfoLinker.h"
10 #include "Error.h"
11 #include "Options.h"
12 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
13 #include "llvm/DebugInfo/DWARF/DWARFVerifier.h"
14 #include "llvm/MC/MCTargetOptionsCommandFlags.h"
15 #include "llvm/ObjCopy/CommonConfig.h"
16 #include "llvm/ObjCopy/ConfigManager.h"
17 #include "llvm/ObjCopy/ObjCopy.h"
18 #include "llvm/Option/Arg.h"
19 #include "llvm/Option/ArgList.h"
20 #include "llvm/Option/Option.h"
21 #include "llvm/Support/CRC.h"
22 #include "llvm/Support/CommandLine.h"
23 #include "llvm/Support/FileUtilities.h"
24 #include "llvm/Support/InitLLVM.h"
25 #include "llvm/Support/PrettyStackTrace.h"
26 #include "llvm/Support/Process.h"
27 #include "llvm/Support/Signals.h"
28 #include "llvm/Support/TargetSelect.h"
29 
30 using namespace llvm;
31 using namespace object;
32 
33 namespace {
34 enum ID {
35   OPT_INVALID = 0, // This is not an option ID.
36 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
37                HELPTEXT, METAVAR, VALUES)                                      \
38   OPT_##ID,
39 #include "Options.inc"
40 #undef OPTION
41 };
42 
43 #define PREFIX(NAME, VALUE)                                                    \
44   static constexpr StringLiteral NAME##_init[] = VALUE;                        \
45   static constexpr ArrayRef<StringLiteral> NAME(NAME##_init,                   \
46                                                 std::size(NAME##_init) - 1);
47 #include "Options.inc"
48 #undef PREFIX
49 
50 static constexpr opt::OptTable::Info InfoTable[] = {
51 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
52                HELPTEXT, METAVAR, VALUES)                                      \
53   {                                                                            \
54       PREFIX,      NAME,      HELPTEXT,                                        \
55       METAVAR,     OPT_##ID,  opt::Option::KIND##Class,                        \
56       PARAM,       FLAGS,     OPT_##GROUP,                                     \
57       OPT_##ALIAS, ALIASARGS, VALUES},
58 #include "Options.inc"
59 #undef OPTION
60 };
61 
62 class DwarfutilOptTable : public opt::GenericOptTable {
63 public:
64   DwarfutilOptTable() : opt::GenericOptTable(InfoTable) {}
65 };
66 } // namespace
67 
68 namespace llvm {
69 namespace dwarfutil {
70 
71 std::string ToolName;
72 
73 static mc::RegisterMCTargetOptionsFlags MOF;
74 
75 static Error validateAndSetOptions(opt::InputArgList &Args, Options &Options) {
76   auto UnknownArgs = Args.filtered(OPT_UNKNOWN);
77   if (!UnknownArgs.empty())
78     return createStringError(
79         std::errc::invalid_argument,
80         formatv("unknown option: {0}", (*UnknownArgs.begin())->getSpelling())
81             .str()
82             .c_str());
83 
84   std::vector<std::string> InputFiles = Args.getAllArgValues(OPT_INPUT);
85   if (InputFiles.size() != 2)
86     return createStringError(
87         std::errc::invalid_argument,
88         formatv("exactly two positional arguments expected, {0} provided",
89                 InputFiles.size())
90             .str()
91             .c_str());
92 
93   Options.InputFileName = InputFiles[0];
94   Options.OutputFileName = InputFiles[1];
95 
96   Options.BuildSeparateDebugFile =
97       Args.hasFlag(OPT_separate_debug_file, OPT_no_separate_debug_file, false);
98   Options.DoODRDeduplication =
99       Args.hasFlag(OPT_odr_deduplication, OPT_no_odr_deduplication, true);
100   Options.DoGarbageCollection =
101       Args.hasFlag(OPT_garbage_collection, OPT_no_garbage_collection, true);
102   Options.Verbose = Args.hasArg(OPT_verbose);
103   Options.Verify = Args.hasArg(OPT_verify);
104 
105   if (opt::Arg *NumThreads = Args.getLastArg(OPT_threads))
106     Options.NumThreads = atoi(NumThreads->getValue());
107   else
108     Options.NumThreads = 0; // Use all available hardware threads
109 
110   if (opt::Arg *Tombstone = Args.getLastArg(OPT_tombstone)) {
111     StringRef S = Tombstone->getValue();
112     if (S == "bfd")
113       Options.Tombstone = TombstoneKind::BFD;
114     else if (S == "maxpc")
115       Options.Tombstone = TombstoneKind::MaxPC;
116     else if (S == "universal")
117       Options.Tombstone = TombstoneKind::Universal;
118     else if (S == "exec")
119       Options.Tombstone = TombstoneKind::Exec;
120     else
121       return createStringError(
122           std::errc::invalid_argument,
123           formatv("unknown tombstone value: '{0}'", S).str().c_str());
124   }
125 
126   if (opt::Arg *LinkerKind = Args.getLastArg(OPT_linker)) {
127     StringRef S = LinkerKind->getValue();
128     if (S == "apple")
129       Options.UseLLVMDWARFLinker = false;
130     else if (S == "llvm")
131       Options.UseLLVMDWARFLinker = true;
132     else
133       return createStringError(
134           std::errc::invalid_argument,
135           formatv("unknown linker kind value: '{0}'", S).str().c_str());
136   }
137 
138   if (opt::Arg *BuildAccelerator = Args.getLastArg(OPT_build_accelerator)) {
139     StringRef S = BuildAccelerator->getValue();
140 
141     if (S == "none")
142       Options.AccelTableKind = DwarfUtilAccelKind::None;
143     else if (S == "DWARF")
144       Options.AccelTableKind = DwarfUtilAccelKind::DWARF;
145     else
146       return createStringError(
147           std::errc::invalid_argument,
148           formatv("unknown build-accelerator value: '{0}'", S).str().c_str());
149   }
150 
151   if (Options.Verbose) {
152     if (Options.NumThreads != 1 && Args.hasArg(OPT_threads))
153       warning("--num-threads set to 1 because verbose mode is specified");
154 
155     Options.NumThreads = 1;
156   }
157 
158   if (Options.DoODRDeduplication && Args.hasArg(OPT_odr_deduplication) &&
159       !Options.DoGarbageCollection)
160     return createStringError(
161         std::errc::invalid_argument,
162         "cannot use --odr-deduplication without --garbage-collection");
163 
164   if (Options.BuildSeparateDebugFile && Options.OutputFileName == "-")
165     return createStringError(
166         std::errc::invalid_argument,
167         "unable to write to stdout when --separate-debug-file specified");
168 
169   return Error::success();
170 }
171 
172 static Error setConfigToAddNewDebugSections(objcopy::ConfigManager &Config,
173                                             ObjectFile &ObjFile) {
174   // Add new debug sections.
175   for (SectionRef Sec : ObjFile.sections()) {
176     Expected<StringRef> SecName = Sec.getName();
177     if (!SecName)
178       return SecName.takeError();
179 
180     if (isDebugSection(*SecName)) {
181       Expected<StringRef> SecData = Sec.getContents();
182       if (!SecData)
183         return SecData.takeError();
184 
185       Config.Common.AddSection.emplace_back(objcopy::NewSectionInfo(
186           *SecName, MemoryBuffer::getMemBuffer(*SecData, *SecName, false)));
187     }
188   }
189 
190   return Error::success();
191 }
192 
193 static Error verifyOutput(const Options &Opts) {
194   if (Opts.OutputFileName == "-") {
195     warning("verification skipped because writing to stdout");
196     return Error::success();
197   }
198 
199   std::string FileName = Opts.BuildSeparateDebugFile
200                              ? Opts.getSeparateDebugFileName()
201                              : Opts.OutputFileName;
202   Expected<OwningBinary<Binary>> BinOrErr = createBinary(FileName);
203   if (!BinOrErr)
204     return createFileError(FileName, BinOrErr.takeError());
205 
206   if (BinOrErr->getBinary()->isObject()) {
207     if (ObjectFile *Obj = static_cast<ObjectFile *>(BinOrErr->getBinary())) {
208       verbose("Verifying DWARF...", Opts.Verbose);
209       std::unique_ptr<DWARFContext> DICtx = DWARFContext::create(*Obj);
210       DIDumpOptions DumpOpts;
211       if (!DICtx->verify(Opts.Verbose ? outs() : nulls(),
212                          DumpOpts.noImplicitRecursion()))
213         return createFileError(FileName,
214                                createError("output verification failed"));
215 
216       return Error::success();
217     }
218   }
219 
220   // The file "FileName" was created by this utility in the previous steps
221   // (i.e. it is already known that it should pass the isObject check).
222   // If the createBinary() function does not return an error, the isObject
223   // check should also be successful.
224   llvm_unreachable(
225       formatv("tool unexpectedly did not emit a supported object file: '{0}'",
226               FileName)
227           .str()
228           .c_str());
229 }
230 
231 class raw_crc_ostream : public raw_ostream {
232 public:
233   explicit raw_crc_ostream(raw_ostream &O) : OS(O) { SetUnbuffered(); }
234 
235   void reserveExtraSpace(uint64_t ExtraSize) override {
236     OS.reserveExtraSpace(ExtraSize);
237   }
238 
239   uint32_t getCRC32() { return CRC32; }
240 
241 protected:
242   raw_ostream &OS;
243   uint32_t CRC32 = 0;
244 
245   /// See raw_ostream::write_impl.
246   void write_impl(const char *Ptr, size_t Size) override {
247     CRC32 = crc32(
248         CRC32, ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(Ptr), Size));
249     OS.write(Ptr, Size);
250   }
251 
252   /// Return the current position within the stream, not counting the bytes
253   /// currently in the buffer.
254   uint64_t current_pos() const override { return OS.tell(); }
255 };
256 
257 static Expected<uint32_t> saveSeparateDebugInfo(const Options &Opts,
258                                                 ObjectFile &InputFile) {
259   objcopy::ConfigManager Config;
260   std::string OutputFilename = Opts.getSeparateDebugFileName();
261   Config.Common.InputFilename = Opts.InputFileName;
262   Config.Common.OutputFilename = OutputFilename;
263   Config.Common.OnlyKeepDebug = true;
264   uint32_t WrittenFileCRC32 = 0;
265 
266   if (Error Err = writeToOutput(
267           Config.Common.OutputFilename, [&](raw_ostream &OutFile) -> Error {
268             raw_crc_ostream CRCBuffer(OutFile);
269             if (Error Err = objcopy::executeObjcopyOnBinary(Config, InputFile,
270                                                             CRCBuffer))
271               return Err;
272 
273             WrittenFileCRC32 = CRCBuffer.getCRC32();
274             return Error::success();
275           }))
276     return std::move(Err);
277 
278   return WrittenFileCRC32;
279 }
280 
281 static Error saveNonDebugInfo(const Options &Opts, ObjectFile &InputFile,
282                               uint32_t GnuDebugLinkCRC32) {
283   objcopy::ConfigManager Config;
284   Config.Common.InputFilename = Opts.InputFileName;
285   Config.Common.OutputFilename = Opts.OutputFileName;
286   Config.Common.StripDebug = true;
287   std::string SeparateDebugFileName = Opts.getSeparateDebugFileName();
288   Config.Common.AddGnuDebugLink = sys::path::filename(SeparateDebugFileName);
289   Config.Common.GnuDebugLinkCRC32 = GnuDebugLinkCRC32;
290 
291   if (Error Err = writeToOutput(
292           Config.Common.OutputFilename, [&](raw_ostream &OutFile) -> Error {
293             if (Error Err =
294                     objcopy::executeObjcopyOnBinary(Config, InputFile, OutFile))
295               return Err;
296 
297             return Error::success();
298           }))
299     return Err;
300 
301   return Error::success();
302 }
303 
304 static Error splitDebugIntoSeparateFile(const Options &Opts,
305                                         ObjectFile &InputFile) {
306   Expected<uint32_t> SeparateDebugFileCRC32OrErr =
307       saveSeparateDebugInfo(Opts, InputFile);
308   if (!SeparateDebugFileCRC32OrErr)
309     return SeparateDebugFileCRC32OrErr.takeError();
310 
311   if (Error Err =
312           saveNonDebugInfo(Opts, InputFile, *SeparateDebugFileCRC32OrErr))
313     return Err;
314 
315   return Error::success();
316 }
317 
318 using DebugInfoBits = SmallString<10000>;
319 
320 static Error addSectionsFromLinkedData(objcopy::ConfigManager &Config,
321                                        ObjectFile &InputFile,
322                                        DebugInfoBits &LinkedDebugInfoBits) {
323   if (isa<ELFObjectFile<ELF32LE>>(&InputFile)) {
324     Expected<ELFObjectFile<ELF32LE>> MemFile = ELFObjectFile<ELF32LE>::create(
325         MemoryBufferRef(LinkedDebugInfoBits, ""));
326     if (!MemFile)
327       return MemFile.takeError();
328 
329     if (Error Err = setConfigToAddNewDebugSections(Config, *MemFile))
330       return Err;
331   } else if (isa<ELFObjectFile<ELF64LE>>(&InputFile)) {
332     Expected<ELFObjectFile<ELF64LE>> MemFile = ELFObjectFile<ELF64LE>::create(
333         MemoryBufferRef(LinkedDebugInfoBits, ""));
334     if (!MemFile)
335       return MemFile.takeError();
336 
337     if (Error Err = setConfigToAddNewDebugSections(Config, *MemFile))
338       return Err;
339   } else if (isa<ELFObjectFile<ELF32BE>>(&InputFile)) {
340     Expected<ELFObjectFile<ELF32BE>> MemFile = ELFObjectFile<ELF32BE>::create(
341         MemoryBufferRef(LinkedDebugInfoBits, ""));
342     if (!MemFile)
343       return MemFile.takeError();
344 
345     if (Error Err = setConfigToAddNewDebugSections(Config, *MemFile))
346       return Err;
347   } else if (isa<ELFObjectFile<ELF64BE>>(&InputFile)) {
348     Expected<ELFObjectFile<ELF64BE>> MemFile = ELFObjectFile<ELF64BE>::create(
349         MemoryBufferRef(LinkedDebugInfoBits, ""));
350     if (!MemFile)
351       return MemFile.takeError();
352 
353     if (Error Err = setConfigToAddNewDebugSections(Config, *MemFile))
354       return Err;
355   } else
356     return createStringError(std::errc::invalid_argument,
357                              "unsupported file format");
358 
359   return Error::success();
360 }
361 
362 static Expected<uint32_t>
363 saveSeparateLinkedDebugInfo(const Options &Opts, ObjectFile &InputFile,
364                             DebugInfoBits LinkedDebugInfoBits) {
365   objcopy::ConfigManager Config;
366   std::string OutputFilename = Opts.getSeparateDebugFileName();
367   Config.Common.InputFilename = Opts.InputFileName;
368   Config.Common.OutputFilename = OutputFilename;
369   Config.Common.StripDebug = true;
370   Config.Common.OnlyKeepDebug = true;
371   uint32_t WrittenFileCRC32 = 0;
372 
373   if (Error Err =
374           addSectionsFromLinkedData(Config, InputFile, LinkedDebugInfoBits))
375     return std::move(Err);
376 
377   if (Error Err = writeToOutput(
378           Config.Common.OutputFilename, [&](raw_ostream &OutFile) -> Error {
379             raw_crc_ostream CRCBuffer(OutFile);
380 
381             if (Error Err = objcopy::executeObjcopyOnBinary(Config, InputFile,
382                                                             CRCBuffer))
383               return Err;
384 
385             WrittenFileCRC32 = CRCBuffer.getCRC32();
386             return Error::success();
387           }))
388     return std::move(Err);
389 
390   return WrittenFileCRC32;
391 }
392 
393 static Error saveSingleLinkedDebugInfo(const Options &Opts,
394                                        ObjectFile &InputFile,
395                                        DebugInfoBits LinkedDebugInfoBits) {
396   objcopy::ConfigManager Config;
397 
398   Config.Common.InputFilename = Opts.InputFileName;
399   Config.Common.OutputFilename = Opts.OutputFileName;
400   Config.Common.StripDebug = true;
401   if (Error Err =
402           addSectionsFromLinkedData(Config, InputFile, LinkedDebugInfoBits))
403     return Err;
404 
405   if (Error Err = writeToOutput(
406           Config.Common.OutputFilename, [&](raw_ostream &OutFile) -> Error {
407             return objcopy::executeObjcopyOnBinary(Config, InputFile, OutFile);
408           }))
409     return Err;
410 
411   return Error::success();
412 }
413 
414 static Error saveLinkedDebugInfo(const Options &Opts, ObjectFile &InputFile,
415                                  DebugInfoBits LinkedDebugInfoBits) {
416   if (Opts.BuildSeparateDebugFile) {
417     Expected<uint32_t> SeparateDebugFileCRC32OrErr =
418         saveSeparateLinkedDebugInfo(Opts, InputFile,
419                                     std::move(LinkedDebugInfoBits));
420     if (!SeparateDebugFileCRC32OrErr)
421       return SeparateDebugFileCRC32OrErr.takeError();
422 
423     if (Error Err =
424             saveNonDebugInfo(Opts, InputFile, *SeparateDebugFileCRC32OrErr))
425       return Err;
426   } else {
427     if (Error Err = saveSingleLinkedDebugInfo(Opts, InputFile,
428                                               std::move(LinkedDebugInfoBits)))
429       return Err;
430   }
431 
432   return Error::success();
433 }
434 
435 static Error saveCopyOfFile(const Options &Opts, ObjectFile &InputFile) {
436   objcopy::ConfigManager Config;
437 
438   Config.Common.InputFilename = Opts.InputFileName;
439   Config.Common.OutputFilename = Opts.OutputFileName;
440 
441   if (Error Err = writeToOutput(
442           Config.Common.OutputFilename, [&](raw_ostream &OutFile) -> Error {
443             return objcopy::executeObjcopyOnBinary(Config, InputFile, OutFile);
444           }))
445     return Err;
446 
447   return Error::success();
448 }
449 
450 static Error applyCLOptions(const struct Options &Opts, ObjectFile &InputFile) {
451   if (Opts.DoGarbageCollection ||
452       Opts.AccelTableKind != DwarfUtilAccelKind::None) {
453     verbose("Do debug info linking...", Opts.Verbose);
454 
455     DebugInfoBits LinkedDebugInfo;
456     raw_svector_ostream OutStream(LinkedDebugInfo);
457 
458     if (Error Err = linkDebugInfo(InputFile, Opts, OutStream))
459       return Err;
460 
461     if (Error Err =
462             saveLinkedDebugInfo(Opts, InputFile, std::move(LinkedDebugInfo)))
463       return Err;
464 
465     return Error::success();
466   } else if (Opts.BuildSeparateDebugFile) {
467     if (Error Err = splitDebugIntoSeparateFile(Opts, InputFile))
468       return Err;
469   } else {
470     if (Error Err = saveCopyOfFile(Opts, InputFile))
471       return Err;
472   }
473 
474   return Error::success();
475 }
476 
477 } // end of namespace dwarfutil
478 } // end of namespace llvm
479 
480 int main(int Argc, char const *Argv[]) {
481   using namespace dwarfutil;
482 
483   InitLLVM X(Argc, Argv);
484   ToolName = Argv[0];
485 
486   // Parse arguments.
487   DwarfutilOptTable T;
488   unsigned MAI;
489   unsigned MAC;
490   ArrayRef<const char *> ArgsArr = ArrayRef(Argv + 1, Argc - 1);
491   opt::InputArgList Args = T.ParseArgs(ArgsArr, MAI, MAC);
492 
493   if (Args.hasArg(OPT_help) || Args.size() == 0) {
494     T.printHelp(
495         outs(), (ToolName + " [options] <input file> <output file>").c_str(),
496         "llvm-dwarfutil is a tool to copy and manipulate debug info", false);
497     return EXIT_SUCCESS;
498   }
499 
500   if (Args.hasArg(OPT_version)) {
501     cl::PrintVersionMessage();
502     return EXIT_SUCCESS;
503   }
504 
505   Options Opts;
506   if (Error Err = validateAndSetOptions(Args, Opts))
507     error(std::move(Err), dwarfutil::ToolName);
508 
509   InitializeAllTargets();
510   InitializeAllTargetMCs();
511   InitializeAllTargetInfos();
512   InitializeAllAsmPrinters();
513 
514   ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr =
515       MemoryBuffer::getFileOrSTDIN(Opts.InputFileName);
516   if (BuffOrErr.getError())
517     error(createFileError(Opts.InputFileName, BuffOrErr.getError()));
518 
519   Expected<std::unique_ptr<Binary>> BinOrErr =
520       object::createBinary(**BuffOrErr);
521   if (!BinOrErr)
522     error(createFileError(Opts.InputFileName, BinOrErr.takeError()));
523 
524   Expected<FilePermissionsApplier> PermsApplierOrErr =
525       FilePermissionsApplier::create(Opts.InputFileName);
526   if (!PermsApplierOrErr)
527     error(createFileError(Opts.InputFileName, PermsApplierOrErr.takeError()));
528 
529   if (!(*BinOrErr)->isObject())
530     error(createFileError(Opts.InputFileName,
531                           createError("unsupported input file")));
532 
533   if (Error Err =
534           applyCLOptions(Opts, *static_cast<ObjectFile *>((*BinOrErr).get())))
535     error(createFileError(Opts.InputFileName, std::move(Err)));
536 
537   BinOrErr->reset();
538   BuffOrErr->reset();
539 
540   if (Error Err = PermsApplierOrErr->apply(Opts.OutputFileName))
541     error(std::move(Err));
542 
543   if (Opts.BuildSeparateDebugFile)
544     if (Error Err = PermsApplierOrErr->apply(Opts.getSeparateDebugFileName()))
545       error(std::move(Err));
546 
547   if (Opts.Verify) {
548     if (Error Err = verifyOutput(Opts))
549       error(std::move(Err));
550   }
551 
552   return EXIT_SUCCESS;
553 }
554