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