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
  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
  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
 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
 282 allClasses(PacketInputStream *in, PacketOutputStream *out)
 283 {
 284     return allClasses1(in, out, 0);
 285 }
 286 
 287 static jboolean
 288 allClassesWithGeneric(PacketInputStream *in, PacketOutputStream *out)
 289 {
 290     return allClasses1(in, out, 1);
 291 }
 292 
 293   /***********************************************************/
 294 
 295 
 296 static jboolean
 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
 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
 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
 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
 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
 559 dispose(PacketInputStream *in, PacketOutputStream *out)
 560 {
 561     return JNI_TRUE;
 562 }
 563 
 564 static jboolean
 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
 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
 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
 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
 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
 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
 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
 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
 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
 823 classPaths(PacketInputStream *in, PacketOutputStream *out)
 824 {
 825     char *ud;
 826     char *cp;
 827 
 828     ud = gdata->property_user_dir;
 829     if ( ud == NULL ) {
 830         ud = "";
 831     }
 832     cp = gdata->property_java_class_path;
 833     if ( cp == NULL ) {
 834         cp = "";
 835     }
 836     (void)outStream_writeString(out, ud);
 837     writePaths(out, cp);
 838     (void)outStream_writeInt(out, 0); // no bootclasspath
 839     return JNI_TRUE;
 840 }
 841 
 842 static jboolean
 843 disposeObjects(PacketInputStream *in, PacketOutputStream *out)
 844 {
 845     int i;
 846     int refCount;
 847     jlong id;
 848     int requestCount;
 849     JNIEnv *env;
 850 
 851     if (gdata->vmDead) {
 852         /* quietly ignore */
 853         return JNI_TRUE;
 854     }
 855 
 856     requestCount = inStream_readInt(in);
 857     if (inStream_error(in)) {
 858         return JNI_TRUE;
 859     }
 860 
 861     env = getEnv();
 862     for (i = 0; i < requestCount; i++) {
 863         id = inStream_readObjectID(in);
 864         refCount = inStream_readInt(in);
 865         if (inStream_error(in)) {
 866             return JNI_TRUE;
 867         }
 868         commonRef_releaseMultiple(env, id, refCount);
 869     }
 870 
 871     return JNI_TRUE;
 872 }
 873 
 874 static jboolean
 875 holdEvents(PacketInputStream *in, PacketOutputStream *out)
 876 {
 877     eventHelper_holdEvents();
 878     return JNI_TRUE;
 879 }
 880 
 881 static jboolean
 882 releaseEvents(PacketInputStream *in, PacketOutputStream *out)
 883 {
 884     eventHelper_releaseEvents();
 885     return JNI_TRUE;
 886 }
 887 
 888 void *VirtualMachine_Cmds[] = { (void *)21
 889     ,(void *)version
 890     ,(void *)classesForSignature
 891     ,(void *)allClasses
 892     ,(void *)getAllThreads
 893     ,(void *)topLevelThreadGroups
 894     ,(void *)dispose
 895     ,(void *)idSizes
 896     ,(void *)suspend
 897     ,(void *)resume
 898     ,(void *)doExit
 899     ,(void *)createString
 900     ,(void *)capabilities
 901     ,(void *)classPaths
 902     ,(void *)disposeObjects
 903     ,(void *)holdEvents
 904     ,(void *)releaseEvents
 905     ,(void *)capabilitiesNew
 906     ,(void *)redefineClasses
 907     ,(void *)setDefaultStratum
 908     ,(void *)allClassesWithGeneric
 909     ,(void *)instanceCounts
 910 };