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 #include "JVMTITools.h"
29
30 extern "C" {
31
32
33 #define PASSED 0
34 #define STATUS_FAILED 2
35
36 static jvmtiEnv *jvmti = NULL;
37 static jvmtiCapabilities caps;
38 static jvmtiEventCallbacks callbacks;
39 static jint result = PASSED;
40 static jmethodID mid1, mid2;
41
42 static jthread currThread = NULL, popThread = NULL;
43 static jclass currClass = NULL, popClass = NULL;
44 static jmethodID currMethod = NULL, popMethod = NULL;
45 static jboolean currFlag = JNI_FALSE, popFlag = JNI_FALSE;
46 static jint currLoc = 0, popLoc = 0;
47
48 void JNICALL
FramePop(jvmtiEnv * jvmti_env,JNIEnv * env,jthread thread,jmethodID method,jboolean wasPopedByException)49 FramePop(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thread,
50 jmethodID method, jboolean wasPopedByException) {
51 jvmtiError err;
52
53 popThread = env->NewGlobalRef(thread);
54
55 err = jvmti_env->GetMethodDeclaringClass(method, &popClass);
56 if (err != JVMTI_ERROR_NONE) {
57 printf("(GetMethodDeclaringClass) unexpected error: %s (%d)\n",
58 TranslateError(err), err);
59 result = STATUS_FAILED;
60 }
61 popClass = (jclass) env->NewGlobalRef(popClass);
62
63 popMethod = method;
64 popFlag = wasPopedByException;
65
66 err = jvmti_env->GetLocalInt(thread, 0, 1, &popLoc);
67 if (err == JVMTI_ERROR_MUST_POSSESS_CAPABILITY &&
68 !caps.can_access_local_variables) {
69 /* It is OK */
70 } else if (err != JVMTI_ERROR_NONE) {
71 printf("(GetLocalInt#pop) unexpected error: %s (%d)\n",
72 TranslateError(err), err);
73 result = STATUS_FAILED;
74 }
75 }
76
77 void JNICALL
ExceptionCatch(jvmtiEnv * jvmti_env,JNIEnv * env,jthread thread,jmethodID method,jlocation location,jobject exception)78 ExceptionCatch(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thread,
79 jmethodID method, jlocation location, jobject exception) {
80 jvmtiError err;
81
82 if (method == mid1 || method == mid2) {
83 currThread = env->NewGlobalRef(thread);
84
85 err = jvmti_env->GetMethodDeclaringClass(
86 method, &currClass);
87 if (err != JVMTI_ERROR_NONE) {
88 printf("(GetMethodDeclaringClass) unexpected error: %s (%d)\n",
89 TranslateError(err), err);
90 result = STATUS_FAILED;
91 }
92 currClass = (jclass) env->NewGlobalRef(currClass);
93
94 currMethod = method;
95
96 err = jvmti_env->GetLocalInt(thread, 0, 1, &currLoc);
97 if (err == JVMTI_ERROR_MUST_POSSESS_CAPABILITY &&
98 !caps.can_access_local_variables) {
99 /* It is OK */
100 } else if (err != JVMTI_ERROR_NONE) {
101 printf("(GetLocalInt#catch) unexpected error: %s (%d)\n",
102 TranslateError(err), err);
103 result = STATUS_FAILED;
104 }
105 if (method == mid2) {
106 currFlag = JNI_TRUE;
107 }
108
109 err = jvmti_env->NotifyFramePop(thread, 0);
110 if (err != JVMTI_ERROR_NONE) {
111 printf("(NotifyFramePop#catch) unexpected error: %s (%d)\n",
112 TranslateError(err), err);
113 result = STATUS_FAILED;
114 }
115 }
116 }
117
118 #ifdef STATIC_BUILD
Agent_OnLoad_nframepop001(JavaVM * jvm,char * options,void * reserved)119 JNIEXPORT jint JNICALL Agent_OnLoad_nframepop001(JavaVM *jvm, char *options, void *reserved) {
120 return Agent_Initialize(jvm, options, reserved);
121 }
Agent_OnAttach_nframepop001(JavaVM * jvm,char * options,void * reserved)122 JNIEXPORT jint JNICALL Agent_OnAttach_nframepop001(JavaVM *jvm, char *options, void *reserved) {
123 return Agent_Initialize(jvm, options, reserved);
124 }
JNI_OnLoad_nframepop001(JavaVM * jvm,char * options,void * reserved)125 JNIEXPORT jint JNI_OnLoad_nframepop001(JavaVM *jvm, char *options, void *reserved) {
126 return JNI_VERSION_1_8;
127 }
128 #endif
Agent_Initialize(JavaVM * jvm,char * options,void * reserved)129 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
130 jint res;
131 jvmtiError err;
132
133 res = jvm->GetEnv((void **) &jvmti, JVMTI_VERSION_1_1);
134 if (res != JNI_OK || jvmti == NULL) {
135 printf("Wrong result of a valid call to GetEnv!\n");
136 return JNI_ERR;
137 }
138
139 err = jvmti->GetPotentialCapabilities(&caps);
140 if (err != JVMTI_ERROR_NONE) {
141 printf("(GetPotentialCapabilities) unexpected error: %s (%d)\n",
142 TranslateError(err), err);
143 return JNI_ERR;
144 }
145
146 err = jvmti->AddCapabilities(&caps);
147 if (err != JVMTI_ERROR_NONE) {
148 printf("(AddCapabilities) unexpected error: %s (%d)\n",
149 TranslateError(err), err);
150 return JNI_ERR;
151 }
152
153 err = jvmti->GetCapabilities(&caps);
154 if (err != JVMTI_ERROR_NONE) {
155 printf("(GetCapabilities) unexpected error: %s (%d)\n",
156 TranslateError(err), err);
157 return JNI_ERR;
158 }
159
160 if (caps.can_generate_frame_pop_events &&
161 caps.can_generate_exception_events) {
162 callbacks.ExceptionCatch = &ExceptionCatch;
163 callbacks.FramePop = &FramePop;
164 err = jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks));
165 if (err != JVMTI_ERROR_NONE) {
166 printf("(SetEventCallbacks) unexpected error: %s (%d)\n",
167 TranslateError(err), err);
168 return JNI_ERR;
169 }
170 } else {
171 printf("Warning: FramePop or ExceptionCatch event is not implemented\n");
172 }
173
174 if (!caps.can_access_local_variables) {
175 printf("Warning: GetLocalInt is not implemented\n");
176 }
177
178 if (!caps.can_suspend) {
179 printf("Warning: suspend/resume is not implemented\n");
180 }
181
182 return JNI_OK;
183 }
184
185 JNIEXPORT void JNICALL
Java_nsk_jvmti_NotifyFramePop_nframepop001_getMethIds(JNIEnv * env,jclass cl)186 Java_nsk_jvmti_NotifyFramePop_nframepop001_getMethIds(JNIEnv *env, jclass cl) {
187 jvmtiError err;
188
189 if (caps.can_generate_frame_pop_events) {
190 err = jvmti->SetEventNotificationMode(JVMTI_ENABLE,
191 JVMTI_EVENT_FRAME_POP, NULL);
192 if (err != JVMTI_ERROR_NONE) {
193 printf("Failed to enable FRAME_POP event: %s (%d)\n",
194 TranslateError(err), err);
195 result = STATUS_FAILED;
196 return;
197 }
198 }
199
200 mid1 = env->GetMethodID(cl, "meth01", "(I)V");
201 if (mid1 == NULL) {
202 printf("Cannot find method \"meth01\"\n");
203 result = STATUS_FAILED;
204 return;
205 }
206
207 mid2 = env->GetMethodID(cl, "meth02", "(I)V");
208 if (mid2 == NULL) {
209 printf("Cannot find method \"meth02\"\n");
210 result = STATUS_FAILED;
211 return;
212 }
213
214 if (caps.can_generate_exception_events) {
215 err = jvmti->SetEventNotificationMode(JVMTI_ENABLE,
216 JVMTI_EVENT_EXCEPTION_CATCH, NULL);
217 if (err != JVMTI_ERROR_NONE) {
218 printf("Failed to enable EXCEPTION_CATCH event: %s (%d)\n",
219 TranslateError(err), err);
220 result = STATUS_FAILED;
221 return;
222 }
223 }
224 }
225
226 JNIEXPORT void JNICALL
Java_nsk_jvmti_NotifyFramePop_nframepop001_setFramePopNotif(JNIEnv * env,jclass cl,jthread thr)227 Java_nsk_jvmti_NotifyFramePop_nframepop001_setFramePopNotif(JNIEnv *env,
228 jclass cl, jthread thr) {
229 jvmtiError err;
230
231 if (!caps.can_generate_frame_pop_events || !caps.can_suspend) {
232 return;
233 }
234
235 err = jvmti->SuspendThread(thr);
236 if (err != JVMTI_ERROR_NONE) {
237 printf("(SuspendThread) unexpected error: %s (%d)\n",
238 TranslateError(err), err);
239 result = STATUS_FAILED;
240 }
241
242 currThread = env->NewGlobalRef(thr);
243
244 currClass = env->FindClass("nsk/jvmti/NotifyFramePop/nframepop001a");
245 if (currClass == NULL) {
246 printf("Cannot find nsk.jvmti.NotifyFramePop.nframepop001a class!\n");
247 result = STATUS_FAILED;
248 return;
249 }
250 currClass = (jclass) env->NewGlobalRef(currClass);
251
252 currMethod = env->GetMethodID(currClass, "run", "()V");
253 if (currMethod == NULL) {
254 printf("Cannot find method \"run\"\n");
255 result = STATUS_FAILED;
256 }
257
258 err = jvmti->GetLocalInt(thr, 0, 1, &currLoc);
259 if (err == JVMTI_ERROR_MUST_POSSESS_CAPABILITY &&
260 !caps.can_access_local_variables) {
261 /* It is OK */
262 } else if (err != JVMTI_ERROR_NONE) {
263 printf("(GetLocalInt) unexpected error: %s (%d)\n",
264 TranslateError(err), err);
265 result = STATUS_FAILED;
266 }
267
268 err = jvmti->NotifyFramePop(thr, 0);
269 if (err != JVMTI_ERROR_NONE) {
270 printf("(NotifyFramePop) unexpected error: %s (%d)\n",
271 TranslateError(err), err);
272 result = STATUS_FAILED;
273 }
274
275 err = jvmti->ResumeThread(thr);
276 if (err != JVMTI_ERROR_NONE) {
277 printf("(ResumeThread) unexpected error: %s (%d)\n",
278 TranslateError(err), err);
279 result = STATUS_FAILED;
280 }
281 }
282
283 JNIEXPORT void JNICALL
Java_nsk_jvmti_NotifyFramePop_nframepop001_checkFrame(JNIEnv * env,jclass cls,jint point)284 Java_nsk_jvmti_NotifyFramePop_nframepop001_checkFrame(JNIEnv *env,
285 jclass cls, jint point) {
286
287 if (!caps.can_generate_frame_pop_events) {
288 return;
289 }
290
291 if (!env->IsSameObject(currThread, popThread)) {
292 printf("Point %d: thread is not the same as expected\n", point);
293 result = STATUS_FAILED;
294 }
295
296 if (!env->IsSameObject(currClass, popClass)) {
297 printf("Point %d: class is not the same as expected\n", point);
298 result = STATUS_FAILED;
299 }
300
301 if (currMethod != popMethod) {
302 printf("Point %d: method ID expected: 0x%p, actual: 0x%p\n",
303 point, currMethod, popMethod);
304 result = STATUS_FAILED;
305 }
306
307 if (currFlag != popFlag) {
308 printf("Point %d: was_poped_by_exception expected: %d, actual: %d\n",
309 point, currFlag, popFlag);
310 result = STATUS_FAILED;
311 }
312
313 if (currLoc != popLoc) {
314 printf("Point %d: local expected: %d, actual: %d\n",
315 point, currLoc, popLoc);
316 result = STATUS_FAILED;
317 }
318
319 currThread = NULL; popThread = NULL;
320 currClass = NULL; popClass = NULL;
321 currMethod = NULL; popMethod = NULL;
322 currFlag = JNI_FALSE; popFlag = JNI_FALSE;
323 currLoc = 0; popLoc = 0;
324 }
325
326 JNIEXPORT jint JNICALL
Java_nsk_jvmti_NotifyFramePop_nframepop001_getRes(JNIEnv * env,jclass cls)327 Java_nsk_jvmti_NotifyFramePop_nframepop001_getRes(JNIEnv *env, jclass cls) {
328 return result;
329 }
330
331 }
332