test/hotspot/jtreg/vmTestbase/nsk/share/JVMTIagent.c
changeset 49934 44839fbb20db
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/JVMTIagent.c	Mon Apr 30 18:10:24 2018 -0700
@@ -0,0 +1,1276 @@
+/*
+ * 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