Home | History | Annotate | Download | only in back
      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     // ANDROID-CHANGED: We want to adjust the capabilities slightly if we are on android.
    717     jboolean is_android_runtime = strcmp(gdata->property_java_vm_name, "Dalvik") == 0;
    718 
    719     (void)outStream_writeBoolean(out, (jboolean)caps.can_generate_field_modification_events);
    720     (void)outStream_writeBoolean(out, (jboolean)caps.can_generate_field_access_events);
    721     (void)outStream_writeBoolean(out, (jboolean)caps.can_get_bytecodes);
    722     (void)outStream_writeBoolean(out, (jboolean)caps.can_get_synthetic_attribute);
    723     (void)outStream_writeBoolean(out, (jboolean)caps.can_get_owned_monitor_info);
    724     (void)outStream_writeBoolean(out, (jboolean)caps.can_get_current_contended_monitor);
    725     (void)outStream_writeBoolean(out, (jboolean)caps.can_get_monitor_info);
    726 
    727     /* new since JDWP version 1.4 */
    728     /* ANDROID-CHANGED: some jdwp clients will send us class files for redefineClasses which we do
    729      * not support. Set this capability to false and set reserved32 instead to indicate that we do
    730      * support .dex file class redefinition.
    731      */
    732     (void)outStream_writeBoolean(out, (jboolean)caps.can_redefine_classes && !is_android_runtime);
    733     (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE /* can_add_method */ );
    734     (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE /* can_unrestrictedly_redefine_classes */ );
    735     /* 11: canPopFrames */
    736     (void)outStream_writeBoolean(out, (jboolean)caps.can_pop_frame);
    737     /* 12: canUseInstanceFilters */
    738     (void)outStream_writeBoolean(out, (jboolean)JNI_TRUE);
    739     /* 13: canGetSourceDebugExtension */
    740     (void)outStream_writeBoolean(out, (jboolean)caps.can_get_source_debug_extension);
    741     /* 14: canRequestVMDeathEvent */
    742     (void)outStream_writeBoolean(out, (jboolean)JNI_TRUE);
    743     /* 15: canSetDefaultStratum */
    744     (void)outStream_writeBoolean(out, (jboolean)JNI_TRUE);
    745     /* 16: canGetInstanceInfo */
    746     (void)outStream_writeBoolean(out, (jboolean)caps.can_tag_objects);
    747     /* 17: canRequestMonitorEvents */
    748     (void)outStream_writeBoolean(out, (jboolean)caps.can_generate_monitor_events);
    749     /* 18: canGetMonitorFrameInfo */
    750     (void)outStream_writeBoolean(out, (jboolean)caps.can_get_owned_monitor_stack_depth_info);
    751     /* remaining reserved */
    752     (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE); /* 19 */
    753     /* 20 Can get constant pool information */
    754     (void)outStream_writeBoolean(out, (jboolean)caps.can_get_constant_pool);
    755     /* 21 Can force early return */
    756     (void)outStream_writeBoolean(out, (jboolean)caps.can_force_early_return);
    757     (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE); /* 22 */
    758     (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE); /* 23 */
    759     (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE); /* 24 */
    760     (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE); /* 25 */
    761     (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE); /* 26 */
    762     (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE); /* 27 */
    763     (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE); /* 28 */
    764     (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE); /* 29 */
    765     (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE); /* 30 */
    766     (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE); /* 31 */
    767     /* ANDROID-CHANGED: Use the reserved32 capability to notify clients that we can support dex
    768      * class redefinition.
    769      */
    770     (void)outStream_writeBoolean(out, (jboolean)caps.can_redefine_classes && is_android_runtime);
    771     return JNI_TRUE;
    772 }
    773 
    774 static int
    775 countPaths(char *string) {
    776     int cnt = 1; /* always have one */
    777     char *pos = string;
    778     char *ps;
    779 
    780     ps = gdata->property_path_separator;
    781     if ( ps == NULL ) {
    782         ps = ";";
    783     }
    784     while ((pos = strchr(pos, ps[0])) != NULL) {
    785         ++cnt;
    786         ++pos;
    787     }
    788     return cnt;
    789 }
    790 
    791 static void
    792 writePaths(PacketOutputStream *out, char *string) {
    793     char *pos;
    794     char *ps;
    795     char *buf;
    796     int   npaths;
    797     int   i;
    798 
    799     buf = jvmtiAllocate((int)strlen(string)+1);
    800 
    801     npaths = countPaths(string);
    802     (void)outStream_writeInt(out, npaths);
    803 
    804     ps = gdata->property_path_separator;
    805     if ( ps == NULL ) {
    806         ps = ";";
    807     }
    808 
    809     pos = string;
    810     for ( i = 0 ; i < npaths ; i++ ) {
    811         char *psPos;
    812         int   plen;
    813 
    814         psPos = strchr(pos, ps[0]);
    815         if ( psPos == NULL ) {
    816             plen = (int)strlen(pos);
    817         } else {
    818             plen = (int)(psPos-pos);
    819             psPos++;
    820         }
    821         (void)memcpy(buf, pos, plen);
    822         buf[plen] = 0;
    823         (void)outStream_writeString(out, buf);
    824         pos = psPos;
    825     }
    826 
    827     jvmtiDeallocate(buf);
    828 }
    829 
    830 
    831 
    832 static jboolean
    833 classPaths(PacketInputStream *in, PacketOutputStream *out)
    834 {
    835     char *ud;
    836     char *bp;
    837     char *cp;
    838 
    839     ud = gdata->property_user_dir;
    840     if ( ud == NULL ) {
    841         ud = "";
    842     }
    843     cp = gdata->property_java_class_path;
    844     if ( cp == NULL ) {
    845         cp = "";
    846     }
    847     bp = gdata->property_sun_boot_class_path;
    848     if ( bp == NULL ) {
    849         bp = "";
    850     }
    851     (void)outStream_writeString(out, ud);
    852     writePaths(out, cp);
    853     writePaths(out, bp);
    854     return JNI_TRUE;
    855 }
    856 
    857 static jboolean
    858 disposeObjects(PacketInputStream *in, PacketOutputStream *out)
    859 {
    860     int i;
    861     int refCount;
    862     jlong id;
    863     int requestCount;
    864     JNIEnv *env;
    865 
    866     if (gdata->vmDead) {
    867         /* quietly ignore */
    868         return JNI_TRUE;
    869     }
    870 
    871     requestCount = inStream_readInt(in);
    872     if (inStream_error(in)) {
    873         return JNI_TRUE;
    874     }
    875 
    876     env = getEnv();
    877     for (i = 0; i < requestCount; i++) {
    878         id = inStream_readObjectID(in);
    879         refCount = inStream_readInt(in);
    880         if (inStream_error(in)) {
    881             return JNI_TRUE;
    882         }
    883         commonRef_releaseMultiple(env, id, refCount);
    884     }
    885 
    886     return JNI_TRUE;
    887 }
    888 
    889 static jboolean
    890 holdEvents(PacketInputStream *in, PacketOutputStream *out)
    891 {
    892     eventHelper_holdEvents();
    893     return JNI_TRUE;
    894 }
    895 
    896 static jboolean
    897 releaseEvents(PacketInputStream *in, PacketOutputStream *out)
    898 {
    899     eventHelper_releaseEvents();
    900     return JNI_TRUE;
    901 }
    902 
    903 void *VirtualMachine_Cmds[] = { (void *)21
    904     ,(void *)version
    905     ,(void *)classesForSignature
    906     ,(void *)allClasses
    907     ,(void *)getAllThreads
    908     ,(void *)topLevelThreadGroups
    909     ,(void *)dispose
    910     ,(void *)idSizes
    911     ,(void *)suspend
    912     ,(void *)resume
    913     ,(void *)doExit
    914     ,(void *)createString
    915     ,(void *)capabilities
    916     ,(void *)classPaths
    917     ,(void *)disposeObjects
    918     ,(void *)holdEvents
    919     ,(void *)releaseEvents
    920     ,(void *)capabilitiesNew
    921     ,(void *)redefineClasses
    922     ,(void *)setDefaultStratum
    923     ,(void *)allClassesWithGeneric
    924     ,(void *)instanceCounts
    925 };
    926