xref: /netbsd-src/external/gpl3/binutils/dist/gprofng/libcollector/jprofile.c (revision cb63e24e8d6aae7ddac1859a9015f48b1d8bd90e)
1 /* Copyright (C) 2021-2024 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 #include <stddef.h>
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 	      jvmti_VMInit (jvmti, jni_env, thread);
289 	      (*jvmti)->GenerateEvents (jvmti, JVMTI_EVENT_COMPILED_METHOD_LOAD);
290 	      (*jvmti)->GenerateEvents (jvmti, JVMTI_EVENT_DYNAMIC_CODE_GENERATED);
291 	      __collector_java_attach = 1;
292 	      (*jvm)->DetachCurrentThread (jvm);
293 	    }
294 	}
295     }
296   return 0;
297 }
298 
299 static int
close_experiment(void)300 close_experiment (void)
301 {
302   /* fixme XXXXX add content here */
303   /* see detach_experiment() */
304   __collector_java_mode = 0;
305   __collector_java_asyncgetcalltrace_loaded = 0;
306   __collector_java_attach = 0;
307   java_gc_on = 0;
308   java_mem_mode = 0;
309   java_sync_mode = 0;
310   is_hotspot_vm = 0;
311   __collector_mutex_init (&jclasses_lock);
312   tsd_key = COLLECTOR_TSD_INVALID_KEY;
313   TprintfT (0, "jprofile: experiment closed.\n");
314   return 0;
315 }
316 
317 static int
detach_experiment(void)318 detach_experiment (void)
319 /* fork child.  Clean up state but don't write to experiment */
320 {
321   __collector_java_mode = 0;
322   java_gc_on = 0;
323   jvm = NULL;
324   java_mem_mode = 0;
325   java_sync_mode = 0;
326   is_hotspot_vm = 0;
327   jvmti = NULL;
328   apistr = NULL;
329   __collector_mutex_init (&jclasses_lock);
330   tsd_key = COLLECTOR_TSD_INVALID_KEY;
331   TprintfT (0, "jprofile: detached from experiment.\n");
332   return 0;
333 }
334 
335 JNIEXPORT jint JNICALL
JVM_OnLoad(JavaVM * vm,char * options,void * reserved)336 JVM_OnLoad (JavaVM *vm, char *options, void *reserved)
337 {
338   jvmtiError err;
339   int use_jvmti = 0;
340   if (!__collector_java_mode)
341     {
342       TprintfT (DBG_LT1, "jprofile: JVM_OnLoad invoked with java mode disabled\n");
343       return JNI_OK;
344     }
345   else
346     TprintfT (DBG_LT1, "jprofile: JVM_OnLoad invoked\n");
347   jvm = vm;
348   jvmti = NULL;
349   if ((*jvm)->GetEnv (jvm, (void **) &jvmti, JVMTI_VERSION_1_0) >= 0 && jvmti)
350     {
351       TprintfT (DBG_LT1, "jprofile: JVMTI found\n");
352       use_jvmti = 1;
353     }
354   if (!use_jvmti)
355     {
356       collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\"/>\n",
357 				     SP_JCMD_CERROR, COL_ERROR_JVMNOTSUPP);
358       return JNI_ERR;
359     }
360   else
361     {
362       Tprintf (DBG_LT0, "\tjprofile: Initializing for JVMTI\n");
363       apistr = "JVMTI 1.0";
364 
365       // setup JVMTI
366       jvmtiCapabilities cpblts;
367       err = (*jvmti)->GetPotentialCapabilities (jvmti, &cpblts);
368       if (err == JVMTI_ERROR_NONE)
369 	{
370 	  jvmtiCapabilities cpblts_set;
371 	  CALL_UTIL (memset)(&cpblts_set, 0, sizeof (cpblts_set));
372 
373 	  /* Add only those capabilities that are among potential ones */
374 	  cpblts_set.can_get_source_file_name = cpblts.can_get_source_file_name;
375 	  Tprintf (DBG_LT1, "\tjprofile: adding can_get_source_file_name capability: %u\n", cpblts.can_get_source_file_name);
376 
377 	  cpblts_set.can_generate_compiled_method_load_events = cpblts.can_generate_compiled_method_load_events;
378 	  Tprintf (DBG_LT1, "\tjprofile: adding can_generate_compiled_method_load_events capability: %u\n", cpblts.can_generate_compiled_method_load_events);
379 
380 	  if (java_sync_mode)
381 	    {
382 	      cpblts_set.can_generate_monitor_events = cpblts.can_generate_monitor_events;
383 	      Tprintf (DBG_LT1, "\tjprofile: adding can_generate_monitor_events capability: %u\n", cpblts.can_generate_monitor_events);
384 	    }
385 	  if (java_gc_on)
386 	    {
387 	      cpblts_set.can_generate_garbage_collection_events = cpblts.can_generate_garbage_collection_events;
388 	      Tprintf (DBG_LT1, "\tjprofile: adding can_generate_garbage_collection_events capability: %u\n", cpblts.can_generate_garbage_collection_events);
389 	    }
390 	  err = (*jvmti)->AddCapabilities (jvmti, &cpblts_set);
391 	  Tprintf (DBG_LT1, "\tjprofile: AddCapabilities() returns: %d\n", err);
392 	}
393       err = (*jvmti)->SetEventCallbacks (jvmti, &callbacks, sizeof ( callbacks));
394       err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, NULL);
395       err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_DEATH, NULL);
396       err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_CLASS_PREPARE, NULL);
397       err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_CLASS_LOAD, NULL);
398       err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_COMPILED_METHOD_LOAD, NULL);
399       err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_COMPILED_METHOD_UNLOAD, NULL);
400       err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_DYNAMIC_CODE_GENERATED, NULL);
401       err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_THREAD_START, NULL);
402       err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_THREAD_END, NULL);
403       err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, NULL);
404       if (java_gc_on)
405 	{
406 	  err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_GARBAGE_COLLECTION_START, NULL);
407 	  err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, NULL);
408 	}
409       if (java_mem_mode)
410 	{
411 	  // err = (*jvmti)->SetEventNotificationMode( jvmti, JVMTI_ENABLE, <no event for heap tracing> , NULL );
412 	  collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\"/>\n",
413 					 SP_JCMD_CWARN, COL_WARN_NO_JAVA_HEAP);
414 	  java_mem_mode = 0;
415 	}
416       if (java_sync_mode)
417 	{
418 	  err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_MONITOR_CONTENDED_ENTER, NULL);
419 	  err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_MONITOR_CONTENDED_ENTERED, NULL);
420 	  //err = (*jvmti)->SetEventNotificationMode( jvmti, JVMTI_ENABLE, JVMTI_EVENT_MONITOR_WAIT, NULL );
421 	  //err = (*jvmti)->SetEventNotificationMode( jvmti, JVMTI_ENABLE, JVMTI_EVENT_MONITOR_WAITED, NULL );
422 	}
423       Tprintf (DBG_LT0, "\tjprofile: JVMTI initialized\n");
424     }
425 
426   /* JVM still uses collector API on Solaris to notify us about dynamically generated code.
427    * If we ask it to generate events we'll end up with duplicate entries in the
428    * map file.
429    */
430   if (use_jvmti)
431     {
432       err = (*jvmti)->GenerateEvents (jvmti, JVMTI_EVENT_DYNAMIC_CODE_GENERATED);
433       err = (*jvmti)->GenerateEvents (jvmti, JVMTI_EVENT_COMPILED_METHOD_LOAD);
434     }
435   Tprintf (DBG_LT1, "\tjprofile: JVM_OnLoad ok\n");
436   return JNI_OK;
437 }
438 
439 /* This is currently just a placeholder */
440 JNIEXPORT jint JNICALL
Agent_OnLoad(JavaVM * vm,char * options,void * reserved)441 Agent_OnLoad (JavaVM *vm, char *options, void *reserved)
442 {
443   return JVM_OnLoad (vm, options, reserved);
444 }
445 
446 static void
rwrite(int fd,const void * buf,size_t nbyte)447 rwrite (int fd, const void *buf, size_t nbyte)
448 {
449   size_t left = nbyte;
450   size_t res;
451   char *ptr = (char*) buf;
452   while (left > 0)
453     {
454       res = CALL_UTIL (write)(fd, ptr, left);
455       if (res == -1)
456 	{
457 	  /*  XXX: we can't write this record, we probably
458 	   *  can't write anything else. Ignore.
459 	   */
460 	  return;
461 	}
462       left -= res;
463       ptr += res;
464     }
465 }
466 
467 void
get_jvm_settings()468 get_jvm_settings ()
469 {
470   jint res;
471   JNIEnv *jni;
472   jclass jcls;
473   jmethodID jmid;
474   jstring jstrin;
475   jstring jstrout;
476   const char *str;
477   res = (*jvm)->GetEnv (jvm, (void **) &jni, JNI_VERSION_1_2);
478   if (res < 0)
479     return;
480 
481   /* I'm not checking if results are valid as JVM is extremely
482    * sensitive to exceptions that might occur during these JNI calls
483    * and will die with a fatal error later anyway.
484    */
485   jcls = (*jni)->FindClass (jni, "java/lang/System");
486   jmid = (*jni)->GetStaticMethodID (jni, jcls, "getProperty", "(Ljava/lang/String;)Ljava/lang/String;");
487   jstrin = (*jni)->NewStringUTF (jni, "java.class.path");
488   jstrout = (*jni)->CallStaticObjectMethod (jni, jcls, jmid, jstrin);
489   str = jstrout ? (*jni)->GetStringUTFChars (jni, jstrout, NULL) : NULL;
490   if (str)
491     {
492       collector_interface->writeLog ("<setting %s=\"%s\"/>\n", SP_JCMD_SRCHPATH, str);
493       (*jni)->ReleaseStringUTFChars (jni, jstrout, str);
494     }
495   jstrin = (*jni)->NewStringUTF (jni, "sun.boot.class.path");
496   jstrout = (*jni)->CallStaticObjectMethod (jni, jcls, jmid, jstrin);
497   str = jstrout ? (*jni)->GetStringUTFChars (jni, jstrout, NULL) : NULL;
498   if (str)
499     {
500       collector_interface->writeLog ("<setting %s=\"%s\"/>\n", SP_JCMD_SRCHPATH, str);
501       (*jni)->ReleaseStringUTFChars (jni, jstrout, str);
502     }
503   jstrin = (*jni)->NewStringUTF (jni, "java.home");
504   jstrout = (*jni)->CallStaticObjectMethod (jni, jcls, jmid, jstrin);
505   str = jstrout ? (*jni)->GetStringUTFChars (jni, jstrout, NULL) : NULL;
506   if (str)
507     {
508       collector_interface->writeLog ("<setting %s=\"%s/../src.zip\"/>\n", SP_JCMD_SRCHPATH, str);
509       (*jni)->ReleaseStringUTFChars (jni, jstrout, str);
510     }
511   jstrin = (*jni)->NewStringUTF (jni, "java.vm.version");
512   jstrout = (*jni)->CallStaticObjectMethod (jni, jcls, jmid, jstrin);
513   str = jstrout ? (*jni)->GetStringUTFChars (jni, jstrout, NULL) : NULL;
514   if (str)
515     {
516       (void) collector_interface->writeLog ("<profile name=\"jprofile\" %s=\"%s\" %s=\"%s\"/>\n",
517 					    SP_JCMD_JVERSION, str, "api", apistr != NULL ? apistr : "N/A");
518       if (__collector_strStartWith (str, "1.4.2_02") < 0)
519 	{
520 	  (void) collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\"/>\n",
521 						SP_JCMD_CWARN, COL_WARN_OLDJAVA);
522 	}
523       (*jni)->ReleaseStringUTFChars (jni, jstrout, str);
524     }
525   is_hotspot_vm = 0;
526   jstrin = (*jni)->NewStringUTF (jni, "sun.management.compiler");
527   jstrout = (*jni)->CallStaticObjectMethod (jni, jcls, jmid, jstrin);
528   str = jstrout ? (*jni)->GetStringUTFChars (jni, jstrout, NULL) : NULL;
529   if (str && __collector_strncmp (str, "HotSpot", 7) == 0)
530     is_hotspot_vm = 1;
531 
532   /* Emulate System.setProperty( "collector.init", "true") */
533   jmid = (*jni)->GetStaticMethodID (jni, jcls, "setProperty",
534 				    "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
535   jstrin = (*jni)->NewStringUTF (jni, "collector.init");
536   jstrout = (*jni)->NewStringUTF (jni, "true");
537   (*jni)->CallStaticObjectMethod (jni, jcls, jmid, jstrin, jstrout);
538 }
539 
540 /*
541  * JVMTI code
542  */
543 
544 static void
jvmti_VMInit(jvmtiEnv * jvmti_env,JNIEnv * jni_env,jthread thread)545 jvmti_VMInit (jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread)
546 {
547   jint class_count = 0;
548   jclass *classes = NULL;
549   int i;
550   TprintfT (DBG_LT1, "jprofile: jvmti_VMInit called\n");
551   get_jvm_settings ();
552 
553   /* determine loaded classes */
554   (*jvmti_env)->GetLoadedClasses (jvmti_env, &class_count, &classes);
555   TprintfT (DBG_LT1, "jprofile: jvmti_VMInit initializing %d classes\n", class_count);
556   for (i = 0; i < class_count; i++)
557     {
558       // PushLocalFrame
559       jvmti_ClassPrepare (jvmti_env, jni_env, NULL, classes[i]);
560       // PopLocalFrame
561       // DeleteLocalRef( classes[i] );
562     }
563   (*jvmti_env)->Deallocate (jvmti_env, (unsigned char*) classes);
564   getResource = (*jni_env)->GetMethodID (jni_env, (*jni_env)->FindClass (jni_env, "java/lang/ClassLoader"), "getResource", "(Ljava/lang/String;)Ljava/net/URL;");
565   toExternalForm = (*jni_env)->GetMethodID (jni_env, (*jni_env)->FindClass (jni_env, "java/net/URL"), "toExternalForm", "()Ljava/lang/String;");
566 
567   /* find the stack unwind routine */
568   jprof_find_asyncgetcalltrace ();
569 }
570 
571 static void
jvmti_VMDeath(jvmtiEnv * jvmti_env,JNIEnv * jni_env)572 jvmti_VMDeath (jvmtiEnv *jvmti_env, JNIEnv* jni_env)
573 {
574   __collector_java_mode = 0;
575   TprintfT (DBG_LT1, "jprofile: jvmti_VMDeath event received\n");
576 }
577 
578 static void
jvmti_ThreadStart(jvmtiEnv * jvmti_env,JNIEnv * jni_env,jthread thread)579 jvmti_ThreadStart (jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread)
580 {
581   jvmtiError err;
582   jvmtiThreadInfo t_info;
583   char *thread_name, *group_name, *parent_name;
584   hrtime_t hrt;
585   collector_thread_t tid;
586   thread_name = group_name = parent_name = NULL;
587   hrt = gethrtime ();
588   tid = __collector_thr_self ();
589   TprintfT (DBG_LT1, "jprofile: jvmti_ThreadStart: thread: %lu jni_env=%p jthread=%p\n",
590 	    (unsigned long) tid, jni_env, thread);
591   err = (*jvmti_env)->GetThreadInfo (jvmti_env, thread, &t_info);
592   if (err == JVMTI_ERROR_NONE)
593     {
594       jvmtiThreadGroupInfo g_info;
595       thread_name = t_info.name;
596       if (t_info.thread_group)
597 	{
598 	  err = (*jvmti_env)->GetThreadGroupInfo (jvmti_env, t_info.thread_group, &g_info);
599 	  if (err == JVMTI_ERROR_NONE)
600 	    {
601 	      group_name = g_info.name;
602 	      if (g_info.parent)
603 		{
604 		  jvmtiThreadGroupInfo p_info;
605 		  err = (*jvmti_env)->GetThreadGroupInfo (jvmti_env, g_info.parent, &p_info);
606 		  if (err == JVMTI_ERROR_NONE)
607 		    {
608 		      parent_name = p_info.name;
609 		      // DeleteLocalRef( p_info.parent );
610 		    }
611 		  // DeleteLocalRef( g_info.parent );
612 		}
613 	    }
614 	}
615       // DeleteLocalRef( t_info.thread_group );
616       // DeleteLocalRef( t_info.context_class_loader );
617     }
618   if (thread_name == NULL)
619     thread_name = "";
620   if (group_name == NULL)
621     group_name = "";
622   if (parent_name == NULL)
623     parent_name = "";
624   collector_interface->writeLog ("<event kind=\"%s\" tstamp=\"%u.%09u\" name=\"%s\" grpname=\"%s\" prntname=\"%s\" tid=\"%lu\" jthr=\"0x%lx\" jenv=\"0x%lx\"/>\n",
625 				 SP_JCMD_JTHRSTART,
626 				 (unsigned) (hrt / NANOSEC), (unsigned) (hrt % NANOSEC),
627 				 thread_name,
628 				 group_name,
629 				 parent_name,
630 				 (unsigned long) tid,
631 				 (unsigned long) thread,
632 				 (unsigned long) jni_env
633 				 );
634   TSD_Entry *tsd = collector_interface->getKey (tsd_key);
635   if (tsd)
636     tsd->env = jni_env;
637 }
638 
639 static void
jvmti_ThreadEnd(jvmtiEnv * jvmti_env,JNIEnv * jni_env,jthread thread)640 jvmti_ThreadEnd (jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread)
641 {
642   hrtime_t hrt = gethrtime ();
643   collector_thread_t tid = __collector_thr_self ();
644   TprintfT (DBG_LT1, "jprofile: jvmti_ThreadEnd: thread: %lu jni_env=%p jthread=%p\n",
645 	    (unsigned long) tid, jni_env, thread);
646 
647   collector_interface->writeLog ("<event kind=\"%s\" tstamp=\"%u.%09u\" tid=\"%lu\"  jthr=\"0x%lx\" jenv=\"0x%lx\"/>\n",
648 				 SP_JCMD_JTHREND,
649 				 (unsigned) (hrt / NANOSEC), (unsigned) (hrt % NANOSEC),
650 				 (unsigned long) tid,
651 				 (unsigned long) thread,
652 				 (unsigned long) jni_env
653 				 );
654   TSD_Entry *tsd = collector_interface->getKey (tsd_key);
655   if (tsd)
656     tsd->env = NULL;
657 }
658 
659 /* The following definitions are borrowed from file jvmticmlr.h, part of jdk7 */
660 typedef enum
661 {
662   JVMTI_CMLR_DUMMY = 1,
663   JVMTI_CMLR_INLINE_INFO = 2
664 } jvmtiCMLRKind;
665 
666 /*
667  * Record that represents arbitrary information passed through JVMTI
668  * CompiledMethodLoadEvent void pointer.
669  */
670 typedef struct _jvmtiCompiledMethodLoadRecordHeader
671 {
672   jvmtiCMLRKind kind;       /* id for the kind of info passed in the record */
673   jint majorinfoversion;    /* major and minor info version values. Init'ed */
674   jint minorinfoversion;    /* to current version value in jvmtiExport.cpp. */
675   struct _jvmtiCompiledMethodLoadRecordHeader* next;
676 } jvmtiCompiledMethodLoadRecordHeader;
677 
678 /*
679  * Record that gives information about the methods on the compile-time
680  * stack at a specific pc address of a compiled method. Each element in
681  * the methods array maps to same element in the bcis array.
682  */
683 typedef struct _PCStackInfo
684 {
685   void* pc;                 /* the pc address for this compiled method */
686   jint numstackframes;      /* number of methods on the stack */
687   jmethodID* methods;       /* array of numstackframes method ids */
688   jint* bcis;               /* array of numstackframes bytecode indices */
689 } PCStackInfo;
690 
691 /*
692  * Record that contains inlining information for each pc address of
693  * an nmethod.
694  */
695 typedef struct _jvmtiCompiledMethodLoadInlineRecord
696 {
697   jvmtiCompiledMethodLoadRecordHeader header; /* common header for casting */
698   jint numpcs; /* number of pc descriptors in this nmethod */
699   PCStackInfo* pcinfo; /* array of numpcs pc descriptors */
700 } jvmtiCompiledMethodLoadInlineRecord;
701 
702 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)703 jvmti_CompiledMethodLoad (jvmtiEnv *jvmti_env, jmethodID method,
704 			  jint code_size, const void *code_addr, jint map_length,
705 			  const jvmtiAddrLocationMap *map,
706 			  const void *compile_info)
707 {
708   TprintfT (DBG_LT2, "jprofile: jvmti_CompiledMethodLoad: mid=0x%lx addr=%p sz=0x%lu map=%p info=%p\n",
709 	    (unsigned long) method, code_addr, (long) code_size, map, compile_info);
710   char name[32];
711   CALL_UTIL (snprintf)(name, sizeof (name), "0x%lx", (unsigned long) method);
712 
713   /* Parse compile_info to get pc -> bci mapping.
714    * Don't interpret compile_info from JVMs other than HotSpot.
715    */
716   int lntsize = 0;
717   DT_lineno *lntable = NULL;
718   if (compile_info != NULL && is_hotspot_vm)
719     {
720       Tprintf (DBG_LT2, "Mapping from compile_info:\n");
721       jvmtiCompiledMethodLoadRecordHeader *currec =
722 	      (jvmtiCompiledMethodLoadRecordHeader*) compile_info;
723       while (currec != NULL)
724 	{
725 	  if (currec->kind == JVMTI_CMLR_INLINE_INFO)
726 	    {
727 	      jvmtiCompiledMethodLoadInlineRecord *inrec =
728 		      (jvmtiCompiledMethodLoadInlineRecord*) currec;
729 	      if (inrec->numpcs <= 0)
730 		break;
731 	      lntsize = inrec->numpcs;
732 	      lntable = (DT_lineno*) alloca (lntsize * sizeof (DT_lineno));
733 	      PCStackInfo *pcrec = inrec->pcinfo;
734 	      DT_lineno *lnorec = lntable;
735 	      for (int i = 0; i < lntsize; ++i)
736 		{
737 		  for (int j = pcrec->numstackframes - 1; j >= 0; --j)
738 		    if (pcrec->methods[j] == method)
739 		      {
740 			lnorec->offset = (char*) pcrec->pc - (char*) code_addr;
741 			lnorec->lineno = pcrec->bcis[j];
742 			Tprintf (DBG_LT2, "   pc: 0x%lx  bci: 0x%lx\n",
743 				 (long) lnorec->offset, (long) lnorec->lineno);
744 			++lnorec;
745 			break;
746 		      }
747 		  ++pcrec;
748 		}
749 	      break;
750 	    }
751 	  currec = currec->next;
752 	}
753     }
754   else if (map != NULL)
755     {
756       Tprintf (DBG_LT2, "Mapping from jvmtiAddrLocationMap:\n");
757       lntsize = map_length;
758       lntable = (DT_lineno*) alloca (lntsize * sizeof (DT_lineno));
759       DT_lineno *lnorec = lntable;
760       for (int i = 0; i < map_length; ++i)
761 	{
762 	  lnorec->offset = (char*) map[i].start_address - (char*) code_addr;
763 	  lnorec->lineno = (unsigned int) map[i].location;
764 	  Tprintf (DBG_LT2, "   pc: 0x%lx  bci: 0x%lx\n",
765 		   (long) lnorec->offset, (long) lnorec->lineno);
766 	  ++lnorec;
767 	}
768     }
769   __collector_int_func_load (DFUNC_JAVA, name, NULL, (void*) code_addr,
770 			     code_size, lntsize, lntable);
771 }
772 
773 static void
jvmti_CompiledMethodUnload(jvmtiEnv * jvmti_env,jmethodID method,const void * code_addr)774 jvmti_CompiledMethodUnload (jvmtiEnv *jvmti_env, jmethodID method, const void* code_addr)
775 {
776   __collector_int_func_unload (DFUNC_API, (void*) code_addr);
777 }
778 
779 static void
jvmti_DynamicCodeGenerated(jvmtiEnv * jvmti_env,const char * name,const void * code_addr,jint code_size)780 jvmti_DynamicCodeGenerated (jvmtiEnv *jvmti_env, const char*name, const void *code_addr, jint code_size)
781 {
782   __collector_int_func_load (DFUNC_API, (char*) name, NULL, (void*) code_addr,
783 			     code_size, 0, NULL);
784 }
785 
786 static void
addToDynamicArchive(const char * name,const unsigned char * class_data,int class_data_len)787 addToDynamicArchive (const char* name, const unsigned char* class_data, int class_data_len)
788 {
789   char path[MAXPATHLEN + 1];
790   mode_t fmode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
791   mode_t dmode = fmode | S_IXUSR | S_IXGRP | S_IXOTH;
792   if (name == NULL)
793     name = "";
794   const char *expdir = collector_interface->getExpDir ();
795   if (CALL_UTIL (strlen)(expdir) +
796       CALL_UTIL (strlen)(SP_DYNAMIC_CLASSES) +
797       CALL_UTIL (strlen)(name) + 8 > sizeof (path))
798     return;
799   CALL_UTIL (snprintf)(path, sizeof (path), "%s/%s/%s.class", expdir, SP_DYNAMIC_CLASSES, name);
800 
801   /* Create all path components step by step starting with SP_DYNAMIC_CLASSES */
802   char *str = path + CALL_UTIL (strlen)(expdir) + 1 + CALL_UTIL (strlen)(SP_DYNAMIC_CLASSES);
803   while (str)
804     {
805       *str = '\0';
806       if (CALL_UTIL (mkdir)(path, dmode) != 0)
807 	{
808 	  /* Checking for EEXIST is not enough, access() is more reliable */
809 	  if (CALL_UTIL (access)(path, F_OK) != 0)
810 	    {
811 	      collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">%s</event>\n",
812 					     SP_JCMD_CERROR, COL_ERROR_MKDIR, errno, path);
813 	      return;
814 	    }
815 	}
816       *str++ = '/';
817       str = CALL_UTIL (strchr)(str, '/');
818     }
819 
820   int fd = CALL_UTIL (open)(path, O_WRONLY | O_CREAT | O_TRUNC, fmode);
821   if (fd < 0)
822     {
823       collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">%s</event>\n",
824 				     SP_JCMD_CERROR, COL_ERROR_OVWOPEN, errno, path);
825       return;
826     }
827   rwrite (fd, class_data, class_data_len);
828   CALL_UTIL (close)(fd);
829 }
830 
831 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)832 jvmti_ClassFileLoadHook (jvmtiEnv *jvmti_env, JNIEnv* jni_env, jclass class_being_redefined,
833 			 jobject loader, const char* name, jobject protection_domain, jint class_data_len,
834 			 const unsigned char* class_data, jint* new_class_data_len, unsigned char** new_class_data)
835 {
836   jclass loaderlass;
837   int err;
838   jvmtiPhase phase_ptr;
839   char *cname = NULL;
840   (*jvmti_env)->GetPhase (jvmti_env, &phase_ptr);
841 
842   /* skip non live phases */
843   if (phase_ptr != JVMTI_PHASE_LIVE)
844     return;
845 
846   /* skip system class loaders */
847   if (!loader)
848     return;
849   loaderlass = (*jni_env)->GetObjectClass (jni_env, loader);
850   err = (*jvmti_env)->GetClassSignature (jvmti_env, loaderlass, &cname, NULL);
851   if (err != JVMTI_ERROR_NONE || !cname || *cname == (char) 0)
852     return;
853 
854   /* skip classes loaded with AppClassLoader (java.class.path) */
855   if (__collector_strcmp (cname, "Lsun/misc/Launcher$AppClassLoader;") == 0)
856     return;
857   addToDynamicArchive (name, class_data, (int) class_data_len);
858 }
859 
860 #define NO_CLASS_NAME "<noname>"
861 #define NO_SOURCE_FILE "<Unknown>"
862 
863 static void
record_jclass(uint64_t class_id,hrtime_t hrt,const char * cname,const char * sname)864 record_jclass (uint64_t class_id, hrtime_t hrt, const char *cname, const char *sname)
865 {
866   size_t clen = ARCH_STRLEN (cname);
867   size_t slen = ARCH_STRLEN (sname);
868   size_t sz = sizeof (ARCH_jclass) + clen + slen;
869   ARCH_jclass *jcls = (ARCH_jclass*) alloca (sz);
870   jcls->comm.tsize = sz;
871   jcls->comm.type = ARCH_JCLASS;
872   jcls->class_id = class_id;
873   jcls->tstamp = hrt;
874   char *str = (char*) (jcls + 1);
875   size_t i = CALL_UTIL (strlcpy)(str, cname, clen);
876   str += i;
877   while (i++ < clen)
878     *str++ = (char) 0; /* pad with 0's */
879   i = CALL_UTIL (strlcpy)(str, sname, slen);
880   str += i;
881   while (i++ < slen)
882     *str++ = (char) 0; /* pad with 0's */
883   collector_interface->writeDataPacket (jprof_hndl, (CM_Packet*) jcls);
884 }
885 
886 static void
record_jmethod(uint64_t class_id,uint64_t method_id,const char * mname,const char * msign)887 record_jmethod (uint64_t class_id, uint64_t method_id,
888 		const char *mname, const char *msign)
889 {
890   size_t mnlen = mname ? ARCH_STRLEN (mname) : 0;
891   size_t mslen = msign ? ARCH_STRLEN (msign) : 0;
892   size_t sz = sizeof (ARCH_jmethod) + mnlen + mslen;
893   ARCH_jmethod *jmth = (ARCH_jmethod*) alloca (sz);
894   if (jmth == NULL)
895     {
896       TprintfT (DBG_LT1, "jprofile: record_jmethod ERROR: failed to alloca(%ld)\n", (long) sz);
897       return;
898     }
899   jmth->comm.tsize = sz;
900   jmth->comm.type = ARCH_JMETHOD;
901   jmth->class_id = class_id;
902   jmth->method_id = method_id;
903   char *str = (char*) (jmth + 1);
904   if (mname)
905     {
906       size_t i = CALL_UTIL (strlcpy)(str, mname, mnlen);
907       str += i;
908       while (i++ < mnlen)
909 	*str++ = (char) 0; /* pad with 0's */
910     }
911   if (msign)
912     {
913       size_t i = CALL_UTIL (strlcpy)(str, msign, mslen);
914       str += i;
915       while (i++ < mslen)
916 	*str++ = (char) 0; /* pad with 0's */
917     }
918   collector_interface->writeDataPacket (jprof_hndl, (CM_Packet*) jmth);
919 }
920 
921 static void
jvmti_ClassPrepare(jvmtiEnv * jvmti_env,JNIEnv * jni_env,jthread thread,jclass klass)922 jvmti_ClassPrepare (jvmtiEnv *jvmti_env, JNIEnv* jni_env,
923 		    jthread thread, jclass klass)
924 {
925   hrtime_t hrt;
926   jint mnum;
927   jmethodID *mptr;
928   char *cname, *sname;
929   char *str1 = NULL;
930   int err = (*jvmti_env)->GetClassSignature (jvmti_env, klass, &str1, NULL);
931   if (err != JVMTI_ERROR_NONE || str1 == NULL || *str1 == (char) 0)
932     cname = NO_CLASS_NAME;
933   else
934     cname = str1;
935   if (*cname != 'L')
936     {
937       DprintfT (SP_DUMP_JAVA | SP_DUMP_TIME, "jvmti_ClassPrepare: GetClassSignature failed. err=%d cname=%s\n", err, cname);
938       return;
939     }
940   char *str2 = NULL;
941   err = (*jvmti_env)->GetSourceFileName (jvmti_env, klass, &str2);
942   if (err != JVMTI_ERROR_NONE || str2 == NULL || *str2 == (char) 0)
943     sname = NO_SOURCE_FILE;
944   else
945     sname = str2;
946   DprintfT (SP_DUMP_JAVA | SP_DUMP_TIME, "jvmti_ClassPrepare: cname=%s sname=%s\n", STR (cname), STR (sname));
947 
948   /* Lock the whole file */
949   __collector_mutex_lock (&jclasses_lock);
950   hrt = gethrtime ();
951   record_jclass ((unsigned long) klass, hrt, cname, sname);
952   (*jvmti_env)->Deallocate (jvmti_env, (unsigned char *) str1);
953   (*jvmti_env)->Deallocate (jvmti_env, (unsigned char *) str2);
954   err = (*jvmti_env)->GetClassMethods (jvmti_env, klass, &mnum, &mptr);
955   if (err == JVMTI_ERROR_NONE)
956     {
957       for (int i = 0; i < mnum; i++)
958 	{
959 	  char *mname, *msign;
960 	  err = (*jvmti_env)->GetMethodName (jvmti_env, mptr[i], &mname, &msign, NULL);
961 	  if (err != JVMTI_ERROR_NONE)
962 	    continue;
963 	  record_jmethod ((unsigned long) klass, (unsigned long) mptr[i], mname, msign);
964 	  // DeleteLocalRef( mptr[i] );
965 	}
966       (*jvmti_env)->Deallocate (jvmti_env, (unsigned char*) mptr);
967     }
968   /* Unlock the file */
969   __collector_mutex_unlock (&jclasses_lock);
970 }
971 
972 /*
973  * The CLASS_LOAD event is enabled to enable AsyncGetCallTrace
974  */
975 static void
jvmti_ClassLoad(jvmtiEnv * jvmti_env,JNIEnv * jni_env,jthread thread,jclass klass)976 jvmti_ClassLoad (jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread, jclass klass)
977 {
978   char *cname;
979   char *str1 = NULL;
980   int err = (*jvmti_env)->GetClassSignature (jvmti_env, klass, &str1, NULL);
981   if (err != JVMTI_ERROR_NONE || str1 == NULL || *str1 == (char) 0)
982     cname = NO_CLASS_NAME;
983   else
984     cname = str1;
985   jstring str = NULL;
986   const char* resourceName;
987   jobject classLoader = NULL;
988   err = (*jvmti)->GetClassLoader (jvmti, klass, &classLoader);
989   DprintfT (SP_DUMP_JAVA | SP_DUMP_TIME, "jprofile: jvmti_ClassLoad err=%d cname=%s\n", err, STR (cname));
990   if (err == 0)
991     {
992       if (classLoader == NULL)
993 	{
994 	  // bootstrap class loader
995 	  resourceName = "";
996 	}
997       else
998 	{
999 	  char* name = (char *) alloca ((CALL_UTIL (strlen)(str1) + 32) * sizeof (char));
1000 	  CALL_UTIL (strlcpy)(name, str1 + 1, CALL_UTIL (strlen)(str1));
1001 	  name[CALL_UTIL (strlen)(name) - 1] = '\0'; // remove the last ';'
1002 	  char* p;
1003 	  for (p = name; *p != '\0'; p++)
1004 	    if (*p == '.')
1005 	      *p = '/';
1006 	  CALL_UTIL (strlcat)(name, ".class", CALL_UTIL (strlen)(name) + CALL_UTIL (strlen)(".class") + 1);
1007 	  if (getResource == NULL || toExternalForm == NULL)
1008 	    {
1009 	      resourceName = "";
1010 	      DprintfT (SP_DUMP_JAVA | SP_DUMP_TIME, "jvmti_ClassLoad: class %s failed to get path with method missing\n", STR (cname));
1011 	    }
1012 	  else
1013 	    {
1014 	      jobject url = (*jni_env)->CallObjectMethod (jni_env, classLoader, getResource, (*jni_env)->NewStringUTF (jni_env, name));
1015 	      if (url == NULL)
1016 		{
1017 		  resourceName = "";
1018 		  DprintfT (SP_DUMP_JAVA | SP_DUMP_TIME, "jvmti_ClassLoad: class %s failed to get path\n", STR (cname));
1019 		}
1020 	      else
1021 		{
1022 		  str = (jstring) (*jni_env)->CallObjectMethod (jni_env, url, toExternalForm);
1023 		  resourceName = (*jni_env)->GetStringUTFChars (jni_env, str, NULL);
1024 		  DprintfT (SP_DUMP_JAVA | SP_DUMP_TIME, "jvmti_ClassLoad: ARCH_JCLASS_LOCATION(Ox%x) class_id=0x%lx  className='%s' fileName '%s'\n",
1025 			    (int) ARCH_JCLASS_LOCATION, (unsigned long) klass, STR (cname), STR (resourceName));
1026 		  size_t clen = ARCH_STRLEN (cname);
1027 		  size_t slen = ARCH_STRLEN (resourceName);
1028 		  size_t sz = sizeof (ARCH_jclass) + clen + slen;
1029 		  ARCH_jclass_location *jcls = (ARCH_jclass_location*) alloca (sz);
1030 		  jcls->comm.tsize = sz;
1031 		  jcls->comm.type = ARCH_JCLASS_LOCATION;
1032 		  jcls->class_id = (unsigned long) klass;
1033 		  char *str = (char*) (jcls + 1);
1034 		  size_t i = CALL_UTIL (strlcpy)(str, cname, clen);
1035 		  str += i;
1036 		  while (i++ < clen)
1037 		    {
1038 		      *str++ = (char) 0; /* pad with 0's */
1039 		    }
1040 		  i = CALL_UTIL (strlcpy)(str, resourceName, slen);
1041 		  str += i;
1042 		  while (i++ < slen)
1043 		    {
1044 		      *str++ = (char) 0; /* pad with 0's */
1045 		    }
1046 		  /* Lock the whole file */
1047 		  __collector_mutex_lock (&jclasses_lock);
1048 		  collector_interface->writeDataPacket (jprof_hndl, (CM_Packet*) jcls);
1049 		  /* Unlock the file */
1050 		  __collector_mutex_unlock (&jclasses_lock);
1051 		}
1052 	    }
1053 	}
1054     }
1055 }
1056 
1057 static void
jvmti_MonitorEnter(jvmtiEnv * jvmti_env,JNIEnv * jni_env,jthread thread,jobject object)1058 jvmti_MonitorEnter (jvmtiEnv *jvmti_env, JNIEnv* jni_env,
1059 		    jthread thread, jobject object)
1060 {
1061   if (collector_jsync_begin)
1062     collector_jsync_begin ();
1063   TSD_Entry *tsd = collector_interface->getKey (tsd_key);
1064   if (tsd == NULL)
1065     return;
1066   tsd->tstamp = gethrtime ();
1067 }
1068 
1069 static void
jvmti_MonitorEntered(jvmtiEnv * jvmti_env,JNIEnv * jni_env,jthread thread,jobject object)1070 jvmti_MonitorEntered (jvmtiEnv *jvmti_env, JNIEnv* jni_env,
1071 		      jthread thread, jobject object)
1072 {
1073   TSD_Entry *tsd = collector_interface->getKey (tsd_key);
1074   if (tsd == NULL)
1075     return;
1076   if (collector_jsync_end)
1077     collector_jsync_end (tsd->tstamp, object);
1078 }
1079 
1080 static void
jvmti_GarbageCollectionStart(jvmtiEnv * jvmti_env)1081 jvmti_GarbageCollectionStart (jvmtiEnv *jvmti_env)
1082 {
1083   hrtime_t hrt = gethrtime ();
1084   collector_interface->writeLog ("<event kind=\"%s\" tstamp=\"%u.%09u\"/>\n",
1085 				 SP_JCMD_GCSTART,
1086 				 (unsigned) (hrt / NANOSEC), (unsigned) (hrt % NANOSEC)
1087 				 );
1088   TprintfT (DBG_LT1, "jprofile: jvmti_GarbageCollectionStart.\n");
1089 }
1090 
1091 static void
jvmti_GarbageCollectionFinish(jvmtiEnv * jvmti_env)1092 jvmti_GarbageCollectionFinish (jvmtiEnv *jvmti_env)
1093 {
1094   hrtime_t hrt = gethrtime ();
1095   collector_interface->writeLog ("<event kind=\"%s\" tstamp=\"%u.%09u\"/>\n",
1096 				 SP_JCMD_GCEND,
1097 				 (unsigned) (hrt / NANOSEC), (unsigned) (hrt % NANOSEC)
1098 				 );
1099   TprintfT (DBG_LT1, "jprofile: jvmti_GarbageCollectionFinish.\n");
1100 }
1101 
1102 #if 0
1103 static void
1104 jvmti_MonitorWait (jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread,
1105 		   jobject object, jlong timed_out)
1106 {
1107   if (collector_sync_begin)
1108     collector_sync_begin ();
1109   TSD_Entry *tsd = collector_interface->getKey (tsd_key);
1110   if (tsd == NULL)
1111     return;
1112   tsd->tstamp = gethrtime ();
1113 }
1114 
1115 static void
1116 jvmti_MonitorWaited (jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread,
1117 		     jobject object, jboolean timed_out)
1118 {
1119   TSD_Entry *tsd = collector_interface->getKey (tsd_key);
1120   if (tsd == NULL)
1121     return;
1122   if (collector_sync_end)
1123     collector_sync_end (tsd->tstamp, object);
1124 }
1125 #endif
1126 
1127 static void
jprof_find_asyncgetcalltrace()1128 jprof_find_asyncgetcalltrace ()
1129 {
1130   void *jvmhandle;
1131   if (__collector_VM_ReadByteInstruction == NULL)
1132     __collector_VM_ReadByteInstruction = (int(*)()) dlsym (RTLD_DEFAULT, "Async_VM_ReadByteInstruction");
1133 
1134   /* look for stack unwind function using default path */
1135   AsyncGetCallTrace = (void (*)(JVMPI_CallTrace*, jint, ucontext_t*))
1136 	  dlsym (RTLD_DEFAULT, "AsyncGetCallTrace");
1137   if (AsyncGetCallTrace != NULL)
1138     {
1139       __collector_java_asyncgetcalltrace_loaded = 1;
1140       TprintfT (DBG_LT1, "jprofile: AsyncGetCallTrace found with RTLD_DEFAULT\n");
1141     }
1142   else
1143     {
1144       /* not found there, find libjvm.so, and ask again */
1145       jvmhandle = dlopen ("libjvm.so", RTLD_LAZY | RTLD_NOLOAD);
1146       if (jvmhandle != NULL)
1147 	{
1148 	  AsyncGetCallTrace = (void (*)(JVMPI_CallTrace*, jint, ucontext_t*))
1149 		  dlsym (jvmhandle, "AsyncGetCallTrace");
1150 	}
1151     }
1152 
1153   if (AsyncGetCallTrace == NULL)
1154     {
1155       /* we could not find it -- write collector error */
1156       TprintfT (0, "jprofile: ERROR -- AsyncGetCallTrace not found in address space\n");
1157       char *err = dlerror ();
1158       collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">%s</event>\n",
1159 				     SP_JCMD_CERROR, COL_ERROR_JVMNOJSTACK, err ? err : "");
1160       __collector_java_mode = 0;
1161     }
1162   else
1163     {
1164       __collector_java_asyncgetcalltrace_loaded = 1;
1165       TprintfT (DBG_LT1, "jprofile: AsyncGetCallTrace initialized in jprof_jvmpi_init_done_event\n");
1166     }
1167 }
1168 
1169 int
__collector_ext_jstack_unwind(char * ptr,int sz,ucontext_t * uc)1170 __collector_ext_jstack_unwind (char *ptr, int sz, ucontext_t *uc)
1171 {
1172   if (AsyncGetCallTrace == NULL)
1173     {
1174       TprintfT (DBG_LT0, "jprofile: __collector_ext_jstack_unwind: AsyncGetCallTrace is NULL\n");
1175       return 0;
1176     }
1177 
1178   TSD_Entry *tsd = collector_interface->getKey (tsd_key);
1179   if (tsd == NULL)
1180     {
1181       TprintfT (DBG_LT3, "jprofile: __collector_ext_jstack_unwind: tsd is NULL\n");
1182       return 0;
1183     }
1184   if (__collector_java_attach && tsd->env == NULL && jvmti != NULL && jvm != NULL)
1185     {
1186       TprintfT (DBG_LT3, "jprofile: __collector_ext_jstack_unwind: tsd->env is NULL under attach\n");
1187       JNIEnv* jni_env = NULL;
1188       (*jvm)->GetEnv (jvm, (void **) &jni_env, JNI_VERSION_1_2);
1189       tsd->env = jni_env;
1190     }
1191   if (tsd->env == NULL)
1192     {
1193       TprintfT (DBG_LT3, "jprofile: __collector_ext_jstack_unwind: tsd->env is NULL\n");
1194       return 0;
1195     }
1196 
1197   /* skip the Java stack whenever another signal handler is present */
1198   if (uc->uc_link)
1199     {
1200       TprintfT (DBG_LT3, "jprofile: __collector_ext_jstack_unwind: uc->uc_link is non-NULL\n");
1201       return 0;
1202     }
1203   /* we don't expect Java frames in signal handlers, so
1204    * unroll the list of saved contexts to the topmost one
1205    */
1206   while (uc->uc_link)
1207     uc = uc->uc_link;
1208   Java_info *jinfo = (Java_info*) ptr;
1209   jinfo->kind = JAVA_INFO;
1210   jinfo->hsize = sizeof (Java_info);
1211   ptr += sizeof (Java_info);
1212   sz -= sizeof (Java_info);
1213 
1214   JVMPI_CallTrace jtrace;
1215   jtrace.env_id = tsd->env;
1216   jtrace.frames = (JVMPI_CallFrame*) ptr;
1217 
1218   /* nframes is how many frames we have room for */
1219   jint nframes = sz / sizeof (JVMPI_CallFrame);
1220 
1221 #if WSIZE(64)
1222   /* bug 6909545: garbage in 64-bit JAVA_INFO */
1223   CALL_UTIL (memset)(jtrace.frames, 0, nframes * sizeof (JVMPI_CallFrame));
1224 #endif
1225 
1226 #if ARCH(SPARC)
1227   // 21328946 JDK bug 8129933 causes <no java callstack recorded> on sparc-Linux
1228   // convert from ucontext_t to sigcontext
1229   struct sigcontext sctx;
1230   sctx.sigc_regs.tpc = uc->uc_mcontext.mc_gregs[MC_PC];
1231   __collector_memcpy (sctx.sigc_regs.u_regs, &uc->uc_mcontext.mc_gregs[3], sizeof (sctx.sigc_regs.u_regs));
1232   uc = (ucontext_t *) (&sctx);
1233 #endif /* SPARC */
1234   AsyncGetCallTrace (&jtrace, nframes, uc);
1235 
1236   if (jtrace.num_frames == nframes)
1237     {
1238       JVMPI_CallFrame *last = &jtrace.frames[nframes - 1];
1239       last->method_id = (jmethodID) SP_TRUNC_STACK_MARKER;
1240       last->lineno = 0;
1241     }
1242 
1243   /* nframes is how many frames we actually got */
1244   nframes = jtrace.num_frames;
1245   TprintfT (DBG_LT3, "jprofile: __collector_ext_jstack_unwind: AsyncGetCallTrace jtrace.numframes = %d\n", nframes);
1246   if (nframes <= 0)
1247     {
1248       /* negative values are error codes */
1249       TprintfT (0, "jprofile: __collector_ext_jstack_unwind: AsyncGetCallTrace returned error: jtrace.numframes = %d\n", nframes);
1250       nframes = 1;
1251       JVMPI_CallFrame *err = (JVMPI_CallFrame*) ptr;
1252       err->lineno = jtrace.num_frames; // bci = error code
1253       err->method_id = 0; // artificial method id
1254     }
1255   jinfo->hsize += nframes * sizeof (JVMPI_CallFrame);
1256   return jinfo->hsize;
1257 }
1258 
1259 /*
1260  *	Collector Java API implementation
1261  */
1262 void
Java_com_sun_forte_st_collector_CollectorAPI__1sample(JNIEnv * jEnv,jclass jCls,jstring jName)1263 Java_com_sun_forte_st_collector_CollectorAPI__1sample(JNIEnv *jEnv, jclass jCls, jstring jName)
1264 {
1265   JNIEnv *jni;
1266   jint res = (*jvm)->GetEnv (jvm, (void **) &jni, JNI_VERSION_1_2);
1267   if (res < 0)
1268     return;
1269   const char *name = jName ? (*jni)->GetStringUTFChars (jni, jName, NULL) : NULL;
1270   __collector_sample ((char*) name);
1271 }
1272 
1273 void
Java_com_sun_forte_st_collector_CollectorAPI__1pause(JNIEnv * jEnv,jclass jCls)1274 Java_com_sun_forte_st_collector_CollectorAPI__1pause(JNIEnv *jEnv, jclass jCls)
1275 {
1276   __collector_pause_m ("JAPI");
1277 }
1278 
1279 void
Java_com_sun_forte_st_collector_CollectorAPI__1resume(JNIEnv * jEnv,jclass jCls)1280 Java_com_sun_forte_st_collector_CollectorAPI__1resume(JNIEnv *jEnv, jclass jCls)
1281 {
1282   __collector_resume ();
1283 }
1284 
1285 void
Java_com_sun_forte_st_collector_CollectorAPI__1terminate(JNIEnv * jEnv,jclass jCls)1286 Java_com_sun_forte_st_collector_CollectorAPI__1terminate(JNIEnv *jEnv, jclass jCls)
1287 {
1288   __collector_terminate_expt ();
1289 }
1290 #endif /* GPROFNG_JAVA_PROFILING */
1291 
1292 static void init_module () __attribute__ ((constructor));
1293 static void
init_module()1294 init_module ()
1295 {
1296 #if defined(GPROFNG_JAVA_PROFILING)
1297   __collector_dlsym_guard = 1;
1298   RegModuleFunc reg_module = (RegModuleFunc) dlsym (RTLD_DEFAULT, "__collector_register_module");
1299   __collector_dlsym_guard = 0;
1300   if (reg_module)
1301     {
1302       jprof_hndl = reg_module (&module_interface);
1303       TprintfT (0, "jprofile: init_module.\n");
1304     }
1305 #endif /* GPROFNG_JAVA_PROFILING */
1306 }
1307 
1308 int __collector_java_mode = 0;
1309 int __collector_java_asyncgetcalltrace_loaded = 0;
1310