JdwpHandler.cpp revision 60fc806b679a3655c228b4093058c59941a49cfe
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 */
44static 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 */
56void 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 */
67static 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 */
85static 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 */
102static 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    LOGV("    --> threadId=%llx objectId=%llx", threadId, objectId);
112    LOGV("        classId=%llx methodId=%x %s.%s",
113        classId, methodId,
114        dvmDbgGetClassDescriptor(classId),
115        dvmDbgGetMethodName(classId, methodId));
116    LOGV("        %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        LOGV("          '%c'(%d): 0x%llx", typeTag, width, value);
128        argArray[i] = value;
129    }
130
131    u4 options = read4BE(&buf);  /* enum InvokeOptions bit flags */
132    LOGV("        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        LOGV("  --> 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                LOGV("      string '%s'", str);
168                free(str);
169            } else {
170                LOGV("      string (null)");
171            }
172        }
173    }
174
175bail:
176    free(argArray);
177    return err;
178}
179
180
181/*
182 * Request for version info.
183 */
184static 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 */
209static 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    LOGV("  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        LOGV("    --> 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 */
258static 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 */
280static 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 */
304static 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 */
321static 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 */
333static 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 */
343static 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 */
353static JdwpError handleVM_Exit(JdwpState* state,
354    const u1* buf, int dataLen, ExpandBuf* pReply)
355{
356    u4 exitCode = get4BE(buf);
357
358    LOGW("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 */
370static 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    LOGV("  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 */
389static 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 */
405static 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 */
436static 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 */
445static 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 */
479static 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 */
513static JdwpError handleRT_Signature(JdwpState* state,
514    const u1* buf, int dataLen, ExpandBuf* pReply)
515{
516    RefTypeId refTypeId = dvmReadRefTypeId(&buf);
517
518    LOGV("  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 */
528static 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 */
542static 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    LOGV("  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 */
562static 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 */
579static 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 */
595static JdwpError handleRT_Interfaces(JdwpState* state,
596    const u1* buf, int dataLen, ExpandBuf* pReply)
597{
598    RefTypeId refTypeId = dvmReadRefTypeId(&buf);
599
600    LOGV("  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 */
611static 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    LOGV("  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 */
629static 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 */
639static 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    LOGV("  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        LOGW("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 */
663static 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 */
677static JdwpError handleRT_FieldsWithGeneric(JdwpState* state,
678    const u1* buf, int dataLen, ExpandBuf* pReply)
679{
680    RefTypeId refTypeId = dvmReadRefTypeId(&buf);
681    LOGV("  Req for fields in refTypeId=0x%llx", refTypeId);
682    LOGV("  --> '%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 */
693static JdwpError handleRT_MethodsWithGeneric(JdwpState* state,
694    const u1* buf, int dataLen, ExpandBuf* pReply)
695{
696    RefTypeId refTypeId = dvmReadRefTypeId(&buf);
697
698    LOGV("  Req for methods in refTypeId=0x%llx", refTypeId);
699    LOGV("  --> '%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 */
709static 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 */
724static 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    LOGV("  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        LOGV("    --> 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 */
751static 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 */
769static 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    LOGV("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 */
788static 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    LOGV("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 */
808static 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    LOGV("  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 */
826static 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    LOGV("  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 */
854static JdwpError handleOR_ReferenceType(JdwpState* state,
855    const u1* buf, int dataLen, ExpandBuf* pReply)
856{
857    ObjectId objectId = dvmReadObjectId(&buf);
858    LOGV("  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 */
873static 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    LOGV("  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 */
894static 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    LOGV("  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        LOGV("    --> 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 */
929static 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 */
944static 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 */
954static 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 */
964static JdwpError handleOR_IsCollected(JdwpState* state,
965    const u1* buf, int dataLen, ExpandBuf* pReply)
966{
967    ObjectId objectId;
968
969    objectId = dvmReadObjectId(&buf);
970    LOGV("  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 */
981static 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    LOGV("  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 */
998static JdwpError handleTR_Name(JdwpState* state,
999    const u1* buf, int dataLen, ExpandBuf* pReply)
1000{
1001    ObjectId threadId = dvmReadObjectId(&buf);
1002
1003    LOGV("  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 */
1020static 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        LOGI("  Warning: ignoring request to suspend self");
1027        return ERR_THREAD_NOT_SUSPENDED;
1028    }
1029    LOGV("  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 */
1039static 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        LOGI("  Warning: ignoring request to resume self");
1046        return ERR_NONE;
1047    }
1048    LOGV("  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 */
1058static JdwpError handleTR_Status(JdwpState* state,
1059    const u1* buf, int dataLen, ExpandBuf* pReply)
1060{
1061    ObjectId threadId = dvmReadObjectId(&buf);
1062
1063    LOGV("  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    LOGV("    --> %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 */
1082static 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 */
1100static 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        LOGV("  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    LOGV("  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 */
1148static 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        LOGV("  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 */
1172static 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 */
1191static 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 */
1207static JdwpError handleTGR_Name(JdwpState* state,
1208    const u1* buf, int dataLen, ExpandBuf* pReply)
1209{
1210    ObjectId threadGroupId = dvmReadObjectId(&buf);
1211    LOGV("  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        LOGW("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 */
1230static 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 */
1245static JdwpError handleTGR_Children(JdwpState* state,
1246    const u1* buf, int dataLen, ExpandBuf* pReply)
1247{
1248    ObjectId threadGroupId = dvmReadObjectId(&buf);
1249    LOGV("  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 */
1279static JdwpError handleAR_Length(JdwpState* state,
1280    const u1* buf, int dataLen, ExpandBuf* pReply)
1281{
1282    ObjectId arrayId = dvmReadObjectId(&buf);
1283    LOGV("  Req for length of array 0x%llx", arrayId);
1284
1285    u4 arrayLength = dvmDbgGetArrayLength(arrayId);
1286
1287    LOGV("    --> %d", arrayLength);
1288
1289    expandBufAdd4BE(pReply, arrayLength);
1290
1291    return ERR_NONE;
1292}
1293
1294/*
1295 * Return the values from an array.
1296 */
1297static 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    LOGV("  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 */
1320static 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    LOGV("  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 */
1340static 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 */
1370static 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            LOGW("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        LOGW("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    LOGV("    --> event requestId=0x%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        LOGW("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 */
1557static 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    LOGV("  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 */
1574static 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    LOGV("  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        LOGV("    --> 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 */
1602static 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    LOGV("  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        LOGV("    --> 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 */
1628static 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    LOGV("  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 */
1656static JdwpError handleCOR_ReflectedType(JdwpState* state,
1657    const u1* buf, int dataLen, ExpandBuf* pReply)
1658{
1659    RefTypeId classObjectId = dvmReadRefTypeId(&buf);
1660
1661    LOGV("  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 */
1677static JdwpError handleDDM_Chunk(JdwpState* state,
1678    const u1* buf, int dataLen, ExpandBuf* pReply)
1679{
1680    u1* replyBuf = NULL;
1681    int replyLen = -1;
1682
1683    LOGV("  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 */
1713typedef JdwpError (*JdwpRequestHandler)(JdwpState* state,
1714    const u1* buf, int dataLen, ExpandBuf* reply);
1715
1716struct 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 */
1729static 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 */
1876void 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            LOGV("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        LOGE("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_LOG(LOG_VERBOSE, LOG_TAG) {
1954        LOGV("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