1/*
2 * Copyright (c) 2017, 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
31extern "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
49static jint result = PASSED;
50
51static jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved);
52
53JNIEXPORT
54jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {
55    return Agent_Initialize(jvm, options, reserved);
56}
57
58JNIEXPORT
59jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) {
60    return Agent_Initialize(jvm, options, reserved);
61}
62
63JNIEXPORT
64jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
65    return JNI_VERSION_9;
66}
67
68static void check_jvmti_error(jvmtiEnv *jvmti, char* fname, jvmtiError err) {
69    if (err != JVMTI_ERROR_NONE) {
70        printf("  ## %s error: %d\n", fname, err);
71        exit(err);
72    }
73}
74
75 static void deallocate(jvmtiEnv *jvmti, char* mem) {
76    jvmtiError err = (*jvmti)->Deallocate(jvmti, (unsigned char*)mem);
77    check_jvmti_error(jvmti, "Deallocate", err);
78}
79
80static void get_phase(jvmtiEnv *jvmti, jvmtiPhase *phase_ptr) {
81    jvmtiError err = (*jvmti)->GetPhase(jvmti, phase_ptr);
82    check_jvmti_error(jvmti, "GetPhase", err);
83}
84
85static jthread get_cur_thread(jvmtiEnv *jvmti) {
86    jthread cur_thread = NULL;
87    jvmtiError err = (*jvmti)->GetCurrentThread(jvmti, &cur_thread);
88    check_jvmti_error(jvmti, "GetCurrentThread", err);
89    return cur_thread;
90}
91
92static intptr_t get_thread_local(jvmtiEnv *jvmti, jthread thread) {
93    void *val = NULL;
94    jvmtiError err = (*jvmti)->GetThreadLocalStorage(jvmti, thread, &val);
95    check_jvmti_error(jvmti, "GetThreadLocalStorage", err);
96    return (intptr_t)val;
97}
98
99static void set_thread_local(jvmtiEnv *jvmti, jthread thread, intptr_t x) {
100    void *val = (void*)x;
101    jvmtiError err = (*jvmti)->SetThreadLocalStorage(jvmti, thread, val);
102    check_jvmti_error(jvmti, "SetThreadLocalStorage", err);
103}
104
105static void print_class_status(jvmtiEnv *jvmti, jclass klass) {
106    jint status = 0;
107    jvmtiError err = (*jvmti)->GetClassStatus(jvmti, klass, &status);
108
109    check_jvmti_error(jvmti, "GetClassStatus", err);
110    // This function is only used in a ClassPrepare event context
111    if ((status & JVMTI_CLASS_STATUS_VERIFIED)    == 0 ||
112        (status & JVMTI_CLASS_STATUS_PREPARED)    == 0 ||
113        (status & JVMTI_CLASS_STATUS_INITIALIZED) == 1 ||
114        (status & JVMTI_CLASS_STATUS_ERROR)       == 1) {
115        printf("  ## Error: unexpected class status: 0x%08x\n", status);
116    }
117    printf("    Class status: 0x%08x\n", status);
118}
119
120static void print_class_signature(jvmtiEnv *jvmti, jclass klass) {
121    char* name = NULL;
122    jvmtiError err = (*jvmti)->GetClassSignature(jvmti, klass, &name, NULL);
123
124    check_jvmti_error(jvmti, "GetClassSignature", err);
125    if (name != NULL) {
126        printf(" class: '%s'\n", name);
127        deallocate(jvmti, name);
128    }
129}
130
131static void print_class_source_file_name(jvmtiEnv *jvmti, jclass klass) {
132    char* name = NULL;
133    jvmtiError err = (*jvmti)->GetSourceFileName(jvmti, klass, &name);
134
135    check_jvmti_error(jvmti, "GetSourceFileName", err);
136    if (name != NULL) {
137        printf("    Class source file name: '%s'\n", name);
138        deallocate(jvmti, name);
139    }
140}
141
142static void print_class_info(jvmtiEnv *jvmti, jclass klass) {
143    jint mods = 0;
144    jboolean is_interface  = JNI_FALSE;
145    jboolean is_array      = JNI_FALSE;
146    jboolean is_modifiable = JNI_FALSE;
147    jvmtiError err = (*jvmti)->GetClassModifiers(jvmti, klass, &mods);
148
149    check_jvmti_error(jvmti, "GetClassModifiers", err);
150    printf("    Class modifiers: 0x%08x\n", mods);
151
152    err = (*jvmti)->IsInterface(jvmti, klass, &is_interface);
153    check_jvmti_error(jvmti, "IsInterface", err);
154    printf("    Class is interface: %d\n", is_interface);
155
156    err = (*jvmti)->IsArrayClass(jvmti, klass, &is_array);
157    check_jvmti_error(jvmti, "IsArrayClass", err);
158    printf("    Class is array: %d\n", is_array);
159
160    err = (*jvmti)->IsModifiableClass(jvmti, klass, &is_modifiable);
161    check_jvmti_error(jvmti, "IsModifiableClass", err);
162    printf("    Class is modifiable: %d\n", is_modifiable);
163}
164
165static jint get_class_methods(jvmtiEnv *jvmti, jclass klass, jmethodID** methods_ptr) {
166    jint count = 0;
167    jvmtiError err = (*jvmti)->GetClassMethods(jvmti, klass, &count, methods_ptr);
168    check_jvmti_error(jvmti, "GetClassMethods", err);
169    return count;
170}
171
172static jint get_class_fields(jvmtiEnv *jvmti, jclass klass, jfieldID** fields_ptr) {
173    jint count = 0;
174    jvmtiError err = (*jvmti)->GetClassFields(jvmti, klass, &count, fields_ptr);
175    check_jvmti_error(jvmti, "GetClassFields", err);
176    return count;
177}
178
179static void print_method_name_sign(jvmtiEnv *jvmti, jmethodID method) {
180    char* name = NULL;
181    char* sign = NULL;
182    jvmtiError err = (*jvmti)->GetMethodName(jvmti, method, &name, &sign, NULL);
183
184    check_jvmti_error(jvmti, "GetMethodName", err);
185    printf("  Method: %s%s\n", name, sign);
186    deallocate(jvmti, name);
187    deallocate(jvmti, sign);
188}
189
190static void print_method_declaring_class(jvmtiEnv *jvmti, jmethodID method) {
191    jclass dclass = NULL;
192    jvmtiError err = (*jvmti)->GetMethodDeclaringClass(jvmti, method, &dclass);
193
194    check_jvmti_error(jvmti, "GetMethodDeclaringClass", err);
195    printf("    Method declaring");
196    print_class_signature(jvmti, dclass);
197}
198
199static void print_method_info(jvmtiEnv *jvmti, jmethodID method) {
200    jint mods = 0;
201    jint locals_max = 0;
202    jint args_size = 0;
203    jboolean is_native   = JNI_FALSE;
204    jboolean is_synth    = JNI_FALSE;
205    jboolean is_obsolete = JNI_FALSE;
206    jvmtiError err = (*jvmti)->GetMethodModifiers(jvmti, method, &mods);
207
208    check_jvmti_error(jvmti, "GetMethodModifiers", err);
209    printf("    Method modifiers: 0x%08x\n", mods);
210
211    err = (*jvmti)->IsMethodNative(jvmti, method, &is_native);
212    check_jvmti_error(jvmti, "IsMethodNative", err);
213    printf("    Method is native: %d\n", is_native);
214
215    if (is_native == JNI_FALSE) {
216        err = (*jvmti)->GetMaxLocals(jvmti, method, &locals_max);
217        check_jvmti_error(jvmti, "GetMaxLocals", err);
218        printf("    Method max locals: %d\n", locals_max);
219
220        err = (*jvmti)->GetArgumentsSize(jvmti, method, &args_size);
221        check_jvmti_error(jvmti, "GetArgumentsSize", err);
222        printf("    Method arguments size: %d\n", args_size);
223    }
224
225    err = (*jvmti)->IsMethodSynthetic(jvmti, method, &is_synth);
226    check_jvmti_error(jvmti, "IsMethodSynthetic", err);
227    printf("    Method is synthetic: %d\n", is_synth);
228
229    err = (*jvmti)->IsMethodObsolete(jvmti, method, &is_obsolete);
230    check_jvmti_error(jvmti, "IsMethodObsolete", err);
231    printf("    Method is obsolete: %d\n", is_obsolete);
232}
233
234static void test_method_functions(jvmtiEnv *jvmti, jmethodID method) {
235    print_method_name_sign(jvmti, method);
236    print_method_declaring_class(jvmti, method);
237    print_method_info(jvmti, method);
238}
239
240static void print_field_name_sign(jvmtiEnv *jvmti, jclass klass, jfieldID field) {
241    char* name = NULL;
242    char* sign = NULL;
243    jvmtiError err = (*jvmti)->GetFieldName(jvmti, klass, field, &name, &sign, NULL);
244
245    check_jvmti_error(jvmti, "GetFieldName", err);
246    printf("  Field: %s %s\n", sign, name);
247    deallocate(jvmti, name);
248    deallocate(jvmti, sign);
249}
250
251static void print_field_declaring_class(jvmtiEnv *jvmti, jclass klass, jfieldID field) {
252    jclass dclass = NULL;
253    jvmtiError err = (*jvmti)->GetFieldDeclaringClass(jvmti, klass, field, &dclass);
254
255    check_jvmti_error(jvmti, "GetFieldDeclaringClass", err);
256    printf("    Field declaring");
257    print_class_signature(jvmti, dclass);
258}
259
260static void print_field_info(jvmtiEnv *jvmti, jclass klass, jfieldID field) {
261    jint mods = 0;
262    jboolean is_synth = JNI_FALSE;
263    jvmtiError err = (*jvmti)->GetFieldModifiers(jvmti, klass, field, &mods);
264
265    check_jvmti_error(jvmti, "GetFieldModifiers", err);
266    printf("    Field modifiers: 0x%08x\n", mods);
267
268    err = (*jvmti)->IsFieldSynthetic(jvmti, klass, field, &is_synth);
269    check_jvmti_error(jvmti, "IsFieldSynthetic", err);
270    printf("    Field is synthetic: %d\n", is_synth);
271}
272
273static void test_field_functions(jvmtiEnv *jvmti, jclass klass, jfieldID field) {
274    print_field_name_sign(jvmti, klass, field);
275    print_field_declaring_class(jvmti, klass, field);
276    print_field_info(jvmti, klass, field);
277}
278
279static void test_class_functions(jvmtiEnv *jvmti, JNIEnv *env, jthread thread, jclass klass) {
280    jint count = 0;
281    jint idx = 0;
282    jmethodID* methods = NULL;
283    jfieldID*  fields = NULL;
284
285    print_class_signature(jvmti, klass);
286    print_class_status(jvmti, klass);
287    print_class_source_file_name(jvmti, klass);
288    print_class_info(jvmti, klass);
289
290    count = get_class_methods(jvmti, klass, &methods);
291    for (idx = 0; idx < count; idx++) {
292        test_method_functions(jvmti, methods[idx]);
293    }
294    if (methods != NULL) {
295        deallocate(jvmti, (char*)methods);
296    }
297    count = get_class_fields(jvmti, klass, &fields);
298    for (idx = 0; idx < count; idx++) {
299        test_field_functions(jvmti, klass, fields[idx]);
300    }
301    if (fields != NULL) {
302        deallocate(jvmti, (char*)fields);
303    }
304}
305
306static void JNICALL
307VMStart(jvmtiEnv *jvmti, JNIEnv* jni) {
308    jvmtiPhase phase;
309
310    printf("VMStart event\n");
311    get_phase(jvmti, &phase);
312    if (phase != JVMTI_PHASE_START && phase != JVMTI_PHASE_LIVE) {
313        printf("  ## Error: unexpected phase: %d, expected: %d or %d\n",
314               phase, JVMTI_PHASE_START, JVMTI_PHASE_LIVE);
315        result = FAILED;
316    }
317}
318
319static void JNICALL
320VMInit(jvmtiEnv *jvmti, JNIEnv* jnii, jthread thread) {
321    jvmtiPhase phase;
322
323    printf("VMInit event\n");
324    get_phase(jvmti, &phase);
325    if (phase != JVMTI_PHASE_LIVE) {
326        printf("  ## Error: unexpected phase: %d, expected: %d\n",
327               phase, JVMTI_PHASE_LIVE);
328        result = FAILED;
329    }
330}
331
332static void JNICALL
333ClassPrepare(jvmtiEnv *jvmti, JNIEnv *env, jthread thread, jclass klass) {
334    static const jint EVENTS_LIMIT = 2;
335    static       jint event_no = 0;
336    jthread cur_thread = get_cur_thread(jvmti);
337    jvmtiPhase phase;
338    intptr_t exp_val = 777;
339    intptr_t act_val;
340
341    get_phase(jvmti, &phase);
342    if (phase != JVMTI_PHASE_START && phase != JVMTI_PHASE_LIVE) {
343        printf("  ## Error: unexpected phase: %d, expected: %d or %d\n",
344               phase, JVMTI_PHASE_START, JVMTI_PHASE_LIVE);
345        return;
346    }
347    if (phase == JVMTI_PHASE_START && event_no < EVENTS_LIMIT) {
348        printf("\nClassPrepare event during the start phase: #%d\n", event_no);
349        // Test the JVMTI class functions during the start phase
350        test_class_functions(jvmti, env, thread, klass);
351
352        set_thread_local(jvmti, thread, exp_val);
353        act_val = get_thread_local(jvmti, cur_thread);
354        if (act_val != exp_val) { // Actual value does not match the expected
355            printf("  ## Unexpected thread-local: %ld, expected: %ld\n",
356                   (long)act_val, (long)exp_val);
357            result = FAILED;
358        } else {
359            printf("    Got expected thread-local: %ld\n", (long)exp_val);
360        }
361        event_no++;
362    }
363}
364
365static
366jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
367    jboolean with_early_vm_start_capability = JNI_FALSE;
368    jvmtiEnv *jvmti = NULL;
369    jvmtiError err;
370    jint res, size;
371    jvmtiCapabilities caps;
372    jvmtiEventCallbacks callbacks;
373
374    if (options != NULL && strstr(options, "with_early_vmstart") != NULL) {
375        with_early_vm_start_capability = JNI_TRUE;
376    }
377
378    res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **) &jvmti), JVMTI_VERSION_9);
379    if (res != JNI_OK || jvmti == NULL) {
380        printf("## Agent_Initialize: Error in GetEnv: res: %d, jvmti env: %p\n", res, jvmti);
381        return JNI_ERR;
382    }
383
384    memset(&caps, 0, sizeof(caps));
385    caps.can_get_source_file_name = 1;
386    caps.can_get_synthetic_attribute = 1;
387
388    if (with_early_vm_start_capability == JNI_TRUE) {
389        caps.can_generate_early_vmstart = 1;
390        printf("Capability enabled: can_generate_early_vmstart\n");
391    } else {
392        printf("Capability disabled: can_generate_early_vmstart\n");
393    }
394    err = (*jvmti)->AddCapabilities(jvmti, &caps);
395    check_jvmti_error(jvmti, "## Agent_Initialize: AddCapabilites", err);
396
397    size = (jint)sizeof(callbacks);
398    memset(&callbacks, 0, size);
399    callbacks.VMStart = VMStart;
400    callbacks.VMInit = VMInit;
401    callbacks.ClassPrepare = ClassPrepare;
402
403    err = (*jvmti)->SetEventCallbacks(jvmti, &callbacks, size);
404    check_jvmti_error(jvmti, "## Agent_Initialize: SetEventCallbacks", err);
405
406    err = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_START, NULL);
407    check_jvmti_error(jvmti, "## Agent_Initialize: SetEventNotificationMode VM_START", err);
408
409    err = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, NULL);
410    check_jvmti_error(jvmti, "## Agent_Initialize: SetEventNotificationMode VM_INIT", err);
411
412    err = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_CLASS_PREPARE, NULL);
413    check_jvmti_error(jvmti, "## Agent_Initialize: SetEventNotificationMode CLASS_PREPARE", err);
414    return JNI_OK;
415}
416
417JNIEXPORT jint JNICALL
418Java_AllowedFunctions_check(JNIEnv *env, jclass cls) {
419    return result;
420}
421
422#ifdef __cplusplus
423}
424#endif
425