llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-lldb Author: Charles Zablit (charles-zablit) <details> <summary>Changes</summary> This patch breaks down `NativeProcessWindows::OnDebugException` into 3 different handlers (one for each exception) for readability. --- Full diff: https://github.com/llvm/llvm-project/pull/200832.diff 2 Files Affected: - (modified) lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp (+132-126) - (modified) lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h (+9) ``````````diff diff --git a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp index 26fc31fb27cf6..47be9e5322112 100644 --- a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp @@ -471,152 +471,158 @@ void NativeProcessWindows::OnDebuggerConnected(lldb::addr_t image_base) { } ExceptionResult -NativeProcessWindows::OnDebugException(bool first_chance, - const ExceptionRecord &record) { +NativeProcessWindows::HandleSingleStepException(const ExceptionRecord &record) { Log *log = GetLog(WindowsLog::Exception); - llvm::sys::ScopedLock lock(m_mutex); + uint32_t wp_id = LLDB_INVALID_INDEX32; +#ifndef __aarch64__ + if (NativeThreadWindows *thread = GetThreadByID(record.GetThreadID())) { + NativeRegisterContextWindows ®_ctx = thread->GetRegisterContext(); + Status error = + reg_ctx.GetWatchpointHitIndex(wp_id, record.GetExceptionAddress()); + if (error.Fail()) + LLDB_LOG(log, + "received error while checking for watchpoint hits, pid = " + "{0}, error = {1}", + thread->GetID(), error); + if (wp_id != LLDB_INVALID_INDEX32) { + addr_t wp_addr = reg_ctx.GetWatchpointAddress(wp_id); + addr_t wp_hit_addr = reg_ctx.GetWatchpointHitAddress(wp_id); + std::string desc = + formatv("{0} {1} {2}", wp_addr, wp_id, wp_hit_addr).str(); + StopThread(record.GetThreadID(), StopReason::eStopReasonWatchpoint, desc); + } + } +#endif + if (wp_id == LLDB_INVALID_INDEX32) + StopThread(record.GetThreadID(), StopReason::eStopReasonTrace); - // Let the debugger establish the internal status. - ProcessDebugger::OnDebugException(first_chance, record); + SetState(eStateStopped, true); + return ExceptionResult::MaskException; +} - static bool initial_stop = false; +ExceptionResult +NativeProcessWindows::HandleBreakpointException(const ExceptionRecord &record) { + Log *log = GetLog(WindowsLog::Exception); + const auto exception_addr = record.GetExceptionAddress(); + const auto thread_id = record.GetThreadID(); + + if (NativeThreadWindows *stop_thread = GetThreadByID(thread_id)) { + auto ®_ctx = stop_thread->GetRegisterContext(); + + if (FindSoftwareBreakpoint(exception_addr)) { + LLDB_LOG(log, "Hit non-loader breakpoint at address {0:x}.", + exception_addr); + StopThread(thread_id, StopReason::eStopReasonBreakpoint); + // The current PC is AFTER the BP opcode, on all architectures. + reg_ctx.SetPC(reg_ctx.GetPC() - GetSoftwareBreakpointPCOffset()); + SetState(eStateStopped, true); + return ExceptionResult::MaskException; + } - switch (record.GetExceptionCode()) { - case DWORD(STATUS_SINGLE_STEP): - case STATUS_WX86_SINGLE_STEP: { -#ifndef __aarch64__ - uint32_t wp_id = LLDB_INVALID_INDEX32; - if (NativeThreadWindows *thread = GetThreadByID(record.GetThreadID())) { - NativeRegisterContextWindows ®_ctx = thread->GetRegisterContext(); - Status error = - reg_ctx.GetWatchpointHitIndex(wp_id, record.GetExceptionAddress()); + // This block of code will only be entered in case of a hardware + // watchpoint or breakpoint hit on AArch64. However, we only handle + // hardware watchpoints below as breakpoints are not yet supported. + const std::vector<ULONG_PTR> &args = record.GetExceptionArguments(); + // Check that the ExceptionInformation array of EXCEPTION_RECORD + // contains at least two elements: the first is a read-write flag + // indicating the type of data access operation (read or write) while + // the second contains the virtual address of the accessed data. + if (args.size() >= 2) { + uint32_t hw_id = LLDB_INVALID_INDEX32; + Status error = reg_ctx.GetWatchpointHitIndex(hw_id, args[1]); if (error.Fail()) LLDB_LOG(log, "received error while checking for watchpoint hits, pid = " "{0}, error = {1}", - thread->GetID(), error); - if (wp_id != LLDB_INVALID_INDEX32) { - addr_t wp_addr = reg_ctx.GetWatchpointAddress(wp_id); - addr_t wp_hit_addr = reg_ctx.GetWatchpointHitAddress(wp_id); - std::string desc = - formatv("{0} {1} {2}", wp_addr, wp_id, wp_hit_addr).str(); - StopThread(record.GetThreadID(), StopReason::eStopReasonWatchpoint, - desc); - } - } - if (wp_id == LLDB_INVALID_INDEX32) -#endif - StopThread(record.GetThreadID(), StopReason::eStopReasonTrace); - - SetState(eStateStopped, true); + thread_id, error); - // Continue the debugger. - return ExceptionResult::MaskException; - } - case DWORD(STATUS_BREAKPOINT): - case STATUS_WX86_BREAKPOINT: { - if (NativeThreadWindows *stop_thread = - GetThreadByID(record.GetThreadID())) { - auto ®_ctx = stop_thread->GetRegisterContext(); - const auto exception_addr = record.GetExceptionAddress(); - const auto thread_id = record.GetThreadID(); - - if (FindSoftwareBreakpoint(exception_addr)) { - LLDB_LOG(log, "Hit non-loader breakpoint at address {0:x}.", - exception_addr); - StopThread(thread_id, StopReason::eStopReasonBreakpoint); - // The current PC is AFTER the BP opcode, on all architectures. - reg_ctx.SetPC(reg_ctx.GetPC() - GetSoftwareBreakpointPCOffset()); + if (hw_id != LLDB_INVALID_INDEX32) { + std::string desc = + formatv("{0} {1} {2}", reg_ctx.GetWatchpointAddress(hw_id), hw_id, + exception_addr) + .str(); + StopThread(thread_id, StopReason::eStopReasonWatchpoint, desc); SetState(eStateStopped, true); return ExceptionResult::MaskException; - } else { - // This block of code will only be entered in case of a hardware - // watchpoint or breakpoint hit on AArch64. However, we only handle - // hardware watchpoints below as breakpoints are not yet supported. - const std::vector<ULONG_PTR> &args = record.GetExceptionArguments(); - // Check that the ExceptionInformation array of EXCEPTION_RECORD - // contains at least two elements: the first is a read-write flag - // indicating the type of data access operation (read or write) while - // the second contains the virtual address of the accessed data. - if (args.size() >= 2) { - uint32_t hw_id = LLDB_INVALID_INDEX32; - Status error = reg_ctx.GetWatchpointHitIndex(hw_id, args[1]); - if (error.Fail()) - LLDB_LOG(log, - "received error while checking for watchpoint hits, pid = " - "{0}, error = {1}", - thread_id, error); - - if (hw_id != LLDB_INVALID_INDEX32) { - std::string desc = - formatv("{0} {1} {2}", reg_ctx.GetWatchpointAddress(hw_id), - hw_id, exception_addr) - .str(); - StopThread(thread_id, StopReason::eStopReasonWatchpoint, desc); - SetState(eStateStopped, true); - return ExceptionResult::MaskException; - } - } } } - - if (!initial_stop) { - initial_stop = true; - LLDB_LOG(log, - "Hit loader breakpoint at address {0:x}, setting initial stop " - "event.", - record.GetExceptionAddress()); - - // We are required to report the reason for the first stop after - // launching or being attached. - if (NativeThreadWindows *thread = GetThreadByID(record.GetThreadID())) - SetStopReasonForThread(*thread, StopReason::eStopReasonBreakpoint); - - // Do not notify the native delegate (e.g. llgs) since at this moment - // the program hasn't returned from Manager::Launch() and the delegate - // might not have an valid native process to operate on. - SetState(eStateStopped, false); - - // Hit the initial stop. Continue the application. - return ExceptionResult::BreakInDebugger; - } - - // Any remaining STATUS_BREAKPOINT is a breakpoint instruction in the - // program's own code (e.g. `__debugbreak()` or `__builtin_debugtrap()`). - // Stop the debugger and let the user decide what to do. - std::string desc = - formatv("Exception {0:x8} encountered at address {1:x8}", - record.GetExceptionCode(), record.GetExceptionAddress()) - .str(); - StopThread(record.GetThreadID(), StopReason::eStopReasonException, - std::move(desc)); - SetState(eStateStopped, true); - - return ExceptionResult::MaskException; } - default: { - LLDB_LOG(log, - "Debugger thread reported exception {0:x} at address {1:x} " - "(first_chance={2})", - record.GetExceptionCode(), record.GetExceptionAddress(), - first_chance); - if (first_chance) - return ExceptionResult::SendToApplication; + if (!m_initial_stop_seen) { + m_initial_stop_seen = true; + LLDB_LOG(log, + "Hit loader breakpoint at address {0:x}, setting initial stop " + "event.", + exception_addr); - std::string desc; - llvm::raw_string_ostream desc_stream(desc); - desc_stream << "Exception " - << llvm::format_hex(record.GetExceptionCode(), 8) - << " encountered at address " - << llvm::format_hex(record.GetExceptionAddress(), 8); - StopThread(record.GetThreadID(), StopReason::eStopReasonException, - desc.c_str()); + // We are required to report the reason for the first stop after + // launching or being attached. + if (NativeThreadWindows *thread = GetThreadByID(thread_id)) + SetStopReasonForThread(*thread, StopReason::eStopReasonBreakpoint); - SetState(eStateStopped, true); + // Do not notify the native delegate (e.g. llgs) since at this moment + // the program hasn't returned from Manager::Launch() and the delegate + // might not have an valid native process to operate on. + SetState(eStateStopped, false); + // Hit the initial stop. Continue the application. return ExceptionResult::BreakInDebugger; } + + // Any remaining STATUS_BREAKPOINT is a breakpoint instruction in the + // program's own code (e.g. `__debugbreak()` or `__builtin_debugtrap()`). + // Stop the debugger and let the user decide what to do. + std::string desc = + formatv("Exception {0:x8} encountered at address {1:x8}", + record.GetExceptionCode(), exception_addr) + .str(); + StopThread(thread_id, StopReason::eStopReasonException, std::move(desc)); + SetState(eStateStopped, true); + return ExceptionResult::MaskException; +} + +ExceptionResult +NativeProcessWindows::HandleGenericException(bool first_chance, + const ExceptionRecord &record) { + Log *log = GetLog(WindowsLog::Exception); + LLDB_LOG(log, + "Debugger thread reported exception {0:x} at address {1:x} " + "(first_chance={2})", + record.GetExceptionCode(), record.GetExceptionAddress(), + first_chance); + + if (first_chance) + return ExceptionResult::SendToApplication; + + std::string desc; + llvm::raw_string_ostream desc_stream(desc); + desc_stream << "Exception " << llvm::format_hex(record.GetExceptionCode(), 8) + << " encountered at address " + << llvm::format_hex(record.GetExceptionAddress(), 8); + StopThread(record.GetThreadID(), StopReason::eStopReasonException, + desc.c_str()); + + SetState(eStateStopped, true); + return ExceptionResult::BreakInDebugger; +} + +ExceptionResult +NativeProcessWindows::OnDebugException(bool first_chance, + const ExceptionRecord &record) { + llvm::sys::ScopedLock lock(m_mutex); + + // Let the debugger establish the internal status. + ProcessDebugger::OnDebugException(first_chance, record); + + switch (record.GetExceptionCode()) { + case DWORD(STATUS_SINGLE_STEP): + case STATUS_WX86_SINGLE_STEP: + return HandleSingleStepException(record); + case DWORD(STATUS_BREAKPOINT): + case STATUS_WX86_BREAKPOINT: + return HandleBreakpointException(record); + default: + return HandleGenericException(first_chance, record); } } diff --git a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h index becb3dbe48188..d2c37d202f242 100644 --- a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h +++ b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h @@ -140,12 +140,21 @@ class NativeProcessWindows : public NativeProcessProtocol, NativeProcessWindows(lldb::pid_t pid, int terminal_fd, NativeDelegate &delegate, llvm::Error &E); + ExceptionResult HandleSingleStepException(const ExceptionRecord &record); + ExceptionResult HandleBreakpointException(const ExceptionRecord &record); + ExceptionResult HandleGenericException(bool first_chance, + const ExceptionRecord &record); + Status CacheLoadedModules(); std::map<lldb_private::FileSpec, lldb::addr_t> m_loaded_modules; /// Set whenever an OS DLL load/unload event has been seen since the last stop /// reply. bool m_pending_library_events = true; + + /// Whether we've seen the loader breakpoint that fires once per process at + /// launch / attach. + bool m_initial_stop_seen = false; }; //------------------------------------------------------------------ `````````` </details> https://github.com/llvm/llvm-project/pull/200832 _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
