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