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