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( 74 NSK_CPP_STUB2( 75 GetPhase 76 , jvmti 77 , &phase 78 ) 79 ) 80 ) 81 exit(NSK_STATUS_FAILED); 82 83 return phase; 84 } 85 86 /* ====================================================================== */ 87 static void doRedirect(jvmtiEnv *jvmti, jvmtiPhase phase) { 88 jvmtiError err; 89 NSK_DISPLAY0("doRedirect: obtaining the JNI function table ...\n"); 90 91 // Store original function table 92 if (!NSK_VERIFY( 93 (err = NSK_CPP_STUB2( 94 GetJNIFunctionTable 95 , jvmti 96 , &orig_jni_functions 97 )) == JVMTI_ERROR_NONE || phase != JVMTI_PHASE_LIVE 98 ) 99 ) 100 { 101 NSK_COMPLAIN2("TEST FAILED: failed to get original JNI function table during %s: %s\n" 102 , TranslatePhase(phase) 103 , TranslateError(err) 104 ); 105 106 result = NSK_STATUS_FAILED; 107 exit(NSK_STATUS_FAILED); 108 } 109 else { 110 NSK_DISPLAY3("CHECK PASSED: the original JNI function table %s during %s phase: %s\n" 111 , (err == JVMTI_ERROR_NONE) ? "has been obtained" : "hasn't been obtained" 112 , TranslatePhase(phase) 113 , TranslateError(err) 114 ); 115 } 116 117 // Get a duplicate of the function table for future modification 118 if (!NSK_VERIFY( 119 (err = NSK_CPP_STUB2( 120 GetJNIFunctionTable 121 , jvmti 122 , &redir_jni_functions 123 )) == JVMTI_ERROR_NONE || phase != JVMTI_PHASE_LIVE 124 ) 125 ) 126 { 127 NSK_COMPLAIN2("TEST FAILED: failed to get JNI function table for interception during %s: %s\n" 128 , TranslatePhase(phase) 129 , TranslateError(err) 130 ); 131 132 result = NSK_STATUS_FAILED; 133 exit(NSK_STATUS_FAILED); 134 } 135 else { 136 NSK_DISPLAY3("CHECK PASSED: the original JNI function table for interception %s during %s phase: %s\n" 137 , (err == JVMTI_ERROR_NONE) ? "has been obtained" : "hasn't been obtained" 138 , TranslatePhase(phase) 139 , TranslateError(err) 140 ); 141 } 142 143 // Redefine desired JNI functions 144 if (phase == JVMTI_PHASE_LIVE) { 145 NSK_DISPLAY0("doRedirect: overwriting the function FindClass; ...\n"); 146 redir_jni_functions->FindClass = MyFindClass; 147 } 148 149 // Set new JNI function table 150 if (!NSK_VERIFY( 151 (err = NSK_CPP_STUB2( 152 SetJNIFunctionTable 153 , jvmti 154 , redir_jni_functions 155 )) == JVMTI_ERROR_NONE || phase != JVMTI_PHASE_LIVE 156 ) 157 ) 158 { 159 NSK_COMPLAIN2("TEST FAILED: failed to set redirected JNI function table during %s: %s\n" 160 , TranslatePhase(phase) 161 , TranslateError(err) 162 ); 163 164 result = NSK_STATUS_FAILED; 165 exit(NSK_STATUS_FAILED); 166 } 167 else { 168 NSK_DISPLAY3("CHECK PASSED: the redirected JNI function table %s during %s phase: %s\n" 169 , (err == JVMTI_ERROR_NONE) ? "has been set" : "hasn't been set" 170 , TranslatePhase(phase) 171 , TranslateError(err) 172 ); 173 } 174 } 175 176 /* ====================================================================== */ 177 static void doRestore(jvmtiEnv *jvmti) { 178 NSK_DISPLAY0("doRestore: restoring the original JNI function table ...\n"); 179 180 // Set new JNI function table 181 if (!NSK_JVMTI_VERIFY( 182 NSK_CPP_STUB2( 183 SetJNIFunctionTable 184 , jvmti 185 , orig_jni_functions 186 ) 187 ) 188 ) 189 { 190 NSK_COMPLAIN0("TEST FAILED: failed to restore original JNI function table\n"); 191 192 result = NSK_STATUS_FAILED; 193 exit(NSK_STATUS_FAILED); 194 } 195 196 NSK_DISPLAY0("doRestore: the original JNI function table is restored successfully\n"); 197 } 198 199 /* ====================================================================== */ 200 static void lock(jvmtiEnv *jvmti) { 201 if (!NSK_JVMTI_VERIFY( 202 NSK_CPP_STUB2( 203 RawMonitorEnter 204 , jvmti 205 , eventLock 206 ) 207 ) 208 ) 209 { 210 result = NSK_STATUS_FAILED; 211 exit(NSK_STATUS_FAILED); 212 } 213 } 214 215 /* ====================================================================== */ 216 static void unlock(jvmtiEnv *jvmti) { 217 if (!NSK_JVMTI_VERIFY( 218 NSK_CPP_STUB2( 219 RawMonitorExit 220 , jvmti 221 , eventLock 222 ) 223 ) 224 ) 225 { 226 result = NSK_STATUS_FAILED; 227 exit(NSK_STATUS_FAILED); 228 } 229 } 230 231 /* ====================================================================== */ 232 static void checkCall(JNIEnv *env 233 , int step 234 , const char *callBackFunc 235 , const char *msg 236 , int exFndCalls 237 ) 238 { 239 jclass cls; 240 241 NSK_TRACE( 242 (cls = NSK_CPP_STUB2( 243 FindClass 244 , env 245 , classSig 246 )) 247 ); 248 249 NSK_TRACE( 250 NSK_CPP_STUB1(ExceptionClear, env) 251 ); 252 253 // The check should pass if the actual number of invocations is not less that the expected number (fnd_calls >= exFndCalls). 254 // If the invocation is not expected (exFndCalls == 0), fnd_calls should be also == 0. 255 if ((exFndCalls > 0 && fnd_calls >= exFndCalls) || (fnd_calls == exFndCalls)) { 256 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" 257 , callBackFunc 258 , (step==1) ? "tested" : "original" 259 , (step==1) ? "redirected" : "restored" 260 , msg 261 , fnd_calls 262 ); 263 264 if (fnd_calls != exFndCalls) { 265 NSK_COMPLAIN2("WARNING: the number of occured calls (%d) exceeds the expected number of calls (%d).\n" 266 , fnd_calls 267 , exFndCalls 268 ); 269 } 270 } else { 271 result = NSK_STATUS_FAILED; 272 273 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" 274 , callBackFunc 275 , (step==1) ? "tested" : "original" 276 , (step==1) ? "redirected" : "restored" 277 , msg 278 , fnd_calls 279 , exFndCalls 280 ); 281 } 282 } 283 284 /* ====================================================================== */ 285 // callback functions 286 void JNICALL 287 VMInit(jvmtiEnv *jvmti, JNIEnv *env, jthread thread) { 288 jvmtiPhase phase = getVMPhase(jvmti); 289 290 NSK_TRACE(lock(jvmti)); 291 292 NSK_DISPLAY1("b) VMInit: the current phase of VM execution %s\n" 293 , TranslatePhase(phase) 294 ); 295 296 // check JNI function table interception 297 fnd_calls = 0; 298 NSK_TRACE(doRedirect(jvmti, phase)); 299 NSK_TRACE(checkCall(env, 1, "VMInit", TranslatePhase(phase), 1)); 300 301 // check restored JNI function table 302 fnd_calls = 0; 303 NSK_TRACE(doRestore(jvmti)); 304 NSK_TRACE(checkCall(env, 2, "VMInit", TranslatePhase(phase), 0)); 305 306 NSK_TRACE(unlock(jvmti)); 307 } 308 309 /* ====================================================================== */ 310 void JNICALL 311 VMDeath(jvmtiEnv *jvmti, JNIEnv *env) { 312 jvmtiPhase phase = getVMPhase(jvmti); 313 314 NSK_TRACE(lock(jvmti)); 315 316 NSK_DISPLAY1("c) VMDeath: the current phase of VM execution %s\n" 317 , TranslatePhase(phase) 318 ); 319 320 // check JNI function table interception 321 fnd_calls = 0; 322 NSK_TRACE(doRedirect(jvmti, phase)); 323 NSK_TRACE(checkCall(env, 1, "VMDeath", TranslatePhase(phase), 1)); 324 325 // check restored JNI function table 326 fnd_calls = 0; 327 NSK_TRACE(doRestore(jvmti)); 328 NSK_TRACE(checkCall(env, 2, "VMDeath", TranslatePhase(phase), 0)); 329 330 (void) memset(&callbacks, 0, sizeof(callbacks)); 331 332 if (!NSK_JVMTI_VERIFY( 333 NSK_CPP_STUB3( 334 SetEventCallbacks 335 , jvmti 336 , &callbacks 337 , sizeof(callbacks) 338 ) 339 ) 340 ) 341 result = NSK_STATUS_FAILED; 342 343 NSK_TRACE(unlock(jvmti)); 344 345 if (result == NSK_STATUS_FAILED) { 346 exit(NSK_STATUS_FAILED); 347 } 348 } 349 350 /* ====================================================================== */ 351 JNIEXPORT jint JNICALL 352 Java_nsk_jvmti_scenarios_jni_1interception_JI01_ji01t001_check(JNIEnv *env, jobject obj) { 353 return result; 354 } 355 356 /* ====================================================================== */ 357 #ifdef STATIC_BUILD 358 JNIEXPORT jint JNICALL Agent_OnLoad_ji01t001(JavaVM *jvm, char *options, void *reserved) { 359 return Agent_Initialize(jvm, options, reserved); 360 } 361 JNIEXPORT jint JNICALL Agent_OnAttach_ji01t001(JavaVM *jvm, char *options, void *reserved) { 362 return Agent_Initialize(jvm, options, reserved); 363 } 364 JNIEXPORT jint JNI_OnLoad_ji01t001(JavaVM *jvm, char *options, void *reserved) { 365 return JNI_VERSION_1_8; 366 } 367 #endif 368 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { 369 if (!NSK_VERIFY( 370 nsk_jvmti_parseOptions(options) 371 ) 372 ) 373 return JNI_ERR; 374 375 376 if (!NSK_VERIFY( 377 NSK_CPP_STUB3( 378 GetEnv 379 , jvm 380 , (void **) &jvmti 381 , JVMTI_VERSION_1_1 382 ) == JNI_OK 383 && jvmti != NULL 384 ) 385 ) 386 return JNI_ERR; 387 388 389 if (!NSK_JVMTI_VERIFY( 390 NSK_CPP_STUB3( 391 CreateRawMonitor 392 , jvmti 393 , "_event_lock" 394 , &eventLock 395 ) 396 ) 397 ) 398 return JNI_ERR; 399 400 NSK_DISPLAY1("a) Trying to intercept JNI functions during %s phase ...\n" 401 , TranslatePhase(getVMPhase(jvmti)) 402 ); 403 404 NSK_TRACE(doRedirect(jvmti, getVMPhase(jvmti))); 405 406 NSK_DISPLAY0("Setting event callbacks...\n"); 407 408 (void) memset(&callbacks, 0, sizeof(callbacks)); 409 callbacks.VMInit = &VMInit; 410 callbacks.VMDeath = &VMDeath; 411 412 if (!NSK_JVMTI_VERIFY( 413 NSK_CPP_STUB3( 414 SetEventCallbacks 415 , jvmti 416 , &callbacks 417 , sizeof(callbacks) 418 ) 419 ) 420 ) 421 return JNI_ERR; 422 423 424 NSK_DISPLAY0("Event callbacks are set\nEnabling events...\n"); 425 426 if (!NSK_JVMTI_VERIFY( 427 NSK_CPP_STUB4( 428 SetEventNotificationMode 429 , jvmti 430 , JVMTI_ENABLE 431 , JVMTI_EVENT_VM_INIT 432 , NULL 433 ) 434 ) 435 ) 436 return JNI_ERR; 437 438 439 if (!NSK_JVMTI_VERIFY( 440 NSK_CPP_STUB4( 441 SetEventNotificationMode 442 , jvmti 443 , JVMTI_ENABLE 444 , JVMTI_EVENT_VM_DEATH 445 , NULL 446 ) 447 ) 448 ) 449 return JNI_ERR; 450 451 NSK_DISPLAY0("Events are enabled\n"); 452 453 return JNI_OK; 454 } 455 456 }