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