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