1 /*
  2  * Copyright (c) 2003, 2024, 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.hpp"
 28 #include "jvmti_thread.hpp"
 29 
 30 
 31 extern "C" {
 32 
 33 const int MAX_COUNT = 50;
 34 
 35 /* scaffold objects */
 36 static jvmtiEnv *jvmti = nullptr;
 37 static jlong timeout = 0;
 38 
 39 /* test objects */
 40 static jthread expected_thread = nullptr;
 41 static jobject expected_object = nullptr;
 42 static volatile int eventsCount = 0;
 43 
 44 static void check_stack_trace(JNIEnv* env, jthread thr);
 45 
 46 void JNICALL
 47 MonitorWaited(jvmtiEnv *jvmti, JNIEnv *jni, jthread thr, jobject obj, jboolean timed_out) {
 48 
 49   LOG("MonitorWaited event:\n\tthread: %p, object: %p, timed_out: %s\n",
 50       thr, obj, (timed_out == JNI_TRUE) ? "true" : "false");
 51 
 52   print_thread_info(jvmti, jni, thr);
 53 
 54   if (expected_thread == nullptr) {
 55     jni->FatalError("expected_thread is null.");
 56   }
 57 
 58   if (expected_object == nullptr) {
 59     jni->FatalError("expected_object is null.");
 60   }
 61 
 62   /* check if event is for tested thread and for tested object */
 63   if (jni->IsSameObject(expected_thread, thr) &&
 64       jni->IsSameObject(expected_object, obj)) {
 65     eventsCount++;
 66     if (timed_out == JNI_TRUE) {
 67       COMPLAIN("Unexpected timed_out value: true\n");
 68       set_agent_fail_status();
 69     }
 70   }
 71 
 72   if (jni->IsVirtualThread(thr)) {
 73     check_stack_trace(jni, thr);
 74   }
 75 }
 76 
 77 /* ========================================================================== */
 78 
 79 static void check_stack_trace(JNIEnv* jni, jthread thr) {
 80   jvmtiError err;
 81   jint count = 0;
 82   jint skipped = 0;
 83 
 84   print_stack_trace(jvmti, jni, nullptr);
 85 
 86   jvmtiFrameInfo frameInfo[MAX_COUNT];
 87 
 88   err = jvmti->GetStackTrace(thr, 0, MAX_COUNT, frameInfo, &count);
 89   check_jvmti_status(jni, err, "event handler: error in JVMTI GetStackTrace call");
 90 
 91   const int expected_count = 8;
 92   const char* expected_methods[expected_count] = {"wait0", "wait", "run", "runWith", "run", "run", "enter0", "enter"};
 93 
 94   if (count != expected_count) {
 95     LOG("Expected 8 methods in the stack but found %d", count);
 96     jni->FatalError("Unexpected method count");
 97   }
 98 
 99   for (int idx = 0; idx < count; idx++) {
100     jclass declaringClass = nullptr;
101     char *clasSignature = nullptr;
102     char *methodName = nullptr;
103 
104     err = jvmti->GetMethodName(frameInfo[idx].method, &methodName, nullptr, nullptr);
105     check_jvmti_status(jni, err, "event handler: error in JVMTI GetMethodName call");
106 
107     if (strcmp(methodName, expected_methods[idx]) != 0) {
108       LOG("Expected method %s but found %s", expected_methods[idx], methodName);
109       jni->FatalError("Unexpected method found");
110     }
111   }
112 }
113 
114 static int prepare() {
115   /* enable MonitorWait event */
116   jvmtiError err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_MONITOR_WAITED, nullptr);
117   if (err != JVMTI_ERROR_NONE) {
118     LOG("Prepare: 11\n");
119     return JNI_FALSE;
120   }
121   return JNI_TRUE;
122 }
123 
124 static int clean() {
125   /* disable MonitorWaited event */
126   jvmtiError err = jvmti->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_MONITOR_WAITED, nullptr);
127   if (err != JVMTI_ERROR_NONE) {
128     set_agent_fail_status();
129   }
130   return JNI_TRUE;
131 }
132 
133 static void JNICALL
134 agentProc(jvmtiEnv *jvmti, JNIEnv *agentJNI, void *arg) {
135 
136   /* wait for initial sync */
137   if (!agent_wait_for_sync(timeout))
138     return;
139 
140   if (!prepare()) {
141     set_agent_fail_status();
142     return;
143   }
144 
145   /* clear events count */
146   eventsCount = 0;
147 
148   /* resume debugee to catch MonitorWaited event */
149   if (!((agent_resume_sync() == JNI_TRUE) && (agent_wait_for_sync(timeout) == JNI_TRUE))) {
150     return;
151   }
152 
153   LOG("Number of MonitorWaited events: %d\n", eventsCount);
154 
155   if (eventsCount == 0) {
156     COMPLAIN("No any MonitorWaited event\n");
157     set_agent_fail_status();
158   }
159 
160   if (!clean()) {
161     set_agent_fail_status();
162     return;
163   }
164 
165   /* resume debugee after last sync */
166   if (!agent_resume_sync())
167     return;
168 }
169 
170 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
171   jvmtiCapabilities caps;
172   jvmtiEventCallbacks callbacks;
173   jvmtiError err;
174   jint res;
175 
176   timeout = 60000;
177   LOG("Timeout: %d msc\n", (int) timeout);
178 
179   res = jvm->GetEnv((void **) &jvmti, JVMTI_VERSION_1_1);
180   if (res != JNI_OK || jvmti == nullptr) {
181     LOG("Wrong result of a valid call to GetEnv!\n");
182     return JNI_ERR;
183   }
184 
185   err = init_agent_data(jvmti, &agent_data);
186   if (err != JVMTI_ERROR_NONE) {
187     return JNI_ERR;
188   }
189 
190   memset(&caps, 0, sizeof(jvmtiCapabilities));
191   caps.can_generate_monitor_events = 1;
192   caps.can_support_virtual_threads = 1;
193 
194   err = jvmti->AddCapabilities(&caps);
195   if (err != JVMTI_ERROR_NONE) {
196     LOG("(AddCapabilities) unexpected error: %s (%d)\n",
197            TranslateError(err), err);
198     return JNI_ERR;
199   }
200 
201   err = jvmti->GetCapabilities(&caps);
202   if (err != JVMTI_ERROR_NONE) {
203     LOG("(GetCapabilities) unexpected error: %s (%d)\n",
204            TranslateError(err), err);
205     return JNI_ERR;
206   }
207 
208   if (!caps.can_generate_monitor_events) {
209     return JNI_ERR;
210   }
211 
212   memset(&callbacks, 0, sizeof(callbacks));
213   callbacks.MonitorWaited = &MonitorWaited;
214   err = jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks));
215   if (err != JVMTI_ERROR_NONE) {
216     return JNI_ERR;
217   }
218 
219   /* register agent proc and arg */
220   set_agent_proc(agentProc, nullptr);
221 
222   return JNI_OK;
223 }
224 
225 JNIEXPORT void JNICALL Java_monitorwaited01_setExpected(JNIEnv *jni, jobject clz, jobject obj, jobject thread) {
226   LOG("Remembering global reference for monitor object is %p\n", obj);
227   /* make object accessible for a long time */
228   expected_object = jni->NewGlobalRef(obj);
229   if (expected_object == nullptr) {
230     jni->FatalError("Error saving global reference to monitor.\n");
231   }
232 
233   /* make thread accessable for a long time */
234   expected_thread = jni->NewGlobalRef(thread);
235   if (thread == nullptr) {
236     jni->FatalError("Error saving global reference to thread.\n");
237   }
238 
239   return;
240 }
241 
242 JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {
243   return Agent_Initialize(jvm, options, reserved);
244 }
245 
246 JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) {
247   return Agent_Initialize(jvm, options, reserved);
248 }
249 
250 }