1 /*
   2  * Copyright (c) 2003, 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 <jvmti.h>
  27 #include "agent_common.h"
  28 
  29 #include "nsk_tools.h"
  30 #include "JVMTITools.h"
  31 #include "jvmti_tools.h"
  32 #include "jni_tools.h"
  33 
  34 extern "C" {
  35 
  36 #define STATUS_FAILED 2
  37 #define PASSED 0
  38 
  39 /* tested methods */
  40 #define METH_NUM 4
  41 static const char *METHODS[][2] = {
  42     {"bpMethod", "()V"},
  43     {"nativeMethod", "()V"},
  44     {"anotherNativeMethod", "(I)V"},
  45     {"runThis", "([Ljava/lang/String;Ljava/io/PrintStream;)I"}
  46 };
  47 
  48 /* event counters for the tested methods and expected numbers
  49  of the events */
  50 static volatile long stepEv[][2] = {
  51     {0, 1},
  52     {0, 0},
  53     {0, 0},
  54     {0, 1}
  55 };
  56 
  57 static const char *CLASS_SIG =
  58     "Lnsk/jvmti/SingleStep/singlestep003;";
  59 
  60 static volatile jint result = PASSED;
  61 static jvmtiEnv *jvmti = NULL;
  62 static jvmtiEventCallbacks callbacks;
  63 
  64 static void setBP(jvmtiEnv *jvmti_env, JNIEnv *env, jclass klass) {
  65     jmethodID mid;
  66 
  67     if (!NSK_JNI_VERIFY(env, (mid = NSK_CPP_STUB4(GetMethodID,
  68             env, klass, METHODS[0][0], METHODS[0][1])) != NULL))
  69         NSK_CPP_STUB2(FatalError, env,
  70             "failed to get ID for the java method\n");
  71 
  72     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3(SetBreakpoint,
  73             jvmti_env, mid, 0)))
  74         NSK_CPP_STUB2(FatalError, env,
  75             "failed to set breakpoint\n");
  76 }
  77 
  78 /** callback functions **/
  79 void JNICALL
  80 ClassLoad(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thread, jclass klass) {
  81     char *sig, *generic;
  82 
  83     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(GetClassSignature,
  84             jvmti_env, klass, &sig, &generic)))
  85         NSK_CPP_STUB2(FatalError, env,
  86             "failed to obtain a class signature\n");
  87 
  88     if (sig != NULL && (strcmp(sig, CLASS_SIG) == 0)) {
  89         NSK_DISPLAY1(
  90             "ClassLoad event received for the class \"%s\"\n"
  91             "\tsetting breakpoint ...\n",
  92             sig);
  93         setBP(jvmti_env, env, klass);
  94     }
  95 }
  96 
  97 void JNICALL
  98 Breakpoint(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thr, jmethodID method,
  99         jlocation loc) {
 100     jclass klass;
 101     char *sig, *generic;
 102 
 103     NSK_DISPLAY0("Breakpoint event received\n");
 104     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3(GetMethodDeclaringClass,
 105             jvmti_env, method, &klass)))
 106         NSK_COMPLAIN0("TEST FAILURE: unable to get method declaring class\n\n");
 107 
 108     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(GetClassSignature,
 109             jvmti_env, klass, &sig, &generic)))
 110         NSK_CPP_STUB2(FatalError, env,
 111             "Breakpoint: failed to obtain a class signature\n");
 112 
 113     if (sig != NULL && (strcmp(sig, CLASS_SIG) == 0)) {
 114         NSK_DISPLAY1("method declaring class \"%s\"\n\tenabling SingleStep events ...\n",
 115             sig);
 116         if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode,
 117                 jvmti_env, JVMTI_ENABLE, JVMTI_EVENT_SINGLE_STEP, thr))) {
 118             result = STATUS_FAILED;
 119             NSK_COMPLAIN0("TEST FAILURE: cannot enable SingleStep events\n\n");
 120         }
 121     } else {
 122         result = STATUS_FAILED;
 123         NSK_COMPLAIN1("TEST FAILURE: unexpected breakpoint event in method of class \"%s\"\n\n",
 124             sig);
 125     }
 126 }
 127 
 128 void JNICALL
 129 SingleStep(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread,
 130         jmethodID method, jlocation location) {
 131     jclass klass;
 132     char *sig, *generic, *methNam, *methSig;
 133     int i;
 134 
 135     if (result == STATUS_FAILED) {
 136         return;
 137     }
 138 
 139     NSK_DISPLAY0(">>>> SingleStep event received\n");
 140 
 141     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB5(GetMethodName,
 142             jvmti_env, method, &methNam, &methSig, NULL))) {
 143         result = STATUS_FAILED;
 144         NSK_COMPLAIN0("TEST FAILED: unable to get method name during SingleStep callback\n\n");
 145         return;
 146     }
 147     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3(GetMethodDeclaringClass,
 148             jvmti_env, method, &klass))) {
 149         result = STATUS_FAILED;
 150         NSK_COMPLAIN0("TEST FAILED: unable to get method declaring class during SingleStep callback\n\n");
 151         return;
 152     }
 153     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(GetClassSignature,
 154             jvmti_env, klass, &sig, &generic))) {
 155         result = STATUS_FAILED;
 156         NSK_COMPLAIN0("TEST FAILED: unable to obtain a class signature during SingleStep callback\n\n");
 157         return;
 158     }
 159 
 160     if (sig != NULL) {
 161         if (stepEv[METH_NUM-1][0] == 1) {
 162             result = STATUS_FAILED;
 163             NSK_COMPLAIN0("TEST FAILED: SingleStep event received after disabling the event generation\n\n");
 164             return;
 165         }
 166 
 167         for (i=0; i<METH_NUM; i++) {
 168             if ((strcmp(methNam,METHODS[i][0]) == 0) &&
 169                     (strcmp(methSig,METHODS[i][1]) == 0) &&
 170                     (strcmp(sig,CLASS_SIG) == 0)) {
 171                 stepEv[i][0]++;
 172 
 173                 if (stepEv[i][1] == 1) {
 174                     NSK_DISPLAY3(
 175                         "CHECK PASSED: SingleStep event received for the method:\n"
 176                         "\t \"%s %s\" of class \"%s\"\n"
 177                         "\tas expected\n",
 178                         methNam, methSig, sig);
 179                 } else {
 180                     result = STATUS_FAILED;
 181                     NSK_COMPLAIN3(
 182                         "TEST FAILED: SingleStep event received for the method:\n"
 183                         "\t \"%s %s\" of class \"%s\"\n",
 184                         methNam, methSig, sig);
 185                 }
 186 
 187                 if (i == (METH_NUM-1)) {
 188                     NSK_DISPLAY0("Disabling the single step event generation\n");
 189                     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode,
 190                             jvmti_env, JVMTI_DISABLE, JVMTI_EVENT_SINGLE_STEP, thread))) {
 191                         result = STATUS_FAILED;
 192                         NSK_COMPLAIN0("TEST FAILED: cannot disable SingleStep events\n\n");
 193                     }
 194                 }
 195             }
 196         }
 197     }
 198 
 199     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(Deallocate,
 200             jvmti_env, (unsigned char*) methNam))) {
 201         result = STATUS_FAILED;
 202         NSK_COMPLAIN0("TEST FAILED: unable to deallocate memory pointed to method name\n\n");
 203     }
 204     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(Deallocate,
 205             jvmti_env, (unsigned char*) methSig))) {
 206         result = STATUS_FAILED;
 207         NSK_COMPLAIN0("TEST FAILED: unable to deallocate memory pointed to method signature\n\n");
 208     }
 209 
 210     NSK_DISPLAY0("<<<<\n\n");
 211 }
 212 /************************/
 213 
 214 /* dummy method used only to provoke SingleStep events */
 215 JNIEXPORT void JNICALL
 216 Java_nsk_jvmti_SingleStep_singlestep003_anotherNativeMethod(
 217         JNIEnv *env, jobject obj, jint i) {
 218     NSK_DISPLAY0("inside the anotherNativeMethod()\n\n");
 219 }
 220 
 221 /* dummy method used only to provoke SingleStep events */
 222 JNIEXPORT void JNICALL
 223 Java_nsk_jvmti_SingleStep_singlestep003_nativeMethod(
 224         JNIEnv *env, jobject obj) {
 225     jint i = 0;
 226 
 227     NSK_DISPLAY0("inside the nativeMethod()\n\n");
 228     i++;
 229 
 230     Java_nsk_jvmti_SingleStep_singlestep003_anotherNativeMethod(env, obj, i);
 231 }
 232 
 233 JNIEXPORT jint JNICALL
 234 Java_nsk_jvmti_SingleStep_singlestep003_check(
 235         JNIEnv *env, jobject obj) {
 236     int i;
 237 
 238     for (i=0; i<METH_NUM; i++)
 239         if (stepEv[i][0] == 0) {
 240             if (stepEv[i][1] == 0) {
 241                 NSK_DISPLAY1("CHECK PASSED: no SingleStep events for the method \"%s\" as expected\n\n",
 242                     METHODS[i][0]);
 243             }
 244             else {
 245                 result = STATUS_FAILED;
 246                 NSK_COMPLAIN1("TEST FAILED: no SingleStep events for the method \"%s\"\n\n",
 247                     METHODS[i][0]);
 248             }
 249         }
 250 
 251     return result;
 252 }
 253 
 254 #ifdef STATIC_BUILD
 255 JNIEXPORT jint JNICALL Agent_OnLoad_singlestep003(JavaVM *jvm, char *options, void *reserved) {
 256     return Agent_Initialize(jvm, options, reserved);
 257 }
 258 JNIEXPORT jint JNICALL Agent_OnAttach_singlestep003(JavaVM *jvm, char *options, void *reserved) {
 259     return Agent_Initialize(jvm, options, reserved);
 260 }
 261 JNIEXPORT jint JNI_OnLoad_singlestep003(JavaVM *jvm, char *options, void *reserved) {
 262     return JNI_VERSION_1_8;
 263 }
 264 #endif
 265 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
 266     jvmtiCapabilities caps;
 267 
 268     /* init framework and parse options */
 269     if (!NSK_VERIFY(nsk_jvmti_parseOptions(options)))
 270         return JNI_ERR;
 271 
 272     /* create JVMTI environment */
 273     if (!NSK_VERIFY((jvmti =
 274             nsk_jvmti_createJVMTIEnv(jvm, reserved)) != NULL))
 275         return JNI_ERR;
 276 
 277     /* add capability to generate compiled method events */
 278     memset(&caps, 0, sizeof(jvmtiCapabilities));
 279     caps.can_generate_breakpoint_events = 1;
 280     caps.can_generate_single_step_events = 1;
 281     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(AddCapabilities,
 282             jvmti, &caps)))
 283         return JNI_ERR;
 284 
 285     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(GetCapabilities,
 286             jvmti, &caps)))
 287         return JNI_ERR;
 288     if (!caps.can_generate_single_step_events)
 289         NSK_DISPLAY0("Warning: generation of single step events is not implemented\n");
 290 
 291     /* set event callback */
 292     NSK_DISPLAY0("setting event callbacks ...\n");
 293     (void) memset(&callbacks, 0, sizeof(callbacks));
 294     callbacks.ClassLoad = &ClassLoad;
 295     callbacks.Breakpoint = &Breakpoint;
 296     callbacks.SingleStep = &SingleStep;
 297     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3(SetEventCallbacks,
 298             jvmti, &callbacks, sizeof(callbacks))))
 299         return JNI_ERR;
 300 
 301     NSK_DISPLAY0("setting event callbacks done\nenabling JVMTI events ...\n");
 302     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode,
 303             jvmti, JVMTI_ENABLE, JVMTI_EVENT_CLASS_LOAD, NULL)))
 304         return JNI_ERR;
 305     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode,
 306             jvmti, JVMTI_ENABLE, JVMTI_EVENT_BREAKPOINT, NULL)))
 307         return JNI_ERR;
 308     NSK_DISPLAY0("enabling the events done\n\n");
 309 
 310     return JNI_OK;
 311 }
 312 
 313 }