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 }