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