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/Config/config.h" 16 #include "llvm/CodeGen/MachineFunction.h" 17 #include "llvm/ExecutionEngine/JITEventListener.h" 18 #include "llvm/ExecutionEngine/OProfileWrapper.h" 19 #include "llvm/ExecutionEngine/RuntimeDyld.h" 20 #include "llvm/IR/DebugInfo.h" 21 #include "llvm/IR/Function.h" 22 #include "llvm/Object/ObjectFile.h" 23 #include "llvm/Object/SymbolSize.h" 24 #include "llvm/Support/Debug.h" 25 #include "llvm/Support/Errno.h" 26 #include "llvm/Support/raw_ostream.h" 27 #include <dirent.h> 28 #include <fcntl.h> 29 30 using namespace llvm; 31 using namespace llvm::object; 32 33 #define DEBUG_TYPE "oprofile-jit-event-listener" 34 35 namespace { 36 37 class OProfileJITEventListener : public JITEventListener { 38 std::unique_ptr<OProfileWrapper> Wrapper; 39 40 void initialize(); 41 std::map<const char*, OwningBinary<ObjectFile>> DebugObjects; 42 43 public: 44 OProfileJITEventListener(std::unique_ptr<OProfileWrapper> LibraryWrapper) 45 : Wrapper(std::move(LibraryWrapper)) { 46 initialize(); 47 } 48 49 ~OProfileJITEventListener(); 50 51 void NotifyObjectEmitted(const ObjectFile &Obj, 52 const RuntimeDyld::LoadedObjectInfo &L) override; 53 54 void NotifyFreeingObject(const ObjectFile &Obj) override; 55 }; 56 57 void OProfileJITEventListener::initialize() { 58 if (!Wrapper->op_open_agent()) { 59 const std::string err_str = sys::StrError(); 60 DEBUG(dbgs() << "Failed to connect to OProfile agent: " << err_str << "\n"); 61 } else { 62 DEBUG(dbgs() << "Connected to OProfile agent.\n"); 63 } 64 } 65 66 OProfileJITEventListener::~OProfileJITEventListener() { 67 if (Wrapper->isAgentAvailable()) { 68 if (Wrapper->op_close_agent() == -1) { 69 const std::string err_str = sys::StrError(); 70 DEBUG(dbgs() << "Failed to disconnect from OProfile agent: " 71 << err_str << "\n"); 72 } else { 73 DEBUG(dbgs() << "Disconnected from OProfile agent.\n"); 74 } 75 } 76 } 77 78 void OProfileJITEventListener::NotifyObjectEmitted( 79 const ObjectFile &Obj, 80 const RuntimeDyld::LoadedObjectInfo &L) { 81 if (!Wrapper->isAgentAvailable()) { 82 return; 83 } 84 85 OwningBinary<ObjectFile> DebugObjOwner = L.getObjectForDebug(Obj); 86 const ObjectFile &DebugObj = *DebugObjOwner.getBinary(); 87 88 // Use symbol info to iterate functions in the object. 89 for (const std::pair<SymbolRef, uint64_t> &P : computeSymbolSizes(DebugObj)) { 90 SymbolRef Sym = P.first; 91 if (Sym.getType() != SymbolRef::ST_Function) 92 continue; 93 94 ErrorOr<StringRef> NameOrErr = Sym.getName(); 95 if (NameOrErr.getError()) 96 continue; 97 StringRef Name = *NameOrErr; 98 ErrorOr<uint64_t> AddrOrErr = Sym.getAddress(); 99 if (AddrOrErr.getError()) 100 continue; 101 uint64_t Addr = *AddrOrErr; 102 uint64_t Size = P.second; 103 104 if (Wrapper->op_write_native_code(Name.data(), Addr, (void *)Addr, Size) == 105 -1) { 106 DEBUG(dbgs() << "Failed to tell OProfile about native function " << Name 107 << " at [" << (void *)Addr << "-" << ((char *)Addr + Size) 108 << "]\n"); 109 continue; 110 } 111 // TODO: support line number info (similar to IntelJITEventListener.cpp) 112 } 113 114 DebugObjects[Obj.getData().data()] = std::move(DebugObjOwner); 115 } 116 117 void OProfileJITEventListener::NotifyFreeingObject(const ObjectFile &Obj) { 118 if (Wrapper->isAgentAvailable()) { 119 120 // If there was no agent registered when the original object was loaded then 121 // we won't have created a debug object for it, so bail out. 122 if (DebugObjects.find(Obj.getData().data()) == DebugObjects.end()) 123 return; 124 125 const ObjectFile &DebugObj = *DebugObjects[Obj.getData().data()].getBinary(); 126 127 // Use symbol info to iterate functions in the object. 128 for (symbol_iterator I = DebugObj.symbol_begin(), 129 E = DebugObj.symbol_end(); 130 I != E; ++I) { 131 if (I->getType() == SymbolRef::ST_Function) { 132 ErrorOr<uint64_t> AddrOrErr = I->getAddress(); 133 if (AddrOrErr.getError()) 134 continue; 135 uint64_t Addr = *AddrOrErr; 136 137 if (Wrapper->op_unload_native_code(Addr) == -1) { 138 DEBUG(dbgs() 139 << "Failed to tell OProfile about unload of native function at " 140 << (void*)Addr << "\n"); 141 continue; 142 } 143 } 144 } 145 } 146 147 DebugObjects.erase(Obj.getData().data()); 148 } 149 150 } // anonymous namespace. 151 152 namespace llvm { 153 JITEventListener *JITEventListener::createOProfileJITEventListener() { 154 return new OProfileJITEventListener(llvm::make_unique<OProfileWrapper>()); 155 } 156 157 } // namespace llvm 158 159