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