1 /*
   2  * Copyright (c) 2007, 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 #include <stdio.h>
  24 #include <jvmti.h>
  25 #include "agent_common.h"
  26 #include <jni.h>
  27 #include <string.h>
  28 #include "jvmti_tools.h"
  29 #include "JVMTITools.h"
  30 
  31 /*
  32    T002:
  33    1. Set a breakpoint in method b().
  34    2. Call method a() which calls b().
  35    Upon reaching the breakpoint, enable SingleStep.
  36    3. Redefine class within SingleStep callback. New class version
  37    contains the same method b() and the changed method a(). Stepping
  38    should be continued in the method b().
  39    4. Pop a currently executed frame. Stepping should be continued
  40    on invoke instruction of the obsolete method a().
  41    5. Pop a frame once more. Stepping should be continued
  42    on invoke instruction of main method and then in the changed
  43    method b().
  44 */
  45 
  46 extern "C" {
  47 
  48 #define FILE_NAME "nsk/jvmti/scenarios/hotswap/HS203/hs203t002/MyThread"
  49 #define SEARCH_NAME "nsk/jvmti/scenarios/hotswap/HS203/hs203t002/MyThread"
  50 #define METHOD_NAME "doTask2"
  51 #define METHOD_SIGN "()V"
  52 #define CLASS_NAME "Lnsk/jvmti/scenarios/hotswap/HS203/hs203t002/MyThread;"
  53 static jint redefineNumber;
  54 static jvmtiEnv * jvmti;
  55 
  56 JNIEXPORT void JNICALL
  57 callbackClassLoad(jvmtiEnv *jvmti,
  58                                         JNIEnv* jni,
  59                                         jthread thread,
  60                                         jclass klass) {
  61     char * className;
  62     char * generic;
  63     redefineNumber=0;
  64     jvmti->GetClassSignature(klass, &className, &generic);
  65     if (strcmp(className,CLASS_NAME) == 0) {
  66         jmethodID method;
  67         method = jni->GetMethodID(klass,METHOD_NAME,METHOD_SIGN);
  68         if (method != NULL) {
  69             jlocation start;
  70             jlocation end;
  71             jvmtiError err ;
  72             err=jvmti->GetMethodLocation(method, &start, &end);
  73             if (err == JVMTI_ERROR_NONE) {
  74                 nsk_printf("Agent:: NO ERRORS FOUND \n");
  75                 err= jvmti->SetBreakpoint(method, start);
  76                 if (err == JVMTI_ERROR_NONE) {
  77                     nsk_printf("Agent:: Breakpoint set \n");
  78                 } else {
  79                     nsk_printf("Agent:: ***ERROR OCCURED ... in SET BREAK POINT ERROR \n");
  80                 }
  81             } else {
  82                 nsk_printf("Agent:: ***ERROR OCCURED .. in METHOD LOCATION FINDER \n");
  83             }
  84         } else {
  85             nsk_printf("Agent:: ***ERROR OCCURED .. COUND NOT FIND THE METHOD AND SIGNATURE SPECIFIED \n");
  86         }
  87     }
  88 }
  89 
  90 void JNICALL callbackSingleStep(jvmtiEnv *jvmti,
  91         JNIEnv* jni, jthread thread,
  92         jmethodID method, jlocation location) {
  93     jclass threadClass;
  94     jvmtiError err;
  95     char fileName[512];
  96 
  97     threadClass = jni->FindClass(SEARCH_NAME);
  98     nsk_printf(" %d..",redefineNumber);
  99     nsk_jvmti_getFileName(redefineNumber, FILE_NAME, fileName, sizeof(fileName)/sizeof(char));
 100 
 101     if(nsk_jvmti_redefineClass(jvmti, threadClass,fileName) == NSK_TRUE) {
 102         nsk_printf("Agent:: Redefined..\n");
 103     } else {
 104         nsk_printf(" Failed to redefine..\n");
 105         return;
 106     }
 107     err=jvmti->SuspendThread(thread);
 108     if (err ==  JVMTI_ERROR_NONE) {
 109         nsk_printf("Agent:: Succeded in suspending..\n");
 110     } else {
 111         nsk_printf(" ## Error occured %s \n",TranslateError(err));
 112     }
 113 }
 114 
 115 void JNICALL callbackBreakpoint(jvmtiEnv *jvmti,
 116                                                                 JNIEnv* jni,
 117                                                                 jthread thread,
 118                                                                 jmethodID method,
 119                                                                 jlocation location) {
 120     nsk_printf("Agent::... BreakPoint Reached..\n");
 121     if (nsk_jvmti_enableNotification(jvmti,JVMTI_EVENT_SINGLE_STEP,thread) == JNI_OK) {
 122         nsk_printf(" ....   Enabled..\n");
 123     }
 124     return;
 125 }
 126 
 127 
 128 #ifdef STATIC_BUILD
 129 JNIEXPORT jint JNICALL Agent_OnLoad_hs203t002(JavaVM *jvm, char *options, void *reserved) {
 130     return Agent_Initialize(jvm, options, reserved);
 131 }
 132 JNIEXPORT jint JNICALL Agent_OnAttach_hs203t002(JavaVM *jvm, char *options, void *reserved) {
 133     return Agent_Initialize(jvm, options, reserved);
 134 }
 135 JNIEXPORT jint JNI_OnLoad_hs203t002(JavaVM *jvm, char *options, void *reserved) {
 136     return JNI_VERSION_1_8;
 137 }
 138 #endif
 139 jint Agent_Initialize(JavaVM *vm, char *options, void *reserved) {
 140         jint rc ;
 141     nsk_printf("Agent:: VM.. Started..\n");
 142     rc=vm->GetEnv((void **)&jvmti, JVMTI_VERSION_1_1);
 143     if (rc!= JNI_OK) {
 144         nsk_printf("Agent:: Could not load JVMTI interface \n");
 145         return JNI_ERR;
 146     } else {
 147         jvmtiCapabilities caps;
 148         jvmtiEventCallbacks eventCallbacks;
 149         if (nsk_jvmti_parseOptions(options) == NSK_FALSE) {
 150             nsk_printf("# error agent Failed to parse options \n");
 151             return JNI_ERR;
 152         }
 153         memset(&caps, 0, sizeof(caps));
 154         caps.can_redefine_classes = 1;
 155         caps.can_suspend=1;
 156         caps.can_pop_frame=1;
 157         caps.can_generate_breakpoint_events=1;
 158         caps.can_generate_all_class_hook_events=1;
 159         caps.can_generate_single_step_events=1;
 160         jvmti->AddCapabilities(&caps);
 161 
 162         memset(&eventCallbacks, 0, sizeof(eventCallbacks));
 163         eventCallbacks.ClassLoad =callbackClassLoad;
 164         eventCallbacks.Breakpoint = callbackBreakpoint;
 165         eventCallbacks.SingleStep =callbackSingleStep;
 166         rc=jvmti->SetEventCallbacks(&eventCallbacks, sizeof(eventCallbacks));
 167         if (rc != JVMTI_ERROR_NONE) {
 168             nsk_printf(" Agent:: Error occured while setting event call back \n");
 169             return JNI_ERR;
 170         }
 171         if ((nsk_jvmti_enableNotification(jvmti,JVMTI_EVENT_CLASS_LOAD,
 172                         NULL) == NSK_TRUE) &&
 173                 (nsk_jvmti_enableNotification(jvmti,JVMTI_EVENT_BREAKPOINT,
 174                                               NULL) == NSK_TRUE)) {
 175             nsk_printf("Agent :: NOTIFICATIONS ARE ENABLED \n");
 176         } else {
 177             nsk_printf(" Error in Eanableing Notifications..");
 178         }
 179     }
 180     return JNI_OK;
 181 }
 182 
 183 
 184 JNIEXPORT jboolean JNICALL
 185 Java_nsk_jvmti_scenarios_hotswap_HS203_hs203t002_hs203t002_popThreadFrame(JNIEnv * jni,
 186         jclass clas,
 187         jthread thread) {
 188     jvmtiError err ;
 189     jboolean retvalue;
 190     jint state;
 191     nsk_printf("Agent:: POPING THE FRAME....\n");
 192     retvalue = JNI_FALSE;
 193     jvmti->GetThreadState(thread, &state);
 194     if (state & JVMTI_THREAD_STATE_SUSPENDED) {
 195         err = jvmti->PopFrame(thread);
 196         if (err == JVMTI_ERROR_NONE) {
 197             nsk_printf("Agent:: NO Errors poped very well ..\n");
 198             retvalue = JNI_TRUE;
 199         } else {
 200             nsk_printf(" ## Error occured %s \n",TranslateError(err));
 201         }
 202     } else {
 203         nsk_printf("Agent:: Thread was not suspened.. check for capabilities, and java method signature \n");
 204     }
 205     return retvalue;
 206 }
 207 
 208 JNIEXPORT jboolean JNICALL
 209 Java_nsk_jvmti_scenarios_hotswap_HS203_hs203t002_hs203t002_resumeThread(JNIEnv * jni,
 210         jclass clas,
 211         jthread thread) {
 212     jvmtiError err ;
 213     jboolean retvalue;
 214     retvalue = JNI_FALSE;
 215     err =jvmti->SetEventNotificationMode(JVMTI_DISABLE,JVMTI_EVENT_SINGLE_STEP,thread);
 216     if (err == JVMTI_ERROR_NONE) {
 217         nsk_printf(" Agent:: cleared Single Step event");
 218     } else {
 219         nsk_printf(" Agent :: Failed to clear Single Step Event");
 220     }
 221     err =jvmti->SetEventNotificationMode(JVMTI_DISABLE,JVMTI_EVENT_BREAKPOINT,thread);
 222     if (err == JVMTI_ERROR_NONE) {
 223         nsk_printf(" Agent:: cleared Break point event");
 224     } else {
 225         nsk_printf(" Agent :: Failed to clear Single Step Event");
 226     }
 227     err = jvmti->ResumeThread(thread);
 228     if (err == JVMTI_ERROR_NONE) {
 229         nsk_printf(" Agent:: Thread Resumed..");
 230     } else {
 231         nsk_printf(" Failed.. to Resume the thread.");
 232     }
 233     return retvalue;
 234 }
 235 
 236 JNIEXPORT jboolean JNICALL
 237 Java_nsk_jvmti_scenarios_hotswap_HS203_hs203t002_hs203t002_suspendThread(JNIEnv * jni,
 238         jclass clas,
 239         jthread thread) {
 240     jvmtiError err ;
 241     jboolean retvalue;
 242     retvalue = JNI_FALSE;
 243     err = jvmti->SuspendThread(thread);
 244     if (err == JVMTI_ERROR_NONE) {
 245         nsk_printf(" Agent:: Thread suspended..");
 246         retvalue= JNI_TRUE;
 247     } else {
 248         nsk_printf(" ## Error occured %s \n",TranslateError(err));
 249     }
 250     return retvalue;
 251 }
 252 
 253 }