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(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 */ 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 */ 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 */ 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 */ 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 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 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 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 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 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 488 JNIEXPORT jint JNICALL Agent_OnLoad_sp06t002(JavaVM *jvm, char *options, void *reserved) { 489 return Agent_Initialize(jvm, options, reserved); 490 } 491 JNIEXPORT jint JNICALL Agent_OnAttach_sp06t002(JavaVM *jvm, char *options, void *reserved) { 492 return Agent_Initialize(jvm, options, reserved); 493 } 494 JNIEXPORT jint JNI_OnLoad_sp06t002(JavaVM *jvm, char *options, void *reserved) { 495 return JNI_VERSION_1_8; 496 } 497 #endif 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 }