]> Git Repo - binutils.git/blob - gprofng/libcollector/jprofile.c
Automatic date update in version.in
[binutils.git] / gprofng / libcollector / jprofile.c
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
183 init_interface (CollectorInterface *_collector_interface)
184 {
185   collector_interface = _collector_interface;
186   return COL_ERROR_NONE;
187 }
188
189 static int
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
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
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
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
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
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
441 Agent_OnLoad (JavaVM *vm, char *options, void *reserved)
442 {
443   return JVM_OnLoad (vm, options, reserved);
444 }
445
446 static void
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
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
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
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
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                                  thread,
632                                  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
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                                  thread,
652                                  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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
1274 Java_com_sun_forte_st_collector_CollectorAPI__1pause(JNIEnv *jEnv, jclass jCls)
1275 {
1276   __collector_pause_m ("JAPI");
1277 }
1278
1279 void
1280 Java_com_sun_forte_st_collector_CollectorAPI__1resume(JNIEnv *jEnv, jclass jCls)
1281 {
1282   __collector_resume ();
1283 }
1284
1285 void
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
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;
This page took 0.097689 seconds and 4 git commands to generate.