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