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