2 * Copyright (C) 2008 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 * Handle messages from debugger.
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.
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"
42 static void showTime(const char* label)
47 gettimeofday(&tv, NULL);
48 min = (tv.tv_sec / 60) % 60;
50 msec = tv.tv_usec / 1000;
52 LOGI("%02d:%02d.%03d %s\n", min, sec, msec, label);
57 * Helper function: read a "location" from an input buffer.
59 static void jdwpReadLocation(const u1** pBuf, JdwpLocation* pLoc)
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);
69 * Helper function: write a "location" into the reply buffer.
71 void dvmJdwpAddLocation(ExpandBuf* pReply, const JdwpLocation* pLoc)
73 expandBufAdd1(pReply, pLoc->typeTag);
74 expandBufAddObjectId(pReply, pLoc->classId);
75 expandBufAddMethodId(pReply, pLoc->methodId);
76 expandBufAdd8BE(pReply, pLoc->idx);
80 * Helper function: read a variable-width value from the input buffer.
82 static u8 jdwpReadValue(const u1** pBuf, int 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;
98 * Helper function: write a variable-width value into the output input buffer.
100 static void jdwpWriteValue(ExpandBuf* pReply, int width, u8 value)
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;
112 * Common code for *_InvokeMethod requests.
114 static JdwpError finishInvoke(JdwpState* state,
115 const u1* buf, int dataLen, ExpandBuf* pReply,
116 ObjectId threadId, ObjectId objectId, RefTypeId classId, MethodId methodId)
118 JdwpError err = ERR_NONE;
121 u4 options; /* enum InvokeOptions bit flags */
124 numArgs = read4BE(&buf);
126 LOGV(" --> threadId=%llx objectId=%llx\n", threadId, objectId);
127 LOGV(" classId=%llx methodId=%x %s.%s\n",
129 dvmDbgGetClassDescriptor(classId),
130 dvmDbgGetMethodName(classId, methodId));
131 LOGV(" %d args:\n", numArgs);
134 argArray = (ObjectId*) malloc(sizeof(ObjectId) * numArgs);
136 for (i = 0; i < (int) numArgs; i++) {
141 typeTag = read1(&buf);
142 width = dvmDbgGetTagWidth(typeTag);
143 value = jdwpReadValue(&buf, width);
145 LOGV(" '%c'(%d): 0x%llx\n", typeTag, width, value);
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)" : "");
157 ObjectId exceptObjId;
159 err = dvmDbgInvokeMethod(threadId, objectId, classId, methodId,
160 numArgs, argArray, options,
161 &resultTag, &resultValue, &exceptObjId);
165 if (err == ERR_NONE) {
166 int width = dvmDbgGetTagWidth(resultTag);
168 expandBufAdd1(pReply, resultTag);
170 jdwpWriteValue(pReply, width, resultValue);
171 expandBufAdd1(pReply, JT_OBJECT);
172 expandBufAddObjectId(pReply, exceptObjId);
174 LOGV(" --> returned '%c' 0x%llx (except=%08llx)\n",
175 resultTag, resultValue, exceptObjId);
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);
184 LOGV(" string (null)\n");
196 * Request for version info.
198 static JdwpError handleVM_Version(JdwpState* state, const u1* buf,
199 int dataLen, ExpandBuf* pReply)
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
207 expandBufAddUtf8String(pReply, (const u1*) "1.5.0"); /* e.g. 1.5.0_04 */
209 expandBufAddUtf8String(pReply, (const u1*) "DalvikVM");
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.
219 static JdwpError handleVM_ClassesBySignature(JdwpState* state,
220 const u1* buf, int dataLen, ExpandBuf* pReply)
222 char* classDescriptor = NULL;
228 classDescriptor = readNewUtf8String(&buf, &strLen);
229 LOGV(" Req for class by signature '%s'\n", classDescriptor);
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.
235 * NOTE: this may mangle "className".
237 if (!dvmDbgFindLoadedClassBySignature(classDescriptor, &refTypeId)) {
238 /* not currently loaded */
239 LOGV(" --> no match!\n");
246 expandBufAdd4BE(pReply, numClasses);
248 if (numClasses > 0) {
252 /* get class vs. interface and status flags */
253 dvmDbgGetClassInfo(refTypeId, &typeTag, &status, NULL);
255 expandBufAdd1(pReply, typeTag);
256 expandBufAddRefTypeId(pReply, refTypeId);
257 expandBufAdd4BE(pReply, status);
260 free(classDescriptor);
266 * Handle request for the thread IDs of all running threads.
268 * We exclude ourselves from the list, because we don't allow ourselves
269 * to be suspended, and that violates some JDWP expectations.
271 static JdwpError handleVM_AllThreads(JdwpState* state,
272 const u1* buf, int dataLen, ExpandBuf* pReply)
275 ObjectId* pThreadIds;
279 dvmDbgGetAllThreads(&pThreadIds, &threadCount);
281 expandBufAdd4BE(pReply, threadCount);
284 for (i = 0; i < (int) threadCount; i++) {
285 expandBufAddObjectId(pReply, *walker++);
294 * List all thread groups that do not have a parent.
296 static JdwpError handleVM_TopLevelThreadGroups(JdwpState* state,
297 const u1* buf, int dataLen, ExpandBuf* pReply)
300 ObjectId threadGroupId;
303 * TODO: maintain a list of parentless thread groups in the VM.
305 * For now, just return "system". Application threads are created
306 * in "main", which is a child of "system".
309 expandBufAdd4BE(pReply, groups);
310 //threadGroupId = debugGetMainThreadGroup();
311 //expandBufAdd8BE(pReply, threadGroupId);
312 threadGroupId = dvmDbgGetSystemThreadGroupId();
313 expandBufAddObjectId(pReply, threadGroupId);
319 * Respond with the sizes of the basic debugger types.
321 * All IDs are 8 bytes.
323 static JdwpError handleVM_IDSizes(JdwpState* state,
324 const u1* buf, int dataLen, ExpandBuf* pReply)
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));
335 * The debugger is politely asking to disconnect. We're good with that.
337 * We could resume threads and clean up pinned references, but we can do
338 * that when the TCP connection drops.
340 static JdwpError handleVM_Dispose(JdwpState* state,
341 const u1* buf, int dataLen, ExpandBuf* pReply)
347 * Suspend the execution of the application running in the VM (i.e. suspend
350 * This needs to increment the "suspend count" on all threads.
352 static JdwpError handleVM_Suspend(JdwpState* state,
353 const u1* buf, int dataLen, ExpandBuf* pReply)
355 dvmDbgSuspendVM(false);
360 * Resume execution. Decrements the "suspend count" of all threads.
362 static JdwpError handleVM_Resume(JdwpState* state,
363 const u1* buf, int dataLen, ExpandBuf* pReply)
370 * The debugger wants the entire VM to exit.
372 static JdwpError handleVM_Exit(JdwpState* state,
373 const u1* buf, int dataLen, ExpandBuf* pReply)
377 exitCode = get4BE(buf);
379 LOGW("Debugger is telling the VM to exit with code=%d\n", exitCode);
381 dvmDbgExit(exitCode);
382 return ERR_NOT_IMPLEMENTED; // shouldn't get here
386 * Create a new string in the VM and return its ID.
388 * (Ctrl-Shift-I in Eclipse on an array of objects causes it to create the
389 * string "java.util.Arrays".)
391 static JdwpError handleVM_CreateString(JdwpState* state,
392 const u1* buf, int dataLen, ExpandBuf* pReply)
398 str = readNewUtf8String(&buf, &strLen);
400 LOGV(" Req to create string '%s'\n", str);
402 stringId = dvmDbgCreateString(str);
403 expandBufAddObjectId(pReply, stringId);
409 * Tell the debugger what we are capable of.
411 static JdwpError handleVM_Capabilities(JdwpState* state,
412 const u1* buf, int dataLen, ExpandBuf* pReply)
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 */
427 * Return classpath and bootclasspath.
429 static JdwpError handleVM_ClassPaths(JdwpState* state,
430 const u1* buf, int dataLen, ExpandBuf* pReply)
432 char baseDir[2] = "/";
438 * TODO: make this real. Not important for remote debugging, but
439 * might be useful for local debugging.
444 expandBufAddUtf8String(pReply, (const u1*) baseDir);
445 expandBufAdd4BE(pReply, classPaths);
446 for (i = 0; i < (int) classPaths; i++) {
447 expandBufAddUtf8String(pReply, (const u1*) ".");
450 expandBufAdd4BE(pReply, bootClassPaths);
451 for (i = 0; i < (int) classPaths; i++) {
452 /* add bootclasspath components as strings */
459 * Release a list of object IDs. (Seen in jdb.)
461 * Currently does nothing.
463 static JdwpError HandleVM_DisposeObjects(JdwpState* state,
464 const u1* buf, int dataLen, ExpandBuf* pReply)
470 * Tell the debugger what we are capable of.
472 static JdwpError handleVM_CapabilitiesNew(JdwpState* state,
473 const u1* buf, int dataLen, ExpandBuf* pReply)
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 */
499 /* fill in reserved22 through reserved32; note count started at 1 */
500 for (i = 22; i <= 32; i++)
501 expandBufAdd1(pReply, false); /* reservedN */
506 * Cough up the complete list of classes.
508 static JdwpError handleVM_AllClassesWithGeneric(JdwpState* state,
509 const u1* buf, int dataLen, ExpandBuf* pReply)
512 RefTypeId* classRefBuf = NULL;
515 dvmDbgGetClassList(&numClasses, &classRefBuf);
517 expandBufAdd4BE(pReply, numClasses);
519 for (i = 0; i < (int) numClasses; i++) {
520 static const u1 genericSignature[1] = "";
525 dvmDbgGetClassInfo(classRefBuf[i], &refTypeTag, &status, &signature);
527 expandBufAdd1(pReply, refTypeTag);
528 expandBufAddRefTypeId(pReply, classRefBuf[i]);
529 expandBufAddUtf8String(pReply, (const u1*) signature);
530 expandBufAddUtf8String(pReply, genericSignature);
531 expandBufAdd4BE(pReply, status);
542 * Given a referenceTypeID, return a string with the JNI reference type
543 * signature (e.g. "Ljava/lang/Error;").
545 static JdwpError handleRT_Signature(JdwpState* state,
546 const u1* buf, int dataLen, ExpandBuf* pReply)
551 refTypeId = dvmReadRefTypeId(&buf);
553 LOGV(" Req for signature of refTypeId=0x%llx\n", refTypeId);
554 signature = dvmDbgGetSignature(refTypeId);
555 expandBufAddUtf8String(pReply, (const u1*) signature);
562 * Return the modifiers (a/k/a access flags) for a reference type.
564 static JdwpError handleRT_Modifiers(JdwpState* state,
565 const u1* buf, int dataLen, ExpandBuf* pReply)
570 refTypeId = dvmReadRefTypeId(&buf);
571 modBits = dvmDbgGetAccessFlags(refTypeId);
573 expandBufAdd4BE(pReply, modBits);
579 * Get values from static fields in a reference type.
581 static JdwpError handleRT_GetValues(JdwpState* state,
582 const u1* buf, int dataLen, ExpandBuf* pReply)
588 refTypeId = dvmReadRefTypeId(&buf);
589 numFields = read4BE(&buf);
591 expandBufAdd4BE(pReply, numFields);
592 for (i = 0; i < (int) numFields; i++) {
598 fieldId = dvmReadFieldId(&buf);
599 fieldTag = dvmDbgGetFieldTag(refTypeId, fieldId);
600 width = dvmDbgGetTagWidth(fieldTag);
602 expandBufAdd1(pReply, fieldTag);
603 ptr = expandBufAddSpace(pReply, width);
604 dvmDbgGetStaticFieldValue(refTypeId, fieldId, ptr, width);
611 * Get the name of the source file in which a reference type was declared.
613 static JdwpError handleRT_SourceFile(JdwpState* state,
614 const u1* buf, int dataLen, ExpandBuf* pReply)
617 const char* fileName;
619 refTypeId = dvmReadRefTypeId(&buf);
621 fileName = dvmDbgGetSourceFile(refTypeId);
622 if (fileName != NULL) {
623 expandBufAddUtf8String(pReply, (const u1*) fileName);
626 return ERR_ABSENT_INFORMATION;
631 * Return the current status of the reference type.
633 static JdwpError handleRT_Status(JdwpState* state,
634 const u1* buf, int dataLen, ExpandBuf* pReply)
640 refTypeId = dvmReadRefTypeId(&buf);
642 /* get status flags */
643 dvmDbgGetClassInfo(refTypeId, &typeTag, &status, NULL);
644 expandBufAdd4BE(pReply, status);
649 * Return interfaces implemented directly by this class.
651 static JdwpError handleRT_Interfaces(JdwpState* state,
652 const u1* buf, int dataLen, ExpandBuf* pReply)
658 refTypeId = dvmReadRefTypeId(&buf);
660 LOGV(" Req for interfaces in %llx (%s)\n", refTypeId,
661 dvmDbgGetClassDescriptor(refTypeId));
663 dvmDbgOutputAllInterfaces(refTypeId, pReply);
669 * Returns the value of the SourceDebugExtension attribute.
671 * JDB seems interested, but DEX files don't currently support this.
673 static JdwpError handleRT_SourceDebugExtension(JdwpState* state,
674 const u1* buf, int dataLen, ExpandBuf* pReply)
676 /* referenceTypeId in, string out */
677 return ERR_ABSENT_INFORMATION;
681 * Like RT_Signature but with the possibility of a "generic signature".
683 static JdwpError handleRT_SignatureWithGeneric(JdwpState* state,
684 const u1* buf, int dataLen, ExpandBuf* pReply)
686 static const u1 genericSignature[1] = "";
690 refTypeId = dvmReadRefTypeId(&buf);
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);
697 expandBufAddUtf8String(pReply, (const u1*) "Lunknown;"); /* native? */
698 expandBufAddUtf8String(pReply, genericSignature);
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.
708 static JdwpError handleRT_ClassLoader(JdwpState* state,
709 const u1* buf, int dataLen, ExpandBuf* pReply)
712 ObjectId classLoaderId;
714 refTypeId = dvmReadRefTypeId(&buf);
716 expandBufAddObjectId(pReply, dvmDbgGetClassLoader(refTypeId));
722 * Given a referenceTypeId, return a block of stuff that describes the
723 * fields declared by a class.
725 static JdwpError handleRT_FieldsWithGeneric(JdwpState* state,
726 const u1* buf, int dataLen, ExpandBuf* pReply)
731 refTypeId = dvmReadRefTypeId(&buf);
732 LOGV(" Req for fields in refTypeId=0x%llx\n", refTypeId);
734 char* tmp = dvmDbgGetSignature(refTypeId);
735 LOGV(" --> '%s'\n", tmp);
739 dvmDbgOutputAllFields(refTypeId, true, pReply);
745 * Given a referenceTypeID, return a block of goodies describing the
746 * methods declared by a class.
748 static JdwpError handleRT_MethodsWithGeneric(JdwpState* state,
749 const u1* buf, int dataLen, ExpandBuf* pReply)
754 refTypeId = dvmReadRefTypeId(&buf);
756 LOGV(" Req for methods in refTypeId=0x%llx\n", refTypeId);
758 char* tmp = dvmDbgGetSignature(refTypeId);
759 LOGV(" --> '%s'\n", tmp);
763 dvmDbgOutputAllMethods(refTypeId, true, pReply);
769 * Return the immediate superclass of a class.
771 static JdwpError handleCT_Superclass(JdwpState* state,
772 const u1* buf, int dataLen, ExpandBuf* pReply)
775 RefTypeId superClassId;
777 classId = dvmReadRefTypeId(&buf);
779 superClassId = dvmDbgGetSuperclass(classId);
781 expandBufAddRefTypeId(pReply, superClassId);
787 * Set static class values.
789 static JdwpError handleCT_SetValues(JdwpState* state,
790 const u1* buf, int dataLen, ExpandBuf* pReply)
796 classId = dvmReadRefTypeId(&buf);
797 values = read4BE(&buf);
799 LOGV(" Req to set %d values in classId=%llx\n", values, classId);
801 for (i = 0; i < (int) values; i++) {
807 fieldId = dvmReadFieldId(&buf);
808 fieldTag = dvmDbgGetStaticFieldTag(classId, fieldId);
809 width = dvmDbgGetTagWidth(fieldTag);
810 value = jdwpReadValue(&buf, width);
812 LOGV(" --> field=%x tag=%c -> %lld\n", fieldId, fieldTag, value);
813 dvmDbgSetStaticFieldValue(classId, fieldId, value, width);
820 * Invoke a static method.
822 * Example: Eclipse sometimes uses java/lang/Class.forName(String s) on
823 * values in the "variables" display.
825 static JdwpError handleCT_InvokeMethod(JdwpState* state,
826 const u1* buf, int dataLen, ExpandBuf* pReply)
832 classId = dvmReadRefTypeId(&buf);
833 threadId = dvmReadObjectId(&buf);
834 methodId = dvmReadMethodId(&buf);
836 return finishInvoke(state, buf, dataLen, pReply,
837 threadId, 0, classId, methodId);
841 * Return line number information for the method, if present.
843 static JdwpError handleM_LineTable(JdwpState* state,
844 const u1* buf, int dataLen, ExpandBuf* pReply)
849 refTypeId = dvmReadRefTypeId(&buf);
850 methodId = dvmReadMethodId(&buf);
852 LOGV(" Req for line table in %s.%s\n",
853 dvmDbgGetClassDescriptor(refTypeId),
854 dvmDbgGetMethodName(refTypeId,methodId));
856 dvmDbgOutputLineTable(refTypeId, methodId, pReply);
862 * Pull out the LocalVariableTable goodies.
864 static JdwpError handleM_VariableTableWithGeneric(JdwpState* state,
865 const u1* buf, int dataLen, ExpandBuf* pReply)
870 classId = dvmReadRefTypeId(&buf);
871 methodId = dvmReadMethodId(&buf);
873 LOGV(" Req for LocalVarTab in class=%s method=%s\n",
874 dvmDbgGetClassDescriptor(classId),
875 dvmDbgGetMethodName(classId, methodId));
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.
884 dvmDbgOutputVariableTable(classId, methodId, true, pReply);
889 * Given an object reference, return the runtime type of the object
892 * This can get called on different things, e.g. threadId gets
895 static JdwpError handleOR_ReferenceType(JdwpState* state,
896 const u1* buf, int dataLen, ExpandBuf* pReply)
902 objectId = dvmReadObjectId(&buf);
903 LOGV(" Req for type of objectId=0x%llx\n", objectId);
905 dvmDbgGetObjectType(objectId, &refTypeTag, &typeId);
907 expandBufAdd1(pReply, refTypeTag);
908 expandBufAddRefTypeId(pReply, typeId);
914 * Get values from the fields of an object.
916 static JdwpError handleOR_GetValues(JdwpState* state,
917 const u1* buf, int dataLen, ExpandBuf* pReply)
923 objectId = dvmReadObjectId(&buf);
924 numFields = read4BE(&buf);
926 LOGV(" Req for %d fields from objectId=0x%llx\n", numFields, objectId);
928 expandBufAdd4BE(pReply, numFields);
930 for (i = 0; i < (int) numFields; i++) {
935 const char* fieldName;
937 fieldId = dvmReadFieldId(&buf);
939 fieldTag = dvmDbgGetFieldTag(objectId, fieldId);
940 width = dvmDbgGetTagWidth(fieldTag);
942 LOGV(" --> fieldId %x --> tag '%c'(%d)\n",
943 fieldId, fieldTag, width);
945 expandBufAdd1(pReply, fieldTag);
946 ptr = expandBufAddSpace(pReply, width);
947 dvmDbgGetFieldValue(objectId, fieldId, ptr, width);
954 * Set values in the fields of an object.
956 static JdwpError handleOR_SetValues(JdwpState* state,
957 const u1* buf, int dataLen, ExpandBuf* pReply)
963 objectId = dvmReadObjectId(&buf);
964 numFields = read4BE(&buf);
966 LOGV(" Req to set %d fields in objectId=0x%llx\n", numFields, objectId);
968 for (i = 0; i < (int) numFields; i++) {
974 fieldId = dvmReadFieldId(&buf);
976 fieldTag = dvmDbgGetFieldTag(objectId, fieldId);
977 width = dvmDbgGetTagWidth(fieldTag);
978 value = jdwpReadValue(&buf, width);
980 LOGV(" --> fieldId=%x tag='%c'(%d) value=%lld\n",
981 fieldId, fieldTag, width, value);
983 dvmDbgSetFieldValue(objectId, fieldId, value, width);
990 * Invoke an instance method. The invocation must occur in the specified
991 * thread, which must have been suspended by an event.
993 * The call is synchronous. All threads in the VM are resumed, unless the
994 * SINGLE_THREADED flag is set.
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.
1000 static JdwpError handleOR_InvokeMethod(JdwpState* state,
1001 const u1* buf, int dataLen, ExpandBuf* pReply)
1008 objectId = dvmReadObjectId(&buf);
1009 threadId = dvmReadObjectId(&buf);
1010 classId = dvmReadRefTypeId(&buf);
1011 methodId = dvmReadMethodId(&buf);
1013 return finishInvoke(state, buf, dataLen, pReply,
1014 threadId, objectId, classId, methodId);
1018 * Disable garbage collection of the specified object.
1020 static JdwpError handleOR_DisableCollection(JdwpState* state,
1021 const u1* buf, int dataLen, ExpandBuf* pReply)
1023 // this is currently a no-op
1028 * Enable garbage collection of the specified object.
1030 static JdwpError handleOR_EnableCollection(JdwpState* state,
1031 const u1* buf, int dataLen, ExpandBuf* pReply)
1033 // this is currently a no-op
1038 * Determine whether an object has been garbage collected.
1040 static JdwpError handleOR_IsCollected(JdwpState* state,
1041 const u1* buf, int dataLen, ExpandBuf* pReply)
1045 objectId = dvmReadObjectId(&buf);
1047 LOGV(" Req IsCollected(0x%llx)\n", objectId);
1049 // TODO: currently returning false; must integrate with GC
1050 expandBufAdd1(pReply, 0);
1056 * Return the string value in a string object.
1058 static JdwpError handleSR_Value(JdwpState* state,
1059 const u1* buf, int dataLen, ExpandBuf* pReply)
1061 ObjectId stringObject;
1064 stringObject = dvmReadObjectId(&buf);
1065 str = dvmDbgStringToUtf8(stringObject);
1067 LOGV(" Req for str %llx --> '%s'\n", stringObject, str);
1069 expandBufAddUtf8String(pReply, (u1*) str);
1076 * Return a thread's name.
1078 static JdwpError handleTR_Name(JdwpState* state,
1079 const u1* buf, int dataLen, ExpandBuf* pReply)
1084 threadId = dvmReadObjectId(&buf);
1086 LOGV(" Req for name of thread 0x%llx\n", threadId);
1087 name = dvmDbgGetThreadName(threadId);
1089 return ERR_INVALID_THREAD;
1091 expandBufAddUtf8String(pReply, (u1*) name);
1098 * Suspend the specified thread.
1100 * It's supposed to remain suspended even if interpreted code wants to
1101 * resume it; only the JDI is allowed to resume it.
1103 static JdwpError handleTR_Suspend(JdwpState* state,
1104 const u1* buf, int dataLen, ExpandBuf* pReply)
1108 threadId = dvmReadObjectId(&buf);
1110 if (threadId == dvmDbgGetThreadSelfId()) {
1111 LOGI(" Warning: ignoring request to suspend self\n");
1112 return ERR_THREAD_NOT_SUSPENDED;
1114 LOGV(" Req to suspend thread 0x%llx\n", threadId);
1116 dvmDbgSuspendThread(threadId);
1122 * Resume the specified thread.
1124 static JdwpError handleTR_Resume(JdwpState* state,
1125 const u1* buf, int dataLen, ExpandBuf* pReply)
1129 threadId = dvmReadObjectId(&buf);
1131 if (threadId == dvmDbgGetThreadSelfId()) {
1132 LOGI(" Warning: ignoring request to resume self\n");
1135 LOGV(" Req to resume thread 0x%llx\n", threadId);
1137 dvmDbgResumeThread(threadId);
1143 * Return status of specified thread.
1145 static JdwpError handleTR_Status(JdwpState* state,
1146 const u1* buf, int dataLen, ExpandBuf* pReply)
1152 threadId = dvmReadObjectId(&buf);
1154 LOGV(" Req for status of thread 0x%llx\n", threadId);
1156 if (!dvmDbgGetThreadStatus(threadId, &threadStatus, &suspendStatus))
1157 return ERR_INVALID_THREAD;
1159 LOGV(" --> %s, %s\n", dvmJdwpThreadStatusStr(threadStatus),
1160 dvmJdwpSuspendStatusStr(suspendStatus));
1162 expandBufAdd4BE(pReply, threadStatus);
1163 expandBufAdd4BE(pReply, suspendStatus);
1169 * Return the thread group that the specified thread is a member of.
1171 static JdwpError handleTR_ThreadGroup(JdwpState* state,
1172 const u1* buf, int dataLen, ExpandBuf* pReply)
1175 ObjectId threadGroupId;
1177 threadId = dvmReadObjectId(&buf);
1179 /* currently not handling these */
1180 threadGroupId = dvmDbgGetThreadGroup(threadId);
1181 expandBufAddObjectId(pReply, threadGroupId);
1187 * Return the current call stack of a suspended thread.
1189 * If the thread isn't suspended, the error code isn't defined, but should
1190 * be THREAD_NOT_SUSPENDED.
1192 static JdwpError handleTR_Frames(JdwpState* state,
1193 const u1* buf, int dataLen, ExpandBuf* pReply)
1196 u4 startFrame, length, frames;
1199 threadId = dvmReadObjectId(&buf);
1200 startFrame = read4BE(&buf);
1201 length = read4BE(&buf);
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;
1211 frameCount = dvmDbgGetThreadFrameCount(threadId);
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 */
1218 if (length == (u4) -1)
1219 length = frameCount;
1220 assert((int) startFrame >= 0 && (int) startFrame < frameCount);
1221 assert((int) (startFrame + length) <= frameCount);
1224 expandBufAdd4BE(pReply, frames);
1225 for (i = startFrame; i < (int) (startFrame+length); i++) {
1229 dvmDbgGetThreadFrame(threadId, i, &frameId, &loc);
1231 expandBufAdd8BE(pReply, frameId);
1232 dvmJdwpAddLocation(pReply, &loc);
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);
1242 * Returns the #of frames on the specified thread, which must be suspended.
1244 static JdwpError handleTR_FrameCount(JdwpState* state,
1245 const u1* buf, int dataLen, ExpandBuf* pReply)
1250 threadId = dvmReadObjectId(&buf);
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;
1260 frameCount = dvmDbgGetThreadFrameCount(threadId);
1262 return ERR_INVALID_THREAD;
1263 expandBufAdd4BE(pReply, (u4)frameCount);
1269 * Get the monitor that the thread is waiting on.
1271 static JdwpError handleTR_CurrentContendedMonitor(JdwpState* state,
1272 const u1* buf, int dataLen, ExpandBuf* pReply)
1276 threadId = dvmReadObjectId(&buf);
1278 // TODO: create an Object to represent the monitor (we're currently
1279 // just using a raw Monitor struct in the VM)
1281 return ERR_NOT_IMPLEMENTED;
1285 * Return the suspend count for the specified thread.
1287 * (The thread *might* still be running -- it might not have examined
1288 * its suspend count recently.)
1290 static JdwpError handleTR_SuspendCount(JdwpState* state,
1291 const u1* buf, int dataLen, ExpandBuf* pReply)
1296 threadId = dvmReadObjectId(&buf);
1298 suspendCount = dvmDbgGetThreadSuspendCount(threadId);
1299 expandBufAdd4BE(pReply, suspendCount);
1305 * Return the name of a thread group.
1307 * The Eclipse debugger recognizes "main" and "system" as special.
1309 static JdwpError handleTGR_Name(JdwpState* state,
1310 const u1* buf, int dataLen, ExpandBuf* pReply)
1312 ObjectId threadGroupId;
1315 threadGroupId = dvmReadObjectId(&buf);
1316 LOGV(" Req for name of threadGroupId=0x%llx\n", threadGroupId);
1318 name = dvmDbgGetThreadGroupName(threadGroupId);
1320 expandBufAddUtf8String(pReply, (u1*) name);
1322 expandBufAddUtf8String(pReply, (u1*) "BAD-GROUP-ID");
1323 LOGW("bad thread group ID\n");
1332 * Returns the thread group -- if any -- that contains the specified
1335 static JdwpError handleTGR_Parent(JdwpState* state,
1336 const u1* buf, int dataLen, ExpandBuf* pReply)
1339 ObjectId parentGroup;
1341 groupId = dvmReadObjectId(&buf);
1343 parentGroup = dvmDbgGetThreadGroupParent(groupId);
1344 expandBufAddObjectId(pReply, parentGroup);
1350 * Return the active threads and thread groups that are part of the
1351 * specified thread group.
1353 static JdwpError handleTGR_Children(JdwpState* state,
1354 const u1* buf, int dataLen, ExpandBuf* pReply)
1356 ObjectId threadGroupId;
1359 ObjectId* pThreadIds;
1363 threadGroupId = dvmReadObjectId(&buf);
1364 LOGV(" Req for threads in threadGroupId=0x%llx\n", threadGroupId);
1366 dvmDbgGetThreadGroupThreads(threadGroupId, &pThreadIds, &threadCount);
1368 expandBufAdd4BE(pReply, threadCount);
1370 walker = pThreadIds;
1371 for (i = 0; i < (int) threadCount; i++)
1372 expandBufAddObjectId(pReply, pThreadIds[i]);
1376 * TODO: finish support for child groups
1378 * For now, just show that "main" is a child of "system".
1380 if (threadGroupId == dvmDbgGetSystemThreadGroupId()) {
1381 expandBufAdd4BE(pReply, 1);
1382 expandBufAddObjectId(pReply, dvmDbgGetMainThreadGroupId());
1384 expandBufAdd4BE(pReply, 0);
1391 * Return the #of components in the array.
1393 static JdwpError handleAR_Length(JdwpState* state,
1394 const u1* buf, int dataLen, ExpandBuf* pReply)
1399 arrayId = dvmReadObjectId(&buf);
1400 LOGV(" Req for length of array 0x%llx\n", arrayId);
1402 arrayLength = dvmDbgGetArrayLength(arrayId);
1404 LOGV(" --> %d\n", arrayLength);
1406 expandBufAdd4BE(pReply, arrayLength);
1412 * Return the values from an array.
1414 static JdwpError handleAR_GetValues(JdwpState* state,
1415 const u1* buf, int dataLen, ExpandBuf* pReply)
1422 arrayId = dvmReadObjectId(&buf);
1423 firstIndex = read4BE(&buf);
1424 length = read4BE(&buf);
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);
1430 expandBufAdd1(pReply, tag);
1431 expandBufAdd4BE(pReply, length);
1433 if (!dvmDbgOutputArray(arrayId, firstIndex, length, pReply))
1434 return ERR_INVALID_LENGTH;
1440 * Set values in an array.
1442 static JdwpError handleAR_SetValues(JdwpState* state,
1443 const u1* buf, int dataLen, ExpandBuf* pReply)
1451 arrayId = dvmReadObjectId(&buf);
1452 firstIndex = read4BE(&buf);
1453 values = read4BE(&buf);
1455 LOGV(" Req to set array values 0x%llx first=%d count=%d\n",
1456 arrayId, firstIndex, values);
1458 if (!dvmDbgSetArrayElements(arrayId, firstIndex, values, buf))
1459 return ERR_INVALID_LENGTH;
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.
1468 static JdwpError handleCLR_VisibleClasses(JdwpState* state,
1469 const u1* buf, int dataLen, ExpandBuf* pReply)
1471 ObjectId classLoaderObject;
1473 RefTypeId* classRefBuf = NULL;
1476 classLoaderObject = dvmReadObjectId(&buf);
1478 dvmDbgGetVisibleClassList(classLoaderObject, &numClasses, &classRefBuf);
1480 expandBufAdd4BE(pReply, numClasses);
1481 for (i = 0; i < (int) numClasses; i++) {
1484 refTypeTag = dvmDbgGetClassObjectType(classRefBuf[i]);
1486 expandBufAdd1(pReply, refTypeTag);
1487 expandBufAddRefTypeId(pReply, classRefBuf[i]);
1494 * Set an event trigger.
1496 * Reply with a requestID.
1498 static JdwpError handleER_Set(JdwpState* state,
1499 const u1* buf, int dataLen, ExpandBuf* pReply)
1503 const u1* origBuf = buf;
1504 /*int origDataLen = dataLen;*/
1511 eventKind = read1(&buf);
1512 suspendPolicy = read1(&buf);
1513 modifierCount = read4BE(&buf);
1515 LOGVV(" Set(kind=%s(%u) suspend=%s(%u) mods=%u)\n",
1516 dvmJdwpEventKindStr(eventKind), eventKind,
1517 dvmJdwpSuspendPolicyStr(suspendPolicy), suspendPolicy,
1520 assert(modifierCount < 256); /* reasonableness check */
1522 pEvent = dvmJdwpEventAlloc(modifierCount);
1523 pEvent->eventKind = eventKind;
1524 pEvent->suspendPolicy = suspendPolicy;
1525 pEvent->modCount = modifierCount;
1528 * Read modifiers. Ordering may be significant (see explanation of Count
1529 * mods in JDWP doc).
1531 for (idx = 0; idx < (int) modifierCount; idx++) {
1534 modKind = read1(&buf);
1536 pEvent->mods[idx].modKind = modKind;
1539 case MK_COUNT: /* report once, when "--count" reaches 0 */
1541 u4 count = read4BE(&buf);
1542 LOGVV(" Count: %u\n", count);
1544 return ERR_INVALID_COUNT;
1545 pEvent->mods[idx].count.count = count;
1548 case MK_CONDITIONAL: /* conditional on expression) */
1550 u4 exprId = read4BE(&buf);
1551 LOGVV(" Conditional: %d\n", exprId);
1552 pEvent->mods[idx].conditional.exprId = exprId;
1555 case MK_THREAD_ONLY: /* only report events in specified thread */
1557 ObjectId threadId = dvmReadObjectId(&buf);
1558 LOGVV(" ThreadOnly: %llx\n", threadId);
1559 pEvent->mods[idx].threadOnly.threadId = threadId;
1562 case MK_CLASS_ONLY: /* for ClassPrepare, MethodEntry */
1564 RefTypeId clazzId = dvmReadRefTypeId(&buf);
1565 LOGVV(" ClassOnly: %llx (%s)\n",
1566 clazzId, dvmDbgGetClassDescriptor(clazzId));
1567 pEvent->mods[idx].classOnly.referenceTypeId = clazzId;
1570 case MK_CLASS_MATCH: /* restrict events to matching classes */
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);
1583 case MK_CLASS_EXCLUDE: /* restrict events to non-matching classes */
1588 pattern = readNewUtf8String(&buf, &strLen);
1589 LOGVV(" ClassExclude: '%s'\n", pattern);
1590 pEvent->mods[idx].classExclude.classPattern =
1591 dvmDotToSlash(pattern);
1595 case MK_LOCATION_ONLY: /* restrict certain events based on loc */
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;
1605 case MK_EXCEPTION_ONLY: /* modifies EK_EXCEPTION events */
1607 RefTypeId exceptionOrNull; /* null == all exceptions */
1608 u1 caught, uncaught;
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),
1618 pEvent->mods[idx].exceptionOnly.refTypeId = exceptionOrNull;
1619 pEvent->mods[idx].exceptionOnly.caught = caught;
1620 pEvent->mods[idx].exceptionOnly.uncaught = uncaught;
1623 case MK_FIELD_ONLY: /* for field access/mod events */
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;;
1632 case MK_STEP: /* for use with EK_SINGLE_STEP */
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));
1644 pEvent->mods[idx].step.threadId = threadId;
1645 pEvent->mods[idx].step.size = size;
1646 pEvent->mods[idx].step.depth = depth;
1649 case MK_INSTANCE_ONLY: /* report events related to a specific obj */
1651 ObjectId instance = dvmReadObjectId(&buf);
1652 LOGVV(" InstanceOnly: %llx\n", instance);
1653 pEvent->mods[idx].instanceOnly.objectId = instance;
1657 LOGW("GLITCH: unsupported modKind=%d\n", modKind);
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.
1666 if (buf != origBuf + dataLen) {
1667 LOGW("GLITCH: dataLen is %d, we have consumed %d\n", dataLen,
1668 (int) (buf - origBuf));
1672 * We reply with an integer "requestID".
1674 requestId = dvmJdwpNextEventSerial(state);
1675 expandBufAdd4BE(pReply, requestId);
1677 pEvent->requestId = requestId;
1679 LOGV(" --> event requestId=0x%x\n", requestId);
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");
1692 * Clear an event. Failure to find an event with a matching ID is a no-op
1693 * and does not return an error.
1695 static JdwpError handleER_Clear(JdwpState* state,
1696 const u1* buf, int dataLen, ExpandBuf* pReply)
1701 eventKind = read1(&buf);
1702 requestId = read4BE(&buf);
1704 LOGV(" Req to clear eventKind=%d requestId=0x%08x\n", eventKind,requestId);
1706 dvmJdwpUnregisterEventById(state, requestId);
1712 * Return the values of arguments and local variables.
1714 static JdwpError handleSF_GetValues(JdwpState* state,
1715 const u1* buf, int dataLen, ExpandBuf* pReply)
1722 threadId = dvmReadObjectId(&buf);
1723 frameId = dvmReadFrameId(&buf);
1724 slots = read4BE(&buf);
1726 LOGV(" Req for %d slots in threadId=%llx frameId=%llx\n",
1727 slots, threadId, frameId);
1729 expandBufAdd4BE(pReply, slots); /* "int values" */
1730 for (i = 0; i < (int) slots; i++) {
1736 slot = read4BE(&buf);
1737 reqSigByte = read1(&buf);
1739 LOGV(" --> slot %d '%c'\n", slot, reqSigByte);
1741 width = dvmDbgGetTagWidth(reqSigByte);
1742 ptr = expandBufAddSpace(pReply, width+1);
1743 dvmDbgGetLocalValue(threadId, frameId, slot, reqSigByte, ptr, width);
1750 * Set the values of arguments and local variables.
1752 static JdwpError handleSF_SetValues(JdwpState* state,
1753 const u1* buf, int dataLen, ExpandBuf* pReply)
1760 threadId = dvmReadObjectId(&buf);
1761 frameId = dvmReadFrameId(&buf);
1762 slots = read4BE(&buf);
1764 LOGV(" Req to set %d slots in threadId=%llx frameId=%llx\n",
1765 slots, threadId, frameId);
1767 for (i = 0; i < (int) slots; i++) {
1773 slot = read4BE(&buf);
1774 sigByte = read1(&buf);
1775 width = dvmDbgGetTagWidth(sigByte);
1776 value = jdwpReadValue(&buf, width);
1778 LOGV(" --> slot %d '%c' %llx\n", slot, sigByte, value);
1779 dvmDbgSetLocalValue(threadId, frameId, slot, sigByte, value, width);
1786 * Returns the value of "this" for the specified frame.
1788 static JdwpError handleSF_ThisObject(JdwpState* state,
1789 const u1* buf, int dataLen, ExpandBuf* pReply)
1797 threadId = dvmReadObjectId(&buf);
1798 frameId = dvmReadFrameId(&buf);
1800 if (!dvmDbgGetThisObject(threadId, frameId, &objectId))
1801 return ERR_INVALID_FRAMEID;
1803 if (objectId == 0) {
1804 typeName = strdup("null");
1807 typeName = dvmDbgGetObjectTypeName(objectId);
1808 objectTag = dvmDbgGetObjectTag(objectId, typeName);
1810 LOGV(" Req for 'this' in thread=%llx frame=%llx --> %llx %s '%c'\n",
1811 threadId, frameId, objectId, typeName, (char)objectTag);
1814 expandBufAdd1(pReply, objectTag);
1815 expandBufAddObjectId(pReply, objectId);
1821 * Return the reference type reflected by this class object.
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.)
1827 static JdwpError handleCOR_ReflectedType(JdwpState* state,
1828 const u1* buf, int dataLen, ExpandBuf* pReply)
1830 RefTypeId classObjectId;
1832 classObjectId = dvmReadRefTypeId(&buf);
1834 LOGV(" Req for refTypeId for class=%llx (%s)\n",
1835 classObjectId, dvmDbgGetClassDescriptor(classObjectId));
1837 /* just hand the type back to them */
1838 if (dvmDbgIsInterface(classObjectId))
1839 expandBufAdd1(pReply, TT_INTERFACE);
1841 expandBufAdd1(pReply, TT_CLASS);
1842 expandBufAddRefTypeId(pReply, classObjectId);
1848 * Handle a DDM packet with a single chunk in it.
1850 static JdwpError handleDDM_Chunk(JdwpState* state,
1851 const u1* buf, int dataLen, ExpandBuf* pReply)
1853 u1* replyBuf = NULL;
1856 LOGV(" Handling DDM packet (%.4s)\n", buf);
1859 * On first DDM packet, notify all handlers that DDM is running.
1861 if (!state->ddmActive) {
1862 state->ddmActive = true;
1863 dvmDbgDdmConnected();
1867 * If they want to send something back, we copy it into the buffer.
1868 * A no-copy approach would be nicer.
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.
1875 if (dvmDbgDdmHandlePacket(buf, dataLen, &replyBuf, &replyLen)) {
1876 assert(replyLen > 0 && replyLen < 1*1024*1024);
1877 memcpy(expandBufAddSpace(pReply, replyLen), replyBuf, replyLen);
1886 typedef JdwpError (*JdwpRequestHandler)(JdwpState* state,
1887 const u1* buf, int dataLen, ExpandBuf* reply);
1892 JdwpRequestHandler func;
1897 * Map commands to functions.
1899 * Command sets 0-63 are incoming requests, 64-127 are outbound requests,
1900 * and 128-256 are vendor-defined.
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" },
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
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" },
1936 { 2, 6, handleRT_GetValues, "ReferenceType.GetValues" },
1937 { 2, 7, handleRT_SourceFile, "ReferenceType.SourceFile" },
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" },
1951 //2, 17, ClassFileVersion
1952 //2, 18, ConstantPool
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" },
1960 /* ArrayType command set (4) */
1963 /* InterfaceType command set (5) */
1965 /* Method command set (6) */
1966 { 6, 1, handleM_LineTable, "Method.LineTable" },
1967 //6, 2, VariableTable
1970 { 6, 5, handleM_VariableTableWithGeneric,
1971 "Method.VariableTableWithGeneric" },
1973 /* Field command set (8) */
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)
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
1989 /* StringReference command set (10) */
1990 { 10, 1, handleSR_Value, "StringReference.Value" },
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" },
2005 { 11, 12, handleTR_SuspendCount, "ThreadReference.SuspendCount" },
2006 //11, 13, OwnedMonitorsStackDepthInfo
2007 //11, 14, ForceEarlyReturn
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" },
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" },
2019 /* ClassLoaderReference command set (14) */
2020 { 14, 1, handleCLR_VisibleClasses,
2021 "ClassLoaderReference.VisibleClasses" },
2023 /* EventRequest command set (15) */
2024 { 15, 1, handleER_Set, "EventRequest.Set" },
2025 { 15, 2, handleER_Clear, "EventRequest.Clear" },
2026 //15, 3, ClearAllBreakpoints
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" },
2034 /* ClassObjectReference command set (17) */
2035 { 17, 1, handleCOR_ReflectedType,"ClassObjectReference.ReflectedType" },
2037 /* Event command set (64) */
2038 //64, 100, Composite <-- sent from VM to debugger, never received by VM
2040 { 199, 1, handleDDM_Chunk, "DDM.Chunk" },
2045 * Process a request from the debugger.
2047 * On entry, the JDWP thread is in VMWAIT.
2049 void dvmJdwpProcessRequest(JdwpState* state, const JdwpReqHeader* pHeader,
2050 const u1* buf, int dataLen, ExpandBuf* pReply)
2052 JdwpError result = ERR_NONE;
2056 * Activity from a debugger, not merely ddms. Mark us as having an
2057 * active debugger session, and zero out the last-activity timestamp.
2059 if (pHeader->cmdSet != kJDWPDdmCmdSet) {
2062 state->lastActivitySec = 0;
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.
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.
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.
2082 dvmJdwpSetWaitForEventThread(state, 0);
2085 * Tell the VM that we're running and shouldn't be interrupted by GC.
2086 * Do this after anything that can stall indefinitely.
2088 dvmDbgThreadRunning();
2090 expandBufAddSpace(pReply, kJDWPHeaderLen);
2092 for (i = 0; i < (int) NELEM(gHandlerMap); i++) {
2093 if (gHandlerMap[i].cmdSet == pHeader->cmdSet &&
2094 gHandlerMap[i].cmd == pHeader->cmd)
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);
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);
2107 dvmPrintHexDumpDbg(buf, dataLen, LOG_TAG);
2108 assert(!"command not implemented"); // make it *really* obvious
2109 result = ERR_NOT_IMPLEMENTED;
2113 * Set up the reply header.
2115 * If we encountered an error, only send the header back.
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));
2124 set4BE(replyBuf + 0, kJDWPHeaderLen);
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**" : "");
2132 dvmPrintHexDumpDbg(expandBufGetBuffer(pReply) + kJDWPHeaderLen,
2137 * Update last-activity timestamp. We really only need this during
2138 * the initial setup. Only update if this is a non-DDMS packet.
2140 if (pHeader->cmdSet != kJDWPDdmCmdSet) {
2141 long lastSec, lastMsec;
2143 dvmJdwpGetNowMsec(&lastSec, &lastMsec);
2144 state->lastActivityMsec = lastMsec;
2145 MEM_BARRIER(); // updating a 64-bit value
2146 state->lastActivitySec = lastSec;
2149 /* tell the VM that GC is okay again */
2150 dvmDbgThreadWaiting();