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