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 <stdlib.h> 25 #include <jvmti.h> 26 #include "agent_common.h" 27 #include <jni.h> 28 #include <string.h> 29 #include "jvmti_tools.h" 30 #include "jni_tools.h" 31 #include "JVMTITools.h" 32 /* 33 hs203T003: 34 1. Set FieldAccessWatch, FieldModificatoinWatch for a field. 35 2. Upon access/modification of the field within a method, redefine 36 a class with the changed field version, and pop a currently executed 37 frame within FieldAccess/FieldModification callback. 38 39 */ 40 extern "C" { 41 #define DIR_NAME "newclass" 42 #define PATH_FORMAT "%s%02d/%s" 43 44 #define FILE_NAME "nsk/jvmti/scenarios/hotswap/HS203/hs203t003/MyThread" 45 #define CLASS_NAME "Lnsk/jvmti/scenarios/hotswap/HS203/hs203t003/MyThread;" 46 #define SEARCH_NAME "nsk/jvmti/scenarios/hotswap/HS203/hs203t003/MyThread" 47 #define FIELDNAME "threadState" 48 #define TYPE "I" 49 50 static jint redefineNumber; 51 static jvmtiEnv * jvmti; 52 static int redefineCnt=0; 53 54 JNIEXPORT void JNICALL callbackClassPrepare(jvmtiEnv *jvmti_env, 55 JNIEnv* jni, 56 jthread thread, 57 jclass klass) { 58 char * className; 59 char * generic; 60 redefineNumber=0; 61 className=NULL; 62 generic=NULL; 63 if ( ! NSK_JVMTI_VERIFY ( NSK_CPP_STUB4(GetClassSignature, 64 jvmti_env, klass, &className, &generic) ) ) { 65 nsk_printf("#error Agent :: while getting classname Signature.\n"); 66 nsk_jvmti_agentFailed(); 67 } else { 68 if (strcmp(className,CLASS_NAME) == 0) { 69 jfieldID field; 70 /* get the field id and set watch on that .*/ 71 if (! NSK_JNI_VERIFY(jni, (field = NSK_CPP_STUB4(GetFieldID, 72 jni, klass, FIELDNAME, TYPE)) != NULL) ) { 73 nsk_printf(" Agent :: (*JNI)->GetFieldID(jni, ... ) returns `null`.\n"); 74 nsk_jvmti_agentFailed(); 75 } else if ( ! NSK_JVMTI_VERIFY(NSK_CPP_STUB3(SetFieldAccessWatch, 76 jvmti_env, klass, field) ) ) { 77 nsk_printf("#error Agent :: occured while jvmti->SetFieldAccessWatch(... ) .\n"); 78 nsk_jvmti_agentFailed(); 79 } 80 } 81 } 82 } 83 84 JNIEXPORT void JNICALL callbackFieldAccess(jvmtiEnv *jvmti_env, 85 JNIEnv* jni, 86 jthread thread, 87 jmethodID method, 88 jlocation location, 89 jclass field_klass, 90 jobject object, 91 jfieldID field) { 92 jclass clas; 93 char fileName[512]; 94 if (redefineCnt < 10) { 95 redefineCnt++; 96 return; 97 } 98 redefineNumber=0; 99 if (! NSK_JNI_VERIFY(jni, (clas = NSK_CPP_STUB2(FindClass, jni, SEARCH_NAME)) != NULL) ) { 100 nsk_printf(" Agent :: (*JNI)->FindClass(jni, %s) returns `null`.\n",SEARCH_NAME); 101 nsk_jvmti_agentFailed(); 102 } else { 103 nsk_jvmti_getFileName(redefineNumber, FILE_NAME, fileName, 104 sizeof(fileName)/sizeof(char)); 105 if ( nsk_jvmti_redefineClass(jvmti_env, clas, fileName ) != NSK_TRUE) { 106 nsk_printf(" Agent :: Failed to redefine.\n"); 107 nsk_jvmti_agentFailed(); 108 } else { 109 nsk_printf(" Agent :: Redefined.\n"); 110 nsk_printf(" Agent :: Suspendeding thread.\n"); 111 /* pop the current working frame. */ 112 if ( ! NSK_JVMTI_VERIFY( NSK_CPP_STUB2(SuspendThread, jvmti_env, thread) ) ) { 113 nsk_printf("#error Agent :: occured suspending Thread.\n"); 114 nsk_jvmti_agentFailed(); 115 } else { 116 nsk_printf(" Agent :: Succeded in suspending.\n"); 117 } 118 } 119 } 120 } 121 122 #ifdef STATIC_BUILD 123 JNIEXPORT jint JNICALL Agent_OnLoad_hs203t003(JavaVM *jvm, char *options, void *reserved) { 124 return Agent_Initialize(jvm, options, reserved); 125 } 126 JNIEXPORT jint JNICALL Agent_OnAttach_hs203t003(JavaVM *jvm, char *options, void *reserved) { 127 return Agent_Initialize(jvm, options, reserved); 128 } 129 JNIEXPORT jint JNI_OnLoad_hs203t003(JavaVM *jvm, char *options, void *reserved) { 130 return JNI_VERSION_1_8; 131 } 132 #endif 133 jint Agent_Initialize(JavaVM *vm, char *options, void *reserved) { 134 if ( ! NSK_VERIFY ( JNI_OK == NSK_CPP_STUB3(GetEnv, vm, 135 (void **)&jvmti, JVMTI_VERSION_1_1) ) ) { 136 nsk_printf(" Agent :: Could not load JVMTI interface.\n"); 137 return JNI_ERR; 138 } else { 139 jvmtiCapabilities caps; 140 jvmtiEventCallbacks eventCallbacks; 141 if (nsk_jvmti_parseOptions(options) == NSK_FALSE ) { 142 nsk_printf("#error Agent :: Failed to parse options.\n"); 143 return JNI_ERR; 144 } 145 memset(&caps, 0, sizeof(caps)); 146 caps.can_redefine_classes = 1; 147 caps.can_suspend=1; 148 caps.can_pop_frame=1; 149 caps.can_generate_all_class_hook_events=1; 150 caps.can_generate_field_access_events=1; 151 if (! NSK_JVMTI_VERIFY ( NSK_CPP_STUB2(AddCapabilities, jvmti, &caps) )) { 152 nsk_printf("#error Agent :: while adding capabilities.\n"); 153 return JNI_ERR; 154 } 155 memset(&eventCallbacks, 0, sizeof(eventCallbacks)); 156 eventCallbacks.ClassPrepare =callbackClassPrepare; 157 eventCallbacks.FieldAccess= callbackFieldAccess; 158 if (!NSK_JVMTI_VERIFY( 159 NSK_CPP_STUB3(SetEventCallbacks, jvmti, 160 &eventCallbacks, sizeof(eventCallbacks)))) { 161 nsk_printf("#error Agent :: while setting event callbacks.\n"); 162 return JNI_ERR; 163 } 164 if ( ( nsk_jvmti_enableNotification(jvmti,JVMTI_EVENT_CLASS_PREPARE, NULL) 165 == NSK_TRUE ) && 166 ( nsk_jvmti_enableNotification(jvmti,JVMTI_EVENT_FIELD_ACCESS, NULL) 167 == NSK_TRUE ) ) { 168 nsk_printf(" Agent :: Notifications are enabled.\n"); 169 } else { 170 nsk_printf("#error Agent :: Eanableing Notifications.\n"); 171 return JNI_ERR; 172 } 173 } 174 return JNI_OK; 175 } 176 177 JNIEXPORT jboolean JNICALL 178 Java_nsk_jvmti_scenarios_hotswap_HS203_hs203t003_hs203t003_isSuspended(JNIEnv * jni, 179 jclass clas, 180 jthread thread) { 181 jboolean retvalue; 182 jint state; 183 retvalue = JNI_FALSE; 184 if ( ! NSK_JVMTI_VERIFY( NSK_CPP_STUB3(GetThreadState, jvmti, thread, &state) ) ) { 185 nsk_printf(" Agent :: Error while getting thread state.\n"); 186 nsk_jvmti_agentFailed(); 187 } else { 188 if ( state & JVMTI_THREAD_STATE_SUSPENDED) { 189 retvalue = JNI_TRUE; 190 } 191 } 192 return retvalue; 193 } 194 195 JNIEXPORT jboolean JNICALL 196 Java_nsk_jvmti_scenarios_hotswap_HS203_hs203t003_hs203t003_popThreadFrame(JNIEnv * jni, 197 jclass clas, 198 jthread thread) { 199 jboolean retvalue; 200 jint state; 201 retvalue = JNI_FALSE; 202 if ( ! NSK_JVMTI_VERIFY( NSK_CPP_STUB3(GetThreadState, jvmti, thread, &state) ) ) { 203 nsk_printf(" Agent :: Error while getting thread state.\n"); 204 nsk_jvmti_agentFailed(); 205 } else { 206 if ( state & JVMTI_THREAD_STATE_SUSPENDED) { 207 if ( ! NSK_JVMTI_VERIFY ( NSK_CPP_STUB2( PopFrame, jvmti, thread) ) ) { 208 nsk_printf("#error Agent :: while poping thread's frame.\n"); 209 nsk_jvmti_agentFailed(); 210 } else { 211 nsk_printf(" Agent :: poped thread frame.\n"); 212 if ( ! NSK_JVMTI_VERIFY ( NSK_CPP_STUB4 (SetEventNotificationMode, jvmti, 213 JVMTI_DISABLE, JVMTI_EVENT_FIELD_ACCESS, NULL) ) ) { 214 nsk_printf("#error Agent :: failed to disable notification JVMTI_EVENT_FIELD ACCESS.\n"); 215 nsk_jvmti_agentFailed(); 216 } else { 217 nsk_printf(" Agent :: Disabled notification JVMTI_EVENT_FIELD ACCESS. \n"); 218 retvalue = JNI_TRUE; 219 } 220 } 221 } else { 222 nsk_printf("#error Agent :: Thread was not suspened."); 223 nsk_jvmti_agentFailed(); 224 } 225 } 226 return retvalue; 227 } 228 229 JNIEXPORT jboolean JNICALL 230 Java_nsk_jvmti_scenarios_hotswap_HS203_hs203t003_hs203t003_resumeThread(JNIEnv * jni, 231 jclass clas, 232 jthread thread) { 233 jboolean retvalue; 234 retvalue = JNI_FALSE; 235 if ( !NSK_JVMTI_VERIFY( NSK_CPP_STUB2 ( ResumeThread, jvmti, thread)) ) { 236 nsk_printf("#error Agent :: while resuming thread.\n"); 237 nsk_jvmti_agentFailed(); 238 } else { 239 nsk_printf(" Agent :: Thread resumed.\n"); 240 retvalue= JNI_TRUE; 241 } 242 return retvalue; 243 } 244 245 }