| //===-- 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 <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()) { | |
| LLVM_DEBUG(dbgs() << "OProfile daemon is not detected.\n"); | |
| return false; | |
| } | |
| std::string error; | |
| if(!DynamicLibrary::LoadLibraryPermanently("libopagent.so", &error)) { | |
| LLVM_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 |