[Lldb-commits] [lldb] [NFC][lldb][windows] break down NativeProcessWindows::OnDebugException (PR #200832)
via lldb-commits
lldb-commits at lists.llvm.org
Mon Jun 1 07:20:08 PDT 2026
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
More information about the lldb-commits
mailing list