1 //===-- IntelJITEventListener.cpp - Tell Intel profiler about JITed 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 to tell Intel(R) VTune(TM) 10 // Amplifier XE 2011 about JITted functions. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "IntelJITEventsWrapper.h" 15 #include "llvm-c/ExecutionEngine.h" 16 #include "llvm/ADT/DenseMap.h" 17 #include "llvm/CodeGen/MachineFunction.h" 18 #include "llvm/Config/config.h" 19 #include "llvm/DebugInfo/DIContext.h" 20 #include "llvm/DebugInfo/DWARF/DWARFContext.h" 21 #include "llvm/ExecutionEngine/JITEventListener.h" 22 #include "llvm/IR/DebugInfo.h" 23 #include "llvm/IR/Function.h" 24 #include "llvm/IR/Metadata.h" 25 #include "llvm/IR/ValueHandle.h" 26 #include "llvm/Object/ObjectFile.h" 27 #include "llvm/Object/SymbolSize.h" 28 #include "llvm/Support/Debug.h" 29 #include "llvm/Support/Errno.h" 30 #include "llvm/Support/raw_ostream.h" 31 32 using namespace llvm; 33 using namespace llvm::object; 34 35 #define DEBUG_TYPE "amplifier-jit-event-listener" 36 37 namespace { 38 39 class IntelJITEventListener : public JITEventListener { 40 typedef DenseMap<void*, unsigned int> MethodIDMap; 41 42 std::unique_ptr<IntelJITEventsWrapper> Wrapper; 43 MethodIDMap MethodIDs; 44 45 typedef SmallVector<const void *, 64> MethodAddressVector; 46 typedef DenseMap<const void *, MethodAddressVector> ObjectMap; 47 48 ObjectMap LoadedObjectMap; 49 std::map<ObjectKey, OwningBinary<ObjectFile>> DebugObjects; 50 51 public: 52 IntelJITEventListener(IntelJITEventsWrapper* libraryWrapper) { 53 Wrapper.reset(libraryWrapper); 54 } 55 56 ~IntelJITEventListener() { 57 } 58 59 void notifyObjectLoaded(ObjectKey Key, const ObjectFile &Obj, 60 const RuntimeDyld::LoadedObjectInfo &L) override; 61 62 void notifyFreeingObject(ObjectKey Key) override; 63 }; 64 65 static LineNumberInfo DILineInfoToIntelJITFormat(uintptr_t StartAddress, 66 uintptr_t Address, 67 DILineInfo Line) { 68 LineNumberInfo Result; 69 70 Result.Offset = Address - StartAddress; 71 Result.LineNumber = Line.Line; 72 73 return Result; 74 } 75 76 static iJIT_Method_Load FunctionDescToIntelJITFormat( 77 IntelJITEventsWrapper& Wrapper, 78 const char* FnName, 79 uintptr_t FnStart, 80 size_t FnSize) { 81 iJIT_Method_Load Result; 82 memset(&Result, 0, sizeof(iJIT_Method_Load)); 83 84 Result.method_id = Wrapper.iJIT_GetNewMethodID(); 85 Result.method_name = const_cast<char*>(FnName); 86 Result.method_load_address = reinterpret_cast<void*>(FnStart); 87 Result.method_size = FnSize; 88 89 Result.class_id = 0; 90 Result.class_file_name = NULL; 91 Result.user_data = NULL; 92 Result.user_data_size = 0; 93 Result.env = iJDE_JittingAPI; 94 95 return Result; 96 } 97 98 void IntelJITEventListener::notifyObjectLoaded( 99 ObjectKey Key, const ObjectFile &Obj, 100 const RuntimeDyld::LoadedObjectInfo &L) { 101 102 OwningBinary<ObjectFile> DebugObjOwner = L.getObjectForDebug(Obj); 103 const ObjectFile *DebugObj = DebugObjOwner.getBinary(); 104 if (!DebugObj) 105 return; 106 107 // Get the address of the object image for use as a unique identifier 108 const void* ObjData = DebugObj->getData().data(); 109 std::unique_ptr<DIContext> Context = DWARFContext::create(*DebugObj); 110 MethodAddressVector Functions; 111 112 // Use symbol info to iterate functions in the object. 113 for (const std::pair<SymbolRef, uint64_t> &P : computeSymbolSizes(*DebugObj)) { 114 SymbolRef Sym = P.first; 115 std::vector<LineNumberInfo> LineInfo; 116 std::string SourceFileName; 117 118 Expected<SymbolRef::Type> SymTypeOrErr = Sym.getType(); 119 if (!SymTypeOrErr) { 120 // TODO: Actually report errors helpfully. 121 consumeError(SymTypeOrErr.takeError()); 122 continue; 123 } 124 SymbolRef::Type SymType = *SymTypeOrErr; 125 if (SymType != SymbolRef::ST_Function) 126 continue; 127 128 Expected<StringRef> Name = Sym.getName(); 129 if (!Name) { 130 // TODO: Actually report errors helpfully. 131 consumeError(Name.takeError()); 132 continue; 133 } 134 135 Expected<uint64_t> AddrOrErr = Sym.getAddress(); 136 if (!AddrOrErr) { 137 // TODO: Actually report errors helpfully. 138 consumeError(AddrOrErr.takeError()); 139 continue; 140 } 141 uint64_t Addr = *AddrOrErr; 142 uint64_t Size = P.second; 143 144 auto SecOrErr = Sym.getSection(); 145 if (!SecOrErr) { 146 // TODO: Actually report errors helpfully. 147 consumeError(SecOrErr.takeError()); 148 continue; 149 } 150 object::section_iterator Sec = *SecOrErr; 151 if (Sec == Obj.section_end()) 152 continue; 153 uint64_t Index = Sec->getIndex(); 154 155 // Record this address in a local vector 156 Functions.push_back((void*)Addr); 157 158 // Build the function loaded notification message 159 iJIT_Method_Load FunctionMessage = 160 FunctionDescToIntelJITFormat(*Wrapper, Name->data(), Addr, Size); 161 DILineInfoTable Lines = 162 Context->getLineInfoForAddressRange({Addr, Index}, Size); 163 DILineInfoTable::iterator Begin = Lines.begin(); 164 DILineInfoTable::iterator End = Lines.end(); 165 for (DILineInfoTable::iterator It = Begin; It != End; ++It) { 166 LineInfo.push_back( 167 DILineInfoToIntelJITFormat((uintptr_t)Addr, It->first, It->second)); 168 } 169 if (LineInfo.size() == 0) { 170 FunctionMessage.source_file_name = 0; 171 FunctionMessage.line_number_size = 0; 172 FunctionMessage.line_number_table = 0; 173 } else { 174 // Source line information for the address range is provided as 175 // a code offset for the start of the corresponding sub-range and 176 // a source line. JIT API treats offsets in LineNumberInfo structures 177 // as the end of the corresponding code region. The start of the code 178 // is taken from the previous element. Need to shift the elements. 179 180 LineNumberInfo last = LineInfo.back(); 181 last.Offset = FunctionMessage.method_size; 182 LineInfo.push_back(last); 183 for (size_t i = LineInfo.size() - 2; i > 0; --i) 184 LineInfo[i].LineNumber = LineInfo[i - 1].LineNumber; 185 186 SourceFileName = Lines.front().second.FileName; 187 FunctionMessage.source_file_name = 188 const_cast<char *>(SourceFileName.c_str()); 189 FunctionMessage.line_number_size = LineInfo.size(); 190 FunctionMessage.line_number_table = &*LineInfo.begin(); 191 } 192 193 Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, 194 &FunctionMessage); 195 MethodIDs[(void*)Addr] = FunctionMessage.method_id; 196 } 197 198 // To support object unload notification, we need to keep a list of 199 // registered function addresses for each loaded object. We will 200 // use the MethodIDs map to get the registered ID for each function. 201 LoadedObjectMap[ObjData] = Functions; 202 DebugObjects[Key] = std::move(DebugObjOwner); 203 } 204 205 void IntelJITEventListener::notifyFreeingObject(ObjectKey Key) { 206 // This object may not have been registered with the listener. If it wasn't, 207 // bail out. 208 if (DebugObjects.find(Key) == DebugObjects.end()) 209 return; 210 211 // Get the address of the object image for use as a unique identifier 212 const ObjectFile &DebugObj = *DebugObjects[Key].getBinary(); 213 const void* ObjData = DebugObj.getData().data(); 214 215 // Get the object's function list from LoadedObjectMap 216 ObjectMap::iterator OI = LoadedObjectMap.find(ObjData); 217 if (OI == LoadedObjectMap.end()) 218 return; 219 MethodAddressVector& Functions = OI->second; 220 221 // Walk the function list, unregistering each function 222 for (MethodAddressVector::iterator FI = Functions.begin(), 223 FE = Functions.end(); 224 FI != FE; 225 ++FI) { 226 void* FnStart = const_cast<void*>(*FI); 227 MethodIDMap::iterator MI = MethodIDs.find(FnStart); 228 if (MI != MethodIDs.end()) { 229 Wrapper->iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_UNLOAD_START, 230 &MI->second); 231 MethodIDs.erase(MI); 232 } 233 } 234 235 // Erase the object from LoadedObjectMap 236 LoadedObjectMap.erase(OI); 237 DebugObjects.erase(Key); 238 } 239 240 } // anonymous namespace. 241 242 namespace llvm { 243 JITEventListener *JITEventListener::createIntelJITEventListener() { 244 return new IntelJITEventListener(new IntelJITEventsWrapper); 245 } 246 247 // for testing 248 JITEventListener *JITEventListener::createIntelJITEventListener( 249 IntelJITEventsWrapper* TestImpl) { 250 return new IntelJITEventListener(TestImpl); 251 } 252 253 } // namespace llvm 254 255 LLVMJITEventListenerRef LLVMCreateIntelJITEventListener(void) 256 { 257 return wrap(JITEventListener::createIntelJITEventListener()); 258 } 259