/* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * Dalvik-specific side of debugger support. (The JDWP code is intended to * be relatively generic.) */ #ifndef _DALVIK_DEBUGGER #define _DALVIK_DEBUGGER #include "Common.h" #include "Misc.h" #include "jdwp/Jdwp.h" #include <pthread.h> /* fwd decl */ struct Object; struct ClassObject; struct Method; struct Thread; /* * used by StepControl to track a set of addresses associated with * a single line. */ typedef struct AddressSet { u4 setSize; u1 set[1]; } AddressSet; INLINE void dvmAddressSetSet(AddressSet *pSet, u4 toSet) { if (toSet < pSet->setSize) { pSet->set[toSet/8] |= 1 << (toSet % 8); } } INLINE bool dvmAddressSetGet(const AddressSet *pSet, u4 toGet) { if (toGet < pSet->setSize) { return (pSet->set[toGet/8] & (1 << (toGet % 8))) != 0; } else { return false; } } /* * Single-step management. */ typedef struct StepControl { /* request */ enum JdwpStepSize size; enum JdwpStepDepth depth; struct Thread* thread; /* don't deref; for comparison only */ /* current state */ bool active; const struct Method* method; int line; /* line #; could be -1 */ const AddressSet* pAddressSet; /* if non-null, address set for line */ int frameDepth; } StepControl; /* * Invoke-during-breakpoint support. */ typedef struct DebugInvokeReq { /* boolean; only set when we're in the tail end of an event handler */ bool ready; /* boolean; set if the JDWP thread wants this thread to do work */ bool invokeNeeded; /* request */ struct Object* obj; /* not used for ClassType.InvokeMethod */ struct Object* thread; struct ClassObject* clazz; struct Method* method; u4 numArgs; u8* argArray; /* will be NULL if numArgs==0 */ u4 options; /* result */ JdwpError err; u1 resultTag; JValue resultValue; ObjectId exceptObj; /* condition variable to wait on while the method executes */ pthread_mutex_t lock; pthread_cond_t cv; } DebugInvokeReq; /* system init/shutdown */ bool dvmDebuggerStartup(void); void dvmDebuggerShutdown(void); void dvmDbgInitMutex(pthread_mutex_t* pMutex); void dvmDbgLockMutex(pthread_mutex_t* pMutex); void dvmDbgUnlockMutex(pthread_mutex_t* pMutex); void dvmDbgInitCond(pthread_cond_t* pCond); void dvmDbgCondWait(pthread_cond_t* pCond, pthread_mutex_t* pMutex); void dvmDbgCondSignal(pthread_cond_t* pCond); void dvmDbgCondBroadcast(pthread_cond_t* pCond); /* * Return the DebugInvokeReq for the current thread. */ DebugInvokeReq* dvmDbgGetInvokeReq(void); /* * Enable/disable breakpoints and step modes. Used to provide a heads-up * when the debugger attaches. */ void dvmDbgConnected(void); void dvmDbgActive(void); void dvmDbgDisconnected(void); /* * Returns "true" if a debugger is connected. Returns "false" if it's * just DDM. */ bool dvmDbgIsDebuggerConnected(void); /* * Time, in milliseconds, since the last debugger activity. Does not * include DDMS activity. Returns -1 if there has been no activity. * Returns 0 if we're in the middle of handling a debugger request. */ s8 dvmDbgLastDebuggerActivity(void); /* * Block/allow GC depending on what we're doing. These return the old * status, which can be fed to dvmDbgThreadGoing() to restore the previous * mode. */ int dvmDbgThreadRunning(void); int dvmDbgThreadWaiting(void); int dvmDbgThreadContinuing(int status); /* * The debugger wants the VM to exit. */ void dvmDbgExit(int status); /* * Class, Object, Array */ const char* dvmDbgGetClassDescriptor(RefTypeId id); RefTypeId dvmDbgGetSuperclass(RefTypeId id); ObjectId dvmDbgGetClassLoader(RefTypeId id); u4 dvmDbgGetAccessFlags(RefTypeId id); bool dvmDbgIsInterface(RefTypeId id); void dvmDbgGetClassList(u4* pNumClasses, RefTypeId** pClassRefBuf); void dvmDbgGetVisibleClassList(ObjectId classLoaderId, u4* pNumClasses, RefTypeId** pClassRefBuf); void dvmDbgGetClassInfo(RefTypeId classId, u1* pTypeTag, u4* pStatus, char** pSignature); bool dvmDbgFindLoadedClassBySignature(const char* classDescriptor, RefTypeId* pRefTypeId); void dvmDbgGetObjectType(ObjectId objectId, u1* pRefTypeTag, RefTypeId* pRefTypeId); u1 dvmDbgGetClassObjectType(RefTypeId refTypeId); char* dvmDbgGetSignature(RefTypeId refTypeId); const char* dvmDbgGetSourceFile(RefTypeId refTypeId); char* dvmDbgGetObjectTypeName(ObjectId objectId); int dvmDbgGetSignatureTag(const char* signature); int dvmDbgGetObjectTag(ObjectId objectId, const char* type); int dvmDbgGetTagWidth(int tag); int dvmDbgGetArrayLength(ObjectId arrayId); int dvmDbgGetArrayElementTag(ObjectId arrayId); bool dvmDbgOutputArray(ObjectId arrayId, int firstIndex, int count, ExpandBuf* pReply); bool dvmDbgSetArrayElements(ObjectId arrayId, int firstIndex, int count, const u1* buf); ObjectId dvmDbgCreateString(const char* str); bool dvmDbgMatchType(RefTypeId instClassId, RefTypeId classId); /* * Method and Field */ const char* dvmDbgGetMethodName(RefTypeId refTypeId, MethodId id); void dvmDbgOutputAllFields(RefTypeId refTypeId, bool withGeneric, ExpandBuf* pReply); void dvmDbgOutputAllMethods(RefTypeId refTypeId, bool withGeneric, ExpandBuf* pReply); void dvmDbgOutputAllInterfaces(RefTypeId refTypeId, ExpandBuf* pReply); void dvmDbgOutputLineTable(RefTypeId refTypeId, MethodId methodId, ExpandBuf* pReply); void dvmDbgOutputVariableTable(RefTypeId refTypeId, MethodId id, bool withGeneric, ExpandBuf* pReply); int dvmDbgGetFieldTag(ObjectId objId, FieldId fieldId); int dvmDbgGetStaticFieldTag(RefTypeId refTypeId, FieldId fieldId); void dvmDbgGetFieldValue(ObjectId objId, FieldId fieldId, u1* ptr, int width); void dvmDbgSetFieldValue(ObjectId objectId, FieldId fieldId, u8 value, int width); void dvmDbgGetStaticFieldValue(RefTypeId refTypeId, FieldId fieldId, u1* ptr, int width); void dvmDbgSetStaticFieldValue(RefTypeId refTypeId, FieldId fieldId, u8 rawValue, int width); char* dvmDbgStringToUtf8(ObjectId strId); /* * Thread, ThreadGroup, Frame */ char* dvmDbgGetThreadName(ObjectId threadId); ObjectId dvmDbgGetThreadGroup(ObjectId threadId); char* dvmDbgGetThreadGroupName(ObjectId threadGroupId); ObjectId dvmDbgGetThreadGroupParent(ObjectId threadGroupId); ObjectId dvmDbgGetSystemThreadGroupId(void); ObjectId dvmDbgGetMainThreadGroupId(void); bool dvmDbgGetThreadStatus(ObjectId threadId, u4* threadStatus, u4* suspendStatus); u4 dvmDbgGetThreadSuspendCount(ObjectId threadId); bool dvmDbgThreadExists(ObjectId threadId); bool dvmDbgIsSuspended(ObjectId threadId); //void dvmDbgWaitForSuspend(ObjectId threadId); void dvmDbgGetThreadGroupThreads(ObjectId threadGroupId, ObjectId** ppThreadIds, u4* pThreadCount); void dvmDbgGetAllThreads(ObjectId** ppThreadIds, u4* pThreadCount); int dvmDbgGetThreadFrameCount(ObjectId threadId); bool dvmDbgGetThreadFrame(ObjectId threadId, int num, FrameId* pFrameId, JdwpLocation* pLoc); ObjectId dvmDbgGetThreadSelfId(void); void dvmDbgSuspendVM(bool isEvent); void dvmDbgResumeVM(void); void dvmDbgSuspendThread(ObjectId threadId); void dvmDbgResumeThread(ObjectId threadId); void dvmDbgSuspendSelf(void); bool dvmDbgGetThisObject(ObjectId threadId, FrameId frameId, ObjectId* pThisId); void dvmDbgGetLocalValue(ObjectId threadId, FrameId frameId, int slot, u1 tag, u1* buf, int expectedLen); void dvmDbgSetLocalValue(ObjectId threadId, FrameId frameId, int slot, u1 tag, u8 value, int width); /* * Debugger notification */ void dvmDbgPostLocationEvent(const struct Method* method, int pcOffset, struct Object* thisPtr, int eventFlags); void dvmDbgPostException(void* throwFp, int throwRelPc, void* catchFp, int catchRelPc, struct Object* exception); void dvmDbgPostThreadStart(struct Thread* thread); void dvmDbgPostThreadDeath(struct Thread* thread); void dvmDbgPostClassPrepare(struct ClassObject* clazz); // FieldAccess, FieldModification /* for "eventFlags" */ enum { DBG_BREAKPOINT = 0x01, DBG_SINGLE_STEP = 0x02, DBG_METHOD_ENTRY = 0x04, DBG_METHOD_EXIT = 0x08, }; bool dvmDbgWatchLocation(const JdwpLocation* pLoc); void dvmDbgUnwatchLocation(const JdwpLocation* pLoc); bool dvmDbgConfigureStep(ObjectId threadId, enum JdwpStepSize size, enum JdwpStepDepth depth); void dvmDbgUnconfigureStep(ObjectId threadId); JdwpError dvmDbgInvokeMethod(ObjectId threadId, ObjectId objectId, RefTypeId classId, MethodId methodId, u4 numArgs, u8* argArray, u4 options, u1* pResultTag, u8* pResultValue, ObjectId* pExceptObj); void dvmDbgExecuteMethod(DebugInvokeReq* pReq); /* Make an AddressSet for a line, for single stepping */ const AddressSet *dvmAddressSetForLine(const struct Method* method, int line); /* * DDM support. */ bool dvmDbgDdmHandlePacket(const u1* buf, int dataLen, u1** pReplyBuf, int* pReplyLen); void dvmDbgDdmConnected(void); void dvmDbgDdmDisconnected(void); void dvmDbgDdmSendChunk(int type, int len, const u1* buf); #define CHUNK_TYPE(_name) \ ((_name)[0] << 24 | (_name)[1] << 16 | (_name)[2] << 8 | (_name)[3]) #endif /*_DALVIK_DEBUGGER*/