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