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