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