1 /*
   2  * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 #include <stdio.h>
  24 #include <jvmti.h>
  25 #include "agent_common.h"
  26 #include <jni.h>
  27 #include <string.h>
  28 
  29 #include "jni_tools.h"
  30 #include "jvmti_tools.h"
  31 
  32 
  33 extern "C" {
  34 static JNIEnv* jni = NULL;
  35 static jvmtiEnv *jvmti = NULL;
  36 static jlong timeout = 0;
  37 static jint testStep;
  38 static jint redefineNumber;
  39 static unsigned char* newClassBytes;
  40 static unsigned char* path;
  41 static jthread testedThread;
  42 static jclass testClass;
  43 static jclass myTestClass;
  44 
  45 #define NAME "nsk/jvmti/scenarios/hotswap/HS204/hs204t001/hs204t001R"
  46 #define CLASS_NAME "Lnsk/jvmti/scenarios/hotswap/HS204/hs204t001/hs204t001R;"
  47 #define PATH_TO_NEW_BYTECODE "pathToNewByteCode"
  48 #define FILE_NAME "nsk/jvmti/scenarios/hotswap/HS204/hs204t001/hs204t001R"
  49 static jint newClassSize;
  50 
  51 char *getClassName(jvmtiEnv *jvmti, jclass  klass) {
  52     char * className;
  53     char * generic;
  54     if( !NSK_JVMTI_VERIFY(NSK_CPP_STUB4(GetClassSignature, jvmti, klass, &className, &generic))) {
  55         nsk_jvmti_setFailStatus();
  56     }
  57     return className;
  58 }
  59 
  60 JNIEXPORT void JNICALL
  61 callbackClassLoad(jvmtiEnv *jvmti_env,
  62         JNIEnv* jni_env,
  63         jthread thread,
  64         jclass klass) {
  65     char * name;
  66     name = getClassName(jvmti_env,klass);
  67     if( (strcmp(name,CLASS_NAME ) == 0) && (redefineNumber== 1) ) {
  68        char fileName[512];
  69         nsk_jvmti_getFileName(redefineNumber, FILE_NAME, fileName,
  70                         sizeof(fileName)/sizeof(char));
  71         NSK_DISPLAY1(">>>>>>CallbackClassLoad ... Name=%s...  >>\n",name);
  72         if ( nsk_jvmti_redefineClass(jvmti, klass, fileName) == NSK_TRUE) {
  73             NSK_DISPLAY0("\nMyClass :: Successfully redefined..\n");
  74             redefineNumber++;
  75         } else {
  76             NSK_COMPLAIN0("\nMyClass :: Failed to redefine ..\n");
  77         }
  78         /* if( (myTestClass =NSK_CPP_STUB2(NewGlobalRef,jni_env, klass)) == NULL) {
  79            NSK_COMPLAIN0("Failed to create global ref...");
  80            }
  81          */
  82     }
  83 }
  84 
  85 JNIEXPORT void JNICALL
  86 callbackClassPrepare(jvmtiEnv *jvmti_env,
  87         JNIEnv* jni_env,
  88         jthread thread,
  89         jclass klass) {
  90     char *  name;
  91     name = getClassName(jvmti_env, klass);
  92     if ( (strcmp(name, CLASS_NAME) ==0 ) && (redefineNumber == 0) ) {
  93         char fileName[512];
  94         nsk_jvmti_getFileName(redefineNumber, FILE_NAME, fileName,
  95                         sizeof(fileName)/sizeof(char));
  96         NSK_DISPLAY1(">>>>>>callbackClassPrepare ... Name=%s...  >>\n",name);
  97         if ( nsk_jvmti_redefineClass(jvmti, klass, fileName) == NSK_TRUE) {
  98             NSK_DISPLAY0("\nMyClass :: Successfully redefined..\n");
  99             redefineNumber++;
 100         } else {
 101             NSK_COMPLAIN0("\nMyClass :: Failed to redefine ..\n");
 102         }
 103         if( (myTestClass = (jclass) NSK_CPP_STUB2(NewGlobalRef,jni_env, klass)) == NULL) {
 104             NSK_COMPLAIN0("Failed to create global ref...");
 105         }
 106     }
 107 }
 108 
 109 JNIEXPORT void JNICALL
 110 callbackClassFileLoadHock(jvmtiEnv *jvmti_env,
 111         JNIEnv* jni_env,
 112         jclass class_being_redefined,
 113         jobject loader,
 114         const char* name,
 115         jobject protection_domain,
 116         jint class_data_len,
 117         const unsigned char* class_data,
 118         jint* new_class_data_len,
 119         unsigned char** new_class_data) {
 120     if (name != NULL && strcmp(name, NAME)==0 && (redefineNumber == 1 )) {
 121         NSK_DISPLAY1(">>>>>>callbackClassFileLoadHock ... Name=%s...  >>\n",name);
 122         /*redefineClass(jvmti_env, myTestClass);*/
 123     }
 124 }
 125 
 126 JNIEXPORT void JNICALL
 127 #ifdef STATIC_BUILD
 128 Agent_OnUnload_hs204t001(JavaVM *jvm)
 129 #else
 130 Agent_OnUnload(JavaVM *jvm)
 131 #endif
 132 {
 133     NSK_DISPLAY0(" VM ... Going Down.. (C/C++) \n");
 134     return;
 135 }
 136 
 137 static void JNICALL agentProc(jvmtiEnv* jvmti, JNIEnv* agentJNI, void* arg) {
 138     redefineNumber = 0;
 139     jni = agentJNI;
 140     testStep=1;
 141     NSK_DISPLAY0("\n\n>>>> Debugge started, waiting for class loading \n");
 142     jni->DeleteGlobalRef(testClass);
 143     jni->DeleteGlobalRef(testedThread);
 144     NSK_DISPLAY0("Waiting for debuggee to become ready\n");
 145     if (!nsk_jvmti_waitForSync(timeout)) {
 146         return;
 147     }
 148     testStep = 1;
 149     NSK_DISPLAY0("\n\n>>>> Debugge started, waiting for class loading \n");
 150     if (!nsk_jvmti_resumeSync())
 151         return;
 152     NSK_DISPLAY0("Waiting for debuggee's threads to finish\n");
 153     if (!nsk_jvmti_waitForSync(timeout))
 154         return;
 155     jni->DeleteGlobalRef(testClass);
 156     jni->DeleteGlobalRef(testedThread);
 157     NSK_DISPLAY0("Let debuggee to finish\n");
 158     if (!nsk_jvmti_resumeSync())
 159         return;
 160 }
 161 
 162 #ifdef STATIC_BUILD
 163 JNIEXPORT jint JNICALL Agent_OnLoad_hs204t001(JavaVM *jvm, char *options, void *reserved) {
 164     return Agent_Initialize(jvm, options, reserved);
 165 }
 166 JNIEXPORT jint JNICALL Agent_OnAttach_hs204t001(JavaVM *jvm, char *options, void *reserved) {
 167     return Agent_Initialize(jvm, options, reserved);
 168 }
 169 JNIEXPORT jint JNI_OnLoad_hs204t001(JavaVM *jvm, char *options, void *reserved) {
 170     return JNI_VERSION_1_8;
 171 }
 172 #endif
 173 jint  Agent_Initialize(JavaVM *vm, char *options, void *reserved) {
 174     jint rc ;
 175     NSK_DISPLAY0(" VM.. Started..\n");
 176     rc=vm->GetEnv((void **)&jvmti, JVMTI_VERSION_1_1);
 177     if ( rc!= JNI_OK ) {
 178         NSK_COMPLAIN0(" Could not load JVMTI interface \n");
 179     } else {
 180         /* Open simple block for better memor usage. */
 181         jvmtiCapabilities caps;
 182         memset(&caps, 0, sizeof(caps));
 183 
 184         /*
 185            set capabilities of
 186            1.ClassFileLoadHock,
 187            2.ClassLoad(doesn;t require any capabilities to set).
 188            3.ClassPrepare (doesn;t require any capabilitiesto set).
 189            4.Redefine (default).
 190            5.PopFrame.
 191          */
 192         caps.can_generate_all_class_hook_events=1;
 193         caps.can_access_local_variables = 1;
 194         caps.can_generate_single_step_events=1;
 195         caps.can_redefine_classes = 1;
 196         caps.can_suspend = 1;
 197         caps.can_pop_frame=1;
 198         caps.can_generate_all_class_hook_events=1;
 199         jvmti->AddCapabilities(&caps);
 200         /*
 201            set the method and other functions..
 202          */
 203         {
 204             jvmtiEventCallbacks eventCallbacks;
 205             memset(&eventCallbacks, 0, sizeof(eventCallbacks));
 206             eventCallbacks.ClassLoad = callbackClassLoad;
 207             eventCallbacks.ClassPrepare=callbackClassPrepare;
 208             eventCallbacks.ClassFileLoadHook=callbackClassFileLoadHock;
 209             rc=jvmti->SetEventCallbacks(&eventCallbacks, sizeof(eventCallbacks));
 210             if (rc != JVMTI_ERROR_NONE) {
 211                 NSK_COMPLAIN0("Error setting event callbacks");
 212                 return JNI_ERR;
 213             }
 214         }
 215         {
 216             nsk_jvmti_enableNotification(jvmti, JVMTI_EVENT_SINGLE_STEP, testedThread);
 217             nsk_jvmti_enableNotification(jvmti, JVMTI_EVENT_CLASS_LOAD, testedThread);
 218             nsk_jvmti_enableNotification(jvmti, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, testedThread);
 219             nsk_jvmti_enableNotification(jvmti, JVMTI_EVENT_CLASS_PREPARE, testedThread);
 220             nsk_jvmti_enableNotification(jvmti, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK,testedThread);
 221         }
 222 
 223         if (!nsk_jvmti_setAgentProc(agentProc, NULL)) {
 224             NSK_COMPLAIN0("setAgentProc failed");
 225         }
 226         if (!nsk_jvmti_parseOptions(options)) {
 227             NSK_COMPLAIN0("Cannot parse options");
 228         }
 229         NSK_DISPLAY1("Wait time: %d\n",nsk_jvmti_getWaitTime());
 230         timeout=nsk_jvmti_getWaitTime();
 231         NSK_DISPLAY1(" returning back.. enter timeout-->%d  \n",timeout);
 232         return JNI_OK;
 233     }
 234     // TODO: shouldn't we return JNI_ERR if GetEnv failed?
 235     return JNI_OK;
 236 }
 237 
 238 JNIEXPORT void JNICALL
 239 Java_nsk_jvmti_scenarios_hotswap_HS204_hs204t001_hs204t001_setThread(JNIEnv * env,
 240                          jclass klass,
 241              jobject thread) {
 242     NSK_DISPLAY0(" Inside the setThread Method");
 243     if (!NSK_JNI_VERIFY(env, (testClass =(jclass) NSK_CPP_STUB2(NewGlobalRef, env, klass)) != NULL))
 244         nsk_jvmti_setFailStatus();
 245     if (!NSK_JNI_VERIFY(env, (testedThread =NSK_CPP_STUB2(NewGlobalRef, env, thread)) != NULL))
 246         nsk_jvmti_setFailStatus();
 247 }
 248 
 249 JNIEXPORT jboolean JNICALL
 250 Java_nsk_jvmti_scenarios_hotswap_HS204_hs204t001_hs204t001_suspendThread(JNIEnv * env,
 251         jclass klass,
 252         jobject thread) {
 253     jint state;
 254     NSK_DISPLAY0("---suspend thread .. \n");
 255     if (NSK_CPP_STUB3(GetThreadState,jvmti,thread, &state) == JVMTI_ERROR_NONE) {
 256         NSK_DISPLAY0(" No Errors in finding state of the thread.\n");
 257         if (state & JVMTI_THREAD_STATE_ALIVE) {
 258             NSK_DISPLAY0(" Thread state is alive .. So can be suspend should be possible ..\n");
 259             nsk_jvmti_disableNotification(jvmti, JVMTI_EVENT_SINGLE_STEP, thread);
 260             if (!NSK_JVMTI_VERIFY(  NSK_CPP_STUB2(SuspendThread, jvmti, thread))) {
 261                 NSK_COMPLAIN0("TEST FAILED: unable to suspend the thread \n");
 262                 nsk_jvmti_setFailStatus();
 263                 return NSK_FALSE;
 264             } else {
 265                 NSK_DISPLAY0(" Sucessfully suspended Thread..\n" );
 266             }
 267         } else {
 268             NSK_COMPLAIN0("Was not able to suspend a thread..\n");
 269             return NSK_FALSE;
 270         }
 271     }
 272     return NSK_TRUE;
 273 }
 274 
 275 JNIEXPORT jboolean JNICALL
 276 Java_nsk_jvmti_scenarios_hotswap_HS204_hs204t001_hs204t001_popFrame(JNIEnv * env,
 277         jclass klass,
 278         jthread thread) {
 279     jint state;
 280     NSK_DISPLAY0("Inside pop_Frame method.....\n");
 281     if (NSK_CPP_STUB3(GetThreadState,jvmti,thread, &state) == JVMTI_ERROR_NONE) {
 282         NSK_DISPLAY0(" Got the state of thread \n");
 283         if ( state & JVMTI_THREAD_STATE_SUSPENDED) {
 284             NSK_DISPLAY0(" Thread is already in suspended mode..\n");
 285             if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(PopFrame, jvmti, thread))) {
 286                 NSK_COMPLAIN0(" TEST FAILED: UNABLE TO POP FRAME \n");
 287                 nsk_jvmti_setFailStatus();
 288                 return NSK_FALSE;
 289             } else {
 290                 NSK_DISPLAY0(" Poped frame safely..");
 291             }
 292             /* We should resume that thread for next execution.. */
 293             if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(ResumeThread, jvmti, thread))) {
 294                 NSK_COMPLAIN0(" TEST FAILED: UNABLE TO Resume thread \n");
 295                 nsk_jvmti_setFailStatus();
 296                 return NSK_FALSE;
 297             } else {
 298                 NSK_DISPLAY0(" Resumed.. thread for next set of executions...");
 299             }
 300         } else {
 301             NSK_DISPLAY0(" Thread is not in Suspened State for poping its status..");
 302         }
 303     }
 304     return NSK_TRUE;
 305 }
 306 }