[Lldb-commits] [lldb] [lldb][Instrumentation] Set selected frame to outside sanitizer libraries (PR #133079)
Michael Buch via lldb-commits
lldb-commits at lists.llvm.org
Wed Mar 26 06:58:16 PDT 2025
https://github.com/Michael137 updated https://github.com/llvm/llvm-project/pull/133079
>From 2314f9e584d736ce2093cc196c7c57c2087cde42 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 26 Mar 2025 12:54:36 +0000
Subject: [PATCH 1/2] [lldb][Instrumentation] Set selected frame to outside
sanitizer libraries
---
.../Target/InstrumentationRuntimeStopInfo.h | 3 ++
lldb/include/lldb/Target/StackFrameList.h | 2 +
lldb/include/lldb/Target/Thread.h | 4 ++
.../Target/InstrumentationRuntimeStopInfo.cpp | 42 +++++++++++++++++++
lldb/source/Target/Process.cpp | 2 +
5 files changed, 53 insertions(+)
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/include/lldb/Target/StackFrameList.h b/lldb/include/lldb/Target/StackFrameList.h
index 8a66296346f2d..be6ec3b09d8aa 100644
--- a/lldb/include/lldb/Target/StackFrameList.h
+++ b/lldb/include/lldb/Target/StackFrameList.h
@@ -36,6 +36,8 @@ class StackFrameList {
/// Get the frame at index \p idx. Invisible frames cannot be indexed.
lldb::StackFrameSP GetFrameAtIndex(uint32_t idx);
+ void ResetSuggestedStackFrameIndex() { m_selected_frame_idx.reset(); }
+
/// Get the first concrete frame with index greater than or equal to \p idx.
/// Unlike \ref GetFrameAtIndex, this cannot return a synthetic frame.
lldb::StackFrameSP GetFrameWithConcreteFrameIndex(uint32_t unwind_idx);
diff --git a/lldb/include/lldb/Target/Thread.h b/lldb/include/lldb/Target/Thread.h
index 1d1e3dcfc1dc6..747d7299025f8 100644
--- a/lldb/include/lldb/Target/Thread.h
+++ b/lldb/include/lldb/Target/Thread.h
@@ -433,6 +433,10 @@ class Thread : public std::enable_shared_from_this<Thread>,
return GetStackFrameList()->GetFrameAtIndex(idx);
}
+ virtual void ResetSuggestedStackFrameIndex() {
+ return GetStackFrameList()->ResetSuggestedStackFrameIndex();
+ }
+
virtual lldb::StackFrameSP
GetFrameWithConcreteFrameIndex(uint32_t unwind_idx);
diff --git a/lldb/source/Target/InstrumentationRuntimeStopInfo.cpp b/lldb/source/Target/InstrumentationRuntimeStopInfo.cpp
index 7f82581cc601e..1daeebdbaf9c7 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) {
+ auto 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.
+ const 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/source/Target/Process.cpp b/lldb/source/Target/Process.cpp
index f2f5598f0ab53..f82cea2d668ed 100644
--- a/lldb/source/Target/Process.cpp
+++ b/lldb/source/Target/Process.cpp
@@ -4257,6 +4257,8 @@ bool Process::ProcessEventData::ShouldStop(Event *event_ptr,
// appropriately. We also need to stop processing actions, since they
// aren't expecting the target to be running.
+ thread_sp->ResetSuggestedStackFrameIndex();
+
// FIXME: we might have run.
if (stop_info_sp->HasTargetRunSinceMe()) {
SetRestarted(true);
>From 6ae615b48bcbbc9b872c27061a8147b82e2215de Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 26 Mar 2025 13:58:03 +0000
Subject: [PATCH 2/2] fixup! add tests
---
lldb/test/API/functionalities/asan/TestMemoryHistory.py | 4 ++++
lldb/test/API/functionalities/asan/TestReportData.py | 4 ++++
lldb/test/API/functionalities/ubsan/basic/TestUbsanBasic.py | 4 ++--
3 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/lldb/test/API/functionalities/asan/TestMemoryHistory.py b/lldb/test/API/functionalities/asan/TestMemoryHistory.py
index b04182a543719..03003f1e4112a 100644
--- a/lldb/test/API/functionalities/asan/TestMemoryHistory.py
+++ b/lldb/test/API/functionalities/asan/TestMemoryHistory.py
@@ -52,6 +52,10 @@ def libsanitizer_tests(self):
substrs=["stopped", "stop reason = Use of deallocated memory"],
)
+ # 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")
+
# test the 'memory history' command
self.expect(
"memory history 'pointer'",
diff --git a/lldb/test/API/functionalities/asan/TestReportData.py b/lldb/test/API/functionalities/asan/TestReportData.py
index fabc985d0ed44..496a2db67c038 100644
--- a/lldb/test/API/functionalities/asan/TestReportData.py
+++ b/lldb/test/API/functionalities/asan/TestReportData.py
@@ -69,6 +69,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
More information about the lldb-commits
mailing list