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