1 /*
  2  * Copyright (c) 200
  3  * git 3, 2019, Oracle and/or its affiliates. All rights reserved.
  4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  5  *
  6  * This code is free software; you can redistribute it and/or modify it
  7  * under the terms of the GNU General Public License version 2 only, as
  8  * published by the Free Software Foundation.
  9  *
 10  * This code is distributed in the hope that it will be useful, but WITHOUT
 11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 13  * version 2 for more details (a copy is included in the LICENSE file that
 14  * accompanied this code).
 15  *
 16  * You should have received a copy of the GNU General Public License version
 17  * 2 along with this work; if not, write to the Free Software Foundation,
 18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 19  *
 20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 21  * or visit www.oracle.com if you need additional information or have any
 22  * questions.
 23  */
 24 
 25 #include <stdio.h>
 26 #include <string.h>
 27 #include <jvmti.h>
 28 #include "jvmti_common.h"
 29 
 30 extern "C" {
 31 
 32 #define STATUS_FAILED 2
 33 #define PASSED 0
 34 
 35 #define METH_NUM 2
 36 
 37 static const char *METHODS[] = {
 38     "bpMethod",
 39     "runThis"
 40 };
 41 
 42 static const char *METHOD_SIGS[] = {
 43     "()V",
 44     "()I"
 45 };
 46 
 47 static volatile long stepEv[] = {0, 0};
 48 
 49 static const char *CLASS_SIG =
 50     "Lsinglestep01;";
 51 
 52 static volatile jint result = PASSED;
 53 static jvmtiEnv *jvmti = NULL;
 54 
 55 static volatile jboolean isVirtualExpected = JNI_FALSE;
 56 
 57 static volatile int callbacksEnabled = NSK_FALSE;
 58 static jrawMonitorID agent_lock;
 59 
 60 static void setBP(jvmtiEnv *jvmti, JNIEnv *jni, jclass klass) {
 61   jmethodID mid;
 62   jvmtiError err;
 63 
 64   mid = jni->GetMethodID(klass, METHODS[0], METHOD_SIGS[0]);
 65   if (mid == NULL) {
 66     jni->FatalError("failed to get ID for the java method\n");
 67   }
 68 
 69   LOG("Setting breakpoint....");
 70   err = jvmti->SetBreakpoint(mid, 0);
 71   if (err != JVMTI_ERROR_NONE) {
 72     jni->FatalError("failed to set breakpoint\n");
 73   }
 74 }
 75 
 76 /** callback functions **/
 77 void JNICALL
 78 ClassLoad(jvmtiEnv *jvmti, JNIEnv *jni, jthread thread, jclass klass) {
 79   char *sig, *generic;
 80   jvmtiError err;
 81 
 82   RawMonitorLocker rml(jvmti, jni, agent_lock);
 83 
 84   if (callbacksEnabled) {
 85     err = jvmti->GetClassSignature(klass, &sig, &generic);
 86     if (err != JVMTI_ERROR_NONE) {
 87       jni->FatalError("failed to obtain a class signature\n");
 88     }
 89     if (sig != NULL && (strcmp(sig, CLASS_SIG) == 0)) {
 90       LOG(
 91           "ClassLoad event received for the class \"%s\"\n"
 92           "\tsetting breakpoint ...\n",
 93           sig);
 94       setBP(jvmti, jni, klass);
 95     }
 96   }
 97 }
 98 
 99 void JNICALL
100 Breakpoint(jvmtiEnv *jvmti, JNIEnv *jni, jthread thr, jmethodID method, jlocation loc) {
101   jclass klass;
102   char *sig, *generic;
103   jvmtiError err;
104 
105   RawMonitorLocker rml(jvmti, jni, agent_lock);
106 
107   if (!callbacksEnabled) {
108     return;
109   }
110 
111   NSK_DISPLAY0("Breakpoint event received\n");
112   err = jvmti->GetMethodDeclaringClass(method, &klass);
113   if (err != JVMTI_ERROR_NONE) {
114     NSK_COMPLAIN0("TEST FAILURE: unable to get method declaring class\n\n");
115   }
116 
117   err = jvmti->GetClassSignature(klass, &sig, &generic);
118   if (err != JVMTI_ERROR_NONE) {
119     jni->FatalError("Breakpoint: failed to obtain a class signature\n");
120   }
121 
122   if (sig != NULL && (strcmp(sig, CLASS_SIG) == 0)) {
123     LOG("method declaring class \"%s\"\n\tenabling SingleStep events ...\n", sig);
124     err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_SINGLE_STEP, thr);
125     if (err != JVMTI_ERROR_NONE) {
126       result = STATUS_FAILED;
127       NSK_COMPLAIN0("TEST FAILURE: cannot enable SingleStep events\n\n");
128     }
129   } else {
130     result = STATUS_FAILED;
131     NSK_COMPLAIN1("TEST FAILURE: unexpected breakpoint event in method of class \"%s\"\n\n",
132                   sig);
133   }
134   isVirtualExpected = jni->IsVirtualThread(thr);
135 }
136 
137 void JNICALL
138 SingleStep(jvmtiEnv *jvmti, JNIEnv *jni, jthread thread,
139            jmethodID method, jlocation location) {
140   jclass klass;
141   char *sig, *generic, *methNam, *methSig;
142   jvmtiError err;
143 
144   if (result == STATUS_FAILED) {
145     return;
146   }
147 
148   NSK_DISPLAY0(">>>> SingleStep event received\n");
149 
150   print_thread_info(jvmti, jni, thread);
151 
152   err = jvmti->GetMethodName(method, &methNam, &methSig, NULL);
153   if (err != JVMTI_ERROR_NONE) {
154     result = STATUS_FAILED;
155     NSK_COMPLAIN0("TEST FAILED: unable to get method name during SingleStep callback\n\n");
156     return;
157   }
158 
159   err = jvmti->GetMethodDeclaringClass(method, &klass);
160   if (err != JVMTI_ERROR_NONE) {
161     result = STATUS_FAILED;
162     NSK_COMPLAIN0("TEST FAILED: unable to get method declaring class during SingleStep callback\n\n");
163     return;
164   }
165 
166   err = jvmti->GetClassSignature(klass, &sig, &generic);
167   if (err != JVMTI_ERROR_NONE) {
168     result = STATUS_FAILED;
169     NSK_COMPLAIN0("TEST FAILED: unable to obtain a class signature during SingleStep callback\n\n");
170     return;
171   }
172 
173   if (sig != NULL) {
174     NSK_DISPLAY3(
175         "\tmethod name: \"%s\"\n"
176         "\tsignature: \"%s\"\n"
177         "\tmethod declaring class: \"%s\"\n",
178         methNam, methSig, sig);
179 
180     if (stepEv[1] == 1) {
181       result = STATUS_FAILED;
182       NSK_COMPLAIN0("TEST FAILED: SingleStep event received after disabling the event generation\n\n");
183     } else if ((strcmp(methNam, METHODS[0]) == 0) &&
184         (strcmp(methSig, METHOD_SIGS[0]) == 0) &&
185         (strcmp(sig, CLASS_SIG) == 0)) {
186       stepEv[0]++;
187       LOG("CHECK PASSED: SingleStep event received for the method \"%s\" as expected\n",
188                    methNam);
189     } else if ((strcmp(methNam, METHODS[1]) == 0) &&
190         (strcmp(methSig, METHOD_SIGS[1]) == 0) &&
191         (strcmp(sig, CLASS_SIG) == 0)) {
192       jboolean isVirtual = jni->IsVirtualThread(thread);
193       if (isVirtualExpected != isVirtual) {
194         LOG("The thread IsVirtualThread %d differs from expected %d.\n", isVirtual, isVirtualExpected);
195         result = STATUS_FAILED;
196       } else {
197         stepEv[1]++;
198         LOG(
199             "CHECK PASSED: SingleStep event received for the method \"%s\" as expected\n"
200             "\tdisabling the event generation\n",
201             methNam);
202       }
203       err = jvmti->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_SINGLE_STEP, thread);
204       if (err != JVMTI_ERROR_NONE) {
205         result = STATUS_FAILED;
206         NSK_COMPLAIN0("TEST FAILED: cannot disable SingleStep events\n\n");
207       }
208     }
209   }
210 
211   err = jvmti->Deallocate((unsigned char *) methNam);
212   if (err != JVMTI_ERROR_NONE) {
213     result = STATUS_FAILED;
214     NSK_COMPLAIN0("TEST FAILED: unable to deallocate memory pointed to method name\n\n");
215   }
216   err = jvmti->Deallocate((unsigned char *) methSig);
217   if (err != JVMTI_ERROR_NONE) {
218     result = STATUS_FAILED;
219     NSK_COMPLAIN0("TEST FAILED: unable to deallocate memory pointed to method signature\n\n");
220   }
221 
222   LOG("<<<<\n\n");
223 }
224 
225 void JNICALL
226 VMStart(jvmtiEnv *jvmti, JNIEnv *jni) {
227   RawMonitorLocker rml(jvmti, jni, agent_lock);
228   callbacksEnabled = NSK_TRUE;
229 }
230 
231 void JNICALL
232 VMDeath(jvmtiEnv *jvmti, JNIEnv *jni) {
233   RawMonitorLocker rml(jvmti, jni, agent_lock);
234   callbacksEnabled = NSK_FALSE;
235 }
236 /************************/
237 
238 JNIEXPORT jint JNICALL
239 Java_singlestep01_check(JNIEnv *jni, jobject obj) {
240   for (int i = 0; i < METH_NUM; i++) {
241     if (stepEv[i] == 0) {
242       result = STATUS_FAILED;
243       NSK_COMPLAIN1("TEST FAILED: no SingleStep events for the method \"%s\"\n\n",
244                     METHODS[i]);
245     } else {
246       stepEv[i] = 0;
247     }
248   }
249   return result;
250 }
251 
252 #ifdef STATIC_BUILD
253 JNIEXPORT jint JNICALL Agent_OnLoad_singlestep01(JavaVM *jvm, char *options, void *reserved) {
254     return Agent_Initialize(jvm, options, reserved);
255 }
256 JNIEXPORT jint JNICALL Agent_OnAttach_singlestep01(JavaVM *jvm, char *options, void *reserved) {
257     return Agent_Initialize(jvm, options, reserved);
258 }
259 JNIEXPORT jint JNI_OnLoad_singlestep01(JavaVM *jvm, char *options, void *reserved) {
260     return JNI_VERSION_1_8;
261 }
262 #endif
263 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
264   jvmtiEventCallbacks callbacks;
265   jvmtiCapabilities caps;
266   jvmtiError err;
267   jint res;
268 
269   res = jvm->GetEnv((void **) &jvmti, JVMTI_VERSION_1_1);
270   if (res != JNI_OK || jvmti == NULL) {
271     LOG("Wrong result of a valid call to GetEnv!\n");
272     return JNI_ERR;
273   }
274   /* add capability to generate compiled method events */
275   memset(&caps, 0, sizeof(jvmtiCapabilities));
276   caps.can_generate_breakpoint_events = 1;
277   caps.can_generate_single_step_events = 1;
278   caps.can_support_virtual_threads = 1;
279 
280   err = jvmti->AddCapabilities(&caps);
281   if (err != JVMTI_ERROR_NONE) {
282     LOG("(AddCapabilities) unexpected error: %s (%d)\n",
283            TranslateError(err), err);
284     return JNI_ERR;
285   }
286 
287   err = jvmti->GetCapabilities(&caps);
288   if (err != JVMTI_ERROR_NONE) {
289     LOG("(GetCapabilities) unexpected error: %s (%d)\n",
290            TranslateError(err), err);
291     return JNI_ERR;
292   }
293 
294   if (!caps.can_generate_single_step_events) {
295     LOG("Warning: generation of single step events is not implemented\n");
296   }
297 
298   /* set event callback */
299   LOG("setting event callbacks ...\n");
300   (void) memset(&callbacks, 0, sizeof(callbacks));
301   callbacks.ClassLoad = &ClassLoad;
302   callbacks.Breakpoint = &Breakpoint;
303   callbacks.SingleStep = &SingleStep;
304   callbacks.VMStart = &VMStart;
305   callbacks.VMDeath = &VMDeath;
306   err = jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks));
307   if (err != JVMTI_ERROR_NONE) {
308     return JNI_ERR;
309   }
310 
311   LOG("setting event callbacks done\nenabling JVMTI events ...\n");
312   err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_VM_START, NULL);
313   if (err != JVMTI_ERROR_NONE) {
314     return JNI_ERR;
315   }
316   err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_VM_DEATH, NULL);
317   if (err != JVMTI_ERROR_NONE) {
318     return JNI_ERR;
319   }
320   err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_CLASS_LOAD, NULL);
321   if (err != JVMTI_ERROR_NONE) {
322     return JNI_ERR;
323   }
324   err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_BREAKPOINT, NULL);
325   if (err != JVMTI_ERROR_NONE) {
326     return JNI_ERR;
327   }
328 
329   LOG("enabling the events done\n\n");
330 
331   agent_lock = create_raw_monitor(jvmti, "agent lock");
332 
333   return JNI_OK;
334 }
335 
336 JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {
337   return Agent_Initialize(jvm, options, reserved);
338 }
339 
340 JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) {
341   return Agent_Initialize(jvm, options, reserved);
342 }
343 
344 }