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