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     int minDepth;
  57     jthread thread;
  58     jclass cls;
  59     jmethodID method;
  60     int methodCompiled;
  61 } ThreadDesc;
  62 
  63 /* descriptions of tested threads */
  64 static ThreadDesc threadsDesc[THREADS_COUNT] = {
  65     {"threadRunning", "testedMethod", "(ZI)V", 2, NULL, NULL, NULL, NSK_FALSE},
  66     {"threadEntering", "testedMethod", "(ZI)V", 2, NULL, NULL, NULL, NSK_FALSE},
  67     {"threadWaiting", "testedMethod", "(ZI)V", 2, NULL, NULL, NULL, NSK_FALSE},
  68     {"threadSleeping", "testedMethod", "(ZI)V", 2, NULL, NULL, NULL, NSK_FALSE},
  69     {"threadRunningInterrupted", "testedMethod", "(ZI)V", 2, NULL, NULL, NULL, NSK_FALSE},
  70     {"threadRunningNative", "testedMethod", "(ZI)V", 2, NULL, NULL, NULL, 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 checkSuspendedThreads();
  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("Suspend each thread\n");
 109         if (!suspendThreadsIndividually(NSK_TRUE))
 110             return;
 111 
 112         NSK_DISPLAY0("Check stack frames of suspended threads\n");
 113         if (!checkSuspendedThreads())
 114             return;
 115 
 116         NSK_DISPLAY0("Resume each thread\n");
 117         if (!suspendThreadsIndividually(NSK_FALSE))
 118             return;
 119 
 120         NSK_DISPLAY0("Clean data\n");
 121         if (!clean()) {
 122             nsk_jvmti_setFailStatus();
 123             return;
 124         }
 125     }
 126 
 127     NSK_DISPLAY0("Let debuggee to finish\n");
 128     if (!nsk_jvmti_resumeSync())
 129         return;
 130 }
 131 
 132 /* ============================================================================= */
 133 
 134 /**
 135  * Generate missed events (COMPILED_METHOD_LOAD only).
 136  */
 137 static int generateEvents() {
 138     if (!NSK_JVMTI_VERIFY(
 139             NSK_CPP_STUB2(GenerateEvents, jvmti, JVMTI_EVENT_COMPILED_METHOD_LOAD))) {
 140         nsk_jvmti_setFailStatus();
 141         return NSK_FALSE;
 142     }
 143     return NSK_TRUE;
 144 }
 145 
 146 /**
 147  * Prepare data.
 148  *    - clean threads list
 149  *    - get all live threads
 150  *    - get threads name
 151  *    - find tested threads
 152  *    - make global refs
 153  *    - enable events
 154  */
 155 static int prepare() {
 156     jthread *allThreadsList = NULL;
 157     jint allThreadsCount = 0;
 158     int found = 0;
 159     int i;
 160 
 161     NSK_DISPLAY1("Find tested threads: %d\n", THREADS_COUNT);
 162 
 163     /* clean threads list */
 164     for (i = 0; i < THREADS_COUNT; i++) {
 165         threadsDesc[i].thread = (jthread)NULL;
 166         threadsDesc[i].method = (jmethodID)NULL;
 167         threadsDesc[i].methodCompiled = NSK_FALSE;
 168     }
 169 
 170     /* get all live threads */
 171     if (!NSK_JVMTI_VERIFY(
 172             NSK_CPP_STUB3(GetAllThreads, jvmti, &allThreadsCount, &allThreadsList)))
 173         return NSK_FALSE;
 174 
 175     if (!NSK_VERIFY(allThreadsCount > 0 && allThreadsList != NULL))
 176         return NSK_FALSE;
 177 
 178     /* find tested threads */
 179     for (i = 0; i < allThreadsCount; i++) {
 180         jvmtiThreadInfo threadInfo;
 181 
 182         if (!NSK_VERIFY(allThreadsList[i] != NULL))
 183             return NSK_FALSE;
 184 
 185         if (!NSK_JVMTI_VERIFY(
 186                 NSK_CPP_STUB3(GetThreadInfo, jvmti, allThreadsList[i], &threadInfo)))
 187             return NSK_FALSE;
 188 
 189         if (threadInfo.name != NULL) {
 190             int j;
 191 
 192             for (j = 0; j < THREADS_COUNT; j++) {
 193                 if (strcmp(threadInfo.name, threadsDesc[j].threadName) == 0) {
 194                     threadsDesc[j].thread = allThreadsList[i];
 195                     NSK_DISPLAY3("    thread #%d (%s): 0x%p\n",
 196                                             j, threadInfo.name, (void*)threadsDesc[j].thread);
 197                 }
 198             }
 199         }
 200     }
 201 
 202     /* deallocate all threads list */
 203     if (!NSK_JVMTI_VERIFY(
 204             NSK_CPP_STUB2(Deallocate, jvmti, (unsigned char*)allThreadsList)))
 205         return NSK_FALSE;
 206 
 207     /* check if all tested threads found */
 208     found = 0;
 209     for (i = 0; i < THREADS_COUNT; i++) {
 210         if (threadsDesc[i].thread == NULL) {
 211             NSK_COMPLAIN2("Not found tested thread #%d (%s)\n", i, threadsDesc[i].threadName);
 212         } else {
 213             found++;
 214         }
 215     }
 216 
 217     if (found < THREADS_COUNT)
 218         return NSK_FALSE;
 219 
 220     /* get threads class and frame method */
 221     NSK_DISPLAY0("Find tested methods:\n");
 222     for (i = 0; i < THREADS_COUNT; i++) {
 223 
 224         if (!NSK_JNI_VERIFY(jni, (threadsDesc[i].cls =
 225                 NSK_CPP_STUB2(GetObjectClass, jni, threadsDesc[i].thread)) != NULL))
 226             return NSK_FALSE;
 227 
 228         if (!NSK_JNI_VERIFY(jni, (threadsDesc[i].method =
 229                 NSK_CPP_STUB4(GetMethodID, jni, threadsDesc[i].cls,
 230                             threadsDesc[i].methodName, threadsDesc[i].methodSig)) != NULL))
 231             return NSK_FALSE;
 232 
 233         NSK_DISPLAY4("    thread #%d (%s): 0x%p (%s)\n",
 234                                 i, threadsDesc[i].threadName,
 235                                 (void*)threadsDesc[i].method,
 236                                 threadsDesc[i].methodName);
 237     }
 238 
 239     /* make global refs */
 240     for (i = 0; i < THREADS_COUNT; i++) {
 241         if (!NSK_JNI_VERIFY(jni, (threadsDesc[i].thread = (jthread)
 242                 NSK_CPP_STUB2(NewGlobalRef, jni, threadsDesc[i].thread)) != NULL))
 243             return NSK_FALSE;
 244         if (!NSK_JNI_VERIFY(jni, (threadsDesc[i].cls = (jclass)
 245                 NSK_CPP_STUB2(NewGlobalRef, jni, threadsDesc[i].cls)) != NULL))
 246             return NSK_FALSE;
 247     }
 248 
 249     NSK_DISPLAY0("Enable tested events\n");
 250     if (!nsk_jvmti_enableEvents(JVMTI_ENABLE, EVENTS_COUNT, eventsList, NULL))
 251         return NSK_FALSE;
 252 
 253     return NSK_TRUE;
 254 }
 255 
 256 /**
 257  * Suspend or resume tested threads.
 258  */
 259 static int suspendThreadsIndividually(int suspend) {
 260     int i;
 261 
 262     for (i = 0; i < THREADS_COUNT; i++) {
 263         if (suspend) {
 264             NSK_DISPLAY2("    suspend thread #%d (%s)\n", i, threadsDesc[i].threadName);
 265             if (!NSK_JVMTI_VERIFY(
 266                     NSK_CPP_STUB2(SuspendThread, jvmti, threadsDesc[i].thread)))
 267                 nsk_jvmti_setFailStatus();
 268         } else {
 269             NSK_DISPLAY2("    resume thread #%d (%s)\n", i, threadsDesc[i].threadName);
 270             if (!NSK_JVMTI_VERIFY(
 271                     NSK_CPP_STUB2(ResumeThread, jvmti, threadsDesc[i].thread)))
 272                 nsk_jvmti_setFailStatus();
 273         }
 274     }
 275     return NSK_TRUE;
 276 }
 277 
 278 /**
 279  * Testcase: check tested threads.
 280  *    - invoke getFrameCount() for each thread
 281  *    - check if frameCount is not less than minimal stack depth
 282  *    - invoke getStackTrace() for each thread
 283  *    - check if stack depth is equal to frameCount
 284  *
 285  * Returns NSK_TRUE if test may continue; or NSK_FALSE for test break.
 286  */
 287 static int checkSuspendedThreads() {
 288     char kind[256] = "";
 289     int i;
 290 
 291     /* check each thread */
 292     for (i = 0; i < THREADS_COUNT; i++) {
 293         jint frameCount = 0;
 294         jint frameStackSize = 0;
 295         jvmtiFrameInfo frameStack[MAX_STACK_SIZE];
 296         int found = 0;
 297 
 298         /* make proper kind */
 299         strcpy(kind, threadsDesc[i].methodCompiled ? "compiled " : "not compiled ");
 300         NSK_DISPLAY2("  thread #%d (%s):\n", i, threadsDesc[i].threadName);
 301 
 302         /* get frame count */
 303         if (!NSK_JVMTI_VERIFY(
 304                 NSK_CPP_STUB3(GetFrameCount, jvmti,
 305                                     threadsDesc[i].thread, &frameCount))) {
 306             nsk_jvmti_setFailStatus();
 307             return NSK_TRUE;
 308         }
 309 
 310         NSK_DISPLAY1("    frameCount:  %d\n", (int)frameCount);
 311 
 312         /* get stack trace */
 313         if (!NSK_JVMTI_VERIFY(
 314                 NSK_CPP_STUB6(GetStackTrace, jvmti, threadsDesc[i].thread,
 315                                     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         /* check frame count */
 323         if (frameCount < threadsDesc[i].minDepth) {
 324             NSK_COMPLAIN5("Too few frameCount of %s thread #%d (%s):\n"
 325                             "#   got frameCount:   %d\n"
 326                             "#   expected minimum: %d\n",
 327                             kind, i, threadsDesc[i].threadName,
 328                             (int)frameCount, threadsDesc[i].minDepth);
 329             nsk_jvmti_setFailStatus();
 330         }
 331 
 332         if (frameStackSize != frameCount) {
 333             NSK_COMPLAIN5("Different frames count for %s thread #%d (%s):\n"
 334                             "#   getStackTrace(): %d\n"
 335                             "#   getFrameCount(): %d\n",
 336                             kind, i, threadsDesc[i].threadName,
 337                             (int)frameStackSize, (int)frameCount);
 338             nsk_jvmti_setFailStatus();
 339         }
 340 
 341     }
 342 
 343     /* test may continue */
 344     return NSK_TRUE;
 345 }
 346 
 347 /**
 348  * Clean data.
 349  *   - disable events
 350  *   - dispose global references to tested threads
 351  */
 352 static int clean() {
 353     int i;
 354 
 355     NSK_DISPLAY0("Disable events\n");
 356     if (!nsk_jvmti_enableEvents(JVMTI_DISABLE, EVENTS_COUNT, eventsList, NULL))
 357         return NSK_FALSE;
 358 
 359     NSK_DISPLAY0("Dispose global references to threads\n");
 360     for (i = 0; i < THREADS_COUNT; i++) {
 361         NSK_TRACE(NSK_CPP_STUB2(DeleteGlobalRef, jni, threadsDesc[i].thread));
 362         NSK_TRACE(NSK_CPP_STUB2(DeleteGlobalRef, jni, threadsDesc[i].cls));
 363     }
 364 
 365     return NSK_TRUE;
 366 }
 367 
 368 /* ============================================================================= */
 369 
 370 /**
 371  * COMPILED_METHOD_LOAD callback.
 372  *   - turn on flag that method is compiled
 373  */
 374 JNIEXPORT void JNICALL
 375 callbackCompiledMethodLoad(jvmtiEnv* jvmti, jmethodID method,
 376                             jint code_size, const void* code_addr,
 377                             jint map_length, const jvmtiAddrLocationMap* map,
 378                             const void* compile_info) {
 379     int i;
 380 
 381     /* check if event is for tested method and turn flag on */
 382     for (i = 0; i < THREADS_COUNT; i++) {
 383         if (threadsDesc[i].method == method) {
 384             threadsDesc[i].methodCompiled = NSK_TRUE;
 385 
 386             NSK_DISPLAY2("  COMPILED_METHOD_LOAD for method #%d (%s):\n",
 387                                 i, threadsDesc[i].methodName);
 388             NSK_DISPLAY1("    methodID:   0x%p\n",
 389                                 (void*)threadsDesc[i].method);
 390             NSK_DISPLAY1("    code_size:  %d\n",
 391                                 (int)code_size);
 392             NSK_DISPLAY1("    map_length: %d\n",
 393                                 (int)map_length);
 394             break;
 395         }
 396     }
 397 }
 398 
 399 /**
 400  * COMPILED_METHOD_UNLOAD callback.
 401  *   - turn off flag that method is compiled
 402  */
 403 JNIEXPORT void JNICALL
 404 callbackCompiledMethodUnload(jvmtiEnv* jvmti, jmethodID method,
 405                              const void* code_addr) {
 406     int i;
 407 
 408     /* check if event is for tested method and turn flag off */
 409     for (i = 0; i < THREADS_COUNT; i++) {
 410         if (threadsDesc[i].method == method) {
 411             threadsDesc[i].methodCompiled = NSK_FALSE;
 412 
 413             NSK_DISPLAY2("  COMPILED_METHOD_UNLOAD for method #%d (%s):\n",
 414                                 i, threadsDesc[i].methodName);
 415             NSK_DISPLAY1("    methodID:   0x%p\n",
 416                                 (void*)threadsDesc[i].method);
 417             break;
 418         }
 419     }
 420 }
 421 
 422 /* ============================================================================= */
 423 
 424 volatile int testedThreadReady = NSK_FALSE;
 425 volatile int testedThreadShouldFinish = NSK_FALSE;
 426 
 427 /** Native running method in tested thread. */
 428 JNIEXPORT void JNICALL
 429 Java_nsk_jvmti_scenarios_sampling_SP06_sp06t001ThreadRunningNative_testedMethod(JNIEnv* jni,
 430                                                                             jobject obj,
 431                                                                             jboolean simulate,
 432                                                                             jint i) {
 433     if (!simulate) {
 434         volatile int k = 0, n = 1000;
 435 
 436         /* run in a continous loop */
 437         testedThreadReady = NSK_TRUE;
 438         while (!testedThreadShouldFinish) {
 439             if (n <= 0)
 440                 n = 1000;
 441             if (k >= n)
 442                 k = 0;
 443             k++;
 444         }
 445     }
 446 }
 447 
 448 /** Wait for native method is running. */
 449 JNIEXPORT jboolean JNICALL
 450 Java_nsk_jvmti_scenarios_sampling_SP06_sp06t001ThreadRunningNative_checkReady(JNIEnv* jni,
 451                                                                             jobject obj) {
 452     while (!testedThreadReady) {
 453         nsk_jvmti_sleep(1000);
 454     }
 455     return testedThreadReady ? JNI_TRUE : JNI_FALSE;
 456 }
 457 
 458 /** Let native method to finish. */
 459 JNIEXPORT void JNICALL
 460 Java_nsk_jvmti_scenarios_sampling_SP06_sp06t001ThreadRunningNative_letFinish(JNIEnv* jni,
 461                                                                             jobject obj) {
 462     testedThreadShouldFinish = NSK_TRUE;
 463 }
 464 
 465 /* ============================================================================= */
 466 
 467 /** Agent library initialization. */
 468 #ifdef STATIC_BUILD
 469 JNIEXPORT jint JNICALL Agent_OnLoad_sp06t001(JavaVM *jvm, char *options, void *reserved) {
 470     return Agent_Initialize(jvm, options, reserved);
 471 }
 472 JNIEXPORT jint JNICALL Agent_OnAttach_sp06t001(JavaVM *jvm, char *options, void *reserved) {
 473     return Agent_Initialize(jvm, options, reserved);
 474 }
 475 JNIEXPORT jint JNI_OnLoad_sp06t001(JavaVM *jvm, char *options, void *reserved) {
 476     return JNI_VERSION_1_8;
 477 }
 478 #endif
 479 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
 480 
 481     if (!NSK_VERIFY(nsk_jvmti_parseOptions(options)))
 482         return JNI_ERR;
 483 
 484     timeout = nsk_jvmti_getWaitTime() * 60 * 1000;
 485 
 486     if (!NSK_VERIFY((jvmti =
 487             nsk_jvmti_createJVMTIEnv(jvm, reserved)) != NULL))
 488         return JNI_ERR;
 489 
 490     {
 491         jvmtiCapabilities caps;
 492         memset(&caps, 0, sizeof(caps));
 493         caps.can_suspend = 1;
 494         caps.can_generate_compiled_method_load_events = 1;
 495         if (!NSK_JVMTI_VERIFY(
 496                 NSK_CPP_STUB2(AddCapabilities, jvmti, &caps)))
 497             return JNI_ERR;
 498     }
 499 
 500     {
 501         jvmtiEventCallbacks eventCallbacks;
 502         memset(&eventCallbacks, 0, sizeof(eventCallbacks));
 503         eventCallbacks.CompiledMethodLoad = callbackCompiledMethodLoad;
 504         eventCallbacks.CompiledMethodUnload = callbackCompiledMethodUnload;
 505         if (!NSK_JVMTI_VERIFY(
 506                 NSK_CPP_STUB3(SetEventCallbacks, jvmti,
 507                                     &eventCallbacks, sizeof(eventCallbacks))))
 508             return JNI_ERR;
 509     }
 510 
 511     if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agentProc, NULL)))
 512         return JNI_ERR;
 513 
 514     return JNI_OK;
 515 }
 516 
 517 /* ============================================================================= */
 518 
 519 }