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