1 /*
2 * Copyright (c) 1998, 2006, 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 "util.h"
27 #include "VirtualMachineImpl.h"
28 #include "commonRef.h"
29 #include "inStream.h"
30 #include "outStream.h"
31 #include "eventHandler.h"
32 #include "eventHelper.h"
33 #include "threadControl.h"
34 #include "SDE.h"
35 #include "FrameID.h"
36
37 // ANDROID-CHANGED: Need to sent metrics before doExit
38 #include "timing.h"
39
40
41 static char *versionName = "Java Debug Wire Protocol (Reference Implementation)";
42 static int majorVersion = 1; /* JDWP major version */
43 static int minorVersion = 8; /* JDWP minor version */
44
45 static jboolean
version(PacketInputStream * in,PacketOutputStream * out)46 version(PacketInputStream *in, PacketOutputStream *out)
47 {
48 char buf[500];
49 char *vmName;
50 char *vmVersion;
51 char *vmInfo;
52
53 if (gdata->vmDead) {
54 outStream_setError(out, JDWP_ERROR(VM_DEAD));
55 return JNI_TRUE;
56 }
57
58 vmVersion = gdata->property_java_version;
59 if (vmVersion == NULL) {
60 vmVersion = "<unknown>";
61 }
62 // ANDROID-CHANGED: The runtime value of the java.version property has always been "0" on
63 // android but the old debugger just sent a different value. Simply sending "0"
64 // can confuse some JDWP clients so we will simply say that we are version "8".
65 if (strcmp(gdata->property_java_vm_name, "Dalvik") == 0 && strcmp(vmVersion, "0") == 0) {
66 vmVersion = "8";
67 }
68 vmName = gdata->property_java_vm_name;
69 if (vmName == NULL) {
70 vmName = "<unknown>";
71 }
72 vmInfo = gdata->property_java_vm_info;
73 if (vmInfo == NULL) {
74 vmInfo = "<unknown>";
75 }
76
77 /*
78 * Write the descriptive version information
79 */
80 (void)snprintf(buf, sizeof(buf),
81 "%s version %d.%d\nJVM Debug Interface version %d.%d\n"
82 "JVM version %s (%s, %s)",
83 versionName, majorVersion, minorVersion,
84 jvmtiMajorVersion(), jvmtiMinorVersion(),
85 vmVersion, vmName, vmInfo);
86 (void)outStream_writeString(out, buf);
87
88 /*
89 * Write the JDWP version numbers
90 */
91 (void)outStream_writeInt(out, majorVersion);
92 (void)outStream_writeInt(out, minorVersion);
93
94 /*
95 * Write the VM version and name
96 */
97 (void)outStream_writeString(out, vmVersion);
98 (void)outStream_writeString(out, vmName);
99
100 return JNI_TRUE;
101 }
102
103 static jboolean
classesForSignature(PacketInputStream * in,PacketOutputStream * out)104 classesForSignature(PacketInputStream *in, PacketOutputStream *out)
105 {
106 JNIEnv *env;
107 char *signature;
108
109 if (gdata->vmDead) {
110 outStream_setError(out, JDWP_ERROR(VM_DEAD));
111 return JNI_TRUE;
112 }
113
114 signature = inStream_readString(in);
115 if (signature == NULL) {
116 outStream_setError(out, JDWP_ERROR(OUT_OF_MEMORY));
117 return JNI_TRUE;
118 }
119 if (inStream_error(in)) {
120 return JNI_TRUE;
121 }
122
123 env = getEnv();
124
125 WITH_LOCAL_REFS(env, 1) {
126
127 jint classCount;
128 jclass *theClasses;
129 jvmtiError error;
130
131 error = allLoadedClasses(&theClasses, &classCount);
132 if ( error == JVMTI_ERROR_NONE ) {
133 /* Count classes in theClasses which match signature */
134 int matchCount = 0;
135 /* Count classes written to the JDWP connection */
136 int writtenCount = 0;
137 int i;
138
139 for (i=0; i<classCount; i++) {
140 jclass clazz = theClasses[i];
141 jint status = classStatus(clazz);
142 char *candidate_signature = NULL;
143 jint wanted =
144 (JVMTI_CLASS_STATUS_PREPARED|JVMTI_CLASS_STATUS_ARRAY|
145 JVMTI_CLASS_STATUS_PRIMITIVE);
146
147 /* We want prepared classes, primitives, and arrays only */
148 if ((status & wanted) == 0) {
149 continue;
150 }
151
152 error = classSignature(clazz, &candidate_signature, NULL);
153 if (error != JVMTI_ERROR_NONE) {
154 break;
155 }
156
157 if (strcmp(candidate_signature, signature) == 0) {
158 /* Float interesting classes (those that
159 * are matching and are prepared) to the
160 * beginning of the array.
161 */
162 theClasses[i] = theClasses[matchCount];
163 theClasses[matchCount++] = clazz;
164 }
165 jvmtiDeallocate(candidate_signature);
166 }
167
168 /* At this point matching prepared classes occupy
169 * indicies 0 thru matchCount-1 of theClasses.
170 */
171
172 if ( error == JVMTI_ERROR_NONE ) {
173 (void)outStream_writeInt(out, matchCount);
174 for (; writtenCount < matchCount; writtenCount++) {
175 jclass clazz = theClasses[writtenCount];
176 jint status = classStatus(clazz);
177 jbyte tag = referenceTypeTag(clazz);
178 (void)outStream_writeByte(out, tag);
179 (void)outStream_writeObjectRef(env, out, clazz);
180 (void)outStream_writeInt(out, map2jdwpClassStatus(status));
181 /* No point in continuing if there's an error */
182 if (outStream_error(out)) {
183 break;
184 }
185 }
186 }
187
188 jvmtiDeallocate(theClasses);
189 }
190
191 if ( error != JVMTI_ERROR_NONE ) {
192 outStream_setError(out, map2jdwpError(error));
193 }
194
195 } END_WITH_LOCAL_REFS(env);
196
197 jvmtiDeallocate(signature);
198
199 return JNI_TRUE;
200 }
201
202 static jboolean
allClasses1(PacketInputStream * in,PacketOutputStream * out,int outputGenerics)203 allClasses1(PacketInputStream *in, PacketOutputStream *out, int outputGenerics)
204 {
205 JNIEnv *env;
206
207 if (gdata->vmDead) {
208 outStream_setError(out, JDWP_ERROR(VM_DEAD));
209 return JNI_TRUE;
210 }
211
212 env = getEnv();
213
214 WITH_LOCAL_REFS(env, 1) {
215
216 jint classCount;
217 jclass *theClasses;
218 jvmtiError error;
219
220 error = allLoadedClasses(&theClasses, &classCount);
221 if ( error != JVMTI_ERROR_NONE ) {
222 outStream_setError(out, map2jdwpError(error));
223 } else {
224 /* Count classes in theClasses which are prepared */
225 int prepCount = 0;
226 /* Count classes written to the JDWP connection */
227 int writtenCount = 0;
228 int i;
229
230 for (i=0; i<classCount; i++) {
231 jclass clazz = theClasses[i];
232 jint status = classStatus(clazz);
233 jint wanted =
234 (JVMTI_CLASS_STATUS_PREPARED|JVMTI_CLASS_STATUS_ARRAY);
235
236 /* We want prepared classes and arrays only */
237 if ((status & wanted) != 0) {
238 /* Float interesting classes (those that
239 * are prepared) to the beginning of the array.
240 */
241 theClasses[i] = theClasses[prepCount];
242 theClasses[prepCount++] = clazz;
243 }
244 }
245
246 /* At this point prepared classes occupy
247 * indicies 0 thru prepCount-1 of theClasses.
248 */
249
250 (void)outStream_writeInt(out, prepCount);
251 for (; writtenCount < prepCount; writtenCount++) {
252 char *signature = NULL;
253 char *genericSignature = NULL;
254 jclass clazz = theClasses[writtenCount];
255 jint status = classStatus(clazz);
256 jbyte tag = referenceTypeTag(clazz);
257 jvmtiError error;
258
259 error = classSignature(clazz, &signature, &genericSignature);
260 if (error != JVMTI_ERROR_NONE) {
261 outStream_setError(out, map2jdwpError(error));
262 break;
263 }
264
265 (void)outStream_writeByte(out, tag);
266 (void)outStream_writeObjectRef(env, out, clazz);
267 (void)outStream_writeString(out, signature);
268 if (outputGenerics == 1) {
269 writeGenericSignature(out, genericSignature);
270 }
271
272 (void)outStream_writeInt(out, map2jdwpClassStatus(status));
273 jvmtiDeallocate(signature);
274 if (genericSignature != NULL) {
275 jvmtiDeallocate(genericSignature);
276 }
277
278 /* No point in continuing if there's an error */
279 if (outStream_error(out)) {
280 break;
281 }
282 }
283 jvmtiDeallocate(theClasses);
284 }
285
286 } END_WITH_LOCAL_REFS(env);
287
288 return JNI_TRUE;
289 }
290
291 static jboolean
allClasses(PacketInputStream * in,PacketOutputStream * out)292 allClasses(PacketInputStream *in, PacketOutputStream *out)
293 {
294 return allClasses1(in, out, 0);
295 }
296
297 static jboolean
allClassesWithGeneric(PacketInputStream * in,PacketOutputStream * out)298 allClassesWithGeneric(PacketInputStream *in, PacketOutputStream *out)
299 {
300 return allClasses1(in, out, 1);
301 }
302
303 /***********************************************************/
304
305
306 static jboolean
instanceCounts(PacketInputStream * in,PacketOutputStream * out)307 instanceCounts(PacketInputStream *in, PacketOutputStream *out)
308 {
309 jint classCount;
310 jclass *classes;
311 JNIEnv *env;
312 int ii;
313
314 if (gdata->vmDead) {
315 outStream_setError(out, JDWP_ERROR(VM_DEAD));
316 return JNI_TRUE;
317 }
318
319 classCount = inStream_readInt(in);
320
321 if (inStream_error(in)) {
322 return JNI_TRUE;
323 }
324 if (classCount == 0) {
325 (void)outStream_writeInt(out, 0);
326 return JNI_TRUE;
327 }
328 if (classCount < 0) {
329 outStream_setError(out, JDWP_ERROR(ILLEGAL_ARGUMENT));
330 return JNI_TRUE;
331 }
332 env = getEnv();
333 classes = jvmtiAllocate(classCount * (int)sizeof(jclass));
334 for (ii = 0; ii < classCount; ii++) {
335 jdwpError errorCode;
336 classes[ii] = inStream_readClassRef(env, in);
337 errorCode = inStream_error(in);
338 if (errorCode != JDWP_ERROR(NONE)) {
339 /*
340 * A class could have been unloaded/gc'd so
341 * if we get an error, just ignore it and keep
342 * going. An instanceCount of 0 will be returned.
343 */
344 if (errorCode == JDWP_ERROR(INVALID_OBJECT) ||
345 errorCode == JDWP_ERROR(INVALID_CLASS)) {
346 inStream_clearError(in);
347 classes[ii] = NULL;
348 continue;
349 }
350 jvmtiDeallocate(classes);
351 return JNI_TRUE;
352 }
353 }
354
355 WITH_LOCAL_REFS(env, 1) {
356 jlong *counts;
357 jvmtiError error;
358
359 counts = jvmtiAllocate(classCount * (int)sizeof(jlong));
360 /* Iterate over heap getting info on these classes */
361 error = classInstanceCounts(classCount, classes, counts);
362 if (error != JVMTI_ERROR_NONE) {
363 outStream_setError(out, map2jdwpError(error));
364 } else {
365 (void)outStream_writeInt(out, classCount);
366 for (ii = 0; ii < classCount; ii++) {
367 (void)outStream_writeLong(out, counts[ii]);
368 }
369 }
370 jvmtiDeallocate(counts);
371 } END_WITH_LOCAL_REFS(env);
372 jvmtiDeallocate(classes);
373 return JNI_TRUE;
374 }
375
376 static jboolean
redefineClasses(PacketInputStream * in,PacketOutputStream * out)377 redefineClasses(PacketInputStream *in, PacketOutputStream *out)
378 {
379 jvmtiClassDefinition *classDefs;
380 jboolean ok = JNI_TRUE;
381 jint classCount;
382 jint i;
383 JNIEnv *env;
384
385 if (gdata->vmDead) {
386 /* quietly ignore */
387 return JNI_TRUE;
388 }
389
390 classCount = inStream_readInt(in);
391 if (inStream_error(in)) {
392 return JNI_TRUE;
393 }
394 if ( classCount == 0 ) {
395 return JNI_TRUE;
396 }
397 /*LINTED*/
398 classDefs = jvmtiAllocate(classCount*(int)sizeof(jvmtiClassDefinition));
399 if (classDefs == NULL) {
400 outStream_setError(out, JDWP_ERROR(OUT_OF_MEMORY));
401 return JNI_TRUE;
402 }
403 /*LINTED*/
404 (void)memset(classDefs, 0, classCount*sizeof(jvmtiClassDefinition));
405
406 env = getEnv();
407 for (i = 0; i < classCount; ++i) {
408 int byteCount;
409 unsigned char * bytes;
410 jclass clazz;
411
412 clazz = inStream_readClassRef(env, in);
413 if (inStream_error(in)) {
414 ok = JNI_FALSE;
415 break;
416 }
417 byteCount = inStream_readInt(in);
418 if (inStream_error(in)) {
419 ok = JNI_FALSE;
420 break;
421 }
422 if ( byteCount <= 0 ) {
423 outStream_setError(out, JDWP_ERROR(INVALID_CLASS_FORMAT));
424 ok = JNI_FALSE;
425 break;
426 }
427 bytes = (unsigned char *)jvmtiAllocate(byteCount);
428 if (bytes == NULL) {
429 outStream_setError(out, JDWP_ERROR(OUT_OF_MEMORY));
430 ok = JNI_FALSE;
431 break;
432 }
433 (void)inStream_readBytes(in, byteCount, (jbyte *)bytes);
434 if (inStream_error(in)) {
435 ok = JNI_FALSE;
436 break;
437 }
438
439 classDefs[i].klass = clazz;
440 classDefs[i].class_byte_count = byteCount;
441 classDefs[i].class_bytes = bytes;
442 }
443
444 if (ok == JNI_TRUE) {
445 jvmtiError error;
446
447 error = JVMTI_FUNC_PTR(gdata->jvmti,RedefineClasses)
448 (gdata->jvmti, classCount, classDefs);
449 if (error != JVMTI_ERROR_NONE) {
450 outStream_setError(out, map2jdwpError(error));
451 } else {
452 /* zap our BP info */
453 for ( i = 0 ; i < classCount; i++ ) {
454 eventHandler_freeClassBreakpoints(classDefs[i].klass);
455 }
456 }
457 }
458
459 /* free up allocated memory */
460 for ( i = 0 ; i < classCount; i++ ) {
461 if ( classDefs[i].class_bytes != NULL ) {
462 jvmtiDeallocate((void*)classDefs[i].class_bytes);
463 }
464 }
465 jvmtiDeallocate(classDefs);
466
467 return JNI_TRUE;
468 }
469
470 static jboolean
setDefaultStratum(PacketInputStream * in,PacketOutputStream * out)471 setDefaultStratum(PacketInputStream *in, PacketOutputStream *out)
472 {
473 char *stratumId;
474
475 if (gdata->vmDead) {
476 /* quietly ignore */
477 return JNI_TRUE;
478 }
479
480 stratumId = inStream_readString(in);
481 if (inStream_error(in)) {
482 return JNI_TRUE;
483 } else if (strcmp(stratumId, "") == 0) {
484 stratumId = NULL;
485 }
486 setGlobalStratumId(stratumId);
487
488 return JNI_TRUE;
489 }
490
491 static jboolean
getAllThreads(PacketInputStream * in,PacketOutputStream * out)492 getAllThreads(PacketInputStream *in, PacketOutputStream *out)
493 {
494 JNIEnv *env;
495
496 if (gdata->vmDead) {
497 outStream_setError(out, JDWP_ERROR(VM_DEAD));
498 return JNI_TRUE;
499 }
500
501 env = getEnv();
502
503 WITH_LOCAL_REFS(env, 1) {
504
505 int i;
506 jint threadCount;
507 jthread *theThreads;
508
509 theThreads = allThreads(&threadCount);
510 if (theThreads == NULL) {
511 outStream_setError(out, JDWP_ERROR(OUT_OF_MEMORY));
512 } else {
513 /* Squish out all of the debugger-spawned threads */
514 threadCount = filterDebugThreads(theThreads, threadCount);
515
516 (void)outStream_writeInt(out, threadCount);
517 for (i = 0; i <threadCount; i++) {
518 (void)outStream_writeObjectRef(env, out, theThreads[i]);
519 }
520
521 jvmtiDeallocate(theThreads);
522 }
523
524 } END_WITH_LOCAL_REFS(env);
525
526 return JNI_TRUE;
527 }
528
529 static jboolean
topLevelThreadGroups(PacketInputStream * in,PacketOutputStream * out)530 topLevelThreadGroups(PacketInputStream *in, PacketOutputStream *out)
531 {
532 JNIEnv *env;
533
534 if (gdata->vmDead) {
535 outStream_setError(out, JDWP_ERROR(VM_DEAD));
536 return JNI_TRUE;
537 }
538
539 env = getEnv();
540
541 WITH_LOCAL_REFS(env, 1) {
542
543 jvmtiError error;
544 jint groupCount;
545 jthreadGroup *groups;
546
547 groups = NULL;
548 error = JVMTI_FUNC_PTR(gdata->jvmti,GetTopThreadGroups)
549 (gdata->jvmti, &groupCount, &groups);
550 if (error != JVMTI_ERROR_NONE) {
551 outStream_setError(out, map2jdwpError(error));
552 } else {
553 int i;
554
555 (void)outStream_writeInt(out, groupCount);
556 for (i = 0; i < groupCount; i++) {
557 (void)outStream_writeObjectRef(env, out, groups[i]);
558 }
559
560 jvmtiDeallocate(groups);
561 }
562
563 } END_WITH_LOCAL_REFS(env);
564
565 return JNI_TRUE;
566 }
567
568 static jboolean
dispose(PacketInputStream * in,PacketOutputStream * out)569 dispose(PacketInputStream *in, PacketOutputStream *out)
570 {
571 return JNI_TRUE;
572 }
573
574 static jboolean
idSizes(PacketInputStream * in,PacketOutputStream * out)575 idSizes(PacketInputStream *in, PacketOutputStream *out)
576 {
577 (void)outStream_writeInt(out, sizeof(jfieldID)); /* fields */
578 (void)outStream_writeInt(out, sizeof(jmethodID)); /* methods */
579 (void)outStream_writeInt(out, sizeof(jlong)); /* objects */
580 (void)outStream_writeInt(out, sizeof(jlong)); /* referent types */
581 (void)outStream_writeInt(out, sizeof(FrameID)); /* frames */
582 return JNI_TRUE;
583 }
584
585 static jboolean
suspend(PacketInputStream * in,PacketOutputStream * out)586 suspend(PacketInputStream *in, PacketOutputStream *out)
587 {
588 jvmtiError error;
589
590 if (gdata->vmDead) {
591 outStream_setError(out, JDWP_ERROR(VM_DEAD));
592 return JNI_TRUE;
593 }
594 error = threadControl_suspendAll();
595 if (error != JVMTI_ERROR_NONE) {
596 outStream_setError(out, map2jdwpError(error));
597 }
598 return JNI_TRUE;
599 }
600
601 static jboolean
resume(PacketInputStream * in,PacketOutputStream * out)602 resume(PacketInputStream *in, PacketOutputStream *out)
603 {
604 jvmtiError error;
605
606 if (gdata->vmDead) {
607 outStream_setError(out, JDWP_ERROR(VM_DEAD));
608 return JNI_TRUE;
609 }
610 error = threadControl_resumeAll();
611 if (error != JVMTI_ERROR_NONE) {
612 outStream_setError(out, map2jdwpError(error));
613 }
614 return JNI_TRUE;
615 }
616
617 static jboolean
doExit(PacketInputStream * in,PacketOutputStream * out)618 doExit(PacketInputStream *in, PacketOutputStream *out)
619 {
620 // ANDROID-CHANGED: We are about to exit(). Send ART cmd processing time,
621 // if there are any remaining.
622 timings_flush();
623
624 jint exitCode;
625
626 exitCode = inStream_readInt(in);
627 if (gdata->vmDead) {
628 /* quietly ignore */
629 return JNI_FALSE;
630 }
631
632 /* We send the reply from here because we are about to exit. */
633 if (inStream_error(in)) {
634 outStream_setError(out, inStream_error(in));
635 }
636 outStream_sendReply(out);
637
638 forceExit(exitCode);
639
640 /* Shouldn't get here */
641 JDI_ASSERT(JNI_FALSE);
642
643 /* Shut up the compiler */
644 return JNI_FALSE;
645
646 }
647
648 static jboolean
createString(PacketInputStream * in,PacketOutputStream * out)649 createString(PacketInputStream *in, PacketOutputStream *out)
650 {
651 JNIEnv *env;
652 char *cstring;
653
654 if (gdata->vmDead) {
655 outStream_setError(out, JDWP_ERROR(VM_DEAD));
656 return JNI_TRUE;
657 }
658
659 cstring = inStream_readString(in);
660 if (cstring == NULL) {
661 outStream_setError(out, JDWP_ERROR(OUT_OF_MEMORY));
662 return JNI_TRUE;
663 }
664 if (inStream_error(in)) {
665 return JNI_TRUE;
666 }
667
668 env = getEnv();
669
670 WITH_LOCAL_REFS(env, 1) {
671
672 jstring string;
673
674 string = JNI_FUNC_PTR(env,NewStringUTF)(env, cstring);
675 if (JNI_FUNC_PTR(env,ExceptionOccurred)(env)) {
676 outStream_setError(out, JDWP_ERROR(OUT_OF_MEMORY));
677 } else {
678 (void)outStream_writeObjectRef(env, out, string);
679 }
680
681 } END_WITH_LOCAL_REFS(env);
682
683 jvmtiDeallocate(cstring);
684
685 return JNI_TRUE;
686 }
687
688 static jboolean
capabilities(PacketInputStream * in,PacketOutputStream * out)689 capabilities(PacketInputStream *in, PacketOutputStream *out)
690 {
691 jvmtiCapabilities caps;
692 jvmtiError error;
693
694 if (gdata->vmDead) {
695 outStream_setError(out, JDWP_ERROR(VM_DEAD));
696 return JNI_TRUE;
697 }
698 error = jvmtiGetCapabilities(&caps);
699 if (error != JVMTI_ERROR_NONE) {
700 outStream_setError(out, map2jdwpError(error));
701 return JNI_TRUE;
702 }
703
704 (void)outStream_writeBoolean(out, (jboolean)caps.can_generate_field_modification_events);
705 (void)outStream_writeBoolean(out, (jboolean)caps.can_generate_field_access_events);
706 (void)outStream_writeBoolean(out, (jboolean)caps.can_get_bytecodes);
707 (void)outStream_writeBoolean(out, (jboolean)caps.can_get_synthetic_attribute);
708 (void)outStream_writeBoolean(out, (jboolean)caps.can_get_owned_monitor_info);
709 (void)outStream_writeBoolean(out, (jboolean)caps.can_get_current_contended_monitor);
710 (void)outStream_writeBoolean(out, (jboolean)caps.can_get_monitor_info);
711 return JNI_TRUE;
712 }
713
714 static jboolean
capabilitiesNew(PacketInputStream * in,PacketOutputStream * out)715 capabilitiesNew(PacketInputStream *in, PacketOutputStream *out)
716 {
717 jvmtiCapabilities caps;
718 jvmtiError error;
719
720 if (gdata->vmDead) {
721 outStream_setError(out, JDWP_ERROR(VM_DEAD));
722 return JNI_TRUE;
723 }
724 error = jvmtiGetCapabilities(&caps);
725 if (error != JVMTI_ERROR_NONE) {
726 outStream_setError(out, map2jdwpError(error));
727 return JNI_TRUE;
728 }
729
730 // ANDROID-CHANGED: We want to adjust the capabilities slightly if we are on android.
731 jboolean is_android_runtime = strcmp(gdata->property_java_vm_name, "Dalvik") == 0;
732
733 (void)outStream_writeBoolean(out, (jboolean)caps.can_generate_field_modification_events);
734 (void)outStream_writeBoolean(out, (jboolean)caps.can_generate_field_access_events);
735 (void)outStream_writeBoolean(out, (jboolean)caps.can_get_bytecodes);
736 (void)outStream_writeBoolean(out, (jboolean)caps.can_get_synthetic_attribute);
737 (void)outStream_writeBoolean(out, (jboolean)caps.can_get_owned_monitor_info);
738 (void)outStream_writeBoolean(out, (jboolean)caps.can_get_current_contended_monitor);
739 (void)outStream_writeBoolean(out, (jboolean)caps.can_get_monitor_info);
740
741 /* new since JDWP version 1.4 */
742 /* ANDROID-CHANGED: some jdwp clients will send us class files for redefineClasses which we do
743 * not support. Set this capability to false and set reserved32 instead to indicate that we do
744 * support .dex file class redefinition.
745 */
746 (void)outStream_writeBoolean(out, (jboolean)caps.can_redefine_classes && !is_android_runtime);
747 (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE /* can_add_method */ );
748 (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE /* can_unrestrictedly_redefine_classes */ );
749 /* 11: canPopFrames */
750 (void)outStream_writeBoolean(out, (jboolean)caps.can_pop_frame);
751 /* 12: canUseInstanceFilters */
752 (void)outStream_writeBoolean(out, (jboolean)JNI_TRUE);
753 /* 13: canGetSourceDebugExtension */
754 (void)outStream_writeBoolean(out, (jboolean)caps.can_get_source_debug_extension);
755 /* 14: canRequestVMDeathEvent */
756 (void)outStream_writeBoolean(out, (jboolean)JNI_TRUE);
757 /* 15: canSetDefaultStratum */
758 (void)outStream_writeBoolean(out, (jboolean)JNI_TRUE);
759 /* 16: canGetInstanceInfo */
760 (void)outStream_writeBoolean(out, (jboolean)caps.can_tag_objects);
761 /* 17: canRequestMonitorEvents */
762 (void)outStream_writeBoolean(out, (jboolean)caps.can_generate_monitor_events);
763 /* 18: canGetMonitorFrameInfo */
764 (void)outStream_writeBoolean(out, (jboolean)caps.can_get_owned_monitor_stack_depth_info);
765 /* remaining reserved */
766 (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE); /* 19 */
767 /* 20 Can get constant pool information */
768 (void)outStream_writeBoolean(out, (jboolean)caps.can_get_constant_pool);
769 /* 21 Can force early return */
770 (void)outStream_writeBoolean(out, (jboolean)caps.can_force_early_return);
771 (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE); /* 22 */
772 (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE); /* 23 */
773 (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE); /* 24 */
774 (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE); /* 25 */
775 (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE); /* 26 */
776 (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE); /* 27 */
777 (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE); /* 28 */
778 (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE); /* 29 */
779 (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE); /* 30 */
780 (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE); /* 31 */
781 /* ANDROID-CHANGED: Use the reserved32 capability to notify clients that we can support dex
782 * class redefinition.
783 */
784 (void)outStream_writeBoolean(out, (jboolean)caps.can_redefine_classes && is_android_runtime);
785 return JNI_TRUE;
786 }
787
788 static int
countPaths(char * string)789 countPaths(char *string) {
790 int cnt = 1; /* always have one */
791 char *pos = string;
792 char *ps;
793
794 ps = gdata->property_path_separator;
795 if ( ps == NULL ) {
796 ps = ";";
797 }
798 while ((pos = strchr(pos, ps[0])) != NULL) {
799 ++cnt;
800 ++pos;
801 }
802 return cnt;
803 }
804
805 static void
writePaths(PacketOutputStream * out,char * string)806 writePaths(PacketOutputStream *out, char *string) {
807 char *pos;
808 char *ps;
809 char *buf;
810 int npaths;
811 int i;
812
813 buf = jvmtiAllocate((int)strlen(string)+1);
814
815 npaths = countPaths(string);
816 (void)outStream_writeInt(out, npaths);
817
818 ps = gdata->property_path_separator;
819 if ( ps == NULL ) {
820 ps = ";";
821 }
822
823 pos = string;
824 for ( i = 0 ; i < npaths ; i++ ) {
825 char *psPos;
826 int plen;
827
828 psPos = strchr(pos, ps[0]);
829 if ( psPos == NULL ) {
830 plen = (int)strlen(pos);
831 } else {
832 plen = (int)(psPos-pos);
833 psPos++;
834 }
835 (void)memcpy(buf, pos, plen);
836 buf[plen] = 0;
837 (void)outStream_writeString(out, buf);
838 pos = psPos;
839 }
840
841 jvmtiDeallocate(buf);
842 }
843
844
845
846 static jboolean
classPaths(PacketInputStream * in,PacketOutputStream * out)847 classPaths(PacketInputStream *in, PacketOutputStream *out)
848 {
849 char *ud;
850 char *bp;
851 char *cp;
852
853 ud = gdata->property_user_dir;
854 if ( ud == NULL ) {
855 ud = "";
856 }
857 cp = gdata->property_java_class_path;
858 if ( cp == NULL ) {
859 cp = "";
860 }
861 bp = gdata->property_sun_boot_class_path;
862 if ( bp == NULL ) {
863 bp = "";
864 }
865 (void)outStream_writeString(out, ud);
866 writePaths(out, cp);
867 writePaths(out, bp);
868 return JNI_TRUE;
869 }
870
871 static jboolean
disposeObjects(PacketInputStream * in,PacketOutputStream * out)872 disposeObjects(PacketInputStream *in, PacketOutputStream *out)
873 {
874 int i;
875 int refCount;
876 jlong id;
877 int requestCount;
878 JNIEnv *env;
879
880 if (gdata->vmDead) {
881 /* quietly ignore */
882 return JNI_TRUE;
883 }
884
885 requestCount = inStream_readInt(in);
886 if (inStream_error(in)) {
887 return JNI_TRUE;
888 }
889
890 env = getEnv();
891 for (i = 0; i < requestCount; i++) {
892 id = inStream_readObjectID(in);
893 refCount = inStream_readInt(in);
894 if (inStream_error(in)) {
895 return JNI_TRUE;
896 }
897 commonRef_releaseMultiple(env, id, refCount);
898 }
899
900 return JNI_TRUE;
901 }
902
903 static jboolean
holdEvents(PacketInputStream * in,PacketOutputStream * out)904 holdEvents(PacketInputStream *in, PacketOutputStream *out)
905 {
906 eventHelper_holdEvents();
907 return JNI_TRUE;
908 }
909
910 static jboolean
releaseEvents(PacketInputStream * in,PacketOutputStream * out)911 releaseEvents(PacketInputStream *in, PacketOutputStream *out)
912 {
913 eventHelper_releaseEvents();
914 return JNI_TRUE;
915 }
916
917 void *VirtualMachine_Cmds[] = { (void *)21
918 ,(void *)version
919 ,(void *)classesForSignature
920 ,(void *)allClasses
921 ,(void *)getAllThreads
922 ,(void *)topLevelThreadGroups
923 ,(void *)dispose
924 ,(void *)idSizes
925 ,(void *)suspend
926 ,(void *)resume
927 ,(void *)doExit
928 ,(void *)createString
929 ,(void *)capabilities
930 ,(void *)classPaths
931 ,(void *)disposeObjects
932 ,(void *)holdEvents
933 ,(void *)releaseEvents
934 ,(void *)capabilitiesNew
935 ,(void *)redefineClasses
936 ,(void *)setDefaultStratum
937 ,(void *)allClassesWithGeneric
938 ,(void *)instanceCounts
939 };
940