1 //===-- OProfileWrapper.cpp - OProfile JIT API Wrapper implementation -----===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file implements the interface in OProfileWrapper.h. It is responsible 10 // for loading the opagent dynamic library when the first call to an op_ 11 // function occurs. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #include "llvm/ExecutionEngine/OProfileWrapper.h" 16 #include "llvm/ADT/SmallString.h" 17 #include "llvm/Support/Debug.h" 18 #include "llvm/Support/DynamicLibrary.h" 19 #include "llvm/Support/Mutex.h" 20 #include "llvm/Support/raw_ostream.h" 21 #include <cstring> 22 #include <dirent.h> 23 #include <fcntl.h> 24 #include <mutex> 25 #include <stddef.h> 26 #include <sys/stat.h> 27 #include <unistd.h> 28 29 #define DEBUG_TYPE "oprofile-wrapper" 30 31 namespace { 32 33 // Global mutex to ensure a single thread initializes oprofile agent. 34 llvm::sys::Mutex OProfileInitializationMutex; 35 36 } // anonymous namespace 37 38 namespace llvm { 39 40 OProfileWrapper::OProfileWrapper() 41 : Agent(0), 42 OpenAgentFunc(0), 43 CloseAgentFunc(0), 44 WriteNativeCodeFunc(0), 45 WriteDebugLineInfoFunc(0), 46 UnloadNativeCodeFunc(0), 47 MajorVersionFunc(0), 48 MinorVersionFunc(0), 49 IsOProfileRunningFunc(0), 50 Initialized(false) { 51 } 52 53 bool OProfileWrapper::initialize() { 54 using namespace llvm; 55 using namespace llvm::sys; 56 57 std::lock_guard<sys::Mutex> Guard(OProfileInitializationMutex); 58 59 if (Initialized) 60 return OpenAgentFunc != 0; 61 62 Initialized = true; 63 64 // If the oprofile daemon is not running, don't load the opagent library 65 if (!isOProfileRunning()) { 66 LLVM_DEBUG(dbgs() << "OProfile daemon is not detected.\n"); 67 return false; 68 } 69 70 std::string error; 71 if(!DynamicLibrary::LoadLibraryPermanently("libopagent.so", &error)) { 72 LLVM_DEBUG( 73 dbgs() 74 << "OProfile connector library libopagent.so could not be loaded: " 75 << error << "\n"); 76 } 77 78 // Get the addresses of the opagent functions 79 OpenAgentFunc = (op_open_agent_ptr_t)(intptr_t) 80 DynamicLibrary::SearchForAddressOfSymbol("op_open_agent"); 81 CloseAgentFunc = (op_close_agent_ptr_t)(intptr_t) 82 DynamicLibrary::SearchForAddressOfSymbol("op_close_agent"); 83 WriteNativeCodeFunc = (op_write_native_code_ptr_t)(intptr_t) 84 DynamicLibrary::SearchForAddressOfSymbol("op_write_native_code"); 85 WriteDebugLineInfoFunc = (op_write_debug_line_info_ptr_t)(intptr_t) 86 DynamicLibrary::SearchForAddressOfSymbol("op_write_debug_line_info"); 87 UnloadNativeCodeFunc = (op_unload_native_code_ptr_t)(intptr_t) 88 DynamicLibrary::SearchForAddressOfSymbol("op_unload_native_code"); 89 MajorVersionFunc = (op_major_version_ptr_t)(intptr_t) 90 DynamicLibrary::SearchForAddressOfSymbol("op_major_version"); 91 MinorVersionFunc = (op_major_version_ptr_t)(intptr_t) 92 DynamicLibrary::SearchForAddressOfSymbol("op_minor_version"); 93 94 // With missing functions, we can do nothing 95 if (!OpenAgentFunc 96 || !CloseAgentFunc 97 || !WriteNativeCodeFunc 98 || !WriteDebugLineInfoFunc 99 || !UnloadNativeCodeFunc) { 100 OpenAgentFunc = 0; 101 CloseAgentFunc = 0; 102 WriteNativeCodeFunc = 0; 103 WriteDebugLineInfoFunc = 0; 104 UnloadNativeCodeFunc = 0; 105 return false; 106 } 107 108 return true; 109 } 110 111 bool OProfileWrapper::isOProfileRunning() { 112 if (IsOProfileRunningFunc != 0) 113 return IsOProfileRunningFunc(); 114 return checkForOProfileProcEntry(); 115 } 116 117 bool OProfileWrapper::checkForOProfileProcEntry() { 118 DIR* ProcDir; 119 120 ProcDir = opendir("/proc"); 121 if (!ProcDir) 122 return false; 123 124 // Walk the /proc tree looking for the oprofile daemon 125 struct dirent* Entry; 126 while (0 != (Entry = readdir(ProcDir))) { 127 if (Entry->d_type == DT_DIR) { 128 // Build a path from the current entry name 129 SmallString<256> CmdLineFName; 130 raw_svector_ostream(CmdLineFName) << "/proc/" << Entry->d_name 131 << "/cmdline"; 132 133 // Open the cmdline file 134 int CmdLineFD = open(CmdLineFName.c_str(), S_IRUSR); 135 if (CmdLineFD != -1) { 136 char ExeName[PATH_MAX+1]; 137 char* BaseName = 0; 138 139 // Read the cmdline file 140 ssize_t NumRead = read(CmdLineFD, ExeName, PATH_MAX+1); 141 close(CmdLineFD); 142 ssize_t Idx = 0; 143 144 if (ExeName[0] != '/') { 145 BaseName = ExeName; 146 } 147 148 // Find the terminator for the first string 149 while (Idx < NumRead-1 && ExeName[Idx] != 0) { 150 Idx++; 151 } 152 153 // Go back to the last non-null character 154 Idx--; 155 156 // Find the last path separator in the first string 157 while (Idx > 0) { 158 if (ExeName[Idx] == '/') { 159 BaseName = ExeName + Idx + 1; 160 break; 161 } 162 Idx--; 163 } 164 165 // Test this to see if it is the oprofile daemon 166 if (BaseName != 0 && (!strcmp("oprofiled", BaseName) || 167 !strcmp("operf", BaseName))) { 168 // If it is, we're done 169 closedir(ProcDir); 170 return true; 171 } 172 } 173 } 174 } 175 176 // We've looked through all the files and didn't find the daemon 177 closedir(ProcDir); 178 return false; 179 } 180 181 bool OProfileWrapper::op_open_agent() { 182 if (!Initialized) 183 initialize(); 184 185 if (OpenAgentFunc != 0) { 186 Agent = OpenAgentFunc(); 187 return Agent != 0; 188 } 189 190 return false; 191 } 192 193 int OProfileWrapper::op_close_agent() { 194 if (!Initialized) 195 initialize(); 196 197 int ret = -1; 198 if (Agent && CloseAgentFunc) { 199 ret = CloseAgentFunc(Agent); 200 if (ret == 0) { 201 Agent = 0; 202 } 203 } 204 return ret; 205 } 206 207 bool OProfileWrapper::isAgentAvailable() { 208 return Agent != 0; 209 } 210 211 int OProfileWrapper::op_write_native_code(const char* Name, 212 uint64_t Addr, 213 void const* Code, 214 const unsigned int Size) { 215 if (!Initialized) 216 initialize(); 217 218 if (Agent && WriteNativeCodeFunc) 219 return WriteNativeCodeFunc(Agent, Name, Addr, Code, Size); 220 221 return -1; 222 } 223 224 int OProfileWrapper::op_write_debug_line_info( 225 void const* Code, 226 size_t NumEntries, 227 struct debug_line_info const* Info) { 228 if (!Initialized) 229 initialize(); 230 231 if (Agent && WriteDebugLineInfoFunc) 232 return WriteDebugLineInfoFunc(Agent, Code, NumEntries, Info); 233 234 return -1; 235 } 236 237 int OProfileWrapper::op_major_version() { 238 if (!Initialized) 239 initialize(); 240 241 if (Agent && MajorVersionFunc) 242 return MajorVersionFunc(); 243 244 return -1; 245 } 246 247 int OProfileWrapper::op_minor_version() { 248 if (!Initialized) 249 initialize(); 250 251 if (Agent && MinorVersionFunc) 252 return MinorVersionFunc(); 253 254 return -1; 255 } 256 257 int OProfileWrapper::op_unload_native_code(uint64_t Addr) { 258 if (!Initialized) 259 initialize(); 260 261 if (Agent && UnloadNativeCodeFunc) 262 return UnloadNativeCodeFunc(Agent, Addr); 263 264 return -1; 265 } 266 267 } // namespace llvm 268