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 };