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 <stdlib.h>
26 #include "jvmti.h"
27 #include "agent_common.h"
28 #include <jvmti_tools.h>
29 #include "JVMTITools.h"
30 
31 extern "C" {
32 
33 // Deallocate memory region allocated by VM
34 #define DEALLOCATE(p) \
35     if (p != NULL)                 \
36         if (!NSK_JVMTI_VERIFY(jvmti->Deallocate(p)))        \
37         {                          \
38             NSK_COMPLAIN0("Failed to deallocate: ##p##\n"); \
39         }
40 
41 static jvmtiEnv *jvmti;
42 static jvmtiCapabilities caps;
43 static jvmtiEventCallbacks callbacks;
44 static int watch_jvmti_events = 0;        /* ignore JVMTI events by default */
45 static volatile int number_of_generated_events = 0;          /* number of generated events */
46 static jboolean result = JNI_TRUE; /* total result of the test */
47 
48 static jrawMonitorID watch_ev_monitor;
49 
set_watch_jvmti_events(int value)50 static void set_watch_jvmti_events(int value) {
51     jvmti->RawMonitorEnter(watch_ev_monitor);
52 
53     watch_jvmti_events = value;
54 
55     jvmti->RawMonitorExit(watch_ev_monitor);
56 }
57 
58 void JNICALL
FramePop(jvmtiEnv * jvmti_env,JNIEnv * env,jthread thread,jmethodID method,jboolean wasPopedByException)59 FramePop(
60         jvmtiEnv *jvmti_env
61         , JNIEnv *env
62         , jthread thread
63         , jmethodID method
64         , jboolean wasPopedByException
65         )
66 {
67     jvmti->RawMonitorEnter(watch_ev_monitor);
68 
69     if (watch_jvmti_events) {
70         NSK_COMPLAIN1("#### FramePop event occurred (%d) ####\n", method);
71         number_of_generated_events++;
72     }
73 
74     jvmti->RawMonitorExit(watch_ev_monitor);
75 }
76 
77 void JNICALL
MethodExit(jvmtiEnv * jvmti_env,JNIEnv * env,jthread thread,jmethodID method,jboolean was_poped_by_exc,jvalue return_value)78 MethodExit(
79         jvmtiEnv *jvmti_env
80         , JNIEnv *env
81         , jthread thread
82         , jmethodID method
83         , jboolean was_poped_by_exc
84         , jvalue return_value
85         )
86 {
87     jvmti->RawMonitorEnter(watch_ev_monitor);
88 
89     if (watch_jvmti_events) {
90         jvmtiThreadInfo thr_info;
91         char *class_signature;
92         char *entry_name;
93         char *entry_sig;
94         jclass klass;
95 
96         int failure = 1;
97 
98         do {
99             if (!NSK_JVMTI_VERIFY(jvmti->GetThreadInfo(thread, &thr_info)))
100             {
101                 break;
102             }
103 
104             if (!NSK_JVMTI_VERIFY(jvmti->GetMethodDeclaringClass(method, &klass)))
105             {
106                 break;
107             }
108 
109             if (!NSK_JVMTI_VERIFY(jvmti->GetClassSignature(klass, &class_signature, NULL)))
110             {
111                 break;
112             }
113 
114             if (!NSK_JVMTI_VERIFY(jvmti->GetMethodName(method, &entry_name, &entry_sig, NULL)))
115             {
116                 break;
117             }
118 
119             failure = 0;
120             NSK_COMPLAIN5("#### MethodExit event occurred: (tid: %d), thread: %s, %s %s %s\n"
121                     , thread
122                     , thr_info.name == NULL ? "<Unnamed>" : thr_info.name
123                     , class_signature
124                     , entry_name
125                     , entry_sig
126                     );
127         } while (0);
128 
129         if (failure) {
130             NSK_COMPLAIN1("#### MethodExit event occurred (tid: %d) ####\n"
131                     , thread
132                     );
133         }
134 
135         DEALLOCATE((unsigned char *)class_signature);
136         DEALLOCATE((unsigned char *)entry_name);
137         DEALLOCATE((unsigned char *)entry_sig);
138 
139         number_of_generated_events++;
140     }
141 
142     jvmti->RawMonitorExit(watch_ev_monitor);
143 }
144 
suspendThread(jobject suspendedThread)145 jboolean suspendThread(jobject suspendedThread) {
146     if (!caps.can_pop_frame || !caps.can_suspend) {
147         return JNI_TRUE;
148     }
149 
150     NSK_DISPLAY0(">>>>>>>> Invoke SuspendThread()\n");
151 
152     if (!NSK_JVMTI_VERIFY(jvmti->SuspendThread(suspendedThread)))
153     {
154         return JNI_FALSE;
155     }
156 
157     NSK_DISPLAY0("<<<<<<<< SuspendThread() is successfully done\n");
158 
159     return JNI_TRUE;
160 }
161 
resThread(jobject suspendedThread)162 jboolean resThread(jobject suspendedThread) {
163     if (!caps.can_pop_frame || !caps.can_suspend) {
164         return JNI_TRUE;
165     }
166 
167     NSK_DISPLAY0(">>>>>>>> Invoke ResumeThread()\n");
168 
169     if (!NSK_JVMTI_VERIFY(jvmti->ResumeThread(suspendedThread)))
170     {
171         return JNI_FALSE;
172     }
173 
174     NSK_DISPLAY0("<<<<<<<< ResumeThread() is successfully done\n");
175 
176     return JNI_TRUE;
177 }
178 
179 JNIEXPORT jboolean JNICALL
Java_nsk_jvmti_PopFrame_popframe005_doPopFrame(JNIEnv * env,jclass klass,jobject frameThr)180 Java_nsk_jvmti_PopFrame_popframe005_doPopFrame(
181     JNIEnv *env
182     , jclass klass
183     , jobject frameThr
184     )
185 {
186     if (!caps.can_pop_frame || !caps.can_suspend) {
187         return JNI_TRUE;
188     }
189 
190     if (suspendThread(frameThr) != JNI_TRUE) {
191         return JNI_FALSE;
192     }
193 
194     if (!NSK_JVMTI_VERIFY(
195             jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_METHOD_EXIT, frameThr)))
196     {
197         result = JNI_FALSE;
198     }
199 
200     if (!NSK_JVMTI_VERIFY(
201             jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_FRAME_POP, frameThr)))
202     {
203         result = JNI_FALSE;
204     }
205 
206     NSK_DISPLAY0(">>>>>>>> Invoke PopFrame()\n");
207 
208     set_watch_jvmti_events(1); /* watch JVMTI events */
209 
210     if (!NSK_JVMTI_VERIFY(jvmti->PopFrame(frameThr)))
211     {
212         result = JNI_FALSE;
213     } else {
214         NSK_DISPLAY0("Check #1 PASSED: PopFrame() is successfully done\n");
215     }
216 
217     set_watch_jvmti_events(0); /* ignore again JVMTI events */
218 
219     if (number_of_generated_events) {
220         NSK_COMPLAIN1("%d JVMTI events have been generated by the function PopFrame()\n"
221                 , number_of_generated_events
222                 );
223         result = JNI_FALSE;
224     } else {
225         NSK_DISPLAY0("Check #2 PASSED: No JVMTI events have been generated by the function PopFrame()\n");
226     }
227 
228     if (resThread(frameThr) != JNI_TRUE)
229         return JNI_FALSE;
230 
231     return result;
232 }
233 
234 #ifdef STATIC_BUILD
Agent_OnLoad_popframe005(JavaVM * jvm,char * options,void * reserved)235 JNIEXPORT jint JNICALL Agent_OnLoad_popframe005(JavaVM *jvm, char *options, void *reserved) {
236     return Agent_Initialize(jvm, options, reserved);
237 }
Agent_OnAttach_popframe005(JavaVM * jvm,char * options,void * reserved)238 JNIEXPORT jint JNICALL Agent_OnAttach_popframe005(JavaVM *jvm, char *options, void *reserved) {
239     return Agent_Initialize(jvm, options, reserved);
240 }
JNI_OnLoad_popframe005(JavaVM * jvm,char * options,void * reserved)241 JNIEXPORT jint JNI_OnLoad_popframe005(JavaVM *jvm, char *options, void *reserved) {
242     return JNI_VERSION_1_8;
243 }
244 #endif
Agent_Initialize(JavaVM * vm,char * options,void * reserved)245 jint Agent_Initialize(JavaVM *vm, char *options, void *reserved)
246 {
247     jvmtiError err;
248 
249     if (!NSK_VERIFY(
250             nsk_jvmti_parseOptions(options)
251             ))
252     {
253         return JNI_ERR;
254     }
255 
256     if (!NSK_VERIFY(
257             (jvmti = nsk_jvmti_createJVMTIEnv(vm, reserved)) != NULL
258             ))
259     {
260         return JNI_ERR;
261     }
262 
263     if (!NSK_JVMTI_VERIFY(jvmti->GetPotentialCapabilities(&caps)))
264     {
265         return JNI_ERR;
266     }
267 
268     if (!NSK_JVMTI_VERIFY(jvmti->AddCapabilities(&caps)))
269     {
270         return JNI_ERR;
271     }
272 
273     if (!NSK_JVMTI_VERIFY(jvmti->GetCapabilities(&caps)))
274     {
275         return JNI_ERR;
276     }
277 
278     if (!caps.can_pop_frame) {
279         NSK_COMPLAIN0("Warning: PopFrame is not implemented\n");
280         return JNI_OK;
281     }
282 
283     if (!caps.can_suspend) {
284         NSK_COMPLAIN0("Warning: suspend/resume is not implemented\n");
285         return JNI_OK;
286     }
287 
288     if (caps.can_generate_frame_pop_events
289         && caps.can_generate_method_exit_events)
290     {
291         callbacks.MethodExit = &MethodExit;
292         callbacks.FramePop = &FramePop;
293 
294         if (!NSK_JVMTI_VERIFY(jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks)
295                     )))
296         {
297             return JNI_ERR;
298         }
299     } else {
300         NSK_COMPLAIN0("Warning: FramePop or MethodExit event is not implemented\n");
301     }
302 
303     err = jvmti->CreateRawMonitor("watch_ev_monitor", &watch_ev_monitor);
304     if (err != JVMTI_ERROR_NONE) {
305         printf("(CreateRawMonitor) unexpected error: %s (%d)\n",
306                TranslateError(err), err);
307         return JNI_ERR;
308     }
309 
310     return JNI_OK;
311 }
312 
313 }
314