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