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