1 /* 2 * Copyright 2015, The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "bcc/Assert.h" 18 #include "bcc/Renderscript/RSTransforms.h" 19 #include "bcc/Support/Log.h" 20 #include "bcinfo/MetadataExtractor.h" 21 22 #include <llvm/Pass.h> 23 #include <llvm/IR/DIBuilder.h> 24 #include <llvm/IR/Function.h> 25 #include <llvm/IR/InstIterator.h> 26 #include <llvm/IR/Instructions.h> 27 #include <llvm/IR/IRBuilder.h> 28 #include <llvm/IR/Module.h> 29 30 namespace { 31 32 const char DEBUG_SOURCE_PATH[] = "/opt/renderscriptdebugger/1"; 33 const char DEBUG_GENERATED_FILE[] = "generated.rs"; 34 const char DEBUG_PROTOTYPE_VAR_NAME[] = "rsDebugOuterForeachT"; 35 const char DEBUG_COMPILE_UNIT_MDNAME[] = "llvm.dbg.cu"; 36 37 /* 38 * LLVM pass to attach debug information to the bits of code 39 * generated by the compiler. 40 */ 41 class RSAddDebugInfoPass : public llvm::ModulePass { 42 43 public: 44 // Pass ID 45 static char ID; 46 47 RSAddDebugInfoPass() : ModulePass(ID), kernelTypeMD(nullptr), 48 sourceFileName(nullptr), emptyExpr(nullptr), abiMetaCU(nullptr), 49 indexVarType(nullptr) { 50 } 51 52 virtual bool runOnModule(llvm::Module &Module) { 53 // Gather information about this bcc module. 54 bcinfo::MetadataExtractor me(&Module); 55 if (!me.extract()) { 56 ALOGE("Could not extract metadata from module!"); 57 return false; 58 } 59 60 size_t nForEachKernels = me.getExportForEachSignatureCount(); 61 const char **forEachKernels = me.getExportForEachNameList(); 62 63 // Set up the debug info builder. 64 llvm::DIBuilder DebugInfo(Module); 65 66 initializeDebugInfo(DebugInfo, Module); 67 68 // Attach DI metadata to each generated function. 69 for (size_t i = 0; i < nForEachKernels; ++i) { 70 std::string expandedName = forEachKernels[i]; 71 expandedName += ".expand"; 72 73 if (llvm::Function *kernelFunc = Module.getFunction(expandedName)) 74 attachDebugInfo(DebugInfo, *kernelFunc); 75 } 76 77 DebugInfo.finalize(); 78 79 cleanupDebugInfo(Module); 80 81 return true; 82 } 83 84 private: 85 86 // @brief Initialize the debug info generation. 87 // 88 // This method does a couple of things: 89 // * Look up debug metadata for kernel ABI and store it if present. 90 // * Store a couple of useful pieces of debug metadata in member 91 // variables so they do not have to be created multiple times. 92 void initializeDebugInfo(llvm::DIBuilder &DebugInfo, 93 const llvm::Module &Module) { 94 llvm::LLVMContext &ctx = Module.getContext(); 95 96 // Start generating debug information for bcc-generated code. 97 DebugInfo.createCompileUnit(llvm::dwarf::DW_LANG_C99, 98 DEBUG_GENERATED_FILE, DEBUG_SOURCE_PATH, 99 "RS", false, "", 0); 100 101 // Pre-generate and save useful pieces of debug metadata. 102 sourceFileName = DebugInfo.createFile(DEBUG_GENERATED_FILE, DEBUG_SOURCE_PATH); 103 emptyExpr = DebugInfo.createExpression(); 104 105 // Lookup compile unit with kernel ABI debug metadata. 106 llvm::NamedMDNode *mdCompileUnitList = 107 Module.getNamedMetadata(DEBUG_COMPILE_UNIT_MDNAME); 108 bccAssert(mdCompileUnitList != nullptr && 109 "DebugInfo pass could not find any existing compile units."); 110 111 llvm::DIGlobalVariable *kernelPrototypeVarMD = nullptr; 112 for (llvm::MDNode* CUNode : mdCompileUnitList->operands()) { 113 if (auto *CU = llvm::dyn_cast<llvm::DICompileUnit>(CUNode)) { 114 for (llvm::DIGlobalVariable* GV : CU->getGlobalVariables()) { 115 if (GV->getDisplayName() == DEBUG_PROTOTYPE_VAR_NAME) { 116 kernelPrototypeVarMD = GV; 117 abiMetaCU = CU; 118 break; 119 } 120 } 121 if (kernelPrototypeVarMD != nullptr) 122 break; 123 } 124 } 125 126 // Lookup the expanded function interface type metadata. 127 llvm::MDTuple *kernelPrototypeMD = nullptr; 128 if (kernelPrototypeVarMD != nullptr) { 129 // Dig into the metadata to look for function prototype. 130 llvm::DIDerivedType *DT = nullptr; 131 DT = llvm::cast<llvm::DIDerivedType>(kernelPrototypeVarMD->getType()); 132 DT = llvm::cast<llvm::DIDerivedType>(DT->getBaseType()); 133 llvm::DISubroutineType *ST = llvm::cast<llvm::DISubroutineType>(DT->getBaseType()); 134 kernelPrototypeMD = llvm::cast<llvm::MDTuple>(ST->getRawTypeArray()); 135 136 indexVarType = llvm::dyn_cast_or_null<llvm::DIType>( 137 kernelPrototypeMD->getOperand(2)); 138 } 139 // Fall back to the function type of void() if there is no proper debug info. 140 if (kernelPrototypeMD == nullptr) 141 kernelPrototypeMD = llvm::MDTuple::get(ctx, {nullptr}); 142 // Fall back to unspecified type if we don't have a proper index type. 143 if (indexVarType == nullptr) 144 indexVarType = DebugInfo.createBasicType("uint32_t", 32, 32, 145 llvm::dwarf::DW_ATE_unsigned); 146 147 // Capture the expanded kernel type debug info. 148 kernelTypeMD = DebugInfo.createSubroutineType(kernelPrototypeMD); 149 } 150 151 /// @brief Add debug information to a generated function. 152 /// 153 /// This procedure adds the following pieces of debug information 154 /// to the function specified by Func: 155 /// * Entry for the function to the current compile unit. 156 /// * Adds debug info entries for each function argument. 157 /// * Adds debug info entry for the rsIndex local variable. 158 /// * File/line information to each instruction set to generates.rs:1. 159 void attachDebugInfo(llvm::DIBuilder &DebugInfo, llvm::Function &Func) { 160 // Lookup the current thread coordinate variable. 161 llvm::AllocaInst* indexVar = nullptr; 162 for (llvm::Instruction &inst : llvm::instructions(Func)) { 163 if (auto *allocaInst = llvm::dyn_cast<llvm::AllocaInst>(&inst)) { 164 if (allocaInst->getName() == bcc::BCC_INDEX_VAR_NAME) { 165 indexVar = allocaInst; 166 break; 167 } 168 } 169 } 170 171 // Create function-level debug metadata. 172 llvm::DISubprogram *ExpandedFunc = DebugInfo.createFunction( 173 sourceFileName, // scope 174 Func.getName(), Func.getName(), 175 sourceFileName, 1, kernelTypeMD, 176 false, true, 1, 0, false 177 ); 178 179 // IRBuilder for allocating variables for arguments. 180 llvm::IRBuilder<> ir(&*Func.getEntryBlock().begin()); 181 182 // Walk through the argument list and expanded function prototype 183 // debuginfo in lockstep to create debug entries for 184 // the expanded function arguments. 185 unsigned argIdx = 1; 186 llvm::MDTuple *argTypes = kernelTypeMD->getTypeArray().get(); 187 for (llvm::Argument &arg : Func.getArgumentList()) { 188 // Stop processing arguments if we run out of debug info. 189 if (argIdx >= argTypes->getNumOperands()) 190 break; 191 192 // Create debuginfo entry for the argument and advance. 193 llvm::DILocalVariable *argVarDI = DebugInfo.createParameterVariable( 194 ExpandedFunc, arg.getName(), argIdx, sourceFileName, 1, 195 llvm::cast<llvm::DIType>(argTypes->getOperand(argIdx).get()), 196 true, 0 197 ); 198 199 // Annotate the argument variable in the IR. 200 llvm::AllocaInst *argVar = 201 ir.CreateAlloca(arg.getType(), nullptr, arg.getName() + ".var"); 202 llvm::StoreInst *argStore = ir.CreateStore(&arg, argVar); 203 llvm::LoadInst *loadedVar = ir.CreateLoad(argVar, arg.getName() + ".l"); 204 DebugInfo.insertDeclare(argVar, argVarDI, emptyExpr, 205 llvm::DebugLoc::get(1, 1, ExpandedFunc), loadedVar); 206 for (llvm::Use &u : arg.uses()) 207 if (u.getUser() != argStore) 208 u.set(loadedVar); 209 argIdx++; 210 } 211 212 // Annotate the index variable with metadata. 213 if (indexVar) { 214 // Debug information for loop index variable. 215 llvm::DILocalVariable *indexVarDI = DebugInfo.createAutoVariable( 216 ExpandedFunc, bcc::BCC_INDEX_VAR_NAME, sourceFileName, 1, 217 indexVarType, true 218 ); 219 220 // Insert declaration annotation in the instruction stream. 221 llvm::Instruction *decl = DebugInfo.insertDeclare( 222 indexVar, indexVarDI, emptyExpr, 223 llvm::DebugLoc::get(1, 1, ExpandedFunc), indexVar); 224 indexVar->moveBefore(decl); 225 } 226 227 // Attach location information to each instruction in the function. 228 for (llvm::Instruction &inst : llvm::instructions(Func)) { 229 inst.setDebugLoc(llvm::DebugLoc::get(1, 1, ExpandedFunc)); 230 } 231 } 232 233 // @brief Clean up the debug info. 234 // 235 // At the moment, it only finds the compile unit for the expanded function 236 // metadata generated by clang and removes it. 237 void cleanupDebugInfo(llvm::Module& Module) { 238 if (abiMetaCU == nullptr) 239 return; 240 241 // Remove the compile unit with the runtime interface DI. 242 llvm::SmallVector<llvm::MDNode*, 4> unitsTmp; 243 llvm::NamedMDNode *debugMD = 244 Module.getNamedMetadata(DEBUG_COMPILE_UNIT_MDNAME); 245 for (llvm::MDNode *cu : debugMD->operands()) 246 if (cu != abiMetaCU) 247 unitsTmp.push_back(cu); 248 debugMD->eraseFromParent(); 249 debugMD = Module.getOrInsertNamedMetadata(DEBUG_COMPILE_UNIT_MDNAME); 250 for (llvm::MDNode *cu : unitsTmp) 251 debugMD->addOperand(cu); 252 } 253 254 private: 255 // private attributes 256 llvm::DISubroutineType* kernelTypeMD; 257 llvm::DIFile *sourceFileName; 258 llvm::DIExpression *emptyExpr; 259 llvm::DICompileUnit *abiMetaCU; 260 llvm::DIType *indexVarType; 261 262 }; // end class RSAddDebugInfoPass 263 264 char RSAddDebugInfoPass::ID = 0; 265 static llvm::RegisterPass<RSAddDebugInfoPass> X("addrsdi", "Add RS DebugInfo Pass"); 266 267 } // end anonymous namespace 268 269 namespace bcc { 270 271 llvm::ModulePass * createRSAddDebugInfoPass() { 272 return new RSAddDebugInfoPass(); 273 } 274 275 } // end namespace bcc 276