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 "JVMTITools.h" 33 #include "jvmti_tools.h" 34 #include "nsk_tools.h" 35 36 extern "C" { 37 38 /* ====================================================================== */ 39 40 static const char *classSig = 41 "Lnsk/jvmti/scenarios/jni_interception/JI01/ji01t001;"; 42 43 static jvmtiEnv *jvmti = NULL; 44 static jrawMonitorID eventLock; 45 static jvmtiEventCallbacks callbacks; 46 static jint result = NSK_STATUS_PASSED; 47 48 /* the original JNI function table */ 49 static jniNativeInterface *orig_jni_functions = NULL; 50 51 /* the redirected JNI function table */ 52 static jniNativeInterface *redir_jni_functions = NULL; 53 54 /* number of the redirected JNI function calls */ 55 static volatile int fnd_calls = 0; 56 57 /* ====================================================================== */ 58 /** redirected JNI functions **/ 59 jclass JNICALL MyFindClass(JNIEnv *env, const char *name) { 60 if (isThreadExpected(jvmti, NULL)) { 61 fnd_calls++; 62 63 NSK_DISPLAY1("MyFindClass: the function was called successfully: number of calls so far = %d\n", fnd_calls); 64 } 65 66 return orig_jni_functions->FindClass(env, name); 67 } 68 69 /* ====================================================================== */ 70 static jvmtiPhase getVMPhase(jvmtiEnv *jvmti) { 71 jvmtiPhase phase; 72 73 if (!NSK_JVMTI_VERIFY(jvmti->GetPhase(&phase))) 74 exit(NSK_STATUS_FAILED); 75 76 return phase; 77 } 78 79 /* ====================================================================== */ 80 static void doRedirect(jvmtiEnv *jvmti, jvmtiPhase phase) { 81 jvmtiError err; 82 NSK_DISPLAY0("doRedirect: obtaining the JNI function table ...\n"); 83 84 // Store original function table 85 err = jvmti->GetJNIFunctionTable(&orig_jni_functions); 86 if (!NSK_VERIFY((err == JVMTI_ERROR_NONE || phase != JVMTI_PHASE_LIVE))) 87 { 88 NSK_COMPLAIN2("TEST FAILED: failed to get original JNI function table during %s: %s\n" 89 , TranslatePhase(phase) 90 , TranslateError(err) 91 ); 92 93 result = NSK_STATUS_FAILED; 94 exit(NSK_STATUS_FAILED); 95 } 96 else { 97 NSK_DISPLAY3("CHECK PASSED: the original JNI function table %s during %s phase: %s\n" 98 , (err == JVMTI_ERROR_NONE) ? "has been obtained" : "hasn't been obtained" 99 , TranslatePhase(phase) 100 , TranslateError(err) 101 ); 102 } 103 104 // Get a duplicate of the function table for future modification 105 if (!NSK_VERIFY( 106 (err = jvmti->GetJNIFunctionTable(&redir_jni_functions)) == JVMTI_ERROR_NONE || phase != JVMTI_PHASE_LIVE)) 107 { 108 NSK_COMPLAIN2("TEST FAILED: failed to get JNI function table for interception during %s: %s\n" 109 , TranslatePhase(phase) 110 , TranslateError(err) 111 ); 112 113 result = NSK_STATUS_FAILED; 114 exit(NSK_STATUS_FAILED); 115 } 116 else { 117 NSK_DISPLAY3("CHECK PASSED: the original JNI function table for interception %s during %s phase: %s\n" 118 , (err == JVMTI_ERROR_NONE) ? "has been obtained" : "hasn't been obtained" 119 , TranslatePhase(phase) 120 , TranslateError(err) 121 ); 122 } 123 124 // Redefine desired JNI functions 125 if (phase == JVMTI_PHASE_LIVE) { 126 NSK_DISPLAY0("doRedirect: overwriting the function FindClass; ...\n"); 127 redir_jni_functions->FindClass = MyFindClass; 128 } 129 130 // Set new JNI function table 131 if (!NSK_VERIFY( 132 (err = jvmti->SetJNIFunctionTable(redir_jni_functions)) == JVMTI_ERROR_NONE || phase != JVMTI_PHASE_LIVE)) 133 { 134 NSK_COMPLAIN2("TEST FAILED: failed to set redirected JNI function table during %s: %s\n" 135 , TranslatePhase(phase) 136 , TranslateError(err) 137 ); 138 139 result = NSK_STATUS_FAILED; 140 exit(NSK_STATUS_FAILED); 141 } 142 else { 143 NSK_DISPLAY3("CHECK PASSED: the redirected JNI function table %s during %s phase: %s\n" 144 , (err == JVMTI_ERROR_NONE) ? "has been set" : "hasn't been set" 145 , TranslatePhase(phase) 146 , TranslateError(err) 147 ); 148 } 149 } 150 151 /* ====================================================================== */ 152 static void doRestore(jvmtiEnv *jvmti) { 153 NSK_DISPLAY0("doRestore: restoring the original JNI function table ...\n"); 154 155 // Set new JNI function table 156 if (!NSK_JVMTI_VERIFY(jvmti->SetJNIFunctionTable(orig_jni_functions))) 157 { 158 NSK_COMPLAIN0("TEST FAILED: failed to restore original JNI function table\n"); 159 160 result = NSK_STATUS_FAILED; 161 exit(NSK_STATUS_FAILED); 162 } 163 164 NSK_DISPLAY0("doRestore: the original JNI function table is restored successfully\n"); 165 } 166 167 /* ====================================================================== */ 168 static void lock(jvmtiEnv *jvmti) { 169 if (!NSK_JVMTI_VERIFY(jvmti->RawMonitorEnter(eventLock))) 170 { 171 result = NSK_STATUS_FAILED; 172 exit(NSK_STATUS_FAILED); 173 } 174 } 175 176 /* ====================================================================== */ 177 static void unlock(jvmtiEnv *jvmti) { 178 if (!NSK_JVMTI_VERIFY(jvmti->RawMonitorExit(eventLock))) 179 { 180 result = NSK_STATUS_FAILED; 181 exit(NSK_STATUS_FAILED); 182 } 183 } 184 185 /* ====================================================================== */ 186 static void checkCall(JNIEnv *env 187 , int step 188 , const char *callBackFunc 189 , const char *msg 190 , int exFndCalls 191 ) 192 { 193 jclass cls; 194 195 NSK_TRACE( 196 (cls = env->FindClass(classSig)) 197 ); 198 199 NSK_TRACE( 200 env->ExceptionClear() 201 ); 202 203 // The check should pass if the actual number of invocations is not less that the expected number (fnd_calls >= exFndCalls). 204 // If the invocation is not expected (exFndCalls == 0), fnd_calls should be also == 0. 205 if ((exFndCalls > 0 && fnd_calls >= exFndCalls) || (fnd_calls == exFndCalls)) { 206 NSK_DISPLAY5("CHECK PASSED: %s: the %s JNI function FindClass() has been %s during %s phase\n\t%d intercepted call(s) as expected\n" 207 , callBackFunc 208 , (step==1) ? "tested" : "original" 209 , (step==1) ? "redirected" : "restored" 210 , msg 211 , fnd_calls 212 ); 213 214 if (fnd_calls != exFndCalls) { 215 NSK_COMPLAIN2("WARNING: the number of occured calls (%d) exceeds the expected number of calls (%d).\n" 216 , fnd_calls 217 , exFndCalls 218 ); 219 } 220 } else { 221 result = NSK_STATUS_FAILED; 222 223 NSK_COMPLAIN6("TEST FAILED: %s: the %s JNI function FindClass() has not been %s during %s phase\n\t%d intercepted call(s) instead of %d as expected\n" 224 , callBackFunc 225 , (step==1) ? "tested" : "original" 226 , (step==1) ? "redirected" : "restored" 227 , msg 228 , fnd_calls 229 , exFndCalls 230 ); 231 } 232 } 233 234 /* ====================================================================== */ 235 // callback functions 236 void JNICALL 237 VMInit(jvmtiEnv *jvmti, JNIEnv *env, jthread thread) { 238 jvmtiPhase phase = getVMPhase(jvmti); 239 240 NSK_TRACE(lock(jvmti)); 241 242 NSK_DISPLAY1("b) VMInit: the current phase of VM execution %s\n" 243 , TranslatePhase(phase) 244 ); 245 246 // check JNI function table interception 247 fnd_calls = 0; 248 NSK_TRACE(doRedirect(jvmti, phase)); 249 NSK_TRACE(checkCall(env, 1, "VMInit", TranslatePhase(phase), 1)); 250 251 // check restored JNI function table 252 fnd_calls = 0; 253 NSK_TRACE(doRestore(jvmti)); 254 NSK_TRACE(checkCall(env, 2, "VMInit", TranslatePhase(phase), 0)); 255 256 NSK_TRACE(unlock(jvmti)); 257 } 258 259 /* ====================================================================== */ 260 void JNICALL 261 VMDeath(jvmtiEnv *jvmti, JNIEnv *env) { 262 jvmtiPhase phase = getVMPhase(jvmti); 263 264 NSK_TRACE(lock(jvmti)); 265 266 NSK_DISPLAY1("c) VMDeath: the current phase of VM execution %s\n" 267 , TranslatePhase(phase) 268 ); 269 270 // check JNI function table interception 271 fnd_calls = 0; 272 NSK_TRACE(doRedirect(jvmti, phase)); 273 NSK_TRACE(checkCall(env, 1, "VMDeath", TranslatePhase(phase), 1)); 274 275 // check restored JNI function table 276 fnd_calls = 0; 277 NSK_TRACE(doRestore(jvmti)); 278 NSK_TRACE(checkCall(env, 2, "VMDeath", TranslatePhase(phase), 0)); 279 280 (void) memset(&callbacks, 0, sizeof(callbacks)); 281 282 if (!NSK_JVMTI_VERIFY(jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks)))) 283 result = NSK_STATUS_FAILED; 284 285 NSK_TRACE(unlock(jvmti)); 286 287 if (result == NSK_STATUS_FAILED) { 288 exit(NSK_STATUS_FAILED); 289 } 290 } 291 292 /* ====================================================================== */ 293 JNIEXPORT jint JNICALL 294 Java_nsk_jvmti_scenarios_jni_1interception_JI01_ji01t001_check(JNIEnv *env, jobject obj) { 295 return result; 296 } 297 298 /* ====================================================================== */ 299 #ifdef STATIC_BUILD 300 JNIEXPORT jint JNICALL Agent_OnLoad_ji01t001(JavaVM *jvm, char *options, void *reserved) { 301 return Agent_Initialize(jvm, options, reserved); 302 } 303 JNIEXPORT jint JNICALL Agent_OnAttach_ji01t001(JavaVM *jvm, char *options, void *reserved) { 304 return Agent_Initialize(jvm, options, reserved); 305 } 306 JNIEXPORT jint JNI_OnLoad_ji01t001(JavaVM *jvm, char *options, void *reserved) { 307 return JNI_VERSION_1_8; 308 } 309 #endif 310 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { 311 if (!NSK_VERIFY( 312 nsk_jvmti_parseOptions(options) 313 ) 314 ) 315 return JNI_ERR; 316 317 318 if (!NSK_VERIFY(jvm->GetEnv((void **) &jvmti, JVMTI_VERSION_1_1) == JNI_OK && jvmti != NULL)) 319 return JNI_ERR; 320 321 322 if (!NSK_JVMTI_VERIFY(jvmti->CreateRawMonitor("_event_lock", &eventLock))) 323 return JNI_ERR; 324 325 NSK_DISPLAY1("a) Trying to intercept JNI functions during %s phase ...\n" 326 , TranslatePhase(getVMPhase(jvmti)) 327 ); 328 329 NSK_TRACE(doRedirect(jvmti, getVMPhase(jvmti))); 330 331 NSK_DISPLAY0("Setting event callbacks...\n"); 332 333 (void) memset(&callbacks, 0, sizeof(callbacks)); 334 callbacks.VMInit = &VMInit; 335 callbacks.VMDeath = &VMDeath; 336 337 if (!NSK_JVMTI_VERIFY(jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks)))) 338 return JNI_ERR; 339 340 341 NSK_DISPLAY0("Event callbacks are set\nEnabling events...\n"); 342 343 if (!NSK_JVMTI_VERIFY(jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, NULL))) 344 return JNI_ERR; 345 346 347 if (!NSK_JVMTI_VERIFY(jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_VM_DEATH, NULL))) 348 return JNI_ERR; 349 350 NSK_DISPLAY0("Events are enabled\n"); 351 352 return JNI_OK; 353 } 354 355 }