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