OSDN Git Service

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