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