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 <stdlib.h>
26 #include <memory.h>
27 
28 #include "jni.h"
29 #include "jvmti.h"
30 #include "agent_common.h"
31 
32 static jvmtiEnv *jvmti;
33 static jint dummy_user_data;
34 static jboolean user_data_error_flag = JNI_FALSE;
35 
36 /*
37  * Default callbacks
38  */
39 
40 static jvmtiEventObjectFree object_free_callback;
41 
default_object_free(jvmtiEnv * env,jlong tag)42 static void JNICALL default_object_free(jvmtiEnv *env, jlong tag) {
43     if (object_free_callback != NULL) {
44         (*object_free_callback)(env, tag);
45     }
46 }
47 
default_heap_object_callback(jlong class_tag,jlong size,jlong * tag_ptr,void * user_data)48 static jvmtiIterationControl JNICALL default_heap_object_callback
49     (jlong class_tag, jlong size, jlong* tag_ptr, void* user_data)
50 {
51     if (user_data != &dummy_user_data && user_data_error_flag == JNI_FALSE) {
52         user_data_error_flag = JNI_TRUE;
53         fprintf(stderr, "WARNING: (default) unexpected value of user_data\n");
54     }
55     return JVMTI_ITERATION_ABORT;
56 }
57 
58 static jvmtiHeapObjectCallback heap_object_callback = default_heap_object_callback;
59 static jvmtiHeapRootCallback heap_root_callback = NULL;
60 static jvmtiStackReferenceCallback stack_ref_callback = NULL;
61 static jvmtiObjectReferenceCallback object_ref_callback = NULL;
62 
63 /*
64  * Basic tagging functions
65  */
66 
Java_nsk_share_jvmti_unit_Heap_setTag0(JNIEnv * env,jclass cls,jobject o,jlong tag)67 JNIEXPORT jint JNICALL Java_nsk_share_jvmti_unit_Heap_setTag0
68   (JNIEnv *env, jclass cls, jobject o, jlong tag)
69 {
70     return (*jvmti)->SetTag(jvmti, o, tag);
71 }
72 
Java_nsk_share_jvmti_unit_Heap_getTag0(JNIEnv * env,jclass cls,jobject o)73 JNIEXPORT jlong JNICALL Java_nsk_share_jvmti_unit_Heap_getTag0
74    (JNIEnv *env, jclass cls, jobject o)
75 {
76     jlong tag;
77     jvmtiError err = (*jvmti)->GetTag(jvmti, o, &tag);
78     if (err != JVMTI_ERROR_NONE) {
79         fprintf(stderr, "ERORR: GetTag failed: JVMTI error=%d\n", err);
80         return 0;
81     }
82     return tag;
83 }
84 
Java_nsk_share_jvmti_unit_Heap_getObjectSize(JNIEnv * env,jclass cls,jobject o)85 JNIEXPORT jlong JNICALL Java_nsk_share_jvmti_unit_Heap_getObjectSize
86     (JNIEnv *env, jclass cls, jobject o)
87 {
88     jlong size;
89     jvmtiError err = (*jvmti)->GetObjectSize(jvmti, o, &size);
90     if (err != JVMTI_ERROR_NONE) {
91         fprintf(stderr, "ERORR: GetObjectSize failed: JVMTI error=%d\n", err);
92         return 0;
93     }
94     return size;
95 }
96 
97 /*
98  * Iterations functions
99  */
100 
Java_nsk_share_jvmti_unit_Heap_iterateOverHeap0(JNIEnv * env,jclass cls,jint filter_kind)101 JNIEXPORT jint JNICALL Java_nsk_share_jvmti_unit_Heap_iterateOverHeap0
102    (JNIEnv *env, jclass cls, jint filter_kind)
103 {
104     if (heap_object_callback == default_heap_object_callback) {
105         fprintf(stderr, "WARNING: default heap_object_callback set\n");
106     }
107     user_data_error_flag = JNI_FALSE;
108     return (*jvmti)->IterateOverHeap(jvmti,
109         filter_kind, heap_object_callback, &dummy_user_data);
110 }
111 
Java_nsk_share_jvmti_unit_Heap_iterateOverInstancesOfClass0(JNIEnv * env,jclass this_cls,jclass target_cls,jint filter_kind)112 JNIEXPORT jint JNICALL Java_nsk_share_jvmti_unit_Heap_iterateOverInstancesOfClass0
113    (JNIEnv *env, jclass this_cls, jclass target_cls, jint filter_kind)
114 {
115     if (heap_object_callback == default_heap_object_callback) {
116         fprintf(stderr, "WARNING: default heap_object_callback set\n");
117     }
118     user_data_error_flag = JNI_FALSE;
119     return (*jvmti)->IterateOverInstancesOfClass(jvmti, target_cls,
120         filter_kind, heap_object_callback, &dummy_user_data);
121 }
122 
Java_nsk_share_jvmti_unit_Heap_iterateOverReachableObjects0(JNIEnv * env,jclass this_cls)123 JNIEXPORT jint JNICALL Java_nsk_share_jvmti_unit_Heap_iterateOverReachableObjects0
124     (JNIEnv *env, jclass this_cls)
125 {
126     jvmtiError err;
127     user_data_error_flag = JNI_FALSE;
128     err = (*jvmti)->IterateOverReachableObjects(jvmti, heap_root_callback,
129         stack_ref_callback, object_ref_callback, &dummy_user_data);
130     if (err != JVMTI_ERROR_NONE) {
131         fprintf(stderr, "IterateOverReachableObjects failed: jvmti error=%d", err);
132     }
133     return err;
134 }
135 
Java_nsk_share_jvmti_unit_Heap_iterateOverObjectsReachableFromObject0(JNIEnv * env,jclass this_cls,jobject o)136 JNIEXPORT jint JNICALL Java_nsk_share_jvmti_unit_Heap_iterateOverObjectsReachableFromObject0
137     (JNIEnv *env, jclass this_cls, jobject o)
138 {
139     jvmtiError err;
140     user_data_error_flag = JNI_FALSE;
141     err = (*jvmti)->IterateOverObjectsReachableFromObject(jvmti, o,
142         object_ref_callback, &dummy_user_data);
143     if (err != JVMTI_ERROR_NONE) {
144         fprintf(stderr, "IterateOverObjectsReachableFromObject failed: jvmti error=%d", err);
145     }
146     return err;
147 }
148 
149 
150 /*
151  * GetObjectsWithTags tests
152  */
153 
154 static jobject object_results_ref;
155 static jobject tag_results_ref;
156 
Java_nsk_share_jvmti_unit_Heap_tagResults(JNIEnv * env,jclass this_cls)157 JNIEXPORT jlongArray JNICALL Java_nsk_share_jvmti_unit_Heap_tagResults
158     (JNIEnv *env, jclass this_cls)
159 {
160     return (jlongArray)tag_results_ref;
161 }
162 
Java_nsk_share_jvmti_unit_Heap_objectResults(JNIEnv * env,jclass this_cls)163 JNIEXPORT jobjectArray JNICALL Java_nsk_share_jvmti_unit_Heap_objectResults
164     (JNIEnv *env, jclass this_cls)
165 {
166     return (jobjectArray)object_results_ref;
167 }
168 
Java_nsk_share_jvmti_unit_Heap_getObjectsWithTags(JNIEnv * env,jclass this_cls,jint count,jlongArray array)169 JNIEXPORT jint JNICALL Java_nsk_share_jvmti_unit_Heap_getObjectsWithTags
170     (JNIEnv *env, jclass this_cls, jint count, jlongArray array)
171 {
172     jlong *tags;
173     jint i;
174     jvmtiError err;
175     jobject *object_results;
176     jlong *tag_results;
177     jclass cls;
178     jobjectArray object_array;
179     jlongArray tag_array;
180 
181     /* get rid of any arrays that we are holding from a previous call */
182 
183     if (object_results_ref != NULL) {
184         (*env)->DeleteGlobalRef(env, object_results_ref);
185         object_results_ref = NULL;
186     }
187     if (tag_results_ref != NULL) {
188         (*env)->DeleteGlobalRef(env, tag_results_ref);
189         tag_results_ref = NULL;
190     }
191 
192     /* copy input list-of-tags from java into C */
193 
194     tags = (jlong*)malloc(count * sizeof(jlong));
195     (*env)->GetLongArrayRegion(env, array, 0, count, tags);
196 
197     err = (*jvmti)->GetObjectsWithTags(jvmti, count, tags,
198                 &count, &object_results, &tag_results);
199 
200     /* free the input argument that we malloced */
201     free(tags);
202     if (err != JVMTI_ERROR_NONE) {
203         fprintf(stderr, "ERROR: GetObjectsWithTags failed: %d\n", err);
204         return err;
205     }
206 
207     /* copy output from C arrays into Java arrays */
208 
209     cls = (*env)->FindClass(env, "java/lang/Object");
210 
211     object_array = (*env)->NewObjectArray(env, count, cls, NULL);
212     tag_array = (*env)->NewLongArray(env, count);
213 
214     for (i=0; i<count; i++) {
215         (*env)->SetObjectArrayElement(env, object_array, i, object_results[i]);
216     }
217     (*env)->SetLongArrayRegion(env, tag_array, 0, count, tag_results);
218 
219     /* create JNI global refs as the current refs are local */
220 
221     object_results_ref = (*env)->NewGlobalRef(env, object_array);
222     tag_results_ref = (*env)->NewGlobalRef(env, tag_array);
223 
224     (*jvmti)->Deallocate(jvmti, (unsigned char*)object_results);
225     (*jvmti)->Deallocate(jvmti, (unsigned char*)tag_results);
226 
227     return count;
228 }
229 
230 /************* Basic Iteration Tests **************/
231 
232 static jint object_count;
233 
tagged_object_count_callback(jlong class_tag,jlong size,jlong * tag_ptr,void * user_data)234 static jvmtiIterationControl JNICALL tagged_object_count_callback
235     (jlong class_tag, jlong size, jlong* tag_ptr, void* user_data)
236 {
237     if (user_data != &dummy_user_data && user_data_error_flag == JNI_FALSE) {
238         user_data_error_flag = JNI_TRUE;
239         fprintf(stderr, "WARNING: (tagged) unexpected value of user_data\n");
240     }
241     if (*tag_ptr != 0) {
242         object_count++;
243     }
244     return JVMTI_ITERATION_CONTINUE;
245 }
246 
total_object_count_callback(jlong class_tag,jlong size,jlong * tag_ptr,void * user_data)247 static jvmtiIterationControl JNICALL total_object_count_callback
248     (jlong class_tag, jlong size, jlong* tag_ptr, void* user_data)
249 {
250     if (user_data != &dummy_user_data && user_data_error_flag == JNI_FALSE) {
251         user_data_error_flag = JNI_TRUE;
252         fprintf(stderr, "WARNING: (total) unexpected value of user_data\n");
253     }
254     if (*tag_ptr != 0) {
255         object_count++;
256     }
257     return JVMTI_ITERATION_CONTINUE;
258 }
259 
260 
Java_nsk_share_jvmti_unit_Heap_setTaggedObjectCountCallback(JNIEnv * env,jclass cls)261 JNIEXPORT void JNICALL Java_nsk_share_jvmti_unit_Heap_setTaggedObjectCountCallback
262     (JNIEnv *env, jclass cls)
263 {
264     heap_object_callback = tagged_object_count_callback;
265     object_count = 0;
266 }
267 
Java_nsk_share_jvmti_unit_Heap_setTotalObjectCountCallback(JNIEnv * env,jclass cls)268 JNIEXPORT void JNICALL Java_nsk_share_jvmti_unit_Heap_setTotalObjectCountCallback
269     (JNIEnv *env, jclass cls)
270 {
271     heap_object_callback = total_object_count_callback;
272     object_count = 0;
273 }
274 
Java_nsk_share_jvmti_unit_Heap_getObjectCount(JNIEnv * env,jclass cls)275 JNIEXPORT jint JNICALL Java_nsk_share_jvmti_unit_Heap_getObjectCount
276     (JNIEnv *env, jclass cls)
277 {
278     return object_count;
279 }
280 
Java_nsk_share_jvmti_unit_Heap_zeroObjectCount(JNIEnv * env,jclass cls)281 JNIEXPORT void JNICALL Java_nsk_share_jvmti_unit_Heap_zeroObjectCount
282     (JNIEnv *env, jclass cls)
283 {
284     object_count = 0;
285 }
286 
287 
288 /************* Basic Iteration Tests *************/
289 
klass_tag_test_callback(jlong class_tag,jlong size,jlong * tag_ptr,void * user_data)290 static jvmtiIterationControl JNICALL klass_tag_test_callback
291     (jlong class_tag, jlong size, jlong* tag_ptr, void* user_data)
292 {
293     if (user_data != &dummy_user_data && user_data_error_flag == JNI_FALSE) {
294         user_data_error_flag = JNI_TRUE;
295         fprintf(stderr, "WARNING: (klass) unexpected value of user_data\n");
296     }
297     if (class_tag != 0) {
298         *tag_ptr = class_tag;
299     }
300     return JVMTI_ITERATION_CONTINUE;
301 }
302 
Java_nsk_share_jvmti_unit_Heap_setKlassTagTestCallback(JNIEnv * env,jclass cls)303 JNIEXPORT void JNICALL Java_nsk_share_jvmti_unit_Heap_setKlassTagTestCallback
304     (JNIEnv *env, jclass cls)
305 {
306     heap_object_callback = klass_tag_test_callback;
307 }
308 
309 /************* Heap Walking Tests *************/
310 
Java_nsk_share_jvmti_unit_Heap_newGlobalRef(JNIEnv * env,jclass cls,jobject o)311 JNIEXPORT jobject JNICALL Java_nsk_share_jvmti_unit_Heap_newGlobalRef
312     (JNIEnv *env, jclass cls, jobject o)
313 {
314     return (*env)->NewGlobalRef(env, o);
315 }
316 
simple_heap_root_callback(jvmtiHeapRootKind root_kind,jlong class_tag,jlong size,jlong * tag_ptr,void * user_data)317 static jvmtiIterationControl JNICALL simple_heap_root_callback
318     (jvmtiHeapRootKind root_kind, jlong class_tag, jlong size,
319     jlong* tag_ptr, void* user_data)
320 {
321     if (user_data != &dummy_user_data && user_data_error_flag == JNI_FALSE) {
322         user_data_error_flag = JNI_TRUE;
323         fprintf(stderr, "WARNING: (heap) unexpected value of user_data\n");
324     }
325     *tag_ptr = root_kind;
326     return JVMTI_ITERATION_CONTINUE;
327 }
328 
simple_stack_ref_callback(jvmtiHeapRootKind root_kind,jlong class_tag,jlong size,jlong * tag_ptr,jlong thread_tag,jint depth,jmethodID method,jint slot,void * user_data)329 static jvmtiIterationControl JNICALL simple_stack_ref_callback
330     (jvmtiHeapRootKind root_kind, jlong class_tag, jlong size, jlong* tag_ptr,
331      jlong thread_tag, jint depth, jmethodID method, jint slot, void* user_data)
332 {
333     if (root_kind == JVMTI_HEAP_ROOT_STACK_LOCAL) {
334         if (method == NULL) {
335             fprintf(stderr, "WARNING: jmethodID missing for STACK_LOCAL\n");
336         }
337     }
338     if (user_data != &dummy_user_data && user_data_error_flag == JNI_FALSE) {
339         user_data_error_flag = JNI_TRUE;
340         fprintf(stderr, "WARNING: (stack) unexpected value of user_data\n");
341     }
342     *tag_ptr = thread_tag;
343     return JVMTI_ITERATION_CONTINUE;
344 }
345 
simple_object_ref_callback(jvmtiObjectReferenceKind reference_kind,jlong class_tag,jlong size,jlong * tag_ptr,jlong referrer_tag,jint referrer_index,void * user_data)346 static jvmtiIterationControl JNICALL simple_object_ref_callback
347     (jvmtiObjectReferenceKind reference_kind, jlong class_tag, jlong size, jlong* tag_ptr,
348      jlong referrer_tag, jint referrer_index, void* user_data)
349 {
350     if (user_data != &dummy_user_data && user_data_error_flag == JNI_FALSE) {
351         user_data_error_flag = JNI_TRUE;
352         fprintf(stderr, "WARNING: (object) unexpected value of user_data\n");
353     }
354     *tag_ptr = 777;
355     return JVMTI_ITERATION_CONTINUE;
356 }
357 
358 
Java_nsk_share_jvmti_unit_Heap_setHeapRootCallback(JNIEnv * env,jclass cls)359 JNIEXPORT void JNICALL Java_nsk_share_jvmti_unit_Heap_setHeapRootCallback
360     (JNIEnv *env, jclass cls)
361 {
362     heap_root_callback = simple_heap_root_callback;
363     stack_ref_callback = NULL;
364     object_ref_callback = NULL;
365 }
366 
Java_nsk_share_jvmti_unit_Heap_setStackRefCallback(JNIEnv * env,jclass cls)367 JNIEXPORT void JNICALL Java_nsk_share_jvmti_unit_Heap_setStackRefCallback
368     (JNIEnv *env, jclass cls)
369 {
370     heap_root_callback = NULL;
371     stack_ref_callback = simple_stack_ref_callback;
372     object_ref_callback = NULL;
373 }
374 
Java_nsk_share_jvmti_unit_Heap_setObjectRefCallback(JNIEnv * env,jclass cls)375 JNIEXPORT void JNICALL Java_nsk_share_jvmti_unit_Heap_setObjectRefCallback
376     (JNIEnv *env, jclass cls)
377 {
378     heap_root_callback = NULL;
379     stack_ref_callback = NULL;
380     object_ref_callback = simple_object_ref_callback;
381 }
382 
383 
384 
385 /*************** OBJECT_FREE tests ************/
386 
387 static jint object_free_count;
388 
389 static void JNICALL
object_free_count_callback(jvmtiEnv * env,jlong tag)390 object_free_count_callback(jvmtiEnv *env, jlong tag) {
391     if (tag == 0) {
392         fprintf(stderr, "WARNING: OBJECT_FREE event called with tag 0!!!\n");
393     }
394     object_free_count++;
395 }
396 
Java_nsk_share_jvmti_unit_Heap_setObjectFreeCallback(JNIEnv * env,jclass cls)397 JNIEXPORT void JNICALL Java_nsk_share_jvmti_unit_Heap_setObjectFreeCallback
398     (JNIEnv *env, jclass cls)
399 {
400     object_free_callback = object_free_count_callback;
401     object_free_count = 0;
402 }
403 
Java_nsk_share_jvmti_unit_Heap_getObjectFreeCount(JNIEnv * env,jclass cls)404 JNIEXPORT jint JNICALL Java_nsk_share_jvmti_unit_Heap_getObjectFreeCount
405     (JNIEnv *env, jclass cls)
406 {
407     return object_free_count;
408 }
409 
Java_nsk_share_jvmti_unit_Heap_zeroObjectFreeCount(JNIEnv * env,jclass cls)410 JNIEXPORT void JNICALL Java_nsk_share_jvmti_unit_Heap_zeroObjectFreeCount
411     (JNIEnv *env, jclass cls)
412 {
413     object_free_count = 0;
414 }
415 
416 /*
417  * Agent_Initialize - add capabilities and enables OBJECT_FREE event
418  */
Agent_Initialize(JavaVM * vm,char * options,void * reserved)419 jint Agent_Initialize(JavaVM *vm, char *options, void *reserved)
420 {
421     jint rc;
422     jvmtiError err;
423     jvmtiCapabilities capabilities;
424     jvmtiEventCallbacks callbacks;
425 
426     /* get JVMTI environment */
427 
428     rc = (*vm)->GetEnv(vm, (void **)&jvmti, JVMTI_VERSION);
429     if (rc != JNI_OK) {
430         fprintf(stderr, "Unable to create jvmtiEnv, GetEnv failed, error=%d\n", rc);
431         return -1;
432     }
433 
434 
435     /* add annotate object capability */
436     err = (*jvmti)->GetCapabilities(jvmti, &capabilities);
437     if (err != JVMTI_ERROR_NONE) {
438         fprintf(stderr, "GetCapabilities failed, error=%d\n", err);
439     }
440     capabilities.can_tag_objects = 1;
441     capabilities.can_generate_object_free_events = 1;
442     err = (*jvmti)->AddCapabilities(jvmti, &capabilities);
443 
444     if (err != JVMTI_ERROR_NONE) {
445         fprintf(stderr, "AddCapabilities failed, error=%d\n", err);
446         return -1;
447     }
448 
449 
450     /* enable OBJECT_FREE events */
451     err = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_OBJECT_FREE, NULL);
452     if (err != JVMTI_ERROR_NONE) {
453         fprintf(stderr, "SetEventNotificationMode failed, error=%d\n", err);
454         return -1;
455     }
456 
457 
458     memset(&callbacks, 0, sizeof(callbacks));
459     callbacks.ObjectFree = default_object_free;
460     err = (*jvmti)->SetEventCallbacks(jvmti, &callbacks, sizeof(callbacks));
461     if (err != JVMTI_ERROR_NONE) {
462         fprintf(stderr, "SetEventCallbacks failed, error=%d\n", err);
463         return -1;
464     }
465 
466     return 0;
467 }
468