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