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