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 char * gszDebuggeeMethodName = "NONE"; 36 static char * gszDebuggeeClassName = "NONE"; 37 static jboolean gIsMethodEntryWorking = JNI_FALSE; 38 static jboolean gIsSingleStepWorking = JNI_FALSE; 39 static jboolean gIsBreakpointWorking = JNI_FALSE; 40 41 static jboolean gIsBreakpointSet = JNI_FALSE; 42 static jboolean gIsFirstCall = JNI_TRUE; 43 static jboolean gIsDebuggerCompatible = JNI_FALSE; 44 45 JNIEXPORT void JNICALL 46 Java_vm_mlvm_indy_func_jvmti_stepBreakPopReturn_INDIFY_1Test_setDebuggeeMethodName(JNIEnv * pEnv, jclass clazz, jstring name) { 47 copyFromJString(pEnv, name, &gszDebuggeeMethodName); 48 NSK_DISPLAY1("Setting debuggee method name to %s\n", gszDebuggeeMethodName); 49 } 50 51 JNIEXPORT void JNICALL 52 Java_vm_mlvm_indy_func_jvmti_stepBreakPopReturn_INDIFY_1Test_setDebuggeeClassName(JNIEnv * pEnv, jclass clazz, jstring name) { 53 copyFromJString(pEnv, name, &gszDebuggeeClassName); 54 NSK_DISPLAY1("Setting debuggee class name to %s\n", gszDebuggeeClassName); 55 } 56 57 JNIEXPORT jboolean JNICALL 58 Java_vm_mlvm_indy_func_jvmti_stepBreakPopReturn_INDIFY_1Test_checkStatus(JNIEnv * pEnv, jclass clazz) { 59 NSK_DISPLAY1("Are we running in debugger-compatible mode? %i\n", gIsDebuggerCompatible); 60 NSK_DISPLAY0("The following values should be non-zero for test to pass:\n"); 61 NSK_DISPLAY1("Method entry event fired? %i\n", gIsMethodEntryWorking); 62 NSK_DISPLAY1("Single step event fired? %i\n", gIsSingleStepWorking); 63 if ( ! gIsDebuggerCompatible ) 64 NSK_DISPLAY1("Breakpoint event fired? %i\n", gIsBreakpointWorking); 65 66 return gIsMethodEntryWorking && gIsSingleStepWorking && (gIsBreakpointWorking || gIsDebuggerCompatible); 67 } 68 69 static void JNICALL 70 MethodEntry(jvmtiEnv *jvmti_env, 71 JNIEnv* jni_env, 72 jthread thread, 73 jmethodID method) { 74 75 struct MethodName * mn; 76 77 mn = getMethodName(jvmti_env, method); 78 if ( ! mn ) 79 return; 80 81 if ( strcmp(mn->classSig, gszDebuggeeClassName) == 0 ) { 82 NSK_DISPLAY2("Entering method: %s.%s\n", mn->classSig, mn->methodName); 83 84 if ( strcmp(mn->methodName, gszDebuggeeMethodName) == 0 ) { 85 gIsMethodEntryWorking = JNI_TRUE; 86 87 if ( ! gIsBreakpointSet ) 88 NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, jvmti_env, JVMTI_ENABLE, JVMTI_EVENT_SINGLE_STEP, NULL)); 89 } 90 } 91 92 free(mn); 93 } 94 95 static void JNICALL 96 SingleStep(jvmtiEnv *jvmti_env, 97 JNIEnv* jni_env, 98 jthread thread, 99 jmethodID method, 100 jlocation location) { 101 102 char * locStr; 103 gIsSingleStepWorking = JNI_TRUE; 104 105 locStr = locationToString(jvmti_env, method, location); 106 NSK_DISPLAY1("Single step event: %s\n", locStr); 107 free(locStr); 108 109 NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, gJvmtiEnv, JVMTI_DISABLE, JVMTI_EVENT_SINGLE_STEP, NULL)); 110 111 if ( ! gIsDebuggerCompatible ) { 112 if ( ! NSK_JVMTI_VERIFY(NSK_CPP_STUB3(SetBreakpoint, jvmti_env, method, location)) ) 113 return; 114 115 NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, gJvmtiEnv, JVMTI_ENABLE, JVMTI_EVENT_BREAKPOINT, NULL)); 116 gIsBreakpointSet = JNI_TRUE; 117 118 NSK_DISPLAY0("Pop a frame\n"); 119 NSK_JVMTI_VERIFY(NSK_CPP_STUB2(PopFrame, gJvmtiEnv, thread)); 120 } else { 121 if ( gIsFirstCall ) { 122 NSK_DISPLAY0("Pop a frame\n"); 123 NSK_JVMTI_VERIFY(NSK_CPP_STUB2(PopFrame, gJvmtiEnv, thread)); 124 gIsFirstCall = JNI_FALSE; 125 } else { 126 gIsFirstCall = JNI_TRUE; 127 } 128 } 129 } 130 131 static void JNICALL 132 Breakpoint(jvmtiEnv *jvmti_env, 133 JNIEnv* jni_env, 134 jthread thread, 135 jmethodID method, 136 jlocation location) { 137 138 139 char * locStr; 140 gIsBreakpointWorking = JNI_TRUE; 141 142 locStr = locationToString(jvmti_env, method, location); 143 NSK_DISPLAY1("Breakpoint event at: %s\n", locStr); 144 free(locStr); 145 146 NSK_JVMTI_VERIFY(NSK_CPP_STUB3(ClearBreakpoint, jvmti_env, method, location)); 147 NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, gJvmtiEnv, JVMTI_DISABLE, JVMTI_EVENT_BREAKPOINT, NULL)); 148 gIsBreakpointSet = JNI_FALSE; 149 150 NSK_DISPLAY0("Forcing early return.\n"); 151 NSK_JVMTI_VERIFY(NSK_CPP_STUB3(ForceEarlyReturnInt, jvmti_env, thread, 0)); 152 } 153 154 jint Agent_Initialize(JavaVM * vm, char * options, void * reserved) { 155 jvmtiEventCallbacks callbacks; 156 jvmtiCapabilities caps; 157 158 if ( ! NSK_VERIFY(nsk_jvmti_parseOptions(options)) ) 159 return JNI_ERR; 160 161 if ( ! NSK_VERIFY((gJvmtiEnv = nsk_jvmti_createJVMTIEnv(vm, reserved)) != NULL) ) 162 return JNI_ERR; 163 164 if ( nsk_jvmti_findOptionValue("debuggerCompatible") ) { 165 gIsDebuggerCompatible = JNI_TRUE; 166 } 167 168 memset(&caps, 0, sizeof(caps)); 169 caps.can_generate_method_entry_events = 1; 170 caps.can_generate_single_step_events = 1; 171 caps.can_generate_breakpoint_events = ! gIsDebuggerCompatible; 172 caps.can_pop_frame = 1; 173 caps.can_force_early_return = 1; 174 175 if ( ! NSK_JVMTI_VERIFY(NSK_CPP_STUB2(AddCapabilities, gJvmtiEnv, &caps)) ) 176 return JNI_ERR; 177 178 memset(&callbacks, 0, sizeof(callbacks)); 179 callbacks.MethodEntry = &MethodEntry; 180 callbacks.SingleStep = &SingleStep; 181 callbacks.Breakpoint = &Breakpoint; 182 183 if ( ! NSK_JVMTI_VERIFY(NSK_CPP_STUB3(SetEventCallbacks, gJvmtiEnv, &callbacks, sizeof(callbacks))) ) 184 return JNI_ERR; 185 186 if ( ! NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode, gJvmtiEnv, JVMTI_ENABLE, JVMTI_EVENT_METHOD_ENTRY, NULL) ) ) 187 return JNI_ERR; 188 189 return JNI_OK; 190 }