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:
DwarfutilOptTable()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
validateAndSetOptions(opt::InputArgList & Args,Options & Options)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
setConfigToAddNewDebugSections(objcopy::ConfigManager & Config,ObjectFile & ObjFile)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
verifyOutput(const Options & Opts)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:
raw_crc_ostream(raw_ostream & O)221 explicit raw_crc_ostream(raw_ostream &O) : OS(O) { SetUnbuffered(); }
222
reserveExtraSpace(uint64_t ExtraSize)223 void reserveExtraSpace(uint64_t ExtraSize) override {
224 OS.reserveExtraSpace(ExtraSize);
225 }
226
getCRC32()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.
write_impl(const char * Ptr,size_t Size)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.
current_pos() const242 uint64_t current_pos() const override { return OS.tell(); }
243 };
244
saveSeparateDebugInfo(const Options & Opts,ObjectFile & InputFile)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
saveNonDebugInfo(const Options & Opts,ObjectFile & InputFile,uint32_t GnuDebugLinkCRC32)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
splitDebugIntoSeparateFile(const Options & Opts,ObjectFile & InputFile)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
addSectionsFromLinkedData(objcopy::ConfigManager & Config,ObjectFile & InputFile,DebugInfoBits & LinkedDebugInfoBits)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>
saveSeparateLinkedDebugInfo(const Options & Opts,ObjectFile & InputFile,DebugInfoBits LinkedDebugInfoBits)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
saveSingleLinkedDebugInfo(const Options & Opts,ObjectFile & InputFile,DebugInfoBits LinkedDebugInfoBits)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
saveLinkedDebugInfo(const Options & Opts,ObjectFile & InputFile,DebugInfoBits LinkedDebugInfoBits)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
saveCopyOfFile(const Options & Opts,ObjectFile & InputFile)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
applyCLOptions(const struct Options & Opts,ObjectFile & InputFile)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
main(int Argc,char const * Argv[])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