1 /* Copyright (C) 2021-2023 Free Software Foundation, Inc.
4 This file is part of GNU Binutils.
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)
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.
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. */
23 #if defined(GPROFNG_JAVA_PROFILING)
25 #include <dlfcn.h> /* dlsym() */
30 #include <sys/param.h> /* MAXPATHLEN */
36 #include "collector.h"
37 #include "gp-experiment.h"
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
46 /* ARCH_STRLEN is defined in dbe, copied here */
47 #define ARCH_STRLEN(s) ((CALL_UTIL(strlen)(s) + 4 ) & ~0x3)
52 jint lineno
; /* line number in the source file */
53 jmethodID method_id
; /* method executed in this frame */
59 JNIEnv
*env_id
; /* Env where trace was recorded */
60 jint num_frames
; /* number of frames in this trace */
61 JVMPI_CallFrame
*frames
; /* frames */
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
;
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) */
83 static CollectorInterface
*collector_interface
= NULL
;
84 static CollectorModule jprof_hndl
= COLLECTOR_MODULE_ERR
;
85 static int __collector_java_attach
= 0;
87 static jmethodID getResource
= NULL
;
88 static jmethodID toExternalForm
= NULL
;
90 /* Java profiling thread specific data */
91 typedef struct TSD_Entry
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
;
111 #define gethrtime collector_interface->getHiResTime
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
);
132 static void jvmti_MonitorWait (jvmtiEnv
*, JNIEnv
*, jthread
, jobject
, jlong
);
133 static void jvmti_MonitorWaited (jvmtiEnv
*, JNIEnv
*, jthread
, jobject
, jboolean
);
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
*);
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;
180 typedef jint (JNICALL JNI_GetCreatedJavaVMs_t
)(JavaVM
**, jsize
, jsize
*);
183 init_interface (CollectorInterface
*_collector_interface
)
185 collector_interface
= _collector_interface
;
186 return COL_ERROR_NONE
;
190 open_experiment (const char *exp
)
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
;
199 if (__collector_strStartWith (args
, "j:") == 0)
204 args
= CALL_UTIL (strchr
)(args
, ';');
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)
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
;
219 Tprintf (DBG_LT2
, "jprofile: TSD key create succeeded %d.\n", tsd_key
);
224 if (__collector_strStartWith (args
, "H:") == 0)
227 collector_heap_record
= (void(*)(int, int, void*))dlsym (RTLD_DEFAULT
, "__collector_heap_record");
230 else if (__collector_strStartWith (args
, "s:") == 0)
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");
237 args
= CALL_UTIL (strchr
)(args
, ';');
242 /* synchronization tracing is enabled by the synctrace module, later in initialization */
243 __collector_java_mode
= 1;
245 return COL_ERROR_NONE
;
248 /* routine called from the syntrace module to enable Java-API synctrace */
250 __collector_jprofile_enable_synctrace ()
252 if (__collector_java_mode
== 0)
254 TprintfT (DBG_LT1
, "jprofile: not turning on Java synctrace; Java mode not enabled\n");
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");
264 __collector_jprofile_start_attach (void)
266 if (!__collector_java_mode
|| __collector_java_asyncgetcalltrace_loaded
)
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
)
274 TprintfT (0, "jprofile attach: pfnGetCreatedJavaVMs is detected.\n");
275 JavaVM
* vmBuf
[1]; // XXXX only detect on jvm
277 (*pfnGetCreatedJavaVMs
)(vmBuf
, 1, &nVMs
);
278 if (vmBuf
[0] != NULL
&& nVMs
> 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
)
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
);
300 close_experiment (void)
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;
311 __collector_mutex_init (&jclasses_lock
);
312 tsd_key
= COLLECTOR_TSD_INVALID_KEY
;
313 TprintfT (0, "jprofile: experiment closed.\n");
318 detach_experiment (void)
319 /* fork child. Clean up state but don't write to experiment */
321 __collector_java_mode
= 0;
329 __collector_mutex_init (&jclasses_lock
);
330 tsd_key
= COLLECTOR_TSD_INVALID_KEY
;
331 TprintfT (0, "jprofile: detached from experiment.\n");
335 JNIEXPORT jint JNICALL
336 JVM_OnLoad (JavaVM
*vm
, char *options
, void *reserved
)
340 if (!__collector_java_mode
)
342 TprintfT (DBG_LT1
, "jprofile: JVM_OnLoad invoked with java mode disabled\n");
346 TprintfT (DBG_LT1
, "jprofile: JVM_OnLoad invoked\n");
349 if ((*jvm
)->GetEnv (jvm
, (void **) &jvmti
, JVMTI_VERSION_1_0
) >= 0 && jvmti
)
351 TprintfT (DBG_LT1
, "jprofile: JVMTI found\n");
356 collector_interface
->writeLog ("<event kind=\"%s\" id=\"%d\"/>\n",
357 SP_JCMD_CERROR
, COL_ERROR_JVMNOTSUPP
);
362 Tprintf (DBG_LT0
, "\tjprofile: Initializing for JVMTI\n");
363 apistr
= "JVMTI 1.0";
366 jvmtiCapabilities cpblts
;
367 err
= (*jvmti
)->GetPotentialCapabilities (jvmti
, &cpblts
);
368 if (err
== JVMTI_ERROR_NONE
)
370 jvmtiCapabilities cpblts_set
;
371 CALL_UTIL (memset
)(&cpblts_set
, 0, sizeof (cpblts_set
));
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
);
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
);
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
);
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
);
390 err
= (*jvmti
)->AddCapabilities (jvmti
, &cpblts_set
);
391 Tprintf (DBG_LT1
, "\tjprofile: AddCapabilities() returns: %d\n", err
);
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
);
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
);
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
);
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 );
423 Tprintf (DBG_LT0
, "\tjprofile: JVMTI initialized\n");
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
432 err
= (*jvmti
)->GenerateEvents (jvmti
, JVMTI_EVENT_DYNAMIC_CODE_GENERATED
);
433 err
= (*jvmti
)->GenerateEvents (jvmti
, JVMTI_EVENT_COMPILED_METHOD_LOAD
);
435 Tprintf (DBG_LT1
, "\tjprofile: JVM_OnLoad ok\n");
439 /* This is currently just a placeholder */
440 JNIEXPORT jint JNICALL
441 Agent_OnLoad (JavaVM
*vm
, char *options
, void *reserved
)
443 return JVM_OnLoad (vm
, options
, reserved
);
447 rwrite (int fd
, const void *buf
, size_t nbyte
)
451 char *ptr
= (char*) buf
;
454 res
= CALL_UTIL (write
)(fd
, ptr
, left
);
457 /* XXX: we can't write this record, we probably
458 * can't write anything else. Ignore.
477 res
= (*jvm
)->GetEnv (jvm
, (void **) &jni
, JNI_VERSION_1_2
);
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.
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
;
492 collector_interface
->writeLog ("<setting %s=\"%s\"/>\n", SP_JCMD_SRCHPATH
, str
);
493 (*jni
)->ReleaseStringUTFChars (jni
, jstrout
, str
);
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
;
500 collector_interface
->writeLog ("<setting %s=\"%s\"/>\n", SP_JCMD_SRCHPATH
, str
);
501 (*jni
)->ReleaseStringUTFChars (jni
, jstrout
, str
);
503 jstrin
= (*jni
)->NewStringUTF (jni
, "java.home");
504 jstrout
= (*jni
)->CallStaticObjectMethod (jni
, jcls
, jmid
, jstrin
);
505 str
= jstrout
? (*jni
)->GetStringUTFChars (jni
, jstrout
, NULL
) : NULL
;
508 collector_interface
->writeLog ("<setting %s=\"%s/../src.zip\"/>\n", SP_JCMD_SRCHPATH
, str
);
509 (*jni
)->ReleaseStringUTFChars (jni
, jstrout
, str
);
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
;
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)
520 (void) collector_interface
->writeLog ("<event kind=\"%s\" id=\"%d\"/>\n",
521 SP_JCMD_CWARN
, COL_WARN_OLDJAVA
);
523 (*jni
)->ReleaseStringUTFChars (jni
, jstrout
, str
);
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)
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
);
545 jvmti_VMInit (jvmtiEnv
*jvmti_env
, JNIEnv
* jni_env
, jthread thread
)
547 jint class_count
= 0;
548 jclass
*classes
= NULL
;
550 TprintfT (DBG_LT1
, "jprofile: jvmti_VMInit called\n");
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
++)
559 jvmti_ClassPrepare (jvmti_env
, jni_env
, NULL
, classes
[i
]);
561 // DeleteLocalRef( classes[i] );
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;");
567 /* find the stack unwind routine */
568 jprof_find_asyncgetcalltrace ();
572 jvmti_VMDeath (jvmtiEnv
*jvmti_env
, JNIEnv
* jni_env
)
574 __collector_java_mode
= 0;
575 TprintfT (DBG_LT1
, "jprofile: jvmti_VMDeath event received\n");
579 jvmti_ThreadStart (jvmtiEnv
*jvmti_env
, JNIEnv
* jni_env
, jthread thread
)
582 jvmtiThreadInfo t_info
;
583 char *thread_name
, *group_name
, *parent_name
;
585 collector_thread_t tid
;
586 thread_name
= group_name
= parent_name
= NULL
;
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
)
594 jvmtiThreadGroupInfo g_info
;
595 thread_name
= t_info
.name
;
596 if (t_info
.thread_group
)
598 err
= (*jvmti_env
)->GetThreadGroupInfo (jvmti_env
, t_info
.thread_group
, &g_info
);
599 if (err
== JVMTI_ERROR_NONE
)
601 group_name
= g_info
.name
;
604 jvmtiThreadGroupInfo p_info
;
605 err
= (*jvmti_env
)->GetThreadGroupInfo (jvmti_env
, g_info
.parent
, &p_info
);
606 if (err
== JVMTI_ERROR_NONE
)
608 parent_name
= p_info
.name
;
609 // DeleteLocalRef( p_info.parent );
611 // DeleteLocalRef( g_info.parent );
615 // DeleteLocalRef( t_info.thread_group );
616 // DeleteLocalRef( t_info.context_class_loader );
618 if (thread_name
== NULL
)
620 if (group_name
== NULL
)
622 if (parent_name
== NULL
)
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",
626 (unsigned) (hrt
/ NANOSEC
), (unsigned) (hrt
% NANOSEC
),
634 TSD_Entry
*tsd
= collector_interface
->getKey (tsd_key
);
640 jvmti_ThreadEnd (jvmtiEnv
*jvmti_env
, JNIEnv
* jni_env
, jthread thread
)
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
);
647 collector_interface
->writeLog ("<event kind=\"%s\" tstamp=\"%u.%09u\" tid=\"%lu\" jthr=\"0x%lx\" jenv=\"0x%lx\"/>\n",
649 (unsigned) (hrt
/ NANOSEC
), (unsigned) (hrt
% NANOSEC
),
654 TSD_Entry
*tsd
= collector_interface
->getKey (tsd_key
);
659 /* The following definitions are borrowed from file jvmticmlr.h, part of jdk7 */
662 JVMTI_CMLR_DUMMY
= 1,
663 JVMTI_CMLR_INLINE_INFO
= 2
667 * Record that represents arbitrary information passed through JVMTI
668 * CompiledMethodLoadEvent void pointer.
670 typedef struct _jvmtiCompiledMethodLoadRecordHeader
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
;
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.
683 typedef struct _PCStackInfo
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 */
692 * Record that contains inlining information for each pc address of
695 typedef struct _jvmtiCompiledMethodLoadInlineRecord
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
;
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
)
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
);
711 CALL_UTIL (snprintf
)(name
, sizeof (name
), "0x%lx", (unsigned long) method
);
713 /* Parse compile_info to get pc -> bci mapping.
714 * Don't interpret compile_info from JVMs other than HotSpot.
717 DT_lineno
*lntable
= NULL
;
718 if (compile_info
!= NULL
&& is_hotspot_vm
)
720 Tprintf (DBG_LT2
, "Mapping from compile_info:\n");
721 jvmtiCompiledMethodLoadRecordHeader
*currec
=
722 (jvmtiCompiledMethodLoadRecordHeader
*) compile_info
;
723 while (currec
!= NULL
)
725 if (currec
->kind
== JVMTI_CMLR_INLINE_INFO
)
727 jvmtiCompiledMethodLoadInlineRecord
*inrec
=
728 (jvmtiCompiledMethodLoadInlineRecord
*) currec
;
729 if (inrec
->numpcs
<= 0)
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
)
737 for (int j
= pcrec
->numstackframes
- 1; j
>= 0; --j
)
738 if (pcrec
->methods
[j
] == method
)
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
);
751 currec
= currec
->next
;
754 else if (map
!= NULL
)
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
)
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
);
769 __collector_int_func_load (DFUNC_JAVA
, name
, NULL
, (void*) code_addr
,
770 code_size
, lntsize
, lntable
);
774 jvmti_CompiledMethodUnload (jvmtiEnv
*jvmti_env
, jmethodID method
, const void* code_addr
)
776 __collector_int_func_unload (DFUNC_API
, (void*) code_addr
);
780 jvmti_DynamicCodeGenerated (jvmtiEnv
*jvmti_env
, const char*name
, const void *code_addr
, jint code_size
)
782 __collector_int_func_load (DFUNC_API
, (char*) name
, NULL
, (void*) code_addr
,
787 addToDynamicArchive (const char* name
, const unsigned char* class_data
, int class_data_len
)
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
;
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
))
799 CALL_UTIL (snprintf
)(path
, sizeof (path
), "%s/%s/%s.class", expdir
, SP_DYNAMIC_CLASSES
, name
);
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
);
806 if (CALL_UTIL (mkdir
)(path
, dmode
) != 0)
808 /* Checking for EEXIST is not enough, access() is more reliable */
809 if (CALL_UTIL (access
)(path
, F_OK
) != 0)
811 collector_interface
->writeLog ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">%s</event>\n",
812 SP_JCMD_CERROR
, COL_ERROR_MKDIR
, errno
, path
);
817 str
= CALL_UTIL (strchr
)(str
, '/');
820 int fd
= CALL_UTIL (open
)(path
, O_WRONLY
| O_CREAT
| O_TRUNC
, fmode
);
823 collector_interface
->writeLog ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">%s</event>\n",
824 SP_JCMD_CERROR
, COL_ERROR_OVWOPEN
, errno
, path
);
827 rwrite (fd
, class_data
, class_data_len
);
828 CALL_UTIL (close
)(fd
);
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
)
838 jvmtiPhase phase_ptr
;
840 (*jvmti_env
)->GetPhase (jvmti_env
, &phase_ptr
);
842 /* skip non live phases */
843 if (phase_ptr
!= JVMTI_PHASE_LIVE
)
846 /* skip system class loaders */
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)
854 /* skip classes loaded with AppClassLoader (java.class.path) */
855 if (__collector_strcmp (cname
, "Lsun/misc/Launcher$AppClassLoader;") == 0)
857 addToDynamicArchive (name
, class_data
, (int) class_data_len
);
860 #define NO_CLASS_NAME "<noname>"
861 #define NO_SOURCE_FILE "<Unknown>"
864 record_jclass (uint64_t class_id
, hrtime_t hrt
, const char *cname
, const char *sname
)
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
;
874 char *str
= (char*) (jcls
+ 1);
875 size_t i
= CALL_UTIL (strlcpy
)(str
, cname
, clen
);
878 *str
++ = (char) 0; /* pad with 0's */
879 i
= CALL_UTIL (strlcpy
)(str
, sname
, slen
);
882 *str
++ = (char) 0; /* pad with 0's */
883 collector_interface
->writeDataPacket (jprof_hndl
, (CM_Packet
*) jcls
);
887 record_jmethod (uint64_t class_id
, uint64_t method_id
,
888 const char *mname
, const char *msign
)
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
);
896 TprintfT (DBG_LT1
, "jprofile: record_jmethod ERROR: failed to alloca(%ld)\n", (long) sz
);
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);
906 size_t i
= CALL_UTIL (strlcpy
)(str
, mname
, mnlen
);
909 *str
++ = (char) 0; /* pad with 0's */
913 size_t i
= CALL_UTIL (strlcpy
)(str
, msign
, mslen
);
916 *str
++ = (char) 0; /* pad with 0's */
918 collector_interface
->writeDataPacket (jprof_hndl
, (CM_Packet
*) jmth
);
922 jvmti_ClassPrepare (jvmtiEnv
*jvmti_env
, JNIEnv
* jni_env
,
923 jthread thread
, jclass klass
)
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
;
937 DprintfT (SP_DUMP_JAVA
| SP_DUMP_TIME
, "jvmti_ClassPrepare: GetClassSignature failed. err=%d cname=%s\n", err
, cname
);
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
;
946 DprintfT (SP_DUMP_JAVA
| SP_DUMP_TIME
, "jvmti_ClassPrepare: cname=%s sname=%s\n", STR (cname
), STR (sname
));
948 /* Lock the whole file */
949 __collector_mutex_lock (&jclasses_lock
);
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
)
957 for (int i
= 0; i
< mnum
; i
++)
960 err
= (*jvmti_env
)->GetMethodName (jvmti_env
, mptr
[i
], &mname
, &msign
, NULL
);
961 if (err
!= JVMTI_ERROR_NONE
)
963 record_jmethod ((unsigned long) klass
, (unsigned long) mptr
[i
], mname
, msign
);
964 // DeleteLocalRef( mptr[i] );
966 (*jvmti_env
)->Deallocate (jvmti_env
, (unsigned char*) mptr
);
968 /* Unlock the file */
969 __collector_mutex_unlock (&jclasses_lock
);
973 * The CLASS_LOAD event is enabled to enable AsyncGetCallTrace
976 jvmti_ClassLoad (jvmtiEnv
*jvmti_env
, JNIEnv
* jni_env
, jthread thread
, jclass klass
)
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
;
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
));
992 if (classLoader
== NULL
)
994 // bootstrap class loader
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 ';'
1003 for (p
= name
; *p
!= '\0'; p
++)
1006 CALL_UTIL (strlcat
)(name
, ".class", CALL_UTIL (strlen
)(name
) + CALL_UTIL (strlen
)(".class") + 1);
1007 if (getResource
== NULL
|| toExternalForm
== NULL
)
1010 DprintfT (SP_DUMP_JAVA
| SP_DUMP_TIME
, "jvmti_ClassLoad: class %s failed to get path with method missing\n", STR (cname
));
1014 jobject url
= (*jni_env
)->CallObjectMethod (jni_env
, classLoader
, getResource
, (*jni_env
)->NewStringUTF (jni_env
, name
));
1018 DprintfT (SP_DUMP_JAVA
| SP_DUMP_TIME
, "jvmti_ClassLoad: class %s failed to get path\n", STR (cname
));
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
);
1038 *str
++ = (char) 0; /* pad with 0's */
1040 i
= CALL_UTIL (strlcpy
)(str
, resourceName
, slen
);
1044 *str
++ = (char) 0; /* pad with 0's */
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
);
1058 jvmti_MonitorEnter (jvmtiEnv
*jvmti_env
, JNIEnv
* jni_env
,
1059 jthread thread
, jobject object
)
1061 if (collector_jsync_begin
)
1062 collector_jsync_begin ();
1063 TSD_Entry
*tsd
= collector_interface
->getKey (tsd_key
);
1066 tsd
->tstamp
= gethrtime ();
1070 jvmti_MonitorEntered (jvmtiEnv
*jvmti_env
, JNIEnv
* jni_env
,
1071 jthread thread
, jobject object
)
1073 TSD_Entry
*tsd
= collector_interface
->getKey (tsd_key
);
1076 if (collector_jsync_end
)
1077 collector_jsync_end (tsd
->tstamp
, object
);
1081 jvmti_GarbageCollectionStart (jvmtiEnv
*jvmti_env
)
1083 hrtime_t hrt
= gethrtime ();
1084 collector_interface
->writeLog ("<event kind=\"%s\" tstamp=\"%u.%09u\"/>\n",
1086 (unsigned) (hrt
/ NANOSEC
), (unsigned) (hrt
% NANOSEC
)
1088 TprintfT (DBG_LT1
, "jprofile: jvmti_GarbageCollectionStart.\n");
1092 jvmti_GarbageCollectionFinish (jvmtiEnv
*jvmti_env
)
1094 hrtime_t hrt
= gethrtime ();
1095 collector_interface
->writeLog ("<event kind=\"%s\" tstamp=\"%u.%09u\"/>\n",
1097 (unsigned) (hrt
/ NANOSEC
), (unsigned) (hrt
% NANOSEC
)
1099 TprintfT (DBG_LT1
, "jprofile: jvmti_GarbageCollectionFinish.\n");
1104 jvmti_MonitorWait (jvmtiEnv
*jvmti_env
, JNIEnv
* jni_env
, jthread thread
,
1105 jobject object
, jlong timed_out
)
1107 if (collector_sync_begin
)
1108 collector_sync_begin ();
1109 TSD_Entry
*tsd
= collector_interface
->getKey (tsd_key
);
1112 tsd
->tstamp
= gethrtime ();
1116 jvmti_MonitorWaited (jvmtiEnv
*jvmti_env
, JNIEnv
* jni_env
, jthread thread
,
1117 jobject object
, jboolean timed_out
)
1119 TSD_Entry
*tsd
= collector_interface
->getKey (tsd_key
);
1122 if (collector_sync_end
)
1123 collector_sync_end (tsd
->tstamp
, object
);
1128 jprof_find_asyncgetcalltrace ()
1131 if (__collector_VM_ReadByteInstruction
== NULL
)
1132 __collector_VM_ReadByteInstruction
= (int(*)()) dlsym (RTLD_DEFAULT
, "Async_VM_ReadByteInstruction");
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
)
1139 __collector_java_asyncgetcalltrace_loaded
= 1;
1140 TprintfT (DBG_LT1
, "jprofile: AsyncGetCallTrace found with RTLD_DEFAULT\n");
1144 /* not found there, find libjvm.so, and ask again */
1145 jvmhandle
= dlopen ("libjvm.so", RTLD_LAZY
| RTLD_NOLOAD
);
1146 if (jvmhandle
!= NULL
)
1148 AsyncGetCallTrace
= (void (*)(JVMPI_CallTrace
*, jint
, ucontext_t
*))
1149 dlsym (jvmhandle
, "AsyncGetCallTrace");
1153 if (AsyncGetCallTrace
== NULL
)
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;
1164 __collector_java_asyncgetcalltrace_loaded
= 1;
1165 TprintfT (DBG_LT1
, "jprofile: AsyncGetCallTrace initialized in jprof_jvmpi_init_done_event\n");
1170 __collector_ext_jstack_unwind (char *ptr
, int sz
, ucontext_t
*uc
)
1172 if (AsyncGetCallTrace
== NULL
)
1174 TprintfT (DBG_LT0
, "jprofile: __collector_ext_jstack_unwind: AsyncGetCallTrace is NULL\n");
1178 TSD_Entry
*tsd
= collector_interface
->getKey (tsd_key
);
1181 TprintfT (DBG_LT3
, "jprofile: __collector_ext_jstack_unwind: tsd is NULL\n");
1184 if (__collector_java_attach
&& tsd
->env
== NULL
&& jvmti
!= NULL
&& jvm
!= NULL
)
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
);
1191 if (tsd
->env
== NULL
)
1193 TprintfT (DBG_LT3
, "jprofile: __collector_ext_jstack_unwind: tsd->env is NULL\n");
1197 /* skip the Java stack whenever another signal handler is present */
1200 TprintfT (DBG_LT3
, "jprofile: __collector_ext_jstack_unwind: uc->uc_link is non-NULL\n");
1203 /* we don't expect Java frames in signal handlers, so
1204 * unroll the list of saved contexts to the topmost one
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
);
1214 JVMPI_CallTrace jtrace
;
1215 jtrace
.env_id
= tsd
->env
;
1216 jtrace
.frames
= (JVMPI_CallFrame
*) ptr
;
1218 /* nframes is how many frames we have room for */
1219 jint nframes
= sz
/ sizeof (JVMPI_CallFrame
);
1222 /* bug 6909545: garbage in 64-bit JAVA_INFO */
1223 CALL_UTIL (memset
)(jtrace
.frames
, 0, nframes
* sizeof (JVMPI_CallFrame
));
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
);
1234 AsyncGetCallTrace (&jtrace
, nframes
, uc
);
1236 if (jtrace
.num_frames
== nframes
)
1238 JVMPI_CallFrame
*last
= &jtrace
.frames
[nframes
- 1];
1239 last
->method_id
= (jmethodID
) SP_TRUNC_STACK_MARKER
;
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
);
1248 /* negative values are error codes */
1249 TprintfT (0, "jprofile: __collector_ext_jstack_unwind: AsyncGetCallTrace returned error: jtrace.numframes = %d\n", nframes
);
1251 JVMPI_CallFrame
*err
= (JVMPI_CallFrame
*) ptr
;
1252 err
->lineno
= jtrace
.num_frames
; // bci = error code
1253 err
->method_id
= 0; // artificial method id
1255 jinfo
->hsize
+= nframes
* sizeof (JVMPI_CallFrame
);
1256 return jinfo
->hsize
;
1260 * Collector Java API implementation
1263 Java_com_sun_forte_st_collector_CollectorAPI__1sample(JNIEnv
*jEnv
, jclass jCls
, jstring jName
)
1266 jint res
= (*jvm
)->GetEnv (jvm
, (void **) &jni
, JNI_VERSION_1_2
);
1269 const char *name
= jName
? (*jni
)->GetStringUTFChars (jni
, jName
, NULL
) : NULL
;
1270 __collector_sample ((char*) name
);
1274 Java_com_sun_forte_st_collector_CollectorAPI__1pause(JNIEnv
*jEnv
, jclass jCls
)
1276 __collector_pause_m ("JAPI");
1280 Java_com_sun_forte_st_collector_CollectorAPI__1resume(JNIEnv
*jEnv
, jclass jCls
)
1282 __collector_resume ();
1286 Java_com_sun_forte_st_collector_CollectorAPI__1terminate(JNIEnv
*jEnv
, jclass jCls
)
1288 __collector_terminate_expt ();
1290 #endif /* GPROFNG_JAVA_PROFILING */
1292 static void init_module () __attribute__ ((constructor
));
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;
1302 jprof_hndl
= reg_module (&module_interface
);
1303 TprintfT (0, "jprofile: init_module.\n");
1305 #endif /* GPROFNG_JAVA_PROFILING */
1308 int __collector_java_mode
= 0;
1309 int __collector_java_asyncgetcalltrace_loaded
= 0;