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 (jvmti_env->GetClassSignature(klass, &className, &generic) ) ) { 64 nsk_printf("#error Agent :: while getting classname Signature.\n"); 65 nsk_jvmti_agentFailed(); 66 } else { 67 if (strcmp(className,CLASS_NAME) == 0) { 68 jfieldID field; 69 /* get the field id and set watch on that .*/ 70 if (! NSK_JNI_VERIFY(jni, (field = jni->GetFieldID(klass, FIELDNAME, TYPE)) != NULL) ) { 71 nsk_printf(" Agent :: (*JNI)->GetFieldID(jni, ... ) returns `null`.\n"); 72 nsk_jvmti_agentFailed(); 73 } else if ( ! NSK_JVMTI_VERIFY(jvmti_env->SetFieldAccessWatch(klass, field) ) ) { 74 nsk_printf("#error Agent :: occured while jvmti->SetFieldAccessWatch(... ) .\n"); 75 nsk_jvmti_agentFailed(); 76 } 77 } 78 } 79 } 80 81 JNIEXPORT void JNICALL callbackFieldAccess(jvmtiEnv *jvmti_env, 82 JNIEnv* jni, 83 jthread thread, 84 jmethodID method, 85 jlocation location, 86 jclass field_klass, 87 jobject object, 88 jfieldID field) { 89 jclass clas; 90 char fileName[512]; 91 if (redefineCnt < 10) { 92 redefineCnt++; 93 return; 94 } 95 redefineNumber=0; 96 if (! NSK_JNI_VERIFY(jni, (clas = jni->FindClass(SEARCH_NAME)) != NULL) ) { 97 nsk_printf(" Agent :: (*JNI)->FindClass(jni, %s) returns `null`.\n",SEARCH_NAME); 98 nsk_jvmti_agentFailed(); 99 } else { 100 nsk_jvmti_getFileName(redefineNumber, FILE_NAME, fileName, 101 sizeof(fileName)/sizeof(char)); 102 if ( nsk_jvmti_redefineClass(jvmti_env, clas, fileName ) != NSK_TRUE) { 103 nsk_printf(" Agent :: Failed to redefine.\n"); 104 nsk_jvmti_agentFailed(); 105 } else { 106 nsk_printf(" Agent :: Redefined.\n"); 107 nsk_printf(" Agent :: Suspendeding thread.\n"); 108 /* pop the current working frame. */ 109 if ( ! NSK_JVMTI_VERIFY(jvmti_env->SuspendThread(thread) ) ) { 110 nsk_printf("#error Agent :: occured suspending Thread.\n"); 111 nsk_jvmti_agentFailed(); 112 } else { 113 nsk_printf(" Agent :: Succeded in suspending.\n"); 114 } 115 } 116 } 117 } 118 119 #ifdef STATIC_BUILD 120 JNIEXPORT jint JNICALL Agent_OnLoad_hs203t003(JavaVM *jvm, char *options, void *reserved) { 121 return Agent_Initialize(jvm, options, reserved); 122 } 123 JNIEXPORT jint JNICALL Agent_OnAttach_hs203t003(JavaVM *jvm, char *options, void *reserved) { 124 return Agent_Initialize(jvm, options, reserved); 125 } 126 JNIEXPORT jint JNI_OnLoad_hs203t003(JavaVM *jvm, char *options, void *reserved) { 127 return JNI_VERSION_1_8; 128 } 129 #endif 130 jint Agent_Initialize(JavaVM *vm, char *options, void *reserved) { 131 if ( ! NSK_VERIFY ( JNI_OK == vm->GetEnv((void **)&jvmti, JVMTI_VERSION_1_1) ) ) { 132 nsk_printf(" Agent :: Could not load JVMTI interface.\n"); 133 return JNI_ERR; 134 } else { 135 jvmtiCapabilities caps; 136 jvmtiEventCallbacks eventCallbacks; 137 if (nsk_jvmti_parseOptions(options) == NSK_FALSE ) { 138 nsk_printf("#error Agent :: Failed to parse options.\n"); 139 return JNI_ERR; 140 } 141 memset(&caps, 0, sizeof(caps)); 142 caps.can_redefine_classes = 1; 143 caps.can_suspend=1; 144 caps.can_pop_frame=1; 145 caps.can_generate_all_class_hook_events=1; 146 caps.can_generate_field_access_events=1; 147 if (! NSK_JVMTI_VERIFY (jvmti->AddCapabilities(&caps) )) { 148 nsk_printf("#error Agent :: while adding capabilities.\n"); 149 return JNI_ERR; 150 } 151 memset(&eventCallbacks, 0, sizeof(eventCallbacks)); 152 eventCallbacks.ClassPrepare =callbackClassPrepare; 153 eventCallbacks.FieldAccess= callbackFieldAccess; 154 if (!NSK_JVMTI_VERIFY(jvmti->SetEventCallbacks(&eventCallbacks, sizeof(eventCallbacks)))) { 155 nsk_printf("#error Agent :: while setting event callbacks.\n"); 156 return JNI_ERR; 157 } 158 if ( ( nsk_jvmti_enableNotification(jvmti,JVMTI_EVENT_CLASS_PREPARE, NULL) 159 == NSK_TRUE ) && 160 ( nsk_jvmti_enableNotification(jvmti,JVMTI_EVENT_FIELD_ACCESS, NULL) 161 == NSK_TRUE ) ) { 162 nsk_printf(" Agent :: Notifications are enabled.\n"); 163 } else { 164 nsk_printf("#error Agent :: Eanableing Notifications.\n"); 165 return JNI_ERR; 166 } 167 } 168 return JNI_OK; 169 } 170 171 JNIEXPORT jboolean JNICALL 172 Java_nsk_jvmti_scenarios_hotswap_HS203_hs203t003_hs203t003_isSuspended(JNIEnv * jni, 173 jclass clas, 174 jthread thread) { 175 jboolean retvalue; 176 jint state; 177 retvalue = JNI_FALSE; 178 if ( ! NSK_JVMTI_VERIFY(jvmti->GetThreadState(thread, &state) ) ) { 179 nsk_printf(" Agent :: Error while getting thread state.\n"); 180 nsk_jvmti_agentFailed(); 181 } else { 182 if ( state & JVMTI_THREAD_STATE_SUSPENDED) { 183 retvalue = JNI_TRUE; 184 } 185 } 186 return retvalue; 187 } 188 189 JNIEXPORT jboolean JNICALL 190 Java_nsk_jvmti_scenarios_hotswap_HS203_hs203t003_hs203t003_popThreadFrame(JNIEnv * jni, 191 jclass clas, 192 jthread thread) { 193 jboolean retvalue; 194 jint state; 195 retvalue = JNI_FALSE; 196 if ( ! NSK_JVMTI_VERIFY(jvmti->GetThreadState(thread, &state) ) ) { 197 nsk_printf(" Agent :: Error while getting thread state.\n"); 198 nsk_jvmti_agentFailed(); 199 } else { 200 if ( state & JVMTI_THREAD_STATE_SUSPENDED) { 201 if ( ! NSK_JVMTI_VERIFY (jvmti->PopFrame(thread) ) ) { 202 nsk_printf("#error Agent :: while poping thread's frame.\n"); 203 nsk_jvmti_agentFailed(); 204 } else { 205 nsk_printf(" Agent :: poped thread frame.\n"); 206 if ( ! NSK_JVMTI_VERIFY ( 207 jvmti->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_FIELD_ACCESS, NULL) ) ) { 208 nsk_printf("#error Agent :: failed to disable notification JVMTI_EVENT_FIELD ACCESS.\n"); 209 nsk_jvmti_agentFailed(); 210 } else { 211 nsk_printf(" Agent :: Disabled notification JVMTI_EVENT_FIELD ACCESS. \n"); 212 retvalue = JNI_TRUE; 213 } 214 } 215 } else { 216 nsk_printf("#error Agent :: Thread was not suspened."); 217 nsk_jvmti_agentFailed(); 218 } 219 } 220 return retvalue; 221 } 222 223 JNIEXPORT jboolean JNICALL 224 Java_nsk_jvmti_scenarios_hotswap_HS203_hs203t003_hs203t003_resumeThread(JNIEnv * jni, 225 jclass clas, 226 jthread thread) { 227 jboolean retvalue; 228 retvalue = JNI_FALSE; 229 if ( !NSK_JVMTI_VERIFY(jvmti->ResumeThread(thread)) ) { 230 nsk_printf("#error Agent :: while resuming thread.\n"); 231 nsk_jvmti_agentFailed(); 232 } else { 233 nsk_printf(" Agent :: Thread resumed.\n"); 234 retvalue= JNI_TRUE; 235 } 236 return retvalue; 237 } 238 239 }