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