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