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