jdk/src/share/back/VirtualMachineImpl.c
changeset 2 90ce3da70b43
child 5506 202f599c92aa
equal deleted inserted replaced
0:fd16c54261b3 2:90ce3da70b43
       
     1 /*
       
     2  * Copyright 1998-2006 Sun Microsystems, Inc.  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.  Sun designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    23  * have any 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 = 6;  /* 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 *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
       
   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
       
   880 holdEvents(PacketInputStream *in, PacketOutputStream *out)
       
   881 {
       
   882     eventHelper_holdEvents();
       
   883     return JNI_TRUE;
       
   884 }
       
   885 
       
   886 static jboolean
       
   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 };