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