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 <stdlib.h>
  25 #include <jvmti.h>
  26 #include "agent_common.h"
  27 #include <jni.h>
  28 #include <string.h>
  29 #include "jvmti_tools.h"
  30 #include "JVMTITools.h"
  31 #include "jni_tools.h"
  32 
  33 extern "C" {
  34 #define FILE_NAME "nsk/jvmti/scenarios/hotswap/HS203/hs203t004/MyThread"
  35 #define CLASS_NAME "Lnsk/jvmti/scenarios/hotswap/HS203/hs203t004/MyThread;"
  36 #define METHOD_NAME "doTask2"
  37 
  38 static jint redefineNumber;
  39 static jvmtiEnv * jvmti;
  40 
  41 JNIEXPORT void JNICALL callbackClassPrepare(jvmtiEnv *jvmti_env,
  42                                         JNIEnv* jni,
  43                                         jthread thread,
  44                                         jclass klass) {
  45     char * className;
  46     className=NULL;
  47 
  48     if (!NSK_JVMTI_VERIFY (NSK_CPP_STUB4(GetClassSignature,
  49                     jvmti_env, klass, &className, NULL) ) ) {
  50         NSK_COMPLAIN0("#error Agent :: while getting classname.\n");
  51         nsk_jvmti_agentFailed();
  52     } else {
  53         if (strcmp(className, CLASS_NAME) == 0) {
  54             if (nsk_jvmti_enableNotification(jvmti_env, JVMTI_EVENT_COMPILED_METHOD_LOAD, NULL) == NSK_TRUE ) {
  55                 NSK_DISPLAY0(" Agent :: notification enabled for COMPILED_METHOD_LOAD.\n");
  56                 if ( ! NSK_JVMTI_VERIFY ( NSK_CPP_STUB2(GenerateEvents, jvmti_env,
  57                                 JVMTI_EVENT_COMPILED_METHOD_LOAD ) )) {
  58                     NSK_COMPLAIN0("#error Agent :: occured while enabling compiled method events.\n");
  59                     nsk_jvmti_agentFailed();
  60                 }
  61             }
  62         }
  63 
  64         if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(Deallocate, jvmti_env, (unsigned char *)className))) {
  65             NSK_COMPLAIN1("#error Agent :: failed to Deallocate className = %s.", className);
  66             nsk_jvmti_agentFailed();
  67         }
  68     }
  69 }
  70 
  71 
  72 JNIEXPORT void JNICALL callbackCompiledMethodLoad(jvmtiEnv *jvmti_env,
  73         jmethodID method,
  74         jint code_size,
  75         const void* code_addr,
  76         jint map_length,
  77         const jvmtiAddrLocationMap* map,
  78         const void* compile_info) {
  79     jclass threadClass;
  80     if (redefineNumber == 0) {
  81         if ( ! NSK_JVMTI_VERIFY ( NSK_CPP_STUB3(GetMethodDeclaringClass,
  82                         jvmti_env, method, &threadClass) ) ) {
  83             NSK_COMPLAIN0("#error Agent :: while geting the declaring class.\n");
  84             nsk_jvmti_agentFailed();
  85         } else {
  86             char *className;
  87             char *methodName;
  88 
  89             className = NULL;
  90             methodName = NULL;
  91 
  92             if ( ! NSK_JVMTI_VERIFY (NSK_CPP_STUB4(GetClassSignature,
  93                             jvmti_env, threadClass, &className, NULL) ) ) {
  94                 NSK_COMPLAIN0("#error Agent :: while getting classname.\n");
  95                 nsk_jvmti_agentFailed();
  96                 return;
  97             }
  98 
  99             if ( ! NSK_JVMTI_VERIFY (NSK_CPP_STUB5(GetMethodName,
 100                             jvmti_env, method, &methodName, NULL, NULL) ) ) {
 101                 NSK_COMPLAIN0("#error Agent :: while getting methodname.\n");
 102                 nsk_jvmti_agentFailed();
 103                 return;
 104             }
 105 
 106             if ((strcmp(className, CLASS_NAME) == 0) && (strcmp(methodName, METHOD_NAME) == 0)) {
 107                 char fileName[512];
 108 
 109                 NSK_DISPLAY2(" Agent :: Got CompiledMethodLoadEvent for class: %s, method: %s.\n", className, methodName);
 110                 NSK_DISPLAY0(" Agent :: redefining class.\n");
 111 
 112                 nsk_jvmti_getFileName(redefineNumber, FILE_NAME, fileName, sizeof(fileName)/sizeof(char));
 113 
 114                 if ( nsk_jvmti_redefineClass(jvmti_env, threadClass, fileName) == NSK_TRUE) {
 115                     NSK_DISPLAY0(" Agent :: Successfully redefined.\n");
 116                     redefineNumber++;
 117                 } else {
 118                     NSK_COMPLAIN0("#error Agent :: Failed to redefine.\n");
 119                     nsk_jvmti_agentFailed();
 120                 }
 121             }
 122 
 123             if ( className != NULL ) {
 124                 if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(Deallocate, jvmti_env, (unsigned char *)className))) {
 125                     NSK_COMPLAIN1("#error Agent :: failed to Deallocate className = %s.", className);
 126                     nsk_jvmti_agentFailed();
 127                 }
 128             }
 129             if ( methodName != NULL ) {
 130                 if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(Deallocate, jvmti_env, (unsigned char *)methodName))) {
 131                     NSK_COMPLAIN1("#error Agent :: failed to Deallocate methodName = %s.", methodName);
 132                     nsk_jvmti_agentFailed();
 133                 }
 134             }
 135         }
 136     }
 137 }
 138 
 139 #ifdef STATIC_BUILD
 140 JNIEXPORT jint JNICALL Agent_OnLoad_hs203t004(JavaVM *jvm, char *options, void *reserved) {
 141     return Agent_Initialize(jvm, options, reserved);
 142 }
 143 JNIEXPORT jint JNICALL Agent_OnAttach_hs203t004(JavaVM *jvm, char *options, void *reserved) {
 144     return Agent_Initialize(jvm, options, reserved);
 145 }
 146 JNIEXPORT jint JNI_OnLoad_hs203t004(JavaVM *jvm, char *options, void *reserved) {
 147     return JNI_VERSION_1_8;
 148 }
 149 #endif
 150 jint  Agent_Initialize(JavaVM *vm, char *options, void *reserved) {
 151     redefineNumber=0;
 152     if ( ! NSK_VERIFY ( JNI_OK == NSK_CPP_STUB3(GetEnv, vm,
 153                     (void **)&jvmti, JVMTI_VERSION_1_1) ) ) {
 154         NSK_DISPLAY0("#error Agent :: Could not load JVMTI interface.\n");
 155         return JNI_ERR;
 156         } else {
 157         jvmtiCapabilities caps;
 158         jvmtiEventCallbacks eventCallbacks;
 159         memset(&caps, 0, sizeof(caps));
 160         if (nsk_jvmti_parseOptions(options) == NSK_FALSE ) {
 161             NSK_DISPLAY0("#error Agent ::  Failed to parse options.\n");
 162             return JNI_ERR;
 163         }
 164         caps.can_redefine_classes = 1;
 165         caps.can_suspend = 1;
 166         caps.can_pop_frame = 1;
 167         caps.can_generate_all_class_hook_events = 1;
 168         caps.can_generate_compiled_method_load_events = 1;
 169         if (! NSK_JVMTI_VERIFY ( NSK_CPP_STUB2(AddCapabilities, jvmti, &caps) )) {
 170             NSK_DISPLAY0("#error Agent :: occured while adding capabilities.\n");
 171             return JNI_ERR;
 172         }
 173         memset(&eventCallbacks, 0, sizeof(eventCallbacks));
 174         eventCallbacks.ClassPrepare =callbackClassPrepare;
 175         eventCallbacks.CompiledMethodLoad=callbackCompiledMethodLoad;
 176         if (!NSK_JVMTI_VERIFY(
 177                     NSK_CPP_STUB3(SetEventCallbacks, jvmti,
 178                         &eventCallbacks, sizeof(eventCallbacks)))) {
 179             NSK_COMPLAIN0("#error Agent :: occured while setting event callback.\n");
 180             return JNI_ERR;
 181         }
 182         if ( nsk_jvmti_enableNotification(jvmti,JVMTI_EVENT_CLASS_PREPARE, NULL) == NSK_TRUE) {
 183             NSK_DISPLAY0(" Agent :: Notifications are enabled.\n");
 184         } else {
 185             NSK_COMPLAIN0("#error Agent :: Error in enableing Notifications.\n");
 186             return JNI_ERR;
 187         }
 188     }
 189     return JNI_OK;
 190 }
 191 
 192 JNIEXPORT void JNICALL
 193 Java_nsk_jvmti_scenarios_hotswap_HS203_hs203t004_hs203t004_suspendThread(JNIEnv * jni,
 194         jobject clas,
 195         jthread thread) {
 196     NSK_DISPLAY0(" Agent :: Suspending Thread.\n");
 197     if (  NSK_JVMTI_VERIFY( NSK_CPP_STUB2(SuspendThread, jvmti, thread) ) ) {
 198         NSK_DISPLAY0(" Agent :: Succeded in suspending.\n");
 199     } else {
 200         NSK_COMPLAIN0("#error Agent :: occured while suspending thread.\n");
 201         nsk_jvmti_agentFailed();
 202     }
 203 }
 204 
 205 JNIEXPORT jboolean JNICALL
 206 Java_nsk_jvmti_scenarios_hotswap_HS203_hs203t004_hs203t004_popThreadFrame(JNIEnv * jni,
 207                                                                                    jobject clas,
 208                                                                                    jthread thread) {
 209     jboolean retvalue;
 210     jint state;
 211 
 212     NSK_DISPLAY0(" Agent :: nsk.jvmti.scenarios.hotswap.HS203.hs203t004.popThreadFrame(... ).\n");
 213     retvalue = JNI_FALSE;
 214     if ( ! NSK_JVMTI_VERIFY ( NSK_CPP_STUB3(GetThreadState, jvmti,
 215                     thread, &state) ) ) {
 216         NSK_COMPLAIN0("#error Agent :: while getting thread's state.\n");
 217         nsk_jvmti_agentFailed();
 218     } else {
 219         if ( state & JVMTI_THREAD_STATE_SUSPENDED) {
 220             if ( ! NSK_JVMTI_VERIFY( NSK_CPP_STUB2(PopFrame, jvmti, thread) ) ){
 221                 NSK_DISPLAY0("#error Agent :: occured while poping thread's frame.\n");
 222                 nsk_jvmti_agentFailed();
 223             } else {
 224                 if ( NSK_JVMTI_VERIFY( NSK_CPP_STUB4(SetEventNotificationMode, jvmti,
 225                                 JVMTI_DISABLE, JVMTI_EVENT_COMPILED_METHOD_LOAD, NULL) ) ) {
 226                     NSK_DISPLAY0(" Agent :: Disabled JVMTI_EVENT_COMPILED_METHOD_LOAD.\n");
 227                     retvalue = JNI_TRUE;
 228                 } else {
 229                     NSK_COMPLAIN0("#error Agent :: Failed to disable JVMTI_EVENT_COMPILED_METHOD_LOAD.\n");
 230                     nsk_jvmti_agentFailed();
 231                 }
 232             }
 233         } else {
 234             NSK_COMPLAIN0("#error Agent :: Thread was not suspened.\n");
 235             nsk_jvmti_agentFailed();
 236         }
 237     }
 238     return retvalue;
 239 }
 240 
 241 JNIEXPORT jboolean JNICALL
 242 Java_nsk_jvmti_scenarios_hotswap_HS203_hs203t004_hs203t004_resumeThread(JNIEnv * jni,
 243         jclass clas,
 244         jthread thread) {
 245     jboolean retvalue;
 246 
 247     retvalue = JNI_FALSE;
 248     if ( NSK_JVMTI_VERIFY ( NSK_CPP_STUB2(ResumeThread, jvmti, thread))) {
 249         NSK_DISPLAY0(" Agent :: Thread resumed.\n");
 250         retvalue= JNI_TRUE;
 251     } else {
 252         NSK_COMPLAIN0("#error Agent :: Failed to resume the thread.\n");
 253         nsk_jvmti_agentFailed();
 254     }
 255     return retvalue;
 256 }
 257 
 258 }