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