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