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 <string.h>
25 #include "jvmti.h"
26 #include "agent_common.h"
27 #include "jni_tools.h"
28 #include "jvmti_tools.h"
29
30 extern "C" {
31
32 /* ============================================================================= */
33
34 /* scaffold objects */
35 static JNIEnv* jni = NULL;
36 static jvmtiEnv *jvmti = NULL;
37 static jlong timeout = 0;
38
39 /* constants */
40 #define THREADS_COUNT 6
41 #define EVENTS_COUNT 2
42 #define MAX_NAME_LENGTH 100
43 #define MAX_STACK_SIZE 100
44
45 /* tested events */
46 static jvmtiEvent eventsList[EVENTS_COUNT] = {
47 JVMTI_EVENT_COMPILED_METHOD_LOAD,
48 JVMTI_EVENT_COMPILED_METHOD_UNLOAD
49 };
50
51 /* thread description structure */
52 typedef struct {
53 char threadName[MAX_NAME_LENGTH];
54 char methodName[MAX_NAME_LENGTH];
55 char methodSig[MAX_NAME_LENGTH];
56 jthread thread;
57 jclass cls;
58 jmethodID method;
59 jlocation location;
60 int methodCompiled;
61 } ThreadDesc;
62
63 /* descriptions of tested threads */
64 static ThreadDesc threadsDesc[THREADS_COUNT] = {
65 { "threadRunning", "testedMethod", "(ZI)V", NULL, NULL, NULL, NSK_JVMTI_INVALID_JLOCATION, NSK_FALSE },
66 { "threadEntering", "testedMethod", "(ZI)V", NULL, NULL, NULL, NSK_JVMTI_INVALID_JLOCATION, NSK_FALSE },
67 { "threadWaiting", "testedMethod", "(ZI)V", NULL, NULL, NULL, NSK_JVMTI_INVALID_JLOCATION, NSK_FALSE },
68 { "threadSleeping", "testedMethod", "(ZI)V", NULL, NULL, NULL, NSK_JVMTI_INVALID_JLOCATION, NSK_FALSE },
69 { "threadRunningInterrupted", "testedMethod", "(ZI)V", NULL, NULL, NULL, NSK_JVMTI_INVALID_JLOCATION, NSK_FALSE },
70 { "threadRunningNative", "testedMethod", "(ZI)V", NULL, NULL, NULL, NSK_JVMTI_INVALID_JLOCATION, NSK_FALSE }
71 };
72
73 /* indexes of known threads */
74 static const int interruptedThreadIndex = THREADS_COUNT - 2;
75 static const int nativeThreadIndex = THREADS_COUNT - 1;
76
77 /* ============================================================================= */
78
79 /* testcase(s) */
80 static int prepare();
81 static int generateEvents();
82 static int checkThreads(int suspended, const char* kind);
83 static int suspendThreadsIndividually(int suspend);
84 static int clean();
85
86 /* ============================================================================= */
87
88 /** Agent algorithm. */
89 static void JNICALL
agentProc(jvmtiEnv * jvmti,JNIEnv * agentJNI,void * arg)90 agentProc(jvmtiEnv* jvmti, JNIEnv* agentJNI, void* arg) {
91 jni = agentJNI;
92
93 NSK_DISPLAY0("Wait for debuggee to become ready\n");
94 if (!nsk_jvmti_waitForSync(timeout))
95 return;
96
97 {
98 NSK_DISPLAY0("Prepare data\n");
99 if (!prepare()) {
100 nsk_jvmti_setFailStatus();
101 return;
102 }
103
104 NSK_DISPLAY0("Generate missed events\n");
105 if (!generateEvents())
106 return;
107
108 NSK_DISPLAY0("Testcase #1: check stack frames of not suspended threads\n");
109 if (!checkThreads(NSK_FALSE, "not suspended"))
110 return;
111
112 NSK_DISPLAY0("Suspend each thread\n");
113 if (!suspendThreadsIndividually(NSK_TRUE))
114 return;
115
116 NSK_DISPLAY0("Testcase #2: check stack frames of suspended threads\n");
117 if (!checkThreads(NSK_TRUE, "suspended"))
118 return;
119
120 NSK_DISPLAY0("Resume each thread\n");
121 if (!suspendThreadsIndividually(NSK_FALSE))
122 return;
123
124 NSK_DISPLAY0("Testcase #3: check stack frames of resumed threads\n");
125 if (!checkThreads(NSK_FALSE, "resumed"))
126 return;
127
128 NSK_DISPLAY0("Clean data\n");
129 if (!clean()) {
130 nsk_jvmti_setFailStatus();
131 return;
132 }
133 }
134
135 NSK_DISPLAY0("Let debuggee to finish\n");
136 if (!nsk_jvmti_resumeSync())
137 return;
138 }
139
140 /* ============================================================================= */
141
142 /**
143 * Generate missed events (COMPILED_METHOD_LOAD only).
144 */
generateEvents()145 static int generateEvents() {
146 if (!NSK_JVMTI_VERIFY(jvmti->GenerateEvents(JVMTI_EVENT_COMPILED_METHOD_LOAD))) {
147 nsk_jvmti_setFailStatus();
148 return NSK_FALSE;
149 }
150 return NSK_TRUE;
151 }
152
153 /**
154 * Prepare data.
155 * - clean threads list
156 * - get all live threads
157 * - get threads name
158 * - find tested threads
159 * - make global refs
160 * - enable events
161 */
prepare()162 static int prepare() {
163 jthread *allThreadsList = NULL;
164 jint allThreadsCount = 0;
165 int found = 0;
166 int i;
167
168 NSK_DISPLAY1("Find tested threads: %d\n", THREADS_COUNT);
169
170 /* clean threads list */
171 for (i = 0; i < THREADS_COUNT; i++) {
172 threadsDesc[i].thread = (jthread)NULL;
173 threadsDesc[i].method = (jmethodID)NULL;
174 threadsDesc[i].location = NSK_JVMTI_INVALID_JLOCATION;
175 threadsDesc[i].methodCompiled = NSK_FALSE;
176 }
177
178 /* get all live threads */
179 if (!NSK_JVMTI_VERIFY(jvmti->GetAllThreads(&allThreadsCount, &allThreadsList)))
180 return NSK_FALSE;
181
182 if (!NSK_VERIFY(allThreadsCount > 0 && allThreadsList != NULL))
183 return NSK_FALSE;
184
185 /* find tested threads */
186 for (i = 0; i < allThreadsCount; i++) {
187 jvmtiThreadInfo threadInfo;
188
189 if (!NSK_VERIFY(allThreadsList[i] != NULL))
190 return NSK_FALSE;
191
192 if (!NSK_JVMTI_VERIFY(jvmti->GetThreadInfo(allThreadsList[i], &threadInfo)))
193 return NSK_FALSE;
194
195 if (threadInfo.name != NULL) {
196 int j;
197
198 for (j = 0; j < THREADS_COUNT; j++) {
199 if (strcmp(threadInfo.name, threadsDesc[j].threadName) == 0) {
200 threadsDesc[j].thread = allThreadsList[i];
201 NSK_DISPLAY3(" thread #%d (%s): 0x%p\n",
202 j, threadInfo.name, (void*)threadsDesc[j].thread);
203 }
204 }
205 }
206 }
207
208 /* deallocate all threads list */
209 if (!NSK_JVMTI_VERIFY(jvmti->Deallocate((unsigned char*)allThreadsList)))
210 return NSK_FALSE;
211
212 /* check if all tested threads found */
213 found = 0;
214 for (i = 0; i < THREADS_COUNT; i++) {
215 if (threadsDesc[i].thread == NULL) {
216 NSK_COMPLAIN2("Not found tested thread #%d (%s)\n", i, threadsDesc[i].threadName);
217 } else {
218 found++;
219 }
220 }
221
222 if (found < THREADS_COUNT)
223 return NSK_FALSE;
224
225 /* get threads class and frame method */
226 NSK_DISPLAY0("Find tested methods:\n");
227 for (i = 0; i < THREADS_COUNT; i++) {
228
229 if (!NSK_JNI_VERIFY(jni, (threadsDesc[i].cls =
230 jni->GetObjectClass(threadsDesc[i].thread)) != NULL))
231 return NSK_FALSE;
232
233 if (!NSK_JNI_VERIFY(jni, (threadsDesc[i].method =
234 jni->GetMethodID(threadsDesc[i].cls, threadsDesc[i].methodName, threadsDesc[i].methodSig)) != NULL))
235 return NSK_FALSE;
236
237 NSK_DISPLAY4(" thread #%d (%s): 0x%p (%s)\n",
238 i, threadsDesc[i].threadName,
239 (void*)threadsDesc[i].method,
240 threadsDesc[i].methodName);
241 }
242
243 /* make global refs */
244 for (i = 0; i < THREADS_COUNT; i++) {
245 if (!NSK_JNI_VERIFY(jni, (threadsDesc[i].thread = (jthread)
246 jni->NewGlobalRef(threadsDesc[i].thread)) != NULL))
247 return NSK_FALSE;
248 if (!NSK_JNI_VERIFY(jni, (threadsDesc[i].cls = (jclass)
249 jni->NewGlobalRef(threadsDesc[i].cls)) != NULL))
250 return NSK_FALSE;
251 }
252
253 NSK_DISPLAY0("Enable tested events\n");
254 if (!nsk_jvmti_enableEvents(JVMTI_ENABLE, EVENTS_COUNT, eventsList, NULL))
255 return NSK_FALSE;
256
257 return NSK_TRUE;
258 }
259
260 /**
261 * Suspend or resume tested threads.
262 */
suspendThreadsIndividually(int suspend)263 static int suspendThreadsIndividually(int suspend) {
264 int i;
265
266 for (i = 0; i < THREADS_COUNT; i++) {
267 if (suspend) {
268 NSK_DISPLAY2(" suspend thread #%d (%s)\n", i, threadsDesc[i].threadName);
269 if (!NSK_JVMTI_VERIFY(jvmti->SuspendThread(threadsDesc[i].thread)))
270 nsk_jvmti_setFailStatus();
271 } else {
272 NSK_DISPLAY2(" resume thread #%d (%s)\n", i, threadsDesc[i].threadName);
273 if (!NSK_JVMTI_VERIFY(jvmti->ResumeThread(threadsDesc[i].thread)))
274 nsk_jvmti_setFailStatus();
275 }
276 }
277 return NSK_TRUE;
278 }
279
280 /**
281 * Testcase: check tested threads.
282 * - call GetFrameCount() and getStackTrace()
283 * - for suspended thread compare number of stack frames returned
284 * - find stack frames with expected methodID
285 *
286 * Returns NSK_TRUE if test may continue; or NSK_FALSE for test break.
287 */
checkThreads(int suspended,const char * kind0)288 static int checkThreads(int suspended, const char* kind0) {
289 char kind[256] = "";
290 int i;
291
292 /* check each thread */
293 for (i = 0; i < THREADS_COUNT; i++) {
294 jint frameCount = 0;
295 jint frameStackSize = 0;
296 jvmtiFrameInfo frameStack[MAX_STACK_SIZE];
297 int found = 0;
298 int j;
299
300 /* make proper kind */
301 strcpy(kind, threadsDesc[i].methodCompiled ? "compiled " : "not compiled ");
302 strcat(kind, kind0);
303 NSK_DISPLAY2(" thread #%d (%s):\n", i, threadsDesc[i].threadName);
304
305 /* get frame count */
306 if (!NSK_JVMTI_VERIFY(jvmti->GetFrameCount(threadsDesc[i].thread, &frameCount))) {
307 nsk_jvmti_setFailStatus();
308 return NSK_TRUE;
309 }
310
311 NSK_DISPLAY1(" frameCount: %d\n", (int)frameCount);
312
313 /* get stack trace */
314 if (!NSK_JVMTI_VERIFY(
315 jvmti->GetStackTrace(threadsDesc[i].thread, 0, MAX_STACK_SIZE, frameStack, &frameStackSize))) {
316 nsk_jvmti_setFailStatus();
317 return NSK_TRUE;
318 }
319
320 NSK_DISPLAY1(" stack depth: %d\n", (int)frameStackSize);
321
322 /* Only check for suspended threads: running threads might have different
323 frames between stack grabbing calls. */
324 if (suspended && (frameStackSize != frameCount)) {
325 NSK_COMPLAIN5("Different frames count for %s thread #%d (%s):\n"
326 "# getStackTrace(): %d\n"
327 "# getFrameCount(): %d\n",
328 kind, i, threadsDesc[i].threadName,
329 (int)frameStackSize, (int)frameCount);
330 nsk_jvmti_setFailStatus();
331 }
332
333 /* find method on the stack */
334 found = 0;
335 for (j = 0; j < frameStackSize; j++) {
336 NSK_DISPLAY3(" %d: methodID: 0x%p, location: %ld\n",
337 j, (void*)frameStack[j].method,
338 (long)frameStack[j].location);
339 /* check frame method */
340 if (frameStack[j].method == NULL) {
341 NSK_COMPLAIN3("NULL methodID in stack for %s thread #%d (%s)\n",
342 kind, i, threadsDesc[i].threadName);
343 nsk_jvmti_setFailStatus();
344 } else if (frameStack[j].method == threadsDesc[i].method) {
345 found++;
346 NSK_DISPLAY1(" found expected method: %s\n",
347 (void*)threadsDesc[i].methodName);
348 }
349 }
350
351 /* check if expected method found */
352 if (found != 1) {
353 NSK_COMPLAIN5("Unexpected method frames on stack for %s thread #%d (%s):\n"
354 "# found frames: %d\n"
355 "# expected: %d\n",
356 kind, i, threadsDesc[i].threadName,
357 found, 1);
358 nsk_jvmti_setFailStatus();
359 }
360 }
361
362 /* test may continue */
363 return NSK_TRUE;
364 }
365
366 /**
367 * Clean data.
368 * - disable events
369 * - dispose global references to tested threads
370 */
clean()371 static int clean() {
372 int i;
373
374 NSK_DISPLAY0("Disable events\n");
375 if (!nsk_jvmti_enableEvents(JVMTI_DISABLE, EVENTS_COUNT, eventsList, NULL))
376 return NSK_FALSE;
377
378 NSK_DISPLAY0("Dispose global references to threads\n");
379 for (i = 0; i < THREADS_COUNT; i++) {
380 NSK_TRACE(jni->DeleteGlobalRef(threadsDesc[i].thread));
381 NSK_TRACE(jni->DeleteGlobalRef(threadsDesc[i].cls));
382 }
383
384 return NSK_TRUE;
385 }
386
387 /* ============================================================================= */
388
389 /**
390 * COMPILED_METHOD_LOAD callback.
391 * - turn on flag that method is compiled
392 */
393 JNIEXPORT void JNICALL
callbackCompiledMethodLoad(jvmtiEnv * jvmti,jmethodID method,jint code_size,const void * code_addr,jint map_length,const jvmtiAddrLocationMap * map,const void * compile_info)394 callbackCompiledMethodLoad(jvmtiEnv* jvmti, jmethodID method,
395 jint code_size, const void* code_addr,
396 jint map_length, const jvmtiAddrLocationMap* map,
397 const void* compile_info) {
398 int i;
399
400 /* check if event is for tested method and turn flag on */
401 for (i = 0; i < THREADS_COUNT; i++) {
402 if (threadsDesc[i].method == method) {
403 threadsDesc[i].methodCompiled = NSK_TRUE;
404
405 NSK_DISPLAY2(" COMPILED_METHOD_LOAD for method #%d (%s):\n",
406 i, threadsDesc[i].methodName);
407 NSK_DISPLAY1(" methodID: 0x%p\n",
408 (void*)threadsDesc[i].method);
409 NSK_DISPLAY1(" code_size: %d\n",
410 (int)code_size);
411 NSK_DISPLAY1(" map_length: %d\n",
412 (int)map_length);
413 break;
414 }
415 }
416 }
417
418 /**
419 * COMPILED_METHOD_UNLOAD callback.
420 * - turn off flag that method is compiled
421 */
422 JNIEXPORT void JNICALL
callbackCompiledMethodUnload(jvmtiEnv * jvmti,jmethodID method,const void * code_addr)423 callbackCompiledMethodUnload(jvmtiEnv* jvmti, jmethodID method,
424 const void* code_addr) {
425 int i;
426
427 /* check if event is for tested method and turn flag off */
428 for (i = 0; i < THREADS_COUNT; i++) {
429 if (threadsDesc[i].method == method) {
430 threadsDesc[i].methodCompiled = NSK_FALSE;
431
432 NSK_DISPLAY2(" COMPILED_METHOD_UNLOAD for method #%d (%s):\n",
433 i, threadsDesc[i].methodName);
434 NSK_DISPLAY1(" methodID: 0x%p\n",
435 (void*)threadsDesc[i].method);
436 break;
437 }
438 }
439 }
440
441 /* ============================================================================= */
442
443 volatile int testedThreadReady = NSK_FALSE;
444 volatile int testedThreadShouldFinish = NSK_FALSE;
445
446 /** Native running method in tested thread. */
447 JNIEXPORT void JNICALL
Java_nsk_jvmti_scenarios_sampling_SP06_sp06t002ThreadRunningNative_testedMethod(JNIEnv * jni,jobject obj,jboolean simulate,jint i)448 Java_nsk_jvmti_scenarios_sampling_SP06_sp06t002ThreadRunningNative_testedMethod(JNIEnv* jni,
449 jobject obj,
450 jboolean simulate,
451 jint i) {
452 if (!simulate) {
453 volatile int k = 0, n = 1000;
454
455 /* run in a continous loop */
456 testedThreadReady = NSK_TRUE;
457 while (!testedThreadShouldFinish) {
458 if (n <= 0)
459 n = 1000;
460 if (k >= n)
461 k = 0;
462 k++;
463 }
464 }
465 }
466
467 /* Wait for native method is running. */
468 JNIEXPORT jboolean JNICALL
Java_nsk_jvmti_scenarios_sampling_SP06_sp06t002ThreadRunningNative_checkReady(JNIEnv * jni,jobject obj)469 Java_nsk_jvmti_scenarios_sampling_SP06_sp06t002ThreadRunningNative_checkReady(JNIEnv* jni,
470 jobject obj) {
471 while (!testedThreadReady) {
472 nsk_jvmti_sleep(1000);
473 }
474 return testedThreadReady ? JNI_TRUE : JNI_FALSE;
475 }
476
477 /** Let native method to finish. */
478 JNIEXPORT void JNICALL
Java_nsk_jvmti_scenarios_sampling_SP06_sp06t002ThreadRunningNative_letFinish(JNIEnv * jni,jobject obj)479 Java_nsk_jvmti_scenarios_sampling_SP06_sp06t002ThreadRunningNative_letFinish(JNIEnv* jni,
480 jobject obj) {
481 testedThreadShouldFinish = NSK_TRUE;
482 }
483
484 /* ============================================================================= */
485
486 /** Agent library initialization. */
487 #ifdef STATIC_BUILD
Agent_OnLoad_sp06t002(JavaVM * jvm,char * options,void * reserved)488 JNIEXPORT jint JNICALL Agent_OnLoad_sp06t002(JavaVM *jvm, char *options, void *reserved) {
489 return Agent_Initialize(jvm, options, reserved);
490 }
Agent_OnAttach_sp06t002(JavaVM * jvm,char * options,void * reserved)491 JNIEXPORT jint JNICALL Agent_OnAttach_sp06t002(JavaVM *jvm, char *options, void *reserved) {
492 return Agent_Initialize(jvm, options, reserved);
493 }
JNI_OnLoad_sp06t002(JavaVM * jvm,char * options,void * reserved)494 JNIEXPORT jint JNI_OnLoad_sp06t002(JavaVM *jvm, char *options, void *reserved) {
495 return JNI_VERSION_1_8;
496 }
497 #endif
Agent_Initialize(JavaVM * jvm,char * options,void * reserved)498 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
499
500 if (!NSK_VERIFY(nsk_jvmti_parseOptions(options)))
501 return JNI_ERR;
502
503 timeout = nsk_jvmti_getWaitTime() * 60 * 1000;
504
505 if (!NSK_VERIFY((jvmti =
506 nsk_jvmti_createJVMTIEnv(jvm, reserved)) != NULL))
507 return JNI_ERR;
508
509 {
510 jvmtiCapabilities caps;
511 memset(&caps, 0, sizeof(caps));
512 caps.can_suspend = 1;
513 caps.can_generate_compiled_method_load_events = 1;
514 if (!NSK_JVMTI_VERIFY(jvmti->AddCapabilities(&caps)))
515 return JNI_ERR;
516 }
517
518 {
519 jvmtiEventCallbacks eventCallbacks;
520 memset(&eventCallbacks, 0, sizeof(eventCallbacks));
521 eventCallbacks.CompiledMethodLoad = callbackCompiledMethodLoad;
522 eventCallbacks.CompiledMethodUnload = callbackCompiledMethodUnload;
523 if (!NSK_JVMTI_VERIFY(jvmti->SetEventCallbacks(&eventCallbacks, sizeof(eventCallbacks))))
524 return JNI_ERR;
525 }
526
527 if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agentProc, NULL)))
528 return JNI_ERR;
529
530 return JNI_OK;
531 }
532
533 /* ============================================================================= */
534
535 }
536