1 /*
   2  * Copyright (c) 2016, 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 <stdio.h>
  25 #include <string.h>
  26 #include "jvmti.h"
  27 
  28 #ifdef __cplusplus
  29 extern "C" {
  30 #endif
  31 
  32 #ifndef JNI_ENV_ARG
  33 
  34 #ifdef __cplusplus
  35 #define JNI_ENV_ARG(x, y) y
  36 #define JNI_ENV_PTR(x) x
  37 #else
  38 #define JNI_ENV_ARG(x,y) x, y
  39 #define JNI_ENV_PTR(x) (*x)
  40 #endif
  41 
  42 #endif
  43 
  44 #define TranslateError(err) "JVMTI error"
  45 
  46 #define PASSED 0
  47 #define FAILED 2
  48 
  49 static const char *EXPECTED_SIGNATURE = "Ljava/util/Collections;";
  50 static const char *EXC_CNAME = "java/lang/Exception";
  51 
  52 static jvmtiEnv *jvmti = NULL;
  53 static jint result = PASSED;
  54 static jboolean printdump = JNI_FALSE;
  55 
  56 static jboolean with_early_vm_start_capability = JNI_FALSE;
  57 
  58 static jboolean class_in_class_load_events_vm_start = JNI_FALSE;
  59 static jboolean class_in_class_load_events_vm_live = JNI_FALSE;
  60 static jboolean class_in_class_prepare_events_vm_start = JNI_FALSE;
  61 static jboolean class_in_class_prepare_events_vm_live = JNI_FALSE;
  62 
  63 static int class_load_events_vm_start_count = 0;
  64 static int class_prepare_events_vm_start_count = 0;
  65 
  66 static jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved);
  67 
  68 JNIEXPORT
  69 jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {
  70     return Agent_Initialize(jvm, options, reserved);
  71 }
  72 
  73 JNIEXPORT
  74 jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) {
  75     return Agent_Initialize(jvm, options, reserved);
  76 }
  77 
  78 JNIEXPORT
  79 jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
  80     return JNI_VERSION_9;
  81 }
  82 
  83 static
  84 jint throw_exc(JNIEnv *env, char *msg) {
  85     jclass exc_class = JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG(env, EXC_CNAME));
  86 
  87     if (exc_class == NULL) {
  88         printf("throw_exc: Error in FindClass(env, %s)\n", EXC_CNAME);
  89         return -1;
  90     }
  91     return JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG(env, exc_class), msg);
  92 }
  93 
  94 static void JNICALL
  95 Callback_ClassFileLoad(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thread, jclass klass) {
  96     jvmtiPhase phase;
  97     char *sig, *generic;
  98     jvmtiError err;
  99 
 100     err = (*jvmti)->GetPhase(jvmti_env,&phase);
 101     if (err != JVMTI_ERROR_NONE) {
 102         printf("ClassLoad event: GetPhase error: %s (%d)\n", TranslateError(err), err);
 103         result = FAILED;
 104         return;
 105     }
 106 
 107     if (phase == JVMTI_PHASE_START || phase == JVMTI_PHASE_LIVE) {
 108 
 109         err = (*jvmti)->GetClassSignature(jvmti_env, klass, &sig, &generic);
 110 
 111         if (err != JVMTI_ERROR_NONE) {
 112             printf("ClassLoad event: GetClassSignature error: %s (%d)\n", TranslateError(err), err);
 113             result = FAILED;
 114             return;
 115         }
 116 
 117         if (phase == JVMTI_PHASE_START) {
 118             class_load_events_vm_start_count++;
 119             if(!strcmp(sig, EXPECTED_SIGNATURE)) {
 120                 class_in_class_load_events_vm_start = JNI_TRUE;
 121             }
 122         } else {
 123             if(!strcmp(sig, EXPECTED_SIGNATURE)) {
 124                 class_in_class_load_events_vm_live = JNI_TRUE;
 125             }
 126         }
 127 
 128         if (printdump == JNI_TRUE) {
 129             printf(">>>    ClassLoad event: phase(%d), class signature %s\n", phase, sig == NULL ? "null": sig);
 130         }
 131     } else {
 132         printf("ClassLoad event: get event in unexpected phase(%d)\n", phase);
 133         result = FAILED;
 134     }
 135 }
 136 
 137 static void JNICALL
 138 Callback_ClassFilePrepare(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thread, jclass klass) {
 139     jvmtiPhase phase;
 140     char *sig, *generic;
 141     jvmtiError err;
 142 
 143     err = (*jvmti)->GetPhase(jvmti_env,&phase);
 144     if (err != JVMTI_ERROR_NONE) {
 145         printf("ClassPrepare event: GetPhase error: %s (%d)\n", TranslateError(err), err);
 146         result = FAILED;
 147         return;
 148     }
 149 
 150     if (phase == JVMTI_PHASE_START || phase == JVMTI_PHASE_LIVE) {
 151 
 152         err = (*jvmti)->GetClassSignature(jvmti_env, klass, &sig, &generic);
 153 
 154         if (err != JVMTI_ERROR_NONE) {
 155             printf("ClassPrepare event: GetClassSignature error: %s (%d)\n", TranslateError(err), err);
 156             result = FAILED;
 157             return;
 158         }
 159 
 160         if (phase == JVMTI_PHASE_START) {
 161             class_prepare_events_vm_start_count++;
 162             if(!strcmp(sig, EXPECTED_SIGNATURE)) {
 163                 class_in_class_prepare_events_vm_start = JNI_TRUE;
 164             }
 165         } else {
 166             if(!strcmp(sig, EXPECTED_SIGNATURE)) {
 167                 class_in_class_prepare_events_vm_live = JNI_TRUE;
 168             }
 169         }
 170 
 171         if (printdump == JNI_TRUE) {
 172             printf(">>>    ClassPrepare event: phase(%d), class signature %s\n", phase, sig == NULL ? "null": sig);
 173         }
 174     } else {
 175         printf("ClassPrepare event: get event in unexpected phase(%d)\n", phase);
 176         result = FAILED;
 177     }
 178 }
 179 
 180 static
 181 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
 182     jint res, size;
 183     jvmtiCapabilities caps;
 184     jvmtiEventCallbacks callbacks;
 185     jvmtiError err;
 186 
 187     if (options != NULL) {
 188         if (strstr(options, "with_early_vmstart") != NULL) {
 189             with_early_vm_start_capability = JNI_TRUE;
 190         }
 191         if (strstr(options, "printdump") != NULL) {
 192             printdump = JNI_TRUE;
 193         }
 194     }
 195 
 196     res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **) &jvmti),
 197         JVMTI_VERSION_9);
 198     if (res != JNI_OK || jvmti == NULL) {
 199         printf("    Error: wrong result of a valid call to GetEnv!\n");
 200         return JNI_ERR;
 201     }
 202 
 203     if (with_early_vm_start_capability == JNI_TRUE) {
 204         printf("Enabling following capability: can_generate_early_vmstart\n");
 205         memset(&caps, 0, sizeof(caps));
 206         caps.can_generate_early_vmstart = 1;
 207 
 208         err = (*jvmti)->AddCapabilities(jvmti, &caps);
 209         if (err != JVMTI_ERROR_NONE) {
 210             printf("    Error in AddCapabilites: %s (%d)\n", TranslateError(err), err);
 211             return JNI_ERR;
 212         }
 213     }
 214 
 215     size = (jint)sizeof(callbacks);
 216 
 217     memset(&callbacks, 0, sizeof(callbacks));
 218     callbacks.ClassLoad = Callback_ClassFileLoad;
 219     callbacks.ClassPrepare = Callback_ClassFilePrepare;
 220 
 221     err = (*jvmti)->SetEventCallbacks(jvmti, &callbacks, size);
 222     if (err != JVMTI_ERROR_NONE) {
 223         printf("    Error in SetEventCallbacks: %s (%d)\n", TranslateError(err), err);
 224         return JNI_ERR;
 225     }
 226 
 227     err = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_CLASS_LOAD, NULL);
 228     if (err != JVMTI_ERROR_NONE) {
 229         printf("    Error in SetEventNotificationMode: %s (%d)\n", TranslateError(err), err);
 230         return JNI_ERR;
 231     }
 232 
 233     err = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_CLASS_PREPARE, NULL);
 234 
 235     if (err != JVMTI_ERROR_NONE) {
 236         printf("    Error in SetEventNotificationMode: %s (%d)\n", TranslateError(err), err);
 237         return JNI_ERR;
 238     }
 239 
 240     return JNI_OK;
 241 }
 242 
 243 JNIEXPORT jint JNICALL
 244 Java_MAAClassLoadPrepare_check(JNIEnv *env, jclass cls) {
 245     jobject loader = NULL;
 246 
 247     if (jvmti == NULL) {
 248         throw_exc(env, "JVMTI client was not properly loaded!\n");
 249         return FAILED;
 250     }
 251 
 252     if (with_early_vm_start_capability == JNI_TRUE) {
 253         /*
 254          * Expecting that "java/util/Collections" class from java.base module is present in the
 255          * ClassLoad and ClassPrepare events during VM Start phase when can_generate_early_vmstart
 256          * capability is enabled
 257          * Expecting that ClassLoad and ClassPrepare events are sent in th
 258          * VM Start phase when can_generate_early_vmstart is enabled(JDK-8165681)
 259          */
 260         if (class_load_events_vm_start_count == 0) {
 261             throw_exc(env, "Didn't get ClassLoad events in start phase!\n");
 262             return FAILED;
 263         }
 264 
 265         printf("Expecting to find '%s' class in ClassLoad events during VM start phase.\n", EXPECTED_SIGNATURE);
 266         if (class_in_class_load_events_vm_start == JNI_FALSE) {
 267             throw_exc(env, "Unable to find expected class in ClassLoad events during start phase!\n");
 268             return FAILED;
 269         }
 270 
 271         if (class_prepare_events_vm_start_count == 0) {
 272             throw_exc(env, "Didn't get ClassPrepare events in start phase!\n");
 273             return FAILED;
 274         }
 275 
 276         printf("Expecting to find '%s' class in ClassPrepare events during VM start phase.\n", EXPECTED_SIGNATURE);
 277         if (class_in_class_prepare_events_vm_start == JNI_FALSE) {
 278             throw_exc(env, "Unable to find expected class in ClassPrepare events during start phase!\n");
 279             return FAILED;
 280         }
 281     } else {
 282         /*
 283          * Expecting that "java/util/Collections" class from java.base module is not present in the
 284          * ClassLoad and ClassPrepare events during VM Start phase when can_generate_early_vmstart
 285          * capability is disabled
 286          */
 287         printf("Expecting that '%s' class is absent in ClassLoad events.\n", EXPECTED_SIGNATURE);
 288         if (class_in_class_prepare_events_vm_start == JNI_TRUE) {
 289             throw_exc(env, "Class is found in ClassLoad events during VM Start phase!\n");
 290             return FAILED;
 291         }
 292 
 293         printf("Expecting that '%s' class is absent in ClassPrepare events.\n", EXPECTED_SIGNATURE);
 294         if (class_in_class_prepare_events_vm_start == JNI_TRUE) {
 295             throw_exc(env, "Class is found in ClassPrepare events during VM Start phase!\n");
 296             return FAILED;
 297         }
 298     }
 299 
 300     /*
 301      * In any case, we not expect to see "java/util/Collections" class from java.base module
 302      * in the ClassLoad and ClassPrepare events during VM Live phase
 303      */
 304     if (class_in_class_prepare_events_vm_live == JNI_TRUE) {
 305         throw_exc(env, "Class is found in ClassLoad events during VM Live phase!\n");
 306         return FAILED;
 307     }
 308 
 309     if (class_in_class_prepare_events_vm_live == JNI_TRUE) {
 310         throw_exc(env, "Class is found in ClassPrepare events during VM Live phase!\n");
 311         return FAILED;
 312     }
 313 
 314     return result;
 315 }
 316 
 317 #ifdef __cplusplus
 318 }
 319 #endif