998d0baab0
Reviewed-by: jwaters, gli, coleenp, lmesnik
1208 lines
42 KiB
C++
1208 lines
42 KiB
C++
/*
|
|
* Copyright (c) 2004, 2024, 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.hpp"
|
|
#include "jni_tools.hpp"
|
|
#include "JVMTITools.hpp"
|
|
#include "jvmti_tools.hpp"
|
|
|
|
extern "C" {
|
|
|
|
static jvmtiEnv *jvmti = nullptr; /* 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 = nullptr; /* name of the test without package prefix */
|
|
static jclass rasCls; /* reference to the auxiliary class RASagent used for HotSwap */
|
|
static class_info *clsInfo = nullptr, *clsInfoFst = nullptr;
|
|
|
|
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(jvmti_env->GetClassSignature(klass, &cls_sig, /*&generic*/nullptr)))
|
|
jni_env->FatalError("JVMTIagent: failed to get class signature\n");
|
|
else {
|
|
if (shortTestName != nullptr) {
|
|
if (strstr((const char*) cls_sig, shortTestName) != nullptr) {
|
|
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(nullptr, "CompiledMethodLoad");
|
|
}
|
|
|
|
void JNICALL
|
|
CompiledMethodUnload(jvmtiEnv *jvmti_env, jmethodID method,
|
|
const void* code_addr) {
|
|
|
|
display(1, "#### JVMTIagent: CompiledMethodUnload occurred ####\n");
|
|
|
|
getVerdict(nullptr, "CompiledMethodUnload");
|
|
}
|
|
|
|
void JNICALL
|
|
DataDumpRequest(jvmtiEnv *jvmti_env) {
|
|
|
|
display(1, "#### JVMTIagent: DataDumpRequest occurred ####\n");
|
|
|
|
getVerdict(nullptr, "DataDumpRequest");
|
|
}
|
|
|
|
void JNICALL
|
|
DynamicCodeGenerated(jvmtiEnv *jvmti_env,
|
|
const char* name,
|
|
const void* address,
|
|
jint length) {
|
|
|
|
display(1, "#### JVMTIagent: DynamicCodeGenerated occurred ####\n");
|
|
|
|
getVerdict(nullptr, "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(jvmti_env->GetMethodDeclaringClass(method, &decl_clazz)))
|
|
jni_env->FatalError("JVMTIagent: failed to get method declaring class\n");
|
|
|
|
if (findAndHotSwap(jni_env, decl_clazz) != 0)
|
|
jni_env->FatalError("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(nullptr, "GarbageCollectionFinish");
|
|
}
|
|
|
|
void JNICALL
|
|
GarbageCollectionStart(jvmtiEnv *jvmti_env) {
|
|
|
|
display(1, "#### JVMTIagent: GarbageCollectionStart occurred ####\n");
|
|
|
|
getVerdict(nullptr, "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(nullptr, "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(jvmti_env->GetMethodDeclaringClass(method, &decl_clazz)))
|
|
jni_env->FatalError("JVMTIagent: failed to get method declaring class\n");
|
|
|
|
if (findAndHotSwap(jni_env, decl_clazz) != 0)
|
|
jni_env->FatalError("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(jvmti_env->GetMethodDeclaringClass(method, &decl_clazz)))
|
|
jni_env->FatalError("JVMTIagent: failed to get method declaring class\n");
|
|
|
|
if (findAndHotSwap(jni_env, decl_clazz) != 0)
|
|
jni_env->FatalError("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(jvmti_env->GetMethodDeclaringClass(method, &decl_clazz)))
|
|
jni_env->FatalError("JVMTIagent: failed to get method declaring class\n");
|
|
|
|
if (findAndHotSwap(jni_env, decl_clazz) != 0)
|
|
jni_env->FatalError("JVMTIagent: failed to hotswap class\n");
|
|
}
|
|
}
|
|
/************************/
|
|
|
|
static void lock(JNIEnv *jni_env) {
|
|
if (!NSK_JVMTI_VERIFY(jvmti->RawMonitorEnter(eventLock)))
|
|
jni_env->FatalError("JVMTIagent: failed to enter a raw monitor\n");
|
|
}
|
|
|
|
static void unlock(JNIEnv *jni_env) {
|
|
if (!NSK_JVMTI_VERIFY(jvmti->RawMonitorExit(eventLock)))
|
|
jni_env->FatalError("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 = nullptr;
|
|
|
|
if (jvmti == nullptr) {
|
|
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(jvmti->GetCapabilities(&capabil)))
|
|
jni_env->FatalError("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 = jni_env->GetStringUTFChars(shortName, nullptr)) != nullptr)) {
|
|
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 = jni_env->NewGlobalRef(cls)) != nullptr)) {
|
|
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 = nullptr;
|
|
jmethodID mid = nullptr;
|
|
jbyteArray classBytes;
|
|
jboolean isCopy;
|
|
|
|
_clsInfo = (class_info*) malloc(sizeof(class_info));
|
|
if (_clsInfo == nullptr)
|
|
jni_env->FatalError("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 = jni_env->NewGlobalRef(clazz)) != nullptr)) {
|
|
printf("ERROR: JVMTIagent: unable to create a new global reference of class \"%s\"\n",
|
|
_clsInfo->clazzsig);
|
|
free(_clsInfo);
|
|
deallocClsInfo(jni_env);
|
|
jni_env->FatalError("JVMTIagent: unable to create a new global reference of class\n");
|
|
}
|
|
|
|
if (!NSK_JNI_VERIFY(jni_env, (mid =
|
|
jni_env->GetStaticMethodID(rasCls, "loadFromClassFile", "(Ljava/lang/String;)[B")) != nullptr))
|
|
jni_env->FatalError("JVMTIagent: unable to get ID of the method \"loadFromClassFile\"\n");
|
|
|
|
classBytes = (jbyteArray) jni_env->CallStaticObjectMethod(rasCls, mid, jni_env->NewStringUTF(cls_sig));
|
|
|
|
clearJavaException(jni_env);
|
|
|
|
(*_clsInfo).bCount = jni_env->GetArrayLength(classBytes);
|
|
|
|
(*_clsInfo).clsBytes =
|
|
jni_env->GetByteArrayElements(classBytes, &isCopy);
|
|
|
|
_clsInfo->next = nullptr;
|
|
|
|
if (clsInfo != nullptr) {
|
|
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(jni_env->DeleteGlobalRef(rasCls));
|
|
|
|
while (clsInfoCurr != nullptr) {
|
|
class_info *_clsInfo = clsInfoCurr;
|
|
|
|
if (!NSK_JVMTI_VERIFY(jvmti->Deallocate((unsigned char*) clsInfoCurr->clazzsig)))
|
|
jni_env->FatalError("JVMTIagent: failed to deallocate memory for clazzsig\n");
|
|
|
|
NSK_TRACE(jni_env->DeleteGlobalRef(clsInfoCurr->cls));
|
|
|
|
clsInfoCurr = (class_info*) clsInfoCurr->next;
|
|
|
|
free(_clsInfo);
|
|
}
|
|
/* fix for 4756585: indicate that stucture class_info is empty now */
|
|
clsInfoFst = nullptr;
|
|
}
|
|
|
|
static int findAndHotSwap(JNIEnv *jni_env, jclass clazz) {
|
|
int ret_code = 0;
|
|
char *clazzsig = nullptr;
|
|
class_info *clsInfoCurr = clsInfoFst;
|
|
|
|
display(1, "\n#### JVMTIagent: findAndHotSwap: obtaining class signature of class to be hotswap ...\n");
|
|
if (!NSK_JVMTI_VERIFY(jvmti->GetClassSignature(clazz, &clazzsig, /*&generic*/nullptr)))
|
|
jni_env->FatalError("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 != nullptr) {
|
|
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(jvmti->Deallocate((unsigned char*) clazzsig)))
|
|
jni_env->FatalError("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(jvmti->Deallocate((unsigned char*) clazzsig)))
|
|
jni_env->FatalError("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(jvmti->RedefineClasses(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(jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_SINGLE_STEP, nullptr)))
|
|
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(jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_METHOD_ENTRY, nullptr)))
|
|
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(jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_METHOD_EXIT, nullptr)))
|
|
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(jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_EXCEPTION_CATCH, nullptr)))
|
|
return JNI_ERR;
|
|
|
|
excCatchEventSet = JNI_TRUE;
|
|
|
|
display(0, "#### JVMTIagent: ... setting ExceptionCatch events done\n");
|
|
}
|
|
}
|
|
|
|
if (!NSK_JVMTI_VERIFY(jvmti->SetEventCallbacks(&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(jvmti->AddCapabilities(&caps)))
|
|
return JNI_ERR;
|
|
|
|
/* Breakpoint events */
|
|
display(0, "#### JVMTIagent: setting Breakpoint events ...\n");
|
|
|
|
callbacks.Breakpoint = &Breakpoint;
|
|
|
|
if (!NSK_JVMTI_VERIFY(jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_BREAKPOINT, nullptr)))
|
|
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(jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, nullptr)))
|
|
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(jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_CLASS_LOAD, nullptr)))
|
|
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(jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_CLASS_PREPARE, nullptr)))
|
|
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(jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_COMPILED_METHOD_LOAD, nullptr)))
|
|
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(jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_COMPILED_METHOD_UNLOAD, nullptr)))
|
|
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(jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_DATA_DUMP_REQUEST, nullptr)))
|
|
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(jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_DYNAMIC_CODE_GENERATED, nullptr)))
|
|
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(jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_EXCEPTION, nullptr)))
|
|
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(jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_FIELD_ACCESS, nullptr)))
|
|
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(jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_FIELD_MODIFICATION, nullptr)))
|
|
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(jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_FRAME_POP, nullptr)))
|
|
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(jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, nullptr)))
|
|
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(jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_GARBAGE_COLLECTION_START, nullptr)))
|
|
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(jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_MONITOR_CONTENDED_ENTER, nullptr)))
|
|
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(jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_MONITOR_CONTENDED_ENTERED, nullptr)))
|
|
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(jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_MONITOR_WAIT, nullptr)))
|
|
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(jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_MONITOR_WAITED, nullptr)))
|
|
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(jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_NATIVE_METHOD_BIND, nullptr)))
|
|
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(jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_OBJECT_FREE, nullptr)))
|
|
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(jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_THREAD_END, nullptr)))
|
|
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(jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_THREAD_START, nullptr)))
|
|
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(jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_VM_DEATH, nullptr)))
|
|
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(jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, nullptr)))
|
|
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(jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_VM_START, nullptr)))
|
|
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(jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_VM_OBJECT_ALLOC, nullptr)))
|
|
return JNI_ERR;
|
|
display(0, "#### JVMTIagent: ... setting VMObjectAlloc events done\n");
|
|
|
|
if (!NSK_JVMTI_VERIFY(jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks))))
|
|
return JNI_ERR;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void clearJavaException(JNIEnv* jni_env) {
|
|
if (jni_env->ExceptionOccurred()) {
|
|
|
|
jni_env->ExceptionDescribe();
|
|
jni_env->ExceptionClear();
|
|
|
|
jni_env->FatalError("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 = (char*) "";
|
|
|
|
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) {
|
|
snprintf(error_msg, sizeof(error_msg), "JVMTIagent: getVerdict: %s event occured after VMDeath",
|
|
evnt);
|
|
|
|
if (jni_env == nullptr) { /* some event callbacks have no pointer to jni */
|
|
printf("ERROR: %s\n", error_msg);
|
|
exit(97);
|
|
}
|
|
else
|
|
jni_env->FatalError(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)) != nullptr))
|
|
return JNI_ERR;
|
|
|
|
doSetup(options);
|
|
|
|
if (!NSK_JVMTI_VERIFY(jvmti->CreateRawMonitor("_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, nullptr)))
|
|
return JNI_ERR;
|
|
|
|
return JNI_OK;
|
|
}
|
|
|
|
}
|