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 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 */ 145 static int generateEvents() { 146 if (!NSK_JVMTI_VERIFY( 147 NSK_CPP_STUB2(GenerateEvents, jvmti, JVMTI_EVENT_COMPILED_METHOD_LOAD))) { 148 nsk_jvmti_setFailStatus(); 149 return NSK_FALSE; 150 } 151 return NSK_TRUE; 152 } 153 154 /** 155 * Prepare data. 156 * - clean threads list 157 * - get all live threads 158 * - get threads name 159 * - find tested threads 160 * - make global refs 161 * - enable events 162 */ 163 static int prepare() { 164 jthread *allThreadsList = NULL; 165 jint allThreadsCount = 0; 166 int found = 0; 167 int i; 168 169 NSK_DISPLAY1("Find tested threads: %d\n", THREADS_COUNT); 170 171 /* clean threads list */ 172 for (i = 0; i < THREADS_COUNT; i++) { 173 threadsDesc[i].thread = (jthread)NULL; 174 threadsDesc[i].method = (jmethodID)NULL; 175 threadsDesc[i].location = NSK_JVMTI_INVALID_JLOCATION; 176 threadsDesc[i].methodCompiled = NSK_FALSE; 177 } 178 179 /* get all live threads */ 180 if (!NSK_JVMTI_VERIFY( 181 NSK_CPP_STUB3(GetAllThreads, jvmti, &allThreadsCount, &allThreadsList))) 182 return NSK_FALSE; 183 184 if (!NSK_VERIFY(allThreadsCount > 0 && allThreadsList != NULL)) 185 return NSK_FALSE; 186 187 /* find tested threads */ 188 for (i = 0; i < allThreadsCount; i++) { 189 jvmtiThreadInfo threadInfo; 190 191 if (!NSK_VERIFY(allThreadsList[i] != NULL)) 192 return NSK_FALSE; 193 194 if (!NSK_JVMTI_VERIFY( 195 NSK_CPP_STUB3(GetThreadInfo, jvmti, allThreadsList[i], &threadInfo))) 196 return NSK_FALSE; 197 198 if (threadInfo.name != NULL) { 199 int j; 200 201 for (j = 0; j < THREADS_COUNT; j++) { 202 if (strcmp(threadInfo.name, threadsDesc[j].threadName) == 0) { 203 threadsDesc[j].thread = allThreadsList[i]; 204 NSK_DISPLAY3(" thread #%d (%s): 0x%p\n", 205 j, threadInfo.name, (void*)threadsDesc[j].thread); 206 } 207 } 208 } 209 } 210 211 /* deallocate all threads list */ 212 if (!NSK_JVMTI_VERIFY( 213 NSK_CPP_STUB2(Deallocate, jvmti, (unsigned char*)allThreadsList))) 214 return NSK_FALSE; 215 216 /* check if all tested threads found */ 217 found = 0; 218 for (i = 0; i < THREADS_COUNT; i++) { 219 if (threadsDesc[i].thread == NULL) { 220 NSK_COMPLAIN2("Not found tested thread #%d (%s)\n", i, threadsDesc[i].threadName); 221 } else { 222 found++; 223 } 224 } 225 226 if (found < THREADS_COUNT) 227 return NSK_FALSE; 228 229 /* get threads class and frame method */ 230 NSK_DISPLAY0("Find tested methods:\n"); 231 for (i = 0; i < THREADS_COUNT; i++) { 232 233 if (!NSK_JNI_VERIFY(jni, (threadsDesc[i].cls = 234 NSK_CPP_STUB2(GetObjectClass, jni, threadsDesc[i].thread)) != NULL)) 235 return NSK_FALSE; 236 237 if (!NSK_JNI_VERIFY(jni, (threadsDesc[i].method = 238 NSK_CPP_STUB4(GetMethodID, jni, threadsDesc[i].cls, 239 threadsDesc[i].methodName, threadsDesc[i].methodSig)) != NULL)) 240 return NSK_FALSE; 241 242 NSK_DISPLAY4(" thread #%d (%s): 0x%p (%s)\n", 243 i, threadsDesc[i].threadName, 244 (void*)threadsDesc[i].method, 245 threadsDesc[i].methodName); 246 } 247 248 /* make global refs */ 249 for (i = 0; i < THREADS_COUNT; i++) { 250 if (!NSK_JNI_VERIFY(jni, (threadsDesc[i].thread = (jthread) 251 NSK_CPP_STUB2(NewGlobalRef, jni, threadsDesc[i].thread)) != NULL)) 252 return NSK_FALSE; 253 if (!NSK_JNI_VERIFY(jni, (threadsDesc[i].cls = (jclass) 254 NSK_CPP_STUB2(NewGlobalRef, jni, threadsDesc[i].cls)) != NULL)) 255 return NSK_FALSE; 256 } 257 258 NSK_DISPLAY0("Enable tested events\n"); 259 if (!nsk_jvmti_enableEvents(JVMTI_ENABLE, EVENTS_COUNT, eventsList, NULL)) 260 return NSK_FALSE; 261 262 return NSK_TRUE; 263 } 264 265 /** 266 * Suspend or resume tested threads. 267 */ 268 static int suspendThreadsIndividually(int suspend) { 269 int i; 270 271 for (i = 0; i < THREADS_COUNT; i++) { 272 if (suspend) { 273 NSK_DISPLAY2(" suspend thread #%d (%s)\n", i, threadsDesc[i].threadName); 274 if (!NSK_JVMTI_VERIFY( 275 NSK_CPP_STUB2(SuspendThread, jvmti, threadsDesc[i].thread))) 276 nsk_jvmti_setFailStatus(); 277 } else { 278 NSK_DISPLAY2(" resume thread #%d (%s)\n", i, threadsDesc[i].threadName); 279 if (!NSK_JVMTI_VERIFY( 280 NSK_CPP_STUB2(ResumeThread, jvmti, threadsDesc[i].thread))) 281 nsk_jvmti_setFailStatus(); 282 } 283 } 284 return NSK_TRUE; 285 } 286 287 /** 288 * Testcase: check tested threads. 289 * - call GetFrameCount() and then GetStackTrace() 290 * - for each stack frame of common depth GetFrameLocation() 291 * - compare frame ifno returned by GetFrameLocation() and GetStackTrace() 292 * - find expected frame for tested method 293 * 294 * Returns NSK_TRUE if test may continue; or NSK_FALSE for test break. 295 */ 296 static int checkThreads(int suspended, const char* kind0) { 297 char kind[256] = ""; 298 int i; 299 300 /* check each thread */ 301 for (i = 0; i < THREADS_COUNT; i++) { 302 jint frameCount = 0; 303 jint frameStackSize = 0; 304 jvmtiFrameInfo frameStack[MAX_STACK_SIZE]; 305 int commonDepth = 0; 306 int found = 0; 307 int j; 308 309 /* make proper kind */ 310 strcpy(kind, threadsDesc[i].methodCompiled ? "compiled " : "not compiled "); 311 strcat(kind, kind0); 312 NSK_DISPLAY2(" thread #%d (%s):\n", i, threadsDesc[i].threadName); 313 314 /* get frame count */ 315 if (!NSK_JVMTI_VERIFY( 316 NSK_CPP_STUB3(GetFrameCount, jvmti, 317 threadsDesc[i].thread, &frameCount))) { 318 nsk_jvmti_setFailStatus(); 319 return NSK_TRUE; 320 } 321 NSK_DISPLAY1(" frameCount: %d\n", (int)frameCount); 322 323 /* get stack trace */ 324 if (!NSK_JVMTI_VERIFY( 325 NSK_CPP_STUB6(GetStackTrace, jvmti, threadsDesc[i].thread, 326 0, MAX_STACK_SIZE, frameStack, &frameStackSize))) { 327 nsk_jvmti_setFailStatus(); 328 return NSK_TRUE; 329 } 330 NSK_DISPLAY1(" stack depth: %d\n", (int)frameStackSize); 331 332 commonDepth = (frameCount < frameStackSize ? frameCount : frameStackSize); 333 NSK_DISPLAY1(" common: %d\n", (int)commonDepth); 334 335 /* check first commonDepth frames and find expected method there */ 336 found = 0; 337 for (j = 0; j < commonDepth; j++) { 338 jmethodID qMethod = (jmethodID)NULL; 339 jlocation qLocation = NSK_JVMTI_INVALID_JLOCATION; 340 341 NSK_DISPLAY3(" %d frame: method: 0x%p, location: %ld\n", 342 j, (void*)frameStack[j].method, 343 (long)frameStack[j].location); 344 /* query frame location */ 345 if (!NSK_JVMTI_VERIFY( 346 NSK_CPP_STUB5(GetFrameLocation, jvmti, threadsDesc[i].thread, 347 j, &qMethod, &qLocation))) { 348 nsk_jvmti_setFailStatus(); 349 continue; 350 } 351 352 NSK_DISPLAY2(" queried: method: 0x%p, location: %ld\n", 353 (void*)qMethod, (long)qLocation); 354 355 /* check frame equalaty */ 356 if (frameStack[j].method != qMethod) { 357 NSK_COMPLAIN6("Different method in stack frame #%d for %s thread #%d (%s):\n" 358 "# GetStackTrace(): 0x%p\n" 359 "# GetFrameLocation(): 0x%p\n", 360 j, kind, i, threadsDesc[i].threadName, 361 (void*)frameStack[j].method, (void*)qMethod); 362 nsk_jvmti_setFailStatus(); 363 } 364 if (frameStack[j].location != qLocation) { 365 NSK_COMPLAIN6("Different location in stack frame #%d for %s thread #%d (%s):\n" 366 "# GetStackTrace(): %ld\n" 367 "# GetFrameLocation(): %ld\n", 368 j, kind, i, threadsDesc[i].threadName, 369 (long)frameStack[j].location, (long)qLocation); 370 nsk_jvmti_setFailStatus(); 371 } 372 373 /* find expected method */ 374 if (frameStack[j].method == threadsDesc[i].method) { 375 found++; 376 NSK_DISPLAY1(" found expected method: %s\n", 377 threadsDesc[i].methodName); 378 } 379 } 380 381 /* check if expected method frame found */ 382 if (found <= 0) { 383 NSK_COMPLAIN3("No expected method frame for %s thread #%d (%s)\n", 384 kind, i, threadsDesc[i].threadName); 385 nsk_jvmti_setFailStatus(); 386 } 387 } 388 389 /* test may continue */ 390 return NSK_TRUE; 391 } 392 393 /** 394 * Clean data. 395 * - disable events 396 * - dispose global references to tested threads 397 */ 398 static int clean() { 399 int i; 400 401 NSK_DISPLAY0("Disable events\n"); 402 if (!nsk_jvmti_enableEvents(JVMTI_DISABLE, EVENTS_COUNT, eventsList, NULL)) 403 return NSK_FALSE; 404 405 NSK_DISPLAY0("Dispose global references to threads\n"); 406 for (i = 0; i < THREADS_COUNT; i++) { 407 NSK_TRACE(NSK_CPP_STUB2(DeleteGlobalRef, jni, threadsDesc[i].thread)); 408 NSK_TRACE(NSK_CPP_STUB2(DeleteGlobalRef, jni, threadsDesc[i].cls)); 409 } 410 411 return NSK_TRUE; 412 } 413 414 /* ============================================================================= */ 415 416 /** 417 * COMPILED_METHOD_LOAD callback. 418 * - turn on flag that method is compiled 419 */ 420 JNIEXPORT void JNICALL 421 callbackCompiledMethodLoad(jvmtiEnv* jvmti, jmethodID method, 422 jint code_size, const void* code_addr, 423 jint map_length, const jvmtiAddrLocationMap* map, 424 const void* compile_info) { 425 int i; 426 427 /* check if event is for tested method and turn flag on */ 428 for (i = 0; i < THREADS_COUNT; i++) { 429 if (threadsDesc[i].method == method) { 430 threadsDesc[i].methodCompiled = NSK_TRUE; 431 432 NSK_DISPLAY2(" COMPILED_METHOD_LOAD for method #%d (%s):\n", 433 i, threadsDesc[i].methodName); 434 NSK_DISPLAY1(" methodID: 0x%p\n", 435 (void*)threadsDesc[i].method); 436 NSK_DISPLAY1(" code_size: %d\n", 437 (int)code_size); 438 NSK_DISPLAY1(" map_length: %d\n", 439 (int)map_length); 440 break; 441 } 442 } 443 } 444 445 /** 446 * COMPILED_METHOD_UNLOAD callback. 447 * - turn off flag that method is compiled 448 */ 449 JNIEXPORT void JNICALL 450 callbackCompiledMethodUnload(jvmtiEnv* jvmti, jmethodID method, 451 const void* code_addr) { 452 int i; 453 454 /* check if event is for tested method and turn flag off */ 455 for (i = 0; i < THREADS_COUNT; i++) { 456 if (threadsDesc[i].method == method) { 457 threadsDesc[i].methodCompiled = NSK_FALSE; 458 459 NSK_DISPLAY2(" COMPILED_METHOD_UNLOAD for method #%d (%s):\n", 460 i, threadsDesc[i].methodName); 461 NSK_DISPLAY1(" methodID: 0x%p\n", 462 (void*)threadsDesc[i].method); 463 break; 464 } 465 } 466 } 467 468 /* ============================================================================= */ 469 470 volatile int testedThreadReady = NSK_FALSE; 471 volatile int testedThreadShouldFinish = NSK_FALSE; 472 473 /** Native running method in tested thread */ 474 JNIEXPORT void JNICALL 475 Java_nsk_jvmti_scenarios_sampling_SP06_sp06t003ThreadRunningNative_testedMethod(JNIEnv* jni, 476 jobject obj, 477 jboolean simulate, 478 jint i) { 479 if (!simulate) { 480 volatile int k = 0, n = 1000; 481 482 /* run in a continous loop */ 483 testedThreadReady = NSK_TRUE; 484 while (!testedThreadShouldFinish) { 485 if (n <= 0) 486 n = 1000; 487 if (k >= n) 488 k = 0; 489 k++; 490 } 491 } 492 } 493 494 /** Wait for native method is running. */ 495 JNIEXPORT jboolean JNICALL 496 Java_nsk_jvmti_scenarios_sampling_SP06_sp06t003ThreadRunningNative_checkReady(JNIEnv* jni, 497 jobject obj) { 498 while (!testedThreadReady) { 499 nsk_jvmti_sleep(1000); 500 } 501 return testedThreadReady ? JNI_TRUE : JNI_FALSE; 502 } 503 504 /** Let native method to finish. */ 505 JNIEXPORT void JNICALL 506 Java_nsk_jvmti_scenarios_sampling_SP06_sp06t003ThreadRunningNative_letFinish(JNIEnv* jni, 507 jobject obj) { 508 testedThreadShouldFinish = NSK_TRUE; 509 } 510 511 /* ============================================================================= */ 512 513 /** Agent library initialization. */ 514 #ifdef STATIC_BUILD 515 JNIEXPORT jint JNICALL Agent_OnLoad_sp06t003(JavaVM *jvm, char *options, void *reserved) { 516 return Agent_Initialize(jvm, options, reserved); 517 } 518 JNIEXPORT jint JNICALL Agent_OnAttach_sp06t003(JavaVM *jvm, char *options, void *reserved) { 519 return Agent_Initialize(jvm, options, reserved); 520 } 521 JNIEXPORT jint JNI_OnLoad_sp06t003(JavaVM *jvm, char *options, void *reserved) { 522 return JNI_VERSION_1_8; 523 } 524 #endif 525 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { 526 527 if (!NSK_VERIFY(nsk_jvmti_parseOptions(options))) 528 return JNI_ERR; 529 530 timeout = nsk_jvmti_getWaitTime() * 60 * 1000; 531 532 if (!NSK_VERIFY((jvmti = 533 nsk_jvmti_createJVMTIEnv(jvm, reserved)) != NULL)) 534 return JNI_ERR; 535 536 { 537 jvmtiCapabilities caps; 538 memset(&caps, 0, sizeof(caps)); 539 caps.can_suspend = 1; 540 caps.can_generate_compiled_method_load_events = 1; 541 if (!NSK_JVMTI_VERIFY( 542 NSK_CPP_STUB2(AddCapabilities, jvmti, &caps))) 543 return JNI_ERR; 544 } 545 546 { 547 jvmtiEventCallbacks eventCallbacks; 548 memset(&eventCallbacks, 0, sizeof(eventCallbacks)); 549 eventCallbacks.CompiledMethodLoad = callbackCompiledMethodLoad; 550 eventCallbacks.CompiledMethodUnload = callbackCompiledMethodUnload; 551 if (!NSK_JVMTI_VERIFY( 552 NSK_CPP_STUB3(SetEventCallbacks, jvmti, 553 &eventCallbacks, sizeof(eventCallbacks)))) 554 return JNI_ERR; 555 } 556 557 if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agentProc, NULL))) 558 return JNI_ERR; 559 560 return JNI_OK; 561 } 562 563 /* ============================================================================= */ 564 565 }