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 <stdio.h> 25 #include <stdarg.h> 26 #include <stdlib.h> 27 #include <string.h> 28 29 #include <jvmti.h> 30 #include "agent_common.h" 31 32 #include "nsk_tools.h" 33 #include "JVMTITools.h" 34 #include "jvmti_tools.h" 35 #include "native_thread.h" 36 37 #ifdef __cplusplus 38 extern "C" { 39 #endif 40 41 #ifndef JNI_ENV_ARG 42 #ifdef __cplusplus 43 #define JNI_ENV_ARG(x, y) y 44 #define JNI_ENV_PTR(x) x 45 #else 46 #define JNI_ENV_ARG(x, y) x, y 47 #define JNI_ENV_PTR(x) (*x) 48 #endif 49 #endif 50 51 #ifndef JNI_ENV_ARG1 52 #ifdef __cplusplus 53 #define JNI_ENV_ARG1(x) 54 #else 55 #define JNI_ENV_ARG1(x) x 56 #endif 57 #endif 58 59 #define PASSED 0 60 #define STATUS_FAILED 2 61 62 #define TRIES 30 63 #define AGENTS 2 64 65 static JavaVM *vm; 66 67 static jvmtiEnv *jvmti[AGENTS]; /* JVMTI env of an agent */ 68 static void *agentThr[AGENTS]; 69 static volatile int redir[AGENTS]; /* redirection in an agent done */ 70 static volatile int thrstarted[AGENTS]; /* an agent started */ 71 72 static volatile int verbose = 0; 73 74 static volatile jint result = PASSED; 75 76 /* the original JNI function table */ 77 static jniNativeInterface *orig_jni_functions[AGENTS]; 78 79 /* the redirected JNI function table */ 80 static jniNativeInterface *redir_jni_functions[AGENTS]; 81 82 /* number of the redirected JNI function calls */ 83 static volatile int redir_calls[AGENTS]; 84 85 static void doRedirect(JNIEnv*, jvmtiEnv*, int); 86 static void provokeIntercept(JNIEnv*, const char*); 87 static int checkIntercept(int, int, int); 88 static int initAgent(int); 89 static void startAgent(int); 90 static int agentA(void*); 91 static int agentB(void*); 92 static void JNICALL VMInitA(jvmtiEnv*, JNIEnv*, jthread); 93 static void JNICALL VMInitB(jvmtiEnv*, JNIEnv*, jthread); 94 95 /** redirected JNI functions **/ 96 /* function redirected inside the agent A */ 97 jint JNICALL MyGetVersionA(JNIEnv *env) { 98 redir_calls[0]++; 99 100 NSK_DISPLAY1("\nMyGetVersionA: the function called successfully: number of calls=%d\n", 101 redir_calls[0]); 102 103 return orig_jni_functions[0]->GetVersion( 104 JNI_ENV_ARG1(env)); 105 } 106 107 /* function redirected inside the agent B */ 108 jint JNICALL MyGetVersionB(JNIEnv *env) { 109 redir_calls[1]++; 110 111 NSK_DISPLAY1("\nMyGetVersionB: the function called successfully: number of calls=%d\n", 112 redir_calls[1]); 113 114 return (orig_jni_functions[1])->GetVersion( 115 JNI_ENV_ARG1(env)); 116 } 117 /*****************************/ 118 119 static void doRedirect(JNIEnv *env, jvmtiEnv *jvmti, int indx) { 120 jvmtiError err; 121 122 NSK_DISPLAY1("\n%s JVMTI env: doRedirect: obtaining the JNI function table ...\n", 123 (indx==0)?"first":"second"); 124 if ((err = (*jvmti)->GetJNIFunctionTable(jvmti, &orig_jni_functions[indx])) != 125 JVMTI_ERROR_NONE) { 126 result = STATUS_FAILED; 127 NSK_COMPLAIN2("TEST FAILED: %s JVMTI env: failed to get original JNI function table: %s\n", 128 (indx==0)?"first":"second", TranslateError(err)); 129 JNI_ENV_PTR(env)->FatalError(JNI_ENV_ARG(env, 130 "failed to get original JNI function table")); 131 } 132 if ((err = (*jvmti)->GetJNIFunctionTable(jvmti, &redir_jni_functions[indx])) != 133 JVMTI_ERROR_NONE) { 134 result = STATUS_FAILED; 135 NSK_COMPLAIN2("TEST FAILED: %s JVMTI env: failed to get redirected JNI function table: %s\n", 136 (indx==0)?"first":"second", TranslateError(err)); 137 JNI_ENV_PTR(env)->FatalError(JNI_ENV_ARG(env, 138 "failed to get redirected JNI function table")); 139 } 140 141 NSK_DISPLAY1("%s JVMTI env: doRedirect: the JNI function table obtained successfully\n\ 142 \toverwriting the function GetVersion() ...\n", 143 (indx==0)?"first":"second"); 144 redir_jni_functions[indx]->GetVersion = 145 (indx==0)?MyGetVersionA:MyGetVersionB; 146 147 if ((err = (*jvmti)->SetJNIFunctionTable(jvmti, redir_jni_functions[indx])) != 148 JVMTI_ERROR_NONE) { 149 result = STATUS_FAILED; 150 NSK_COMPLAIN2("TEST FAILED: %s JVMTI env: failed to set new JNI function table: %s\n", 151 (indx==0)?"first":"second", TranslateError(err)); 152 JNI_ENV_PTR(env)->FatalError(JNI_ENV_ARG(env, 153 "failed to set new JNI function table")); 154 } 155 156 NSK_DISPLAY1("%s JVMTI env: doRedirect: the functions are overwritten successfully\n", 157 (indx==0)?"first":"second"); 158 } 159 160 static void provokeIntercept(JNIEnv *env, const char *name) { 161 jint res; 162 163 res = JNI_ENV_PTR(env)-> 164 GetVersion(JNI_ENV_ARG1(env)); 165 NSK_DISPLAY2("\nGetVersion() called by the agent %s returns %d\n", 166 name, res); 167 } 168 169 static int checkIntercept(int indx, int env_num, int exCalls) { 170 if (redir_calls[indx] == exCalls) { 171 NSK_DISPLAY5("\nCHECK PASSED: GetVersion() interception set in the %s JVMTI env %s properly:\n\ 172 \t%d interception(s) with the%s%s JVMTI env as expected\n", 173 (indx==0)?"first":"second", 174 (exCalls==0)?"overwritten by another environment":"works", 175 redir_calls[indx], 176 (indx==env_num)?" same ":" ", 177 (env_num==0)?"first":"second"); 178 } 179 else { 180 result = STATUS_FAILED; 181 NSK_COMPLAIN6("\nTEST FAILED: GetVersion() interception set in the %s JVMTI env doesn't %s properly:\n\ 182 \t%d interception(s) with the%s%s JVMTI env instead of %d as expected\n", 183 (indx==0)?"first":"second", 184 (exCalls==0)?"overwritten by another environment":"work", 185 redir_calls[indx], 186 (indx==env_num)?" same ":" ", 187 (env_num==0)?"first":"second", 188 exCalls); 189 return STATUS_FAILED; 190 } 191 192 return PASSED; 193 } 194 195 static int initAgent(int indx) { 196 jvmtiEventCallbacks callbacks; /* callback functions */ 197 int exitCode = PASSED; 198 jvmtiError err; 199 jint res; 200 201 thrstarted[indx] = redir[indx] = redir_calls[indx] = 0; 202 203 NSK_DISPLAY1("\nagent %s initializer: obtaining the JVMTI env ...\n", 204 (indx==0)?"A":"B"); 205 res = JNI_ENV_PTR(vm)-> 206 GetEnv(JNI_ENV_ARG(vm, (void **) &jvmti[indx]), JVMTI_VERSION_1_1); 207 if (res != JNI_OK || jvmti[indx] == NULL) { 208 NSK_COMPLAIN1("TEST FAILURE: failed to call GetEnv for the agent %s\n", 209 (indx==0)?"A":"B"); 210 result = STATUS_FAILED; 211 return STATUS_FAILED; 212 } 213 214 NSK_DISPLAY1("\nagent %s initializer: the JVMTI env obtained\n\tsetting event callbacks ...\n", 215 (indx==0)?"A":"B"); 216 (void) memset(&callbacks, 0, sizeof(callbacks)); 217 switch(indx) { 218 case 0: 219 callbacks.VMInit = &VMInitA; 220 break; 221 case 1: 222 callbacks.VMInit = &VMInitB; 223 break; 224 } 225 if ((err = (*jvmti[indx])->SetEventCallbacks(jvmti[indx], 226 &callbacks, sizeof(callbacks))) != JVMTI_ERROR_NONE) { 227 NSK_COMPLAIN1("TEST FAILURE: failed to set event callbacks: %s\n", 228 TranslateError(err)); 229 result = STATUS_FAILED; 230 return STATUS_FAILED; 231 } 232 233 NSK_DISPLAY1("\nagent %s initializer: setting event callbacks done\n\tenabling events ...\n", 234 (indx==0)?"A":"B"); 235 if ((err = (*jvmti[indx])->SetEventNotificationMode(jvmti[indx], 236 JVMTI_ENABLE, 237 JVMTI_EVENT_VM_INIT, NULL)) != JVMTI_ERROR_NONE) { /* enable event globally */ 238 NSK_COMPLAIN2("TEST FAILURE: failed to enable JVMTI_EVENT_VM_INIT event for the agent %s: %s\n", 239 (indx==0)?"A":"B", TranslateError(err)); 240 result = STATUS_FAILED; 241 return STATUS_FAILED; 242 } 243 NSK_DISPLAY2("\nagent %s initializer: enabling events done, returning exit code %d\n", 244 (indx==0)?"A":"B", exitCode); 245 246 return exitCode; 247 } 248 249 static void startAgent(int indx) { 250 int tries = 0; 251 252 NSK_DISPLAY1("\nstartAgent: starting agent %s thread ...\n", 253 (indx==0)?"A":"B"); 254 agentThr[indx] = THREAD_new((indx==0)?agentA:agentB, 255 (indx==0)?"agent A":"agent B"); 256 if (THREAD_start(agentThr[indx]) == NULL) { 257 NSK_COMPLAIN1("TEST FAILURE: cannot start the agent %s thread\n", 258 (indx==0)?"A":"B"); 259 exit(STATUS_FAILED); 260 } 261 262 NSK_DISPLAY1("\nstartAgent: waiting for the agent %s to be started ...\n", 263 (indx==0)?"A":"B"); 264 do { 265 THREAD_sleep(1); 266 tries++; 267 if (tries > TRIES) { 268 NSK_COMPLAIN2("TEST FAILURE: the agent %s thread is still not started after %d attempts\n", 269 (indx==0)?"A":"B", TRIES); 270 exit(STATUS_FAILED); 271 } 272 } while(thrstarted[indx] != 1); 273 274 NSK_DISPLAY1("\nstartAgent: the agent %s thread started\n", 275 (indx==0)?"A":"B"); 276 } 277 278 /* agent thread procedures */ 279 static int agentA(void *context) { 280 JNIEnv *env; 281 jint res; 282 int tries = 0; 283 int i; 284 int exitCode = PASSED; 285 286 NSK_DISPLAY0("\nthe agent A started\n\tattaching the thread to the VM ...\n"); 287 if ((res = 288 JNI_ENV_PTR(vm)->AttachCurrentThread( 289 JNI_ENV_ARG(vm, (void **) &env), (void *) 0)) != 0) { 290 NSK_COMPLAIN1("TEST FAILURE: AttachCurrentThread() returns: %d\n", 291 res); 292 exit(STATUS_FAILED); 293 } 294 295 /* intercept the JNI function table */ 296 /* check the interception set in another JVMTI env */ 297 NSK_DISPLAY0("\n>>> TEST CASE #1) First JVMTI env: checking the redirection set in the same env ...\n\ 298 \nagent A (first JVMTI env): redirecting the function table ...\n"); 299 doRedirect(env, jvmti[0], 0); 300 301 /* check that the interception has been set properly */ 302 NSK_DISPLAY0("\nagent A (first JVMTI env): checking that the interception has been set properly ...\n"); 303 provokeIntercept(env, "A"); 304 checkIntercept(0, 0, 1); /* expected interceptions: 1 */ 305 NSK_DISPLAY0("\n<<< TEST CASE #1) done\n"); 306 307 /* the flag set too late in order to make sure that 308 the agent B will be started _after_ the interception */ 309 thrstarted[0] = 1; 310 311 redir[0] = 1; 312 313 NSK_DISPLAY0("\nagent A: waiting for the redirection in agent B ...\n"); 314 do { 315 THREAD_sleep(1); 316 tries++; 317 if (tries > TRIES) { 318 NSK_COMPLAIN1("TEST FAILURE: failed to wait for the redirection in agent B after %d attempts\n", 319 TRIES); 320 if ((res = JNI_ENV_PTR(vm)->DetachCurrentThread(JNI_ENV_ARG1(vm))) != 0) { 321 NSK_COMPLAIN1("TEST WARNING: agent A: DetachCurrentThread() returns: %d\n", res); 322 } 323 exit(STATUS_FAILED); 324 } 325 } while(redir[1] != 1); 326 327 /* check the interception set in another JVMTI env */ 328 NSK_DISPLAY0("\n>>> TEST CASE #4) First JVMTI env: checking the redirection set in second JVMTI env ...\n"); 329 for (i=0; i<AGENTS; i++) { 330 redir_calls[i] = 0; 331 } 332 provokeIntercept(env, "A"); 333 /* check that the previous interception has been overwritten */ 334 checkIntercept(0, 0, 1); /* expected interceptions: 1 */ 335 /* check the current interception set in another JVMTI env */ 336 checkIntercept(1, 0, 1); /* expected interceptions: 1 */ 337 NSK_DISPLAY0("\n<<< TEST CASE #4) done\n"); 338 339 NSK_DISPLAY1("\nagent A: detaching and returning exit code %d\n", 340 exitCode); 341 if ((res = JNI_ENV_PTR(vm)->DetachCurrentThread(JNI_ENV_ARG1(vm))) != 0) { 342 NSK_COMPLAIN1("TEST WARNING: agent A: DetachCurrentThread() returns: %d\n", res); 343 } 344 return exitCode; 345 } 346 347 static int agentB(void *context) { 348 JNIEnv *env; 349 jint res; 350 int tries = 0; 351 int i; 352 int exitCode = PASSED; 353 354 NSK_DISPLAY0("\nthe agent B started\n\tattaching the thread to the VM ...\n"); 355 if ((res = 356 JNI_ENV_PTR(vm)->AttachCurrentThread( 357 JNI_ENV_ARG(vm, (void **) &env), (void *) 0)) != 0) { 358 NSK_COMPLAIN1("TEST FAILURE: AttachCurrentThread() returns: %d\n", 359 res); 360 if ((res = JNI_ENV_PTR(vm)->DetachCurrentThread(JNI_ENV_ARG1(vm))) != 0) { 361 NSK_COMPLAIN1("TEST WARNING: agent B: DetachCurrentThread() returns: %d\n", res); 362 } 363 exit(STATUS_FAILED); 364 } 365 366 thrstarted[1] = 1; 367 368 NSK_DISPLAY0("\nagent B: waiting for the redirection in agent A ...\n"); 369 do { 370 THREAD_sleep(1); 371 tries++; 372 if (tries > TRIES) { 373 NSK_COMPLAIN1("TEST FAILURE: failed to wait for the redirection in agent A after %d attempts\n", 374 TRIES); 375 if ((res = JNI_ENV_PTR(vm)->DetachCurrentThread(JNI_ENV_ARG1(vm))) != 0) { 376 NSK_COMPLAIN1("TEST WARNING: agent B: DetachCurrentThread() returns: %d\n", res); 377 } 378 exit(STATUS_FAILED); 379 } 380 } while(redir[0] != 1); 381 382 /* check the interception set in another JVMTI env */ 383 NSK_DISPLAY0("\n>>> TEST CASE #2) Second JVMTI env: checking the redirection set in first JVMTI env ...\n"); 384 for (i=0; i<AGENTS; i++) { 385 redir_calls[i] = 0; 386 } 387 provokeIntercept(env, "B"); 388 checkIntercept(0, 1, 1); /* expected interceptions: 1 */ 389 NSK_DISPLAY0("\n<<< TEST CASE #2) done\n"); 390 391 /* intercept the JNI function table */ 392 NSK_DISPLAY0("\n>>> TEST CASE #3) Second JVMTI env: checking the redirection set in the same env ...\n\ 393 \nagent B (second JVMTI env): redirecting the function table ...\n"); 394 doRedirect(env, jvmti[1], 1); 395 396 for (i=0; i<AGENTS; i++) { 397 redir_calls[i] = 0; 398 } 399 provokeIntercept(env, "B"); 400 /* check that the previous interception has been overwritten */ 401 checkIntercept(0, 1, 1); /* expected interceptions: 1 */ 402 /* check that the current interception has been set properly */ 403 checkIntercept(1, 1, 1); /* expected interceptions: 1 */ 404 NSK_DISPLAY0("\n<<< TEST CASE #3) done\n"); 405 406 redir[1] = 1; 407 408 NSK_DISPLAY1("\nagent B: detaching and returning exit code %d\n", 409 exitCode); 410 if ((res = JNI_ENV_PTR(vm)->DetachCurrentThread(JNI_ENV_ARG1(vm))) != 0) { 411 NSK_COMPLAIN1("TEST WARNING: agent B: DetachCurrentThread() returns: %d\n", res); 412 } 413 return exitCode; 414 } 415 /*********************/ 416 417 /* callback functions */ 418 void JNICALL 419 VMInitA(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thread) { 420 NSK_DISPLAY0("\nagent A: VMInit event\n"); 421 422 startAgent(0); 423 } 424 425 void JNICALL 426 VMInitB(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thread) { 427 NSK_DISPLAY0("\nagent B: VMInit event\n"); 428 429 startAgent(1); 430 } 431 /*********************/ 432 433 JNIEXPORT jint JNICALL 434 Java_nsk_jvmti_scenarios_jni_1interception_JI05_ji05t001_getResult(JNIEnv *env, jobject obj) { 435 int i; 436 437 for (i=0; i<AGENTS; i++) { 438 NSK_DISPLAY1("\ngetResult: waiting for the agent %s thread...\n", 439 (i==0)?"A":"B"); 440 THREAD_waitFor(agentThr[i]); 441 if (THREAD_status(agentThr[i]) != PASSED) { 442 result = STATUS_FAILED; 443 NSK_COMPLAIN2("TEST FAILED: the agent %s thread done with the error code %d\n", 444 (i==0)?"A":"B", THREAD_status(agentThr[i])); 445 } 446 else NSK_DISPLAY2("getResult: the agent %s thread done with the code %d\n", 447 (i==0)?"A":"B", THREAD_status(agentThr[i])); 448 free(agentThr[i]); 449 } 450 451 return result; 452 } 453 454 #ifdef STATIC_BUILD 455 JNIEXPORT jint JNICALL Agent_OnLoad_ji05t001(JavaVM *jvm, char *options, void *reserved) { 456 return Agent_Initialize(jvm, options, reserved); 457 } 458 JNIEXPORT jint JNICALL Agent_OnAttach_ji05t001(JavaVM *jvm, char *options, void *reserved) { 459 return Agent_Initialize(jvm, options, reserved); 460 } 461 JNIEXPORT jint JNI_OnLoad_ji05t001(JavaVM *jvm, char *options, void *reserved) { 462 return JNI_VERSION_1_8; 463 } 464 #endif 465 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { 466 int i; 467 468 /* init framework and parse options */ 469 if (!NSK_VERIFY(nsk_jvmti_parseOptions(options))) 470 return JNI_ERR; 471 472 vm = jvm; 473 474 for (i=0; i<AGENTS; i++) { 475 NSK_DISPLAY1("initializing agent %s ...\n", 476 (i==0)?"A":"B"); 477 if (initAgent(i) != PASSED) 478 return JNI_ERR; 479 } 480 481 return JNI_OK; 482 } 483 484 #ifdef __cplusplus 485 } 486 #endif