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 <string.h> 25 #include "jvmti.h" 26 #include "agent_common.h" 27 #include "jni_tools.h" 28 #include "jvmti_tools.h" 29 30 extern "C" { 31 32 /* ============================================================================= */ 33 34 /* scaffold objects */ 35 static jlong timeout = 0; 36 37 /* constant names */ 38 #define DEBUGEE_CLASS_NAME "nsk/jvmti/ClassFileLoadHook/classfloadhk006" 39 #define TESTED_CLASS_NAME "nsk/jvmti/ClassFileLoadHook/classfloadhk006r" 40 #define TESTED_CLASS_SIG "L" TESTED_CLASS_NAME ";" 41 42 #define BYTECODE_FIELD_SIG "[B" 43 #define REDEF_BYTECODE_FIELD_NAME "redefClassBytes" 44 45 #define TESTED_CLASS_FIELD_NAME "testedClass" 46 #define TESTED_CLASS_FIELD_SIG "Ljava/lang/Class;" 47 48 static jclass testedClass = NULL; 49 50 static jint redefClassSize = 0; 51 static unsigned char* redefClassBytes = NULL; 52 53 static volatile int eventsCount = 0; 54 55 /* ============================================================================= */ 56 57 /** Check (strictly or not) if bytecode has expected size and bytes or complain an error. */ 58 static int checkBytecode(const char kind[], jint size, const unsigned char bytes[], 59 jint expectedSize, const unsigned char expectedBytes[], 60 int strict) { 61 int success = NSK_TRUE; 62 63 NSK_DISPLAY3("Check %s bytecode: 0x%p:%d\n", kind, (void*)bytes, (int)size); 64 if (nsk_getVerboseMode()) { 65 nsk_printHexBytes(" ", 16, size, bytes); 66 } 67 68 if (bytes == NULL) { 69 NSK_COMPLAIN2("Unexpected NULL pointer to %s bytecode in CLASS_FILE_LOAD_HOOK: 0x%p\n", 70 kind, (void*)bytes); 71 return NSK_FALSE; 72 } 73 74 if (size <= 0) { 75 NSK_COMPLAIN2("Unexpected zero size of %s bytecode in CLASS_FILE_LOAD_HOOK: %d\n", 76 kind, (int)size); 77 return NSK_FALSE; 78 } 79 80 if (strict) { 81 if (size != expectedSize) { 82 NSK_COMPLAIN3("Unexpected size of %s bytecode in CLASS_FILE_LOAD_HOOK:\n" 83 "# got size: %d\n" 84 "# expected: %d\n", 85 kind, (int)size, (int)expectedSize); 86 success = NSK_FALSE; 87 } else { 88 jint different = 0; 89 jint i; 90 91 for (i = 0; i < size; i++) { 92 if (bytes[i] != expectedBytes[i]) { 93 different++; 94 } 95 } 96 if (different > 0) { 97 NSK_COMPLAIN2("Unexpected bytes in %s bytecode in CLASS_FILE_LOAD_HOOK:\n" 98 "# different bytes: %d\n" 99 "# total bytes: %d\n", 100 (int)different, (int)size); 101 success = NSK_FALSE; 102 } 103 } 104 105 if (!success) { 106 NSK_COMPLAIN2("Got %s bytecode is not equal to expected bytecode: %d bytes\n", 107 kind, expectedSize); 108 if (nsk_getVerboseMode()) { 109 nsk_printHexBytes(" ", 16, expectedSize, expectedBytes); 110 } 111 } else { 112 NSK_DISPLAY1("All %s bytecode is equal to expected one\n", kind); 113 } 114 } 115 116 return success; 117 } 118 119 /** Get classfile bytecode from a static field of given class. */ 120 static int getBytecode(jvmtiEnv* jvmti, JNIEnv* jni, jclass cls, 121 const char fieldName[], const char fieldSig[], 122 jint* size, unsigned char* *bytes) { 123 124 jfieldID fieldID = NULL; 125 jbyteArray array = NULL; 126 jbyte* elements; 127 int i; 128 129 NSK_DISPLAY1("Find static field: %s\n", fieldName); 130 if (!NSK_JNI_VERIFY(jni, (fieldID = 131 NSK_CPP_STUB4(GetStaticFieldID, jni, cls, fieldName, fieldSig)) != NULL)) { 132 nsk_jvmti_setFailStatus(); 133 return NSK_FALSE; 134 } 135 NSK_DISPLAY1(" ... got fieldID: 0x%p\n", (void*)fieldID); 136 137 NSK_DISPLAY1("Get classfile bytes array from static field: %s\n", fieldName); 138 if (!NSK_JNI_VERIFY(jni, (array = (jbyteArray) 139 NSK_CPP_STUB3(GetStaticObjectField, jni, cls, fieldID)) != NULL)) { 140 nsk_jvmti_setFailStatus(); 141 return NSK_FALSE; 142 } 143 NSK_DISPLAY1(" ... got array object: 0x%p\n", (void*)array); 144 145 if (!NSK_JNI_VERIFY(jni, (*size = 146 NSK_CPP_STUB2(GetArrayLength, jni, array)) > 0)) { 147 nsk_jvmti_setFailStatus(); 148 return NSK_FALSE; 149 } 150 NSK_DISPLAY1(" ... got array size: %d bytes\n", (int)*size); 151 152 { 153 jboolean isCopy; 154 if (!NSK_JNI_VERIFY(jni, (elements = 155 NSK_CPP_STUB3(GetByteArrayElements, jni, array, 156 &isCopy)) != NULL)) { 157 nsk_jvmti_setFailStatus(); 158 return NSK_FALSE; 159 } 160 } 161 NSK_DISPLAY1(" ... got elements list: 0x%p\n", (void*)elements); 162 163 if (!NSK_JVMTI_VERIFY( 164 NSK_CPP_STUB3(Allocate, jvmti, *size, bytes))) { 165 nsk_jvmti_setFailStatus(); 166 return NSK_FALSE; 167 } 168 NSK_DISPLAY1(" ... created bytes array: 0x%p\n", (void*)*bytes); 169 170 for (i = 0; i < *size; i++) { 171 (*bytes)[i] = (unsigned char)elements[i]; 172 } 173 NSK_DISPLAY1(" ... copied bytecode: %d bytes\n", (int)*size); 174 175 NSK_DISPLAY1("Release elements list: 0x%p\n", (void*)elements); 176 NSK_TRACE(NSK_CPP_STUB4(ReleaseByteArrayElements, jni, array, elements, JNI_ABORT)); 177 NSK_DISPLAY0(" ... released\n"); 178 179 return NSK_TRUE; 180 } 181 182 /** Get global reference to object from a static field of given class. */ 183 static jobject getObject(jvmtiEnv* jvmti, JNIEnv* jni, jclass cls, 184 const char fieldName[], const char fieldSig[]) { 185 186 jfieldID fieldID = NULL; 187 jobject obj = NULL; 188 189 NSK_DISPLAY1("Find static field: %s\n", fieldName); 190 if (!NSK_JNI_VERIFY(jni, (fieldID = 191 NSK_CPP_STUB4(GetStaticFieldID, jni, cls, fieldName, fieldSig)) != NULL)) { 192 nsk_jvmti_setFailStatus(); 193 return NULL; 194 } 195 NSK_DISPLAY1(" ... got fieldID: 0x%p\n", (void*)fieldID); 196 197 NSK_DISPLAY1("Get object from static field: %s\n", fieldName); 198 if (!NSK_JNI_VERIFY(jni, (obj = 199 NSK_CPP_STUB3(GetStaticObjectField, jni, cls, fieldID)) != NULL)) { 200 nsk_jvmti_setFailStatus(); 201 return NULL; 202 } 203 NSK_DISPLAY1(" ... got object: 0x%p\n", (void*)obj); 204 205 NSK_DISPLAY1("Make global reference to object: 0x%p\n", obj); 206 if (!NSK_JNI_VERIFY(jni, (obj = 207 NSK_CPP_STUB2(NewGlobalRef, jni, obj)) != NULL)) { 208 nsk_jvmti_setFailStatus(); 209 return NULL; 210 } 211 NSK_DISPLAY1(" ... got global ref: 0x%p\n", (void*)obj); 212 213 return obj; 214 } 215 216 /** Redefine given class with new bytecode. */ 217 static int redefineClass(jvmtiEnv* jvmti, jclass klass, const char className[], 218 jint size, unsigned char bytes[]) { 219 jvmtiClassDefinition classDef; 220 221 classDef.klass = klass; 222 classDef.class_byte_count = size; 223 classDef.class_bytes = bytes; 224 225 NSK_DISPLAY1("Redefine class: %s\n", className); 226 if (!NSK_JVMTI_VERIFY( 227 NSK_CPP_STUB3(RedefineClasses, jvmti, 1, &classDef))) { 228 nsk_jvmti_setFailStatus(); 229 return NSK_FALSE; 230 } 231 NSK_DISPLAY1(" ... redefined with bytecode: %d bytes\n", (int)size); 232 233 return NSK_TRUE; 234 } 235 236 /* ============================================================================= */ 237 238 /** Agent algorithm. */ 239 static void JNICALL 240 agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { 241 NSK_DISPLAY0("Wait for debuggee to load original class\n"); 242 if (!NSK_VERIFY(nsk_jvmti_waitForSync(timeout))) 243 return; 244 245 /* perform testing */ 246 { 247 { 248 jclass debugeeClass = NULL; 249 250 NSK_DISPLAY0(">>> Obtain debuggee class\n"); 251 NSK_DISPLAY1("Find debugee class: %s\n", DEBUGEE_CLASS_NAME); 252 if (!NSK_JNI_VERIFY(jni, (debugeeClass = 253 NSK_CPP_STUB2(FindClass, jni, DEBUGEE_CLASS_NAME)) != NULL)) { 254 nsk_jvmti_setFailStatus(); 255 return; 256 } 257 NSK_DISPLAY1(" ... found class: 0x%p\n", (void*)debugeeClass); 258 259 NSK_DISPLAY0(">>> Obtain tested class object\n"); 260 if (!NSK_VERIFY((testedClass = (jclass) 261 getObject(jvmti, jni, debugeeClass, TESTED_CLASS_FIELD_NAME, 262 TESTED_CLASS_FIELD_SIG)) != NULL)) 263 return; 264 265 NSK_DISPLAY0(">>> Obtain redefined bytecode of tested class\n"); 266 if (!NSK_VERIFY(getBytecode(jvmti, jni, debugeeClass, 267 REDEF_BYTECODE_FIELD_NAME, 268 BYTECODE_FIELD_SIG, 269 &redefClassSize, &redefClassBytes))) 270 return; 271 } 272 273 NSK_DISPLAY0(">>> Redefine tested class\n"); 274 { 275 if (!NSK_VERIFY(redefineClass(jvmti, testedClass, TESTED_CLASS_NAME, 276 redefClassSize, redefClassBytes))) 277 return; 278 } 279 280 NSK_DISPLAY0(">>> Testcase #1: Redefine class and check CLASS_FILE_LOAD_HOOK event\n"); 281 { 282 jvmtiEvent event = JVMTI_EVENT_CLASS_FILE_LOAD_HOOK; 283 284 NSK_DISPLAY1("Enable event: %s\n", "CLASS_FILE_LOAD_HOOK"); 285 if (!NSK_VERIFY(nsk_jvmti_enableEvents(JVMTI_ENABLE, 1, &event, NULL))) 286 return; 287 NSK_DISPLAY0(" ... event enabled\n"); 288 289 NSK_VERIFY(redefineClass(jvmti, testedClass, TESTED_CLASS_NAME, 290 redefClassSize, redefClassBytes)); 291 292 NSK_DISPLAY1("Disable event: %s\n", "CLASS_FILE_LOAD_HOOK"); 293 if (NSK_VERIFY(nsk_jvmti_enableEvents(JVMTI_DISABLE, 1, &event, NULL))) { 294 NSK_DISPLAY0(" ... event disabled\n"); 295 } 296 297 NSK_DISPLAY1("Check if event was received: %s\n", "CLASS_FILE_LOAD_HOOK"); 298 if (eventsCount != 1) { 299 NSK_COMPLAIN3("Unexpected number of %s events received for tested class:\n" 300 "# received: %d events\n" 301 "# expected: %d events\n", 302 "CLASS_FILE_LOAD_HOOK", eventsCount, 1); 303 nsk_jvmti_setFailStatus(); 304 } else { 305 NSK_DISPLAY1(" ... received: %d events\n", eventsCount); 306 } 307 } 308 309 NSK_DISPLAY0(">>> Clean used data\n"); 310 { 311 NSK_DISPLAY1("Delete global reference to tested class object: 0x%p\n", (void*)testedClass); 312 NSK_CPP_STUB2(DeleteGlobalRef, jni, testedClass); 313 314 NSK_DISPLAY1("Deallocate redefined bytecode array: 0x%p\n", (void*)redefClassBytes); 315 if (!NSK_JVMTI_VERIFY( 316 NSK_CPP_STUB2(Deallocate, jvmti, redefClassBytes))) { 317 nsk_jvmti_setFailStatus(); 318 } 319 } 320 } 321 322 NSK_DISPLAY0("Let debugee to finish\n"); 323 if (!NSK_VERIFY(nsk_jvmti_resumeSync())) 324 return; 325 } 326 327 /* ============================================================================= */ 328 329 /** Callback for CLASS_FILE_LOAD_HOOK event **/ 330 static void JNICALL 331 callbackClassFileLoadHook(jvmtiEnv *jvmti, JNIEnv *jni, 332 jclass class_being_redefined, 333 jobject loader, const char* name, jobject protection_domain, 334 jint class_data_len, const unsigned char* class_data, 335 jint *new_class_data_len, unsigned char** new_class_data) { 336 337 NSK_DISPLAY5(" <CLASS_FILE_LOAD_HOOK>: name: %s, loader: 0x%p, redefined: 0x%p, bytecode: 0x%p:%d\n", 338 nsk_null_string(name), (void*)loader, (void*)class_being_redefined, 339 (void*)class_data, (int)class_data_len); 340 341 if (name != NULL && (strcmp(name, TESTED_CLASS_NAME) == 0)) { 342 NSK_DISPLAY1("SUCCESS! CLASS_FILE_LOAD_HOOK for tested class: %s\n", TESTED_CLASS_NAME); 343 eventsCount++; 344 345 NSK_DISPLAY1("Check class_being_redefined: 0x%p\n", (void*)class_being_redefined); 346 if (class_being_redefined == NULL) { 347 NSK_COMPLAIN1("Unexpected NULL class_being_redefined in CLASS_FILE_LOAD_HOOK: 0x%p\n", 348 (void*)class_being_redefined); 349 nsk_jvmti_setFailStatus(); 350 } else if (!NSK_CPP_STUB3(IsSameObject, jni, class_being_redefined, testedClass)) { 351 NSK_COMPLAIN2("Unexpected class_being_redefined in CLASS_FILE_LOAD_HOOK:\n" 352 "# got class: 0x%p\n" 353 "# expected same as: 0x%p\n", 354 (void*)class_being_redefined, (void*)testedClass); 355 nsk_jvmti_setFailStatus(); 356 } 357 358 if (!checkBytecode("redefined", class_data_len, class_data, 359 redefClassSize, redefClassBytes, NSK_TRUE)) { 360 nsk_jvmti_setFailStatus(); 361 } 362 } 363 } 364 365 /* ============================================================================= */ 366 367 /** Agent library initialization. */ 368 #ifdef STATIC_BUILD 369 JNIEXPORT jint JNICALL Agent_OnLoad_classfloadhk006(JavaVM *jvm, char *options, void *reserved) { 370 return Agent_Initialize(jvm, options, reserved); 371 } 372 JNIEXPORT jint JNICALL Agent_OnAttach_classfloadhk006(JavaVM *jvm, char *options, void *reserved) { 373 return Agent_Initialize(jvm, options, reserved); 374 } 375 JNIEXPORT jint JNI_OnLoad_classfloadhk006(JavaVM *jvm, char *options, void *reserved) { 376 return JNI_VERSION_1_8; 377 } 378 #endif 379 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { 380 jvmtiEnv* jvmti = NULL; 381 382 /* init framework and parse options */ 383 if (!NSK_VERIFY(nsk_jvmti_parseOptions(options))) 384 return JNI_ERR; 385 386 timeout = nsk_jvmti_getWaitTime() * 60 * 1000; 387 388 /* create JVMTI environment */ 389 if (!NSK_VERIFY((jvmti = 390 nsk_jvmti_createJVMTIEnv(jvm, reserved)) != NULL)) 391 return JNI_ERR; 392 393 NSK_DISPLAY1("Add required capabilities: %s\n", "can_generate_eraly_class_hook_events, can_redefine_classes"); 394 { 395 jvmtiCapabilities caps; 396 397 memset(&caps, 0, sizeof(caps)); 398 caps.can_generate_all_class_hook_events = 1; 399 caps.can_redefine_classes = 1; 400 if (!NSK_JVMTI_VERIFY( 401 NSK_CPP_STUB2(AddCapabilities, jvmti, &caps))) { 402 return JNI_ERR; 403 } 404 } 405 NSK_DISPLAY0(" ... added\n"); 406 407 NSK_DISPLAY1("Set callback for event: %s\n", "CLASS_FILE_LOAD_HOOK"); 408 { 409 jvmtiEventCallbacks callbacks; 410 jint size = (jint)sizeof(callbacks); 411 412 memset(&callbacks, 0, sizeof(callbacks)); 413 callbacks.ClassFileLoadHook = callbackClassFileLoadHook; 414 if (!NSK_JVMTI_VERIFY( 415 NSK_CPP_STUB3(SetEventCallbacks, jvmti, &callbacks, size))) { 416 return JNI_ERR; 417 } 418 } 419 NSK_DISPLAY0(" ... set\n"); 420 421 /* register agent proc and arg */ 422 if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agentProc, NULL))) 423 return JNI_ERR; 424 425 return JNI_OK; 426 } 427 428 /* ============================================================================= */ 429 430 }