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