1*0b57cec5SDimitry Andric //===-- OProfileWrapper.cpp - OProfile JIT API Wrapper implementation -----===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric // 9*0b57cec5SDimitry Andric // This file implements the interface in OProfileWrapper.h. It is responsible 10*0b57cec5SDimitry Andric // for loading the opagent dynamic library when the first call to an op_ 11*0b57cec5SDimitry Andric // function occurs. 12*0b57cec5SDimitry Andric // 13*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 14*0b57cec5SDimitry Andric 15*0b57cec5SDimitry Andric #include "llvm/ExecutionEngine/OProfileWrapper.h" 16*0b57cec5SDimitry Andric #include "llvm/ADT/SmallString.h" 17*0b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 18*0b57cec5SDimitry Andric #include "llvm/Support/DynamicLibrary.h" 19*0b57cec5SDimitry Andric #include "llvm/Support/Mutex.h" 20*0b57cec5SDimitry Andric #include "llvm/Support/MutexGuard.h" 21*0b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 22*0b57cec5SDimitry Andric #include <cstring> 23*0b57cec5SDimitry Andric #include <dirent.h> 24*0b57cec5SDimitry Andric #include <fcntl.h> 25*0b57cec5SDimitry Andric #include <stddef.h> 26*0b57cec5SDimitry Andric #include <sys/stat.h> 27*0b57cec5SDimitry Andric #include <unistd.h> 28*0b57cec5SDimitry Andric 29*0b57cec5SDimitry Andric #define DEBUG_TYPE "oprofile-wrapper" 30*0b57cec5SDimitry Andric 31*0b57cec5SDimitry Andric namespace { 32*0b57cec5SDimitry Andric 33*0b57cec5SDimitry Andric // Global mutex to ensure a single thread initializes oprofile agent. 34*0b57cec5SDimitry Andric llvm::sys::Mutex OProfileInitializationMutex; 35*0b57cec5SDimitry Andric 36*0b57cec5SDimitry Andric } // anonymous namespace 37*0b57cec5SDimitry Andric 38*0b57cec5SDimitry Andric namespace llvm { 39*0b57cec5SDimitry Andric 40*0b57cec5SDimitry Andric OProfileWrapper::OProfileWrapper() 41*0b57cec5SDimitry Andric : Agent(0), 42*0b57cec5SDimitry Andric OpenAgentFunc(0), 43*0b57cec5SDimitry Andric CloseAgentFunc(0), 44*0b57cec5SDimitry Andric WriteNativeCodeFunc(0), 45*0b57cec5SDimitry Andric WriteDebugLineInfoFunc(0), 46*0b57cec5SDimitry Andric UnloadNativeCodeFunc(0), 47*0b57cec5SDimitry Andric MajorVersionFunc(0), 48*0b57cec5SDimitry Andric MinorVersionFunc(0), 49*0b57cec5SDimitry Andric IsOProfileRunningFunc(0), 50*0b57cec5SDimitry Andric Initialized(false) { 51*0b57cec5SDimitry Andric } 52*0b57cec5SDimitry Andric 53*0b57cec5SDimitry Andric bool OProfileWrapper::initialize() { 54*0b57cec5SDimitry Andric using namespace llvm; 55*0b57cec5SDimitry Andric using namespace llvm::sys; 56*0b57cec5SDimitry Andric 57*0b57cec5SDimitry Andric MutexGuard Guard(OProfileInitializationMutex); 58*0b57cec5SDimitry Andric 59*0b57cec5SDimitry Andric if (Initialized) 60*0b57cec5SDimitry Andric return OpenAgentFunc != 0; 61*0b57cec5SDimitry Andric 62*0b57cec5SDimitry Andric Initialized = true; 63*0b57cec5SDimitry Andric 64*0b57cec5SDimitry Andric // If the oprofile daemon is not running, don't load the opagent library 65*0b57cec5SDimitry Andric if (!isOProfileRunning()) { 66*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "OProfile daemon is not detected.\n"); 67*0b57cec5SDimitry Andric return false; 68*0b57cec5SDimitry Andric } 69*0b57cec5SDimitry Andric 70*0b57cec5SDimitry Andric std::string error; 71*0b57cec5SDimitry Andric if(!DynamicLibrary::LoadLibraryPermanently("libopagent.so", &error)) { 72*0b57cec5SDimitry Andric LLVM_DEBUG( 73*0b57cec5SDimitry Andric dbgs() 74*0b57cec5SDimitry Andric << "OProfile connector library libopagent.so could not be loaded: " 75*0b57cec5SDimitry Andric << error << "\n"); 76*0b57cec5SDimitry Andric } 77*0b57cec5SDimitry Andric 78*0b57cec5SDimitry Andric // Get the addresses of the opagent functions 79*0b57cec5SDimitry Andric OpenAgentFunc = (op_open_agent_ptr_t)(intptr_t) 80*0b57cec5SDimitry Andric DynamicLibrary::SearchForAddressOfSymbol("op_open_agent"); 81*0b57cec5SDimitry Andric CloseAgentFunc = (op_close_agent_ptr_t)(intptr_t) 82*0b57cec5SDimitry Andric DynamicLibrary::SearchForAddressOfSymbol("op_close_agent"); 83*0b57cec5SDimitry Andric WriteNativeCodeFunc = (op_write_native_code_ptr_t)(intptr_t) 84*0b57cec5SDimitry Andric DynamicLibrary::SearchForAddressOfSymbol("op_write_native_code"); 85*0b57cec5SDimitry Andric WriteDebugLineInfoFunc = (op_write_debug_line_info_ptr_t)(intptr_t) 86*0b57cec5SDimitry Andric DynamicLibrary::SearchForAddressOfSymbol("op_write_debug_line_info"); 87*0b57cec5SDimitry Andric UnloadNativeCodeFunc = (op_unload_native_code_ptr_t)(intptr_t) 88*0b57cec5SDimitry Andric DynamicLibrary::SearchForAddressOfSymbol("op_unload_native_code"); 89*0b57cec5SDimitry Andric MajorVersionFunc = (op_major_version_ptr_t)(intptr_t) 90*0b57cec5SDimitry Andric DynamicLibrary::SearchForAddressOfSymbol("op_major_version"); 91*0b57cec5SDimitry Andric MinorVersionFunc = (op_major_version_ptr_t)(intptr_t) 92*0b57cec5SDimitry Andric DynamicLibrary::SearchForAddressOfSymbol("op_minor_version"); 93*0b57cec5SDimitry Andric 94*0b57cec5SDimitry Andric // With missing functions, we can do nothing 95*0b57cec5SDimitry Andric if (!OpenAgentFunc 96*0b57cec5SDimitry Andric || !CloseAgentFunc 97*0b57cec5SDimitry Andric || !WriteNativeCodeFunc 98*0b57cec5SDimitry Andric || !WriteDebugLineInfoFunc 99*0b57cec5SDimitry Andric || !UnloadNativeCodeFunc) { 100*0b57cec5SDimitry Andric OpenAgentFunc = 0; 101*0b57cec5SDimitry Andric CloseAgentFunc = 0; 102*0b57cec5SDimitry Andric WriteNativeCodeFunc = 0; 103*0b57cec5SDimitry Andric WriteDebugLineInfoFunc = 0; 104*0b57cec5SDimitry Andric UnloadNativeCodeFunc = 0; 105*0b57cec5SDimitry Andric return false; 106*0b57cec5SDimitry Andric } 107*0b57cec5SDimitry Andric 108*0b57cec5SDimitry Andric return true; 109*0b57cec5SDimitry Andric } 110*0b57cec5SDimitry Andric 111*0b57cec5SDimitry Andric bool OProfileWrapper::isOProfileRunning() { 112*0b57cec5SDimitry Andric if (IsOProfileRunningFunc != 0) 113*0b57cec5SDimitry Andric return IsOProfileRunningFunc(); 114*0b57cec5SDimitry Andric return checkForOProfileProcEntry(); 115*0b57cec5SDimitry Andric } 116*0b57cec5SDimitry Andric 117*0b57cec5SDimitry Andric bool OProfileWrapper::checkForOProfileProcEntry() { 118*0b57cec5SDimitry Andric DIR* ProcDir; 119*0b57cec5SDimitry Andric 120*0b57cec5SDimitry Andric ProcDir = opendir("/proc"); 121*0b57cec5SDimitry Andric if (!ProcDir) 122*0b57cec5SDimitry Andric return false; 123*0b57cec5SDimitry Andric 124*0b57cec5SDimitry Andric // Walk the /proc tree looking for the oprofile daemon 125*0b57cec5SDimitry Andric struct dirent* Entry; 126*0b57cec5SDimitry Andric while (0 != (Entry = readdir(ProcDir))) { 127*0b57cec5SDimitry Andric if (Entry->d_type == DT_DIR) { 128*0b57cec5SDimitry Andric // Build a path from the current entry name 129*0b57cec5SDimitry Andric SmallString<256> CmdLineFName; 130*0b57cec5SDimitry Andric raw_svector_ostream(CmdLineFName) << "/proc/" << Entry->d_name 131*0b57cec5SDimitry Andric << "/cmdline"; 132*0b57cec5SDimitry Andric 133*0b57cec5SDimitry Andric // Open the cmdline file 134*0b57cec5SDimitry Andric int CmdLineFD = open(CmdLineFName.c_str(), S_IRUSR); 135*0b57cec5SDimitry Andric if (CmdLineFD != -1) { 136*0b57cec5SDimitry Andric char ExeName[PATH_MAX+1]; 137*0b57cec5SDimitry Andric char* BaseName = 0; 138*0b57cec5SDimitry Andric 139*0b57cec5SDimitry Andric // Read the cmdline file 140*0b57cec5SDimitry Andric ssize_t NumRead = read(CmdLineFD, ExeName, PATH_MAX+1); 141*0b57cec5SDimitry Andric close(CmdLineFD); 142*0b57cec5SDimitry Andric ssize_t Idx = 0; 143*0b57cec5SDimitry Andric 144*0b57cec5SDimitry Andric if (ExeName[0] != '/') { 145*0b57cec5SDimitry Andric BaseName = ExeName; 146*0b57cec5SDimitry Andric } 147*0b57cec5SDimitry Andric 148*0b57cec5SDimitry Andric // Find the terminator for the first string 149*0b57cec5SDimitry Andric while (Idx < NumRead-1 && ExeName[Idx] != 0) { 150*0b57cec5SDimitry Andric Idx++; 151*0b57cec5SDimitry Andric } 152*0b57cec5SDimitry Andric 153*0b57cec5SDimitry Andric // Go back to the last non-null character 154*0b57cec5SDimitry Andric Idx--; 155*0b57cec5SDimitry Andric 156*0b57cec5SDimitry Andric // Find the last path separator in the first string 157*0b57cec5SDimitry Andric while (Idx > 0) { 158*0b57cec5SDimitry Andric if (ExeName[Idx] == '/') { 159*0b57cec5SDimitry Andric BaseName = ExeName + Idx + 1; 160*0b57cec5SDimitry Andric break; 161*0b57cec5SDimitry Andric } 162*0b57cec5SDimitry Andric Idx--; 163*0b57cec5SDimitry Andric } 164*0b57cec5SDimitry Andric 165*0b57cec5SDimitry Andric // Test this to see if it is the oprofile daemon 166*0b57cec5SDimitry Andric if (BaseName != 0 && (!strcmp("oprofiled", BaseName) || 167*0b57cec5SDimitry Andric !strcmp("operf", BaseName))) { 168*0b57cec5SDimitry Andric // If it is, we're done 169*0b57cec5SDimitry Andric closedir(ProcDir); 170*0b57cec5SDimitry Andric return true; 171*0b57cec5SDimitry Andric } 172*0b57cec5SDimitry Andric } 173*0b57cec5SDimitry Andric } 174*0b57cec5SDimitry Andric } 175*0b57cec5SDimitry Andric 176*0b57cec5SDimitry Andric // We've looked through all the files and didn't find the daemon 177*0b57cec5SDimitry Andric closedir(ProcDir); 178*0b57cec5SDimitry Andric return false; 179*0b57cec5SDimitry Andric } 180*0b57cec5SDimitry Andric 181*0b57cec5SDimitry Andric bool OProfileWrapper::op_open_agent() { 182*0b57cec5SDimitry Andric if (!Initialized) 183*0b57cec5SDimitry Andric initialize(); 184*0b57cec5SDimitry Andric 185*0b57cec5SDimitry Andric if (OpenAgentFunc != 0) { 186*0b57cec5SDimitry Andric Agent = OpenAgentFunc(); 187*0b57cec5SDimitry Andric return Agent != 0; 188*0b57cec5SDimitry Andric } 189*0b57cec5SDimitry Andric 190*0b57cec5SDimitry Andric return false; 191*0b57cec5SDimitry Andric } 192*0b57cec5SDimitry Andric 193*0b57cec5SDimitry Andric int OProfileWrapper::op_close_agent() { 194*0b57cec5SDimitry Andric if (!Initialized) 195*0b57cec5SDimitry Andric initialize(); 196*0b57cec5SDimitry Andric 197*0b57cec5SDimitry Andric int ret = -1; 198*0b57cec5SDimitry Andric if (Agent && CloseAgentFunc) { 199*0b57cec5SDimitry Andric ret = CloseAgentFunc(Agent); 200*0b57cec5SDimitry Andric if (ret == 0) { 201*0b57cec5SDimitry Andric Agent = 0; 202*0b57cec5SDimitry Andric } 203*0b57cec5SDimitry Andric } 204*0b57cec5SDimitry Andric return ret; 205*0b57cec5SDimitry Andric } 206*0b57cec5SDimitry Andric 207*0b57cec5SDimitry Andric bool OProfileWrapper::isAgentAvailable() { 208*0b57cec5SDimitry Andric return Agent != 0; 209*0b57cec5SDimitry Andric } 210*0b57cec5SDimitry Andric 211*0b57cec5SDimitry Andric int OProfileWrapper::op_write_native_code(const char* Name, 212*0b57cec5SDimitry Andric uint64_t Addr, 213*0b57cec5SDimitry Andric void const* Code, 214*0b57cec5SDimitry Andric const unsigned int Size) { 215*0b57cec5SDimitry Andric if (!Initialized) 216*0b57cec5SDimitry Andric initialize(); 217*0b57cec5SDimitry Andric 218*0b57cec5SDimitry Andric if (Agent && WriteNativeCodeFunc) 219*0b57cec5SDimitry Andric return WriteNativeCodeFunc(Agent, Name, Addr, Code, Size); 220*0b57cec5SDimitry Andric 221*0b57cec5SDimitry Andric return -1; 222*0b57cec5SDimitry Andric } 223*0b57cec5SDimitry Andric 224*0b57cec5SDimitry Andric int OProfileWrapper::op_write_debug_line_info( 225*0b57cec5SDimitry Andric void const* Code, 226*0b57cec5SDimitry Andric size_t NumEntries, 227*0b57cec5SDimitry Andric struct debug_line_info const* Info) { 228*0b57cec5SDimitry Andric if (!Initialized) 229*0b57cec5SDimitry Andric initialize(); 230*0b57cec5SDimitry Andric 231*0b57cec5SDimitry Andric if (Agent && WriteDebugLineInfoFunc) 232*0b57cec5SDimitry Andric return WriteDebugLineInfoFunc(Agent, Code, NumEntries, Info); 233*0b57cec5SDimitry Andric 234*0b57cec5SDimitry Andric return -1; 235*0b57cec5SDimitry Andric } 236*0b57cec5SDimitry Andric 237*0b57cec5SDimitry Andric int OProfileWrapper::op_major_version() { 238*0b57cec5SDimitry Andric if (!Initialized) 239*0b57cec5SDimitry Andric initialize(); 240*0b57cec5SDimitry Andric 241*0b57cec5SDimitry Andric if (Agent && MajorVersionFunc) 242*0b57cec5SDimitry Andric return MajorVersionFunc(); 243*0b57cec5SDimitry Andric 244*0b57cec5SDimitry Andric return -1; 245*0b57cec5SDimitry Andric } 246*0b57cec5SDimitry Andric 247*0b57cec5SDimitry Andric int OProfileWrapper::op_minor_version() { 248*0b57cec5SDimitry Andric if (!Initialized) 249*0b57cec5SDimitry Andric initialize(); 250*0b57cec5SDimitry Andric 251*0b57cec5SDimitry Andric if (Agent && MinorVersionFunc) 252*0b57cec5SDimitry Andric return MinorVersionFunc(); 253*0b57cec5SDimitry Andric 254*0b57cec5SDimitry Andric return -1; 255*0b57cec5SDimitry Andric } 256*0b57cec5SDimitry Andric 257*0b57cec5SDimitry Andric int OProfileWrapper::op_unload_native_code(uint64_t Addr) { 258*0b57cec5SDimitry Andric if (!Initialized) 259*0b57cec5SDimitry Andric initialize(); 260*0b57cec5SDimitry Andric 261*0b57cec5SDimitry Andric if (Agent && UnloadNativeCodeFunc) 262*0b57cec5SDimitry Andric return UnloadNativeCodeFunc(Agent, Addr); 263*0b57cec5SDimitry Andric 264*0b57cec5SDimitry Andric return -1; 265*0b57cec5SDimitry Andric } 266*0b57cec5SDimitry Andric 267*0b57cec5SDimitry Andric } // namespace llvm 268