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 #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: 62 AutoArrayPtr(T* ptr) : m_ptr(ptr) { 63 } 64 65 ~AutoArrayPtr() { 66 delete [] m_ptr; 67 } 68 69 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: 82 AutoCOMPtr(T* ptr) : m_ptr(ptr) { 83 } 84 85 ~AutoCOMPtr() { 86 if (m_ptr) { 87 m_ptr->Release(); 88 } 89 } 90 91 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 103 AutoJavaString(JNIEnv* env, jstring str) 104 : m_env(env), m_str(str), m_buf(env->GetStringUTFChars(str, nullptr)) { 105 } 106 107 ~AutoJavaString() { 108 if (m_buf) { 109 m_env->ReleaseStringUTFChars(m_str, m_buf); 110 } 111 } 112 113 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 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 131 ~AutoJavaByteArray() { 132 if (bytePtr) { 133 env->ReleaseByteArrayElements(byteArray, bytePtr, releaseMode); 134 } 135 } 136 137 void setReleaseMode(jint mode) { 138 releaseMode = mode; 139 } 140 141 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 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 */ 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: 253 SAOutputCallbacks() : m_refCount(1), m_msgBuffer(nullptr) { 254 } 255 256 ~SAOutputCallbacks() { 257 clearBuffer(); 258 } 259 260 const char* getBuffer() const { 261 return m_msgBuffer; 262 } 263 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 281 STDMETHODIMP_(ULONG) SAOutputCallbacks::AddRef(THIS) { 282 return InterlockedIncrement(&m_refCount); 283 } 284 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 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 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 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 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 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 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 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 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 } 507 508 return true; 509 } 510 511 static bool addThreads(JNIEnv* env, jobject obj) { 512 IDebugSystemObjects* ptrIDebugSystemObjects = (IDebugSystemObjects*) env->GetLongField(obj, 513 ptrIDebugSystemObjects_ID); 514 CHECK_EXCEPTION_(false); 515 516 ULONG numThreads = 0; 517 COM_VERIFY_OK_(ptrIDebugSystemObjects->GetNumberThreads(&numThreads), 518 "Windbg Error: GetNumberThreads failed!", false); 519 520 AutoArrayPtr<ULONG> ptrSysThreadIds(new ULONG[numThreads]); 521 522 if (ptrSysThreadIds == nullptr) { 523 THROW_NEW_DEBUGGER_EXCEPTION_("out of memory to allocate thread ids!", false); 524 } 525 526 AutoArrayPtr<ULONG> ptrThreadIds(new ULONG[numThreads]); 527 528 if (ptrThreadIds == nullptr) { 529 THROW_NEW_DEBUGGER_EXCEPTION_("out of memory to allocate thread ids!", false); 530 } 531 532 COM_VERIFY_OK_(ptrIDebugSystemObjects->GetThreadIdsByIndex(0, numThreads, 533 ptrThreadIds, ptrSysThreadIds), 534 "Windbg Error: GetThreadIdsByIndex failed!", false); 535 536 537 IDebugAdvanced* ptrIDebugAdvanced = (IDebugAdvanced*) env->GetLongField(obj, 538 ptrIDebugAdvanced_ID); 539 CHECK_EXCEPTION_(false); 540 541 // for each thread, get register context and save it. 542 for (ULONG t = 0; t < numThreads; t++) { 543 COM_VERIFY_OK_(ptrIDebugSystemObjects->SetCurrentThreadId(ptrThreadIds[t]), 544 "Windbg Error: SetCurrentThread failed!", false); 545 546 jlongArray regs = env->NewLongArray(NPRGREG); 547 CHECK_EXCEPTION_(false); 548 549 jlong* ptrRegs = env->GetLongArrayElements(regs, nullptr); 550 CHECK_EXCEPTION_(false); 551 552 // copy register values from the CONTEXT struct 553 CONTEXT context; 554 memset(&context, 0, sizeof(CONTEXT)); 555 556 #undef REG_INDEX 557 #ifdef _M_IX86 558 #define REG_INDEX(x) sun_jvm_hotspot_debugger_x86_X86ThreadContext_##x 559 560 context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS; 561 ptrIDebugAdvanced->GetThreadContext(&context, sizeof(CONTEXT)); 562 563 ptrRegs[REG_INDEX(GS)] = context.SegGs; 564 ptrRegs[REG_INDEX(FS)] = context.SegFs; 565 ptrRegs[REG_INDEX(ES)] = context.SegEs; 566 ptrRegs[REG_INDEX(DS)] = context.SegDs; 567 568 ptrRegs[REG_INDEX(EDI)] = context.Edi; 569 ptrRegs[REG_INDEX(ESI)] = context.Esi; 570 ptrRegs[REG_INDEX(EBX)] = context.Ebx; 571 ptrRegs[REG_INDEX(EDX)] = context.Edx; 572 ptrRegs[REG_INDEX(ECX)] = context.Ecx; 573 ptrRegs[REG_INDEX(EAX)] = context.Eax; 574 575 ptrRegs[REG_INDEX(FP)] = context.Ebp; 576 ptrRegs[REG_INDEX(PC)] = context.Eip; 577 ptrRegs[REG_INDEX(CS)] = context.SegCs; 578 ptrRegs[REG_INDEX(EFL)] = context.EFlags; 579 ptrRegs[REG_INDEX(SP)] = context.Esp; 580 ptrRegs[REG_INDEX(SS)] = context.SegSs; 581 582 ptrRegs[REG_INDEX(DR0)] = context.Dr0; 583 ptrRegs[REG_INDEX(DR1)] = context.Dr1; 584 ptrRegs[REG_INDEX(DR2)] = context.Dr2; 585 ptrRegs[REG_INDEX(DR3)] = context.Dr3; 586 ptrRegs[REG_INDEX(DR6)] = context.Dr6; 587 ptrRegs[REG_INDEX(DR7)] = context.Dr7; 588 589 #elif _M_AMD64 590 #define REG_INDEX(x) sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_##x 591 592 context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS; 593 ptrIDebugAdvanced->GetThreadContext(&context, sizeof(CONTEXT)); 594 595 // Segment Registers and processor flags 596 ptrRegs[REG_INDEX(CS)] = context.SegCs; 597 ptrRegs[REG_INDEX(DS)] = context.SegDs; 598 ptrRegs[REG_INDEX(ES)] = context.SegEs; 599 ptrRegs[REG_INDEX(FS)] = context.SegFs; 600 ptrRegs[REG_INDEX(GS)] = context.SegGs; 601 ptrRegs[REG_INDEX(SS)] = context.SegSs; 602 ptrRegs[REG_INDEX(RFL)] = context.EFlags; 603 604 // Integer registers 605 ptrRegs[REG_INDEX(RDI)] = context.Rdi; 606 ptrRegs[REG_INDEX(RSI)] = context.Rsi; 607 ptrRegs[REG_INDEX(RAX)] = context.Rax; 608 ptrRegs[REG_INDEX(RCX)] = context.Rcx; 609 ptrRegs[REG_INDEX(RDX)] = context.Rdx; 610 ptrRegs[REG_INDEX(RBX)] = context.Rbx; 611 ptrRegs[REG_INDEX(RBP)] = context.Rbp; 612 ptrRegs[REG_INDEX(RSP)] = context.Rsp; 613 614 ptrRegs[REG_INDEX(R8)] = context.R8; 615 ptrRegs[REG_INDEX(R9)] = context.R9; 616 ptrRegs[REG_INDEX(R10)] = context.R10; 617 ptrRegs[REG_INDEX(R11)] = context.R11; 618 ptrRegs[REG_INDEX(R12)] = context.R12; 619 ptrRegs[REG_INDEX(R13)] = context.R13; 620 ptrRegs[REG_INDEX(R14)] = context.R14; 621 ptrRegs[REG_INDEX(R15)] = context.R15; 622 623 // Program counter 624 ptrRegs[REG_INDEX(RIP)] = context.Rip; 625 #endif 626 627 env->ReleaseLongArrayElements(regs, ptrRegs, JNI_COMMIT); 628 CHECK_EXCEPTION_(false); 629 630 env->CallVoidMethod(obj, setThreadIntegerRegisterSet_ID, (jlong)ptrThreadIds[t], regs); 631 CHECK_EXCEPTION_(false); 632 633 ULONG sysId; 634 COM_VERIFY_OK_(ptrIDebugSystemObjects->GetCurrentThreadSystemId(&sysId), 635 "Windbg Error: GetCurrentThreadSystemId failed!", false); 636 637 env->CallVoidMethod(obj, addThread_ID, (jlong) sysId); 638 CHECK_EXCEPTION_(false); 639 } 640 641 return true; 642 } 643 644 /* 645 * Class: sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal 646 * Method: attach0 647 * Signature: (Ljava/lang/String;Ljava/lang/String;)V 648 */ 649 JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal_attach0__Ljava_lang_String_2Ljava_lang_String_2 650 (JNIEnv *env, jobject obj, jstring execName, jstring coreFileName) { 651 652 if (!getWindbgInterfaces(env, obj)) { 653 return; 654 } 655 656 if (!openDumpFile(env, obj, coreFileName)) { 657 return; 658 } 659 660 if (!addLoadObjects(env, obj)) { 661 return; 662 } 663 664 if (!addThreads(env, obj)) { 665 return; 666 } 667 } 668 669 /* 670 * Class: sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal 671 * Method: attach0 672 * Signature: (I)V 673 */ 674 JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal_attach0__I 675 (JNIEnv *env, jobject obj, jint pid) { 676 677 if (!getWindbgInterfaces(env, obj)) { 678 return; 679 } 680 681 if (!attachToProcess(env, obj, pid)) { 682 return; 683 } 684 685 if (!addLoadObjects(env, obj)) { 686 return; 687 } 688 689 if (!addThreads(env, obj)) { 690 return; 691 } 692 } 693 694 695 #define RELEASE(fieldID) \ 696 do { \ 697 IUnknown* ptr = (IUnknown*)env->GetLongField(obj, fieldID); \ 698 CHECK_EXCEPTION_(false); \ 699 if (ptr) { \ 700 ptr->Release(); \ 701 } \ 702 } while (false) 703 704 static bool releaseWindbgInterfaces(JNIEnv* env, jobject obj) { 705 RELEASE(ptrIDebugDataSpaces_ID); 706 RELEASE(ptrIDebugOutputCallbacks_ID); 707 RELEASE(ptrIDebugAdvanced_ID); 708 RELEASE(ptrIDebugSymbols_ID); 709 RELEASE(ptrIDebugSystemObjects_ID); 710 RELEASE(ptrIDebugControl_ID); 711 RELEASE(ptrIDebugClient_ID); 712 713 return true; 714 } 715 716 /* 717 * Class: sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal 718 * Method: detach0 719 * Signature: ()V 720 */ 721 JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal_detach0 722 (JNIEnv *env, jobject obj) { 723 IDebugClient* ptrIDebugClient = (IDebugClient*) env->GetLongField(obj, ptrIDebugClient_ID); 724 CHECK_EXCEPTION; 725 ptrIDebugClient->DetachProcesses(); 726 releaseWindbgInterfaces(env, obj); 727 } 728 729 730 /* 731 * Class: sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal 732 * Method: readBytesFromProcess0 733 * Signature: (JJ)[B 734 */ 735 JNIEXPORT jbyteArray JNICALL Java_sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal_readBytesFromProcess0 736 (JNIEnv *env, jobject obj, jlong address, jlong numBytes) { 737 jbyteArray byteArray = env->NewByteArray((jsize)numBytes); 738 CHECK_EXCEPTION_(0); 739 740 AutoJavaByteArray arrayBytes(env, byteArray); 741 CHECK_EXCEPTION_(0); 742 743 IDebugDataSpaces* ptrIDebugDataSpaces = (IDebugDataSpaces*) env->GetLongField(obj, 744 ptrIDebugDataSpaces_ID); 745 CHECK_EXCEPTION_(0); 746 747 ULONG bytesRead; 748 const HRESULT hr = ptrIDebugDataSpaces->ReadVirtual((ULONG64)address, arrayBytes, 749 (ULONG)numBytes, &bytesRead); 750 if (hr != S_OK || bytesRead != numBytes) { 751 return 0; 752 } 753 754 arrayBytes.setReleaseMode(0); 755 756 return byteArray; 757 } 758 759 /* 760 * Class: sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal 761 * Method: getThreadIdFromSysId0 762 * Signature: (J)J 763 */ 764 JNIEXPORT jlong JNICALL Java_sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal_getThreadIdFromSysId0 765 (JNIEnv *env, jobject obj, jlong sysId) { 766 IDebugSystemObjects* ptrIDebugSystemObjects = (IDebugSystemObjects*) env->GetLongField(obj, 767 ptrIDebugSystemObjects_ID); 768 CHECK_EXCEPTION_(0); 769 770 ULONG id = 0; 771 HRESULT hr = ptrIDebugSystemObjects->GetThreadIdBySystemId((ULONG)sysId, &id); 772 if (hr != S_OK) { 773 // This is not considered fatal and does happen on occassion, usually with an 774 // 0x80004002 "No such interface supported". The root cause is not fully understood, 775 // but by ignoring this error and returning NULL, stacking walking code will get 776 // null registers and fallback to using the "last java frame" if setup. 777 printf("WARNING: GetThreadIdBySystemId failed with 0x%x for sysId (%" PRIu64 ")\n", 778 hr, sysId); 779 return -1; 780 } 781 return (jlong) id; 782 } 783 784 /* 785 * Class: sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal 786 * Method: consoleExecuteCommand0 787 * Signature: (Ljava/lang/String;)Ljava/lang/String; 788 */ 789 JNIEXPORT jstring JNICALL Java_sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal_consoleExecuteCommand0 790 (JNIEnv *env, jobject obj, jstring cmd) { 791 AutoJavaString command(env, cmd); 792 CHECK_EXCEPTION_(0); 793 794 IDebugClient* ptrIDebugClient = (IDebugClient*) env->GetLongField(obj, ptrIDebugClient_ID); 795 CHECK_EXCEPTION_(0); 796 797 IDebugClient* tmpClientPtr = 0; 798 COM_VERIFY_OK_(ptrIDebugClient->CreateClient(&tmpClientPtr), 799 "Windbg Error: CreateClient failed!", 0); 800 AutoCOMPtr<IDebugClient> tmpClient(tmpClientPtr); 801 802 IDebugControl* tmpControlPtr = 0; 803 COM_VERIFY_OK_(tmpClient->QueryInterface(__uuidof(IDebugControl), (PVOID*) &tmpControlPtr), 804 "Windbg Error: QueryInterface (IDebugControl) failed", 0); 805 AutoCOMPtr<IDebugControl> tmpControl(tmpControlPtr); 806 807 SAOutputCallbacks* saOutputCallbacks = (SAOutputCallbacks*) env->GetLongField(obj, 808 ptrIDebugOutputCallbacks_ID); 809 CHECK_EXCEPTION_(0); 810 811 saOutputCallbacks->clearBuffer(); 812 813 COM_VERIFY_OK_(tmpClient->SetOutputCallbacks(saOutputCallbacks), 814 "Windbg Error: SetOutputCallbacks failed!", 0); 815 816 tmpControl->Execute(DEBUG_OUTPUT_VERBOSE, command, DEBUG_EXECUTE_DEFAULT); 817 818 const char* output = saOutputCallbacks->getBuffer(); 819 if (output == 0) { 820 output = ""; 821 } 822 823 jstring res = env->NewStringUTF(output); 824 saOutputCallbacks->clearBuffer(); 825 return res; 826 } 827 828 /* 829 * Class: sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal 830 * Method: lookupByName0 831 * Signature: (Ljava/lang/String;Ljava/lang/String;)J 832 */ 833 834 JNIEXPORT jlong JNICALL Java_sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal_lookupByName0 835 (JNIEnv *env, jobject obj, jstring objName, jstring sym) { 836 IDebugSymbols* ptrIDebugSymbols = (IDebugSymbols*)env->GetLongField(obj, ptrIDebugSymbols_ID); 837 CHECK_EXCEPTION_(0); 838 839 AutoJavaString name(env, sym); 840 CHECK_EXCEPTION_(0); 841 842 ULONG64 offset = 0L; 843 if (strstr(name, "::") != 0) { 844 ptrIDebugSymbols->AddSymbolOptions(SYMOPT_UNDNAME); 845 } else { 846 ptrIDebugSymbols->RemoveSymbolOptions(SYMOPT_UNDNAME); 847 } 848 if (ptrIDebugSymbols->GetOffsetByName(name, &offset) != S_OK) { 849 return (jlong) 0; 850 } 851 return (jlong) offset; 852 } 853 854 #define SYMBOL_BUFSIZE 512 855 /* 856 * Class: sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal 857 * Method: lookupByAddress0 858 * Signature: (J)Lsun/jvm/hotspot/debugger/cdbg/ClosestSymbol; 859 */ 860 JNIEXPORT jobject JNICALL Java_sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal_lookupByAddress0 861 (JNIEnv *env, jobject obj, jlong address) { 862 IDebugSymbols* ptrIDebugSymbols = (IDebugSymbols*) env->GetLongField(obj, ptrIDebugSymbols_ID); 863 CHECK_EXCEPTION_(0); 864 865 ULONG64 disp = 0L; 866 char buf[SYMBOL_BUFSIZE]; 867 memset(buf, 0, sizeof(buf)); 868 869 if (ptrIDebugSymbols->GetNameByOffset(address, buf, sizeof(buf), 0, &disp) != S_OK) { 870 return 0; 871 } 872 873 jstring sym = env->NewStringUTF(buf); 874 CHECK_EXCEPTION_(0); 875 jobject res = env->CallObjectMethod(obj, createClosestSymbol_ID, sym, disp); 876 CHECK_EXCEPTION_(0); 877 return res; 878 }