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