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