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