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 }