duke@435: /* mikael@6198: * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. duke@435: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. duke@435: * duke@435: * This code is free software; you can redistribute it and/or modify it duke@435: * under the terms of the GNU General Public License version 2 only, as duke@435: * published by the Free Software Foundation. duke@435: * duke@435: * This code is distributed in the hope that it will be useful, but WITHOUT duke@435: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or duke@435: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License duke@435: * version 2 for more details (a copy is included in the LICENSE file that duke@435: * accompanied this code). duke@435: * duke@435: * You should have received a copy of the GNU General Public License version duke@435: * 2 along with this work; if not, write to the Free Software Foundation, duke@435: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. duke@435: * trims@1907: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA trims@1907: * or visit www.oracle.com if you need additional information or have any trims@1907: * questions. duke@435: * duke@435: */ duke@435: duke@435: // this is source code windbg based SA debugger agent to debug duke@435: // Dr. Watson dump files and process snapshots. duke@435: duke@435: #include "sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal.h" duke@435: morris@4535: #ifdef _M_IX86 duke@435: #include "sun_jvm_hotspot_debugger_x86_X86ThreadContext.h" duke@435: #define NPRGREG sun_jvm_hotspot_debugger_x86_X86ThreadContext_NPRGREG duke@435: #elif _M_AMD64 duke@435: #include "sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext.h" duke@435: #define NPRGREG sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_NPRGREG duke@435: #else duke@435: #error "SA windbg back-end is not supported for your cpu!" duke@435: #endif duke@435: duke@435: #include duke@435: #include duke@435: duke@435: #ifndef STDMETHODV duke@435: #define STDMETHODV(method) virtual HRESULT STDMETHODVCALLTYPE method duke@435: #endif duke@435: duke@435: #define DEBUG_NO_IMPLEMENTATION duke@435: #include duke@435: #include duke@435: duke@435: // simple template to manage array delete across early (error) returns duke@435: duke@435: template duke@435: class AutoArrayPtr { duke@435: T* m_ptr; duke@435: public: duke@435: AutoArrayPtr(T* ptr) : m_ptr(ptr) { duke@435: } duke@435: duke@435: ~AutoArrayPtr() { duke@435: delete [] m_ptr; duke@435: } duke@435: duke@435: T* asPtr() { duke@435: return m_ptr; duke@435: } duke@435: }; duke@435: duke@435: class AutoJavaString { duke@435: JNIEnv* m_env; duke@435: jstring m_str; duke@435: const char* m_buf; duke@435: duke@435: public: duke@435: AutoJavaString(JNIEnv* env, jstring str, const char* buf) duke@435: : m_env(env), m_str(str), m_buf(buf) { duke@435: } duke@435: duke@435: ~AutoJavaString() { duke@435: m_env->ReleaseStringUTFChars(m_str, m_buf); duke@435: } duke@435: duke@435: operator const char* () { duke@435: return m_buf; duke@435: } duke@435: }; duke@435: duke@435: // field and method IDs we want here duke@435: duke@435: static jfieldID imagePath_ID = 0; duke@435: static jfieldID symbolPath_ID = 0; duke@435: static jfieldID ptrIDebugClient_ID = 0; duke@435: static jfieldID ptrIDebugControl_ID = 0; duke@435: static jfieldID ptrIDebugDataSpaces_ID = 0; duke@435: static jfieldID ptrIDebugOutputCallbacks_ID = 0; duke@435: static jfieldID ptrIDebugAdvanced_ID = 0; duke@435: static jfieldID ptrIDebugSymbols_ID = 0; duke@435: static jfieldID ptrIDebugSystemObjects_ID = 0; duke@435: duke@435: static jmethodID addLoadObject_ID = 0; duke@435: static jmethodID addThread_ID = 0; duke@435: static jmethodID createClosestSymbol_ID = 0; duke@435: static jmethodID setThreadIntegerRegisterSet_ID = 0; duke@435: duke@435: #define CHECK_EXCEPTION_(value) if(env->ExceptionOccurred()) { return value; } duke@435: #define CHECK_EXCEPTION if(env->ExceptionOccurred()) { return;} duke@435: duke@435: #define THROW_NEW_DEBUGGER_EXCEPTION_(str, value) { \ duke@435: throwNewDebuggerException(env, str); return value; } duke@435: duke@435: #define THROW_NEW_DEBUGGER_EXCEPTION(str) { throwNewDebuggerException(env, str); \ duke@435: return;} duke@435: duke@435: static void throwNewDebuggerException(JNIEnv* env, const char* errMsg) { duke@435: env->ThrowNew(env->FindClass("sun/jvm/hotspot/debugger/DebuggerException"), errMsg); duke@435: } duke@435: duke@435: /* duke@435: * Class: sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal duke@435: * Method: initIDs duke@435: * Signature: ()V duke@435: */ duke@435: JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal_initIDs duke@435: (JNIEnv *env, jclass clazz) { duke@435: imagePath_ID = env->GetStaticFieldID(clazz, "imagePath", "Ljava/lang/String;"); duke@435: CHECK_EXCEPTION; duke@435: duke@435: symbolPath_ID = env->GetStaticFieldID(clazz, "symbolPath", "Ljava/lang/String;"); duke@435: CHECK_EXCEPTION; duke@435: duke@435: ptrIDebugClient_ID = env->GetFieldID(clazz, "ptrIDebugClient", "J"); duke@435: CHECK_EXCEPTION; duke@435: duke@435: ptrIDebugControl_ID = env->GetFieldID(clazz, "ptrIDebugControl", "J"); duke@435: CHECK_EXCEPTION; duke@435: duke@435: ptrIDebugDataSpaces_ID = env->GetFieldID(clazz, "ptrIDebugDataSpaces", "J"); duke@435: CHECK_EXCEPTION; duke@435: duke@435: ptrIDebugOutputCallbacks_ID = env->GetFieldID(clazz, duke@435: "ptrIDebugOutputCallbacks", "J"); duke@435: CHECK_EXCEPTION; duke@435: duke@435: ptrIDebugAdvanced_ID = env->GetFieldID(clazz, "ptrIDebugAdvanced", "J"); duke@435: CHECK_EXCEPTION; duke@435: duke@435: ptrIDebugSymbols_ID = env->GetFieldID(clazz, duke@435: "ptrIDebugSymbols", "J"); duke@435: CHECK_EXCEPTION; duke@435: duke@435: ptrIDebugSystemObjects_ID = env->GetFieldID(clazz, duke@435: "ptrIDebugSystemObjects", "J"); duke@435: CHECK_EXCEPTION; duke@435: duke@435: addLoadObject_ID = env->GetMethodID(clazz, "addLoadObject", duke@435: "(Ljava/lang/String;JJ)V"); duke@435: CHECK_EXCEPTION; duke@435: duke@435: addThread_ID = env->GetMethodID(clazz, "addThread", "(J)V"); duke@435: CHECK_EXCEPTION; duke@435: duke@435: createClosestSymbol_ID = env->GetMethodID(clazz, "createClosestSymbol", duke@435: "(Ljava/lang/String;J)Lsun/jvm/hotspot/debugger/cdbg/ClosestSymbol;"); duke@435: CHECK_EXCEPTION; duke@435: duke@435: setThreadIntegerRegisterSet_ID = env->GetMethodID(clazz, duke@435: "setThreadIntegerRegisterSet", "(J[J)V"); duke@435: CHECK_EXCEPTION; duke@435: duke@435: } duke@435: duke@435: // class for IDebugOutputCallbacks duke@435: duke@435: class SAOutputCallbacks : public IDebugOutputCallbacks { duke@435: LONG m_refCount; duke@435: char* m_msgBuffer; duke@435: duke@435: public: duke@435: SAOutputCallbacks() : m_refCount(0), m_msgBuffer(0) { duke@435: } duke@435: duke@435: ~SAOutputCallbacks() { duke@435: clearBuffer(); duke@435: } duke@435: duke@435: const char* getBuffer() const { duke@435: return m_msgBuffer; duke@435: } duke@435: duke@435: void clearBuffer() { duke@435: if (m_msgBuffer) { duke@435: free(m_msgBuffer); duke@435: m_msgBuffer = 0; duke@435: } duke@435: } duke@435: duke@435: STDMETHOD_(ULONG, AddRef)(THIS); duke@435: STDMETHOD_(ULONG, Release)(THIS); duke@435: STDMETHOD(QueryInterface)(THIS_ duke@435: IN REFIID interfaceId, duke@435: OUT PVOID* ppInterface); duke@435: STDMETHOD(Output)(THIS_ duke@435: IN ULONG mask, duke@435: IN PCSTR msg); duke@435: }; duke@435: duke@435: STDMETHODIMP_(ULONG) SAOutputCallbacks::AddRef(THIS) { duke@435: InterlockedIncrement(&m_refCount); duke@435: return m_refCount; duke@435: } duke@435: duke@435: STDMETHODIMP_(ULONG) SAOutputCallbacks::Release(THIS) { duke@435: LONG retVal; duke@435: InterlockedDecrement(&m_refCount); duke@435: retVal = m_refCount; duke@435: if (retVal == 0) { duke@435: delete this; duke@435: } duke@435: return retVal; duke@435: } duke@435: duke@435: STDMETHODIMP SAOutputCallbacks::QueryInterface(THIS_ duke@435: IN REFIID interfaceId, duke@435: OUT PVOID* ppInterface) { duke@435: *ppInterface = 0; duke@435: HRESULT res = E_NOINTERFACE; duke@435: if (TRUE == IsEqualIID(interfaceId, __uuidof(IUnknown)) || duke@435: TRUE == IsEqualIID(interfaceId, __uuidof(IDebugOutputCallbacks))) { duke@435: *ppInterface = (IDebugOutputCallbacks*) this; duke@435: AddRef(); duke@435: res = S_OK; duke@435: } duke@435: return res; duke@435: } duke@435: duke@435: STDMETHODIMP SAOutputCallbacks::Output(THIS_ duke@435: IN ULONG mask, duke@435: IN PCSTR msg) { duke@435: int len = (int) (strlen(msg) + 1); duke@435: if (m_msgBuffer == 0) { duke@435: m_msgBuffer = (char*) malloc(len); duke@435: if (m_msgBuffer == 0) { duke@435: fprintf(stderr, "out of memory debugger output!\n"); duke@435: return S_FALSE; duke@435: } duke@435: strcpy(m_msgBuffer, msg); duke@435: } else { duke@435: m_msgBuffer = (char*) realloc(m_msgBuffer, len + strlen(m_msgBuffer)); duke@435: if (m_msgBuffer == 0) { duke@435: fprintf(stderr, "out of memory debugger output!\n"); duke@435: return S_FALSE; duke@435: } duke@435: strcat(m_msgBuffer, msg); duke@435: } duke@435: return S_OK; duke@435: } duke@435: duke@435: static bool getWindbgInterfaces(JNIEnv* env, jobject obj) { duke@435: // get windbg interfaces .. duke@435: duke@435: IDebugClient* ptrIDebugClient = 0; duke@435: if (DebugCreate(__uuidof(IDebugClient), (PVOID*) &ptrIDebugClient) != S_OK) { duke@435: THROW_NEW_DEBUGGER_EXCEPTION_("Windbg Error: not able to create IDebugClient object!", false); duke@435: } duke@435: env->SetLongField(obj, ptrIDebugClient_ID, (jlong) ptrIDebugClient); duke@435: duke@435: IDebugControl* ptrIDebugControl = 0; duke@435: if (ptrIDebugClient->QueryInterface(__uuidof(IDebugControl), (PVOID*) &ptrIDebugControl) duke@435: != S_OK) { duke@435: THROW_NEW_DEBUGGER_EXCEPTION_("Windbg Error: not able to get IDebugControl", false); duke@435: } duke@435: env->SetLongField(obj, ptrIDebugControl_ID, (jlong) ptrIDebugControl); duke@435: duke@435: IDebugDataSpaces* ptrIDebugDataSpaces = 0; duke@435: if (ptrIDebugClient->QueryInterface(__uuidof(IDebugDataSpaces), (PVOID*) &ptrIDebugDataSpaces) duke@435: != S_OK) { duke@435: THROW_NEW_DEBUGGER_EXCEPTION_("Windbg Error: not able to get IDebugDataSpaces object!", false); duke@435: } duke@435: env->SetLongField(obj, ptrIDebugDataSpaces_ID, (jlong) ptrIDebugDataSpaces); duke@435: duke@435: SAOutputCallbacks* ptrIDebugOutputCallbacks = new SAOutputCallbacks(); duke@435: ptrIDebugOutputCallbacks->AddRef(); duke@435: env->SetLongField(obj, ptrIDebugOutputCallbacks_ID, (jlong) ptrIDebugOutputCallbacks); duke@435: CHECK_EXCEPTION_(false); duke@435: duke@435: IDebugAdvanced* ptrIDebugAdvanced = 0; duke@435: if (ptrIDebugClient->QueryInterface(__uuidof(IDebugAdvanced), (PVOID*) &ptrIDebugAdvanced) duke@435: != S_OK) { duke@435: THROW_NEW_DEBUGGER_EXCEPTION_("Windbg Error: not able to get IDebugAdvanced object!", false); duke@435: } duke@435: env->SetLongField(obj, ptrIDebugAdvanced_ID, (jlong) ptrIDebugAdvanced); duke@435: duke@435: IDebugSymbols* ptrIDebugSymbols = 0; duke@435: if (ptrIDebugClient->QueryInterface(__uuidof(IDebugSymbols), (PVOID*) &ptrIDebugSymbols) duke@435: != S_OK) { duke@435: THROW_NEW_DEBUGGER_EXCEPTION_("Windbg Error: not able to get IDebugSymbols object!", false); duke@435: } duke@435: env->SetLongField(obj, ptrIDebugSymbols_ID, (jlong) ptrIDebugSymbols); duke@435: duke@435: IDebugSystemObjects* ptrIDebugSystemObjects = 0; duke@435: if (ptrIDebugClient->QueryInterface(__uuidof(IDebugSystemObjects), (PVOID*) &ptrIDebugSystemObjects) duke@435: != S_OK) { duke@435: THROW_NEW_DEBUGGER_EXCEPTION_("Windbg Error: not able to get IDebugSystemObjects object!", false); duke@435: } duke@435: env->SetLongField(obj, ptrIDebugSystemObjects_ID, (jlong) ptrIDebugSystemObjects); duke@435: duke@435: return true; duke@435: } duke@435: duke@435: static bool setImageAndSymbolPath(JNIEnv* env, jobject obj) { duke@435: jboolean isCopy; duke@435: jclass clazz = env->GetObjectClass(obj); duke@435: jstring path; duke@435: const char* buf; duke@435: duke@435: path = (jstring) env->GetStaticObjectField(clazz, imagePath_ID); duke@435: buf = env->GetStringUTFChars(path, &isCopy); duke@435: CHECK_EXCEPTION_(false); duke@435: AutoJavaString imagePath(env, path, buf); duke@435: duke@435: path = (jstring) env->GetStaticObjectField(clazz, symbolPath_ID); duke@435: buf = env->GetStringUTFChars(path, &isCopy); duke@435: CHECK_EXCEPTION_(false); duke@435: AutoJavaString symbolPath(env, path, buf); duke@435: duke@435: IDebugSymbols* ptrIDebugSymbols = (IDebugSymbols*) env->GetLongField(obj, duke@435: ptrIDebugSymbols_ID); duke@435: CHECK_EXCEPTION_(false); duke@435: duke@435: ptrIDebugSymbols->SetImagePath(imagePath); duke@435: ptrIDebugSymbols->SetSymbolPath(symbolPath); duke@435: return true; duke@435: } duke@435: duke@435: static bool openDumpFile(JNIEnv* env, jobject obj, jstring coreFileName) { duke@435: // open the dump file duke@435: jboolean isCopy; duke@435: const char* buf = env->GetStringUTFChars(coreFileName, &isCopy); duke@435: CHECK_EXCEPTION_(false); duke@435: AutoJavaString coreFile(env, coreFileName, buf); duke@435: if (setImageAndSymbolPath(env, obj) == false) { duke@435: return false; duke@435: } duke@435: duke@435: IDebugClient* ptrIDebugClient = (IDebugClient*) env->GetLongField(obj, duke@435: ptrIDebugClient_ID); duke@435: CHECK_EXCEPTION_(false); duke@435: if (ptrIDebugClient->OpenDumpFile(coreFile) != S_OK) { duke@435: THROW_NEW_DEBUGGER_EXCEPTION_("Windbg Error: OpenDumpFile failed!", false); duke@435: } duke@435: duke@435: IDebugControl* ptrIDebugControl = (IDebugControl*) env->GetLongField(obj, duke@435: ptrIDebugControl_ID); duke@435: CHECK_EXCEPTION_(false); duke@435: if (ptrIDebugControl->WaitForEvent(DEBUG_WAIT_DEFAULT, INFINITE) != S_OK) { duke@435: THROW_NEW_DEBUGGER_EXCEPTION_("Windbg Error: WaitForEvent failed!", false); duke@435: } duke@435: duke@435: return true; duke@435: } duke@435: duke@435: duke@435: static bool attachToProcess(JNIEnv* env, jobject obj, jint pid) { duke@435: if (setImageAndSymbolPath(env, obj) == false) { duke@435: return false; duke@435: } duke@435: IDebugClient* ptrIDebugClient = (IDebugClient*) env->GetLongField(obj, duke@435: ptrIDebugClient_ID); duke@435: CHECK_EXCEPTION_(false); duke@435: duke@435: /*********************************************************************************** duke@435: duke@435: We are attaching to a process in 'read-only' mode. i.e., we do not want to duke@435: put breakpoints, suspend/resume threads etc. For read-only JDI and HSDB kind of sla@4642: usage this should suffice. duke@435: duke@435: Please refer to DEBUG_ATTACH_NONINVASIVE mode source comments from dbgeng.h. duke@435: In this mode, debug engine does not call DebugActiveProrcess. i.e., we are not duke@435: actually debugging at all. We can safely 'detach' from the process anytime duke@435: we want and debuggee process is left as is on all Windows variants. duke@435: duke@435: This also makes JDI-on-SA installation/usage simpler because with this we would duke@435: not need a tool like ServiceInstaller from http://www.kcmultimedia.com/smaster. duke@435: duke@435: ***********************************************************************************/ duke@435: duke@435: duke@435: if (ptrIDebugClient->AttachProcess(0, pid, DEBUG_ATTACH_NONINVASIVE) != S_OK) { duke@435: THROW_NEW_DEBUGGER_EXCEPTION_("Windbg Error: AttachProcess failed!", false); duke@435: } duke@435: duke@435: IDebugControl* ptrIDebugControl = (IDebugControl*) env->GetLongField(obj, duke@435: ptrIDebugControl_ID); duke@435: CHECK_EXCEPTION_(false); duke@435: if (ptrIDebugControl->WaitForEvent(DEBUG_WAIT_DEFAULT, INFINITE) != S_OK) { duke@435: THROW_NEW_DEBUGGER_EXCEPTION_("Windbg Error: WaitForEvent failed!", false); duke@435: } duke@435: duke@435: return true; duke@435: } duke@435: duke@435: duke@435: static bool addLoadObjects(JNIEnv* env, jobject obj) { duke@435: IDebugSymbols* ptrIDebugSymbols = (IDebugSymbols*) env->GetLongField(obj, duke@435: ptrIDebugSymbols_ID); duke@435: CHECK_EXCEPTION_(false); duke@435: ULONG loaded = 0, unloaded = 0; duke@435: if (ptrIDebugSymbols->GetNumberModules(&loaded, &unloaded) != S_OK) { duke@435: THROW_NEW_DEBUGGER_EXCEPTION_("Windbg Error: GetNumberModules failed!", false); duke@435: } duke@435: duke@435: AutoArrayPtr params(new DEBUG_MODULE_PARAMETERS[loaded]); duke@435: duke@435: if (params.asPtr() == 0) { duke@435: THROW_NEW_DEBUGGER_EXCEPTION_("out of memory to allocate debug module params!", false); duke@435: } duke@435: duke@435: if (ptrIDebugSymbols->GetModuleParameters(loaded, 0, NULL, params.asPtr()) != S_OK) { duke@435: THROW_NEW_DEBUGGER_EXCEPTION_("Windbg Error: GetModuleParameters failed!", false); duke@435: } duke@435: duke@435: for (int u = 0; u < (int)loaded; u++) { duke@435: TCHAR imageName[MAX_PATH]; duke@435: if (ptrIDebugSymbols->GetModuleNames(DEBUG_ANY_ID, params.asPtr()[u].Base, duke@435: imageName, MAX_PATH, NULL, NULL, duke@435: 0, NULL, NULL, 0, NULL) != S_OK) { duke@435: THROW_NEW_DEBUGGER_EXCEPTION_("Windbg Error: GetModuleNames failed!", false); duke@435: } duke@435: duke@435: jstring strName = env->NewStringUTF(imageName); duke@435: CHECK_EXCEPTION_(false); duke@435: env->CallVoidMethod(obj, addLoadObject_ID, strName, (jlong) params.asPtr()[u].Size, duke@435: (jlong) params.asPtr()[u].Base); duke@435: CHECK_EXCEPTION_(false); duke@435: } duke@435: duke@435: return true; duke@435: } duke@435: duke@435: static bool addThreads(JNIEnv* env, jobject obj) { duke@435: IDebugSystemObjects* ptrIDebugSystemObjects = (IDebugSystemObjects*) env->GetLongField(obj, duke@435: ptrIDebugSystemObjects_ID); duke@435: CHECK_EXCEPTION_(false); duke@435: duke@435: ULONG numThreads = 0; duke@435: if (ptrIDebugSystemObjects->GetNumberThreads(&numThreads) != S_OK) { duke@435: THROW_NEW_DEBUGGER_EXCEPTION_("Windbg Error: GetNumberThreads failed!", false); duke@435: } duke@435: duke@435: AutoArrayPtr ptrSysThreadIds = new ULONG[numThreads]; duke@435: duke@435: if (ptrSysThreadIds.asPtr() == 0) { duke@435: THROW_NEW_DEBUGGER_EXCEPTION_("out of memory to allocate thread ids!", false); duke@435: } duke@435: duke@435: AutoArrayPtr ptrThreadIds = new ULONG[numThreads]; duke@435: duke@435: if (ptrThreadIds.asPtr() == 0) { duke@435: THROW_NEW_DEBUGGER_EXCEPTION_("out of memory to allocate thread ids!", false); duke@435: } duke@435: duke@435: if (ptrIDebugSystemObjects->GetThreadIdsByIndex(0, numThreads, duke@435: ptrThreadIds.asPtr(), ptrSysThreadIds.asPtr()) != S_OK) { duke@435: THROW_NEW_DEBUGGER_EXCEPTION_("Windbg Error: GetThreadIdsByIndex failed!", false); duke@435: } duke@435: duke@435: duke@435: IDebugAdvanced* ptrIDebugAdvanced = (IDebugAdvanced*) env->GetLongField(obj, duke@435: ptrIDebugAdvanced_ID); duke@435: CHECK_EXCEPTION_(false); duke@435: duke@435: // for each thread, get register context and save it. duke@435: for (ULONG t = 0; t < numThreads; t++) { duke@435: if (ptrIDebugSystemObjects->SetCurrentThreadId(ptrThreadIds.asPtr()[t]) != S_OK) { duke@435: THROW_NEW_DEBUGGER_EXCEPTION_("Windbg Error: SetCurrentThread failed!", false); duke@435: } duke@435: duke@435: jlongArray regs = env->NewLongArray(NPRGREG); duke@435: CHECK_EXCEPTION_(false); duke@435: duke@435: jboolean isCopy = JNI_FALSE; duke@435: jlong* ptrRegs = env->GetLongArrayElements(regs, &isCopy); duke@435: CHECK_EXCEPTION_(false); duke@435: duke@435: // copy register values from the CONTEXT struct duke@435: CONTEXT context; duke@435: memset(&context, 0, sizeof(CONTEXT)); duke@435: duke@435: #undef REG_INDEX morris@4535: #ifdef _M_IX86 duke@435: #define REG_INDEX(x) sun_jvm_hotspot_debugger_x86_X86ThreadContext_##x duke@435: duke@435: context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS; duke@435: ptrIDebugAdvanced->GetThreadContext(&context, sizeof(CONTEXT)); duke@435: duke@435: ptrRegs[REG_INDEX(GS)] = context.SegGs; duke@435: ptrRegs[REG_INDEX(FS)] = context.SegFs; duke@435: ptrRegs[REG_INDEX(ES)] = context.SegEs; duke@435: ptrRegs[REG_INDEX(DS)] = context.SegDs; duke@435: duke@435: ptrRegs[REG_INDEX(EDI)] = context.Edi; duke@435: ptrRegs[REG_INDEX(ESI)] = context.Esi; duke@435: ptrRegs[REG_INDEX(EBX)] = context.Ebx; duke@435: ptrRegs[REG_INDEX(EDX)] = context.Edx; duke@435: ptrRegs[REG_INDEX(ECX)] = context.Ecx; duke@435: ptrRegs[REG_INDEX(EAX)] = context.Eax; duke@435: duke@435: ptrRegs[REG_INDEX(FP)] = context.Ebp; duke@435: ptrRegs[REG_INDEX(PC)] = context.Eip; duke@435: ptrRegs[REG_INDEX(CS)] = context.SegCs; duke@435: ptrRegs[REG_INDEX(EFL)] = context.EFlags; duke@435: ptrRegs[REG_INDEX(SP)] = context.Esp; duke@435: ptrRegs[REG_INDEX(SS)] = context.SegSs; duke@435: duke@435: ptrRegs[REG_INDEX(DR0)] = context.Dr0; duke@435: ptrRegs[REG_INDEX(DR1)] = context.Dr1; duke@435: ptrRegs[REG_INDEX(DR2)] = context.Dr2; duke@435: ptrRegs[REG_INDEX(DR3)] = context.Dr3; duke@435: ptrRegs[REG_INDEX(DR6)] = context.Dr6; duke@435: ptrRegs[REG_INDEX(DR7)] = context.Dr7; duke@435: duke@435: #elif _M_AMD64 duke@435: #define REG_INDEX(x) sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_##x duke@435: duke@435: context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS; duke@435: ptrIDebugAdvanced->GetThreadContext(&context, sizeof(CONTEXT)); duke@435: duke@435: // Segment Registers and processor flags duke@435: ptrRegs[REG_INDEX(CS)] = context.SegCs; duke@435: ptrRegs[REG_INDEX(DS)] = context.SegDs; duke@435: ptrRegs[REG_INDEX(ES)] = context.SegEs; duke@435: ptrRegs[REG_INDEX(FS)] = context.SegFs; duke@435: ptrRegs[REG_INDEX(GS)] = context.SegGs; duke@435: ptrRegs[REG_INDEX(SS)] = context.SegSs; duke@435: ptrRegs[REG_INDEX(RFL)] = context.EFlags; duke@435: duke@435: // Integer registers duke@435: ptrRegs[REG_INDEX(RDI)] = context.Rdi; duke@435: ptrRegs[REG_INDEX(RSI)] = context.Rsi; duke@435: ptrRegs[REG_INDEX(RAX)] = context.Rax; duke@435: ptrRegs[REG_INDEX(RCX)] = context.Rcx; duke@435: ptrRegs[REG_INDEX(RDX)] = context.Rdx; duke@435: ptrRegs[REG_INDEX(RBX)] = context.Rbx; duke@435: ptrRegs[REG_INDEX(RBP)] = context.Rbp; duke@435: ptrRegs[REG_INDEX(RSP)] = context.Rsp; duke@435: duke@435: ptrRegs[REG_INDEX(R8)] = context.R8; duke@435: ptrRegs[REG_INDEX(R9)] = context.R9; duke@435: ptrRegs[REG_INDEX(R10)] = context.R10; duke@435: ptrRegs[REG_INDEX(R11)] = context.R11; duke@435: ptrRegs[REG_INDEX(R12)] = context.R12; duke@435: ptrRegs[REG_INDEX(R13)] = context.R13; duke@435: ptrRegs[REG_INDEX(R14)] = context.R14; duke@435: ptrRegs[REG_INDEX(R15)] = context.R15; duke@435: duke@435: // Program counter duke@435: ptrRegs[REG_INDEX(RIP)] = context.Rip; duke@435: #endif duke@435: duke@435: env->ReleaseLongArrayElements(regs, ptrRegs, JNI_COMMIT); duke@435: CHECK_EXCEPTION_(false); duke@435: duke@435: env->CallVoidMethod(obj, setThreadIntegerRegisterSet_ID, duke@435: (jlong) ptrThreadIds.asPtr()[t], regs); duke@435: CHECK_EXCEPTION_(false); duke@435: duke@435: ULONG sysId; duke@435: if (ptrIDebugSystemObjects->GetCurrentThreadSystemId(&sysId) != S_OK) { duke@435: THROW_NEW_DEBUGGER_EXCEPTION_("Windbg Error: GetCurrentThreadSystemId failed!", false); duke@435: } duke@435: duke@435: env->CallVoidMethod(obj, addThread_ID, (jlong) sysId); duke@435: CHECK_EXCEPTION_(false); duke@435: } duke@435: duke@435: return true; duke@435: } duke@435: duke@435: /* duke@435: * Class: sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal duke@435: * Method: attach0 duke@435: * Signature: (Ljava/lang/String;Ljava/lang/String;)V duke@435: */ duke@435: JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal_attach0__Ljava_lang_String_2Ljava_lang_String_2 duke@435: (JNIEnv *env, jobject obj, jstring execName, jstring coreFileName) { duke@435: duke@435: if (getWindbgInterfaces(env, obj) == false) { duke@435: return; duke@435: } duke@435: duke@435: if (openDumpFile(env, obj, coreFileName) == false) { duke@435: return; duke@435: } duke@435: duke@435: if (addLoadObjects(env, obj) == false) { duke@435: return; duke@435: } duke@435: duke@435: if (addThreads(env, obj) == false) { duke@435: return; duke@435: } duke@435: } duke@435: duke@435: /* duke@435: * Class: sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal duke@435: * Method: attach0 duke@435: * Signature: (I)V duke@435: */ duke@435: JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal_attach0__I duke@435: (JNIEnv *env, jobject obj, jint pid) { duke@435: duke@435: if (getWindbgInterfaces(env, obj) == false) { duke@435: return; duke@435: } duke@435: duke@435: if (attachToProcess(env, obj, pid) == false) { duke@435: return; duke@435: } duke@435: duke@435: if (addLoadObjects(env, obj) == false) { duke@435: return; duke@435: } duke@435: duke@435: if (addThreads(env, obj) == false) { duke@435: return; duke@435: } duke@435: } duke@435: duke@435: duke@435: static bool releaseWindbgInterfaces(JNIEnv* env, jobject obj) { duke@435: IDebugDataSpaces* ptrIDebugDataSpaces = (IDebugDataSpaces*) env->GetLongField(obj, duke@435: ptrIDebugDataSpaces_ID); duke@435: CHECK_EXCEPTION_(false); duke@435: if (ptrIDebugDataSpaces != 0) { duke@435: ptrIDebugDataSpaces->Release(); duke@435: } duke@435: duke@435: IDebugOutputCallbacks* ptrIDebugOutputCallbacks = (IDebugOutputCallbacks*) duke@435: env->GetLongField(obj, ptrIDebugOutputCallbacks_ID); duke@435: CHECK_EXCEPTION_(false); duke@435: if (ptrIDebugOutputCallbacks != 0) { duke@435: ptrIDebugOutputCallbacks->Release(); duke@435: } duke@435: duke@435: IDebugAdvanced* ptrIDebugAdvanced = (IDebugAdvanced*) env->GetLongField(obj, duke@435: ptrIDebugAdvanced_ID); duke@435: CHECK_EXCEPTION_(false); duke@435: duke@435: if (ptrIDebugAdvanced != 0) { duke@435: ptrIDebugAdvanced->Release(); duke@435: } duke@435: duke@435: IDebugSymbols* ptrIDebugSymbols = (IDebugSymbols*) env->GetLongField(obj, duke@435: ptrIDebugSymbols_ID); duke@435: CHECK_EXCEPTION_(false); duke@435: if (ptrIDebugSymbols != 0) { duke@435: ptrIDebugSymbols->Release(); duke@435: } duke@435: duke@435: IDebugSystemObjects* ptrIDebugSystemObjects = (IDebugSystemObjects*) env->GetLongField(obj, duke@435: ptrIDebugSystemObjects_ID); duke@435: CHECK_EXCEPTION_(false); duke@435: if (ptrIDebugSystemObjects != 0) { duke@435: ptrIDebugSystemObjects->Release(); duke@435: } duke@435: duke@435: IDebugControl* ptrIDebugControl = (IDebugControl*) env->GetLongField(obj, duke@435: ptrIDebugControl_ID); duke@435: CHECK_EXCEPTION_(false); duke@435: if (ptrIDebugControl != 0) { duke@435: ptrIDebugControl->Release(); duke@435: } duke@435: duke@435: IDebugClient* ptrIDebugClient = (IDebugClient*) env->GetLongField(obj, duke@435: ptrIDebugClient_ID); duke@435: CHECK_EXCEPTION_(false); duke@435: if (ptrIDebugClient != 0) { duke@435: ptrIDebugClient->Release(); duke@435: } duke@435: duke@435: return true; duke@435: } duke@435: duke@435: /* duke@435: * Class: sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal duke@435: * Method: detach0 duke@435: * Signature: ()V duke@435: */ duke@435: JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal_detach0 duke@435: (JNIEnv *env, jobject obj) { duke@435: IDebugClient* ptrIDebugClient = (IDebugClient*) env->GetLongField(obj, duke@435: ptrIDebugClient_ID); duke@435: CHECK_EXCEPTION; duke@435: ptrIDebugClient->DetachProcesses(); duke@435: releaseWindbgInterfaces(env, obj); duke@435: } duke@435: duke@435: duke@435: /* duke@435: * Class: sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal duke@435: * Method: readBytesFromProcess0 duke@435: * Signature: (JJ)[B duke@435: */ duke@435: JNIEXPORT jbyteArray JNICALL Java_sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal_readBytesFromProcess0 duke@435: (JNIEnv *env, jobject obj, jlong address, jlong numBytes) { duke@435: jbyteArray byteArray = env->NewByteArray((long) numBytes); duke@435: CHECK_EXCEPTION_(0); duke@435: duke@435: jboolean isCopy = JNI_FALSE; duke@435: jbyte* bytePtr = env->GetByteArrayElements(byteArray, &isCopy); duke@435: CHECK_EXCEPTION_(0); duke@435: duke@435: IDebugDataSpaces* ptrIDebugDataSpaces = (IDebugDataSpaces*) env->GetLongField(obj, duke@435: ptrIDebugDataSpaces_ID); duke@435: CHECK_EXCEPTION_(0); duke@435: duke@435: ULONG bytesRead; duke@435: if (ptrIDebugDataSpaces->ReadVirtual((ULONG64) address, (PVOID) bytePtr, duke@435: (ULONG)numBytes, &bytesRead) != S_OK) { duke@435: THROW_NEW_DEBUGGER_EXCEPTION_("Windbg Error: ReadVirtual failed!", 0); duke@435: } duke@435: duke@435: if (bytesRead != numBytes) { duke@435: return 0; duke@435: } duke@435: duke@435: env->ReleaseByteArrayElements(byteArray, bytePtr, 0); duke@435: CHECK_EXCEPTION_(0); duke@435: duke@435: return byteArray; duke@435: } duke@435: duke@435: /* duke@435: * Class: sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal duke@435: * Method: getThreadIdFromSysId0 duke@435: * Signature: (J)J duke@435: */ duke@435: JNIEXPORT jlong JNICALL Java_sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal_getThreadIdFromSysId0 duke@435: (JNIEnv *env, jobject obj, jlong sysId) { duke@435: IDebugSystemObjects* ptrIDebugSystemObjects = (IDebugSystemObjects*) env->GetLongField(obj, duke@435: ptrIDebugSystemObjects_ID); duke@435: CHECK_EXCEPTION_(0); duke@435: duke@435: ULONG id = 0; duke@435: if (ptrIDebugSystemObjects->GetThreadIdBySystemId((ULONG)sysId, &id) != S_OK) { duke@435: THROW_NEW_DEBUGGER_EXCEPTION_("Windbg Error: GetThreadIdBySystemId failed!", 0); duke@435: } duke@435: duke@435: return (jlong) id; duke@435: } duke@435: duke@435: // manage COM 'auto' pointers (to avoid multiple Release duke@435: // calls at every early (exception) returns). Similar to AutoArrayPtr. duke@435: duke@435: template duke@435: class AutoCOMPtr { duke@435: T* m_ptr; duke@435: duke@435: public: duke@435: AutoCOMPtr(T* ptr) : m_ptr(ptr) { duke@435: } duke@435: duke@435: ~AutoCOMPtr() { duke@435: if (m_ptr) { duke@435: m_ptr->Release(); duke@435: } duke@435: } duke@435: duke@435: T* operator->() { duke@435: return m_ptr; duke@435: } duke@435: }; duke@435: duke@435: /* duke@435: * Class: sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal duke@435: * Method: consoleExecuteCommand0 duke@435: * Signature: (Ljava/lang/String;)Ljava/lang/String; duke@435: */ duke@435: JNIEXPORT jstring JNICALL Java_sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal_consoleExecuteCommand0 duke@435: (JNIEnv *env, jobject obj, jstring cmd) { duke@435: jboolean isCopy = JNI_FALSE; duke@435: const char* buf = env->GetStringUTFChars(cmd, &isCopy); duke@435: CHECK_EXCEPTION_(0); duke@435: AutoJavaString command(env, cmd, buf); duke@435: duke@435: IDebugClient* ptrIDebugClient = (IDebugClient*) env->GetLongField(obj, ptrIDebugClient_ID); duke@435: CHECK_EXCEPTION_(0); duke@435: duke@435: IDebugClient* tmpClientPtr = 0; duke@435: if (ptrIDebugClient->CreateClient(&tmpClientPtr) != S_OK) { duke@435: THROW_NEW_DEBUGGER_EXCEPTION_("Windbg Error: CreateClient failed!", 0); duke@435: } duke@435: AutoCOMPtr tmpClient(tmpClientPtr); duke@435: duke@435: IDebugControl* tmpControlPtr = 0; duke@435: if (tmpClient->QueryInterface(__uuidof(IDebugControl), (PVOID*) &tmpControlPtr) != S_OK) { duke@435: THROW_NEW_DEBUGGER_EXCEPTION_("Windbg Error: QueryInterface (IDebugControl) failed", 0); duke@435: } duke@435: AutoCOMPtr tmpControl(tmpControlPtr); duke@435: duke@435: SAOutputCallbacks* saOutputCallbacks = (SAOutputCallbacks*) env->GetLongField(obj, duke@435: ptrIDebugOutputCallbacks_ID); duke@435: CHECK_EXCEPTION_(0); duke@435: duke@435: saOutputCallbacks->clearBuffer(); duke@435: duke@435: if (tmpClient->SetOutputCallbacks(saOutputCallbacks) != S_OK) { duke@435: THROW_NEW_DEBUGGER_EXCEPTION_("Windbg Error: SetOutputCallbacks failed!", 0); duke@435: } duke@435: duke@435: tmpControl->Execute(DEBUG_OUTPUT_VERBOSE, command, DEBUG_EXECUTE_DEFAULT); duke@435: duke@435: const char* output = saOutputCallbacks->getBuffer(); duke@435: if (output == 0) { duke@435: output = ""; duke@435: } duke@435: duke@435: jstring res = env->NewStringUTF(output); duke@435: saOutputCallbacks->clearBuffer(); duke@435: return res; duke@435: } duke@435: duke@435: /* duke@435: * Class: sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal duke@435: * Method: lookupByName0 duke@435: * Signature: (Ljava/lang/String;Ljava/lang/String;)J duke@435: */ duke@435: duke@435: JNIEXPORT jlong JNICALL Java_sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal_lookupByName0 duke@435: (JNIEnv *env, jobject obj, jstring objName, jstring sym) { duke@435: IDebugSymbols* ptrIDebugSymbols = (IDebugSymbols*) env->GetLongField(obj, duke@435: ptrIDebugSymbols_ID); duke@435: CHECK_EXCEPTION_(0); duke@435: duke@435: jboolean isCopy; duke@435: const char* buf = env->GetStringUTFChars(sym, &isCopy); duke@435: CHECK_EXCEPTION_(0); duke@435: AutoJavaString name(env, sym, buf); duke@435: duke@435: ULONG64 offset = 0L; duke@435: if (strstr(name, "::") != 0) { duke@435: ptrIDebugSymbols->AddSymbolOptions(SYMOPT_UNDNAME); duke@435: } else { duke@435: ptrIDebugSymbols->RemoveSymbolOptions(SYMOPT_UNDNAME); duke@435: } duke@435: if (ptrIDebugSymbols->GetOffsetByName(name, &offset) != S_OK) { duke@435: return (jlong) 0; duke@435: } duke@435: return (jlong) offset; duke@435: } duke@435: duke@435: #define SYMBOL_BUFSIZE 512 duke@435: /* duke@435: * Class: sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal duke@435: * Method: lookupByAddress0 duke@435: * Signature: (J)Lsun/jvm/hotspot/debugger/cdbg/ClosestSymbol; duke@435: */ duke@435: JNIEXPORT jobject JNICALL Java_sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal_lookupByAddress0 duke@435: (JNIEnv *env, jobject obj, jlong address) { duke@435: IDebugSymbols* ptrIDebugSymbols = (IDebugSymbols*) env->GetLongField(obj, duke@435: ptrIDebugSymbols_ID); duke@435: CHECK_EXCEPTION_(0); duke@435: duke@435: ULONG64 disp = 0L; duke@435: char buf[SYMBOL_BUFSIZE]; duke@435: memset(buf, 0, sizeof(buf)); duke@435: duke@435: if (ptrIDebugSymbols->GetNameByOffset(address, buf, sizeof(buf),0,&disp) duke@435: != S_OK) { duke@435: return 0; duke@435: } duke@435: duke@435: jstring sym = env->NewStringUTF(buf); duke@435: CHECK_EXCEPTION_(0); duke@435: jobject res = env->CallObjectMethod(obj, createClosestSymbol_ID, sym, disp); duke@435: CHECK_EXCEPTION_(0); duke@435: return res; duke@435: }