| //===- DbgInfoPrinter.cpp - Print debug info in a human readable form ------==// | |
| // | |
| // The LLVM Compiler Infrastructure | |
| // | |
| // This file is distributed under the University of Illinois Open Source | |
| // License. See LICENSE.TXT for details. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // This file implements a pass that prints instructions, and associated debug | |
| // info: | |
| // | |
| // - source/line/col information | |
| // - original variable name | |
| // - original type name | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "llvm/Pass.h" | |
| #include "llvm/Function.h" | |
| #include "llvm/IntrinsicInst.h" | |
| #include "llvm/Metadata.h" | |
| #include "llvm/Module.h" | |
| #include "llvm/Assembly/Writer.h" | |
| #include "llvm/Analysis/DebugInfo.h" | |
| #include "llvm/Analysis/Passes.h" | |
| #include "llvm/Support/CFG.h" | |
| #include "llvm/Support/CommandLine.h" | |
| #include "llvm/Support/raw_ostream.h" | |
| using namespace llvm; | |
| static cl::opt<bool> | |
| PrintDirectory("print-fullpath", | |
| cl::desc("Print fullpath when printing debug info"), | |
| cl::Hidden); | |
| namespace { | |
| class PrintDbgInfo : public FunctionPass { | |
| raw_ostream &Out; | |
| void printVariableDeclaration(const Value *V); | |
| public: | |
| static char ID; // Pass identification | |
| PrintDbgInfo() : FunctionPass(ID), Out(errs()) { | |
| initializePrintDbgInfoPass(*PassRegistry::getPassRegistry()); | |
| } | |
| virtual bool runOnFunction(Function &F); | |
| virtual void getAnalysisUsage(AnalysisUsage &AU) const { | |
| AU.setPreservesAll(); | |
| } | |
| }; | |
| char PrintDbgInfo::ID = 0; | |
| } | |
| INITIALIZE_PASS(PrintDbgInfo, "print-dbginfo", | |
| "Print debug info in human readable form", false, false) | |
| FunctionPass *llvm::createDbgInfoPrinterPass() { return new PrintDbgInfo(); } | |
| /// Find the debug info descriptor corresponding to this global variable. | |
| static Value *findDbgGlobalDeclare(GlobalVariable *V) { | |
| const Module *M = V->getParent(); | |
| NamedMDNode *NMD = M->getNamedMetadata("llvm.dbg.gv"); | |
| if (!NMD) | |
| return 0; | |
| for (unsigned i = 0, e = NMD->getNumOperands(); i != e; ++i) { | |
| DIDescriptor DIG(cast<MDNode>(NMD->getOperand(i))); | |
| if (!DIG.isGlobalVariable()) | |
| continue; | |
| if (DIGlobalVariable(DIG).getGlobal() == V) | |
| return DIG; | |
| } | |
| return 0; | |
| } | |
| /// Find the debug info descriptor corresponding to this function. | |
| static Value *findDbgSubprogramDeclare(Function *V) { | |
| const Module *M = V->getParent(); | |
| NamedMDNode *NMD = M->getNamedMetadata("llvm.dbg.sp"); | |
| if (!NMD) | |
| return 0; | |
| for (unsigned i = 0, e = NMD->getNumOperands(); i != e; ++i) { | |
| DIDescriptor DIG(cast<MDNode>(NMD->getOperand(i))); | |
| if (!DIG.isSubprogram()) | |
| continue; | |
| if (DISubprogram(DIG).getFunction() == V) | |
| return DIG; | |
| } | |
| return 0; | |
| } | |
| /// Finds the llvm.dbg.declare intrinsic corresponding to this value if any. | |
| /// It looks through pointer casts too. | |
| static const DbgDeclareInst *findDbgDeclare(const Value *V) { | |
| V = V->stripPointerCasts(); | |
| if (!isa<Instruction>(V) && !isa<Argument>(V)) | |
| return 0; | |
| const Function *F = NULL; | |
| if (const Instruction *I = dyn_cast<Instruction>(V)) | |
| F = I->getParent()->getParent(); | |
| else if (const Argument *A = dyn_cast<Argument>(V)) | |
| F = A->getParent(); | |
| for (Function::const_iterator FI = F->begin(), FE = F->end(); FI != FE; ++FI) | |
| for (BasicBlock::const_iterator BI = (*FI).begin(), BE = (*FI).end(); | |
| BI != BE; ++BI) | |
| if (const DbgDeclareInst *DDI = dyn_cast<DbgDeclareInst>(BI)) | |
| if (DDI->getAddress() == V) | |
| return DDI; | |
| return 0; | |
| } | |
| static bool getLocationInfo(const Value *V, std::string &DisplayName, | |
| std::string &Type, unsigned &LineNo, | |
| std::string &File, std::string &Dir) { | |
| DICompileUnit Unit; | |
| DIType TypeD; | |
| if (GlobalVariable *GV = dyn_cast<GlobalVariable>(const_cast<Value*>(V))) { | |
| Value *DIGV = findDbgGlobalDeclare(GV); | |
| if (!DIGV) return false; | |
| DIGlobalVariable Var(cast<MDNode>(DIGV)); | |
| StringRef D = Var.getDisplayName(); | |
| if (!D.empty()) | |
| DisplayName = D; | |
| LineNo = Var.getLineNumber(); | |
| Unit = Var.getCompileUnit(); | |
| TypeD = Var.getType(); | |
| } else if (Function *F = dyn_cast<Function>(const_cast<Value*>(V))){ | |
| Value *DIF = findDbgSubprogramDeclare(F); | |
| if (!DIF) return false; | |
| DISubprogram Var(cast<MDNode>(DIF)); | |
| StringRef D = Var.getDisplayName(); | |
| if (!D.empty()) | |
| DisplayName = D; | |
| LineNo = Var.getLineNumber(); | |
| Unit = Var.getCompileUnit(); | |
| TypeD = Var.getType(); | |
| } else { | |
| const DbgDeclareInst *DDI = findDbgDeclare(V); | |
| if (!DDI) return false; | |
| DIVariable Var(cast<MDNode>(DDI->getVariable())); | |
| StringRef D = Var.getName(); | |
| if (!D.empty()) | |
| DisplayName = D; | |
| LineNo = Var.getLineNumber(); | |
| Unit = Var.getCompileUnit(); | |
| TypeD = Var.getType(); | |
| } | |
| StringRef T = TypeD.getName(); | |
| if (!T.empty()) | |
| Type = T; | |
| StringRef F = Unit.getFilename(); | |
| if (!F.empty()) | |
| File = F; | |
| StringRef D = Unit.getDirectory(); | |
| if (!D.empty()) | |
| Dir = D; | |
| return true; | |
| } | |
| void PrintDbgInfo::printVariableDeclaration(const Value *V) { | |
| std::string DisplayName, File, Directory, Type; | |
| unsigned LineNo = 0; | |
| if (!getLocationInfo(V, DisplayName, Type, LineNo, File, Directory)) | |
| return; | |
| Out << "; "; | |
| WriteAsOperand(Out, V, false, 0); | |
| if (isa<Function>(V)) | |
| Out << " is function " << DisplayName | |
| << " of type " << Type << " declared at "; | |
| else | |
| Out << " is variable " << DisplayName | |
| << " of type " << Type << " declared at "; | |
| if (PrintDirectory) | |
| Out << Directory << "/"; | |
| Out << File << ":" << LineNo << "\n"; | |
| } | |
| bool PrintDbgInfo::runOnFunction(Function &F) { | |
| if (F.isDeclaration()) | |
| return false; | |
| Out << "function " << F.getName() << "\n\n"; | |
| for (Function::iterator I = F.begin(), E = F.end(); I != E; ++I) { | |
| BasicBlock *BB = I; | |
| if (I != F.begin() && (pred_begin(BB) == pred_end(BB))) | |
| // Skip dead blocks. | |
| continue; | |
| Out << BB->getName(); | |
| Out << ":"; | |
| Out << "\n"; | |
| for (BasicBlock::const_iterator i = BB->begin(), e = BB->end(); | |
| i != e; ++i) { | |
| printVariableDeclaration(i); | |
| if (const User *U = dyn_cast<User>(i)) { | |
| for(unsigned i=0;i<U->getNumOperands();i++) | |
| printVariableDeclaration(U->getOperand(i)); | |
| } | |
| } | |
| } | |
| return false; | |
| } |