1 /*
  2  * Copyright (c) 2003, 2019, 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 "jvmti_common.h"
 28 
 29 extern "C" {
 30 
 31 #define STATUS_FAILED 2
 32 #define PASSED 0
 33 
 34 /* tested methods */
 35 #define METH_NUM 4
 36 static const char *METHODS[][2] = {
 37     {"bpMethod", "()V"},
 38     {"nativeMethod", "()V"},
 39     {"anotherNativeMethod", "(I)V"},
 40     {"runThis", "()I"}
 41 };
 42 
 43 /* event counters for the tested methods and expected numbers
 44  of the events */
 45 static volatile long stepEv[][2] = {
 46     {0, 1},
 47     {0, 0},
 48     {0, 0},
 49     {0, 1}
 50 };
 51 
 52 static const char *CLASS_SIG =
 53     "Lsinglestep03;";
 54 
 55 static volatile jint result = PASSED;
 56 static jvmtiEnv *jvmti = NULL;
 57 static jvmtiEventCallbacks callbacks;
 58 
 59 static volatile int callbacksEnabled = NSK_FALSE;
 60 static jrawMonitorID agent_lock;
 61 
 62 static void setBP(jvmtiEnv *jvmti, JNIEnv *jni, jclass klass) {
 63   jmethodID mid;
 64   jvmtiError err;
 65 
 66   mid = jni->GetMethodID(klass, METHODS[0][0], METHODS[0][1]);
 67   if (mid == NULL) {
 68     jni->FatalError("failed to get ID for the java method\n");
 69   }
 70 
 71   err = jvmti->SetBreakpoint(mid, 0);
 72   if (err != JVMTI_ERROR_NONE) {
 73     jni->FatalError("failed to set breakpoint\n");
 74   }
 75 }
 76 
 77 /** callback functions **/
 78 void JNICALL
 79 ClassLoad(jvmtiEnv *jvmti, JNIEnv *jni, jthread thread, jclass klass) {
 80   char *sig, *generic;
 81   jvmtiError err;
 82 
 83   RawMonitorLocker rml(jvmti, jni, agent_lock);
 84 
 85   if (!callbacksEnabled) {
 86     return;
 87   }
 88 
 89   err = jvmti->GetClassSignature(klass, &sig, &generic);
 90   if (err != JVMTI_ERROR_NONE) {
 91     jni->FatalError("failed to obtain a class signature\n");
 92   }
 93 
 94   if (sig != NULL && (strcmp(sig, CLASS_SIG) == 0)) {
 95     NSK_DISPLAY1(
 96         "ClassLoad event received for the class \"%s\"\n"
 97         "\tsetting breakpoint ...\n",
 98         sig);
 99     setBP(jvmti, jni, klass);
100   }
101 }
102 
103 void JNICALL
104 VMStart(jvmtiEnv *jvmti, JNIEnv *jni) {
105   RawMonitorLocker rml(jvmti, jni, agent_lock);
106   callbacksEnabled = NSK_TRUE;
107 }
108 
109 void JNICALL
110 VMDeath(jvmtiEnv *jvmti, JNIEnv *jni) {
111   RawMonitorLocker rml(jvmti, jni, agent_lock);
112   callbacksEnabled = NSK_FALSE;
113 }
114 
115 void JNICALL
116 Breakpoint(jvmtiEnv *jvmti, JNIEnv *jni, jthread thr, jmethodID method,
117            jlocation loc) {
118   jclass klass;
119   char *sig, *generic;
120   jvmtiError err;
121 
122   RawMonitorLocker rml(jvmti, jni, agent_lock);
123 
124   if (!callbacksEnabled) {
125     return;
126   }
127 
128   NSK_DISPLAY0("Breakpoint event received\n");
129   err = jvmti->GetMethodDeclaringClass(method, &klass);
130   if (err != JVMTI_ERROR_NONE) {
131     NSK_COMPLAIN0("TEST FAILURE: unable to get method declaring class\n\n");
132   }
133 
134   err = jvmti->GetClassSignature(klass, &sig, &generic);
135   if (err != JVMTI_ERROR_NONE) {
136     jni->FatalError("Breakpoint: failed to obtain a class signature\n");
137   }
138 
139   if (sig != NULL && (strcmp(sig, CLASS_SIG) == 0)) {
140     NSK_DISPLAY1("method declaring class \"%s\"\n\tenabling SingleStep events ...\n",
141                  sig);
142     err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_SINGLE_STEP, thr);
143     if (err != JVMTI_ERROR_NONE) {
144       result = STATUS_FAILED;
145       NSK_COMPLAIN0("TEST FAILURE: cannot enable SingleStep events\n\n");
146     }
147   } else {
148     result = STATUS_FAILED;
149     NSK_COMPLAIN1("TEST FAILURE: unexpected breakpoint event in method of class \"%s\"\n\n",
150                   sig);
151   }
152 
153 }
154 
155 void JNICALL
156 SingleStep(jvmtiEnv *jvmti, JNIEnv *jni, jthread thread,
157            jmethodID method, jlocation location) {
158   jvmtiError err;
159   jclass klass;
160   char *sig, *generic, *methNam, *methSig;
161   int i;
162 
163   if (result == STATUS_FAILED) {
164     return;
165   }
166 
167   NSK_DISPLAY0(">>>> SingleStep event received\n");
168 
169   err = jvmti->GetMethodName(method, &methNam, &methSig, NULL);
170   if (err != JVMTI_ERROR_NONE) {
171     result = STATUS_FAILED;
172     NSK_COMPLAIN0("TEST FAILED: unable to get method name during SingleStep callback\n\n");
173     return;
174   }
175 
176   err = jvmti->GetMethodDeclaringClass(method, &klass);
177   if (err != JVMTI_ERROR_NONE) {
178     result = STATUS_FAILED;
179     NSK_COMPLAIN0("TEST FAILED: unable to get method declaring class during SingleStep callback\n\n");
180     return;
181   }
182 
183   err = jvmti->GetClassSignature(klass, &sig, &generic);
184   if (err != JVMTI_ERROR_NONE) {
185     result = STATUS_FAILED;
186     NSK_COMPLAIN0("TEST FAILED: unable to obtain a class signature during SingleStep callback\n\n");
187     return;
188   }
189 
190   if (sig != NULL) {
191     if (stepEv[METH_NUM - 1][0] == 1) {
192       result = STATUS_FAILED;
193       NSK_COMPLAIN0("TEST FAILED: SingleStep event received after disabling the event generation\n\n");
194       return;
195     }
196 
197     for (i = 0; i < METH_NUM; i++) {
198       if ((strcmp(methNam, METHODS[i][0]) == 0) &&
199           (strcmp(methSig, METHODS[i][1]) == 0) &&
200           (strcmp(sig, CLASS_SIG) == 0)) {
201         stepEv[i][0]++;
202 
203         if (stepEv[i][1] == 1) {
204           NSK_DISPLAY3(
205               "CHECK PASSED: SingleStep event received for the method:\n"
206               "\t \"%s %s\" of class \"%s\"\n"
207               "\tas expected\n",
208               methNam, methSig, sig);
209         } else {
210           result = STATUS_FAILED;
211           LOG(
212               "TEST FAILED: SingleStep event received for the method:\n"
213               "\t \"%s %s\" of class \"%s\"\n",
214               methNam, methSig, sig);
215         }
216 
217         if (i == (METH_NUM - 1)) {
218           NSK_DISPLAY0("Disabling the single step event generation\n");
219           err = jvmti->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_SINGLE_STEP, thread);
220           if (err != JVMTI_ERROR_NONE) {
221             result = STATUS_FAILED;
222             NSK_COMPLAIN0("TEST FAILED: cannot disable SingleStep events\n\n");
223           }
224         }
225       }
226     }
227   }
228 
229   err = jvmti->Deallocate((unsigned char *) methNam);
230   if (err != JVMTI_ERROR_NONE) {
231     result = STATUS_FAILED;
232     NSK_COMPLAIN0("TEST FAILED: unable to deallocate memory pointed to method name\n\n");
233   }
234   err = jvmti->Deallocate((unsigned char *) methSig);
235   if (err != JVMTI_ERROR_NONE) {
236     result = STATUS_FAILED;
237     NSK_COMPLAIN0("TEST FAILED: unable to deallocate memory pointed to method signature\n\n");
238   }
239 
240   NSK_DISPLAY0("<<<<\n\n");
241 }
242 /************************/
243 
244 /* dummy method used only to provoke SingleStep events */
245 JNIEXPORT void JNICALL
246 Java_singlestep03_anotherNativeMethod(
247     JNIEnv *jni, jobject obj, jint i) {
248   NSK_DISPLAY0("inside the anotherNativeMethod()\n\n");
249 }
250 
251 /* dummy method used only to provoke SingleStep events */
252 JNIEXPORT void JNICALL
253 Java_singlestep03_nativeMethod(
254     JNIEnv *jni, jobject obj) {
255   jint i = 0;
256 
257   NSK_DISPLAY0("inside the nativeMethod()\n\n");
258   i++;
259 
260   Java_singlestep03_anotherNativeMethod(jni, obj, i);
261 }
262 
263 JNIEXPORT jint JNICALL Java_singlestep03_check(JNIEnv *jni, jobject obj) {
264 
265   for (int i = 0; i < METH_NUM; i++)
266     if (stepEv[i][0] == 0) {
267       if (stepEv[i][1] == 0) {
268         NSK_DISPLAY1("CHECK PASSED: no SingleStep events for the method \"%s\" as expected\n\n",
269                      METHODS[i][0]);
270       } else {
271         result = STATUS_FAILED;
272         NSK_COMPLAIN1("TEST FAILED: no SingleStep events for the method \"%s\"\n\n",
273                       METHODS[i][0]);
274       }
275     }
276 
277   return result;
278 }
279 
280 #ifdef STATIC_BUILD
281 JNIEXPORT jint JNICALL Agent_OnLoad_singlestep03(JavaVM *jvm, char *options, void *reserved) {
282     return Agent_Initialize(jvm, options, reserved);
283 }
284 JNIEXPORT jint JNICALL Agent_OnAttach_singlestep03(JavaVM *jvm, char *options, void *reserved) {
285     return Agent_Initialize(jvm, options, reserved);
286 }
287 JNIEXPORT jint JNI_OnLoad_singlestep03(JavaVM *jvm, char *options, void *reserved) {
288     return JNI_VERSION_1_8;
289 }
290 #endif
291 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
292   jvmtiCapabilities caps;
293   jvmtiError err;
294   jint res;
295 
296   res = jvm->GetEnv((void **) &jvmti, JVMTI_VERSION_1_1);
297   if (res != JNI_OK || jvmti == NULL) {
298     LOG("Wrong result of a valid call to GetEnv!\n");
299     return JNI_ERR;
300   }
301 
302   /* add capability to generate compiled method events */
303   memset(&caps, 0, sizeof(jvmtiCapabilities));
304   caps.can_generate_breakpoint_events = 1;
305   caps.can_generate_single_step_events = 1;
306   err = jvmti->AddCapabilities(&caps);
307   if (err != JVMTI_ERROR_NONE) {
308     LOG("(AddCapabilities) unexpected error: %s (%d)\n",
309            TranslateError(err), err);
310     return JNI_ERR;
311   }
312 
313   err = jvmti->GetCapabilities(&caps);
314   if (err != JVMTI_ERROR_NONE) {
315     LOG("(GetCapabilities) unexpected error: %s (%d)\n",
316            TranslateError(err), err);
317     return JNI_ERR;
318   }
319   if (!caps.can_generate_single_step_events)
320     NSK_DISPLAY0("Warning: generation of single step events is not implemented\n");
321 
322   /* set event callback */
323   NSK_DISPLAY0("setting event callbacks ...\n");
324   (void) memset(&callbacks, 0, sizeof(callbacks));
325   callbacks.ClassLoad = &ClassLoad;
326   callbacks.Breakpoint = &Breakpoint;
327   callbacks.SingleStep = &SingleStep;
328   callbacks.VMStart = &VMStart;
329   callbacks.VMDeath = &VMDeath;
330 
331   err = jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks));
332   if (err != JVMTI_ERROR_NONE) {
333     return JNI_ERR;
334   }
335 
336   NSK_DISPLAY0("setting event callbacks done\nenabling JVMTI events ...\n");
337   err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_VM_START, NULL);
338   if (err != JVMTI_ERROR_NONE) {
339     return JNI_ERR;
340   }
341   err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_VM_DEATH, NULL);
342   if (err != JVMTI_ERROR_NONE) {
343     return JNI_ERR;
344   }
345   err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_CLASS_LOAD, NULL);
346   if (err != JVMTI_ERROR_NONE) {
347     return JNI_ERR;
348   }
349   err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_BREAKPOINT, NULL);
350   if (err != JVMTI_ERROR_NONE) {
351     return JNI_ERR;
352   }
353 
354   NSK_DISPLAY0("enabling the events done\n\n");
355 
356   agent_lock = create_raw_monitor(jvmti, "agent lock");
357 
358   return JNI_OK;
359 }
360 
361 JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {
362   return Agent_Initialize(jvm, options, reserved);
363 }
364 
365 JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) {
366   return Agent_Initialize(jvm, options, reserved);
367 }
368 
369 }