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