1 /*
   2  * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 // Disable CRT security warning against strcpy/strcat
  26 #pragma warning(disable: 4996)
  27 
  28 #if _MSC_VER >= 1900
  29 // typedef ignored on left when no variable is declared
  30 #pragma warning(disable: 4091) 
  31 #endif
  32 
  33 // this is source code windbg based SA debugger agent to debug
  34 // Dr. Watson dump files and process snapshots.
  35 
  36 #include "sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal.h"
  37 
  38 #ifdef _M_IX86
  39   #include "sun_jvm_hotspot_debugger_x86_X86ThreadContext.h"
  40   #define NPRGREG sun_jvm_hotspot_debugger_x86_X86ThreadContext_NPRGREG
  41 #elif _M_AMD64
  42   #include "sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext.h"
  43   #define NPRGREG sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_NPRGREG
  44 #else
  45   #error "SA windbg back-end is not supported for your cpu!"
  46 #endif
  47 
  48 #include <limits.h>
  49 #include <windows.h>
  50 
  51 #ifndef STDMETHODV
  52 #define STDMETHODV(method) virtual HRESULT STDMETHODVCALLTYPE method
  53 #endif
  54 
  55 #define DEBUG_NO_IMPLEMENTATION
  56 #include <dbgeng.h>
  57 #include <dbghelp.h>
  58 
  59 // simple template to manage array delete across early (error) returns
  60 
  61 template <class T>
  62 class AutoArrayPtr {
  63       T* m_ptr;
  64    public:
  65       AutoArrayPtr(T* ptr) : m_ptr(ptr) {
  66       }
  67 
  68       ~AutoArrayPtr() {
  69          delete [] m_ptr;
  70       }
  71 
  72       T* asPtr() {
  73          return m_ptr;
  74       }
  75 };
  76 
  77 class AutoJavaString {
  78       JNIEnv* m_env;
  79       jstring m_str;
  80       const char* m_buf;
  81 
  82    public:
  83       AutoJavaString(JNIEnv* env, jstring str, const char* buf)
  84         : m_env(env), m_str(str), m_buf(buf) {
  85       }
  86 
  87       ~AutoJavaString() {
  88          m_env->ReleaseStringUTFChars(m_str, m_buf);
  89       }
  90 
  91       operator const char* () {
  92          return m_buf;
  93       }
  94 };
  95 
  96 // field and method IDs we want here
  97 
  98 static jfieldID imagePath_ID                    = 0;
  99 static jfieldID symbolPath_ID                   = 0;
 100 static jfieldID ptrIDebugClient_ID              = 0;
 101 static jfieldID ptrIDebugControl_ID             = 0;
 102 static jfieldID ptrIDebugDataSpaces_ID          = 0;
 103 static jfieldID ptrIDebugOutputCallbacks_ID     = 0;
 104 static jfieldID ptrIDebugAdvanced_ID            = 0;
 105 static jfieldID ptrIDebugSymbols_ID             = 0;
 106 static jfieldID ptrIDebugSystemObjects_ID       = 0;
 107 
 108 static jmethodID addLoadObject_ID               = 0;
 109 static jmethodID addThread_ID                   = 0;
 110 static jmethodID createClosestSymbol_ID         = 0;
 111 static jmethodID setThreadIntegerRegisterSet_ID = 0;
 112 
 113 #define CHECK_EXCEPTION_(value) if(env->ExceptionOccurred()) { return value; }
 114 #define CHECK_EXCEPTION if(env->ExceptionOccurred()) { return;}
 115 
 116 #define THROW_NEW_DEBUGGER_EXCEPTION_(str, value) { \
 117                           throwNewDebuggerException(env, str); return value; }
 118 
 119 #define THROW_NEW_DEBUGGER_EXCEPTION(str) { throwNewDebuggerException(env, str); \
 120  return;}
 121 
 122 static void throwNewDebuggerException(JNIEnv* env, const char* errMsg) {
 123   jclass clazz = env->FindClass("sun/jvm/hotspot/debugger/DebuggerException");
 124   CHECK_EXCEPTION;
 125   env->ThrowNew(clazz, errMsg);
 126 }
 127 
 128 /*
 129  * Class:     sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal
 130  * Method:    initIDs
 131  * Signature: ()V
 132  */
 133 JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal_initIDs
 134   (JNIEnv *env, jclass clazz) {
 135   imagePath_ID = env->GetStaticFieldID(clazz, "imagePath", "Ljava/lang/String;");
 136   CHECK_EXCEPTION;
 137 
 138   symbolPath_ID = env->GetStaticFieldID(clazz, "symbolPath", "Ljava/lang/String;");
 139   CHECK_EXCEPTION;
 140 
 141   ptrIDebugClient_ID = env->GetFieldID(clazz, "ptrIDebugClient", "J");
 142   CHECK_EXCEPTION;
 143 
 144   ptrIDebugControl_ID = env->GetFieldID(clazz, "ptrIDebugControl", "J");
 145   CHECK_EXCEPTION;
 146 
 147   ptrIDebugDataSpaces_ID = env->GetFieldID(clazz, "ptrIDebugDataSpaces", "J");
 148   CHECK_EXCEPTION;
 149 
 150   ptrIDebugOutputCallbacks_ID = env->GetFieldID(clazz,
 151                                             "ptrIDebugOutputCallbacks", "J");
 152   CHECK_EXCEPTION;
 153 
 154   ptrIDebugAdvanced_ID = env->GetFieldID(clazz, "ptrIDebugAdvanced", "J");
 155   CHECK_EXCEPTION;
 156 
 157   ptrIDebugSymbols_ID = env->GetFieldID(clazz,
 158                                          "ptrIDebugSymbols", "J");
 159   CHECK_EXCEPTION;
 160 
 161   ptrIDebugSystemObjects_ID = env->GetFieldID(clazz,
 162                                          "ptrIDebugSystemObjects", "J");
 163   CHECK_EXCEPTION;
 164 
 165   addLoadObject_ID = env->GetMethodID(clazz, "addLoadObject",
 166                                          "(Ljava/lang/String;JJ)V");
 167   CHECK_EXCEPTION;
 168 
 169   addThread_ID = env->GetMethodID(clazz, "addThread", "(J)V");
 170   CHECK_EXCEPTION;
 171 
 172   createClosestSymbol_ID = env->GetMethodID(clazz, "createClosestSymbol",
 173     "(Ljava/lang/String;J)Lsun/jvm/hotspot/debugger/cdbg/ClosestSymbol;");
 174   CHECK_EXCEPTION;
 175 
 176   setThreadIntegerRegisterSet_ID = env->GetMethodID(clazz,
 177                                          "setThreadIntegerRegisterSet", "(J[J)V");
 178   CHECK_EXCEPTION;
 179 
 180 }
 181 
 182 // class for IDebugOutputCallbacks
 183 
 184 class SAOutputCallbacks : public IDebugOutputCallbacks {
 185    LONG  m_refCount;
 186    char* m_msgBuffer;
 187 
 188    public:
 189       SAOutputCallbacks() : m_refCount(0), m_msgBuffer(0) {
 190       }
 191 
 192       ~SAOutputCallbacks() {
 193          clearBuffer();
 194       }
 195 
 196       const char* getBuffer() const {
 197          return m_msgBuffer;
 198       }
 199 
 200       void clearBuffer() {
 201          if (m_msgBuffer) {
 202             free(m_msgBuffer);
 203             m_msgBuffer = 0;
 204          }
 205       }
 206 
 207       STDMETHOD_(ULONG, AddRef)(THIS);
 208       STDMETHOD_(ULONG, Release)(THIS);
 209       STDMETHOD(QueryInterface)(THIS_
 210                                 IN REFIID interfaceId,
 211                                 OUT PVOID* ppInterface);
 212       STDMETHOD(Output)(THIS_
 213                         IN ULONG mask,
 214                         IN PCSTR msg);
 215 };
 216 
 217 STDMETHODIMP_(ULONG) SAOutputCallbacks::AddRef(THIS) {
 218    InterlockedIncrement(&m_refCount);
 219    return m_refCount;
 220 }
 221 
 222 STDMETHODIMP_(ULONG) SAOutputCallbacks::Release(THIS) {
 223    LONG retVal;
 224    InterlockedDecrement(&m_refCount);
 225    retVal = m_refCount;
 226    if (retVal == 0) {
 227       delete this;
 228    }
 229    return retVal;
 230 }
 231 
 232 STDMETHODIMP SAOutputCallbacks::QueryInterface(THIS_
 233                                           IN REFIID interfaceId,
 234                                           OUT PVOID* ppInterface) {
 235    *ppInterface = 0;
 236    HRESULT res = E_NOINTERFACE;
 237    if (TRUE == IsEqualIID(interfaceId, __uuidof(IUnknown)) ||
 238        TRUE == IsEqualIID(interfaceId, __uuidof(IDebugOutputCallbacks))) {
 239       *ppInterface = (IDebugOutputCallbacks*) this;
 240       AddRef();
 241       res = S_OK;
 242    }
 243    return res;
 244 }
 245 
 246 STDMETHODIMP SAOutputCallbacks::Output(THIS_
 247                                        IN ULONG mask,
 248                                        IN PCSTR msg) {
 249    int len = (int) (strlen(msg) + 1);
 250    if (m_msgBuffer == 0) {
 251       m_msgBuffer = (char*) malloc(len);
 252       if (m_msgBuffer == 0) {
 253          fprintf(stderr, "out of memory debugger output!\n");
 254          return S_FALSE;
 255       }
 256       strcpy(m_msgBuffer, msg);
 257    } else {
 258       m_msgBuffer = (char*) realloc(m_msgBuffer, len + strlen(m_msgBuffer));
 259       if (m_msgBuffer == 0) {
 260          fprintf(stderr, "out of memory debugger output!\n");
 261          return S_FALSE;
 262       }
 263       strcat(m_msgBuffer, msg);
 264    }
 265    return S_OK;
 266 }
 267 
 268 static bool getWindbgInterfaces(JNIEnv* env, jobject obj) {
 269   // get windbg interfaces ..
 270 
 271   IDebugClient* ptrIDebugClient = 0;
 272   if (DebugCreate(__uuidof(IDebugClient), (PVOID*) &ptrIDebugClient) != S_OK) {
 273      THROW_NEW_DEBUGGER_EXCEPTION_("Windbg Error: not able to create IDebugClient object!", false);
 274   }
 275   env->SetLongField(obj, ptrIDebugClient_ID, (jlong) ptrIDebugClient);
 276 
 277   IDebugControl* ptrIDebugControl = 0;
 278   if (ptrIDebugClient->QueryInterface(__uuidof(IDebugControl), (PVOID*) &ptrIDebugControl)
 279      != S_OK) {
 280      THROW_NEW_DEBUGGER_EXCEPTION_("Windbg Error: not able to get IDebugControl", false);
 281   }
 282   env->SetLongField(obj, ptrIDebugControl_ID, (jlong) ptrIDebugControl);
 283 
 284   IDebugDataSpaces* ptrIDebugDataSpaces = 0;
 285   if (ptrIDebugClient->QueryInterface(__uuidof(IDebugDataSpaces), (PVOID*) &ptrIDebugDataSpaces)
 286      != S_OK) {
 287      THROW_NEW_DEBUGGER_EXCEPTION_("Windbg Error: not able to get IDebugDataSpaces object!", false);
 288   }
 289   env->SetLongField(obj, ptrIDebugDataSpaces_ID, (jlong) ptrIDebugDataSpaces);
 290 
 291   SAOutputCallbacks* ptrIDebugOutputCallbacks = new SAOutputCallbacks();
 292   ptrIDebugOutputCallbacks->AddRef();
 293   env->SetLongField(obj, ptrIDebugOutputCallbacks_ID, (jlong) ptrIDebugOutputCallbacks);
 294   CHECK_EXCEPTION_(false);
 295 
 296   IDebugAdvanced* ptrIDebugAdvanced = 0;
 297   if (ptrIDebugClient->QueryInterface(__uuidof(IDebugAdvanced), (PVOID*) &ptrIDebugAdvanced)
 298      != S_OK) {
 299      THROW_NEW_DEBUGGER_EXCEPTION_("Windbg Error: not able to get IDebugAdvanced object!", false);
 300   }
 301   env->SetLongField(obj, ptrIDebugAdvanced_ID, (jlong) ptrIDebugAdvanced);
 302 
 303   IDebugSymbols* ptrIDebugSymbols = 0;
 304   if (ptrIDebugClient->QueryInterface(__uuidof(IDebugSymbols), (PVOID*) &ptrIDebugSymbols)
 305      != S_OK) {
 306      THROW_NEW_DEBUGGER_EXCEPTION_("Windbg Error: not able to get IDebugSymbols object!", false);
 307   }
 308   env->SetLongField(obj, ptrIDebugSymbols_ID, (jlong) ptrIDebugSymbols);
 309 
 310   IDebugSystemObjects* ptrIDebugSystemObjects = 0;
 311   if (ptrIDebugClient->QueryInterface(__uuidof(IDebugSystemObjects), (PVOID*) &ptrIDebugSystemObjects)
 312      != S_OK) {
 313      THROW_NEW_DEBUGGER_EXCEPTION_("Windbg Error: not able to get IDebugSystemObjects object!", false);
 314   }
 315   env->SetLongField(obj, ptrIDebugSystemObjects_ID, (jlong) ptrIDebugSystemObjects);
 316 
 317   return true;
 318 }
 319 
 320 static bool setImageAndSymbolPath(JNIEnv* env, jobject obj) {
 321   jboolean isCopy;
 322   jclass clazz = env->GetObjectClass(obj);
 323   CHECK_EXCEPTION_(false);
 324   jstring path;
 325   const char* buf;
 326 
 327   path = (jstring) env->GetStaticObjectField(clazz, imagePath_ID);
 328   CHECK_EXCEPTION_(false);
 329   if (path == NULL) {
 330      THROW_NEW_DEBUGGER_EXCEPTION_("Windbg Error: not able to get imagePath field ID!", false);
 331   }
 332   buf = env->GetStringUTFChars(path, &isCopy);
 333   CHECK_EXCEPTION_(false);
 334   AutoJavaString imagePath(env, path, buf);
 335 
 336   path = (jstring) env->GetStaticObjectField(clazz, symbolPath_ID);
 337   CHECK_EXCEPTION_(false);
 338   if (path == NULL) {
 339      THROW_NEW_DEBUGGER_EXCEPTION_("Windbg Error: not able to get symbolPath field ID!", false);
 340   }
 341   buf = env->GetStringUTFChars(path, &isCopy);
 342   CHECK_EXCEPTION_(false);
 343   AutoJavaString symbolPath(env, path, buf);
 344 
 345   IDebugSymbols* ptrIDebugSymbols = (IDebugSymbols*) env->GetLongField(obj,
 346                                                       ptrIDebugSymbols_ID);
 347   CHECK_EXCEPTION_(false);
 348 
 349   ptrIDebugSymbols->SetImagePath(imagePath);
 350   ptrIDebugSymbols->SetSymbolPath(symbolPath);
 351   return true;
 352 }
 353 
 354 static bool openDumpFile(JNIEnv* env, jobject obj, jstring coreFileName) {
 355   // open the dump file
 356   jboolean isCopy;
 357   const char* buf = env->GetStringUTFChars(coreFileName, &isCopy);
 358   CHECK_EXCEPTION_(false);
 359   AutoJavaString coreFile(env, coreFileName, buf);
 360   if (setImageAndSymbolPath(env, obj) == false) {
 361      return false;
 362   }
 363 
 364   IDebugClient* ptrIDebugClient = (IDebugClient*) env->GetLongField(obj,
 365                                                       ptrIDebugClient_ID);
 366   CHECK_EXCEPTION_(false);
 367   if (ptrIDebugClient->OpenDumpFile(coreFile) != S_OK) {
 368      THROW_NEW_DEBUGGER_EXCEPTION_("Windbg Error: OpenDumpFile failed!", false);
 369   }
 370 
 371   IDebugControl* ptrIDebugControl = (IDebugControl*) env->GetLongField(obj,
 372                                                      ptrIDebugControl_ID);
 373   CHECK_EXCEPTION_(false);
 374   if (ptrIDebugControl->WaitForEvent(DEBUG_WAIT_DEFAULT, INFINITE) != S_OK) {
 375      THROW_NEW_DEBUGGER_EXCEPTION_("Windbg Error: WaitForEvent failed!", false);
 376   }
 377 
 378   return true;
 379 }
 380 
 381 
 382 static bool attachToProcess(JNIEnv* env, jobject obj, jint pid) {
 383   if (setImageAndSymbolPath(env, obj) == false) {
 384      return false;
 385   }
 386   IDebugClient* ptrIDebugClient = (IDebugClient*) env->GetLongField(obj,
 387                                                       ptrIDebugClient_ID);
 388   CHECK_EXCEPTION_(false);
 389 
 390   /***********************************************************************************
 391 
 392      We are attaching to a process in 'read-only' mode. i.e., we do not want to
 393      put breakpoints, suspend/resume threads etc. For read-only JDI and HSDB kind of
 394      usage this should suffice.
 395 
 396      Please refer to DEBUG_ATTACH_NONINVASIVE mode source comments from dbgeng.h.
 397      In this mode, debug engine does not call DebugActiveProrcess. i.e., we are not
 398      actually debugging at all. We can safely 'detach' from the process anytime
 399      we want and debuggee process is left as is on all Windows variants.
 400 
 401      This also makes JDI-on-SA installation/usage simpler because with this we would
 402      not need a tool like ServiceInstaller from http://www.kcmultimedia.com/smaster.
 403 
 404   ***********************************************************************************/
 405 
 406 
 407   if (ptrIDebugClient->AttachProcess(0, pid, DEBUG_ATTACH_NONINVASIVE) != S_OK) {
 408      THROW_NEW_DEBUGGER_EXCEPTION_("Windbg Error: AttachProcess failed!", false);
 409   }
 410 
 411   IDebugControl* ptrIDebugControl = (IDebugControl*) env->GetLongField(obj,
 412                                                      ptrIDebugControl_ID);
 413   CHECK_EXCEPTION_(false);
 414   if (ptrIDebugControl->WaitForEvent(DEBUG_WAIT_DEFAULT, INFINITE) != S_OK) {
 415      THROW_NEW_DEBUGGER_EXCEPTION_("Windbg Error: WaitForEvent failed!", false);
 416   }
 417 
 418   return true;
 419 }
 420 
 421 
 422 static bool addLoadObjects(JNIEnv* env, jobject obj) {
 423   IDebugSymbols* ptrIDebugSymbols = (IDebugSymbols*) env->GetLongField(obj,
 424                                                       ptrIDebugSymbols_ID);
 425   CHECK_EXCEPTION_(false);
 426   ULONG loaded = 0, unloaded = 0;
 427   if (ptrIDebugSymbols->GetNumberModules(&loaded, &unloaded) != S_OK) {
 428      THROW_NEW_DEBUGGER_EXCEPTION_("Windbg Error: GetNumberModules failed!", false);
 429   }
 430 
 431   AutoArrayPtr<DEBUG_MODULE_PARAMETERS> params(new DEBUG_MODULE_PARAMETERS[loaded]);
 432 
 433   if (params.asPtr() == 0) {
 434       THROW_NEW_DEBUGGER_EXCEPTION_("out of memory to allocate debug module params!", false);
 435   }
 436 
 437   if (ptrIDebugSymbols->GetModuleParameters(loaded, 0, NULL, params.asPtr()) != S_OK) {
 438      THROW_NEW_DEBUGGER_EXCEPTION_("Windbg Error: GetModuleParameters failed!", false);
 439   }
 440 
 441   for (int u = 0; u < (int)loaded; u++) {
 442      TCHAR imageName[MAX_PATH];
 443      if (ptrIDebugSymbols->GetModuleNames(DEBUG_ANY_ID, params.asPtr()[u].Base,
 444                                       imageName, MAX_PATH, NULL, NULL,
 445                                       0, NULL, NULL, 0, NULL) != S_OK) {
 446         THROW_NEW_DEBUGGER_EXCEPTION_("Windbg Error: GetModuleNames failed!", false);
 447      }
 448 
 449      jstring strName = env->NewStringUTF(imageName);
 450      CHECK_EXCEPTION_(false);
 451      env->CallVoidMethod(obj, addLoadObject_ID, strName, (jlong) params.asPtr()[u].Size,
 452                                (jlong) params.asPtr()[u].Base);
 453      CHECK_EXCEPTION_(false);
 454   }
 455 
 456   return true;
 457 }
 458 
 459 static bool addThreads(JNIEnv* env, jobject obj) {
 460   IDebugSystemObjects* ptrIDebugSystemObjects = (IDebugSystemObjects*) env->GetLongField(obj,
 461                                                       ptrIDebugSystemObjects_ID);
 462   CHECK_EXCEPTION_(false);
 463 
 464   ULONG numThreads = 0;
 465   if (ptrIDebugSystemObjects->GetNumberThreads(&numThreads) != S_OK) {
 466      THROW_NEW_DEBUGGER_EXCEPTION_("Windbg Error: GetNumberThreads failed!", false);
 467   }
 468 
 469   AutoArrayPtr<ULONG> ptrSysThreadIds = new ULONG[numThreads];
 470 
 471   if (ptrSysThreadIds.asPtr() == 0) {
 472      THROW_NEW_DEBUGGER_EXCEPTION_("out of memory to allocate thread ids!", false);
 473   }
 474 
 475   AutoArrayPtr<ULONG> ptrThreadIds = new ULONG[numThreads];
 476 
 477   if (ptrThreadIds.asPtr() == 0) {
 478      THROW_NEW_DEBUGGER_EXCEPTION_("out of memory to allocate thread ids!", false);
 479   }
 480 
 481   if (ptrIDebugSystemObjects->GetThreadIdsByIndex(0, numThreads,
 482                                       ptrThreadIds.asPtr(), ptrSysThreadIds.asPtr()) != S_OK) {
 483      THROW_NEW_DEBUGGER_EXCEPTION_("Windbg Error: GetThreadIdsByIndex failed!", false);
 484   }
 485 
 486 
 487   IDebugAdvanced* ptrIDebugAdvanced = (IDebugAdvanced*) env->GetLongField(obj,
 488                                                       ptrIDebugAdvanced_ID);
 489   CHECK_EXCEPTION_(false);
 490 
 491   // for each thread, get register context and save it.
 492   for (ULONG t = 0; t < numThreads; t++) {
 493      if (ptrIDebugSystemObjects->SetCurrentThreadId(ptrThreadIds.asPtr()[t]) != S_OK) {
 494         THROW_NEW_DEBUGGER_EXCEPTION_("Windbg Error: SetCurrentThread failed!", false);
 495      }
 496 
 497      jlongArray regs = env->NewLongArray(NPRGREG);
 498      CHECK_EXCEPTION_(false);
 499 
 500      jboolean isCopy = JNI_FALSE;
 501      jlong* ptrRegs = env->GetLongArrayElements(regs, &isCopy);
 502      CHECK_EXCEPTION_(false);
 503 
 504      // copy register values from the CONTEXT struct
 505      CONTEXT context;
 506      memset(&context, 0, sizeof(CONTEXT));
 507 
 508 #undef REG_INDEX
 509 #ifdef _M_IX86
 510      #define REG_INDEX(x) sun_jvm_hotspot_debugger_x86_X86ThreadContext_##x
 511 
 512      context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
 513      ptrIDebugAdvanced->GetThreadContext(&context, sizeof(CONTEXT));
 514 
 515      ptrRegs[REG_INDEX(GS)]  = context.SegGs;
 516      ptrRegs[REG_INDEX(FS)]  = context.SegFs;
 517      ptrRegs[REG_INDEX(ES)]  = context.SegEs;
 518      ptrRegs[REG_INDEX(DS)]  = context.SegDs;
 519 
 520      ptrRegs[REG_INDEX(EDI)] = context.Edi;
 521      ptrRegs[REG_INDEX(ESI)] = context.Esi;
 522      ptrRegs[REG_INDEX(EBX)] = context.Ebx;
 523      ptrRegs[REG_INDEX(EDX)] = context.Edx;
 524      ptrRegs[REG_INDEX(ECX)] = context.Ecx;
 525      ptrRegs[REG_INDEX(EAX)] = context.Eax;
 526 
 527      ptrRegs[REG_INDEX(FP)] = context.Ebp;
 528      ptrRegs[REG_INDEX(PC)] = context.Eip;
 529      ptrRegs[REG_INDEX(CS)]  = context.SegCs;
 530      ptrRegs[REG_INDEX(EFL)] = context.EFlags;
 531      ptrRegs[REG_INDEX(SP)] = context.Esp;
 532      ptrRegs[REG_INDEX(SS)]  = context.SegSs;
 533 
 534      ptrRegs[REG_INDEX(DR0)] = context.Dr0;
 535      ptrRegs[REG_INDEX(DR1)] = context.Dr1;
 536      ptrRegs[REG_INDEX(DR2)] = context.Dr2;
 537      ptrRegs[REG_INDEX(DR3)] = context.Dr3;
 538      ptrRegs[REG_INDEX(DR6)] = context.Dr6;
 539      ptrRegs[REG_INDEX(DR7)] = context.Dr7;
 540 
 541 #elif _M_AMD64
 542      #define REG_INDEX(x) sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_##x
 543 
 544      context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
 545      ptrIDebugAdvanced->GetThreadContext(&context, sizeof(CONTEXT));
 546 
 547      // Segment Registers and processor flags
 548      ptrRegs[REG_INDEX(CS)]  = context.SegCs;
 549      ptrRegs[REG_INDEX(DS)]  = context.SegDs;
 550      ptrRegs[REG_INDEX(ES)]  = context.SegEs;
 551      ptrRegs[REG_INDEX(FS)]  = context.SegFs;
 552      ptrRegs[REG_INDEX(GS)]  = context.SegGs;
 553      ptrRegs[REG_INDEX(SS)]  = context.SegSs;
 554      ptrRegs[REG_INDEX(RFL)] = context.EFlags;
 555 
 556      // Integer registers
 557      ptrRegs[REG_INDEX(RDI)] = context.Rdi;
 558      ptrRegs[REG_INDEX(RSI)] = context.Rsi;
 559      ptrRegs[REG_INDEX(RAX)] = context.Rax;
 560      ptrRegs[REG_INDEX(RCX)] = context.Rcx;
 561      ptrRegs[REG_INDEX(RDX)] = context.Rdx;
 562      ptrRegs[REG_INDEX(RBX)] = context.Rbx;
 563      ptrRegs[REG_INDEX(RBP)] = context.Rbp;
 564      ptrRegs[REG_INDEX(RSP)] = context.Rsp;
 565 
 566      ptrRegs[REG_INDEX(R8)]  = context.R8;
 567      ptrRegs[REG_INDEX(R9)]  = context.R9;
 568      ptrRegs[REG_INDEX(R10)] = context.R10;
 569      ptrRegs[REG_INDEX(R11)] = context.R11;
 570      ptrRegs[REG_INDEX(R12)] = context.R12;
 571      ptrRegs[REG_INDEX(R13)] = context.R13;
 572      ptrRegs[REG_INDEX(R14)] = context.R14;
 573      ptrRegs[REG_INDEX(R15)] = context.R15;
 574 
 575      // Program counter
 576      ptrRegs[REG_INDEX(RIP)] = context.Rip;
 577 #endif
 578 
 579      env->ReleaseLongArrayElements(regs, ptrRegs, JNI_COMMIT);
 580      CHECK_EXCEPTION_(false);
 581 
 582      env->CallVoidMethod(obj, setThreadIntegerRegisterSet_ID,
 583                         (jlong) ptrThreadIds.asPtr()[t], regs);
 584      CHECK_EXCEPTION_(false);
 585 
 586      ULONG sysId;
 587      if (ptrIDebugSystemObjects->GetCurrentThreadSystemId(&sysId) != S_OK) {
 588         THROW_NEW_DEBUGGER_EXCEPTION_("Windbg Error: GetCurrentThreadSystemId failed!", false);
 589      }
 590 
 591      env->CallVoidMethod(obj, addThread_ID, (jlong) sysId);
 592      CHECK_EXCEPTION_(false);
 593   }
 594 
 595   return true;
 596 }
 597 
 598 /*
 599  * Class:     sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal
 600  * Method:    attach0
 601  * Signature: (Ljava/lang/String;Ljava/lang/String;)V
 602  */
 603 JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal_attach0__Ljava_lang_String_2Ljava_lang_String_2
 604   (JNIEnv *env, jobject obj, jstring execName, jstring coreFileName) {
 605 
 606   if (getWindbgInterfaces(env, obj) == false) {
 607      return;
 608   }
 609 
 610   if (openDumpFile(env, obj, coreFileName) == false) {
 611      return;
 612   }
 613 
 614   if (addLoadObjects(env, obj) == false) {
 615      return;
 616   }
 617 
 618   if (addThreads(env, obj) == false) {
 619      return;
 620   }
 621 }
 622 
 623 /*
 624  * Class:     sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal
 625  * Method:    attach0
 626  * Signature: (I)V
 627  */
 628 JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal_attach0__I
 629   (JNIEnv *env, jobject obj, jint pid) {
 630 
 631   if (getWindbgInterfaces(env, obj) == false) {
 632      return;
 633   }
 634 
 635   if (attachToProcess(env, obj, pid) == false) {
 636      return;
 637   }
 638 
 639   if (addLoadObjects(env, obj) == false) {
 640      return;
 641   }
 642 
 643   if (addThreads(env, obj) == false) {
 644      return;
 645   }
 646 }
 647 
 648 
 649 static bool releaseWindbgInterfaces(JNIEnv* env, jobject obj) {
 650   IDebugDataSpaces* ptrIDebugDataSpaces = (IDebugDataSpaces*) env->GetLongField(obj,
 651                                                       ptrIDebugDataSpaces_ID);
 652   CHECK_EXCEPTION_(false);
 653   if (ptrIDebugDataSpaces != 0) {
 654      ptrIDebugDataSpaces->Release();
 655   }
 656 
 657   IDebugOutputCallbacks* ptrIDebugOutputCallbacks = (IDebugOutputCallbacks*)
 658                           env->GetLongField(obj, ptrIDebugOutputCallbacks_ID);
 659   CHECK_EXCEPTION_(false);
 660   if (ptrIDebugOutputCallbacks != 0) {
 661      ptrIDebugOutputCallbacks->Release();
 662   }
 663 
 664   IDebugAdvanced* ptrIDebugAdvanced = (IDebugAdvanced*) env->GetLongField(obj,
 665                                                       ptrIDebugAdvanced_ID);
 666   CHECK_EXCEPTION_(false);
 667 
 668   if (ptrIDebugAdvanced != 0) {
 669      ptrIDebugAdvanced->Release();
 670   }
 671 
 672   IDebugSymbols* ptrIDebugSymbols = (IDebugSymbols*) env->GetLongField(obj,
 673                                                       ptrIDebugSymbols_ID);
 674   CHECK_EXCEPTION_(false);
 675   if (ptrIDebugSymbols != 0) {
 676      ptrIDebugSymbols->Release();
 677   }
 678 
 679   IDebugSystemObjects* ptrIDebugSystemObjects = (IDebugSystemObjects*) env->GetLongField(obj,
 680                                                       ptrIDebugSystemObjects_ID);
 681   CHECK_EXCEPTION_(false);
 682   if (ptrIDebugSystemObjects != 0) {
 683      ptrIDebugSystemObjects->Release();
 684   }
 685 
 686   IDebugControl* ptrIDebugControl = (IDebugControl*) env->GetLongField(obj,
 687                                                      ptrIDebugControl_ID);
 688   CHECK_EXCEPTION_(false);
 689   if (ptrIDebugControl != 0) {
 690      ptrIDebugControl->Release();
 691   }
 692 
 693   IDebugClient* ptrIDebugClient = (IDebugClient*) env->GetLongField(obj,
 694                                                       ptrIDebugClient_ID);
 695   CHECK_EXCEPTION_(false);
 696   if (ptrIDebugClient != 0) {
 697      ptrIDebugClient->Release();
 698   }
 699 
 700   return true;
 701 }
 702 
 703 /*
 704  * Class:     sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal
 705  * Method:    detach0
 706  * Signature: ()V
 707  */
 708 JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal_detach0
 709   (JNIEnv *env, jobject obj) {
 710   IDebugClient* ptrIDebugClient = (IDebugClient*) env->GetLongField(obj,
 711                                                       ptrIDebugClient_ID);
 712   CHECK_EXCEPTION;
 713   ptrIDebugClient->DetachProcesses();
 714   releaseWindbgInterfaces(env, obj);
 715 }
 716 
 717 
 718 /*
 719  * Class:     sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal
 720  * Method:    readBytesFromProcess0
 721  * Signature: (JJ)[B
 722  */
 723 JNIEXPORT jbyteArray JNICALL Java_sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal_readBytesFromProcess0
 724   (JNIEnv *env, jobject obj, jlong address, jlong numBytes) {
 725   jbyteArray byteArray = env->NewByteArray((long) numBytes);
 726   CHECK_EXCEPTION_(0);
 727 
 728   jboolean isCopy = JNI_FALSE;
 729   jbyte* bytePtr = env->GetByteArrayElements(byteArray, &isCopy);
 730   CHECK_EXCEPTION_(0);
 731 
 732   IDebugDataSpaces* ptrIDebugDataSpaces = (IDebugDataSpaces*) env->GetLongField(obj,
 733                                                        ptrIDebugDataSpaces_ID);
 734   CHECK_EXCEPTION_(0);
 735 
 736   ULONG bytesRead;
 737   if (ptrIDebugDataSpaces->ReadVirtual((ULONG64) address, (PVOID) bytePtr,
 738                                   (ULONG)numBytes, &bytesRead) != S_OK) {
 739      THROW_NEW_DEBUGGER_EXCEPTION_("Windbg Error: ReadVirtual failed!", 0);
 740   }
 741 
 742   if (bytesRead != numBytes) {
 743      return 0;
 744   }
 745 
 746   env->ReleaseByteArrayElements(byteArray, bytePtr, 0);
 747   CHECK_EXCEPTION_(0);
 748 
 749   return byteArray;
 750 }
 751 
 752 /*
 753  * Class:     sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal
 754  * Method:    getThreadIdFromSysId0
 755  * Signature: (J)J
 756  */
 757 JNIEXPORT jlong JNICALL Java_sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal_getThreadIdFromSysId0
 758   (JNIEnv *env, jobject obj, jlong sysId) {
 759   IDebugSystemObjects* ptrIDebugSystemObjects = (IDebugSystemObjects*) env->GetLongField(obj,
 760                                                     ptrIDebugSystemObjects_ID);
 761   CHECK_EXCEPTION_(0);
 762 
 763   ULONG id = 0;
 764   if (ptrIDebugSystemObjects->GetThreadIdBySystemId((ULONG)sysId, &id) != S_OK) {
 765      THROW_NEW_DEBUGGER_EXCEPTION_("Windbg Error: GetThreadIdBySystemId failed!", 0);
 766   }
 767 
 768   return (jlong) id;
 769 }
 770 
 771 // manage COM 'auto' pointers (to avoid multiple Release
 772 // calls at every early (exception) returns). Similar to AutoArrayPtr.
 773 
 774 template <class T>
 775 class AutoCOMPtr {
 776       T* m_ptr;
 777 
 778    public:
 779       AutoCOMPtr(T* ptr) : m_ptr(ptr) {
 780       }
 781 
 782       ~AutoCOMPtr() {
 783          if (m_ptr) {
 784             m_ptr->Release();
 785          }
 786       }
 787 
 788       T* operator->() {
 789          return m_ptr;
 790       }
 791 };
 792 
 793 /*
 794  * Class:     sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal
 795  * Method:    consoleExecuteCommand0
 796  * Signature: (Ljava/lang/String;)Ljava/lang/String;
 797  */
 798 JNIEXPORT jstring JNICALL Java_sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal_consoleExecuteCommand0
 799   (JNIEnv *env, jobject obj, jstring cmd) {
 800   jboolean isCopy = JNI_FALSE;
 801   const char* buf = env->GetStringUTFChars(cmd, &isCopy);
 802   CHECK_EXCEPTION_(0);
 803   AutoJavaString command(env, cmd, buf);
 804 
 805   IDebugClient* ptrIDebugClient = (IDebugClient*) env->GetLongField(obj, ptrIDebugClient_ID);
 806   CHECK_EXCEPTION_(0);
 807 
 808   IDebugClient*  tmpClientPtr = 0;
 809   if (ptrIDebugClient->CreateClient(&tmpClientPtr) != S_OK) {
 810      THROW_NEW_DEBUGGER_EXCEPTION_("Windbg Error: CreateClient failed!", 0);
 811   }
 812   AutoCOMPtr<IDebugClient> tmpClient(tmpClientPtr);
 813 
 814   IDebugControl* tmpControlPtr = 0;
 815   if (tmpClient->QueryInterface(__uuidof(IDebugControl), (PVOID*) &tmpControlPtr) != S_OK) {
 816      THROW_NEW_DEBUGGER_EXCEPTION_("Windbg Error: QueryInterface (IDebugControl) failed", 0);
 817   }
 818   AutoCOMPtr<IDebugControl> tmpControl(tmpControlPtr);
 819 
 820   SAOutputCallbacks* saOutputCallbacks = (SAOutputCallbacks*) env->GetLongField(obj,
 821                                                                    ptrIDebugOutputCallbacks_ID);
 822   CHECK_EXCEPTION_(0);
 823 
 824   saOutputCallbacks->clearBuffer();
 825 
 826   if (tmpClient->SetOutputCallbacks(saOutputCallbacks) != S_OK) {
 827      THROW_NEW_DEBUGGER_EXCEPTION_("Windbg Error: SetOutputCallbacks failed!", 0);
 828   }
 829 
 830   tmpControl->Execute(DEBUG_OUTPUT_VERBOSE, command, DEBUG_EXECUTE_DEFAULT);
 831 
 832   const char* output = saOutputCallbacks->getBuffer();
 833   if (output == 0) {
 834      output = "";
 835   }
 836 
 837   jstring res = env->NewStringUTF(output);
 838   saOutputCallbacks->clearBuffer();
 839   return res;
 840 }
 841 
 842 /*
 843  * Class:     sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal
 844  * Method:    lookupByName0
 845  * Signature: (Ljava/lang/String;Ljava/lang/String;)J
 846  */
 847 
 848 JNIEXPORT jlong JNICALL Java_sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal_lookupByName0
 849 (JNIEnv *env, jobject obj, jstring objName, jstring sym) {
 850   IDebugSymbols* ptrIDebugSymbols = (IDebugSymbols*) env->GetLongField(obj,
 851                                                       ptrIDebugSymbols_ID);
 852   CHECK_EXCEPTION_(0);
 853 
 854   jboolean isCopy;
 855   const char* buf = env->GetStringUTFChars(sym, &isCopy);
 856   CHECK_EXCEPTION_(0);
 857   AutoJavaString name(env, sym, buf);
 858 
 859   ULONG64 offset = 0L;
 860   if (strstr(name, "::") != 0) {
 861     ptrIDebugSymbols->AddSymbolOptions(SYMOPT_UNDNAME);
 862   } else {
 863     ptrIDebugSymbols->RemoveSymbolOptions(SYMOPT_UNDNAME);
 864   }
 865   if (ptrIDebugSymbols->GetOffsetByName(name, &offset) != S_OK) {
 866     return (jlong) 0;
 867   }
 868   return (jlong) offset;
 869 }
 870 
 871 #define SYMBOL_BUFSIZE 512
 872 /*
 873  * Class:     sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal
 874  * Method:    lookupByAddress0
 875  * Signature: (J)Lsun/jvm/hotspot/debugger/cdbg/ClosestSymbol;
 876  */
 877 JNIEXPORT jobject JNICALL Java_sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal_lookupByAddress0
 878 (JNIEnv *env, jobject obj, jlong address) {
 879   IDebugSymbols* ptrIDebugSymbols = (IDebugSymbols*) env->GetLongField(obj,
 880                                                       ptrIDebugSymbols_ID);
 881   CHECK_EXCEPTION_(0);
 882 
 883   ULONG64 disp = 0L;
 884   char buf[SYMBOL_BUFSIZE];
 885   memset(buf, 0, sizeof(buf));
 886 
 887   if (ptrIDebugSymbols->GetNameByOffset(address, buf, sizeof(buf),0,&disp)
 888       != S_OK) {
 889     return 0;
 890   }
 891 
 892   jstring sym = env->NewStringUTF(buf);
 893   CHECK_EXCEPTION_(0);
 894   jobject res = env->CallObjectMethod(obj, createClosestSymbol_ID, sym, disp);
 895   CHECK_EXCEPTION_(0);
 896   return res;
 897 }