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