1 /* 2 * Copyright (c) 2019, 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 <stdint.h> 25 #include <stdio.h> 26 #include <stdlib.h> 27 #include <string.h> 28 #include "jvmti.h" 29 30 #ifdef __cplusplus 31 extern "C" { 32 #endif 33 34 #ifndef JNI_ENV_ARG 35 36 #ifdef __cplusplus 37 #define JNI_ENV_ARG(x, y) y 38 #define JNI_ENV_PTR(x) x 39 #else 40 #define JNI_ENV_ARG(x,y) x, y 41 #define JNI_ENV_PTR(x) (*x) 42 #endif 43 44 #endif 45 46 #define PASSED 0 47 #define FAILED 2 48 49 static jvmtiEnv* jvmti = NULL; 50 51 static jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved); 52 53 JNIEXPORT jint JNICALL 54 Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { 55 return Agent_Initialize(jvm, options, reserved); 56 } 57 58 JNIEXPORT jint JNICALL 59 Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) { 60 return Agent_Initialize(jvm, options, reserved); 61 } 62 63 JNIEXPORT jint JNICALL 64 JNI_OnLoad(JavaVM *jvm, void *reserved) { 65 return JNI_VERSION_9; 66 } 67 68 static void 69 check_jvmti_error(jvmtiEnv *jvmti, char* fname, jvmtiError err) { 70 if (err != JVMTI_ERROR_NONE) { 71 printf(" ## %s error: %d\n", fname, err); 72 fflush(0); 73 exit(err); 74 } 75 } 76 77 static char* 78 get_class_signature(jvmtiEnv *jvmti, jclass klass) { 79 char* sign = NULL; 80 jvmtiError err = (*jvmti)->GetClassSignature(jvmti, klass, &sign, NULL); 81 82 check_jvmti_error(jvmti, "GetClassSignature", err); 83 return sign; 84 } 85 86 static jboolean 87 is_class_status_prepared(jvmtiEnv *jvmti, jclass klass) { 88 char* sign = get_class_signature(jvmti, klass); 89 jint status = 0; 90 jvmtiError err = (*jvmti)->GetClassStatus(jvmti, klass, &status); 91 92 check_jvmti_error(jvmti, "GetClassStatus", err); 93 printf(" Class %s status: 0x%08x\n", sign, status); 94 printf(" Class %s is prepared: %d\n", sign, (status & JVMTI_CLASS_STATUS_PREPARED) != 0); 95 fflush(0); 96 97 return (status & JVMTI_CLASS_STATUS_PREPARED) != 0; 98 } 99 100 static jboolean 101 is_class_in_loaded_classes(JNIEnv *env, jclass klass) { 102 char* sign = get_class_signature(jvmti, klass); 103 jint class_count = 0; 104 jclass* classes = NULL; 105 jvmtiError err = (*jvmti)->GetLoadedClasses(jvmti, &class_count, &classes); 106 107 check_jvmti_error(jvmti, "GetLoadedClasses", err); 108 109 for (int i = 0; i < class_count; i++) { 110 jclass cls = classes[i]; 111 jboolean same = (*env)->IsSameObject(env, cls, klass); 112 if (same) { 113 printf("Found class %s in the list of loaded classes\n", sign); 114 fflush(0); 115 return JNI_TRUE; 116 } 117 } 118 printf("Error: Have not found class %s in the list of loaded classes\n", sign); 119 fflush(0); 120 return JNI_FALSE; 121 } 122 123 static void JNICALL 124 ClassPrepare(jvmtiEnv *jvmti, JNIEnv *env, jthread thread, jclass klass) { 125 char* sign = get_class_signature(jvmti, klass); 126 127 sign = (sign == NULL) ? "NULL" : sign; 128 129 if (strcmp(sign, "LFoo2;") == 0 || strcmp(sign, "LFoo3;") == 0) { 130 printf("ClassPrepare event for class: %s\n", sign); 131 fflush(0); 132 } 133 } 134 135 static jint 136 Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { 137 jvmtiError err; 138 jint size; 139 jint res; 140 jvmtiEventCallbacks callbacks; 141 142 printf("Agent_Initialize started\n"); 143 fflush(0); 144 res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **) &jvmti), JVMTI_VERSION_9); 145 if (res != JNI_OK || jvmti == NULL) { 146 printf("## Agent_Initialize: Error in GetEnv: res: %d, jvmti env: %p\n", res, jvmti); 147 return JNI_ERR; 148 } 149 150 size = (jint)sizeof(callbacks); 151 memset(&callbacks, 0, size); 152 callbacks.ClassPrepare = ClassPrepare; 153 154 err = (*jvmti)->SetEventCallbacks(jvmti, &callbacks, size); 155 check_jvmti_error(jvmti, "## Agent_Initialize: SetEventCallbacks", err); 156 157 err = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_CLASS_PREPARE, NULL); 158 check_jvmti_error(jvmti, "## Agent_Initialize: SetEventNotificationMode CLASS_PREPARE", err); 159 return JNI_OK; 160 } 161 162 JNIEXPORT jint JNICALL 163 Java_ClassStatus_check(JNIEnv *env, jclass cls, jclass klass) { 164 if (is_class_in_loaded_classes(env, klass) != JNI_TRUE || 165 is_class_status_prepared(jvmti, klass) != JNI_TRUE) { 166 return FAILED; 167 } 168 return PASSED; 169 } 170 171 #ifdef __cplusplus 172 } 173 #endif