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