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: 58 AutoArrayPtr(T* ptr) : m_ptr(ptr) { 59 } 60 61 ~AutoArrayPtr() { 62 delete [] m_ptr; 63 } 64 65 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: 78 AutoCOMPtr(T* ptr) : m_ptr(ptr) { 79 } 80 81 ~AutoCOMPtr() { 82 if (m_ptr) { 83 m_ptr->Release(); 84 } 85 } 86 87 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 99 AutoJavaString(JNIEnv* env, jstring str) 100 : m_env(env), m_str(str), m_buf(env->GetStringUTFChars(str, nullptr)) { 101 } 102 103 ~AutoJavaString() { 104 if (m_buf) { 105 m_env->ReleaseStringUTFChars(m_str, m_buf); 106 } 107 } 108 109 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 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 127 ~AutoJavaByteArray() { 128 if (bytePtr) { 129 env->ReleaseByteArrayElements(byteArray, bytePtr, releaseMode); 130 } 131 } 132 133 void setReleaseMode(jint mode) { 134 releaseMode = mode; 135 } 136 137 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 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 */ 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: 249 SAOutputCallbacks() : m_refCount(1), m_msgBuffer(nullptr) { 250 } 251 252 ~SAOutputCallbacks() { 253 clearBuffer(); 254 } 255 256 const char* getBuffer() const { 257 return m_msgBuffer; 258 } 259 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 277 STDMETHODIMP_(ULONG) SAOutputCallbacks::AddRef(THIS) { 278 return InterlockedIncrement(&m_refCount); 279 } 280 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 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 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 char* newBuffer = (char*)realloc(m_msgBuffer, len + strlen(m_msgBuffer)); 316 if (newBuffer == nullptr) { 317 // old m_msgBuffer buffer is still valid 318 fprintf(stderr, "out of memory debugger output!\n"); 319 return S_FALSE; 320 } 321 m_msgBuffer = newBuffer; 322 strcat(m_msgBuffer, msg); 323 } 324 return S_OK; 325 } 326 327 static bool getWindbgInterfaces(JNIEnv* env, jobject obj) { 328 // get windbg interfaces .. 329 330 IDebugClient* ptrIDebugClient = 0; 331 COM_VERIFY_OK_(DebugCreate(__uuidof(IDebugClient), (PVOID*) &ptrIDebugClient), 332 "Windbg Error: not able to create IDebugClient object!", false); 333 env->SetLongField(obj, ptrIDebugClient_ID, (jlong) ptrIDebugClient); 334 335 IDebugControl* ptrIDebugControl = 0; 336 COM_VERIFY_OK_(ptrIDebugClient->QueryInterface( 337 __uuidof(IDebugControl), (PVOID*) &ptrIDebugControl), 338 "Windbg Error: not able to get IDebugControl", false); 339 env->SetLongField(obj, ptrIDebugControl_ID, (jlong) ptrIDebugControl); 340 341 IDebugDataSpaces* ptrIDebugDataSpaces = 0; 342 COM_VERIFY_OK_(ptrIDebugClient->QueryInterface( 343 __uuidof(IDebugDataSpaces), (PVOID*) &ptrIDebugDataSpaces), 344 "Windbg Error: not able to get IDebugDataSpaces object!", false); 345 env->SetLongField(obj, ptrIDebugDataSpaces_ID, (jlong) ptrIDebugDataSpaces); 346 347 SAOutputCallbacks* ptrIDebugOutputCallbacks = new SAOutputCallbacks(); 348 env->SetLongField(obj, ptrIDebugOutputCallbacks_ID, (jlong) ptrIDebugOutputCallbacks); 349 CHECK_EXCEPTION_(false); 350 351 IDebugAdvanced* ptrIDebugAdvanced = 0; 352 COM_VERIFY_OK_(ptrIDebugClient->QueryInterface( 353 __uuidof(IDebugAdvanced), (PVOID*) &ptrIDebugAdvanced), 354 "Windbg Error: not able to get IDebugAdvanced object!", false); 355 env->SetLongField(obj, ptrIDebugAdvanced_ID, (jlong) ptrIDebugAdvanced); 356 357 IDebugSymbols* ptrIDebugSymbols = 0; 358 COM_VERIFY_OK_(ptrIDebugClient->QueryInterface( 359 __uuidof(IDebugSymbols), (PVOID*) &ptrIDebugSymbols), 360 "Windbg Error: not able to get IDebugSymbols object!", false); 361 env->SetLongField(obj, ptrIDebugSymbols_ID, (jlong) ptrIDebugSymbols); 362 363 IDebugSystemObjects* ptrIDebugSystemObjects = 0; 364 COM_VERIFY_OK_(ptrIDebugClient->QueryInterface( 365 __uuidof(IDebugSystemObjects), (PVOID*) &ptrIDebugSystemObjects), 366 "Windbg Error: not able to get IDebugSystemObjects object!", false); 367 env->SetLongField(obj, ptrIDebugSystemObjects_ID, (jlong) ptrIDebugSystemObjects); 368 369 return true; 370 } 371 372 static bool setImageAndSymbolPath(JNIEnv* env, jobject obj) { 373 jclass clazz = env->GetObjectClass(obj); 374 CHECK_EXCEPTION_(false); 375 jstring path; 376 377 path = (jstring) env->GetStaticObjectField(clazz, imagePath_ID); 378 CHECK_EXCEPTION_(false); 379 if (path == nullptr) { 380 THROW_NEW_DEBUGGER_EXCEPTION_("Windbg Error: not able to get imagePath field ID!", false); 381 } 382 AutoJavaString imagePath(env, path); 383 CHECK_EXCEPTION_(false); 384 385 path = (jstring) env->GetStaticObjectField(clazz, symbolPath_ID); 386 CHECK_EXCEPTION_(false); 387 if (path == nullptr) { 388 THROW_NEW_DEBUGGER_EXCEPTION_("Windbg Error: not able to get symbolPath field ID!", false); 389 } 390 AutoJavaString symbolPath(env, path); 391 CHECK_EXCEPTION_(false); 392 393 IDebugSymbols* ptrIDebugSymbols = (IDebugSymbols*)env->GetLongField(obj, ptrIDebugSymbols_ID); 394 CHECK_EXCEPTION_(false); 395 396 ptrIDebugSymbols->SetImagePath(imagePath); 397 ptrIDebugSymbols->SetSymbolPath(symbolPath); 398 return true; 399 } 400 401 static HRESULT WaitForEvent(IDebugControl *ptrIDebugControl) { 402 HRESULT hr = ptrIDebugControl->WaitForEvent(DEBUG_WAIT_DEFAULT, INFINITE); 403 // see JDK-8204994: sometimes WaitForEvent fails with E_ACCESSDENIED, 404 // but succeeds on 2nd call. 405 // To minimize possible noise retry 3 times. 406 for (int i = 0; hr == E_ACCESSDENIED && i < 3; i++) { 407 // yield current thread use of a processor (short delay). 408 SwitchToThread(); 409 hr = ptrIDebugControl->WaitForEvent(DEBUG_WAIT_DEFAULT, INFINITE); 410 } 411 return hr; 412 } 413 414 static bool openDumpFile(JNIEnv* env, jobject obj, jstring coreFileName) { 415 // open the dump file 416 AutoJavaString coreFile(env, coreFileName); 417 CHECK_EXCEPTION_(false); 418 if (!setImageAndSymbolPath(env, obj)) { 419 return false; 420 } 421 422 IDebugClient* ptrIDebugClient = (IDebugClient*)env->GetLongField(obj, ptrIDebugClient_ID); 423 CHECK_EXCEPTION_(false); 424 COM_VERIFY_OK_(ptrIDebugClient->OpenDumpFile(coreFile), 425 "Windbg Error: OpenDumpFile failed!", false); 426 427 IDebugControl* ptrIDebugControl = (IDebugControl*)env->GetLongField(obj, ptrIDebugControl_ID); 428 CHECK_EXCEPTION_(false); 429 COM_VERIFY_OK_(WaitForEvent(ptrIDebugControl), 430 "Windbg Error: WaitForEvent failed!", false); 431 432 return true; 433 } 434 435 436 static bool attachToProcess(JNIEnv* env, jobject obj, jint pid) { 437 if (!setImageAndSymbolPath(env, obj)) { 438 return false; 439 } 440 IDebugClient* ptrIDebugClient = (IDebugClient*)env->GetLongField(obj, ptrIDebugClient_ID); 441 CHECK_EXCEPTION_(false); 442 443 /*********************************************************************************** 444 445 We are attaching to a process in 'read-only' mode. i.e., we do not want to 446 put breakpoints, suspend/resume threads etc. For read-only JDI and HSDB kind of 447 usage this should suffice. 448 449 Please refer to DEBUG_ATTACH_NONINVASIVE mode source comments from dbgeng.h. 450 In this mode, debug engine does not call DebugActiveProrcess. i.e., we are not 451 actually debugging at all. We can safely 'detach' from the process anytime 452 we want and debuggee process is left as is on all Windows variants. 453 454 This also makes JDI-on-SA installation/usage simpler because with this we would 455 not need a tool like ServiceInstaller from http://www.kcmultimedia.com/smaster. 456 457 ***********************************************************************************/ 458 459 460 COM_VERIFY_OK_(ptrIDebugClient->AttachProcess(0, pid, DEBUG_ATTACH_NONINVASIVE), 461 "Windbg Error: AttachProcess failed!", false); 462 463 IDebugControl* ptrIDebugControl = (IDebugControl*) env->GetLongField(obj, 464 ptrIDebugControl_ID); 465 CHECK_EXCEPTION_(false); 466 COM_VERIFY_OK_(WaitForEvent(ptrIDebugControl), 467 "Windbg Error: WaitForEvent failed!", false); 468 469 return true; 470 } 471 472 473 static bool addLoadObjects(JNIEnv* env, jobject obj) { 474 IDebugSymbols* ptrIDebugSymbols = (IDebugSymbols*) env->GetLongField(obj, 475 ptrIDebugSymbols_ID); 476 CHECK_EXCEPTION_(false); 477 ULONG loaded = 0, unloaded = 0; 478 COM_VERIFY_OK_(ptrIDebugSymbols->GetNumberModules(&loaded, &unloaded), 479 "Windbg Error: GetNumberModules failed!", false); 480 481 AutoArrayPtr<DEBUG_MODULE_PARAMETERS> params(new DEBUG_MODULE_PARAMETERS[loaded]); 482 483 if (params == nullptr) { 484 THROW_NEW_DEBUGGER_EXCEPTION_("out of memory to allocate debug module params!", false); 485 } 486 487 COM_VERIFY_OK_(ptrIDebugSymbols->GetModuleParameters(loaded, nullptr, 0, params), 488 "Windbg Error: GetModuleParameters failed!", false); 489 490 for (int u = 0; u < (int)loaded; u++) { 491 TCHAR imageName[MAX_PATH]; 492 COM_VERIFY_OK_(ptrIDebugSymbols->GetModuleNames(DEBUG_ANY_ID, params[u].Base, 493 imageName, MAX_PATH, nullptr, nullptr, 494 0, nullptr, nullptr, 0, nullptr), 495 "Windbg Error: GetModuleNames failed!", false); 496 497 jstring strName = env->NewStringUTF(imageName); 498 CHECK_EXCEPTION_(false); 499 env->CallVoidMethod(obj, addLoadObject_ID, strName, (jlong) params[u].Size, 500 (jlong) params[u].Base); 501 CHECK_EXCEPTION_(false); 502 } 503 504 return true; 505 } 506 507 static bool addThreads(JNIEnv* env, jobject obj) { 508 IDebugSystemObjects* ptrIDebugSystemObjects = (IDebugSystemObjects*) env->GetLongField(obj, 509 ptrIDebugSystemObjects_ID); 510 CHECK_EXCEPTION_(false); 511 512 ULONG numThreads = 0; 513 COM_VERIFY_OK_(ptrIDebugSystemObjects->GetNumberThreads(&numThreads), 514 "Windbg Error: GetNumberThreads failed!", false); 515 516 AutoArrayPtr<ULONG> ptrSysThreadIds(new ULONG[numThreads]); 517 518 if (ptrSysThreadIds == nullptr) { 519 THROW_NEW_DEBUGGER_EXCEPTION_("out of memory to allocate thread ids!", false); 520 } 521 522 AutoArrayPtr<ULONG> ptrThreadIds(new ULONG[numThreads]); 523 524 if (ptrThreadIds == nullptr) { 525 THROW_NEW_DEBUGGER_EXCEPTION_("out of memory to allocate thread ids!", false); 526 } 527 528 COM_VERIFY_OK_(ptrIDebugSystemObjects->GetThreadIdsByIndex(0, numThreads, 529 ptrThreadIds, ptrSysThreadIds), 530 "Windbg Error: GetThreadIdsByIndex failed!", false); 531 532 533 IDebugAdvanced* ptrIDebugAdvanced = (IDebugAdvanced*) env->GetLongField(obj, 534 ptrIDebugAdvanced_ID); 535 CHECK_EXCEPTION_(false); 536 537 // for each thread, get register context and save it. 538 for (ULONG t = 0; t < numThreads; t++) { 539 COM_VERIFY_OK_(ptrIDebugSystemObjects->SetCurrentThreadId(ptrThreadIds[t]), 540 "Windbg Error: SetCurrentThread failed!", false); 541 542 jlongArray regs = env->NewLongArray(NPRGREG); 543 CHECK_EXCEPTION_(false); 544 545 jlong* ptrRegs = env->GetLongArrayElements(regs, nullptr); 546 CHECK_EXCEPTION_(false); 547 548 // copy register values from the CONTEXT struct 549 CONTEXT context; 550 memset(&context, 0, sizeof(CONTEXT)); 551 552 #undef REG_INDEX 553 #ifdef _M_IX86 554 #define REG_INDEX(x) sun_jvm_hotspot_debugger_x86_X86ThreadContext_##x 555 556 context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS; 557 ptrIDebugAdvanced->GetThreadContext(&context, sizeof(CONTEXT)); 558 559 ptrRegs[REG_INDEX(GS)] = context.SegGs; 560 ptrRegs[REG_INDEX(FS)] = context.SegFs; 561 ptrRegs[REG_INDEX(ES)] = context.SegEs; 562 ptrRegs[REG_INDEX(DS)] = context.SegDs; 563 564 ptrRegs[REG_INDEX(EDI)] = context.Edi; 565 ptrRegs[REG_INDEX(ESI)] = context.Esi; 566 ptrRegs[REG_INDEX(EBX)] = context.Ebx; 567 ptrRegs[REG_INDEX(EDX)] = context.Edx; 568 ptrRegs[REG_INDEX(ECX)] = context.Ecx; 569 ptrRegs[REG_INDEX(EAX)] = context.Eax; 570 571 ptrRegs[REG_INDEX(FP)] = context.Ebp; 572 ptrRegs[REG_INDEX(PC)] = context.Eip; 573 ptrRegs[REG_INDEX(CS)] = context.SegCs; 574 ptrRegs[REG_INDEX(EFL)] = context.EFlags; 575 ptrRegs[REG_INDEX(SP)] = context.Esp; 576 ptrRegs[REG_INDEX(SS)] = context.SegSs; 577 578 ptrRegs[REG_INDEX(DR0)] = context.Dr0; 579 ptrRegs[REG_INDEX(DR1)] = context.Dr1; 580 ptrRegs[REG_INDEX(DR2)] = context.Dr2; 581 ptrRegs[REG_INDEX(DR3)] = context.Dr3; 582 ptrRegs[REG_INDEX(DR6)] = context.Dr6; 583 ptrRegs[REG_INDEX(DR7)] = context.Dr7; 584 585 #elif _M_AMD64 586 #define REG_INDEX(x) sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_##x 587 588 context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS; 589 ptrIDebugAdvanced->GetThreadContext(&context, sizeof(CONTEXT)); 590 591 // Segment Registers and processor flags 592 ptrRegs[REG_INDEX(CS)] = context.SegCs; 593 ptrRegs[REG_INDEX(DS)] = context.SegDs; 594 ptrRegs[REG_INDEX(ES)] = context.SegEs; 595 ptrRegs[REG_INDEX(FS)] = context.SegFs; 596 ptrRegs[REG_INDEX(GS)] = context.SegGs; 597 ptrRegs[REG_INDEX(SS)] = context.SegSs; 598 ptrRegs[REG_INDEX(RFL)] = context.EFlags; 599 600 // Integer registers 601 ptrRegs[REG_INDEX(RDI)] = context.Rdi; 602 ptrRegs[REG_INDEX(RSI)] = context.Rsi; 603 ptrRegs[REG_INDEX(RAX)] = context.Rax; 604 ptrRegs[REG_INDEX(RCX)] = context.Rcx; 605 ptrRegs[REG_INDEX(RDX)] = context.Rdx; 606 ptrRegs[REG_INDEX(RBX)] = context.Rbx; 607 ptrRegs[REG_INDEX(RBP)] = context.Rbp; 608 ptrRegs[REG_INDEX(RSP)] = context.Rsp; 609 610 ptrRegs[REG_INDEX(R8)] = context.R8; 611 ptrRegs[REG_INDEX(R9)] = context.R9; 612 ptrRegs[REG_INDEX(R10)] = context.R10; 613 ptrRegs[REG_INDEX(R11)] = context.R11; 614 ptrRegs[REG_INDEX(R12)] = context.R12; 615 ptrRegs[REG_INDEX(R13)] = context.R13; 616 ptrRegs[REG_INDEX(R14)] = context.R14; 617 ptrRegs[REG_INDEX(R15)] = context.R15; 618 619 // Program counter 620 ptrRegs[REG_INDEX(RIP)] = context.Rip; 621 #endif 622 623 env->ReleaseLongArrayElements(regs, ptrRegs, JNI_COMMIT); 624 CHECK_EXCEPTION_(false); 625 626 env->CallVoidMethod(obj, setThreadIntegerRegisterSet_ID, (jlong)ptrThreadIds[t], regs); 627 CHECK_EXCEPTION_(false); 628 629 ULONG sysId; 630 COM_VERIFY_OK_(ptrIDebugSystemObjects->GetCurrentThreadSystemId(&sysId), 631 "Windbg Error: GetCurrentThreadSystemId failed!", false); 632 633 env->CallVoidMethod(obj, addThread_ID, (jlong) sysId); 634 CHECK_EXCEPTION_(false); 635 } 636 637 return true; 638 } 639 640 /* 641 * Class: sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal 642 * Method: attach0 643 * Signature: (Ljava/lang/String;Ljava/lang/String;)V 644 */ 645 JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal_attach0__Ljava_lang_String_2Ljava_lang_String_2 646 (JNIEnv *env, jobject obj, jstring execName, jstring coreFileName) { 647 648 if (!getWindbgInterfaces(env, obj)) { 649 return; 650 } 651 652 if (!openDumpFile(env, obj, coreFileName)) { 653 return; 654 } 655 656 if (!addLoadObjects(env, obj)) { 657 return; 658 } 659 660 if (!addThreads(env, obj)) { 661 return; 662 } 663 } 664 665 /* 666 * Class: sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal 667 * Method: attach0 668 * Signature: (I)V 669 */ 670 JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal_attach0__I 671 (JNIEnv *env, jobject obj, jint pid) { 672 673 if (!getWindbgInterfaces(env, obj)) { 674 return; 675 } 676 677 if (!attachToProcess(env, obj, pid)) { 678 return; 679 } 680 681 if (!addLoadObjects(env, obj)) { 682 return; 683 } 684 685 if (!addThreads(env, obj)) { 686 return; 687 } 688 } 689 690 691 #define RELEASE(fieldID) \ 692 do { \ 693 IUnknown* ptr = (IUnknown*)env->GetLongField(obj, fieldID); \ 694 CHECK_EXCEPTION_(false); \ 695 if (ptr) { \ 696 ptr->Release(); \ 697 } \ 698 } while (false) 699 700 static bool releaseWindbgInterfaces(JNIEnv* env, jobject obj) { 701 RELEASE(ptrIDebugDataSpaces_ID); 702 RELEASE(ptrIDebugOutputCallbacks_ID); 703 RELEASE(ptrIDebugAdvanced_ID); 704 RELEASE(ptrIDebugSymbols_ID); 705 RELEASE(ptrIDebugSystemObjects_ID); 706 RELEASE(ptrIDebugControl_ID); 707 RELEASE(ptrIDebugClient_ID); 708 709 return true; 710 } 711 712 /* 713 * Class: sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal 714 * Method: detach0 715 * Signature: ()V 716 */ 717 JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal_detach0 718 (JNIEnv *env, jobject obj) { 719 IDebugClient* ptrIDebugClient = (IDebugClient*) env->GetLongField(obj, ptrIDebugClient_ID); 720 CHECK_EXCEPTION; 721 ptrIDebugClient->DetachProcesses(); 722 releaseWindbgInterfaces(env, obj); 723 } 724 725 726 /* 727 * Class: sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal 728 * Method: readBytesFromProcess0 729 * Signature: (JJ)[B 730 */ 731 JNIEXPORT jbyteArray JNICALL Java_sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal_readBytesFromProcess0 732 (JNIEnv *env, jobject obj, jlong address, jlong numBytes) { 733 jbyteArray byteArray = env->NewByteArray((jsize)numBytes); 734 CHECK_EXCEPTION_(0); 735 736 AutoJavaByteArray arrayBytes(env, byteArray); 737 CHECK_EXCEPTION_(0); 738 739 IDebugDataSpaces* ptrIDebugDataSpaces = (IDebugDataSpaces*) env->GetLongField(obj, 740 ptrIDebugDataSpaces_ID); 741 CHECK_EXCEPTION_(0); 742 743 ULONG bytesRead; 744 const HRESULT hr = ptrIDebugDataSpaces->ReadVirtual((ULONG64)address, arrayBytes, 745 (ULONG)numBytes, &bytesRead); 746 if (hr != S_OK || 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 */ 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 */ 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 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 */ 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 }