1 // Copyright 2019 The SwiftShader Authors. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #ifndef rr_LLVMReactorDebugInfo_hpp 16 #define rr_LLVMReactorDebugInfo_hpp 17 18 #include "Reactor.hpp" 19 #include "ReactorDebugInfo.hpp" 20 21 #ifdef ENABLE_RR_DEBUG_INFO 22 23 # include <memory> 24 # include <unordered_map> 25 # include <unordered_set> 26 # include <vector> 27 28 // Forward declarations 29 namespace llvm { 30 31 class BasicBlock; 32 class ConstantFolder; 33 class DIBuilder; 34 class DICompileUnit; 35 class DIFile; 36 class DILocation; 37 class DIScope; 38 class DISubprogram; 39 class DIType; 40 class Function; 41 class Instruction; 42 class IRBuilderDefaultInserter; 43 class JITEventListener; 44 class LLVMContext; 45 class LoadedObjectInfo; 46 class Module; 47 class Type; 48 class Value; 49 50 namespace object { 51 class ObjectFile; 52 } 53 54 template<typename T, typename Inserter> 55 class IRBuilder; 56 57 } // namespace llvm 58 59 namespace rr { 60 61 class Type; 62 class Value; 63 64 // DebugInfo generates LLVM DebugInfo IR from the C++ source that calls 65 // into Reactor functions. See docs/ReactorDebugInfo.mk for more information. 66 class DebugInfo 67 { 68 public: 69 using IRBuilder = llvm::IRBuilder<llvm::ConstantFolder, llvm::IRBuilderDefaultInserter>; 70 71 DebugInfo(IRBuilder *builder, 72 llvm::LLVMContext *context, 73 llvm::Module *module, 74 llvm::Function *function); 75 76 ~DebugInfo(); 77 78 // Finalize debug info generation. Must be called before the LLVM module 79 // is built. 80 void Finalize(); 81 82 // Updates the current source location. 83 void EmitLocation(); 84 85 // Binds the value to its symbol in the source file. 86 // See docs/ReactorDebugInfo.mk for more information. 87 void EmitVariable(Value *value); 88 89 // Forcefully flush the binding of the last variable name. 90 // Used for binding the initializer of `For` loops. 91 void Flush(); 92 93 // NotifyObjectEmitted informs any attached debuggers of the JIT'd 94 // object. 95 static void NotifyObjectEmitted(uint64_t key, const llvm::object::ObjectFile &obj, const llvm::LoadedObjectInfo &l); 96 97 // NotifyFreeingObject informs any attached debuggers that the JIT'd 98 // object is now invalid. 99 static void NotifyFreeingObject(uint64_t key); 100 101 private: 102 struct Token 103 { 104 enum Kind 105 { 106 Identifier, 107 Return 108 }; 109 Kind kind; 110 std::string identifier; 111 }; 112 113 using LineTokens = std::unordered_map<unsigned int, Token>; 114 115 struct Pending 116 { 117 std::string name; 118 Location location; 119 llvm::DILocation *diLocation = nullptr; 120 llvm::Value *value = nullptr; 121 llvm::Instruction *insertAfter = nullptr; 122 llvm::BasicBlock *block = nullptr; 123 llvm::DIScope *scope = nullptr; 124 bool addNopOnNextLine = false; 125 }; 126 127 struct Scope 128 { 129 Location location; 130 llvm::DIScope *di; 131 std::unordered_set<std::string> symbols; 132 Pending pending; 133 }; 134 135 void registerBasicTypes(); 136 137 void emitPending(Scope &scope, IRBuilder *builder); 138 139 // Returns the source location of the non-Reactor calling function. 140 Location getCallerLocation() const; 141 142 // Returns the backtrace for the callstack, starting at the first 143 // non-Reactor file. If limit is non-zero, then a maximum of limit 144 // frames will be returned. 145 Backtrace getCallerBacktrace(size_t limit = 0) const; 146 147 llvm::DILocation *getLocation(const Backtrace &backtrace, size_t i); 148 149 llvm::DIType *getOrCreateType(llvm::Type *type); 150 llvm::DIFile *getOrCreateFile(const char *path); 151 LineTokens const *getOrParseFileTokens(const char *path); 152 153 // Synchronizes diScope with the current backtrace. 154 void syncScope(Backtrace const &backtrace); 155 156 IRBuilder *builder; 157 llvm::LLVMContext *context; 158 llvm::Module *module; 159 llvm::Function *function; 160 161 std::unique_ptr<llvm::DIBuilder> diBuilder; 162 llvm::DICompileUnit *diCU; 163 llvm::DISubprogram *diSubprogram; 164 llvm::DILocation *diRootLocation; 165 std::vector<Scope> diScope; 166 std::unordered_map<std::string, llvm::DIFile *> diFiles; 167 std::unordered_map<llvm::Type *, llvm::DIType *> diTypes; 168 std::unordered_map<std::string, std::unique_ptr<LineTokens>> fileTokens; 169 std::vector<void const *> pushed; 170 }; 171 172 } // namespace rr 173 174 #endif // ENABLE_RR_DEBUG_INFO 175 176 #endif // rr_LLVMReactorDebugInfo_hpp 177