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