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