1 /*
2  * Copyright (c) 2003, 2018, 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 "jvmti.h"
27 #include "agent_common.h"
28 #include "JVMTITools.h"
29 
30 extern "C" {
31 
32 
33 #define PASSED 0
34 #define STATUS_FAILED 2
35 
36 static JavaVM *jvm_ins;
37 static jvmtiEnv *jvmti = NULL;
38 static jvmtiEventCallbacks callbacks;
39 static jint result = PASSED;
40 static jboolean printdump = JNI_FALSE;
41 static jboolean agent_was_started = JNI_FALSE;
42 static jboolean done = JNI_FALSE;
43 
44 
jthr(JNIEnv * env)45 jthread jthr(JNIEnv *env) {
46     jclass thrClass;
47     jmethodID cid;
48     jthread res;
49 
50     thrClass = env->FindClass("java/lang/Thread");
51     cid = env->GetMethodID(thrClass, "<init>", "()V");
52     res = env->NewObject(thrClass, cid);
53     return res;
54 }
55 
agent_start(jvmtiEnv * jvmti_env,JNIEnv * jni_env,void * p)56 void JNICALL agent_start(jvmtiEnv* jvmti_env, JNIEnv* jni_env, void *p) {
57     JNIEnv *env;
58 
59     if (jvmti_env != jvmti) {
60         printf("(agent_start) JVMTI envs don't match\n");
61         result = STATUS_FAILED;
62     }
63 
64     jvm_ins->GetEnv((void **) &env, JNI_VERSION_1_2);
65     if (jni_env != env) {
66         printf("(agent_start) JNI envs don't match\n");
67         result = STATUS_FAILED;
68     }
69 
70     if ((size_t)p != 12345) {
71         printf("(agent_start) args don't match\n");
72         result = STATUS_FAILED;
73     }
74     done = JNI_TRUE;
75 }
76 
77 
78 
vm_init(jvmtiEnv * jvmti_env,JNIEnv * env,jthread thread)79 void JNICALL vm_init(jvmtiEnv* jvmti_env, JNIEnv *env, jthread thread) {
80     jvmtiError err;
81 
82     if (!agent_was_started) {
83         agent_was_started = JNI_TRUE;
84 
85         err = jvmti->RunAgentThread(jthr(env), agent_start,
86             (void *)999, JVMTI_THREAD_MAX_PRIORITY+1);
87         if (err != JVMTI_ERROR_INVALID_PRIORITY) {
88             printf("(RunAgentThread#1) expected JVMTI_ERROR_INVALID_PRIORITY got error: %s (%d)\n",
89                    TranslateError(err), err);
90             result = STATUS_FAILED;
91         }
92         err = jvmti->RunAgentThread(jthr(env), agent_start,
93             (void *)999, JVMTI_THREAD_MIN_PRIORITY-1);
94         if (err != JVMTI_ERROR_INVALID_PRIORITY) {
95             printf("(RunAgentThread#1) expected JVMTI_ERROR_INVALID_PRIORITY got error: %s (%d)\n",
96                    TranslateError(err), err);
97             result = STATUS_FAILED;
98         }
99         err = jvmti->RunAgentThread(jthr(env), agent_start,
100             (void *)12345, JVMTI_THREAD_NORM_PRIORITY);
101         if (err != JVMTI_ERROR_NONE) {
102             printf("(RunAgentThread#2) unexpected error: %s (%d)\n",
103                    TranslateError(err), err);
104             result = STATUS_FAILED;
105         }
106     }
107 }
108 
109 #ifdef STATIC_BUILD
Agent_OnLoad_agentthr(JavaVM * jvm,char * options,void * reserved)110 JNIEXPORT jint JNICALL Agent_OnLoad_agentthr(JavaVM *jvm, char *options, void *reserved) {
111     return Agent_Initialize(jvm, options, reserved);
112 }
Agent_OnAttach_agentthr(JavaVM * jvm,char * options,void * reserved)113 JNIEXPORT jint JNICALL Agent_OnAttach_agentthr(JavaVM *jvm, char *options, void *reserved) {
114     return Agent_Initialize(jvm, options, reserved);
115 }
JNI_OnLoad_agentthr(JavaVM * jvm,char * options,void * reserved)116 JNIEXPORT jint JNI_OnLoad_agentthr(JavaVM *jvm, char *options, void *reserved) {
117     return JNI_VERSION_1_8;
118 }
119 #endif
Agent_Initialize(JavaVM * jvm,char * options,void * reserved)120 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
121     jvmtiError err;
122     jint res;
123 
124     if (options != NULL && strcmp(options, "printdump") == 0) {
125         printdump = JNI_TRUE;
126     }
127 
128     jvm_ins = jvm;
129     res = jvm->GetEnv((void **) &jvmti, JVMTI_VERSION_1_1);
130     if (res != JNI_OK || jvmti == NULL) {
131         printf("Wrong result of a valid call to GetEnv!\n");
132         return JNI_ERR;
133     }
134 
135     callbacks.VMInit = &vm_init;
136     err = jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks));
137     if (err != JVMTI_ERROR_NONE) {
138         printf("(SetEventCallbacks) unexpected error: %s (%d)\n",
139                TranslateError(err), err);
140         return JNI_ERR;
141     }
142 
143     err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, NULL);
144     if (err != JVMTI_ERROR_NONE) {
145         printf("Failed to enable JVMTI_EVENT_THREAD_START: %s (%d)\n",
146                TranslateError(err), err);
147         return JNI_ERR;
148     }
149 
150     return JNI_OK;
151 }
152 
153 JNIEXPORT jboolean JNICALL
Java_nsk_jvmti_unit_agentthr_isOver(JNIEnv * env,jclass cls)154 Java_nsk_jvmti_unit_agentthr_isOver(JNIEnv *env, jclass cls) {
155     return done;
156 }
157 
158 JNIEXPORT jint JNICALL
Java_nsk_jvmti_unit_agentthr_getRes(JNIEnv * env,jclass cls)159 Java_nsk_jvmti_unit_agentthr_getRes(JNIEnv *env, jclass cls) {
160     if (!done) {
161         printf("agent thread has not completed\n");
162         result = STATUS_FAILED;
163     }
164     return result;
165 }
166 
167 }
168