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