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