//===-- OProfileWrapper.cpp - OProfile JIT API Wrapper implementation -----===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements the interface in OProfileWrapper.h. It is responsible // for loading the opagent dynamic library when the first call to an op_ // function occurs. // //===----------------------------------------------------------------------===// #include "llvm/ExecutionEngine/OProfileWrapper.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/Debug.h" #include "llvm/Support/DynamicLibrary.h" #include "llvm/Support/Mutex.h" #include "llvm/Support/MutexGuard.h" #include "llvm/Support/raw_ostream.h" #include <cstring> #include <dirent.h> #include <fcntl.h> #include <sstream> #include <stddef.h> #include <sys/stat.h> #include <unistd.h> #define DEBUG_TYPE "oprofile-wrapper" namespace { // Global mutex to ensure a single thread initializes oprofile agent. llvm::sys::Mutex OProfileInitializationMutex; } // anonymous namespace namespace llvm { OProfileWrapper::OProfileWrapper() : Agent(0), OpenAgentFunc(0), CloseAgentFunc(0), WriteNativeCodeFunc(0), WriteDebugLineInfoFunc(0), UnloadNativeCodeFunc(0), MajorVersionFunc(0), MinorVersionFunc(0), IsOProfileRunningFunc(0), Initialized(false) { } bool OProfileWrapper::initialize() { using namespace llvm; using namespace llvm::sys; MutexGuard Guard(OProfileInitializationMutex); if (Initialized) return OpenAgentFunc != 0; Initialized = true; // If the oprofile daemon is not running, don't load the opagent library if (!isOProfileRunning()) { DEBUG(dbgs() << "OProfile daemon is not detected.\n"); return false; } std::string error; if(!DynamicLibrary::LoadLibraryPermanently("libopagent.so", &error)) { DEBUG(dbgs() << "OProfile connector library libopagent.so could not be loaded: " << error << "\n"); } // Get the addresses of the opagent functions OpenAgentFunc = (op_open_agent_ptr_t)(intptr_t) DynamicLibrary::SearchForAddressOfSymbol("op_open_agent"); CloseAgentFunc = (op_close_agent_ptr_t)(intptr_t) DynamicLibrary::SearchForAddressOfSymbol("op_close_agent"); WriteNativeCodeFunc = (op_write_native_code_ptr_t)(intptr_t) DynamicLibrary::SearchForAddressOfSymbol("op_write_native_code"); WriteDebugLineInfoFunc = (op_write_debug_line_info_ptr_t)(intptr_t) DynamicLibrary::SearchForAddressOfSymbol("op_write_debug_line_info"); UnloadNativeCodeFunc = (op_unload_native_code_ptr_t)(intptr_t) DynamicLibrary::SearchForAddressOfSymbol("op_unload_native_code"); MajorVersionFunc = (op_major_version_ptr_t)(intptr_t) DynamicLibrary::SearchForAddressOfSymbol("op_major_version"); MinorVersionFunc = (op_major_version_ptr_t)(intptr_t) DynamicLibrary::SearchForAddressOfSymbol("op_minor_version"); // With missing functions, we can do nothing if (!OpenAgentFunc || !CloseAgentFunc || !WriteNativeCodeFunc || !WriteDebugLineInfoFunc || !UnloadNativeCodeFunc) { OpenAgentFunc = 0; CloseAgentFunc = 0; WriteNativeCodeFunc = 0; WriteDebugLineInfoFunc = 0; UnloadNativeCodeFunc = 0; return false; } return true; } bool OProfileWrapper::isOProfileRunning() { if (IsOProfileRunningFunc != 0) return IsOProfileRunningFunc(); return checkForOProfileProcEntry(); } bool OProfileWrapper::checkForOProfileProcEntry() { DIR* ProcDir; ProcDir = opendir("/proc"); if (!ProcDir) return false; // Walk the /proc tree looking for the oprofile daemon struct dirent* Entry; while (0 != (Entry = readdir(ProcDir))) { if (Entry->d_type == DT_DIR) { // Build a path from the current entry name SmallString<256> CmdLineFName; raw_svector_ostream(CmdLineFName) << "/proc/" << Entry->d_name << "/cmdline"; // Open the cmdline file int CmdLineFD = open(CmdLineFName.c_str(), S_IRUSR); if (CmdLineFD != -1) { char ExeName[PATH_MAX+1]; char* BaseName = 0; // Read the cmdline file ssize_t NumRead = read(CmdLineFD, ExeName, PATH_MAX+1); close(CmdLineFD); ssize_t Idx = 0; if (ExeName[0] != '/') { BaseName = ExeName; } // Find the terminator for the first string while (Idx < NumRead-1 && ExeName[Idx] != 0) { Idx++; } // Go back to the last non-null character Idx--; // Find the last path separator in the first string while (Idx > 0) { if (ExeName[Idx] == '/') { BaseName = ExeName + Idx + 1; break; } Idx--; } // Test this to see if it is the oprofile daemon if (BaseName != 0 && (!strcmp("oprofiled", BaseName) || !strcmp("operf", BaseName))) { // If it is, we're done closedir(ProcDir); return true; } } } } // We've looked through all the files and didn't find the daemon closedir(ProcDir); return false; } bool OProfileWrapper::op_open_agent() { if (!Initialized) initialize(); if (OpenAgentFunc != 0) { Agent = OpenAgentFunc(); return Agent != 0; } return false; } int OProfileWrapper::op_close_agent() { if (!Initialized) initialize(); int ret = -1; if (Agent && CloseAgentFunc) { ret = CloseAgentFunc(Agent); if (ret == 0) { Agent = 0; } } return ret; } bool OProfileWrapper::isAgentAvailable() { return Agent != 0; } int OProfileWrapper::op_write_native_code(const char* Name, uint64_t Addr, void const* Code, const unsigned int Size) { if (!Initialized) initialize(); if (Agent && WriteNativeCodeFunc) return WriteNativeCodeFunc(Agent, Name, Addr, Code, Size); return -1; } int OProfileWrapper::op_write_debug_line_info( void const* Code, size_t NumEntries, struct debug_line_info const* Info) { if (!Initialized) initialize(); if (Agent && WriteDebugLineInfoFunc) return WriteDebugLineInfoFunc(Agent, Code, NumEntries, Info); return -1; } int OProfileWrapper::op_major_version() { if (!Initialized) initialize(); if (Agent && MajorVersionFunc) return MajorVersionFunc(); return -1; } int OProfileWrapper::op_minor_version() { if (!Initialized) initialize(); if (Agent && MinorVersionFunc) return MinorVersionFunc(); return -1; } int OProfileWrapper::op_unload_native_code(uint64_t Addr) { if (!Initialized) initialize(); if (Agent && UnloadNativeCodeFunc) return UnloadNativeCodeFunc(Agent, Addr); return -1; } } // namespace llvm