xref: /freebsd-src/contrib/llvm-project/llvm/lib/ExecutionEngine/OProfileJIT/OProfileWrapper.cpp (revision 5b27928474e6a4103d65b347544705c40c9618fd)
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