1 /* 2 * Copyright (c) 2007, 2019, 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)) { 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) == NSK_TRUE) && 159 (nsk_jvmti_enableNotification(jvmti,JVMTI_EVENT_FIELD_ACCESS, NULL) == NSK_TRUE)) { 160 nsk_printf(" Agent :: Notifications are enabled.\n"); 161 } else { 162 nsk_printf("#error Agent :: Eanableing Notifications.\n"); 163 return JNI_ERR; 164 } 165 } 166 return JNI_OK; 167 } 168 169 JNIEXPORT jboolean JNICALL 170 Java_nsk_jvmti_scenarios_hotswap_HS203_hs203t003_hs203t003_isSuspended(JNIEnv * jni, 171 jclass clas, 172 jthread thread) { 173 jboolean retvalue; 174 jint state; 175 retvalue = JNI_FALSE; 176 if (!NSK_JVMTI_VERIFY(jvmti->GetThreadState(thread, &state))) { 177 nsk_printf(" Agent :: Error while getting thread state.\n"); 178 nsk_jvmti_agentFailed(); 179 } else { 180 if (state & JVMTI_THREAD_STATE_SUSPENDED) { 181 retvalue = JNI_TRUE; 182 } 183 } 184 return retvalue; 185 } 186 187 JNIEXPORT jboolean JNICALL 188 Java_nsk_jvmti_scenarios_hotswap_HS203_hs203t003_hs203t003_popThreadFrame(JNIEnv * jni, 189 jclass clas, 190 jthread thread) { 191 jboolean retvalue; 192 jint state; 193 retvalue = JNI_FALSE; 194 if (!NSK_JVMTI_VERIFY(jvmti->GetThreadState(thread, &state))) { 195 nsk_printf(" Agent :: Error while getting thread state.\n"); 196 nsk_jvmti_agentFailed(); 197 } else { 198 if (state & JVMTI_THREAD_STATE_SUSPENDED) { 199 if (!NSK_JVMTI_VERIFY(jvmti->PopFrame(thread))) { 200 nsk_printf("#error Agent :: while poping thread's frame.\n"); 201 nsk_jvmti_agentFailed(); 202 } else { 203 nsk_printf(" Agent :: poped thread frame.\n"); 204 if (!NSK_JVMTI_VERIFY( 205 jvmti->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_FIELD_ACCESS, NULL))) { 206 nsk_printf("#error Agent :: failed to disable notification JVMTI_EVENT_FIELD ACCESS.\n"); 207 nsk_jvmti_agentFailed(); 208 } else { 209 nsk_printf(" Agent :: Disabled notification JVMTI_EVENT_FIELD ACCESS. \n"); 210 retvalue = JNI_TRUE; 211 } 212 } 213 } else { 214 nsk_printf("#error Agent :: Thread was not suspened."); 215 nsk_jvmti_agentFailed(); 216 } 217 } 218 return retvalue; 219 } 220 221 JNIEXPORT jboolean JNICALL 222 Java_nsk_jvmti_scenarios_hotswap_HS203_hs203t003_hs203t003_resumeThread(JNIEnv * jni, 223 jclass clas, 224 jthread thread) { 225 jboolean retvalue; 226 retvalue = JNI_FALSE; 227 if (!NSK_JVMTI_VERIFY(jvmti->ResumeThread(thread))) { 228 nsk_printf("#error Agent :: while resuming thread.\n"); 229 nsk_jvmti_agentFailed(); 230 } else { 231 nsk_printf(" Agent :: Thread resumed.\n"); 232 retvalue= JNI_TRUE; 233 } 234 return retvalue; 235 } 236 237 }