Author: Michael Buch
Date: 2025-09-08T17:03:31Z
New Revision: 879f40ab041b31fa73b9b25e4ec9e06e810bc767

URL: 
https://github.com/llvm/llvm-project/commit/879f40ab041b31fa73b9b25e4ec9e06e810bc767
DIFF: 
https://github.com/llvm/llvm-project/commit/879f40ab041b31fa73b9b25e4ec9e06e810bc767.diff

LOG: [lldb][Instrumentation] Set selected frame to outside sanitizer libraries 
(#133079)

When hitting a sanitizer breakpoint, LLDB currently displays the frame
in the sanitizer dylib (which we usually don't have debug-info for),
which isn't very helpful to the user. A more helpful frame to display
would be the first frame not in the sanitizer library (we have a
[similar heuristic when we trap inside
libc++](https://github.com/llvm/llvm-project/pull/108825)). This patch
does just that, by implementing the `GetSuggestedStackFrameIndex` API

Depends on https://github.com/llvm/llvm-project/pull/133078

Added: 
    

Modified: 
    lldb/include/lldb/Target/InstrumentationRuntimeStopInfo.h
    lldb/source/Target/InstrumentationRuntimeStopInfo.cpp
    lldb/test/API/functionalities/asan/TestMemoryHistory.py
    lldb/test/API/functionalities/asan/TestReportData.py
    lldb/test/API/functionalities/ubsan/basic/TestUbsanBasic.py

Removed: 
    


################################################################################
diff  --git a/lldb/include/lldb/Target/InstrumentationRuntimeStopInfo.h 
b/lldb/include/lldb/Target/InstrumentationRuntimeStopInfo.h
index 5345160850914..dafa41c11327a 100644
--- a/lldb/include/lldb/Target/InstrumentationRuntimeStopInfo.h
+++ b/lldb/include/lldb/Target/InstrumentationRuntimeStopInfo.h
@@ -24,6 +24,9 @@ class InstrumentationRuntimeStopInfo : public StopInfo {
     return lldb::eStopReasonInstrumentation;
   }
 
+  std::optional<uint32_t>
+  GetSuggestedStackFrameIndex(bool inlined_stack) override;
+
   const char *GetDescription() override;
 
   bool DoShouldNotify(Event *event_ptr) override { return true; }

diff  --git a/lldb/source/Target/InstrumentationRuntimeStopInfo.cpp 
b/lldb/source/Target/InstrumentationRuntimeStopInfo.cpp
index 7f82581cc601e..aef895def7939 100644
--- a/lldb/source/Target/InstrumentationRuntimeStopInfo.cpp
+++ b/lldb/source/Target/InstrumentationRuntimeStopInfo.cpp
@@ -8,13 +8,20 @@
 
 #include "lldb/Target/InstrumentationRuntimeStopInfo.h"
 
+#include "lldb/Core/Module.h"
 #include "lldb/Target/InstrumentationRuntime.h"
 #include "lldb/Target/Process.h"
+#include "lldb/lldb-enumerations.h"
 #include "lldb/lldb-private.h"
 
 using namespace lldb;
 using namespace lldb_private;
 
+static bool IsStoppedInDarwinSanitizer(Thread &thread, Module &module) {
+  return module.GetFileSpec().GetFilename().GetStringRef().starts_with(
+      "libclang_rt.");
+}
+
 InstrumentationRuntimeStopInfo::InstrumentationRuntimeStopInfo(
     Thread &thread, std::string description,
     StructuredData::ObjectSP additional_data)
@@ -34,3 +41,38 @@ 
InstrumentationRuntimeStopInfo::CreateStopReasonWithInstrumentationData(
   return StopInfoSP(
       new InstrumentationRuntimeStopInfo(thread, description, additionalData));
 }
+
+std::optional<uint32_t>
+InstrumentationRuntimeStopInfo::GetSuggestedStackFrameIndex(
+    bool inlined_stack) {
+  ThreadSP thread_sp = GetThread();
+  if (!thread_sp)
+    return std::nullopt;
+
+  // Defensive upper-bound of when we stop walking up the frames in
+  // case we somehow ended up looking at an infinite recursion.
+  constexpr size_t max_stack_depth = 128;
+
+  // Start at parent frame.
+  size_t stack_idx = 1;
+  StackFrameSP most_relevant_frame_sp =
+      thread_sp->GetStackFrameAtIndex(stack_idx);
+
+  while (most_relevant_frame_sp && stack_idx <= max_stack_depth) {
+    auto const &sc =
+        most_relevant_frame_sp->GetSymbolContext(lldb::eSymbolContextModule);
+
+    if (!sc.module_sp)
+      return std::nullopt;
+
+    // Found a frame outside of the sanitizer runtime libraries.
+    // That's the one we want to display.
+    if (!IsStoppedInDarwinSanitizer(*thread_sp, *sc.module_sp))
+      return stack_idx;
+
+    ++stack_idx;
+    most_relevant_frame_sp = thread_sp->GetStackFrameAtIndex(stack_idx);
+  }
+
+  return stack_idx;
+}

diff  --git a/lldb/test/API/functionalities/asan/TestMemoryHistory.py 
b/lldb/test/API/functionalities/asan/TestMemoryHistory.py
index 66f6e3e7502c1..a8f400de8ab08 100644
--- a/lldb/test/API/functionalities/asan/TestMemoryHistory.py
+++ b/lldb/test/API/functionalities/asan/TestMemoryHistory.py
@@ -94,6 +94,10 @@ def libsanitizers_asan_tests(self):
         )
         self.check_traces()
 
+        # Make sure we're not stopped in the sanitizer library but instead at 
the
+        # point of failure in the user-code.
+        self.assertEqual(self.frame().GetFunctionName(), "main")
+
         # do the same using SB API
         process = self.dbg.GetSelectedTarget().process
         val = (
@@ -218,6 +222,10 @@ def compiler_rt_asan_tests(self):
 
         self.check_traces()
 
+        # Make sure we're not stopped in the sanitizer library but instead at 
the
+        # point of failure in the user-code.
+        self.assertEqual(self.frame().GetFunctionName(), "main")
+
         # make sure the 'memory history' command still works even when we're
         # generating a report now
         self.expect(

diff  --git a/lldb/test/API/functionalities/asan/TestReportData.py 
b/lldb/test/API/functionalities/asan/TestReportData.py
index dd6834a01b80c..ccc1b846d1607 100644
--- a/lldb/test/API/functionalities/asan/TestReportData.py
+++ b/lldb/test/API/functionalities/asan/TestReportData.py
@@ -67,6 +67,10 @@ def asan_tests(self, libsanitizers=False):
             lldb.eStopReasonInstrumentation,
         )
 
+        # Make sure we're not stopped in the sanitizer library but instead at 
the
+        # point of failure in the user-code.
+        self.assertEqual(self.frame().GetFunctionName(), "main")
+
         self.expect(
             "bt",
             "The backtrace should show the crashing line",

diff  --git a/lldb/test/API/functionalities/ubsan/basic/TestUbsanBasic.py 
b/lldb/test/API/functionalities/ubsan/basic/TestUbsanBasic.py
index 868a2864d2b5e..f46d167d910ea 100644
--- a/lldb/test/API/functionalities/ubsan/basic/TestUbsanBasic.py
+++ b/lldb/test/API/functionalities/ubsan/basic/TestUbsanBasic.py
@@ -52,8 +52,8 @@ def ubsan_tests(self):
             substrs=["1 match found"],
         )
 
-        # We should be stopped in __ubsan_on_report
-        self.assertIn("__ubsan_on_report", frame.GetFunctionName())
+        # We should not be stopped in the sanitizer library.
+        self.assertIn("main", frame.GetFunctionName())
 
         # The stopped thread backtrace should contain either 'align line'
         found = False


        
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to