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