1234285Sdim//===-- OProfileJITEventListener.cpp - Tell OProfile about JITted code ----===// 2234285Sdim// 3234285Sdim// The LLVM Compiler Infrastructure 4234285Sdim// 5234285Sdim// This file is distributed under the University of Illinois Open Source 6234285Sdim// License. See LICENSE.TXT for details. 7234285Sdim// 8234285Sdim//===----------------------------------------------------------------------===// 9234285Sdim// 10234285Sdim// This file defines a JITEventListener object that uses OProfileWrapper to tell 11234285Sdim// oprofile about JITted functions, including source line information. 12234285Sdim// 13234285Sdim//===----------------------------------------------------------------------===// 14234285Sdim 15234285Sdim#include "llvm/Config/config.h" 16234285Sdim#include "llvm/ExecutionEngine/JITEventListener.h" 17234285Sdim 18234285Sdim#define DEBUG_TYPE "oprofile-jit-event-listener" 19239462Sdim#include "llvm/DebugInfo.h" 20249423Sdim#include "llvm/IR/Function.h" 21234285Sdim#include "llvm/ADT/OwningPtr.h" 22234285Sdim#include "llvm/CodeGen/MachineFunction.h" 23263508Sdim#include "llvm/ExecutionEngine/ObjectImage.h" 24234285Sdim#include "llvm/ExecutionEngine/OProfileWrapper.h" 25263508Sdim#include "llvm/Object/ObjectFile.h" 26234285Sdim#include "llvm/Support/Debug.h" 27234285Sdim#include "llvm/Support/raw_ostream.h" 28234285Sdim#include "llvm/Support/Errno.h" 29234285Sdim#include "EventListenerCommon.h" 30234285Sdim 31234285Sdim#include <dirent.h> 32234285Sdim#include <fcntl.h> 33234285Sdim 34234285Sdimusing namespace llvm; 35234285Sdimusing namespace llvm::jitprofiling; 36234285Sdim 37234285Sdimnamespace { 38234285Sdim 39234285Sdimclass OProfileJITEventListener : public JITEventListener { 40234285Sdim OProfileWrapper& Wrapper; 41234285Sdim 42234285Sdim void initialize(); 43234285Sdim 44234285Sdimpublic: 45234285Sdim OProfileJITEventListener(OProfileWrapper& LibraryWrapper) 46234285Sdim : Wrapper(LibraryWrapper) { 47234285Sdim initialize(); 48234285Sdim } 49234285Sdim 50234285Sdim ~OProfileJITEventListener(); 51234285Sdim 52234285Sdim virtual void NotifyFunctionEmitted(const Function &F, 53234285Sdim void *FnStart, size_t FnSize, 54234285Sdim const JITEvent_EmittedFunctionDetails &Details); 55234285Sdim 56234285Sdim virtual void NotifyFreeingMachineCode(void *OldPtr); 57263508Sdim 58263508Sdim virtual void NotifyObjectEmitted(const ObjectImage &Obj); 59263508Sdim 60263508Sdim virtual void NotifyFreeingObject(const ObjectImage &Obj); 61234285Sdim}; 62234285Sdim 63234285Sdimvoid OProfileJITEventListener::initialize() { 64234285Sdim if (!Wrapper.op_open_agent()) { 65234285Sdim const std::string err_str = sys::StrError(); 66234285Sdim DEBUG(dbgs() << "Failed to connect to OProfile agent: " << err_str << "\n"); 67234285Sdim } else { 68234285Sdim DEBUG(dbgs() << "Connected to OProfile agent.\n"); 69234285Sdim } 70234285Sdim} 71234285Sdim 72234285SdimOProfileJITEventListener::~OProfileJITEventListener() { 73234285Sdim if (Wrapper.isAgentAvailable()) { 74234285Sdim if (Wrapper.op_close_agent() == -1) { 75234285Sdim const std::string err_str = sys::StrError(); 76234285Sdim DEBUG(dbgs() << "Failed to disconnect from OProfile agent: " 77234285Sdim << err_str << "\n"); 78234285Sdim } else { 79234285Sdim DEBUG(dbgs() << "Disconnected from OProfile agent.\n"); 80234285Sdim } 81234285Sdim } 82234285Sdim} 83234285Sdim 84234285Sdimstatic debug_line_info LineStartToOProfileFormat( 85234285Sdim const MachineFunction &MF, FilenameCache &Filenames, 86234285Sdim uintptr_t Address, DebugLoc Loc) { 87234285Sdim debug_line_info Result; 88234285Sdim Result.vma = Address; 89234285Sdim Result.lineno = Loc.getLine(); 90234285Sdim Result.filename = Filenames.getFilename( 91234285Sdim Loc.getScope(MF.getFunction()->getContext())); 92234285Sdim DEBUG(dbgs() << "Mapping " << reinterpret_cast<void*>(Result.vma) << " to " 93234285Sdim << Result.filename << ":" << Result.lineno << "\n"); 94234285Sdim return Result; 95234285Sdim} 96234285Sdim 97234285Sdim// Adds the just-emitted function to the symbol table. 98234285Sdimvoid OProfileJITEventListener::NotifyFunctionEmitted( 99234285Sdim const Function &F, void *FnStart, size_t FnSize, 100234285Sdim const JITEvent_EmittedFunctionDetails &Details) { 101234285Sdim assert(F.hasName() && FnStart != 0 && "Bad symbol to add"); 102234285Sdim if (Wrapper.op_write_native_code(F.getName().data(), 103234285Sdim reinterpret_cast<uint64_t>(FnStart), 104234285Sdim FnStart, FnSize) == -1) { 105234285Sdim DEBUG(dbgs() << "Failed to tell OProfile about native function " 106234285Sdim << F.getName() << " at [" 107234285Sdim << FnStart << "-" << ((char*)FnStart + FnSize) << "]\n"); 108234285Sdim return; 109234285Sdim } 110234285Sdim 111234285Sdim if (!Details.LineStarts.empty()) { 112234285Sdim // Now we convert the line number information from the address/DebugLoc 113234285Sdim // format in Details to the address/filename/lineno format that OProfile 114234285Sdim // expects. Note that OProfile 0.9.4 has a bug that causes it to ignore 115234285Sdim // line numbers for addresses above 4G. 116234285Sdim FilenameCache Filenames; 117234285Sdim std::vector<debug_line_info> LineInfo; 118234285Sdim LineInfo.reserve(1 + Details.LineStarts.size()); 119234285Sdim 120234285Sdim DebugLoc FirstLoc = Details.LineStarts[0].Loc; 121234285Sdim assert(!FirstLoc.isUnknown() 122234285Sdim && "LineStarts should not contain unknown DebugLocs"); 123234285Sdim MDNode *FirstLocScope = FirstLoc.getScope(F.getContext()); 124234285Sdim DISubprogram FunctionDI = getDISubprogram(FirstLocScope); 125234285Sdim if (FunctionDI.Verify()) { 126234285Sdim // If we have debug info for the function itself, use that as the line 127234285Sdim // number of the first several instructions. Otherwise, after filling 128234285Sdim // LineInfo, we'll adjust the address of the first line number to point at 129234285Sdim // the start of the function. 130234285Sdim debug_line_info line_info; 131234285Sdim line_info.vma = reinterpret_cast<uintptr_t>(FnStart); 132234285Sdim line_info.lineno = FunctionDI.getLineNumber(); 133234285Sdim line_info.filename = Filenames.getFilename(FirstLocScope); 134234285Sdim LineInfo.push_back(line_info); 135234285Sdim } 136234285Sdim 137234285Sdim for (std::vector<EmittedFunctionDetails::LineStart>::const_iterator 138234285Sdim I = Details.LineStarts.begin(), E = Details.LineStarts.end(); 139234285Sdim I != E; ++I) { 140234285Sdim LineInfo.push_back(LineStartToOProfileFormat( 141234285Sdim *Details.MF, Filenames, I->Address, I->Loc)); 142234285Sdim } 143234285Sdim 144234285Sdim // In case the function didn't have line info of its own, adjust the first 145234285Sdim // line info's address to include the start of the function. 146234285Sdim LineInfo[0].vma = reinterpret_cast<uintptr_t>(FnStart); 147234285Sdim 148234285Sdim if (Wrapper.op_write_debug_line_info(FnStart, LineInfo.size(), 149234285Sdim &*LineInfo.begin()) == -1) { 150234285Sdim DEBUG(dbgs() 151234285Sdim << "Failed to tell OProfile about line numbers for native function " 152234285Sdim << F.getName() << " at [" 153234285Sdim << FnStart << "-" << ((char*)FnStart + FnSize) << "]\n"); 154234285Sdim } 155234285Sdim } 156234285Sdim} 157234285Sdim 158234285Sdim// Removes the being-deleted function from the symbol table. 159234285Sdimvoid OProfileJITEventListener::NotifyFreeingMachineCode(void *FnStart) { 160234285Sdim assert(FnStart && "Invalid function pointer"); 161234285Sdim if (Wrapper.op_unload_native_code(reinterpret_cast<uint64_t>(FnStart)) == -1) { 162234285Sdim DEBUG(dbgs() 163234285Sdim << "Failed to tell OProfile about unload of native function at " 164234285Sdim << FnStart << "\n"); 165234285Sdim } 166234285Sdim} 167234285Sdim 168263508Sdimvoid OProfileJITEventListener::NotifyObjectEmitted(const ObjectImage &Obj) { 169263508Sdim if (!Wrapper.isAgentAvailable()) { 170263508Sdim return; 171263508Sdim } 172263508Sdim 173263508Sdim // Use symbol info to iterate functions in the object. 174263508Sdim error_code ec; 175263508Sdim for (object::symbol_iterator I = Obj.begin_symbols(), 176263508Sdim E = Obj.end_symbols(); 177263508Sdim I != E && !ec; 178263508Sdim I.increment(ec)) { 179263508Sdim object::SymbolRef::Type SymType; 180263508Sdim if (I->getType(SymType)) continue; 181263508Sdim if (SymType == object::SymbolRef::ST_Function) { 182263508Sdim StringRef Name; 183263508Sdim uint64_t Addr; 184263508Sdim uint64_t Size; 185263508Sdim if (I->getName(Name)) continue; 186263508Sdim if (I->getAddress(Addr)) continue; 187263508Sdim if (I->getSize(Size)) continue; 188263508Sdim 189263508Sdim if (Wrapper.op_write_native_code(Name.data(), Addr, (void*)Addr, Size) 190263508Sdim == -1) { 191263508Sdim DEBUG(dbgs() << "Failed to tell OProfile about native function " 192263508Sdim << Name << " at [" 193263508Sdim << (void*)Addr << "-" << ((char*)Addr + Size) << "]\n"); 194263508Sdim continue; 195263508Sdim } 196263508Sdim // TODO: support line number info (similar to IntelJITEventListener.cpp) 197263508Sdim } 198263508Sdim } 199263508Sdim} 200263508Sdim 201263508Sdimvoid OProfileJITEventListener::NotifyFreeingObject(const ObjectImage &Obj) { 202263508Sdim if (!Wrapper.isAgentAvailable()) { 203263508Sdim return; 204263508Sdim } 205263508Sdim 206263508Sdim // Use symbol info to iterate functions in the object. 207263508Sdim error_code ec; 208263508Sdim for (object::symbol_iterator I = Obj.begin_symbols(), 209263508Sdim E = Obj.end_symbols(); 210263508Sdim I != E && !ec; 211263508Sdim I.increment(ec)) { 212263508Sdim object::SymbolRef::Type SymType; 213263508Sdim if (I->getType(SymType)) continue; 214263508Sdim if (SymType == object::SymbolRef::ST_Function) { 215263508Sdim uint64_t Addr; 216263508Sdim if (I->getAddress(Addr)) continue; 217263508Sdim 218263508Sdim if (Wrapper.op_unload_native_code(Addr) == -1) { 219263508Sdim DEBUG(dbgs() 220263508Sdim << "Failed to tell OProfile about unload of native function at " 221263508Sdim << (void*)Addr << "\n"); 222263508Sdim continue; 223263508Sdim } 224263508Sdim } 225263508Sdim } 226263508Sdim} 227263508Sdim 228234285Sdim} // anonymous namespace. 229234285Sdim 230234285Sdimnamespace llvm { 231234285SdimJITEventListener *JITEventListener::createOProfileJITEventListener() { 232234285Sdim static OwningPtr<OProfileWrapper> JITProfilingWrapper(new OProfileWrapper); 233234285Sdim return new OProfileJITEventListener(*JITProfilingWrapper); 234234285Sdim} 235234285Sdim 236234285Sdim// for testing 237234285SdimJITEventListener *JITEventListener::createOProfileJITEventListener( 238234285Sdim OProfileWrapper* TestImpl) { 239234285Sdim return new OProfileJITEventListener(*TestImpl); 240234285Sdim} 241234285Sdim 242234285Sdim} // namespace llvm 243234285Sdim 244