xref: /freebsd/contrib/llvm-project/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp (revision 9f23cbd6cae82fd77edfad7173432fa8dccd0a95)
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 *BuildAccelerator = Args.getLastArg(OPT_build_accelerator)) {
127     StringRef S = BuildAccelerator->getValue();
128 
129     if (S == "none")
130       Options.AccelTableKind = DwarfUtilAccelKind::None;
131     else if (S == "DWARF")
132       Options.AccelTableKind = DwarfUtilAccelKind::DWARF;
133     else
134       return createStringError(
135           std::errc::invalid_argument,
136           formatv("unknown build-accelerator value: '{0}'", S).str().c_str());
137   }
138 
139   if (Options.Verbose) {
140     if (Options.NumThreads != 1 && Args.hasArg(OPT_threads))
141       warning("--num-threads set to 1 because verbose mode is specified");
142 
143     Options.NumThreads = 1;
144   }
145 
146   if (Options.DoODRDeduplication && Args.hasArg(OPT_odr_deduplication) &&
147       !Options.DoGarbageCollection)
148     return createStringError(
149         std::errc::invalid_argument,
150         "cannot use --odr-deduplication without --garbage-collection");
151 
152   if (Options.BuildSeparateDebugFile && Options.OutputFileName == "-")
153     return createStringError(
154         std::errc::invalid_argument,
155         "unable to write to stdout when --separate-debug-file specified");
156 
157   return Error::success();
158 }
159 
160 static Error setConfigToAddNewDebugSections(objcopy::ConfigManager &Config,
161                                             ObjectFile &ObjFile) {
162   // Add new debug sections.
163   for (SectionRef Sec : ObjFile.sections()) {
164     Expected<StringRef> SecName = Sec.getName();
165     if (!SecName)
166       return SecName.takeError();
167 
168     if (isDebugSection(*SecName)) {
169       Expected<StringRef> SecData = Sec.getContents();
170       if (!SecData)
171         return SecData.takeError();
172 
173       Config.Common.AddSection.emplace_back(objcopy::NewSectionInfo(
174           *SecName, MemoryBuffer::getMemBuffer(*SecData, *SecName, false)));
175     }
176   }
177 
178   return Error::success();
179 }
180 
181 static Error verifyOutput(const Options &Opts) {
182   if (Opts.OutputFileName == "-") {
183     warning("verification skipped because writing to stdout");
184     return Error::success();
185   }
186 
187   std::string FileName = Opts.BuildSeparateDebugFile
188                              ? Opts.getSeparateDebugFileName()
189                              : Opts.OutputFileName;
190   Expected<OwningBinary<Binary>> BinOrErr = createBinary(FileName);
191   if (!BinOrErr)
192     return createFileError(FileName, BinOrErr.takeError());
193 
194   if (BinOrErr->getBinary()->isObject()) {
195     if (ObjectFile *Obj = static_cast<ObjectFile *>(BinOrErr->getBinary())) {
196       verbose("Verifying DWARF...", Opts.Verbose);
197       std::unique_ptr<DWARFContext> DICtx = DWARFContext::create(*Obj);
198       DIDumpOptions DumpOpts;
199       if (!DICtx->verify(Opts.Verbose ? outs() : nulls(),
200                          DumpOpts.noImplicitRecursion()))
201         return createFileError(FileName,
202                                createError("output verification failed"));
203 
204       return Error::success();
205     }
206   }
207 
208   // The file "FileName" was created by this utility in the previous steps
209   // (i.e. it is already known that it should pass the isObject check).
210   // If the createBinary() function does not return an error, the isObject
211   // check should also be successful.
212   llvm_unreachable(
213       formatv("tool unexpectedly did not emit a supported object file: '{0}'",
214               FileName)
215           .str()
216           .c_str());
217 }
218 
219 class raw_crc_ostream : public raw_ostream {
220 public:
221   explicit raw_crc_ostream(raw_ostream &O) : OS(O) { SetUnbuffered(); }
222 
223   void reserveExtraSpace(uint64_t ExtraSize) override {
224     OS.reserveExtraSpace(ExtraSize);
225   }
226 
227   uint32_t getCRC32() { return CRC32; }
228 
229 protected:
230   raw_ostream &OS;
231   uint32_t CRC32 = 0;
232 
233   /// See raw_ostream::write_impl.
234   void write_impl(const char *Ptr, size_t Size) override {
235     CRC32 = crc32(
236         CRC32, ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(Ptr), Size));
237     OS.write(Ptr, Size);
238   }
239 
240   /// Return the current position within the stream, not counting the bytes
241   /// currently in the buffer.
242   uint64_t current_pos() const override { return OS.tell(); }
243 };
244 
245 static Expected<uint32_t> saveSeparateDebugInfo(const Options &Opts,
246                                                 ObjectFile &InputFile) {
247   objcopy::ConfigManager Config;
248   std::string OutputFilename = Opts.getSeparateDebugFileName();
249   Config.Common.InputFilename = Opts.InputFileName;
250   Config.Common.OutputFilename = OutputFilename;
251   Config.Common.OnlyKeepDebug = true;
252   uint32_t WrittenFileCRC32 = 0;
253 
254   if (Error Err = writeToOutput(
255           Config.Common.OutputFilename, [&](raw_ostream &OutFile) -> Error {
256             raw_crc_ostream CRCBuffer(OutFile);
257             if (Error Err = objcopy::executeObjcopyOnBinary(Config, InputFile,
258                                                             CRCBuffer))
259               return Err;
260 
261             WrittenFileCRC32 = CRCBuffer.getCRC32();
262             return Error::success();
263           }))
264     return std::move(Err);
265 
266   return WrittenFileCRC32;
267 }
268 
269 static Error saveNonDebugInfo(const Options &Opts, ObjectFile &InputFile,
270                               uint32_t GnuDebugLinkCRC32) {
271   objcopy::ConfigManager Config;
272   Config.Common.InputFilename = Opts.InputFileName;
273   Config.Common.OutputFilename = Opts.OutputFileName;
274   Config.Common.StripDebug = true;
275   std::string SeparateDebugFileName = Opts.getSeparateDebugFileName();
276   Config.Common.AddGnuDebugLink = sys::path::filename(SeparateDebugFileName);
277   Config.Common.GnuDebugLinkCRC32 = GnuDebugLinkCRC32;
278 
279   if (Error Err = writeToOutput(
280           Config.Common.OutputFilename, [&](raw_ostream &OutFile) -> Error {
281             if (Error Err =
282                     objcopy::executeObjcopyOnBinary(Config, InputFile, OutFile))
283               return Err;
284 
285             return Error::success();
286           }))
287     return Err;
288 
289   return Error::success();
290 }
291 
292 static Error splitDebugIntoSeparateFile(const Options &Opts,
293                                         ObjectFile &InputFile) {
294   Expected<uint32_t> SeparateDebugFileCRC32OrErr =
295       saveSeparateDebugInfo(Opts, InputFile);
296   if (!SeparateDebugFileCRC32OrErr)
297     return SeparateDebugFileCRC32OrErr.takeError();
298 
299   if (Error Err =
300           saveNonDebugInfo(Opts, InputFile, *SeparateDebugFileCRC32OrErr))
301     return Err;
302 
303   return Error::success();
304 }
305 
306 using DebugInfoBits = SmallString<10000>;
307 
308 static Error addSectionsFromLinkedData(objcopy::ConfigManager &Config,
309                                        ObjectFile &InputFile,
310                                        DebugInfoBits &LinkedDebugInfoBits) {
311   if (isa<ELFObjectFile<ELF32LE>>(&InputFile)) {
312     Expected<ELFObjectFile<ELF32LE>> MemFile = ELFObjectFile<ELF32LE>::create(
313         MemoryBufferRef(LinkedDebugInfoBits, ""));
314     if (!MemFile)
315       return MemFile.takeError();
316 
317     if (Error Err = setConfigToAddNewDebugSections(Config, *MemFile))
318       return Err;
319   } else if (isa<ELFObjectFile<ELF64LE>>(&InputFile)) {
320     Expected<ELFObjectFile<ELF64LE>> MemFile = ELFObjectFile<ELF64LE>::create(
321         MemoryBufferRef(LinkedDebugInfoBits, ""));
322     if (!MemFile)
323       return MemFile.takeError();
324 
325     if (Error Err = setConfigToAddNewDebugSections(Config, *MemFile))
326       return Err;
327   } else if (isa<ELFObjectFile<ELF32BE>>(&InputFile)) {
328     Expected<ELFObjectFile<ELF32BE>> MemFile = ELFObjectFile<ELF32BE>::create(
329         MemoryBufferRef(LinkedDebugInfoBits, ""));
330     if (!MemFile)
331       return MemFile.takeError();
332 
333     if (Error Err = setConfigToAddNewDebugSections(Config, *MemFile))
334       return Err;
335   } else if (isa<ELFObjectFile<ELF64BE>>(&InputFile)) {
336     Expected<ELFObjectFile<ELF64BE>> MemFile = ELFObjectFile<ELF64BE>::create(
337         MemoryBufferRef(LinkedDebugInfoBits, ""));
338     if (!MemFile)
339       return MemFile.takeError();
340 
341     if (Error Err = setConfigToAddNewDebugSections(Config, *MemFile))
342       return Err;
343   } else
344     return createStringError(std::errc::invalid_argument,
345                              "unsupported file format");
346 
347   return Error::success();
348 }
349 
350 static Expected<uint32_t>
351 saveSeparateLinkedDebugInfo(const Options &Opts, ObjectFile &InputFile,
352                             DebugInfoBits LinkedDebugInfoBits) {
353   objcopy::ConfigManager Config;
354   std::string OutputFilename = Opts.getSeparateDebugFileName();
355   Config.Common.InputFilename = Opts.InputFileName;
356   Config.Common.OutputFilename = OutputFilename;
357   Config.Common.StripDebug = true;
358   Config.Common.OnlyKeepDebug = true;
359   uint32_t WrittenFileCRC32 = 0;
360 
361   if (Error Err =
362           addSectionsFromLinkedData(Config, InputFile, LinkedDebugInfoBits))
363     return std::move(Err);
364 
365   if (Error Err = writeToOutput(
366           Config.Common.OutputFilename, [&](raw_ostream &OutFile) -> Error {
367             raw_crc_ostream CRCBuffer(OutFile);
368 
369             if (Error Err = objcopy::executeObjcopyOnBinary(Config, InputFile,
370                                                             CRCBuffer))
371               return Err;
372 
373             WrittenFileCRC32 = CRCBuffer.getCRC32();
374             return Error::success();
375           }))
376     return std::move(Err);
377 
378   return WrittenFileCRC32;
379 }
380 
381 static Error saveSingleLinkedDebugInfo(const Options &Opts,
382                                        ObjectFile &InputFile,
383                                        DebugInfoBits LinkedDebugInfoBits) {
384   objcopy::ConfigManager Config;
385 
386   Config.Common.InputFilename = Opts.InputFileName;
387   Config.Common.OutputFilename = Opts.OutputFileName;
388   Config.Common.StripDebug = true;
389   if (Error Err =
390           addSectionsFromLinkedData(Config, InputFile, LinkedDebugInfoBits))
391     return Err;
392 
393   if (Error Err = writeToOutput(
394           Config.Common.OutputFilename, [&](raw_ostream &OutFile) -> Error {
395             return objcopy::executeObjcopyOnBinary(Config, InputFile, OutFile);
396           }))
397     return Err;
398 
399   return Error::success();
400 }
401 
402 static Error saveLinkedDebugInfo(const Options &Opts, ObjectFile &InputFile,
403                                  DebugInfoBits LinkedDebugInfoBits) {
404   if (Opts.BuildSeparateDebugFile) {
405     Expected<uint32_t> SeparateDebugFileCRC32OrErr =
406         saveSeparateLinkedDebugInfo(Opts, InputFile,
407                                     std::move(LinkedDebugInfoBits));
408     if (!SeparateDebugFileCRC32OrErr)
409       return SeparateDebugFileCRC32OrErr.takeError();
410 
411     if (Error Err =
412             saveNonDebugInfo(Opts, InputFile, *SeparateDebugFileCRC32OrErr))
413       return Err;
414   } else {
415     if (Error Err = saveSingleLinkedDebugInfo(Opts, InputFile,
416                                               std::move(LinkedDebugInfoBits)))
417       return Err;
418   }
419 
420   return Error::success();
421 }
422 
423 static Error saveCopyOfFile(const Options &Opts, ObjectFile &InputFile) {
424   objcopy::ConfigManager Config;
425 
426   Config.Common.InputFilename = Opts.InputFileName;
427   Config.Common.OutputFilename = Opts.OutputFileName;
428 
429   if (Error Err = writeToOutput(
430           Config.Common.OutputFilename, [&](raw_ostream &OutFile) -> Error {
431             return objcopy::executeObjcopyOnBinary(Config, InputFile, OutFile);
432           }))
433     return Err;
434 
435   return Error::success();
436 }
437 
438 static Error applyCLOptions(const struct Options &Opts, ObjectFile &InputFile) {
439   if (Opts.DoGarbageCollection ||
440       Opts.AccelTableKind != DwarfUtilAccelKind::None) {
441     verbose("Do debug info linking...", Opts.Verbose);
442 
443     DebugInfoBits LinkedDebugInfo;
444     raw_svector_ostream OutStream(LinkedDebugInfo);
445 
446     if (Error Err = linkDebugInfo(InputFile, Opts, OutStream))
447       return Err;
448 
449     if (Error Err =
450             saveLinkedDebugInfo(Opts, InputFile, std::move(LinkedDebugInfo)))
451       return Err;
452 
453     return Error::success();
454   } else if (Opts.BuildSeparateDebugFile) {
455     if (Error Err = splitDebugIntoSeparateFile(Opts, InputFile))
456       return Err;
457   } else {
458     if (Error Err = saveCopyOfFile(Opts, InputFile))
459       return Err;
460   }
461 
462   return Error::success();
463 }
464 
465 } // end of namespace dwarfutil
466 } // end of namespace llvm
467 
468 int main(int Argc, char const *Argv[]) {
469   using namespace dwarfutil;
470 
471   InitLLVM X(Argc, Argv);
472   ToolName = Argv[0];
473 
474   // Parse arguments.
475   DwarfutilOptTable T;
476   unsigned MAI;
477   unsigned MAC;
478   ArrayRef<const char *> ArgsArr = ArrayRef(Argv + 1, Argc - 1);
479   opt::InputArgList Args = T.ParseArgs(ArgsArr, MAI, MAC);
480 
481   if (Args.hasArg(OPT_help) || Args.size() == 0) {
482     T.printHelp(
483         outs(), (ToolName + " [options] <input file> <output file>").c_str(),
484         "llvm-dwarfutil is a tool to copy and manipulate debug info", false);
485     return EXIT_SUCCESS;
486   }
487 
488   if (Args.hasArg(OPT_version)) {
489     cl::PrintVersionMessage();
490     return EXIT_SUCCESS;
491   }
492 
493   Options Opts;
494   if (Error Err = validateAndSetOptions(Args, Opts))
495     error(std::move(Err), dwarfutil::ToolName);
496 
497   InitializeAllTargets();
498   InitializeAllTargetMCs();
499   InitializeAllTargetInfos();
500   InitializeAllAsmPrinters();
501 
502   ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr =
503       MemoryBuffer::getFileOrSTDIN(Opts.InputFileName);
504   if (BuffOrErr.getError())
505     error(createFileError(Opts.InputFileName, BuffOrErr.getError()));
506 
507   Expected<std::unique_ptr<Binary>> BinOrErr =
508       object::createBinary(**BuffOrErr);
509   if (!BinOrErr)
510     error(createFileError(Opts.InputFileName, BinOrErr.takeError()));
511 
512   Expected<FilePermissionsApplier> PermsApplierOrErr =
513       FilePermissionsApplier::create(Opts.InputFileName);
514   if (!PermsApplierOrErr)
515     error(createFileError(Opts.InputFileName, PermsApplierOrErr.takeError()));
516 
517   if (!(*BinOrErr)->isObject())
518     error(createFileError(Opts.InputFileName,
519                           createError("unsupported input file")));
520 
521   if (Error Err =
522           applyCLOptions(Opts, *static_cast<ObjectFile *>((*BinOrErr).get())))
523     error(createFileError(Opts.InputFileName, std::move(Err)));
524 
525   BinOrErr->reset();
526   BuffOrErr->reset();
527 
528   if (Error Err = PermsApplierOrErr->apply(Opts.OutputFileName))
529     error(std::move(Err));
530 
531   if (Opts.BuildSeparateDebugFile)
532     if (Error Err = PermsApplierOrErr->apply(Opts.getSeparateDebugFileName()))
533       error(std::move(Err));
534 
535   if (Opts.Verify) {
536     if (Error Err = verifyOutput(Opts))
537       error(std::move(Err));
538   }
539 
540   return EXIT_SUCCESS;
541 }
542