1 //===-- OProfileJITEventListener.cpp - Tell OProfile about JITted code ----===// 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 // This file defines a JITEventListener object that uses OProfileWrapper to tell 11 // oprofile about JITted functions, including source line information. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #include "llvm-c/ExecutionEngine.h" 16 #include "llvm/CodeGen/MachineFunction.h" 17 #include "llvm/Config/config.h" 18 #include "llvm/DebugInfo/DWARF/DWARFContext.h" 19 #include "llvm/ExecutionEngine/JITEventListener.h" 20 #include "llvm/ExecutionEngine/OProfileWrapper.h" 21 #include "llvm/ExecutionEngine/RuntimeDyld.h" 22 #include "llvm/IR/DebugInfo.h" 23 #include "llvm/IR/Function.h" 24 #include "llvm/Object/ObjectFile.h" 25 #include "llvm/Object/SymbolSize.h" 26 #include "llvm/Support/Debug.h" 27 #include "llvm/Support/Errno.h" 28 #include "llvm/Support/raw_ostream.h" 29 #include <dirent.h> 30 #include <fcntl.h> 31 32 using namespace llvm; 33 using namespace llvm::object; 34 35 #define DEBUG_TYPE "oprofile-jit-event-listener" 36 37 namespace { 38 39 class OProfileJITEventListener : public JITEventListener { 40 std::unique_ptr<OProfileWrapper> Wrapper; 41 42 void initialize(); 43 std::map<const char*, OwningBinary<ObjectFile>> DebugObjects; 44 45 public: 46 OProfileJITEventListener(std::unique_ptr<OProfileWrapper> LibraryWrapper) 47 : Wrapper(std::move(LibraryWrapper)) { 48 initialize(); 49 } 50 51 ~OProfileJITEventListener(); 52 53 void NotifyObjectEmitted(const ObjectFile &Obj, 54 const RuntimeDyld::LoadedObjectInfo &L) override; 55 56 void NotifyFreeingObject(const ObjectFile &Obj) override; 57 }; 58 59 void OProfileJITEventListener::initialize() { 60 if (!Wrapper->op_open_agent()) { 61 const std::string err_str = sys::StrError(); 62 LLVM_DEBUG(dbgs() << "Failed to connect to OProfile agent: " << err_str 63 << "\n"); 64 } else { 65 LLVM_DEBUG(dbgs() << "Connected to OProfile agent.\n"); 66 } 67 } 68 69 OProfileJITEventListener::~OProfileJITEventListener() { 70 if (Wrapper->isAgentAvailable()) { 71 if (Wrapper->op_close_agent() == -1) { 72 const std::string err_str = sys::StrError(); 73 LLVM_DEBUG(dbgs() << "Failed to disconnect from OProfile agent: " 74 << err_str << "\n"); 75 } else { 76 LLVM_DEBUG(dbgs() << "Disconnected from OProfile agent.\n"); 77 } 78 } 79 } 80 81 void OProfileJITEventListener::NotifyObjectEmitted( 82 const ObjectFile &Obj, 83 const RuntimeDyld::LoadedObjectInfo &L) { 84 if (!Wrapper->isAgentAvailable()) { 85 return; 86 } 87 88 OwningBinary<ObjectFile> DebugObjOwner = L.getObjectForDebug(Obj); 89 const ObjectFile &DebugObj = *DebugObjOwner.getBinary(); 90 std::unique_ptr<DIContext> Context = DWARFContext::create(DebugObj); 91 92 // Use symbol info to iterate functions in the object. 93 for (const std::pair<SymbolRef, uint64_t> &P : computeSymbolSizes(DebugObj)) { 94 SymbolRef Sym = P.first; 95 if (!Sym.getType() || *Sym.getType() != SymbolRef::ST_Function) 96 continue; 97 98 Expected<StringRef> NameOrErr = Sym.getName(); 99 if (!NameOrErr) 100 continue; 101 StringRef Name = *NameOrErr; 102 Expected<uint64_t> AddrOrErr = Sym.getAddress(); 103 if (!AddrOrErr) 104 continue; 105 uint64_t Addr = *AddrOrErr; 106 uint64_t Size = P.second; 107 108 if (Wrapper->op_write_native_code(Name.data(), Addr, (void *)Addr, Size) == 109 -1) { 110 LLVM_DEBUG(dbgs() << "Failed to tell OProfile about native function " 111 << Name << " at [" << (void *)Addr << "-" 112 << ((char *)Addr + Size) << "]\n"); 113 continue; 114 } 115 116 DILineInfoTable Lines = Context->getLineInfoForAddressRange(Addr, Size); 117 size_t i = 0; 118 size_t num_entries = Lines.size(); 119 struct debug_line_info *debug_line; 120 debug_line = (struct debug_line_info *)calloc( 121 num_entries, sizeof(struct debug_line_info)); 122 123 for (auto& It : Lines) { 124 debug_line[i].vma = (unsigned long)It.first; 125 debug_line[i].lineno = It.second.Line; 126 debug_line[i].filename = 127 const_cast<char *>(Lines.front().second.FileName.c_str()); 128 ++i; 129 } 130 131 if (Wrapper->op_write_debug_line_info((void *)Addr, num_entries, 132 debug_line) == -1) { 133 LLVM_DEBUG(dbgs() << "Failed to tell OProfiler about debug object at [" 134 << (void *)Addr << "-" << ((char *)Addr + Size) 135 << "]\n"); 136 continue; 137 } 138 } 139 140 DebugObjects[Obj.getData().data()] = std::move(DebugObjOwner); 141 } 142 143 void OProfileJITEventListener::NotifyFreeingObject(const ObjectFile &Obj) { 144 if (Wrapper->isAgentAvailable()) { 145 146 // If there was no agent registered when the original object was loaded then 147 // we won't have created a debug object for it, so bail out. 148 if (DebugObjects.find(Obj.getData().data()) == DebugObjects.end()) 149 return; 150 151 const ObjectFile &DebugObj = *DebugObjects[Obj.getData().data()].getBinary(); 152 153 // Use symbol info to iterate functions in the object. 154 for (symbol_iterator I = DebugObj.symbol_begin(), 155 E = DebugObj.symbol_end(); 156 I != E; ++I) { 157 if (I->getType() && *I->getType() == SymbolRef::ST_Function) { 158 Expected<uint64_t> AddrOrErr = I->getAddress(); 159 if (!AddrOrErr) 160 continue; 161 uint64_t Addr = *AddrOrErr; 162 163 if (Wrapper->op_unload_native_code(Addr) == -1) { 164 LLVM_DEBUG( 165 dbgs() 166 << "Failed to tell OProfile about unload of native function at " 167 << (void *)Addr << "\n"); 168 continue; 169 } 170 } 171 } 172 } 173 174 DebugObjects.erase(Obj.getData().data()); 175 } 176 177 } // anonymous namespace. 178 179 namespace llvm { 180 JITEventListener *JITEventListener::createOProfileJITEventListener() { 181 return new OProfileJITEventListener(llvm::make_unique<OProfileWrapper>()); 182 } 183 184 } // namespace llvm 185 186 LLVMJITEventListenerRef LLVMCreateOProfileJITEventListener(void) 187 { 188 return wrap(JITEventListener::createOProfileJITEventListener()); 189 } 190