1 /*
   2  * Copyright (c) 2007, 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 "jni_tools.h"
  28 #include "agent_common.h"
  29 
  30 extern "C" {
  31 
  32 #define STATUS_FAILED 2
  33 #define PASSED 0
  34 
  35 #define JVMTI_ERROR_CHECK(str,res)   \
  36     if (res != JVMTI_ERROR_NONE) {  \
  37         printf("%s %d\n" ,str, res); \
  38         return res;                  \
  39     }
  40 
  41 #define JVMTI_ERROR_CHECK_EXPECTED_ERROR(str,res,err) \
  42     if (res != err) {                                \
  43         printf("%s unexpected error %d\n", str, res); \
  44         return res;                                   \
  45     }
  46 
  47 #define JVMTI_ERROR_CHECK_VOID(str,res) \
  48     if (res != JVMTI_ERROR_NONE) {      \
  49         printf("%s %d\n" ,str, res);    \
  50         iGlobalStatus = STATUS_FAILED;         \
  51     }
  52 
  53 #define JVMTI_ERROR_CHECK_EXPECTED_ERROR_VOID(str,res,err) \
  54     if (res != err) {                                      \
  55         printf("%s unexpected error %d\n",str, res);       \
  56         iGlobalStatus = STATUS_FAILED;                            \
  57     }
  58 
  59 
  60 static jvmtiEnv *jvmti;
  61 static jint iGlobalStatus = PASSED;
  62 static jvmtiCapabilities jvmti_caps;
  63 static jrawMonitorID jraw_monitor;
  64 
  65 
  66 #define MAX_FRAMES_CNT  30
  67 static jvmtiStackInfo  *stack_buf1    = NULL;
  68 static jvmtiStackInfo  *stack_buf2    = NULL;
  69 static jthread         *thread_list   = NULL;
  70 static jvmtiThreadInfo *thread_info   = NULL;
  71 static jint             threads_count = 0;
  72 
  73 
  74 #ifdef STATIC_BUILD
  75 JNIEXPORT jint JNICALL Agent_OnLoad_getallstktr001(JavaVM *jvm, char *options, void *reserved) {
  76     return Agent_Initialize(jvm, options, reserved);
  77 }
  78 JNIEXPORT jint JNICALL Agent_OnAttach_getallstktr001(JavaVM *jvm, char *options, void *reserved) {
  79     return Agent_Initialize(jvm, options, reserved);
  80 }
  81 JNIEXPORT jint JNI_OnLoad_getallstktr001(JavaVM *jvm, char *options, void *reserved) {
  82     return JNI_VERSION_1_8;
  83 }
  84 #endif
  85 jint Agent_Initialize(JavaVM * jvm, char *options, void *reserved) {
  86     jint res;
  87 
  88     res = jvm->GetEnv((void **) &jvmti, JVMTI_VERSION_1_1);
  89     if (res < 0) {
  90         printf("Wrong result of a valid call to GetEnv!\n");
  91         return JNI_ERR;
  92     }
  93 
  94     /* Add capabilities */
  95     res = jvmti->GetPotentialCapabilities(&jvmti_caps);
  96     JVMTI_ERROR_CHECK("GetPotentialCapabilities returned error", res);
  97 
  98     res = jvmti->AddCapabilities(&jvmti_caps);
  99     JVMTI_ERROR_CHECK("GetPotentialCapabilities returned error", res);
 100 
 101     return JNI_OK;
 102 }
 103 
 104 
 105 JNIEXPORT jint JNICALL
 106 Java_nsk_jvmti_unit_GetAllStackTraces_getallstktr001_GetResult(
 107     JNIEnv * env, jclass cls)
 108 {
 109     return iGlobalStatus;
 110 }
 111 
 112 
 113 JNIEXPORT void JNICALL
 114 Java_nsk_jvmti_unit_GetAllStackTraces_getallstktr001_CreateRawMonitor(
 115     JNIEnv * env, jclass cls)
 116 {
 117     jvmtiError ret;
 118     char sz[128];
 119 
 120     sprintf(sz, "Raw-monitor");
 121     ret = jvmti->CreateRawMonitor(sz, &jraw_monitor);
 122 
 123     if (ret != JVMTI_ERROR_NONE) {
 124         printf("Error: Raw monitor create %d \n", ret);
 125         iGlobalStatus = STATUS_FAILED;
 126     }
 127 }
 128 
 129 JNIEXPORT void JNICALL
 130 Java_nsk_jvmti_unit_GetAllStackTraces_getallstktr001_RawMonitorEnter(
 131     JNIEnv * env, jclass cls)
 132 {
 133     jvmtiError ret;
 134 
 135     ret = jvmti->RawMonitorEnter(jraw_monitor);
 136 
 137     if (ret != JVMTI_ERROR_NONE) {
 138         printf("Error: Raw monitor enter %d \n", ret);
 139         iGlobalStatus = STATUS_FAILED;
 140     }
 141 }
 142 
 143 JNIEXPORT void JNICALL
 144 Java_nsk_jvmti_unit_GetAllStackTraces_getallstktr001_RawMonitorExit(
 145     JNIEnv * env, jclass cls)
 146 {
 147     jvmtiError ret;
 148 
 149     ret = jvmti->RawMonitorExit(jraw_monitor);
 150 
 151     if (ret != JVMTI_ERROR_NONE) {
 152         printf("Error: RawMonitorExit %d \n", ret);
 153         iGlobalStatus = STATUS_FAILED;
 154     }
 155 }
 156 
 157 void compare_all_frames(int ti, int frames_count,
 158                         jvmtiFrameInfo *fr_buf1,
 159                         jvmtiFrameInfo *fr_buf2)
 160 {
 161     int fi;
 162     jvmtiFrameInfo *fr1, *fr2;
 163 
 164     for (fi = 0; fi < frames_count; fi++) {
 165         fr1 = &fr_buf1[fi];
 166         fr2 = &fr_buf2[fi];
 167         if (fr1->method != fr2->method) {
 168             printf("FAILED: compare frame: thread %d: frame %d: "
 169                    "different methods", ti, fi);
 170             iGlobalStatus = STATUS_FAILED;
 171             return;
 172         }
 173         if (fr1->location != fr2->location) {
 174             printf("FAILED: compare frame: thread %d: frame %d: "
 175                    "different locations", ti, fi);
 176             iGlobalStatus = STATUS_FAILED;
 177             return;
 178         }
 179         printf("thr #%d: compare frame #%d: fields are the same: "
 180                " method: 0x%p, location: %#" LL "x\n",
 181                ti, fi, fr1->method, fr1->location);
 182         fflush(0);
 183     }
 184 }
 185 
 186 void compare_one_stack_trace(int ti,
 187                              jvmtiStackInfo *stk1,
 188                              jvmtiStackInfo *stk2,
 189                              jvmtiThreadInfo *thr_info)
 190 {
 191     static const char* TEST_THREAD_NAME_PREFIX = "getallstktr001-";
 192     size_t PFX_LEN = strlen(TEST_THREAD_NAME_PREFIX);
 193 
 194     if (thr_info->name != NULL) {
 195         printf("compare stack #%d: thread: %s\n", ti, thr_info->name);
 196     } else {
 197         printf("compare stack #%d: thread is NULL\n", ti);
 198         return;
 199     }
 200 
 201     if (strlen(thr_info->name) < PFX_LEN ||
 202         strncmp(thr_info->name, TEST_THREAD_NAME_PREFIX, PFX_LEN) != 0)
 203     {
 204         printf("compare stack #%d: %s isn't tested thread - skip it\n",
 205                 ti, thr_info->name);
 206         return;
 207     }
 208 
 209     if (stk1->state != stk2->state)  {
 210         printf("FAILED: compare stack #%d: different states: "
 211                "st1: %d, st2: %d\n",
 212                 ti, stk1->state, stk2->state);
 213         iGlobalStatus = STATUS_FAILED;
 214         return;
 215     }
 216     if (stk1->frame_count != stk2->frame_count)  {
 217         printf("FAILED: compare stack #%d: different frame_count: "
 218                "cnt1: %d, cnt2: %d\n",
 219                 ti, stk1->frame_count, stk2->frame_count);
 220         iGlobalStatus = STATUS_FAILED;
 221         return;
 222     }
 223 
 224     printf("compare stack #%d: fields are the same: "
 225            " jthread: 0x%p, state: %d, frame_count: %d\n",
 226            ti, stk1->thread, stk1->state, stk1->frame_count);
 227 
 228     fflush(0);
 229     compare_all_frames(ti,
 230                        stk1->frame_count,
 231                        stk1->frame_buffer,
 232                        stk2->frame_buffer);
 233 }
 234 
 235 void compare_all_stack_traces(int thr_count,
 236                               jvmtiStackInfo  *stk_buf1,
 237                               jvmtiStackInfo  *stk_buf2,
 238                               jvmtiThreadInfo *thr_info)
 239 {
 240     int ti;
 241     for (ti = 0; ti < thr_count; ti++) {
 242         compare_one_stack_trace(ti, &stk_buf1[ti], &stk_buf2[ti], &thr_info[ti]);
 243     }
 244 }
 245 
 246 
 247 JNIEXPORT void JNICALL
 248 Java_nsk_jvmti_unit_GetAllStackTraces_getallstktr001_GetAllStackTraces(
 249      JNIEnv * env, jclass cls)
 250 {
 251     jvmtiError ret;
 252     int ti;
 253 
 254     ret = jvmti->GetAllStackTraces(MAX_FRAMES_CNT, &stack_buf1, &threads_count);
 255     if (ret != JVMTI_ERROR_NONE) {
 256         printf("Error: GetAllStackTraces %d \n", ret);
 257         iGlobalStatus = STATUS_FAILED;
 258     }
 259 
 260     ret = jvmti->Allocate(sizeof(jthread) * threads_count,
 261                           (unsigned char**) &thread_list);
 262     if (ret != JVMTI_ERROR_NONE) {
 263         printf("Error: Allocate failed with  %d \n", ret);
 264         iGlobalStatus = STATUS_FAILED;
 265     }
 266 
 267     for (ti = 0; ti < threads_count; ti++) {
 268         thread_list[ti] =
 269           (jthread)env->NewGlobalRef(stack_buf1[ti].thread);
 270     }
 271 }
 272 
 273 JNIEXPORT void JNICALL
 274 Java_nsk_jvmti_unit_GetAllStackTraces_getallstktr001_GetThreadsInfo(
 275      JNIEnv * env, jclass cls)
 276 {
 277     jvmtiError ret;
 278     int ti;
 279 
 280     ret = jvmti->Allocate(sizeof(jvmtiThreadInfo) * threads_count,
 281                           (unsigned char**)&thread_info);
 282     if (ret != JVMTI_ERROR_NONE) {
 283         printf("Error: Allocate failed with  %d \n", ret);
 284         iGlobalStatus = STATUS_FAILED;
 285     }
 286 
 287     for (ti = 0; ti < threads_count; ti++) {
 288         ret = jvmti->GetThreadInfo(thread_list[ti], &thread_info[ti]);
 289         if (ret != JVMTI_ERROR_NONE) {
 290             printf("Error: GetThreadInfo %d \n", ret);
 291             iGlobalStatus = STATUS_FAILED;
 292         }
 293         printf("GetThreadInfo %d: thread: %s\n", ti, thread_info[ti].name);
 294         fflush(0);
 295     }
 296 }
 297 
 298 JNIEXPORT void JNICALL
 299 Java_nsk_jvmti_unit_GetAllStackTraces_getallstktr001_GetThreadListStackTraces(
 300      JNIEnv * env, jclass cls)
 301 {
 302     jvmtiError ret;
 303 
 304     ret = jvmti->GetThreadListStackTraces(
 305         threads_count, thread_list, MAX_FRAMES_CNT, &stack_buf2);
 306     if (ret != JVMTI_ERROR_NONE) {
 307         printf("Error: GetThreadListStackTraces %d \n", ret);
 308         iGlobalStatus = STATUS_FAILED;
 309     }
 310 
 311 }
 312 
 313 JNIEXPORT void JNICALL
 314 Java_nsk_jvmti_unit_GetAllStackTraces_getallstktr001_ForceGC(
 315      JNIEnv * env, jclass cls)
 316 {
 317     jvmtiError ret;
 318     ret = jvmti->ForceGarbageCollection();
 319 
 320     if (ret != JVMTI_ERROR_NONE) {
 321         printf("Error: ForceGarbageCollection %d \n", ret);
 322         iGlobalStatus = STATUS_FAILED;
 323     }
 324 }
 325 
 326 JNIEXPORT void JNICALL
 327 Java_nsk_jvmti_unit_GetAllStackTraces_getallstktr001_CompareStackTraces(
 328      JNIEnv * env, jclass cls)
 329 {
 330     compare_all_stack_traces(threads_count, stack_buf1, stack_buf2, thread_info);
 331 }
 332 
 333 JNIEXPORT void JNICALL
 334 Java_nsk_jvmti_unit_GetAllStackTraces_getallstktr001_DeallocateBuffers(
 335      JNIEnv * env, jclass cls)
 336 {
 337     jvmtiError ret;
 338 
 339     ret = jvmti->Deallocate((unsigned char *) stack_buf1);
 340     if (ret != JVMTI_ERROR_NONE) {
 341         printf("Error: Deallocate stack_buf1 failed with  %d \n", ret);
 342         iGlobalStatus = STATUS_FAILED;
 343     }
 344 
 345     ret = jvmti->Deallocate((unsigned char *) stack_buf2);
 346     if (ret != JVMTI_ERROR_NONE) {
 347         printf("Error: Deallocate stack_buf2 failed with  %d \n", ret);
 348         iGlobalStatus = STATUS_FAILED;
 349     }
 350 
 351     ret = jvmti->Deallocate((unsigned char *) thread_info);
 352     if (ret != JVMTI_ERROR_NONE) {
 353         printf("Error: Deallocate thread_info failed with  %d \n", ret);
 354         iGlobalStatus = STATUS_FAILED;
 355     }
 356     ret = jvmti->Deallocate((unsigned char *) thread_list);
 357     if (ret != JVMTI_ERROR_NONE) {
 358         printf("Error: Deallocate thread_list failed with  %d \n", ret);
 359         iGlobalStatus = STATUS_FAILED;
 360     }
 361 }
 362 
 363 }