1 /* 2 * Copyright (c) 2010, 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 24 #include <stdio.h> 25 #include <string.h> 26 #include <stdlib.h> 27 #include "jvmti.h" 28 #include "agent_common.h" 29 #include "JVMTITools.h" 30 #include "jvmti_tools.h" 31 #include "mlvmJvmtiUtils.h" 32 33 static jvmtiEnv* gJvmtiEnv = NULL; 34 35 static jboolean gIsMethodEntryWorking = JNI_FALSE; 36 static jboolean gIsSingleStepWorking = JNI_FALSE; 37 static jboolean gIsErrorOccured = JNI_FALSE; 38 39 static jboolean gIsDebuggerCompatible = JNI_FALSE; 40 41 static jint gPopFrameDepth = 2; 42 43 typedef struct TLS { 44 jint countOfFramesToPop; 45 } TLSStruct; 46 47 static char * gszRedefineTriggerMethodName = "NONE"; 48 static char * gszRedefinedClassFileName = "NONE"; 49 static jboolean gIsClassRedefined = JNI_FALSE; 50 51 JNIEXPORT void JNICALL 52 Java_vm_mlvm_indy_func_jvmti_share_IndyRedefineClass_setRedefineTriggerMethodName(JNIEnv * pEnv, jclass clazz, jstring name) { 53 copyFromJString(pEnv, name, &gszRedefineTriggerMethodName); 54 NSK_DISPLAY1("Setting redefine trigger method name to %s\n", gszRedefineTriggerMethodName); 55 } 56 57 JNIEXPORT void JNICALL 58 Java_vm_mlvm_indy_func_jvmti_share_IndyRedefineClass_setRedefinedClassFileName(JNIEnv * pEnv, jclass clazz, jstring name) { 59 copyFromJString(pEnv, name, &gszRedefinedClassFileName); 60 NSK_DISPLAY1("Setting redefined class name to %s\n", gszRedefinedClassFileName); 61 gIsClassRedefined = JNI_FALSE; 62 } 63 64 JNIEXPORT void JNICALL 65 Java_vm_mlvm_indy_func_jvmti_share_IndyRedefineClass_setPopFrameDepthAfterRedefine(JNIEnv * pEnv, jclass clazz, jint depth) { 66 gPopFrameDepth = depth; 67 } 68 69 JNIEXPORT jboolean JNICALL 70 Java_vm_mlvm_indy_func_jvmti_share_IndyRedefineClass_checkStatus(JNIEnv * pEnv, jclass clazz) { 71 NSK_DISPLAY0("The following values should be non-zero for test to pass:\n"); 72 NSK_DISPLAY1("Method entry event fired? %i\n", gIsMethodEntryWorking); 73 NSK_DISPLAY1("Single step event fired? %i\n", gIsSingleStepWorking); 74 NSK_DISPLAY0("The following value should be zero for test to pass:\n"); 75 NSK_DISPLAY1("Any other error occured? %i\n", gIsErrorOccured); 76 return gIsMethodEntryWorking && gIsSingleStepWorking && ! gIsErrorOccured; 77 } 78 79 static void popFrameLogic(jvmtiEnv * jvmti_env, jthread thread) { 80 81 TLSStruct * tls = (TLSStruct *) getTLS(jvmti_env, thread, sizeof(TLSStruct)); 82 83 if ( ! tls ) 84 return; 85 86 if ( tls->countOfFramesToPop <= 0 ) { 87 88 NSK_DISPLAY0("Disabling single step\n"); 89 if ( ! NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, jvmti_env, JVMTI_DISABLE, JVMTI_EVENT_SINGLE_STEP, NULL)) ) 90 gIsErrorOccured = JNI_TRUE; 91 92 } else { 93 94 NSK_DISPLAY0("Enabling single step\n"); 95 if ( ! NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, jvmti_env, JVMTI_ENABLE, JVMTI_EVENT_SINGLE_STEP, NULL)) ) 96 gIsErrorOccured = JNI_TRUE; 97 98 if ( tls->countOfFramesToPop == 1 ) { 99 NSK_DISPLAY0("Popping a frame\n"); 100 if ( ! NSK_JVMTI_VERIFY(NSK_CPP_STUB2(PopFrame, jvmti_env, thread)) ) 101 gIsErrorOccured = JNI_TRUE; 102 } else { 103 NSK_DISPLAY0("Forcing early return\n"); 104 if ( ! NSK_JVMTI_VERIFY(NSK_CPP_STUB2(ForceEarlyReturnVoid, jvmti_env, thread)) ) 105 gIsErrorOccured = JNI_TRUE; 106 } 107 108 --tls->countOfFramesToPop; 109 } 110 } 111 112 static void JNICALL 113 MethodEntry(jvmtiEnv *jvmti_env, 114 JNIEnv* jni_env, 115 jthread thread, 116 jmethodID method) { 117 118 struct MethodName * mn; 119 TLSStruct * tls; 120 jclass clazz; 121 122 gIsMethodEntryWorking = JNI_TRUE; 123 mn = getMethodName(jvmti_env, method); 124 if ( ! mn ) 125 return; 126 127 if ( strcmp(mn->methodName, gszRedefineTriggerMethodName) != 0 ) { 128 free(mn); 129 return; 130 } 131 132 NSK_DISPLAY2("Entering redefine tigger method: %s.%s\n", mn->classSig, mn->methodName); 133 free(mn); mn = NULL; 134 135 if ( gIsClassRedefined ) { 136 NSK_DISPLAY0("Class is already redefined.\n"); 137 return; 138 } 139 140 NSK_DISPLAY1("Redefining class %s\n", gszRedefinedClassFileName); 141 142 if ( ! NSK_JVMTI_VERIFY(NSK_CPP_STUB3(GetMethodDeclaringClass, jvmti_env, method, &clazz)) ) 143 return; 144 145 if ( ! NSK_VERIFY(nsk_jvmti_redefineClass(jvmti_env, clazz, gszRedefinedClassFileName)) ) { 146 gIsErrorOccured = JNI_TRUE; 147 return; 148 } 149 150 gIsClassRedefined = JNI_TRUE; 151 152 tls = (TLSStruct *) getTLS(jvmti_env, thread, sizeof(TLSStruct)); 153 tls->countOfFramesToPop = gPopFrameDepth; 154 155 popFrameLogic(jvmti_env, thread); 156 } 157 158 static void JNICALL 159 SingleStep(jvmtiEnv *jvmti_env, 160 JNIEnv* jni_env, 161 jthread thread, 162 jmethodID method, 163 jlocation location) { 164 165 char * locStr; 166 gIsSingleStepWorking = JNI_TRUE; 167 locStr = locationToString(jvmti_env, method, location); 168 NSK_DISPLAY1("Single step event: %s\n", locStr); 169 free(locStr); 170 171 popFrameLogic(jvmti_env, thread); 172 } 173 174 jint Agent_Initialize(JavaVM * vm, char * options, void * reserved) { 175 jvmtiEventCallbacks callbacks; 176 jvmtiCapabilities caps; 177 178 if ( ! NSK_VERIFY(nsk_jvmti_parseOptions(options)) ) 179 return JNI_ERR; 180 181 if ( ! NSK_VERIFY((gJvmtiEnv = nsk_jvmti_createJVMTIEnv(vm, reserved)) != NULL) ) 182 return JNI_ERR; 183 184 if ( nsk_jvmti_findOptionValue("debuggerCompatible") ) { 185 gIsDebuggerCompatible = JNI_TRUE; 186 } 187 188 memset(&caps, 0, sizeof(caps)); 189 caps.can_generate_method_entry_events = 1; 190 caps.can_generate_single_step_events = 1; 191 caps.can_pop_frame = 1; 192 caps.can_force_early_return = 1; 193 caps.can_redefine_classes = 1; 194 195 if ( ! NSK_JVMTI_VERIFY(NSK_CPP_STUB2(AddCapabilities, gJvmtiEnv, &caps)) ) 196 return JNI_ERR; 197 198 memset(&callbacks, 0, sizeof(callbacks)); 199 callbacks.MethodEntry = &MethodEntry; 200 callbacks.SingleStep = &SingleStep; 201 202 if ( ! NSK_JVMTI_VERIFY(NSK_CPP_STUB3(SetEventCallbacks, gJvmtiEnv, &callbacks, sizeof(callbacks))) ) 203 return JNI_ERR; 204 205 if ( ! NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, gJvmtiEnv, JVMTI_ENABLE, JVMTI_EVENT_METHOD_ENTRY, NULL) ) ) 206 return JNI_ERR; 207 208 if ( ! NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, gJvmtiEnv, JVMTI_DISABLE, JVMTI_EVENT_SINGLE_STEP, NULL) ) ) 209 return JNI_ERR; 210 211 return JNI_OK; 212 }