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