[Lldb-commits] [lldb] [lldb][Windows] ignore loader breakpoints in system modules (PR #208233)

2026-07-23 Thread Charles Zablit via lldb-commits

https://github.com/charles-zablit closed 
https://github.com/llvm/llvm-project/pull/208233
___
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb][Windows] ignore loader breakpoints in system modules (PR #208233)

2026-07-22 Thread Charles Zablit via lldb-commits


@@ -293,8 +297,12 @@ Status ProcessWindows::DoDestroy() {
 
 Status ProcessWindows::DoHalt(bool &caused_stop) {
   StateType state = GetPrivateState();
-  if (state != eStateStopped)
-return HaltProcess(caused_stop);
+  if (state != eStateStopped) {
+m_pending_halt = true;

charles-zablit wrote:

On Windows there's no SIGSTOP to pause a debuggee. To pause a running process 
from the debugger `DebugBreakProcess()` is used. It works by injecting a new 
thread into the target process that executes an `int3` instruction. The `int3` 
causes an `EXCEPTION_BREAKPOINT`.

`EXCEPTION_BREAKPOINT` is ambiguous because it can mean either of the 
following, without side data to differentiate them:

- Did the debuggee hit a breakpoint lldb set?: real stop, report it.
- Is this the loader's startup int3?: ignore it.
- Is this the artificial int3 lldb just injected to implement `Halt/Interrupt`? 
it's not a "real" breakpoint at all, ignore it.

`m_expecting_loader_int3` resolves the 2nd case.
`m_pending_halt` resolves the 3rd case.

https://github.com/llvm/llvm-project/pull/208233
___
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb][Windows] ignore loader breakpoints in system modules (PR #208233)

2026-07-22 Thread Charles Zablit via lldb-commits

https://github.com/charles-zablit deleted 
https://github.com/llvm/llvm-project/pull/208233
___
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb][Windows] ignore loader breakpoints in system modules (PR #208233)

2026-07-22 Thread Charles Zablit via lldb-commits


@@ -293,8 +297,12 @@ Status ProcessWindows::DoDestroy() {
 
 Status ProcessWindows::DoHalt(bool &caused_stop) {
   StateType state = GetPrivateState();
-  if (state != eStateStopped)
-return HaltProcess(caused_stop);
+  if (state != eStateStopped) {
+m_pending_halt = true;

charles-zablit wrote:

The Halt comes in as a Debug Exception yes.
It's not a real debug exception, it's just a "virtual breakpoint" that ntdll 
inserts when a process is spawned halted.
lldb currently treat it as a real breakpoint, which is unexpected to the user, 
because lldb looks like it hit a breakpoint that does not exist.
The m_pending_halt essentially says "disregard the first halt breakpoint we hit"

https://github.com/llvm/llvm-project/pull/208233
___
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb][Windows] ignore loader breakpoints in system modules (PR #208233)

2026-07-21 Thread via lldb-commits


@@ -293,8 +297,12 @@ Status ProcessWindows::DoDestroy() {
 
 Status ProcessWindows::DoHalt(bool &caused_stop) {
   StateType state = GetPrivateState();
-  if (state != eStateStopped)
-return HaltProcess(caused_stop);
+  if (state != eStateStopped) {
+m_pending_halt = true;

jimingham wrote:

You need this because the stop from a Halt comes in as an EXCEPTION_BREAKPOINT?

https://github.com/llvm/llvm-project/pull/208233
___
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb][Windows] ignore loader breakpoints in system modules (PR #208233)

2026-07-20 Thread via lldb-commits

https://github.com/Nerixyz approved this pull request.

This looks good to me now. I think it should be noted that we only need to do 
this when attaching to a process. We notice this in lldb-dap when launching in 
a terminal, because that will attach to the process.

The documentation for 
[`DebugActiveProcess`](https://learn.microsoft.com/en-us/windows/win32/api/debugapi/nf-debugapi-debugactiveprocess)
 also mentions this:
> After all of this is done, the system resumes all threads in the process. 
> When the first thread in the process resumes, it executes a breakpoint 
> instruction that causes an EXCEPTION_DEBUG_EVENT debugging event to be sent 
> to the debugger. All future debugging events are sent to the debugger by 
> using the normal mechanism and rules.

https://github.com/llvm/llvm-project/pull/208233
___
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb][Windows] ignore loader breakpoints in system modules (PR #208233)

2026-07-20 Thread Charles Zablit via lldb-commits


@@ -664,6 +627,17 @@ NativeProcessWindows::HandleBreakpointException(const 
ExceptionRecord &record) {
 return ExceptionResult::BreakInDebugger;
   }
 
+  if (m_expecting_loader_int3) {
+m_expecting_loader_int3 = false;

charles-zablit wrote:

That's a bug. I moved the call to `IsSystemModuleAddress` up the chain in both 
places where this happens.

https://github.com/llvm/llvm-project/pull/208233
___
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb][Windows] ignore loader breakpoints in system modules (PR #208233)

2026-07-20 Thread Charles Zablit via lldb-commits

https://github.com/charles-zablit edited 
https://github.com/llvm/llvm-project/pull/208233
___
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb][Windows] ignore loader breakpoints in system modules (PR #208233)

2026-07-20 Thread Charles Zablit via lldb-commits


@@ -19,16 +19,85 @@
 #include "lldb/Host/ProcessLaunchInfo.h"
 #include "lldb/Target/MemoryRegionInfo.h"
 #include "lldb/Target/Process.h"
+#include "lldb/Utility/FileSpec.h"
 #include "llvm/Support/ConvertUTF.h"
 #include "llvm/Support/Error.h"
 
 #include "DebuggerThread.h"
 #include "ExceptionRecord.h"
 #include "ProcessWindowsLog.h"
 
+#include 
+#include 
+#include 
+
 using namespace lldb;
 using namespace lldb_private;
 
+static void NormalizeWindowsPath(std::string &s) {
+  for (char &c : s) {
+if (c == '/')
+  c = '\\';
+else
+  c = std::tolower(static_cast(c));
+  }
+}
+
+bool ProcessDebugger::IsSystemDLL(const FileSpec &spec) {
+  if (!spec)
+return false;
+
+  static const std::string windows_prefix = []() {
+std::string prefix;
+wchar_t buf[MAX_PATH];
+UINT len = ::GetWindowsDirectoryW(buf, MAX_PATH);
+if (len == 0 || len >= MAX_PATH)
+  return prefix;
+llvm::convertWideToUTF8(std::wstring_view(buf, len), prefix);
+NormalizeWindowsPath(prefix);
+if (!prefix.empty() && prefix.back() != '\\')
+  prefix += '\\';
+return prefix;
+  }();
+
+  if (windows_prefix.empty())
+return false;
+
+  std::string path = spec.GetPath();
+  NormalizeWindowsPath(path);
+  return llvm::StringRef(path).starts_with(windows_prefix);

charles-zablit wrote:

Fixed

https://github.com/llvm/llvm-project/pull/208233
___
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb][Windows] ignore loader breakpoints in system modules (PR #208233)

2026-07-20 Thread Charles Zablit via lldb-commits


@@ -19,16 +19,85 @@
 #include "lldb/Host/ProcessLaunchInfo.h"
 #include "lldb/Target/MemoryRegionInfo.h"
 #include "lldb/Target/Process.h"
+#include "lldb/Utility/FileSpec.h"
 #include "llvm/Support/ConvertUTF.h"
 #include "llvm/Support/Error.h"
 
 #include "DebuggerThread.h"
 #include "ExceptionRecord.h"
 #include "ProcessWindowsLog.h"
 
+#include 
+#include 
+#include 
+
 using namespace lldb;
 using namespace lldb_private;
 
+static void NormalizeWindowsPath(std::string &s) {
+  for (char &c : s) {
+if (c == '/')
+  c = '\\';
+else
+  c = std::tolower(static_cast(c));
+  }
+}
+
+bool ProcessDebugger::IsSystemDLL(const FileSpec &spec) {

charles-zablit wrote:

Switched to `StringRef` 👍 

https://github.com/llvm/llvm-project/pull/208233
___
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb][Windows] ignore loader breakpoints in system modules (PR #208233)

2026-07-20 Thread Charles Zablit via lldb-commits

https://github.com/charles-zablit updated 
https://github.com/llvm/llvm-project/pull/208233

>From d6abb3698fd1419ec5c89df61a9243cf6fcc0772 Mon Sep 17 00:00:00 2001
From: Charles Zablit 
Date: Wed, 8 Jul 2026 15:46:39 +0100
Subject: [PATCH 1/6] [lldb][Windows] ignore loader breakpoints in system
 modules

---
 .../Windows/Common/NativeProcessWindows.cpp   | 55 ---
 .../Windows/Common/ProcessDebugger.cpp| 69 +++
 .../Process/Windows/Common/ProcessDebugger.h  |  5 ++
 .../Process/Windows/Common/ProcessWindows.cpp | 16 -
 4 files changed, 101 insertions(+), 44 deletions(-)

diff --git 
a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp 
b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp
index ada92894efc47..f1de697c34b67 100644
--- a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp
+++ b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp
@@ -50,44 +50,6 @@ using namespace llvm;
 
 namespace lldb_private {
 
-namespace {
-
-void NormalizeWindowsPath(std::string &s) {
-  for (char &c : s) {
-if (c == '/')
-  c = '\\';
-else
-  c = std::tolower(static_cast(c));
-  }
-}
-
-bool IsSystemDLL(const FileSpec &spec) {
-  if (!spec)
-return false;
-
-  static const std::string windows_prefix = []() {
-std::string prefix;
-wchar_t buf[MAX_PATH];
-UINT len = ::GetWindowsDirectoryW(buf, MAX_PATH);
-if (len == 0 || len >= MAX_PATH)
-  return prefix;
-llvm::convertWideToUTF8(std::wstring_view(buf, len), prefix);
-NormalizeWindowsPath(prefix);
-if (!prefix.empty() && prefix.back() != '\\')
-  prefix += '\\';
-return prefix;
-  }();
-
-  if (windows_prefix.empty())
-return false;
-
-  std::string path = spec.GetPath();
-  NormalizeWindowsPath(path);
-  return llvm::StringRef(path).starts_with(windows_prefix);
-}
-
-} // namespace
-
 NativeProcessWindows::NativeProcessWindows(ProcessLaunchInfo &launch_info,
NativeDelegate &delegate,
llvm::Error &E)
@@ -635,9 +597,8 @@ NativeProcessWindows::HandleBreakpointException(const 
ExceptionRecord &record) {
 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.
+  // Our own DebugBreakProcess() injection, used to implement
+  // Halt()/Interrupt().
   if (m_pending_halt) {
 LLDB_LOG(log,
  "DebugBreakProcess injection treated as Halt SIGSTOP for tid "
@@ -664,6 +625,14 @@ NativeProcessWindows::HandleBreakpointException(const 
ExceptionRecord &record) {
 return ExceptionResult::BreakInDebugger;
   }
 
+  if (IsSystemModuleAddress(exception_addr)) {
+LLDB_LOG(log,
+ "Ignoring loader/OS breakpoint at address {0:x} in a system "
+ "module.",
+ exception_addr);
+return ExceptionResult::MaskException;
+  }
+
   std::string desc = formatv("Exception {0:x8} encountered at address {1:x8}",
  record.GetExceptionValue(), exception_addr)
  .str();
@@ -776,7 +745,7 @@ DllEventAction NativeProcessWindows::OnLoadDll(const 
ModuleSpec &module_spec,
 return DllEventAction::ContinueDebugLoop;
 
   // Can't resolve a breakpoint in a system DLL.
-  if (!resolved || IsSystemDLL(resolved))
+  if (!resolved || ProcessDebugger::IsSystemDLL(resolved))
 return DllEventAction::ContinueDebugLoop;
 
   NativeThreadWindows *loader_thread = GetThreadByID(thread_id);
@@ -819,7 +788,7 @@ DllEventAction 
NativeProcessWindows::OnUnloadDll(lldb::addr_t module_addr,
   if (!m_initial_stop_seen || !m_client_supports_libraries_read)
 return DllEventAction::ContinueDebugLoop;
 
-  if (!unloaded_spec || IsSystemDLL(unloaded_spec))
+  if (!unloaded_spec || ProcessDebugger::IsSystemDLL(unloaded_spec))
 return DllEventAction::ContinueDebugLoop;
 
   NativeThreadWindows *unloader_thread = GetThreadByID(thread_id);
diff --git a/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp 
b/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp
index 63fc20f36b07b..a4322c3d3f536 100644
--- a/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp
+++ b/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp
@@ -19,6 +19,7 @@
 #include "lldb/Host/ProcessLaunchInfo.h"
 #include "lldb/Target/MemoryRegionInfo.h"
 #include "lldb/Target/Process.h"
+#include "lldb/Utility/FileSpec.h"
 #include "llvm/Support/ConvertUTF.h"
 #include "llvm/Support/Error.h"
 
@@ -26,9 +27,77 @@
 #include "ExceptionRecord.h"
 #include "ProcessWindowsLog.h"
 
+#include 
+#include 
+#include 
+
 using namespace lldb;
 using namespace lldb_private;
 
+static void NormalizeWindowsPath(std::string &s) {
+  for (char &c : s) {
+if (c == '/')

[Lldb-commits] [lldb] [lldb][Windows] ignore loader breakpoints in system modules (PR #208233)

2026-07-13 Thread Charles Zablit via lldb-commits

charles-zablit wrote:

> What is the logic behind `m_pending_halt`? You set it in 
> `ProcessWindows::DoHalt` but then you also check for it when handling an 
> `EXCEPTION_BREAKPOINT`. Why do you need to check there?

This is to tell appart `int3` exceptions we caused to interrupt the process, 
versus any other ones (real exceptions). When lldb halts a process, the process 
will be halted through an `EXCEPTION_BREAKPOINT` but there is no way to 
differentiate it with a real breakpoint.

https://github.com/llvm/llvm-project/pull/208233
___
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb][Windows] ignore loader breakpoints in system modules (PR #208233)

2026-07-10 Thread Alex Langford via lldb-commits

https://github.com/bulbazord commented:

What is the logic behind `m_pending_halt`? You set it in 
`ProcessWindows::DoHalt` but then you also check for it when handling an 
`EXCEPTION_BREAKPOINT`. Why do you need to check there?

https://github.com/llvm/llvm-project/pull/208233
___
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb][Windows] ignore loader breakpoints in system modules (PR #208233)

2026-07-09 Thread Charles Zablit via lldb-commits

charles-zablit wrote:

The handler only runs for `STATUS_BREAKPOINT` whereas fatal errors use 
different instructions: `__builtin_trap()` uses `STATUS_ILLEGAL_INSTRUCTION` 
for instance. This means fatal errors exceptions don't enter 
`HandleBreakpointException` and are therefore not masked.

I've narrowed down the int3 masking to one stop in the latest commit.

https://github.com/llvm/llvm-project/pull/208233
___
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb][Windows] ignore loader breakpoints in system modules (PR #208233)

2026-07-09 Thread Charles Zablit via lldb-commits

https://github.com/charles-zablit updated 
https://github.com/llvm/llvm-project/pull/208233

>From d6abb3698fd1419ec5c89df61a9243cf6fcc0772 Mon Sep 17 00:00:00 2001
From: Charles Zablit 
Date: Wed, 8 Jul 2026 15:46:39 +0100
Subject: [PATCH 1/5] [lldb][Windows] ignore loader breakpoints in system
 modules

---
 .../Windows/Common/NativeProcessWindows.cpp   | 55 ---
 .../Windows/Common/ProcessDebugger.cpp| 69 +++
 .../Process/Windows/Common/ProcessDebugger.h  |  5 ++
 .../Process/Windows/Common/ProcessWindows.cpp | 16 -
 4 files changed, 101 insertions(+), 44 deletions(-)

diff --git 
a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp 
b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp
index ada92894efc47..f1de697c34b67 100644
--- a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp
+++ b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp
@@ -50,44 +50,6 @@ using namespace llvm;
 
 namespace lldb_private {
 
-namespace {
-
-void NormalizeWindowsPath(std::string &s) {
-  for (char &c : s) {
-if (c == '/')
-  c = '\\';
-else
-  c = std::tolower(static_cast(c));
-  }
-}
-
-bool IsSystemDLL(const FileSpec &spec) {
-  if (!spec)
-return false;
-
-  static const std::string windows_prefix = []() {
-std::string prefix;
-wchar_t buf[MAX_PATH];
-UINT len = ::GetWindowsDirectoryW(buf, MAX_PATH);
-if (len == 0 || len >= MAX_PATH)
-  return prefix;
-llvm::convertWideToUTF8(std::wstring_view(buf, len), prefix);
-NormalizeWindowsPath(prefix);
-if (!prefix.empty() && prefix.back() != '\\')
-  prefix += '\\';
-return prefix;
-  }();
-
-  if (windows_prefix.empty())
-return false;
-
-  std::string path = spec.GetPath();
-  NormalizeWindowsPath(path);
-  return llvm::StringRef(path).starts_with(windows_prefix);
-}
-
-} // namespace
-
 NativeProcessWindows::NativeProcessWindows(ProcessLaunchInfo &launch_info,
NativeDelegate &delegate,
llvm::Error &E)
@@ -635,9 +597,8 @@ NativeProcessWindows::HandleBreakpointException(const 
ExceptionRecord &record) {
 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.
+  // Our own DebugBreakProcess() injection, used to implement
+  // Halt()/Interrupt().
   if (m_pending_halt) {
 LLDB_LOG(log,
  "DebugBreakProcess injection treated as Halt SIGSTOP for tid "
@@ -664,6 +625,14 @@ NativeProcessWindows::HandleBreakpointException(const 
ExceptionRecord &record) {
 return ExceptionResult::BreakInDebugger;
   }
 
+  if (IsSystemModuleAddress(exception_addr)) {
+LLDB_LOG(log,
+ "Ignoring loader/OS breakpoint at address {0:x} in a system "
+ "module.",
+ exception_addr);
+return ExceptionResult::MaskException;
+  }
+
   std::string desc = formatv("Exception {0:x8} encountered at address {1:x8}",
  record.GetExceptionValue(), exception_addr)
  .str();
@@ -776,7 +745,7 @@ DllEventAction NativeProcessWindows::OnLoadDll(const 
ModuleSpec &module_spec,
 return DllEventAction::ContinueDebugLoop;
 
   // Can't resolve a breakpoint in a system DLL.
-  if (!resolved || IsSystemDLL(resolved))
+  if (!resolved || ProcessDebugger::IsSystemDLL(resolved))
 return DllEventAction::ContinueDebugLoop;
 
   NativeThreadWindows *loader_thread = GetThreadByID(thread_id);
@@ -819,7 +788,7 @@ DllEventAction 
NativeProcessWindows::OnUnloadDll(lldb::addr_t module_addr,
   if (!m_initial_stop_seen || !m_client_supports_libraries_read)
 return DllEventAction::ContinueDebugLoop;
 
-  if (!unloaded_spec || IsSystemDLL(unloaded_spec))
+  if (!unloaded_spec || ProcessDebugger::IsSystemDLL(unloaded_spec))
 return DllEventAction::ContinueDebugLoop;
 
   NativeThreadWindows *unloader_thread = GetThreadByID(thread_id);
diff --git a/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp 
b/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp
index 63fc20f36b07b..a4322c3d3f536 100644
--- a/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp
+++ b/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp
@@ -19,6 +19,7 @@
 #include "lldb/Host/ProcessLaunchInfo.h"
 #include "lldb/Target/MemoryRegionInfo.h"
 #include "lldb/Target/Process.h"
+#include "lldb/Utility/FileSpec.h"
 #include "llvm/Support/ConvertUTF.h"
 #include "llvm/Support/Error.h"
 
@@ -26,9 +27,77 @@
 #include "ExceptionRecord.h"
 #include "ProcessWindowsLog.h"
 
+#include 
+#include 
+#include 
+
 using namespace lldb;
 using namespace lldb_private;
 
+static void NormalizeWindowsPath(std::string &s) {
+  for (char &c : s) {
+if (c == '/')

[Lldb-commits] [lldb] [lldb][Windows] ignore loader breakpoints in system modules (PR #208233)

2026-07-08 Thread Charles Zablit via lldb-commits

https://github.com/charles-zablit edited 
https://github.com/llvm/llvm-project/pull/208233
___
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb][Windows] ignore loader breakpoints in system modules (PR #208233)

2026-07-08 Thread Charles Zablit via lldb-commits

https://github.com/charles-zablit updated 
https://github.com/llvm/llvm-project/pull/208233

>From d6abb3698fd1419ec5c89df61a9243cf6fcc0772 Mon Sep 17 00:00:00 2001
From: Charles Zablit 
Date: Wed, 8 Jul 2026 15:46:39 +0100
Subject: [PATCH 1/4] [lldb][Windows] ignore loader breakpoints in system
 modules

---
 .../Windows/Common/NativeProcessWindows.cpp   | 55 ---
 .../Windows/Common/ProcessDebugger.cpp| 69 +++
 .../Process/Windows/Common/ProcessDebugger.h  |  5 ++
 .../Process/Windows/Common/ProcessWindows.cpp | 16 -
 4 files changed, 101 insertions(+), 44 deletions(-)

diff --git 
a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp 
b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp
index ada92894efc47..f1de697c34b67 100644
--- a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp
+++ b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp
@@ -50,44 +50,6 @@ using namespace llvm;
 
 namespace lldb_private {
 
-namespace {
-
-void NormalizeWindowsPath(std::string &s) {
-  for (char &c : s) {
-if (c == '/')
-  c = '\\';
-else
-  c = std::tolower(static_cast(c));
-  }
-}
-
-bool IsSystemDLL(const FileSpec &spec) {
-  if (!spec)
-return false;
-
-  static const std::string windows_prefix = []() {
-std::string prefix;
-wchar_t buf[MAX_PATH];
-UINT len = ::GetWindowsDirectoryW(buf, MAX_PATH);
-if (len == 0 || len >= MAX_PATH)
-  return prefix;
-llvm::convertWideToUTF8(std::wstring_view(buf, len), prefix);
-NormalizeWindowsPath(prefix);
-if (!prefix.empty() && prefix.back() != '\\')
-  prefix += '\\';
-return prefix;
-  }();
-
-  if (windows_prefix.empty())
-return false;
-
-  std::string path = spec.GetPath();
-  NormalizeWindowsPath(path);
-  return llvm::StringRef(path).starts_with(windows_prefix);
-}
-
-} // namespace
-
 NativeProcessWindows::NativeProcessWindows(ProcessLaunchInfo &launch_info,
NativeDelegate &delegate,
llvm::Error &E)
@@ -635,9 +597,8 @@ NativeProcessWindows::HandleBreakpointException(const 
ExceptionRecord &record) {
 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.
+  // Our own DebugBreakProcess() injection, used to implement
+  // Halt()/Interrupt().
   if (m_pending_halt) {
 LLDB_LOG(log,
  "DebugBreakProcess injection treated as Halt SIGSTOP for tid "
@@ -664,6 +625,14 @@ NativeProcessWindows::HandleBreakpointException(const 
ExceptionRecord &record) {
 return ExceptionResult::BreakInDebugger;
   }
 
+  if (IsSystemModuleAddress(exception_addr)) {
+LLDB_LOG(log,
+ "Ignoring loader/OS breakpoint at address {0:x} in a system "
+ "module.",
+ exception_addr);
+return ExceptionResult::MaskException;
+  }
+
   std::string desc = formatv("Exception {0:x8} encountered at address {1:x8}",
  record.GetExceptionValue(), exception_addr)
  .str();
@@ -776,7 +745,7 @@ DllEventAction NativeProcessWindows::OnLoadDll(const 
ModuleSpec &module_spec,
 return DllEventAction::ContinueDebugLoop;
 
   // Can't resolve a breakpoint in a system DLL.
-  if (!resolved || IsSystemDLL(resolved))
+  if (!resolved || ProcessDebugger::IsSystemDLL(resolved))
 return DllEventAction::ContinueDebugLoop;
 
   NativeThreadWindows *loader_thread = GetThreadByID(thread_id);
@@ -819,7 +788,7 @@ DllEventAction 
NativeProcessWindows::OnUnloadDll(lldb::addr_t module_addr,
   if (!m_initial_stop_seen || !m_client_supports_libraries_read)
 return DllEventAction::ContinueDebugLoop;
 
-  if (!unloaded_spec || IsSystemDLL(unloaded_spec))
+  if (!unloaded_spec || ProcessDebugger::IsSystemDLL(unloaded_spec))
 return DllEventAction::ContinueDebugLoop;
 
   NativeThreadWindows *unloader_thread = GetThreadByID(thread_id);
diff --git a/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp 
b/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp
index 63fc20f36b07b..a4322c3d3f536 100644
--- a/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp
+++ b/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp
@@ -19,6 +19,7 @@
 #include "lldb/Host/ProcessLaunchInfo.h"
 #include "lldb/Target/MemoryRegionInfo.h"
 #include "lldb/Target/Process.h"
+#include "lldb/Utility/FileSpec.h"
 #include "llvm/Support/ConvertUTF.h"
 #include "llvm/Support/Error.h"
 
@@ -26,9 +27,77 @@
 #include "ExceptionRecord.h"
 #include "ProcessWindowsLog.h"
 
+#include 
+#include 
+#include 
+
 using namespace lldb;
 using namespace lldb_private;
 
+static void NormalizeWindowsPath(std::string &s) {
+  for (char &c : s) {
+if (c == '/')

[Lldb-commits] [lldb] [lldb][Windows] ignore loader breakpoints in system modules (PR #208233)

2026-07-08 Thread via lldb-commits

github-actions[bot] wrote:


# :window: Windows x64 Test Results

* 33344 tests passed
* 902 tests skipped
* 3 tests failed

## Failed Tests
(click on a test name to see its output)

### lldb-api

lldb-api.commands/expression/expr-in-syscall/TestExpressionInSyscall.py

```
Script:
--
C:/Python312/python.exe 
C:/_work/llvm-project/llvm-project/lldb\test\API\dotest.py -u CXXFLAGS -u 
CFLAGS --env LLVM_LIBS_DIR=C:/_work/llvm-project/llvm-project/build/./lib --env 
LLVM_INCLUDE_DIR=C:/_work/llvm-project/llvm-project/build/include --env 
LLVM_TOOLS_DIR=C:/_work/llvm-project/llvm-project/build/./bin --triple 
x86_64-pc-windows-msvc --build-dir 
C:/_work/llvm-project/llvm-project/build/lldb-test-build 
--lldb-module-cache-dir 
C:/_work/llvm-project/llvm-project/build/lldb-test-build/module-cache-lldb\lldb-api
 --clang-module-cache-dir 
C:/_work/llvm-project/llvm-project/build/lldb-test-build/module-cache-clang\lldb-api
 --executable C:/_work/llvm-project/llvm-project/build/./bin/lldb.exe 
--lldb-python-dir C:\_work\llvm-project\llvm-project\build\Lib\site-packages 
--compiler C:/_work/llvm-project/llvm-project/build/./bin/clang.exe --dsymutil 
C:/_work/llvm-project/llvm-project/build/./bin/dsymutil.exe --make 
C:/ProgramData/chocolatey/bin/make.exe --llvm-tools-dir 
C:/_work/llvm-project/llvm-project/build/./bin --lldb-obj-root 
C:/_work/llvm-project/llvm-project/build/tools/lldb --lldb-libs-dir 
C:/_work/llvm-project/llvm-project/build/./lib --cmake-build-type Release --env 
LLDB_LAUNCH_FLAG_USE_PIPES=1 
C:\_work\llvm-project\llvm-project\lldb\test\API\commands\expression\expr-in-syscall
 -p TestExpressionInSyscall.py
--
Exit Code: 1

Command Output (stdout):
--
Skipping the following test categories: libc++, libstdcxx, dwo, dsym, gmodules, 
debugserver, objc, fork, pexpect


--
Command Output (stderr):
--
UNSUPPORTED: LLDB 
(C:\_work\llvm-project\llvm-project\build\bin\clang.exe-x86_64) :: 
test_setpgid_dsym 
(TestExpressionInSyscall.ExprSyscallTestCase.test_setpgid_dsym) (test case does 
not fall in any category of interest for this run) 

FAIL: LLDB (C:\_work\llvm-project\llvm-project\build\bin\clang.exe-x86_64) :: 
test_setpgid_dwarf 
(TestExpressionInSyscall.ExprSyscallTestCase.test_setpgid_dwarf)

Log Files:

 - 
C:\_work\llvm-project\llvm-project\build\lldb-test-build\commands\expression\expr-in-syscall\TestExpressionInSyscall\Failure_test_setpgid_dwarf.log

UNSUPPORTED: LLDB 
(C:\_work\llvm-project\llvm-project\build\bin\clang.exe-x86_64) :: 
test_setpgid_dwo (TestExpressionInSyscall.ExprSyscallTestCase.test_setpgid_dwo) 
(test case does not fall in any category of interest for this run) 

==

FAIL: test_setpgid_dwarf 
(TestExpressionInSyscall.ExprSyscallTestCase.test_setpgid_dwarf)

--

Traceback (most recent call last):

  File 
"C:\_work\llvm-project\llvm-project\lldb\packages\Python\lldbsuite\test\lldbtest.py",
 line 2186, in test_method

return attrvalue(self)

   ^^^

  File 
"C:\_work\llvm-project\llvm-project\lldb\test\API\commands\expression\expr-in-syscall\TestExpressionInSyscall.py",
 line 57, in test_setpgid

self.assertEqual(process.GetState(), lldb.eStateStopped, PROCESS_STOPPED)

AssertionError: 6 != 5 : Process status should be stopped

Config=x86_64-C:\_work\llvm-project\llvm-project\build\bin\clang.exe

--

Ran 3 tests in 7.998s



FAILED (failures=1, skipped=2)


--

```


lldb-api.commands/expression/no-deadlock/TestExprDoesntBlock.py

```
Script:
--
C:/Python312/python.exe 
C:/_work/llvm-project/llvm-project/lldb\test\API\dotest.py -u CXXFLAGS -u 
CFLAGS --env LLVM_LIBS_DIR=C:/_work/llvm-project/llvm-project/build/./lib --env 
LLVM_INCLUDE_DIR=C:/_work/llvm-project/llvm-project/build/include --env 
LLVM_TOOLS_DIR=C:/_work/llvm-project/llvm-project/build/./bin --triple 
x86_64-pc-windows-msvc --build-dir 
C:/_work/llvm-project/llvm-project/build/lldb-test-build 
--lldb-module-cache-dir 
C:/_work/llvm-project/llvm-project/build/lldb-test-build/module-cache-lldb\lldb-api
 --clang-module-cache-dir 
C:/_work/llvm-project/llvm-project/build/lldb-test-build/module-cache-clang\lldb-api
 --executable C:/_work/llvm-project/llvm-project/build/./bin/lldb.exe 
--lldb-python-dir C:\_work\llvm-project\llvm-project\build\Lib\site-packages 
--compiler C:/_work/llvm-project/llvm-project/build/./bin/clang.exe --dsymutil 
C:/_work/llvm-project/llvm-project/build/./bin/dsymutil.exe --make 
C:/ProgramData/chocolatey/bin/make.exe --llvm-tools-dir 
C:/_work/llvm-project/llvm-project/build/./bin --lldb-obj-root 
C:/_work/llvm-project/llvm-project/build/tools/lldb --lldb-libs-dir 
C:/_work/llvm-project/llvm-project/build/./lib --cmake-build-type Release --env 
LLDB_LAUNCH_FLAG_USE_PIPES=1 
C:\_work\llvm-project\llvm-project\lldb\test\API\commands\expression\no-deadlock
 -p TestExp

[Lldb-commits] [lldb] [lldb][Windows] ignore loader breakpoints in system modules (PR #208233)

2026-07-08 Thread Charles Zablit via lldb-commits

charles-zablit wrote:

> I'll read this properly tomorrow, but -
> 
> > This is because ntdll executes an int3 breakpoint during process 
> > initialization when a debugger is attached.
> 
> Do you know why it does this, is it to give the debugger a chance to set 
> itself up?
> 
> If that is the case I'm curious what sorts of things that might be, 
> considering that we apparently haven't needed it so far.

It's indeed to give the debugger a chance to set itself up, and we do use it: 
in `integratedTerminal` mode we start the debuggee _paused_ and then we attach 
to it. This produces 2 breaks:
1. an attach break
2. the loader's debugger break (this is the one that shows up unexpectedly)

A regular launch (the debuggee spawns attached to the process) only has the 
second break.

https://github.com/llvm/llvm-project/pull/208233
___
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb][Windows] ignore loader breakpoints in system modules (PR #208233)

2026-07-08 Thread Charles Zablit via lldb-commits

https://github.com/charles-zablit updated 
https://github.com/llvm/llvm-project/pull/208233

>From d6abb3698fd1419ec5c89df61a9243cf6fcc0772 Mon Sep 17 00:00:00 2001
From: Charles Zablit 
Date: Wed, 8 Jul 2026 15:46:39 +0100
Subject: [PATCH 1/3] [lldb][Windows] ignore loader breakpoints in system
 modules

---
 .../Windows/Common/NativeProcessWindows.cpp   | 55 ---
 .../Windows/Common/ProcessDebugger.cpp| 69 +++
 .../Process/Windows/Common/ProcessDebugger.h  |  5 ++
 .../Process/Windows/Common/ProcessWindows.cpp | 16 -
 4 files changed, 101 insertions(+), 44 deletions(-)

diff --git 
a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp 
b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp
index ada92894efc47..f1de697c34b67 100644
--- a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp
+++ b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp
@@ -50,44 +50,6 @@ using namespace llvm;
 
 namespace lldb_private {
 
-namespace {
-
-void NormalizeWindowsPath(std::string &s) {
-  for (char &c : s) {
-if (c == '/')
-  c = '\\';
-else
-  c = std::tolower(static_cast(c));
-  }
-}
-
-bool IsSystemDLL(const FileSpec &spec) {
-  if (!spec)
-return false;
-
-  static const std::string windows_prefix = []() {
-std::string prefix;
-wchar_t buf[MAX_PATH];
-UINT len = ::GetWindowsDirectoryW(buf, MAX_PATH);
-if (len == 0 || len >= MAX_PATH)
-  return prefix;
-llvm::convertWideToUTF8(std::wstring_view(buf, len), prefix);
-NormalizeWindowsPath(prefix);
-if (!prefix.empty() && prefix.back() != '\\')
-  prefix += '\\';
-return prefix;
-  }();
-
-  if (windows_prefix.empty())
-return false;
-
-  std::string path = spec.GetPath();
-  NormalizeWindowsPath(path);
-  return llvm::StringRef(path).starts_with(windows_prefix);
-}
-
-} // namespace
-
 NativeProcessWindows::NativeProcessWindows(ProcessLaunchInfo &launch_info,
NativeDelegate &delegate,
llvm::Error &E)
@@ -635,9 +597,8 @@ NativeProcessWindows::HandleBreakpointException(const 
ExceptionRecord &record) {
 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.
+  // Our own DebugBreakProcess() injection, used to implement
+  // Halt()/Interrupt().
   if (m_pending_halt) {
 LLDB_LOG(log,
  "DebugBreakProcess injection treated as Halt SIGSTOP for tid "
@@ -664,6 +625,14 @@ NativeProcessWindows::HandleBreakpointException(const 
ExceptionRecord &record) {
 return ExceptionResult::BreakInDebugger;
   }
 
+  if (IsSystemModuleAddress(exception_addr)) {
+LLDB_LOG(log,
+ "Ignoring loader/OS breakpoint at address {0:x} in a system "
+ "module.",
+ exception_addr);
+return ExceptionResult::MaskException;
+  }
+
   std::string desc = formatv("Exception {0:x8} encountered at address {1:x8}",
  record.GetExceptionValue(), exception_addr)
  .str();
@@ -776,7 +745,7 @@ DllEventAction NativeProcessWindows::OnLoadDll(const 
ModuleSpec &module_spec,
 return DllEventAction::ContinueDebugLoop;
 
   // Can't resolve a breakpoint in a system DLL.
-  if (!resolved || IsSystemDLL(resolved))
+  if (!resolved || ProcessDebugger::IsSystemDLL(resolved))
 return DllEventAction::ContinueDebugLoop;
 
   NativeThreadWindows *loader_thread = GetThreadByID(thread_id);
@@ -819,7 +788,7 @@ DllEventAction 
NativeProcessWindows::OnUnloadDll(lldb::addr_t module_addr,
   if (!m_initial_stop_seen || !m_client_supports_libraries_read)
 return DllEventAction::ContinueDebugLoop;
 
-  if (!unloaded_spec || IsSystemDLL(unloaded_spec))
+  if (!unloaded_spec || ProcessDebugger::IsSystemDLL(unloaded_spec))
 return DllEventAction::ContinueDebugLoop;
 
   NativeThreadWindows *unloader_thread = GetThreadByID(thread_id);
diff --git a/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp 
b/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp
index 63fc20f36b07b..a4322c3d3f536 100644
--- a/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp
+++ b/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp
@@ -19,6 +19,7 @@
 #include "lldb/Host/ProcessLaunchInfo.h"
 #include "lldb/Target/MemoryRegionInfo.h"
 #include "lldb/Target/Process.h"
+#include "lldb/Utility/FileSpec.h"
 #include "llvm/Support/ConvertUTF.h"
 #include "llvm/Support/Error.h"
 
@@ -26,9 +27,77 @@
 #include "ExceptionRecord.h"
 #include "ProcessWindowsLog.h"
 
+#include 
+#include 
+#include 
+
 using namespace lldb;
 using namespace lldb_private;
 
+static void NormalizeWindowsPath(std::string &s) {
+  for (char &c : s) {
+if (c == '/')

[Lldb-commits] [lldb] [lldb][Windows] ignore loader breakpoints in system modules (PR #208233)

2026-07-08 Thread David Spickett via lldb-commits

DavidSpickett wrote:

I'll read this properly tomorrow, but -

> This is because ntdll executes an int3 breakpoint during process 
> initialization when a debugger is attached.

Do you know why it does this, is it to give the debugger a chance to set itself 
up?

If that is the case I'm curious what sorts of things that might be, considering 
that we apparently haven't needed it so far.

https://github.com/llvm/llvm-project/pull/208233
___
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb][Windows] ignore loader breakpoints in system modules (PR #208233)

2026-07-08 Thread via lldb-commits

llvmorg-github-actions[bot] wrote:




@llvm/pr-subscribers-lldb

Author: Charles Zablit (charles-zablit)


Changes

Currently, when debugging a program with `lldb-dap` on Windows and the 
`integratedTerminal` option, lldb-dap immediatly stops with an `0x8003` 
Exception. This is because `ntdll` executes an `int3` breakpoint during process 
initialization when a debugger is attached.

This patch makes lldb and lldb-server ignore `int3` breakpoints are in system 
modules.

Fixes https://github.com/llvm/llvm-project/issues/198763

---
Full diff: https://github.com/llvm/llvm-project/pull/208233.diff


5 Files Affected:

- (modified) 
lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp (+12-43) 
- (modified) lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp 
(+69) 
- (modified) lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.h (+5) 
- (modified) lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp 
(+15-1) 
- (modified) 
lldb/test/API/tools/lldb-dap/runInTerminal/TestDAP_runInTerminal.py (-1) 


``diff
diff --git 
a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp 
b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp
index ada92894efc47..f1de697c34b67 100644
--- a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp
+++ b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp
@@ -50,44 +50,6 @@ using namespace llvm;
 
 namespace lldb_private {
 
-namespace {
-
-void NormalizeWindowsPath(std::string &s) {
-  for (char &c : s) {
-if (c == '/')
-  c = '\\';
-else
-  c = std::tolower(static_cast(c));
-  }
-}
-
-bool IsSystemDLL(const FileSpec &spec) {
-  if (!spec)
-return false;
-
-  static const std::string windows_prefix = []() {
-std::string prefix;
-wchar_t buf[MAX_PATH];
-UINT len = ::GetWindowsDirectoryW(buf, MAX_PATH);
-if (len == 0 || len >= MAX_PATH)
-  return prefix;
-llvm::convertWideToUTF8(std::wstring_view(buf, len), prefix);
-NormalizeWindowsPath(prefix);
-if (!prefix.empty() && prefix.back() != '\\')
-  prefix += '\\';
-return prefix;
-  }();
-
-  if (windows_prefix.empty())
-return false;
-
-  std::string path = spec.GetPath();
-  NormalizeWindowsPath(path);
-  return llvm::StringRef(path).starts_with(windows_prefix);
-}
-
-} // namespace
-
 NativeProcessWindows::NativeProcessWindows(ProcessLaunchInfo &launch_info,
NativeDelegate &delegate,
llvm::Error &E)
@@ -635,9 +597,8 @@ NativeProcessWindows::HandleBreakpointException(const 
ExceptionRecord &record) {
 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.
+  // Our own DebugBreakProcess() injection, used to implement
+  // Halt()/Interrupt().
   if (m_pending_halt) {
 LLDB_LOG(log,
  "DebugBreakProcess injection treated as Halt SIGSTOP for tid "
@@ -664,6 +625,14 @@ NativeProcessWindows::HandleBreakpointException(const 
ExceptionRecord &record) {
 return ExceptionResult::BreakInDebugger;
   }
 
+  if (IsSystemModuleAddress(exception_addr)) {
+LLDB_LOG(log,
+ "Ignoring loader/OS breakpoint at address {0:x} in a system "
+ "module.",
+ exception_addr);
+return ExceptionResult::MaskException;
+  }
+
   std::string desc = formatv("Exception {0:x8} encountered at address {1:x8}",
  record.GetExceptionValue(), exception_addr)
  .str();
@@ -776,7 +745,7 @@ DllEventAction NativeProcessWindows::OnLoadDll(const 
ModuleSpec &module_spec,
 return DllEventAction::ContinueDebugLoop;
 
   // Can't resolve a breakpoint in a system DLL.
-  if (!resolved || IsSystemDLL(resolved))
+  if (!resolved || ProcessDebugger::IsSystemDLL(resolved))
 return DllEventAction::ContinueDebugLoop;
 
   NativeThreadWindows *loader_thread = GetThreadByID(thread_id);
@@ -819,7 +788,7 @@ DllEventAction 
NativeProcessWindows::OnUnloadDll(lldb::addr_t module_addr,
   if (!m_initial_stop_seen || !m_client_supports_libraries_read)
 return DllEventAction::ContinueDebugLoop;
 
-  if (!unloaded_spec || IsSystemDLL(unloaded_spec))
+  if (!unloaded_spec || ProcessDebugger::IsSystemDLL(unloaded_spec))
 return DllEventAction::ContinueDebugLoop;
 
   NativeThreadWindows *unloader_thread = GetThreadByID(thread_id);
diff --git a/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp 
b/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp
index 63fc20f36b07b..a4322c3d3f536 100644
--- a/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp
+++ b/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp
@@ -19,6 +19,7 @@
 #include "lldb/Host/ProcessLaunchInfo.

[Lldb-commits] [lldb] [lldb][Windows] ignore loader breakpoints in system modules (PR #208233)

2026-07-08 Thread Charles Zablit via lldb-commits

https://github.com/charles-zablit created 
https://github.com/llvm/llvm-project/pull/208233

Currently, when debugging a program with `lldb-dap` on Windows and the 
`integratedTerminal` option, lldb-dap immediatly stops with an `0x8003` 
Exception. This is because `ntdll` executes an `int3` breakpoint during process 
initialization when a debugger is attached.

This patch makes lldb and lldb-server ignore `int3` breakpoints are in system 
modules.

Fixes https://github.com/llvm/llvm-project/issues/198763

>From d6abb3698fd1419ec5c89df61a9243cf6fcc0772 Mon Sep 17 00:00:00 2001
From: Charles Zablit 
Date: Wed, 8 Jul 2026 15:46:39 +0100
Subject: [PATCH 1/2] [lldb][Windows] ignore loader breakpoints in system
 modules

---
 .../Windows/Common/NativeProcessWindows.cpp   | 55 ---
 .../Windows/Common/ProcessDebugger.cpp| 69 +++
 .../Process/Windows/Common/ProcessDebugger.h  |  5 ++
 .../Process/Windows/Common/ProcessWindows.cpp | 16 -
 4 files changed, 101 insertions(+), 44 deletions(-)

diff --git 
a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp 
b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp
index ada92894efc47..f1de697c34b67 100644
--- a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp
+++ b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp
@@ -50,44 +50,6 @@ using namespace llvm;
 
 namespace lldb_private {
 
-namespace {
-
-void NormalizeWindowsPath(std::string &s) {
-  for (char &c : s) {
-if (c == '/')
-  c = '\\';
-else
-  c = std::tolower(static_cast(c));
-  }
-}
-
-bool IsSystemDLL(const FileSpec &spec) {
-  if (!spec)
-return false;
-
-  static const std::string windows_prefix = []() {
-std::string prefix;
-wchar_t buf[MAX_PATH];
-UINT len = ::GetWindowsDirectoryW(buf, MAX_PATH);
-if (len == 0 || len >= MAX_PATH)
-  return prefix;
-llvm::convertWideToUTF8(std::wstring_view(buf, len), prefix);
-NormalizeWindowsPath(prefix);
-if (!prefix.empty() && prefix.back() != '\\')
-  prefix += '\\';
-return prefix;
-  }();
-
-  if (windows_prefix.empty())
-return false;
-
-  std::string path = spec.GetPath();
-  NormalizeWindowsPath(path);
-  return llvm::StringRef(path).starts_with(windows_prefix);
-}
-
-} // namespace
-
 NativeProcessWindows::NativeProcessWindows(ProcessLaunchInfo &launch_info,
NativeDelegate &delegate,
llvm::Error &E)
@@ -635,9 +597,8 @@ NativeProcessWindows::HandleBreakpointException(const 
ExceptionRecord &record) {
 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.
+  // Our own DebugBreakProcess() injection, used to implement
+  // Halt()/Interrupt().
   if (m_pending_halt) {
 LLDB_LOG(log,
  "DebugBreakProcess injection treated as Halt SIGSTOP for tid "
@@ -664,6 +625,14 @@ NativeProcessWindows::HandleBreakpointException(const 
ExceptionRecord &record) {
 return ExceptionResult::BreakInDebugger;
   }
 
+  if (IsSystemModuleAddress(exception_addr)) {
+LLDB_LOG(log,
+ "Ignoring loader/OS breakpoint at address {0:x} in a system "
+ "module.",
+ exception_addr);
+return ExceptionResult::MaskException;
+  }
+
   std::string desc = formatv("Exception {0:x8} encountered at address {1:x8}",
  record.GetExceptionValue(), exception_addr)
  .str();
@@ -776,7 +745,7 @@ DllEventAction NativeProcessWindows::OnLoadDll(const 
ModuleSpec &module_spec,
 return DllEventAction::ContinueDebugLoop;
 
   // Can't resolve a breakpoint in a system DLL.
-  if (!resolved || IsSystemDLL(resolved))
+  if (!resolved || ProcessDebugger::IsSystemDLL(resolved))
 return DllEventAction::ContinueDebugLoop;
 
   NativeThreadWindows *loader_thread = GetThreadByID(thread_id);
@@ -819,7 +788,7 @@ DllEventAction 
NativeProcessWindows::OnUnloadDll(lldb::addr_t module_addr,
   if (!m_initial_stop_seen || !m_client_supports_libraries_read)
 return DllEventAction::ContinueDebugLoop;
 
-  if (!unloaded_spec || IsSystemDLL(unloaded_spec))
+  if (!unloaded_spec || ProcessDebugger::IsSystemDLL(unloaded_spec))
 return DllEventAction::ContinueDebugLoop;
 
   NativeThreadWindows *unloader_thread = GetThreadByID(thread_id);
diff --git a/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp 
b/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp
index 63fc20f36b07b..a4322c3d3f536 100644
--- a/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp
+++ b/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp
@@ -19,6 +19,7 @@
 #include "lldb/Host/ProcessLaunchInfo.h"
 #include "lldb/Target/MemoryReg