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