OSDN Git Service

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