1234285Sdim//===-- OProfileWrapper.cpp - OProfile JIT API Wrapper implementation -----===//
2234285Sdim//
3234285Sdim//                     The LLVM Compiler Infrastructure
4234285Sdim//
5234285Sdim// This file is distributed under the University of Illinois Open Source
6234285Sdim// License. See LICENSE.TXT for details.
7234285Sdim//
8234285Sdim//===----------------------------------------------------------------------===//
9234285Sdim//
10234285Sdim// This file implements the interface in OProfileWrapper.h. It is responsible
11234285Sdim// for loading the opagent dynamic library when the first call to an op_
12234285Sdim// function occurs.
13234285Sdim//
14234285Sdim//===----------------------------------------------------------------------===//
15234285Sdim
16234285Sdim#include "llvm/ExecutionEngine/OProfileWrapper.h"
17276479Sdim#include "llvm/ADT/SmallString.h"
18234285Sdim#include "llvm/Support/Debug.h"
19234285Sdim#include "llvm/Support/DynamicLibrary.h"
20234285Sdim#include "llvm/Support/Mutex.h"
21234285Sdim#include "llvm/Support/MutexGuard.h"
22276479Sdim#include "llvm/Support/raw_ostream.h"
23261991Sdim#include <cstring>
24261991Sdim#include <dirent.h>
25261991Sdim#include <fcntl.h>
26234285Sdim#include <sstream>
27234285Sdim#include <stddef.h>
28234285Sdim#include <sys/stat.h>
29249423Sdim#include <unistd.h>
30234285Sdim
31276479Sdim#define DEBUG_TYPE "oprofile-wrapper"
32276479Sdim
33234285Sdimnamespace {
34234285Sdim
35234285Sdim// Global mutex to ensure a single thread initializes oprofile agent.
36234285Sdimllvm::sys::Mutex OProfileInitializationMutex;
37234285Sdim
38234285Sdim} // anonymous namespace
39234285Sdim
40234285Sdimnamespace llvm {
41234285Sdim
42234285SdimOProfileWrapper::OProfileWrapper()
43234285Sdim: Agent(0),
44234285Sdim  OpenAgentFunc(0),
45234285Sdim  CloseAgentFunc(0),
46234285Sdim  WriteNativeCodeFunc(0),
47234285Sdim  WriteDebugLineInfoFunc(0),
48234285Sdim  UnloadNativeCodeFunc(0),
49234285Sdim  MajorVersionFunc(0),
50234285Sdim  MinorVersionFunc(0),
51234285Sdim  IsOProfileRunningFunc(0),
52234285Sdim  Initialized(false) {
53234285Sdim}
54234285Sdim
55234285Sdimbool OProfileWrapper::initialize() {
56234285Sdim  using namespace llvm;
57234285Sdim  using namespace llvm::sys;
58234285Sdim
59234285Sdim  MutexGuard Guard(OProfileInitializationMutex);
60234285Sdim
61234285Sdim  if (Initialized)
62234285Sdim    return OpenAgentFunc != 0;
63234285Sdim
64234285Sdim  Initialized = true;
65234285Sdim
66234285Sdim  // If the oprofile daemon is not running, don't load the opagent library
67234285Sdim  if (!isOProfileRunning()) {
68234285Sdim    DEBUG(dbgs() << "OProfile daemon is not detected.\n");
69234285Sdim    return false;
70234285Sdim  }
71234285Sdim
72234285Sdim  std::string error;
73234285Sdim  if(!DynamicLibrary::LoadLibraryPermanently("libopagent.so", &error)) {
74234285Sdim    DEBUG(dbgs()
75234285Sdim            << "OProfile connector library libopagent.so could not be loaded: "
76234285Sdim            << error << "\n");
77234285Sdim  }
78234285Sdim
79234285Sdim  // Get the addresses of the opagent functions
80234285Sdim  OpenAgentFunc = (op_open_agent_ptr_t)(intptr_t)
81234285Sdim          DynamicLibrary::SearchForAddressOfSymbol("op_open_agent");
82234285Sdim  CloseAgentFunc = (op_close_agent_ptr_t)(intptr_t)
83234285Sdim          DynamicLibrary::SearchForAddressOfSymbol("op_close_agent");
84234285Sdim  WriteNativeCodeFunc = (op_write_native_code_ptr_t)(intptr_t)
85234285Sdim          DynamicLibrary::SearchForAddressOfSymbol("op_write_native_code");
86234285Sdim  WriteDebugLineInfoFunc = (op_write_debug_line_info_ptr_t)(intptr_t)
87234285Sdim          DynamicLibrary::SearchForAddressOfSymbol("op_write_debug_line_info");
88234285Sdim  UnloadNativeCodeFunc = (op_unload_native_code_ptr_t)(intptr_t)
89234285Sdim          DynamicLibrary::SearchForAddressOfSymbol("op_unload_native_code");
90234285Sdim  MajorVersionFunc = (op_major_version_ptr_t)(intptr_t)
91234285Sdim          DynamicLibrary::SearchForAddressOfSymbol("op_major_version");
92234285Sdim  MinorVersionFunc = (op_major_version_ptr_t)(intptr_t)
93234285Sdim          DynamicLibrary::SearchForAddressOfSymbol("op_minor_version");
94234285Sdim
95234285Sdim  // With missing functions, we can do nothing
96234285Sdim  if (!OpenAgentFunc
97234285Sdim      || !CloseAgentFunc
98234285Sdim      || !WriteNativeCodeFunc
99234285Sdim      || !WriteDebugLineInfoFunc
100234285Sdim      || !UnloadNativeCodeFunc) {
101234285Sdim    OpenAgentFunc = 0;
102234285Sdim    CloseAgentFunc = 0;
103234285Sdim    WriteNativeCodeFunc = 0;
104234285Sdim    WriteDebugLineInfoFunc = 0;
105234285Sdim    UnloadNativeCodeFunc = 0;
106234285Sdim    return false;
107234285Sdim  }
108234285Sdim
109234285Sdim  return true;
110234285Sdim}
111234285Sdim
112234285Sdimbool OProfileWrapper::isOProfileRunning() {
113234285Sdim  if (IsOProfileRunningFunc != 0)
114234285Sdim    return IsOProfileRunningFunc();
115234285Sdim  return checkForOProfileProcEntry();
116234285Sdim}
117234285Sdim
118234285Sdimbool OProfileWrapper::checkForOProfileProcEntry() {
119234285Sdim  DIR* ProcDir;
120234285Sdim
121234285Sdim  ProcDir = opendir("/proc");
122234285Sdim  if (!ProcDir)
123234285Sdim    return false;
124234285Sdim
125234285Sdim  // Walk the /proc tree looking for the oprofile daemon
126234285Sdim  struct dirent* Entry;
127234285Sdim  while (0 != (Entry = readdir(ProcDir))) {
128234285Sdim    if (Entry->d_type == DT_DIR) {
129234285Sdim      // Build a path from the current entry name
130234285Sdim      SmallString<256> CmdLineFName;
131234285Sdim      raw_svector_ostream(CmdLineFName) << "/proc/" << Entry->d_name
132234285Sdim                                        << "/cmdline";
133234285Sdim
134234285Sdim      // Open the cmdline file
135234285Sdim      int CmdLineFD = open(CmdLineFName.c_str(), S_IRUSR);
136234285Sdim      if (CmdLineFD != -1) {
137234285Sdim        char    ExeName[PATH_MAX+1];
138234285Sdim        char*   BaseName = 0;
139234285Sdim
140234285Sdim        // Read the cmdline file
141234285Sdim        ssize_t NumRead = read(CmdLineFD, ExeName, PATH_MAX+1);
142234285Sdim        close(CmdLineFD);
143234285Sdim        ssize_t Idx = 0;
144234285Sdim
145261991Sdim        if (ExeName[0] != '/') {
146261991Sdim          BaseName = ExeName;
147261991Sdim        }
148261991Sdim
149234285Sdim        // Find the terminator for the first string
150234285Sdim        while (Idx < NumRead-1 && ExeName[Idx] != 0) {
151234285Sdim          Idx++;
152234285Sdim        }
153234285Sdim
154234285Sdim        // Go back to the last non-null character
155234285Sdim        Idx--;
156234285Sdim
157234285Sdim        // Find the last path separator in the first string
158234285Sdim        while (Idx > 0) {
159234285Sdim          if (ExeName[Idx] == '/') {
160234285Sdim            BaseName = ExeName + Idx + 1;
161234285Sdim            break;
162234285Sdim          }
163234285Sdim          Idx--;
164234285Sdim        }
165234285Sdim
166234285Sdim        // Test this to see if it is the oprofile daemon
167261991Sdim        if (BaseName != 0 && (!strcmp("oprofiled", BaseName) ||
168261991Sdim                              !strcmp("operf", BaseName))) {
169234285Sdim          // If it is, we're done
170234285Sdim          closedir(ProcDir);
171234285Sdim          return true;
172234285Sdim        }
173234285Sdim      }
174234285Sdim    }
175234285Sdim  }
176234285Sdim
177234285Sdim  // We've looked through all the files and didn't find the daemon
178234285Sdim  closedir(ProcDir);
179234285Sdim  return false;
180234285Sdim}
181234285Sdim
182234285Sdimbool OProfileWrapper::op_open_agent() {
183234285Sdim  if (!Initialized)
184234285Sdim    initialize();
185234285Sdim
186234285Sdim  if (OpenAgentFunc != 0) {
187234285Sdim    Agent = OpenAgentFunc();
188234285Sdim    return Agent != 0;
189234285Sdim  }
190234285Sdim
191234285Sdim  return false;
192234285Sdim}
193234285Sdim
194234285Sdimint OProfileWrapper::op_close_agent() {
195234285Sdim  if (!Initialized)
196234285Sdim    initialize();
197234285Sdim
198234285Sdim  int ret = -1;
199234285Sdim  if (Agent && CloseAgentFunc) {
200234285Sdim    ret = CloseAgentFunc(Agent);
201234285Sdim    if (ret == 0) {
202234285Sdim      Agent = 0;
203234285Sdim    }
204234285Sdim  }
205234285Sdim  return ret;
206234285Sdim}
207234285Sdim
208234285Sdimbool OProfileWrapper::isAgentAvailable() {
209234285Sdim  return Agent != 0;
210234285Sdim}
211234285Sdim
212234285Sdimint OProfileWrapper::op_write_native_code(const char* Name,
213234285Sdim                                          uint64_t Addr,
214234285Sdim                                          void const* Code,
215234285Sdim                                          const unsigned int Size) {
216234285Sdim  if (!Initialized)
217234285Sdim    initialize();
218234285Sdim
219234285Sdim  if (Agent && WriteNativeCodeFunc)
220234285Sdim    return WriteNativeCodeFunc(Agent, Name, Addr, Code, Size);
221234285Sdim
222234285Sdim  return -1;
223234285Sdim}
224234285Sdim
225234285Sdimint OProfileWrapper::op_write_debug_line_info(
226234285Sdim  void const* Code,
227234285Sdim  size_t NumEntries,
228234285Sdim  struct debug_line_info const* Info) {
229234285Sdim  if (!Initialized)
230234285Sdim    initialize();
231234285Sdim
232234285Sdim  if (Agent && WriteDebugLineInfoFunc)
233234285Sdim    return WriteDebugLineInfoFunc(Agent, Code, NumEntries, Info);
234234285Sdim
235234285Sdim  return -1;
236234285Sdim}
237234285Sdim
238234285Sdimint OProfileWrapper::op_major_version() {
239234285Sdim  if (!Initialized)
240234285Sdim    initialize();
241234285Sdim
242234285Sdim  if (Agent && MajorVersionFunc)
243234285Sdim    return MajorVersionFunc();
244234285Sdim
245234285Sdim  return -1;
246234285Sdim}
247234285Sdim
248234285Sdimint OProfileWrapper::op_minor_version() {
249234285Sdim  if (!Initialized)
250234285Sdim    initialize();
251234285Sdim
252234285Sdim  if (Agent && MinorVersionFunc)
253234285Sdim    return MinorVersionFunc();
254234285Sdim
255234285Sdim  return -1;
256234285Sdim}
257234285Sdim
258234285Sdimint  OProfileWrapper::op_unload_native_code(uint64_t Addr) {
259234285Sdim  if (!Initialized)
260234285Sdim    initialize();
261234285Sdim
262234285Sdim  if (Agent && UnloadNativeCodeFunc)
263234285Sdim    return UnloadNativeCodeFunc(Agent, Addr);
264234285Sdim
265234285Sdim  return -1;
266234285Sdim}
267234285Sdim
268234285Sdim} // namespace llvm
269