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