source: trunk/openjdk/jdk/src/share/back/util.c

Last change on this file was 278, checked in by dmik, 14 years ago

trunk: Merged in openjdk6 b22 from branches/vendor/oracle.

File size: 89.1 KB
Line 
1/*
2 * Copyright (c) 1998, 2007, 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. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26#include <ctype.h>
27
28#include "util.h"
29#include "transport.h"
30#include "eventHandler.h"
31#include "threadControl.h"
32#include "outStream.h"
33#include "inStream.h"
34#include "invoker.h"
35
36/* Global data area */
37BackendGlobalData *gdata = NULL;
38
39/* Forward declarations */
40static jboolean isInterface(jclass clazz);
41static jboolean isArrayClass(jclass clazz);
42static char * getPropertyUTF8(JNIEnv *env, char *propertyName);
43
44/* Save an object reference for use later (create a NewGlobalRef) */
45void
46saveGlobalRef(JNIEnv *env, jobject obj, jobject *pobj)
47{
48 jobject newobj;
49
50 if ( pobj == NULL ) {
51 EXIT_ERROR(AGENT_ERROR_ILLEGAL_ARGUMENT,"saveGlobalRef pobj");
52 }
53 if ( *pobj != NULL ) {
54 EXIT_ERROR(AGENT_ERROR_ILLEGAL_ARGUMENT,"saveGlobalRef *pobj");
55 }
56 if ( env == NULL ) {
57 EXIT_ERROR(AGENT_ERROR_ILLEGAL_ARGUMENT,"saveGlobalRef env");
58 }
59 if ( obj == NULL ) {
60 EXIT_ERROR(AGENT_ERROR_ILLEGAL_ARGUMENT,"saveGlobalRef obj");
61 }
62 newobj = JNI_FUNC_PTR(env,NewGlobalRef)(env, obj);
63 if ( newobj == NULL ) {
64 EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"NewGlobalRef");
65 }
66 *pobj = newobj;
67}
68
69/* Toss a previously saved object reference */
70void
71tossGlobalRef(JNIEnv *env, jobject *pobj)
72{
73 jobject obj;
74
75 if ( pobj == NULL ) {
76 EXIT_ERROR(AGENT_ERROR_ILLEGAL_ARGUMENT,"tossGlobalRef pobj");
77 }
78 obj = *pobj;
79 if ( env == NULL ) {
80 EXIT_ERROR(AGENT_ERROR_ILLEGAL_ARGUMENT,"tossGlobalRef env");
81 }
82 if ( obj == NULL ) {
83 EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"tossGlobalRef obj");
84 }
85 JNI_FUNC_PTR(env,DeleteGlobalRef)(env, obj);
86 *pobj = NULL;
87}
88
89static jclass
90findClass(JNIEnv *env, const char * name)
91{
92 jclass x;
93
94 if ( env == NULL ) {
95 EXIT_ERROR(AGENT_ERROR_ILLEGAL_ARGUMENT,"findClass env");
96 }
97 if ( name == NULL || name[0] == 0 ) {
98 EXIT_ERROR(AGENT_ERROR_ILLEGAL_ARGUMENT,"findClass name");
99 }
100 x = JNI_FUNC_PTR(env,FindClass)(env, name);
101 if (x == NULL) {
102 ERROR_MESSAGE(("JDWP Can't find class %s", name));
103 EXIT_ERROR(AGENT_ERROR_NULL_POINTER,NULL);
104 }
105 if ( JNI_FUNC_PTR(env,ExceptionOccurred)(env) ) {
106 ERROR_MESSAGE(("JDWP Exception occurred finding class %s", name));
107 EXIT_ERROR(AGENT_ERROR_NULL_POINTER,NULL);
108 }
109 return x;
110}
111
112static jmethodID
113getMethod(JNIEnv *env, jclass clazz, const char * name, const char *signature)
114{
115 jmethodID method;
116
117 if ( env == NULL ) {
118 EXIT_ERROR(AGENT_ERROR_ILLEGAL_ARGUMENT,"getMethod env");
119 }
120 if ( clazz == NULL ) {
121 EXIT_ERROR(AGENT_ERROR_ILLEGAL_ARGUMENT,"getMethod clazz");
122 }
123 if ( name == NULL || name[0] == 0 ) {
124 EXIT_ERROR(AGENT_ERROR_ILLEGAL_ARGUMENT,"getMethod name");
125 }
126 if ( signature == NULL || signature[0] == 0 ) {
127 EXIT_ERROR(AGENT_ERROR_ILLEGAL_ARGUMENT,"getMethod signature");
128 }
129 method = JNI_FUNC_PTR(env,GetMethodID)(env, clazz, name, signature);
130 if (method == NULL) {
131 ERROR_MESSAGE(("JDWP Can't find method %s with signature %s",
132 name, signature));
133 EXIT_ERROR(AGENT_ERROR_NULL_POINTER,NULL);
134 }
135 if ( JNI_FUNC_PTR(env,ExceptionOccurred)(env) ) {
136 ERROR_MESSAGE(("JDWP Exception occurred finding method %s with signature %s",
137 name, signature));
138 EXIT_ERROR(AGENT_ERROR_NULL_POINTER,NULL);
139 }
140 return method;
141}
142
143static jmethodID
144getStaticMethod(JNIEnv *env, jclass clazz, const char * name, const char *signature)
145{
146 jmethodID method;
147
148 if ( env == NULL ) {
149 EXIT_ERROR(AGENT_ERROR_ILLEGAL_ARGUMENT,"getStaticMethod env");
150 }
151 if ( clazz == NULL ) {
152 EXIT_ERROR(AGENT_ERROR_ILLEGAL_ARGUMENT,"getStaticMethod clazz");
153 }
154 if ( name == NULL || name[0] == 0 ) {
155 EXIT_ERROR(AGENT_ERROR_ILLEGAL_ARGUMENT,"getStaticMethod name");
156 }
157 if ( signature == NULL || signature[0] == 0 ) {
158 EXIT_ERROR(AGENT_ERROR_ILLEGAL_ARGUMENT,"getStaticMethod signature");
159 }
160 method = JNI_FUNC_PTR(env,GetStaticMethodID)(env, clazz, name, signature);
161 if (method == NULL) {
162 ERROR_MESSAGE(("JDWP Can't find method %s with signature %s",
163 name, signature));
164 EXIT_ERROR(AGENT_ERROR_NULL_POINTER,NULL);
165 }
166 if ( JNI_FUNC_PTR(env,ExceptionOccurred)(env) ) {
167 ERROR_MESSAGE(("JDWP Exception occurred finding method %s with signature %s",
168 name, signature));
169 EXIT_ERROR(AGENT_ERROR_NULL_POINTER,NULL);
170 }
171 return method;
172}
173
174void
175util_initialize(JNIEnv *env)
176{
177 WITH_LOCAL_REFS(env, 6) {
178
179 jvmtiError error;
180 jclass localClassClass;
181 jclass localThreadClass;
182 jclass localThreadGroupClass;
183 jclass localClassLoaderClass;
184 jclass localStringClass;
185 jclass localSystemClass;
186 jclass localPropertiesClass;
187 jclass localVMSupportClass;
188 jobject localAgentProperties;
189 jmethodID getAgentProperties;
190 jint groupCount;
191 jthreadGroup *groups;
192 jthreadGroup localSystemThreadGroup;
193
194 /* Find some standard classes */
195
196 localClassClass = findClass(env,"java/lang/Class");
197 localThreadClass = findClass(env,"java/lang/Thread");
198 localThreadGroupClass = findClass(env,"java/lang/ThreadGroup");
199 localClassLoaderClass = findClass(env,"java/lang/ClassLoader");
200 localStringClass = findClass(env,"java/lang/String");
201 localSystemClass = findClass(env,"java/lang/System");
202 localPropertiesClass = findClass(env,"java/util/Properties");
203
204 /* Save references */
205
206 saveGlobalRef(env, localClassClass, &(gdata->classClass));
207 saveGlobalRef(env, localThreadClass, &(gdata->threadClass));
208 saveGlobalRef(env, localThreadGroupClass, &(gdata->threadGroupClass));
209 saveGlobalRef(env, localClassLoaderClass, &(gdata->classLoaderClass));
210 saveGlobalRef(env, localStringClass, &(gdata->stringClass));
211 saveGlobalRef(env, localSystemClass, &(gdata->systemClass));
212
213 /* Find some standard methods */
214
215 gdata->threadConstructor =
216 getMethod(env, gdata->threadClass,
217 "<init>", "(Ljava/lang/ThreadGroup;Ljava/lang/String;)V");
218 gdata->threadSetDaemon =
219 getMethod(env, gdata->threadClass, "setDaemon", "(Z)V");
220 gdata->threadResume =
221 getMethod(env, gdata->threadClass, "resume", "()V");
222 gdata->systemGetProperty =
223 getStaticMethod(env, gdata->systemClass,
224 "getProperty", "(Ljava/lang/String;)Ljava/lang/String;");
225 gdata->setProperty =
226 getMethod(env, localPropertiesClass,
227 "setProperty", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;");
228
229 /* Find the system thread group */
230
231 groups = NULL;
232 groupCount = 0;
233 error = JVMTI_FUNC_PTR(gdata->jvmti,GetTopThreadGroups)
234 (gdata->jvmti, &groupCount, &groups);
235 if (error != JVMTI_ERROR_NONE ) {
236 EXIT_ERROR(error, "Can't get system thread group");
237 }
238 if ( groupCount == 0 ) {
239 EXIT_ERROR(AGENT_ERROR_NULL_POINTER, "Can't get system thread group");
240 }
241 localSystemThreadGroup = groups[0];
242 saveGlobalRef(env, localSystemThreadGroup, &(gdata->systemThreadGroup));
243
244 /* Get some basic Java property values we will need at some point */
245 gdata->property_java_version
246 = getPropertyUTF8(env, "java.version");
247 gdata->property_java_vm_name
248 = getPropertyUTF8(env, "java.vm.name");
249 gdata->property_java_vm_info
250 = getPropertyUTF8(env, "java.vm.info");
251 gdata->property_java_class_path
252 = getPropertyUTF8(env, "java.class.path");
253 gdata->property_sun_boot_class_path
254 = getPropertyUTF8(env, "sun.boot.class.path");
255 gdata->property_sun_boot_library_path
256 = getPropertyUTF8(env, "sun.boot.library.path");
257 gdata->property_path_separator
258 = getPropertyUTF8(env, "path.separator");
259 gdata->property_user_dir
260 = getPropertyUTF8(env, "user.dir");
261
262 /* Get agent properties: invoke sun.misc.VMSupport.getAgentProperties */
263 localVMSupportClass = JNI_FUNC_PTR(env,FindClass)
264 (env, "sun/misc/VMSupport");
265 if (localVMSupportClass == NULL) {
266 gdata->agent_properties = NULL;
267 if (JNI_FUNC_PTR(env,ExceptionOccurred)(env)) {
268 JNI_FUNC_PTR(env,ExceptionClear)(env);
269 }
270 } else {
271 getAgentProperties =
272 getStaticMethod(env, localVMSupportClass,
273 "getAgentProperties", "()Ljava/util/Properties;");
274 localAgentProperties =
275 JNI_FUNC_PTR(env,CallStaticObjectMethod)
276 (env, localVMSupportClass, getAgentProperties);
277 saveGlobalRef(env, localAgentProperties, &(gdata->agent_properties));
278 if (JNI_FUNC_PTR(env,ExceptionOccurred)(env)) {
279 JNI_FUNC_PTR(env,ExceptionClear)(env);
280 EXIT_ERROR(AGENT_ERROR_INTERNAL,
281 "Exception occurred calling sun.misc.VMSupport.getAgentProperties");
282 }
283 }
284
285 } END_WITH_LOCAL_REFS(env);
286
287}
288
289void
290util_reset(void)
291{
292}
293
294jboolean
295isObjectTag(jbyte tag) {
296 return (tag == JDWP_TAG(OBJECT)) ||
297 (tag == JDWP_TAG(STRING)) ||
298 (tag == JDWP_TAG(THREAD)) ||
299 (tag == JDWP_TAG(THREAD_GROUP)) ||
300 (tag == JDWP_TAG(CLASS_LOADER)) ||
301 (tag == JDWP_TAG(CLASS_OBJECT)) ||
302 (tag == JDWP_TAG(ARRAY));
303}
304
305jbyte
306specificTypeKey(JNIEnv *env, jobject object)
307{
308 if (object == NULL) {
309 return JDWP_TAG(OBJECT);
310 } else if (JNI_FUNC_PTR(env,IsInstanceOf)(env, object, gdata->stringClass)) {
311 return JDWP_TAG(STRING);
312 } else if (JNI_FUNC_PTR(env,IsInstanceOf)(env, object, gdata->threadClass)) {
313 return JDWP_TAG(THREAD);
314 } else if (JNI_FUNC_PTR(env,IsInstanceOf)(env, object, gdata->threadGroupClass)) {
315 return JDWP_TAG(THREAD_GROUP);
316 } else if (JNI_FUNC_PTR(env,IsInstanceOf)(env, object, gdata->classLoaderClass)) {
317 return JDWP_TAG(CLASS_LOADER);
318 } else if (JNI_FUNC_PTR(env,IsInstanceOf)(env, object, gdata->classClass)) {
319 return JDWP_TAG(CLASS_OBJECT);
320 } else {
321 jboolean classIsArray;
322
323 WITH_LOCAL_REFS(env, 1) {
324 jclass clazz;
325 clazz = JNI_FUNC_PTR(env,GetObjectClass)(env, object);
326 classIsArray = isArrayClass(clazz);
327 } END_WITH_LOCAL_REFS(env);
328
329 return (classIsArray ? JDWP_TAG(ARRAY) : JDWP_TAG(OBJECT));
330 }
331}
332
333static void
334writeFieldValue(JNIEnv *env, PacketOutputStream *out, jobject object,
335 jfieldID field)
336{
337 jclass clazz;
338 char *signature = NULL;
339 jvmtiError error;
340 jbyte typeKey;
341
342 clazz = JNI_FUNC_PTR(env,GetObjectClass)(env, object);
343 error = fieldSignature(clazz, field, NULL, &signature, NULL);
344 if (error != JVMTI_ERROR_NONE) {
345 outStream_setError(out, map2jdwpError(error));
346 return;
347 }
348 typeKey = signature[0];
349 jvmtiDeallocate(signature);
350
351 /*
352 * For primitive types, the type key is bounced back as is. Objects
353 * are handled in the switch statement below.
354 */
355 if ((typeKey != JDWP_TAG(OBJECT)) && (typeKey != JDWP_TAG(ARRAY))) {
356 (void)outStream_writeByte(out, typeKey);
357 }
358
359 switch (typeKey) {
360 case JDWP_TAG(OBJECT):
361 case JDWP_TAG(ARRAY): {
362 jobject value = JNI_FUNC_PTR(env,GetObjectField)(env, object, field);
363 (void)outStream_writeByte(out, specificTypeKey(env, value));
364 (void)outStream_writeObjectRef(env, out, value);
365 break;
366 }
367
368 case JDWP_TAG(BYTE):
369 (void)outStream_writeByte(out,
370 JNI_FUNC_PTR(env,GetByteField)(env, object, field));
371 break;
372
373 case JDWP_TAG(CHAR):
374 (void)outStream_writeChar(out,
375 JNI_FUNC_PTR(env,GetCharField)(env, object, field));
376 break;
377
378 case JDWP_TAG(FLOAT):
379 (void)outStream_writeFloat(out,
380 JNI_FUNC_PTR(env,GetFloatField)(env, object, field));
381 break;
382
383 case JDWP_TAG(DOUBLE):
384 (void)outStream_writeDouble(out,
385 JNI_FUNC_PTR(env,GetDoubleField)(env, object, field));
386 break;
387
388 case JDWP_TAG(INT):
389 (void)outStream_writeInt(out,
390 JNI_FUNC_PTR(env,GetIntField)(env, object, field));
391 break;
392
393 case JDWP_TAG(LONG):
394 (void)outStream_writeLong(out,
395 JNI_FUNC_PTR(env,GetLongField)(env, object, field));
396 break;
397
398 case JDWP_TAG(SHORT):
399 (void)outStream_writeShort(out,
400 JNI_FUNC_PTR(env,GetShortField)(env, object, field));
401 break;
402
403 case JDWP_TAG(BOOLEAN):
404 (void)outStream_writeBoolean(out,
405 JNI_FUNC_PTR(env,GetBooleanField)(env, object, field));
406 break;
407 }
408}
409
410static void
411writeStaticFieldValue(JNIEnv *env, PacketOutputStream *out, jclass clazz,
412 jfieldID field)
413{
414 jvmtiError error;
415 char *signature = NULL;
416 jbyte typeKey;
417
418 error = fieldSignature(clazz, field, NULL, &signature, NULL);
419 if (error != JVMTI_ERROR_NONE) {
420 outStream_setError(out, map2jdwpError(error));
421 return;
422 }
423 typeKey = signature[0];
424 jvmtiDeallocate(signature);
425
426 /*
427 * For primitive types, the type key is bounced back as is. Objects
428 * are handled in the switch statement below.
429 */
430 if ((typeKey != JDWP_TAG(OBJECT)) && (typeKey != JDWP_TAG(ARRAY))) {
431 (void)outStream_writeByte(out, typeKey);
432 }
433
434 switch (typeKey) {
435 case JDWP_TAG(OBJECT):
436 case JDWP_TAG(ARRAY): {
437 jobject value = JNI_FUNC_PTR(env,GetStaticObjectField)(env, clazz, field);
438 (void)outStream_writeByte(out, specificTypeKey(env, value));
439 (void)outStream_writeObjectRef(env, out, value);
440 break;
441 }
442
443 case JDWP_TAG(BYTE):
444 (void)outStream_writeByte(out,
445 JNI_FUNC_PTR(env,GetStaticByteField)(env, clazz, field));
446 break;
447
448 case JDWP_TAG(CHAR):
449 (void)outStream_writeChar(out,
450 JNI_FUNC_PTR(env,GetStaticCharField)(env, clazz, field));
451 break;
452
453 case JDWP_TAG(FLOAT):
454 (void)outStream_writeFloat(out,
455 JNI_FUNC_PTR(env,GetStaticFloatField)(env, clazz, field));
456 break;
457
458 case JDWP_TAG(DOUBLE):
459 (void)outStream_writeDouble(out,
460 JNI_FUNC_PTR(env,GetStaticDoubleField)(env, clazz, field));
461 break;
462
463 case JDWP_TAG(INT):
464 (void)outStream_writeInt(out,
465 JNI_FUNC_PTR(env,GetStaticIntField)(env, clazz, field));
466 break;
467
468 case JDWP_TAG(LONG):
469 (void)outStream_writeLong(out,
470 JNI_FUNC_PTR(env,GetStaticLongField)(env, clazz, field));
471 break;
472
473 case JDWP_TAG(SHORT):
474 (void)outStream_writeShort(out,
475 JNI_FUNC_PTR(env,GetStaticShortField)(env, clazz, field));
476 break;
477
478 case JDWP_TAG(BOOLEAN):
479 (void)outStream_writeBoolean(out,
480 JNI_FUNC_PTR(env,GetStaticBooleanField)(env, clazz, field));
481 break;
482 }
483}
484
485void
486sharedGetFieldValues(PacketInputStream *in, PacketOutputStream *out,
487 jboolean isStatic)
488{
489 JNIEnv *env = getEnv();
490 jint length;
491 jobject object;
492 jclass clazz;
493
494 object = NULL;
495 clazz = NULL;
496
497 if (isStatic) {
498 clazz = inStream_readClassRef(env, in);
499 } else {
500 object = inStream_readObjectRef(env, in);
501 }
502
503 length = inStream_readInt(in);
504 if (inStream_error(in)) {
505 return;
506 }
507
508 WITH_LOCAL_REFS(env, length + 1) { /* +1 for class with instance fields */
509
510 int i;
511
512 (void)outStream_writeInt(out, length);
513 for (i = 0; (i < length) && !outStream_error(out); i++) {
514 jfieldID field = inStream_readFieldID(in);
515
516 if (isStatic) {
517 writeStaticFieldValue(env, out, clazz, field);
518 } else {
519 writeFieldValue(env, out, object, field);
520 }
521 }
522
523 } END_WITH_LOCAL_REFS(env);
524}
525
526jboolean
527sharedInvoke(PacketInputStream *in, PacketOutputStream *out)
528{
529 jvalue *arguments = NULL;
530 jint options;
531 jvmtiError error;
532 jbyte invokeType;
533 jclass clazz;
534 jmethodID method;
535 jint argumentCount;
536 jobject instance;
537 jthread thread;
538 JNIEnv *env;
539
540 /*
541 * Instance methods start with the instance, thread and class,
542 * and statics and constructors start with the class and then the
543 * thread.
544 */
545 env = getEnv();
546 if (inStream_command(in) == JDWP_COMMAND(ObjectReference, InvokeMethod)) {
547 instance = inStream_readObjectRef(env, in);
548 thread = inStream_readThreadRef(env, in);
549 clazz = inStream_readClassRef(env, in);
550 } else { /* static method or constructor */
551 instance = NULL;
552 clazz = inStream_readClassRef(env, in);
553 thread = inStream_readThreadRef(env, in);
554 }
555
556 /*
557 * ... and the rest of the packet is identical for all commands
558 */
559 method = inStream_readMethodID(in);
560 argumentCount = inStream_readInt(in);
561 if (inStream_error(in)) {
562 return JNI_TRUE;
563 }
564
565 /* If count == 0, don't try and allocate 0 bytes, you'll get NULL */
566 if ( argumentCount > 0 ) {
567 int i;
568 /*LINTED*/
569 arguments = jvmtiAllocate(argumentCount * (jint)sizeof(*arguments));
570 if (arguments == NULL) {
571 outStream_setError(out, JDWP_ERROR(OUT_OF_MEMORY));
572 return JNI_TRUE;
573 }
574 for (i = 0; (i < argumentCount) && !inStream_error(in); i++) {
575 arguments[i] = inStream_readValue(in, NULL);
576 }
577 if (inStream_error(in)) {
578 return JNI_TRUE;
579 }
580 }
581
582 options = inStream_readInt(in);
583 if (inStream_error(in)) {
584 if ( arguments != NULL ) {
585 jvmtiDeallocate(arguments);
586 }
587 return JNI_TRUE;
588 }
589
590 if (inStream_command(in) == JDWP_COMMAND(ClassType, NewInstance)) {
591 invokeType = INVOKE_CONSTRUCTOR;
592 } else if (inStream_command(in) == JDWP_COMMAND(ClassType, InvokeMethod)) {
593 invokeType = INVOKE_STATIC;
594 } else if (inStream_command(in) == JDWP_COMMAND(ObjectReference, InvokeMethod)) {
595 invokeType = INVOKE_INSTANCE;
596 } else {
597 outStream_setError(out, JDWP_ERROR(INTERNAL));
598 if ( arguments != NULL ) {
599 jvmtiDeallocate(arguments);
600 }
601 return JNI_TRUE;
602 }
603
604 /*
605 * Request the invoke. If there are no errors in the request,
606 * the interrupting thread will actually do the invoke and a
607 * reply will be generated subsequently, so we don't reply here.
608 */
609 error = invoker_requestInvoke(invokeType, (jbyte)options, inStream_id(in),
610 thread, clazz, method,
611 instance, arguments, argumentCount);
612 if (error != JVMTI_ERROR_NONE) {
613 outStream_setError(out, map2jdwpError(error));
614 if ( arguments != NULL ) {
615 jvmtiDeallocate(arguments);
616 }
617 return JNI_TRUE;
618 }
619
620 return JNI_FALSE; /* Don't reply */
621}
622
623jint
624uniqueID(void)
625{
626 static jint currentID = 0;
627 return currentID++;
628}
629
630int
631filterDebugThreads(jthread *threads, int count)
632{
633 int i;
634 int current;
635
636 /* Squish out all of the debugger-spawned threads */
637 for (i = 0, current = 0; i < count; i++) {
638 jthread thread = threads[i];
639 if (!threadControl_isDebugThread(thread)) {
640 if (i > current) {
641 threads[current] = thread;
642 }
643 current++;
644 }
645 }
646 return current;
647}
648
649jbyte
650referenceTypeTag(jclass clazz)
651{
652 jbyte tag;
653
654 if (isInterface(clazz)) {
655 tag = JDWP_TYPE_TAG(INTERFACE);
656 } else if (isArrayClass(clazz)) {
657 tag = JDWP_TYPE_TAG(ARRAY);
658 } else {
659 tag = JDWP_TYPE_TAG(CLASS);
660 }
661
662 return tag;
663}
664
665/**
666 * Get field modifiers
667 */
668jvmtiError
669fieldModifiers(jclass clazz, jfieldID field, jint *pmodifiers)
670{
671 jvmtiError error;
672
673 *pmodifiers = 0;
674 error = JVMTI_FUNC_PTR(gdata->jvmti,GetFieldModifiers)
675 (gdata->jvmti, clazz, field, pmodifiers);
676 return error;
677}
678
679/**
680 * Get method modifiers
681 */
682jvmtiError
683methodModifiers(jmethodID method, jint *pmodifiers)
684{
685 jvmtiError error;
686
687 *pmodifiers = 0;
688 error = JVMTI_FUNC_PTR(gdata->jvmti,GetMethodModifiers)
689 (gdata->jvmti, method, pmodifiers);
690 return error;
691}
692
693/* Returns a local ref to the declaring class for a method, or NULL. */
694jvmtiError
695methodClass(jmethodID method, jclass *pclazz)
696{
697 jvmtiError error;
698
699 *pclazz = NULL;
700 error = FUNC_PTR(gdata->jvmti,GetMethodDeclaringClass)
701 (gdata->jvmti, method, pclazz);
702 return error;
703}
704
705/* Returns a local ref to the declaring class for a method, or NULL. */
706jvmtiError
707methodLocation(jmethodID method, jlocation *ploc1, jlocation *ploc2)
708{
709 jvmtiError error;
710
711 error = JVMTI_FUNC_PTR(gdata->jvmti,GetMethodLocation)
712 (gdata->jvmti, method, ploc1, ploc2);
713 return error;
714}
715
716/**
717 * Get method signature
718 */
719jvmtiError
720methodSignature(jmethodID method,
721 char **pname, char **psignature, char **pgeneric_signature)
722{
723 jvmtiError error;
724 char *name = NULL;
725 char *signature = NULL;
726 char *generic_signature = NULL;
727
728 error = FUNC_PTR(gdata->jvmti,GetMethodName)
729 (gdata->jvmti, method, &name, &signature, &generic_signature);
730
731 if ( pname != NULL ) {
732 *pname = name;
733 } else if ( name != NULL ) {
734 jvmtiDeallocate(name);
735 }
736 if ( psignature != NULL ) {
737 *psignature = signature;
738 } else if ( signature != NULL ) {
739 jvmtiDeallocate(signature);
740 }
741 if ( pgeneric_signature != NULL ) {
742 *pgeneric_signature = generic_signature;
743 } else if ( generic_signature != NULL ) {
744 jvmtiDeallocate(generic_signature);
745 }
746 return error;
747}
748
749/*
750 * Get the return type key of the method
751 * V or B C D F I J S Z L [
752 */
753jvmtiError
754methodReturnType(jmethodID method, char *typeKey)
755{
756 char *signature;
757 jvmtiError error;
758
759 signature = NULL;
760 error = methodSignature(method, NULL, &signature, NULL);
761 if (error == JVMTI_ERROR_NONE) {
762 if (signature == NULL ) {
763 error = AGENT_ERROR_INVALID_TAG;
764 } else {
765 char * xx;
766
767 xx = strchr(signature, ')');
768 if (xx == NULL || *(xx + 1) == 0) {
769 error = AGENT_ERROR_INVALID_TAG;
770 } else {
771 *typeKey = *(xx + 1);
772 }
773 jvmtiDeallocate(signature);
774 }
775 }
776 return error;
777}
778
779
780/**
781 * Return class loader for a class (must be inside a WITH_LOCAL_REFS)
782 */
783jvmtiError
784classLoader(jclass clazz, jobject *pclazz)
785{
786 jvmtiError error;
787
788 *pclazz = NULL;
789 error = JVMTI_FUNC_PTR(gdata->jvmti,GetClassLoader)
790 (gdata->jvmti, clazz, pclazz);
791 return error;
792}
793
794/**
795 * Get field signature
796 */
797jvmtiError
798fieldSignature(jclass clazz, jfieldID field,
799 char **pname, char **psignature, char **pgeneric_signature)
800{
801 jvmtiError error;
802 char *name = NULL;
803 char *signature = NULL;
804 char *generic_signature = NULL;
805
806 error = JVMTI_FUNC_PTR(gdata->jvmti,GetFieldName)
807 (gdata->jvmti, clazz, field, &name, &signature, &generic_signature);
808
809 if ( pname != NULL ) {
810 *pname = name;
811 } else if ( name != NULL ) {
812 jvmtiDeallocate(name);
813 }
814 if ( psignature != NULL ) {
815 *psignature = signature;
816 } else if ( signature != NULL ) {
817 jvmtiDeallocate(signature);
818 }
819 if ( pgeneric_signature != NULL ) {
820 *pgeneric_signature = generic_signature;
821 } else if ( generic_signature != NULL ) {
822 jvmtiDeallocate(generic_signature);
823 }
824 return error;
825}
826
827JNIEnv *
828getEnv(void)
829{
830 JNIEnv *env = NULL;
831 jint rc;
832
833 rc = FUNC_PTR(gdata->jvm,GetEnv)
834 (gdata->jvm, (void **)&env, JNI_VERSION_1_2);
835 if (rc != JNI_OK) {
836 ERROR_MESSAGE(("JDWP Unable to get JNI 1.2 environment, jvm->GetEnv() return code = %d",
837 rc));
838 EXIT_ERROR(AGENT_ERROR_NO_JNI_ENV,NULL);
839 }
840 return env;
841}
842
843jvmtiError
844spawnNewThread(jvmtiStartFunction func, void *arg, char *name)
845{
846 JNIEnv *env = getEnv();
847 jvmtiError error;
848
849 LOG_MISC(("Spawning new thread: %s", name));
850
851 WITH_LOCAL_REFS(env, 3) {
852
853 jthread thread;
854 jstring nameString;
855
856 nameString = JNI_FUNC_PTR(env,NewStringUTF)(env, name);
857 if (JNI_FUNC_PTR(env,ExceptionOccurred)(env)) {
858 JNI_FUNC_PTR(env,ExceptionClear)(env);
859 error = AGENT_ERROR_OUT_OF_MEMORY;
860 goto err;
861 }
862
863 thread = JNI_FUNC_PTR(env,NewObject)
864 (env, gdata->threadClass, gdata->threadConstructor,
865 gdata->systemThreadGroup, nameString);
866 if (JNI_FUNC_PTR(env,ExceptionOccurred)(env)) {
867 JNI_FUNC_PTR(env,ExceptionClear)(env);
868 error = AGENT_ERROR_OUT_OF_MEMORY;
869 goto err;
870 }
871
872 /*
873 * Make the debugger thread a daemon
874 */
875 JNI_FUNC_PTR(env,CallVoidMethod)
876 (env, thread, gdata->threadSetDaemon, JNI_TRUE);
877 if (JNI_FUNC_PTR(env,ExceptionOccurred)(env)) {
878 JNI_FUNC_PTR(env,ExceptionClear)(env);
879 error = AGENT_ERROR_JNI_EXCEPTION;
880 goto err;
881 }
882
883 error = threadControl_addDebugThread(thread);
884 if (error == JVMTI_ERROR_NONE) {
885 /*
886 * Debugger threads need cycles in all sorts of strange
887 * situations (e.g. infinite cpu-bound loops), so give the
888 * thread a high priority. Note that if the VM has an application
889 * thread running at the max priority, there is still a chance
890 * that debugger threads will be starved. (There needs to be
891 * a way to give debugger threads a priority higher than any
892 * application thread).
893 */
894 error = JVMTI_FUNC_PTR(gdata->jvmti,RunAgentThread)
895 (gdata->jvmti, thread, func, arg,
896 JVMTI_THREAD_MAX_PRIORITY);
897 }
898
899 err: ;
900
901 } END_WITH_LOCAL_REFS(env);
902
903 return error;
904}
905
906jvmtiError
907jvmtiGetCapabilities(jvmtiCapabilities *caps)
908{
909 if ( gdata->vmDead ) {
910 return AGENT_ERROR_VM_DEAD;
911 }
912 if (!gdata->haveCachedJvmtiCapabilities) {
913 jvmtiError error;
914
915 error = JVMTI_FUNC_PTR(gdata->jvmti,GetCapabilities)
916 (gdata->jvmti, &(gdata->cachedJvmtiCapabilities));
917 if (error != JVMTI_ERROR_NONE) {
918 return error;
919 }
920 gdata->haveCachedJvmtiCapabilities = JNI_TRUE;
921 }
922
923 *caps = gdata->cachedJvmtiCapabilities;
924
925 return JVMTI_ERROR_NONE;
926}
927
928static jint
929jvmtiVersion(void)
930{
931 if (gdata->cachedJvmtiVersion == 0) {
932 jvmtiError error;
933 error = JVMTI_FUNC_PTR(gdata->jvmti,GetVersionNumber)
934 (gdata->jvmti, &(gdata->cachedJvmtiVersion));
935 if (error != JVMTI_ERROR_NONE) {
936 EXIT_ERROR(error, "on getting the JVMTI version number");
937 }
938 }
939 return gdata->cachedJvmtiVersion;
940}
941
942jint
943jvmtiMajorVersion(void)
944{
945 return (jvmtiVersion() & JVMTI_VERSION_MASK_MAJOR)
946 >> JVMTI_VERSION_SHIFT_MAJOR;
947}
948
949jint
950jvmtiMinorVersion(void)
951{
952 return (jvmtiVersion() & JVMTI_VERSION_MASK_MINOR)
953 >> JVMTI_VERSION_SHIFT_MINOR;
954}
955
956jint
957jvmtiMicroVersion(void)
958{
959 return (jvmtiVersion() & JVMTI_VERSION_MASK_MICRO)
960 >> JVMTI_VERSION_SHIFT_MICRO;
961}
962
963jboolean
964canSuspendResumeThreadLists(void)
965{
966 jvmtiError error;
967 jvmtiCapabilities cap;
968
969 error = jvmtiGetCapabilities(&cap);
970 return (error == JVMTI_ERROR_NONE && cap.can_suspend);
971}
972
973jvmtiError
974getSourceDebugExtension(jclass clazz, char **extensionPtr)
975{
976 return JVMTI_FUNC_PTR(gdata->jvmti,GetSourceDebugExtension)
977 (gdata->jvmti, clazz, extensionPtr);
978}
979
980/*
981 * Convert the signature "Ljava/lang/Foo;" to a
982 * classname "java.lang.Foo" compatible with the pattern.
983 * Signature is overwritten in-place.
984 */
985void
986convertSignatureToClassname(char *convert)
987{
988 char *p;
989
990 p = convert + 1;
991 while ((*p != ';') && (*p != '\0')) {
992 char c = *p;
993 if (c == '/') {
994 *(p-1) = '.';
995 } else {
996 *(p-1) = c;
997 }
998 p++;
999 }
1000 *(p-1) = '\0';
1001}
1002
1003static void
1004handleInterrupt(void)
1005{
1006 /*
1007 * An interrupt is handled:
1008 *
1009 * 1) for running application threads by deferring the interrupt
1010 * until the current event handler has concluded.
1011 *
1012 * 2) for debugger threads by ignoring the interrupt; this is the
1013 * most robust solution since debugger threads don't use interrupts
1014 * to signal any condition.
1015 *
1016 * 3) for application threads that have not started or already
1017 * ended by ignoring the interrupt. In the former case, the application
1018 * is relying on timing to determine whether or not the thread sees
1019 * the interrupt; in the latter case, the interrupt is meaningless.
1020 */
1021 jthread thread = threadControl_currentThread();
1022 if ((thread != NULL) && (!threadControl_isDebugThread(thread))) {
1023 threadControl_setPendingInterrupt(thread);
1024 }
1025}
1026
1027static jvmtiError
1028ignore_vm_death(jvmtiError error)
1029{
1030 if (error == JVMTI_ERROR_WRONG_PHASE) {
1031 LOG_MISC(("VM_DEAD, in debugMonitor*()?"));
1032 return JVMTI_ERROR_NONE; /* JVMTI does this, not JVMDI? */
1033 }
1034 return error;
1035}
1036
1037void
1038debugMonitorEnter(jrawMonitorID monitor)
1039{
1040 jvmtiError error;
1041 while (JNI_TRUE) {
1042 error = FUNC_PTR(gdata->jvmti,RawMonitorEnter)
1043 (gdata->jvmti, monitor);
1044 error = ignore_vm_death(error);
1045 if (error == JVMTI_ERROR_INTERRUPT) {
1046 handleInterrupt();
1047 } else {
1048 break;
1049 }
1050 }
1051 if (error != JVMTI_ERROR_NONE) {
1052 EXIT_ERROR(error, "on raw monitor enter");
1053 }
1054}
1055
1056void
1057debugMonitorExit(jrawMonitorID monitor)
1058{
1059 jvmtiError error;
1060
1061 error = FUNC_PTR(gdata->jvmti,RawMonitorExit)
1062 (gdata->jvmti, monitor);
1063 error = ignore_vm_death(error);
1064 if (error != JVMTI_ERROR_NONE) {
1065 EXIT_ERROR(error, "on raw monitor exit");
1066 }
1067}
1068
1069void
1070debugMonitorWait(jrawMonitorID monitor)
1071{
1072 jvmtiError error;
1073 error = FUNC_PTR(gdata->jvmti,RawMonitorWait)
1074 (gdata->jvmti, monitor, ((jlong)(-1)));
1075
1076 /*
1077 * According to the JLS (17.8), here we have
1078 * either :
1079 * a- been notified
1080 * b- gotten a suprious wakeup
1081 * c- been interrupted
1082 * If both a and c have happened, the VM must choose
1083 * which way to return - a or c. If it chooses c
1084 * then the notify is gone - either to some other
1085 * thread that is also waiting, or it is dropped
1086 * on the floor.
1087 *
1088 * a is what we expect. b won't hurt us any -
1089 * callers should be programmed to handle
1090 * spurious wakeups. In case of c,
1091 * then the interrupt has been cleared, but
1092 * we don't want to consume it. It came from
1093 * user code and is intended for user code, not us.
1094 * So, we will remember that the interrupt has
1095 * occured and re-activate it when this thread
1096 * goes back into user code.
1097 * That being said, what do we do here? Since
1098 * we could have been notified too, here we will
1099 * just pretend that we have been. It won't hurt
1100 * anything to return in the same way as if
1101 * we were notified since callers have to be able to
1102 * handle spurious wakeups anyway.
1103 */
1104 if (error == JVMTI_ERROR_INTERRUPT) {
1105 handleInterrupt();
1106 error = JVMTI_ERROR_NONE;
1107 }
1108 error = ignore_vm_death(error);
1109 if (error != JVMTI_ERROR_NONE) {
1110 EXIT_ERROR(error, "on raw monitor wait");
1111 }
1112}
1113
1114void
1115debugMonitorTimedWait(jrawMonitorID monitor, jlong millis)
1116{
1117 jvmtiError error;
1118 error = FUNC_PTR(gdata->jvmti,RawMonitorWait)
1119 (gdata->jvmti, monitor, millis);
1120 if (error == JVMTI_ERROR_INTERRUPT) {
1121 /* See comment above */
1122 handleInterrupt();
1123 error = JVMTI_ERROR_NONE;
1124 }
1125 error = ignore_vm_death(error);
1126 if (error != JVMTI_ERROR_NONE) {
1127 EXIT_ERROR(error, "on raw monitor timed wait");
1128 }
1129}
1130
1131void
1132debugMonitorNotify(jrawMonitorID monitor)
1133{
1134 jvmtiError error;
1135
1136 error = FUNC_PTR(gdata->jvmti,RawMonitorNotify)
1137 (gdata->jvmti, monitor);
1138 error = ignore_vm_death(error);
1139 if (error != JVMTI_ERROR_NONE) {
1140 EXIT_ERROR(error, "on raw monitor notify");
1141 }
1142}
1143
1144void
1145debugMonitorNotifyAll(jrawMonitorID monitor)
1146{
1147 jvmtiError error;
1148
1149 error = FUNC_PTR(gdata->jvmti,RawMonitorNotifyAll)
1150 (gdata->jvmti, monitor);
1151 error = ignore_vm_death(error);
1152 if (error != JVMTI_ERROR_NONE) {
1153 EXIT_ERROR(error, "on raw monitor notify all");
1154 }
1155}
1156
1157jrawMonitorID
1158debugMonitorCreate(char *name)
1159{
1160 jrawMonitorID monitor;
1161 jvmtiError error;
1162
1163 error = FUNC_PTR(gdata->jvmti,CreateRawMonitor)
1164 (gdata->jvmti, name, &monitor);
1165 if (error != JVMTI_ERROR_NONE) {
1166 EXIT_ERROR(error, "on creation of a raw monitor");
1167 }
1168 return monitor;
1169}
1170
1171void
1172debugMonitorDestroy(jrawMonitorID monitor)
1173{
1174 jvmtiError error;
1175
1176 error = FUNC_PTR(gdata->jvmti,DestroyRawMonitor)
1177 (gdata->jvmti, monitor);
1178 error = ignore_vm_death(error);
1179 if (error != JVMTI_ERROR_NONE) {
1180 EXIT_ERROR(error, "on destruction of raw monitor");
1181 }
1182}
1183
1184/**
1185 * Return array of all threads (must be inside a WITH_LOCAL_REFS)
1186 */
1187jthread *
1188allThreads(jint *count)
1189{
1190 jthread *threads;
1191 jvmtiError error;
1192
1193 *count = 0;
1194 threads = NULL;
1195 error = JVMTI_FUNC_PTR(gdata->jvmti,GetAllThreads)
1196 (gdata->jvmti, count, &threads);
1197 if (error == AGENT_ERROR_OUT_OF_MEMORY) {
1198 return NULL; /* Let caller deal with no memory? */
1199 }
1200 if (error != JVMTI_ERROR_NONE) {
1201 EXIT_ERROR(error, "getting all threads");
1202 }
1203 return threads;
1204}
1205
1206/**
1207 * Fill the passed in structure with thread group info.
1208 * name field is JVMTI allocated. parent is global ref.
1209 */
1210void
1211threadGroupInfo(jthreadGroup group, jvmtiThreadGroupInfo *info)
1212{
1213 jvmtiError error;
1214
1215 error = JVMTI_FUNC_PTR(gdata->jvmti,GetThreadGroupInfo)
1216 (gdata->jvmti, group, info);
1217 if (error != JVMTI_ERROR_NONE) {
1218 EXIT_ERROR(error, "on getting thread group info");
1219 }
1220}
1221
1222/**
1223 * Return class signature string
1224 */
1225jvmtiError
1226classSignature(jclass clazz, char **psignature, char **pgeneric_signature)
1227{
1228 jvmtiError error;
1229 char *signature = NULL;
1230
1231 /*
1232 * pgeneric_signature can be NULL, and GetClassSignature
1233 * accepts NULL.
1234 */
1235 error = FUNC_PTR(gdata->jvmti,GetClassSignature)
1236 (gdata->jvmti, clazz, &signature, pgeneric_signature);
1237
1238 if ( psignature != NULL ) {
1239 *psignature = signature;
1240 } else if ( signature != NULL ) {
1241 jvmtiDeallocate(signature);
1242 }
1243 return error;
1244}
1245
1246/* Get class name (not signature) */
1247char *
1248getClassname(jclass clazz)
1249{
1250 char *classname;
1251
1252 classname = NULL;
1253 if ( clazz != NULL ) {
1254 if (classSignature(clazz, &classname, NULL) != JVMTI_ERROR_NONE) {
1255 classname = NULL;
1256 } else {
1257 /* Convert in place */
1258 convertSignatureToClassname(classname);
1259 }
1260 }
1261 return classname; /* Caller must free this memory */
1262}
1263
1264void
1265writeGenericSignature(PacketOutputStream *out, char *genericSignature)
1266{
1267 if (genericSignature == NULL) {
1268 (void)outStream_writeString(out, "");
1269 } else {
1270 (void)outStream_writeString(out, genericSignature);
1271 }
1272}
1273
1274jint
1275classStatus(jclass clazz)
1276{
1277 jint status;
1278 jvmtiError error;
1279
1280 error = JVMTI_FUNC_PTR(gdata->jvmti,GetClassStatus)
1281 (gdata->jvmti, clazz, &status);
1282 if (error != JVMTI_ERROR_NONE) {
1283 EXIT_ERROR(error, "on getting class status");
1284 }
1285 return status;
1286}
1287
1288static jboolean
1289isArrayClass(jclass clazz)
1290{
1291 jboolean isArray = JNI_FALSE;
1292 jvmtiError error;
1293
1294 error = JVMTI_FUNC_PTR(gdata->jvmti,IsArrayClass)
1295 (gdata->jvmti, clazz, &isArray);
1296 if (error != JVMTI_ERROR_NONE) {
1297 EXIT_ERROR(error, "on checking for an array class");
1298 }
1299 return isArray;
1300}
1301
1302static jboolean
1303isInterface(jclass clazz)
1304{
1305 jboolean isInterface = JNI_FALSE;
1306 jvmtiError error;
1307
1308 error = JVMTI_FUNC_PTR(gdata->jvmti,IsInterface)
1309 (gdata->jvmti, clazz, &isInterface);
1310 if (error != JVMTI_ERROR_NONE) {
1311 EXIT_ERROR(error, "on checking for an interface");
1312 }
1313 return isInterface;
1314}
1315
1316jvmtiError
1317isFieldSynthetic(jclass clazz, jfieldID field, jboolean *psynthetic)
1318{
1319 jvmtiError error;
1320
1321 error = JVMTI_FUNC_PTR(gdata->jvmti,IsFieldSynthetic)
1322 (gdata->jvmti, clazz, field, psynthetic);
1323 if ( error == JVMTI_ERROR_MUST_POSSESS_CAPABILITY ) {
1324 /* If the query is not supported, we assume it is not synthetic. */
1325 *psynthetic = JNI_FALSE;
1326 return JVMTI_ERROR_NONE;
1327 }
1328 return error;
1329}
1330
1331jvmtiError
1332isMethodSynthetic(jmethodID method, jboolean *psynthetic)
1333{
1334 jvmtiError error;
1335
1336 error = JVMTI_FUNC_PTR(gdata->jvmti,IsMethodSynthetic)
1337 (gdata->jvmti, method, psynthetic);
1338 if ( error == JVMTI_ERROR_MUST_POSSESS_CAPABILITY ) {
1339 /* If the query is not supported, we assume it is not synthetic. */
1340 *psynthetic = JNI_FALSE;
1341 return JVMTI_ERROR_NONE;
1342 }
1343 return error;
1344}
1345
1346jboolean
1347isMethodNative(jmethodID method)
1348{
1349 jboolean isNative = JNI_FALSE;
1350 jvmtiError error;
1351
1352 error = JVMTI_FUNC_PTR(gdata->jvmti,IsMethodNative)
1353 (gdata->jvmti, method, &isNative);
1354 if (error != JVMTI_ERROR_NONE) {
1355 EXIT_ERROR(error, "on checking for a native interface");
1356 }
1357 return isNative;
1358}
1359
1360jboolean
1361isSameObject(JNIEnv *env, jobject o1, jobject o2)
1362{
1363 if ( o1==o2 ) {
1364 return JNI_TRUE;
1365 }
1366 return FUNC_PTR(env,IsSameObject)(env, o1, o2);
1367}
1368
1369jint
1370objectHashCode(jobject object)
1371{
1372 jint hashCode = 0;
1373 jvmtiError error;
1374
1375 if ( object!=NULL ) {
1376 error = JVMTI_FUNC_PTR(gdata->jvmti,GetObjectHashCode)
1377 (gdata->jvmti, object, &hashCode);
1378 if (error != JVMTI_ERROR_NONE) {
1379 EXIT_ERROR(error, "on getting an object hash code");
1380 }
1381 }
1382 return hashCode;
1383}
1384
1385/* Get all implemented interfaces (must be inside a WITH_LOCAL_REFS) */
1386jvmtiError
1387allInterfaces(jclass clazz, jclass **ppinterfaces, jint *pcount)
1388{
1389 jvmtiError error;
1390
1391 *pcount = 0;
1392 *ppinterfaces = NULL;
1393 error = JVMTI_FUNC_PTR(gdata->jvmti,GetImplementedInterfaces)
1394 (gdata->jvmti, clazz, pcount, ppinterfaces);
1395 return error;
1396}
1397
1398/* Get all loaded classes (must be inside a WITH_LOCAL_REFS) */
1399jvmtiError
1400allLoadedClasses(jclass **ppclasses, jint *pcount)
1401{
1402 jvmtiError error;
1403
1404 *pcount = 0;
1405 *ppclasses = NULL;
1406 error = JVMTI_FUNC_PTR(gdata->jvmti,GetLoadedClasses)
1407 (gdata->jvmti, pcount, ppclasses);
1408 return error;
1409}
1410
1411/* Get all loaded classes for a loader (must be inside a WITH_LOCAL_REFS) */
1412jvmtiError
1413allClassLoaderClasses(jobject loader, jclass **ppclasses, jint *pcount)
1414{
1415 jvmtiError error;
1416
1417 *pcount = 0;
1418 *ppclasses = NULL;
1419 error = JVMTI_FUNC_PTR(gdata->jvmti,GetClassLoaderClasses)
1420 (gdata->jvmti, loader, pcount, ppclasses);
1421 return error;
1422}
1423
1424static jboolean
1425is_a_nested_class(char *outer_sig, int outer_sig_len, char *sig, int sep)
1426{
1427 char *inner;
1428
1429 /* Assumed outer class signature is "LOUTERCLASSNAME;"
1430 * inner class signature is "LOUTERCLASSNAME$INNERNAME;"
1431 *
1432 * INNERNAME can take the form:
1433 * [0-9][1-9]* anonymous class somewhere in the file
1434 * [0-9][1-9]*NAME local class somewhere in the OUTER class
1435 * NAME nested class in OUTER
1436 *
1437 * If NAME itself contains a $ (sep) then classname is further nested
1438 * inside another class.
1439 *
1440 */
1441
1442 /* Check prefix first */
1443 if ( strncmp(sig, outer_sig, outer_sig_len-1) != 0 ) {
1444 return JNI_FALSE;
1445 }
1446
1447 /* Prefix must be followed by a $ (sep) */
1448 if ( sig[outer_sig_len-1] != sep ) {
1449 return JNI_FALSE; /* No sep follows the match, must not be nested. */
1450 }
1451
1452 /* Walk past any digits, if we reach the end, must be pure anonymous */
1453 inner = sig + outer_sig_len;
1454#if 1 /* We want to return local classes */
1455 while ( *inner && isdigit(*inner) ) {
1456 inner++;
1457 }
1458 /* But anonymous class names can't be trusted. */
1459 if ( *inner == ';' ) {
1460 return JNI_FALSE; /* A pure anonymous class */
1461 }
1462#else
1463 if ( *inner && isdigit(*inner) ) {
1464 return JNI_FALSE; /* A pure anonymous or local class */
1465 }
1466#endif
1467
1468 /* Nested deeper? */
1469 if ( strchr(inner, sep) != NULL ) {
1470 return JNI_FALSE; /* Nested deeper than we want? */
1471 }
1472 return JNI_TRUE;
1473}
1474
1475/* Get all nested classes for a class (must be inside a WITH_LOCAL_REFS) */
1476jvmtiError
1477allNestedClasses(jclass parent_clazz, jclass **ppnested, jint *pcount)
1478{
1479 jvmtiError error;
1480 jobject parent_loader;
1481 jclass *classes;
1482 char *signature;
1483 size_t len;
1484 jint count;
1485 jint ncount;
1486 int i;
1487
1488 *ppnested = NULL;
1489 *pcount = 0;
1490
1491 parent_loader = NULL;
1492 classes = NULL;
1493 signature = NULL;
1494 count = 0;
1495 ncount = 0;
1496
1497 error = classLoader(parent_clazz, &parent_loader);
1498 if (error != JVMTI_ERROR_NONE) {
1499 return error;
1500 }
1501 error = classSignature(parent_clazz, &signature, NULL);
1502 if (error != JVMTI_ERROR_NONE) {
1503 return error;
1504 }
1505 len = strlen(signature);
1506
1507 error = allClassLoaderClasses(parent_loader, &classes, &count);
1508 if ( error != JVMTI_ERROR_NONE ) {
1509 jvmtiDeallocate(signature);
1510 return error;
1511 }
1512
1513 for (i=0; i<count; i++) {
1514 jclass clazz;
1515 char *candidate_signature;
1516
1517 clazz = classes[i];
1518 candidate_signature = NULL;
1519 error = classSignature(clazz, &candidate_signature, NULL);
1520 if (error != JVMTI_ERROR_NONE) {
1521 break;
1522 }
1523
1524 if ( is_a_nested_class(signature, (int)len, candidate_signature, '$') ||
1525 is_a_nested_class(signature, (int)len, candidate_signature, '#') ) {
1526 /* Float nested classes to top */
1527 classes[i] = classes[ncount];
1528 classes[ncount++] = clazz;
1529 }
1530 jvmtiDeallocate(candidate_signature);
1531 }
1532
1533 jvmtiDeallocate(signature);
1534
1535 if ( count != 0 && ncount == 0 ) {
1536 jvmtiDeallocate(classes);
1537 classes = NULL;
1538 }
1539
1540 *ppnested = classes;
1541 *pcount = ncount;
1542 return error;
1543}
1544
1545void
1546createLocalRefSpace(JNIEnv *env, jint capacity)
1547{
1548 /*
1549 * Save current exception since it might get overwritten by
1550 * the calls below. Note we must depend on space in the existing
1551 * frame because asking for a new frame may generate an exception.
1552 */
1553 jobject throwable = JNI_FUNC_PTR(env,ExceptionOccurred)(env);
1554
1555 /*
1556 * Use the current frame if necessary; otherwise create a new one
1557 */
1558 if (JNI_FUNC_PTR(env,PushLocalFrame)(env, capacity) < 0) {
1559 EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"PushLocalFrame: Unable to push JNI frame");
1560 }
1561
1562 /*
1563 * TO DO: This could be more efficient if it used EnsureLocalCapacity,
1564 * but that would not work if two functions on the call stack
1565 * use this function. We would need to either track reserved
1566 * references on a per-thread basis or come up with a convention
1567 * that would prevent two functions from depending on this function
1568 * at the same time.
1569 */
1570
1571 /*
1572 * Restore exception state from before call
1573 */
1574 if (throwable != NULL) {
1575 JNI_FUNC_PTR(env,Throw)(env, throwable);
1576 } else {
1577 JNI_FUNC_PTR(env,ExceptionClear)(env);
1578 }
1579}
1580
1581jboolean
1582isClass(jobject object)
1583{
1584 JNIEnv *env = getEnv();
1585 return JNI_FUNC_PTR(env,IsInstanceOf)(env, object, gdata->classClass);
1586}
1587
1588jboolean
1589isThread(jobject object)
1590{
1591 JNIEnv *env = getEnv();
1592 return JNI_FUNC_PTR(env,IsInstanceOf)(env, object, gdata->threadClass);
1593}
1594
1595jboolean
1596isThreadGroup(jobject object)
1597{
1598 JNIEnv *env = getEnv();
1599 return JNI_FUNC_PTR(env,IsInstanceOf)(env, object, gdata->threadGroupClass);
1600}
1601
1602jboolean
1603isString(jobject object)
1604{
1605 JNIEnv *env = getEnv();
1606 return JNI_FUNC_PTR(env,IsInstanceOf)(env, object, gdata->stringClass);
1607}
1608
1609jboolean
1610isClassLoader(jobject object)
1611{
1612 JNIEnv *env = getEnv();
1613 return JNI_FUNC_PTR(env,IsInstanceOf)(env, object, gdata->classLoaderClass);
1614}
1615
1616jboolean
1617isArray(jobject object)
1618{
1619 JNIEnv *env = getEnv();
1620 jboolean is;
1621
1622 WITH_LOCAL_REFS(env, 1) {
1623 jclass clazz;
1624 clazz = JNI_FUNC_PTR(env,GetObjectClass)(env, object);
1625 is = isArrayClass(clazz);
1626 } END_WITH_LOCAL_REFS(env);
1627
1628 return is;
1629}
1630
1631/**
1632 * Return property value as jstring
1633 */
1634static jstring
1635getPropertyValue(JNIEnv *env, char *propertyName)
1636{
1637 jstring valueString;
1638 jstring nameString;
1639
1640 valueString = NULL;
1641
1642 /* Create new String object to hold the property name */
1643 nameString = JNI_FUNC_PTR(env,NewStringUTF)(env, propertyName);
1644 if (JNI_FUNC_PTR(env,ExceptionOccurred)(env)) {
1645 JNI_FUNC_PTR(env,ExceptionClear)(env);
1646 /* NULL will be returned below */
1647 } else {
1648 /* Call valueString = System.getProperty(nameString) */
1649 valueString = JNI_FUNC_PTR(env,CallStaticObjectMethod)
1650 (env, gdata->systemClass, gdata->systemGetProperty, nameString);
1651 if (JNI_FUNC_PTR(env,ExceptionOccurred)(env)) {
1652 JNI_FUNC_PTR(env,ExceptionClear)(env);
1653 valueString = NULL;
1654 }
1655 }
1656 return valueString;
1657}
1658
1659/**
1660 * Set an agent property
1661 */
1662void
1663setAgentPropertyValue(JNIEnv *env, char *propertyName, char* propertyValue)
1664{
1665 jstring nameString;
1666 jstring valueString;
1667
1668 if (gdata->agent_properties == NULL) {
1669 /* VMSupport doesn't exist; so ignore */
1670 return;
1671 }
1672
1673 /* Create jstrings for property name and value */
1674 nameString = JNI_FUNC_PTR(env,NewStringUTF)(env, propertyName);
1675 if (nameString != NULL) {
1676 valueString = JNI_FUNC_PTR(env,NewStringUTF)(env, propertyValue);
1677 if (valueString != NULL) {
1678 /* invoke Properties.setProperty */
1679 JNI_FUNC_PTR(env,CallObjectMethod)
1680 (env, gdata->agent_properties,
1681 gdata->setProperty,
1682 nameString, valueString);
1683 }
1684 }
1685 if (JNI_FUNC_PTR(env,ExceptionOccurred)(env)) {
1686 JNI_FUNC_PTR(env,ExceptionClear)(env);
1687 }
1688}
1689
1690/**
1691 * Return property value as JDWP allocated string in UTF8 encoding
1692 */
1693static char *
1694getPropertyUTF8(JNIEnv *env, char *propertyName)
1695{
1696 jvmtiError error;
1697 char *value;
1698
1699 value = NULL;
1700 error = JVMTI_FUNC_PTR(gdata->jvmti,GetSystemProperty)
1701 (gdata->jvmti, (const char *)propertyName, &value);
1702 if (error != JVMTI_ERROR_NONE) {
1703 jstring valueString;
1704
1705 value = NULL;
1706 valueString = getPropertyValue(env, propertyName);
1707
1708 if (valueString != NULL) {
1709 const char *utf;
1710
1711 /* Get the UTF8 encoding for this property value string */
1712 utf = JNI_FUNC_PTR(env,GetStringUTFChars)(env, valueString, NULL);
1713 /* Make a copy for returning, release the JNI copy */
1714 value = jvmtiAllocate((int)strlen(utf) + 1);
1715 if (value != NULL) {
1716 (void)strcpy(value, utf);
1717 }
1718 JNI_FUNC_PTR(env,ReleaseStringUTFChars)(env, valueString, utf);
1719 }
1720 }
1721 if ( value == NULL ) {
1722 ERROR_MESSAGE(("JDWP Can't get property value for %s", propertyName));
1723 EXIT_ERROR(AGENT_ERROR_NULL_POINTER,NULL);
1724 }
1725 return value;
1726}
1727
1728jboolean
1729isMethodObsolete(jmethodID method)
1730{
1731 jvmtiError error;
1732 jboolean obsolete = JNI_TRUE;
1733
1734 if ( method != NULL ) {
1735 error = JVMTI_FUNC_PTR(gdata->jvmti,IsMethodObsolete)
1736 (gdata->jvmti, method, &obsolete);
1737 if (error != JVMTI_ERROR_NONE) {
1738 obsolete = JNI_TRUE;
1739 }
1740 }
1741 return obsolete;
1742}
1743
1744/* Get the jvmti environment to be used with tags */
1745static jvmtiEnv *
1746getSpecialJvmti(void)
1747{
1748 jvmtiEnv *jvmti;
1749 jvmtiError error;
1750 int rc;
1751
1752 /* Get one time use JVMTI Env */
1753 jvmtiCapabilities caps;
1754
1755 rc = JVM_FUNC_PTR(gdata->jvm,GetEnv)
1756 (gdata->jvm, (void **)&jvmti, JVMTI_VERSION_1);
1757 if (rc != JNI_OK) {
1758 return NULL;
1759 }
1760 (void)memset(&caps, 0, (int)sizeof(caps));
1761 caps.can_tag_objects = 1;
1762 error = JVMTI_FUNC_PTR(jvmti,AddCapabilities)(jvmti, &caps);
1763 if ( error != JVMTI_ERROR_NONE ) {
1764 return NULL;
1765 }
1766 return jvmti;
1767}
1768
1769void
1770writeCodeLocation(PacketOutputStream *out, jclass clazz,
1771 jmethodID method, jlocation location)
1772{
1773 jbyte tag;
1774
1775 if (clazz != NULL) {
1776 tag = referenceTypeTag(clazz);
1777 } else {
1778 tag = JDWP_TYPE_TAG(CLASS);
1779 }
1780 (void)outStream_writeByte(out, tag);
1781 (void)outStream_writeObjectRef(getEnv(), out, clazz);
1782 (void)outStream_writeMethodID(out, isMethodObsolete(method)?NULL:method);
1783 (void)outStream_writeLocation(out, location);
1784}
1785
1786void *
1787jvmtiAllocate(jint numBytes)
1788{
1789 void *ptr;
1790 jvmtiError error;
1791 if ( numBytes == 0 ) {
1792 return NULL;
1793 }
1794 error = FUNC_PTR(gdata->jvmti,Allocate)
1795 (gdata->jvmti, numBytes, (unsigned char**)&ptr);
1796 if (error != JVMTI_ERROR_NONE ) {
1797 EXIT_ERROR(error, "Can't allocate jvmti memory");
1798 }
1799 return ptr;
1800}
1801
1802void
1803jvmtiDeallocate(void *ptr)
1804{
1805 jvmtiError error;
1806 if ( ptr == NULL ) {
1807 return;
1808 }
1809 error = FUNC_PTR(gdata->jvmti,Deallocate)
1810 (gdata->jvmti, ptr);
1811 if (error != JVMTI_ERROR_NONE ) {
1812 EXIT_ERROR(error, "Can't deallocate jvmti memory");
1813 }
1814}
1815
1816/* Rarely needed, transport library uses JDWP errors, only use? */
1817jvmtiError
1818map2jvmtiError(jdwpError error)
1819{
1820 switch ( error ) {
1821 case JDWP_ERROR(NONE):
1822 return JVMTI_ERROR_NONE;
1823 case JDWP_ERROR(INVALID_THREAD):
1824 return JVMTI_ERROR_INVALID_THREAD;
1825 case JDWP_ERROR(INVALID_THREAD_GROUP):
1826 return JVMTI_ERROR_INVALID_THREAD_GROUP;
1827 case JDWP_ERROR(INVALID_PRIORITY):
1828 return JVMTI_ERROR_INVALID_PRIORITY;
1829 case JDWP_ERROR(THREAD_NOT_SUSPENDED):
1830 return JVMTI_ERROR_THREAD_NOT_SUSPENDED;
1831 case JDWP_ERROR(THREAD_SUSPENDED):
1832 return JVMTI_ERROR_THREAD_SUSPENDED;
1833 case JDWP_ERROR(INVALID_OBJECT):
1834 return JVMTI_ERROR_INVALID_OBJECT;
1835 case JDWP_ERROR(INVALID_CLASS):
1836 return JVMTI_ERROR_INVALID_CLASS;
1837 case JDWP_ERROR(CLASS_NOT_PREPARED):
1838 return JVMTI_ERROR_CLASS_NOT_PREPARED;
1839 case JDWP_ERROR(INVALID_METHODID):
1840 return JVMTI_ERROR_INVALID_METHODID;
1841 case JDWP_ERROR(INVALID_LOCATION):
1842 return JVMTI_ERROR_INVALID_LOCATION;
1843 case JDWP_ERROR(INVALID_FIELDID):
1844 return JVMTI_ERROR_INVALID_FIELDID;
1845 case JDWP_ERROR(INVALID_FRAMEID):
1846 return AGENT_ERROR_INVALID_FRAMEID;
1847 case JDWP_ERROR(NO_MORE_FRAMES):
1848 return JVMTI_ERROR_NO_MORE_FRAMES;
1849 case JDWP_ERROR(OPAQUE_FRAME):
1850 return JVMTI_ERROR_OPAQUE_FRAME;
1851 case JDWP_ERROR(NOT_CURRENT_FRAME):
1852 return AGENT_ERROR_NOT_CURRENT_FRAME;
1853 case JDWP_ERROR(TYPE_MISMATCH):
1854 return JVMTI_ERROR_TYPE_MISMATCH;
1855 case JDWP_ERROR(INVALID_SLOT):
1856 return JVMTI_ERROR_INVALID_SLOT;
1857 case JDWP_ERROR(DUPLICATE):
1858 return JVMTI_ERROR_DUPLICATE;
1859 case JDWP_ERROR(NOT_FOUND):
1860 return JVMTI_ERROR_NOT_FOUND;
1861 case JDWP_ERROR(INVALID_MONITOR):
1862 return JVMTI_ERROR_INVALID_MONITOR;
1863 case JDWP_ERROR(NOT_MONITOR_OWNER):
1864 return JVMTI_ERROR_NOT_MONITOR_OWNER;
1865 case JDWP_ERROR(INTERRUPT):
1866 return JVMTI_ERROR_INTERRUPT;
1867 case JDWP_ERROR(INVALID_CLASS_FORMAT):
1868 return JVMTI_ERROR_INVALID_CLASS_FORMAT;
1869 case JDWP_ERROR(CIRCULAR_CLASS_DEFINITION):
1870 return JVMTI_ERROR_CIRCULAR_CLASS_DEFINITION;
1871 case JDWP_ERROR(FAILS_VERIFICATION):
1872 return JVMTI_ERROR_FAILS_VERIFICATION;
1873 case JDWP_ERROR(ADD_METHOD_NOT_IMPLEMENTED):
1874 return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_ADDED;
1875 case JDWP_ERROR(SCHEMA_CHANGE_NOT_IMPLEMENTED):
1876 return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED;
1877 case JDWP_ERROR(INVALID_TYPESTATE):
1878 return JVMTI_ERROR_INVALID_TYPESTATE;
1879 case JDWP_ERROR(HIERARCHY_CHANGE_NOT_IMPLEMENTED):
1880 return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED;
1881 case JDWP_ERROR(DELETE_METHOD_NOT_IMPLEMENTED):
1882 return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_DELETED;
1883 case JDWP_ERROR(UNSUPPORTED_VERSION):
1884 return JVMTI_ERROR_UNSUPPORTED_VERSION;
1885 case JDWP_ERROR(NAMES_DONT_MATCH):
1886 return JVMTI_ERROR_NAMES_DONT_MATCH;
1887 case JDWP_ERROR(CLASS_MODIFIERS_CHANGE_NOT_IMPLEMENTED):
1888 return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_MODIFIERS_CHANGED;
1889 case JDWP_ERROR(METHOD_MODIFIERS_CHANGE_NOT_IMPLEMENTED):
1890 return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_MODIFIERS_CHANGED;
1891 case JDWP_ERROR(NOT_IMPLEMENTED):
1892 return JVMTI_ERROR_NOT_AVAILABLE;
1893 case JDWP_ERROR(NULL_POINTER):
1894 return JVMTI_ERROR_NULL_POINTER;
1895 case JDWP_ERROR(ABSENT_INFORMATION):
1896 return JVMTI_ERROR_ABSENT_INFORMATION;
1897 case JDWP_ERROR(INVALID_EVENT_TYPE):
1898 return JVMTI_ERROR_INVALID_EVENT_TYPE;
1899 case JDWP_ERROR(ILLEGAL_ARGUMENT):
1900 return JVMTI_ERROR_ILLEGAL_ARGUMENT;
1901 case JDWP_ERROR(OUT_OF_MEMORY):
1902 return JVMTI_ERROR_OUT_OF_MEMORY;
1903 case JDWP_ERROR(ACCESS_DENIED):
1904 return JVMTI_ERROR_ACCESS_DENIED;
1905 case JDWP_ERROR(VM_DEAD):
1906 return JVMTI_ERROR_WRONG_PHASE;
1907 case JDWP_ERROR(UNATTACHED_THREAD):
1908 return JVMTI_ERROR_UNATTACHED_THREAD;
1909 case JDWP_ERROR(INVALID_TAG):
1910 return AGENT_ERROR_INVALID_TAG;
1911 case JDWP_ERROR(ALREADY_INVOKING):
1912 return AGENT_ERROR_ALREADY_INVOKING;
1913 case JDWP_ERROR(INVALID_INDEX):
1914 return AGENT_ERROR_INVALID_INDEX;
1915 case JDWP_ERROR(INVALID_LENGTH):
1916 return AGENT_ERROR_INVALID_LENGTH;
1917 case JDWP_ERROR(INVALID_STRING):
1918 return AGENT_ERROR_INVALID_STRING;
1919 case JDWP_ERROR(INVALID_CLASS_LOADER):
1920 return AGENT_ERROR_INVALID_CLASS_LOADER;
1921 case JDWP_ERROR(INVALID_ARRAY):
1922 return AGENT_ERROR_INVALID_ARRAY;
1923 case JDWP_ERROR(TRANSPORT_LOAD):
1924 return AGENT_ERROR_TRANSPORT_LOAD;
1925 case JDWP_ERROR(TRANSPORT_INIT):
1926 return AGENT_ERROR_TRANSPORT_INIT;
1927 case JDWP_ERROR(NATIVE_METHOD):
1928 return AGENT_ERROR_NATIVE_METHOD;
1929 case JDWP_ERROR(INVALID_COUNT):
1930 return AGENT_ERROR_INVALID_COUNT;
1931 case JDWP_ERROR(INTERNAL):
1932 return AGENT_ERROR_JDWP_INTERNAL;
1933 }
1934 return AGENT_ERROR_INTERNAL;
1935}
1936
1937static jvmtiEvent index2jvmti[EI_max-EI_min+1];
1938static jdwpEvent index2jdwp [EI_max-EI_min+1];
1939
1940void
1941eventIndexInit(void)
1942{
1943 (void)memset(index2jvmti, 0, (int)sizeof(index2jvmti));
1944 (void)memset(index2jdwp, 0, (int)sizeof(index2jdwp));
1945
1946 index2jvmti[EI_SINGLE_STEP -EI_min] = JVMTI_EVENT_SINGLE_STEP;
1947 index2jvmti[EI_BREAKPOINT -EI_min] = JVMTI_EVENT_BREAKPOINT;
1948 index2jvmti[EI_FRAME_POP -EI_min] = JVMTI_EVENT_FRAME_POP;
1949 index2jvmti[EI_EXCEPTION -EI_min] = JVMTI_EVENT_EXCEPTION;
1950 index2jvmti[EI_THREAD_START -EI_min] = JVMTI_EVENT_THREAD_START;
1951 index2jvmti[EI_THREAD_END -EI_min] = JVMTI_EVENT_THREAD_END;
1952 index2jvmti[EI_CLASS_PREPARE -EI_min] = JVMTI_EVENT_CLASS_PREPARE;
1953 index2jvmti[EI_GC_FINISH -EI_min] = JVMTI_EVENT_GARBAGE_COLLECTION_FINISH;
1954 index2jvmti[EI_CLASS_LOAD -EI_min] = JVMTI_EVENT_CLASS_LOAD;
1955 index2jvmti[EI_FIELD_ACCESS -EI_min] = JVMTI_EVENT_FIELD_ACCESS;
1956 index2jvmti[EI_FIELD_MODIFICATION -EI_min] = JVMTI_EVENT_FIELD_MODIFICATION;
1957 index2jvmti[EI_EXCEPTION_CATCH -EI_min] = JVMTI_EVENT_EXCEPTION_CATCH;
1958 index2jvmti[EI_METHOD_ENTRY -EI_min] = JVMTI_EVENT_METHOD_ENTRY;
1959 index2jvmti[EI_METHOD_EXIT -EI_min] = JVMTI_EVENT_METHOD_EXIT;
1960 index2jvmti[EI_MONITOR_CONTENDED_ENTER -EI_min] = JVMTI_EVENT_MONITOR_CONTENDED_ENTER;
1961 index2jvmti[EI_MONITOR_CONTENDED_ENTERED -EI_min] = JVMTI_EVENT_MONITOR_CONTENDED_ENTERED;
1962 index2jvmti[EI_MONITOR_WAIT -EI_min] = JVMTI_EVENT_MONITOR_WAIT;
1963 index2jvmti[EI_MONITOR_WAITED -EI_min] = JVMTI_EVENT_MONITOR_WAITED;
1964 index2jvmti[EI_VM_INIT -EI_min] = JVMTI_EVENT_VM_INIT;
1965 index2jvmti[EI_VM_DEATH -EI_min] = JVMTI_EVENT_VM_DEATH;
1966
1967 index2jdwp[EI_SINGLE_STEP -EI_min] = JDWP_EVENT(SINGLE_STEP);
1968 index2jdwp[EI_BREAKPOINT -EI_min] = JDWP_EVENT(BREAKPOINT);
1969 index2jdwp[EI_FRAME_POP -EI_min] = JDWP_EVENT(FRAME_POP);
1970 index2jdwp[EI_EXCEPTION -EI_min] = JDWP_EVENT(EXCEPTION);
1971 index2jdwp[EI_THREAD_START -EI_min] = JDWP_EVENT(THREAD_START);
1972 index2jdwp[EI_THREAD_END -EI_min] = JDWP_EVENT(THREAD_END);
1973 index2jdwp[EI_CLASS_PREPARE -EI_min] = JDWP_EVENT(CLASS_PREPARE);
1974 index2jdwp[EI_GC_FINISH -EI_min] = JDWP_EVENT(CLASS_UNLOAD);
1975 index2jdwp[EI_CLASS_LOAD -EI_min] = JDWP_EVENT(CLASS_LOAD);
1976 index2jdwp[EI_FIELD_ACCESS -EI_min] = JDWP_EVENT(FIELD_ACCESS);
1977 index2jdwp[EI_FIELD_MODIFICATION -EI_min] = JDWP_EVENT(FIELD_MODIFICATION);
1978 index2jdwp[EI_EXCEPTION_CATCH -EI_min] = JDWP_EVENT(EXCEPTION_CATCH);
1979 index2jdwp[EI_METHOD_ENTRY -EI_min] = JDWP_EVENT(METHOD_ENTRY);
1980 index2jdwp[EI_METHOD_EXIT -EI_min] = JDWP_EVENT(METHOD_EXIT);
1981 index2jdwp[EI_MONITOR_CONTENDED_ENTER -EI_min] = JDWP_EVENT(MONITOR_CONTENDED_ENTER);
1982 index2jdwp[EI_MONITOR_CONTENDED_ENTERED -EI_min] = JDWP_EVENT(MONITOR_CONTENDED_ENTERED);
1983 index2jdwp[EI_MONITOR_WAIT -EI_min] = JDWP_EVENT(MONITOR_WAIT);
1984 index2jdwp[EI_MONITOR_WAITED -EI_min] = JDWP_EVENT(MONITOR_WAITED);
1985 index2jdwp[EI_VM_INIT -EI_min] = JDWP_EVENT(VM_INIT);
1986 index2jdwp[EI_VM_DEATH -EI_min] = JDWP_EVENT(VM_DEATH);
1987}
1988
1989jdwpEvent
1990eventIndex2jdwp(EventIndex i)
1991{
1992 if ( i < EI_min || i > EI_max ) {
1993 EXIT_ERROR(AGENT_ERROR_INVALID_INDEX,"bad EventIndex");
1994 }
1995 return index2jdwp[i-EI_min];
1996}
1997
1998jvmtiEvent
1999eventIndex2jvmti(EventIndex i)
2000{
2001 if ( i < EI_min || i > EI_max ) {
2002 EXIT_ERROR(AGENT_ERROR_INVALID_INDEX,"bad EventIndex");
2003 }
2004 return index2jvmti[i-EI_min];
2005}
2006
2007EventIndex
2008jdwp2EventIndex(jdwpEvent eventType)
2009{
2010 switch ( eventType ) {
2011 case JDWP_EVENT(SINGLE_STEP):
2012 return EI_SINGLE_STEP;
2013 case JDWP_EVENT(BREAKPOINT):
2014 return EI_BREAKPOINT;
2015 case JDWP_EVENT(FRAME_POP):
2016 return EI_FRAME_POP;
2017 case JDWP_EVENT(EXCEPTION):
2018 return EI_EXCEPTION;
2019 case JDWP_EVENT(THREAD_START):
2020 return EI_THREAD_START;
2021 case JDWP_EVENT(THREAD_END):
2022 return EI_THREAD_END;
2023 case JDWP_EVENT(CLASS_PREPARE):
2024 return EI_CLASS_PREPARE;
2025 case JDWP_EVENT(CLASS_UNLOAD):
2026 return EI_GC_FINISH;
2027 case JDWP_EVENT(CLASS_LOAD):
2028 return EI_CLASS_LOAD;
2029 case JDWP_EVENT(FIELD_ACCESS):
2030 return EI_FIELD_ACCESS;
2031 case JDWP_EVENT(FIELD_MODIFICATION):
2032 return EI_FIELD_MODIFICATION;
2033 case JDWP_EVENT(EXCEPTION_CATCH):
2034 return EI_EXCEPTION_CATCH;
2035 case JDWP_EVENT(METHOD_ENTRY):
2036 return EI_METHOD_ENTRY;
2037 case JDWP_EVENT(METHOD_EXIT):
2038 return EI_METHOD_EXIT;
2039 case JDWP_EVENT(METHOD_EXIT_WITH_RETURN_VALUE):
2040 return EI_METHOD_EXIT;
2041 case JDWP_EVENT(MONITOR_CONTENDED_ENTER):
2042 return EI_MONITOR_CONTENDED_ENTER;
2043 case JDWP_EVENT(MONITOR_CONTENDED_ENTERED):
2044 return EI_MONITOR_CONTENDED_ENTERED;
2045 case JDWP_EVENT(MONITOR_WAIT):
2046 return EI_MONITOR_WAIT;
2047 case JDWP_EVENT(MONITOR_WAITED):
2048 return EI_MONITOR_WAITED;
2049 case JDWP_EVENT(VM_INIT):
2050 return EI_VM_INIT;
2051 case JDWP_EVENT(VM_DEATH):
2052 return EI_VM_DEATH;
2053 default:
2054 break;
2055 }
2056
2057 /*
2058 * Event type not recognized - don't exit with error as caller
2059 * may wish to return error to debugger.
2060 */
2061 return (EventIndex)0;
2062}
2063
2064EventIndex
2065jvmti2EventIndex(jvmtiEvent kind)
2066{
2067 switch ( kind ) {
2068 case JVMTI_EVENT_SINGLE_STEP:
2069 return EI_SINGLE_STEP;
2070 case JVMTI_EVENT_BREAKPOINT:
2071 return EI_BREAKPOINT;
2072 case JVMTI_EVENT_FRAME_POP:
2073 return EI_FRAME_POP;
2074 case JVMTI_EVENT_EXCEPTION:
2075 return EI_EXCEPTION;
2076 case JVMTI_EVENT_THREAD_START:
2077 return EI_THREAD_START;
2078 case JVMTI_EVENT_THREAD_END:
2079 return EI_THREAD_END;
2080 case JVMTI_EVENT_CLASS_PREPARE:
2081 return EI_CLASS_PREPARE;
2082 case JVMTI_EVENT_GARBAGE_COLLECTION_FINISH:
2083 return EI_GC_FINISH;
2084 case JVMTI_EVENT_CLASS_LOAD:
2085 return EI_CLASS_LOAD;
2086 case JVMTI_EVENT_FIELD_ACCESS:
2087 return EI_FIELD_ACCESS;
2088 case JVMTI_EVENT_FIELD_MODIFICATION:
2089 return EI_FIELD_MODIFICATION;
2090 case JVMTI_EVENT_EXCEPTION_CATCH:
2091 return EI_EXCEPTION_CATCH;
2092 case JVMTI_EVENT_METHOD_ENTRY:
2093 return EI_METHOD_ENTRY;
2094 case JVMTI_EVENT_METHOD_EXIT:
2095 return EI_METHOD_EXIT;
2096 /*
2097 * There is no JVMTI_EVENT_METHOD_EXIT_WITH_RETURN_VALUE.
2098 * The normal JVMTI_EVENT_METHOD_EXIT always contains the return value.
2099 */
2100 case JVMTI_EVENT_MONITOR_CONTENDED_ENTER:
2101 return EI_MONITOR_CONTENDED_ENTER;
2102 case JVMTI_EVENT_MONITOR_CONTENDED_ENTERED:
2103 return EI_MONITOR_CONTENDED_ENTERED;
2104 case JVMTI_EVENT_MONITOR_WAIT:
2105 return EI_MONITOR_WAIT;
2106 case JVMTI_EVENT_MONITOR_WAITED:
2107 return EI_MONITOR_WAITED;
2108 case JVMTI_EVENT_VM_INIT:
2109 return EI_VM_INIT;
2110 case JVMTI_EVENT_VM_DEATH:
2111 return EI_VM_DEATH;
2112 default:
2113 EXIT_ERROR(AGENT_ERROR_INVALID_INDEX,"JVMTI to EventIndex mapping");
2114 break;
2115 }
2116 return (EventIndex)0;
2117}
2118
2119/* This routine is commonly used, maps jvmti and agent errors to the best
2120 * jdwp error code we can map to.
2121 */
2122jdwpError
2123map2jdwpError(jvmtiError error)
2124{
2125 switch ( error ) {
2126 case JVMTI_ERROR_NONE:
2127 return JDWP_ERROR(NONE);
2128 case AGENT_ERROR_INVALID_THREAD:
2129 case JVMTI_ERROR_INVALID_THREAD:
2130 return JDWP_ERROR(INVALID_THREAD);
2131 case JVMTI_ERROR_INVALID_THREAD_GROUP:
2132 return JDWP_ERROR(INVALID_THREAD_GROUP);
2133 case JVMTI_ERROR_INVALID_PRIORITY:
2134 return JDWP_ERROR(INVALID_PRIORITY);
2135 case JVMTI_ERROR_THREAD_NOT_SUSPENDED:
2136 return JDWP_ERROR(THREAD_NOT_SUSPENDED);
2137 case JVMTI_ERROR_THREAD_SUSPENDED:
2138 return JDWP_ERROR(THREAD_SUSPENDED);
2139 case JVMTI_ERROR_THREAD_NOT_ALIVE:
2140 return JDWP_ERROR(INVALID_THREAD);
2141 case AGENT_ERROR_INVALID_OBJECT:
2142 case JVMTI_ERROR_INVALID_OBJECT:
2143 return JDWP_ERROR(INVALID_OBJECT);
2144 case JVMTI_ERROR_INVALID_CLASS:
2145 return JDWP_ERROR(INVALID_CLASS);
2146 case JVMTI_ERROR_CLASS_NOT_PREPARED:
2147 return JDWP_ERROR(CLASS_NOT_PREPARED);
2148 case JVMTI_ERROR_INVALID_METHODID:
2149 return JDWP_ERROR(INVALID_METHODID);
2150 case JVMTI_ERROR_INVALID_LOCATION:
2151 return JDWP_ERROR(INVALID_LOCATION);
2152 case JVMTI_ERROR_INVALID_FIELDID:
2153 return JDWP_ERROR(INVALID_FIELDID);
2154 case AGENT_ERROR_NO_MORE_FRAMES:
2155 case JVMTI_ERROR_NO_MORE_FRAMES:
2156 return JDWP_ERROR(NO_MORE_FRAMES);
2157 case JVMTI_ERROR_OPAQUE_FRAME:
2158 return JDWP_ERROR(OPAQUE_FRAME);
2159 case JVMTI_ERROR_TYPE_MISMATCH:
2160 return JDWP_ERROR(TYPE_MISMATCH);
2161 case JVMTI_ERROR_INVALID_SLOT:
2162 return JDWP_ERROR(INVALID_SLOT);
2163 case JVMTI_ERROR_DUPLICATE:
2164 return JDWP_ERROR(DUPLICATE);
2165 case JVMTI_ERROR_NOT_FOUND:
2166 return JDWP_ERROR(NOT_FOUND);
2167 case JVMTI_ERROR_INVALID_MONITOR:
2168 return JDWP_ERROR(INVALID_MONITOR);
2169 case JVMTI_ERROR_NOT_MONITOR_OWNER:
2170 return JDWP_ERROR(NOT_MONITOR_OWNER);
2171 case JVMTI_ERROR_INTERRUPT:
2172 return JDWP_ERROR(INTERRUPT);
2173 case JVMTI_ERROR_INVALID_CLASS_FORMAT:
2174 return JDWP_ERROR(INVALID_CLASS_FORMAT);
2175 case JVMTI_ERROR_CIRCULAR_CLASS_DEFINITION:
2176 return JDWP_ERROR(CIRCULAR_CLASS_DEFINITION);
2177 case JVMTI_ERROR_FAILS_VERIFICATION:
2178 return JDWP_ERROR(FAILS_VERIFICATION);
2179 case JVMTI_ERROR_INVALID_TYPESTATE:
2180 return JDWP_ERROR(INVALID_TYPESTATE);
2181 case JVMTI_ERROR_UNSUPPORTED_VERSION:
2182 return JDWP_ERROR(UNSUPPORTED_VERSION);
2183 case JVMTI_ERROR_NAMES_DONT_MATCH:
2184 return JDWP_ERROR(NAMES_DONT_MATCH);
2185 case AGENT_ERROR_NULL_POINTER:
2186 case JVMTI_ERROR_NULL_POINTER:
2187 return JDWP_ERROR(NULL_POINTER);
2188 case JVMTI_ERROR_ABSENT_INFORMATION:
2189 return JDWP_ERROR(ABSENT_INFORMATION);
2190 case AGENT_ERROR_INVALID_EVENT_TYPE:
2191 case JVMTI_ERROR_INVALID_EVENT_TYPE:
2192 return JDWP_ERROR(INVALID_EVENT_TYPE);
2193 case AGENT_ERROR_ILLEGAL_ARGUMENT:
2194 case JVMTI_ERROR_ILLEGAL_ARGUMENT:
2195 return JDWP_ERROR(ILLEGAL_ARGUMENT);
2196 case JVMTI_ERROR_OUT_OF_MEMORY:
2197 case AGENT_ERROR_OUT_OF_MEMORY:
2198 return JDWP_ERROR(OUT_OF_MEMORY);
2199 case JVMTI_ERROR_ACCESS_DENIED:
2200 return JDWP_ERROR(ACCESS_DENIED);
2201 case JVMTI_ERROR_WRONG_PHASE:
2202 case AGENT_ERROR_VM_DEAD:
2203 case AGENT_ERROR_NO_JNI_ENV:
2204 return JDWP_ERROR(VM_DEAD);
2205 case AGENT_ERROR_JNI_EXCEPTION:
2206 case JVMTI_ERROR_UNATTACHED_THREAD:
2207 return JDWP_ERROR(UNATTACHED_THREAD);
2208 case JVMTI_ERROR_NOT_AVAILABLE:
2209 case JVMTI_ERROR_MUST_POSSESS_CAPABILITY:
2210 return JDWP_ERROR(NOT_IMPLEMENTED);
2211 case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED:
2212 return JDWP_ERROR(HIERARCHY_CHANGE_NOT_IMPLEMENTED);
2213 case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_DELETED:
2214 return JDWP_ERROR(DELETE_METHOD_NOT_IMPLEMENTED);
2215 case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_ADDED:
2216 return JDWP_ERROR(ADD_METHOD_NOT_IMPLEMENTED);
2217 case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED:
2218 return JDWP_ERROR(SCHEMA_CHANGE_NOT_IMPLEMENTED);
2219 case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_MODIFIERS_CHANGED:
2220 return JDWP_ERROR(CLASS_MODIFIERS_CHANGE_NOT_IMPLEMENTED);
2221 case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_MODIFIERS_CHANGED:
2222 return JDWP_ERROR(METHOD_MODIFIERS_CHANGE_NOT_IMPLEMENTED);
2223 case AGENT_ERROR_NOT_CURRENT_FRAME:
2224 return JDWP_ERROR(NOT_CURRENT_FRAME);
2225 case AGENT_ERROR_INVALID_TAG:
2226 return JDWP_ERROR(INVALID_TAG);
2227 case AGENT_ERROR_ALREADY_INVOKING:
2228 return JDWP_ERROR(ALREADY_INVOKING);
2229 case AGENT_ERROR_INVALID_INDEX:
2230 return JDWP_ERROR(INVALID_INDEX);
2231 case AGENT_ERROR_INVALID_LENGTH:
2232 return JDWP_ERROR(INVALID_LENGTH);
2233 case AGENT_ERROR_INVALID_STRING:
2234 return JDWP_ERROR(INVALID_STRING);
2235 case AGENT_ERROR_INVALID_CLASS_LOADER:
2236 return JDWP_ERROR(INVALID_CLASS_LOADER);
2237 case AGENT_ERROR_INVALID_ARRAY:
2238 return JDWP_ERROR(INVALID_ARRAY);
2239 case AGENT_ERROR_TRANSPORT_LOAD:
2240 return JDWP_ERROR(TRANSPORT_LOAD);
2241 case AGENT_ERROR_TRANSPORT_INIT:
2242 return JDWP_ERROR(TRANSPORT_INIT);
2243 case AGENT_ERROR_NATIVE_METHOD:
2244 return JDWP_ERROR(NATIVE_METHOD);
2245 case AGENT_ERROR_INVALID_COUNT:
2246 return JDWP_ERROR(INVALID_COUNT);
2247 case AGENT_ERROR_INVALID_FRAMEID:
2248 return JDWP_ERROR(INVALID_FRAMEID);
2249 case JVMTI_ERROR_INTERNAL:
2250 case JVMTI_ERROR_INVALID_ENVIRONMENT:
2251 case AGENT_ERROR_INTERNAL:
2252 case AGENT_ERROR_JVMTI_INTERNAL:
2253 case AGENT_ERROR_JDWP_INTERNAL:
2254 return JDWP_ERROR(INTERNAL);
2255 default:
2256 break;
2257 }
2258 return JDWP_ERROR(INTERNAL);
2259}
2260
2261jint
2262map2jdwpSuspendStatus(jint state)
2263{
2264 jint status = 0;
2265 if ( ( state & JVMTI_THREAD_STATE_SUSPENDED ) != 0 ) {
2266 status = JDWP_SUSPEND_STATUS(SUSPENDED);
2267 }
2268 return status;
2269}
2270
2271jdwpThreadStatus
2272map2jdwpThreadStatus(jint state)
2273{
2274 jdwpThreadStatus status;
2275
2276 status = (jdwpThreadStatus)(-1);
2277
2278 if ( ! ( state & JVMTI_THREAD_STATE_ALIVE ) ) {
2279 if ( state & JVMTI_THREAD_STATE_TERMINATED ) {
2280 status = JDWP_THREAD_STATUS(ZOMBIE);
2281 } else {
2282 /* FIXUP? New JDWP #define for not started? */
2283 status = (jdwpThreadStatus)(-1);
2284 }
2285 } else {
2286 if ( state & JVMTI_THREAD_STATE_SLEEPING ) {
2287 status = JDWP_THREAD_STATUS(SLEEPING);
2288 } else if ( state & JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER ) {
2289 status = JDWP_THREAD_STATUS(MONITOR);
2290 } else if ( state & JVMTI_THREAD_STATE_WAITING ) {
2291 status = JDWP_THREAD_STATUS(WAIT);
2292 } else if ( state & JVMTI_THREAD_STATE_RUNNABLE ) {
2293 status = JDWP_THREAD_STATUS(RUNNING);
2294 }
2295 }
2296 return status;
2297}
2298
2299jint
2300map2jdwpClassStatus(jint classStatus)
2301{
2302 jint status = 0;
2303 if ( ( classStatus & JVMTI_CLASS_STATUS_VERIFIED ) != 0 ) {
2304 status |= JDWP_CLASS_STATUS(VERIFIED);
2305 }
2306 if ( ( classStatus & JVMTI_CLASS_STATUS_PREPARED ) != 0 ) {
2307 status |= JDWP_CLASS_STATUS(PREPARED);
2308 }
2309 if ( ( classStatus & JVMTI_CLASS_STATUS_INITIALIZED ) != 0 ) {
2310 status |= JDWP_CLASS_STATUS(INITIALIZED);
2311 }
2312 if ( ( classStatus & JVMTI_CLASS_STATUS_ERROR ) != 0 ) {
2313 status |= JDWP_CLASS_STATUS(ERROR);
2314 }
2315 return status;
2316}
2317
2318void
2319log_debugee_location(const char *func,
2320 jthread thread, jmethodID method, jlocation location)
2321{
2322 int logging_locations = LOG_TEST(JDWP_LOG_LOC);
2323
2324 if ( logging_locations ) {
2325 char *method_name;
2326 char *class_sig;
2327 jvmtiError error;
2328 jvmtiThreadInfo info;
2329 jint state;
2330
2331 /* Get thread information */
2332 info.name = NULL;
2333 error = FUNC_PTR(gdata->jvmti,GetThreadInfo)
2334 (gdata->jvmti, thread, &info);
2335 if ( error != JVMTI_ERROR_NONE) {
2336 info.name = NULL;
2337 }
2338 error = FUNC_PTR(gdata->jvmti,GetThreadState)
2339 (gdata->jvmti, thread, &state);
2340 if ( error != JVMTI_ERROR_NONE) {
2341 state = 0;
2342 }
2343
2344 /* Get method if necessary */
2345 if ( method==NULL ) {
2346 error = FUNC_PTR(gdata->jvmti,GetFrameLocation)
2347 (gdata->jvmti, thread, 0, &method, &location);
2348 if ( error != JVMTI_ERROR_NONE ) {
2349 method = NULL;
2350 location = 0;
2351 }
2352 }
2353
2354 /* Get method name */
2355 method_name = NULL;
2356 if ( method != NULL ) {
2357 error = methodSignature(method, &method_name, NULL, NULL);
2358 if ( error != JVMTI_ERROR_NONE ) {
2359 method_name = NULL;
2360 }
2361 }
2362
2363 /* Get class signature */
2364 class_sig = NULL;
2365 if ( method != NULL ) {
2366 jclass clazz;
2367
2368 error = methodClass(method, &clazz);
2369 if ( error == JVMTI_ERROR_NONE ) {
2370 error = classSignature(clazz, &class_sig, NULL);
2371 if ( error != JVMTI_ERROR_NONE ) {
2372 class_sig = NULL;
2373 }
2374 }
2375 }
2376
2377 /* Issue log message */
2378 LOG_LOC(("%s: debugee: thread=%p(%s:0x%x),method=%p(%s@%d;%s)",
2379 func,
2380 thread, info.name==NULL ? "?" : info.name, state,
2381 method, method_name==NULL ? "?" : method_name,
2382 (int)location, class_sig==NULL ? "?" : class_sig));
2383
2384 /* Free memory */
2385 if ( class_sig != NULL ) {
2386 jvmtiDeallocate(class_sig);
2387 }
2388 if ( method_name != NULL ) {
2389 jvmtiDeallocate(method_name);
2390 }
2391 if ( info.name != NULL ) {
2392 jvmtiDeallocate(info.name);
2393 }
2394 }
2395}
2396
2397/* ********************************************************************* */
2398/* JDK 6.0: Use of new Heap Iteration functions */
2399/* ********************************************************************* */
2400
2401/* ********************************************************************* */
2402/* Instances */
2403
2404/* Structure to hold class instances heap iteration data (arg user_data) */
2405typedef struct ClassInstancesData {
2406 jint instCount;
2407 jint maxInstances;
2408 jlong objTag;
2409 jvmtiError error;
2410} ClassInstancesData;
2411
2412/* Callback for instance object tagging (heap_reference_callback). */
2413static jint JNICALL
2414cbObjectTagInstance(jvmtiHeapReferenceKind reference_kind,
2415 const jvmtiHeapReferenceInfo* reference_info, jlong class_tag,
2416 jlong referrer_class_tag, jlong size,
2417 jlong* tag_ptr, jlong* referrer_tag_ptr, jint length, void* user_data)
2418{
2419 ClassInstancesData *data;
2420
2421 /* Check data structure */
2422 data = (ClassInstancesData*)user_data;
2423 if (data == NULL) {
2424 data->error = AGENT_ERROR_ILLEGAL_ARGUMENT;
2425 return JVMTI_VISIT_ABORT;
2426 }
2427
2428 /* If we have tagged enough objects, just abort */
2429 if ( data->maxInstances != 0 && data->instCount >= data->maxInstances ) {
2430 return JVMTI_VISIT_ABORT;
2431 }
2432
2433 /* If tagged already, just continue */
2434 if ( (*tag_ptr) != (jlong)0 ) {
2435 return JVMTI_VISIT_OBJECTS;
2436 }
2437
2438 /* Tag the object so we don't count it again, and so we can retrieve it */
2439 (*tag_ptr) = data->objTag;
2440 data->instCount++;
2441 return JVMTI_VISIT_OBJECTS;
2442}
2443
2444/* Get instances for one class */
2445jvmtiError
2446classInstances(jclass klass, ObjectBatch *instances, int maxInstances)
2447{
2448 ClassInstancesData data;
2449 jvmtiHeapCallbacks heap_callbacks;
2450 jvmtiError error;
2451 jvmtiEnv *jvmti;
2452
2453 /* Check interface assumptions */
2454
2455 if (klass == NULL) {
2456 return AGENT_ERROR_INVALID_OBJECT;
2457 }
2458
2459 if ( maxInstances < 0 || instances == NULL) {
2460 return AGENT_ERROR_ILLEGAL_ARGUMENT;
2461 }
2462
2463 /* Initialize return information */
2464 instances->count = 0;
2465 instances->objects = NULL;
2466
2467 /* Get jvmti environment to use */
2468 jvmti = getSpecialJvmti();
2469 if ( jvmti == NULL ) {
2470 return AGENT_ERROR_INTERNAL;
2471 }
2472
2473 /* Setup data to passed around the callbacks */
2474 data.instCount = 0;
2475 data.maxInstances = maxInstances;
2476 data.objTag = (jlong)1;
2477 data.error = JVMTI_ERROR_NONE;
2478
2479 /* Clear out callbacks structure */
2480 (void)memset(&heap_callbacks,0,sizeof(heap_callbacks));
2481
2482 /* Set the callbacks we want */
2483 heap_callbacks.heap_reference_callback = &cbObjectTagInstance;
2484
2485 /* Follow references, no initiating object, just this class, all objects */
2486 error = JVMTI_FUNC_PTR(jvmti,FollowReferences)
2487 (jvmti, 0, klass, NULL, &heap_callbacks, &data);
2488 if ( error == JVMTI_ERROR_NONE ) {
2489 error = data.error;
2490 }
2491
2492 /* Get all the instances now that they are tagged */
2493 if ( error == JVMTI_ERROR_NONE ) {
2494 error = JVMTI_FUNC_PTR(jvmti,GetObjectsWithTags)
2495 (jvmti, 1, &(data.objTag), &(instances->count),
2496 &(instances->objects), NULL);
2497 /* Verify we got the count we expected */
2498 if ( data.instCount != instances->count ) {
2499 error = AGENT_ERROR_INTERNAL;
2500 }
2501 }
2502
2503 /* Dispose of any special jvmti environment */
2504 (void)JVMTI_FUNC_PTR(jvmti,DisposeEnvironment)(jvmti);
2505 return error;
2506}
2507
2508/* ********************************************************************* */
2509/* Instance counts. */
2510
2511/* Macros to convert a class or instance tag to an index and back again */
2512#define INDEX2CLASSTAG(i) ((jlong)((i)+1))
2513#define CLASSTAG2INDEX(t) (((int)(t))-1)
2514#define JLONG_ABS(x) (((x)<(jlong)0)?-(x):(x))
2515
2516/* Structure to hold class count heap traversal data (arg user_data) */
2517typedef struct ClassCountData {
2518 int classCount;
2519 jlong *counts;
2520 jlong negObjTag;
2521 jvmtiError error;
2522} ClassCountData;
2523
2524/* Two different cbObjectCounter's, one for FollowReferences, one for
2525 * IterateThroughHeap. Pick a card, any card.
2526 */
2527
2528/* Callback for object count heap traversal (heap_reference_callback) */
2529static jint JNICALL
2530cbObjectCounterFromRef(jvmtiHeapReferenceKind reference_kind,
2531 const jvmtiHeapReferenceInfo* reference_info, jlong class_tag,
2532 jlong referrer_class_tag, jlong size,
2533 jlong* tag_ptr, jlong* referrer_tag_ptr, jint length, void* user_data)
2534{
2535 ClassCountData *data;
2536 int index;
2537 jlong jindex;
2538 jlong tag;
2539
2540 /* Check data structure */
2541 data = (ClassCountData*)user_data;
2542 if (data == NULL) {
2543 data->error = AGENT_ERROR_ILLEGAL_ARGUMENT;
2544 return JVMTI_VISIT_ABORT;
2545 }
2546
2547 /* Classes with no class_tag should have been filtered out. */
2548 if ( class_tag == (jlong)0 ) {
2549 data->error = AGENT_ERROR_INTERNAL;
2550 return JVMTI_VISIT_ABORT;
2551 }
2552
2553 /* Class tag not one we really want (jclass not in supplied list) */
2554 if ( class_tag == data->negObjTag ) {
2555 return JVMTI_VISIT_OBJECTS;
2556 }
2557
2558 /* If object tag is negative, just continue, we counted it */
2559 tag = (*tag_ptr);
2560 if ( tag < (jlong)0 ) {
2561 return JVMTI_VISIT_OBJECTS;
2562 }
2563
2564 /* Tag the object with a negative value just so we don't count it again */
2565 if ( tag == (jlong)0 ) {
2566 /* This object had no tag value, so we give it the negObjTag value */
2567 (*tag_ptr) = data->negObjTag;
2568 } else {
2569 /* If this object had a positive tag value, it must be one of the
2570 * jclass objects we tagged. We need to preserve the value of
2571 * this tag for later objects that might have this as a class
2572 * tag, so we just make the existing tag value negative.
2573 */
2574 (*tag_ptr) = -tag;
2575 }
2576
2577 /* Absolute value of class tag is an index into the counts[] array */
2578 jindex = JLONG_ABS(class_tag);
2579 index = CLASSTAG2INDEX(jindex);
2580 if (index < 0 || index >= data->classCount) {
2581 data->error = AGENT_ERROR_ILLEGAL_ARGUMENT;
2582 return JVMTI_VISIT_ABORT;
2583 }
2584
2585 /* Bump instance count on this class */
2586 data->counts[index]++;
2587 return JVMTI_VISIT_OBJECTS;
2588}
2589
2590/* Callback for instance count heap traversal (heap_iteration_callback) */
2591static jint JNICALL
2592cbObjectCounter(jlong class_tag, jlong size, jlong* tag_ptr, jint length,
2593 void* user_data)
2594{
2595 ClassCountData *data;
2596 int index;
2597
2598 /* Check data structure */
2599 data = (ClassCountData*)user_data;
2600 if (data == NULL) {
2601 data->error = AGENT_ERROR_ILLEGAL_ARGUMENT;
2602 return JVMTI_VISIT_ABORT;
2603 }
2604
2605 /* Classes with no tag should be filtered out. */
2606 if ( class_tag == (jlong)0 ) {
2607 data->error = AGENT_ERROR_INTERNAL;
2608 return JVMTI_VISIT_ABORT;
2609 }
2610
2611 /* Class tag is actually an index into data arrays */
2612 index = CLASSTAG2INDEX(class_tag);
2613 if (index < 0 || index >= data->classCount) {
2614 data->error = AGENT_ERROR_ILLEGAL_ARGUMENT;
2615 return JVMTI_VISIT_ABORT;
2616 }
2617
2618 /* Bump instance count on this class */
2619 data->counts[index]++;
2620 return JVMTI_VISIT_OBJECTS;
2621}
2622
2623/* Get instance counts for a set of classes */
2624jvmtiError
2625classInstanceCounts(jint classCount, jclass *classes, jlong *counts)
2626{
2627 jvmtiHeapCallbacks heap_callbacks;
2628 ClassCountData data;
2629 jvmtiError error;
2630 jvmtiEnv *jvmti;
2631 int i;
2632
2633 /* Check interface assumptions */
2634 if ( classes == NULL || classCount <= 0 || counts == NULL ) {
2635 return AGENT_ERROR_ILLEGAL_ARGUMENT;
2636 }
2637
2638 /* Initialize return information */
2639 for ( i = 0 ; i < classCount ; i++ ) {
2640 counts[i] = (jlong)0;
2641 }
2642
2643 /* Get jvmti environment to use */
2644 jvmti = getSpecialJvmti();
2645 if ( jvmti == NULL ) {
2646 return AGENT_ERROR_INTERNAL;
2647 }
2648
2649 /* Setup class data structure */
2650 data.error = JVMTI_ERROR_NONE;
2651 data.classCount = classCount;
2652 data.counts = counts;
2653
2654 error = JVMTI_ERROR_NONE;
2655 /* Set tags on classes, use index in classes[] as the tag value. */
2656 error = JVMTI_ERROR_NONE;
2657 for ( i = 0 ; i < classCount ; i++ ) {
2658 if (classes[i] != NULL) {
2659 jlong tag;
2660
2661 tag = INDEX2CLASSTAG(i);
2662 error = JVMTI_FUNC_PTR(jvmti,SetTag) (jvmti, classes[i], tag);
2663 if ( error != JVMTI_ERROR_NONE ) {
2664 break;
2665 }
2666 }
2667 }
2668
2669 /* Traverse heap, two ways to do this for instance counts. */
2670 if ( error == JVMTI_ERROR_NONE ) {
2671
2672 /* Clear out callbacks structure */
2673 (void)memset(&heap_callbacks,0,sizeof(heap_callbacks));
2674
2675 /* Check debug flags to see how to do this. */
2676 if ( (gdata->debugflags & USE_ITERATE_THROUGH_HEAP) == 0 ) {
2677
2678 /* Using FollowReferences only gives us live objects, but we
2679 * need to tag the objects to avoid counting them twice since
2680 * the callback is per reference.
2681 * The jclass objects have been tagged with their index in the
2682 * supplied list, and that tag may flip to negative if it
2683 * is also an object of interest.
2684 * All other objects being counted that weren't in the
2685 * supplied classes list will have a negative classCount
2686 * tag value. So all objects counted will have negative tags.
2687 * If the absolute tag value is an index in the supplied
2688 * list, then it's one of the supplied classes.
2689 */
2690 data.negObjTag = -INDEX2CLASSTAG(classCount);
2691
2692 /* Setup callbacks, only using object reference callback */
2693 heap_callbacks.heap_reference_callback = &cbObjectCounterFromRef;
2694
2695 /* Follow references, no initiating object, tagged classes only */
2696 error = JVMTI_FUNC_PTR(jvmti,FollowReferences)
2697 (jvmti, JVMTI_HEAP_FILTER_CLASS_UNTAGGED,
2698 NULL, NULL, &heap_callbacks, &data);
2699
2700 } else {
2701
2702 /* Using IterateThroughHeap means that we will visit each object
2703 * once, so no special tag tricks here. Just simple counting.
2704 * However in this case the object might not be live, so we do
2705 * a GC beforehand to make sure we minimize this.
2706 */
2707
2708 /* FIXUP: Need some kind of trigger here to avoid excessive GC's? */
2709 error = JVMTI_FUNC_PTR(jvmti,ForceGarbageCollection)(jvmti);
2710 if ( error != JVMTI_ERROR_NONE ) {
2711
2712 /* Setup callbacks, just need object callback */
2713 heap_callbacks.heap_iteration_callback = &cbObjectCounter;
2714
2715 /* Iterate through entire heap, tagged classes only */
2716 error = JVMTI_FUNC_PTR(jvmti,IterateThroughHeap)
2717 (jvmti, JVMTI_HEAP_FILTER_CLASS_UNTAGGED,
2718 NULL, &heap_callbacks, &data);
2719
2720 }
2721 }
2722
2723 /* Use data error if needed */
2724 if ( error == JVMTI_ERROR_NONE ) {
2725 error = data.error;
2726 }
2727
2728 }
2729
2730 /* Dispose of any special jvmti environment */
2731 (void)JVMTI_FUNC_PTR(jvmti,DisposeEnvironment)(jvmti);
2732 return error;
2733}
2734
2735/* ********************************************************************* */
2736/* Referrers */
2737
2738/* Structure to hold object referrer heap traversal data (arg user_data) */
2739typedef struct ReferrerData {
2740 int refCount;
2741 int maxObjects;
2742 jlong refTag;
2743 jlong objTag;
2744 jboolean selfRef;
2745 jvmtiError error;
2746} ReferrerData;
2747
2748/* Callback for referrers object tagging (heap_reference_callback). */
2749static jint JNICALL
2750cbObjectTagReferrer(jvmtiHeapReferenceKind reference_kind,
2751 const jvmtiHeapReferenceInfo* reference_info, jlong class_tag,
2752 jlong referrer_class_tag, jlong size,
2753 jlong* tag_ptr, jlong* referrer_tag_ptr, jint length, void* user_data)
2754{
2755 ReferrerData *data;
2756
2757 /* Check data structure */
2758 data = (ReferrerData*)user_data;
2759 if (data == NULL) {
2760 data->error = AGENT_ERROR_ILLEGAL_ARGUMENT;
2761 return JVMTI_VISIT_ABORT;
2762 }
2763
2764 /* If we have tagged enough objects, just abort */
2765 if ( data->maxObjects != 0 && data->refCount >= data->maxObjects ) {
2766 return JVMTI_VISIT_ABORT;
2767 }
2768
2769 /* If not of interest, just continue */
2770 if ( (*tag_ptr) != data->objTag ) {
2771 return JVMTI_VISIT_OBJECTS;
2772 }
2773
2774 /* Self reference that we haven't counted? */
2775 if ( tag_ptr == referrer_tag_ptr ) {
2776 if ( data->selfRef == JNI_FALSE ) {
2777 data->selfRef = JNI_TRUE;
2778 data->refCount++;
2779 }
2780 return JVMTI_VISIT_OBJECTS;
2781 }
2782
2783 /* If the referrer can be tagged, and hasn't been tagged, tag it */
2784 if ( referrer_tag_ptr != NULL ) {
2785 if ( (*referrer_tag_ptr) == (jlong)0 ) {
2786 *referrer_tag_ptr = data->refTag;
2787 data->refCount++;
2788 }
2789 }
2790 return JVMTI_VISIT_OBJECTS;
2791}
2792
2793/* Heap traversal to find referrers of an object */
2794jvmtiError
2795objectReferrers(jobject obj, ObjectBatch *referrers, int maxObjects)
2796{
2797 jvmtiHeapCallbacks heap_callbacks;
2798 ReferrerData data;
2799 jvmtiError error;
2800 jvmtiEnv *jvmti;
2801
2802 /* Check interface assumptions */
2803 if (obj == NULL) {
2804 return AGENT_ERROR_INVALID_OBJECT;
2805 }
2806 if (referrers == NULL || maxObjects < 0 ) {
2807 return AGENT_ERROR_ILLEGAL_ARGUMENT;
2808 }
2809
2810 /* Initialize return information */
2811 referrers->count = 0;
2812 referrers->objects = NULL;
2813
2814 /* Get jvmti environment to use */
2815 jvmti = getSpecialJvmti();
2816 if ( jvmti == NULL ) {
2817 return AGENT_ERROR_INTERNAL;
2818 }
2819
2820 /* Fill in the data structure passed around the callbacks */
2821 data.refCount = 0;
2822 data.maxObjects = maxObjects;
2823 data.objTag = (jlong)1;
2824 data.refTag = (jlong)2;
2825 data.selfRef = JNI_FALSE;
2826 data.error = JVMTI_ERROR_NONE;
2827
2828 /* Tag the object of interest */
2829 error = JVMTI_FUNC_PTR(jvmti,SetTag) (jvmti, obj, data.objTag);
2830
2831 /* No need to go any further if we can't tag the object */
2832 if ( error == JVMTI_ERROR_NONE ) {
2833
2834 /* Clear out callbacks structure */
2835 (void)memset(&heap_callbacks,0,sizeof(heap_callbacks));
2836
2837 /* Setup callbacks we want */
2838 heap_callbacks.heap_reference_callback = &cbObjectTagReferrer;
2839
2840 /* Follow references, no initiating object, all classes, 1 tagged objs */
2841 error = JVMTI_FUNC_PTR(jvmti,FollowReferences)
2842 (jvmti, JVMTI_HEAP_FILTER_UNTAGGED,
2843 NULL, NULL, &heap_callbacks, &data);
2844
2845 /* Use data error if needed */
2846 if ( error == JVMTI_ERROR_NONE ) {
2847 error = data.error;
2848 }
2849
2850 }
2851
2852 /* Watch out for self-reference */
2853 if ( error == JVMTI_ERROR_NONE && data.selfRef == JNI_TRUE ) {
2854 /* Tag itself as a referer */
2855 error = JVMTI_FUNC_PTR(jvmti,SetTag) (jvmti, obj, data.refTag);
2856 }
2857
2858 /* Get the jobjects for the tagged referrer objects. */
2859 if ( error == JVMTI_ERROR_NONE ) {
2860 error = JVMTI_FUNC_PTR(jvmti,GetObjectsWithTags)
2861 (jvmti, 1, &(data.refTag), &(referrers->count),
2862 &(referrers->objects), NULL);
2863 /* Verify we got the count we expected */
2864 if ( data.refCount != referrers->count ) {
2865 error = AGENT_ERROR_INTERNAL;
2866 }
2867 }
2868
2869 /* Dispose of any special jvmti environment */
2870 (void)JVMTI_FUNC_PTR(jvmti,DisposeEnvironment)(jvmti);
2871 return error;
2872}
Note: See TracBrowser for help on using the repository browser.