Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / llvm / tools / llvm-dwarfutil / llvm-dwarfutil.cpp
blobe09060abb62673fe4d444bac82452f2a05f8d52a
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 //===----------------------------------------------------------------------===//
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"
30 using namespace llvm;
31 using namespace object;
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
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
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
55 class DwarfutilOptTable : public opt::GenericOptTable {
56 public:
57 DwarfutilOptTable() : opt::GenericOptTable(InfoTable) {}
59 } // namespace
61 namespace llvm {
62 namespace dwarfutil {
64 std::string ToolName;
66 static mc::RegisterMCTargetOptionsFlags MOF;
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());
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());
86 Options.InputFileName = InputFiles[0];
87 Options.OutputFileName = InputFiles[1];
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);
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
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());
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());
131 if (opt::Arg *BuildAccelerator = Args.getLastArg(OPT_build_accelerator)) {
132 StringRef S = BuildAccelerator->getValue();
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());
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");
148 Options.NumThreads = 1;
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");
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");
162 return Error::success();
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();
173 if (isDebugSection(*SecName)) {
174 Expected<StringRef> SecData = Sec.getContents();
175 if (!SecData)
176 return SecData.takeError();
178 Config.Common.AddSection.emplace_back(objcopy::NewSectionInfo(
179 *SecName, MemoryBuffer::getMemBuffer(*SecData, *SecName, false)));
183 return Error::success();
186 static Error verifyOutput(const Options &Opts) {
187 if (Opts.OutputFileName == "-") {
188 warning("verification skipped because writing to stdout");
189 return Error::success();
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());
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"));
209 return Error::success();
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());
224 class raw_crc_ostream : public raw_ostream {
225 public:
226 explicit raw_crc_ostream(raw_ostream &O) : OS(O) { SetUnbuffered(); }
228 void reserveExtraSpace(uint64_t ExtraSize) override {
229 OS.reserveExtraSpace(ExtraSize);
232 uint32_t getCRC32() { return CRC32; }
234 protected:
235 raw_ostream &OS;
236 uint32_t CRC32 = 0;
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);
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(); }
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;
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;
266 WrittenFileCRC32 = CRCBuffer.getCRC32();
267 return Error::success();
269 return std::move(Err);
271 return WrittenFileCRC32;
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;
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;
290 return Error::success();
292 return Err;
294 return Error::success();
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();
304 if (Error Err =
305 saveNonDebugInfo(Opts, InputFile, *SeparateDebugFileCRC32OrErr))
306 return Err;
308 return Error::success();
311 using DebugInfoBits = SmallString<10000>;
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();
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();
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();
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();
346 if (Error Err = setConfigToAddNewDebugSections(Config, *MemFile))
347 return Err;
348 } else
349 return createStringError(std::errc::invalid_argument,
350 "unsupported file format");
352 return Error::success();
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;
366 if (Error Err =
367 addSectionsFromLinkedData(Config, InputFile, LinkedDebugInfoBits))
368 return std::move(Err);
370 if (Error Err = writeToOutput(
371 Config.Common.OutputFilename, [&](raw_ostream &OutFile) -> Error {
372 raw_crc_ostream CRCBuffer(OutFile);
374 if (Error Err = objcopy::executeObjcopyOnBinary(Config, InputFile,
375 CRCBuffer))
376 return Err;
378 WrittenFileCRC32 = CRCBuffer.getCRC32();
379 return Error::success();
381 return std::move(Err);
383 return WrittenFileCRC32;
386 static Error saveSingleLinkedDebugInfo(const Options &Opts,
387 ObjectFile &InputFile,
388 DebugInfoBits LinkedDebugInfoBits) {
389 objcopy::ConfigManager Config;
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;
398 if (Error Err = writeToOutput(
399 Config.Common.OutputFilename, [&](raw_ostream &OutFile) -> Error {
400 return objcopy::executeObjcopyOnBinary(Config, InputFile, OutFile);
402 return Err;
404 return Error::success();
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();
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;
425 return Error::success();
428 static Error saveCopyOfFile(const Options &Opts, ObjectFile &InputFile) {
429 objcopy::ConfigManager Config;
431 Config.Common.InputFilename = Opts.InputFileName;
432 Config.Common.OutputFilename = Opts.OutputFileName;
434 if (Error Err = writeToOutput(
435 Config.Common.OutputFilename, [&](raw_ostream &OutFile) -> Error {
436 return objcopy::executeObjcopyOnBinary(Config, InputFile, OutFile);
438 return Err;
440 return Error::success();
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);
448 DebugInfoBits LinkedDebugInfo;
449 raw_svector_ostream OutStream(LinkedDebugInfo);
451 if (Error Err = linkDebugInfo(InputFile, Opts, OutStream))
452 return Err;
454 if (Error Err =
455 saveLinkedDebugInfo(Opts, InputFile, std::move(LinkedDebugInfo)))
456 return Err;
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;
467 return Error::success();
470 } // end of namespace dwarfutil
471 } // end of namespace llvm
473 int main(int Argc, char const *Argv[]) {
474 using namespace dwarfutil;
476 InitLLVM X(Argc, Argv);
477 ToolName = Argv[0];
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);
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;
493 if (Args.hasArg(OPT_version)) {
494 cl::PrintVersionMessage();
495 return EXIT_SUCCESS;
498 Options Opts;
499 if (Error Err = validateAndSetOptions(Args, Opts))
500 error(std::move(Err), dwarfutil::ToolName);
502 InitializeAllTargets();
503 InitializeAllTargetMCs();
504 InitializeAllTargetInfos();
505 InitializeAllAsmPrinters();
507 ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr =
508 MemoryBuffer::getFileOrSTDIN(Opts.InputFileName);
509 if (BuffOrErr.getError())
510 error(createFileError(Opts.InputFileName, BuffOrErr.getError()));
512 Expected<std::unique_ptr<Binary>> BinOrErr =
513 object::createBinary(**BuffOrErr);
514 if (!BinOrErr)
515 error(createFileError(Opts.InputFileName, BinOrErr.takeError()));
517 Expected<FilePermissionsApplier> PermsApplierOrErr =
518 FilePermissionsApplier::create(Opts.InputFileName);
519 if (!PermsApplierOrErr)
520 error(createFileError(Opts.InputFileName, PermsApplierOrErr.takeError()));
522 if (!(*BinOrErr)->isObject())
523 error(createFileError(Opts.InputFileName,
524 createError("unsupported input file")));
526 if (Error Err =
527 applyCLOptions(Opts, *static_cast<ObjectFile *>((*BinOrErr).get())))
528 error(createFileError(Opts.InputFileName, std::move(Err)));
530 BinOrErr->reset();
531 BuffOrErr->reset();
533 if (Error Err = PermsApplierOrErr->apply(Opts.OutputFileName))
534 error(std::move(Err));
536 if (Opts.BuildSeparateDebugFile)
537 if (Error Err = PermsApplierOrErr->apply(Opts.getSeparateDebugFileName()))
538 error(std::move(Err));
540 if (Opts.Verify) {
541 if (Error Err = verifyOutput(Opts))
542 error(std::move(Err));
545 return EXIT_SUCCESS;