1 /*
2  * Copyright (c) 2004, 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 <stdlib.h>
26 #include <string.h>
27 
28 #include <jvmti.h>
29 #include "agent_common.h"
30 
31 #include "nsk_tools.h"
32 #include "native_thread.h"
33 #include "JVMTITools.h"
34 #include "jvmti_tools.h"
35 
36 extern "C" {
37 
38 #define PASSED  0
39 #define STATUS_FAILED  2
40 
41 #define MAX_ATTEMPTS 15
42 
43 static const char *expHSMethod = "redefclass029HotMethod";
44 static const char *expHSSignature = "(I)V";
45 
46 #define EVENTS_COUNT 2
47 static jvmtiEvent eventsList[EVENTS_COUNT] = {
48     JVMTI_EVENT_COMPILED_METHOD_LOAD,
49     JVMTI_EVENT_COMPILED_METHOD_UNLOAD
50 };
51 
52 static jvmtiEnv *jvmti = NULL;
53 static jlong timeout = 0;
54 static volatile int fire = 0; /* CompiledMethodLoad received for hotspot method */
55 static jmethodID hsMethodID; /* hotspot method ID */
56 
57 static volatile int enteredHotMethod = 0; /* "hot" method is entered */
58 
59 static jint bytesCount; /* number of bytes of a redefining class */
60 static jbyte *clsBytes; /* bytes defining a redefining class */
61 
62 /** pass info about redefinition to Java **/
Java_nsk_jvmti_RedefineClasses_redefclass029_isRedefinitionOccurred(JNIEnv * jni_env,jclass cls)63 JNIEXPORT jboolean JNICALL Java_nsk_jvmti_RedefineClasses_redefclass029_isRedefinitionOccurred
64         (JNIEnv *jni_env, jclass cls)
65 {
66     if (fire == 1) {
67         NSK_DISPLAY0("isRedefinitionOccurred is called: fired!\n");
68         return JNI_TRUE;
69     } else {
70         return JNI_FALSE;
71     }
72 }
73 
74 /** notify native agent from Java when "hot" method is executed **/
Java_nsk_jvmti_RedefineClasses_redefclass029_notifyNativeAgent(JNIEnv * jni_env,jclass cls)75 JNIEXPORT void JNICALL Java_nsk_jvmti_RedefineClasses_redefclass029_notifyNativeAgent
76         (JNIEnv *jni_env, jclass cls)
77 {
78     if (enteredHotMethod == 0) {
79         NSK_DISPLAY0("notifyNativeAgent is called\n");
80         enteredHotMethod = 1;
81     }
82 }
83 
Java_nsk_jvmti_RedefineClasses_redefclass029_storeClassBytes(JNIEnv * jni_env,jclass cls,jbyteArray classBytes)84 JNIEXPORT void JNICALL Java_nsk_jvmti_RedefineClasses_redefclass029_storeClassBytes
85         (JNIEnv *jni_env, jclass cls, jbyteArray classBytes) {
86     jboolean isCopy;
87 
88     bytesCount = jni_env->GetArrayLength(classBytes);
89     clsBytes =
90         jni_env->GetByteArrayElements(classBytes, &isCopy);
91 }
92 
93 /** callback functions **/
94 void JNICALL
CompiledMethodLoad(jvmtiEnv * jvmti_env,jmethodID method,jint code_size,const void * code_addr,jint map_length,const jvmtiAddrLocationMap * map,const void * compile_info)95 CompiledMethodLoad(jvmtiEnv *jvmti_env, jmethodID method, jint code_size,
96         const void* code_addr,  jint map_length, const jvmtiAddrLocationMap* map,
97         const void* compile_info) {
98     char *name;
99     char *sig;
100 
101     NSK_DISPLAY0("CompiledMethodLoad event received for:\n");
102     if (!NSK_JVMTI_VERIFY(jvmti_env->GetMethodName(method, &name, &sig, NULL))) {
103         nsk_jvmti_setFailStatus();
104         return;
105     }
106     NSK_DISPLAY5("\tmethod: name=\"%s\" signature=\"%s\"\n"
107                  "\tcompiled code size=%d\n"
108                  "\tstarting native address=0x%p\n"
109                  "\tnumber of address location map entries=%d\n",
110                  name, sig, code_size, code_addr, map_length);
111 
112     if ((strcmp(name, expHSMethod) == 0) &&
113             (strcmp(sig, expHSSignature) == 0)) {
114         NSK_DISPLAY0("CompiledMethodLoad: a tested hotspot method found\n");
115 
116         // CR 6604375: check whether "hot" method was entered
117         if (enteredHotMethod) {
118             hsMethodID = method;
119             fire = 1;
120         } else {
121             NSK_DISPLAY0("Compilation occured before method execution. Ignoring.\n");
122         }
123     }
124 }
125 
126 JNIEXPORT void JNICALL
CompiledMethodUnload(jvmtiEnv * jvmti_env,jmethodID method,const void * code_addr)127 CompiledMethodUnload(jvmtiEnv* jvmti_env, jmethodID method,
128         const void* code_addr) {
129     char *name;
130     char *sig;
131     jvmtiError err;
132 
133     NSK_DISPLAY0("CompiledMethodUnload event received\n");
134     // Check for the case that the class has been unloaded
135     err = jvmti_env->GetMethodName(method, &name, &sig, NULL);
136     if (err == JVMTI_ERROR_NONE) {
137         NSK_DISPLAY3("for: \tmethod: name=\"%s\" signature=\"%s\"\n\tnative address=0x%p\n",
138           name, sig, code_addr);
139         jvmti_env->Deallocate((unsigned char*)name);
140         jvmti_env->Deallocate((unsigned char*)sig);
141     }
142 }
143 /************************/
144 
145 /** agent's procedure **/
146 static void JNICALL
agentProc(jvmtiEnv * jvmti_env,JNIEnv * jni_env,void * arg)147 agentProc(jvmtiEnv* jvmti_env, JNIEnv* jni_env, void* arg) {
148     int tries = 0;
149     jclass decl_cls;
150     char *cls_sig;
151     jvmtiClassDefinition classDef;
152 
153     /* testing sync */
154     NSK_DISPLAY1("agentProc: waiting for the debuggee start for %d msecs...\n\n",
155         (int) timeout);
156     if (!nsk_jvmti_waitForSync(timeout))
157         return;
158     NSK_DISPLAY0("agentProc: resuming the debuggee ...\n\n");
159     if (!nsk_jvmti_resumeSync())
160         return;
161 
162     /* at first, send all generated CompiledMethodLoad events */
163     NSK_DISPLAY0("agentProc: sending all generated CompiledMethodLoad events ...\n\n");
164     if (!NSK_JVMTI_VERIFY(jvmti->GenerateEvents(JVMTI_EVENT_COMPILED_METHOD_LOAD))) {
165         nsk_jvmti_setFailStatus();
166         nsk_jvmti_resumeSync();
167         return;
168     }
169 
170     NSK_DISPLAY0("agentProc: waiting for hotspot method compilation...\n\n");
171     do {
172         THREAD_sleep(1);
173         tries++;
174         if (tries > MAX_ATTEMPTS) {
175             printf("WARNING: CompiledMethodLoad event is still not received for \"%s\" after %d attempts\n"
176                    "\tThe test has no results\n\n",
177                    expHSMethod, MAX_ATTEMPTS);
178             nsk_jvmti_resumeSync();
179             exit(95 + PASSED);
180         }
181     } while (fire == 0);
182 
183     NSK_DISPLAY0("agentProc: hotspot method compiled\n\n");
184 
185     if (!NSK_JVMTI_VERIFY(jvmti_env->GetMethodDeclaringClass(hsMethodID, &decl_cls))) {
186         nsk_jvmti_setFailStatus();
187         nsk_jvmti_resumeSync();
188         return;
189     }
190     if (!NSK_JVMTI_VERIFY(jvmti_env->GetClassSignature(decl_cls, &cls_sig, NULL))) {
191         nsk_jvmti_setFailStatus();
192         nsk_jvmti_resumeSync();
193         return;
194     } else {
195         NSK_DISPLAY1("agentProc: hotspot method class signature: \"%s\"\n\n",
196                      cls_sig);
197     }
198 
199     /* fill the structure jvmtiClassDefinition */
200     classDef.klass = decl_cls;
201     classDef.class_byte_count = bytesCount;
202     classDef.class_bytes = (unsigned char*) clsBytes;
203 
204     NSK_DISPLAY1("agentProc: >>>>>>>> Invoke RedefineClasses():\n"
205                  "\tnew class byte count=%d\n",
206                  classDef.class_byte_count);
207     if (!NSK_JVMTI_VERIFY(jvmti->RedefineClasses(1, &classDef))) {
208       nsk_jvmti_setFailStatus();
209       nsk_jvmti_resumeSync();
210       return;
211     }
212     NSK_DISPLAY0("agentProc: <<<<<<<< RedefineClasses() is successfully done\n");
213 
214     /* testing sync */
215     NSK_DISPLAY1("agentProc: waiting for the debuggee finish for %d msecs...\n\n",
216         (int) timeout);
217     if (!nsk_jvmti_waitForSync(timeout))
218         return;
219     NSK_DISPLAY0("agentProc: final resuming of the debuggee ...\n\n");
220     if (!nsk_jvmti_resumeSync())
221         return;
222 
223     NSK_DISPLAY0("agentProc: finished\n\n");
224 }
225 
226 #ifdef STATIC_BUILD
Agent_OnLoad_redefclass029(JavaVM * jvm,char * options,void * reserved)227 JNIEXPORT jint JNICALL Agent_OnLoad_redefclass029(JavaVM *jvm, char *options, void *reserved) {
228     return Agent_Initialize(jvm, options, reserved);
229 }
Agent_OnAttach_redefclass029(JavaVM * jvm,char * options,void * reserved)230 JNIEXPORT jint JNICALL Agent_OnAttach_redefclass029(JavaVM *jvm, char *options, void *reserved) {
231     return Agent_Initialize(jvm, options, reserved);
232 }
JNI_OnLoad_redefclass029(JavaVM * jvm,char * options,void * reserved)233 JNIEXPORT jint JNI_OnLoad_redefclass029(JavaVM *jvm, char *options, void *reserved) {
234     return JNI_VERSION_1_8;
235 }
236 #endif
Agent_Initialize(JavaVM * jvm,char * options,void * reserved)237 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
238     jvmtiCapabilities caps;
239     jvmtiEventCallbacks callbacks;
240 
241     /* init framework and parse options */
242     if (!NSK_VERIFY(nsk_jvmti_parseOptions(options)))
243         return JNI_ERR;
244 
245     /* obtain WAITTIME parameter */
246         timeout = nsk_jvmti_getWaitTime() * 60000;
247     NSK_DISPLAY1("waittime=%d msecs\n", (int) timeout);
248 
249     /* create JVMTI environment */
250     if (!NSK_VERIFY((jvmti =
251             nsk_jvmti_createJVMTIEnv(jvm, reserved)) != NULL))
252         return JNI_ERR;
253 
254     /* add required capabilities */
255     memset(&caps, 0, sizeof(jvmtiCapabilities));
256     caps.can_generate_compiled_method_load_events = 1;
257     caps.can_redefine_classes = 1;
258     if (!NSK_JVMTI_VERIFY(jvmti->AddCapabilities(&caps)))
259         return JNI_ERR;
260 
261     /* set event callback */
262     NSK_DISPLAY0("setting event callbacks ...\n");
263     (void) memset(&callbacks, 0, sizeof(callbacks));
264     callbacks.CompiledMethodLoad = &CompiledMethodLoad;
265     callbacks.CompiledMethodUnload = &CompiledMethodUnload;
266     if (!NSK_JVMTI_VERIFY(jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks))))
267         return JNI_ERR;
268 
269     NSK_DISPLAY0("setting event callbacks done\nenabling events ...\n");
270     if (!nsk_jvmti_enableEvents(JVMTI_ENABLE, EVENTS_COUNT,
271             eventsList, NULL))
272         return JNI_ERR;
273     NSK_DISPLAY0("enabling the events done\n\n");
274 
275     /* register agent proc */
276     if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agentProc, NULL)))
277         return JNI_ERR;
278 
279     return JNI_OK;
280 }
281 
282 }
283