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 }