📄 debugger.c
字号:
/* * Copyright (c) 1999-2002 Sun Microsystems, Inc. All Rights Reserved. * * This software is the confidential and proprietary information of Sun * Microsystems, Inc. ("Confidential Information"). You shall not * disclose such Confidential Information and shall use it only in * accordance with the terms of the license agreement you entered into * with Sun. * * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING * THIS SOFTWARE OR ITS DERIVATIVES. * * Use is subject to license terms. *//*========================================================================= * KVM *========================================================================= * SYSTEM: KVM * SUBSYSTEM: Java-level debugger * FILE: debugger.c * OVERVIEW: This file defines the Java-level debugger interface for * KVM based on JPDA (Java Platform Debug Architecture). * AUTHOR: Jonathan Coles, Sun Labs (summer 2000) * Bill Pittore, Sun Labs *=======================================================================*//*========================================================================= * Include files *=======================================================================*/#include "global.h"#if ENABLE_JAVA_DEBUGGER /* Extends until the end of the file */#include "thread.h"#ifdef PILOT#include <sys_types.h>#include <netinet_in.h>#endif#ifdef WINDOWS#define WIN32_LEAN_AND_MEAN#define NOMSG#ifdef GCC# include <winsock.h>#else# include <winsock2.h>#endif#endif /* WINDOWS *//*======================================================================== * Definitions and declarations *========================================================================*/#if INCLUDEDEBUGCODE#ifndef PILOT#include <stdarg.h>#endifstatic void printDebuggerInfo(const char *major, const char *minor, const char *format,...);static void printEventInfo(const char *format,...);static void printValueFromTag(void *address, unsigned char tag);#define TRACE_DEBUGGER(argList) \ if (tracedebugger) { printDebuggerInfo argList ; } else #define DEBUGGER_EVENT(argList) \ if (tracedebugger) { printEventInfo argList ; } else #else#define TRACE_DEBUGGER(argList)#define DEBUGGER_EVENT(argList)#endif /* INCLUDEDEBUGCODE */static void clearEvent(VMEventPtr ep);/*======================================================================== * Variables *========================================================================*/static bool_t resumeOK = FALSE;HASHTABLE debuggerHashTable;ID_HASH_ENTRY bucketFreeList = NULL;WEAKPOINTERLIST debugRoot = NULL;unsigned long *bucketMap = NULL;unsigned long bucketsAllocated;unsigned long uniqueDebuggerID = 1;VMEventPtr eventHead = NIL;EVENTMODIFIER modHead = NIL;struct CE_Modifiers *CE_ModHead = NIL;struct Modifiers *ModHead = NIL;static long requestID = 1;bool_t vmDebugReady;bool_t debuggerActive;bool_t waitOnSuspend;bool_t allThreadsSuspended = FALSE;bool_t suspend; /* Suspend all threads on VM startup. * Set to TRUE by default in main.c. */int _method_index_base = 0;short debuggerPort = DEFAULT_DEBUGGER_PORT;long debuggerNotifyList=Dbg_EventKind_NONE;#define GET_VMTHREAD(threadID) (getObjectPtr(threadID) == NULL ? NULL : ((JAVATHREAD)getObjectPtr(threadID))->VMthread)/*======================================================================== * Debugging operations *========================================================================*/#if INCLUDEDEBUGCODE/*======================================================================== * OP Code Lengths used by isLegalOffset() below. *========================================================================*/static const unsigned char opcodeLengths[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0 */ 1, 1, 1, 1, 1, 1, 2, 3, 2, 3, /* 10 */ 3, 2, 2, 2, 2, 2, 1, 1, 1, 1, /* 20 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 30 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 */ 1, 1, 1, 1, 2, 2, 2, 2, 2, 1, /* 50 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 70 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 80 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 90 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 100 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 110 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 120 */ 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, /* 130 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 140 */ 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, /* 150 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, /* 160 */ 0, 0, 1, 1, 1, 1, 1, 1, 3, 3, /* 170 */ 3, 3, 3, 3, 3, 5, 0, 3, 2, 3, /* 180 */ 1, 1, 3, 3, 1, 1, 0, 4, 3, 3, /* 190 */ 5, 5, 1, /* 200 - 202 */ 3, 3, 3, 3, 3, 3, 3, /* 202 - 209. Artificial */ 3, 3, 3, 0, 3, 3, 3, 5, 3, 3, /* 210. Artificial */ 4, 3, 3, 1 /* 220 - 223. Artificial */ };/*======================================================================== * Function: isLegalOffset() * Overview: Given a method and an offset, it determines if the * offset is a legal offset into the bytecode of the method. * Interface: * parameters: pointer to thisMethod * long offset * returns: TRUE if it is a legal offset, FALSE otherwise * *=======================================================================*/static bool_t isLegalOffset(METHOD thisMethod, long offset) { unsigned char *code = thisMethod->u.java.code; unsigned int codeLength = thisMethod->u.java.codeLength; unsigned char *expectedCode = &code[offset]; unsigned char *currentCode = code; if (offset >= (long)codeLength) { return FALSE; } while (currentCode < expectedCode) { unsigned char token = currentCode[0]; switch(token) { case TABLESWITCH: { long low, high; currentCode = (unsigned char *)((long)(currentCode + 4) & ~3); low = getAlignedCell(currentCode + 4); high = getAlignedCell(currentCode + 8); currentCode += 12 + (high - low + 1) * 4; break; } case LOOKUPSWITCH: { long pairs; currentCode = (unsigned char *)((long)(currentCode + 4) & ~3); pairs = getAlignedCell(currentCode + 4); currentCode += 8 + pairs * 8; break; } case WIDE: currentCode += ((currentCode[1] == IINC) ? 6 : 4); break; default: currentCode += opcodeLengths[token]; break; } } return (currentCode == expectedCode); }#endif /* INCLUDEDEBUGCODE */static void nop(PACKET_INPUT_STREAM_HANDLE inH, PACKET_OUTPUT_STREAM_HANDLE outH){ struct CmdPacket *cmd = &unhand(inH)->packet->type.cmd; TRACE_DEBUGGER(("Unknown Command", "", "%d/%d", cmd->cmdSet, cmd->cmd)); outStream_setError(outH, JDWP_Error_NOT_IMPLEMENTED);}static void * allocAlignedBytes(long size) { void *p;#if COMPILER_SUPPORTS_LONG /* * mallocBytes allocates a cell sized block which means that * the address returned is always 4 byte aligned. We need * 8 byte aligned so we add 4 more bytes to size then * re-adjust the address of newMod */ p = callocPermanentObject(ByteSizeToCellSize((size + 4))); /* roundup to next 8 byte boundary */ p = (void *)(((unsigned long)p + 7) & ~7);#else p = callocPermanentObject(ByteSizeToCellSize(size));#endif return (p);}static void setResumeOK(bool_t val) { resumeOK = val;}/*======================================================================== * Function: isValidThread() * Overview: determines whether a thread actually exists * * Interface: * parameters: thread * returns: bool_t * * Notes: *=======================================================================*/static bool_t isValidThread(THREAD thread){ THREAD tptr; for (tptr = AllThreads; tptr != NULL; tptr = tptr->nextAliveThread) { if (tptr == thread) { return TRUE; } } return FALSE;}/*======================================================================== * Function: isValidJavaThread() * Overview: determines whether this Java thread actually exists * * Interface: * parameters: object to test * returns: bool_t * * Notes: *=======================================================================*/static bool_t isValidJavaThread(OBJECT obj){ THREAD tptr; for (tptr = AllThreads; tptr != NULL; tptr = tptr->nextAliveThread) { if (tptr->javaThread == (JAVATHREAD)obj) { return TRUE; } } return FALSE;}static bool_t isValidObject(OBJECT object){ if (object == NULL || object->ofClass == NULL) { return FALSE; } else if (!inCurrentHeap(object)) { CLASS clazz = object->ofClass; /* These are the only user visible types that don't live in the * heap. Anything else is almost certainly a bug. */ return clazz == (CLASS)JavaLangClass || clazz == (CLASS)JavaLangString || clazz == (CLASS)PrimitiveArrayClasses[T_CHAR]; } else { /* Occasionally, Java instances point to heap values that shouldn't * be externally visible. (E.g. Thread's point to an "implementation".) * Let's make sure the type of the object really is something the * user ought to know about. */ GCT_ObjectType type = getObjectType((cell*)object); return (type == GCT_INSTANCE || type == GCT_ARRAY || type == GCT_OBJECTARRAY); }}static unsigned long debuggerHash(OBJECT p){ return (unsigned long)objectHashCode(p);}static void freeBucket(ID_HASH_ENTRY bucket) { ID_HASH_ENTRY tmpBucket, *freeBucketPtr, *lastBucketPtr; unsigned long index; index = (bucket->key >> DEBUGGER_INDEX_SHIFT) & DEBUGGER_INDEX_MASK; freeBucketPtr = (ID_HASH_ENTRY *)&debuggerHashTable->bucket[index]; lastBucketPtr = freeBucketPtr; for (tmpBucket = *freeBucketPtr; tmpBucket != NULL; tmpBucket = tmpBucket->next) { if (bucket == tmpBucket) { *lastBucketPtr = tmpBucket->next; break; } lastBucketPtr = &tmpBucket->next; } bucket->next = bucketFreeList; bucketFreeList = bucket; bucket->key = 0;}/*======================================================================== * Function: addToDebugRoot() * Overview: add this object to the debug root * Interface: * parameters: pointer to object * returns: index into array * * Notes: * The debugRoot contains object references and these * references will be updated by the GC since debugRoot is a * weak Pointerlist type. We also keep a parallel array * called the bucketMap which contains a pointer to the * hash bucket that will contain this entry. We do this * so we can easily re-use buckets since they are allocated * from permanent memory. If we re-use a debugRoot entry * (because it was GC'd and NULL'd out) we set the bucket->key * value to 0 so that the getObjectID code will notice that * this bucket is free and re-use it. * Note that classes/objects that are in permanent memory * have an ID that is their actual address. We distinguish * between these and transient objects by bit 0 being set in * the ID. *=======================================================================*/static unsigned int addToDebugRoot(void *object, ID_HASH_ENTRY bucket){ unsigned long i; unsigned long length = debugRoot->length; ID_HASH_ENTRY tmpBucket; unsigned long *tmpPtr;#if INCLUDEDEBUGCODE /** * Note: debugRoot->data[length - 1] is always empty. */ if (debugRoot->data[length - 1].cellp != NULL) { fatalError(KVM_MSG_DEBUG_ROOT_CANNOT_BE_FULL); }#endif for (i = 0; ; i++) { if (debugRoot->data[i].cellp == NULL) { debugRoot->data[i].cellp = (cell *)object; if (bucketMap[i] != 0) { /* This debugRoot entry was freed by the GC, so lets free * up the bucket that corresponds to it. */ tmpBucket = (ID_HASH_ENTRY)bucketMap[i];#if INCLUDEDEBUGCODE if (i != tmpBucket->rootIndex) fatalError(KVM_MSG_DEBUG_HASHTABLE_INCONSISTENT);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -