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