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