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 jni->GetStaticFieldID(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 jni->GetStaticObjectField(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 = jni->GetArrayLength(array)) > 0)) { 146 nsk_jvmti_setFailStatus(); 147 return NSK_FALSE; 148 } 149 NSK_DISPLAY1(" ... got array size: %d bytes\n", (int)*size); 150 151 { 152 jboolean isCopy; 153 if (!NSK_JNI_VERIFY(jni, (elements = jni->GetByteArrayElements(array, &isCopy)) != NULL)) { 154 nsk_jvmti_setFailStatus(); 155 return NSK_FALSE; 156 } 157 } 158 NSK_DISPLAY1(" ... got elements list: 0x%p\n", (void*)elements); 159 160 if (!NSK_JVMTI_VERIFY(jvmti->Allocate(*size, bytes))) { 161 nsk_jvmti_setFailStatus(); 162 return NSK_FALSE; 163 } 164 NSK_DISPLAY1(" ... created bytes array: 0x%p\n", (void*)*bytes); 165 166 for (i = 0; i < *size; i++) { 167 (*bytes)[i] = (unsigned char)elements[i]; 168 } 169 NSK_DISPLAY1(" ... copied bytecode: %d bytes\n", (int)*size); 170 171 NSK_DISPLAY1("Release elements list: 0x%p\n", (void*)elements); 172 NSK_TRACE(jni->ReleaseByteArrayElements(array, elements, JNI_ABORT)); 173 NSK_DISPLAY0(" ... released\n"); 174 175 return NSK_TRUE; 176 } 177 178 /** Get global reference to object from a static field of given class. */ 179 static jobject getObject(jvmtiEnv* jvmti, JNIEnv* jni, jclass cls, 180 const char fieldName[], const char fieldSig[]) { 181 182 jfieldID fieldID = NULL; 183 jobject obj = NULL; 184 185 NSK_DISPLAY1("Find static field: %s\n", fieldName); 186 if (!NSK_JNI_VERIFY(jni, (fieldID = 187 jni->GetStaticFieldID(cls, fieldName, fieldSig)) != NULL)) { 188 nsk_jvmti_setFailStatus(); 189 return NULL; 190 } 191 NSK_DISPLAY1(" ... got fieldID: 0x%p\n", (void*)fieldID); 192 193 NSK_DISPLAY1("Get object from static field: %s\n", fieldName); 194 if (!NSK_JNI_VERIFY(jni, (obj = jni->GetStaticObjectField(cls, fieldID)) != NULL)) { 195 nsk_jvmti_setFailStatus(); 196 return NULL; 197 } 198 NSK_DISPLAY1(" ... got object: 0x%p\n", (void*)obj); 199 200 NSK_DISPLAY1("Make global reference to object: 0x%p\n", obj); 201 if (!NSK_JNI_VERIFY(jni, (obj = jni->NewGlobalRef(obj)) != NULL)) { 202 nsk_jvmti_setFailStatus(); 203 return NULL; 204 } 205 NSK_DISPLAY1(" ... got global ref: 0x%p\n", (void*)obj); 206 207 return obj; 208 } 209 210 /** Redefine given class with new bytecode. */ 211 static int redefineClass(jvmtiEnv* jvmti, jclass klass, const char className[], 212 jint size, unsigned char bytes[]) { 213 jvmtiClassDefinition classDef; 214 215 classDef.klass = klass; 216 classDef.class_byte_count = size; 217 classDef.class_bytes = bytes; 218 219 NSK_DISPLAY1("Redefine class: %s\n", className); 220 if (!NSK_JVMTI_VERIFY(jvmti->RedefineClasses(1, &classDef))) { 221 nsk_jvmti_setFailStatus(); 222 return NSK_FALSE; 223 } 224 NSK_DISPLAY1(" ... redefined with bytecode: %d bytes\n", (int)size); 225 226 return NSK_TRUE; 227 } 228 229 /* ============================================================================= */ 230 231 /** Agent algorithm. */ 232 static void JNICALL 233 agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { 234 NSK_DISPLAY0("Wait for debuggee to load original class\n"); 235 if (!NSK_VERIFY(nsk_jvmti_waitForSync(timeout))) 236 return; 237 238 /* perform testing */ 239 { 240 { 241 jclass debugeeClass = NULL; 242 243 NSK_DISPLAY0(">>> Obtain debuggee class\n"); 244 NSK_DISPLAY1("Find debugee class: %s\n", DEBUGEE_CLASS_NAME); 245 if (!NSK_JNI_VERIFY(jni, (debugeeClass = 246 jni->FindClass(DEBUGEE_CLASS_NAME)) != NULL)) { 247 nsk_jvmti_setFailStatus(); 248 return; 249 } 250 NSK_DISPLAY1(" ... found class: 0x%p\n", (void*)debugeeClass); 251 252 NSK_DISPLAY0(">>> Obtain tested class object\n"); 253 if (!NSK_VERIFY((testedClass = (jclass) 254 getObject(jvmti, jni, debugeeClass, TESTED_CLASS_FIELD_NAME, 255 TESTED_CLASS_FIELD_SIG)) != NULL)) 256 return; 257 258 NSK_DISPLAY0(">>> Obtain redefined bytecode of tested class\n"); 259 if (!NSK_VERIFY(getBytecode(jvmti, jni, debugeeClass, 260 REDEF_BYTECODE_FIELD_NAME, 261 BYTECODE_FIELD_SIG, 262 &redefClassSize, &redefClassBytes))) 263 return; 264 } 265 266 NSK_DISPLAY0(">>> Redefine tested class\n"); 267 { 268 if (!NSK_VERIFY(redefineClass(jvmti, testedClass, TESTED_CLASS_NAME, 269 redefClassSize, redefClassBytes))) 270 return; 271 } 272 273 NSK_DISPLAY0(">>> Testcase #1: Redefine class and check CLASS_FILE_LOAD_HOOK event\n"); 274 { 275 jvmtiEvent event = JVMTI_EVENT_CLASS_FILE_LOAD_HOOK; 276 277 NSK_DISPLAY1("Enable event: %s\n", "CLASS_FILE_LOAD_HOOK"); 278 if (!NSK_VERIFY(nsk_jvmti_enableEvents(JVMTI_ENABLE, 1, &event, NULL))) 279 return; 280 NSK_DISPLAY0(" ... event enabled\n"); 281 282 NSK_VERIFY(redefineClass(jvmti, testedClass, TESTED_CLASS_NAME, 283 redefClassSize, redefClassBytes)); 284 285 NSK_DISPLAY1("Disable event: %s\n", "CLASS_FILE_LOAD_HOOK"); 286 if (NSK_VERIFY(nsk_jvmti_enableEvents(JVMTI_DISABLE, 1, &event, NULL))) { 287 NSK_DISPLAY0(" ... event disabled\n"); 288 } 289 290 NSK_DISPLAY1("Check if event was received: %s\n", "CLASS_FILE_LOAD_HOOK"); 291 if (eventsCount != 1) { 292 NSK_COMPLAIN3("Unexpected number of %s events received for tested class:\n" 293 "# received: %d events\n" 294 "# expected: %d events\n", 295 "CLASS_FILE_LOAD_HOOK", eventsCount, 1); 296 nsk_jvmti_setFailStatus(); 297 } else { 298 NSK_DISPLAY1(" ... received: %d events\n", eventsCount); 299 } 300 } 301 302 NSK_DISPLAY0(">>> Clean used data\n"); 303 { 304 NSK_DISPLAY1("Delete global reference to tested class object: 0x%p\n", (void*)testedClass); 305 jni->DeleteGlobalRef(testedClass); 306 307 NSK_DISPLAY1("Deallocate redefined bytecode array: 0x%p\n", (void*)redefClassBytes); 308 if (!NSK_JVMTI_VERIFY(jvmti->Deallocate(redefClassBytes))) { 309 nsk_jvmti_setFailStatus(); 310 } 311 } 312 } 313 314 NSK_DISPLAY0("Let debugee to finish\n"); 315 if (!NSK_VERIFY(nsk_jvmti_resumeSync())) 316 return; 317 } 318 319 /* ============================================================================= */ 320 321 /** Callback for CLASS_FILE_LOAD_HOOK event **/ 322 static void JNICALL 323 callbackClassFileLoadHook(jvmtiEnv *jvmti, JNIEnv *jni, 324 jclass class_being_redefined, 325 jobject loader, const char* name, jobject protection_domain, 326 jint class_data_len, const unsigned char* class_data, 327 jint *new_class_data_len, unsigned char** new_class_data) { 328 329 NSK_DISPLAY5(" <CLASS_FILE_LOAD_HOOK>: name: %s, loader: 0x%p, redefined: 0x%p, bytecode: 0x%p:%d\n", 330 nsk_null_string(name), (void*)loader, (void*)class_being_redefined, 331 (void*)class_data, (int)class_data_len); 332 333 if (name != NULL && (strcmp(name, TESTED_CLASS_NAME) == 0)) { 334 NSK_DISPLAY1("SUCCESS! CLASS_FILE_LOAD_HOOK for tested class: %s\n", TESTED_CLASS_NAME); 335 eventsCount++; 336 337 NSK_DISPLAY1("Check class_being_redefined: 0x%p\n", (void*)class_being_redefined); 338 if (class_being_redefined == NULL) { 339 NSK_COMPLAIN1("Unexpected NULL class_being_redefined in CLASS_FILE_LOAD_HOOK: 0x%p\n", 340 (void*)class_being_redefined); 341 nsk_jvmti_setFailStatus(); 342 } else if (!jni->IsSameObject(class_being_redefined, testedClass)) { 343 NSK_COMPLAIN2("Unexpected class_being_redefined in CLASS_FILE_LOAD_HOOK:\n" 344 "# got class: 0x%p\n" 345 "# expected same as: 0x%p\n", 346 (void*)class_being_redefined, (void*)testedClass); 347 nsk_jvmti_setFailStatus(); 348 } 349 350 if (!checkBytecode("redefined", class_data_len, class_data, 351 redefClassSize, redefClassBytes, NSK_TRUE)) { 352 nsk_jvmti_setFailStatus(); 353 } 354 } 355 } 356 357 /* ============================================================================= */ 358 359 /** Agent library initialization. */ 360 #ifdef STATIC_BUILD 361 JNIEXPORT jint JNICALL Agent_OnLoad_classfloadhk006(JavaVM *jvm, char *options, void *reserved) { 362 return Agent_Initialize(jvm, options, reserved); 363 } 364 JNIEXPORT jint JNICALL Agent_OnAttach_classfloadhk006(JavaVM *jvm, char *options, void *reserved) { 365 return Agent_Initialize(jvm, options, reserved); 366 } 367 JNIEXPORT jint JNI_OnLoad_classfloadhk006(JavaVM *jvm, char *options, void *reserved) { 368 return JNI_VERSION_1_8; 369 } 370 #endif 371 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { 372 jvmtiEnv* jvmti = NULL; 373 374 /* init framework and parse options */ 375 if (!NSK_VERIFY(nsk_jvmti_parseOptions(options))) 376 return JNI_ERR; 377 378 timeout = nsk_jvmti_getWaitTime() * 60 * 1000; 379 380 /* create JVMTI environment */ 381 if (!NSK_VERIFY((jvmti = 382 nsk_jvmti_createJVMTIEnv(jvm, reserved)) != NULL)) 383 return JNI_ERR; 384 385 NSK_DISPLAY1("Add required capabilities: %s\n", "can_generate_eraly_class_hook_events, can_redefine_classes"); 386 { 387 jvmtiCapabilities caps; 388 389 memset(&caps, 0, sizeof(caps)); 390 caps.can_generate_all_class_hook_events = 1; 391 caps.can_redefine_classes = 1; 392 if (!NSK_JVMTI_VERIFY(jvmti->AddCapabilities(&caps))) { 393 return JNI_ERR; 394 } 395 } 396 NSK_DISPLAY0(" ... added\n"); 397 398 NSK_DISPLAY1("Set callback for event: %s\n", "CLASS_FILE_LOAD_HOOK"); 399 { 400 jvmtiEventCallbacks callbacks; 401 jint size = (jint)sizeof(callbacks); 402 403 memset(&callbacks, 0, sizeof(callbacks)); 404 callbacks.ClassFileLoadHook = callbackClassFileLoadHook; 405 if (!NSK_JVMTI_VERIFY(jvmti->SetEventCallbacks(&callbacks, size))) { 406 return JNI_ERR; 407 } 408 } 409 NSK_DISPLAY0(" ... set\n"); 410 411 /* register agent proc and arg */ 412 if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agentProc, NULL))) 413 return JNI_ERR; 414 415 return JNI_OK; 416 } 417 418 /* ============================================================================= */ 419 420 }