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