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 }