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