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