10b57cec5SDimitry Andric //===-- OProfileWrapper.cpp - OProfile JIT API Wrapper implementation -----===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file implements the interface in OProfileWrapper.h. It is responsible 100b57cec5SDimitry Andric // for loading the opagent dynamic library when the first call to an op_ 110b57cec5SDimitry Andric // function occurs. 120b57cec5SDimitry Andric // 130b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 140b57cec5SDimitry Andric 150b57cec5SDimitry Andric #include "llvm/ExecutionEngine/OProfileWrapper.h" 160b57cec5SDimitry Andric #include "llvm/ADT/SmallString.h" 170b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 180b57cec5SDimitry Andric #include "llvm/Support/DynamicLibrary.h" 190b57cec5SDimitry Andric #include "llvm/Support/Mutex.h" 200b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 210b57cec5SDimitry Andric #include <cstring> 220b57cec5SDimitry Andric #include <dirent.h> 230b57cec5SDimitry Andric #include <fcntl.h> 24*8bcb0991SDimitry Andric #include <mutex> 250b57cec5SDimitry Andric #include <stddef.h> 260b57cec5SDimitry Andric #include <sys/stat.h> 270b57cec5SDimitry Andric #include <unistd.h> 280b57cec5SDimitry Andric 290b57cec5SDimitry Andric #define DEBUG_TYPE "oprofile-wrapper" 300b57cec5SDimitry Andric 310b57cec5SDimitry Andric namespace { 320b57cec5SDimitry Andric 330b57cec5SDimitry Andric // Global mutex to ensure a single thread initializes oprofile agent. 340b57cec5SDimitry Andric llvm::sys::Mutex OProfileInitializationMutex; 350b57cec5SDimitry Andric 360b57cec5SDimitry Andric } // anonymous namespace 370b57cec5SDimitry Andric 380b57cec5SDimitry Andric namespace llvm { 390b57cec5SDimitry Andric 400b57cec5SDimitry Andric OProfileWrapper::OProfileWrapper() 410b57cec5SDimitry Andric : Agent(0), 420b57cec5SDimitry Andric OpenAgentFunc(0), 430b57cec5SDimitry Andric CloseAgentFunc(0), 440b57cec5SDimitry Andric WriteNativeCodeFunc(0), 450b57cec5SDimitry Andric WriteDebugLineInfoFunc(0), 460b57cec5SDimitry Andric UnloadNativeCodeFunc(0), 470b57cec5SDimitry Andric MajorVersionFunc(0), 480b57cec5SDimitry Andric MinorVersionFunc(0), 490b57cec5SDimitry Andric IsOProfileRunningFunc(0), 500b57cec5SDimitry Andric Initialized(false) { 510b57cec5SDimitry Andric } 520b57cec5SDimitry Andric 530b57cec5SDimitry Andric bool OProfileWrapper::initialize() { 540b57cec5SDimitry Andric using namespace llvm; 550b57cec5SDimitry Andric using namespace llvm::sys; 560b57cec5SDimitry Andric 57*8bcb0991SDimitry Andric std::lock_guard<sys::Mutex> Guard(OProfileInitializationMutex); 580b57cec5SDimitry Andric 590b57cec5SDimitry Andric if (Initialized) 600b57cec5SDimitry Andric return OpenAgentFunc != 0; 610b57cec5SDimitry Andric 620b57cec5SDimitry Andric Initialized = true; 630b57cec5SDimitry Andric 640b57cec5SDimitry Andric // If the oprofile daemon is not running, don't load the opagent library 650b57cec5SDimitry Andric if (!isOProfileRunning()) { 660b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "OProfile daemon is not detected.\n"); 670b57cec5SDimitry Andric return false; 680b57cec5SDimitry Andric } 690b57cec5SDimitry Andric 700b57cec5SDimitry Andric std::string error; 710b57cec5SDimitry Andric if(!DynamicLibrary::LoadLibraryPermanently("libopagent.so", &error)) { 720b57cec5SDimitry Andric LLVM_DEBUG( 730b57cec5SDimitry Andric dbgs() 740b57cec5SDimitry Andric << "OProfile connector library libopagent.so could not be loaded: " 750b57cec5SDimitry Andric << error << "\n"); 760b57cec5SDimitry Andric } 770b57cec5SDimitry Andric 780b57cec5SDimitry Andric // Get the addresses of the opagent functions 790b57cec5SDimitry Andric OpenAgentFunc = (op_open_agent_ptr_t)(intptr_t) 800b57cec5SDimitry Andric DynamicLibrary::SearchForAddressOfSymbol("op_open_agent"); 810b57cec5SDimitry Andric CloseAgentFunc = (op_close_agent_ptr_t)(intptr_t) 820b57cec5SDimitry Andric DynamicLibrary::SearchForAddressOfSymbol("op_close_agent"); 830b57cec5SDimitry Andric WriteNativeCodeFunc = (op_write_native_code_ptr_t)(intptr_t) 840b57cec5SDimitry Andric DynamicLibrary::SearchForAddressOfSymbol("op_write_native_code"); 850b57cec5SDimitry Andric WriteDebugLineInfoFunc = (op_write_debug_line_info_ptr_t)(intptr_t) 860b57cec5SDimitry Andric DynamicLibrary::SearchForAddressOfSymbol("op_write_debug_line_info"); 870b57cec5SDimitry Andric UnloadNativeCodeFunc = (op_unload_native_code_ptr_t)(intptr_t) 880b57cec5SDimitry Andric DynamicLibrary::SearchForAddressOfSymbol("op_unload_native_code"); 890b57cec5SDimitry Andric MajorVersionFunc = (op_major_version_ptr_t)(intptr_t) 900b57cec5SDimitry Andric DynamicLibrary::SearchForAddressOfSymbol("op_major_version"); 910b57cec5SDimitry Andric MinorVersionFunc = (op_major_version_ptr_t)(intptr_t) 920b57cec5SDimitry Andric DynamicLibrary::SearchForAddressOfSymbol("op_minor_version"); 930b57cec5SDimitry Andric 940b57cec5SDimitry Andric // With missing functions, we can do nothing 950b57cec5SDimitry Andric if (!OpenAgentFunc 960b57cec5SDimitry Andric || !CloseAgentFunc 970b57cec5SDimitry Andric || !WriteNativeCodeFunc 980b57cec5SDimitry Andric || !WriteDebugLineInfoFunc 990b57cec5SDimitry Andric || !UnloadNativeCodeFunc) { 1000b57cec5SDimitry Andric OpenAgentFunc = 0; 1010b57cec5SDimitry Andric CloseAgentFunc = 0; 1020b57cec5SDimitry Andric WriteNativeCodeFunc = 0; 1030b57cec5SDimitry Andric WriteDebugLineInfoFunc = 0; 1040b57cec5SDimitry Andric UnloadNativeCodeFunc = 0; 1050b57cec5SDimitry Andric return false; 1060b57cec5SDimitry Andric } 1070b57cec5SDimitry Andric 1080b57cec5SDimitry Andric return true; 1090b57cec5SDimitry Andric } 1100b57cec5SDimitry Andric 1110b57cec5SDimitry Andric bool OProfileWrapper::isOProfileRunning() { 1120b57cec5SDimitry Andric if (IsOProfileRunningFunc != 0) 1130b57cec5SDimitry Andric return IsOProfileRunningFunc(); 1140b57cec5SDimitry Andric return checkForOProfileProcEntry(); 1150b57cec5SDimitry Andric } 1160b57cec5SDimitry Andric 1170b57cec5SDimitry Andric bool OProfileWrapper::checkForOProfileProcEntry() { 1180b57cec5SDimitry Andric DIR* ProcDir; 1190b57cec5SDimitry Andric 1200b57cec5SDimitry Andric ProcDir = opendir("/proc"); 1210b57cec5SDimitry Andric if (!ProcDir) 1220b57cec5SDimitry Andric return false; 1230b57cec5SDimitry Andric 1240b57cec5SDimitry Andric // Walk the /proc tree looking for the oprofile daemon 1250b57cec5SDimitry Andric struct dirent* Entry; 1260b57cec5SDimitry Andric while (0 != (Entry = readdir(ProcDir))) { 1270b57cec5SDimitry Andric if (Entry->d_type == DT_DIR) { 1280b57cec5SDimitry Andric // Build a path from the current entry name 1290b57cec5SDimitry Andric SmallString<256> CmdLineFName; 1300b57cec5SDimitry Andric raw_svector_ostream(CmdLineFName) << "/proc/" << Entry->d_name 1310b57cec5SDimitry Andric << "/cmdline"; 1320b57cec5SDimitry Andric 1330b57cec5SDimitry Andric // Open the cmdline file 1340b57cec5SDimitry Andric int CmdLineFD = open(CmdLineFName.c_str(), S_IRUSR); 1350b57cec5SDimitry Andric if (CmdLineFD != -1) { 1360b57cec5SDimitry Andric char ExeName[PATH_MAX+1]; 1370b57cec5SDimitry Andric char* BaseName = 0; 1380b57cec5SDimitry Andric 1390b57cec5SDimitry Andric // Read the cmdline file 1400b57cec5SDimitry Andric ssize_t NumRead = read(CmdLineFD, ExeName, PATH_MAX+1); 1410b57cec5SDimitry Andric close(CmdLineFD); 1420b57cec5SDimitry Andric ssize_t Idx = 0; 1430b57cec5SDimitry Andric 1440b57cec5SDimitry Andric if (ExeName[0] != '/') { 1450b57cec5SDimitry Andric BaseName = ExeName; 1460b57cec5SDimitry Andric } 1470b57cec5SDimitry Andric 1480b57cec5SDimitry Andric // Find the terminator for the first string 1490b57cec5SDimitry Andric while (Idx < NumRead-1 && ExeName[Idx] != 0) { 1500b57cec5SDimitry Andric Idx++; 1510b57cec5SDimitry Andric } 1520b57cec5SDimitry Andric 1530b57cec5SDimitry Andric // Go back to the last non-null character 1540b57cec5SDimitry Andric Idx--; 1550b57cec5SDimitry Andric 1560b57cec5SDimitry Andric // Find the last path separator in the first string 1570b57cec5SDimitry Andric while (Idx > 0) { 1580b57cec5SDimitry Andric if (ExeName[Idx] == '/') { 1590b57cec5SDimitry Andric BaseName = ExeName + Idx + 1; 1600b57cec5SDimitry Andric break; 1610b57cec5SDimitry Andric } 1620b57cec5SDimitry Andric Idx--; 1630b57cec5SDimitry Andric } 1640b57cec5SDimitry Andric 1650b57cec5SDimitry Andric // Test this to see if it is the oprofile daemon 1660b57cec5SDimitry Andric if (BaseName != 0 && (!strcmp("oprofiled", BaseName) || 1670b57cec5SDimitry Andric !strcmp("operf", BaseName))) { 1680b57cec5SDimitry Andric // If it is, we're done 1690b57cec5SDimitry Andric closedir(ProcDir); 1700b57cec5SDimitry Andric return true; 1710b57cec5SDimitry Andric } 1720b57cec5SDimitry Andric } 1730b57cec5SDimitry Andric } 1740b57cec5SDimitry Andric } 1750b57cec5SDimitry Andric 1760b57cec5SDimitry Andric // We've looked through all the files and didn't find the daemon 1770b57cec5SDimitry Andric closedir(ProcDir); 1780b57cec5SDimitry Andric return false; 1790b57cec5SDimitry Andric } 1800b57cec5SDimitry Andric 1810b57cec5SDimitry Andric bool OProfileWrapper::op_open_agent() { 1820b57cec5SDimitry Andric if (!Initialized) 1830b57cec5SDimitry Andric initialize(); 1840b57cec5SDimitry Andric 1850b57cec5SDimitry Andric if (OpenAgentFunc != 0) { 1860b57cec5SDimitry Andric Agent = OpenAgentFunc(); 1870b57cec5SDimitry Andric return Agent != 0; 1880b57cec5SDimitry Andric } 1890b57cec5SDimitry Andric 1900b57cec5SDimitry Andric return false; 1910b57cec5SDimitry Andric } 1920b57cec5SDimitry Andric 1930b57cec5SDimitry Andric int OProfileWrapper::op_close_agent() { 1940b57cec5SDimitry Andric if (!Initialized) 1950b57cec5SDimitry Andric initialize(); 1960b57cec5SDimitry Andric 1970b57cec5SDimitry Andric int ret = -1; 1980b57cec5SDimitry Andric if (Agent && CloseAgentFunc) { 1990b57cec5SDimitry Andric ret = CloseAgentFunc(Agent); 2000b57cec5SDimitry Andric if (ret == 0) { 2010b57cec5SDimitry Andric Agent = 0; 2020b57cec5SDimitry Andric } 2030b57cec5SDimitry Andric } 2040b57cec5SDimitry Andric return ret; 2050b57cec5SDimitry Andric } 2060b57cec5SDimitry Andric 2070b57cec5SDimitry Andric bool OProfileWrapper::isAgentAvailable() { 2080b57cec5SDimitry Andric return Agent != 0; 2090b57cec5SDimitry Andric } 2100b57cec5SDimitry Andric 2110b57cec5SDimitry Andric int OProfileWrapper::op_write_native_code(const char* Name, 2120b57cec5SDimitry Andric uint64_t Addr, 2130b57cec5SDimitry Andric void const* Code, 2140b57cec5SDimitry Andric const unsigned int Size) { 2150b57cec5SDimitry Andric if (!Initialized) 2160b57cec5SDimitry Andric initialize(); 2170b57cec5SDimitry Andric 2180b57cec5SDimitry Andric if (Agent && WriteNativeCodeFunc) 2190b57cec5SDimitry Andric return WriteNativeCodeFunc(Agent, Name, Addr, Code, Size); 2200b57cec5SDimitry Andric 2210b57cec5SDimitry Andric return -1; 2220b57cec5SDimitry Andric } 2230b57cec5SDimitry Andric 2240b57cec5SDimitry Andric int OProfileWrapper::op_write_debug_line_info( 2250b57cec5SDimitry Andric void const* Code, 2260b57cec5SDimitry Andric size_t NumEntries, 2270b57cec5SDimitry Andric struct debug_line_info const* Info) { 2280b57cec5SDimitry Andric if (!Initialized) 2290b57cec5SDimitry Andric initialize(); 2300b57cec5SDimitry Andric 2310b57cec5SDimitry Andric if (Agent && WriteDebugLineInfoFunc) 2320b57cec5SDimitry Andric return WriteDebugLineInfoFunc(Agent, Code, NumEntries, Info); 2330b57cec5SDimitry Andric 2340b57cec5SDimitry Andric return -1; 2350b57cec5SDimitry Andric } 2360b57cec5SDimitry Andric 2370b57cec5SDimitry Andric int OProfileWrapper::op_major_version() { 2380b57cec5SDimitry Andric if (!Initialized) 2390b57cec5SDimitry Andric initialize(); 2400b57cec5SDimitry Andric 2410b57cec5SDimitry Andric if (Agent && MajorVersionFunc) 2420b57cec5SDimitry Andric return MajorVersionFunc(); 2430b57cec5SDimitry Andric 2440b57cec5SDimitry Andric return -1; 2450b57cec5SDimitry Andric } 2460b57cec5SDimitry Andric 2470b57cec5SDimitry Andric int OProfileWrapper::op_minor_version() { 2480b57cec5SDimitry Andric if (!Initialized) 2490b57cec5SDimitry Andric initialize(); 2500b57cec5SDimitry Andric 2510b57cec5SDimitry Andric if (Agent && MinorVersionFunc) 2520b57cec5SDimitry Andric return MinorVersionFunc(); 2530b57cec5SDimitry Andric 2540b57cec5SDimitry Andric return -1; 2550b57cec5SDimitry Andric } 2560b57cec5SDimitry Andric 2570b57cec5SDimitry Andric int OProfileWrapper::op_unload_native_code(uint64_t Addr) { 2580b57cec5SDimitry Andric if (!Initialized) 2590b57cec5SDimitry Andric initialize(); 2600b57cec5SDimitry Andric 2610b57cec5SDimitry Andric if (Agent && UnloadNativeCodeFunc) 2620b57cec5SDimitry Andric return UnloadNativeCodeFunc(Agent, Addr); 2630b57cec5SDimitry Andric 2640b57cec5SDimitry Andric return -1; 2650b57cec5SDimitry Andric } 2660b57cec5SDimitry Andric 2670b57cec5SDimitry Andric } // namespace llvm 268