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