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