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 free(str); 380 if (stringId == 0) 381 return ERR_OUT_OF_MEMORY; 382 383 expandBufAddObjectId(pReply, stringId); 384 return ERR_NONE; 385 } 386 387 /* 388 * Tell the debugger what we are capable of. 389 */ 390 static JdwpError handleVM_Capabilities(JdwpState* state, 391 const u1* buf, int dataLen, ExpandBuf* pReply) 392 { 393 expandBufAdd1(pReply, false); /* canWatchFieldModification */ 394 expandBufAdd1(pReply, false); /* canWatchFieldAccess */ 395 expandBufAdd1(pReply, false); /* canGetBytecodes */ 396 expandBufAdd1(pReply, true); /* canGetSyntheticAttribute */ 397 expandBufAdd1(pReply, false); /* canGetOwnedMonitorInfo */ 398 expandBufAdd1(pReply, false); /* canGetCurrentContendedMonitor */ 399 expandBufAdd1(pReply, false); /* canGetMonitorInfo */ 400 return ERR_NONE; 401 } 402 403 /* 404 * Return classpath and bootclasspath. 405 */ 406 static JdwpError handleVM_ClassPaths(JdwpState* state, 407 const u1* buf, int dataLen, ExpandBuf* pReply) 408 { 409 char baseDir[2] = "/"; 410 411 /* 412 * TODO: make this real. Not important for remote debugging, but 413 * might be useful for local debugging. 414 */ 415 u4 classPaths = 1; 416 u4 bootClassPaths = 0; 417 418 expandBufAddUtf8String(pReply, (const u1*) baseDir); 419 expandBufAdd4BE(pReply, classPaths); 420 for (u4 i = 0; i < classPaths; i++) { 421 expandBufAddUtf8String(pReply, (const u1*) "."); 422 } 423 424 expandBufAdd4BE(pReply, bootClassPaths); 425 for (u4 i = 0; i < classPaths; i++) { 426 /* add bootclasspath components as strings */ 427 } 428 429 return ERR_NONE; 430 } 431 432 /* 433 * Release a list of object IDs. (Seen in jdb.) 434 * 435 * Currently does nothing. 436 */ 437 static JdwpError HandleVM_DisposeObjects(JdwpState* state, 438 const u1* buf, int dataLen, ExpandBuf* pReply) 439 { 440 return ERR_NONE; 441 } 442 443 /* 444 * Tell the debugger what we are capable of. 445 */ 446 static JdwpError handleVM_CapabilitiesNew(JdwpState* state, 447 const u1* buf, int dataLen, ExpandBuf* pReply) 448 { 449 expandBufAdd1(pReply, false); /* canWatchFieldModification */ 450 expandBufAdd1(pReply, false); /* canWatchFieldAccess */ 451 expandBufAdd1(pReply, false); /* canGetBytecodes */ 452 expandBufAdd1(pReply, true); /* canGetSyntheticAttribute */ 453 expandBufAdd1(pReply, false); /* canGetOwnedMonitorInfo */ 454 expandBufAdd1(pReply, false); /* canGetCurrentContendedMonitor */ 455 expandBufAdd1(pReply, false); /* canGetMonitorInfo */ 456 expandBufAdd1(pReply, false); /* canRedefineClasses */ 457 expandBufAdd1(pReply, false); /* canAddMethod */ 458 expandBufAdd1(pReply, false); /* canUnrestrictedlyRedefineClasses */ 459 expandBufAdd1(pReply, false); /* canPopFrames */ 460 expandBufAdd1(pReply, false); /* canUseInstanceFilters */ 461 expandBufAdd1(pReply, false); /* canGetSourceDebugExtension */ 462 expandBufAdd1(pReply, false); /* canRequestVMDeathEvent */ 463 expandBufAdd1(pReply, false); /* canSetDefaultStratum */ 464 expandBufAdd1(pReply, false); /* 1.6: canGetInstanceInfo */ 465 expandBufAdd1(pReply, false); /* 1.6: canRequestMonitorEvents */ 466 expandBufAdd1(pReply, false); /* 1.6: canGetMonitorFrameInfo */ 467 expandBufAdd1(pReply, false); /* 1.6: canUseSourceNameFilters */ 468 expandBufAdd1(pReply, false); /* 1.6: canGetConstantPool */ 469 expandBufAdd1(pReply, false); /* 1.6: canForceEarlyReturn */ 470 471 /* fill in reserved22 through reserved32; note count started at 1 */ 472 for (int i = 22; i <= 32; i++) 473 expandBufAdd1(pReply, false); /* reservedN */ 474 return ERR_NONE; 475 } 476 477 /* 478 * Cough up the complete list of classes. 479 */ 480 static JdwpError handleVM_AllClassesWithGeneric(JdwpState* state, 481 const u1* buf, int dataLen, ExpandBuf* pReply) 482 { 483 u4 numClasses = 0; 484 RefTypeId* classRefBuf = NULL; 485 486 dvmDbgGetClassList(&numClasses, &classRefBuf); 487 488 expandBufAdd4BE(pReply, numClasses); 489 490 for (u4 i = 0; i < numClasses; i++) { 491 static const u1 genericSignature[1] = ""; 492 u1 refTypeTag; 493 const char* signature; 494 u4 status; 495 496 dvmDbgGetClassInfo(classRefBuf[i], &refTypeTag, &status, &signature); 497 498 expandBufAdd1(pReply, refTypeTag); 499 expandBufAddRefTypeId(pReply, classRefBuf[i]); 500 expandBufAddUtf8String(pReply, (const u1*) signature); 501 expandBufAddUtf8String(pReply, genericSignature); 502 expandBufAdd4BE(pReply, status); 503 } 504 505 free(classRefBuf); 506 507 return ERR_NONE; 508 } 509 510 /* 511 * Given a referenceTypeID, return a string with the JNI reference type 512 * signature (e.g. "Ljava/lang/Error;"). 513 */ 514 static JdwpError handleRT_Signature(JdwpState* state, 515 const u1* buf, int dataLen, ExpandBuf* pReply) 516 { 517 RefTypeId refTypeId = dvmReadRefTypeId(&buf); 518 519 ALOGV(" Req for signature of refTypeId=0x%llx", refTypeId); 520 const char* signature = dvmDbgGetSignature(refTypeId); 521 expandBufAddUtf8String(pReply, (const u1*) signature); 522 523 return ERR_NONE; 524 } 525 526 /* 527 * Return the modifiers (a/k/a access flags) for a reference type. 528 */ 529 static JdwpError handleRT_Modifiers(JdwpState* state, 530 const u1* buf, int dataLen, ExpandBuf* pReply) 531 { 532 RefTypeId refTypeId = dvmReadRefTypeId(&buf); 533 u4 modBits = dvmDbgGetAccessFlags(refTypeId); 534 535 expandBufAdd4BE(pReply, modBits); 536 537 return ERR_NONE; 538 } 539 540 /* 541 * Get values from static fields in a reference type. 542 */ 543 static JdwpError handleRT_GetValues(JdwpState* state, 544 const u1* buf, int dataLen, ExpandBuf* pReply) 545 { 546 RefTypeId refTypeId = dvmReadRefTypeId(&buf); 547 u4 numFields = read4BE(&buf); 548 549 ALOGV(" RT_GetValues %u:", numFields); 550 551 expandBufAdd4BE(pReply, numFields); 552 for (u4 i = 0; i < numFields; i++) { 553 FieldId fieldId = dvmReadFieldId(&buf); 554 dvmDbgGetStaticFieldValue(refTypeId, fieldId, pReply); 555 } 556 557 return ERR_NONE; 558 } 559 560 /* 561 * Get the name of the source file in which a reference type was declared. 562 */ 563 static JdwpError handleRT_SourceFile(JdwpState* state, 564 const u1* buf, int dataLen, ExpandBuf* pReply) 565 { 566 RefTypeId refTypeId = dvmReadRefTypeId(&buf); 567 568 const char* fileName = dvmDbgGetSourceFile(refTypeId); 569 if (fileName != NULL) { 570 expandBufAddUtf8String(pReply, (const u1*) fileName); 571 return ERR_NONE; 572 } else { 573 return ERR_ABSENT_INFORMATION; 574 } 575 } 576 577 /* 578 * Return the current status of the reference type. 579 */ 580 static JdwpError handleRT_Status(JdwpState* state, 581 const u1* buf, int dataLen, ExpandBuf* pReply) 582 { 583 RefTypeId refTypeId = dvmReadRefTypeId(&buf); 584 585 /* get status flags */ 586 u1 typeTag; 587 u4 status; 588 dvmDbgGetClassInfo(refTypeId, &typeTag, &status, NULL); 589 expandBufAdd4BE(pReply, status); 590 return ERR_NONE; 591 } 592 593 /* 594 * Return interfaces implemented directly by this class. 595 */ 596 static JdwpError handleRT_Interfaces(JdwpState* state, 597 const u1* buf, int dataLen, ExpandBuf* pReply) 598 { 599 RefTypeId refTypeId = dvmReadRefTypeId(&buf); 600 601 ALOGV(" Req for interfaces in %llx (%s)", refTypeId, 602 dvmDbgGetClassDescriptor(refTypeId)); 603 604 dvmDbgOutputAllInterfaces(refTypeId, pReply); 605 606 return ERR_NONE; 607 } 608 609 /* 610 * Return the class object corresponding to this type. 611 */ 612 static JdwpError handleRT_ClassObject(JdwpState* state, 613 const u1* buf, int dataLen, ExpandBuf* pReply) 614 { 615 RefTypeId refTypeId = dvmReadRefTypeId(&buf); 616 ObjectId classObjId = dvmDbgGetClassObject(refTypeId); 617 618 ALOGV(" RefTypeId %llx -> ObjectId %llx", refTypeId, classObjId); 619 620 expandBufAddObjectId(pReply, classObjId); 621 622 return ERR_NONE; 623 } 624 625 /* 626 * Returns the value of the SourceDebugExtension attribute. 627 * 628 * JDB seems interested, but DEX files don't currently support this. 629 */ 630 static JdwpError handleRT_SourceDebugExtension(JdwpState* state, 631 const u1* buf, int dataLen, ExpandBuf* pReply) 632 { 633 /* referenceTypeId in, string out */ 634 return ERR_ABSENT_INFORMATION; 635 } 636 637 /* 638 * Like RT_Signature but with the possibility of a "generic signature". 639 */ 640 static JdwpError handleRT_SignatureWithGeneric(JdwpState* state, 641 const u1* buf, int dataLen, ExpandBuf* pReply) 642 { 643 static const u1 genericSignature[1] = ""; 644 645 RefTypeId refTypeId = dvmReadRefTypeId(&buf); 646 647 ALOGV(" Req for signature of refTypeId=0x%llx", refTypeId); 648 const char* signature = dvmDbgGetSignature(refTypeId); 649 if (signature != NULL) { 650 expandBufAddUtf8String(pReply, (const u1*) signature); 651 } else { 652 ALOGW("No signature for refTypeId=0x%llx", refTypeId); 653 expandBufAddUtf8String(pReply, (const u1*) "Lunknown;"); 654 } 655 expandBufAddUtf8String(pReply, genericSignature); 656 657 return ERR_NONE; 658 } 659 660 /* 661 * Return the instance of java.lang.ClassLoader that loaded the specified 662 * reference type, or null if it was loaded by the system loader. 663 */ 664 static JdwpError handleRT_ClassLoader(JdwpState* state, 665 const u1* buf, int dataLen, ExpandBuf* pReply) 666 { 667 RefTypeId refTypeId = dvmReadRefTypeId(&buf); 668 669 expandBufAddObjectId(pReply, dvmDbgGetClassLoader(refTypeId)); 670 671 return ERR_NONE; 672 } 673 674 /* 675 * Given a referenceTypeId, return a block of stuff that describes the 676 * fields declared by a class. 677 */ 678 static JdwpError handleRT_FieldsWithGeneric(JdwpState* state, 679 const u1* buf, int dataLen, ExpandBuf* pReply) 680 { 681 RefTypeId refTypeId = dvmReadRefTypeId(&buf); 682 ALOGV(" Req for fields in refTypeId=0x%llx", refTypeId); 683 ALOGV(" --> '%s'", dvmDbgGetSignature(refTypeId)); 684 685 dvmDbgOutputAllFields(refTypeId, true, pReply); 686 687 return ERR_NONE; 688 } 689 690 /* 691 * Given a referenceTypeID, return a block of goodies describing the 692 * methods declared by a class. 693 */ 694 static JdwpError handleRT_MethodsWithGeneric(JdwpState* state, 695 const u1* buf, int dataLen, ExpandBuf* pReply) 696 { 697 RefTypeId refTypeId = dvmReadRefTypeId(&buf); 698 699 ALOGV(" Req for methods in refTypeId=0x%llx", refTypeId); 700 ALOGV(" --> '%s'", dvmDbgGetSignature(refTypeId)); 701 702 dvmDbgOutputAllMethods(refTypeId, true, pReply); 703 704 return ERR_NONE; 705 } 706 707 /* 708 * Return the immediate superclass of a class. 709 */ 710 static JdwpError handleCT_Superclass(JdwpState* state, 711 const u1* buf, int dataLen, ExpandBuf* pReply) 712 { 713 RefTypeId classId = dvmReadRefTypeId(&buf); 714 715 RefTypeId superClassId = dvmDbgGetSuperclass(classId); 716 717 expandBufAddRefTypeId(pReply, superClassId); 718 719 return ERR_NONE; 720 } 721 722 /* 723 * Set static class values. 724 */ 725 static JdwpError handleCT_SetValues(JdwpState* state, 726 const u1* buf, int dataLen, ExpandBuf* pReply) 727 { 728 RefTypeId classId = dvmReadRefTypeId(&buf); 729 u4 values = read4BE(&buf); 730 731 ALOGV(" Req to set %d values in classId=%llx", values, classId); 732 733 for (u4 i = 0; i < values; i++) { 734 FieldId fieldId = dvmReadFieldId(&buf); 735 u1 fieldTag = dvmDbgGetStaticFieldBasicTag(classId, fieldId); 736 int width = dvmDbgGetTagWidth(fieldTag); 737 u8 value = jdwpReadValue(&buf, width); 738 739 ALOGV(" --> field=%x tag=%c -> %lld", fieldId, fieldTag, value); 740 dvmDbgSetStaticFieldValue(classId, fieldId, value, width); 741 } 742 743 return ERR_NONE; 744 } 745 746 /* 747 * Invoke a static method. 748 * 749 * Example: Eclipse sometimes uses java/lang/Class.forName(String s) on 750 * values in the "variables" display. 751 */ 752 static JdwpError handleCT_InvokeMethod(JdwpState* state, 753 const u1* buf, int dataLen, ExpandBuf* pReply) 754 { 755 RefTypeId classId = dvmReadRefTypeId(&buf); 756 ObjectId threadId = dvmReadObjectId(&buf); 757 MethodId methodId = dvmReadMethodId(&buf); 758 759 return finishInvoke(state, buf, dataLen, pReply, 760 threadId, 0, classId, methodId, false); 761 } 762 763 /* 764 * Create a new object of the requested type, and invoke the specified 765 * constructor. 766 * 767 * Example: in IntelliJ, create a watch on "new String(myByteArray)" to 768 * see the contents of a byte[] as a string. 769 */ 770 static JdwpError handleCT_NewInstance(JdwpState* state, 771 const u1* buf, int dataLen, ExpandBuf* pReply) 772 { 773 RefTypeId classId = dvmReadRefTypeId(&buf); 774 ObjectId threadId = dvmReadObjectId(&buf); 775 MethodId methodId = dvmReadMethodId(&buf); 776 777 ALOGV("Creating instance of %s", dvmDbgGetClassDescriptor(classId)); 778 ObjectId objectId = dvmDbgCreateObject(classId); 779 if (objectId == 0) 780 return ERR_OUT_OF_MEMORY; 781 782 return finishInvoke(state, buf, dataLen, pReply, 783 threadId, objectId, classId, methodId, true); 784 } 785 786 /* 787 * Create a new array object of the requested type and length. 788 */ 789 static JdwpError handleAT_newInstance(JdwpState* state, 790 const u1* buf, int dataLen, ExpandBuf* pReply) 791 { 792 RefTypeId arrayTypeId = dvmReadRefTypeId(&buf); 793 u4 length = read4BE(&buf); 794 795 ALOGV("Creating array %s[%u]", 796 dvmDbgGetClassDescriptor(arrayTypeId), length); 797 ObjectId objectId = dvmDbgCreateArrayObject(arrayTypeId, length); 798 if (objectId == 0) 799 return ERR_OUT_OF_MEMORY; 800 801 expandBufAdd1(pReply, JT_ARRAY); 802 expandBufAddObjectId(pReply, objectId); 803 return ERR_NONE; 804 } 805 806 /* 807 * Return line number information for the method, if present. 808 */ 809 static JdwpError handleM_LineTable(JdwpState* state, 810 const u1* buf, int dataLen, ExpandBuf* pReply) 811 { 812 RefTypeId refTypeId = dvmReadRefTypeId(&buf); 813 MethodId methodId = dvmReadMethodId(&buf); 814 815 ALOGV(" Req for line table in %s.%s", 816 dvmDbgGetClassDescriptor(refTypeId), 817 dvmDbgGetMethodName(refTypeId,methodId)); 818 819 dvmDbgOutputLineTable(refTypeId, methodId, pReply); 820 821 return ERR_NONE; 822 } 823 824 /* 825 * Pull out the LocalVariableTable goodies. 826 */ 827 static JdwpError handleM_VariableTableWithGeneric(JdwpState* state, 828 const u1* buf, int dataLen, ExpandBuf* pReply) 829 { 830 RefTypeId classId = dvmReadRefTypeId(&buf); 831 MethodId methodId = dvmReadMethodId(&buf); 832 833 ALOGV(" Req for LocalVarTab in class=%s method=%s", 834 dvmDbgGetClassDescriptor(classId), 835 dvmDbgGetMethodName(classId, methodId)); 836 837 /* 838 * We could return ERR_ABSENT_INFORMATION here if the DEX file was 839 * built without local variable information. That will cause Eclipse 840 * to make a best-effort attempt at displaying local variables 841 * anonymously. However, the attempt isn't very good, so we're probably 842 * better off just not showing anything. 843 */ 844 dvmDbgOutputVariableTable(classId, methodId, true, pReply); 845 return ERR_NONE; 846 } 847 848 /* 849 * Given an object reference, return the runtime type of the object 850 * (class or array). 851 * 852 * This can get called on different things, e.g. threadId gets 853 * passed in here. 854 */ 855 static JdwpError handleOR_ReferenceType(JdwpState* state, 856 const u1* buf, int dataLen, ExpandBuf* pReply) 857 { 858 ObjectId objectId = dvmReadObjectId(&buf); 859 ALOGV(" Req for type of objectId=0x%llx", objectId); 860 861 u1 refTypeTag; 862 RefTypeId typeId; 863 dvmDbgGetObjectType(objectId, &refTypeTag, &typeId); 864 865 expandBufAdd1(pReply, refTypeTag); 866 expandBufAddRefTypeId(pReply, typeId); 867 868 return ERR_NONE; 869 } 870 871 /* 872 * Get values from the fields of an object. 873 */ 874 static JdwpError handleOR_GetValues(JdwpState* state, 875 const u1* buf, int dataLen, ExpandBuf* pReply) 876 { 877 ObjectId objectId = dvmReadObjectId(&buf); 878 u4 numFields = read4BE(&buf); 879 880 ALOGV(" Req for %d fields from objectId=0x%llx", numFields, objectId); 881 882 expandBufAdd4BE(pReply, numFields); 883 884 for (u4 i = 0; i < numFields; i++) { 885 FieldId fieldId = dvmReadFieldId(&buf); 886 dvmDbgGetFieldValue(objectId, fieldId, pReply); 887 } 888 889 return ERR_NONE; 890 } 891 892 /* 893 * Set values in the fields of an object. 894 */ 895 static JdwpError handleOR_SetValues(JdwpState* state, 896 const u1* buf, int dataLen, ExpandBuf* pReply) 897 { 898 ObjectId objectId = dvmReadObjectId(&buf); 899 u4 numFields = read4BE(&buf); 900 901 ALOGV(" Req to set %d fields in objectId=0x%llx", numFields, objectId); 902 903 for (u4 i = 0; i < numFields; i++) { 904 FieldId fieldId = dvmReadFieldId(&buf); 905 906 u1 fieldTag = dvmDbgGetFieldBasicTag(objectId, fieldId); 907 int width = dvmDbgGetTagWidth(fieldTag); 908 u8 value = jdwpReadValue(&buf, width); 909 910 ALOGV(" --> fieldId=%x tag='%c'(%d) value=%lld", 911 fieldId, fieldTag, width, value); 912 913 dvmDbgSetFieldValue(objectId, fieldId, value, width); 914 } 915 916 return ERR_NONE; 917 } 918 919 /* 920 * Invoke an instance method. The invocation must occur in the specified 921 * thread, which must have been suspended by an event. 922 * 923 * The call is synchronous. All threads in the VM are resumed, unless the 924 * SINGLE_THREADED flag is set. 925 * 926 * If you ask Eclipse to "inspect" an object (or ask JDB to "print" an 927 * object), it will try to invoke the object's toString() function. This 928 * feature becomes crucial when examining ArrayLists with Eclipse. 929 */ 930 static JdwpError handleOR_InvokeMethod(JdwpState* state, 931 const u1* buf, int dataLen, ExpandBuf* pReply) 932 { 933 ObjectId objectId = dvmReadObjectId(&buf); 934 ObjectId threadId = dvmReadObjectId(&buf); 935 RefTypeId classId = dvmReadRefTypeId(&buf); 936 MethodId methodId = dvmReadMethodId(&buf); 937 938 return finishInvoke(state, buf, dataLen, pReply, 939 threadId, objectId, classId, methodId, false); 940 } 941 942 /* 943 * Disable garbage collection of the specified object. 944 */ 945 static JdwpError handleOR_DisableCollection(JdwpState* state, 946 const u1* buf, int dataLen, ExpandBuf* pReply) 947 { 948 // this is currently a no-op 949 return ERR_NONE; 950 } 951 952 /* 953 * Enable garbage collection of the specified object. 954 */ 955 static JdwpError handleOR_EnableCollection(JdwpState* state, 956 const u1* buf, int dataLen, ExpandBuf* pReply) 957 { 958 // this is currently a no-op 959 return ERR_NONE; 960 } 961 962 /* 963 * Determine whether an object has been garbage collected. 964 */ 965 static JdwpError handleOR_IsCollected(JdwpState* state, 966 const u1* buf, int dataLen, ExpandBuf* pReply) 967 { 968 ObjectId objectId; 969 970 objectId = dvmReadObjectId(&buf); 971 ALOGV(" Req IsCollected(0x%llx)", objectId); 972 973 // TODO: currently returning false; must integrate with GC 974 expandBufAdd1(pReply, 0); 975 976 return ERR_NONE; 977 } 978 979 /* 980 * Return the string value in a string object. 981 */ 982 static JdwpError handleSR_Value(JdwpState* state, 983 const u1* buf, int dataLen, ExpandBuf* pReply) 984 { 985 ObjectId stringObject = dvmReadObjectId(&buf); 986 char* str = dvmDbgStringToUtf8(stringObject); 987 988 ALOGV(" Req for str %llx --> '%s'", stringObject, str); 989 990 expandBufAddUtf8String(pReply, (u1*) str); 991 free(str); 992 993 return ERR_NONE; 994 } 995 996 /* 997 * Return a thread's name. 998 */ 999 static JdwpError handleTR_Name(JdwpState* state, 1000 const u1* buf, int dataLen, ExpandBuf* pReply) 1001 { 1002 ObjectId threadId = dvmReadObjectId(&buf); 1003 1004 ALOGV(" Req for name of thread 0x%llx", threadId); 1005 char* name = dvmDbgGetThreadName(threadId); 1006 if (name == NULL) 1007 return ERR_INVALID_THREAD; 1008 1009 expandBufAddUtf8String(pReply, (u1*) name); 1010 free(name); 1011 1012 return ERR_NONE; 1013 } 1014 1015 /* 1016 * Suspend the specified thread. 1017 * 1018 * It's supposed to remain suspended even if interpreted code wants to 1019 * resume it; only the JDI is allowed to resume it. 1020 */ 1021 static JdwpError handleTR_Suspend(JdwpState* state, 1022 const u1* buf, int dataLen, ExpandBuf* pReply) 1023 { 1024 ObjectId threadId = dvmReadObjectId(&buf); 1025 1026 if (threadId == dvmDbgGetThreadSelfId()) { 1027 ALOGI(" Warning: ignoring request to suspend self"); 1028 return ERR_THREAD_NOT_SUSPENDED; 1029 } 1030 ALOGV(" Req to suspend thread 0x%llx", threadId); 1031 1032 dvmDbgSuspendThread(threadId); 1033 1034 return ERR_NONE; 1035 } 1036 1037 /* 1038 * Resume the specified thread. 1039 */ 1040 static JdwpError handleTR_Resume(JdwpState* state, 1041 const u1* buf, int dataLen, ExpandBuf* pReply) 1042 { 1043 ObjectId threadId = dvmReadObjectId(&buf); 1044 1045 if (threadId == dvmDbgGetThreadSelfId()) { 1046 ALOGI(" Warning: ignoring request to resume self"); 1047 return ERR_NONE; 1048 } 1049 ALOGV(" Req to resume thread 0x%llx", threadId); 1050 1051 dvmDbgResumeThread(threadId); 1052 1053 return ERR_NONE; 1054 } 1055 1056 /* 1057 * Return status of specified thread. 1058 */ 1059 static JdwpError handleTR_Status(JdwpState* state, 1060 const u1* buf, int dataLen, ExpandBuf* pReply) 1061 { 1062 ObjectId threadId = dvmReadObjectId(&buf); 1063 1064 ALOGV(" Req for status of thread 0x%llx", threadId); 1065 1066 u4 threadStatus; 1067 u4 suspendStatus; 1068 if (!dvmDbgGetThreadStatus(threadId, &threadStatus, &suspendStatus)) 1069 return ERR_INVALID_THREAD; 1070 1071 ALOGV(" --> %s, %s", 1072 dvmJdwpThreadStatusStr((JdwpThreadStatus) threadStatus), 1073 dvmJdwpSuspendStatusStr((JdwpSuspendStatus) suspendStatus)); 1074 1075 expandBufAdd4BE(pReply, threadStatus); 1076 expandBufAdd4BE(pReply, suspendStatus); 1077 1078 return ERR_NONE; 1079 } 1080 1081 /* 1082 * Return the thread group that the specified thread is a member of. 1083 */ 1084 static JdwpError handleTR_ThreadGroup(JdwpState* state, 1085 const u1* buf, int dataLen, ExpandBuf* pReply) 1086 { 1087 ObjectId threadId = dvmReadObjectId(&buf); 1088 1089 /* currently not handling these */ 1090 ObjectId threadGroupId = dvmDbgGetThreadGroup(threadId); 1091 expandBufAddObjectId(pReply, threadGroupId); 1092 1093 return ERR_NONE; 1094 } 1095 1096 /* 1097 * Return the current call stack of a suspended thread. 1098 * 1099 * If the thread isn't suspended, the error code isn't defined, but should 1100 * be THREAD_NOT_SUSPENDED. 1101 */ 1102 static JdwpError handleTR_Frames(JdwpState* state, 1103 const u1* buf, int dataLen, ExpandBuf* pReply) 1104 { 1105 ObjectId threadId = dvmReadObjectId(&buf); 1106 u4 startFrame = read4BE(&buf); 1107 u4 length = read4BE(&buf); 1108 1109 if (!dvmDbgThreadExists(threadId)) 1110 return ERR_INVALID_THREAD; 1111 if (!dvmDbgIsSuspended(threadId)) { 1112 ALOGV(" Rejecting req for frames in running thread '%s' (%llx)", 1113 dvmDbgGetThreadName(threadId), threadId); 1114 return ERR_THREAD_NOT_SUSPENDED; 1115 } 1116 1117 int frameCount = dvmDbgGetThreadFrameCount(threadId); 1118 1119 ALOGV(" Request for frames: threadId=%llx start=%d length=%d [count=%d]", 1120 threadId, startFrame, length, frameCount); 1121 if (frameCount <= 0) 1122 return ERR_THREAD_NOT_SUSPENDED; /* == 0 means 100% native */ 1123 1124 if (length == (u4) -1) 1125 length = frameCount; 1126 assert((int) startFrame >= 0 && (int) startFrame < frameCount); 1127 assert((int) (startFrame + length) <= frameCount); 1128 1129 u4 frames = length; 1130 expandBufAdd4BE(pReply, frames); 1131 for (u4 i = startFrame; i < (startFrame+length); i++) { 1132 FrameId frameId; 1133 JdwpLocation loc; 1134 1135 dvmDbgGetThreadFrame(threadId, i, &frameId, &loc); 1136 1137 expandBufAdd8BE(pReply, frameId); 1138 dvmJdwpAddLocation(pReply, &loc); 1139 1140 LOGVV(" Frame %d: id=%llx loc={type=%d cls=%llx mth=%x loc=%llx}", 1141 i, frameId, loc.typeTag, loc.classId, loc.methodId, loc.idx); 1142 } 1143 1144 return ERR_NONE; 1145 } 1146 1147 /* 1148 * Returns the #of frames on the specified thread, which must be suspended. 1149 */ 1150 static JdwpError handleTR_FrameCount(JdwpState* state, 1151 const u1* buf, int dataLen, ExpandBuf* pReply) 1152 { 1153 ObjectId threadId = dvmReadObjectId(&buf); 1154 1155 if (!dvmDbgThreadExists(threadId)) 1156 return ERR_INVALID_THREAD; 1157 if (!dvmDbgIsSuspended(threadId)) { 1158 ALOGV(" Rejecting req for frames in running thread '%s' (%llx)", 1159 dvmDbgGetThreadName(threadId), threadId); 1160 return ERR_THREAD_NOT_SUSPENDED; 1161 } 1162 1163 int frameCount = dvmDbgGetThreadFrameCount(threadId); 1164 if (frameCount < 0) 1165 return ERR_INVALID_THREAD; 1166 expandBufAdd4BE(pReply, (u4)frameCount); 1167 1168 return ERR_NONE; 1169 } 1170 1171 /* 1172 * Get the monitor that the thread is waiting on. 1173 */ 1174 static JdwpError handleTR_CurrentContendedMonitor(JdwpState* state, 1175 const u1* buf, int dataLen, ExpandBuf* pReply) 1176 { 1177 ObjectId threadId; 1178 1179 threadId = dvmReadObjectId(&buf); 1180 1181 // TODO: create an Object to represent the monitor (we're currently 1182 // just using a raw Monitor struct in the VM) 1183 1184 return ERR_NOT_IMPLEMENTED; 1185 } 1186 1187 /* 1188 * Return the suspend count for the specified thread. 1189 * 1190 * (The thread *might* still be running -- it might not have examined 1191 * its suspend count recently.) 1192 */ 1193 static JdwpError handleTR_SuspendCount(JdwpState* state, 1194 const u1* buf, int dataLen, ExpandBuf* pReply) 1195 { 1196 ObjectId threadId = dvmReadObjectId(&buf); 1197 1198 u4 suspendCount = dvmDbgGetThreadSuspendCount(threadId); 1199 expandBufAdd4BE(pReply, suspendCount); 1200 1201 return ERR_NONE; 1202 } 1203 1204 /* 1205 * Return the name of a thread group. 1206 * 1207 * The Eclipse debugger recognizes "main" and "system" as special. 1208 */ 1209 static JdwpError handleTGR_Name(JdwpState* state, 1210 const u1* buf, int dataLen, ExpandBuf* pReply) 1211 { 1212 ObjectId threadGroupId = dvmReadObjectId(&buf); 1213 ALOGV(" Req for name of threadGroupId=0x%llx", threadGroupId); 1214 1215 char* name = dvmDbgGetThreadGroupName(threadGroupId); 1216 if (name != NULL) 1217 expandBufAddUtf8String(pReply, (u1*) name); 1218 else { 1219 expandBufAddUtf8String(pReply, (u1*) "BAD-GROUP-ID"); 1220 ALOGW("bad thread group ID"); 1221 } 1222 1223 free(name); 1224 1225 return ERR_NONE; 1226 } 1227 1228 /* 1229 * Returns the thread group -- if any -- that contains the specified 1230 * thread group. 1231 */ 1232 static JdwpError handleTGR_Parent(JdwpState* state, 1233 const u1* buf, int dataLen, ExpandBuf* pReply) 1234 { 1235 ObjectId groupId = dvmReadObjectId(&buf); 1236 1237 ObjectId parentGroup = dvmDbgGetThreadGroupParent(groupId); 1238 expandBufAddObjectId(pReply, parentGroup); 1239 1240 return ERR_NONE; 1241 } 1242 1243 /* 1244 * Return the active threads and thread groups that are part of the 1245 * specified thread group. 1246 */ 1247 static JdwpError handleTGR_Children(JdwpState* state, 1248 const u1* buf, int dataLen, ExpandBuf* pReply) 1249 { 1250 ObjectId threadGroupId = dvmReadObjectId(&buf); 1251 ALOGV(" Req for threads in threadGroupId=0x%llx", threadGroupId); 1252 1253 ObjectId* pThreadIds; 1254 u4 threadCount; 1255 dvmDbgGetThreadGroupThreads(threadGroupId, &pThreadIds, &threadCount); 1256 1257 expandBufAdd4BE(pReply, threadCount); 1258 1259 for (u4 i = 0; i < threadCount; i++) 1260 expandBufAddObjectId(pReply, pThreadIds[i]); 1261 free(pThreadIds); 1262 1263 /* 1264 * TODO: finish support for child groups 1265 * 1266 * For now, just show that "main" is a child of "system". 1267 */ 1268 if (threadGroupId == dvmDbgGetSystemThreadGroupId()) { 1269 expandBufAdd4BE(pReply, 1); 1270 expandBufAddObjectId(pReply, dvmDbgGetMainThreadGroupId()); 1271 } else { 1272 expandBufAdd4BE(pReply, 0); 1273 } 1274 1275 return ERR_NONE; 1276 } 1277 1278 /* 1279 * Return the #of components in the array. 1280 */ 1281 static JdwpError handleAR_Length(JdwpState* state, 1282 const u1* buf, int dataLen, ExpandBuf* pReply) 1283 { 1284 ObjectId arrayId = dvmReadObjectId(&buf); 1285 ALOGV(" Req for length of array 0x%llx", arrayId); 1286 1287 u4 arrayLength = dvmDbgGetArrayLength(arrayId); 1288 1289 ALOGV(" --> %d", arrayLength); 1290 1291 expandBufAdd4BE(pReply, arrayLength); 1292 1293 return ERR_NONE; 1294 } 1295 1296 /* 1297 * Return the values from an array. 1298 */ 1299 static JdwpError handleAR_GetValues(JdwpState* state, 1300 const u1* buf, int dataLen, ExpandBuf* pReply) 1301 { 1302 ObjectId arrayId = dvmReadObjectId(&buf); 1303 u4 firstIndex = read4BE(&buf); 1304 u4 length = read4BE(&buf); 1305 1306 u1 tag = dvmDbgGetArrayElementTag(arrayId); 1307 ALOGV(" Req for array values 0x%llx first=%d len=%d (elem tag=%c)", 1308 arrayId, firstIndex, length, tag); 1309 1310 expandBufAdd1(pReply, tag); 1311 expandBufAdd4BE(pReply, length); 1312 1313 if (!dvmDbgOutputArray(arrayId, firstIndex, length, pReply)) 1314 return ERR_INVALID_LENGTH; 1315 1316 return ERR_NONE; 1317 } 1318 1319 /* 1320 * Set values in an array. 1321 */ 1322 static JdwpError handleAR_SetValues(JdwpState* state, 1323 const u1* buf, int dataLen, ExpandBuf* pReply) 1324 { 1325 ObjectId arrayId = dvmReadObjectId(&buf); 1326 u4 firstIndex = read4BE(&buf); 1327 u4 values = read4BE(&buf); 1328 1329 ALOGV(" Req to set array values 0x%llx first=%d count=%d", 1330 arrayId, firstIndex, values); 1331 1332 if (!dvmDbgSetArrayElements(arrayId, firstIndex, values, buf)) 1333 return ERR_INVALID_LENGTH; 1334 1335 return ERR_NONE; 1336 } 1337 1338 /* 1339 * Return the set of classes visible to a class loader. All classes which 1340 * have the class loader as a defining or initiating loader are returned. 1341 */ 1342 static JdwpError handleCLR_VisibleClasses(JdwpState* state, 1343 const u1* buf, int dataLen, ExpandBuf* pReply) 1344 { 1345 ObjectId classLoaderObject; 1346 u4 numClasses = 0; 1347 RefTypeId* classRefBuf = NULL; 1348 int i; 1349 1350 classLoaderObject = dvmReadObjectId(&buf); 1351 1352 dvmDbgGetVisibleClassList(classLoaderObject, &numClasses, &classRefBuf); 1353 1354 expandBufAdd4BE(pReply, numClasses); 1355 for (i = 0; i < (int) numClasses; i++) { 1356 u1 refTypeTag; 1357 1358 refTypeTag = dvmDbgGetClassObjectType(classRefBuf[i]); 1359 1360 expandBufAdd1(pReply, refTypeTag); 1361 expandBufAddRefTypeId(pReply, classRefBuf[i]); 1362 } 1363 1364 return ERR_NONE; 1365 } 1366 1367 /* 1368 * Set an event trigger. 1369 * 1370 * Reply with a requestID. 1371 */ 1372 static JdwpError handleER_Set(JdwpState* state, 1373 const u1* buf, int dataLen, ExpandBuf* pReply) 1374 { 1375 const u1* origBuf = buf; 1376 1377 u1 eventKind = read1(&buf); 1378 u1 suspendPolicy = read1(&buf); 1379 u4 modifierCount = read4BE(&buf); 1380 1381 LOGVV(" Set(kind=%s(%u) suspend=%s(%u) mods=%u)", 1382 dvmJdwpEventKindStr(eventKind), eventKind, 1383 dvmJdwpSuspendPolicyStr(suspendPolicy), suspendPolicy, 1384 modifierCount); 1385 1386 assert(modifierCount < 256); /* reasonableness check */ 1387 1388 JdwpEvent* pEvent = dvmJdwpEventAlloc(modifierCount); 1389 pEvent->eventKind = static_cast<JdwpEventKind>(eventKind); 1390 pEvent->suspendPolicy = static_cast<JdwpSuspendPolicy>(suspendPolicy); 1391 pEvent->modCount = modifierCount; 1392 1393 /* 1394 * Read modifiers. Ordering may be significant (see explanation of Count 1395 * mods in JDWP doc). 1396 */ 1397 for (u4 idx = 0; idx < modifierCount; idx++) { 1398 u1 modKind = read1(&buf); 1399 1400 pEvent->mods[idx].modKind = modKind; 1401 1402 switch (modKind) { 1403 case MK_COUNT: /* report once, when "--count" reaches 0 */ 1404 { 1405 u4 count = read4BE(&buf); 1406 LOGVV(" Count: %u", count); 1407 if (count == 0) 1408 return ERR_INVALID_COUNT; 1409 pEvent->mods[idx].count.count = count; 1410 } 1411 break; 1412 case MK_CONDITIONAL: /* conditional on expression) */ 1413 { 1414 u4 exprId = read4BE(&buf); 1415 LOGVV(" Conditional: %d", exprId); 1416 pEvent->mods[idx].conditional.exprId = exprId; 1417 } 1418 break; 1419 case MK_THREAD_ONLY: /* only report events in specified thread */ 1420 { 1421 ObjectId threadId = dvmReadObjectId(&buf); 1422 LOGVV(" ThreadOnly: %llx", threadId); 1423 pEvent->mods[idx].threadOnly.threadId = threadId; 1424 } 1425 break; 1426 case MK_CLASS_ONLY: /* for ClassPrepare, MethodEntry */ 1427 { 1428 RefTypeId clazzId = dvmReadRefTypeId(&buf); 1429 LOGVV(" ClassOnly: %llx (%s)", 1430 clazzId, dvmDbgGetClassDescriptor(clazzId)); 1431 pEvent->mods[idx].classOnly.refTypeId = clazzId; 1432 } 1433 break; 1434 case MK_CLASS_MATCH: /* restrict events to matching classes */ 1435 { 1436 char* pattern; 1437 size_t strLen; 1438 1439 pattern = readNewUtf8String(&buf, &strLen); 1440 LOGVV(" ClassMatch: '%s'", pattern); 1441 /* pattern is "java.foo.*", we want "java/foo/ *" */ 1442 pEvent->mods[idx].classMatch.classPattern = 1443 dvmDotToSlash(pattern); 1444 free(pattern); 1445 } 1446 break; 1447 case MK_CLASS_EXCLUDE: /* restrict events to non-matching classes */ 1448 { 1449 char* pattern; 1450 size_t strLen; 1451 1452 pattern = readNewUtf8String(&buf, &strLen); 1453 LOGVV(" ClassExclude: '%s'", pattern); 1454 pEvent->mods[idx].classExclude.classPattern = 1455 dvmDotToSlash(pattern); 1456 free(pattern); 1457 } 1458 break; 1459 case MK_LOCATION_ONLY: /* restrict certain events based on loc */ 1460 { 1461 JdwpLocation loc; 1462 1463 jdwpReadLocation(&buf, &loc); 1464 LOGVV(" LocationOnly: typeTag=%d classId=%llx methodId=%x idx=%llx", 1465 loc.typeTag, loc.classId, loc.methodId, loc.idx); 1466 pEvent->mods[idx].locationOnly.loc = loc; 1467 } 1468 break; 1469 case MK_EXCEPTION_ONLY: /* modifies EK_EXCEPTION events */ 1470 { 1471 RefTypeId exceptionOrNull; /* null == all exceptions */ 1472 u1 caught, uncaught; 1473 1474 exceptionOrNull = dvmReadRefTypeId(&buf); 1475 caught = read1(&buf); 1476 uncaught = read1(&buf); 1477 LOGVV(" ExceptionOnly: type=%llx(%s) caught=%d uncaught=%d", 1478 exceptionOrNull, (exceptionOrNull == 0) ? "null" 1479 : dvmDbgGetClassDescriptor(exceptionOrNull), 1480 caught, uncaught); 1481 1482 pEvent->mods[idx].exceptionOnly.refTypeId = exceptionOrNull; 1483 pEvent->mods[idx].exceptionOnly.caught = caught; 1484 pEvent->mods[idx].exceptionOnly.uncaught = uncaught; 1485 } 1486 break; 1487 case MK_FIELD_ONLY: /* for field access/mod events */ 1488 { 1489 RefTypeId declaring = dvmReadRefTypeId(&buf); 1490 FieldId fieldId = dvmReadFieldId(&buf); 1491 LOGVV(" FieldOnly: %llx %x", declaring, fieldId); 1492 pEvent->mods[idx].fieldOnly.refTypeId = declaring; 1493 pEvent->mods[idx].fieldOnly.fieldId = fieldId; 1494 } 1495 break; 1496 case MK_STEP: /* for use with EK_SINGLE_STEP */ 1497 { 1498 ObjectId threadId; 1499 u4 size, depth; 1500 1501 threadId = dvmReadObjectId(&buf); 1502 size = read4BE(&buf); 1503 depth = read4BE(&buf); 1504 LOGVV(" Step: thread=%llx size=%s depth=%s", 1505 threadId, dvmJdwpStepSizeStr(size), 1506 dvmJdwpStepDepthStr(depth)); 1507 1508 pEvent->mods[idx].step.threadId = threadId; 1509 pEvent->mods[idx].step.size = size; 1510 pEvent->mods[idx].step.depth = depth; 1511 } 1512 break; 1513 case MK_INSTANCE_ONLY: /* report events related to a specific obj */ 1514 { 1515 ObjectId instance = dvmReadObjectId(&buf); 1516 LOGVV(" InstanceOnly: %llx", instance); 1517 pEvent->mods[idx].instanceOnly.objectId = instance; 1518 } 1519 break; 1520 default: 1521 ALOGW("GLITCH: unsupported modKind=%d", modKind); 1522 break; 1523 } 1524 } 1525 1526 /* 1527 * Make sure we consumed all data. It is possible that the remote side 1528 * has sent us bad stuff, but for now we blame ourselves. 1529 */ 1530 if (buf != origBuf + dataLen) { 1531 ALOGW("GLITCH: dataLen is %d, we have consumed %d", dataLen, 1532 (int) (buf - origBuf)); 1533 } 1534 1535 /* 1536 * We reply with an integer "requestID". 1537 */ 1538 u4 requestId = dvmJdwpNextEventSerial(state); 1539 expandBufAdd4BE(pReply, requestId); 1540 1541 pEvent->requestId = requestId; 1542 1543 ALOGV(" --> event requestId=%#x", requestId); 1544 1545 /* add it to the list */ 1546 JdwpError err = dvmJdwpRegisterEvent(state, pEvent); 1547 if (err != ERR_NONE) { 1548 /* registration failed, probably because event is bogus */ 1549 dvmJdwpEventFree(pEvent); 1550 ALOGW("WARNING: event request rejected"); 1551 } 1552 return err; 1553 } 1554 1555 /* 1556 * Clear an event. Failure to find an event with a matching ID is a no-op 1557 * and does not return an error. 1558 */ 1559 static JdwpError handleER_Clear(JdwpState* state, 1560 const u1* buf, int dataLen, ExpandBuf* pReply) 1561 { 1562 u1 eventKind; 1563 eventKind = read1(&buf); 1564 u4 requestId = read4BE(&buf); 1565 1566 ALOGV(" Req to clear eventKind=%d requestId=%#x", eventKind, requestId); 1567 1568 dvmJdwpUnregisterEventById(state, requestId); 1569 1570 return ERR_NONE; 1571 } 1572 1573 /* 1574 * Return the values of arguments and local variables. 1575 */ 1576 static JdwpError handleSF_GetValues(JdwpState* state, 1577 const u1* buf, int dataLen, ExpandBuf* pReply) 1578 { 1579 ObjectId threadId = dvmReadObjectId(&buf); 1580 FrameId frameId = dvmReadFrameId(&buf); 1581 u4 slots = read4BE(&buf); 1582 1583 ALOGV(" Req for %d slots in threadId=%llx frameId=%llx", 1584 slots, threadId, frameId); 1585 1586 expandBufAdd4BE(pReply, slots); /* "int values" */ 1587 for (u4 i = 0; i < slots; i++) { 1588 u4 slot = read4BE(&buf); 1589 u1 reqSigByte = read1(&buf); 1590 1591 ALOGV(" --> slot %d '%c'", slot, reqSigByte); 1592 1593 int width = dvmDbgGetTagWidth(reqSigByte); 1594 u1* ptr = expandBufAddSpace(pReply, width+1); 1595 dvmDbgGetLocalValue(threadId, frameId, slot, reqSigByte, ptr, width); 1596 } 1597 1598 return ERR_NONE; 1599 } 1600 1601 /* 1602 * Set the values of arguments and local variables. 1603 */ 1604 static JdwpError handleSF_SetValues(JdwpState* state, 1605 const u1* buf, int dataLen, ExpandBuf* pReply) 1606 { 1607 ObjectId threadId = dvmReadObjectId(&buf); 1608 FrameId frameId = dvmReadFrameId(&buf); 1609 u4 slots = read4BE(&buf); 1610 1611 ALOGV(" Req to set %d slots in threadId=%llx frameId=%llx", 1612 slots, threadId, frameId); 1613 1614 for (u4 i = 0; i < slots; i++) { 1615 u4 slot = read4BE(&buf); 1616 u1 sigByte = read1(&buf); 1617 int width = dvmDbgGetTagWidth(sigByte); 1618 u8 value = jdwpReadValue(&buf, width); 1619 1620 ALOGV(" --> slot %d '%c' %llx", slot, sigByte, value); 1621 dvmDbgSetLocalValue(threadId, frameId, slot, sigByte, value, width); 1622 } 1623 1624 return ERR_NONE; 1625 } 1626 1627 /* 1628 * Returns the value of "this" for the specified frame. 1629 */ 1630 static JdwpError handleSF_ThisObject(JdwpState* state, 1631 const u1* buf, int dataLen, ExpandBuf* pReply) 1632 { 1633 ObjectId threadId = dvmReadObjectId(&buf); 1634 FrameId frameId = dvmReadFrameId(&buf); 1635 1636 ObjectId objectId; 1637 if (!dvmDbgGetThisObject(threadId, frameId, &objectId)) 1638 return ERR_INVALID_FRAMEID; 1639 1640 u1 objectTag = dvmDbgGetObjectTag(objectId); 1641 ALOGV(" Req for 'this' in thread=%llx frame=%llx --> %llx %s '%c'", 1642 threadId, frameId, objectId, dvmDbgGetObjectTypeName(objectId), 1643 (char)objectTag); 1644 1645 expandBufAdd1(pReply, objectTag); 1646 expandBufAddObjectId(pReply, objectId); 1647 1648 return ERR_NONE; 1649 } 1650 1651 /* 1652 * Return the reference type reflected by this class object. 1653 * 1654 * This appears to be required because ReferenceTypeId values are NEVER 1655 * reused, whereas ClassIds can be recycled like any other object. (Either 1656 * that, or I have no idea what this is for.) 1657 */ 1658 static JdwpError handleCOR_ReflectedType(JdwpState* state, 1659 const u1* buf, int dataLen, ExpandBuf* pReply) 1660 { 1661 RefTypeId classObjectId = dvmReadRefTypeId(&buf); 1662 1663 ALOGV(" Req for refTypeId for class=%llx (%s)", 1664 classObjectId, dvmDbgGetClassDescriptor(classObjectId)); 1665 1666 /* just hand the type back to them */ 1667 if (dvmDbgIsInterface(classObjectId)) 1668 expandBufAdd1(pReply, TT_INTERFACE); 1669 else 1670 expandBufAdd1(pReply, TT_CLASS); 1671 expandBufAddRefTypeId(pReply, classObjectId); 1672 1673 return ERR_NONE; 1674 } 1675 1676 /* 1677 * Handle a DDM packet with a single chunk in it. 1678 */ 1679 static JdwpError handleDDM_Chunk(JdwpState* state, 1680 const u1* buf, int dataLen, ExpandBuf* pReply) 1681 { 1682 u1* replyBuf = NULL; 1683 int replyLen = -1; 1684 1685 ALOGV(" Handling DDM packet (%.4s)", buf); 1686 1687 /* 1688 * On first DDM packet, notify all handlers that DDM is running. 1689 */ 1690 if (!state->ddmActive) { 1691 state->ddmActive = true; 1692 dvmDbgDdmConnected(); 1693 } 1694 1695 /* 1696 * If they want to send something back, we copy it into the buffer. 1697 * A no-copy approach would be nicer. 1698 * 1699 * TODO: consider altering the JDWP stuff to hold the packet header 1700 * in a separate buffer. That would allow us to writev() DDM traffic 1701 * instead of copying it into the expanding buffer. The reduction in 1702 * heap requirements is probably more valuable than the efficiency. 1703 */ 1704 if (dvmDbgDdmHandlePacket(buf, dataLen, &replyBuf, &replyLen)) { 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