1 /* 2 * Copyright (c) 2004, 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 <stdlib.h> 25 #include <string.h> 26 #include "jni_tools.h" 27 #include "agent_common.h" 28 #include "jvmti_tools.h" 29 30 extern "C" { 31 32 #define MAX_DEPTH 1024 33 34 /* ========================================================================== */ 35 36 static const int NUMBER_OF_SAMPLES = 1000; 37 static const int DISPLAYING_FREQUENCY = 100; 38 static const jlong SAMPLING_INTERVAL = 10; 39 40 /* scaffold objects */ 41 static jlong timeout = 0; 42 43 /* test objects */ 44 static jthread thread = NULL; 45 static jrawMonitorID waitLock = NULL; 46 static jfieldID field = NULL; 47 static jmethodID methodRun = NULL; 48 static jmethodID methodCatcher = NULL; 49 static jmethodID methodThrower = NULL; 50 static jint MAX_LADDER = 0; 51 static int sampleCount = 0; 52 static jint frameCount = 0; 53 static jvmtiFrameInfo frameBuffer[MAX_DEPTH]; 54 55 /* ========================================================================== */ 56 57 static int prepare(jvmtiEnv* jvmti, JNIEnv* jni) { 58 const char* THREAD_NAME = "Debuggee Thread"; 59 jvmtiThreadInfo info; 60 jthread *threads = NULL; 61 jint threads_count = 0; 62 jclass klass = NULL; 63 jfieldID fid = NULL; 64 int i; 65 66 NSK_DISPLAY0("Prepare: find tested thread\n"); 67 68 /* get all live threads */ 69 if (!NSK_JVMTI_VERIFY(jvmti->GetAllThreads(&threads_count, &threads))) 70 return NSK_FALSE; 71 72 if (!NSK_VERIFY(threads_count > 0 && threads != NULL)) 73 return NSK_FALSE; 74 75 /* find tested thread */ 76 for (i = 0; i < threads_count; i++) { 77 if (!NSK_VERIFY(threads[i] != NULL)) 78 return NSK_FALSE; 79 80 /* get thread information */ 81 if (!NSK_JVMTI_VERIFY(jvmti->GetThreadInfo(threads[i], &info))) 82 return NSK_FALSE; 83 84 NSK_DISPLAY3(" thread #%d (%s): %p\n", i, info.name, threads[i]); 85 86 /* find by name */ 87 if (info.name != NULL && (strcmp(info.name, THREAD_NAME) == 0)) { 88 thread = threads[i]; 89 } 90 91 if (info.name != NULL) { 92 if (!NSK_JVMTI_VERIFY(jvmti->Deallocate((unsigned char*)info.name))) 93 return NSK_FALSE; 94 } 95 } 96 97 /* deallocate threads list */ 98 if (!NSK_JVMTI_VERIFY(jvmti->Deallocate((unsigned char*)threads))) 99 return NSK_FALSE; 100 101 if (thread == NULL) { 102 NSK_COMPLAIN0("Debuggee thread not found"); 103 return NSK_FALSE; 104 } 105 106 /* get tested thread class */ 107 if (!NSK_JNI_VERIFY(jni, (klass = jni->GetObjectClass(thread)) != NULL)) 108 return NSK_FALSE; 109 110 /* get tested thread field 'MAX_LADDER' */ 111 if (!NSK_JNI_VERIFY(jni, (fid = jni->GetStaticFieldID(klass, "MAX_LADDER", "I")) != NULL)) 112 return NSK_FALSE; 113 114 MAX_LADDER = jni->GetStaticIntField(klass, fid); 115 NSK_DISPLAY1("MAX_LADDER: %d\n", MAX_LADDER); 116 117 /* get tested thread field 'depth' */ 118 if (!NSK_JNI_VERIFY(jni, (field = jni->GetFieldID(klass, "depth", "I")) != NULL)) 119 return NSK_FALSE; 120 121 /* get tested thread method 'run' */ 122 if (!NSK_JNI_VERIFY(jni, (methodRun = jni->GetMethodID(klass, "run", "()V")) != NULL)) 123 return NSK_FALSE; 124 125 /* get tested thread method 'catcher' */ 126 if (!NSK_JNI_VERIFY(jni, (methodCatcher = 127 jni->GetMethodID(klass, "catcher", "(II)V")) != NULL)) 128 return NSK_FALSE; 129 130 /* get tested thread method 'thrower' */ 131 if (!NSK_JNI_VERIFY(jni, (methodThrower= jni->GetMethodID(klass, "thrower", "(I)V")) != NULL)) 132 return NSK_FALSE; 133 134 if (!NSK_JVMTI_VERIFY(jvmti->CreateRawMonitor("waitLock", &waitLock))) 135 return NSK_FALSE; 136 137 return NSK_TRUE; 138 } 139 140 /* ============================================================================= */ 141 142 static int wait_for(jvmtiEnv* jvmti, jlong millis) { 143 144 if (!NSK_JVMTI_VERIFY(jvmti->RawMonitorEnter(waitLock))) 145 return NSK_FALSE; 146 147 if (!NSK_JVMTI_VERIFY(jvmti->RawMonitorWait(waitLock, millis))) 148 nsk_jvmti_setFailStatus(); 149 150 if (!NSK_JVMTI_VERIFY(jvmti->RawMonitorExit(waitLock))) 151 return NSK_FALSE; 152 153 return NSK_TRUE; 154 } 155 156 static int displayFrameInfo(jvmtiEnv* jvmti, jint i) { 157 char buffer[32]; 158 char *name = NULL; 159 char *signature = NULL; 160 161 if (!NSK_JVMTI_VERIFY(jvmti->GetMethodName(frameBuffer[frameCount-1-i].method, &name, &signature, NULL))) 162 return NSK_FALSE; 163 164 NSK_DISPLAY4(" [%d] method: %s%s, location: %s\n", i, name, 165 signature, jlong_to_string(frameBuffer[frameCount-1-i].location, buffer)); 166 if (name != NULL) 167 jvmti->Deallocate((unsigned char*)name); 168 if (signature != NULL) 169 jvmti->Deallocate((unsigned char*)signature); 170 171 return NSK_TRUE; 172 } 173 174 static int complainFrameInfo(jvmtiEnv* jvmti, jint i, jmethodID method) { 175 char buffer[32]; 176 char *name = NULL; 177 char *signature = NULL; 178 179 if (!NSK_JVMTI_VERIFY(jvmti->GetMethodName(frameBuffer[frameCount-1-i].method, &name, &signature, NULL))) 180 return NSK_FALSE; 181 182 NSK_COMPLAIN3(" got method: %s%s, location: %s\n", name, signature, 183 jlong_to_string(frameBuffer[frameCount-1-i].location, buffer)); 184 if (name != NULL) 185 jvmti->Deallocate((unsigned char*)name); 186 if (signature != NULL) 187 jvmti->Deallocate((unsigned char*)signature); 188 189 if (!NSK_JVMTI_VERIFY(jvmti->GetMethodName(method, &name, &signature, NULL))) 190 return NSK_FALSE; 191 192 NSK_COMPLAIN2(" expected method: %s%s\n", name, signature); 193 194 return NSK_TRUE; 195 } 196 197 static int checkStackTrace(jvmtiEnv* jvmti, JNIEnv* jni) { 198 int res = NSK_TRUE; 199 jmethodID method = NULL; 200 jint depth; 201 jint i; 202 int displayFlag = 203 (nsk_getVerboseMode() && (sampleCount % DISPLAYING_FREQUENCY) == 0); 204 205 if (!NSK_JVMTI_VERIFY(jvmti->SuspendThread(thread))) 206 return NSK_FALSE; 207 208 depth = jni->GetIntField(thread, field); 209 210 /* get stack trace */ 211 if (!NSK_JVMTI_VERIFY(jvmti->GetStackTrace(thread, 0, MAX_DEPTH, frameBuffer, &frameCount))) { 212 res = NSK_FALSE; 213 } 214 215 if (!NSK_JVMTI_VERIFY(jvmti->ResumeThread(thread))) 216 res = NSK_FALSE; 217 218 if (res) { 219 if (displayFlag) { 220 NSK_DISPLAY3("Sample #%d, frameCount: %d, depth: %d\n", 221 sampleCount, frameCount, depth); 222 } 223 for (i = 0; i < frameCount; i++) { 224 if (displayFlag && !displayFrameInfo(jvmti, i)) 225 res = NSK_FALSE; 226 if (i == 0) { 227 method = methodRun; 228 } else if (i <= (depth + 1)) { 229 method = methodCatcher; 230 } else if (i <= (MAX_LADDER + 2)) { 231 method = methodThrower; 232 } else { 233 continue; 234 } 235 if (!NSK_VERIFY(frameBuffer[frameCount-1-i].method == method)) { 236 NSK_COMPLAIN3("Sample #%d, depth=%d, wrong frame [%d]:\n", 237 sampleCount, depth, i); 238 complainFrameInfo(jvmti, i, method); 239 res = NSK_FALSE; 240 } 241 } 242 } 243 244 return res; 245 } 246 247 /* ========================================================================== */ 248 249 /* agent algorithm */ 250 static void JNICALL 251 agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { 252 253 /* wait for initial sync */ 254 if (!nsk_jvmti_waitForSync(timeout)) 255 return; 256 257 if (!prepare(jvmti, jni)) { 258 nsk_jvmti_setFailStatus(); 259 return; 260 } 261 262 /* sample stack of the tested thread */ 263 for (sampleCount = 0; 264 sampleCount < NUMBER_OF_SAMPLES && !nsk_jvmti_isFailStatus(); 265 sampleCount++) { 266 wait_for(jvmti, SAMPLING_INTERVAL); 267 if (!checkStackTrace(jvmti, jni)) 268 nsk_jvmti_setFailStatus(); 269 } 270 271 /* resume debugee after last sync */ 272 if (!nsk_jvmti_resumeSync()) 273 return; 274 } 275 276 /* ========================================================================== */ 277 278 /* agent library initialization */ 279 #ifdef STATIC_BUILD 280 JNIEXPORT jint JNICALL Agent_OnLoad_sp07t002(JavaVM *jvm, char *options, void *reserved) { 281 return Agent_Initialize(jvm, options, reserved); 282 } 283 JNIEXPORT jint JNICALL Agent_OnAttach_sp07t002(JavaVM *jvm, char *options, void *reserved) { 284 return Agent_Initialize(jvm, options, reserved); 285 } 286 JNIEXPORT jint JNI_OnLoad_sp07t002(JavaVM *jvm, char *options, void *reserved) { 287 return JNI_VERSION_1_8; 288 } 289 #endif 290 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { 291 jvmtiEnv* jvmti = NULL; 292 jvmtiCapabilities caps; 293 294 /* init framework and parse options */ 295 if (!NSK_VERIFY(nsk_jvmti_parseOptions(options))) 296 return JNI_ERR; 297 298 timeout = nsk_jvmti_getWaitTime() * 60000; 299 NSK_DISPLAY1("Timeout: %d msc\n", (int)timeout); 300 301 /* create JVMTI environment */ 302 if (!NSK_VERIFY((jvmti = 303 nsk_jvmti_createJVMTIEnv(jvm, reserved)) != NULL)) 304 return JNI_ERR; 305 306 memset(&caps, 0, sizeof(caps)); 307 caps.can_suspend = 1; 308 if (!NSK_JVMTI_VERIFY(jvmti->AddCapabilities(&caps))) 309 return JNI_ERR; 310 311 /* register agent proc and arg */ 312 if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agentProc, NULL))) 313 return JNI_ERR; 314 315 return JNI_OK; 316 } 317 318 /* ========================================================================== */ 319 320 }