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