https://github.com/vogelsgesang updated https://github.com/llvm/llvm-project/pull/108870
>From 04daaac0eade25a439856bbb287e15860aba1dfd Mon Sep 17 00:00:00 2001 From: Adrian Vogelsgesang <avogelsges...@salesforce.com> Date: Tue, 27 Aug 2024 17:34:11 +0000 Subject: [PATCH 1/6] [lldb][libc++] Hide all libc++ implementation details from stacktraces This commit changes the libc++ frame recognizer to hide implementation details of libc++ more aggressively. The applied heuristic is rather straightforward: We consider every function name starting with `__` as an implementation detail. This works pretty neatly for `std::invoke`, `std::function`, `std::sort`, `std::map::emplace` and many others. Also, this should align quite nicely with libc++'s general coding convention of using the `__` for their implementation details, thereby keeping the future maintenance effort low. However, it is noteworthy, that this does not work 100% in all cases: E.g., for `std::ranges::sort`, itself is not really a function call, but an object with an overloaded `operator()`, which means that there is no actual call `std::ranges::sort` in the call stack. --- libcxx/docs/UserDocumentation.rst | 26 ++++++ .../CPlusPlus/CPPLanguageRuntime.cpp | 27 ++---- .../cpp/libcxx-internals-recognizer/Makefile | 5 ++ .../TestLibcxxInternalsRecognizer.py | 56 ++++++++++++ .../cpp/libcxx-internals-recognizer/main.cpp | 86 +++++++++++++++++++ 5 files changed, 181 insertions(+), 19 deletions(-) create mode 100644 lldb/test/API/lang/cpp/libcxx-internals-recognizer/Makefile create mode 100644 lldb/test/API/lang/cpp/libcxx-internals-recognizer/TestLibcxxInternalsRecognizer.py create mode 100644 lldb/test/API/lang/cpp/libcxx-internals-recognizer/main.cpp diff --git a/libcxx/docs/UserDocumentation.rst b/libcxx/docs/UserDocumentation.rst index 6659fa54f49df5..8999b4f23e91d2 100644 --- a/libcxx/docs/UserDocumentation.rst +++ b/libcxx/docs/UserDocumentation.rst @@ -346,6 +346,32 @@ Third-party Integrations Libc++ provides integration with a few third-party tools. +Debugging libc++ internals in LLDB +---------------------------------- + +LLDB hides the implementation details of libc++ by default. + +E.g., when setting a breakpoint in a comparator passed to ``std::sort``, the +backtrace will read as + +.. code-block:: + + (lldb) thread backtrace + * thread #1, name = 'a.out', stop reason = breakpoint 3.1 + * frame #0: 0x000055555555520e a.out`my_comparator(a=1, b=8) at test-std-sort.cpp:6:3 + frame #7: 0x0000555555555615 a.out`void std::__1::sort[abi:ne200000]<std::__1::__wrap_iter<int*>, bool (*)(int, int)>(__first=(item = 8), __last=(item = 0), __comp=(a.out`my_less(int, int) at test-std-sort.cpp:5)) at sort.h:1003:3 + frame #8: 0x000055555555531a a.out`main at test-std-sort.cpp:24:3 + +Note how the caller of ``my_comparator`` is shown as ``std::sort``. Looking at +the frame numbers, we can see that frames #1 until #6 were hidden. Those frames +represent internal implementation details such as ``__sort4`` and similar +utility functions. + +To also show those implementation details, use ``thread backtrace -u``. +Alternatively, to disable those compact backtraces for good, use +``frame recognizer list`` and ``frame recognizer delete`` to delete the libc++ +frame recognizer. + GDB Pretty printers for libc++ ------------------------------ diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp index faa05e8f834ea1..d0e84bdeb94f01 100644 --- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp @@ -45,7 +45,7 @@ char CPPLanguageRuntime::ID = 0; /// A frame recognizer that is installed to hide libc++ implementation /// details from the backtrace. class LibCXXFrameRecognizer : public StackFrameRecognizer { - std::array<RegularExpression, 4> m_hidden_regex; + std::array<RegularExpression, 2> m_hidden_regex; RecognizedStackFrameSP m_hidden_frame; struct LibCXXHiddenFrame : public RecognizedStackFrame { @@ -55,28 +55,17 @@ class LibCXXFrameRecognizer : public StackFrameRecognizer { public: LibCXXFrameRecognizer() : m_hidden_regex{ - // internal implementation details of std::function + // internal implementation details in the `std::` namespace // std::__1::__function::__alloc_func<void (*)(), std::__1::allocator<void (*)()>, void ()>::operator()[abi:ne200000] // std::__1::__function::__func<void (*)(), std::__1::allocator<void (*)()>, void ()>::operator() // std::__1::__function::__value_func<void ()>::operator()[abi:ne200000]() const - RegularExpression{"" - R"(^std::__[^:]*::)" // Namespace. - R"(__function::.*::operator\(\))"}, - // internal implementation details of std::function in ABI v2 // std::__2::__function::__policy_invoker<void (int, int)>::__call_impl[abi:ne200000]<std::__2::__function::__default_alloc_func<int (*)(int, int), int (int, int)>> - RegularExpression{"" - R"(^std::__[^:]*::)" // Namespace. - R"(__function::.*::__call_impl)"}, - // internal implementation details of std::invoke - // std::__1::__invoke[abi:ne200000]<void (*&)()> - RegularExpression{ - R"(^std::__[^:]*::)" // Namespace. - R"(__invoke)"}, - // internal implementation details of std::invoke - // std::__1::__invoke_void_return_wrapper<void, true>::__call[abi:ne200000]<void (*&)()> - RegularExpression{ - R"(^std::__[^:]*::)" // Namespace. - R"(__invoke_void_return_wrapper<.*>::__call)"} + // std::__1::__invoke[abi:ne200000]<void (*&)()> + // std::__1::__invoke_void_return_wrapper<void, true>::__call[abi:ne200000]<void (*&)()> + RegularExpression{R"(^std::__[^:]*::__)"}, + // internal implementation details in the `std::ranges` namespace + // std::__1::ranges::__sort::__sort_fn_impl[abi:ne200000]<std::__1::__wrap_iter<int*>, std::__1::__wrap_iter<int*>, bool (*)(int, int), std::__1::identity> + RegularExpression{R"(^std::__[^:]*::ranges::__)"}, }, m_hidden_frame(new LibCXXHiddenFrame()) {} diff --git a/lldb/test/API/lang/cpp/libcxx-internals-recognizer/Makefile b/lldb/test/API/lang/cpp/libcxx-internals-recognizer/Makefile new file mode 100644 index 00000000000000..bb571299664934 --- /dev/null +++ b/lldb/test/API/lang/cpp/libcxx-internals-recognizer/Makefile @@ -0,0 +1,5 @@ +CXX_SOURCES := main.cpp +USE_LIBCPP := 1 +CXXFLAGS_EXTRAS := -std=c++20 + +include Makefile.rules diff --git a/lldb/test/API/lang/cpp/libcxx-internals-recognizer/TestLibcxxInternalsRecognizer.py b/lldb/test/API/lang/cpp/libcxx-internals-recognizer/TestLibcxxInternalsRecognizer.py new file mode 100644 index 00000000000000..a5b4e4fe995c38 --- /dev/null +++ b/lldb/test/API/lang/cpp/libcxx-internals-recognizer/TestLibcxxInternalsRecognizer.py @@ -0,0 +1,56 @@ +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class LibCxxInternalsRecognizerTestCase(TestBase): + NO_DEBUG_INFO_TESTCASE = True + + @add_test_categories(["libc++"]) + def test_frame_recognizer(self): + """Test that implementation details of libc++ are hidden""" + self.build() + (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( + self, "break here", lldb.SBFileSpec("main.cpp") + ) + + expected_parents = { + "sort_less(int, int)": ["::sort", "test_algorithms"], + # `std::ranges::sort` is implemented as an object of types `__sort`, + # which unfortunately means that there is no `std::ranges::sort` + # stack frame, and `main` is the direct parent of `my_less_ranges`. + "ranges_sort_less(int, int)": ["test_algorithms"], + # `ranges::views::transform` internally uses `std::invoke`, and that + # call also shows up in the stack trace + "view_transform(int)": ["::invoke", "ranges::transform_view", "test_algorithms"], + # Various types of `invoke` calls + "consume_number(int)": ["::invoke", "test_invoke"], + "invoke_add(int, int)": ["::invoke", "test_invoke"], + "Callable::member_function(int) const": ["::invoke", "test_invoke"], + "Callable::operator()(int) const": ["::invoke", "test_invoke"], + # Containers + "MyKey::operator<(MyKey const&) const": ["less", "::emplace", "test_containers"], + } + stop_set = set() + while process.GetState() != lldb.eStateExited: + fn = thread.GetFrameAtIndex(0).GetFunctionName() + stop_set.add(fn) + self.assertIn(fn, expected_parents.keys()) + frame_id = 1 + for expected_parent in expected_parents[fn]: + # Skip all hidden frames + while ( + frame_id < thread.GetNumFrames() + and thread.GetFrameAtIndex(frame_id).IsHidden() + ): + frame_id = frame_id + 1 + # Expect the correct parent frame + self.assertIn( + expected_parent, thread.GetFrameAtIndex(frame_id).GetFunctionName() + ) + frame_id = frame_id + 1 + process.Continue() + + # Make sure that we actually verified all intended scenarios + self.assertEqual(len(stop_set), len(expected_parents)) diff --git a/lldb/test/API/lang/cpp/libcxx-internals-recognizer/main.cpp b/lldb/test/API/lang/cpp/libcxx-internals-recognizer/main.cpp new file mode 100644 index 00000000000000..870301b0970439 --- /dev/null +++ b/lldb/test/API/lang/cpp/libcxx-internals-recognizer/main.cpp @@ -0,0 +1,86 @@ +#include <algorithm> +#include <functional> +#include <map> +#include <ranges> +#include <vector> + +bool sort_less(int a, int b) { + __builtin_printf("break here"); + return a < b; +} + +bool ranges_sort_less(int a, int b) { + __builtin_printf("break here"); + return a < b; +} + +int view_transform(int a) { + __builtin_printf("break here"); + return a * a; +} + +void test_algorithms() { + std::vector<int> vec{8, 1, 3, 2}; + + // The internal frames for `std::sort` should be hidden + std::sort(vec.begin(), vec.end(), sort_less); + + // The internal frames for `ranges::sort` should be hidden + std::ranges::sort(vec.begin(), vec.end(), ranges_sort_less); + + // Same for views + for (auto x : vec | std::ranges::views::transform(view_transform)) { + // no-op + } +} + +void consume_number(int i) { __builtin_printf("break here"); } + +int invoke_add(int i, int j) { + __builtin_printf("break here"); + return i + j; +} + +struct Callable { + Callable(int num) : num_(num) {} + void operator()(int i) const { __builtin_printf("break here"); } + void member_function(int i) const { __builtin_printf("break here"); } + int num_; +}; + +void test_invoke() { + // Invoke a void-returning function + std::invoke(consume_number, -9); + + // Invoke a non-void-returning function + std::invoke(invoke_add, 1, 10); + + // Invoke a member function + const Callable foo(314159); + std::invoke(&Callable::member_function, foo, 1); + + // Invoke a function object + std::invoke(Callable(12), 18); +} + +struct MyKey { + int x; + bool operator==(const MyKey &) const = default; + bool operator<(const MyKey &other) const { + __builtin_printf("break here"); + return x < other.x; + } +}; + +void test_containers() { + std::map<MyKey, int> map; + map.emplace(MyKey{1}, 2); + map.emplace(MyKey{2}, 3); +} + +int main() { + test_algorithms(); + test_invoke(); + test_containers(); + return 0; +} >From d0cf329c94728a9cf0da97a2545a4a6c9e185e3f Mon Sep 17 00:00:00 2001 From: Adrian Vogelsgesang <avogelsges...@salesforce.com> Date: Tue, 17 Sep 2024 08:37:08 +0000 Subject: [PATCH 2/6] Remove superseded std::invoke tests --- .../lang/cpp/std-invoke-recognizer/Makefile | 5 --- .../TestStdInvokeRecognizer.py | 44 ------------------- .../lang/cpp/std-invoke-recognizer/main.cpp | 30 ------------- 3 files changed, 79 deletions(-) delete mode 100644 lldb/test/API/lang/cpp/std-invoke-recognizer/Makefile delete mode 100644 lldb/test/API/lang/cpp/std-invoke-recognizer/TestStdInvokeRecognizer.py delete mode 100644 lldb/test/API/lang/cpp/std-invoke-recognizer/main.cpp diff --git a/lldb/test/API/lang/cpp/std-invoke-recognizer/Makefile b/lldb/test/API/lang/cpp/std-invoke-recognizer/Makefile deleted file mode 100644 index 69014eb9c0f2eb..00000000000000 --- a/lldb/test/API/lang/cpp/std-invoke-recognizer/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -CXX_SOURCES := main.cpp -USE_LIBCPP := 1 -CXXFLAGS_EXTRAS := -std=c++17 - -include Makefile.rules diff --git a/lldb/test/API/lang/cpp/std-invoke-recognizer/TestStdInvokeRecognizer.py b/lldb/test/API/lang/cpp/std-invoke-recognizer/TestStdInvokeRecognizer.py deleted file mode 100644 index dbe29610bf7982..00000000000000 --- a/lldb/test/API/lang/cpp/std-invoke-recognizer/TestStdInvokeRecognizer.py +++ /dev/null @@ -1,44 +0,0 @@ -import lldb -from lldbsuite.test.decorators import * -from lldbsuite.test.lldbtest import * -from lldbsuite.test import lldbutil - - -class LibCxxStdFunctionRecognizerTestCase(TestBase): - NO_DEBUG_INFO_TESTCASE = True - - @add_test_categories(["libc++"]) - def test_frame_recognizer(self): - """Test that implementation details of `std::invoke` are hidden""" - self.build() - (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( - self, "break here", lldb.SBFileSpec("main.cpp") - ) - - stop_cnt = 0 - while process.GetState() != lldb.eStateExited: - stop_cnt += 1 - self.assertTrue( - any( - f in thread.GetFrameAtIndex(0).GetFunctionName() - for f in ["consume_number", "add", "Callable"] - ) - ) - # Skip all hidden frames - frame_id = 1 - while ( - frame_id < thread.GetNumFrames() - and thread.GetFrameAtIndex(frame_id).IsHidden() - ): - frame_id = frame_id + 1 - # Expect `std::invoke` to be the direct parent - self.assertIn( - "::invoke", thread.GetFrameAtIndex(frame_id).GetFunctionName() - ) - # And right above that, there should be the `main` frame - self.assertIn( - "main", thread.GetFrameAtIndex(frame_id + 1).GetFunctionName() - ) - process.Continue() - - self.assertEqual(stop_cnt, 4) diff --git a/lldb/test/API/lang/cpp/std-invoke-recognizer/main.cpp b/lldb/test/API/lang/cpp/std-invoke-recognizer/main.cpp deleted file mode 100644 index bafbbd28386e8b..00000000000000 --- a/lldb/test/API/lang/cpp/std-invoke-recognizer/main.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include <functional> - -void consume_number(int i) { __builtin_printf("break here"); } - -int add(int i, int j) { - // break here - return i + j; -} - -struct Callable { - Callable(int num) : num_(num) {} - void operator()(int i) const { __builtin_printf("break here"); } - void member_function(int i) const { __builtin_printf("break here"); } - int num_; -}; - -int main() { - // Invoke a void-returning function - std::invoke(consume_number, -9); - - // Invoke a non-void-returning function - std::invoke(add, 1, 10); - - // Invoke a member function - const Callable foo(314159); - std::invoke(&Callable::member_function, foo, 1); - - // Invoke a function object - std::invoke(Callable(12), 18); -} >From d31e3c541cab88c1b7589120a6eed88c667e1191 Mon Sep 17 00:00:00 2001 From: Adrian Vogelsgesang <avogelsges...@salesforce.com> Date: Sat, 21 Sep 2024 08:50:14 +0000 Subject: [PATCH 3/6] Don't hide frame of entry point into libc++ --- .../CPlusPlus/CPPLanguageRuntime.cpp | 15 ++++++++++++++- .../TestLibcxxInternalsRecognizer.py | 8 ++++---- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp index d0e84bdeb94f01..a3fc876476d0aa 100644 --- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp @@ -79,9 +79,22 @@ class LibCXXFrameRecognizer : public StackFrameRecognizer { if (!sc.function) return {}; + // Check if we have a regex match + bool matches_regex = false; for (RegularExpression &r : m_hidden_regex) - if (r.Execute(sc.function->GetNameNoArguments())) + if (r.Execute(sc.function->GetNameNoArguments())) { + matches_regex = true; + break; + } + + if (matches_regex) { + // Only hide this frame if the immediate caller is also within libc++. + lldb::StackFrameSP parent_frame = frame_sp->GetThread()->GetStackFrameAtIndex(frame_sp->GetFrameIndex() + 1); + const auto& parent_sc = parent_frame->GetSymbolContext(lldb::eSymbolContextFunction); + if (parent_sc.function->GetNameNoArguments().GetStringRef().starts_with("std::")) { return m_hidden_frame; + } + } return {}; } diff --git a/lldb/test/API/lang/cpp/libcxx-internals-recognizer/TestLibcxxInternalsRecognizer.py b/lldb/test/API/lang/cpp/libcxx-internals-recognizer/TestLibcxxInternalsRecognizer.py index a5b4e4fe995c38..a751525f1a9298 100644 --- a/lldb/test/API/lang/cpp/libcxx-internals-recognizer/TestLibcxxInternalsRecognizer.py +++ b/lldb/test/API/lang/cpp/libcxx-internals-recognizer/TestLibcxxInternalsRecognizer.py @@ -17,10 +17,10 @@ def test_frame_recognizer(self): expected_parents = { "sort_less(int, int)": ["::sort", "test_algorithms"], - # `std::ranges::sort` is implemented as an object of types `__sort`, - # which unfortunately means that there is no `std::ranges::sort` - # stack frame, and `main` is the direct parent of `my_less_ranges`. - "ranges_sort_less(int, int)": ["test_algorithms"], + # `std::ranges::sort` is implemented as an object of types `__sort`. + # We never hide the frame of the entry-point into the standard library, even + # if the name starts with `__` which usually indicates an internal function. + "ranges_sort_less(int, int)": ["ranges::__sort::operator()", "test_algorithms"], # `ranges::views::transform` internally uses `std::invoke`, and that # call also shows up in the stack trace "view_transform(int)": ["::invoke", "ranges::transform_view", "test_algorithms"], >From 79b591ce8d834b1037c51dd8305093d7356bcf97 Mon Sep 17 00:00:00 2001 From: Adrian Vogelsgesang <avogelsges...@salesforce.com> Date: Sat, 21 Sep 2024 09:46:26 +0000 Subject: [PATCH 4/6] Fix code formatting --- .../CPlusPlus/CPPLanguageRuntime.cpp | 16 ++++++++++------ .../TestLibcxxInternalsRecognizer.py | 17 ++++++++++++++--- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp index a3fc876476d0aa..2a35182b42c945 100644 --- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp @@ -80,18 +80,22 @@ class LibCXXFrameRecognizer : public StackFrameRecognizer { return {}; // Check if we have a regex match - bool matches_regex = false; + bool matches_regex = false; for (RegularExpression &r : m_hidden_regex) if (r.Execute(sc.function->GetNameNoArguments())) { - matches_regex = true; - break; + matches_regex = true; + break; } if (matches_regex) { // Only hide this frame if the immediate caller is also within libc++. - lldb::StackFrameSP parent_frame = frame_sp->GetThread()->GetStackFrameAtIndex(frame_sp->GetFrameIndex() + 1); - const auto& parent_sc = parent_frame->GetSymbolContext(lldb::eSymbolContextFunction); - if (parent_sc.function->GetNameNoArguments().GetStringRef().starts_with("std::")) { + lldb::StackFrameSP parent_frame = + frame_sp->GetThread()->GetStackFrameAtIndex( + frame_sp->GetFrameIndex() + 1); + const auto &parent_sc = + parent_frame->GetSymbolContext(lldb::eSymbolContextFunction); + if (parent_sc.function->GetNameNoArguments().GetStringRef().starts_with( + "std::")) { return m_hidden_frame; } } diff --git a/lldb/test/API/lang/cpp/libcxx-internals-recognizer/TestLibcxxInternalsRecognizer.py b/lldb/test/API/lang/cpp/libcxx-internals-recognizer/TestLibcxxInternalsRecognizer.py index a751525f1a9298..ad48208f21e502 100644 --- a/lldb/test/API/lang/cpp/libcxx-internals-recognizer/TestLibcxxInternalsRecognizer.py +++ b/lldb/test/API/lang/cpp/libcxx-internals-recognizer/TestLibcxxInternalsRecognizer.py @@ -20,17 +20,28 @@ def test_frame_recognizer(self): # `std::ranges::sort` is implemented as an object of types `__sort`. # We never hide the frame of the entry-point into the standard library, even # if the name starts with `__` which usually indicates an internal function. - "ranges_sort_less(int, int)": ["ranges::__sort::operator()", "test_algorithms"], + "ranges_sort_less(int, int)": [ + "ranges::__sort::operator()", + "test_algorithms", + ], # `ranges::views::transform` internally uses `std::invoke`, and that # call also shows up in the stack trace - "view_transform(int)": ["::invoke", "ranges::transform_view", "test_algorithms"], + "view_transform(int)": [ + "::invoke", + "ranges::transform_view", + "test_algorithms", + ], # Various types of `invoke` calls "consume_number(int)": ["::invoke", "test_invoke"], "invoke_add(int, int)": ["::invoke", "test_invoke"], "Callable::member_function(int) const": ["::invoke", "test_invoke"], "Callable::operator()(int) const": ["::invoke", "test_invoke"], # Containers - "MyKey::operator<(MyKey const&) const": ["less", "::emplace", "test_containers"], + "MyKey::operator<(MyKey const&) const": [ + "less", + "::emplace", + "test_containers", + ], } stop_set = set() while process.GetState() != lldb.eStateExited: >From c272d51457e22932ba6394526fb9c1415d0f4fb0 Mon Sep 17 00:00:00 2001 From: Adrian Vogelsgesang <avogelsges...@salesforce.com> Date: Sat, 21 Sep 2024 19:47:43 +0000 Subject: [PATCH 5/6] Update documentation in libc++ to recommend `disable` --- libcxx/docs/UserDocumentation.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/libcxx/docs/UserDocumentation.rst b/libcxx/docs/UserDocumentation.rst index 8999b4f23e91d2..3d6cdae7c55e74 100644 --- a/libcxx/docs/UserDocumentation.rst +++ b/libcxx/docs/UserDocumentation.rst @@ -368,9 +368,8 @@ represent internal implementation details such as ``__sort4`` and similar utility functions. To also show those implementation details, use ``thread backtrace -u``. -Alternatively, to disable those compact backtraces for good, use -``frame recognizer list`` and ``frame recognizer delete`` to delete the libc++ -frame recognizer. +Alternatively, to disable those compact backtraces, use ``frame recognizer list`` +and ``frame recognizer disable`` on the "libc++ frame recognizer". GDB Pretty printers for libc++ ------------------------------ >From a02a62313206f6730c407260d747951119920a52 Mon Sep 17 00:00:00 2001 From: Adrian Vogelsgesang <avogelsges...@salesforce.com> Date: Mon, 23 Sep 2024 18:38:11 +0000 Subject: [PATCH 6/6] Address comments --- libcxx/docs/UserDocumentation.rst | 4 ++++ .../CPlusPlus/CPPLanguageRuntime.cpp | 15 +++++++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/libcxx/docs/UserDocumentation.rst b/libcxx/docs/UserDocumentation.rst index 3d6cdae7c55e74..10c0a50045626a 100644 --- a/libcxx/docs/UserDocumentation.rst +++ b/libcxx/docs/UserDocumentation.rst @@ -371,6 +371,10 @@ To also show those implementation details, use ``thread backtrace -u``. Alternatively, to disable those compact backtraces, use ``frame recognizer list`` and ``frame recognizer disable`` on the "libc++ frame recognizer". +Futhermore, stepping into libc++ functions is disabled by default. This is controlled via the +setting ``target.process.thread.step-avoid-regexp`` which defaults to ``^std::`` and can be +disabled using ``settings set target.process.thread.step-avoid-regexp ""``. + GDB Pretty printers for libc++ ------------------------------ diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp index 2a35182b42c945..565a51b8635d2f 100644 --- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp @@ -81,19 +81,26 @@ class LibCXXFrameRecognizer : public StackFrameRecognizer { // Check if we have a regex match bool matches_regex = false; - for (RegularExpression &r : m_hidden_regex) + for (RegularExpression &r : m_hidden_regex) { if (r.Execute(sc.function->GetNameNoArguments())) { matches_regex = true; break; } + } if (matches_regex) { // Only hide this frame if the immediate caller is also within libc++. - lldb::StackFrameSP parent_frame = - frame_sp->GetThread()->GetStackFrameAtIndex( + lldb::ThreadSP thread_sp = frame_sp->GetThread(); + if (!thread_sp) + return {}; + lldb::StackFrameSP parent_frame_sp = thread_sp->GetStackFrameAtIndex( frame_sp->GetFrameIndex() + 1); + if (!parent_frame_sp) + return {}; const auto &parent_sc = - parent_frame->GetSymbolContext(lldb::eSymbolContextFunction); + parent_frame_sp->GetSymbolContext(lldb::eSymbolContextFunction); + if (!parent_sc.function) + return {}; if (parent_sc.function->GetNameNoArguments().GetStringRef().starts_with( "std::")) { return m_hidden_frame; _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits