1 //===-- DebuggerThread.cpp ------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "DebuggerThread.h" 10 #include "ExceptionRecord.h" 11 #include "IDebugDelegate.h" 12 13 #include "lldb/Core/ModuleSpec.h" 14 #include "lldb/Host/ProcessLaunchInfo.h" 15 #include "lldb/Host/ThreadLauncher.h" 16 #include "lldb/Host/windows/AutoHandle.h" 17 #include "lldb/Host/windows/HostProcessWindows.h" 18 #include "lldb/Host/windows/HostThreadWindows.h" 19 #include "lldb/Host/windows/ProcessLauncherWindows.h" 20 #include "lldb/Target/Process.h" 21 #include "lldb/Utility/FileSpec.h" 22 #include "lldb/Utility/Log.h" 23 #include "lldb/Utility/Predicate.h" 24 #include "lldb/Utility/Status.h" 25 26 #include "Plugins/Process/Windows/Common/ProcessWindowsLog.h" 27 28 #include "llvm/ADT/STLExtras.h" 29 #include "llvm/Support/ConvertUTF.h" 30 #include "llvm/Support/Threading.h" 31 #include "llvm/Support/raw_ostream.h" 32 33 #include <optional> 34 #include <psapi.h> 35 36 #ifndef STATUS_WX86_BREAKPOINT 37 #define STATUS_WX86_BREAKPOINT 0x4000001FL // For WOW64 38 #endif 39 40 using namespace lldb; 41 using namespace lldb_private; 42 43 DebuggerThread::DebuggerThread(DebugDelegateSP debug_delegate) 44 : m_debug_delegate(debug_delegate), m_pid_to_detach(0), 45 m_is_shutting_down(false) { 46 m_debugging_ended_event = ::CreateEvent(nullptr, TRUE, FALSE, nullptr); 47 } 48 49 DebuggerThread::~DebuggerThread() { ::CloseHandle(m_debugging_ended_event); } 50 51 Status DebuggerThread::DebugLaunch(const ProcessLaunchInfo &launch_info) { 52 Log *log = GetLog(WindowsLog::Process); 53 LLDB_LOG(log, "launching '{0}'", launch_info.GetExecutableFile().GetPath()); 54 55 Status result; 56 llvm::Expected<HostThread> secondary_thread = ThreadLauncher::LaunchThread( 57 "lldb.plugin.process-windows.secondary[?]", 58 [this, launch_info] { return DebuggerThreadLaunchRoutine(launch_info); }); 59 if (!secondary_thread) { 60 result = Status::FromError(secondary_thread.takeError()); 61 LLDB_LOG(log, "couldn't launch debugger thread. {0}", result); 62 } 63 64 return result; 65 } 66 67 Status DebuggerThread::DebugAttach(lldb::pid_t pid, 68 const ProcessAttachInfo &attach_info) { 69 Log *log = GetLog(WindowsLog::Process); 70 LLDB_LOG(log, "attaching to '{0}'", pid); 71 72 Status result; 73 llvm::Expected<HostThread> secondary_thread = ThreadLauncher::LaunchThread( 74 "lldb.plugin.process-windows.secondary[?]", [this, pid, attach_info] { 75 return DebuggerThreadAttachRoutine(pid, attach_info); 76 }); 77 if (!secondary_thread) { 78 result = Status::FromError(secondary_thread.takeError()); 79 LLDB_LOG(log, "couldn't attach to process '{0}'. {1}", pid, result); 80 } 81 82 return result; 83 } 84 85 lldb::thread_result_t DebuggerThread::DebuggerThreadLaunchRoutine( 86 const ProcessLaunchInfo &launch_info) { 87 // Grab a shared_ptr reference to this so that we know it won't get deleted 88 // until after the thread routine has exited. 89 std::shared_ptr<DebuggerThread> this_ref(shared_from_this()); 90 91 Log *log = GetLog(WindowsLog::Process); 92 LLDB_LOG(log, "preparing to launch '{0}' on background thread.", 93 launch_info.GetExecutableFile().GetPath()); 94 95 Status error; 96 ProcessLauncherWindows launcher; 97 HostProcess process(launcher.LaunchProcess(launch_info, error)); 98 // If we couldn't create the process, notify waiters immediately. Otherwise 99 // enter the debug loop and wait until we get the create process debug 100 // notification. Note that if the process was created successfully, we can 101 // throw away the process handle we got from CreateProcess because Windows 102 // will give us another (potentially more useful?) handle when it sends us 103 // the CREATE_PROCESS_DEBUG_EVENT. 104 if (error.Success()) 105 DebugLoop(); 106 else 107 m_debug_delegate->OnDebuggerError(error, 0); 108 109 return {}; 110 } 111 112 lldb::thread_result_t DebuggerThread::DebuggerThreadAttachRoutine( 113 lldb::pid_t pid, const ProcessAttachInfo &attach_info) { 114 // Grab a shared_ptr reference to this so that we know it won't get deleted 115 // until after the thread routine has exited. 116 std::shared_ptr<DebuggerThread> this_ref(shared_from_this()); 117 118 Log *log = GetLog(WindowsLog::Process); 119 LLDB_LOG(log, "preparing to attach to process '{0}' on background thread.", 120 pid); 121 122 if (!DebugActiveProcess((DWORD)pid)) { 123 Status error(::GetLastError(), eErrorTypeWin32); 124 m_debug_delegate->OnDebuggerError(error, 0); 125 return {}; 126 } 127 128 // The attach was successful, enter the debug loop. From here on out, this 129 // is no different than a create process operation, so all the same comments 130 // in DebugLaunch should apply from this point out. 131 DebugLoop(); 132 133 return {}; 134 } 135 136 Status DebuggerThread::StopDebugging(bool terminate) { 137 Status error; 138 139 lldb::pid_t pid = m_process.GetProcessId(); 140 141 Log *log = GetLog(WindowsLog::Process); 142 LLDB_LOG(log, "terminate = {0}, inferior={1}.", terminate, pid); 143 144 // Set m_is_shutting_down to true if it was false. Return if it was already 145 // true. 146 bool expected = false; 147 if (!m_is_shutting_down.compare_exchange_strong(expected, true)) 148 return error; 149 150 // Make a copy of the process, since the termination sequence will reset 151 // DebuggerThread's internal copy and it needs to remain open for the Wait 152 // operation. 153 HostProcess process_copy = m_process; 154 lldb::process_t handle = m_process.GetNativeProcess().GetSystemHandle(); 155 156 if (terminate) { 157 if (handle != nullptr && handle != LLDB_INVALID_PROCESS) { 158 // Initiate the termination before continuing the exception, so that the 159 // next debug event we get is the exit process event, and not some other 160 // event. 161 BOOL terminate_suceeded = TerminateProcess(handle, 0); 162 LLDB_LOG(log, 163 "calling TerminateProcess({0}, 0) (inferior={1}), success={2}", 164 handle, pid, terminate_suceeded); 165 } else { 166 LLDB_LOG(log, 167 "NOT calling TerminateProcess because the inferior is not valid " 168 "({0}, 0) (inferior={1})", 169 handle, pid); 170 } 171 } 172 173 // If we're stuck waiting for an exception to continue (e.g. the user is at a 174 // breakpoint messing around in the debugger), continue it now. But only 175 // AFTER calling TerminateProcess to make sure that the very next call to 176 // WaitForDebugEvent is an exit process event. 177 if (m_active_exception.get()) { 178 LLDB_LOG(log, "masking active exception"); 179 ContinueAsyncException(ExceptionResult::MaskException); 180 } 181 182 if (!terminate) { 183 // Indicate that we want to detach. 184 m_pid_to_detach = GetProcess().GetProcessId(); 185 186 // Force a fresh break so that the detach can happen from the debugger 187 // thread. 188 if (!::DebugBreakProcess( 189 GetProcess().GetNativeProcess().GetSystemHandle())) { 190 error = Status(::GetLastError(), eErrorTypeWin32); 191 } 192 } 193 194 LLDB_LOG(log, "waiting for detach from process {0} to complete.", pid); 195 196 DWORD wait_result = WaitForSingleObject(m_debugging_ended_event, 5000); 197 if (wait_result != WAIT_OBJECT_0) { 198 error = Status(GetLastError(), eErrorTypeWin32); 199 LLDB_LOG(log, "error: WaitForSingleObject({0}, 5000) returned {1}", 200 m_debugging_ended_event, wait_result); 201 } else 202 LLDB_LOG(log, "detach from process {0} completed successfully.", pid); 203 204 if (!error.Success()) { 205 LLDB_LOG(log, "encountered an error while trying to stop process {0}. {1}", 206 pid, error); 207 } 208 return error; 209 } 210 211 void DebuggerThread::ContinueAsyncException(ExceptionResult result) { 212 if (!m_active_exception.get()) 213 return; 214 215 Log *log = GetLog(WindowsLog::Process | WindowsLog::Exception); 216 LLDB_LOG(log, "broadcasting for inferior process {0}.", 217 m_process.GetProcessId()); 218 219 m_active_exception.reset(); 220 m_exception_pred.SetValue(result, eBroadcastAlways); 221 } 222 223 void DebuggerThread::FreeProcessHandles() { 224 m_process = HostProcess(); 225 m_main_thread = HostThread(); 226 if (m_image_file) { 227 ::CloseHandle(m_image_file); 228 m_image_file = nullptr; 229 } 230 } 231 232 void DebuggerThread::DebugLoop() { 233 Log *log = GetLog(WindowsLog::Event); 234 DEBUG_EVENT dbe = {}; 235 bool should_debug = true; 236 LLDB_LOGV(log, "Entering WaitForDebugEvent loop"); 237 while (should_debug) { 238 LLDB_LOGV(log, "Calling WaitForDebugEvent"); 239 BOOL wait_result = WaitForDebugEvent(&dbe, INFINITE); 240 if (wait_result) { 241 DWORD continue_status = DBG_CONTINUE; 242 bool shutting_down = m_is_shutting_down; 243 switch (dbe.dwDebugEventCode) { 244 default: 245 llvm_unreachable("Unhandle debug event code!"); 246 case EXCEPTION_DEBUG_EVENT: { 247 ExceptionResult status = HandleExceptionEvent( 248 dbe.u.Exception, dbe.dwThreadId, shutting_down); 249 250 if (status == ExceptionResult::MaskException) 251 continue_status = DBG_CONTINUE; 252 else if (status == ExceptionResult::SendToApplication) 253 continue_status = DBG_EXCEPTION_NOT_HANDLED; 254 255 break; 256 } 257 case CREATE_THREAD_DEBUG_EVENT: 258 continue_status = 259 HandleCreateThreadEvent(dbe.u.CreateThread, dbe.dwThreadId); 260 break; 261 case CREATE_PROCESS_DEBUG_EVENT: 262 continue_status = 263 HandleCreateProcessEvent(dbe.u.CreateProcessInfo, dbe.dwThreadId); 264 break; 265 case EXIT_THREAD_DEBUG_EVENT: 266 continue_status = 267 HandleExitThreadEvent(dbe.u.ExitThread, dbe.dwThreadId); 268 break; 269 case EXIT_PROCESS_DEBUG_EVENT: 270 continue_status = 271 HandleExitProcessEvent(dbe.u.ExitProcess, dbe.dwThreadId); 272 should_debug = false; 273 break; 274 case LOAD_DLL_DEBUG_EVENT: 275 continue_status = HandleLoadDllEvent(dbe.u.LoadDll, dbe.dwThreadId); 276 break; 277 case UNLOAD_DLL_DEBUG_EVENT: 278 continue_status = HandleUnloadDllEvent(dbe.u.UnloadDll, dbe.dwThreadId); 279 break; 280 case OUTPUT_DEBUG_STRING_EVENT: 281 continue_status = HandleODSEvent(dbe.u.DebugString, dbe.dwThreadId); 282 break; 283 case RIP_EVENT: 284 continue_status = HandleRipEvent(dbe.u.RipInfo, dbe.dwThreadId); 285 if (dbe.u.RipInfo.dwType == SLE_ERROR) 286 should_debug = false; 287 break; 288 } 289 290 LLDB_LOGV(log, "calling ContinueDebugEvent({0}, {1}, {2}) on thread {3}.", 291 dbe.dwProcessId, dbe.dwThreadId, continue_status, 292 ::GetCurrentThreadId()); 293 294 ::ContinueDebugEvent(dbe.dwProcessId, dbe.dwThreadId, continue_status); 295 296 // We have to DebugActiveProcessStop after ContinueDebugEvent, otherwise 297 // the target process will crash 298 if (shutting_down) { 299 // A breakpoint that occurs while `m_pid_to_detach` is non-zero is a 300 // magic exception that we use simply to wake up the DebuggerThread so 301 // that we can close out the debug loop. 302 if (m_pid_to_detach != 0 && 303 (dbe.u.Exception.ExceptionRecord.ExceptionCode == 304 EXCEPTION_BREAKPOINT || 305 dbe.u.Exception.ExceptionRecord.ExceptionCode == 306 STATUS_WX86_BREAKPOINT)) { 307 LLDB_LOG(log, 308 "Breakpoint exception is cue to detach from process {0:x}", 309 m_pid_to_detach.load()); 310 311 // detaching with leaving breakpoint exception event on the queue may 312 // cause target process to crash so process events as possible since 313 // target threads are running at this time, there is possibility to 314 // have some breakpoint exception between last WaitForDebugEvent and 315 // DebugActiveProcessStop but ignore for now. 316 while (WaitForDebugEvent(&dbe, 0)) { 317 continue_status = DBG_CONTINUE; 318 if (dbe.dwDebugEventCode == EXCEPTION_DEBUG_EVENT && 319 !(dbe.u.Exception.ExceptionRecord.ExceptionCode == 320 EXCEPTION_BREAKPOINT || 321 dbe.u.Exception.ExceptionRecord.ExceptionCode == 322 STATUS_WX86_BREAKPOINT || 323 dbe.u.Exception.ExceptionRecord.ExceptionCode == 324 EXCEPTION_SINGLE_STEP)) 325 continue_status = DBG_EXCEPTION_NOT_HANDLED; 326 ::ContinueDebugEvent(dbe.dwProcessId, dbe.dwThreadId, 327 continue_status); 328 } 329 330 ::DebugActiveProcessStop(m_pid_to_detach); 331 m_detached = true; 332 } 333 } 334 335 if (m_detached) { 336 should_debug = false; 337 } 338 } else { 339 LLDB_LOG(log, "returned FALSE from WaitForDebugEvent. Error = {0}", 340 ::GetLastError()); 341 342 should_debug = false; 343 } 344 } 345 FreeProcessHandles(); 346 347 LLDB_LOG(log, "WaitForDebugEvent loop completed, exiting."); 348 ::SetEvent(m_debugging_ended_event); 349 } 350 351 ExceptionResult 352 DebuggerThread::HandleExceptionEvent(const EXCEPTION_DEBUG_INFO &info, 353 DWORD thread_id, bool shutting_down) { 354 Log *log = GetLog(WindowsLog::Event | WindowsLog::Exception); 355 if (shutting_down) { 356 bool is_breakpoint = 357 (info.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT || 358 info.ExceptionRecord.ExceptionCode == STATUS_WX86_BREAKPOINT); 359 360 // Don't perform any blocking operations while we're shutting down. That 361 // will cause TerminateProcess -> WaitForSingleObject to time out. 362 // We should not send breakpoint exceptions to the application. 363 return is_breakpoint ? ExceptionResult::MaskException 364 : ExceptionResult::SendToApplication; 365 } 366 367 bool first_chance = (info.dwFirstChance != 0); 368 369 m_active_exception.reset( 370 new ExceptionRecord(info.ExceptionRecord, thread_id)); 371 LLDB_LOG(log, "encountered {0} chance exception {1:x} on thread {2:x}", 372 first_chance ? "first" : "second", 373 info.ExceptionRecord.ExceptionCode, thread_id); 374 375 ExceptionResult result = 376 m_debug_delegate->OnDebugException(first_chance, *m_active_exception); 377 m_exception_pred.SetValue(result, eBroadcastNever); 378 379 LLDB_LOG(log, "waiting for ExceptionPred != BreakInDebugger"); 380 result = *m_exception_pred.WaitForValueNotEqualTo( 381 ExceptionResult::BreakInDebugger); 382 383 LLDB_LOG(log, "got ExceptionPred = {0}", (int)m_exception_pred.GetValue()); 384 return result; 385 } 386 387 DWORD 388 DebuggerThread::HandleCreateThreadEvent(const CREATE_THREAD_DEBUG_INFO &info, 389 DWORD thread_id) { 390 Log *log = GetLog(WindowsLog::Event | WindowsLog::Thread); 391 LLDB_LOG(log, "Thread {0} spawned in process {1}", thread_id, 392 m_process.GetProcessId()); 393 HostThread thread(info.hThread); 394 thread.GetNativeThread().SetOwnsHandle(false); 395 m_debug_delegate->OnCreateThread(thread); 396 return DBG_CONTINUE; 397 } 398 399 DWORD 400 DebuggerThread::HandleCreateProcessEvent(const CREATE_PROCESS_DEBUG_INFO &info, 401 DWORD thread_id) { 402 Log *log = GetLog(WindowsLog::Event | WindowsLog::Process); 403 uint32_t process_id = ::GetProcessId(info.hProcess); 404 405 LLDB_LOG(log, "process {0} spawned", process_id); 406 407 std::string thread_name; 408 llvm::raw_string_ostream name_stream(thread_name); 409 name_stream << "lldb.plugin.process-windows.secondary[" << process_id << "]"; 410 llvm::set_thread_name(thread_name); 411 412 // info.hProcess and info.hThread are closed automatically by Windows when 413 // EXIT_PROCESS_DEBUG_EVENT is received. 414 m_process = HostProcess(info.hProcess); 415 ((HostProcessWindows &)m_process.GetNativeProcess()).SetOwnsHandle(false); 416 m_main_thread = HostThread(info.hThread); 417 m_main_thread.GetNativeThread().SetOwnsHandle(false); 418 m_image_file = info.hFile; 419 420 lldb::addr_t load_addr = reinterpret_cast<lldb::addr_t>(info.lpBaseOfImage); 421 m_debug_delegate->OnDebuggerConnected(load_addr); 422 423 return DBG_CONTINUE; 424 } 425 426 DWORD 427 DebuggerThread::HandleExitThreadEvent(const EXIT_THREAD_DEBUG_INFO &info, 428 DWORD thread_id) { 429 Log *log = GetLog(WindowsLog::Event | WindowsLog::Thread); 430 LLDB_LOG(log, "Thread {0} exited with code {1} in process {2}", thread_id, 431 info.dwExitCode, m_process.GetProcessId()); 432 m_debug_delegate->OnExitThread(thread_id, info.dwExitCode); 433 return DBG_CONTINUE; 434 } 435 436 DWORD 437 DebuggerThread::HandleExitProcessEvent(const EXIT_PROCESS_DEBUG_INFO &info, 438 DWORD thread_id) { 439 Log *log = GetLog(WindowsLog::Event | WindowsLog::Thread); 440 LLDB_LOG(log, "process {0} exited with code {1}", m_process.GetProcessId(), 441 info.dwExitCode); 442 443 m_debug_delegate->OnExitProcess(info.dwExitCode); 444 445 return DBG_CONTINUE; 446 } 447 448 static std::optional<std::string> GetFileNameFromHandleFallback(HANDLE hFile) { 449 // Check that file is not empty as we cannot map a file with zero length. 450 DWORD dwFileSizeHi = 0; 451 DWORD dwFileSizeLo = ::GetFileSize(hFile, &dwFileSizeHi); 452 if (dwFileSizeLo == 0 && dwFileSizeHi == 0) 453 return std::nullopt; 454 455 AutoHandle filemap( 456 ::CreateFileMappingW(hFile, nullptr, PAGE_READONLY, 0, 1, NULL), nullptr); 457 if (!filemap.IsValid()) 458 return std::nullopt; 459 460 auto view_deleter = [](void *pMem) { ::UnmapViewOfFile(pMem); }; 461 std::unique_ptr<void, decltype(view_deleter)> pMem( 462 ::MapViewOfFile(filemap.get(), FILE_MAP_READ, 0, 0, 1), view_deleter); 463 if (!pMem) 464 return std::nullopt; 465 466 std::array<wchar_t, MAX_PATH + 1> mapped_filename; 467 if (!::GetMappedFileNameW(::GetCurrentProcess(), pMem.get(), 468 mapped_filename.data(), mapped_filename.size())) 469 return std::nullopt; 470 471 // A series of null-terminated strings, plus an additional null character 472 std::array<wchar_t, 512> drive_strings; 473 drive_strings[0] = L'\0'; 474 if (!::GetLogicalDriveStringsW(drive_strings.size(), drive_strings.data())) 475 return std::nullopt; 476 477 std::array<wchar_t, 3> drive = {L"_:"}; 478 for (const wchar_t *it = drive_strings.data(); *it != L'\0'; 479 it += wcslen(it) + 1) { 480 // Copy the drive letter to the template string 481 drive[0] = it[0]; 482 std::array<wchar_t, MAX_PATH> device_name; 483 if (::QueryDosDeviceW(drive.data(), device_name.data(), 484 device_name.size())) { 485 size_t device_name_len = wcslen(device_name.data()); 486 if (device_name_len < mapped_filename.size()) { 487 bool match = _wcsnicmp(mapped_filename.data(), device_name.data(), 488 device_name_len) == 0; 489 if (match && mapped_filename[device_name_len] == L'\\') { 490 // Replace device path with its drive letter 491 std::wstring rebuilt_path(drive.data()); 492 rebuilt_path.append(&mapped_filename[device_name_len]); 493 std::string path_utf8; 494 llvm::convertWideToUTF8(rebuilt_path, path_utf8); 495 return path_utf8; 496 } 497 } 498 } 499 } 500 return std::nullopt; 501 } 502 503 DWORD 504 DebuggerThread::HandleLoadDllEvent(const LOAD_DLL_DEBUG_INFO &info, 505 DWORD thread_id) { 506 Log *log = GetLog(WindowsLog::Event); 507 if (info.hFile == nullptr) { 508 // Not sure what this is, so just ignore it. 509 LLDB_LOG(log, "Warning: Inferior {0} has a NULL file handle, returning...", 510 m_process.GetProcessId()); 511 return DBG_CONTINUE; 512 } 513 514 auto on_load_dll = [&](llvm::StringRef path) { 515 FileSpec file_spec(path); 516 ModuleSpec module_spec(file_spec); 517 lldb::addr_t load_addr = reinterpret_cast<lldb::addr_t>(info.lpBaseOfDll); 518 519 LLDB_LOG(log, "Inferior {0} - DLL '{1}' loaded at address {2:x}...", 520 m_process.GetProcessId(), path, info.lpBaseOfDll); 521 522 m_debug_delegate->OnLoadDll(module_spec, load_addr); 523 }; 524 525 std::vector<wchar_t> buffer(1); 526 DWORD required_size = 527 GetFinalPathNameByHandleW(info.hFile, &buffer[0], 0, VOLUME_NAME_DOS); 528 if (required_size > 0) { 529 buffer.resize(required_size + 1); 530 required_size = GetFinalPathNameByHandleW(info.hFile, &buffer[0], 531 required_size, VOLUME_NAME_DOS); 532 std::string path_str_utf8; 533 llvm::convertWideToUTF8(buffer.data(), path_str_utf8); 534 llvm::StringRef path_str = path_str_utf8; 535 const char *path = path_str.data(); 536 if (path_str.starts_with("\\\\?\\")) 537 path += 4; 538 539 on_load_dll(path); 540 } else if (std::optional<std::string> path = 541 GetFileNameFromHandleFallback(info.hFile)) { 542 on_load_dll(*path); 543 } else { 544 LLDB_LOG( 545 log, 546 "Inferior {0} - Error {1} occurred calling GetFinalPathNameByHandle", 547 m_process.GetProcessId(), ::GetLastError()); 548 } 549 // Windows does not automatically close info.hFile, so we need to do it. 550 ::CloseHandle(info.hFile); 551 return DBG_CONTINUE; 552 } 553 554 DWORD 555 DebuggerThread::HandleUnloadDllEvent(const UNLOAD_DLL_DEBUG_INFO &info, 556 DWORD thread_id) { 557 Log *log = GetLog(WindowsLog::Event); 558 LLDB_LOG(log, "process {0} unloading DLL at addr {1:x}.", 559 m_process.GetProcessId(), info.lpBaseOfDll); 560 561 m_debug_delegate->OnUnloadDll( 562 reinterpret_cast<lldb::addr_t>(info.lpBaseOfDll)); 563 return DBG_CONTINUE; 564 } 565 566 DWORD 567 DebuggerThread::HandleODSEvent(const OUTPUT_DEBUG_STRING_INFO &info, 568 DWORD thread_id) { 569 return DBG_CONTINUE; 570 } 571 572 DWORD 573 DebuggerThread::HandleRipEvent(const RIP_INFO &info, DWORD thread_id) { 574 Log *log = GetLog(WindowsLog::Event); 575 LLDB_LOG(log, "encountered error {0} (type={1}) in process {2} thread {3}", 576 info.dwError, info.dwType, m_process.GetProcessId(), thread_id); 577 578 Status error(info.dwError, eErrorTypeWin32); 579 m_debug_delegate->OnDebuggerError(error, info.dwType); 580 581 return DBG_CONTINUE; 582 } 583