1 /* 2 * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. 3 * Copyright (c) 2020, NTT DATA. 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * This code is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 only, as 8 * published by the Free Software Foundation. 9 * 10 * This code is distributed in the hope that it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 * version 2 for more details (a copy is included in the LICENSE file that 14 * accompanied this code). 15 * 16 * You should have received a copy of the GNU General Public License version 17 * 2 along with this work; if not, write to the Free Software Foundation, 18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 19 * 20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 21 * or visit www.oracle.com if you need additional information or have any 22 * questions. 23 */ 24 25 #include <jni.h> 26 #include <jvmti.h> 27 #include <errno.h> 28 #include <stdio.h> 29 #include <stdlib.h> 30 31 #define MAX_FRAMES 100 32 #define ERR_MSG_LEN 1024 33 34 #ifdef __cplusplus 35 extern "C" { 36 #endif 37 38 static jvmtiEnv *jvmti = NULL; 39 40 JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { 41 return jvm->GetEnv(reinterpret_cast<void**>(&jvmti), JVMTI_VERSION_11); 42 } 43 44 static void check_frame_info(JNIEnv *env, jvmtiFrameInfo *fi1, jvmtiFrameInfo *fi2) { 45 char err_msg[ERR_MSG_LEN] = {0}; 46 if (fi1->method != fi2->method) { /* jvmtiFrameInfo::method */ 47 snprintf(err_msg, sizeof(err_msg), 48 "method is different: fi1 = %lx, fi2 = %lx", 49 fi1->method, fi2->method); 50 env->FatalError(err_msg); 51 } else if (fi1->location != fi2->location) { /* jvmtiFrameInfo::location */ 52 snprintf(err_msg, sizeof(err_msg), 53 "location is different: fi1 = %ld, fi2 = %ld", 54 fi1->location, fi2->location); 55 env->FatalError(err_msg); 56 } 57 } 58 59 static void check_stack_info(JNIEnv *env, jvmtiStackInfo *si1, jvmtiStackInfo *si2) { 60 char err_msg[ERR_MSG_LEN] = {0}; 61 62 jboolean is_same = env->IsSameObject(si1->thread, si2->thread); 63 if (env->ExceptionOccurred()) { 64 env->ExceptionDescribe(); 65 env->FatalError(__FILE__); 66 } 67 68 if (!is_same) { /* jvmtiStackInfo::thread */ 69 snprintf(err_msg, sizeof(err_msg), 70 "thread is different: si1 = %p, si2 = %p", si1->thread, si2->thread); 71 env->FatalError(err_msg); 72 } else if (si1->state != si2->state) { /* jvmtiStackInfo::state */ 73 snprintf(err_msg, sizeof(err_msg), 74 "state is different: si1 = %d, si2 = %d", si1->state, si2->state); 75 env->FatalError(err_msg); 76 } else if (si1->frame_count != si2->frame_count) { /* jvmtiStackInfo::frame_count */ 77 snprintf(err_msg, sizeof(err_msg), 78 "frame_count is different: si1 = %d, si2 = %d", 79 si1->frame_count, si2->frame_count); 80 env->FatalError(err_msg); 81 } else { 82 /* Iterate all jvmtiFrameInfo to check */ 83 for (int i = 0; i < si1->frame_count; i++) { 84 check_frame_info(env, &si1->frame_buffer[i], &si2->frame_buffer[i]); 85 } 86 } 87 } 88 89 JNIEXPORT void JNICALL Java_GetThreadListStackTraces_checkCallStacks(JNIEnv *env, jclass cls) { 90 jvmtiError result; 91 char err_msg[ERR_MSG_LEN] = {0}; 92 jthread *jthreads; 93 jint num_threads; 94 jvmtiStackInfo *si1, *si2; 95 96 /* Get all stack traces to compare */ 97 result = jvmti->GetAllStackTraces(MAX_FRAMES, &si1, &num_threads); 98 if (result != JVMTI_ERROR_NONE) { 99 snprintf(err_msg, sizeof(err_msg), 100 "GetAllStackTraces(): result = %d", result); 101 env->FatalError(err_msg); 102 } 103 104 /* Create jthread array to pass GetThreadListStackTraces() */ 105 jthreads = reinterpret_cast<jthread *>(malloc(sizeof(jthread) * num_threads)); 106 if (jthreads == NULL) { 107 snprintf(err_msg, sizeof(err_msg), "malloc(): errno = %d", errno); 108 env->FatalError(err_msg); 109 } 110 for (jint i = 0; i < num_threads; i++) { 111 jthreads[i] = si1[i].thread; 112 } 113 114 /* Get all stack traces from GetThreadListStackTraces() (Test target) */ 115 result = jvmti->GetThreadListStackTraces(num_threads, jthreads, MAX_FRAMES, &si2); 116 if (result != JVMTI_ERROR_NONE) { 117 snprintf(err_msg, sizeof(err_msg), 118 "GetThreadListStackTraces(): result = %d", result); 119 env->FatalError(err_msg); 120 } 121 122 /* Iterate all jvmtiStackInfo to check */ 123 for (jint i = 0; i < num_threads; i++) { 124 check_stack_info(env, si1, si2); 125 } 126 127 free(jthreads); 128 jvmti->Deallocate(reinterpret_cast<unsigned char *>(si1)); 129 jvmti->Deallocate(reinterpret_cast<unsigned char *>(si2)); 130 } 131 132 JNIEXPORT void JNICALL Java_OneGetThreadListStackTraces_checkCallStacks(JNIEnv *env, jclass cls, jthread thread) { 133 jvmtiStackInfo *stack_info, *target_info, *target_one_info; 134 jvmtiError result; 135 char err_msg[ERR_MSG_LEN] = {0}; 136 137 /* Get all stack traces */ 138 jint num_threads; 139 result = jvmti->GetAllStackTraces(MAX_FRAMES, &stack_info, &num_threads); 140 if (result != JVMTI_ERROR_NONE) { 141 snprintf(err_msg, sizeof(err_msg), 142 "GetAllStackTraces(): result = %d", result); 143 env->FatalError(err_msg); 144 } 145 146 /* Find jvmtiStackInfo for `thread` (in arguments) */ 147 jboolean is_same; 148 target_info = NULL; 149 for (jint i = 0; i < num_threads; i++) { 150 is_same = env->IsSameObject(stack_info[i].thread, thread); 151 if (env->ExceptionOccurred()) { 152 env->ExceptionDescribe(); 153 env->FatalError(__FILE__); 154 } 155 if (is_same) { 156 target_info = &stack_info[i]; 157 break; 158 } 159 } 160 if (target_info == NULL) { 161 env->FatalError("Target thread not found"); 162 } 163 164 /* 165 * Get jvmtiStackInfo via GetThreadListStackTraces(). 166 * It expects to perform in Thread Local Handshake because thread count is 1. 167 */ 168 result = jvmti->GetThreadListStackTraces(1, &thread, 169 MAX_FRAMES, &target_one_info); 170 if (result != JVMTI_ERROR_NONE) { 171 snprintf(err_msg, sizeof(err_msg), 172 "GetThreadListStackTraces(): result = %d", result); 173 env->FatalError(err_msg); 174 } 175 176 check_stack_info(env, target_info, target_one_info); 177 178 jvmti->Deallocate(reinterpret_cast<unsigned char *>(stack_info)); 179 jvmti->Deallocate(reinterpret_cast<unsigned char *>(target_one_info)); 180 } 181 182 #ifdef __cplusplus 183 } 184 #endif