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