[Lldb-commits] [lldb] [lldb][windows] add assert frame recognizer Windows (PR #224269)

via lldb-commits lldb-commits at lists.llvm.org
Thu Sep 17 04:26:40 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 implements `AssertFrameRecognizer` on Windows.

Since the Windows C Runtime can be either statically or dynamically linked, lldb can't match the module name to be able to support both. Therefore, the matches on `abort` and `_wassert` do not check the name of the module.

The `assert.test` test was also relaxed to check the Windows error format (`Exception 0xc0000409`), since Windows surfaces `__fastfail` as a `STATUS_STACK_BUFFER_OVERRUN` exception rather than a POSIX signal.

rdar://175328961

---

This relands https://github.com/llvm/llvm-project/pull/197282, reverted in https://github.com/llvm/llvm-project/pull/198263 for two buildbot failures.

1. **lldb-x86_64-win** failed with `0xC0000005` in `frame recognizer list` (`commands/frame/recognizer/TestFrameRecognizer.py`, `test_frame_recognizer_target_specific`). This is due to a call to `strlen(nullptr)` which is fixed by https://github.com/llvm/llvm-project/pull/224267.

2. **lldb-remote-linux-win** started running `Recognizer`/`assert.test` and failed with `"stop reason = signal SIGABRT"` where the test expects `"hit program assert"`. That bot debugs a remote Linux target from a Windows host: system-linux is a host feature, so the known-broken Linux target (llvm.org/pr56144) was not skipped. Add remote-linux to the UNSUPPORTED list.

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


2 Files Affected:

- (modified) lldb/source/Target/AssertFrameRecognizer.cpp (+40-13) 
- (modified) lldb/test/Shell/Recognizer/assert.test (+4-3) 


``````````diff
diff --git a/lldb/source/Target/AssertFrameRecognizer.cpp b/lldb/source/Target/AssertFrameRecognizer.cpp
index 7455f86388e6b1..0768b5eab02c8a 100644
--- a/lldb/source/Target/AssertFrameRecognizer.cpp
+++ b/lldb/source/Target/AssertFrameRecognizer.cpp
@@ -16,15 +16,15 @@ using namespace lldb_private;
 namespace lldb_private {
 /// Fetches the abort frame location depending on the current platform.
 ///
-/// \param[in] os
-///    The target's os type.
+/// \param[in] triple
+///    The target's triple.
 /// \param[in,out] location
 ///    The struct that will contain the abort module spec and symbol names.
 /// \return
 ///    \b true, if the platform is supported
 ///    \b false, otherwise.
-bool GetAbortLocation(llvm::Triple::OSType os, SymbolLocation &location) {
-  switch (os) {
+bool GetAbortLocation(const llvm::Triple &triple, SymbolLocation &location) {
+  switch (triple.getOS()) {
   case llvm::Triple::Darwin:
   case llvm::Triple::MacOSX:
   case llvm::Triple::IOS:
@@ -44,6 +44,19 @@ bool GetAbortLocation(llvm::Triple::OSType os, SymbolLocation &location) {
     location.symbols.push_back(ConstString("pthread_kill"));
     location.symbols_are_regex = true;
     break;
+  case llvm::Triple::Win32:
+    if (!triple.isWindowsMSVCEnvironment()) {
+      Log *log = GetLog(LLDBLog::Unwind);
+      LLDB_LOG(log, "AssertFrameRecognizer::GetAbortLocation Unsupported "
+                    "Windows environment");
+      return false;
+    }
+    // Windows MSVC CRT can be statically or dynamically linked. With dynamic
+    // linking, abort lives in ucrtbase.dll. With static linking it's embedded
+    // in the executable.
+    // Match on the symbol only to handle both.
+    location.symbols.push_back(ConstString("abort"));
+    break;
   default:
     Log *log = GetLog(LLDBLog::Unwind);
     LLDB_LOG(log, "AssertFrameRecognizer::GetAbortLocation Unsupported OS");
@@ -55,15 +68,15 @@ bool GetAbortLocation(llvm::Triple::OSType os, SymbolLocation &location) {
 
 /// Fetches the assert frame location depending on the current platform.
 ///
-/// \param[in] os
-///    The target's os type.
+/// \param[in] triple
+///    The target's triple.
 /// \param[in,out] location
 ///    The struct that will contain the assert module spec and symbol names.
 /// \return
 ///    \b true, if the platform is supported
 ///    \b false, otherwise.
-bool GetAssertLocation(llvm::Triple::OSType os, SymbolLocation &location) {
-  switch (os) {
+bool GetAssertLocation(const llvm::Triple &triple, SymbolLocation &location) {
+  switch (triple.getOS()) {
   case llvm::Triple::Darwin:
   case llvm::Triple::MacOSX:
   case llvm::Triple::IOS:
@@ -80,6 +93,16 @@ bool GetAssertLocation(llvm::Triple::OSType os, SymbolLocation &location) {
     location.symbols.push_back(ConstString("__assert_fail"));
     location.symbols.push_back(ConstString("__GI___assert_fail"));
     break;
+  case llvm::Triple::Win32:
+    if (!triple.isWindowsMSVCEnvironment()) {
+      Log *log = GetLog(LLDBLog::Unwind);
+      LLDB_LOG(log, "AssertFrameRecognizer::GetAssertLocation Unsupported "
+                    "Windows environment");
+      return false;
+    }
+    // See comment in GetAbortLocation for why we skip the module check.
+    location.symbols.push_back(ConstString("_wassert"));
+    break;
   default:
     Log *log = GetLog(LLDBLog::Unwind);
     LLDB_LOG(log, "AssertFrameRecognizer::GetAssertLocation Unsupported OS");
@@ -91,10 +114,10 @@ bool GetAssertLocation(llvm::Triple::OSType os, SymbolLocation &location) {
 
 void RegisterAssertFrameRecognizer(Process *process) {
   Target &target = process->GetTarget();
-  llvm::Triple::OSType os = target.GetArchitecture().GetTriple().getOS();
+  const llvm::Triple &triple = target.GetArchitecture().GetTriple();
   SymbolLocation location;
 
-  if (!GetAbortLocation(os, location))
+  if (!GetAbortLocation(triple, location))
     return;
 
   if (!location.symbols_are_regex) {
@@ -136,10 +159,10 @@ AssertFrameRecognizer::RecognizeFrame(lldb::StackFrameSP frame_sp) {
   ThreadSP thread_sp = frame_sp->GetThread();
   ProcessSP process_sp = thread_sp->GetProcess();
   Target &target = process_sp->GetTarget();
-  llvm::Triple::OSType os = target.GetArchitecture().GetTriple().getOS();
+  const llvm::Triple &triple = target.GetArchitecture().GetTriple();
   SymbolLocation location;
 
-  if (!GetAssertLocation(os, location))
+  if (!GetAssertLocation(triple, location))
     return RecognizedStackFrameSP();
 
   const uint32_t frames_to_fetch = 6;
@@ -160,7 +183,11 @@ AssertFrameRecognizer::RecognizeFrame(lldb::StackFrameSP frame_sp) {
     SymbolContext sym_ctx =
         prev_frame_sp->GetSymbolContext(eSymbolContextEverything);
 
-    if (!sym_ctx.module_sp ||
+    if (!sym_ctx.module_sp)
+      continue;
+    // On Windows the abort/assert symbols may live in the executable (static
+    // CRT) or a CRT DLL, so skip the module check there.
+    if (!triple.isOSWindows() &&
         !sym_ctx.module_sp->GetFileSpec().FileEquals(location.module_spec))
       continue;
 
diff --git a/lldb/test/Shell/Recognizer/assert.test b/lldb/test/Shell/Recognizer/assert.test
index 201e834cf357ea..a8bb734e1bb024 100644
--- a/lldb/test/Shell/Recognizer/assert.test
+++ b/lldb/test/Shell/Recognizer/assert.test
@@ -2,9 +2,10 @@
 # XFAIL: system-netbsd
 #
 # llvm.org/pr56144
-# UNSUPPORTED: system-linux
+# system-linux only covers a Linux host; remote-linux catches the bots which
+# debug a Linux target from another host.
+# UNSUPPORTED: system-linux, remote-linux
 #
-# UNSUPPORTED: system-windows
 # RUN: %clang_host -g -O0 %S/Inputs/assert.c -o %t.out
 # RUN: %lldb -b -s %s %t.out | FileCheck %s
 run
@@ -14,5 +15,5 @@ frame recognizer info 0
 # CHECK: frame 0 is recognized by Assert StackFrame Recognizer
 set set thread-format "{${thread.stop-reason-raw}}\n"
 thread info
-# CHECK: signal SIGABRT
+# CHECK: {{(signal SIGABRT|Exception 0x[0-9a-fA-F]+)}}
 q

``````````

</details>


https://github.com/llvm/llvm-project/pull/224269


More information about the lldb-commits mailing list