1/* 2 * Copyright (c) 1998, 2016, 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 37static char *versionName = "Java Debug Wire Protocol (Reference Implementation)"; 38static int majorVersion = 9; /* JDWP major version */ 39static int minorVersion = 0; /* JDWP minor version */ 40 41static jboolean 42version(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 93static jboolean 94classesForSignature(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 198static jboolean 199allModules(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 233static jboolean 234allClasses1(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 322static jboolean 323allClasses(PacketInputStream *in, PacketOutputStream *out) 324{ 325 return allClasses1(in, out, 0); 326} 327 328static jboolean 329allClassesWithGeneric(PacketInputStream *in, PacketOutputStream *out) 330{ 331 return allClasses1(in, out, 1); 332} 333 334 /***********************************************************/ 335 336 337static jboolean 338instanceCounts(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 407static jboolean 408redefineClasses(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 501static jboolean 502setDefaultStratum(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 522static jboolean 523getAllThreads(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 560static jboolean 561topLevelThreadGroups(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 599static jboolean 600dispose(PacketInputStream *in, PacketOutputStream *out) 601{ 602 return JNI_TRUE; 603} 604 605static jboolean 606idSizes(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 616static jboolean 617suspend(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 632static jboolean 633resume(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 648static jboolean 649doExit(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 675static jboolean 676createString(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 715static jboolean 716capabilities(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 741static jboolean 742capabilitiesNew(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 806static int 807countPaths(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 823static void 824writePaths(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 ; 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 863 864static jboolean 865classPaths(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 884static jboolean 885disposeObjects(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 916static jboolean 917holdEvents(PacketInputStream *in, PacketOutputStream *out) 918{ 919 eventHelper_holdEvents(); 920 return JNI_TRUE; 921} 922 923static jboolean 924releaseEvents(PacketInputStream *in, PacketOutputStream *out) 925{ 926 eventHelper_releaseEvents(); 927 return JNI_TRUE; 928} 929 930void *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}; 954