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