1 | //===-- ModuleDebugInfoPrinter.cpp - Prints module debug info metadata ----===// |
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 | // This pass decodes the debug info metadata in a module and prints in a |
10 | // (sufficiently-prepared-) human-readable form. |
11 | // |
12 | // For example, run this pass from opt along with the -analyze option, and |
13 | // it'll print to standard output. |
14 | // |
15 | //===----------------------------------------------------------------------===// |
16 | |
17 | #include "llvm/Analysis/ModuleDebugInfoPrinter.h" |
18 | #include "llvm/Analysis/Passes.h" |
19 | #include "llvm/BinaryFormat/Dwarf.h" |
20 | #include "llvm/IR/DebugInfo.h" |
21 | #include "llvm/IR/PassManager.h" |
22 | #include "llvm/InitializePasses.h" |
23 | #include "llvm/Pass.h" |
24 | #include "llvm/Support/ErrorHandling.h" |
25 | #include "llvm/Support/raw_ostream.h" |
26 | using namespace llvm; |
27 | |
28 | static void printFile(raw_ostream &O, StringRef Filename, StringRef Directory, |
29 | unsigned Line = 0) { |
30 | if (Filename.empty()) |
31 | return; |
32 | |
33 | O << " from " ; |
34 | if (!Directory.empty()) |
35 | O << Directory << "/" ; |
36 | O << Filename; |
37 | if (Line) |
38 | O << ":" << Line; |
39 | } |
40 | |
41 | static void printModuleDebugInfo(raw_ostream &O, const Module *M, |
42 | const DebugInfoFinder &Finder) { |
43 | // Printing the nodes directly isn't particularly helpful (since they |
44 | // reference other nodes that won't be printed, particularly for the |
45 | // filenames), so just print a few useful things. |
46 | for (DICompileUnit *CU : Finder.compile_units()) { |
47 | O << "Compile unit: " ; |
48 | auto Lang = dwarf::LanguageString(Language: CU->getSourceLanguage()); |
49 | if (!Lang.empty()) |
50 | O << Lang; |
51 | else |
52 | O << "unknown-language(" << CU->getSourceLanguage() << ")" ; |
53 | printFile(O, Filename: CU->getFilename(), Directory: CU->getDirectory()); |
54 | O << '\n'; |
55 | } |
56 | |
57 | for (DISubprogram *S : Finder.subprograms()) { |
58 | O << "Subprogram: " << S->getName(); |
59 | printFile(O, Filename: S->getFilename(), Directory: S->getDirectory(), Line: S->getLine()); |
60 | if (!S->getLinkageName().empty()) |
61 | O << " ('" << S->getLinkageName() << "')" ; |
62 | O << '\n'; |
63 | } |
64 | |
65 | for (auto *GVU : Finder.global_variables()) { |
66 | const auto *GV = GVU->getVariable(); |
67 | O << "Global variable: " << GV->getName(); |
68 | printFile(O, Filename: GV->getFilename(), Directory: GV->getDirectory(), Line: GV->getLine()); |
69 | if (!GV->getLinkageName().empty()) |
70 | O << " ('" << GV->getLinkageName() << "')" ; |
71 | O << '\n'; |
72 | } |
73 | |
74 | for (const DIType *T : Finder.types()) { |
75 | O << "Type:" ; |
76 | if (!T->getName().empty()) |
77 | O << ' ' << T->getName(); |
78 | printFile(O, Filename: T->getFilename(), Directory: T->getDirectory(), Line: T->getLine()); |
79 | if (auto *BT = dyn_cast<DIBasicType>(Val: T)) { |
80 | O << " " ; |
81 | auto Encoding = dwarf::AttributeEncodingString(Encoding: BT->getEncoding()); |
82 | if (!Encoding.empty()) |
83 | O << Encoding; |
84 | else |
85 | O << "unknown-encoding(" << BT->getEncoding() << ')'; |
86 | } else { |
87 | O << ' '; |
88 | auto Tag = dwarf::TagString(Tag: T->getTag()); |
89 | if (!Tag.empty()) |
90 | O << Tag; |
91 | else |
92 | O << "unknown-tag(" << T->getTag() << ")" ; |
93 | } |
94 | if (auto *CT = dyn_cast<DICompositeType>(Val: T)) { |
95 | if (auto *S = CT->getRawIdentifier()) |
96 | O << " (identifier: '" << S->getString() << "')" ; |
97 | } |
98 | O << '\n'; |
99 | } |
100 | } |
101 | |
102 | ModuleDebugInfoPrinterPass::ModuleDebugInfoPrinterPass(raw_ostream &OS) |
103 | : OS(OS) {} |
104 | |
105 | PreservedAnalyses ModuleDebugInfoPrinterPass::run(Module &M, |
106 | ModuleAnalysisManager &AM) { |
107 | Finder.processModule(M); |
108 | printModuleDebugInfo(O&: OS, M: &M, Finder); |
109 | return PreservedAnalyses::all(); |
110 | } |
111 | |