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 #define METH_NUM 2
  40 static const char *METHODS[][2] = {
  41     {"bpMethod", "()V"},
  42     {"bpMethod2", "()I"}
  43 };
  44 
  45 static const char *CLASS_SIG =
  46     "Lnsk/jvmti/Breakpoint/breakpoint001;";
  47 
  48 static const char *THREAD_NAME = "breakpoint001Thr";
  49 
  50 static volatile int bpEvents[METH_NUM];
  51 static volatile jint result = PASSED;
  52 static jvmtiEnv *jvmti = NULL;
  53 static jvmtiEventCallbacks callbacks;
  54 
  55 static int vm_started = 0;
  56 static jrawMonitorID agent_lock;
  57 
  58 static void initCounters() {
  59     int i;
  60 
  61     for(i=0; i<METH_NUM; i++)
  62         bpEvents[i] = 0;
  63 }
  64 
  65 static void setBP(jvmtiEnv *jvmti_env, JNIEnv *env, jclass klass) {
  66     jmethodID mid;
  67     int i;
  68 
  69     for (i=0; i<METH_NUM; i++) {
  70         if (!NSK_JNI_VERIFY(env, (mid = NSK_CPP_STUB4(GetMethodID,
  71                 env, klass, METHODS[i][0], METHODS[i][1])) != NULL))
  72             NSK_CPP_STUB2(FatalError, env,
  73                 "failed to get ID for the java method\n");
  74 
  75         if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3(SetBreakpoint,
  76                 jvmti_env, mid, 0)))
  77             NSK_CPP_STUB2(FatalError, env,
  78                 "failed to set breakpoint\n");
  79     }
  80 }
  81 
  82 /** callback functions **/
  83 void JNICALL
  84 ClassLoad(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thread, jclass klass) {
  85     char *sig, *generic;
  86 
  87     jvmti->RawMonitorEnter(agent_lock);
  88 
  89     if (vm_started) {
  90         // GetClassSignature may be called only during the start or the live phase
  91         if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(GetClassSignature,
  92                                             jvmti_env, klass, &sig, &generic)))
  93             NSK_CPP_STUB2(FatalError, env,
  94                           "failed to obtain a class signature\n");
  95 
  96         if (sig != NULL && (strcmp(sig, CLASS_SIG) == 0)) {
  97             NSK_DISPLAY1(
  98                 "ClassLoad event received for the class \"%s\"\n"
  99                 "\tsetting breakpoints ...\n",
 100                 sig);
 101             setBP(jvmti_env, env, klass);
 102         }
 103     }
 104 
 105     jvmti->RawMonitorExit(agent_lock);
 106 }
 107 
 108 void JNICALL
 109 Breakpoint(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread,
 110         jmethodID method, jlocation location) {
 111     jclass klass;
 112     char *clsSig, *generic, *methNam, *methSig;
 113     jvmtiThreadInfo thr_info;
 114     int checkStatus = PASSED;
 115     int i;
 116 
 117     NSK_DISPLAY0(">>>> Breakpoint event received\n");
 118 
 119     /* checking thread info */
 120     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3(GetThreadInfo,
 121             jvmti_env, thread, &thr_info))) {
 122         result = STATUS_FAILED;
 123         NSK_COMPLAIN0("TEST FAILED: unable to get thread info during Breakpoint callback\n\n");
 124         return;
 125     }
 126     if (thr_info.name == NULL ||
 127             strcmp(thr_info.name,THREAD_NAME) != 0 ||
 128             thr_info.is_daemon==JNI_TRUE) {
 129         result = checkStatus = STATUS_FAILED;
 130         NSK_COMPLAIN2(
 131             "TEST FAILED: Breakpoint event with unexpected thread info:\n"
 132             "\tname: \"%s\"\ttype: %s thread\n\n",
 133             (thr_info.name == NULL)?"NULL":thr_info.name,
 134             (thr_info.is_daemon==JNI_TRUE)?"deamon":"user");
 135     }
 136     else
 137         NSK_DISPLAY2("CHECK PASSED: thread name: \"%s\"\ttype: %s thread\n",
 138             thr_info.name, (thr_info.is_daemon==JNI_TRUE)?"deamon":"user");
 139 
 140     /* checking location */
 141     if (location != 0) {
 142         result = checkStatus = STATUS_FAILED;
 143         NSK_COMPLAIN1("TEST FAILED: Breakpoint event with unexpected location %ld:\n\n",
 144             (long) location);
 145     }
 146     else
 147         NSK_DISPLAY1("CHECK PASSED: location: %ld as expected\n",
 148             (long) location);
 149 
 150     /* checking method info */
 151     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3(GetMethodDeclaringClass,
 152             jvmti_env, method, &klass))) {
 153         result = checkStatus = STATUS_FAILED;
 154         NSK_COMPLAIN0("TEST FAILED: unable to get method declaring class during Breakpoint callback\n\n");
 155         return;
 156     }
 157     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(GetClassSignature,
 158             jvmti_env, klass, &clsSig, &generic))) {
 159         result = checkStatus = STATUS_FAILED;
 160         NSK_COMPLAIN0("TEST FAILED: unable to obtain a class signature during Breakpoint callback\n\n");
 161         return;
 162     }
 163     if (clsSig == NULL ||
 164             strcmp(clsSig,CLASS_SIG) != 0) {
 165         result = checkStatus = STATUS_FAILED;
 166         NSK_COMPLAIN1(
 167             "TEST FAILED: Breakpoint event with unexpected class signature:\n"
 168             "\t\"%s\"\n\n",
 169             (clsSig == NULL) ? "NULL" : clsSig);
 170     }
 171     else
 172         NSK_DISPLAY1("CHECK PASSED: class signature: \"%s\"\n",
 173             clsSig);
 174 
 175     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB5(GetMethodName,
 176             jvmti_env, method, &methNam, &methSig, NULL))) {
 177         result = checkStatus = STATUS_FAILED;
 178         NSK_COMPLAIN0("TEST FAILED: unable to get method name during Breakpoint callback\n\n");
 179         return;
 180     }
 181 
 182     for (i=0; i<METH_NUM; i++)
 183         if (strcmp(methNam,METHODS[i][0]) &&
 184                 strcmp(methSig,METHODS[i][1])) {
 185             NSK_DISPLAY2("CHECK PASSED: method name: \"%s\"\tsignature: \"%s\"\n",
 186                 methNam, methSig);
 187             if (checkStatus == PASSED)
 188                 bpEvents[i]++;
 189             break;
 190         }
 191 
 192     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(Deallocate,
 193             jvmti_env, (unsigned char*) methNam))) {
 194         result = STATUS_FAILED;
 195         NSK_COMPLAIN0("TEST FAILED: unable to deallocate memory pointed to method name\n\n");
 196     }
 197     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(Deallocate,
 198             jvmti_env, (unsigned char*) methSig))) {
 199         result = STATUS_FAILED;
 200         NSK_COMPLAIN0("TEST FAILED: unable to deallocate memory pointed to method signature\n\n");
 201     }
 202 
 203     NSK_DISPLAY0("<<<<\n\n");
 204 }
 205 
 206 
 207 void JNICALL
 208 VMStart(jvmtiEnv *jvmti_env, JNIEnv* jni_env) {
 209     jvmti->RawMonitorEnter(agent_lock);
 210 
 211     vm_started = 1;
 212 
 213     jvmti->RawMonitorExit(agent_lock);
 214 }
 215 
 216 /************************/
 217 
 218 JNIEXPORT jint JNICALL
 219 Java_nsk_jvmti_Breakpoint_breakpoint001_check(
 220         JNIEnv *env, jobject obj) {
 221     int i;
 222 
 223     for (i=0; i<METH_NUM; i++) {
 224         if (bpEvents[i] != 1) {
 225             result = STATUS_FAILED;
 226             NSK_COMPLAIN3(
 227                 "TEST FAILED: wrong number of Breakpoint events\n"
 228                 "\tfor the method \"%s %s\":\n"
 229                 "\t\tgot: %d\texpected: 1\n",
 230                 METHODS[i][0], METHODS[i][1], bpEvents[i]);
 231         }
 232         else
 233             NSK_DISPLAY3("CHECK PASSED: %d Breakpoint event(s) for the method \"%s %s\" as expected\n",
 234                 bpEvents[i], METHODS[i][0], METHODS[i][1]);
 235     }
 236 
 237     return result;
 238 }
 239 
 240 #ifdef STATIC_BUILD
 241 JNIEXPORT jint JNICALL Agent_OnLoad_breakpoint001(JavaVM *jvm, char *options, void *reserved) {
 242     return Agent_Initialize(jvm, options, reserved);
 243 }
 244 JNIEXPORT jint JNICALL Agent_OnAttach_breakpoint001(JavaVM *jvm, char *options, void *reserved) {
 245     return Agent_Initialize(jvm, options, reserved);
 246 }
 247 JNIEXPORT jint JNI_OnLoad_breakpoint001(JavaVM *jvm, char *options, void *reserved) {
 248     return JNI_VERSION_1_8;
 249 }
 250 #endif
 251 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
 252     jvmtiCapabilities caps;
 253 
 254     /* init framework and parse options */
 255     if (!NSK_VERIFY(nsk_jvmti_parseOptions(options)))
 256         return JNI_ERR;
 257 
 258     /* create JVMTI environment */
 259     if (!NSK_VERIFY((jvmti =
 260             nsk_jvmti_createJVMTIEnv(jvm, reserved)) != NULL))
 261         return JNI_ERR;
 262 
 263     initCounters();
 264 
 265     /* add capability to generate compiled method events */
 266     memset(&caps, 0, sizeof(jvmtiCapabilities));
 267     caps.can_generate_breakpoint_events = 1;
 268     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(AddCapabilities,
 269             jvmti, &caps)))
 270         return JNI_ERR;
 271 
 272     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(GetCapabilities,
 273             jvmti, &caps)))
 274         return JNI_ERR;
 275 
 276     if (!caps.can_generate_single_step_events)
 277         NSK_DISPLAY0("Warning: generation of single step events is not implemented\n");
 278 
 279     /* set event callback */
 280     NSK_DISPLAY0("setting event callbacks ...\n");
 281     (void) memset(&callbacks, 0, sizeof(callbacks));
 282     callbacks.ClassLoad = &ClassLoad;
 283     callbacks.Breakpoint = &Breakpoint;
 284     callbacks.VMStart = &VMStart;
 285     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3(SetEventCallbacks,
 286             jvmti, &callbacks, sizeof(callbacks))))
 287         return JNI_ERR;
 288 
 289     NSK_DISPLAY0("setting event callbacks done\nenabling JVMTI events ...\n");
 290 
 291     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode,
 292             jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_START, NULL)))
 293         return JNI_ERR;
 294     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode,
 295             jvmti, JVMTI_ENABLE, JVMTI_EVENT_CLASS_LOAD, NULL)))
 296         return JNI_ERR;
 297     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode,
 298             jvmti, JVMTI_ENABLE, JVMTI_EVENT_BREAKPOINT, NULL)))
 299         return JNI_ERR;
 300     NSK_DISPLAY0("enabling the events done\n\n");
 301 
 302     if (jvmti->CreateRawMonitor("agent_lock", &agent_lock) != JVMTI_ERROR_NONE) {
 303         return JNI_ERR;
 304     }
 305 
 306     return JNI_OK;
 307 }
 308 
 309 }