xref: /netbsd-src/external/gpl3/binutils.old/dist/gprofng/libcollector/jprofile.c (revision c42dbd0ed2e61fe6eda8590caa852ccf34719964)
1 /* Copyright (C) 2021 Free Software Foundation, Inc.
2    Contributed by Oracle.
3 
4    This file is part of GNU Binutils.
5 
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3, or (at your option)
9    any later version.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, 51 Franklin Street - Fifth Floor, Boston,
19    MA 02110-1301, USA.  */
20 
21 #include "config.h"
22 
23 #if defined(GPROFNG_JAVA_PROFILING)
24 #include <alloca.h>
25 #include <dlfcn.h> /* dlsym()	*/
26 #include <sys/stat.h>
27 #include <fcntl.h>
28 #include <unistd.h>
29 #include <errno.h>
30 #include <sys/param.h> /* MAXPATHLEN */
31 
32 #include <jni.h>
33 #include <jvmti.h>
34 
35 #include "gp-defs.h"
36 #include "collector.h"
37 #include "gp-experiment.h"
38 #include "tsd.h"
39 
40 /* TprintfT(<level>,...) definitions.  Adjust per module as needed */
41 #define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings
42 #define DBG_LT1 1 // for configuration details, warnings
43 #define DBG_LT2 2
44 #define DBG_LT3 3
45 
46 /* ARCH_STRLEN is defined in dbe, copied here */
47 #define ARCH_STRLEN(s)      ((CALL_UTIL(strlen)(s) + 4 ) & ~0x3)
48 
49 /* call frame */
50 typedef struct
51 {
52   jint lineno;              /* line number in the source file */
53   jmethodID method_id;      /* method executed in this frame */
54 } JVMPI_CallFrame;
55 
56 /* call trace */
57 typedef struct
58 {
59   JNIEnv *env_id;           /* Env where trace was recorded */
60   jint num_frames;          /* number of frames in this trace */
61   JVMPI_CallFrame *frames;  /* frames */
62 } JVMPI_CallTrace;
63 
64 extern void __collector_jprofile_enable_synctrace (void);
65 int __collector_jprofile_start_attach (void);
66 static int init_interface (CollectorInterface*);
67 static int open_experiment (const char *);
68 static int close_experiment (void);
69 static int detach_experiment (void);
70 static void jprof_find_asyncgetcalltrace (void);
71 static char *apistr = NULL;
72 
73 static ModuleInterface module_interface = {
74   "*"SP_JCLASSES_FILE,      /* description, exempt from limit */
75   init_interface,           /* initInterface */
76   open_experiment,          /* openExperiment */
77   NULL,                     /* startDataCollection */
78   NULL,                     /* stopDataCollection */
79   close_experiment,         /* closeExperiment */
80   detach_experiment         /* detachExperiment (fork child) */
81 };
82 
83 static CollectorInterface *collector_interface = NULL;
84 static CollectorModule jprof_hndl = COLLECTOR_MODULE_ERR;
85 static int __collector_java_attach = 0;
86 static JavaVM *jvm;
87 static jmethodID getResource = NULL;
88 static jmethodID toExternalForm = NULL;
89 
90 /* Java profiling thread specific data */
91 typedef struct TSD_Entry
92 {
93   JNIEnv *env;
94   hrtime_t tstamp;
95 } TSD_Entry;
96 
97 static unsigned tsd_key = COLLECTOR_TSD_INVALID_KEY;
98 static collector_mutex_t jclasses_lock = COLLECTOR_MUTEX_INITIALIZER;
99 static int java_gc_on = 0;
100 static int java_mem_mode = 0;
101 static int java_sync_mode = 0;
102 static int is_hotspot_vm = 0;
103 static void get_jvm_settings ();
104 static void rwrite (int fd, const void *buf, size_t nbyte);
105 static void addToDynamicArchive (const char* name, const unsigned char* class_data, int class_data_len);
106 static void (*AsyncGetCallTrace)(JVMPI_CallTrace*, jint, ucontext_t*) = NULL;
107 static void (*collector_heap_record)(int, int, void*) = NULL;
108 static void (*collector_jsync_begin)() = NULL;
109 static void (*collector_jsync_end)(hrtime_t, void *) = NULL;
110 
111 #define gethrtime collector_interface->getHiResTime
112 
113 /*
114  * JVMTI declarations
115  */
116 
117 static jvmtiEnv *jvmti;
118 static void jvmti_VMInit (jvmtiEnv*, JNIEnv*, jthread);
119 static void jvmti_VMDeath (jvmtiEnv*, JNIEnv*);
120 static void jvmti_ThreadStart (jvmtiEnv*, JNIEnv*, jthread);
121 static void jvmti_ThreadEnd (jvmtiEnv*, JNIEnv*, jthread);
122 static void jvmti_CompiledMethodLoad (jvmtiEnv*, jmethodID, jint, const void*,
123 				      jint, const jvmtiAddrLocationMap*, const void*);
124 static void jvmti_CompiledMethodUnload (jvmtiEnv*, jmethodID, const void*);
125 static void jvmti_DynamicCodeGenerated (jvmtiEnv*, const char*, const void*, jint);
126 static void jvmti_ClassPrepare (jvmtiEnv*, JNIEnv*, jthread, jclass);
127 static void jvmti_ClassLoad (jvmtiEnv*, JNIEnv*, jthread, jclass);
128 //static void jvmti_ClassUnload( jvmtiEnv*, JNIEnv*, jthread, jclass );
129 static void jvmti_MonitorEnter (jvmtiEnv *, JNIEnv*, jthread, jobject);
130 static void jvmti_MonitorEntered (jvmtiEnv *, JNIEnv*, jthread, jobject);
131 #if 0
132 static void jvmti_MonitorWait (jvmtiEnv *, JNIEnv*, jthread, jobject, jlong);
133 static void jvmti_MonitorWaited (jvmtiEnv *, JNIEnv*, jthread, jobject, jboolean);
134 #endif
135 static void jvmti_ClassFileLoadHook (jvmtiEnv *jvmti_env, JNIEnv* jni_env, jclass class_being_redefined,
136 				     jobject loader, const char* name, jobject protection_domain,
137 				     jint class_data_len, const unsigned char* class_data,
138 				     jint* new_class_data_len, unsigned char** new_class_data);
139 static void jvmti_GarbageCollectionStart (jvmtiEnv *);
140 static void
141 jvmti_GarbageCollectionFinish (jvmtiEnv *);
142 jvmtiEventCallbacks callbacks = {
143   jvmti_VMInit,                 // 50 jvmtiEventVMInit;
144   jvmti_VMDeath,                // 51 jvmtiEventVMDeath;
145   jvmti_ThreadStart,            // 52 jvmtiEventThreadStart;
146   jvmti_ThreadEnd,              // 53 jvmtiEventThreadEnd;
147   jvmti_ClassFileLoadHook,      // 54 jvmtiEventClassFileLoadHook;
148   jvmti_ClassLoad,              // 55 jvmtiEventClassLoad;
149   jvmti_ClassPrepare,           // 56 jvmtiEventClassPrepare;
150   NULL,                         // 57 reserved57;
151   NULL,                         // 58 jvmtiEventException;
152   NULL,                         // 59 jvmtiEventExceptionCatch;
153   NULL,                         // 60 jvmtiEventSingleStep;
154   NULL,                         // 61 jvmtiEventFramePop;
155   NULL,                         // 62 jvmtiEventBreakpoint;
156   NULL,                         // 63 jvmtiEventFieldAccess;
157   NULL,                         // 64 jvmtiEventFieldModification;
158   NULL,                         // 65 jvmtiEventMethodEntry;
159   NULL,                         // 66 jvmtiEventMethodExit;
160   NULL,                         // 67 jvmtiEventNativeMethodBind;
161   jvmti_CompiledMethodLoad,     // 68 jvmtiEventCompiledMethodLoad;
162   jvmti_CompiledMethodUnload,   // 69 jvmtiEventCompiledMethodUnload;
163   jvmti_DynamicCodeGenerated,   // 70 jvmtiEventDynamicCodeGenerated;
164   NULL,                         // 71 jvmtiEventDataDumpRequest;
165   NULL,                         // 72 jvmtiEventDataResetRequest;
166   NULL, /*jvmti_MonitorWait,*/  // 73 jvmtiEventMonitorWait;
167   NULL, /*jvmti_MonitorWaited,*/ // 74 jvmtiEventMonitorWaited;
168   jvmti_MonitorEnter,           // 75 jvmtiEventMonitorContendedEnter;
169   jvmti_MonitorEntered,         // 76 jvmtiEventMonitorContendedEntered;
170   NULL,                         // 77 jvmtiEventMonitorContendedExit;
171   NULL,                         // 78 jvmtiEventReserved;
172   NULL,                         // 79 jvmtiEventReserved;
173   NULL,                         // 80 jvmtiEventReserved;
174   jvmti_GarbageCollectionStart, // 81 jvmtiEventGarbageCollectionStart;
175   jvmti_GarbageCollectionFinish, // 82 jvmtiEventGarbageCollectionFinish;
176   NULL,                         // 83 jvmtiEventObjectFree;
177   NULL                          // 84 jvmtiEventVMObjectAlloc;
178 };
179 
180 typedef jint (JNICALL JNI_GetCreatedJavaVMs_t)(JavaVM **, jsize, jsize *);
181 
182 int
init_interface(CollectorInterface * _collector_interface)183 init_interface (CollectorInterface *_collector_interface)
184 {
185   collector_interface = _collector_interface;
186   return COL_ERROR_NONE;
187 }
188 
189 static int
open_experiment(const char * exp)190 open_experiment (const char *exp)
191 {
192   if (collector_interface == NULL)
193     return COL_ERROR_JAVAINIT;
194   TprintfT (0, "jprofile: open_experiment %s\n", exp);
195   const char *params = collector_interface->getParams ();
196   const char *args = params;
197   while (args)
198     {
199       if (__collector_strStartWith (args, "j:") == 0)
200 	{
201 	  args += 2;
202 	  break;
203 	}
204       args = CALL_UTIL (strchr)(args, ';');
205       if (args)
206 	args++;
207     }
208   if (args == NULL)     /* Java profiling not specified */
209     return COL_ERROR_JAVAINIT;
210   tsd_key = collector_interface->createKey (sizeof ( TSD_Entry), NULL, NULL);
211   if (tsd_key == (unsigned) - 1)
212     {
213       TprintfT (0, "jprofile: TSD key create failed.\n");
214       collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">TSD key not created</event>\n",
215 				     SP_JCMD_CERROR, COL_ERROR_JAVAINIT);
216       return COL_ERROR_JAVAINIT;
217     }
218   else
219     Tprintf (DBG_LT2, "jprofile: TSD key create succeeded %d.\n", tsd_key);
220 
221   args = params;
222   while (args)
223     {
224       if (__collector_strStartWith (args, "H:") == 0)
225 	{
226 	  java_mem_mode = 1;
227 	  collector_heap_record = (void(*)(int, int, void*))dlsym (RTLD_DEFAULT, "__collector_heap_record");
228 	}
229 #if 0
230       else if (__collector_strStartWith (args, "s:") == 0)
231 	{
232 	  java_sync_mode = 1;
233 	  collector_jsync_begin = (void(*)(hrtime_t, void *))dlsym (RTLD_DEFAULT, "__collector_jsync_begin");
234 	  collector_jsync_end = (void(*)(hrtime_t, void *))dlsym (RTLD_DEFAULT, "__collector_jsync_end");
235 	}
236 #endif
237       args = CALL_UTIL (strchr)(args, ';');
238       if (args)
239 	args++;
240     }
241 
242   /* synchronization tracing is enabled by the synctrace module, later in initialization */
243   __collector_java_mode = 1;
244   java_gc_on = 1;
245   return COL_ERROR_NONE;
246 }
247 
248 /* routine called from the syntrace module to enable Java-API synctrace */
249 void
__collector_jprofile_enable_synctrace()250 __collector_jprofile_enable_synctrace ()
251 {
252   if (__collector_java_mode == 0)
253     {
254       TprintfT (DBG_LT1, "jprofile: not turning on Java synctrace; Java mode not enabled\n");
255       return;
256     }
257   java_sync_mode = 1;
258   collector_jsync_begin = (void(*)(hrtime_t, void *))dlsym (RTLD_DEFAULT, "__collector_jsync_begin");
259   collector_jsync_end = (void(*)(hrtime_t, void *))dlsym (RTLD_DEFAULT, "__collector_jsync_end");
260   TprintfT (DBG_LT1, "jprofile: turning on Java synctrace, and requesting events\n");
261 }
262 
263 int
__collector_jprofile_start_attach(void)264 __collector_jprofile_start_attach (void)
265 {
266   if (!__collector_java_mode || __collector_java_asyncgetcalltrace_loaded)
267     return 0;
268   void *g_sHandle = RTLD_DEFAULT;
269   /* Now get the function addresses */
270   JNI_GetCreatedJavaVMs_t *pfnGetCreatedJavaVMs;
271   pfnGetCreatedJavaVMs = (JNI_GetCreatedJavaVMs_t *) dlsym (g_sHandle, "JNI_GetCreatedJavaVMs");
272   if (pfnGetCreatedJavaVMs != NULL)
273     {
274       TprintfT (0, "jprofile attach: pfnGetCreatedJavaVMs is detected.\n");
275       JavaVM * vmBuf[1]; // XXXX only detect on jvm
276       jsize nVMs = 0;
277       (*pfnGetCreatedJavaVMs)(vmBuf, 1, &nVMs);
278       if (vmBuf[0] != NULL && nVMs > 0)
279 	{
280 	  jvm = vmBuf[0];
281 	  JNIEnv* jni_env = NULL;
282 	  (*jvm)->AttachCurrentThread (jvm, (void **) &jni_env, NULL);
283 	  Agent_OnLoad (jvm, NULL, NULL);
284 	  if ((*jvm)->GetEnv (jvm, (void **) &jni_env, JNI_VERSION_1_2) >= 0 && jni_env && jvmti)
285 	    {
286 	      jthread thread;
287 	      (*jvmti)->GetCurrentThread (jvmti, &thread);
288 #ifdef DEBUG
289 	      collector_thread_t tid;
290 	      tid = __collector_thr_self ();
291 	      TprintfT (0, "jprofile attach: AttachCurrentThread: thread: %lu jni_env=%p jthread=%p\n",
292 			(unsigned long) tid, jni_env, thread);
293 #endif /* DEBUG */
294 	      jvmti_VMInit (jvmti, jni_env, thread);
295 	      (*jvmti)->GenerateEvents (jvmti, JVMTI_EVENT_COMPILED_METHOD_LOAD);
296 	      (*jvmti)->GenerateEvents (jvmti, JVMTI_EVENT_DYNAMIC_CODE_GENERATED);
297 	      __collector_java_attach = 1;
298 	      (*jvm)->DetachCurrentThread (jvm);
299 	    }
300 	}
301     }
302   return 0;
303 }
304 
305 static int
close_experiment(void)306 close_experiment (void)
307 {
308   /* fixme XXXXX add content here */
309   /* see detach_experiment() */
310   __collector_java_mode = 0;
311   __collector_java_asyncgetcalltrace_loaded = 0;
312   __collector_java_attach = 0;
313   java_gc_on = 0;
314   java_mem_mode = 0;
315   java_sync_mode = 0;
316   is_hotspot_vm = 0;
317   __collector_mutex_init (&jclasses_lock);
318   tsd_key = COLLECTOR_TSD_INVALID_KEY;
319   TprintfT (0, "jprofile: experiment closed.\n");
320   return 0;
321 }
322 
323 static int
detach_experiment(void)324 detach_experiment (void)
325 /* fork child.  Clean up state but don't write to experiment */
326 {
327   __collector_java_mode = 0;
328   java_gc_on = 0;
329   jvm = NULL;
330   java_mem_mode = 0;
331   java_sync_mode = 0;
332   is_hotspot_vm = 0;
333   jvmti = NULL;
334   apistr = NULL;
335   __collector_mutex_init (&jclasses_lock);
336   tsd_key = COLLECTOR_TSD_INVALID_KEY;
337   TprintfT (0, "jprofile: detached from experiment.\n");
338   return 0;
339 }
340 
341 JNIEXPORT jint JNICALL
JVM_OnLoad(JavaVM * vm,char * options,void * reserved)342 JVM_OnLoad (JavaVM *vm, char *options, void *reserved)
343 {
344   jvmtiError err;
345   int use_jvmti = 0;
346   if (!__collector_java_mode)
347     {
348       TprintfT (DBG_LT1, "jprofile: JVM_OnLoad invoked with java mode disabled\n");
349       return JNI_OK;
350     }
351   else
352     TprintfT (DBG_LT1, "jprofile: JVM_OnLoad invoked\n");
353   jvm = vm;
354   jvmti = NULL;
355   if ((*jvm)->GetEnv (jvm, (void **) &jvmti, JVMTI_VERSION_1_0) >= 0 && jvmti)
356     {
357       TprintfT (DBG_LT1, "jprofile: JVMTI found\n");
358       use_jvmti = 1;
359     }
360   if (!use_jvmti)
361     {
362       collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\"/>\n",
363 				     SP_JCMD_CERROR, COL_ERROR_JVMNOTSUPP);
364       return JNI_ERR;
365     }
366   else
367     {
368       Tprintf (DBG_LT0, "\tjprofile: Initializing for JVMTI\n");
369       apistr = "JVMTI 1.0";
370 
371       // setup JVMTI
372       jvmtiCapabilities cpblts;
373       err = (*jvmti)->GetPotentialCapabilities (jvmti, &cpblts);
374       if (err == JVMTI_ERROR_NONE)
375 	{
376 	  jvmtiCapabilities cpblts_set;
377 	  CALL_UTIL (memset)(&cpblts_set, 0, sizeof (cpblts_set));
378 
379 	  /* Add only those capabilities that are among potential ones */
380 	  cpblts_set.can_get_source_file_name = cpblts.can_get_source_file_name;
381 	  Tprintf (DBG_LT1, "\tjprofile: adding can_get_source_file_name capability: %u\n", cpblts.can_get_source_file_name);
382 
383 	  cpblts_set.can_generate_compiled_method_load_events = cpblts.can_generate_compiled_method_load_events;
384 	  Tprintf (DBG_LT1, "\tjprofile: adding can_generate_compiled_method_load_events capability: %u\n", cpblts.can_generate_compiled_method_load_events);
385 
386 	  if (java_sync_mode)
387 	    {
388 	      cpblts_set.can_generate_monitor_events = cpblts.can_generate_monitor_events;
389 	      Tprintf (DBG_LT1, "\tjprofile: adding can_generate_monitor_events capability: %u\n", cpblts.can_generate_monitor_events);
390 	    }
391 	  if (java_gc_on)
392 	    {
393 	      cpblts_set.can_generate_garbage_collection_events = cpblts.can_generate_garbage_collection_events;
394 	      Tprintf (DBG_LT1, "\tjprofile: adding can_generate_garbage_collection_events capability: %u\n", cpblts.can_generate_garbage_collection_events);
395 	    }
396 	  err = (*jvmti)->AddCapabilities (jvmti, &cpblts_set);
397 	  Tprintf (DBG_LT1, "\tjprofile: AddCapabilities() returns: %d\n", err);
398 	}
399       err = (*jvmti)->SetEventCallbacks (jvmti, &callbacks, sizeof ( callbacks));
400       err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, NULL);
401       err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_DEATH, NULL);
402       err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_CLASS_PREPARE, NULL);
403       err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_CLASS_LOAD, NULL);
404       err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_COMPILED_METHOD_LOAD, NULL);
405       err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_COMPILED_METHOD_UNLOAD, NULL);
406       err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_DYNAMIC_CODE_GENERATED, NULL);
407       err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_THREAD_START, NULL);
408       err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_THREAD_END, NULL);
409       err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, NULL);
410       if (java_gc_on)
411 	{
412 	  err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_GARBAGE_COLLECTION_START, NULL);
413 	  err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, NULL);
414 	}
415       if (java_mem_mode)
416 	{
417 	  // err = (*jvmti)->SetEventNotificationMode( jvmti, JVMTI_ENABLE, <no event for heap tracing> , NULL );
418 	  collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\"/>\n",
419 					 SP_JCMD_CWARN, COL_WARN_NO_JAVA_HEAP);
420 	  java_mem_mode = 0;
421 	}
422       if (java_sync_mode)
423 	{
424 	  err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_MONITOR_CONTENDED_ENTER, NULL);
425 	  err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_MONITOR_CONTENDED_ENTERED, NULL);
426 	  //err = (*jvmti)->SetEventNotificationMode( jvmti, JVMTI_ENABLE, JVMTI_EVENT_MONITOR_WAIT, NULL );
427 	  //err = (*jvmti)->SetEventNotificationMode( jvmti, JVMTI_ENABLE, JVMTI_EVENT_MONITOR_WAITED, NULL );
428 	}
429       Tprintf (DBG_LT0, "\tjprofile: JVMTI initialized\n");
430     }
431 
432   /* JVM still uses collector API on Solaris to notify us about dynamically generated code.
433    * If we ask it to generate events we'll end up with duplicate entries in the
434    * map file.
435    */
436   if (use_jvmti)
437     {
438       err = (*jvmti)->GenerateEvents (jvmti, JVMTI_EVENT_DYNAMIC_CODE_GENERATED);
439       err = (*jvmti)->GenerateEvents (jvmti, JVMTI_EVENT_COMPILED_METHOD_LOAD);
440     }
441   Tprintf (DBG_LT1, "\tjprofile: JVM_OnLoad ok\n");
442   return JNI_OK;
443 }
444 
445 /* This is currently just a placeholder */
446 JNIEXPORT jint JNICALL
Agent_OnLoad(JavaVM * vm,char * options,void * reserved)447 Agent_OnLoad (JavaVM *vm, char *options, void *reserved)
448 {
449   return JVM_OnLoad (vm, options, reserved);
450 }
451 
452 static void
rwrite(int fd,const void * buf,size_t nbyte)453 rwrite (int fd, const void *buf, size_t nbyte)
454 {
455   size_t left = nbyte;
456   size_t res;
457   char *ptr = (char*) buf;
458   while (left > 0)
459     {
460       res = CALL_UTIL (write)(fd, ptr, left);
461       if (res == -1)
462 	{
463 	  /*  XXX: we can't write this record, we probably
464 	   *  can't write anything else. Ignore.
465 	   */
466 	  return;
467 	}
468       left -= res;
469       ptr += res;
470     }
471 }
472 
473 void
get_jvm_settings()474 get_jvm_settings ()
475 {
476   jint res;
477   JNIEnv *jni;
478   jclass jcls;
479   jmethodID jmid;
480   jstring jstrin;
481   jstring jstrout;
482   const char *str;
483   res = (*jvm)->GetEnv (jvm, (void **) &jni, JNI_VERSION_1_2);
484   if (res < 0)
485     return;
486 
487   /* I'm not checking if results are valid as JVM is extremely
488    * sensitive to exceptions that might occur during these JNI calls
489    * and will die with a fatal error later anyway.
490    */
491   jcls = (*jni)->FindClass (jni, "java/lang/System");
492   jmid = (*jni)->GetStaticMethodID (jni, jcls, "getProperty", "(Ljava/lang/String;)Ljava/lang/String;");
493   jstrin = (*jni)->NewStringUTF (jni, "java.class.path");
494   jstrout = (*jni)->CallStaticObjectMethod (jni, jcls, jmid, jstrin);
495   str = jstrout ? (*jni)->GetStringUTFChars (jni, jstrout, NULL) : NULL;
496   if (str)
497     {
498       collector_interface->writeLog ("<setting %s=\"%s\"/>\n", SP_JCMD_SRCHPATH, str);
499       (*jni)->ReleaseStringUTFChars (jni, jstrout, str);
500     }
501   jstrin = (*jni)->NewStringUTF (jni, "sun.boot.class.path");
502   jstrout = (*jni)->CallStaticObjectMethod (jni, jcls, jmid, jstrin);
503   str = jstrout ? (*jni)->GetStringUTFChars (jni, jstrout, NULL) : NULL;
504   if (str)
505     {
506       collector_interface->writeLog ("<setting %s=\"%s\"/>\n", SP_JCMD_SRCHPATH, str);
507       (*jni)->ReleaseStringUTFChars (jni, jstrout, str);
508     }
509   jstrin = (*jni)->NewStringUTF (jni, "java.home");
510   jstrout = (*jni)->CallStaticObjectMethod (jni, jcls, jmid, jstrin);
511   str = jstrout ? (*jni)->GetStringUTFChars (jni, jstrout, NULL) : NULL;
512   if (str)
513     {
514       collector_interface->writeLog ("<setting %s=\"%s/../src.zip\"/>\n", SP_JCMD_SRCHPATH, str);
515       (*jni)->ReleaseStringUTFChars (jni, jstrout, str);
516     }
517   jstrin = (*jni)->NewStringUTF (jni, "java.vm.version");
518   jstrout = (*jni)->CallStaticObjectMethod (jni, jcls, jmid, jstrin);
519   str = jstrout ? (*jni)->GetStringUTFChars (jni, jstrout, NULL) : NULL;
520   if (str)
521     {
522       (void) collector_interface->writeLog ("<profile name=\"jprofile\" %s=\"%s\" %s=\"%s\"/>\n",
523 					    SP_JCMD_JVERSION, str, "api", apistr != NULL ? apistr : "N/A");
524       if (__collector_strStartWith (str, "1.4.2_02") < 0)
525 	{
526 	  (void) collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\"/>\n",
527 						SP_JCMD_CWARN, COL_WARN_OLDJAVA);
528 	}
529       (*jni)->ReleaseStringUTFChars (jni, jstrout, str);
530     }
531   is_hotspot_vm = 0;
532   jstrin = (*jni)->NewStringUTF (jni, "sun.management.compiler");
533   jstrout = (*jni)->CallStaticObjectMethod (jni, jcls, jmid, jstrin);
534   str = jstrout ? (*jni)->GetStringUTFChars (jni, jstrout, NULL) : NULL;
535   if (str && __collector_strncmp (str, "HotSpot", 7) == 0)
536     is_hotspot_vm = 1;
537 
538   /* Emulate System.setProperty( "collector.init", "true") */
539   jmid = (*jni)->GetStaticMethodID (jni, jcls, "setProperty",
540 				    "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
541   jstrin = (*jni)->NewStringUTF (jni, "collector.init");
542   jstrout = (*jni)->NewStringUTF (jni, "true");
543   (*jni)->CallStaticObjectMethod (jni, jcls, jmid, jstrin, jstrout);
544 }
545 
546 /*
547  * JVMTI code
548  */
549 
550 static void
jvmti_VMInit(jvmtiEnv * jvmti_env,JNIEnv * jni_env,jthread thread)551 jvmti_VMInit (jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread)
552 {
553   jint class_count = 0;
554   jclass *classes = NULL;
555   int i;
556   TprintfT (DBG_LT1, "jprofile: jvmti_VMInit called\n");
557   get_jvm_settings ();
558 
559   /* determine loaded classes */
560   (*jvmti_env)->GetLoadedClasses (jvmti_env, &class_count, &classes);
561   TprintfT (DBG_LT1, "jprofile: jvmti_VMInit initializing %d classes\n", class_count);
562   for (i = 0; i < class_count; i++)
563     {
564       // PushLocalFrame
565       jvmti_ClassPrepare (jvmti_env, jni_env, NULL, classes[i]);
566       // PopLocalFrame
567       // DeleteLocalRef( classes[i] );
568     }
569   (*jvmti_env)->Deallocate (jvmti_env, (unsigned char*) classes);
570   getResource = (*jni_env)->GetMethodID (jni_env, (*jni_env)->FindClass (jni_env, "java/lang/ClassLoader"), "getResource", "(Ljava/lang/String;)Ljava/net/URL;");
571   toExternalForm = (*jni_env)->GetMethodID (jni_env, (*jni_env)->FindClass (jni_env, "java/net/URL"), "toExternalForm", "()Ljava/lang/String;");
572 
573   /* find the stack unwind routine */
574   jprof_find_asyncgetcalltrace ();
575 }
576 
577 static void
jvmti_VMDeath(jvmtiEnv * jvmti_env,JNIEnv * jni_env)578 jvmti_VMDeath (jvmtiEnv *jvmti_env, JNIEnv* jni_env)
579 {
580   __collector_java_mode = 0;
581   TprintfT (DBG_LT1, "jprofile: jvmti_VMDeath event received\n");
582 }
583 
584 static void
jvmti_ThreadStart(jvmtiEnv * jvmti_env,JNIEnv * jni_env,jthread thread)585 jvmti_ThreadStart (jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread)
586 {
587   jvmtiError err;
588   jvmtiThreadInfo t_info;
589   char *thread_name, *group_name, *parent_name;
590   hrtime_t hrt;
591   collector_thread_t tid;
592   thread_name = group_name = parent_name = NULL;
593   hrt = gethrtime ();
594   tid = __collector_thr_self ();
595   TprintfT (DBG_LT1, "jprofile: jvmti_ThreadStart: thread: %lu jni_env=%p jthread=%p\n",
596 	    (unsigned long) tid, jni_env, thread);
597   err = (*jvmti_env)->GetThreadInfo (jvmti_env, thread, &t_info);
598   if (err == JVMTI_ERROR_NONE)
599     {
600       jvmtiThreadGroupInfo g_info;
601       thread_name = t_info.name;
602       if (t_info.thread_group)
603 	{
604 	  err = (*jvmti_env)->GetThreadGroupInfo (jvmti_env, t_info.thread_group, &g_info);
605 	  if (err == JVMTI_ERROR_NONE)
606 	    {
607 	      group_name = g_info.name;
608 	      if (g_info.parent)
609 		{
610 		  jvmtiThreadGroupInfo p_info;
611 		  err = (*jvmti_env)->GetThreadGroupInfo (jvmti_env, g_info.parent, &p_info);
612 		  if (err == JVMTI_ERROR_NONE)
613 		    {
614 		      parent_name = p_info.name;
615 		      // DeleteLocalRef( p_info.parent );
616 		    }
617 		  // DeleteLocalRef( g_info.parent );
618 		}
619 	    }
620 	}
621       // DeleteLocalRef( t_info.thread_group );
622       // DeleteLocalRef( t_info.context_class_loader );
623     }
624   if (thread_name == NULL)
625     thread_name = "";
626   if (group_name == NULL)
627     group_name = "";
628   if (parent_name == NULL)
629     parent_name = "";
630   collector_interface->writeLog ("<event kind=\"%s\" tstamp=\"%u.%09u\" name=\"%s\" grpname=\"%s\" prntname=\"%s\" tid=\"%lu\" jthr=\"0x%lx\" jenv=\"0x%lx\"/>\n",
631 				 SP_JCMD_JTHRSTART,
632 				 (unsigned) (hrt / NANOSEC), (unsigned) (hrt % NANOSEC),
633 				 thread_name,
634 				 group_name,
635 				 parent_name,
636 				 (unsigned long) tid,
637 				 thread,
638 				 jni_env
639 				 );
640   TSD_Entry *tsd = collector_interface->getKey (tsd_key);
641   if (tsd)
642     tsd->env = jni_env;
643 }
644 
645 static void
jvmti_ThreadEnd(jvmtiEnv * jvmti_env,JNIEnv * jni_env,jthread thread)646 jvmti_ThreadEnd (jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread)
647 {
648   hrtime_t hrt = gethrtime ();
649   collector_thread_t tid = __collector_thr_self ();
650   TprintfT (DBG_LT1, "jprofile: jvmti_ThreadEnd: thread: %lu jni_env=%p jthread=%p\n",
651 	    (unsigned long) tid, jni_env, thread);
652 
653   collector_interface->writeLog ("<event kind=\"%s\" tstamp=\"%u.%09u\" tid=\"%lu\"  jthr=\"0x%lx\" jenv=\"0x%lx\"/>\n",
654 				 SP_JCMD_JTHREND,
655 				 (unsigned) (hrt / NANOSEC), (unsigned) (hrt % NANOSEC),
656 				 (unsigned long) tid,
657 				 thread,
658 				 jni_env
659 				 );
660   TSD_Entry *tsd = collector_interface->getKey (tsd_key);
661   if (tsd)
662     tsd->env = NULL;
663 }
664 
665 /* The following definitions are borrowed from file jvmticmlr.h, part of jdk7 */
666 typedef enum
667 {
668   JVMTI_CMLR_DUMMY = 1,
669   JVMTI_CMLR_INLINE_INFO = 2
670 } jvmtiCMLRKind;
671 
672 /*
673  * Record that represents arbitrary information passed through JVMTI
674  * CompiledMethodLoadEvent void pointer.
675  */
676 typedef struct _jvmtiCompiledMethodLoadRecordHeader
677 {
678   jvmtiCMLRKind kind;       /* id for the kind of info passed in the record */
679   jint majorinfoversion;    /* major and minor info version values. Init'ed */
680   jint minorinfoversion;    /* to current version value in jvmtiExport.cpp. */
681   struct _jvmtiCompiledMethodLoadRecordHeader* next;
682 } jvmtiCompiledMethodLoadRecordHeader;
683 
684 /*
685  * Record that gives information about the methods on the compile-time
686  * stack at a specific pc address of a compiled method. Each element in
687  * the methods array maps to same element in the bcis array.
688  */
689 typedef struct _PCStackInfo
690 {
691   void* pc;                 /* the pc address for this compiled method */
692   jint numstackframes;      /* number of methods on the stack */
693   jmethodID* methods;       /* array of numstackframes method ids */
694   jint* bcis;               /* array of numstackframes bytecode indices */
695 } PCStackInfo;
696 
697 /*
698  * Record that contains inlining information for each pc address of
699  * an nmethod.
700  */
701 typedef struct _jvmtiCompiledMethodLoadInlineRecord
702 {
703   jvmtiCompiledMethodLoadRecordHeader header; /* common header for casting */
704   jint numpcs; /* number of pc descriptors in this nmethod */
705   PCStackInfo* pcinfo; /* array of numpcs pc descriptors */
706 } jvmtiCompiledMethodLoadInlineRecord;
707 
708 static void
jvmti_CompiledMethodLoad(jvmtiEnv * jvmti_env,jmethodID method,jint code_size,const void * code_addr,jint map_length,const jvmtiAddrLocationMap * map,const void * compile_info)709 jvmti_CompiledMethodLoad (jvmtiEnv *jvmti_env, jmethodID method,
710 			  jint code_size, const void *code_addr, jint map_length,
711 			  const jvmtiAddrLocationMap *map,
712 			  const void *compile_info)
713 {
714   TprintfT (DBG_LT2, "jprofile: jvmti_CompiledMethodLoad: mid=0x%lx addr=%p sz=0x%lu map=%p info=%p\n",
715 	    (unsigned long) method, code_addr, (long) code_size, map, compile_info);
716   char name[32];
717   CALL_UTIL (snprintf)(name, sizeof (name), "0x%lx", (unsigned long) method);
718 
719   /* Parse compile_info to get pc -> bci mapping.
720    * Don't interpret compile_info from JVMs other than HotSpot.
721    */
722   int lntsize = 0;
723   DT_lineno *lntable = NULL;
724   if (compile_info != NULL && is_hotspot_vm)
725     {
726       Tprintf (DBG_LT2, "Mapping from compile_info:\n");
727       jvmtiCompiledMethodLoadRecordHeader *currec =
728 	      (jvmtiCompiledMethodLoadRecordHeader*) compile_info;
729       while (currec != NULL)
730 	{
731 	  if (currec->kind == JVMTI_CMLR_INLINE_INFO)
732 	    {
733 	      jvmtiCompiledMethodLoadInlineRecord *inrec =
734 		      (jvmtiCompiledMethodLoadInlineRecord*) currec;
735 	      if (inrec->numpcs <= 0)
736 		break;
737 	      lntsize = inrec->numpcs;
738 	      lntable = (DT_lineno*) alloca (lntsize * sizeof (DT_lineno));
739 	      PCStackInfo *pcrec = inrec->pcinfo;
740 	      DT_lineno *lnorec = lntable;
741 	      for (int i = 0; i < lntsize; ++i)
742 		{
743 		  for (int j = pcrec->numstackframes - 1; j >= 0; --j)
744 		    if (pcrec->methods[j] == method)
745 		      {
746 			lnorec->offset = (char*) pcrec->pc - (char*) code_addr;
747 			lnorec->lineno = pcrec->bcis[j];
748 			Tprintf (DBG_LT2, "   pc: 0x%lx  bci: 0x%lx\n",
749 				 (long) lnorec->offset, (long) lnorec->lineno);
750 			++lnorec;
751 			break;
752 		      }
753 		  ++pcrec;
754 		}
755 	      break;
756 	    }
757 	  currec = currec->next;
758 	}
759     }
760   else if (map != NULL)
761     {
762       Tprintf (DBG_LT2, "Mapping from jvmtiAddrLocationMap:\n");
763       lntsize = map_length;
764       lntable = (DT_lineno*) alloca (lntsize * sizeof (DT_lineno));
765       DT_lineno *lnorec = lntable;
766       for (int i = 0; i < map_length; ++i)
767 	{
768 	  lnorec->offset = (char*) map[i].start_address - (char*) code_addr;
769 	  lnorec->lineno = (unsigned int) map[i].location;
770 	  Tprintf (DBG_LT2, "   pc: 0x%lx  bci: 0x%lx\n",
771 		   (long) lnorec->offset, (long) lnorec->lineno);
772 	  ++lnorec;
773 	}
774     }
775   __collector_int_func_load (DFUNC_JAVA, name, NULL, (void*) code_addr,
776 			     code_size, lntsize, lntable);
777 }
778 
779 static void
jvmti_CompiledMethodUnload(jvmtiEnv * jvmti_env,jmethodID method,const void * code_addr)780 jvmti_CompiledMethodUnload (jvmtiEnv *jvmti_env, jmethodID method, const void* code_addr)
781 {
782   __collector_int_func_unload (DFUNC_API, (void*) code_addr);
783 }
784 
785 static void
jvmti_DynamicCodeGenerated(jvmtiEnv * jvmti_env,const char * name,const void * code_addr,jint code_size)786 jvmti_DynamicCodeGenerated (jvmtiEnv *jvmti_env, const char*name, const void *code_addr, jint code_size)
787 {
788   __collector_int_func_load (DFUNC_API, (char*) name, NULL, (void*) code_addr,
789 			     code_size, 0, NULL);
790 }
791 
792 static void
addToDynamicArchive(const char * name,const unsigned char * class_data,int class_data_len)793 addToDynamicArchive (const char* name, const unsigned char* class_data, int class_data_len)
794 {
795   char path[MAXPATHLEN + 1];
796   mode_t fmode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
797   mode_t dmode = fmode | S_IXUSR | S_IXGRP | S_IXOTH;
798   if (name == NULL)
799     name = "";
800   const char *expdir = collector_interface->getExpDir ();
801   if (CALL_UTIL (strlen)(expdir) +
802       CALL_UTIL (strlen)(SP_DYNAMIC_CLASSES) +
803       CALL_UTIL (strlen)(name) + 8 > sizeof (path))
804     return;
805   CALL_UTIL (snprintf)(path, sizeof (path), "%s/%s/%s.class", expdir, SP_DYNAMIC_CLASSES, name);
806 
807   /* Create all path components step by step starting with SP_DYNAMIC_CLASSES */
808   char *str = path + CALL_UTIL (strlen)(expdir) + 1 + CALL_UTIL (strlen)(SP_DYNAMIC_CLASSES);
809   while (str)
810     {
811       *str = '\0';
812       if (CALL_UTIL (mkdir)(path, dmode) != 0)
813 	{
814 	  /* Checking for EEXIST is not enough, access() is more reliable */
815 	  if (CALL_UTIL (access)(path, F_OK) != 0)
816 	    {
817 	      collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">%s</event>\n",
818 					     SP_JCMD_CERROR, COL_ERROR_MKDIR, errno, path);
819 	      return;
820 	    }
821 	}
822       *str++ = '/';
823       str = CALL_UTIL (strchr)(str, '/');
824     }
825 
826   int fd = CALL_UTIL (open)(path, O_WRONLY | O_CREAT | O_TRUNC, fmode);
827   if (fd < 0)
828     {
829       collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">%s</event>\n",
830 				     SP_JCMD_CERROR, COL_ERROR_OVWOPEN, errno, path);
831       return;
832     }
833   rwrite (fd, class_data, class_data_len);
834   CALL_UTIL (close)(fd);
835 }
836 
837 static void
jvmti_ClassFileLoadHook(jvmtiEnv * jvmti_env,JNIEnv * jni_env,jclass class_being_redefined,jobject loader,const char * name,jobject protection_domain,jint class_data_len,const unsigned char * class_data,jint * new_class_data_len,unsigned char ** new_class_data)838 jvmti_ClassFileLoadHook (jvmtiEnv *jvmti_env, JNIEnv* jni_env, jclass class_being_redefined,
839 			 jobject loader, const char* name, jobject protection_domain, jint class_data_len,
840 			 const unsigned char* class_data, jint* new_class_data_len, unsigned char** new_class_data)
841 {
842   jclass loaderlass;
843   int err;
844   jvmtiPhase phase_ptr;
845   char *cname = NULL;
846   (*jvmti_env)->GetPhase (jvmti_env, &phase_ptr);
847 
848   /* skip non live phases */
849   if (phase_ptr != JVMTI_PHASE_LIVE)
850     return;
851 
852   /* skip system class loaders */
853   if (!loader)
854     return;
855   loaderlass = (*jni_env)->GetObjectClass (jni_env, loader);
856   err = (*jvmti_env)->GetClassSignature (jvmti_env, loaderlass, &cname, NULL);
857   if (err != JVMTI_ERROR_NONE || !cname || *cname == (char) 0)
858     return;
859 
860   /* skip classes loaded with AppClassLoader (java.class.path) */
861   if (__collector_strcmp (cname, "Lsun/misc/Launcher$AppClassLoader;") == 0)
862     return;
863   addToDynamicArchive (name, class_data, (int) class_data_len);
864 }
865 
866 #define NO_CLASS_NAME "<noname>"
867 #define NO_SOURCE_FILE "<Unknown>"
868 
869 static void
record_jclass(uint64_t class_id,hrtime_t hrt,const char * cname,const char * sname)870 record_jclass (uint64_t class_id, hrtime_t hrt, const char *cname, const char *sname)
871 {
872   size_t clen = ARCH_STRLEN (cname);
873   size_t slen = ARCH_STRLEN (sname);
874   size_t sz = sizeof (ARCH_jclass) + clen + slen;
875   ARCH_jclass *jcls = (ARCH_jclass*) alloca (sz);
876   jcls->comm.tsize = sz;
877   jcls->comm.type = ARCH_JCLASS;
878   jcls->class_id = class_id;
879   jcls->tstamp = hrt;
880   char *str = (char*) (jcls + 1);
881   size_t i = CALL_UTIL (strlcpy)(str, cname, clen);
882   str += i;
883   while (i++ < clen)
884     *str++ = (char) 0; /* pad with 0's */
885   i = CALL_UTIL (strlcpy)(str, sname, slen);
886   str += i;
887   while (i++ < slen)
888     *str++ = (char) 0; /* pad with 0's */
889   collector_interface->writeDataPacket (jprof_hndl, (CM_Packet*) jcls);
890 }
891 
892 static void
record_jmethod(uint64_t class_id,uint64_t method_id,const char * mname,const char * msign)893 record_jmethod (uint64_t class_id, uint64_t method_id,
894 		const char *mname, const char *msign)
895 {
896   size_t mnlen = mname ? ARCH_STRLEN (mname) : 0;
897   size_t mslen = msign ? ARCH_STRLEN (msign) : 0;
898   size_t sz = sizeof (ARCH_jmethod) + mnlen + mslen;
899   ARCH_jmethod *jmth = (ARCH_jmethod*) alloca (sz);
900   if (jmth == NULL)
901     {
902       TprintfT (DBG_LT1, "jprofile: record_jmethod ERROR: failed to alloca(%ld)\n", (long) sz);
903       return;
904     }
905   jmth->comm.tsize = sz;
906   jmth->comm.type = ARCH_JMETHOD;
907   jmth->class_id = class_id;
908   jmth->method_id = method_id;
909   char *str = (char*) (jmth + 1);
910   if (mname)
911     {
912       size_t i = CALL_UTIL (strlcpy)(str, mname, mnlen);
913       str += i;
914       while (i++ < mnlen)
915 	*str++ = (char) 0; /* pad with 0's */
916     }
917   if (msign)
918     {
919       size_t i = CALL_UTIL (strlcpy)(str, msign, mslen);
920       str += i;
921       while (i++ < mslen)
922 	*str++ = (char) 0; /* pad with 0's */
923     }
924   collector_interface->writeDataPacket (jprof_hndl, (CM_Packet*) jmth);
925 }
926 
927 static void
jvmti_ClassPrepare(jvmtiEnv * jvmti_env,JNIEnv * jni_env,jthread thread,jclass klass)928 jvmti_ClassPrepare (jvmtiEnv *jvmti_env, JNIEnv* jni_env,
929 		    jthread thread, jclass klass)
930 {
931   hrtime_t hrt;
932   jint mnum;
933   jmethodID *mptr;
934   char *cname, *sname;
935   char *str1 = NULL;
936   int err = (*jvmti_env)->GetClassSignature (jvmti_env, klass, &str1, NULL);
937   if (err != JVMTI_ERROR_NONE || str1 == NULL || *str1 == (char) 0)
938     cname = NO_CLASS_NAME;
939   else
940     cname = str1;
941   if (*cname != 'L')
942     {
943       DprintfT (SP_DUMP_JAVA | SP_DUMP_TIME, "jvmti_ClassPrepare: GetClassSignature failed. err=%d cname=%s\n", err, cname);
944       return;
945     }
946   char *str2 = NULL;
947   err = (*jvmti_env)->GetSourceFileName (jvmti_env, klass, &str2);
948   if (err != JVMTI_ERROR_NONE || str2 == NULL || *str2 == (char) 0)
949     sname = NO_SOURCE_FILE;
950   else
951     sname = str2;
952   DprintfT (SP_DUMP_JAVA | SP_DUMP_TIME, "jvmti_ClassPrepare: cname=%s sname=%s\n", STR (cname), STR (sname));
953 
954   /* Lock the whole file */
955   __collector_mutex_lock (&jclasses_lock);
956   hrt = gethrtime ();
957   record_jclass ((unsigned long) klass, hrt, cname, sname);
958   (*jvmti_env)->Deallocate (jvmti_env, (unsigned char *) str1);
959   (*jvmti_env)->Deallocate (jvmti_env, (unsigned char *) str2);
960   err = (*jvmti_env)->GetClassMethods (jvmti_env, klass, &mnum, &mptr);
961   if (err == JVMTI_ERROR_NONE)
962     {
963       for (int i = 0; i < mnum; i++)
964 	{
965 	  char *mname, *msign;
966 	  err = (*jvmti_env)->GetMethodName (jvmti_env, mptr[i], &mname, &msign, NULL);
967 	  if (err != JVMTI_ERROR_NONE)
968 	    continue;
969 	  record_jmethod ((unsigned long) klass, (unsigned long) mptr[i], mname, msign);
970 	  // DeleteLocalRef( mptr[i] );
971 	}
972       (*jvmti_env)->Deallocate (jvmti_env, (unsigned char*) mptr);
973     }
974   /* Unlock the file */
975   __collector_mutex_unlock (&jclasses_lock);
976 }
977 
978 /*
979  * The CLASS_LOAD event is enabled to enable AsyncGetCallTrace
980  */
981 static void
jvmti_ClassLoad(jvmtiEnv * jvmti_env,JNIEnv * jni_env,jthread thread,jclass klass)982 jvmti_ClassLoad (jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread, jclass klass)
983 {
984   char *cname;
985   char *str1 = NULL;
986   int err = (*jvmti_env)->GetClassSignature (jvmti_env, klass, &str1, NULL);
987   if (err != JVMTI_ERROR_NONE || str1 == NULL || *str1 == (char) 0)
988     cname = NO_CLASS_NAME;
989   else
990     cname = str1;
991   jstring str = NULL;
992   const char* resourceName;
993   jobject classLoader = NULL;
994   err = (*jvmti)->GetClassLoader (jvmti, klass, &classLoader);
995   DprintfT (SP_DUMP_JAVA | SP_DUMP_TIME, "jprofile: jvmti_ClassLoad err=%d cname=%s\n", err, STR (cname));
996   if (err == 0)
997     {
998       if (classLoader == NULL)
999 	{
1000 	  // bootstrap class loader
1001 	  resourceName = "";
1002 	}
1003       else
1004 	{
1005 	  char* name = (char *) alloca ((CALL_UTIL (strlen)(str1) + 32) * sizeof (char));
1006 	  CALL_UTIL (strlcpy)(name, str1 + 1, CALL_UTIL (strlen)(str1));
1007 	  name[CALL_UTIL (strlen)(name) - 1] = '\0'; // remove the last ';'
1008 	  char* p;
1009 	  for (p = name; *p != '\0'; p++)
1010 	    if (*p == '.')
1011 	      *p = '/';
1012 	  CALL_UTIL (strlcat)(name, ".class", CALL_UTIL (strlen)(name) + CALL_UTIL (strlen)(".class") + 1);
1013 	  if (getResource == NULL || toExternalForm == NULL)
1014 	    {
1015 	      resourceName = "";
1016 	      DprintfT (SP_DUMP_JAVA | SP_DUMP_TIME, "jvmti_ClassLoad: class %s failed to get path with method missing\n", STR (cname));
1017 	    }
1018 	  else
1019 	    {
1020 	      jobject url = (*jni_env)->CallObjectMethod (jni_env, classLoader, getResource, (*jni_env)->NewStringUTF (jni_env, name));
1021 	      if (url == NULL)
1022 		{
1023 		  resourceName = "";
1024 		  DprintfT (SP_DUMP_JAVA | SP_DUMP_TIME, "jvmti_ClassLoad: class %s failed to get path\n", STR (cname));
1025 		}
1026 	      else
1027 		{
1028 		  str = (jstring) (*jni_env)->CallObjectMethod (jni_env, url, toExternalForm);
1029 		  resourceName = (*jni_env)->GetStringUTFChars (jni_env, str, NULL);
1030 		  DprintfT (SP_DUMP_JAVA | SP_DUMP_TIME, "jvmti_ClassLoad: ARCH_JCLASS_LOCATION(Ox%x) class_id=0x%lx  className='%s' fileName '%s'\n",
1031 			    (int) ARCH_JCLASS_LOCATION, (unsigned long) klass, STR (cname), STR (resourceName));
1032 		  size_t clen = ARCH_STRLEN (cname);
1033 		  size_t slen = ARCH_STRLEN (resourceName);
1034 		  size_t sz = sizeof (ARCH_jclass) + clen + slen;
1035 		  ARCH_jclass_location *jcls = (ARCH_jclass_location*) alloca (sz);
1036 		  jcls->comm.tsize = sz;
1037 		  jcls->comm.type = ARCH_JCLASS_LOCATION;
1038 		  jcls->class_id = (unsigned long) klass;
1039 		  char *str = (char*) (jcls + 1);
1040 		  size_t i = CALL_UTIL (strlcpy)(str, cname, clen);
1041 		  str += i;
1042 		  while (i++ < clen)
1043 		    {
1044 		      *str++ = (char) 0; /* pad with 0's */
1045 		    }
1046 		  i = CALL_UTIL (strlcpy)(str, resourceName, slen);
1047 		  str += i;
1048 		  while (i++ < slen)
1049 		    {
1050 		      *str++ = (char) 0; /* pad with 0's */
1051 		    }
1052 		  /* Lock the whole file */
1053 		  __collector_mutex_lock (&jclasses_lock);
1054 		  collector_interface->writeDataPacket (jprof_hndl, (CM_Packet*) jcls);
1055 		  /* Unlock the file */
1056 		  __collector_mutex_unlock (&jclasses_lock);
1057 		}
1058 	    }
1059 	}
1060     }
1061 }
1062 
1063 static void
jvmti_MonitorEnter(jvmtiEnv * jvmti_env,JNIEnv * jni_env,jthread thread,jobject object)1064 jvmti_MonitorEnter (jvmtiEnv *jvmti_env, JNIEnv* jni_env,
1065 		    jthread thread, jobject object)
1066 {
1067   if (collector_jsync_begin)
1068     collector_jsync_begin ();
1069   TSD_Entry *tsd = collector_interface->getKey (tsd_key);
1070   if (tsd == NULL)
1071     return;
1072   tsd->tstamp = gethrtime ();
1073 }
1074 
1075 static void
jvmti_MonitorEntered(jvmtiEnv * jvmti_env,JNIEnv * jni_env,jthread thread,jobject object)1076 jvmti_MonitorEntered (jvmtiEnv *jvmti_env, JNIEnv* jni_env,
1077 		      jthread thread, jobject object)
1078 {
1079   TSD_Entry *tsd = collector_interface->getKey (tsd_key);
1080   if (tsd == NULL)
1081     return;
1082   if (collector_jsync_end)
1083     collector_jsync_end (tsd->tstamp, object);
1084 }
1085 
1086 static void
jvmti_GarbageCollectionStart(jvmtiEnv * jvmti_env)1087 jvmti_GarbageCollectionStart (jvmtiEnv *jvmti_env)
1088 {
1089   hrtime_t hrt = gethrtime ();
1090   collector_interface->writeLog ("<event kind=\"%s\" tstamp=\"%u.%09u\"/>\n",
1091 				 SP_JCMD_GCSTART,
1092 				 (unsigned) (hrt / NANOSEC), (unsigned) (hrt % NANOSEC)
1093 				 );
1094   TprintfT (DBG_LT1, "jprofile: jvmti_GarbageCollectionStart.\n");
1095 }
1096 
1097 static void
jvmti_GarbageCollectionFinish(jvmtiEnv * jvmti_env)1098 jvmti_GarbageCollectionFinish (jvmtiEnv *jvmti_env)
1099 {
1100   hrtime_t hrt = gethrtime ();
1101   collector_interface->writeLog ("<event kind=\"%s\" tstamp=\"%u.%09u\"/>\n",
1102 				 SP_JCMD_GCEND,
1103 				 (unsigned) (hrt / NANOSEC), (unsigned) (hrt % NANOSEC)
1104 				 );
1105   TprintfT (DBG_LT1, "jprofile: jvmti_GarbageCollectionFinish.\n");
1106 }
1107 
1108 #if 0
1109 static void
1110 jvmti_MonitorWait (jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread,
1111 		   jobject object, jlong timed_out)
1112 {
1113   if (collector_sync_begin)
1114     collector_sync_begin ();
1115   TSD_Entry *tsd = collector_interface->getKey (tsd_key);
1116   if (tsd == NULL)
1117     return;
1118   tsd->tstamp = gethrtime ();
1119 }
1120 
1121 static void
1122 jvmti_MonitorWaited (jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread,
1123 		     jobject object, jboolean timed_out)
1124 {
1125   TSD_Entry *tsd = collector_interface->getKey (tsd_key);
1126   if (tsd == NULL)
1127     return;
1128   if (collector_sync_end)
1129     collector_sync_end (tsd->tstamp, object);
1130 }
1131 #endif
1132 
1133 static void
jprof_find_asyncgetcalltrace()1134 jprof_find_asyncgetcalltrace ()
1135 {
1136   void *jvmhandle;
1137   if (__collector_VM_ReadByteInstruction == NULL)
1138     __collector_VM_ReadByteInstruction = (int(*)()) dlsym (RTLD_DEFAULT, "Async_VM_ReadByteInstruction");
1139 
1140   /* look for stack unwind function using default path */
1141   AsyncGetCallTrace = (void (*)(JVMPI_CallTrace*, jint, ucontext_t*))
1142 	  dlsym (RTLD_DEFAULT, "AsyncGetCallTrace");
1143   if (AsyncGetCallTrace != NULL)
1144     {
1145       __collector_java_asyncgetcalltrace_loaded = 1;
1146       TprintfT (DBG_LT1, "jprofile: AsyncGetCallTrace found with RTLD_DEFAULT\n");
1147     }
1148   else
1149     {
1150       /* not found there, find libjvm.so, and ask again */
1151       jvmhandle = dlopen ("libjvm.so", RTLD_LAZY | RTLD_NOLOAD);
1152       if (jvmhandle != NULL)
1153 	{
1154 	  AsyncGetCallTrace = (void (*)(JVMPI_CallTrace*, jint, ucontext_t*))
1155 		  dlsym (jvmhandle, "AsyncGetCallTrace");
1156 	}
1157     }
1158 
1159   if (AsyncGetCallTrace == NULL)
1160     {
1161       /* we could not find it -- write collector error */
1162       TprintfT (0, "jprofile: ERROR -- AsyncGetCallTrace not found in address space\n");
1163       char *err = dlerror ();
1164       collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">%s</event>\n",
1165 				     SP_JCMD_CERROR, COL_ERROR_JVMNOJSTACK, err ? err : "");
1166       __collector_java_mode = 0;
1167     }
1168   else
1169     {
1170       __collector_java_asyncgetcalltrace_loaded = 1;
1171       TprintfT (DBG_LT1, "jprofile: AsyncGetCallTrace initialized in jprof_jvmpi_init_done_event\n");
1172     }
1173 }
1174 
1175 int
__collector_ext_jstack_unwind(char * ptr,int sz,ucontext_t * uc)1176 __collector_ext_jstack_unwind (char *ptr, int sz, ucontext_t *uc)
1177 {
1178   if (AsyncGetCallTrace == NULL)
1179     {
1180       TprintfT (DBG_LT0, "jprofile: __collector_ext_jstack_unwind: AsyncGetCallTrace is NULL\n");
1181       return 0;
1182     }
1183 
1184   TSD_Entry *tsd = collector_interface->getKey (tsd_key);
1185   if (tsd == NULL)
1186     {
1187       TprintfT (DBG_LT3, "jprofile: __collector_ext_jstack_unwind: tsd is NULL\n");
1188       return 0;
1189     }
1190   if (__collector_java_attach && tsd->env == NULL && jvmti != NULL && jvm != NULL)
1191     {
1192       TprintfT (DBG_LT3, "jprofile: __collector_ext_jstack_unwind: tsd->env is NULL under attach\n");
1193       JNIEnv* jni_env = NULL;
1194       (*jvm)->GetEnv (jvm, (void **) &jni_env, JNI_VERSION_1_2);
1195       tsd->env = jni_env;
1196     }
1197   if (tsd->env == NULL)
1198     {
1199       TprintfT (DBG_LT3, "jprofile: __collector_ext_jstack_unwind: tsd->env is NULL\n");
1200       return 0;
1201     }
1202 
1203   /* skip the Java stack whenever another signal handler is present */
1204   if (uc->uc_link)
1205     {
1206       TprintfT (DBG_LT3, "jprofile: __collector_ext_jstack_unwind: uc->uc_link is non-NULL\n");
1207       return 0;
1208     }
1209   /* we don't expect Java frames in signal handlers, so
1210    * unroll the list of saved contexts to the topmost one
1211    */
1212   while (uc->uc_link)
1213     uc = uc->uc_link;
1214   Java_info *jinfo = (Java_info*) ptr;
1215   jinfo->kind = JAVA_INFO;
1216   jinfo->hsize = sizeof (Java_info);
1217   ptr += sizeof (Java_info);
1218   sz -= sizeof (Java_info);
1219 
1220   JVMPI_CallTrace jtrace;
1221   jtrace.env_id = tsd->env;
1222   jtrace.frames = (JVMPI_CallFrame*) ptr;
1223 
1224   /* nframes is how many frames we have room for */
1225   jint nframes = sz / sizeof (JVMPI_CallFrame);
1226 
1227 #if WSIZE(64)
1228   /* bug 6909545: garbage in 64-bit JAVA_INFO */
1229   CALL_UTIL (memset)(jtrace.frames, 0, nframes * sizeof (JVMPI_CallFrame));
1230 #endif
1231 
1232 #if ARCH(SPARC)
1233   // 21328946 JDK bug 8129933 causes <no java callstack recorded> on sparc-Linux
1234   // convert from ucontext_t to sigcontext
1235   struct sigcontext sctx;
1236   sctx.sigc_regs.tpc = uc->uc_mcontext.mc_gregs[MC_PC];
1237   __collector_memcpy (sctx.sigc_regs.u_regs, &uc->uc_mcontext.mc_gregs[3], sizeof (sctx.sigc_regs.u_regs));
1238   uc = (ucontext_t *) (&sctx);
1239 #endif /* SPARC */
1240   AsyncGetCallTrace (&jtrace, nframes, uc);
1241 
1242   if (jtrace.num_frames == nframes)
1243     {
1244       JVMPI_CallFrame *last = &jtrace.frames[nframes - 1];
1245       last->method_id = (jmethodID) SP_TRUNC_STACK_MARKER;
1246       last->lineno = 0;
1247     }
1248 
1249   /* nframes is how many frames we actually got */
1250   nframes = jtrace.num_frames;
1251   TprintfT (DBG_LT3, "jprofile: __collector_ext_jstack_unwind: AsyncGetCallTrace jtrace.numframes = %d\n", nframes);
1252   if (nframes <= 0)
1253     {
1254       /* negative values are error codes */
1255       TprintfT (0, "jprofile: __collector_ext_jstack_unwind: AsyncGetCallTrace returned error: jtrace.numframes = %d\n", nframes);
1256       nframes = 1;
1257       JVMPI_CallFrame *err = (JVMPI_CallFrame*) ptr;
1258       err->lineno = jtrace.num_frames; // bci = error code
1259       err->method_id = 0; // artificial method id
1260     }
1261   jinfo->hsize += nframes * sizeof (JVMPI_CallFrame);
1262   return jinfo->hsize;
1263 }
1264 
1265 /*
1266  *	Collector Java API implementation
1267  */
1268 void
Java_com_sun_forte_st_collector_CollectorAPI__1sample(JNIEnv * jEnv,jclass jCls,jstring jName)1269 Java_com_sun_forte_st_collector_CollectorAPI__1sample(JNIEnv *jEnv, jclass jCls, jstring jName)
1270 {
1271   JNIEnv *jni;
1272   jint res = (*jvm)->GetEnv (jvm, (void **) &jni, JNI_VERSION_1_2);
1273   if (res < 0)
1274     return;
1275   const char *name = jName ? (*jni)->GetStringUTFChars (jni, jName, NULL) : NULL;
1276   __collector_sample ((char*) name);
1277 }
1278 
1279 void
Java_com_sun_forte_st_collector_CollectorAPI__1pause(JNIEnv * jEnv,jclass jCls)1280 Java_com_sun_forte_st_collector_CollectorAPI__1pause(JNIEnv *jEnv, jclass jCls)
1281 {
1282   __collector_pause_m ("JAPI");
1283 }
1284 
1285 void
Java_com_sun_forte_st_collector_CollectorAPI__1resume(JNIEnv * jEnv,jclass jCls)1286 Java_com_sun_forte_st_collector_CollectorAPI__1resume(JNIEnv *jEnv, jclass jCls)
1287 {
1288   __collector_resume ();
1289 }
1290 
1291 void
Java_com_sun_forte_st_collector_CollectorAPI__1terminate(JNIEnv * jEnv,jclass jCls)1292 Java_com_sun_forte_st_collector_CollectorAPI__1terminate(JNIEnv *jEnv, jclass jCls)
1293 {
1294   __collector_terminate_expt ();
1295 }
1296 #endif /* GPROFNG_JAVA_PROFILING */
1297 
1298 static void init_module () __attribute__ ((constructor));
1299 static void
init_module()1300 init_module ()
1301 {
1302 #if defined(GPROFNG_JAVA_PROFILING)
1303   __collector_dlsym_guard = 1;
1304   RegModuleFunc reg_module = (RegModuleFunc) dlsym (RTLD_DEFAULT, "__collector_register_module");
1305   __collector_dlsym_guard = 0;
1306   if (reg_module)
1307     {
1308       jprof_hndl = reg_module (&module_interface);
1309       TprintfT (0, "jprofile: init_module.\n");
1310     }
1311 #endif /* GPROFNG_JAVA_PROFILING */
1312 }
1313 
1314 int __collector_java_mode = 0;
1315 int __collector_java_asyncgetcalltrace_loaded = 0;
1316