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