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 }