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