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/ExecutionEngine/JITEventListener.h" 17 18#define DEBUG_TYPE "oprofile-jit-event-listener" 19#include "llvm/DebugInfo.h" 20#include "llvm/Function.h" 21#include "llvm/ADT/OwningPtr.h" 22#include "llvm/CodeGen/MachineFunction.h" 23#include "llvm/ExecutionEngine/OProfileWrapper.h" 24#include "llvm/Support/Debug.h" 25#include "llvm/Support/raw_ostream.h" 26#include "llvm/Support/Errno.h" 27#include "EventListenerCommon.h" 28 29#include <dirent.h> 30#include <fcntl.h> 31 32using namespace llvm; 33using namespace llvm::jitprofiling; 34 35namespace { 36 37class OProfileJITEventListener : public JITEventListener { 38 OProfileWrapper& Wrapper; 39 40 void initialize(); 41 42public: 43 OProfileJITEventListener(OProfileWrapper& LibraryWrapper) 44 : Wrapper(LibraryWrapper) { 45 initialize(); 46 } 47 48 ~OProfileJITEventListener(); 49 50 virtual void NotifyFunctionEmitted(const Function &F, 51 void *FnStart, size_t FnSize, 52 const JITEvent_EmittedFunctionDetails &Details); 53 54 virtual void NotifyFreeingMachineCode(void *OldPtr); 55}; 56 57void 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 66OProfileJITEventListener::~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 78static debug_line_info LineStartToOProfileFormat( 79 const MachineFunction &MF, FilenameCache &Filenames, 80 uintptr_t Address, DebugLoc Loc) { 81 debug_line_info Result; 82 Result.vma = Address; 83 Result.lineno = Loc.getLine(); 84 Result.filename = Filenames.getFilename( 85 Loc.getScope(MF.getFunction()->getContext())); 86 DEBUG(dbgs() << "Mapping " << reinterpret_cast<void*>(Result.vma) << " to " 87 << Result.filename << ":" << Result.lineno << "\n"); 88 return Result; 89} 90 91// Adds the just-emitted function to the symbol table. 92void OProfileJITEventListener::NotifyFunctionEmitted( 93 const Function &F, void *FnStart, size_t FnSize, 94 const JITEvent_EmittedFunctionDetails &Details) { 95 assert(F.hasName() && FnStart != 0 && "Bad symbol to add"); 96 if (Wrapper.op_write_native_code(F.getName().data(), 97 reinterpret_cast<uint64_t>(FnStart), 98 FnStart, FnSize) == -1) { 99 DEBUG(dbgs() << "Failed to tell OProfile about native function " 100 << F.getName() << " at [" 101 << FnStart << "-" << ((char*)FnStart + FnSize) << "]\n"); 102 return; 103 } 104 105 if (!Details.LineStarts.empty()) { 106 // Now we convert the line number information from the address/DebugLoc 107 // format in Details to the address/filename/lineno format that OProfile 108 // expects. Note that OProfile 0.9.4 has a bug that causes it to ignore 109 // line numbers for addresses above 4G. 110 FilenameCache Filenames; 111 std::vector<debug_line_info> LineInfo; 112 LineInfo.reserve(1 + Details.LineStarts.size()); 113 114 DebugLoc FirstLoc = Details.LineStarts[0].Loc; 115 assert(!FirstLoc.isUnknown() 116 && "LineStarts should not contain unknown DebugLocs"); 117 MDNode *FirstLocScope = FirstLoc.getScope(F.getContext()); 118 DISubprogram FunctionDI = getDISubprogram(FirstLocScope); 119 if (FunctionDI.Verify()) { 120 // If we have debug info for the function itself, use that as the line 121 // number of the first several instructions. Otherwise, after filling 122 // LineInfo, we'll adjust the address of the first line number to point at 123 // the start of the function. 124 debug_line_info line_info; 125 line_info.vma = reinterpret_cast<uintptr_t>(FnStart); 126 line_info.lineno = FunctionDI.getLineNumber(); 127 line_info.filename = Filenames.getFilename(FirstLocScope); 128 LineInfo.push_back(line_info); 129 } 130 131 for (std::vector<EmittedFunctionDetails::LineStart>::const_iterator 132 I = Details.LineStarts.begin(), E = Details.LineStarts.end(); 133 I != E; ++I) { 134 LineInfo.push_back(LineStartToOProfileFormat( 135 *Details.MF, Filenames, I->Address, I->Loc)); 136 } 137 138 // In case the function didn't have line info of its own, adjust the first 139 // line info's address to include the start of the function. 140 LineInfo[0].vma = reinterpret_cast<uintptr_t>(FnStart); 141 142 if (Wrapper.op_write_debug_line_info(FnStart, LineInfo.size(), 143 &*LineInfo.begin()) == -1) { 144 DEBUG(dbgs() 145 << "Failed to tell OProfile about line numbers for native function " 146 << F.getName() << " at [" 147 << FnStart << "-" << ((char*)FnStart + FnSize) << "]\n"); 148 } 149 } 150} 151 152// Removes the being-deleted function from the symbol table. 153void OProfileJITEventListener::NotifyFreeingMachineCode(void *FnStart) { 154 assert(FnStart && "Invalid function pointer"); 155 if (Wrapper.op_unload_native_code(reinterpret_cast<uint64_t>(FnStart)) == -1) { 156 DEBUG(dbgs() 157 << "Failed to tell OProfile about unload of native function at " 158 << FnStart << "\n"); 159 } 160} 161 162} // anonymous namespace. 163 164namespace llvm { 165JITEventListener *JITEventListener::createOProfileJITEventListener() { 166 static OwningPtr<OProfileWrapper> JITProfilingWrapper(new OProfileWrapper); 167 return new OProfileJITEventListener(*JITProfilingWrapper); 168} 169 170// for testing 171JITEventListener *JITEventListener::createOProfileJITEventListener( 172 OProfileWrapper* TestImpl) { 173 return new OProfileJITEventListener(*TestImpl); 174} 175 176} // namespace llvm 177 178