| /* |
| * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. |
| * |
| * This code 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 |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| /* |
| * |
| * JVMTI agent used for run every test from the testbase in a special |
| * debug mode. This mode is intended to be part of serviceability |
| * reliability testing. |
| */ |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <stdarg.h> |
| #include <string.h> |
| #include <jvmti.h> |
| |
| #include "nsk_tools.h" |
| #include "jni_tools.h" |
| #include "JVMTITools.h" |
| #include "jvmti_tools.h" |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| |
| static jvmtiEnv *jvmti = NULL; /* JVMTI env */ |
| static jvmtiEventCallbacks callbacks; |
| static jrawMonitorID eventLock; /* raw monitor used for exclusive ownership of HotSwap function */ |
| |
| static volatile int debug_mode = 0; /* 0 - verbose mode off; |
| 1 - verbose mode on; |
| 2 - verbose mode on including all JVMTI events reporting, |
| produces a huge number of messages */ |
| |
| /* stress level */ |
| static volatile int stress_lev = 0; /* 0 - default mode: generation of all events except |
| ExceptionCatch, |
| MethodEntry/Exit, SingleStep; |
| 1 - generation of all events except |
| MethodEntry/Exit, |
| SingleStep; |
| 2 - generation of all events except |
| SingleStep; |
| 3 - generation of all events, including |
| ExceptionCatch, |
| MethodEntry/Exit, |
| SingleStep |
| */ |
| |
| #define TRUE 1 |
| #define FALSE 0 |
| |
| /**** the following is used for "postVM_DEATH" events watching ****/ |
| static volatile int vm_death_occured = FALSE; |
| /************************************************/ |
| |
| /**** the following is used for HotSwap mode ****/ |
| |
| /* HotSwap modes: |
| HOTSWAP_OFF - default mode: HotSwap off; |
| HOTSWAP_EVERY_METHOD_ENTRY - HotSwap tested class in every method entry event |
| of running test |
| HOTSWAP_EVERY_METHOD_ENTRY_FOR_EVERY_CLASS - HotSwap tested class in every |
| method entry event of every class |
| HOTSWAP_EVERY_SINGLE_STEP - HotSwap tested class in every single step event |
| of running test |
| HOTSWAP_EVERY_EXCEPTION - HotSwap tested class in every exception event |
| of running test |
| HOTSWAP_EVERY_EXCEPTION_FOR_EVERY_CLASS - HotSwap tested class in every |
| exception event of every class |
| */ |
| |
| #define HOTSWAP_OFF 0 |
| #define HOTSWAP_EVERY_METHOD_ENTRY 2 |
| #define HOTSWAP_EVERY_METHOD_ENTRY_FOR_EVERY_CLASS 20 |
| #define HOTSWAP_EVERY_SINGLE_STEP 3 |
| #define HOTSWAP_EVERY_EXCEPTION 4 |
| #define HOTSWAP_EVERY_EXCEPTION_FOR_EVERY_CLASS 40 |
| |
| static int hotswap = HOTSWAP_OFF; |
| |
| typedef struct { /* test class info */ |
| char *clazzsig; /* class signature */ |
| jclass cls; /* a class to be redefined */ |
| jint bCount; /* number of bytes defining the class */ |
| jbyte *clsBytes; /* bytes defining the class */ |
| struct class_info *next; |
| } class_info; |
| |
| |
| static const char *shortTestName = NULL; /* name of the test without package prefix */ |
| static jclass rasCls; /* reference to the auxiliary class RASagent used for HotSwap */ |
| static class_info *clsInfo = NULL, *clsInfoFst = NULL; |
| |
| static void lock(JNIEnv*); |
| static void unlock(JNIEnv*); |
| static jint allocClsInfo(JNIEnv*, char*, jclass); |
| static void deallocClsInfo(JNIEnv*); |
| static int findAndHotSwap(JNIEnv*, jclass); |
| static int doHotSwap(JNIEnv*, jclass, jint, jbyte*); |
| static void display(int, const char format[], ...); |
| static void clearJavaException(JNIEnv*); |
| static int enableEventsCaps(); |
| static int addStressEvents(); |
| static void getVerdict(JNIEnv*, const char *); |
| /************************************************/ |
| |
| /** callback functions **/ |
| void JNICALL |
| Breakpoint(jvmtiEnv *jvmti_env, JNIEnv *jni_env, jthread thr, jmethodID method, |
| jlocation loc) { |
| |
| display(1, "#### JVMTIagent: Breakpoint occurred ####\n"); |
| |
| getVerdict(jni_env, "Breakpoint"); |
| } |
| |
| void JNICALL |
| ClassFileLoadHook(jvmtiEnv *jvmti_env, JNIEnv *jni_env, |
| jclass class_beeing_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) { |
| |
| display(1, "#### JVMTIagent: ClassFileLoadHook occurred ####\n"); |
| |
| getVerdict(jni_env, "ClassFileLoadHook"); |
| } |
| |
| void JNICALL |
| ClassLoad(jvmtiEnv *jvmti_env, JNIEnv *jni_env, jthread thread, jclass klass) { |
| char *cls_sig; |
| jint clsByteCount; |
| |
| display((hotswap != HOTSWAP_OFF)?0:1, |
| "#### JVMTIagent: ClassLoad occurred ####\n"); |
| |
| getVerdict(jni_env, "ClassLoad"); |
| |
| if (hotswap != HOTSWAP_OFF) { |
| /* enter into a raw monitor for exclusive work with redefined class */ |
| lock(jni_env); |
| display(0, "#### JVMTIagent: ClassLoad: >>>>>>>> entered the raw monitor \"eventLock\" ####\n"); |
| |
| if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(GetClassSignature, |
| jvmti_env, klass, &cls_sig, /*&generic*/NULL))) |
| NSK_CPP_STUB2(FatalError, jni_env, |
| "JVMTIagent: failed to get class signature\n"); |
| else { |
| if (shortTestName != NULL) { |
| if (strstr((const char*) cls_sig, shortTestName) != NULL) { |
| display(0, "#### JVMTIagent: found test class matched with \"%s\"\n\ |
| <JVMTIagent>\tsignature=%s\n", |
| shortTestName, cls_sig); |
| clsByteCount = allocClsInfo(jni_env, cls_sig, klass); |
| display(0, "#### JVMTIagent: %d bytes defining the class have been successfully loaded\n", |
| clsByteCount); |
| } |
| } |
| } |
| |
| /* exit from the raw monitor */ |
| unlock(jni_env); |
| display(0, "#### JVMTIagent: ClassLoad: <<<<<<<< exited from the raw monitor \"eventLock\" ####\n\n"); |
| } |
| } |
| |
| void JNICALL |
| ClassPrepare(jvmtiEnv *jvmti_env, JNIEnv *jni_env, |
| jthread thr, jclass cls) { |
| |
| display(1, "#### JVMTIagent: ClassPrepare occurred ####\n"); |
| |
| getVerdict(jni_env, "ClassPrepare"); |
| } |
| |
| void JNICALL |
| CompiledMethodLoad(jvmtiEnv *jvmti_env, jmethodID method, jint code_size, |
| const void* code_addr, jint map_length, |
| const jvmtiAddrLocationMap* map, const void* compile_info) { |
| |
| display(1, "#### JVMTIagent: CompiledMethodLoad occurred ####\n"); |
| |
| getVerdict(NULL, "CompiledMethodLoad"); |
| } |
| |
| void JNICALL |
| CompiledMethodUnload(jvmtiEnv *jvmti_env, jmethodID method, |
| const void* code_addr) { |
| |
| display(1, "#### JVMTIagent: CompiledMethodUnload occurred ####\n"); |
| |
| getVerdict(NULL, "CompiledMethodUnload"); |
| } |
| |
| void JNICALL |
| DataDumpRequest(jvmtiEnv *jvmti_env) { |
| |
| display(1, "#### JVMTIagent: DataDumpRequest occurred ####\n"); |
| |
| getVerdict(NULL, "DataDumpRequest"); |
| } |
| |
| void JNICALL |
| DynamicCodeGenerated(jvmtiEnv *jvmti_env, |
| const char* name, |
| const void* address, |
| jint length) { |
| |
| display(1, "#### JVMTIagent: DynamicCodeGenerated occurred ####\n"); |
| |
| getVerdict(NULL, "DynamicCodeGenerated"); |
| } |
| |
| void JNICALL |
| Exception(jvmtiEnv *jvmti_env, JNIEnv *jni_env, jthread thr, |
| jmethodID method, jlocation location, jobject exception, |
| jmethodID catch_method, jlocation catch_location) { |
| jclass decl_clazz; |
| |
| display((hotswap == HOTSWAP_EVERY_EXCEPTION || |
| hotswap == HOTSWAP_EVERY_EXCEPTION_FOR_EVERY_CLASS)?0:1, |
| "#### JVMTIagent: Exception occurred ####\n"); |
| |
| getVerdict(jni_env, "Exception"); |
| |
| if (hotswap == HOTSWAP_EVERY_EXCEPTION || |
| hotswap == HOTSWAP_EVERY_EXCEPTION_FOR_EVERY_CLASS) { |
| if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3(GetMethodDeclaringClass, |
| jvmti_env, method, &decl_clazz))) |
| NSK_CPP_STUB2(FatalError, jni_env, |
| "JVMTIagent: failed to get method declaring class\n"); |
| |
| if (findAndHotSwap(jni_env, decl_clazz) != 0) |
| NSK_CPP_STUB2(FatalError, jni_env, |
| "JVMTIagent: failed to hotswap class\n"); |
| } |
| } |
| |
| void JNICALL |
| FieldAccess(jvmtiEnv *jvmti_env, JNIEnv *jni_env, |
| jthread thr, jmethodID method, |
| jlocation location, jclass field_klass, jobject obj, jfieldID field) { |
| |
| display(1, "#### JVMTIagent: FieldAccess occurred ####\n"); |
| |
| getVerdict(jni_env, "FieldAccess"); |
| } |
| |
| void JNICALL |
| FieldModification(jvmtiEnv *jvmti_env, JNIEnv *jni_env, |
| jthread thr, jmethodID method, jlocation location, |
| jclass field_klass, jobject obj, |
| jfieldID field, char sig, jvalue new_value) { |
| |
| display(1, "#### JVMTIagent: FieldModification occurred ####\n"); |
| |
| getVerdict(jni_env, "FieldModification"); |
| } |
| |
| void JNICALL |
| FramePop(jvmtiEnv *jvmti_env, JNIEnv *jni_env, |
| jthread thr, jmethodID method, jboolean wasPopedByException) { |
| |
| display(1, "#### JVMTIagent: FramePop occurred ####\n"); |
| |
| getVerdict(jni_env, "FramePop"); |
| } |
| |
| void JNICALL |
| GarbageCollectionFinish(jvmtiEnv *jvmti_env) { |
| |
| display(1, "#### JVMTIagent: GarbageCollectionFinish occurred ####\n"); |
| |
| getVerdict(NULL, "GarbageCollectionFinish"); |
| } |
| |
| void JNICALL |
| GarbageCollectionStart(jvmtiEnv *jvmti_env) { |
| |
| display(1, "#### JVMTIagent: GarbageCollectionStart occurred ####\n"); |
| |
| getVerdict(NULL, "GarbageCollectionStart"); |
| } |
| |
| void JNICALL |
| MonitorContendedEnter(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thr, |
| jobject obj) { |
| |
| display(1, "#### JVMTIagent: MonitorContendedEnter occurred ####\n"); |
| |
| getVerdict(jni_env, "MonitorContendedEnter"); |
| } |
| |
| void JNICALL |
| MonitorContendedEntered(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thr, |
| jobject obj) { |
| |
| display(1, "#### JVMTIagent: MonitorContendedEntered occurred ####\n"); |
| |
| getVerdict(jni_env, "MonitorContendedEntered"); |
| } |
| |
| void JNICALL |
| MonitorWait(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thr, jobject obj, |
| jlong tout) { |
| |
| display(1, "#### JVMTIagent: MonitorWait occurred ####\n"); |
| |
| getVerdict(jni_env, "MonitorWait"); |
| } |
| |
| void JNICALL |
| MonitorWaited(jvmtiEnv *jvmti_env, JNIEnv* jni_env, |
| jthread thr, jobject obj, jboolean timed_out) { |
| |
| display(1, "#### JVMTIagent: MonitorWaited occurred ####\n"); |
| |
| getVerdict(jni_env, "MonitorWaited"); |
| } |
| |
| void JNICALL |
| NativeMethodBind(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread, |
| jmethodID method, void *addr, void **new_addr) { |
| |
| display(1, "#### JVMTIagent: NativeMethodBind occurred ####\n"); |
| |
| getVerdict(jni_env, "NativeMethodBind"); |
| } |
| |
| void JNICALL |
| ObjectFree(jvmtiEnv *jvmti_env, jlong tag) { |
| |
| display(1, "#### JVMTIagent: ObjectFree occurred ####\n"); |
| |
| getVerdict(NULL, "ObjectFree"); |
| } |
| |
| void JNICALL |
| ThreadEnd(jvmtiEnv *jvmti_env, JNIEnv *jni_env, jthread thread) { |
| |
| display(1, "#### JVMTIagent: ThreadEnd occurred ####\n"); |
| |
| getVerdict(jni_env, "ThreadEnd"); |
| } |
| |
| void JNICALL |
| ThreadStart(jvmtiEnv *jvmti_env, JNIEnv *jni_env, jthread thread) { |
| |
| display(1, "#### JVMTIagent: ThreadStart occurred ####\n"); |
| |
| getVerdict(jni_env, "ThreadStart"); |
| } |
| |
| void JNICALL |
| VMDeath(jvmtiEnv *jvmti_env, JNIEnv *jni_env) { |
| vm_death_occured = TRUE; |
| |
| display(0, "#### JVMTIagent: VMDeath occurred ####\n"); |
| |
| if (hotswap != HOTSWAP_OFF) { |
| deallocClsInfo(jni_env); |
| display(0, "#### JVMTIagent: allocated memory was successfully freed ####\n"); |
| } |
| } |
| |
| void JNICALL |
| VMInit(jvmtiEnv *jvmti_env, JNIEnv *jni_env, jthread thr) { |
| |
| display(0, "#### JVMTIagent: VMInit occurred ####\n"); |
| |
| getVerdict(jni_env, "VMInit"); |
| } |
| |
| void JNICALL |
| VMStart(jvmtiEnv *jvmti_env, JNIEnv* jni_env) { |
| |
| display(0, "#### JVMTIagent: VMStart occurred ####\n"); |
| |
| getVerdict(jni_env, "VMStart"); |
| } |
| |
| JNIEXPORT void JNICALL |
| VMObjectAlloc(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread, |
| jobject object, jclass object_klass, jlong size) { |
| |
| display(1, "#### JVMTIagent: VMObjectAlloc occurred ####\n"); |
| |
| getVerdict(jni_env, "VMObjectAlloc"); |
| } |
| |
| void JNICALL |
| SingleStep(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread, |
| jmethodID method, jlocation location) { |
| jclass decl_clazz; |
| |
| display((hotswap == HOTSWAP_EVERY_SINGLE_STEP)?0:1, |
| "#### JVMTIagent: SingleStep occurred ####\n"); |
| |
| getVerdict(jni_env, "SingleStep"); |
| |
| if (hotswap == HOTSWAP_EVERY_SINGLE_STEP) { |
| if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3(GetMethodDeclaringClass, |
| jvmti_env, method, &decl_clazz))) |
| NSK_CPP_STUB2(FatalError, jni_env, |
| "JVMTIagent: failed to get method declaring class\n"); |
| |
| if (findAndHotSwap(jni_env, decl_clazz) != 0) |
| NSK_CPP_STUB2(FatalError, jni_env, |
| "JVMTIagent: failed to hotswap class\n"); |
| } |
| } |
| |
| void JNICALL |
| MethodEntry(jvmtiEnv *jvmti_env, JNIEnv *jni_env, |
| jthread thr, jmethodID method) { |
| jclass decl_clazz; |
| |
| display((hotswap == HOTSWAP_EVERY_METHOD_ENTRY || |
| hotswap == HOTSWAP_EVERY_METHOD_ENTRY_FOR_EVERY_CLASS)?0:1, |
| "#### JVMTIagent: MethodEntry occurred ####\n"); |
| |
| getVerdict(jni_env, "MethodEntry"); |
| |
| if (hotswap == HOTSWAP_EVERY_METHOD_ENTRY || |
| hotswap == HOTSWAP_EVERY_METHOD_ENTRY_FOR_EVERY_CLASS) { |
| if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3(GetMethodDeclaringClass, |
| jvmti_env, method, &decl_clazz))) |
| NSK_CPP_STUB2(FatalError, jni_env, |
| "JVMTIagent: failed to get method declaring class\n"); |
| |
| if (findAndHotSwap(jni_env, decl_clazz) != 0) |
| NSK_CPP_STUB2(FatalError, jni_env, |
| "JVMTIagent: failed to hotswap class\n"); |
| } |
| } |
| |
| void JNICALL |
| MethodExit(jvmtiEnv *jvmti_env, JNIEnv *jni_env, |
| jthread thr, jmethodID method, |
| jboolean was_poped_by_exc, jvalue return_value) { |
| |
| display(1, "#### JVMTIagent: MethodExit occurred ####\n"); |
| |
| getVerdict(jni_env, "MethodExit"); |
| } |
| |
| void JNICALL |
| ExceptionCatch(jvmtiEnv *jvmti_env, JNIEnv *jni_env, jthread thr, |
| jmethodID method, jlocation location, jobject exception) { |
| jclass decl_clazz; |
| |
| display((hotswap == HOTSWAP_EVERY_EXCEPTION || |
| hotswap == HOTSWAP_EVERY_EXCEPTION_FOR_EVERY_CLASS)?0:1, |
| "#### JVMTIagent: ExceptionCatch occurred ####\n"); |
| |
| getVerdict(jni_env, "ExceptionCatch"); |
| |
| if (hotswap == HOTSWAP_EVERY_EXCEPTION || |
| hotswap == HOTSWAP_EVERY_EXCEPTION_FOR_EVERY_CLASS) { |
| if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3(GetMethodDeclaringClass, |
| jvmti_env, method, &decl_clazz))) |
| NSK_CPP_STUB2(FatalError, jni_env, |
| "JVMTIagent: failed to get method declaring class\n"); |
| |
| if (findAndHotSwap(jni_env, decl_clazz) != 0) |
| NSK_CPP_STUB2(FatalError, jni_env, |
| "JVMTIagent: failed to hotswap class\n"); |
| } |
| } |
| /************************/ |
| |
| static void lock(JNIEnv *jni_env) { |
| if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(RawMonitorEnter, |
| jvmti, eventLock))) |
| NSK_CPP_STUB2(FatalError, jni_env, |
| "JVMTIagent: failed to enter a raw monitor\n"); |
| } |
| |
| static void unlock(JNIEnv *jni_env) { |
| if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(RawMonitorExit, |
| jvmti, eventLock))) |
| NSK_CPP_STUB2(FatalError, jni_env, |
| "JVMTIagent: failed to exit a raw monitor\n"); |
| } |
| |
| JNIEXPORT jint JNICALL |
| Java_nsk_share_RASagent_setHotSwapMode(JNIEnv *jni_env, jclass cls, |
| jboolean vrb, jint level, jstring shortName) { |
| jvmtiCapabilities capabil; |
| jmethodID mid = NULL; |
| |
| if (jvmti == NULL) { |
| printf("ERROR(%s,%d): JVMTIagent was not properly loaded: JVMTI env = NULL\n", |
| __FILE__, __LINE__); |
| return 1; |
| } |
| |
| /* get supported JVMTI capabilities */ |
| if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(GetCapabilities, |
| jvmti, &capabil))) |
| NSK_CPP_STUB2(FatalError, jni_env, |
| "JVMTIagent: failed to get capabilities\n"); |
| if (capabil.can_redefine_classes != 1) { /* ???????????? */ |
| printf("ERROR: JVMTIagent: Class File Redefinition (HotSwap) is not implemented in this VM\n"); |
| return 1; |
| } |
| |
| if (vrb == JNI_TRUE && debug_mode == 0) |
| debug_mode = 1; |
| |
| hotswap = level; |
| switch (hotswap) { |
| case HOTSWAP_OFF: |
| display(0, "#### JVMTIagent: hotswap mode off ####\n"); |
| return 0; |
| case HOTSWAP_EVERY_METHOD_ENTRY: |
| stress_lev = 2; |
| display(0, "#### JVMTIagent: hotswapping class in every method entry event enabled ####\n\ |
| <JVMTIagent>\tHotSwap stress level: %d\n", |
| stress_lev); |
| break; |
| case HOTSWAP_EVERY_METHOD_ENTRY_FOR_EVERY_CLASS: |
| stress_lev = 2; |
| display(0, "#### JVMTIagent: hotswapping class in every method entry event for every class enabled ####\n\ |
| <JVMTIagent>\tHotSwap stress level: %d\n", |
| stress_lev); |
| break; |
| case HOTSWAP_EVERY_SINGLE_STEP: |
| stress_lev = 3; |
| display(0, "#### JVMTIagent: hotswapping class in every single step event enabled ####\n\ |
| <JVMTIagent>\tHotSwap stress level: %d\n", |
| stress_lev); |
| break; |
| case HOTSWAP_EVERY_EXCEPTION: |
| stress_lev = 4; |
| display(0, "#### JVMTIagent: hotswapping class in every exception event enabled ####\n\ |
| <JVMTIagent>\tHotSwap stress level: %d\n", |
| stress_lev); |
| break; |
| case HOTSWAP_EVERY_EXCEPTION_FOR_EVERY_CLASS: |
| stress_lev = 40; |
| display(0, "#### JVMTIagent: hotswapping class in every exception event for every class enabled ####\n\ |
| <JVMTIagent>\tHotSwap stress level: %d\n", |
| stress_lev); |
| break; |
| default: |
| printf("ERROR(%s,%d): JVMTIagent: unknown value of HotSwap stress level: \"%d\"\n", |
| __FILE__,__LINE__,hotswap); |
| return 1; |
| } |
| |
| if (!NSK_JNI_VERIFY(jni_env, (shortTestName = NSK_CPP_STUB3(GetStringUTFChars, |
| jni_env, shortName, NULL)) != NULL)) { |
| printf("ERROR: JVMTIagent: unable to get UTF-8 characters of the string\n"); |
| return 1; |
| } |
| display(0, "#### JVMTIagent: short name of current test is \"%s\"\n", |
| shortTestName); |
| |
| if (!NSK_JNI_VERIFY(jni_env, (rasCls = NSK_CPP_STUB2(NewGlobalRef, |
| jni_env, cls)) != NULL)) { |
| printf("ERROR JVMTIagent: unable to create a new global reference of the class \"RASagent\"\n"); |
| return 1; |
| } |
| |
| if (addStressEvents() != 0) { |
| printf("ERROR(%s,%d): JVMTIagent terminated abnormally! ####\n", |
| __FILE__,__LINE__); |
| return 1; |
| } |
| |
| return 0; |
| } |
| |
| static jint allocClsInfo(JNIEnv *jni_env, char *cls_sig, jclass clazz) { |
| class_info *_clsInfo = NULL; |
| jmethodID mid = NULL; |
| jbyteArray classBytes; |
| jboolean isCopy; |
| |
| if ((_clsInfo = (class_info*) |
| malloc(sizeof(class_info))) == NULL) |
| NSK_CPP_STUB2(FatalError, jni_env, |
| "JVMTIagent: cannot allocate memory for class_info\n"); |
| |
| /* fill the structure class_info */ |
| _clsInfo->clazzsig = cls_sig; |
| |
| if (!NSK_JNI_VERIFY(jni_env, ((*_clsInfo).cls = NSK_CPP_STUB2(NewGlobalRef, |
| jni_env, clazz)) != NULL)) { |
| printf("ERROR: JVMTIagent: unable to create a new global reference of class \"%s\"\n", |
| _clsInfo->clazzsig); |
| free(_clsInfo); |
| deallocClsInfo(jni_env); |
| NSK_CPP_STUB2(FatalError, jni_env, |
| "JVMTIagent: unable to create a new global reference of class\n"); |
| } |
| |
| if (!NSK_JNI_VERIFY(jni_env, (mid = |
| NSK_CPP_STUB4(GetStaticMethodID, jni_env, rasCls, |
| "loadFromClassFile", "(Ljava/lang/String;)[B")) != NULL)) |
| NSK_CPP_STUB2(FatalError, jni_env, |
| "JVMTIagent: unable to get ID of the method \"loadFromClassFile\"\n"); |
| |
| classBytes = (jbyteArray) NSK_CPP_STUB4(CallStaticObjectMethod, |
| jni_env, rasCls, mid, NSK_CPP_STUB2(NewStringUTF, jni_env, cls_sig)); |
| |
| clearJavaException(jni_env); |
| |
| (*_clsInfo).bCount = NSK_CPP_STUB2(GetArrayLength, jni_env, classBytes); |
| |
| (*_clsInfo).clsBytes = |
| NSK_CPP_STUB3(GetByteArrayElements, jni_env, classBytes, &isCopy); |
| |
| _clsInfo->next = NULL; |
| |
| if (clsInfo != NULL) { |
| clsInfo->next = (struct class_info*) _clsInfo; |
| } |
| else { |
| clsInfoFst = _clsInfo; |
| } |
| clsInfo = _clsInfo; |
| |
| return (*_clsInfo).bCount; |
| } |
| |
| static void deallocClsInfo(JNIEnv *jni_env) { |
| class_info *clsInfoCurr = clsInfoFst; |
| |
| NSK_TRACE(NSK_CPP_STUB2(DeleteGlobalRef, jni_env, rasCls)); |
| |
| while(clsInfoCurr != NULL) { |
| class_info *_clsInfo = clsInfoCurr; |
| |
| if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(Deallocate, |
| jvmti, (unsigned char*) clsInfoCurr->clazzsig))) |
| NSK_CPP_STUB2(FatalError, jni_env, |
| "JVMTIagent: failed to deallocate memory for clazzsig\n"); |
| |
| NSK_TRACE(NSK_CPP_STUB2(DeleteGlobalRef, jni_env, clsInfoCurr->cls)); |
| |
| clsInfoCurr = (class_info*) clsInfoCurr->next; |
| |
| free(_clsInfo); |
| } |
| /* fix for 4756585: indicate that stucture class_info is empty now */ |
| clsInfoFst = NULL; |
| } |
| |
| static int findAndHotSwap(JNIEnv *jni_env, jclass clazz) { |
| int ret_code = 0; |
| char *clazzsig = NULL; |
| class_info *clsInfoCurr = clsInfoFst; |
| |
| display(1, "\n#### JVMTIagent: findAndHotSwap: obtaining class signature of class to be hotswap ...\n"); |
| if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(GetClassSignature, |
| jvmti, clazz, &clazzsig, /*&generic*/NULL))) |
| NSK_CPP_STUB2(FatalError, jni_env, |
| "JVMTIagent: findAndHotSwap: failed to get class signature\n"); |
| else { |
| display(1, "#### JVMTIagent: findAndHotSwap: ... class signature obtained: \"%s\"\n", |
| clazzsig); |
| |
| /* enter into a raw monitor for exclusive work with redefined class */ |
| lock(jni_env); |
| display(0, "#### JVMTIagent: findAndHotSwap: >>>>>>>> entered the raw monitor \"eventLock\" ####\n"); |
| |
| while(clsInfoCurr != NULL) { |
| if (hotswap == HOTSWAP_EVERY_METHOD_ENTRY_FOR_EVERY_CLASS || |
| hotswap == HOTSWAP_EVERY_EXCEPTION_FOR_EVERY_CLASS) { |
| display(1, "\n#### JVMTIagent: findAndHotSwap: going to hotswap tested class \"%s\" during execution of class \"%s\" ...\n", |
| clsInfoCurr->clazzsig, clazzsig); |
| if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(Deallocate, |
| jvmti, (unsigned char*) clazzsig))) |
| NSK_CPP_STUB2(FatalError, jni_env, |
| "JVMTIagent: findAndHotSwap: failed to deallocate memory for clazzsig\n"); |
| |
| if (doHotSwap(jni_env, clsInfoCurr->cls, |
| clsInfoCurr->bCount, clsInfoCurr->clsBytes) != 0) { |
| ret_code = 1; |
| break; |
| } |
| } |
| else { |
| if (strcmp(clazzsig, clsInfoCurr->clazzsig) == 0) { |
| display(0, "\n#### JVMTIagent: findAndHotSwap: tested class found \"%s\" ...\n", |
| clazzsig); |
| |
| if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(Deallocate, |
| jvmti, (unsigned char*) clazzsig))) |
| NSK_CPP_STUB2(FatalError, jni_env, |
| "JVMTIagent: findAndHotSwap: failed to deallocate memory for clazzsig\n"); |
| |
| display(0, "\n#### JVMTIagent: findAndHotSwap: going to hotswap tested class \"%s\" ...\n", |
| clsInfoCurr->clazzsig); |
| if (doHotSwap(jni_env, clsInfoCurr->cls, |
| clsInfoCurr->bCount, clsInfoCurr->clsBytes) != 0) { |
| ret_code = 1; |
| break; |
| } |
| } |
| } |
| |
| clsInfoCurr = (class_info*) clsInfoCurr->next; |
| } |
| |
| /* exit raw monitor */ |
| unlock(jni_env); |
| display(0, "#### JVMTIagent: findAndHotSwap: <<<<<<<< exited from the raw monitor \"eventLock\" ####\n\n"); |
| } |
| |
| return ret_code; |
| } |
| |
| static int doHotSwap(JNIEnv *jni_env, jclass redefCls, jint bCount, |
| jbyte *classBytes) { |
| jvmtiClassDefinition classDef; |
| |
| /* fill the structure jvmtiClassDefinition */ |
| classDef.klass = redefCls; |
| classDef.class_byte_count = bCount; |
| classDef.class_bytes = (unsigned char*) classBytes; |
| |
| display(0, "#### JVMTIagent: >>>>>>>> Invoke RedefineClasses():\n\ |
| <JVMTIagent>\tnew class byte count=%d\n", |
| classDef.class_byte_count); |
| if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3(RedefineClasses, |
| jvmti, 1, &classDef))) |
| return 1; |
| |
| display(0, "#### JVMTIagent: <<<<<<<< RedefineClasses() is successfully done ####\n"); |
| |
| return 0; |
| } |
| |
| static int addStressEvents() { |
| static int stepEventSet = JNI_FALSE; |
| static int methodsEventSet = JNI_FALSE; |
| static int excCatchEventSet = JNI_FALSE; |
| |
| if (stress_lev >= 3) { |
| /* SingleStep events */ |
| if (stepEventSet == JNI_FALSE) { /* don't set the event twice */ |
| display(0, "#### JVMTIagent: setting SingleStep events ...\n"); |
| |
| callbacks.SingleStep = &SingleStep; |
| |
| if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, |
| jvmti, JVMTI_ENABLE, JVMTI_EVENT_SINGLE_STEP, NULL))) |
| return JNI_ERR; |
| |
| stepEventSet = JNI_TRUE; |
| |
| display(0, "#### JVMTIagent: ... setting SingleStep events done\n"); |
| } |
| } |
| |
| if (stress_lev >= 2) { |
| /* MethodEntry/Exit events */ |
| if (methodsEventSet == JNI_FALSE) { /* don't set the event twice */ |
| display(0, "#### JVMTIagent: setting MethodEntry events ...\n"); |
| |
| callbacks.MethodEntry = &MethodEntry; |
| |
| if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, |
| jvmti, JVMTI_ENABLE, JVMTI_EVENT_METHOD_ENTRY, NULL))) |
| return JNI_ERR; |
| |
| display(0, "#### JVMTIagent: ... setting MethodEntry events done\n"); |
| |
| /* MethodExit events */ |
| display(0, "#### JVMTIagent: setting MethodExit events ...\n"); |
| |
| callbacks.MethodExit = &MethodExit; |
| |
| if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, |
| jvmti, JVMTI_ENABLE, JVMTI_EVENT_METHOD_EXIT, NULL))) |
| return JNI_ERR; |
| |
| display(0, "#### JVMTIagent: ... setting MethodExit events done\n"); |
| |
| methodsEventSet = JNI_TRUE; |
| } |
| } |
| |
| if (stress_lev >= 1) { |
| /* ExceptionCatch events */ |
| if (excCatchEventSet == JNI_FALSE) { /* don't set the event twice */ |
| display(0, "#### JVMTIagent: setting ExceptionCatch events ...\n"); |
| |
| callbacks.ExceptionCatch = &ExceptionCatch; |
| |
| if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, |
| jvmti, JVMTI_ENABLE, JVMTI_EVENT_EXCEPTION_CATCH, NULL))) |
| return JNI_ERR; |
| |
| excCatchEventSet = JNI_TRUE; |
| |
| display(0, "#### JVMTIagent: ... setting ExceptionCatch events done\n"); |
| } |
| } |
| |
| if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3(SetEventCallbacks, |
| jvmti, &callbacks, sizeof(callbacks)))) |
| return JNI_ERR; |
| else |
| return 0; |
| } |
| |
| static int enableEventsCaps() { |
| jvmtiCapabilities caps; |
| |
| memset(&caps, 0, sizeof(jvmtiCapabilities)); |
| |
| /* add all capabilities */ |
| caps.can_redefine_classes = 1; |
| caps.can_generate_breakpoint_events = 1; |
| caps.can_generate_all_class_hook_events = 1; |
| caps.can_generate_single_step_events = 1; |
| caps.can_generate_method_entry_events = 1; |
| caps.can_generate_method_exit_events = 1; |
| caps.can_generate_exception_events = 1; |
| caps.can_generate_compiled_method_load_events = 1; |
| caps.can_generate_field_access_events = 1; |
| caps.can_generate_field_modification_events = 1; |
| caps.can_generate_frame_pop_events = 1; |
| caps.can_generate_garbage_collection_events = 1; |
| caps.can_generate_monitor_events = 1; |
| caps.can_generate_native_method_bind_events = 1; |
| caps.can_generate_object_free_events = 1; |
| caps.can_generate_vm_object_alloc_events = 1; |
| if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(AddCapabilities, |
| jvmti, &caps))) |
| return JNI_ERR; |
| |
| /* Breakpoint events */ |
| display(0, "#### JVMTIagent: setting Breakpoint events ...\n"); |
| |
| callbacks.Breakpoint = &Breakpoint; |
| |
| if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, |
| jvmti, JVMTI_ENABLE, JVMTI_EVENT_BREAKPOINT, NULL))) |
| return JNI_ERR; |
| display(0, "#### JVMTIagent: ... setting Breakpoint events done\n"); |
| |
| /* ClassFileLoadHook events */ |
| display(0, "#### JVMTIagent: setting ClassFileLoadHook events ...\n"); |
| |
| callbacks.ClassFileLoadHook = &ClassFileLoadHook; |
| |
| if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, |
| jvmti, JVMTI_ENABLE, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, NULL))) |
| return JNI_ERR; |
| display(0, "#### JVMTIagent: ... setting ClassFileLoadHook events done\n"); |
| |
| /* ClassLoad events */ |
| display(0, "#### JVMTIagent: setting ClassLoad events ...\n"); |
| |
| callbacks.ClassLoad = &ClassLoad; |
| |
| if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, |
| jvmti, JVMTI_ENABLE, JVMTI_EVENT_CLASS_LOAD, NULL))) |
| return JNI_ERR; |
| display(0, "#### JVMTIagent: ... setting ClassLoad events done\n"); |
| |
| /* ClassPrepare events */ |
| display(0, "#### JVMTIagent: setting ClassPrepare events ...\n"); |
| |
| callbacks.ClassPrepare = &ClassPrepare; |
| |
| if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, |
| jvmti, JVMTI_ENABLE, JVMTI_EVENT_CLASS_PREPARE, NULL))) |
| return JNI_ERR; |
| display(0, "#### JVMTIagent: ... setting ClassPrepare events done\n"); |
| |
| /* CompiledMethodLoad events */ |
| display(0, "#### JVMTIagent: setting CompiledMethodLoad events ...\n"); |
| |
| callbacks.CompiledMethodLoad = &CompiledMethodLoad; |
| |
| if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, |
| jvmti, JVMTI_ENABLE, JVMTI_EVENT_COMPILED_METHOD_LOAD, NULL))) |
| return JNI_ERR; |
| display(0, "#### JVMTIagent: ... setting CompiledMethodLoad events done\n"); |
| |
| /* CompiledMethodUnload events */ |
| display(0, "#### JVMTIagent: setting CompiledMethodUnload events ...\n"); |
| |
| callbacks.CompiledMethodUnload = &CompiledMethodUnload; |
| |
| if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, |
| jvmti, JVMTI_ENABLE, JVMTI_EVENT_COMPILED_METHOD_UNLOAD, NULL))) |
| return JNI_ERR; |
| display(0, "#### JVMTIagent: ... setting CompiledMethodUnload events done\n"); |
| |
| /* DataDumpRequest events */ |
| display(0, "#### JVMTIagent: setting DataDumpRequest events ...\n"); |
| |
| callbacks.DataDumpRequest = &DataDumpRequest; |
| |
| if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, |
| jvmti, JVMTI_ENABLE, JVMTI_EVENT_DATA_DUMP_REQUEST, NULL))) |
| return JNI_ERR; |
| display(0, "#### JVMTIagent: ... setting DataDumpRequest events done\n"); |
| |
| /* DynamicCodeGenerated events */ |
| display(0, "#### JVMTIagent: setting DynamicCodeGenerated events ...\n"); |
| |
| callbacks.DynamicCodeGenerated = &DynamicCodeGenerated; |
| |
| if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, |
| jvmti, JVMTI_ENABLE, JVMTI_EVENT_DYNAMIC_CODE_GENERATED, NULL))) |
| return JNI_ERR; |
| display(0, "#### JVMTIagent: ... setting DynamicCodeGenerated events done\n"); |
| |
| /* Exception events */ |
| display(0, "#### JVMTIagent: setting Exception events ...\n"); |
| |
| callbacks.Exception = &Exception; |
| |
| if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, |
| jvmti, JVMTI_ENABLE, JVMTI_EVENT_EXCEPTION, NULL))) |
| return JNI_ERR; |
| display(0, "#### JVMTIagent: ... setting Exception events done\n"); |
| |
| /* FieldAccess events */ |
| display(0, "#### JVMTIagent: setting FieldAccess events ...\n"); |
| |
| callbacks.FieldAccess = &FieldAccess; |
| |
| if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, |
| jvmti, JVMTI_ENABLE, JVMTI_EVENT_FIELD_ACCESS, NULL))) |
| return JNI_ERR; |
| display(0, "#### JVMTIagent: ... setting FieldAccess events done\n"); |
| |
| /* FieldModification events */ |
| display(0, "#### JVMTIagent: setting FieldModification events ...\n"); |
| |
| callbacks.FieldModification = &FieldModification; |
| |
| if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, |
| jvmti, JVMTI_ENABLE, JVMTI_EVENT_FIELD_MODIFICATION, NULL))) |
| return JNI_ERR; |
| display(0, "#### JVMTIagent: ... setting FieldModification events done\n"); |
| |
| /* FramePop events */ |
| display(0, "#### JVMTIagent: setting FramePop events ...\n"); |
| |
| callbacks.FramePop = &FramePop; |
| |
| if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, |
| jvmti, JVMTI_ENABLE, JVMTI_EVENT_FRAME_POP, NULL))) |
| return JNI_ERR; |
| display(0, "#### JVMTIagent: ... setting FramePop events done\n"); |
| |
| /* GarbageCollectionFinish events */ |
| display(0, "#### JVMTIagent: setting GarbageCollectionFinish events ...\n"); |
| |
| callbacks.GarbageCollectionFinish = &GarbageCollectionFinish; |
| |
| if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, |
| jvmti, JVMTI_ENABLE, JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, NULL))) |
| return JNI_ERR; |
| display(0, "#### JVMTIagent: ... setting GarbageCollectionFinish events done\n"); |
| |
| /* GarbageCollectionStart events */ |
| display(0, "#### JVMTIagent: setting GarbageCollectionStart events ...\n"); |
| |
| callbacks.GarbageCollectionStart = &GarbageCollectionStart; |
| |
| if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, |
| jvmti, JVMTI_ENABLE, JVMTI_EVENT_GARBAGE_COLLECTION_START, NULL))) |
| return JNI_ERR; |
| display(0, "#### JVMTIagent: ... setting GarbageCollectionStart events done\n"); |
| |
| /* MonitorContendedEnter events */ |
| display(0, "#### JVMTIagent: setting MonitorContendedEnter events ...\n"); |
| |
| callbacks.MonitorContendedEnter = &MonitorContendedEnter; |
| |
| if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, |
| jvmti, JVMTI_ENABLE, JVMTI_EVENT_MONITOR_CONTENDED_ENTER, NULL))) |
| return JNI_ERR; |
| display(0, "#### JVMTIagent: ... setting MonitorContendedEnter events done\n"); |
| |
| /* MonitorContendedEntered events */ |
| display(0, "#### JVMTIagent: setting MonitorContendedEntered events ...\n"); |
| |
| callbacks.MonitorContendedEntered = &MonitorContendedEntered; |
| |
| if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, |
| jvmti, JVMTI_ENABLE, JVMTI_EVENT_MONITOR_CONTENDED_ENTERED, NULL))) |
| return JNI_ERR; |
| display(0, "#### JVMTIagent: ... setting MonitorContendedEntered events done\n"); |
| |
| /* MonitorWait events */ |
| display(0, "#### JVMTIagent: setting MonitorWait events ...\n"); |
| |
| callbacks.MonitorWait = &MonitorWait; |
| |
| if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, |
| jvmti, JVMTI_ENABLE, JVMTI_EVENT_MONITOR_WAIT, NULL))) |
| return JNI_ERR; |
| display(0, "#### JVMTIagent: ... setting MonitorWait events done\n"); |
| |
| /* MonitorWaited events */ |
| display(0, "#### JVMTIagent: setting MonitorWaited events ...\n"); |
| |
| callbacks.MonitorWaited = &MonitorWaited; |
| |
| if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, |
| jvmti, JVMTI_ENABLE, JVMTI_EVENT_MONITOR_WAITED, NULL))) |
| return JNI_ERR; |
| display(0, "#### JVMTIagent: ... setting MonitorWaited events done\n"); |
| |
| /* NativeMethodBind events */ |
| display(0, "#### JVMTIagent: setting NativeMethodBind events ...\n"); |
| |
| callbacks.NativeMethodBind = &NativeMethodBind; |
| |
| if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, |
| jvmti, JVMTI_ENABLE, JVMTI_EVENT_NATIVE_METHOD_BIND, NULL))) |
| return JNI_ERR; |
| display(0, "#### JVMTIagent: ... setting NativeMethodBind events done\n"); |
| |
| /* ObjectFree events */ |
| display(0, "#### JVMTIagent: setting ObjectFree events ...\n"); |
| |
| callbacks.ObjectFree = &ObjectFree; |
| |
| if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, |
| jvmti, JVMTI_ENABLE, JVMTI_EVENT_OBJECT_FREE, NULL))) |
| return JNI_ERR; |
| display(0, "#### JVMTIagent: ... setting ObjectFree events done\n"); |
| |
| /* ThreadEnd events */ |
| display(0, "#### JVMTIagent: setting ThreadEnd events ...\n"); |
| |
| callbacks.ThreadEnd = &ThreadEnd; |
| |
| if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, |
| jvmti, JVMTI_ENABLE, JVMTI_EVENT_THREAD_END, NULL))) |
| return JNI_ERR; |
| display(0, "#### JVMTIagent: ... setting ThreadEnd events done\n"); |
| |
| /* ThreadStart events */ |
| display(0, "#### JVMTIagent: setting ThreadStart events ...\n"); |
| |
| callbacks.ThreadStart = &ThreadStart; |
| |
| if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, |
| jvmti, JVMTI_ENABLE, JVMTI_EVENT_THREAD_START, NULL))) |
| return JNI_ERR; |
| display(0, "#### JVMTIagent: ... setting ThreadStart events done\n"); |
| |
| /* VMDeath events */ |
| display(0, "#### JVMTIagent: setting VMDeath events ...\n"); |
| |
| callbacks.VMDeath = &VMDeath; |
| |
| if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, |
| jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_DEATH, NULL))) |
| return JNI_ERR; |
| display(0, "#### JVMTIagent: ... setting VMDeath events done\n"); |
| |
| /* VMInit events */ |
| display(0, "#### JVMTIagent: setting VMInit events ...\n"); |
| |
| callbacks.VMInit = &VMInit; |
| |
| if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, |
| jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, NULL))) |
| return JNI_ERR; |
| display(0, "#### JVMTIagent: ... setting VMInit events done\n"); |
| |
| /* VMStart events */ |
| display(0, "#### JVMTIagent: setting VMStart events ...\n"); |
| |
| callbacks.VMStart = &VMStart; |
| |
| if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, |
| jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_START, NULL))) |
| return JNI_ERR; |
| display(0, "#### JVMTIagent: ... setting VMStart events done\n"); |
| |
| /* VMObjectAlloc events */ |
| display(0, "#### JVMTIagent: setting VMObjectAlloc events ...\n"); |
| |
| callbacks.VMObjectAlloc = &VMObjectAlloc; |
| |
| if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, |
| jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_OBJECT_ALLOC, NULL))) |
| return JNI_ERR; |
| display(0, "#### JVMTIagent: ... setting VMObjectAlloc events done\n"); |
| |
| if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3(SetEventCallbacks, |
| jvmti, &callbacks, sizeof(callbacks)))) |
| return JNI_ERR; |
| |
| return 0; |
| } |
| |
| static void clearJavaException(JNIEnv* jni_env) { |
| if (NSK_CPP_STUB1(ExceptionOccurred, jni_env)) { |
| |
| NSK_CPP_STUB1(ExceptionDescribe, jni_env); |
| NSK_CPP_STUB1(ExceptionClear, jni_env); |
| |
| NSK_CPP_STUB2(FatalError, jni_env, |
| "JVMTIagent: exception occurred in java code, aborting\n"); |
| } |
| } |
| |
| static int get_tok(char **src, char *buf, int buflen, char sep) { |
| int i; |
| char *p = *src; |
| for (i = 0; i < buflen; i++) { |
| if (p[i] == 0 || p[i] == sep) { |
| buf[i] = 0; |
| if (p[i] == sep) { |
| i++; |
| } |
| *src += i; |
| return i; |
| } |
| buf[i] = p[i]; |
| } |
| /* overflow */ |
| return 0; |
| } |
| |
| static void doSetup(char *str) { |
| if (str == 0) |
| str = ""; |
| |
| if ((strcmp(str, "help")) == 0) { |
| printf("#### JVMTIagent usage: -agentlib:JVMTIagent[=[help]|[=[verbose]|[verbose2],[stress0|stress1|stress2|stress3]]]\n"); |
| printf("#### where: help\tprint this message\n"); |
| printf("#### verbose\tturn verbose mode on\n"); |
| printf("#### verbose2\tturn extended verbose mode on (including reporting JVMTI events)\n"); |
| printf("#### stress0, or empty value\tturn stress level 0 on (default mode):\n"); |
| printf("#### enable event generation except ExceptionCatch, MethodEntry/Exit, SingleStep\n"); |
| printf("#### stress1\tturn stress level 1 on:\n"); |
| printf("#### enable generation of ExceptionCatch events\n"); |
| printf("#### stress2\tturn stress level 2 on:\n"); |
| printf("#### enable generation of ExceptionCatch,\n"); |
| printf("#### MethodEntry/Exit events\n"); |
| printf("#### stress3\tturn stress level 3 on:\n"); |
| printf("#### enable generation of ExceptionCatch,\n"); |
| printf("#### MethodEntry/Exit,\n"); |
| printf("#### SingleStep events\n"); |
| exit(1); |
| } |
| |
| while (*str) { |
| char buf[1000]; |
| |
| if (!get_tok(&str, buf, sizeof(buf), ',')) { |
| printf("ERROR: JVMTIagent: bad option: \"%s\"!\n", str); |
| exit(1); |
| } |
| if ((strcmp(buf, "verbose")) == 0) { |
| printf("#### JVMTIagent: turned verbose mode on ####\n"); |
| debug_mode = 1; |
| } |
| if ((strcmp(buf, "verbose2")) == 0) { |
| printf("#### JVMTIagent: turned extended verbose mode on ####\n"); |
| debug_mode = 2; |
| } |
| if ((strcmp(buf, "stress0")) == 0) { |
| if (debug_mode > 0) |
| printf("#### JVMTIagent: turned stress level 0 on ####\n"); |
| stress_lev = 0; |
| } |
| if ((strcmp(buf, "stress1")) == 0) { |
| if (debug_mode > 0) |
| printf("#### JVMTIagent: turned stress level 1 on ####\n"); |
| stress_lev = 1; |
| } |
| if ((strcmp(buf, "stress2")) == 0) { |
| if (debug_mode > 0) |
| printf("#### JVMTIagent: turned stress level 2 on ####\n"); |
| stress_lev = 2; |
| } |
| if ((strcmp(buf, "stress3")) == 0) { |
| if (debug_mode > 0) |
| printf("#### JVMTIagent: turned stress level 3 on ####\n"); |
| stress_lev = 3; |
| } |
| } |
| } |
| |
| static void getVerdict(JNIEnv *jni_env, const char *evnt) { |
| char error_msg[80]; |
| |
| if (vm_death_occured == TRUE) { |
| sprintf(error_msg, "JVMTIagent: getVerdict: %s event occured after VMDeath", |
| evnt); |
| |
| if (jni_env==NULL) { /* some event callbacks have no pointer to jni */ |
| printf("ERROR: %s\n", error_msg); |
| exit(97); |
| } |
| else |
| NSK_CPP_STUB2(FatalError, jni_env, error_msg); |
| } |
| } |
| |
| static void display(int level, const char format[], ...) { |
| va_list ar; |
| |
| if (debug_mode > level) { |
| va_start(ar, format); |
| vprintf(format, ar); |
| va_end(ar); |
| } |
| } |
| |
| /* agent procedure */ |
| static void JNICALL |
| agentProc(jvmtiEnv* jvmti_env, JNIEnv* jni_env, void* arg) { |
| } |
| |
| JNIEXPORT jint JNICALL |
| Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { |
| /* create JVMTI environment */ |
| if (!NSK_VERIFY((jvmti = |
| nsk_jvmti_createJVMTIEnv(jvm, reserved)) != NULL)) |
| return JNI_ERR; |
| |
| doSetup(options); |
| |
| if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3(CreateRawMonitor, |
| jvmti, "_event_lock", &eventLock))) |
| return JNI_ERR; |
| |
| if (enableEventsCaps() == 0 && addStressEvents() == 0) { |
| display(0, "#### JVMTIagent: all events were successfully enabled and capabilities/events callbacks set ####\n\n"); |
| } else { |
| printf("ERROR(%s,%d): JVMTIagent terminated abnormally! ####\n", |
| __FILE__,__LINE__); |
| return JNI_ERR; |
| } |
| |
| /* register agent proc and arg */ |
| if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agentProc, NULL))) |
| return JNI_ERR; |
| |
| return JNI_OK; |
| } |
| |
| #ifdef __cplusplus |
| } |
| #endif |