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 LOGV(" --> threadId=%llx objectId=%llx", threadId, objectId); 112 LOGV(" classId=%llx methodId=%x %s.%s", 113 classId, methodId, 114 dvmDbgGetClassDescriptor(classId), 115 dvmDbgGetMethodName(classId, methodId)); 116 LOGV(" %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 LOGV(" '%c'(%d): 0x%llx", typeTag, width, value); 128 argArray[i] = value; 129 } 130 131 u4 options = read4BE(&buf); /* enum InvokeOptions bit flags */ 132 LOGV(" 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 LOGV(" --> 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 LOGV(" string '%s'", str); 168 free(str); 169 } else { 170 LOGV(" 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 LOGV(" 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 LOGV(" --> 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 LOGW("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 LOGV(" 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 LOGV(" 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 LOGV(" 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 LOGV(" 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 LOGV(" 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 LOGV(" 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 LOGW("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 LOGV(" Req for fields in refTypeId=0x%llx", refTypeId); 682 LOGV(" --> '%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 LOGV(" Req for methods in refTypeId=0x%llx", refTypeId); 699 LOGV(" --> '%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 LOGV(" 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 LOGV(" --> 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 LOGV("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 LOGV("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 LOGV(" 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 LOGV(" 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 LOGV(" 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 LOGV(" 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 LOGV(" 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 LOGV(" --> 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 LOGV(" 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 LOGV(" 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 LOGV(" 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 LOGI(" Warning: ignoring request to suspend self"); 1027 return ERR_THREAD_NOT_SUSPENDED; 1028 } 1029 LOGV(" 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 LOGI(" Warning: ignoring request to resume self"); 1046 return ERR_NONE; 1047 } 1048 LOGV(" 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 LOGV(" 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 LOGV(" --> %s, %s", dvmJdwpThreadStatusStr(threadStatus), 1071 dvmJdwpSuspendStatusStr(suspendStatus)); 1072 1073 expandBufAdd4BE(pReply, threadStatus); 1074 expandBufAdd4BE(pReply, suspendStatus); 1075 1076 return ERR_NONE; 1077 } 1078 1079 /* 1080 * Return the thread group that the specified thread is a member of. 1081 */ 1082 static JdwpError handleTR_ThreadGroup(JdwpState* state, 1083 const u1* buf, int dataLen, ExpandBuf* pReply) 1084 { 1085 ObjectId threadId = dvmReadObjectId(&buf); 1086 1087 /* currently not handling these */ 1088 ObjectId threadGroupId = dvmDbgGetThreadGroup(threadId); 1089 expandBufAddObjectId(pReply, threadGroupId); 1090 1091 return ERR_NONE; 1092 } 1093 1094 /* 1095 * Return the current call stack of a suspended thread. 1096 * 1097 * If the thread isn't suspended, the error code isn't defined, but should 1098 * be THREAD_NOT_SUSPENDED. 1099 */ 1100 static JdwpError handleTR_Frames(JdwpState* state, 1101 const u1* buf, int dataLen, ExpandBuf* pReply) 1102 { 1103 ObjectId threadId = dvmReadObjectId(&buf); 1104 u4 startFrame = read4BE(&buf); 1105 u4 length = read4BE(&buf); 1106 1107 if (!dvmDbgThreadExists(threadId)) 1108 return ERR_INVALID_THREAD; 1109 if (!dvmDbgIsSuspended(threadId)) { 1110 LOGV(" Rejecting req for frames in running thread '%s' (%llx)", 1111 dvmDbgGetThreadName(threadId), threadId); 1112 return ERR_THREAD_NOT_SUSPENDED; 1113 } 1114 1115 int frameCount = dvmDbgGetThreadFrameCount(threadId); 1116 1117 LOGV(" Request for frames: threadId=%llx start=%d length=%d [count=%d]", 1118 threadId, startFrame, length, frameCount); 1119 if (frameCount <= 0) 1120 return ERR_THREAD_NOT_SUSPENDED; /* == 0 means 100% native */ 1121 1122 if (length == (u4) -1) 1123 length = frameCount; 1124 assert((int) startFrame >= 0 && (int) startFrame < frameCount); 1125 assert((int) (startFrame + length) <= frameCount); 1126 1127 u4 frames = length; 1128 expandBufAdd4BE(pReply, frames); 1129 for (u4 i = startFrame; i < (startFrame+length); i++) { 1130 FrameId frameId; 1131 JdwpLocation loc; 1132 1133 dvmDbgGetThreadFrame(threadId, i, &frameId, &loc); 1134 1135 expandBufAdd8BE(pReply, frameId); 1136 dvmJdwpAddLocation(pReply, &loc); 1137 1138 LOGVV(" Frame %d: id=%llx loc={type=%d cls=%llx mth=%x loc=%llx}", 1139 i, frameId, loc.typeTag, loc.classId, loc.methodId, loc.idx); 1140 } 1141 1142 return ERR_NONE; 1143 } 1144 1145 /* 1146 * Returns the #of frames on the specified thread, which must be suspended. 1147 */ 1148 static JdwpError handleTR_FrameCount(JdwpState* state, 1149 const u1* buf, int dataLen, ExpandBuf* pReply) 1150 { 1151 ObjectId threadId = dvmReadObjectId(&buf); 1152 1153 if (!dvmDbgThreadExists(threadId)) 1154 return ERR_INVALID_THREAD; 1155 if (!dvmDbgIsSuspended(threadId)) { 1156 LOGV(" Rejecting req for frames in running thread '%s' (%llx)", 1157 dvmDbgGetThreadName(threadId), threadId); 1158 return ERR_THREAD_NOT_SUSPENDED; 1159 } 1160 1161 int frameCount = dvmDbgGetThreadFrameCount(threadId); 1162 if (frameCount < 0) 1163 return ERR_INVALID_THREAD; 1164 expandBufAdd4BE(pReply, (u4)frameCount); 1165 1166 return ERR_NONE; 1167 } 1168 1169 /* 1170 * Get the monitor that the thread is waiting on. 1171 */ 1172 static JdwpError handleTR_CurrentContendedMonitor(JdwpState* state, 1173 const u1* buf, int dataLen, ExpandBuf* pReply) 1174 { 1175 ObjectId threadId; 1176 1177 threadId = dvmReadObjectId(&buf); 1178 1179 // TODO: create an Object to represent the monitor (we're currently 1180 // just using a raw Monitor struct in the VM) 1181 1182 return ERR_NOT_IMPLEMENTED; 1183 } 1184 1185 /* 1186 * Return the suspend count for the specified thread. 1187 * 1188 * (The thread *might* still be running -- it might not have examined 1189 * its suspend count recently.) 1190 */ 1191 static JdwpError handleTR_SuspendCount(JdwpState* state, 1192 const u1* buf, int dataLen, ExpandBuf* pReply) 1193 { 1194 ObjectId threadId = dvmReadObjectId(&buf); 1195 1196 u4 suspendCount = dvmDbgGetThreadSuspendCount(threadId); 1197 expandBufAdd4BE(pReply, suspendCount); 1198 1199 return ERR_NONE; 1200 } 1201 1202 /* 1203 * Return the name of a thread group. 1204 * 1205 * The Eclipse debugger recognizes "main" and "system" as special. 1206 */ 1207 static JdwpError handleTGR_Name(JdwpState* state, 1208 const u1* buf, int dataLen, ExpandBuf* pReply) 1209 { 1210 ObjectId threadGroupId = dvmReadObjectId(&buf); 1211 LOGV(" Req for name of threadGroupId=0x%llx", threadGroupId); 1212 1213 char* name = dvmDbgGetThreadGroupName(threadGroupId); 1214 if (name != NULL) 1215 expandBufAddUtf8String(pReply, (u1*) name); 1216 else { 1217 expandBufAddUtf8String(pReply, (u1*) "BAD-GROUP-ID"); 1218 LOGW("bad thread group ID"); 1219 } 1220 1221 free(name); 1222 1223 return ERR_NONE; 1224 } 1225 1226 /* 1227 * Returns the thread group -- if any -- that contains the specified 1228 * thread group. 1229 */ 1230 static JdwpError handleTGR_Parent(JdwpState* state, 1231 const u1* buf, int dataLen, ExpandBuf* pReply) 1232 { 1233 ObjectId groupId = dvmReadObjectId(&buf); 1234 1235 ObjectId parentGroup = dvmDbgGetThreadGroupParent(groupId); 1236 expandBufAddObjectId(pReply, parentGroup); 1237 1238 return ERR_NONE; 1239 } 1240 1241 /* 1242 * Return the active threads and thread groups that are part of the 1243 * specified thread group. 1244 */ 1245 static JdwpError handleTGR_Children(JdwpState* state, 1246 const u1* buf, int dataLen, ExpandBuf* pReply) 1247 { 1248 ObjectId threadGroupId = dvmReadObjectId(&buf); 1249 LOGV(" Req for threads in threadGroupId=0x%llx", threadGroupId); 1250 1251 ObjectId* pThreadIds; 1252 u4 threadCount; 1253 dvmDbgGetThreadGroupThreads(threadGroupId, &pThreadIds, &threadCount); 1254 1255 expandBufAdd4BE(pReply, threadCount); 1256 1257 for (u4 i = 0; i < threadCount; i++) 1258 expandBufAddObjectId(pReply, pThreadIds[i]); 1259 free(pThreadIds); 1260 1261 /* 1262 * TODO: finish support for child groups 1263 * 1264 * For now, just show that "main" is a child of "system". 1265 */ 1266 if (threadGroupId == dvmDbgGetSystemThreadGroupId()) { 1267 expandBufAdd4BE(pReply, 1); 1268 expandBufAddObjectId(pReply, dvmDbgGetMainThreadGroupId()); 1269 } else { 1270 expandBufAdd4BE(pReply, 0); 1271 } 1272 1273 return ERR_NONE; 1274 } 1275 1276 /* 1277 * Return the #of components in the array. 1278 */ 1279 static JdwpError handleAR_Length(JdwpState* state, 1280 const u1* buf, int dataLen, ExpandBuf* pReply) 1281 { 1282 ObjectId arrayId = dvmReadObjectId(&buf); 1283 LOGV(" Req for length of array 0x%llx", arrayId); 1284 1285 u4 arrayLength = dvmDbgGetArrayLength(arrayId); 1286 1287 LOGV(" --> %d", arrayLength); 1288 1289 expandBufAdd4BE(pReply, arrayLength); 1290 1291 return ERR_NONE; 1292 } 1293 1294 /* 1295 * Return the values from an array. 1296 */ 1297 static JdwpError handleAR_GetValues(JdwpState* state, 1298 const u1* buf, int dataLen, ExpandBuf* pReply) 1299 { 1300 ObjectId arrayId = dvmReadObjectId(&buf); 1301 u4 firstIndex = read4BE(&buf); 1302 u4 length = read4BE(&buf); 1303 1304 u1 tag = dvmDbgGetArrayElementTag(arrayId); 1305 LOGV(" Req for array values 0x%llx first=%d len=%d (elem tag=%c)", 1306 arrayId, firstIndex, length, tag); 1307 1308 expandBufAdd1(pReply, tag); 1309 expandBufAdd4BE(pReply, length); 1310 1311 if (!dvmDbgOutputArray(arrayId, firstIndex, length, pReply)) 1312 return ERR_INVALID_LENGTH; 1313 1314 return ERR_NONE; 1315 } 1316 1317 /* 1318 * Set values in an array. 1319 */ 1320 static JdwpError handleAR_SetValues(JdwpState* state, 1321 const u1* buf, int dataLen, ExpandBuf* pReply) 1322 { 1323 ObjectId arrayId = dvmReadObjectId(&buf); 1324 u4 firstIndex = read4BE(&buf); 1325 u4 values = read4BE(&buf); 1326 1327 LOGV(" Req to set array values 0x%llx first=%d count=%d", 1328 arrayId, firstIndex, values); 1329 1330 if (!dvmDbgSetArrayElements(arrayId, firstIndex, values, buf)) 1331 return ERR_INVALID_LENGTH; 1332 1333 return ERR_NONE; 1334 } 1335 1336 /* 1337 * Return the set of classes visible to a class loader. All classes which 1338 * have the class loader as a defining or initiating loader are returned. 1339 */ 1340 static JdwpError handleCLR_VisibleClasses(JdwpState* state, 1341 const u1* buf, int dataLen, ExpandBuf* pReply) 1342 { 1343 ObjectId classLoaderObject; 1344 u4 numClasses = 0; 1345 RefTypeId* classRefBuf = NULL; 1346 int i; 1347 1348 classLoaderObject = dvmReadObjectId(&buf); 1349 1350 dvmDbgGetVisibleClassList(classLoaderObject, &numClasses, &classRefBuf); 1351 1352 expandBufAdd4BE(pReply, numClasses); 1353 for (i = 0; i < (int) numClasses; i++) { 1354 u1 refTypeTag; 1355 1356 refTypeTag = dvmDbgGetClassObjectType(classRefBuf[i]); 1357 1358 expandBufAdd1(pReply, refTypeTag); 1359 expandBufAddRefTypeId(pReply, classRefBuf[i]); 1360 } 1361 1362 return ERR_NONE; 1363 } 1364 1365 /* 1366 * Set an event trigger. 1367 * 1368 * Reply with a requestID. 1369 */ 1370 static JdwpError handleER_Set(JdwpState* state, 1371 const u1* buf, int dataLen, ExpandBuf* pReply) 1372 { 1373 const u1* origBuf = buf; 1374 1375 u1 eventKind = read1(&buf); 1376 u1 suspendPolicy = read1(&buf); 1377 u4 modifierCount = read4BE(&buf); 1378 1379 LOGVV(" Set(kind=%s(%u) suspend=%s(%u) mods=%u)", 1380 dvmJdwpEventKindStr(eventKind), eventKind, 1381 dvmJdwpSuspendPolicyStr(suspendPolicy), suspendPolicy, 1382 modifierCount); 1383 1384 assert(modifierCount < 256); /* reasonableness check */ 1385 1386 JdwpEvent* pEvent = dvmJdwpEventAlloc(modifierCount); 1387 pEvent->eventKind = static_cast<JdwpEventKind>(eventKind); 1388 pEvent->suspendPolicy = static_cast<JdwpSuspendPolicy>(suspendPolicy); 1389 pEvent->modCount = modifierCount; 1390 1391 /* 1392 * Read modifiers. Ordering may be significant (see explanation of Count 1393 * mods in JDWP doc). 1394 */ 1395 for (u4 idx = 0; idx < modifierCount; idx++) { 1396 u1 modKind = read1(&buf); 1397 1398 pEvent->mods[idx].modKind = modKind; 1399 1400 switch (modKind) { 1401 case MK_COUNT: /* report once, when "--count" reaches 0 */ 1402 { 1403 u4 count = read4BE(&buf); 1404 LOGVV(" Count: %u", count); 1405 if (count == 0) 1406 return ERR_INVALID_COUNT; 1407 pEvent->mods[idx].count.count = count; 1408 } 1409 break; 1410 case MK_CONDITIONAL: /* conditional on expression) */ 1411 { 1412 u4 exprId = read4BE(&buf); 1413 LOGVV(" Conditional: %d", exprId); 1414 pEvent->mods[idx].conditional.exprId = exprId; 1415 } 1416 break; 1417 case MK_THREAD_ONLY: /* only report events in specified thread */ 1418 { 1419 ObjectId threadId = dvmReadObjectId(&buf); 1420 LOGVV(" ThreadOnly: %llx", threadId); 1421 pEvent->mods[idx].threadOnly.threadId = threadId; 1422 } 1423 break; 1424 case MK_CLASS_ONLY: /* for ClassPrepare, MethodEntry */ 1425 { 1426 RefTypeId clazzId = dvmReadRefTypeId(&buf); 1427 LOGVV(" ClassOnly: %llx (%s)", 1428 clazzId, dvmDbgGetClassDescriptor(clazzId)); 1429 pEvent->mods[idx].classOnly.refTypeId = clazzId; 1430 } 1431 break; 1432 case MK_CLASS_MATCH: /* restrict events to matching classes */ 1433 { 1434 char* pattern; 1435 size_t strLen; 1436 1437 pattern = readNewUtf8String(&buf, &strLen); 1438 LOGVV(" ClassMatch: '%s'", pattern); 1439 /* pattern is "java.foo.*", we want "java/foo/ *" */ 1440 pEvent->mods[idx].classMatch.classPattern = 1441 dvmDotToSlash(pattern); 1442 free(pattern); 1443 } 1444 break; 1445 case MK_CLASS_EXCLUDE: /* restrict events to non-matching classes */ 1446 { 1447 char* pattern; 1448 size_t strLen; 1449 1450 pattern = readNewUtf8String(&buf, &strLen); 1451 LOGVV(" ClassExclude: '%s'", pattern); 1452 pEvent->mods[idx].classExclude.classPattern = 1453 dvmDotToSlash(pattern); 1454 free(pattern); 1455 } 1456 break; 1457 case MK_LOCATION_ONLY: /* restrict certain events based on loc */ 1458 { 1459 JdwpLocation loc; 1460 1461 jdwpReadLocation(&buf, &loc); 1462 LOGVV(" LocationOnly: typeTag=%d classId=%llx methodId=%x idx=%llx", 1463 loc.typeTag, loc.classId, loc.methodId, loc.idx); 1464 pEvent->mods[idx].locationOnly.loc = loc; 1465 } 1466 break; 1467 case MK_EXCEPTION_ONLY: /* modifies EK_EXCEPTION events */ 1468 { 1469 RefTypeId exceptionOrNull; /* null == all exceptions */ 1470 u1 caught, uncaught; 1471 1472 exceptionOrNull = dvmReadRefTypeId(&buf); 1473 caught = read1(&buf); 1474 uncaught = read1(&buf); 1475 LOGVV(" ExceptionOnly: type=%llx(%s) caught=%d uncaught=%d", 1476 exceptionOrNull, (exceptionOrNull == 0) ? "null" 1477 : dvmDbgGetClassDescriptor(exceptionOrNull), 1478 caught, uncaught); 1479 1480 pEvent->mods[idx].exceptionOnly.refTypeId = exceptionOrNull; 1481 pEvent->mods[idx].exceptionOnly.caught = caught; 1482 pEvent->mods[idx].exceptionOnly.uncaught = uncaught; 1483 } 1484 break; 1485 case MK_FIELD_ONLY: /* for field access/mod events */ 1486 { 1487 RefTypeId declaring = dvmReadRefTypeId(&buf); 1488 FieldId fieldId = dvmReadFieldId(&buf); 1489 LOGVV(" FieldOnly: %llx %x", declaring, fieldId); 1490 pEvent->mods[idx].fieldOnly.refTypeId = declaring; 1491 pEvent->mods[idx].fieldOnly.fieldId = fieldId; 1492 } 1493 break; 1494 case MK_STEP: /* for use with EK_SINGLE_STEP */ 1495 { 1496 ObjectId threadId; 1497 u4 size, depth; 1498 1499 threadId = dvmReadObjectId(&buf); 1500 size = read4BE(&buf); 1501 depth = read4BE(&buf); 1502 LOGVV(" Step: thread=%llx size=%s depth=%s", 1503 threadId, dvmJdwpStepSizeStr(size), 1504 dvmJdwpStepDepthStr(depth)); 1505 1506 pEvent->mods[idx].step.threadId = threadId; 1507 pEvent->mods[idx].step.size = size; 1508 pEvent->mods[idx].step.depth = depth; 1509 } 1510 break; 1511 case MK_INSTANCE_ONLY: /* report events related to a specific obj */ 1512 { 1513 ObjectId instance = dvmReadObjectId(&buf); 1514 LOGVV(" InstanceOnly: %llx", instance); 1515 pEvent->mods[idx].instanceOnly.objectId = instance; 1516 } 1517 break; 1518 default: 1519 LOGW("GLITCH: unsupported modKind=%d", modKind); 1520 break; 1521 } 1522 } 1523 1524 /* 1525 * Make sure we consumed all data. It is possible that the remote side 1526 * has sent us bad stuff, but for now we blame ourselves. 1527 */ 1528 if (buf != origBuf + dataLen) { 1529 LOGW("GLITCH: dataLen is %d, we have consumed %d", dataLen, 1530 (int) (buf - origBuf)); 1531 } 1532 1533 /* 1534 * We reply with an integer "requestID". 1535 */ 1536 u4 requestId = dvmJdwpNextEventSerial(state); 1537 expandBufAdd4BE(pReply, requestId); 1538 1539 pEvent->requestId = requestId; 1540 1541 LOGV(" --> event requestId=%#x", requestId); 1542 1543 /* add it to the list */ 1544 JdwpError err = dvmJdwpRegisterEvent(state, pEvent); 1545 if (err != ERR_NONE) { 1546 /* registration failed, probably because event is bogus */ 1547 dvmJdwpEventFree(pEvent); 1548 LOGW("WARNING: event request rejected"); 1549 } 1550 return err; 1551 } 1552 1553 /* 1554 * Clear an event. Failure to find an event with a matching ID is a no-op 1555 * and does not return an error. 1556 */ 1557 static JdwpError handleER_Clear(JdwpState* state, 1558 const u1* buf, int dataLen, ExpandBuf* pReply) 1559 { 1560 u1 eventKind; 1561 eventKind = read1(&buf); 1562 u4 requestId = read4BE(&buf); 1563 1564 LOGV(" Req to clear eventKind=%d requestId=%#x", eventKind, requestId); 1565 1566 dvmJdwpUnregisterEventById(state, requestId); 1567 1568 return ERR_NONE; 1569 } 1570 1571 /* 1572 * Return the values of arguments and local variables. 1573 */ 1574 static JdwpError handleSF_GetValues(JdwpState* state, 1575 const u1* buf, int dataLen, ExpandBuf* pReply) 1576 { 1577 ObjectId threadId = dvmReadObjectId(&buf); 1578 FrameId frameId = dvmReadFrameId(&buf); 1579 u4 slots = read4BE(&buf); 1580 1581 LOGV(" Req for %d slots in threadId=%llx frameId=%llx", 1582 slots, threadId, frameId); 1583 1584 expandBufAdd4BE(pReply, slots); /* "int values" */ 1585 for (u4 i = 0; i < slots; i++) { 1586 u4 slot = read4BE(&buf); 1587 u1 reqSigByte = read1(&buf); 1588 1589 LOGV(" --> slot %d '%c'", slot, reqSigByte); 1590 1591 int width = dvmDbgGetTagWidth(reqSigByte); 1592 u1* ptr = expandBufAddSpace(pReply, width+1); 1593 dvmDbgGetLocalValue(threadId, frameId, slot, reqSigByte, ptr, width); 1594 } 1595 1596 return ERR_NONE; 1597 } 1598 1599 /* 1600 * Set the values of arguments and local variables. 1601 */ 1602 static JdwpError handleSF_SetValues(JdwpState* state, 1603 const u1* buf, int dataLen, ExpandBuf* pReply) 1604 { 1605 ObjectId threadId = dvmReadObjectId(&buf); 1606 FrameId frameId = dvmReadFrameId(&buf); 1607 u4 slots = read4BE(&buf); 1608 1609 LOGV(" Req to set %d slots in threadId=%llx frameId=%llx", 1610 slots, threadId, frameId); 1611 1612 for (u4 i = 0; i < slots; i++) { 1613 u4 slot = read4BE(&buf); 1614 u1 sigByte = read1(&buf); 1615 int width = dvmDbgGetTagWidth(sigByte); 1616 u8 value = jdwpReadValue(&buf, width); 1617 1618 LOGV(" --> slot %d '%c' %llx", slot, sigByte, value); 1619 dvmDbgSetLocalValue(threadId, frameId, slot, sigByte, value, width); 1620 } 1621 1622 return ERR_NONE; 1623 } 1624 1625 /* 1626 * Returns the value of "this" for the specified frame. 1627 */ 1628 static JdwpError handleSF_ThisObject(JdwpState* state, 1629 const u1* buf, int dataLen, ExpandBuf* pReply) 1630 { 1631 ObjectId threadId = dvmReadObjectId(&buf); 1632 FrameId frameId = dvmReadFrameId(&buf); 1633 1634 ObjectId objectId; 1635 if (!dvmDbgGetThisObject(threadId, frameId, &objectId)) 1636 return ERR_INVALID_FRAMEID; 1637 1638 u1 objectTag = dvmDbgGetObjectTag(objectId); 1639 LOGV(" Req for 'this' in thread=%llx frame=%llx --> %llx %s '%c'", 1640 threadId, frameId, objectId, dvmDbgGetObjectTypeName(objectId), 1641 (char)objectTag); 1642 1643 expandBufAdd1(pReply, objectTag); 1644 expandBufAddObjectId(pReply, objectId); 1645 1646 return ERR_NONE; 1647 } 1648 1649 /* 1650 * Return the reference type reflected by this class object. 1651 * 1652 * This appears to be required because ReferenceTypeId values are NEVER 1653 * reused, whereas ClassIds can be recycled like any other object. (Either 1654 * that, or I have no idea what this is for.) 1655 */ 1656 static JdwpError handleCOR_ReflectedType(JdwpState* state, 1657 const u1* buf, int dataLen, ExpandBuf* pReply) 1658 { 1659 RefTypeId classObjectId = dvmReadRefTypeId(&buf); 1660 1661 LOGV(" Req for refTypeId for class=%llx (%s)", 1662 classObjectId, dvmDbgGetClassDescriptor(classObjectId)); 1663 1664 /* just hand the type back to them */ 1665 if (dvmDbgIsInterface(classObjectId)) 1666 expandBufAdd1(pReply, TT_INTERFACE); 1667 else 1668 expandBufAdd1(pReply, TT_CLASS); 1669 expandBufAddRefTypeId(pReply, classObjectId); 1670 1671 return ERR_NONE; 1672 } 1673 1674 /* 1675 * Handle a DDM packet with a single chunk in it. 1676 */ 1677 static JdwpError handleDDM_Chunk(JdwpState* state, 1678 const u1* buf, int dataLen, ExpandBuf* pReply) 1679 { 1680 u1* replyBuf = NULL; 1681 int replyLen = -1; 1682 1683 LOGV(" Handling DDM packet (%.4s)", buf); 1684 1685 /* 1686 * On first DDM packet, notify all handlers that DDM is running. 1687 */ 1688 if (!state->ddmActive) { 1689 state->ddmActive = true; 1690 dvmDbgDdmConnected(); 1691 } 1692 1693 /* 1694 * If they want to send something back, we copy it into the buffer. 1695 * A no-copy approach would be nicer. 1696 * 1697 * TODO: consider altering the JDWP stuff to hold the packet header 1698 * in a separate buffer. That would allow us to writev() DDM traffic 1699 * instead of copying it into the expanding buffer. The reduction in 1700 * heap requirements is probably more valuable than the efficiency. 1701 */ 1702 if (dvmDbgDdmHandlePacket(buf, dataLen, &replyBuf, &replyLen)) { 1703 assert(replyLen > 0 && replyLen < 1*1024*1024); 1704 memcpy(expandBufAddSpace(pReply, replyLen), replyBuf, replyLen); 1705 free(replyBuf); 1706 } 1707 return ERR_NONE; 1708 } 1709 1710 /* 1711 * Handler map decl. 1712 */ 1713 typedef JdwpError (*JdwpRequestHandler)(JdwpState* state, 1714 const u1* buf, int dataLen, ExpandBuf* reply); 1715 1716 struct JdwpHandlerMap { 1717 u1 cmdSet; 1718 u1 cmd; 1719 JdwpRequestHandler func; 1720 const char* descr; 1721 }; 1722 1723 /* 1724 * Map commands to functions. 1725 * 1726 * Command sets 0-63 are incoming requests, 64-127 are outbound requests, 1727 * and 128-256 are vendor-defined. 1728 */ 1729 static const JdwpHandlerMap gHandlerMap[] = { 1730 /* VirtualMachine command set (1) */ 1731 { 1, 1, handleVM_Version, "VirtualMachine.Version" }, 1732 { 1, 2, handleVM_ClassesBySignature, 1733 "VirtualMachine.ClassesBySignature" }, 1734 //1, 3, VirtualMachine.AllClasses 1735 { 1, 4, handleVM_AllThreads, "VirtualMachine.AllThreads" }, 1736 { 1, 5, handleVM_TopLevelThreadGroups, 1737 "VirtualMachine.TopLevelThreadGroups" }, 1738 { 1, 6, handleVM_Dispose, "VirtualMachine.Dispose" }, 1739 { 1, 7, handleVM_IDSizes, "VirtualMachine.IDSizes" }, 1740 { 1, 8, handleVM_Suspend, "VirtualMachine.Suspend" }, 1741 { 1, 9, handleVM_Resume, "VirtualMachine.Resume" }, 1742 { 1, 10, handleVM_Exit, "VirtualMachine.Exit" }, 1743 { 1, 11, handleVM_CreateString, "VirtualMachine.CreateString" }, 1744 { 1, 12, handleVM_Capabilities, "VirtualMachine.Capabilities" }, 1745 { 1, 13, handleVM_ClassPaths, "VirtualMachine.ClassPaths" }, 1746 { 1, 14, HandleVM_DisposeObjects, "VirtualMachine.DisposeObjects" }, 1747 //1, 15, HoldEvents 1748 //1, 16, ReleaseEvents 1749 { 1, 17, handleVM_CapabilitiesNew, 1750 "VirtualMachine.CapabilitiesNew" }, 1751 //1, 18, RedefineClasses 1752 //1, 19, SetDefaultStratum 1753 { 1, 20, handleVM_AllClassesWithGeneric, 1754 "VirtualMachine.AllClassesWithGeneric"}, 1755 //1, 21, InstanceCounts 1756 1757 /* ReferenceType command set (2) */ 1758 { 2, 1, handleRT_Signature, "ReferenceType.Signature" }, 1759 { 2, 2, handleRT_ClassLoader, "ReferenceType.ClassLoader" }, 1760 { 2, 3, handleRT_Modifiers, "ReferenceType.Modifiers" }, 1761 //2, 4, Fields 1762 //2, 5, Methods 1763 { 2, 6, handleRT_GetValues, "ReferenceType.GetValues" }, 1764 { 2, 7, handleRT_SourceFile, "ReferenceType.SourceFile" }, 1765 //2, 8, NestedTypes 1766 { 2, 9, handleRT_Status, "ReferenceType.Status" }, 1767 { 2, 10, handleRT_Interfaces, "ReferenceType.Interfaces" }, 1768 { 2, 11, handleRT_ClassObject, "ReferenceType.ClassObject" }, 1769 { 2, 12, handleRT_SourceDebugExtension, 1770 "ReferenceType.SourceDebugExtension" }, 1771 { 2, 13, handleRT_SignatureWithGeneric, 1772 "ReferenceType.SignatureWithGeneric" }, 1773 { 2, 14, handleRT_FieldsWithGeneric, 1774 "ReferenceType.FieldsWithGeneric" }, 1775 { 2, 15, handleRT_MethodsWithGeneric, 1776 "ReferenceType.MethodsWithGeneric" }, 1777 //2, 16, Instances 1778 //2, 17, ClassFileVersion 1779 //2, 18, ConstantPool 1780 1781 /* ClassType command set (3) */ 1782 { 3, 1, handleCT_Superclass, "ClassType.Superclass" }, 1783 { 3, 2, handleCT_SetValues, "ClassType.SetValues" }, 1784 { 3, 3, handleCT_InvokeMethod, "ClassType.InvokeMethod" }, 1785 { 3, 4, handleCT_NewInstance, "ClassType.NewInstance" }, 1786 1787 /* ArrayType command set (4) */ 1788 { 4, 1, handleAT_newInstance, "ArrayType.NewInstance" }, 1789 1790 /* InterfaceType command set (5) */ 1791 1792 /* Method command set (6) */ 1793 { 6, 1, handleM_LineTable, "Method.LineTable" }, 1794 //6, 2, VariableTable 1795 //6, 3, Bytecodes 1796 //6, 4, IsObsolete 1797 { 6, 5, handleM_VariableTableWithGeneric, 1798 "Method.VariableTableWithGeneric" }, 1799 1800 /* Field command set (8) */ 1801 1802 /* ObjectReference command set (9) */ 1803 { 9, 1, handleOR_ReferenceType, "ObjectReference.ReferenceType" }, 1804 { 9, 2, handleOR_GetValues, "ObjectReference.GetValues" }, 1805 { 9, 3, handleOR_SetValues, "ObjectReference.SetValues" }, 1806 //9, 4, (not defined) 1807 //9, 5, MonitorInfo 1808 { 9, 6, handleOR_InvokeMethod, "ObjectReference.InvokeMethod" }, 1809 { 9, 7, handleOR_DisableCollection, 1810 "ObjectReference.DisableCollection" }, 1811 { 9, 8, handleOR_EnableCollection, 1812 "ObjectReference.EnableCollection" }, 1813 { 9, 9, handleOR_IsCollected, "ObjectReference.IsCollected" }, 1814 //9, 10, ReferringObjects 1815 1816 /* StringReference command set (10) */ 1817 { 10, 1, handleSR_Value, "StringReference.Value" }, 1818 1819 /* ThreadReference command set (11) */ 1820 { 11, 1, handleTR_Name, "ThreadReference.Name" }, 1821 { 11, 2, handleTR_Suspend, "ThreadReference.Suspend" }, 1822 { 11, 3, handleTR_Resume, "ThreadReference.Resume" }, 1823 { 11, 4, handleTR_Status, "ThreadReference.Status" }, 1824 { 11, 5, handleTR_ThreadGroup, "ThreadReference.ThreadGroup" }, 1825 { 11, 6, handleTR_Frames, "ThreadReference.Frames" }, 1826 { 11, 7, handleTR_FrameCount, "ThreadReference.FrameCount" }, 1827 //11, 8, OwnedMonitors 1828 { 11, 9, handleTR_CurrentContendedMonitor, 1829 "ThreadReference.CurrentContendedMonitor" }, 1830 //11, 10, Stop 1831 //11, 11, Interrupt 1832 { 11, 12, handleTR_SuspendCount, "ThreadReference.SuspendCount" }, 1833 //11, 13, OwnedMonitorsStackDepthInfo 1834 //11, 14, ForceEarlyReturn 1835 1836 /* ThreadGroupReference command set (12) */ 1837 { 12, 1, handleTGR_Name, "ThreadGroupReference.Name" }, 1838 { 12, 2, handleTGR_Parent, "ThreadGroupReference.Parent" }, 1839 { 12, 3, handleTGR_Children, "ThreadGroupReference.Children" }, 1840 1841 /* ArrayReference command set (13) */ 1842 { 13, 1, handleAR_Length, "ArrayReference.Length" }, 1843 { 13, 2, handleAR_GetValues, "ArrayReference.GetValues" }, 1844 { 13, 3, handleAR_SetValues, "ArrayReference.SetValues" }, 1845 1846 /* ClassLoaderReference command set (14) */ 1847 { 14, 1, handleCLR_VisibleClasses, 1848 "ClassLoaderReference.VisibleClasses" }, 1849 1850 /* EventRequest command set (15) */ 1851 { 15, 1, handleER_Set, "EventRequest.Set" }, 1852 { 15, 2, handleER_Clear, "EventRequest.Clear" }, 1853 //15, 3, ClearAllBreakpoints 1854 1855 /* StackFrame command set (16) */ 1856 { 16, 1, handleSF_GetValues, "StackFrame.GetValues" }, 1857 { 16, 2, handleSF_SetValues, "StackFrame.SetValues" }, 1858 { 16, 3, handleSF_ThisObject, "StackFrame.ThisObject" }, 1859 //16, 4, PopFrames 1860 1861 /* ClassObjectReference command set (17) */ 1862 { 17, 1, handleCOR_ReflectedType,"ClassObjectReference.ReflectedType" }, 1863 1864 /* Event command set (64) */ 1865 //64, 100, Composite <-- sent from VM to debugger, never received by VM 1866 1867 { 199, 1, handleDDM_Chunk, "DDM.Chunk" }, 1868 }; 1869 1870 1871 /* 1872 * Process a request from the debugger. 1873 * 1874 * On entry, the JDWP thread is in VMWAIT. 1875 */ 1876 void dvmJdwpProcessRequest(JdwpState* state, const JdwpReqHeader* pHeader, 1877 const u1* buf, int dataLen, ExpandBuf* pReply) 1878 { 1879 JdwpError result = ERR_NONE; 1880 int i, respLen; 1881 1882 if (pHeader->cmdSet != kJDWPDdmCmdSet) { 1883 /* 1884 * Activity from a debugger, not merely ddms. Mark us as having an 1885 * active debugger session, and zero out the last-activity timestamp 1886 * so waitForDebugger() doesn't return if we stall for a bit here. 1887 */ 1888 dvmDbgActive(); 1889 dvmQuasiAtomicSwap64(0, &state->lastActivityWhen); 1890 } 1891 1892 /* 1893 * If a debugger event has fired in another thread, wait until the 1894 * initiating thread has suspended itself before processing messages 1895 * from the debugger. Otherwise we (the JDWP thread) could be told to 1896 * resume the thread before it has suspended. 1897 * 1898 * We call with an argument of zero to wait for the current event 1899 * thread to finish, and then clear the block. Depending on the thread 1900 * suspend policy, this may allow events in other threads to fire, 1901 * but those events have no bearing on what the debugger has sent us 1902 * in the current request. 1903 * 1904 * Note that we MUST clear the event token before waking the event 1905 * thread up, or risk waiting for the thread to suspend after we've 1906 * told it to resume. 1907 */ 1908 dvmJdwpSetWaitForEventThread(state, 0); 1909 1910 /* 1911 * Tell the VM that we're running and shouldn't be interrupted by GC. 1912 * Do this after anything that can stall indefinitely. 1913 */ 1914 dvmDbgThreadRunning(); 1915 1916 expandBufAddSpace(pReply, kJDWPHeaderLen); 1917 1918 for (i = 0; i < (int) NELEM(gHandlerMap); i++) { 1919 if (gHandlerMap[i].cmdSet == pHeader->cmdSet && 1920 gHandlerMap[i].cmd == pHeader->cmd) 1921 { 1922 LOGV("REQ: %s (cmd=%d/%d dataLen=%d id=0x%06x)", 1923 gHandlerMap[i].descr, pHeader->cmdSet, pHeader->cmd, 1924 dataLen, pHeader->id); 1925 result = (*gHandlerMap[i].func)(state, buf, dataLen, pReply); 1926 break; 1927 } 1928 } 1929 if (i == NELEM(gHandlerMap)) { 1930 LOGE("REQ: UNSUPPORTED (cmd=%d/%d dataLen=%d id=0x%06x)", 1931 pHeader->cmdSet, pHeader->cmd, dataLen, pHeader->id); 1932 if (dataLen > 0) 1933 dvmPrintHexDumpDbg(buf, dataLen, LOG_TAG); 1934 assert(!"command not implemented"); // make it *really* obvious 1935 result = ERR_NOT_IMPLEMENTED; 1936 } 1937 1938 /* 1939 * Set up the reply header. 1940 * 1941 * If we encountered an error, only send the header back. 1942 */ 1943 u1* replyBuf = expandBufGetBuffer(pReply); 1944 set4BE(replyBuf + 4, pHeader->id); 1945 set1(replyBuf + 8, kJDWPFlagReply); 1946 set2BE(replyBuf + 9, result); 1947 if (result == ERR_NONE) 1948 set4BE(replyBuf + 0, expandBufGetLength(pReply)); 1949 else 1950 set4BE(replyBuf + 0, kJDWPHeaderLen); 1951 1952 respLen = expandBufGetLength(pReply) - kJDWPHeaderLen; 1953 IF_LOG(LOG_VERBOSE, LOG_TAG) { 1954 LOGV("reply: dataLen=%d err=%s(%d)%s", respLen, 1955 dvmJdwpErrorStr(result), result, 1956 result != ERR_NONE ? " **FAILED**" : ""); 1957 if (respLen > 0) 1958 dvmPrintHexDumpDbg(expandBufGetBuffer(pReply) + kJDWPHeaderLen, 1959 respLen, LOG_TAG); 1960 } 1961 1962 /* 1963 * Update last-activity timestamp. We really only need this during 1964 * the initial setup. Only update if this is a non-DDMS packet. 1965 */ 1966 if (pHeader->cmdSet != kJDWPDdmCmdSet) { 1967 dvmQuasiAtomicSwap64(dvmJdwpGetNowMsec(), &state->lastActivityWhen); 1968 } 1969 1970 /* tell the VM that GC is okay again */ 1971 dvmDbgThreadWaiting(); 1972 } 1973