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 <string.h>
26 #include <jvmti.h>
27 #include "agent_common.h"
28 
29 #include "nsk_tools.h"
30 #include "JVMTITools.h"
31 #include "jvmti_tools.h"
32 
33 extern "C" {
34 
35 #define STATUS_FAILED 2
36 #define PASSED 0
37 
38 #define MAX_SIZE 256
39 
40 static jvmtiEnv *jvmti = NULL;
41 static jvmtiEventCallbacks callbacks;
42 static jvmtiCapabilities caps;
43 
44 static volatile int gcfinish = 0, gcstart = 0, objfree = 0;
45 static long objectCount = 0;
46 
47 static jlong nanos = 0;
48 static jlong timeout = 0;
49 static jvmtiTimerInfo timer_info1, timer_info2;
50 static int user_data = 0;
51 
52 typedef struct _LocalStorage {
53     unsigned char data[MAX_SIZE];
54 } LocalStorage;
55 
56 static LocalStorage stor;
57 
envStorageFunc(jvmtiEnv * jvmti_env,const char * msg)58 static void envStorageFunc(jvmtiEnv *jvmti_env, const char *msg) {
59     LocalStorage* obtainedData = NULL;
60     LocalStorage* storedData = &stor;
61 
62     NSK_DISPLAY2("%s: setting an environment local storage 0x%p ...\n",
63         msg, (void*) &stor);
64     if (!NSK_JVMTI_VERIFY(jvmti_env->SetEnvironmentLocalStorage((const void*) &stor))) {
65         nsk_jvmti_setFailStatus();
66         NSK_COMPLAIN1("%s: unable to set an environment local storage\n\n",
67             msg);
68         return;
69     }
70 
71     NSK_DISPLAY1("%s: getting an environment local storage ...\n",
72         msg);
73     if (!NSK_JVMTI_VERIFY(jvmti_env->GetEnvironmentLocalStorage((void**) &obtainedData))) {
74         nsk_jvmti_setFailStatus();
75         NSK_COMPLAIN1("%s: unable to get an environment local storage\n\n",
76             msg);
77         return;
78     }
79     else {
80         if (obtainedData != storedData) {
81             nsk_jvmti_setFailStatus();
82             NSK_COMPLAIN3(
83                 "%s: obtained an environment local storage has unexpected pointer:\n"
84                 "got: 0x%p\texpected: 0x%p\n\n",
85                 msg, (void*) obtainedData, (void*) storedData);
86         }
87     }
88 }
89 
timerFunc(jvmtiEnv * jvmti_env,const char * msg)90 static void timerFunc(jvmtiEnv *jvmti_env, const char *msg) {
91     if (!NSK_JVMTI_VERIFY(jvmti_env->GetCurrentThreadCpuTimerInfo(&timer_info1))) {
92         nsk_jvmti_setFailStatus();
93         NSK_COMPLAIN1("%s: GetCurrentThreadCpuTimerInfo returned unexpected error code\n\n",
94             msg);
95     }
96     /* Check the returned jvmtiTimerInfo structure */
97     if (timer_info1.max_value == 0) {
98         nsk_jvmti_setFailStatus();
99         NSK_COMPLAIN1("%s: GetCurrentThreadCpuTimerInfo returned zero in jvmtiTimerInfo.max_value\n\n",
100             msg);
101     }
102     if (timer_info1.may_skip_forward != JNI_TRUE && timer_info1.may_skip_forward != JNI_FALSE) {
103         nsk_jvmti_setFailStatus();
104         NSK_COMPLAIN1("%s: GetCurrentThreadCpuTimerInfo returned unknown type value in jvmtiTimerInfo.may_skip_forward\n\n",
105             msg);
106     }
107     if (timer_info1.may_skip_backward != JNI_TRUE && timer_info1.may_skip_backward != JNI_FALSE) {
108         nsk_jvmti_setFailStatus();
109         NSK_COMPLAIN1("%s: GetCurrentThreadCpuTimerInfo returned unknown type value in jvmtiTimerInfo.may_skip_backward\n\n",
110             msg);
111     }
112     /* ---------------------------------------------------------------------- */
113 
114     if (!NSK_JVMTI_VERIFY(jvmti_env->GetCurrentThreadCpuTime(&nanos))) {
115         nsk_jvmti_setFailStatus();
116         NSK_COMPLAIN1("%s: GetCurrentThreadCpuTime returned unexpected error code\n\n",
117             msg);
118     }
119     /* ---------------------------------------------------------------------- */
120 
121 
122     if (!NSK_JVMTI_VERIFY(jvmti_env->GetTimerInfo(&timer_info2))) {
123         nsk_jvmti_setFailStatus();
124         NSK_COMPLAIN1("%s: GetTimerInfo returned unexpected error code\n\n",
125             msg);
126     }
127     /* Check the returned jvmtiTimerInfo structure */
128     if (timer_info2.max_value == 0) {
129         nsk_jvmti_setFailStatus();
130         NSK_COMPLAIN1("%s: GetTimerInfo returned zero in jvmtiTimerInfo.max_value\n\n",
131             msg);
132     }
133     if (timer_info2.may_skip_forward != JNI_TRUE && timer_info2.may_skip_forward != JNI_FALSE) {
134         nsk_jvmti_setFailStatus();
135         NSK_COMPLAIN1("%s: GetTimerInfo returned unknown type value in jvmtiTimerInfo.may_skip_forward\n\n",
136             msg);
137     }
138     if (timer_info2.may_skip_backward != JNI_TRUE && timer_info2.may_skip_backward != JNI_FALSE) {
139         nsk_jvmti_setFailStatus();
140         NSK_COMPLAIN1("%s: GetTimerInfo returned unknown type value in jvmtiTimerInfo.may_skip_backward\n\n",
141             msg);
142     }
143     /* ---------------------------------------------------------------------- */
144 
145     nanos = 0;
146     if (!NSK_JVMTI_VERIFY(jvmti_env->GetTime(&nanos))) {
147         nsk_jvmti_setFailStatus();
148         NSK_COMPLAIN1("%s: GetTime returned unexpected error code\n\n",
149             msg);
150     }
151 
152 }
153 
154 /** callback functions **/
155 void JNICALL
GarbageCollectionFinish(jvmtiEnv * jvmti_env)156 GarbageCollectionFinish(jvmtiEnv *jvmti_env) {
157     gcfinish++;
158     NSK_DISPLAY1(">>>> GarbageCollectionFinish event #%d received\n",
159         gcfinish);
160 
161     timerFunc(jvmti_env, "GarbageCollectionFinish");
162 
163     envStorageFunc(jvmti_env, "GarbageCollectionFinish");
164 
165     NSK_DISPLAY0("<<<<\n\n");
166 }
167 
168 void JNICALL
GarbageCollectionStart(jvmtiEnv * jvmti_env)169 GarbageCollectionStart(jvmtiEnv *jvmti_env) {
170     gcstart++;
171     NSK_DISPLAY1(">>>> GarbageCollectionStart event #%d received\n",
172         gcstart);
173 
174     timerFunc(jvmti_env, "GarbageCollectionStart");
175 
176     envStorageFunc(jvmti_env, "GarbageCollectionStart");
177 
178     NSK_DISPLAY0("<<<<\n\n");
179 }
180 
181 void JNICALL
ObjectFree(jvmtiEnv * jvmti_env,jlong tag)182 ObjectFree(jvmtiEnv *jvmti_env, jlong tag) {
183     NSK_DISPLAY0(">>>> ObjectFree event received\n");
184     objfree++;
185 
186     timerFunc(jvmti_env, "ObjectFree");
187 
188     envStorageFunc(jvmti_env, "ObjectFree");
189 
190     NSK_DISPLAY0("<<<<\n\n");
191 }
192 
193 jvmtiIterationControl JNICALL
heapObjectCallback(jlong class_tag,jlong size,jlong * tag_ptr,void * user_data)194 heapObjectCallback(jlong class_tag,
195                    jlong size,
196                    jlong* tag_ptr,
197                    void* user_data) {
198 
199     /* set tag */
200     *tag_ptr = (jlong)++objectCount;
201 
202     /* iterate over only first MAX_SIZE objects */
203     if (objectCount >= MAX_SIZE)
204         return JVMTI_ITERATION_ABORT;
205 
206     return JVMTI_ITERATION_CONTINUE;
207 }
208 
209 /************************/
210 
211 static void JNICALL
agentProc(jvmtiEnv * jvmti,JNIEnv * jni,void * arg)212 agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) {
213 
214     NSK_DISPLAY0("Wait for debugee start\n\n");
215     if (!NSK_VERIFY(nsk_jvmti_waitForSync(timeout)))
216         return;
217 
218     NSK_DISPLAY0("Call IterateOverHeap to tag random objects for ObjectFree evnts\n\n");
219     {
220         if (!NSK_JVMTI_VERIFY(jvmti->IterateOverHeap(JVMTI_HEAP_OBJECT_UNTAGGED,
221                                                      heapObjectCallback,
222                                                      &user_data))) {
223             nsk_jvmti_setFailStatus();
224         }
225     }
226     if (objectCount == 0) {
227         nsk_jvmti_setFailStatus();
228         NSK_COMPLAIN0("IterateOverHeap call had not visited any object\n\n");
229     } else {
230         NSK_DISPLAY1("Number of objects IterateOverHeap visited: %d\n\n", objectCount);
231     }
232 
233     NSK_DISPLAY0("Let debugee to provoke GC\n");
234     if (!NSK_VERIFY(nsk_jvmti_resumeSync()))
235         return;
236     if (!NSK_VERIFY(nsk_jvmti_waitForSync(timeout)))
237         return;
238 
239     NSK_DISPLAY0("Let debugee to finish\n");
240     if (!NSK_VERIFY(nsk_jvmti_resumeSync()))
241         return;
242 }
243 
244 #ifdef STATIC_BUILD
Agent_OnLoad_ap10t001(JavaVM * jvm,char * options,void * reserved)245 JNIEXPORT jint JNICALL Agent_OnLoad_ap10t001(JavaVM *jvm, char *options, void *reserved) {
246     return Agent_Initialize(jvm, options, reserved);
247 }
Agent_OnAttach_ap10t001(JavaVM * jvm,char * options,void * reserved)248 JNIEXPORT jint JNICALL Agent_OnAttach_ap10t001(JavaVM *jvm, char *options, void *reserved) {
249     return Agent_Initialize(jvm, options, reserved);
250 }
JNI_OnLoad_ap10t001(JavaVM * jvm,char * options,void * reserved)251 JNIEXPORT jint JNI_OnLoad_ap10t001(JavaVM *jvm, char *options, void *reserved) {
252     return JNI_VERSION_1_8;
253 }
254 #endif
Agent_Initialize(JavaVM * jvm,char * options,void * reserved)255 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
256     /* init framework and parse options */
257     if (!NSK_VERIFY(nsk_jvmti_parseOptions(options)))
258         return JNI_ERR;
259 
260     /* create JVMTI environment */
261     if (!NSK_VERIFY((jvmti =
262             nsk_jvmti_createJVMTIEnv(jvm, reserved)) != NULL))
263         return JNI_ERR;
264 
265     /* add capability to generate compiled method events */
266     memset(&caps, 0, sizeof(jvmtiCapabilities));
267     caps.can_tag_objects = 1;
268     caps.can_get_current_thread_cpu_time = 1;
269     caps.can_get_thread_cpu_time = 1;
270     caps.can_generate_object_free_events = 1;
271     caps.can_generate_garbage_collection_events = 1;
272     if (!NSK_JVMTI_VERIFY(jvmti->AddCapabilities(&caps)))
273         return JNI_ERR;
274 
275     if (!NSK_JVMTI_VERIFY(jvmti->GetCapabilities(&caps)))
276         return JNI_ERR;
277 
278     if (!caps.can_generate_garbage_collection_events)
279         NSK_DISPLAY0("Warning: generation of garbage collection events is not implemented\n");
280     if (!caps.can_generate_object_free_events)
281         NSK_DISPLAY0("Warning: generation of object free events is not implemented\n");
282     if (!caps.can_tag_objects)
283         NSK_DISPLAY0("Warning: tagging objects is not implemented\n");
284 
285     /* set event callback */
286     NSK_DISPLAY0("setting event callbacks ...\n");
287     (void) memset(&callbacks, 0, sizeof(callbacks));
288 
289     callbacks.GarbageCollectionStart = &GarbageCollectionStart;
290     callbacks.GarbageCollectionFinish = &GarbageCollectionFinish;
291     callbacks.ObjectFree = &ObjectFree;
292 
293     if (!NSK_JVMTI_VERIFY(jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks))))
294         return JNI_ERR;
295 
296     NSK_DISPLAY0("setting event callbacks done\nenabling JVMTI events ...\n");
297     if (!NSK_JVMTI_VERIFY(jvmti->SetEventNotificationMode(JVMTI_ENABLE,
298                                                           JVMTI_EVENT_GARBAGE_COLLECTION_START,
299                                                           NULL)))
300         return JNI_ERR;
301     if (!NSK_JVMTI_VERIFY(jvmti->SetEventNotificationMode(JVMTI_ENABLE,
302                                                           JVMTI_EVENT_GARBAGE_COLLECTION_FINISH,
303                                                           NULL)))
304         return JNI_ERR;
305     if (!NSK_JVMTI_VERIFY(jvmti->SetEventNotificationMode(JVMTI_ENABLE,
306                                                           JVMTI_EVENT_OBJECT_FREE,
307                                                           NULL)))
308         return JNI_ERR;
309     NSK_DISPLAY0("enabling the events done\n\n");
310 
311     if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agentProc, NULL)))
312         return JNI_ERR;
313 
314     return JNI_OK;
315 }
316 
317 }
318