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