1 //===- Debugify.cpp - Attach synthetic debug info to everything -----------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 /// 10 /// \file This pass attaches synthetic debug info to everything. It can be used 11 /// to create targeted tests for debug info preservation. 12 /// 13 //===----------------------------------------------------------------------===// 14 15 #include "llvm/ADT/BitVector.h" 16 #include "llvm/ADT/StringExtras.h" 17 #include "llvm/IR/BasicBlock.h" 18 #include "llvm/IR/Constants.h" 19 #include "llvm/IR/DIBuilder.h" 20 #include "llvm/IR/DebugInfo.h" 21 #include "llvm/IR/Function.h" 22 #include "llvm/IR/GlobalVariable.h" 23 #include "llvm/IR/InstIterator.h" 24 #include "llvm/IR/Instruction.h" 25 #include "llvm/IR/Instructions.h" 26 #include "llvm/IR/IntrinsicInst.h" 27 #include "llvm/IR/Module.h" 28 #include "llvm/IR/Type.h" 29 #include "llvm/Pass.h" 30 #include "llvm/Support/raw_ostream.h" 31 #include "llvm/Transforms/IPO.h" 32 33 using namespace llvm; 34 35 namespace { 36 37 bool applyDebugifyMetadata(Module &M) { 38 // Skip modules with debug info. 39 if (M.getNamedMetadata("llvm.dbg.cu")) { 40 errs() << "Debugify: Skipping module with debug info\n"; 41 return false; 42 } 43 44 DIBuilder DIB(M); 45 LLVMContext &Ctx = M.getContext(); 46 47 // Get a DIType which corresponds to Ty. 48 DenseMap<uint64_t, DIType *> TypeCache; 49 auto getCachedDIType = [&](Type *Ty) -> DIType * { 50 uint64_t Size = M.getDataLayout().getTypeAllocSizeInBits(Ty); 51 DIType *&DTy = TypeCache[Size]; 52 if (!DTy) { 53 std::string Name = "ty" + utostr(Size); 54 DTy = DIB.createBasicType(Name, Size, dwarf::DW_ATE_unsigned); 55 } 56 return DTy; 57 }; 58 59 unsigned NextLine = 1; 60 unsigned NextVar = 1; 61 auto File = DIB.createFile(M.getName(), "/"); 62 auto CU = 63 DIB.createCompileUnit(dwarf::DW_LANG_C, DIB.createFile(M.getName(), "/"), 64 "debugify", /*isOptimized=*/true, "", 0); 65 66 // Visit each instruction. 67 for (Function &F : M) { 68 if (F.isDeclaration()) 69 continue; 70 71 auto SPType = DIB.createSubroutineType(DIB.getOrCreateTypeArray(None)); 72 bool IsLocalToUnit = F.hasPrivateLinkage() || F.hasInternalLinkage(); 73 auto SP = 74 DIB.createFunction(CU, F.getName(), F.getName(), File, NextLine, SPType, 75 IsLocalToUnit, F.hasExactDefinition(), NextLine, 76 DINode::FlagZero, /*isOptimized=*/true); 77 F.setSubprogram(SP); 78 for (BasicBlock &BB : F) { 79 // Attach debug locations. 80 for (Instruction &I : BB) 81 I.setDebugLoc(DILocation::get(Ctx, NextLine++, 1, SP)); 82 83 // Attach debug values. 84 for (Instruction &I : BB) { 85 // Skip void-valued instructions. 86 if (I.getType()->isVoidTy()) 87 continue; 88 89 // Skip the terminator instruction and any just-inserted intrinsics. 90 if (isa<TerminatorInst>(&I) || isa<DbgValueInst>(&I)) 91 break; 92 93 std::string Name = utostr(NextVar++); 94 const DILocation *Loc = I.getDebugLoc().get(); 95 auto LocalVar = DIB.createAutoVariable(SP, Name, File, Loc->getLine(), 96 getCachedDIType(I.getType()), 97 /*AlwaysPreserve=*/true); 98 DIB.insertDbgValueIntrinsic(&I, LocalVar, DIB.createExpression(), Loc, 99 BB.getTerminator()); 100 } 101 } 102 DIB.finalizeSubprogram(SP); 103 } 104 DIB.finalize(); 105 106 // Track the number of distinct lines and variables. 107 NamedMDNode *NMD = M.getOrInsertNamedMetadata("llvm.debugify"); 108 auto *IntTy = Type::getInt32Ty(Ctx); 109 auto addDebugifyOperand = [&](unsigned N) { 110 NMD->addOperand(MDNode::get( 111 Ctx, ValueAsMetadata::getConstant(ConstantInt::get(IntTy, N)))); 112 }; 113 addDebugifyOperand(NextLine - 1); // Original number of lines. 114 addDebugifyOperand(NextVar - 1); // Original number of variables. 115 return true; 116 } 117 118 void checkDebugifyMetadata(Module &M) { 119 // Skip modules without debugify metadata. 120 NamedMDNode *NMD = M.getNamedMetadata("llvm.debugify"); 121 if (!NMD) 122 return; 123 124 auto getDebugifyOperand = [&](unsigned Idx) -> unsigned { 125 return mdconst::extract<ConstantInt>(NMD->getOperand(Idx)->getOperand(0)) 126 ->getZExtValue(); 127 }; 128 unsigned OriginalNumLines = getDebugifyOperand(0); 129 unsigned OriginalNumVars = getDebugifyOperand(1); 130 bool HasErrors = false; 131 132 // Find missing lines. 133 BitVector MissingLines{OriginalNumLines, true}; 134 for (Function &F : M) { 135 for (Instruction &I : instructions(F)) { 136 if (isa<DbgValueInst>(&I)) 137 continue; 138 139 auto DL = I.getDebugLoc(); 140 if (DL) { 141 MissingLines.reset(DL.getLine() - 1); 142 continue; 143 } 144 145 outs() << "ERROR: Instruction with empty DebugLoc -- "; 146 I.print(outs()); 147 outs() << "\n"; 148 HasErrors = true; 149 } 150 } 151 for (unsigned Idx : MissingLines.set_bits()) 152 outs() << "WARNING: Missing line " << Idx + 1 << "\n"; 153 154 // Find missing variables. 155 BitVector MissingVars{OriginalNumVars, true}; 156 for (Function &F : M) { 157 for (Instruction &I : instructions(F)) { 158 auto *DVI = dyn_cast<DbgValueInst>(&I); 159 if (!DVI) 160 continue; 161 162 unsigned Var = ~0U; 163 (void)to_integer(DVI->getVariable()->getName(), Var, 10); 164 assert(Var <= OriginalNumVars && "Unexpected name for DILocalVariable"); 165 MissingVars.reset(Var - 1); 166 } 167 } 168 for (unsigned Idx : MissingVars.set_bits()) 169 outs() << "ERROR: Missing variable " << Idx + 1 << "\n"; 170 HasErrors |= MissingVars.count() > 0; 171 172 outs() << "CheckDebugify: " << (HasErrors ? "FAIL" : "PASS") << "\n"; 173 } 174 175 /// Attach synthetic debug info to everything. 176 struct DebugifyPass : public ModulePass { 177 bool runOnModule(Module &M) override { return applyDebugifyMetadata(M); } 178 179 DebugifyPass() : ModulePass(ID) {} 180 181 void getAnalysisUsage(AnalysisUsage &AU) const override { 182 AU.setPreservesAll(); 183 } 184 185 static char ID; // Pass identification. 186 }; 187 188 /// Check debug info inserted by -debugify for completeness. 189 struct CheckDebugifyPass : public ModulePass { 190 bool runOnModule(Module &M) override { 191 checkDebugifyMetadata(M); 192 return false; 193 } 194 195 CheckDebugifyPass() : ModulePass(ID) {} 196 197 void getAnalysisUsage(AnalysisUsage &AU) const override { 198 AU.setPreservesAll(); 199 } 200 201 static char ID; // Pass identification. 202 }; 203 204 } // end anonymous namespace 205 206 char DebugifyPass::ID = 0; 207 static RegisterPass<DebugifyPass> X("debugify", 208 "Attach debug info to everything"); 209 210 char CheckDebugifyPass::ID = 0; 211 static RegisterPass<CheckDebugifyPass> Y("check-debugify", 212 "Check debug info from -debugify"); 213