| //===- 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; |
| } |