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 <string.h>
25 #include "jvmti.h"
26
27 extern "C" {
28
29 #define AGENT_NAME "agent2"
30
31 static JavaVM *java_vm = NULL;
32 static jthread exp_thread = NULL;
33 static jvmtiEnv *jvmti2 = NULL;
34 static jint agent2_event_count = 0;
35 static bool fail_status = false;
36
37 static void
check_jvmti_status(JNIEnv * env,jvmtiError err,const char * msg)38 check_jvmti_status(JNIEnv* env, jvmtiError err, const char* msg) {
39 if (err != JVMTI_ERROR_NONE) {
40 printf("check_jvmti_status: JVMTI function returned error: %d\n", err);
41 fail_status = true;
42 env->FatalError(msg);
43 }
44 }
45
46 static void JNICALL
CompiledMethodLoad(jvmtiEnv * jvmti,jmethodID method,jint code_size,const void * code_addr,jint map_length,const jvmtiAddrLocationMap * map,const void * compile_info)47 CompiledMethodLoad(jvmtiEnv* jvmti, jmethodID method,
48 jint code_size, const void* code_addr,
49 jint map_length, const jvmtiAddrLocationMap* map,
50 const void* compile_info) {
51 JNIEnv* env = NULL;
52 jthread thread = NULL;
53 char* name = NULL;
54 char* sign = NULL;
55 jvmtiError err;
56
57 // Posted on JavaThread's, so it is legal to obtain JNIEnv*
58 if (java_vm->GetEnv((void **) (&env), JNI_VERSION_9) != JNI_OK) {
59 fail_status = true;
60 return;
61 }
62
63 err = jvmti->GetCurrentThread(&thread);
64 check_jvmti_status(env, err, "CompiledMethodLoad: Error in JVMTI GetCurrentThread");
65 if (!env->IsSameObject(thread, exp_thread)) {
66 return; // skip events from unexpected threads
67 }
68 agent2_event_count++;
69
70 err = jvmti->GetMethodName(method, &name, &sign, NULL);
71 check_jvmti_status(env, err, "CompiledMethodLoad: Error in JVMTI GetMethodName");
72
73 printf("%s: CompiledMethodLoad: %s%s\n", AGENT_NAME, name, sign);
74 fflush(0);
75 }
76
77 JNIEXPORT jint JNICALL
Agent_OnLoad(JavaVM * jvm,char * options,void * reserved)78 Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {
79 jvmtiEventCallbacks callbacks;
80 jvmtiCapabilities caps;
81 jvmtiError err;
82
83 java_vm = jvm;
84 if (jvm->GetEnv((void **) (&jvmti2), JVMTI_VERSION_9) != JNI_OK) {
85 return JNI_ERR;
86 }
87
88 memset(&callbacks, 0, sizeof(callbacks));
89 callbacks.CompiledMethodLoad = &CompiledMethodLoad;
90
91 err = jvmti2->SetEventCallbacks(&callbacks, sizeof(jvmtiEventCallbacks));
92 if (err != JVMTI_ERROR_NONE) {
93 printf("Agent_OnLoad: Error in JVMTI SetEventCallbacks: %d\n", err);
94 fail_status = true;
95 return JNI_ERR;
96 }
97
98 memset(&caps, 0, sizeof(caps));
99 caps.can_generate_compiled_method_load_events = 1;
100
101 err = jvmti2->AddCapabilities(&caps);
102 if (err != JVMTI_ERROR_NONE) {
103 printf("Agent_OnLoad: Error in JVMTI AddCapabilities: %d\n", err);
104 fail_status = true;
105 return JNI_ERR;
106 }
107 return JNI_OK;
108 }
109
110 JNIEXPORT void JNICALL
Java_MyPackage_GenerateEventsTest_agent2SetThread(JNIEnv * env,jclass cls,jthread thread)111 Java_MyPackage_GenerateEventsTest_agent2SetThread(JNIEnv *env, jclass cls, jthread thread) {
112 jvmtiError err;
113
114 exp_thread = (jthread)env->NewGlobalRef(thread);
115
116 err = jvmti2->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_COMPILED_METHOD_LOAD, NULL);
117 check_jvmti_status(env, err, "setThread2: Error in JVMTI SetEventNotificationMode: JVMTI_ENABLE");
118 }
119
120 JNIEXPORT jboolean JNICALL
Java_MyPackage_GenerateEventsTest_agent2FailStatus(JNIEnv * env,jclass cls)121 Java_MyPackage_GenerateEventsTest_agent2FailStatus(JNIEnv *env, jclass cls) {
122 jvmtiError err;
123
124 err = jvmti2->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_COMPILED_METHOD_LOAD, NULL);
125 check_jvmti_status(env, err, "check2: Error in JVMTI SetEventNotificationMode: JVMTI_DISABLE");
126
127 printf("\n");
128 if (agent2_event_count == 0) {
129 printf("check2: Zero events in agent2 as expected\n");
130 } else {
131 fail_status = true;
132 printf("check2: Unexpected non-zero event count in agent2: %d\n", agent2_event_count);
133 }
134 printf("\n");
135 fflush(0);
136
137 return fail_status;
138 }
139
140 } // extern "C"
141