1 /* 2 * Copyright (c) 2003, 2021, 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 <inttypes.h> 27 #include "jvmti.h" 28 #include "agent_common.h" 29 #include "JVMTITools.h" 30 31 extern "C" { 32 33 34 #define PASSED 0 35 #define STATUS_FAILED 2 36 37 #define EXP_STATUS (JVMTI_CLASS_STATUS_VERIFIED | JVMTI_CLASS_STATUS_PREPARED) 38 39 typedef struct { 40 char *sig; 41 jint status; 42 jint mcount; 43 jint fcount; 44 jint icount; 45 } writable_class_info; 46 47 typedef struct { 48 const char *sig; 49 jint status; 50 jint mcount; 51 jint fcount; 52 jint icount; 53 } class_info; 54 55 static jvmtiEnv *jvmti = NULL; 56 static jvmtiEventCallbacks callbacks; 57 static jint result = PASSED; 58 static jboolean printdump = JNI_FALSE; 59 static size_t eventsCount = 0; 60 static size_t eventsExpected = 0; 61 static class_info classes[] = { 62 { "Lnsk/jvmti/ClassPrepare/classprep001$TestInterface;", EXP_STATUS, 2, 1, 0 }, 63 { "Lnsk/jvmti/ClassPrepare/classprep001$TestClass;", EXP_STATUS, 3, 2, 2 } 64 }; 65 // These classes are loaded on a different thread. 66 // We should not get ClassPrepare events for them. 67 static const class_info unexpectedClasses[] = { 68 { "Lnsk/jvmti/ClassPrepare/classprep001$TestInterface2;", 0, 0, 0, 0 }, 69 { "Lnsk/jvmti/ClassPrepare/classprep001$TestClass2;", 0, 0, 0, 0} 70 }; 71 72 void printStatus(jint status) { 73 int flags = 0; 74 if ((status & JVMTI_CLASS_STATUS_VERIFIED) != 0) { 75 printf("JVMTI_CLASS_STATUS_VERIFIED"); 76 flags++; 77 } 78 if ((status & JVMTI_CLASS_STATUS_PREPARED) != 0) { 79 if (flags > 0) printf(" | "); 80 printf("JVMTI_CLASS_STATUS_PREPARED"); 81 flags++; 82 } 83 if ((status & JVMTI_CLASS_STATUS_INITIALIZED) != 0) { 84 if (flags > 0) printf(" | "); 85 printf("JVMTI_CLASS_STATUS_INITIALIZED"); 86 flags++; 87 } 88 if ((status & JVMTI_CLASS_STATUS_ERROR) != 0) { 89 if (flags > 0) printf(" | "); 90 printf("JVMTI_CLASS_STATUS_ERROR"); 91 flags++; 92 } 93 printf(" (0x%x)\n", status); 94 } 95 96 const size_t NOT_FOUND = (size_t)(-1); 97 98 size_t findClass(const char *classSig, const class_info *arr, int size) { 99 for (int i = 0; i < size; i++) { 100 if (strcmp(classSig, arr[i].sig) == 0) { 101 return i; 102 } 103 } 104 return NOT_FOUND; 105 } 106 107 void JNICALL ClassPrepare(jvmtiEnv *jvmti_env, JNIEnv *env, 108 jthread thr, jclass cls) { 109 jvmtiError err; 110 writable_class_info inf; 111 jmethodID *methods; 112 jfieldID *fields; 113 jclass *interfaces; 114 char *name, *sig, *generic; 115 int i; 116 117 err = jvmti_env->GetClassSignature(cls, &inf.sig, &generic); 118 if (err != JVMTI_ERROR_NONE) { 119 printf("(GetClassSignature#%" PRIuPTR ") unexpected error: %s (%d)\n", 120 eventsCount, TranslateError(err), err); 121 result = STATUS_FAILED; 122 return; 123 } 124 err = jvmti_env->GetClassStatus(cls, &inf.status); 125 if (err != JVMTI_ERROR_NONE) { 126 printf("(GetClassStatus#%" PRIuPTR ") unexpected error: %s (%d)\n", 127 eventsCount, TranslateError(err), err); 128 result = STATUS_FAILED; 129 } 130 err = jvmti_env->GetClassMethods(cls, &inf.mcount, &methods); 131 if (err != JVMTI_ERROR_NONE) { 132 printf("(GetClassMethods#%" PRIuPTR ") unexpected error: %s (%d)\n", 133 eventsCount, TranslateError(err), err); 134 result = STATUS_FAILED; 135 return; 136 } 137 err = jvmti_env->GetClassFields(cls, &inf.fcount, &fields); 138 if (err != JVMTI_ERROR_NONE) { 139 printf("(GetClassMethods#%" PRIuPTR ") unexpected error: %s (%d)\n", 140 eventsCount, TranslateError(err), err); 141 result = STATUS_FAILED; 142 return; 143 } 144 err = jvmti_env->GetImplementedInterfaces(cls, 145 &inf.icount, &interfaces); 146 if (err != JVMTI_ERROR_NONE) { 147 printf("(GetImplementedInterfaces#%" PRIuPTR ") unexpected error: %s (%d)\n", 148 eventsCount, TranslateError(err), err); 149 result = STATUS_FAILED; 150 return; 151 } 152 153 if (printdump == JNI_TRUE) { 154 printf(">>> [class prepare event #%" PRIuPTR "]", eventsCount); 155 printf(" \"%s\"\n", inf.sig); 156 printf(">>> status: "); 157 printStatus(inf.status); 158 printf(">>> %d methods:", inf.mcount); 159 for (i = 0; i < inf.mcount; i++) { 160 if (i > 0) printf(","); 161 if (methods[i] == NULL) { 162 printf(" null"); 163 } else { 164 err = jvmti_env->GetMethodName(methods[i], 165 &name, &sig, &generic); 166 if (err == JVMTI_ERROR_NONE) { 167 printf(" \"%s%s\"", name, sig); 168 } else { 169 printf(" ???"); 170 } 171 } 172 } 173 printf("\n"); 174 printf(">>> %d fields:", inf.fcount); 175 for (i = 0; i < inf.fcount; i++) { 176 if (i > 0) printf(","); 177 if (fields[i] == NULL) { 178 printf(" null"); 179 } else { 180 err = jvmti_env->GetFieldName(cls, fields[i], 181 &name, &sig, &generic); 182 if (err == JVMTI_ERROR_NONE) { 183 printf(" \"%s, %s\"", name, sig); 184 } else { 185 printf(" ???"); 186 } 187 } 188 } 189 printf("\n"); 190 printf(">>> %d interfaces:", inf.icount); 191 for (i = 0; i < inf.icount; i++) { 192 if (i > 0) printf(","); 193 if (interfaces[i] == NULL) { 194 printf(" null"); 195 } else { 196 err = jvmti_env->GetClassSignature( 197 interfaces[i], &sig, &generic); 198 if (err == JVMTI_ERROR_NONE) { 199 printf(" \"%s\"", sig); 200 } else { 201 printf(" ???"); 202 } 203 } 204 } 205 printf("\n"); 206 } 207 208 size_t expectedClassIdx = findClass(inf.sig, classes, sizeof(classes)/sizeof(class_info)); 209 // Test classes loading may cause system classes loading - skip them. 210 if (expectedClassIdx == NOT_FOUND) { 211 size_t unexpectedClassIdx = findClass(inf.sig, unexpectedClasses, 212 sizeof(unexpectedClasses)/sizeof(class_info)); 213 if (unexpectedClassIdx != NOT_FOUND) { 214 printf("# wrong class: \"%s\"\n", inf.sig); 215 result = STATUS_FAILED; 216 } 217 return; 218 } 219 220 if (eventsCount != expectedClassIdx) { 221 printf("(#%" PRIuPTR ") unexpected order: %" PRIuPTR ", expected: %" PRIuPTR "\n", 222 eventsCount, expectedClassIdx, eventsCount); 223 result = STATUS_FAILED; 224 return; 225 } 226 227 if (inf.status != classes[eventsCount].status) { 228 printf("(#%" PRIuPTR ") wrong status: ", eventsCount); 229 printStatus(inf.status); 230 printf(" expected: "); 231 printStatus(classes[eventsCount].status); 232 result = STATUS_FAILED; 233 } 234 if (inf.mcount != classes[eventsCount].mcount) { 235 printf("(#%" PRIuPTR ") wrong number of methods: 0x%x", 236 eventsCount, inf.mcount); 237 printf(", expected: 0x%x\n", classes[eventsCount].mcount); 238 result = STATUS_FAILED; 239 } 240 if (inf.fcount != classes[eventsCount].fcount) { 241 printf("(#%" PRIuPTR ") wrong number of fields: 0x%x", 242 eventsCount, inf.fcount); 243 printf(", expected: 0x%x\n", classes[eventsCount].fcount); 244 result = STATUS_FAILED; 245 } 246 if (inf.icount != classes[eventsCount].icount) { 247 printf("(#%" PRIuPTR ") wrong number of interfaces: 0x%x", 248 eventsCount, inf.icount); 249 printf(", expected: 0x%x\n", classes[eventsCount].icount); 250 result = STATUS_FAILED; 251 } 252 eventsCount++; 253 } 254 255 #ifdef STATIC_BUILD 256 JNIEXPORT jint JNICALL Agent_OnLoad_classprep001(JavaVM *jvm, char *options, void *reserved) { 257 return Agent_Initialize(jvm, options, reserved); 258 } 259 JNIEXPORT jint JNICALL Agent_OnAttach_classprep001(JavaVM *jvm, char *options, void *reserved) { 260 return Agent_Initialize(jvm, options, reserved); 261 } 262 JNIEXPORT jint JNI_OnLoad_classprep001(JavaVM *jvm, char *options, void *reserved) { 263 return JNI_VERSION_1_8; 264 } 265 #endif 266 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { 267 jvmtiError err; 268 jint res; 269 270 if (options != NULL && strcmp(options, "printdump") == 0) { 271 printdump = JNI_TRUE; 272 } 273 274 res = jvm->GetEnv((void **) &jvmti, JVMTI_VERSION_1_1); 275 if (res != JNI_OK || jvmti == NULL) { 276 printf("Wrong result of a valid call to GetEnv!\n"); 277 return JNI_ERR; 278 } 279 280 callbacks.ClassPrepare = &ClassPrepare; 281 err = jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks)); 282 if (err != JVMTI_ERROR_NONE) { 283 printf("(SetEventCallbacks) unexpected error: %s (%d)\n", 284 TranslateError(err), err); 285 return JNI_ERR; 286 } 287 288 return JNI_OK; 289 } 290 291 JNIEXPORT void JNICALL 292 Java_nsk_jvmti_ClassPrepare_classprep001_getReady(JNIEnv *env, jclass cls, jthread thread) { 293 jvmtiError err; 294 295 if (jvmti == NULL) { 296 printf("JVMTI client was not properly loaded!\n"); 297 return; 298 } 299 300 err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, 301 JVMTI_EVENT_CLASS_PREPARE, thread); 302 if (err == JVMTI_ERROR_NONE) { 303 eventsExpected = sizeof(classes)/sizeof(class_info); 304 } else { 305 printf("Failed to enable JVMTI_EVENT_CLASS_PREPARE: %s (%d)\n", 306 TranslateError(err), err); 307 result = STATUS_FAILED; 308 } 309 } 310 311 JNIEXPORT jint JNICALL 312 Java_nsk_jvmti_ClassPrepare_classprep001_check(JNIEnv *env, jclass cls, jthread thread) { 313 jvmtiError err; 314 315 if (jvmti == NULL) { 316 printf("JVMTI client was not properly loaded!\n"); 317 return STATUS_FAILED; 318 } 319 320 err = jvmti->SetEventNotificationMode(JVMTI_DISABLE, 321 JVMTI_EVENT_CLASS_PREPARE, thread); 322 if (err != JVMTI_ERROR_NONE) { 323 printf("Failed to disable JVMTI_EVENT_CLASS_PREPARE: %s (%d)\n", 324 TranslateError(err), err); 325 result = STATUS_FAILED; 326 } 327 328 if (eventsCount != eventsExpected) { 329 printf("Wrong number of class prepare events: %" PRIuPTR ", expected: %" PRIuPTR "\n", 330 eventsCount, eventsExpected); 331 result = STATUS_FAILED; 332 } 333 return result; 334 } 335 336 }