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