1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 /* 18 * Handle messages from debugger. 19 * 20 * GENERAL NOTE: we're not currently testing the message length for 21 * correctness. This is usually a bad idea, but here we can probably 22 * get away with it so long as the debugger isn't broken. We can 23 * change the "read" macros to use "dataLen" to avoid wandering into 24 * bad territory, and have a single "is dataLen correct" check at the 25 * end of each function. Not needed at this time. 26 */ 27 #include "jdwp/JdwpPriv.h" 28 #include "jdwp/JdwpHandler.h" 29 #include "jdwp/JdwpEvent.h" 30 #include "jdwp/JdwpConstants.h" 31 #include "jdwp/ExpandBuf.h" 32 33 #include "Bits.h" 34 #include "Atomic.h" 35 #include "DalvikVersion.h" 36 37 #include <stdlib.h> 38 #include <string.h> 39 #include <unistd.h> 40 41 #if 0 42 #include <time.h> 43 #include <sys/time.h> 44 static void showTime(const char* label) 45 { 46 struct timeval tv; 47 int min, sec, msec; 48 49 gettimeofday(&tv, NULL); 50 min = (tv.tv_sec / 60) % 60; 51 sec = tv.tv_sec % 60; 52 msec = tv.tv_usec / 1000; 53 54 LOGI("%02d:%02d.%03d %s\n", min, sec, msec, label); 55 } 56 #endif 57 58 /* 59 * Helper function: read a "location" from an input buffer. 60 */ 61 static void jdwpReadLocation(const u1** pBuf, JdwpLocation* pLoc) 62 { 63 memset(pLoc, 0, sizeof(*pLoc)); /* allows memcmp() later */ 64 pLoc->typeTag = read1(pBuf); 65 pLoc->classId = dvmReadObjectId(pBuf); 66 pLoc->methodId = dvmReadMethodId(pBuf); 67 pLoc->idx = read8BE(pBuf); 68 } 69 70 /* 71 * Helper function: write a "location" into the reply buffer. 72 */ 73 void dvmJdwpAddLocation(ExpandBuf* pReply, const JdwpLocation* pLoc) 74 { 75 expandBufAdd1(pReply, pLoc->typeTag); 76 expandBufAddObjectId(pReply, pLoc->classId); 77 expandBufAddMethodId(pReply, pLoc->methodId); 78 expandBufAdd8BE(pReply, pLoc->idx); 79 } 80 81 /* 82 * Helper function: read a variable-width value from the input buffer. 83 */ 84 static u8 jdwpReadValue(const u1** pBuf, int width) 85 { 86 u8 value; 87 88 switch (width) { 89 case 1: value = read1(pBuf); break; 90 case 2: value = read2BE(pBuf); break; 91 case 4: value = read4BE(pBuf); break; 92 case 8: value = read8BE(pBuf); break; 93 default: value = (u8) -1; assert(false); break; 94 } 95 96 return value; 97 } 98 99 /* 100 * Helper function: write a variable-width value into the output input buffer. 101 */ 102 static void jdwpWriteValue(ExpandBuf* pReply, int width, u8 value) 103 { 104 switch (width) { 105 case 1: expandBufAdd1(pReply, value); break; 106 case 2: expandBufAdd2BE(pReply, value); break; 107 case 4: expandBufAdd4BE(pReply, value); break; 108 case 8: expandBufAdd8BE(pReply, value); break; 109 default: assert(false); break; 110 } 111 } 112 113 /* 114 * Common code for *_InvokeMethod requests. 115 * 116 * If "isConstructor" is set, this returns "objectId" rather than the 117 * expected-to-be-void return value of the called function. 118 */ 119 static JdwpError finishInvoke(JdwpState* state, 120 const u1* buf, int dataLen, ExpandBuf* pReply, 121 ObjectId threadId, ObjectId objectId, RefTypeId classId, MethodId methodId, 122 bool isConstructor) 123 { 124 JdwpError err = ERR_NONE; 125 u8* argArray = NULL; 126 u4 numArgs; 127 u4 options; /* enum InvokeOptions bit flags */ 128 int i; 129 130 assert(!isConstructor || objectId != 0); 131 132 numArgs = read4BE(&buf); 133 134 LOGV(" --> threadId=%llx objectId=%llx\n", threadId, objectId); 135 LOGV(" classId=%llx methodId=%x %s.%s\n", 136 classId, methodId, 137 dvmDbgGetClassDescriptor(classId), 138 dvmDbgGetMethodName(classId, methodId)); 139 LOGV(" %d args:\n", numArgs); 140 141 if (numArgs > 0) 142 argArray = (ObjectId*) malloc(sizeof(ObjectId) * numArgs); 143 144 for (i = 0; i < (int) numArgs; i++) { 145 u1 typeTag; 146 u8 value; 147 int width; 148 149 typeTag = read1(&buf); 150 width = dvmDbgGetTagWidth(typeTag); 151 value = jdwpReadValue(&buf, width); 152 153 LOGV(" '%c'(%d): 0x%llx\n", typeTag, width, value); 154 argArray[i] = value; 155 } 156 157 options = read4BE(&buf); 158 LOGV(" options=0x%04x%s%s\n", options, 159 (options & INVOKE_SINGLE_THREADED) ? " (SINGLE_THREADED)" : "", 160 (options & INVOKE_NONVIRTUAL) ? " (NONVIRTUAL)" : ""); 161 162 163 u1 resultTag; 164 u8 resultValue; 165 ObjectId exceptObjId; 166 167 err = dvmDbgInvokeMethod(threadId, objectId, classId, methodId, 168 numArgs, argArray, options, 169 &resultTag, &resultValue, &exceptObjId); 170 if (err != ERR_NONE) 171 goto bail; 172 173 if (err == ERR_NONE) { 174 if (isConstructor) { 175 expandBufAdd1(pReply, JT_OBJECT); 176 expandBufAddObjectId(pReply, objectId); 177 } else { 178 int width = dvmDbgGetTagWidth(resultTag); 179 180 expandBufAdd1(pReply, resultTag); 181 if (width != 0) 182 jdwpWriteValue(pReply, width, resultValue); 183 } 184 expandBufAdd1(pReply, JT_OBJECT); 185 expandBufAddObjectId(pReply, exceptObjId); 186 187 LOGV(" --> returned '%c' 0x%llx (except=%08llx)\n", 188 resultTag, resultValue, exceptObjId); 189 190 /* show detailed debug output */ 191 if (resultTag == JT_STRING && exceptObjId == 0) { 192 if (resultValue != 0) { 193 char* str = dvmDbgStringToUtf8(resultValue); 194 LOGV(" string '%s'\n", str); 195 free(str); 196 } else { 197 LOGV(" string (null)\n"); 198 } 199 } 200 } 201 202 bail: 203 free(argArray); 204 return err; 205 } 206 207 208 /* 209 * Request for version info. 210 */ 211 static JdwpError handleVM_Version(JdwpState* state, const u1* buf, 212 int dataLen, ExpandBuf* pReply) 213 { 214 char tmpBuf[128]; 215 216 /* text information on VM version */ 217 sprintf(tmpBuf, "Android DalvikVM %d.%d.%d", 218 DALVIK_MAJOR_VERSION, DALVIK_MINOR_VERSION, DALVIK_BUG_VERSION); 219 expandBufAddUtf8String(pReply, (const u1*) tmpBuf); 220 /* JDWP version numbers */ 221 expandBufAdd4BE(pReply, 1); // major 222 expandBufAdd4BE(pReply, 5); // minor 223 /* VM JRE version */ 224 expandBufAddUtf8String(pReply, (const u1*) "1.5.0"); /* e.g. 1.5.0_04 */ 225 /* target VM name */ 226 expandBufAddUtf8String(pReply, (const u1*) "DalvikVM"); 227 228 return ERR_NONE; 229 } 230 231 /* 232 * Given a class JNI signature (e.g. "Ljava/lang/Error;"), return the 233 * referenceTypeID. We need to send back more than one if the class has 234 * been loaded by multiple class loaders. 235 */ 236 static JdwpError handleVM_ClassesBySignature(JdwpState* state, 237 const u1* buf, int dataLen, ExpandBuf* pReply) 238 { 239 char* classDescriptor = NULL; 240 u4 numClasses; 241 size_t strLen; 242 RefTypeId refTypeId; 243 int i; 244 245 classDescriptor = readNewUtf8String(&buf, &strLen); 246 LOGV(" Req for class by signature '%s'\n", classDescriptor); 247 248 /* 249 * TODO: if a class with the same name has been loaded multiple times 250 * (by different class loaders), we're supposed to return each of them. 251 * 252 * NOTE: this may mangle "className". 253 */ 254 if (!dvmDbgFindLoadedClassBySignature(classDescriptor, &refTypeId)) { 255 /* not currently loaded */ 256 LOGV(" --> no match!\n"); 257 numClasses = 0; 258 } else { 259 /* just the one */ 260 numClasses = 1; 261 } 262 263 expandBufAdd4BE(pReply, numClasses); 264 265 if (numClasses > 0) { 266 u1 typeTag; 267 u4 status; 268 269 /* get class vs. interface and status flags */ 270 dvmDbgGetClassInfo(refTypeId, &typeTag, &status, NULL); 271 272 expandBufAdd1(pReply, typeTag); 273 expandBufAddRefTypeId(pReply, refTypeId); 274 expandBufAdd4BE(pReply, status); 275 } 276 277 free(classDescriptor); 278 279 return ERR_NONE; 280 } 281 282 /* 283 * Handle request for the thread IDs of all running threads. 284 * 285 * We exclude ourselves from the list, because we don't allow ourselves 286 * to be suspended, and that violates some JDWP expectations. 287 */ 288 static JdwpError handleVM_AllThreads(JdwpState* state, 289 const u1* buf, int dataLen, ExpandBuf* pReply) 290 { 291 u4 threadCount; 292 ObjectId* pThreadIds; 293 ObjectId* walker; 294 int i; 295 296 dvmDbgGetAllThreads(&pThreadIds, &threadCount); 297 298 expandBufAdd4BE(pReply, threadCount); 299 300 walker = pThreadIds; 301 for (i = 0; i < (int) threadCount; i++) { 302 expandBufAddObjectId(pReply, *walker++); 303 } 304 305 free(pThreadIds); 306 307 return ERR_NONE; 308 } 309 310 /* 311 * List all thread groups that do not have a parent. 312 */ 313 static JdwpError handleVM_TopLevelThreadGroups(JdwpState* state, 314 const u1* buf, int dataLen, ExpandBuf* pReply) 315 { 316 u4 groups; 317 ObjectId threadGroupId; 318 319 /* 320 * TODO: maintain a list of parentless thread groups in the VM. 321 * 322 * For now, just return "system". Application threads are created 323 * in "main", which is a child of "system". 324 */ 325 groups = 1; 326 expandBufAdd4BE(pReply, groups); 327 //threadGroupId = debugGetMainThreadGroup(); 328 //expandBufAdd8BE(pReply, threadGroupId); 329 threadGroupId = dvmDbgGetSystemThreadGroupId(); 330 expandBufAddObjectId(pReply, threadGroupId); 331 332 return ERR_NONE; 333 } 334 335 /* 336 * Respond with the sizes of the basic debugger types. 337 * 338 * All IDs are 8 bytes. 339 */ 340 static JdwpError handleVM_IDSizes(JdwpState* state, 341 const u1* buf, int dataLen, ExpandBuf* pReply) 342 { 343 expandBufAdd4BE(pReply, sizeof(FieldId)); 344 expandBufAdd4BE(pReply, sizeof(MethodId)); 345 expandBufAdd4BE(pReply, sizeof(ObjectId)); 346 expandBufAdd4BE(pReply, sizeof(RefTypeId)); 347 expandBufAdd4BE(pReply, sizeof(FrameId)); 348 return ERR_NONE; 349 } 350 351 /* 352 * The debugger is politely asking to disconnect. We're good with that. 353 * 354 * We could resume threads and clean up pinned references, but we can do 355 * that when the TCP connection drops. 356 */ 357 static JdwpError handleVM_Dispose(JdwpState* state, 358 const u1* buf, int dataLen, ExpandBuf* pReply) 359 { 360 return ERR_NONE; 361 } 362 363 /* 364 * Suspend the execution of the application running in the VM (i.e. suspend 365 * all threads). 366 * 367 * This needs to increment the "suspend count" on all threads. 368 */ 369 static JdwpError handleVM_Suspend(JdwpState* state, 370 const u1* buf, int dataLen, ExpandBuf* pReply) 371 { 372 dvmDbgSuspendVM(false); 373 return ERR_NONE; 374 } 375 376 /* 377 * Resume execution. Decrements the "suspend count" of all threads. 378 */ 379 static JdwpError handleVM_Resume(JdwpState* state, 380 const u1* buf, int dataLen, ExpandBuf* pReply) 381 { 382 dvmDbgResumeVM(); 383 return ERR_NONE; 384 } 385 386 /* 387 * The debugger wants the entire VM to exit. 388 */ 389 static JdwpError handleVM_Exit(JdwpState* state, 390 const u1* buf, int dataLen, ExpandBuf* pReply) 391 { 392 u4 exitCode; 393 394 exitCode = get4BE(buf); 395 396 LOGW("Debugger is telling the VM to exit with code=%d\n", exitCode); 397 398 dvmDbgExit(exitCode); 399 return ERR_NOT_IMPLEMENTED; // shouldn't get here 400 } 401 402 /* 403 * Create a new string in the VM and return its ID. 404 * 405 * (Ctrl-Shift-I in Eclipse on an array of objects causes it to create the 406 * string "java.util.Arrays".) 407 */ 408 static JdwpError handleVM_CreateString(JdwpState* state, 409 const u1* buf, int dataLen, ExpandBuf* pReply) 410 { 411 char* str; 412 size_t strLen; 413 ObjectId stringId; 414 415 str = readNewUtf8String(&buf, &strLen); 416 417 LOGV(" Req to create string '%s'\n", str); 418 419 stringId = dvmDbgCreateString(str); 420 if (stringId == 0) 421 return ERR_OUT_OF_MEMORY; 422 423 expandBufAddObjectId(pReply, stringId); 424 return ERR_NONE; 425 } 426 427 /* 428 * Tell the debugger what we are capable of. 429 */ 430 static JdwpError handleVM_Capabilities(JdwpState* state, 431 const u1* buf, int dataLen, ExpandBuf* pReply) 432 { 433 int i; 434 435 expandBufAdd1(pReply, false); /* canWatchFieldModification */ 436 expandBufAdd1(pReply, false); /* canWatchFieldAccess */ 437 expandBufAdd1(pReply, false); /* canGetBytecodes */ 438 expandBufAdd1(pReply, false); /* canGetSyntheticAttribute */ 439 expandBufAdd1(pReply, false); /* canGetOwnedMonitorInfo */ 440 expandBufAdd1(pReply, false); /* canGetCurrentContendedMonitor */ 441 expandBufAdd1(pReply, false); /* canGetMonitorInfo */ 442 return ERR_NONE; 443 } 444 445 /* 446 * Return classpath and bootclasspath. 447 */ 448 static JdwpError handleVM_ClassPaths(JdwpState* state, 449 const u1* buf, int dataLen, ExpandBuf* pReply) 450 { 451 char baseDir[2] = "/"; 452 u4 classPaths; 453 u4 bootClassPaths; 454 int i; 455 456 /* 457 * TODO: make this real. Not important for remote debugging, but 458 * might be useful for local debugging. 459 */ 460 classPaths = 1; 461 bootClassPaths = 0; 462 463 expandBufAddUtf8String(pReply, (const u1*) baseDir); 464 expandBufAdd4BE(pReply, classPaths); 465 for (i = 0; i < (int) classPaths; i++) { 466 expandBufAddUtf8String(pReply, (const u1*) "."); 467 } 468 469 expandBufAdd4BE(pReply, bootClassPaths); 470 for (i = 0; i < (int) classPaths; i++) { 471 /* add bootclasspath components as strings */ 472 } 473 474 return ERR_NONE; 475 } 476 477 /* 478 * Release a list of object IDs. (Seen in jdb.) 479 * 480 * Currently does nothing. 481 */ 482 static JdwpError HandleVM_DisposeObjects(JdwpState* state, 483 const u1* buf, int dataLen, ExpandBuf* pReply) 484 { 485 return ERR_NONE; 486 } 487 488 /* 489 * Tell the debugger what we are capable of. 490 */ 491 static JdwpError handleVM_CapabilitiesNew(JdwpState* state, 492 const u1* buf, int dataLen, ExpandBuf* pReply) 493 { 494 int i; 495 496 expandBufAdd1(pReply, false); /* canWatchFieldModification */ 497 expandBufAdd1(pReply, false); /* canWatchFieldAccess */ 498 expandBufAdd1(pReply, false); /* canGetBytecodes */ 499 expandBufAdd1(pReply, false); /* canGetSyntheticAttribute */ 500 expandBufAdd1(pReply, false); /* canGetOwnedMonitorInfo */ 501 expandBufAdd1(pReply, false); /* canGetCurrentContendedMonitor */ 502 expandBufAdd1(pReply, false); /* canGetMonitorInfo */ 503 expandBufAdd1(pReply, false); /* canRedefineClasses */ 504 expandBufAdd1(pReply, false); /* canAddMethod */ 505 expandBufAdd1(pReply, false); /* canUnrestrictedlyRedefineClasses */ 506 expandBufAdd1(pReply, false); /* canPopFrames */ 507 expandBufAdd1(pReply, false); /* canUseInstanceFilters */ 508 expandBufAdd1(pReply, false); /* canGetSourceDebugExtension */ 509 expandBufAdd1(pReply, false); /* canRequestVMDeathEvent */ 510 expandBufAdd1(pReply, false); /* canSetDefaultStratum */ 511 expandBufAdd1(pReply, false); /* 1.6: canGetInstanceInfo */ 512 expandBufAdd1(pReply, false); /* 1.6: canRequestMonitorEvents */ 513 expandBufAdd1(pReply, false); /* 1.6: canGetMonitorFrameInfo */ 514 expandBufAdd1(pReply, false); /* 1.6: canUseSourceNameFilters */ 515 expandBufAdd1(pReply, false); /* 1.6: canGetConstantPool */ 516 expandBufAdd1(pReply, false); /* 1.6: canForceEarlyReturn */ 517 518 /* fill in reserved22 through reserved32; note count started at 1 */ 519 for (i = 22; i <= 32; i++) 520 expandBufAdd1(pReply, false); /* reservedN */ 521 return ERR_NONE; 522 } 523 524 /* 525 * Cough up the complete list of classes. 526 */ 527 static JdwpError handleVM_AllClassesWithGeneric(JdwpState* state, 528 const u1* buf, int dataLen, ExpandBuf* pReply) 529 { 530 u4 numClasses = 0; 531 RefTypeId* classRefBuf = NULL; 532 int i; 533 534 dvmDbgGetClassList(&numClasses, &classRefBuf); 535 536 expandBufAdd4BE(pReply, numClasses); 537 538 for (i = 0; i < (int) numClasses; i++) { 539 static const u1 genericSignature[1] = ""; 540 u1 refTypeTag; 541 char* signature; 542 u4 status; 543 544 dvmDbgGetClassInfo(classRefBuf[i], &refTypeTag, &status, &signature); 545 546 expandBufAdd1(pReply, refTypeTag); 547 expandBufAddRefTypeId(pReply, classRefBuf[i]); 548 expandBufAddUtf8String(pReply, (const u1*) signature); 549 expandBufAddUtf8String(pReply, genericSignature); 550 expandBufAdd4BE(pReply, status); 551 552 free(signature); 553 } 554 555 free(classRefBuf); 556 557 return ERR_NONE; 558 } 559 560 /* 561 * Given a referenceTypeID, return a string with the JNI reference type 562 * signature (e.g. "Ljava/lang/Error;"). 563 */ 564 static JdwpError handleRT_Signature(JdwpState* state, 565 const u1* buf, int dataLen, ExpandBuf* pReply) 566 { 567 char* signature; 568 RefTypeId refTypeId; 569 570 refTypeId = dvmReadRefTypeId(&buf); 571 572 LOGV(" Req for signature of refTypeId=0x%llx\n", refTypeId); 573 signature = dvmDbgGetSignature(refTypeId); 574 expandBufAddUtf8String(pReply, (const u1*) signature); 575 free(signature); 576 577 return ERR_NONE; 578 } 579 580 /* 581 * Return the modifiers (a/k/a access flags) for a reference type. 582 */ 583 static JdwpError handleRT_Modifiers(JdwpState* state, 584 const u1* buf, int dataLen, ExpandBuf* pReply) 585 { 586 RefTypeId refTypeId; 587 u4 modBits; 588 589 refTypeId = dvmReadRefTypeId(&buf); 590 modBits = dvmDbgGetAccessFlags(refTypeId); 591 592 expandBufAdd4BE(pReply, modBits); 593 594 return ERR_NONE; 595 } 596 597 /* 598 * Get values from static fields in a reference type. 599 */ 600 static JdwpError handleRT_GetValues(JdwpState* state, 601 const u1* buf, int dataLen, ExpandBuf* pReply) 602 { 603 RefTypeId refTypeId; 604 u4 numFields; 605 int i; 606 607 refTypeId = dvmReadRefTypeId(&buf); 608 numFields = read4BE(&buf); 609 610 expandBufAdd4BE(pReply, numFields); 611 for (i = 0; i < (int) numFields; i++) { 612 FieldId fieldId; 613 u1 fieldTag; 614 int width; 615 u1* ptr; 616 617 fieldId = dvmReadFieldId(&buf); 618 fieldTag = dvmDbgGetFieldTag(refTypeId, fieldId); 619 width = dvmDbgGetTagWidth(fieldTag); 620 621 expandBufAdd1(pReply, fieldTag); 622 ptr = expandBufAddSpace(pReply, width); 623 dvmDbgGetStaticFieldValue(refTypeId, fieldId, ptr, width); 624 } 625 626 return ERR_NONE; 627 } 628 629 /* 630 * Get the name of the source file in which a reference type was declared. 631 */ 632 static JdwpError handleRT_SourceFile(JdwpState* state, 633 const u1* buf, int dataLen, ExpandBuf* pReply) 634 { 635 RefTypeId refTypeId; 636 const char* fileName; 637 638 refTypeId = dvmReadRefTypeId(&buf); 639 640 fileName = dvmDbgGetSourceFile(refTypeId); 641 if (fileName != NULL) { 642 expandBufAddUtf8String(pReply, (const u1*) fileName); 643 return ERR_NONE; 644 } else { 645 return ERR_ABSENT_INFORMATION; 646 } 647 } 648 649 /* 650 * Return the current status of the reference type. 651 */ 652 static JdwpError handleRT_Status(JdwpState* state, 653 const u1* buf, int dataLen, ExpandBuf* pReply) 654 { 655 RefTypeId refTypeId; 656 u1 typeTag; 657 u4 status; 658 659 refTypeId = dvmReadRefTypeId(&buf); 660 661 /* get status flags */ 662 dvmDbgGetClassInfo(refTypeId, &typeTag, &status, NULL); 663 expandBufAdd4BE(pReply, status); 664 return ERR_NONE; 665 } 666 667 /* 668 * Return interfaces implemented directly by this class. 669 */ 670 static JdwpError handleRT_Interfaces(JdwpState* state, 671 const u1* buf, int dataLen, ExpandBuf* pReply) 672 { 673 RefTypeId refTypeId; 674 675 refTypeId = dvmReadRefTypeId(&buf); 676 677 LOGV(" Req for interfaces in %llx (%s)\n", refTypeId, 678 dvmDbgGetClassDescriptor(refTypeId)); 679 680 dvmDbgOutputAllInterfaces(refTypeId, pReply); 681 682 return ERR_NONE; 683 } 684 685 /* 686 * Return the class object corresponding to this type. 687 */ 688 static JdwpError handleRT_ClassObject(JdwpState* state, 689 const u1* buf, int dataLen, ExpandBuf* pReply) 690 { 691 RefTypeId refTypeId; 692 ObjectId classObjId; 693 694 refTypeId = dvmReadRefTypeId(&buf); 695 classObjId = dvmDbgGetClassObject(refTypeId); 696 697 LOGV(" RefTypeId %llx -> ObjectId %llx\n", refTypeId, classObjId); 698 699 expandBufAddObjectId(pReply, classObjId); 700 701 return ERR_NONE; 702 } 703 704 /* 705 * Returns the value of the SourceDebugExtension attribute. 706 * 707 * JDB seems interested, but DEX files don't currently support this. 708 */ 709 static JdwpError handleRT_SourceDebugExtension(JdwpState* state, 710 const u1* buf, int dataLen, ExpandBuf* pReply) 711 { 712 /* referenceTypeId in, string out */ 713 return ERR_ABSENT_INFORMATION; 714 } 715 716 /* 717 * Like RT_Signature but with the possibility of a "generic signature". 718 */ 719 static JdwpError handleRT_SignatureWithGeneric(JdwpState* state, 720 const u1* buf, int dataLen, ExpandBuf* pReply) 721 { 722 static const u1 genericSignature[1] = ""; 723 char* signature; 724 RefTypeId refTypeId; 725 726 refTypeId = dvmReadRefTypeId(&buf); 727 728 LOGV(" Req for signature of refTypeId=0x%llx\n", refTypeId); 729 signature = dvmDbgGetSignature(refTypeId); 730 if (signature != NULL) 731 expandBufAddUtf8String(pReply, (const u1*) signature); 732 else 733 expandBufAddUtf8String(pReply, (const u1*) "Lunknown;"); /* native? */ 734 expandBufAddUtf8String(pReply, genericSignature); 735 free(signature); 736 737 return ERR_NONE; 738 } 739 740 /* 741 * Return the instance of java.lang.ClassLoader that loaded the specified 742 * reference type, or null if it was loaded by the system loader. 743 */ 744 static JdwpError handleRT_ClassLoader(JdwpState* state, 745 const u1* buf, int dataLen, ExpandBuf* pReply) 746 { 747 RefTypeId refTypeId; 748 ObjectId classLoaderId; 749 750 refTypeId = dvmReadRefTypeId(&buf); 751 752 expandBufAddObjectId(pReply, dvmDbgGetClassLoader(refTypeId)); 753 754 return ERR_NONE; 755 } 756 757 /* 758 * Given a referenceTypeId, return a block of stuff that describes the 759 * fields declared by a class. 760 */ 761 static JdwpError handleRT_FieldsWithGeneric(JdwpState* state, 762 const u1* buf, int dataLen, ExpandBuf* pReply) 763 { 764 RefTypeId refTypeId; 765 int i, numFields; 766 767 refTypeId = dvmReadRefTypeId(&buf); 768 LOGV(" Req for fields in refTypeId=0x%llx\n", refTypeId); 769 { 770 char* tmp = dvmDbgGetSignature(refTypeId); 771 LOGV(" --> '%s'\n", tmp); 772 free(tmp); 773 } 774 775 dvmDbgOutputAllFields(refTypeId, true, pReply); 776 777 return ERR_NONE; 778 } 779 780 /* 781 * Given a referenceTypeID, return a block of goodies describing the 782 * methods declared by a class. 783 */ 784 static JdwpError handleRT_MethodsWithGeneric(JdwpState* state, 785 const u1* buf, int dataLen, ExpandBuf* pReply) 786 { 787 RefTypeId refTypeId; 788 int i; 789 790 refTypeId = dvmReadRefTypeId(&buf); 791 792 LOGV(" Req for methods in refTypeId=0x%llx\n", refTypeId); 793 { 794 char* tmp = dvmDbgGetSignature(refTypeId); 795 LOGV(" --> '%s'\n", tmp); 796 free(tmp); 797 } 798 799 dvmDbgOutputAllMethods(refTypeId, true, pReply); 800 801 return ERR_NONE; 802 } 803 804 /* 805 * Return the immediate superclass of a class. 806 */ 807 static JdwpError handleCT_Superclass(JdwpState* state, 808 const u1* buf, int dataLen, ExpandBuf* pReply) 809 { 810 RefTypeId classId; 811 RefTypeId superClassId; 812 813 classId = dvmReadRefTypeId(&buf); 814 815 superClassId = dvmDbgGetSuperclass(classId); 816 817 expandBufAddRefTypeId(pReply, superClassId); 818 819 return ERR_NONE; 820 } 821 822 /* 823 * Set static class values. 824 */ 825 static JdwpError handleCT_SetValues(JdwpState* state, 826 const u1* buf, int dataLen, ExpandBuf* pReply) 827 { 828 RefTypeId classId; 829 u4 values; 830 int i; 831 832 classId = dvmReadRefTypeId(&buf); 833 values = read4BE(&buf); 834 835 LOGV(" Req to set %d values in classId=%llx\n", values, classId); 836 837 for (i = 0; i < (int) values; i++) { 838 FieldId fieldId; 839 u1 fieldTag; 840 u8 value; 841 int width; 842 843 fieldId = dvmReadFieldId(&buf); 844 fieldTag = dvmDbgGetStaticFieldTag(classId, fieldId); 845 width = dvmDbgGetTagWidth(fieldTag); 846 value = jdwpReadValue(&buf, width); 847 848 LOGV(" --> field=%x tag=%c -> %lld\n", fieldId, fieldTag, value); 849 dvmDbgSetStaticFieldValue(classId, fieldId, value, width); 850 } 851 852 return ERR_NONE; 853 } 854 855 /* 856 * Invoke a static method. 857 * 858 * Example: Eclipse sometimes uses java/lang/Class.forName(String s) on 859 * values in the "variables" display. 860 */ 861 static JdwpError handleCT_InvokeMethod(JdwpState* state, 862 const u1* buf, int dataLen, ExpandBuf* pReply) 863 { 864 RefTypeId classId; 865 ObjectId threadId; 866 MethodId methodId; 867 868 classId = dvmReadRefTypeId(&buf); 869 threadId = dvmReadObjectId(&buf); 870 methodId = dvmReadMethodId(&buf); 871 872 return finishInvoke(state, buf, dataLen, pReply, 873 threadId, 0, classId, methodId, false); 874 } 875 876 /* 877 * Create a new object of the requested type, and invoke the specified 878 * constructor. 879 * 880 * Example: in IntelliJ, create a watch on "new String(myByteArray)" to 881 * see the contents of a byte[] as a string. 882 */ 883 static JdwpError handleCT_NewInstance(JdwpState* state, 884 const u1* buf, int dataLen, ExpandBuf* pReply) 885 { 886 RefTypeId classId; 887 ObjectId threadId; 888 MethodId methodId; 889 ObjectId objectId; 890 u4 numArgs; 891 892 classId = dvmReadRefTypeId(&buf); 893 threadId = dvmReadObjectId(&buf); 894 methodId = dvmReadMethodId(&buf); 895 896 LOGV("Creating instance of %s\n", dvmDbgGetClassDescriptor(classId)); 897 objectId = dvmDbgCreateObject(classId); 898 if (objectId == 0) 899 return ERR_OUT_OF_MEMORY; 900 901 return finishInvoke(state, buf, dataLen, pReply, 902 threadId, objectId, classId, methodId, true); 903 } 904 905 /* 906 * Return line number information for the method, if present. 907 */ 908 static JdwpError handleM_LineTable(JdwpState* state, 909 const u1* buf, int dataLen, ExpandBuf* pReply) 910 { 911 RefTypeId refTypeId; 912 MethodId methodId; 913 914 refTypeId = dvmReadRefTypeId(&buf); 915 methodId = dvmReadMethodId(&buf); 916 917 LOGV(" Req for line table in %s.%s\n", 918 dvmDbgGetClassDescriptor(refTypeId), 919 dvmDbgGetMethodName(refTypeId,methodId)); 920 921 dvmDbgOutputLineTable(refTypeId, methodId, pReply); 922 923 return ERR_NONE; 924 } 925 926 /* 927 * Pull out the LocalVariableTable goodies. 928 */ 929 static JdwpError handleM_VariableTableWithGeneric(JdwpState* state, 930 const u1* buf, int dataLen, ExpandBuf* pReply) 931 { 932 RefTypeId classId; 933 MethodId methodId; 934 935 classId = dvmReadRefTypeId(&buf); 936 methodId = dvmReadMethodId(&buf); 937 938 LOGV(" Req for LocalVarTab in class=%s method=%s\n", 939 dvmDbgGetClassDescriptor(classId), 940 dvmDbgGetMethodName(classId, methodId)); 941 942 /* 943 * We could return ERR_ABSENT_INFORMATION here if the DEX file was 944 * built without local variable information. That will cause Eclipse 945 * to make a best-effort attempt at displaying local variables 946 * anonymously. However, the attempt isn't very good, so we're probably 947 * better off just not showing anything. 948 */ 949 dvmDbgOutputVariableTable(classId, methodId, true, pReply); 950 return ERR_NONE; 951 } 952 953 /* 954 * Given an object reference, return the runtime type of the object 955 * (class or array). 956 * 957 * This can get called on different things, e.g. threadId gets 958 * passed in here. 959 */ 960 static JdwpError handleOR_ReferenceType(JdwpState* state, 961 const u1* buf, int dataLen, ExpandBuf* pReply) 962 { 963 ObjectId objectId; 964 u1 refTypeTag; 965 RefTypeId typeId; 966 967 objectId = dvmReadObjectId(&buf); 968 LOGV(" Req for type of objectId=0x%llx\n", objectId); 969 970 dvmDbgGetObjectType(objectId, &refTypeTag, &typeId); 971 972 expandBufAdd1(pReply, refTypeTag); 973 expandBufAddRefTypeId(pReply, typeId); 974 975 return ERR_NONE; 976 } 977 978 /* 979 * Get values from the fields of an object. 980 */ 981 static JdwpError handleOR_GetValues(JdwpState* state, 982 const u1* buf, int dataLen, ExpandBuf* pReply) 983 { 984 ObjectId objectId; 985 u4 numFields; 986 int i; 987 988 objectId = dvmReadObjectId(&buf); 989 numFields = read4BE(&buf); 990 991 LOGV(" Req for %d fields from objectId=0x%llx\n", numFields, objectId); 992 993 expandBufAdd4BE(pReply, numFields); 994 995 for (i = 0; i < (int) numFields; i++) { 996 FieldId fieldId; 997 u1 fieldTag; 998 int width; 999 u1* ptr; 1000 const char* fieldName; 1001 1002 fieldId = dvmReadFieldId(&buf); 1003 1004 fieldTag = dvmDbgGetFieldTag(objectId, fieldId); 1005 width = dvmDbgGetTagWidth(fieldTag); 1006 1007 LOGV(" --> fieldId %x --> tag '%c'(%d)\n", 1008 fieldId, fieldTag, width); 1009 1010 expandBufAdd1(pReply, fieldTag); 1011 ptr = expandBufAddSpace(pReply, width); 1012 dvmDbgGetFieldValue(objectId, fieldId, ptr, width); 1013 } 1014 1015 return ERR_NONE; 1016 } 1017 1018 /* 1019 * Set values in the fields of an object. 1020 */ 1021 static JdwpError handleOR_SetValues(JdwpState* state, 1022 const u1* buf, int dataLen, ExpandBuf* pReply) 1023 { 1024 ObjectId objectId; 1025 u4 numFields; 1026 int i; 1027 1028 objectId = dvmReadObjectId(&buf); 1029 numFields = read4BE(&buf); 1030 1031 LOGV(" Req to set %d fields in objectId=0x%llx\n", numFields, objectId); 1032 1033 for (i = 0; i < (int) numFields; i++) { 1034 FieldId fieldId; 1035 u1 fieldTag; 1036 int width; 1037 u8 value; 1038 1039 fieldId = dvmReadFieldId(&buf); 1040 1041 fieldTag = dvmDbgGetFieldTag(objectId, fieldId); 1042 width = dvmDbgGetTagWidth(fieldTag); 1043 value = jdwpReadValue(&buf, width); 1044 1045 LOGV(" --> fieldId=%x tag='%c'(%d) value=%lld\n", 1046 fieldId, fieldTag, width, value); 1047 1048 dvmDbgSetFieldValue(objectId, fieldId, value, width); 1049 } 1050 1051 return ERR_NONE; 1052 } 1053 1054 /* 1055 * Invoke an instance method. The invocation must occur in the specified 1056 * thread, which must have been suspended by an event. 1057 * 1058 * The call is synchronous. All threads in the VM are resumed, unless the 1059 * SINGLE_THREADED flag is set. 1060 * 1061 * If you ask Eclipse to "inspect" an object (or ask JDB to "print" an 1062 * object), it will try to invoke the object's toString() function. This 1063 * feature becomes crucial when examining ArrayLists with Eclipse. 1064 */ 1065 static JdwpError handleOR_InvokeMethod(JdwpState* state, 1066 const u1* buf, int dataLen, ExpandBuf* pReply) 1067 { 1068 ObjectId objectId; 1069 ObjectId threadId; 1070 RefTypeId classId; 1071 MethodId methodId; 1072 1073 objectId = dvmReadObjectId(&buf); 1074 threadId = dvmReadObjectId(&buf); 1075 classId = dvmReadRefTypeId(&buf); 1076 methodId = dvmReadMethodId(&buf); 1077 1078 return finishInvoke(state, buf, dataLen, pReply, 1079 threadId, objectId, classId, methodId, false); 1080 } 1081 1082 /* 1083 * Disable garbage collection of the specified object. 1084 */ 1085 static JdwpError handleOR_DisableCollection(JdwpState* state, 1086 const u1* buf, int dataLen, ExpandBuf* pReply) 1087 { 1088 // this is currently a no-op 1089 return ERR_NONE; 1090 } 1091 1092 /* 1093 * Enable garbage collection of the specified object. 1094 */ 1095 static JdwpError handleOR_EnableCollection(JdwpState* state, 1096 const u1* buf, int dataLen, ExpandBuf* pReply) 1097 { 1098 // this is currently a no-op 1099 return ERR_NONE; 1100 } 1101 1102 /* 1103 * Determine whether an object has been garbage collected. 1104 */ 1105 static JdwpError handleOR_IsCollected(JdwpState* state, 1106 const u1* buf, int dataLen, ExpandBuf* pReply) 1107 { 1108 ObjectId objectId; 1109 1110 objectId = dvmReadObjectId(&buf); 1111 1112 LOGV(" Req IsCollected(0x%llx)\n", objectId); 1113 1114 // TODO: currently returning false; must integrate with GC 1115 expandBufAdd1(pReply, 0); 1116 1117 return ERR_NONE; 1118 } 1119 1120 /* 1121 * Return the string value in a string object. 1122 */ 1123 static JdwpError handleSR_Value(JdwpState* state, 1124 const u1* buf, int dataLen, ExpandBuf* pReply) 1125 { 1126 ObjectId stringObject; 1127 char* str; 1128 1129 stringObject = dvmReadObjectId(&buf); 1130 str = dvmDbgStringToUtf8(stringObject); 1131 1132 LOGV(" Req for str %llx --> '%s'\n", stringObject, str); 1133 1134 expandBufAddUtf8String(pReply, (u1*) str); 1135 free(str); 1136 1137 return ERR_NONE; 1138 } 1139 1140 /* 1141 * Return a thread's name. 1142 */ 1143 static JdwpError handleTR_Name(JdwpState* state, 1144 const u1* buf, int dataLen, ExpandBuf* pReply) 1145 { 1146 ObjectId threadId; 1147 char* name; 1148 1149 threadId = dvmReadObjectId(&buf); 1150 1151 LOGV(" Req for name of thread 0x%llx\n", threadId); 1152 name = dvmDbgGetThreadName(threadId); 1153 if (name == NULL) 1154 return ERR_INVALID_THREAD; 1155 1156 expandBufAddUtf8String(pReply, (u1*) name); 1157 free(name); 1158 1159 return ERR_NONE; 1160 } 1161 1162 /* 1163 * Suspend the specified thread. 1164 * 1165 * It's supposed to remain suspended even if interpreted code wants to 1166 * resume it; only the JDI is allowed to resume it. 1167 */ 1168 static JdwpError handleTR_Suspend(JdwpState* state, 1169 const u1* buf, int dataLen, ExpandBuf* pReply) 1170 { 1171 ObjectId threadId; 1172 1173 threadId = dvmReadObjectId(&buf); 1174 1175 if (threadId == dvmDbgGetThreadSelfId()) { 1176 LOGI(" Warning: ignoring request to suspend self\n"); 1177 return ERR_THREAD_NOT_SUSPENDED; 1178 } 1179 LOGV(" Req to suspend thread 0x%llx\n", threadId); 1180 1181 dvmDbgSuspendThread(threadId); 1182 1183 return ERR_NONE; 1184 } 1185 1186 /* 1187 * Resume the specified thread. 1188 */ 1189 static JdwpError handleTR_Resume(JdwpState* state, 1190 const u1* buf, int dataLen, ExpandBuf* pReply) 1191 { 1192 ObjectId threadId; 1193 1194 threadId = dvmReadObjectId(&buf); 1195 1196 if (threadId == dvmDbgGetThreadSelfId()) { 1197 LOGI(" Warning: ignoring request to resume self\n"); 1198 return ERR_NONE; 1199 } 1200 LOGV(" Req to resume thread 0x%llx\n", threadId); 1201 1202 dvmDbgResumeThread(threadId); 1203 1204 return ERR_NONE; 1205 } 1206 1207 /* 1208 * Return status of specified thread. 1209 */ 1210 static JdwpError handleTR_Status(JdwpState* state, 1211 const u1* buf, int dataLen, ExpandBuf* pReply) 1212 { 1213 ObjectId threadId; 1214 u4 threadStatus; 1215 u4 suspendStatus; 1216 1217 threadId = dvmReadObjectId(&buf); 1218 1219 LOGV(" Req for status of thread 0x%llx\n", threadId); 1220 1221 if (!dvmDbgGetThreadStatus(threadId, &threadStatus, &suspendStatus)) 1222 return ERR_INVALID_THREAD; 1223 1224 LOGV(" --> %s, %s\n", dvmJdwpThreadStatusStr(threadStatus), 1225 dvmJdwpSuspendStatusStr(suspendStatus)); 1226 1227 expandBufAdd4BE(pReply, threadStatus); 1228 expandBufAdd4BE(pReply, suspendStatus); 1229 1230 return ERR_NONE; 1231 } 1232 1233 /* 1234 * Return the thread group that the specified thread is a member of. 1235 */ 1236 static JdwpError handleTR_ThreadGroup(JdwpState* state, 1237 const u1* buf, int dataLen, ExpandBuf* pReply) 1238 { 1239 ObjectId threadId; 1240 ObjectId threadGroupId; 1241 1242 threadId = dvmReadObjectId(&buf); 1243 1244 /* currently not handling these */ 1245 threadGroupId = dvmDbgGetThreadGroup(threadId); 1246 expandBufAddObjectId(pReply, threadGroupId); 1247 1248 return ERR_NONE; 1249 } 1250 1251 /* 1252 * Return the current call stack of a suspended thread. 1253 * 1254 * If the thread isn't suspended, the error code isn't defined, but should 1255 * be THREAD_NOT_SUSPENDED. 1256 */ 1257 static JdwpError handleTR_Frames(JdwpState* state, 1258 const u1* buf, int dataLen, ExpandBuf* pReply) 1259 { 1260 ObjectId threadId; 1261 u4 startFrame, length, frames; 1262 int i, frameCount; 1263 1264 threadId = dvmReadObjectId(&buf); 1265 startFrame = read4BE(&buf); 1266 length = read4BE(&buf); 1267 1268 if (!dvmDbgThreadExists(threadId)) 1269 return ERR_INVALID_THREAD; 1270 if (!dvmDbgIsSuspended(threadId)) { 1271 LOGV(" Rejecting req for frames in running thread '%s' (%llx)\n", 1272 dvmDbgGetThreadName(threadId), threadId); 1273 return ERR_THREAD_NOT_SUSPENDED; 1274 } 1275 1276 frameCount = dvmDbgGetThreadFrameCount(threadId); 1277 1278 LOGV(" Request for frames: threadId=%llx start=%d length=%d [count=%d]\n", 1279 threadId, startFrame, length, frameCount); 1280 if (frameCount <= 0) 1281 return ERR_THREAD_NOT_SUSPENDED; /* == 0 means 100% native */ 1282 1283 if (length == (u4) -1) 1284 length = frameCount; 1285 assert((int) startFrame >= 0 && (int) startFrame < frameCount); 1286 assert((int) (startFrame + length) <= frameCount); 1287 1288 frames = length; 1289 expandBufAdd4BE(pReply, frames); 1290 for (i = startFrame; i < (int) (startFrame+length); i++) { 1291 FrameId frameId; 1292 JdwpLocation loc; 1293 1294 dvmDbgGetThreadFrame(threadId, i, &frameId, &loc); 1295 1296 expandBufAdd8BE(pReply, frameId); 1297 dvmJdwpAddLocation(pReply, &loc); 1298 1299 LOGVV(" Frame %d: id=%llx loc={type=%d cls=%llx mth=%x loc=%llx}\n", 1300 i, frameId, loc.typeTag, loc.classId, loc.methodId, loc.idx); 1301 } 1302 1303 return ERR_NONE; 1304 } 1305 1306 /* 1307 * Returns the #of frames on the specified thread, which must be suspended. 1308 */ 1309 static JdwpError handleTR_FrameCount(JdwpState* state, 1310 const u1* buf, int dataLen, ExpandBuf* pReply) 1311 { 1312 ObjectId threadId; 1313 int frameCount; 1314 1315 threadId = dvmReadObjectId(&buf); 1316 1317 if (!dvmDbgThreadExists(threadId)) 1318 return ERR_INVALID_THREAD; 1319 if (!dvmDbgIsSuspended(threadId)) { 1320 LOGV(" Rejecting req for frames in running thread '%s' (%llx)\n", 1321 dvmDbgGetThreadName(threadId), threadId); 1322 return ERR_THREAD_NOT_SUSPENDED; 1323 } 1324 1325 frameCount = dvmDbgGetThreadFrameCount(threadId); 1326 if (frameCount < 0) 1327 return ERR_INVALID_THREAD; 1328 expandBufAdd4BE(pReply, (u4)frameCount); 1329 1330 return ERR_NONE; 1331 } 1332 1333 /* 1334 * Get the monitor that the thread is waiting on. 1335 */ 1336 static JdwpError handleTR_CurrentContendedMonitor(JdwpState* state, 1337 const u1* buf, int dataLen, ExpandBuf* pReply) 1338 { 1339 ObjectId threadId; 1340 1341 threadId = dvmReadObjectId(&buf); 1342 1343 // TODO: create an Object to represent the monitor (we're currently 1344 // just using a raw Monitor struct in the VM) 1345 1346 return ERR_NOT_IMPLEMENTED; 1347 } 1348 1349 /* 1350 * Return the suspend count for the specified thread. 1351 * 1352 * (The thread *might* still be running -- it might not have examined 1353 * its suspend count recently.) 1354 */ 1355 static JdwpError handleTR_SuspendCount(JdwpState* state, 1356 const u1* buf, int dataLen, ExpandBuf* pReply) 1357 { 1358 ObjectId threadId; 1359 u4 suspendCount; 1360 1361 threadId = dvmReadObjectId(&buf); 1362 1363 suspendCount = dvmDbgGetThreadSuspendCount(threadId); 1364 expandBufAdd4BE(pReply, suspendCount); 1365 1366 return ERR_NONE; 1367 } 1368 1369 /* 1370 * Return the name of a thread group. 1371 * 1372 * The Eclipse debugger recognizes "main" and "system" as special. 1373 */ 1374 static JdwpError handleTGR_Name(JdwpState* state, 1375 const u1* buf, int dataLen, ExpandBuf* pReply) 1376 { 1377 ObjectId threadGroupId; 1378 char* name = NULL; 1379 1380 threadGroupId = dvmReadObjectId(&buf); 1381 LOGV(" Req for name of threadGroupId=0x%llx\n", threadGroupId); 1382 1383 name = dvmDbgGetThreadGroupName(threadGroupId); 1384 if (name != NULL) 1385 expandBufAddUtf8String(pReply, (u1*) name); 1386 else { 1387 expandBufAddUtf8String(pReply, (u1*) "BAD-GROUP-ID"); 1388 LOGW("bad thread group ID\n"); 1389 } 1390 1391 free(name); 1392 1393 return ERR_NONE; 1394 } 1395 1396 /* 1397 * Returns the thread group -- if any -- that contains the specified 1398 * thread group. 1399 */ 1400 static JdwpError handleTGR_Parent(JdwpState* state, 1401 const u1* buf, int dataLen, ExpandBuf* pReply) 1402 { 1403 ObjectId groupId; 1404 ObjectId parentGroup; 1405 1406 groupId = dvmReadObjectId(&buf); 1407 1408 parentGroup = dvmDbgGetThreadGroupParent(groupId); 1409 expandBufAddObjectId(pReply, parentGroup); 1410 1411 return ERR_NONE; 1412 } 1413 1414 /* 1415 * Return the active threads and thread groups that are part of the 1416 * specified thread group. 1417 */ 1418 static JdwpError handleTGR_Children(JdwpState* state, 1419 const u1* buf, int dataLen, ExpandBuf* pReply) 1420 { 1421 ObjectId threadGroupId; 1422 u4 threadCount; 1423 ObjectId threadId; 1424 ObjectId* pThreadIds; 1425 ObjectId* walker; 1426 int i; 1427 1428 threadGroupId = dvmReadObjectId(&buf); 1429 LOGV(" Req for threads in threadGroupId=0x%llx\n", threadGroupId); 1430 1431 dvmDbgGetThreadGroupThreads(threadGroupId, &pThreadIds, &threadCount); 1432 1433 expandBufAdd4BE(pReply, threadCount); 1434 1435 walker = pThreadIds; 1436 for (i = 0; i < (int) threadCount; i++) 1437 expandBufAddObjectId(pReply, pThreadIds[i]); 1438 free(pThreadIds); 1439 1440 /* 1441 * TODO: finish support for child groups 1442 * 1443 * For now, just show that "main" is a child of "system". 1444 */ 1445 if (threadGroupId == dvmDbgGetSystemThreadGroupId()) { 1446 expandBufAdd4BE(pReply, 1); 1447 expandBufAddObjectId(pReply, dvmDbgGetMainThreadGroupId()); 1448 } else { 1449 expandBufAdd4BE(pReply, 0); 1450 } 1451 1452 return ERR_NONE; 1453 } 1454 1455 /* 1456 * Return the #of components in the array. 1457 */ 1458 static JdwpError handleAR_Length(JdwpState* state, 1459 const u1* buf, int dataLen, ExpandBuf* pReply) 1460 { 1461 ObjectId arrayId; 1462 u4 arrayLength; 1463 1464 arrayId = dvmReadObjectId(&buf); 1465 LOGV(" Req for length of array 0x%llx\n", arrayId); 1466 1467 arrayLength = dvmDbgGetArrayLength(arrayId); 1468 1469 LOGV(" --> %d\n", arrayLength); 1470 1471 expandBufAdd4BE(pReply, arrayLength); 1472 1473 return ERR_NONE; 1474 } 1475 1476 /* 1477 * Return the values from an array. 1478 */ 1479 static JdwpError handleAR_GetValues(JdwpState* state, 1480 const u1* buf, int dataLen, ExpandBuf* pReply) 1481 { 1482 ObjectId arrayId; 1483 u4 firstIndex; 1484 u4 length; 1485 u1 tag; 1486 1487 arrayId = dvmReadObjectId(&buf); 1488 firstIndex = read4BE(&buf); 1489 length = read4BE(&buf); 1490 1491 tag = dvmDbgGetArrayElementTag(arrayId); 1492 LOGV(" Req for array values 0x%llx first=%d len=%d (elem tag=%c)\n", 1493 arrayId, firstIndex, length, tag); 1494 1495 expandBufAdd1(pReply, tag); 1496 expandBufAdd4BE(pReply, length); 1497 1498 if (!dvmDbgOutputArray(arrayId, firstIndex, length, pReply)) 1499 return ERR_INVALID_LENGTH; 1500 1501 return ERR_NONE; 1502 } 1503 1504 /* 1505 * Set values in an array. 1506 */ 1507 static JdwpError handleAR_SetValues(JdwpState* state, 1508 const u1* buf, int dataLen, ExpandBuf* pReply) 1509 { 1510 ObjectId arrayId; 1511 u4 firstIndex; 1512 u4 values; 1513 u1 tag; 1514 int i; 1515 1516 arrayId = dvmReadObjectId(&buf); 1517 firstIndex = read4BE(&buf); 1518 values = read4BE(&buf); 1519 1520 LOGV(" Req to set array values 0x%llx first=%d count=%d\n", 1521 arrayId, firstIndex, values); 1522 1523 if (!dvmDbgSetArrayElements(arrayId, firstIndex, values, buf)) 1524 return ERR_INVALID_LENGTH; 1525 1526 return ERR_NONE; 1527 } 1528 1529 /* 1530 * Return the set of classes visible to a class loader. All classes which 1531 * have the class loader as a defining or initiating loader are returned. 1532 */ 1533 static JdwpError handleCLR_VisibleClasses(JdwpState* state, 1534 const u1* buf, int dataLen, ExpandBuf* pReply) 1535 { 1536 ObjectId classLoaderObject; 1537 u4 numClasses = 0; 1538 RefTypeId* classRefBuf = NULL; 1539 int i; 1540 1541 classLoaderObject = dvmReadObjectId(&buf); 1542 1543 dvmDbgGetVisibleClassList(classLoaderObject, &numClasses, &classRefBuf); 1544 1545 expandBufAdd4BE(pReply, numClasses); 1546 for (i = 0; i < (int) numClasses; i++) { 1547 u1 refTypeTag; 1548 1549 refTypeTag = dvmDbgGetClassObjectType(classRefBuf[i]); 1550 1551 expandBufAdd1(pReply, refTypeTag); 1552 expandBufAddRefTypeId(pReply, classRefBuf[i]); 1553 } 1554 1555 return ERR_NONE; 1556 } 1557 1558 /* 1559 * Set an event trigger. 1560 * 1561 * Reply with a requestID. 1562 */ 1563 static JdwpError handleER_Set(JdwpState* state, 1564 const u1* buf, int dataLen, ExpandBuf* pReply) 1565 { 1566 JdwpEvent* pEvent; 1567 JdwpError err; 1568 const u1* origBuf = buf; 1569 /*int origDataLen = dataLen;*/ 1570 u1 eventKind; 1571 u1 suspendPolicy; 1572 u4 modifierCount; 1573 u4 requestId; 1574 int idx; 1575 1576 eventKind = read1(&buf); 1577 suspendPolicy = read1(&buf); 1578 modifierCount = read4BE(&buf); 1579 1580 LOGVV(" Set(kind=%s(%u) suspend=%s(%u) mods=%u)\n", 1581 dvmJdwpEventKindStr(eventKind), eventKind, 1582 dvmJdwpSuspendPolicyStr(suspendPolicy), suspendPolicy, 1583 modifierCount); 1584 1585 assert(modifierCount < 256); /* reasonableness check */ 1586 1587 pEvent = dvmJdwpEventAlloc(modifierCount); 1588 pEvent->eventKind = eventKind; 1589 pEvent->suspendPolicy = suspendPolicy; 1590 pEvent->modCount = modifierCount; 1591 1592 /* 1593 * Read modifiers. Ordering may be significant (see explanation of Count 1594 * mods in JDWP doc). 1595 */ 1596 for (idx = 0; idx < (int) modifierCount; idx++) { 1597 u1 modKind; 1598 1599 modKind = read1(&buf); 1600 1601 pEvent->mods[idx].modKind = modKind; 1602 1603 switch (modKind) { 1604 case MK_COUNT: /* report once, when "--count" reaches 0 */ 1605 { 1606 u4 count = read4BE(&buf); 1607 LOGVV(" Count: %u\n", count); 1608 if (count == 0) 1609 return ERR_INVALID_COUNT; 1610 pEvent->mods[idx].count.count = count; 1611 } 1612 break; 1613 case MK_CONDITIONAL: /* conditional on expression) */ 1614 { 1615 u4 exprId = read4BE(&buf); 1616 LOGVV(" Conditional: %d\n", exprId); 1617 pEvent->mods[idx].conditional.exprId = exprId; 1618 } 1619 break; 1620 case MK_THREAD_ONLY: /* only report events in specified thread */ 1621 { 1622 ObjectId threadId = dvmReadObjectId(&buf); 1623 LOGVV(" ThreadOnly: %llx\n", threadId); 1624 pEvent->mods[idx].threadOnly.threadId = threadId; 1625 } 1626 break; 1627 case MK_CLASS_ONLY: /* for ClassPrepare, MethodEntry */ 1628 { 1629 RefTypeId clazzId = dvmReadRefTypeId(&buf); 1630 LOGVV(" ClassOnly: %llx (%s)\n", 1631 clazzId, dvmDbgGetClassDescriptor(clazzId)); 1632 pEvent->mods[idx].classOnly.referenceTypeId = clazzId; 1633 } 1634 break; 1635 case MK_CLASS_MATCH: /* restrict events to matching classes */ 1636 { 1637 char* pattern; 1638 size_t strLen; 1639 1640 pattern = readNewUtf8String(&buf, &strLen); 1641 LOGVV(" ClassMatch: '%s'\n", pattern); 1642 /* pattern is "java.foo.*", we want "java/foo/ *" */ 1643 pEvent->mods[idx].classMatch.classPattern = 1644 dvmDotToSlash(pattern); 1645 free(pattern); 1646 } 1647 break; 1648 case MK_CLASS_EXCLUDE: /* restrict events to non-matching classes */ 1649 { 1650 char* pattern; 1651 size_t strLen; 1652 1653 pattern = readNewUtf8String(&buf, &strLen); 1654 LOGVV(" ClassExclude: '%s'\n", pattern); 1655 pEvent->mods[idx].classExclude.classPattern = 1656 dvmDotToSlash(pattern); 1657 free(pattern); 1658 } 1659 break; 1660 case MK_LOCATION_ONLY: /* restrict certain events based on loc */ 1661 { 1662 JdwpLocation loc; 1663 1664 jdwpReadLocation(&buf, &loc); 1665 LOGVV(" LocationOnly: typeTag=%d classId=%llx methodId=%x idx=%llx\n", 1666 loc.typeTag, loc.classId, loc.methodId, loc.idx); 1667 pEvent->mods[idx].locationOnly.loc = loc; 1668 } 1669 break; 1670 case MK_EXCEPTION_ONLY: /* modifies EK_EXCEPTION events */ 1671 { 1672 RefTypeId exceptionOrNull; /* null == all exceptions */ 1673 u1 caught, uncaught; 1674 1675 exceptionOrNull = dvmReadRefTypeId(&buf); 1676 caught = read1(&buf); 1677 uncaught = read1(&buf); 1678 LOGVV(" ExceptionOnly: type=%llx(%s) caught=%d uncaught=%d\n", 1679 exceptionOrNull, (exceptionOrNull == 0) ? "null" 1680 : dvmDbgGetClassDescriptor(exceptionOrNull), 1681 caught, uncaught); 1682 1683 pEvent->mods[idx].exceptionOnly.refTypeId = exceptionOrNull; 1684 pEvent->mods[idx].exceptionOnly.caught = caught; 1685 pEvent->mods[idx].exceptionOnly.uncaught = uncaught; 1686 } 1687 break; 1688 case MK_FIELD_ONLY: /* for field access/mod events */ 1689 { 1690 RefTypeId declaring = dvmReadRefTypeId(&buf); 1691 FieldId fieldId = dvmReadFieldId(&buf); 1692 LOGVV(" FieldOnly: %llx %x\n", declaring, fieldId); 1693 pEvent->mods[idx].fieldOnly.refTypeId = declaring; 1694 pEvent->mods[idx].fieldOnly.fieldId = fieldId;; 1695 } 1696 break; 1697 case MK_STEP: /* for use with EK_SINGLE_STEP */ 1698 { 1699 ObjectId threadId; 1700 u4 size, depth; 1701 1702 threadId = dvmReadObjectId(&buf); 1703 size = read4BE(&buf); 1704 depth = read4BE(&buf); 1705 LOGVV(" Step: thread=%llx size=%s depth=%s\n", 1706 threadId, dvmJdwpStepSizeStr(size), 1707 dvmJdwpStepDepthStr(depth)); 1708 1709 pEvent->mods[idx].step.threadId = threadId; 1710 pEvent->mods[idx].step.size = size; 1711 pEvent->mods[idx].step.depth = depth; 1712 } 1713 break; 1714 case MK_INSTANCE_ONLY: /* report events related to a specific obj */ 1715 { 1716 ObjectId instance = dvmReadObjectId(&buf); 1717 LOGVV(" InstanceOnly: %llx\n", instance); 1718 pEvent->mods[idx].instanceOnly.objectId = instance; 1719 } 1720 break; 1721 default: 1722 LOGW("GLITCH: unsupported modKind=%d\n", modKind); 1723 break; 1724 } 1725 } 1726 1727 /* 1728 * Make sure we consumed all data. It is possible that the remote side 1729 * has sent us bad stuff, but for now we blame ourselves. 1730 */ 1731 if (buf != origBuf + dataLen) { 1732 LOGW("GLITCH: dataLen is %d, we have consumed %d\n", dataLen, 1733 (int) (buf - origBuf)); 1734 } 1735 1736 /* 1737 * We reply with an integer "requestID". 1738 */ 1739 requestId = dvmJdwpNextEventSerial(state); 1740 expandBufAdd4BE(pReply, requestId); 1741 1742 pEvent->requestId = requestId; 1743 1744 LOGV(" --> event requestId=0x%x\n", requestId); 1745 1746 /* add it to the list */ 1747 err = dvmJdwpRegisterEvent(state, pEvent); 1748 if (err != ERR_NONE) { 1749 /* registration failed, probably because event is bogus */ 1750 dvmJdwpEventFree(pEvent); 1751 LOGW("WARNING: event request rejected\n"); 1752 } 1753 return err; 1754 } 1755 1756 /* 1757 * Clear an event. Failure to find an event with a matching ID is a no-op 1758 * and does not return an error. 1759 */ 1760 static JdwpError handleER_Clear(JdwpState* state, 1761 const u1* buf, int dataLen, ExpandBuf* pReply) 1762 { 1763 u1 eventKind; 1764 u4 requestId; 1765 1766 eventKind = read1(&buf); 1767 requestId = read4BE(&buf); 1768 1769 LOGV(" Req to clear eventKind=%d requestId=0x%08x\n", eventKind,requestId); 1770 1771 dvmJdwpUnregisterEventById(state, requestId); 1772 1773 return ERR_NONE; 1774 } 1775 1776 /* 1777 * Return the values of arguments and local variables. 1778 */ 1779 static JdwpError handleSF_GetValues(JdwpState* state, 1780 const u1* buf, int dataLen, ExpandBuf* pReply) 1781 { 1782 ObjectId threadId; 1783 FrameId frameId; 1784 u4 slots; 1785 int i; 1786 1787 threadId = dvmReadObjectId(&buf); 1788 frameId = dvmReadFrameId(&buf); 1789 slots = read4BE(&buf); 1790 1791 LOGV(" Req for %d slots in threadId=%llx frameId=%llx\n", 1792 slots, threadId, frameId); 1793 1794 expandBufAdd4BE(pReply, slots); /* "int values" */ 1795 for (i = 0; i < (int) slots; i++) { 1796 u4 slot; 1797 u1 reqSigByte; 1798 int width; 1799 u1* ptr; 1800 1801 slot = read4BE(&buf); 1802 reqSigByte = read1(&buf); 1803 1804 LOGV(" --> slot %d '%c'\n", slot, reqSigByte); 1805 1806 width = dvmDbgGetTagWidth(reqSigByte); 1807 ptr = expandBufAddSpace(pReply, width+1); 1808 dvmDbgGetLocalValue(threadId, frameId, slot, reqSigByte, ptr, width); 1809 } 1810 1811 return ERR_NONE; 1812 } 1813 1814 /* 1815 * Set the values of arguments and local variables. 1816 */ 1817 static JdwpError handleSF_SetValues(JdwpState* state, 1818 const u1* buf, int dataLen, ExpandBuf* pReply) 1819 { 1820 ObjectId threadId; 1821 FrameId frameId; 1822 u4 slots; 1823 int i; 1824 1825 threadId = dvmReadObjectId(&buf); 1826 frameId = dvmReadFrameId(&buf); 1827 slots = read4BE(&buf); 1828 1829 LOGV(" Req to set %d slots in threadId=%llx frameId=%llx\n", 1830 slots, threadId, frameId); 1831 1832 for (i = 0; i < (int) slots; i++) { 1833 u4 slot; 1834 u1 sigByte; 1835 u8 value; 1836 int width; 1837 1838 slot = read4BE(&buf); 1839 sigByte = read1(&buf); 1840 width = dvmDbgGetTagWidth(sigByte); 1841 value = jdwpReadValue(&buf, width); 1842 1843 LOGV(" --> slot %d '%c' %llx\n", slot, sigByte, value); 1844 dvmDbgSetLocalValue(threadId, frameId, slot, sigByte, value, width); 1845 } 1846 1847 return ERR_NONE; 1848 } 1849 1850 /* 1851 * Returns the value of "this" for the specified frame. 1852 */ 1853 static JdwpError handleSF_ThisObject(JdwpState* state, 1854 const u1* buf, int dataLen, ExpandBuf* pReply) 1855 { 1856 ObjectId threadId; 1857 FrameId frameId; 1858 u1 objectTag; 1859 ObjectId objectId; 1860 char* typeName; 1861 1862 threadId = dvmReadObjectId(&buf); 1863 frameId = dvmReadFrameId(&buf); 1864 1865 if (!dvmDbgGetThisObject(threadId, frameId, &objectId)) 1866 return ERR_INVALID_FRAMEID; 1867 1868 if (objectId == 0) { 1869 typeName = strdup("null"); 1870 objectTag = 0; 1871 } else { 1872 typeName = dvmDbgGetObjectTypeName(objectId); 1873 objectTag = dvmDbgGetObjectTag(objectId, typeName); 1874 } 1875 LOGV(" Req for 'this' in thread=%llx frame=%llx --> %llx %s '%c'\n", 1876 threadId, frameId, objectId, typeName, (char)objectTag); 1877 free(typeName); 1878 1879 expandBufAdd1(pReply, objectTag); 1880 expandBufAddObjectId(pReply, objectId); 1881 1882 return ERR_NONE; 1883 } 1884 1885 /* 1886 * Return the reference type reflected by this class object. 1887 * 1888 * This appears to be required because ReferenceTypeId values are NEVER 1889 * reused, whereas ClassIds can be recycled like any other object. (Either 1890 * that, or I have no idea what this is for.) 1891 */ 1892 static JdwpError handleCOR_ReflectedType(JdwpState* state, 1893 const u1* buf, int dataLen, ExpandBuf* pReply) 1894 { 1895 RefTypeId classObjectId; 1896 1897 classObjectId = dvmReadRefTypeId(&buf); 1898 1899 LOGV(" Req for refTypeId for class=%llx (%s)\n", 1900 classObjectId, dvmDbgGetClassDescriptor(classObjectId)); 1901 1902 /* just hand the type back to them */ 1903 if (dvmDbgIsInterface(classObjectId)) 1904 expandBufAdd1(pReply, TT_INTERFACE); 1905 else 1906 expandBufAdd1(pReply, TT_CLASS); 1907 expandBufAddRefTypeId(pReply, classObjectId); 1908 1909 return ERR_NONE; 1910 } 1911 1912 /* 1913 * Handle a DDM packet with a single chunk in it. 1914 */ 1915 static JdwpError handleDDM_Chunk(JdwpState* state, 1916 const u1* buf, int dataLen, ExpandBuf* pReply) 1917 { 1918 u1* replyBuf = NULL; 1919 int replyLen = -1; 1920 1921 LOGV(" Handling DDM packet (%.4s)\n", buf); 1922 1923 /* 1924 * On first DDM packet, notify all handlers that DDM is running. 1925 */ 1926 if (!state->ddmActive) { 1927 state->ddmActive = true; 1928 dvmDbgDdmConnected(); 1929 } 1930 1931 /* 1932 * If they want to send something back, we copy it into the buffer. 1933 * A no-copy approach would be nicer. 1934 * 1935 * TODO: consider altering the JDWP stuff to hold the packet header 1936 * in a separate buffer. That would allow us to writev() DDM traffic 1937 * instead of copying it into the expanding buffer. The reduction in 1938 * heap requirements is probably more valuable than the efficiency. 1939 */ 1940 if (dvmDbgDdmHandlePacket(buf, dataLen, &replyBuf, &replyLen)) { 1941 assert(replyLen > 0 && replyLen < 1*1024*1024); 1942 memcpy(expandBufAddSpace(pReply, replyLen), replyBuf, replyLen); 1943 free(replyBuf); 1944 } 1945 return ERR_NONE; 1946 } 1947 1948 /* 1949 * Handler map decl. 1950 */ 1951 typedef JdwpError (*JdwpRequestHandler)(JdwpState* state, 1952 const u1* buf, int dataLen, ExpandBuf* reply); 1953 1954 typedef struct { 1955 u1 cmdSet; 1956 u1 cmd; 1957 JdwpRequestHandler func; 1958 const char* descr; 1959 } JdwpHandlerMap; 1960 1961 /* 1962 * Map commands to functions. 1963 * 1964 * Command sets 0-63 are incoming requests, 64-127 are outbound requests, 1965 * and 128-256 are vendor-defined. 1966 */ 1967 static const JdwpHandlerMap gHandlerMap[] = { 1968 /* VirtualMachine command set (1) */ 1969 { 1, 1, handleVM_Version, "VirtualMachine.Version" }, 1970 { 1, 2, handleVM_ClassesBySignature, 1971 "VirtualMachine.ClassesBySignature" }, 1972 //1, 3, VirtualMachine.AllClasses 1973 { 1, 4, handleVM_AllThreads, "VirtualMachine.AllThreads" }, 1974 { 1, 5, handleVM_TopLevelThreadGroups, 1975 "VirtualMachine.TopLevelThreadGroups" }, 1976 { 1, 6, handleVM_Dispose, "VirtualMachine.Dispose" }, 1977 { 1, 7, handleVM_IDSizes, "VirtualMachine.IDSizes" }, 1978 { 1, 8, handleVM_Suspend, "VirtualMachine.Suspend" }, 1979 { 1, 9, handleVM_Resume, "VirtualMachine.Resume" }, 1980 { 1, 10, handleVM_Exit, "VirtualMachine.Exit" }, 1981 { 1, 11, handleVM_CreateString, "VirtualMachine.CreateString" }, 1982 { 1, 12, handleVM_Capabilities, "VirtualMachine.Capabilities" }, 1983 { 1, 13, handleVM_ClassPaths, "VirtualMachine.ClassPaths" }, 1984 { 1, 14, HandleVM_DisposeObjects, "VirtualMachine.DisposeObjects" }, 1985 //1, 15, HoldEvents 1986 //1, 16, ReleaseEvents 1987 { 1, 17, handleVM_CapabilitiesNew, 1988 "VirtualMachine.CapabilitiesNew" }, 1989 //1, 18, RedefineClasses 1990 //1, 19, SetDefaultStratum 1991 { 1, 20, handleVM_AllClassesWithGeneric, 1992 "VirtualMachine.AllClassesWithGeneric"}, 1993 //1, 21, InstanceCounts 1994 1995 /* ReferenceType command set (2) */ 1996 { 2, 1, handleRT_Signature, "ReferenceType.Signature" }, 1997 { 2, 2, handleRT_ClassLoader, "ReferenceType.ClassLoader" }, 1998 { 2, 3, handleRT_Modifiers, "ReferenceType.Modifiers" }, 1999 //2, 4, Fields 2000 //2, 5, Methods 2001 { 2, 6, handleRT_GetValues, "ReferenceType.GetValues" }, 2002 { 2, 7, handleRT_SourceFile, "ReferenceType.SourceFile" }, 2003 //2, 8, NestedTypes 2004 { 2, 9, handleRT_Status, "ReferenceType.Status" }, 2005 { 2, 10, handleRT_Interfaces, "ReferenceType.Interfaces" }, 2006 { 2, 11, handleRT_ClassObject, "ReferenceType.ClassObject" }, 2007 { 2, 12, handleRT_SourceDebugExtension, 2008 "ReferenceType.SourceDebugExtension" }, 2009 { 2, 13, handleRT_SignatureWithGeneric, 2010 "ReferenceType.SignatureWithGeneric" }, 2011 { 2, 14, handleRT_FieldsWithGeneric, 2012 "ReferenceType.FieldsWithGeneric" }, 2013 { 2, 15, handleRT_MethodsWithGeneric, 2014 "ReferenceType.MethodsWithGeneric" }, 2015 //2, 16, Instances 2016 //2, 17, ClassFileVersion 2017 //2, 18, ConstantPool 2018 2019 /* ClassType command set (3) */ 2020 { 3, 1, handleCT_Superclass, "ClassType.Superclass" }, 2021 { 3, 2, handleCT_SetValues, "ClassType.SetValues" }, 2022 { 3, 3, handleCT_InvokeMethod, "ClassType.InvokeMethod" }, 2023 { 3, 4, handleCT_NewInstance, "ClassType.NewInstance" }, 2024 2025 /* ArrayType command set (4) */ 2026 //4, 1, NewInstance 2027 2028 /* InterfaceType command set (5) */ 2029 2030 /* Method command set (6) */ 2031 { 6, 1, handleM_LineTable, "Method.LineTable" }, 2032 //6, 2, VariableTable 2033 //6, 3, Bytecodes 2034 //6, 4, IsObsolete 2035 { 6, 5, handleM_VariableTableWithGeneric, 2036 "Method.VariableTableWithGeneric" }, 2037 2038 /* Field command set (8) */ 2039 2040 /* ObjectReference command set (9) */ 2041 { 9, 1, handleOR_ReferenceType, "ObjectReference.ReferenceType" }, 2042 { 9, 2, handleOR_GetValues, "ObjectReference.GetValues" }, 2043 { 9, 3, handleOR_SetValues, "ObjectReference.SetValues" }, 2044 //9, 4, (not defined) 2045 //9, 5, MonitorInfo 2046 { 9, 6, handleOR_InvokeMethod, "ObjectReference.InvokeMethod" }, 2047 { 9, 7, handleOR_DisableCollection, 2048 "ObjectReference.DisableCollection" }, 2049 { 9, 8, handleOR_EnableCollection, 2050 "ObjectReference.EnableCollection" }, 2051 { 9, 9, handleOR_IsCollected, "ObjectReference.IsCollected" }, 2052 //9, 10, ReferringObjects 2053 2054 /* StringReference command set (10) */ 2055 { 10, 1, handleSR_Value, "StringReference.Value" }, 2056 2057 /* ThreadReference command set (11) */ 2058 { 11, 1, handleTR_Name, "ThreadReference.Name" }, 2059 { 11, 2, handleTR_Suspend, "ThreadReference.Suspend" }, 2060 { 11, 3, handleTR_Resume, "ThreadReference.Resume" }, 2061 { 11, 4, handleTR_Status, "ThreadReference.Status" }, 2062 { 11, 5, handleTR_ThreadGroup, "ThreadReference.ThreadGroup" }, 2063 { 11, 6, handleTR_Frames, "ThreadReference.Frames" }, 2064 { 11, 7, handleTR_FrameCount, "ThreadReference.FrameCount" }, 2065 //11, 8, OwnedMonitors 2066 { 11, 9, handleTR_CurrentContendedMonitor, 2067 "ThreadReference.CurrentContendedMonitor" }, 2068 //11, 10, Stop 2069 //11, 11, Interrupt 2070 { 11, 12, handleTR_SuspendCount, "ThreadReference.SuspendCount" }, 2071 //11, 13, OwnedMonitorsStackDepthInfo 2072 //11, 14, ForceEarlyReturn 2073 2074 /* ThreadGroupReference command set (12) */ 2075 { 12, 1, handleTGR_Name, "ThreadGroupReference.Name" }, 2076 { 12, 2, handleTGR_Parent, "ThreadGroupReference.Parent" }, 2077 { 12, 3, handleTGR_Children, "ThreadGroupReference.Children" }, 2078 2079 /* ArrayReference command set (13) */ 2080 { 13, 1, handleAR_Length, "ArrayReference.Length" }, 2081 { 13, 2, handleAR_GetValues, "ArrayReference.GetValues" }, 2082 { 13, 3, handleAR_SetValues, "ArrayReference.SetValues" }, 2083 2084 /* ClassLoaderReference command set (14) */ 2085 { 14, 1, handleCLR_VisibleClasses, 2086 "ClassLoaderReference.VisibleClasses" }, 2087 2088 /* EventRequest command set (15) */ 2089 { 15, 1, handleER_Set, "EventRequest.Set" }, 2090 { 15, 2, handleER_Clear, "EventRequest.Clear" }, 2091 //15, 3, ClearAllBreakpoints 2092 2093 /* StackFrame command set (16) */ 2094 { 16, 1, handleSF_GetValues, "StackFrame.GetValues" }, 2095 { 16, 2, handleSF_SetValues, "StackFrame.SetValues" }, 2096 { 16, 3, handleSF_ThisObject, "StackFrame.ThisObject" }, 2097 //16, 4, PopFrames 2098 2099 /* ClassObjectReference command set (17) */ 2100 { 17, 1, handleCOR_ReflectedType,"ClassObjectReference.ReflectedType" }, 2101 2102 /* Event command set (64) */ 2103 //64, 100, Composite <-- sent from VM to debugger, never received by VM 2104 2105 { 199, 1, handleDDM_Chunk, "DDM.Chunk" }, 2106 }; 2107 2108 2109 /* 2110 * Process a request from the debugger. 2111 * 2112 * On entry, the JDWP thread is in VMWAIT. 2113 */ 2114 void dvmJdwpProcessRequest(JdwpState* state, const JdwpReqHeader* pHeader, 2115 const u1* buf, int dataLen, ExpandBuf* pReply) 2116 { 2117 JdwpError result = ERR_NONE; 2118 int i, respLen; 2119 2120 /* 2121 * Activity from a debugger, not merely ddms. Mark us as having an 2122 * active debugger session, and zero out the last-activity timestamp. 2123 */ 2124 if (pHeader->cmdSet != kJDWPDdmCmdSet) { 2125 dvmDbgActive(); 2126 2127 state->lastActivitySec = 0; 2128 MEM_BARRIER(); 2129 } 2130 2131 /* 2132 * If a debugger event has fired in another thread, wait until the 2133 * initiating thread has suspended itself before processing messages 2134 * from the debugger. Otherwise we (the JDWP thread) could be told to 2135 * resume the thread before it has suspended. 2136 * 2137 * We call with an argument of zero to wait for the current event 2138 * thread to finish, and then clear the block. Depending on the thread 2139 * suspend policy, this may allow events in other threads to fire, 2140 * but those events have no bearing on what the debugger has sent us 2141 * in the current request. 2142 * 2143 * Note that we MUST clear the event token before waking the event 2144 * thread up, or risk waiting for the thread to suspend after we've 2145 * told it to resume. 2146 */ 2147 dvmJdwpSetWaitForEventThread(state, 0); 2148 2149 /* 2150 * Tell the VM that we're running and shouldn't be interrupted by GC. 2151 * Do this after anything that can stall indefinitely. 2152 */ 2153 dvmDbgThreadRunning(); 2154 2155 expandBufAddSpace(pReply, kJDWPHeaderLen); 2156 2157 for (i = 0; i < (int) NELEM(gHandlerMap); i++) { 2158 if (gHandlerMap[i].cmdSet == pHeader->cmdSet && 2159 gHandlerMap[i].cmd == pHeader->cmd) 2160 { 2161 LOGV("REQ: %s (cmd=%d/%d dataLen=%d id=0x%06x)\n", 2162 gHandlerMap[i].descr, pHeader->cmdSet, pHeader->cmd, 2163 dataLen, pHeader->id); 2164 result = (*gHandlerMap[i].func)(state, buf, dataLen, pReply); 2165 break; 2166 } 2167 } 2168 if (i == NELEM(gHandlerMap)) { 2169 LOGE("REQ: UNSUPPORTED (cmd=%d/%d dataLen=%d id=0x%06x)\n", 2170 pHeader->cmdSet, pHeader->cmd, dataLen, pHeader->id); 2171 if (dataLen > 0) 2172 dvmPrintHexDumpDbg(buf, dataLen, LOG_TAG); 2173 assert(!"command not implemented"); // make it *really* obvious 2174 result = ERR_NOT_IMPLEMENTED; 2175 } 2176 2177 /* 2178 * Set up the reply header. 2179 * 2180 * If we encountered an error, only send the header back. 2181 */ 2182 u1* replyBuf = expandBufGetBuffer(pReply); 2183 set4BE(replyBuf + 4, pHeader->id); 2184 set1(replyBuf + 8, kJDWPFlagReply); 2185 set2BE(replyBuf + 9, result); 2186 if (result == ERR_NONE) 2187 set4BE(replyBuf + 0, expandBufGetLength(pReply)); 2188 else 2189 set4BE(replyBuf + 0, kJDWPHeaderLen); 2190 2191 respLen = expandBufGetLength(pReply) - kJDWPHeaderLen; 2192 IF_LOG(LOG_VERBOSE, LOG_TAG) { 2193 LOGV("reply: dataLen=%d err=%s(%d)%s\n", respLen, 2194 dvmJdwpErrorStr(result), result, 2195 result != ERR_NONE ? " **FAILED**" : ""); 2196 if (respLen > 0) 2197 dvmPrintHexDumpDbg(expandBufGetBuffer(pReply) + kJDWPHeaderLen, 2198 respLen, LOG_TAG); 2199 } 2200 2201 /* 2202 * Update last-activity timestamp. We really only need this during 2203 * the initial setup. Only update if this is a non-DDMS packet. 2204 */ 2205 if (pHeader->cmdSet != kJDWPDdmCmdSet) { 2206 long lastSec, lastMsec; 2207 2208 dvmJdwpGetNowMsec(&lastSec, &lastMsec); 2209 state->lastActivityMsec = lastMsec; 2210 MEM_BARRIER(); // updating a 64-bit value 2211 state->lastActivitySec = lastSec; 2212 } 2213 2214 /* tell the VM that GC is okay again */ 2215 dvmDbgThreadWaiting(); 2216 } 2217 2218