/* * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ #include #include #include #include #include #include "agent_common.h" #include "nsk_tools.h" #include "JVMTITools.h" #include "jvmti_tools.h" #include "native_thread.h" #ifdef __cplusplus extern "C" { #endif #ifndef JNI_ENV_ARG #ifdef __cplusplus #define JNI_ENV_ARG(x, y) y #define JNI_ENV_PTR(x) x #else #define JNI_ENV_ARG(x, y) x, y #define JNI_ENV_PTR(x) (*x) #endif #endif #ifndef JNI_ENV_ARG1 #ifdef __cplusplus #define JNI_ENV_ARG1(x) #else #define JNI_ENV_ARG1(x) x #endif #endif #define PASSED 0 #define STATUS_FAILED 2 #define TRIES 30 #define AGENTS 2 static JavaVM *vm; static jvmtiEnv *jvmti[AGENTS]; /* JVMTI env of an agent */ static void *agentThr[AGENTS]; static volatile int redir[AGENTS]; /* redirection in an agent done */ static volatile int thrstarted[AGENTS]; /* an agent started */ static volatile int verbose = 0; static volatile jint result = PASSED; /* the original JNI function table */ static jniNativeInterface *orig_jni_functions[AGENTS]; /* the redirected JNI function table */ static jniNativeInterface *redir_jni_functions[AGENTS]; /* number of the redirected JNI function calls */ static volatile int redir_calls[AGENTS]; static void doRedirect(JNIEnv*, jvmtiEnv*, int); static void provokeIntercept(JNIEnv*, const char*); static int checkIntercept(int, int, int); static int initAgent(int); static void startAgent(int); static int agentA(void*); static int agentB(void*); static void JNICALL VMInitA(jvmtiEnv*, JNIEnv*, jthread); static void JNICALL VMInitB(jvmtiEnv*, JNIEnv*, jthread); /** redirected JNI functions **/ /* function redirected inside the agent A */ jint JNICALL MyGetVersionA(JNIEnv *env) { redir_calls[0]++; NSK_DISPLAY1("\nMyGetVersionA: the function called successfully: number of calls=%d\n", redir_calls[0]); return orig_jni_functions[0]->GetVersion( JNI_ENV_ARG1(env)); } /* function redirected inside the agent B */ jint JNICALL MyGetVersionB(JNIEnv *env) { redir_calls[1]++; NSK_DISPLAY1("\nMyGetVersionB: the function called successfully: number of calls=%d\n", redir_calls[1]); return (orig_jni_functions[1])->GetVersion( JNI_ENV_ARG1(env)); } /*****************************/ static void doRedirect(JNIEnv *env, jvmtiEnv *jvmti, int indx) { jvmtiError err; NSK_DISPLAY1("\n%s JVMTI env: doRedirect: obtaining the JNI function table ...\n", (indx==0)?"first":"second"); if ((err = (*jvmti)->GetJNIFunctionTable(jvmti, &orig_jni_functions[indx])) != JVMTI_ERROR_NONE) { result = STATUS_FAILED; NSK_COMPLAIN2("TEST FAILED: %s JVMTI env: failed to get original JNI function table: %s\n", (indx==0)?"first":"second", TranslateError(err)); JNI_ENV_PTR(env)->FatalError(JNI_ENV_ARG(env, "failed to get original JNI function table")); } if ((err = (*jvmti)->GetJNIFunctionTable(jvmti, &redir_jni_functions[indx])) != JVMTI_ERROR_NONE) { result = STATUS_FAILED; NSK_COMPLAIN2("TEST FAILED: %s JVMTI env: failed to get redirected JNI function table: %s\n", (indx==0)?"first":"second", TranslateError(err)); JNI_ENV_PTR(env)->FatalError(JNI_ENV_ARG(env, "failed to get redirected JNI function table")); } NSK_DISPLAY1("%s JVMTI env: doRedirect: the JNI function table obtained successfully\n\ \toverwriting the function GetVersion() ...\n", (indx==0)?"first":"second"); redir_jni_functions[indx]->GetVersion = (indx==0)?MyGetVersionA:MyGetVersionB; if ((err = (*jvmti)->SetJNIFunctionTable(jvmti, redir_jni_functions[indx])) != JVMTI_ERROR_NONE) { result = STATUS_FAILED; NSK_COMPLAIN2("TEST FAILED: %s JVMTI env: failed to set new JNI function table: %s\n", (indx==0)?"first":"second", TranslateError(err)); JNI_ENV_PTR(env)->FatalError(JNI_ENV_ARG(env, "failed to set new JNI function table")); } NSK_DISPLAY1("%s JVMTI env: doRedirect: the functions are overwritten successfully\n", (indx==0)?"first":"second"); } static void provokeIntercept(JNIEnv *env, const char *name) { jint res; res = JNI_ENV_PTR(env)-> GetVersion(JNI_ENV_ARG1(env)); NSK_DISPLAY2("\nGetVersion() called by the agent %s returns %d\n", name, res); } static int checkIntercept(int indx, int env_num, int exCalls) { if (redir_calls[indx] == exCalls) { NSK_DISPLAY5("\nCHECK PASSED: GetVersion() interception set in the %s JVMTI env %s properly:\n\ \t%d interception(s) with the%s%s JVMTI env as expected\n", (indx==0)?"first":"second", (exCalls==0)?"overwritten by another environment":"works", redir_calls[indx], (indx==env_num)?" same ":" ", (env_num==0)?"first":"second"); } else { result = STATUS_FAILED; NSK_COMPLAIN6("\nTEST FAILED: GetVersion() interception set in the %s JVMTI env doesn't %s properly:\n\ \t%d interception(s) with the%s%s JVMTI env instead of %d as expected\n", (indx==0)?"first":"second", (exCalls==0)?"overwritten by another environment":"work", redir_calls[indx], (indx==env_num)?" same ":" ", (env_num==0)?"first":"second", exCalls); return STATUS_FAILED; } return PASSED; } static int initAgent(int indx) { jvmtiEventCallbacks callbacks; /* callback functions */ int exitCode = PASSED; jvmtiError err; jint res; thrstarted[indx] = redir[indx] = redir_calls[indx] = 0; NSK_DISPLAY1("\nagent %s initializer: obtaining the JVMTI env ...\n", (indx==0)?"A":"B"); res = JNI_ENV_PTR(vm)-> GetEnv(JNI_ENV_ARG(vm, (void **) &jvmti[indx]), JVMTI_VERSION_1_1); if (res != JNI_OK || jvmti[indx] == NULL) { NSK_COMPLAIN1("TEST FAILURE: failed to call GetEnv for the agent %s\n", (indx==0)?"A":"B"); result = STATUS_FAILED; return STATUS_FAILED; } NSK_DISPLAY1("\nagent %s initializer: the JVMTI env obtained\n\tsetting event callbacks ...\n", (indx==0)?"A":"B"); (void) memset(&callbacks, 0, sizeof(callbacks)); switch(indx) { case 0: callbacks.VMInit = &VMInitA; break; case 1: callbacks.VMInit = &VMInitB; break; } if ((err = (*jvmti[indx])->SetEventCallbacks(jvmti[indx], &callbacks, sizeof(callbacks))) != JVMTI_ERROR_NONE) { NSK_COMPLAIN1("TEST FAILURE: failed to set event callbacks: %s\n", TranslateError(err)); result = STATUS_FAILED; return STATUS_FAILED; } NSK_DISPLAY1("\nagent %s initializer: setting event callbacks done\n\tenabling events ...\n", (indx==0)?"A":"B"); if ((err = (*jvmti[indx])->SetEventNotificationMode(jvmti[indx], JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, NULL)) != JVMTI_ERROR_NONE) { /* enable event globally */ NSK_COMPLAIN2("TEST FAILURE: failed to enable JVMTI_EVENT_VM_INIT event for the agent %s: %s\n", (indx==0)?"A":"B", TranslateError(err)); result = STATUS_FAILED; return STATUS_FAILED; } NSK_DISPLAY2("\nagent %s initializer: enabling events done, returning exit code %d\n", (indx==0)?"A":"B", exitCode); return exitCode; } static void startAgent(int indx) { int tries = 0; NSK_DISPLAY1("\nstartAgent: starting agent %s thread ...\n", (indx==0)?"A":"B"); agentThr[indx] = THREAD_new((indx==0)?agentA:agentB, (indx==0)?"agent A":"agent B"); if (THREAD_start(agentThr[indx]) == NULL) { NSK_COMPLAIN1("TEST FAILURE: cannot start the agent %s thread\n", (indx==0)?"A":"B"); exit(STATUS_FAILED); } NSK_DISPLAY1("\nstartAgent: waiting for the agent %s to be started ...\n", (indx==0)?"A":"B"); do { THREAD_sleep(1); tries++; if (tries > TRIES) { NSK_COMPLAIN2("TEST FAILURE: the agent %s thread is still not started after %d attempts\n", (indx==0)?"A":"B", TRIES); exit(STATUS_FAILED); } } while(thrstarted[indx] != 1); NSK_DISPLAY1("\nstartAgent: the agent %s thread started\n", (indx==0)?"A":"B"); } /* agent thread procedures */ static int agentA(void *context) { JNIEnv *env; jint res; int tries = 0; int i; int exitCode = PASSED; NSK_DISPLAY0("\nthe agent A started\n\tattaching the thread to the VM ...\n"); if ((res = JNI_ENV_PTR(vm)->AttachCurrentThread( JNI_ENV_ARG(vm, (void **) &env), (void *) 0)) != 0) { NSK_COMPLAIN1("TEST FAILURE: AttachCurrentThread() returns: %d\n", res); exit(STATUS_FAILED); } /* intercept the JNI function table */ /* check the interception set in another JVMTI env */ NSK_DISPLAY0("\n>>> TEST CASE #1) First JVMTI env: checking the redirection set in the same env ...\n\ \nagent A (first JVMTI env): redirecting the function table ...\n"); doRedirect(env, jvmti[0], 0); /* check that the interception has been set properly */ NSK_DISPLAY0("\nagent A (first JVMTI env): checking that the interception has been set properly ...\n"); provokeIntercept(env, "A"); checkIntercept(0, 0, 1); /* expected interceptions: 1 */ NSK_DISPLAY0("\n<<< TEST CASE #1) done\n"); /* the flag set too late in order to make sure that the agent B will be started _after_ the interception */ thrstarted[0] = 1; redir[0] = 1; NSK_DISPLAY0("\nagent A: waiting for the redirection in agent B ...\n"); do { THREAD_sleep(1); tries++; if (tries > TRIES) { NSK_COMPLAIN1("TEST FAILURE: failed to wait for the redirection in agent B after %d attempts\n", TRIES); exit(STATUS_FAILED); } } while(redir[1] != 1); /* check the interception set in another JVMTI env */ NSK_DISPLAY0("\n>>> TEST CASE #4) First JVMTI env: checking the redirection set in second JVMTI env ...\n"); for (i=0; iDetachCurrentThread(JNI_ENV_ARG1(vm))) != 0) { NSK_COMPLAIN1("TEST WARNING: agent A: DetachCurrentThread() returns: %d\n", res); } return exitCode; } static int agentB(void *context) { JNIEnv *env; jint res; int tries = 0; int i; int exitCode = PASSED; NSK_DISPLAY0("\nthe agent B started\n\tattaching the thread to the VM ...\n"); if ((res = JNI_ENV_PTR(vm)->AttachCurrentThread( JNI_ENV_ARG(vm, (void **) &env), (void *) 0)) != 0) { NSK_COMPLAIN1("TEST FAILURE: AttachCurrentThread() returns: %d\n", res); exit(STATUS_FAILED); } thrstarted[1] = 1; NSK_DISPLAY0("\nagent B: waiting for the redirection in agent A ...\n"); do { THREAD_sleep(1); tries++; if (tries > TRIES) { NSK_COMPLAIN1("TEST FAILURE: failed to wait for the redirection in agent A after %d attempts\n", TRIES); exit(STATUS_FAILED); } } while(redir[0] != 1); /* check the interception set in another JVMTI env */ NSK_DISPLAY0("\n>>> TEST CASE #2) Second JVMTI env: checking the redirection set in first JVMTI env ...\n"); for (i=0; i>> TEST CASE #3) Second JVMTI env: checking the redirection set in the same env ...\n\ \nagent B (second JVMTI env): redirecting the function table ...\n"); doRedirect(env, jvmti[1], 1); for (i=0; iDetachCurrentThread(JNI_ENV_ARG1(vm))) != 0) { NSK_COMPLAIN1("TEST WARNING: agent B: DetachCurrentThread() returns: %d\n", res); } return exitCode; } /*********************/ /* callback functions */ void JNICALL VMInitA(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thread) { NSK_DISPLAY0("\nagent A: VMInit event\n"); startAgent(0); } void JNICALL VMInitB(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thread) { NSK_DISPLAY0("\nagent B: VMInit event\n"); startAgent(1); } /*********************/ JNIEXPORT jint JNICALL Java_nsk_jvmti_scenarios_jni_1interception_JI05_ji05t001_getResult(JNIEnv *env, jobject obj) { int i; for (i=0; i