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(Filename: "libopagent.so" , ErrMsg: &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(symbolName: "op_open_agent" ); |
81 | CloseAgentFunc = (op_close_agent_ptr_t)(intptr_t) |
82 | DynamicLibrary::SearchForAddressOfSymbol(symbolName: "op_close_agent" ); |
83 | WriteNativeCodeFunc = (op_write_native_code_ptr_t)(intptr_t) |
84 | DynamicLibrary::SearchForAddressOfSymbol(symbolName: "op_write_native_code" ); |
85 | WriteDebugLineInfoFunc = (op_write_debug_line_info_ptr_t)(intptr_t) |
86 | DynamicLibrary::SearchForAddressOfSymbol(symbolName: "op_write_debug_line_info" ); |
87 | UnloadNativeCodeFunc = (op_unload_native_code_ptr_t)(intptr_t) |
88 | DynamicLibrary::SearchForAddressOfSymbol(symbolName: "op_unload_native_code" ); |
89 | MajorVersionFunc = (op_major_version_ptr_t)(intptr_t) |
90 | DynamicLibrary::SearchForAddressOfSymbol(symbolName: "op_major_version" ); |
91 | MinorVersionFunc = (op_major_version_ptr_t)(intptr_t) |
92 | DynamicLibrary::SearchForAddressOfSymbol(symbolName: "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(name: "/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(dirp: 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(file: 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(fd: CmdLineFD, buf: ExeName, PATH_MAX+1); |
141 | close(fd: 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(s1: "oprofiled" , s2: BaseName) || |
167 | !strcmp(s1: "operf" , s2: BaseName))) { |
168 | // If it is, we're done |
169 | closedir(dirp: 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(dirp: 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 | |