1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315 |
- /* Copyright (C) 2021 Free Software Foundation, Inc.
- Contributed by Oracle.
- This file is part of GNU Binutils.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3, or (at your option)
- any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, 51 Franklin Street - Fifth Floor, Boston,
- MA 02110-1301, USA. */
- #include "config.h"
- #if defined(GPROFNG_JAVA_PROFILING)
- #include <alloca.h>
- #include <dlfcn.h> /* dlsym() */
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <unistd.h>
- #include <errno.h>
- #include <sys/param.h> /* MAXPATHLEN */
- #include <jni.h>
- #include <jvmti.h>
- #include "gp-defs.h"
- #include "collector.h"
- #include "gp-experiment.h"
- #include "tsd.h"
- /* TprintfT(<level>,...) definitions. Adjust per module as needed */
- #define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings
- #define DBG_LT1 1 // for configuration details, warnings
- #define DBG_LT2 2
- #define DBG_LT3 3
- /* ARCH_STRLEN is defined in dbe, copied here */
- #define ARCH_STRLEN(s) ((CALL_UTIL(strlen)(s) + 4 ) & ~0x3)
- /* call frame */
- typedef struct
- {
- jint lineno; /* line number in the source file */
- jmethodID method_id; /* method executed in this frame */
- } JVMPI_CallFrame;
- /* call trace */
- typedef struct
- {
- JNIEnv *env_id; /* Env where trace was recorded */
- jint num_frames; /* number of frames in this trace */
- JVMPI_CallFrame *frames; /* frames */
- } JVMPI_CallTrace;
- extern void __collector_jprofile_enable_synctrace (void);
- int __collector_jprofile_start_attach (void);
- static int init_interface (CollectorInterface*);
- static int open_experiment (const char *);
- static int close_experiment (void);
- static int detach_experiment (void);
- static void jprof_find_asyncgetcalltrace (void);
- static char *apistr = NULL;
- static ModuleInterface module_interface = {
- "*"SP_JCLASSES_FILE, /* description, exempt from limit */
- init_interface, /* initInterface */
- open_experiment, /* openExperiment */
- NULL, /* startDataCollection */
- NULL, /* stopDataCollection */
- close_experiment, /* closeExperiment */
- detach_experiment /* detachExperiment (fork child) */
- };
- static CollectorInterface *collector_interface = NULL;
- static CollectorModule jprof_hndl = COLLECTOR_MODULE_ERR;
- static int __collector_java_attach = 0;
- static JavaVM *jvm;
- static jmethodID getResource = NULL;
- static jmethodID toExternalForm = NULL;
- /* Java profiling thread specific data */
- typedef struct TSD_Entry
- {
- JNIEnv *env;
- hrtime_t tstamp;
- } TSD_Entry;
- static unsigned tsd_key = COLLECTOR_TSD_INVALID_KEY;
- static collector_mutex_t jclasses_lock = COLLECTOR_MUTEX_INITIALIZER;
- static int java_gc_on = 0;
- static int java_mem_mode = 0;
- static int java_sync_mode = 0;
- static int is_hotspot_vm = 0;
- static void get_jvm_settings ();
- static void rwrite (int fd, const void *buf, size_t nbyte);
- static void addToDynamicArchive (const char* name, const unsigned char* class_data, int class_data_len);
- static void (*AsyncGetCallTrace)(JVMPI_CallTrace*, jint, ucontext_t*) = NULL;
- static void (*collector_heap_record)(int, int, void*) = NULL;
- static void (*collector_jsync_begin)() = NULL;
- static void (*collector_jsync_end)(hrtime_t, void *) = NULL;
- #define gethrtime collector_interface->getHiResTime
- /*
- * JVMTI declarations
- */
- static jvmtiEnv *jvmti;
- static void jvmti_VMInit (jvmtiEnv*, JNIEnv*, jthread);
- static void jvmti_VMDeath (jvmtiEnv*, JNIEnv*);
- static void jvmti_ThreadStart (jvmtiEnv*, JNIEnv*, jthread);
- static void jvmti_ThreadEnd (jvmtiEnv*, JNIEnv*, jthread);
- static void jvmti_CompiledMethodLoad (jvmtiEnv*, jmethodID, jint, const void*,
- jint, const jvmtiAddrLocationMap*, const void*);
- static void jvmti_CompiledMethodUnload (jvmtiEnv*, jmethodID, const void*);
- static void jvmti_DynamicCodeGenerated (jvmtiEnv*, const char*, const void*, jint);
- static void jvmti_ClassPrepare (jvmtiEnv*, JNIEnv*, jthread, jclass);
- static void jvmti_ClassLoad (jvmtiEnv*, JNIEnv*, jthread, jclass);
- //static void jvmti_ClassUnload( jvmtiEnv*, JNIEnv*, jthread, jclass );
- static void jvmti_MonitorEnter (jvmtiEnv *, JNIEnv*, jthread, jobject);
- static void jvmti_MonitorEntered (jvmtiEnv *, JNIEnv*, jthread, jobject);
- #if 0
- static void jvmti_MonitorWait (jvmtiEnv *, JNIEnv*, jthread, jobject, jlong);
- static void jvmti_MonitorWaited (jvmtiEnv *, JNIEnv*, jthread, jobject, jboolean);
- #endif
- static void jvmti_ClassFileLoadHook (jvmtiEnv *jvmti_env, JNIEnv* jni_env, jclass class_being_redefined,
- jobject loader, const char* name, jobject protection_domain,
- jint class_data_len, const unsigned char* class_data,
- jint* new_class_data_len, unsigned char** new_class_data);
- static void jvmti_GarbageCollectionStart (jvmtiEnv *);
- static void
- jvmti_GarbageCollectionFinish (jvmtiEnv *);
- jvmtiEventCallbacks callbacks = {
- jvmti_VMInit, // 50 jvmtiEventVMInit;
- jvmti_VMDeath, // 51 jvmtiEventVMDeath;
- jvmti_ThreadStart, // 52 jvmtiEventThreadStart;
- jvmti_ThreadEnd, // 53 jvmtiEventThreadEnd;
- jvmti_ClassFileLoadHook, // 54 jvmtiEventClassFileLoadHook;
- jvmti_ClassLoad, // 55 jvmtiEventClassLoad;
- jvmti_ClassPrepare, // 56 jvmtiEventClassPrepare;
- NULL, // 57 reserved57;
- NULL, // 58 jvmtiEventException;
- NULL, // 59 jvmtiEventExceptionCatch;
- NULL, // 60 jvmtiEventSingleStep;
- NULL, // 61 jvmtiEventFramePop;
- NULL, // 62 jvmtiEventBreakpoint;
- NULL, // 63 jvmtiEventFieldAccess;
- NULL, // 64 jvmtiEventFieldModification;
- NULL, // 65 jvmtiEventMethodEntry;
- NULL, // 66 jvmtiEventMethodExit;
- NULL, // 67 jvmtiEventNativeMethodBind;
- jvmti_CompiledMethodLoad, // 68 jvmtiEventCompiledMethodLoad;
- jvmti_CompiledMethodUnload, // 69 jvmtiEventCompiledMethodUnload;
- jvmti_DynamicCodeGenerated, // 70 jvmtiEventDynamicCodeGenerated;
- NULL, // 71 jvmtiEventDataDumpRequest;
- NULL, // 72 jvmtiEventDataResetRequest;
- NULL, /*jvmti_MonitorWait,*/ // 73 jvmtiEventMonitorWait;
- NULL, /*jvmti_MonitorWaited,*/ // 74 jvmtiEventMonitorWaited;
- jvmti_MonitorEnter, // 75 jvmtiEventMonitorContendedEnter;
- jvmti_MonitorEntered, // 76 jvmtiEventMonitorContendedEntered;
- NULL, // 77 jvmtiEventMonitorContendedExit;
- NULL, // 78 jvmtiEventReserved;
- NULL, // 79 jvmtiEventReserved;
- NULL, // 80 jvmtiEventReserved;
- jvmti_GarbageCollectionStart, // 81 jvmtiEventGarbageCollectionStart;
- jvmti_GarbageCollectionFinish, // 82 jvmtiEventGarbageCollectionFinish;
- NULL, // 83 jvmtiEventObjectFree;
- NULL // 84 jvmtiEventVMObjectAlloc;
- };
- typedef jint (JNICALL JNI_GetCreatedJavaVMs_t)(JavaVM **, jsize, jsize *);
- int
- init_interface (CollectorInterface *_collector_interface)
- {
- collector_interface = _collector_interface;
- return COL_ERROR_NONE;
- }
- static int
- open_experiment (const char *exp)
- {
- if (collector_interface == NULL)
- return COL_ERROR_JAVAINIT;
- TprintfT (0, "jprofile: open_experiment %s\n", exp);
- const char *params = collector_interface->getParams ();
- const char *args = params;
- while (args)
- {
- if (__collector_strStartWith (args, "j:") == 0)
- {
- args += 2;
- break;
- }
- args = CALL_UTIL (strchr)(args, ';');
- if (args)
- args++;
- }
- if (args == NULL) /* Java profiling not specified */
- return COL_ERROR_JAVAINIT;
- tsd_key = collector_interface->createKey (sizeof ( TSD_Entry), NULL, NULL);
- if (tsd_key == (unsigned) - 1)
- {
- TprintfT (0, "jprofile: TSD key create failed.\n");
- collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">TSD key not created</event>\n",
- SP_JCMD_CERROR, COL_ERROR_JAVAINIT);
- return COL_ERROR_JAVAINIT;
- }
- else
- Tprintf (DBG_LT2, "jprofile: TSD key create succeeded %d.\n", tsd_key);
- args = params;
- while (args)
- {
- if (__collector_strStartWith (args, "H:") == 0)
- {
- java_mem_mode = 1;
- collector_heap_record = (void(*)(int, int, void*))dlsym (RTLD_DEFAULT, "__collector_heap_record");
- }
- #if 0
- else if (__collector_strStartWith (args, "s:") == 0)
- {
- java_sync_mode = 1;
- collector_jsync_begin = (void(*)(hrtime_t, void *))dlsym (RTLD_DEFAULT, "__collector_jsync_begin");
- collector_jsync_end = (void(*)(hrtime_t, void *))dlsym (RTLD_DEFAULT, "__collector_jsync_end");
- }
- #endif
- args = CALL_UTIL (strchr)(args, ';');
- if (args)
- args++;
- }
- /* synchronization tracing is enabled by the synctrace module, later in initialization */
- __collector_java_mode = 1;
- java_gc_on = 1;
- return COL_ERROR_NONE;
- }
- /* routine called from the syntrace module to enable Java-API synctrace */
- void
- __collector_jprofile_enable_synctrace ()
- {
- if (__collector_java_mode == 0)
- {
- TprintfT (DBG_LT1, "jprofile: not turning on Java synctrace; Java mode not enabled\n");
- return;
- }
- java_sync_mode = 1;
- collector_jsync_begin = (void(*)(hrtime_t, void *))dlsym (RTLD_DEFAULT, "__collector_jsync_begin");
- collector_jsync_end = (void(*)(hrtime_t, void *))dlsym (RTLD_DEFAULT, "__collector_jsync_end");
- TprintfT (DBG_LT1, "jprofile: turning on Java synctrace, and requesting events\n");
- }
- int
- __collector_jprofile_start_attach (void)
- {
- if (!__collector_java_mode || __collector_java_asyncgetcalltrace_loaded)
- return 0;
- void *g_sHandle = RTLD_DEFAULT;
- /* Now get the function addresses */
- JNI_GetCreatedJavaVMs_t *pfnGetCreatedJavaVMs;
- pfnGetCreatedJavaVMs = (JNI_GetCreatedJavaVMs_t *) dlsym (g_sHandle, "JNI_GetCreatedJavaVMs");
- if (pfnGetCreatedJavaVMs != NULL)
- {
- TprintfT (0, "jprofile attach: pfnGetCreatedJavaVMs is detected.\n");
- JavaVM * vmBuf[1]; // XXXX only detect on jvm
- jsize nVMs = 0;
- (*pfnGetCreatedJavaVMs)(vmBuf, 1, &nVMs);
- if (vmBuf[0] != NULL && nVMs > 0)
- {
- jvm = vmBuf[0];
- JNIEnv* jni_env = NULL;
- (*jvm)->AttachCurrentThread (jvm, (void **) &jni_env, NULL);
- Agent_OnLoad (jvm, NULL, NULL);
- if ((*jvm)->GetEnv (jvm, (void **) &jni_env, JNI_VERSION_1_2) >= 0 && jni_env && jvmti)
- {
- jthread thread;
- (*jvmti)->GetCurrentThread (jvmti, &thread);
- #ifdef DEBUG
- collector_thread_t tid;
- tid = __collector_thr_self ();
- TprintfT (0, "jprofile attach: AttachCurrentThread: thread: %lu jni_env=%p jthread=%p\n",
- (unsigned long) tid, jni_env, thread);
- #endif /* DEBUG */
- jvmti_VMInit (jvmti, jni_env, thread);
- (*jvmti)->GenerateEvents (jvmti, JVMTI_EVENT_COMPILED_METHOD_LOAD);
- (*jvmti)->GenerateEvents (jvmti, JVMTI_EVENT_DYNAMIC_CODE_GENERATED);
- __collector_java_attach = 1;
- (*jvm)->DetachCurrentThread (jvm);
- }
- }
- }
- return 0;
- }
- static int
- close_experiment (void)
- {
- /* fixme XXXXX add content here */
- /* see detach_experiment() */
- __collector_java_mode = 0;
- __collector_java_asyncgetcalltrace_loaded = 0;
- __collector_java_attach = 0;
- java_gc_on = 0;
- java_mem_mode = 0;
- java_sync_mode = 0;
- is_hotspot_vm = 0;
- __collector_mutex_init (&jclasses_lock);
- tsd_key = COLLECTOR_TSD_INVALID_KEY;
- TprintfT (0, "jprofile: experiment closed.\n");
- return 0;
- }
- static int
- detach_experiment (void)
- /* fork child. Clean up state but don't write to experiment */
- {
- __collector_java_mode = 0;
- java_gc_on = 0;
- jvm = NULL;
- java_mem_mode = 0;
- java_sync_mode = 0;
- is_hotspot_vm = 0;
- jvmti = NULL;
- apistr = NULL;
- __collector_mutex_init (&jclasses_lock);
- tsd_key = COLLECTOR_TSD_INVALID_KEY;
- TprintfT (0, "jprofile: detached from experiment.\n");
- return 0;
- }
- JNIEXPORT jint JNICALL
- JVM_OnLoad (JavaVM *vm, char *options, void *reserved)
- {
- jvmtiError err;
- int use_jvmti = 0;
- if (!__collector_java_mode)
- {
- TprintfT (DBG_LT1, "jprofile: JVM_OnLoad invoked with java mode disabled\n");
- return JNI_OK;
- }
- else
- TprintfT (DBG_LT1, "jprofile: JVM_OnLoad invoked\n");
- jvm = vm;
- jvmti = NULL;
- if ((*jvm)->GetEnv (jvm, (void **) &jvmti, JVMTI_VERSION_1_0) >= 0 && jvmti)
- {
- TprintfT (DBG_LT1, "jprofile: JVMTI found\n");
- use_jvmti = 1;
- }
- if (!use_jvmti)
- {
- collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\"/>\n",
- SP_JCMD_CERROR, COL_ERROR_JVMNOTSUPP);
- return JNI_ERR;
- }
- else
- {
- Tprintf (DBG_LT0, "\tjprofile: Initializing for JVMTI\n");
- apistr = "JVMTI 1.0";
- // setup JVMTI
- jvmtiCapabilities cpblts;
- err = (*jvmti)->GetPotentialCapabilities (jvmti, &cpblts);
- if (err == JVMTI_ERROR_NONE)
- {
- jvmtiCapabilities cpblts_set;
- CALL_UTIL (memset)(&cpblts_set, 0, sizeof (cpblts_set));
- /* Add only those capabilities that are among potential ones */
- cpblts_set.can_get_source_file_name = cpblts.can_get_source_file_name;
- Tprintf (DBG_LT1, "\tjprofile: adding can_get_source_file_name capability: %u\n", cpblts.can_get_source_file_name);
- cpblts_set.can_generate_compiled_method_load_events = cpblts.can_generate_compiled_method_load_events;
- Tprintf (DBG_LT1, "\tjprofile: adding can_generate_compiled_method_load_events capability: %u\n", cpblts.can_generate_compiled_method_load_events);
- if (java_sync_mode)
- {
- cpblts_set.can_generate_monitor_events = cpblts.can_generate_monitor_events;
- Tprintf (DBG_LT1, "\tjprofile: adding can_generate_monitor_events capability: %u\n", cpblts.can_generate_monitor_events);
- }
- if (java_gc_on)
- {
- cpblts_set.can_generate_garbage_collection_events = cpblts.can_generate_garbage_collection_events;
- Tprintf (DBG_LT1, "\tjprofile: adding can_generate_garbage_collection_events capability: %u\n", cpblts.can_generate_garbage_collection_events);
- }
- err = (*jvmti)->AddCapabilities (jvmti, &cpblts_set);
- Tprintf (DBG_LT1, "\tjprofile: AddCapabilities() returns: %d\n", err);
- }
- err = (*jvmti)->SetEventCallbacks (jvmti, &callbacks, sizeof ( callbacks));
- err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, NULL);
- err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_DEATH, NULL);
- err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_CLASS_PREPARE, NULL);
- err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_CLASS_LOAD, NULL);
- err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_COMPILED_METHOD_LOAD, NULL);
- err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_COMPILED_METHOD_UNLOAD, NULL);
- err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_DYNAMIC_CODE_GENERATED, NULL);
- err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_THREAD_START, NULL);
- err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_THREAD_END, NULL);
- err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, NULL);
- if (java_gc_on)
- {
- err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_GARBAGE_COLLECTION_START, NULL);
- err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, NULL);
- }
- if (java_mem_mode)
- {
- // err = (*jvmti)->SetEventNotificationMode( jvmti, JVMTI_ENABLE, <no event for heap tracing> , NULL );
- collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\"/>\n",
- SP_JCMD_CWARN, COL_WARN_NO_JAVA_HEAP);
- java_mem_mode = 0;
- }
- if (java_sync_mode)
- {
- err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_MONITOR_CONTENDED_ENTER, NULL);
- err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_MONITOR_CONTENDED_ENTERED, NULL);
- //err = (*jvmti)->SetEventNotificationMode( jvmti, JVMTI_ENABLE, JVMTI_EVENT_MONITOR_WAIT, NULL );
- //err = (*jvmti)->SetEventNotificationMode( jvmti, JVMTI_ENABLE, JVMTI_EVENT_MONITOR_WAITED, NULL );
- }
- Tprintf (DBG_LT0, "\tjprofile: JVMTI initialized\n");
- }
- /* JVM still uses collector API on Solaris to notify us about dynamically generated code.
- * If we ask it to generate events we'll end up with duplicate entries in the
- * map file.
- */
- if (use_jvmti)
- {
- err = (*jvmti)->GenerateEvents (jvmti, JVMTI_EVENT_DYNAMIC_CODE_GENERATED);
- err = (*jvmti)->GenerateEvents (jvmti, JVMTI_EVENT_COMPILED_METHOD_LOAD);
- }
- Tprintf (DBG_LT1, "\tjprofile: JVM_OnLoad ok\n");
- return JNI_OK;
- }
- /* This is currently just a placeholder */
- JNIEXPORT jint JNICALL
- Agent_OnLoad (JavaVM *vm, char *options, void *reserved)
- {
- return JVM_OnLoad (vm, options, reserved);
- }
- static void
- rwrite (int fd, const void *buf, size_t nbyte)
- {
- size_t left = nbyte;
- size_t res;
- char *ptr = (char*) buf;
- while (left > 0)
- {
- res = CALL_UTIL (write)(fd, ptr, left);
- if (res == -1)
- {
- /* XXX: we can't write this record, we probably
- * can't write anything else. Ignore.
- */
- return;
- }
- left -= res;
- ptr += res;
- }
- }
- void
- get_jvm_settings ()
- {
- jint res;
- JNIEnv *jni;
- jclass jcls;
- jmethodID jmid;
- jstring jstrin;
- jstring jstrout;
- const char *str;
- res = (*jvm)->GetEnv (jvm, (void **) &jni, JNI_VERSION_1_2);
- if (res < 0)
- return;
- /* I'm not checking if results are valid as JVM is extremely
- * sensitive to exceptions that might occur during these JNI calls
- * and will die with a fatal error later anyway.
- */
- jcls = (*jni)->FindClass (jni, "java/lang/System");
- jmid = (*jni)->GetStaticMethodID (jni, jcls, "getProperty", "(Ljava/lang/String;)Ljava/lang/String;");
- jstrin = (*jni)->NewStringUTF (jni, "java.class.path");
- jstrout = (*jni)->CallStaticObjectMethod (jni, jcls, jmid, jstrin);
- str = jstrout ? (*jni)->GetStringUTFChars (jni, jstrout, NULL) : NULL;
- if (str)
- {
- collector_interface->writeLog ("<setting %s=\"%s\"/>\n", SP_JCMD_SRCHPATH, str);
- (*jni)->ReleaseStringUTFChars (jni, jstrout, str);
- }
- jstrin = (*jni)->NewStringUTF (jni, "sun.boot.class.path");
- jstrout = (*jni)->CallStaticObjectMethod (jni, jcls, jmid, jstrin);
- str = jstrout ? (*jni)->GetStringUTFChars (jni, jstrout, NULL) : NULL;
- if (str)
- {
- collector_interface->writeLog ("<setting %s=\"%s\"/>\n", SP_JCMD_SRCHPATH, str);
- (*jni)->ReleaseStringUTFChars (jni, jstrout, str);
- }
- jstrin = (*jni)->NewStringUTF (jni, "java.home");
- jstrout = (*jni)->CallStaticObjectMethod (jni, jcls, jmid, jstrin);
- str = jstrout ? (*jni)->GetStringUTFChars (jni, jstrout, NULL) : NULL;
- if (str)
- {
- collector_interface->writeLog ("<setting %s=\"%s/../src.zip\"/>\n", SP_JCMD_SRCHPATH, str);
- (*jni)->ReleaseStringUTFChars (jni, jstrout, str);
- }
- jstrin = (*jni)->NewStringUTF (jni, "java.vm.version");
- jstrout = (*jni)->CallStaticObjectMethod (jni, jcls, jmid, jstrin);
- str = jstrout ? (*jni)->GetStringUTFChars (jni, jstrout, NULL) : NULL;
- if (str)
- {
- (void) collector_interface->writeLog ("<profile name=\"jprofile\" %s=\"%s\" %s=\"%s\"/>\n",
- SP_JCMD_JVERSION, str, "api", apistr != NULL ? apistr : "N/A");
- if (__collector_strStartWith (str, "1.4.2_02") < 0)
- {
- (void) collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\"/>\n",
- SP_JCMD_CWARN, COL_WARN_OLDJAVA);
- }
- (*jni)->ReleaseStringUTFChars (jni, jstrout, str);
- }
- is_hotspot_vm = 0;
- jstrin = (*jni)->NewStringUTF (jni, "sun.management.compiler");
- jstrout = (*jni)->CallStaticObjectMethod (jni, jcls, jmid, jstrin);
- str = jstrout ? (*jni)->GetStringUTFChars (jni, jstrout, NULL) : NULL;
- if (str && __collector_strncmp (str, "HotSpot", 7) == 0)
- is_hotspot_vm = 1;
- /* Emulate System.setProperty( "collector.init", "true") */
- jmid = (*jni)->GetStaticMethodID (jni, jcls, "setProperty",
- "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
- jstrin = (*jni)->NewStringUTF (jni, "collector.init");
- jstrout = (*jni)->NewStringUTF (jni, "true");
- (*jni)->CallStaticObjectMethod (jni, jcls, jmid, jstrin, jstrout);
- }
- /*
- * JVMTI code
- */
- static void
- jvmti_VMInit (jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread)
- {
- jint class_count = 0;
- jclass *classes = NULL;
- int i;
- TprintfT (DBG_LT1, "jprofile: jvmti_VMInit called\n");
- get_jvm_settings ();
- /* determine loaded classes */
- (*jvmti_env)->GetLoadedClasses (jvmti_env, &class_count, &classes);
- TprintfT (DBG_LT1, "jprofile: jvmti_VMInit initializing %d classes\n", class_count);
- for (i = 0; i < class_count; i++)
- {
- // PushLocalFrame
- jvmti_ClassPrepare (jvmti_env, jni_env, NULL, classes[i]);
- // PopLocalFrame
- // DeleteLocalRef( classes[i] );
- }
- (*jvmti_env)->Deallocate (jvmti_env, (unsigned char*) classes);
- getResource = (*jni_env)->GetMethodID (jni_env, (*jni_env)->FindClass (jni_env, "java/lang/ClassLoader"), "getResource", "(Ljava/lang/String;)Ljava/net/URL;");
- toExternalForm = (*jni_env)->GetMethodID (jni_env, (*jni_env)->FindClass (jni_env, "java/net/URL"), "toExternalForm", "()Ljava/lang/String;");
- /* find the stack unwind routine */
- jprof_find_asyncgetcalltrace ();
- }
- static void
- jvmti_VMDeath (jvmtiEnv *jvmti_env, JNIEnv* jni_env)
- {
- __collector_java_mode = 0;
- TprintfT (DBG_LT1, "jprofile: jvmti_VMDeath event received\n");
- }
- static void
- jvmti_ThreadStart (jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread)
- {
- jvmtiError err;
- jvmtiThreadInfo t_info;
- char *thread_name, *group_name, *parent_name;
- hrtime_t hrt;
- collector_thread_t tid;
- thread_name = group_name = parent_name = NULL;
- hrt = gethrtime ();
- tid = __collector_thr_self ();
- TprintfT (DBG_LT1, "jprofile: jvmti_ThreadStart: thread: %lu jni_env=%p jthread=%p\n",
- (unsigned long) tid, jni_env, thread);
- err = (*jvmti_env)->GetThreadInfo (jvmti_env, thread, &t_info);
- if (err == JVMTI_ERROR_NONE)
- {
- jvmtiThreadGroupInfo g_info;
- thread_name = t_info.name;
- if (t_info.thread_group)
- {
- err = (*jvmti_env)->GetThreadGroupInfo (jvmti_env, t_info.thread_group, &g_info);
- if (err == JVMTI_ERROR_NONE)
- {
- group_name = g_info.name;
- if (g_info.parent)
- {
- jvmtiThreadGroupInfo p_info;
- err = (*jvmti_env)->GetThreadGroupInfo (jvmti_env, g_info.parent, &p_info);
- if (err == JVMTI_ERROR_NONE)
- {
- parent_name = p_info.name;
- // DeleteLocalRef( p_info.parent );
- }
- // DeleteLocalRef( g_info.parent );
- }
- }
- }
- // DeleteLocalRef( t_info.thread_group );
- // DeleteLocalRef( t_info.context_class_loader );
- }
- if (thread_name == NULL)
- thread_name = "";
- if (group_name == NULL)
- group_name = "";
- if (parent_name == NULL)
- parent_name = "";
- collector_interface->writeLog ("<event kind=\"%s\" tstamp=\"%u.%09u\" name=\"%s\" grpname=\"%s\" prntname=\"%s\" tid=\"%lu\" jthr=\"0x%lx\" jenv=\"0x%lx\"/>\n",
- SP_JCMD_JTHRSTART,
- (unsigned) (hrt / NANOSEC), (unsigned) (hrt % NANOSEC),
- thread_name,
- group_name,
- parent_name,
- (unsigned long) tid,
- thread,
- jni_env
- );
- TSD_Entry *tsd = collector_interface->getKey (tsd_key);
- if (tsd)
- tsd->env = jni_env;
- }
- static void
- jvmti_ThreadEnd (jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread)
- {
- hrtime_t hrt = gethrtime ();
- collector_thread_t tid = __collector_thr_self ();
- TprintfT (DBG_LT1, "jprofile: jvmti_ThreadEnd: thread: %lu jni_env=%p jthread=%p\n",
- (unsigned long) tid, jni_env, thread);
- collector_interface->writeLog ("<event kind=\"%s\" tstamp=\"%u.%09u\" tid=\"%lu\" jthr=\"0x%lx\" jenv=\"0x%lx\"/>\n",
- SP_JCMD_JTHREND,
- (unsigned) (hrt / NANOSEC), (unsigned) (hrt % NANOSEC),
- (unsigned long) tid,
- thread,
- jni_env
- );
- TSD_Entry *tsd = collector_interface->getKey (tsd_key);
- if (tsd)
- tsd->env = NULL;
- }
- /* The following definitions are borrowed from file jvmticmlr.h, part of jdk7 */
- typedef enum
- {
- JVMTI_CMLR_DUMMY = 1,
- JVMTI_CMLR_INLINE_INFO = 2
- } jvmtiCMLRKind;
- /*
- * Record that represents arbitrary information passed through JVMTI
- * CompiledMethodLoadEvent void pointer.
- */
- typedef struct _jvmtiCompiledMethodLoadRecordHeader
- {
- jvmtiCMLRKind kind; /* id for the kind of info passed in the record */
- jint majorinfoversion; /* major and minor info version values. Init'ed */
- jint minorinfoversion; /* to current version value in jvmtiExport.cpp. */
- struct _jvmtiCompiledMethodLoadRecordHeader* next;
- } jvmtiCompiledMethodLoadRecordHeader;
- /*
- * Record that gives information about the methods on the compile-time
- * stack at a specific pc address of a compiled method. Each element in
- * the methods array maps to same element in the bcis array.
- */
- typedef struct _PCStackInfo
- {
- void* pc; /* the pc address for this compiled method */
- jint numstackframes; /* number of methods on the stack */
- jmethodID* methods; /* array of numstackframes method ids */
- jint* bcis; /* array of numstackframes bytecode indices */
- } PCStackInfo;
- /*
- * Record that contains inlining information for each pc address of
- * an nmethod.
- */
- typedef struct _jvmtiCompiledMethodLoadInlineRecord
- {
- jvmtiCompiledMethodLoadRecordHeader header; /* common header for casting */
- jint numpcs; /* number of pc descriptors in this nmethod */
- PCStackInfo* pcinfo; /* array of numpcs pc descriptors */
- } jvmtiCompiledMethodLoadInlineRecord;
- static void
- jvmti_CompiledMethodLoad (jvmtiEnv *jvmti_env, jmethodID method,
- jint code_size, const void *code_addr, jint map_length,
- const jvmtiAddrLocationMap *map,
- const void *compile_info)
- {
- TprintfT (DBG_LT2, "jprofile: jvmti_CompiledMethodLoad: mid=0x%lx addr=%p sz=0x%lu map=%p info=%p\n",
- (unsigned long) method, code_addr, (long) code_size, map, compile_info);
- char name[32];
- CALL_UTIL (snprintf)(name, sizeof (name), "0x%lx", (unsigned long) method);
- /* Parse compile_info to get pc -> bci mapping.
- * Don't interpret compile_info from JVMs other than HotSpot.
- */
- int lntsize = 0;
- DT_lineno *lntable = NULL;
- if (compile_info != NULL && is_hotspot_vm)
- {
- Tprintf (DBG_LT2, "Mapping from compile_info:\n");
- jvmtiCompiledMethodLoadRecordHeader *currec =
- (jvmtiCompiledMethodLoadRecordHeader*) compile_info;
- while (currec != NULL)
- {
- if (currec->kind == JVMTI_CMLR_INLINE_INFO)
- {
- jvmtiCompiledMethodLoadInlineRecord *inrec =
- (jvmtiCompiledMethodLoadInlineRecord*) currec;
- if (inrec->numpcs <= 0)
- break;
- lntsize = inrec->numpcs;
- lntable = (DT_lineno*) alloca (lntsize * sizeof (DT_lineno));
- PCStackInfo *pcrec = inrec->pcinfo;
- DT_lineno *lnorec = lntable;
- for (int i = 0; i < lntsize; ++i)
- {
- for (int j = pcrec->numstackframes - 1; j >= 0; --j)
- if (pcrec->methods[j] == method)
- {
- lnorec->offset = (char*) pcrec->pc - (char*) code_addr;
- lnorec->lineno = pcrec->bcis[j];
- Tprintf (DBG_LT2, " pc: 0x%lx bci: 0x%lx\n",
- (long) lnorec->offset, (long) lnorec->lineno);
- ++lnorec;
- break;
- }
- ++pcrec;
- }
- break;
- }
- currec = currec->next;
- }
- }
- else if (map != NULL)
- {
- Tprintf (DBG_LT2, "Mapping from jvmtiAddrLocationMap:\n");
- lntsize = map_length;
- lntable = (DT_lineno*) alloca (lntsize * sizeof (DT_lineno));
- DT_lineno *lnorec = lntable;
- for (int i = 0; i < map_length; ++i)
- {
- lnorec->offset = (char*) map[i].start_address - (char*) code_addr;
- lnorec->lineno = (unsigned int) map[i].location;
- Tprintf (DBG_LT2, " pc: 0x%lx bci: 0x%lx\n",
- (long) lnorec->offset, (long) lnorec->lineno);
- ++lnorec;
- }
- }
- __collector_int_func_load (DFUNC_JAVA, name, NULL, (void*) code_addr,
- code_size, lntsize, lntable);
- }
- static void
- jvmti_CompiledMethodUnload (jvmtiEnv *jvmti_env, jmethodID method, const void* code_addr)
- {
- __collector_int_func_unload (DFUNC_API, (void*) code_addr);
- }
- static void
- jvmti_DynamicCodeGenerated (jvmtiEnv *jvmti_env, const char*name, const void *code_addr, jint code_size)
- {
- __collector_int_func_load (DFUNC_API, (char*) name, NULL, (void*) code_addr,
- code_size, 0, NULL);
- }
- static void
- addToDynamicArchive (const char* name, const unsigned char* class_data, int class_data_len)
- {
- char path[MAXPATHLEN + 1];
- mode_t fmode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
- mode_t dmode = fmode | S_IXUSR | S_IXGRP | S_IXOTH;
- if (name == NULL)
- name = "";
- const char *expdir = collector_interface->getExpDir ();
- if (CALL_UTIL (strlen)(expdir) +
- CALL_UTIL (strlen)(SP_DYNAMIC_CLASSES) +
- CALL_UTIL (strlen)(name) + 8 > sizeof (path))
- return;
- CALL_UTIL (snprintf)(path, sizeof (path), "%s/%s/%s.class", expdir, SP_DYNAMIC_CLASSES, name);
- /* Create all path components step by step starting with SP_DYNAMIC_CLASSES */
- char *str = path + CALL_UTIL (strlen)(expdir) + 1 + CALL_UTIL (strlen)(SP_DYNAMIC_CLASSES);
- while (str)
- {
- *str = '\0';
- if (CALL_UTIL (mkdir)(path, dmode) != 0)
- {
- /* Checking for EEXIST is not enough, access() is more reliable */
- if (CALL_UTIL (access)(path, F_OK) != 0)
- {
- collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">%s</event>\n",
- SP_JCMD_CERROR, COL_ERROR_MKDIR, errno, path);
- return;
- }
- }
- *str++ = '/';
- str = CALL_UTIL (strchr)(str, '/');
- }
- int fd = CALL_UTIL (open)(path, O_WRONLY | O_CREAT | O_TRUNC, fmode);
- if (fd < 0)
- {
- collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">%s</event>\n",
- SP_JCMD_CERROR, COL_ERROR_OVWOPEN, errno, path);
- return;
- }
- rwrite (fd, class_data, class_data_len);
- CALL_UTIL (close)(fd);
- }
- static void
- jvmti_ClassFileLoadHook (jvmtiEnv *jvmti_env, JNIEnv* jni_env, jclass class_being_redefined,
- jobject loader, const char* name, jobject protection_domain, jint class_data_len,
- const unsigned char* class_data, jint* new_class_data_len, unsigned char** new_class_data)
- {
- jclass loaderlass;
- int err;
- jvmtiPhase phase_ptr;
- char *cname = NULL;
- (*jvmti_env)->GetPhase (jvmti_env, &phase_ptr);
- /* skip non live phases */
- if (phase_ptr != JVMTI_PHASE_LIVE)
- return;
- /* skip system class loaders */
- if (!loader)
- return;
- loaderlass = (*jni_env)->GetObjectClass (jni_env, loader);
- err = (*jvmti_env)->GetClassSignature (jvmti_env, loaderlass, &cname, NULL);
- if (err != JVMTI_ERROR_NONE || !cname || *cname == (char) 0)
- return;
- /* skip classes loaded with AppClassLoader (java.class.path) */
- if (__collector_strcmp (cname, "Lsun/misc/Launcher$AppClassLoader;") == 0)
- return;
- addToDynamicArchive (name, class_data, (int) class_data_len);
- }
- #define NO_CLASS_NAME "<noname>"
- #define NO_SOURCE_FILE "<Unknown>"
- static void
- record_jclass (uint64_t class_id, hrtime_t hrt, const char *cname, const char *sname)
- {
- size_t clen = ARCH_STRLEN (cname);
- size_t slen = ARCH_STRLEN (sname);
- size_t sz = sizeof (ARCH_jclass) + clen + slen;
- ARCH_jclass *jcls = (ARCH_jclass*) alloca (sz);
- jcls->comm.tsize = sz;
- jcls->comm.type = ARCH_JCLASS;
- jcls->class_id = class_id;
- jcls->tstamp = hrt;
- char *str = (char*) (jcls + 1);
- size_t i = CALL_UTIL (strlcpy)(str, cname, clen);
- str += i;
- while (i++ < clen)
- *str++ = (char) 0; /* pad with 0's */
- i = CALL_UTIL (strlcpy)(str, sname, slen);
- str += i;
- while (i++ < slen)
- *str++ = (char) 0; /* pad with 0's */
- collector_interface->writeDataPacket (jprof_hndl, (CM_Packet*) jcls);
- }
- static void
- record_jmethod (uint64_t class_id, uint64_t method_id,
- const char *mname, const char *msign)
- {
- size_t mnlen = mname ? ARCH_STRLEN (mname) : 0;
- size_t mslen = msign ? ARCH_STRLEN (msign) : 0;
- size_t sz = sizeof (ARCH_jmethod) + mnlen + mslen;
- ARCH_jmethod *jmth = (ARCH_jmethod*) alloca (sz);
- if (jmth == NULL)
- {
- TprintfT (DBG_LT1, "jprofile: record_jmethod ERROR: failed to alloca(%ld)\n", (long) sz);
- return;
- }
- jmth->comm.tsize = sz;
- jmth->comm.type = ARCH_JMETHOD;
- jmth->class_id = class_id;
- jmth->method_id = method_id;
- char *str = (char*) (jmth + 1);
- if (mname)
- {
- size_t i = CALL_UTIL (strlcpy)(str, mname, mnlen);
- str += i;
- while (i++ < mnlen)
- *str++ = (char) 0; /* pad with 0's */
- }
- if (msign)
- {
- size_t i = CALL_UTIL (strlcpy)(str, msign, mslen);
- str += i;
- while (i++ < mslen)
- *str++ = (char) 0; /* pad with 0's */
- }
- collector_interface->writeDataPacket (jprof_hndl, (CM_Packet*) jmth);
- }
- static void
- jvmti_ClassPrepare (jvmtiEnv *jvmti_env, JNIEnv* jni_env,
- jthread thread, jclass klass)
- {
- hrtime_t hrt;
- jint mnum;
- jmethodID *mptr;
- char *cname, *sname;
- char *str1 = NULL;
- int err = (*jvmti_env)->GetClassSignature (jvmti_env, klass, &str1, NULL);
- if (err != JVMTI_ERROR_NONE || str1 == NULL || *str1 == (char) 0)
- cname = NO_CLASS_NAME;
- else
- cname = str1;
- if (*cname != 'L')
- {
- DprintfT (SP_DUMP_JAVA | SP_DUMP_TIME, "jvmti_ClassPrepare: GetClassSignature failed. err=%d cname=%s\n", err, cname);
- return;
- }
- char *str2 = NULL;
- err = (*jvmti_env)->GetSourceFileName (jvmti_env, klass, &str2);
- if (err != JVMTI_ERROR_NONE || str2 == NULL || *str2 == (char) 0)
- sname = NO_SOURCE_FILE;
- else
- sname = str2;
- DprintfT (SP_DUMP_JAVA | SP_DUMP_TIME, "jvmti_ClassPrepare: cname=%s sname=%s\n", STR (cname), STR (sname));
- /* Lock the whole file */
- __collector_mutex_lock (&jclasses_lock);
- hrt = gethrtime ();
- record_jclass ((unsigned long) klass, hrt, cname, sname);
- (*jvmti_env)->Deallocate (jvmti_env, (unsigned char *) str1);
- (*jvmti_env)->Deallocate (jvmti_env, (unsigned char *) str2);
- err = (*jvmti_env)->GetClassMethods (jvmti_env, klass, &mnum, &mptr);
- if (err == JVMTI_ERROR_NONE)
- {
- for (int i = 0; i < mnum; i++)
- {
- char *mname, *msign;
- err = (*jvmti_env)->GetMethodName (jvmti_env, mptr[i], &mname, &msign, NULL);
- if (err != JVMTI_ERROR_NONE)
- continue;
- record_jmethod ((unsigned long) klass, (unsigned long) mptr[i], mname, msign);
- // DeleteLocalRef( mptr[i] );
- }
- (*jvmti_env)->Deallocate (jvmti_env, (unsigned char*) mptr);
- }
- /* Unlock the file */
- __collector_mutex_unlock (&jclasses_lock);
- }
- /*
- * The CLASS_LOAD event is enabled to enable AsyncGetCallTrace
- */
- static void
- jvmti_ClassLoad (jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread, jclass klass)
- {
- char *cname;
- char *str1 = NULL;
- int err = (*jvmti_env)->GetClassSignature (jvmti_env, klass, &str1, NULL);
- if (err != JVMTI_ERROR_NONE || str1 == NULL || *str1 == (char) 0)
- cname = NO_CLASS_NAME;
- else
- cname = str1;
- jstring str = NULL;
- const char* resourceName;
- jobject classLoader = NULL;
- err = (*jvmti)->GetClassLoader (jvmti, klass, &classLoader);
- DprintfT (SP_DUMP_JAVA | SP_DUMP_TIME, "jprofile: jvmti_ClassLoad err=%d cname=%s\n", err, STR (cname));
- if (err == 0)
- {
- if (classLoader == NULL)
- {
- // bootstrap class loader
- resourceName = "";
- }
- else
- {
- char* name = (char *) alloca ((CALL_UTIL (strlen)(str1) + 32) * sizeof (char));
- CALL_UTIL (strlcpy)(name, str1 + 1, CALL_UTIL (strlen)(str1));
- name[CALL_UTIL (strlen)(name) - 1] = '\0'; // remove the last ';'
- char* p;
- for (p = name; *p != '\0'; p++)
- if (*p == '.')
- *p = '/';
- CALL_UTIL (strlcat)(name, ".class", CALL_UTIL (strlen)(name) + CALL_UTIL (strlen)(".class") + 1);
- if (getResource == NULL || toExternalForm == NULL)
- {
- resourceName = "";
- DprintfT (SP_DUMP_JAVA | SP_DUMP_TIME, "jvmti_ClassLoad: class %s failed to get path with method missing\n", STR (cname));
- }
- else
- {
- jobject url = (*jni_env)->CallObjectMethod (jni_env, classLoader, getResource, (*jni_env)->NewStringUTF (jni_env, name));
- if (url == NULL)
- {
- resourceName = "";
- DprintfT (SP_DUMP_JAVA | SP_DUMP_TIME, "jvmti_ClassLoad: class %s failed to get path\n", STR (cname));
- }
- else
- {
- str = (jstring) (*jni_env)->CallObjectMethod (jni_env, url, toExternalForm);
- resourceName = (*jni_env)->GetStringUTFChars (jni_env, str, NULL);
- DprintfT (SP_DUMP_JAVA | SP_DUMP_TIME, "jvmti_ClassLoad: ARCH_JCLASS_LOCATION(Ox%x) class_id=0x%lx className='%s' fileName '%s'\n",
- (int) ARCH_JCLASS_LOCATION, (unsigned long) klass, STR (cname), STR (resourceName));
- size_t clen = ARCH_STRLEN (cname);
- size_t slen = ARCH_STRLEN (resourceName);
- size_t sz = sizeof (ARCH_jclass) + clen + slen;
- ARCH_jclass_location *jcls = (ARCH_jclass_location*) alloca (sz);
- jcls->comm.tsize = sz;
- jcls->comm.type = ARCH_JCLASS_LOCATION;
- jcls->class_id = (unsigned long) klass;
- char *str = (char*) (jcls + 1);
- size_t i = CALL_UTIL (strlcpy)(str, cname, clen);
- str += i;
- while (i++ < clen)
- {
- *str++ = (char) 0; /* pad with 0's */
- }
- i = CALL_UTIL (strlcpy)(str, resourceName, slen);
- str += i;
- while (i++ < slen)
- {
- *str++ = (char) 0; /* pad with 0's */
- }
- /* Lock the whole file */
- __collector_mutex_lock (&jclasses_lock);
- collector_interface->writeDataPacket (jprof_hndl, (CM_Packet*) jcls);
- /* Unlock the file */
- __collector_mutex_unlock (&jclasses_lock);
- }
- }
- }
- }
- }
- static void
- jvmti_MonitorEnter (jvmtiEnv *jvmti_env, JNIEnv* jni_env,
- jthread thread, jobject object)
- {
- if (collector_jsync_begin)
- collector_jsync_begin ();
- TSD_Entry *tsd = collector_interface->getKey (tsd_key);
- if (tsd == NULL)
- return;
- tsd->tstamp = gethrtime ();
- }
- static void
- jvmti_MonitorEntered (jvmtiEnv *jvmti_env, JNIEnv* jni_env,
- jthread thread, jobject object)
- {
- TSD_Entry *tsd = collector_interface->getKey (tsd_key);
- if (tsd == NULL)
- return;
- if (collector_jsync_end)
- collector_jsync_end (tsd->tstamp, object);
- }
- static void
- jvmti_GarbageCollectionStart (jvmtiEnv *jvmti_env)
- {
- hrtime_t hrt = gethrtime ();
- collector_interface->writeLog ("<event kind=\"%s\" tstamp=\"%u.%09u\"/>\n",
- SP_JCMD_GCSTART,
- (unsigned) (hrt / NANOSEC), (unsigned) (hrt % NANOSEC)
- );
- TprintfT (DBG_LT1, "jprofile: jvmti_GarbageCollectionStart.\n");
- }
- static void
- jvmti_GarbageCollectionFinish (jvmtiEnv *jvmti_env)
- {
- hrtime_t hrt = gethrtime ();
- collector_interface->writeLog ("<event kind=\"%s\" tstamp=\"%u.%09u\"/>\n",
- SP_JCMD_GCEND,
- (unsigned) (hrt / NANOSEC), (unsigned) (hrt % NANOSEC)
- );
- TprintfT (DBG_LT1, "jprofile: jvmti_GarbageCollectionFinish.\n");
- }
- #if 0
- static void
- jvmti_MonitorWait (jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread,
- jobject object, jlong timed_out)
- {
- if (collector_sync_begin)
- collector_sync_begin ();
- TSD_Entry *tsd = collector_interface->getKey (tsd_key);
- if (tsd == NULL)
- return;
- tsd->tstamp = gethrtime ();
- }
- static void
- jvmti_MonitorWaited (jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread,
- jobject object, jboolean timed_out)
- {
- TSD_Entry *tsd = collector_interface->getKey (tsd_key);
- if (tsd == NULL)
- return;
- if (collector_sync_end)
- collector_sync_end (tsd->tstamp, object);
- }
- #endif
- static void
- jprof_find_asyncgetcalltrace ()
- {
- void *jvmhandle;
- if (__collector_VM_ReadByteInstruction == NULL)
- __collector_VM_ReadByteInstruction = (int(*)()) dlsym (RTLD_DEFAULT, "Async_VM_ReadByteInstruction");
- /* look for stack unwind function using default path */
- AsyncGetCallTrace = (void (*)(JVMPI_CallTrace*, jint, ucontext_t*))
- dlsym (RTLD_DEFAULT, "AsyncGetCallTrace");
- if (AsyncGetCallTrace != NULL)
- {
- __collector_java_asyncgetcalltrace_loaded = 1;
- TprintfT (DBG_LT1, "jprofile: AsyncGetCallTrace found with RTLD_DEFAULT\n");
- }
- else
- {
- /* not found there, find libjvm.so, and ask again */
- jvmhandle = dlopen ("libjvm.so", RTLD_LAZY | RTLD_NOLOAD);
- if (jvmhandle != NULL)
- {
- AsyncGetCallTrace = (void (*)(JVMPI_CallTrace*, jint, ucontext_t*))
- dlsym (jvmhandle, "AsyncGetCallTrace");
- }
- }
- if (AsyncGetCallTrace == NULL)
- {
- /* we could not find it -- write collector error */
- TprintfT (0, "jprofile: ERROR -- AsyncGetCallTrace not found in address space\n");
- char *err = dlerror ();
- collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">%s</event>\n",
- SP_JCMD_CERROR, COL_ERROR_JVMNOJSTACK, err ? err : "");
- __collector_java_mode = 0;
- }
- else
- {
- __collector_java_asyncgetcalltrace_loaded = 1;
- TprintfT (DBG_LT1, "jprofile: AsyncGetCallTrace initialized in jprof_jvmpi_init_done_event\n");
- }
- }
- int
- __collector_ext_jstack_unwind (char *ptr, int sz, ucontext_t *uc)
- {
- if (AsyncGetCallTrace == NULL)
- {
- TprintfT (DBG_LT0, "jprofile: __collector_ext_jstack_unwind: AsyncGetCallTrace is NULL\n");
- return 0;
- }
- TSD_Entry *tsd = collector_interface->getKey (tsd_key);
- if (tsd == NULL)
- {
- TprintfT (DBG_LT3, "jprofile: __collector_ext_jstack_unwind: tsd is NULL\n");
- return 0;
- }
- if (__collector_java_attach && tsd->env == NULL && jvmti != NULL && jvm != NULL)
- {
- TprintfT (DBG_LT3, "jprofile: __collector_ext_jstack_unwind: tsd->env is NULL under attach\n");
- JNIEnv* jni_env = NULL;
- (*jvm)->GetEnv (jvm, (void **) &jni_env, JNI_VERSION_1_2);
- tsd->env = jni_env;
- }
- if (tsd->env == NULL)
- {
- TprintfT (DBG_LT3, "jprofile: __collector_ext_jstack_unwind: tsd->env is NULL\n");
- return 0;
- }
- /* skip the Java stack whenever another signal handler is present */
- if (uc->uc_link)
- {
- TprintfT (DBG_LT3, "jprofile: __collector_ext_jstack_unwind: uc->uc_link is non-NULL\n");
- return 0;
- }
- /* we don't expect Java frames in signal handlers, so
- * unroll the list of saved contexts to the topmost one
- */
- while (uc->uc_link)
- uc = uc->uc_link;
- Java_info *jinfo = (Java_info*) ptr;
- jinfo->kind = JAVA_INFO;
- jinfo->hsize = sizeof (Java_info);
- ptr += sizeof (Java_info);
- sz -= sizeof (Java_info);
- JVMPI_CallTrace jtrace;
- jtrace.env_id = tsd->env;
- jtrace.frames = (JVMPI_CallFrame*) ptr;
- /* nframes is how many frames we have room for */
- jint nframes = sz / sizeof (JVMPI_CallFrame);
- #if WSIZE(64)
- /* bug 6909545: garbage in 64-bit JAVA_INFO */
- CALL_UTIL (memset)(jtrace.frames, 0, nframes * sizeof (JVMPI_CallFrame));
- #endif
- #if ARCH(SPARC)
- // 21328946 JDK bug 8129933 causes <no java callstack recorded> on sparc-Linux
- // convert from ucontext_t to sigcontext
- struct sigcontext sctx;
- sctx.sigc_regs.tpc = uc->uc_mcontext.mc_gregs[MC_PC];
- __collector_memcpy (sctx.sigc_regs.u_regs, &uc->uc_mcontext.mc_gregs[3], sizeof (sctx.sigc_regs.u_regs));
- uc = (ucontext_t *) (&sctx);
- #endif /* SPARC */
- AsyncGetCallTrace (&jtrace, nframes, uc);
- if (jtrace.num_frames == nframes)
- {
- JVMPI_CallFrame *last = &jtrace.frames[nframes - 1];
- last->method_id = (jmethodID) SP_TRUNC_STACK_MARKER;
- last->lineno = 0;
- }
- /* nframes is how many frames we actually got */
- nframes = jtrace.num_frames;
- TprintfT (DBG_LT3, "jprofile: __collector_ext_jstack_unwind: AsyncGetCallTrace jtrace.numframes = %d\n", nframes);
- if (nframes <= 0)
- {
- /* negative values are error codes */
- TprintfT (0, "jprofile: __collector_ext_jstack_unwind: AsyncGetCallTrace returned error: jtrace.numframes = %d\n", nframes);
- nframes = 1;
- JVMPI_CallFrame *err = (JVMPI_CallFrame*) ptr;
- err->lineno = jtrace.num_frames; // bci = error code
- err->method_id = 0; // artificial method id
- }
- jinfo->hsize += nframes * sizeof (JVMPI_CallFrame);
- return jinfo->hsize;
- }
- /*
- * Collector Java API implementation
- */
- void
- Java_com_sun_forte_st_collector_CollectorAPI__1sample(JNIEnv *jEnv, jclass jCls, jstring jName)
- {
- JNIEnv *jni;
- jint res = (*jvm)->GetEnv (jvm, (void **) &jni, JNI_VERSION_1_2);
- if (res < 0)
- return;
- const char *name = jName ? (*jni)->GetStringUTFChars (jni, jName, NULL) : NULL;
- __collector_sample ((char*) name);
- }
- void
- Java_com_sun_forte_st_collector_CollectorAPI__1pause(JNIEnv *jEnv, jclass jCls)
- {
- __collector_pause_m ("JAPI");
- }
- void
- Java_com_sun_forte_st_collector_CollectorAPI__1resume(JNIEnv *jEnv, jclass jCls)
- {
- __collector_resume ();
- }
- void
- Java_com_sun_forte_st_collector_CollectorAPI__1terminate(JNIEnv *jEnv, jclass jCls)
- {
- __collector_terminate_expt ();
- }
- #endif /* GPROFNG_JAVA_PROFILING */
- static void init_module () __attribute__ ((constructor));
- static void
- init_module ()
- {
- #if defined(GPROFNG_JAVA_PROFILING)
- __collector_dlsym_guard = 1;
- RegModuleFunc reg_module = (RegModuleFunc) dlsym (RTLD_DEFAULT, "__collector_register_module");
- __collector_dlsym_guard = 0;
- if (reg_module)
- {
- jprof_hndl = reg_module (&module_interface);
- TprintfT (0, "jprofile: init_module.\n");
- }
- #endif /* GPROFNG_JAVA_PROFILING */
- }
- int __collector_java_mode = 0;
- int __collector_java_asyncgetcalltrace_loaded = 0;
|