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:
AutoArrayPtr(T * ptr)58   AutoArrayPtr(T* ptr) : m_ptr(ptr) {
59   }
60 
~AutoArrayPtr()61   ~AutoArrayPtr() {
62     delete [] m_ptr;
63   }
64 
operator T*() const65   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:
AutoCOMPtr(T * ptr)78   AutoCOMPtr(T* ptr) : m_ptr(ptr) {
79   }
80 
~AutoCOMPtr()81   ~AutoCOMPtr() {
82     if (m_ptr) {
83       m_ptr->Release();
84     }
85   }
86 
operator ->() const87   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
AutoJavaString(JNIEnv * env,jstring str)99   AutoJavaString(JNIEnv* env, jstring str)
100     : m_env(env), m_str(str), m_buf(env->GetStringUTFChars(str, nullptr)) {
101   }
102 
~AutoJavaString()103   ~AutoJavaString() {
104     if (m_buf) {
105       m_env->ReleaseStringUTFChars(m_str, m_buf);
106     }
107   }
108 
operator const char*() const109   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
AutoJavaByteArray(JNIEnv * env,jbyteArray byteArray,jint releaseMode=JNI_ABORT)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 
~AutoJavaByteArray()127   ~AutoJavaByteArray() {
128     if (bytePtr) {
129       env->ReleaseByteArrayElements(byteArray, bytePtr, releaseMode);
130     }
131   }
132 
setReleaseMode(jint mode)133   void setReleaseMode(jint mode) {
134     releaseMode = mode;
135   }
136 
operator jbyte*() const137   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 
throwNewDebuggerException(JNIEnv * env,const char * errMsg)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  */
Java_sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal_initIDs(JNIEnv * env,jclass clazz)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:
SAOutputCallbacks()249   SAOutputCallbacks() : m_refCount(1), m_msgBuffer(nullptr) {
250   }
251 
~SAOutputCallbacks()252   ~SAOutputCallbacks() {
253     clearBuffer();
254   }
255 
getBuffer() const256   const char* getBuffer() const {
257     return m_msgBuffer;
258   }
259 
clearBuffer()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 
STDMETHODIMP_(ULONG)277 STDMETHODIMP_(ULONG) SAOutputCallbacks::AddRef(THIS) {
278   return InterlockedIncrement(&m_refCount);
279 }
280 
STDMETHODIMP_(ULONG)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 
QueryInterface(THIS_ IN REFIID interfaceId,OUT PVOID * ppInterface)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 
Output(THIS_ IN ULONG mask,IN PCSTR msg)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     m_msgBuffer = (char*) realloc(m_msgBuffer, len + strlen(m_msgBuffer));
316     if (m_msgBuffer == 0) {
317       fprintf(stderr, "out of memory debugger output!\n");
318       return S_FALSE;
319     }
320     strcat(m_msgBuffer, msg);
321   }
322   return S_OK;
323 }
324 
getWindbgInterfaces(JNIEnv * env,jobject obj)325 static bool getWindbgInterfaces(JNIEnv* env, jobject obj) {
326   // get windbg interfaces ..
327 
328   IDebugClient* ptrIDebugClient = 0;
329   COM_VERIFY_OK_(DebugCreate(__uuidof(IDebugClient), (PVOID*) &ptrIDebugClient),
330                  "Windbg Error: not able to create IDebugClient object!", false);
331   env->SetLongField(obj, ptrIDebugClient_ID, (jlong) ptrIDebugClient);
332 
333   IDebugControl* ptrIDebugControl = 0;
334   COM_VERIFY_OK_(ptrIDebugClient->QueryInterface(
335                     __uuidof(IDebugControl), (PVOID*) &ptrIDebugControl),
336                  "Windbg Error: not able to get IDebugControl", false);
337   env->SetLongField(obj, ptrIDebugControl_ID, (jlong) ptrIDebugControl);
338 
339   IDebugDataSpaces* ptrIDebugDataSpaces = 0;
340   COM_VERIFY_OK_(ptrIDebugClient->QueryInterface(
341                     __uuidof(IDebugDataSpaces), (PVOID*) &ptrIDebugDataSpaces),
342                  "Windbg Error: not able to get IDebugDataSpaces object!", false);
343   env->SetLongField(obj, ptrIDebugDataSpaces_ID, (jlong) ptrIDebugDataSpaces);
344 
345   SAOutputCallbacks* ptrIDebugOutputCallbacks = new SAOutputCallbacks();
346   env->SetLongField(obj, ptrIDebugOutputCallbacks_ID, (jlong) ptrIDebugOutputCallbacks);
347   CHECK_EXCEPTION_(false);
348 
349   IDebugAdvanced* ptrIDebugAdvanced = 0;
350   COM_VERIFY_OK_(ptrIDebugClient->QueryInterface(
351                     __uuidof(IDebugAdvanced), (PVOID*) &ptrIDebugAdvanced),
352                  "Windbg Error: not able to get IDebugAdvanced object!", false);
353   env->SetLongField(obj, ptrIDebugAdvanced_ID, (jlong) ptrIDebugAdvanced);
354 
355   IDebugSymbols* ptrIDebugSymbols = 0;
356   COM_VERIFY_OK_(ptrIDebugClient->QueryInterface(
357                     __uuidof(IDebugSymbols), (PVOID*) &ptrIDebugSymbols),
358                  "Windbg Error: not able to get IDebugSymbols object!", false);
359   env->SetLongField(obj, ptrIDebugSymbols_ID, (jlong) ptrIDebugSymbols);
360 
361   IDebugSystemObjects* ptrIDebugSystemObjects = 0;
362   COM_VERIFY_OK_(ptrIDebugClient->QueryInterface(
363                     __uuidof(IDebugSystemObjects), (PVOID*) &ptrIDebugSystemObjects),
364                  "Windbg Error: not able to get IDebugSystemObjects object!", false);
365   env->SetLongField(obj, ptrIDebugSystemObjects_ID, (jlong) ptrIDebugSystemObjects);
366 
367   return true;
368 }
369 
setImageAndSymbolPath(JNIEnv * env,jobject obj)370 static bool setImageAndSymbolPath(JNIEnv* env, jobject obj) {
371   jclass clazz = env->GetObjectClass(obj);
372   CHECK_EXCEPTION_(false);
373   jstring path;
374 
375   path = (jstring) env->GetStaticObjectField(clazz, imagePath_ID);
376   CHECK_EXCEPTION_(false);
377   if (path == nullptr) {
378      THROW_NEW_DEBUGGER_EXCEPTION_("Windbg Error: not able to get imagePath field ID!", false);
379   }
380   AutoJavaString imagePath(env, path);
381   CHECK_EXCEPTION_(false);
382 
383   path = (jstring) env->GetStaticObjectField(clazz, symbolPath_ID);
384   CHECK_EXCEPTION_(false);
385   if (path == nullptr) {
386      THROW_NEW_DEBUGGER_EXCEPTION_("Windbg Error: not able to get symbolPath field ID!", false);
387   }
388   AutoJavaString symbolPath(env, path);
389   CHECK_EXCEPTION_(false);
390 
391   IDebugSymbols* ptrIDebugSymbols = (IDebugSymbols*)env->GetLongField(obj, ptrIDebugSymbols_ID);
392   CHECK_EXCEPTION_(false);
393 
394   ptrIDebugSymbols->SetImagePath(imagePath);
395   ptrIDebugSymbols->SetSymbolPath(symbolPath);
396   return true;
397 }
398 
WaitForEvent(IDebugControl * ptrIDebugControl)399 static HRESULT WaitForEvent(IDebugControl *ptrIDebugControl) {
400   HRESULT hr = ptrIDebugControl->WaitForEvent(DEBUG_WAIT_DEFAULT, INFINITE);
401   // see JDK-8204994: sometimes WaitForEvent fails with E_ACCESSDENIED,
402   // but succeeds on 2nd call.
403   // To minimize possible noise retry 3 times.
404   for (int i = 0; hr == E_ACCESSDENIED && i < 3; i++) {
405     // yield current thread use of a processor (short delay).
406     SwitchToThread();
407     hr = ptrIDebugControl->WaitForEvent(DEBUG_WAIT_DEFAULT, INFINITE);
408   }
409   return hr;
410 }
411 
openDumpFile(JNIEnv * env,jobject obj,jstring coreFileName)412 static bool openDumpFile(JNIEnv* env, jobject obj, jstring coreFileName) {
413   // open the dump file
414   AutoJavaString coreFile(env, coreFileName);
415   CHECK_EXCEPTION_(false);
416   if (!setImageAndSymbolPath(env, obj)) {
417      return false;
418   }
419 
420   IDebugClient* ptrIDebugClient = (IDebugClient*)env->GetLongField(obj, ptrIDebugClient_ID);
421   CHECK_EXCEPTION_(false);
422   COM_VERIFY_OK_(ptrIDebugClient->OpenDumpFile(coreFile),
423                  "Windbg Error: OpenDumpFile failed!", false);
424 
425   IDebugControl* ptrIDebugControl = (IDebugControl*)env->GetLongField(obj, ptrIDebugControl_ID);
426   CHECK_EXCEPTION_(false);
427   COM_VERIFY_OK_(WaitForEvent(ptrIDebugControl),
428                  "Windbg Error: WaitForEvent failed!", false);
429 
430   return true;
431 }
432 
433 
attachToProcess(JNIEnv * env,jobject obj,jint pid)434 static bool attachToProcess(JNIEnv* env, jobject obj, jint pid) {
435   if (!setImageAndSymbolPath(env, obj)) {
436      return false;
437   }
438   IDebugClient* ptrIDebugClient = (IDebugClient*)env->GetLongField(obj, ptrIDebugClient_ID);
439   CHECK_EXCEPTION_(false);
440 
441   /***********************************************************************************
442 
443      We are attaching to a process in 'read-only' mode. i.e., we do not want to
444      put breakpoints, suspend/resume threads etc. For read-only JDI and HSDB kind of
445      usage this should suffice.
446 
447      Please refer to DEBUG_ATTACH_NONINVASIVE mode source comments from dbgeng.h.
448      In this mode, debug engine does not call DebugActiveProrcess. i.e., we are not
449      actually debugging at all. We can safely 'detach' from the process anytime
450      we want and debuggee process is left as is on all Windows variants.
451 
452      This also makes JDI-on-SA installation/usage simpler because with this we would
453      not need a tool like ServiceInstaller from http://www.kcmultimedia.com/smaster.
454 
455   ***********************************************************************************/
456 
457 
458   COM_VERIFY_OK_(ptrIDebugClient->AttachProcess(0, pid, DEBUG_ATTACH_NONINVASIVE),
459                  "Windbg Error: AttachProcess failed!", false);
460 
461   IDebugControl* ptrIDebugControl = (IDebugControl*) env->GetLongField(obj,
462                                                      ptrIDebugControl_ID);
463   CHECK_EXCEPTION_(false);
464   COM_VERIFY_OK_(WaitForEvent(ptrIDebugControl),
465                  "Windbg Error: WaitForEvent failed!", false);
466 
467   return true;
468 }
469 
470 
addLoadObjects(JNIEnv * env,jobject obj)471 static bool addLoadObjects(JNIEnv* env, jobject obj) {
472   IDebugSymbols* ptrIDebugSymbols = (IDebugSymbols*) env->GetLongField(obj,
473                                                       ptrIDebugSymbols_ID);
474   CHECK_EXCEPTION_(false);
475   ULONG loaded = 0, unloaded = 0;
476   COM_VERIFY_OK_(ptrIDebugSymbols->GetNumberModules(&loaded, &unloaded),
477                  "Windbg Error: GetNumberModules failed!", false);
478 
479   AutoArrayPtr<DEBUG_MODULE_PARAMETERS> params(new DEBUG_MODULE_PARAMETERS[loaded]);
480 
481   if (params == nullptr) {
482       THROW_NEW_DEBUGGER_EXCEPTION_("out of memory to allocate debug module params!", false);
483   }
484 
485   COM_VERIFY_OK_(ptrIDebugSymbols->GetModuleParameters(loaded, nullptr, 0, params),
486                  "Windbg Error: GetModuleParameters failed!", false);
487 
488   for (int u = 0; u < (int)loaded; u++) {
489     TCHAR imageName[MAX_PATH];
490     COM_VERIFY_OK_(ptrIDebugSymbols->GetModuleNames(DEBUG_ANY_ID, params[u].Base,
491                                                     imageName, MAX_PATH, nullptr, nullptr,
492                                                     0, nullptr, nullptr, 0, nullptr),
493                    "Windbg Error: GetModuleNames failed!", false);
494 
495     jstring strName = env->NewStringUTF(imageName);
496     CHECK_EXCEPTION_(false);
497     env->CallVoidMethod(obj, addLoadObject_ID, strName, (jlong) params[u].Size,
498                         (jlong) params[u].Base);
499     CHECK_EXCEPTION_(false);
500   }
501 
502   return true;
503 }
504 
addThreads(JNIEnv * env,jobject obj)505 static bool addThreads(JNIEnv* env, jobject obj) {
506   IDebugSystemObjects* ptrIDebugSystemObjects = (IDebugSystemObjects*) env->GetLongField(obj,
507                                                       ptrIDebugSystemObjects_ID);
508   CHECK_EXCEPTION_(false);
509 
510   ULONG numThreads = 0;
511   COM_VERIFY_OK_(ptrIDebugSystemObjects->GetNumberThreads(&numThreads),
512                  "Windbg Error: GetNumberThreads failed!", false);
513 
514   AutoArrayPtr<ULONG> ptrSysThreadIds(new ULONG[numThreads]);
515 
516   if (ptrSysThreadIds == nullptr) {
517      THROW_NEW_DEBUGGER_EXCEPTION_("out of memory to allocate thread ids!", false);
518   }
519 
520   AutoArrayPtr<ULONG> ptrThreadIds(new ULONG[numThreads]);
521 
522   if (ptrThreadIds == nullptr) {
523      THROW_NEW_DEBUGGER_EXCEPTION_("out of memory to allocate thread ids!", false);
524   }
525 
526   COM_VERIFY_OK_(ptrIDebugSystemObjects->GetThreadIdsByIndex(0, numThreads,
527                                       ptrThreadIds, ptrSysThreadIds),
528                  "Windbg Error: GetThreadIdsByIndex failed!", false);
529 
530 
531   IDebugAdvanced* ptrIDebugAdvanced = (IDebugAdvanced*) env->GetLongField(obj,
532                                                       ptrIDebugAdvanced_ID);
533   CHECK_EXCEPTION_(false);
534 
535   // for each thread, get register context and save it.
536   for (ULONG t = 0; t < numThreads; t++) {
537     COM_VERIFY_OK_(ptrIDebugSystemObjects->SetCurrentThreadId(ptrThreadIds[t]),
538                    "Windbg Error: SetCurrentThread failed!", false);
539 
540     jlongArray regs = env->NewLongArray(NPRGREG);
541     CHECK_EXCEPTION_(false);
542 
543     jlong* ptrRegs = env->GetLongArrayElements(regs, nullptr);
544     CHECK_EXCEPTION_(false);
545 
546     // copy register values from the CONTEXT struct
547     CONTEXT context;
548     memset(&context, 0, sizeof(CONTEXT));
549 
550 #undef REG_INDEX
551 #ifdef _M_IX86
552     #define REG_INDEX(x) sun_jvm_hotspot_debugger_x86_X86ThreadContext_##x
553 
554     context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
555     ptrIDebugAdvanced->GetThreadContext(&context, sizeof(CONTEXT));
556 
557     ptrRegs[REG_INDEX(GS)]  = context.SegGs;
558     ptrRegs[REG_INDEX(FS)]  = context.SegFs;
559     ptrRegs[REG_INDEX(ES)]  = context.SegEs;
560     ptrRegs[REG_INDEX(DS)]  = context.SegDs;
561 
562     ptrRegs[REG_INDEX(EDI)] = context.Edi;
563     ptrRegs[REG_INDEX(ESI)] = context.Esi;
564     ptrRegs[REG_INDEX(EBX)] = context.Ebx;
565     ptrRegs[REG_INDEX(EDX)] = context.Edx;
566     ptrRegs[REG_INDEX(ECX)] = context.Ecx;
567     ptrRegs[REG_INDEX(EAX)] = context.Eax;
568 
569     ptrRegs[REG_INDEX(FP)] = context.Ebp;
570     ptrRegs[REG_INDEX(PC)] = context.Eip;
571     ptrRegs[REG_INDEX(CS)]  = context.SegCs;
572     ptrRegs[REG_INDEX(EFL)] = context.EFlags;
573     ptrRegs[REG_INDEX(SP)] = context.Esp;
574     ptrRegs[REG_INDEX(SS)]  = context.SegSs;
575 
576     ptrRegs[REG_INDEX(DR0)] = context.Dr0;
577     ptrRegs[REG_INDEX(DR1)] = context.Dr1;
578     ptrRegs[REG_INDEX(DR2)] = context.Dr2;
579     ptrRegs[REG_INDEX(DR3)] = context.Dr3;
580     ptrRegs[REG_INDEX(DR6)] = context.Dr6;
581     ptrRegs[REG_INDEX(DR7)] = context.Dr7;
582 
583 #elif _M_AMD64
584     #define REG_INDEX(x) sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_##x
585 
586     context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
587     ptrIDebugAdvanced->GetThreadContext(&context, sizeof(CONTEXT));
588 
589     // Segment Registers and processor flags
590     ptrRegs[REG_INDEX(CS)]  = context.SegCs;
591     ptrRegs[REG_INDEX(DS)]  = context.SegDs;
592     ptrRegs[REG_INDEX(ES)]  = context.SegEs;
593     ptrRegs[REG_INDEX(FS)]  = context.SegFs;
594     ptrRegs[REG_INDEX(GS)]  = context.SegGs;
595     ptrRegs[REG_INDEX(SS)]  = context.SegSs;
596     ptrRegs[REG_INDEX(RFL)] = context.EFlags;
597 
598     // Integer registers
599     ptrRegs[REG_INDEX(RDI)] = context.Rdi;
600     ptrRegs[REG_INDEX(RSI)] = context.Rsi;
601     ptrRegs[REG_INDEX(RAX)] = context.Rax;
602     ptrRegs[REG_INDEX(RCX)] = context.Rcx;
603     ptrRegs[REG_INDEX(RDX)] = context.Rdx;
604     ptrRegs[REG_INDEX(RBX)] = context.Rbx;
605     ptrRegs[REG_INDEX(RBP)] = context.Rbp;
606     ptrRegs[REG_INDEX(RSP)] = context.Rsp;
607 
608     ptrRegs[REG_INDEX(R8)]  = context.R8;
609     ptrRegs[REG_INDEX(R9)]  = context.R9;
610     ptrRegs[REG_INDEX(R10)] = context.R10;
611     ptrRegs[REG_INDEX(R11)] = context.R11;
612     ptrRegs[REG_INDEX(R12)] = context.R12;
613     ptrRegs[REG_INDEX(R13)] = context.R13;
614     ptrRegs[REG_INDEX(R14)] = context.R14;
615     ptrRegs[REG_INDEX(R15)] = context.R15;
616 
617     // Program counter
618     ptrRegs[REG_INDEX(RIP)] = context.Rip;
619 #endif
620 
621     env->ReleaseLongArrayElements(regs, ptrRegs, JNI_COMMIT);
622     CHECK_EXCEPTION_(false);
623 
624     env->CallVoidMethod(obj, setThreadIntegerRegisterSet_ID, (jlong)ptrThreadIds[t], regs);
625     CHECK_EXCEPTION_(false);
626 
627     ULONG sysId;
628     COM_VERIFY_OK_(ptrIDebugSystemObjects->GetCurrentThreadSystemId(&sysId),
629                    "Windbg Error: GetCurrentThreadSystemId failed!", false);
630 
631     env->CallVoidMethod(obj, addThread_ID, (jlong) sysId);
632     CHECK_EXCEPTION_(false);
633   }
634 
635   return true;
636 }
637 
638 /*
639  * Class:     sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal
640  * Method:    attach0
641  * Signature: (Ljava/lang/String;Ljava/lang/String;)V
642  */
Java_sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal_attach0__Ljava_lang_String_2Ljava_lang_String_2(JNIEnv * env,jobject obj,jstring execName,jstring coreFileName)643 JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal_attach0__Ljava_lang_String_2Ljava_lang_String_2
644   (JNIEnv *env, jobject obj, jstring execName, jstring coreFileName) {
645 
646   if (!getWindbgInterfaces(env, obj)) {
647      return;
648   }
649 
650   if (!openDumpFile(env, obj, coreFileName)) {
651      return;
652   }
653 
654   if (!addLoadObjects(env, obj)) {
655      return;
656   }
657 
658   if (!addThreads(env, obj)) {
659      return;
660   }
661 }
662 
663 /*
664  * Class:     sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal
665  * Method:    attach0
666  * Signature: (I)V
667  */
Java_sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal_attach0__I(JNIEnv * env,jobject obj,jint pid)668 JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal_attach0__I
669   (JNIEnv *env, jobject obj, jint pid) {
670 
671   if (!getWindbgInterfaces(env, obj)) {
672      return;
673   }
674 
675   if (!attachToProcess(env, obj, pid)) {
676      return;
677   }
678 
679   if (!addLoadObjects(env, obj)) {
680      return;
681   }
682 
683   if (!addThreads(env, obj)) {
684      return;
685   }
686 }
687 
688 
689 #define RELEASE(fieldID) \
690   do { \
691     IUnknown* ptr = (IUnknown*)env->GetLongField(obj, fieldID); \
692     CHECK_EXCEPTION_(false); \
693     if (ptr) { \
694       ptr->Release(); \
695     } \
696   } while (false)
697 
releaseWindbgInterfaces(JNIEnv * env,jobject obj)698 static bool releaseWindbgInterfaces(JNIEnv* env, jobject obj) {
699   RELEASE(ptrIDebugDataSpaces_ID);
700   RELEASE(ptrIDebugOutputCallbacks_ID);
701   RELEASE(ptrIDebugAdvanced_ID);
702   RELEASE(ptrIDebugSymbols_ID);
703   RELEASE(ptrIDebugSystemObjects_ID);
704   RELEASE(ptrIDebugControl_ID);
705   RELEASE(ptrIDebugClient_ID);
706 
707   return true;
708 }
709 
710 /*
711  * Class:     sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal
712  * Method:    detach0
713  * Signature: ()V
714  */
Java_sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal_detach0(JNIEnv * env,jobject obj)715 JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal_detach0
716     (JNIEnv *env, jobject obj) {
717   IDebugClient* ptrIDebugClient = (IDebugClient*) env->GetLongField(obj, ptrIDebugClient_ID);
718   CHECK_EXCEPTION;
719   ptrIDebugClient->DetachProcesses();
720   releaseWindbgInterfaces(env, obj);
721 }
722 
723 
724 /*
725  * Class:     sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal
726  * Method:    readBytesFromProcess0
727  * Signature: (JJ)[B
728  */
Java_sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal_readBytesFromProcess0(JNIEnv * env,jobject obj,jlong address,jlong numBytes)729 JNIEXPORT jbyteArray JNICALL Java_sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal_readBytesFromProcess0
730     (JNIEnv *env, jobject obj, jlong address, jlong numBytes) {
731   jbyteArray byteArray = env->NewByteArray((jsize)numBytes);
732   CHECK_EXCEPTION_(0);
733 
734   AutoJavaByteArray arrayBytes(env, byteArray);
735   CHECK_EXCEPTION_(0);
736 
737   IDebugDataSpaces* ptrIDebugDataSpaces = (IDebugDataSpaces*) env->GetLongField(obj,
738                                                        ptrIDebugDataSpaces_ID);
739   CHECK_EXCEPTION_(0);
740 
741   ULONG bytesRead;
742   COM_VERIFY_OK_(ptrIDebugDataSpaces->ReadVirtual((ULONG64)address, arrayBytes,
743                                                   (ULONG)numBytes, &bytesRead),
744                  "Windbg Error: ReadVirtual failed!", 0);
745 
746   if (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  */
Java_sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal_getThreadIdFromSysId0(JNIEnv * env,jobject obj,jlong sysId)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  */
Java_sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal_consoleExecuteCommand0(JNIEnv * env,jobject obj,jstring cmd)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 
Java_sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal_lookupByName0(JNIEnv * env,jobject obj,jstring objName,jstring sym)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  */
Java_sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal_lookupByAddress0(JNIEnv * env,jobject obj,jlong address)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 }
868