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
OProfileWrapper()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
initialize()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
isOProfileRunning()1110b57cec5SDimitry Andric bool OProfileWrapper::isOProfileRunning() {
1120b57cec5SDimitry Andric if (IsOProfileRunningFunc != 0)
1130b57cec5SDimitry Andric return IsOProfileRunningFunc();
1140b57cec5SDimitry Andric return checkForOProfileProcEntry();
1150b57cec5SDimitry Andric }
1160b57cec5SDimitry Andric
checkForOProfileProcEntry()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
op_open_agent()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
op_close_agent()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
isAgentAvailable()2070b57cec5SDimitry Andric bool OProfileWrapper::isAgentAvailable() {
2080b57cec5SDimitry Andric return Agent != 0;
2090b57cec5SDimitry Andric }
2100b57cec5SDimitry Andric
op_write_native_code(const char * Name,uint64_t Addr,void const * Code,const unsigned int Size)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
op_write_debug_line_info(void const * Code,size_t NumEntries,struct debug_line_info const * Info)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
op_major_version()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
op_minor_version()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
op_unload_native_code(uint64_t Addr)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