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