llvm.org GIT mirror llvm / 13ace66
Add DebugIR pass -- emits IR file and replace source lines with IR lines in MD - requires existing debug information to be present - fixes up file name and line number information in metadata - emits a "<orig_filename>-debug.ll" succinct IR file (without !dbg metadata or debug intrinsics) that can be read by a debugger - initialize pass in opt tool to enable the "-debug-ir" flag - lit tests to follow git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@181467 91177308-0d34-0410-b5e6-96231b3b80d8 Daniel Malea 6 years ago
7 changed file(s) with 263 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
165165 public:
166166 explicit DIScope(const MDNode *N = 0) : DIDescriptor (N) {}
167167
168 /// Set the filename by allocating a new string MDNode for
169 /// it and attaching it to the underlying node.
170 void setFilename(StringRef Name, LLVMContext &Context);
168171 StringRef getFilename() const;
169172 StringRef getDirectory() const;
170173 };
9999 void initializeDAHPass(PassRegistry&);
100100 void initializeDCEPass(PassRegistry&);
101101 void initializeDSEPass(PassRegistry&);
102 void initializeDebugIRPass(PassRegistry&);
102103 void initializeDeadInstEliminationPass(PassRegistry&);
103104 void initializeDeadMachineInstructionElimPass(PassRegistry&);
104105 void initializeDependenceAnalysisPass(PassRegistry&);
7777 // checking on loads, stores, and other memory intrinsics.
7878 FunctionPass *createBoundsCheckingPass();
7979
80 /// createDebugIRPass - Create and return a pass that modifies a module's
81 /// debug metadata to point back to IR instead of the original source file
82 ModulePass *createDebugIRPass(StringRef FilenamePostfix);
83
8084 } // End llvm namespace
8185
8286 #endif
692692 if (MDNode *T = dyn_cast_or_null(DbgNode->getOperand(18)))
693693 return DIArray(T);
694694 return DIArray();
695 }
696
697 void DIScope::setFilename(StringRef Name, LLVMContext &Context) {
698 if (!DbgNode)
699 return;
700 MDString *MDName(MDString::get(Context, Name));
701 const_cast(getNodeField(DbgNode, 1))->replaceOperandWith(0, MDName);
695702 }
696703
697704 StringRef DIScope::getFilename() const {
11 AddressSanitizer.cpp
22 BlackList.cpp
33 BoundsChecking.cpp
4 DebugIR.cpp
45 EdgeProfiling.cpp
56 GCOVProfiling.cpp
67 MemorySanitizer.cpp
0 //===--- DebugIR.cpp - Transform debug metadata to allow debugging IR -----===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // A Module transform pass that emits a succinct version of the IR and replaces
10 // the source file metadata to allow debuggers to step through the IR.
11 //
12 // The location where the IR file is emitted is the same as the directory
13 // operand of the !llvm.dbg.cu metadata node present in the input module. The
14 // file name is constructed from the original file name by stripping the
15 // extension and replacing it with "-debug.ll" or the Postfix string specified
16 // at construction.
17 //
18 // FIXME: instead of replacing debug metadata, additional metadata should be
19 // used to point capable debuggers to the IR file without destroying the
20 // mapping to the original source file.
21 //
22 // FIXME: this pass should not depend on the existance of debug metadata in
23 // the module as it does now. Instead, it should use DIBuilder to create the
24 // required metadata.
25 //
26 //===----------------------------------------------------------------------===//
27
28 #include
29
30 #include "llvm/ADT/ArrayRef.h"
31 #include "llvm/ADT/SmallSet.h"
32 #include "llvm/DebugInfo.h"
33 #include "llvm/DIBuilder.h"
34 #include "llvm/IR/AsmWriter.h"
35 #include "llvm/IR/Instruction.h"
36 #include "llvm/IR/IntrinsicInst.h"
37 #include "llvm/IR/Module.h"
38 #include "llvm/Pass.h"
39 #include "llvm/Transforms/Instrumentation.h"
40 #include "llvm/Support/Debug.h"
41 #include "llvm/Support/ToolOutputFile.h"
42 #include "llvm/Support/raw_ostream.h"
43 using namespace llvm;
44
45 namespace {
46
47 /// Returns true if Node's name contains the string "llvm.dbg"
48 bool isDebugNamedMetadata(const NamedMDNode *Node) {
49 return Node->getName().str().find("llvm.dbg") != std::string::npos;
50 }
51
52 /// Returns true if Inst is a call to llvm.dbg.value or llvm.dbg.declare
53 bool isDebugIntrinsic(const IntrinsicInst *Inst) {
54 Intrinsic::ID id = Inst->getIntrinsicID();
55 return id == Intrinsic::dbg_value || id == Intrinsic::dbg_declare;
56 }
57
58 /// An AssemblyWriter which generates a succinct representation of the module
59 /// (without debug intrinsics or metadata) suitable for debugging. As IR
60 /// instructions are printed, !dbg metadata nodes are added (or updated)
61 /// to point to the corresponding line in the generated IR file instead
62 /// of the original source file. The input module must have been constructed
63 /// with debug metadata (i.e. clang -g).
64 class IRDebugInfoHelper : public llvm::AssemblyWriter {
65 /// Directory of debug metadata
66 const DebugInfoFinder &Finder;
67
68 /// Flags to control the verbosity of the generated IR file
69 bool hideDebugIntrinsics;
70 bool hideDebugMetadata;
71
72 /// Set to track metadata nodes to be printed (used only when
73 /// printDebugMetadata == false)
74 SmallSet NonDebugNodes;
75
76 public:
77 IRDebugInfoHelper(
78 formatted_raw_ostream &o, const Module *M,
79 AssemblyAnnotationWriter *AAW, const DebugInfoFinder &Finder,
80 bool hideDebugIntrinsics = true, bool hideDebugMetadata = true)
81 : AssemblyWriter(o, M, AAW), Finder(Finder),
82 hideDebugIntrinsics(hideDebugIntrinsics),
83 hideDebugMetadata(hideDebugMetadata) {}
84
85 private:
86 virtual void printInstruction(const Instruction &I) {
87 DebugLoc Loc(I.getDebugLoc());
88
89 if (hideDebugMetadata)
90 removeDebugMetadata(const_cast(I));
91
92 AssemblyWriter::printInstruction(I);
93 Out.flush();
94 // Adjust line number by 1 because we have not yet printed the \n
95 unsigned Line = Out.getLine() + 1;
96
97 DebugLoc NewLoc;
98 if (!Loc.isUnknown())
99 // I had a previous debug location: re-use the DebugLoc
100 NewLoc = DebugLoc::get(Line, /* FIXME: support columns */ 0,
101 Loc.getScope(I.getContext()),
102 Loc.getInlinedAt(I.getContext()));
103 else if (MDNode *scope = findFunctionMD(I.getParent()->getParent()))
104 // I had no previous debug location, but M has some debug information
105 NewLoc = DebugLoc::get(Line, 0, scope, /*FIXME: inlined instructions*/ 0);
106 else
107 // Neither I nor M has any debug information -- nothing to do here.
108 // FIXME: support debugging of undecorated IR (generated by clang without
109 // the -g option)
110 return;
111
112 if (hideDebugMetadata)
113 saveNonDebugMetadata(I);
114
115 addDebugLocation(const_cast(I), NewLoc);
116 }
117
118 virtual void printInstructionLine(const Instruction &I) {
119 if (hideDebugIntrinsics)
120 if (const IntrinsicInst *II = dyn_cast(&I))
121 if (isDebugIntrinsic(II))
122 return;
123 AssemblyWriter::printInstructionLine(I);
124 }
125
126 virtual void writeMDNode(unsigned Slot, const MDNode *Node) {
127 if (hideDebugMetadata == false || isDebugMetadata(Node) == false)
128 AssemblyWriter::writeMDNode(Slot, Node);
129 }
130
131 virtual void printNamedMDNode(const NamedMDNode *NMD) {
132 if (hideDebugMetadata == false || isDebugNamedMetadata(NMD) == false)
133 AssemblyWriter::printNamedMDNode(NMD);
134 }
135
136 /// Returns the MDNode that corresponds with F
137 MDNode *findFunctionMD(const Function *F) {
138 for (DebugInfoFinder::iterator i = Finder.subprogram_begin(),
139 e = Finder.subprogram_end();
140 i != e; ++i) {
141 DISubprogram S(*i);
142 if (S.getFunction() == F)
143 return *i;
144 }
145 // cannot find F -- likely means there is no debug information
146 return 0;
147 }
148
149 /// Saves all non-debug metadata attached to I
150 void saveNonDebugMetadata(const Instruction &I) {
151 typedef SmallVector, 4> MDNodeVector;
152 MDNodeVector Others;
153 I.getAllMetadataOtherThanDebugLoc(Others);
154 for (MDNodeVector::iterator i = Others.begin(), e = Others.end(); i != e;
155 ++i)
156 NonDebugNodes.insert(i->second);
157 }
158
159 /// Returns true if Node was not saved as non-debug metadata with
160 /// saveNonDebugMetadata(), false otherwise.
161 bool isDebugMetadata(const MDNode *Node) {
162 return NonDebugNodes.count(Node) == 0;
163 }
164
165 void removeDebugMetadata(Instruction &I) {
166 if (I.getMetadata(LLVMContext::MD_dbg))
167 I.setMetadata(LLVMContext::MD_dbg, 0);
168 }
169
170 void addDebugLocation(Instruction &I, DebugLoc Loc) {
171 MDNode *MD = Loc.getAsMDNode(I.getContext());
172 I.setMetadata(LLVMContext::MD_dbg, MD);
173 }
174 };
175
176 class DebugIR : public ModulePass {
177 std::string Postfix;
178 std::string Filename;
179 DebugInfoFinder Finder;
180
181 public:
182 static char ID;
183
184 DebugIR() : ModulePass(ID), Postfix("-debug.ll") {}
185
186 /// Customize the postfix string used to replace the extension of the
187 /// original filename that appears in the !llvm.dbg.cu metadata node.
188 DebugIR(StringRef postfix) : ModulePass(ID), Postfix(postfix) {}
189
190 private:
191 // Modify the filename embedded in the Compilation-Unit debug information of M
192 bool replaceFilename(Module &M) {
193 bool changed = false;
194
195 // Sanity check -- if llvm.dbg.cu node exists, the DebugInfoFinder
196 // better have found at least one CU!
197 if (M.getNamedMetadata("llvm.dbg.cu"))
198 assert(Finder.compile_unit_count() > 0 &&
199 "Found no compile units but llvm.dbg.cu node exists");
200
201 for (DebugInfoFinder::iterator i = Finder.compile_unit_begin(),
202 e = Finder.compile_unit_end();
203 i != e; ++i) {
204 DICompileUnit CU(*i);
205 Filename = CU.getFilename();
206
207 // Replace extension with postfix
208 size_t dot = Filename.find_last_of(".");
209 if (dot != std::string::npos)
210 Filename.erase(dot);
211 Filename += Postfix;
212
213 CU.setFilename(Filename, M.getContext());
214 changed = true;
215 }
216 return changed;
217 }
218
219 void writeAndUpdateDebugIRFile(Module *M) {
220 std::string error;
221 tool_output_file OutFile(Filename.c_str(), error);
222 OutFile.keep();
223 formatted_raw_ostream OS;
224 OS.setStream(OutFile.os(), false);
225
226 IRDebugInfoHelper W(OS, M, 0, Finder);
227 W.printModule(M);
228 }
229
230 bool runOnModule(Module &M) {
231 Finder.processModule(M);
232 bool changed = replaceFilename(M);
233 if (changed)
234 writeAndUpdateDebugIRFile(&M);
235 return changed;
236 }
237 };
238
239 } // anonymous namespace
240
241 char DebugIR::ID = 0;
242 INITIALIZE_PASS(DebugIR, "debug-ir", "Enable debugging IR", false, false)
243 ModulePass *llvm::createDebugIRPass(StringRef FilenamePostfix) {
244 return new DebugIR(FilenamePostfix);
245 }
566566 // Initialize passes
567567 PassRegistry &Registry = *PassRegistry::getPassRegistry();
568568 initializeCore(Registry);
569 initializeDebugIRPass(Registry);
569570 initializeScalarOpts(Registry);
570571 initializeObjCARCOpts(Registry);
571572 initializeVectorization(Registry);