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