[Lldb-commits] [lldb] [lldb] Add frame recognizers for libc++ `std::invoke` (PR #105695)

Adrian Vogelsgesang via lldb-commits lldb-commits at lists.llvm.org
Mon Aug 26 04:40:14 PDT 2024


https://github.com/vogelsgesang updated https://github.com/llvm/llvm-project/pull/105695

>From e90463e8967c2019e220b063ed4ce73cd0172bf3 Mon Sep 17 00:00:00 2001
From: Adrian Vogelsgesang <avogelsgesang at salesforce.com>
Date: Thu, 22 Aug 2024 10:50:13 +0000
Subject: [PATCH 1/5] [lldb-dap] Add frame recognizers for libc++ `std::invoke`

With this commit, we also hide the implementation details of
`std::invoke`. To do so, the `LibCXXFrameRecognizer` got a couple more
regular expressions.

The regular expression passed into the `AddRecognizer` became
problematic, as it was evaluated on the demangled name. Those names also
included result types for C++ symbols. For `std::__invoke` the return
type is a huge `decltype(...)`, making the regular expresison really
hard to write.

Instead, I added support for `AddRecognizer` to match on the demangled
names without result type and argument types.

By hiding the implementation details of `invoke`, also the back traces
for `std::function` become even nicer, because `std::function` is using
`__invoke` internally.
---
 .../lldb/Target/StackFrameRecognizer.h        |  8 +++-
 lldb/source/Commands/Options.td               |  2 +-
 .../CPlusPlus/CPPLanguageRuntime.cpp          | 48 ++++++++++++++-----
 lldb/source/Target/StackFrameRecognizer.cpp   | 41 ++++++++++++++--
 .../TestStdFunctionRecognizer.py              | 21 +++++++-
 .../lang/cpp/std-invoke-recognizer/Makefile   |  5 ++
 .../TestStdInvokeRecognizer.py                | 31 ++++++++++++
 .../lang/cpp/std-invoke-recognizer/main.cpp   | 40 ++++++++++++++++
 8 files changed, 175 insertions(+), 21 deletions(-)
 create mode 100644 lldb/test/API/lang/cpp/std-invoke-recognizer/Makefile
 create mode 100644 lldb/test/API/lang/cpp/std-invoke-recognizer/TestStdInvokeRecognizer.py
 create mode 100644 lldb/test/API/lang/cpp/std-invoke-recognizer/main.cpp

diff --git a/lldb/include/lldb/Target/StackFrameRecognizer.h b/lldb/include/lldb/Target/StackFrameRecognizer.h
index 2f5c5caa6a4561..fe25dbbde745d1 100644
--- a/lldb/include/lldb/Target/StackFrameRecognizer.h
+++ b/lldb/include/lldb/Target/StackFrameRecognizer.h
@@ -107,12 +107,14 @@ class StackFrameRecognizerManager {
 public:
   void AddRecognizer(lldb::StackFrameRecognizerSP recognizer,
                      ConstString module, llvm::ArrayRef<ConstString> symbols,
-                     bool first_instruction_only = true);
+                     bool first_instruction_only = true,
+                     Mangled::NamePreference mangling_preference = Mangled::ePreferDemangled);
 
   void AddRecognizer(lldb::StackFrameRecognizerSP recognizer,
                      lldb::RegularExpressionSP module,
                      lldb::RegularExpressionSP symbol,
-                     bool first_instruction_only = true);
+                     bool first_instruction_only = true,
+                     Mangled::NamePreference mangling_preference = Mangled::ePreferDemangled);
 
   void ForEach(std::function<
                void(uint32_t recognizer_id, std::string recognizer_name,
@@ -143,10 +145,12 @@ class StackFrameRecognizerManager {
     std::vector<ConstString> symbols;
     lldb::RegularExpressionSP symbol_regexp;
     bool first_instruction_only;
+    Mangled::NamePreference mangling_preference;
   };
 
   std::deque<RegisteredEntry> m_recognizers;
   uint16_t m_generation = 0;
+  std::unordered_set<Mangled::NamePreference> m_used_manglings;
 };
 
 /// \class ValueObjectRecognizerSynthesizedValue
diff --git a/lldb/source/Commands/Options.td b/lldb/source/Commands/Options.td
index 9c4dbed6939ba9..df906e9d7c808f 100644
--- a/lldb/source/Commands/Options.td
+++ b/lldb/source/Commands/Options.td
@@ -1049,7 +1049,7 @@ let Command = "thread backtrace" in {
   def thread_backtrace_extended : Option<"extended", "e">, Group<1>,
   Arg<"Boolean">, Desc<"Show the extended backtrace, if available">;
   def thread_backtrace_unfiltered : Option<"unfiltered", "u">, Group<1>,
-  Desc<"Filter out frames according to installed frame recognizers">;
+  Desc<"Do not filter out frames according to installed frame recognizers">;
 }
 
 let Command = "thread step scope" in {
diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp
index 1e4a2cbb1133f7..6d446a099efc78 100644
--- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include <cstring>
+#include <iostream>
 
 #include <memory>
 
@@ -44,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 {
-  RegularExpression m_hidden_function_regex;
+  std::array<RegularExpression, 3> m_hidden_regex;
   RecognizedStackFrameSP m_hidden_frame;
 
   struct LibCXXHiddenFrame : public RecognizedStackFrame {
@@ -53,10 +54,32 @@ class LibCXXFrameRecognizer : public StackFrameRecognizer {
 
 public:
   LibCXXFrameRecognizer()
-      : m_hidden_function_regex(
-            R"(^std::__.*::(__function.*::operator\(\)|__invoke))"
-            R"((\[.*\])?)"    // ABI tag.
-            R"(( const)?$)"), // const.
+      : m_hidden_regex{
+            // internal implementation details of std::function
+            //    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\(\))"
+              R"((\[.*\])?)"    // ABI tag.
+              R"(( const)?$)"}, // const.
+            // internal implementation details of std::invoke
+            //   std::__1::__invoke[abi:ne200000]<void (*&)()>
+            RegularExpression{
+              R"(^std::__[^:]*::)" // Namespace.
+              R"(__invoke)"
+              R"((\[.*\])?)"  // ABI tag.
+              R"(<.*>)"},     // template argument.
+            // 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)"
+              R"((\[.*\])?)"  // ABI tag.
+              R"(<.*>)"}      // template argument.
+
+        },
         m_hidden_frame(new LibCXXHiddenFrame()) {}
 
   std::string GetName() override { return "libc++ frame recognizer"; }
@@ -69,8 +92,9 @@ class LibCXXFrameRecognizer : public StackFrameRecognizer {
     if (!sc.function)
       return {};
 
-    if (m_hidden_function_regex.Execute(sc.function->GetNameNoArguments()))
-      return m_hidden_frame;
+    for (RegularExpression &r : m_hidden_regex)
+      if (r.Execute(sc.function->GetNameNoArguments()))
+        return m_hidden_frame;
 
     return {};
   }
@@ -81,8 +105,9 @@ CPPLanguageRuntime::CPPLanguageRuntime(Process *process)
   if (process)
     process->GetTarget().GetFrameRecognizerManager().AddRecognizer(
         StackFrameRecognizerSP(new LibCXXFrameRecognizer()), {},
-        std::make_shared<RegularExpression>("^std::__.*::"),
-        /*first_instruction_only*/ false);
+        std::make_shared<RegularExpression>("^std::__[^:]*::"),
+        /*first_instruction_only=*/ false,
+        /*mangling_preference=*/ Mangled::ePreferDemangledWithoutArguments);
 }
 
 bool CPPLanguageRuntime::IsAllowedRuntimeValue(ConstString name) {
@@ -108,8 +133,7 @@ bool contains_lambda_identifier(llvm::StringRef &str_ref) {
 
 CPPLanguageRuntime::LibCppStdFunctionCallableInfo
 line_entry_helper(Target &target, const SymbolContext &sc, Symbol *symbol,
-                  llvm::StringRef first_template_param_sref,
-                  bool has_invoke) {
+                  llvm::StringRef first_template_param_sref, bool has_invoke) {
 
   CPPLanguageRuntime::LibCppStdFunctionCallableInfo optional_info;
 
@@ -190,7 +214,7 @@ CPPLanguageRuntime::FindLibCppStdFunctionCallableInfo(
     ValueObjectSP sub_member_f_(member_f_->GetChildMemberWithName("__f_"));
 
     if (sub_member_f_)
-        member_f_ = sub_member_f_;
+      member_f_ = sub_member_f_;
   }
 
   if (!member_f_)
diff --git a/lldb/source/Target/StackFrameRecognizer.cpp b/lldb/source/Target/StackFrameRecognizer.cpp
index 44411afc65dda9..37901a2ea526a8 100644
--- a/lldb/source/Target/StackFrameRecognizer.cpp
+++ b/lldb/source/Target/StackFrameRecognizer.cpp
@@ -62,19 +62,24 @@ void StackFrameRecognizerManager::BumpGeneration() {
 
 void StackFrameRecognizerManager::AddRecognizer(
     StackFrameRecognizerSP recognizer, ConstString module,
-    llvm::ArrayRef<ConstString> symbols, bool first_instruction_only) {
+    llvm::ArrayRef<ConstString> symbols, bool first_instruction_only,
+    Mangled::NamePreference mangling_preference) {
   m_recognizers.push_front({(uint32_t)m_recognizers.size(), recognizer, false,
                             module, RegularExpressionSP(), symbols,
                             RegularExpressionSP(), first_instruction_only});
+  m_used_manglings.insert(mangling_preference);
   BumpGeneration();
 }
 
 void StackFrameRecognizerManager::AddRecognizer(
     StackFrameRecognizerSP recognizer, RegularExpressionSP module,
-    RegularExpressionSP symbol, bool first_instruction_only) {
+    RegularExpressionSP symbol, bool first_instruction_only,
+    Mangled::NamePreference mangling_preference) {
   m_recognizers.push_front({(uint32_t)m_recognizers.size(), recognizer, true,
                             ConstString(), module, std::vector<ConstString>(),
-                            symbol, first_instruction_only});
+                            symbol, first_instruction_only,
+                            mangling_preference});
+  m_used_manglings.insert(mangling_preference);
   BumpGeneration();
 }
 
@@ -119,13 +124,30 @@ bool StackFrameRecognizerManager::RemoveRecognizerWithID(
 void StackFrameRecognizerManager::RemoveAllRecognizers() {
   BumpGeneration();
   m_recognizers.clear();
+  m_used_manglings.clear();
 }
 
 StackFrameRecognizerSP
 StackFrameRecognizerManager::GetRecognizerForFrame(StackFrameSP frame) {
   const SymbolContext &symctx = frame->GetSymbolContext(
       eSymbolContextModule | eSymbolContextFunction | eSymbolContextSymbol);
-  ConstString function_name = symctx.GetFunctionName();
+  ConstString function_name_mangled;
+  ConstString function_name_demangled;
+  ConstString function_name_noargs;
+  for (Mangled::NamePreference m : m_used_manglings) {
+    switch (m) {
+    case Mangled::ePreferMangled:
+      function_name_mangled = symctx.GetFunctionName(m);
+      break;
+    case Mangled::ePreferDemangled:
+      function_name_demangled = symctx.GetFunctionName(m);
+      break;
+    case Mangled::ePreferDemangledWithoutArguments:
+      function_name_noargs = symctx.GetFunctionName(m);
+      break;
+    }
+  }
+
   ModuleSP module_sp = symctx.module_sp;
   if (!module_sp)
     return StackFrameRecognizerSP();
@@ -145,6 +167,17 @@ StackFrameRecognizerManager::GetRecognizerForFrame(StackFrameSP frame) {
       if (!entry.module_regexp->Execute(module_name.GetStringRef()))
         continue;
 
+    ConstString function_name = [&]() {
+      switch (entry.mangling_preference) {
+      case Mangled::ePreferMangled:
+        return function_name_mangled;
+      case Mangled::ePreferDemangled:
+        return function_name_demangled;
+      case Mangled::ePreferDemangledWithoutArguments:
+        return function_name_noargs;
+      }
+    }();
+
     if (!entry.symbols.empty())
       if (!llvm::is_contained(entry.symbols, function_name))
         continue;
diff --git a/lldb/test/API/lang/cpp/std-function-recognizer/TestStdFunctionRecognizer.py b/lldb/test/API/lang/cpp/std-function-recognizer/TestStdFunctionRecognizer.py
index 8d4b6bfe17166e..fa7a4f379e92b4 100644
--- a/lldb/test/API/lang/cpp/std-function-recognizer/TestStdFunctionRecognizer.py
+++ b/lldb/test/API/lang/cpp/std-function-recognizer/TestStdFunctionRecognizer.py
@@ -7,6 +7,23 @@
 class LibCxxStdFunctionRecognizerTestCase(TestBase):
     NO_DEBUG_INFO_TESTCASE = True
 
+    @add_test_categories(["libc++"])
+    def test_frame_recognizer(self):
+        """Test that std::function all implementation details are hidden in SBFrame"""
+        self.build()
+        (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
+            self, "// break here", lldb.SBFileSpec("main.cpp")
+        )
+        self.assertIn("foo", thread.GetFrameAtIndex(0).GetFunctionName())
+        # 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::function<...>::operator()` to be the direct parent of `foo`
+        self.assertIn("::operator()", thread.GetFrameAtIndex(frame_id).GetFunctionName())
+        # And right above that, there should be the `main` frame
+        self.assertIn("main", thread.GetFrameAtIndex(frame_id + 1).GetFunctionName())
+
     @add_test_categories(["libc++"])
     def test_backtrace(self):
         """Test that std::function implementation details are hidden in bt"""
@@ -27,12 +44,12 @@ def test_backtrace(self):
         self.expect(
             "thread backtrace -u",
             ordered=True,
-            patterns=["frame.*foo", "frame.*std::__.*::__function", "frame.*main"],
+            patterns=["frame.*foo", "frame.*std::__[^:]*::__function", "frame.*main"],
         )
         self.expect(
             "thread backtrace --unfiltered",
             ordered=True,
-            patterns=["frame.*foo", "frame.*std::__.*::__function", "frame.*main"],
+            patterns=["frame.*foo", "frame.*std::__[^:]*::__function", "frame.*main"],
         )
 
     @add_test_categories(["libc++"])
diff --git a/lldb/test/API/lang/cpp/std-invoke-recognizer/Makefile b/lldb/test/API/lang/cpp/std-invoke-recognizer/Makefile
new file mode 100644
index 00000000000000..69014eb9c0f2eb
--- /dev/null
+++ b/lldb/test/API/lang/cpp/std-invoke-recognizer/Makefile
@@ -0,0 +1,5 @@
+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
new file mode 100644
index 00000000000000..ef75e1afd9cba5
--- /dev/null
+++ b/lldb/test/API/lang/cpp/std-invoke-recognizer/TestStdInvokeRecognizer.py
@@ -0,0 +1,31 @@
+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 details of `std::invoke`"""
+        self.build()
+        (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
+            self, "// break here", lldb.SBFileSpec("main.cpp")
+        )
+
+        while process.GetState() != lldb.eStateExited:
+            self.assertTrue(any(f in thread.GetFrameAtIndex(0).GetFunctionName() for f in ["print_num", "add", "PrintAdder"]))
+            print(thread.GetFrameAtIndex(0).GetFunctionName())
+            # Skip all hidden frames
+            frame_id = 1
+            while frame_id < thread.GetNumFrames() and thread.GetFrameAtIndex(frame_id).IsHidden():
+                print(thread.GetFrameAtIndex(frame_id).GetFunctionName())
+                frame_id = frame_id + 1
+            print(thread.GetFrameAtIndex(frame_id).GetFunctionName())
+            # 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()
diff --git a/lldb/test/API/lang/cpp/std-invoke-recognizer/main.cpp b/lldb/test/API/lang/cpp/std-invoke-recognizer/main.cpp
new file mode 100644
index 00000000000000..78497d2938fe8a
--- /dev/null
+++ b/lldb/test/API/lang/cpp/std-invoke-recognizer/main.cpp
@@ -0,0 +1,40 @@
+#include <functional>
+#include <iostream>
+
+void print_num(int i) {
+  // break here
+  std::cout << i << '\n';
+}
+
+int add(int i, int j) {
+  // break here
+  return i + j;
+}
+
+struct PrintAdder {
+  PrintAdder(int num) : num_(num) {}
+  void operator()(int i) const {
+    // break here
+    std::cout << i << '\n';
+  }
+  void print_add(int i) const {
+    // break here
+    std::cout << num_ + i << '\n';
+  }
+  int num_;
+};
+
+int main() {
+  // Invoke a void-returning function
+  std::invoke(print_num, -9);
+
+  // Invoke a non-void-returning function
+  std::cout << std::invoke(add, 1, 10) << '\n';
+
+  // Invoke a member function
+  const PrintAdder foo(314159);
+  std::invoke(&PrintAdder::print_add, foo, 1);
+
+  // Invoke a function object
+  std::invoke(PrintAdder(12), 18);
+}

>From 6947b139c7515bb601a9993714e7ee0590997393 Mon Sep 17 00:00:00 2001
From: Adrian Vogelsgesang <avogelsgesang at salesforce.com>
Date: Sun, 25 Aug 2024 23:24:57 +0200
Subject: [PATCH 2/5] Remove caching of demangled name in StackFrameRecognizer

They are already cached in `Mangled`
---
 .../lldb/Target/StackFrameRecognizer.h        |  1 -
 lldb/source/Target/StackFrameRecognizer.cpp   | 26 +++----------------
 2 files changed, 3 insertions(+), 24 deletions(-)

diff --git a/lldb/include/lldb/Target/StackFrameRecognizer.h b/lldb/include/lldb/Target/StackFrameRecognizer.h
index fe25dbbde745d1..4ef0d1b2f56dfb 100644
--- a/lldb/include/lldb/Target/StackFrameRecognizer.h
+++ b/lldb/include/lldb/Target/StackFrameRecognizer.h
@@ -150,7 +150,6 @@ class StackFrameRecognizerManager {
 
   std::deque<RegisteredEntry> m_recognizers;
   uint16_t m_generation = 0;
-  std::unordered_set<Mangled::NamePreference> m_used_manglings;
 };
 
 /// \class ValueObjectRecognizerSynthesizedValue
diff --git a/lldb/source/Target/StackFrameRecognizer.cpp b/lldb/source/Target/StackFrameRecognizer.cpp
index 37901a2ea526a8..7c0dfde993948f 100644
--- a/lldb/source/Target/StackFrameRecognizer.cpp
+++ b/lldb/source/Target/StackFrameRecognizer.cpp
@@ -67,7 +67,6 @@ void StackFrameRecognizerManager::AddRecognizer(
   m_recognizers.push_front({(uint32_t)m_recognizers.size(), recognizer, false,
                             module, RegularExpressionSP(), symbols,
                             RegularExpressionSP(), first_instruction_only});
-  m_used_manglings.insert(mangling_preference);
   BumpGeneration();
 }
 
@@ -79,7 +78,6 @@ void StackFrameRecognizerManager::AddRecognizer(
                             ConstString(), module, std::vector<ConstString>(),
                             symbol, first_instruction_only,
                             mangling_preference});
-  m_used_manglings.insert(mangling_preference);
   BumpGeneration();
 }
 
@@ -124,30 +122,12 @@ bool StackFrameRecognizerManager::RemoveRecognizerWithID(
 void StackFrameRecognizerManager::RemoveAllRecognizers() {
   BumpGeneration();
   m_recognizers.clear();
-  m_used_manglings.clear();
 }
 
 StackFrameRecognizerSP
 StackFrameRecognizerManager::GetRecognizerForFrame(StackFrameSP frame) {
   const SymbolContext &symctx = frame->GetSymbolContext(
       eSymbolContextModule | eSymbolContextFunction | eSymbolContextSymbol);
-  ConstString function_name_mangled;
-  ConstString function_name_demangled;
-  ConstString function_name_noargs;
-  for (Mangled::NamePreference m : m_used_manglings) {
-    switch (m) {
-    case Mangled::ePreferMangled:
-      function_name_mangled = symctx.GetFunctionName(m);
-      break;
-    case Mangled::ePreferDemangled:
-      function_name_demangled = symctx.GetFunctionName(m);
-      break;
-    case Mangled::ePreferDemangledWithoutArguments:
-      function_name_noargs = symctx.GetFunctionName(m);
-      break;
-    }
-  }
-
   ModuleSP module_sp = symctx.module_sp;
   if (!module_sp)
     return StackFrameRecognizerSP();
@@ -170,11 +150,11 @@ StackFrameRecognizerManager::GetRecognizerForFrame(StackFrameSP frame) {
     ConstString function_name = [&]() {
       switch (entry.mangling_preference) {
       case Mangled::ePreferMangled:
-        return function_name_mangled;
+        return symctx.GetFunctionName(entry.mangling_preference);
       case Mangled::ePreferDemangled:
-        return function_name_demangled;
+        return symctx.GetFunctionName(entry.mangling_preference);
       case Mangled::ePreferDemangledWithoutArguments:
-        return function_name_noargs;
+        return symctx.GetFunctionName(entry.mangling_preference);
       }
     }();
 

>From e384eb9d94eb2f09a58db5805dc70af53cece93c Mon Sep 17 00:00:00 2001
From: Adrian Vogelsgesang <avogelsgesang at salesforce.com>
Date: Mon, 26 Aug 2024 00:00:59 +0200
Subject: [PATCH 3/5] Copy additional content from adrian-prantl's commit

---
 .../lldb/Target/StackFrameRecognizer.h        | 21 ++++--
 lldb/source/Commands/CommandObjectFrame.cpp   | 68 ++++++++++++-------
 .../CPlusPlus/CPPLanguageRuntime.cpp          |  4 +-
 .../AppleObjCRuntime/AppleObjCRuntimeV2.cpp   |  2 +-
 .../AbortWithPayloadFrameRecognizer.cpp       | 11 +--
 lldb/source/Target/AssertFrameRecognizer.cpp  |  2 +
 lldb/source/Target/StackFrameRecognizer.cpp   | 36 ++++------
 .../Target/VerboseTrapFrameRecognizer.cpp     |  3 +-
 .../frame/recognizer/TestFrameRecognizer.py   | 20 +++---
 .../completion/TestCompletion.py              |  2 +-
 .../TestStdFunctionRecognizer.py              |  9 ++-
 .../TestStdInvokeRecognizer.py                | 20 ++++--
 .../Target/StackFrameRecognizerTest.cpp       |  3 +-
 13 files changed, 125 insertions(+), 76 deletions(-)

diff --git a/lldb/include/lldb/Target/StackFrameRecognizer.h b/lldb/include/lldb/Target/StackFrameRecognizer.h
index 4ef0d1b2f56dfb..617b1617d404a1 100644
--- a/lldb/include/lldb/Target/StackFrameRecognizer.h
+++ b/lldb/include/lldb/Target/StackFrameRecognizer.h
@@ -105,21 +105,30 @@ class ScriptedStackFrameRecognizer : public StackFrameRecognizer {
 /// Class that provides a registry of known stack frame recognizers.
 class StackFrameRecognizerManager {
 public:
+  /// Add a new recognizer that triggers on a given symbol name.
+  ///
+  /// \param symbol_mangling controls whether the symbol name should be
+  /// compared to the mangled or demangled name.
   void AddRecognizer(lldb::StackFrameRecognizerSP recognizer,
                      ConstString module, llvm::ArrayRef<ConstString> symbols,
-                     bool first_instruction_only = true,
-                     Mangled::NamePreference mangling_preference = Mangled::ePreferDemangled);
+                     Mangled::NamePreference symbol_mangling,
+                     bool first_instruction_only = true);
 
+  /// Add a new recognizer that triggers on a symbol regex.
+  ///
+  /// \param symbol_mangling controls whether the regex should apply
+  /// to the mangled or demangled name.
   void AddRecognizer(lldb::StackFrameRecognizerSP recognizer,
                      lldb::RegularExpressionSP module,
                      lldb::RegularExpressionSP symbol,
-                     bool first_instruction_only = true,
-                     Mangled::NamePreference mangling_preference = Mangled::ePreferDemangled);
+                     Mangled::NamePreference symbol_mangling,
+                     bool first_instruction_only = true);
 
   void ForEach(std::function<
                void(uint32_t recognizer_id, std::string recognizer_name,
                     std::string module, llvm::ArrayRef<ConstString> symbols,
-                    bool regexp)> const &callback);
+                    Mangled::NamePreference name_reference, bool regexp)> const
+                   &callback);
 
   bool RemoveRecognizerWithID(uint32_t recognizer_id);
 
@@ -144,8 +153,8 @@ class StackFrameRecognizerManager {
     lldb::RegularExpressionSP module_regexp;
     std::vector<ConstString> symbols;
     lldb::RegularExpressionSP symbol_regexp;
+    Mangled::NamePreference symbol_mangling;
     bool first_instruction_only;
-    Mangled::NamePreference mangling_preference;
   };
 
   std::deque<RegisteredEntry> m_recognizers;
diff --git a/lldb/source/Commands/CommandObjectFrame.cpp b/lldb/source/Commands/CommandObjectFrame.cpp
index 46c75e3dd159c0..ef57582a203b39 100644
--- a/lldb/source/Commands/CommandObjectFrame.cpp
+++ b/lldb/source/Commands/CommandObjectFrame.cpp
@@ -168,8 +168,7 @@ class CommandObjectFrameDiagnose : public CommandObjectParsed {
     // We've already handled the case where the value object sp is null, so
     // this is just to make sure future changes don't skip that:
     assert(valobj_sp.get() && "Must have a valid ValueObject to print");
-    ValueObjectPrinter printer(*valobj_sp, &result.GetOutputStream(),
-                               options);
+    ValueObjectPrinter printer(*valobj_sp, &result.GetOutputStream(), options);
     if (llvm::Error error = printer.PrintValueObject())
       result.AppendError(toString(std::move(error)));
   }
@@ -899,13 +898,16 @@ void CommandObjectFrameRecognizerAdd::DoExecute(Args &command,
     auto func =
         RegularExpressionSP(new RegularExpression(m_options.m_symbols.front()));
     GetTarget().GetFrameRecognizerManager().AddRecognizer(
-        recognizer_sp, module, func, m_options.m_first_instruction_only);
+        recognizer_sp, module, func, Mangled::NamePreference::ePreferDemangled,
+        m_options.m_first_instruction_only);
   } else {
     auto module = ConstString(m_options.m_module);
     std::vector<ConstString> symbols(m_options.m_symbols.begin(),
                                      m_options.m_symbols.end());
     GetTarget().GetFrameRecognizerManager().AddRecognizer(
-        recognizer_sp, module, symbols, m_options.m_first_instruction_only);
+        recognizer_sp, module, symbols,
+        Mangled::NamePreference::ePreferDemangled,
+        m_options.m_first_instruction_only);
   }
 #endif
 
@@ -927,6 +929,34 @@ class CommandObjectFrameRecognizerClear : public CommandObjectParsed {
   }
 };
 
+static void
+PrintRecognizerDetails(Stream &strm, const std::string &name,
+                       const std::string &module,
+                       llvm::ArrayRef<lldb_private::ConstString> symbols,
+                       Mangled::NamePreference symbol_mangling, bool regexp) {
+  strm << name << ", ";
+
+  if (!module.empty())
+    strm << "module " << module << ", ";
+
+  switch (symbol_mangling) {
+  case Mangled::NamePreference ::ePreferMangled:
+    strm << "mangled symbol ";
+    break;
+  case Mangled::NamePreference ::ePreferDemangled:
+    strm << "demangled symbol ";
+    break;
+  case Mangled::NamePreference ::ePreferDemangledWithoutArguments:
+    strm << "demangled (no args) symbol ";
+    break;
+  }
+
+  if (regexp)
+    strm << "regex ";
+
+  llvm::interleaveComma(symbols, strm);
+}
+
 class CommandObjectFrameRecognizerDelete : public CommandObjectParsed {
 public:
   CommandObjectFrameRecognizerDelete(CommandInterpreter &interpreter)
@@ -947,19 +977,13 @@ class CommandObjectFrameRecognizerDelete : public CommandObjectParsed {
     GetTarget().GetFrameRecognizerManager().ForEach(
         [&request](uint32_t rid, std::string rname, std::string module,
                    llvm::ArrayRef<lldb_private::ConstString> symbols,
-                   bool regexp) {
+                   Mangled::NamePreference symbol_mangling, bool regexp) {
           StreamString strm;
           if (rname.empty())
             rname = "(internal)";
 
-          strm << rname;
-          if (!module.empty())
-            strm << ", module " << module;
-          if (!symbols.empty())
-            for (auto &symbol : symbols)
-              strm << ", symbol " << symbol;
-          if (regexp)
-            strm << " (regexp)";
+          PrintRecognizerDetails(strm, rname, module, symbols, symbol_mangling,
+                                 regexp);
 
           request.TryCompleteCurrentArg(std::to_string(rid), strm.GetString());
         });
@@ -1016,22 +1040,18 @@ class CommandObjectFrameRecognizerList : public CommandObjectParsed {
   void DoExecute(Args &command, CommandReturnObject &result) override {
     bool any_printed = false;
     GetTarget().GetFrameRecognizerManager().ForEach(
-        [&result, &any_printed](
-            uint32_t recognizer_id, std::string name, std::string module,
-            llvm::ArrayRef<ConstString> symbols, bool regexp) {
+        [&result,
+         &any_printed](uint32_t recognizer_id, std::string name,
+                       std::string module, llvm::ArrayRef<ConstString> symbols,
+                       Mangled::NamePreference symbol_mangling, bool regexp) {
           Stream &stream = result.GetOutputStream();
 
           if (name.empty())
             name = "(internal)";
 
-          stream << std::to_string(recognizer_id) << ": " << name;
-          if (!module.empty())
-            stream << ", module " << module;
-          if (!symbols.empty())
-            for (auto &symbol : symbols)
-              stream << ", symbol " << symbol;
-          if (regexp)
-            stream << " (regexp)";
+          stream << std::to_string(recognizer_id) << ": ";
+          PrintRecognizerDetails(stream, name, module, symbols, symbol_mangling,
+                                 regexp);
 
           stream.EOL();
           stream.Flush();
diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp
index 6d446a099efc78..a9204d9f8857df 100644
--- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp
@@ -106,8 +106,8 @@ CPPLanguageRuntime::CPPLanguageRuntime(Process *process)
     process->GetTarget().GetFrameRecognizerManager().AddRecognizer(
         StackFrameRecognizerSP(new LibCXXFrameRecognizer()), {},
         std::make_shared<RegularExpression>("^std::__[^:]*::"),
-        /*first_instruction_only=*/ false,
-        /*mangling_preference=*/ Mangled::ePreferDemangledWithoutArguments);
+        /*mangling_preference=*/Mangled::ePreferDemangledWithoutArguments,
+        /*first_instruction_only=*/false);
 }
 
 bool CPPLanguageRuntime::IsAllowedRuntimeValue(ConstString name) {
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
index 9409497f1c81ba..c810ba0c3b171e 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
@@ -3465,6 +3465,6 @@ static void RegisterObjCExceptionRecognizer(Process *process) {
 
   process->GetTarget().GetFrameRecognizerManager().AddRecognizer(
       StackFrameRecognizerSP(new ObjCExceptionThrowFrameRecognizer()),
-      module.GetFilename(), symbols,
+      module.GetFilename(), symbols, Mangled::NamePreference::ePreferDemangled,
       /*first_instruction_only*/ true);
 }
diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/AbortWithPayloadFrameRecognizer.cpp b/lldb/source/Plugins/SystemRuntime/MacOSX/AbortWithPayloadFrameRecognizer.cpp
index d42e31c2aea0a0..cd9260a27719ba 100644
--- a/lldb/source/Plugins/SystemRuntime/MacOSX/AbortWithPayloadFrameRecognizer.cpp
+++ b/lldb/source/Plugins/SystemRuntime/MacOSX/AbortWithPayloadFrameRecognizer.cpp
@@ -36,8 +36,9 @@ void RegisterAbortWithPayloadFrameRecognizer(Process *process) {
     return;
 
   process->GetTarget().GetFrameRecognizerManager().AddRecognizer(
-      std::make_shared<AbortWithPayloadFrameRecognizer>(), module_name, 
-      sym_name, /*first_instruction_only*/ false);
+      std::make_shared<AbortWithPayloadFrameRecognizer>(), module_name,
+      sym_name, Mangled::NamePreference::ePreferDemangled,
+      /*first_instruction_only*/ false);
 }
 
 RecognizedStackFrameSP
@@ -55,7 +56,7 @@ AbortWithPayloadFrameRecognizer::RecognizeFrame(lldb::StackFrameSP frame_sp) {
   static constexpr llvm::StringLiteral info_key("abort_with_payload");
 
   Log *log = GetLog(LLDBLog::SystemRuntime);
-  
+
   if (!frame_sp) {
     LLDB_LOG(log, "abort_with_payload recognizer: invalid frame.");
     return {};
@@ -196,8 +197,8 @@ AbortWithPayloadFrameRecognizer::RecognizeFrame(lldb::StackFrameSP frame_sp) {
   abort_dict_sp->AddStringItem(reason_key, reason_string);
   abort_dict_sp->AddIntegerItem(flags_key, flags_val);
 
-  // This will overwrite the abort_with_payload information in the dictionary  
-  // already.  But we can only crash on abort_with_payload once, so that 
+  // This will overwrite the abort_with_payload information in the dictionary
+  // already.  But we can only crash on abort_with_payload once, so that
   // shouldn't matter.
   process->GetExtendedCrashInfoDict()->AddItem(info_key, abort_dict_sp);
 
diff --git a/lldb/source/Target/AssertFrameRecognizer.cpp b/lldb/source/Target/AssertFrameRecognizer.cpp
index da7c102645c014..00b1f54023f168 100644
--- a/lldb/source/Target/AssertFrameRecognizer.cpp
+++ b/lldb/source/Target/AssertFrameRecognizer.cpp
@@ -89,6 +89,7 @@ void RegisterAssertFrameRecognizer(Process *process) {
     target.GetFrameRecognizerManager().AddRecognizer(
         std::make_shared<AssertFrameRecognizer>(),
         location.module_spec.GetFilename(), location.symbols,
+        Mangled::ePreferDemangled,
         /*first_instruction_only*/ false);
     return;
   }
@@ -112,6 +113,7 @@ void RegisterAssertFrameRecognizer(Process *process) {
       std::make_shared<AssertFrameRecognizer>(),
       std::make_shared<RegularExpression>(std::move(module_re)),
       std::make_shared<RegularExpression>(std::move(symbol_re)),
+      Mangled::ePreferDemangled,
       /*first_instruction_only*/ false);
 }
 
diff --git a/lldb/source/Target/StackFrameRecognizer.cpp b/lldb/source/Target/StackFrameRecognizer.cpp
index 7c0dfde993948f..fa24253320a3f2 100644
--- a/lldb/source/Target/StackFrameRecognizer.cpp
+++ b/lldb/source/Target/StackFrameRecognizer.cpp
@@ -62,28 +62,29 @@ void StackFrameRecognizerManager::BumpGeneration() {
 
 void StackFrameRecognizerManager::AddRecognizer(
     StackFrameRecognizerSP recognizer, ConstString module,
-    llvm::ArrayRef<ConstString> symbols, bool first_instruction_only,
-    Mangled::NamePreference mangling_preference) {
+    llvm::ArrayRef<ConstString> symbols,
+    Mangled::NamePreference symbol_mangling, bool first_instruction_only) {
   m_recognizers.push_front({(uint32_t)m_recognizers.size(), recognizer, false,
                             module, RegularExpressionSP(), symbols,
-                            RegularExpressionSP(), first_instruction_only});
+                            RegularExpressionSP(), symbol_mangling,
+                            first_instruction_only});
   BumpGeneration();
 }
 
 void StackFrameRecognizerManager::AddRecognizer(
     StackFrameRecognizerSP recognizer, RegularExpressionSP module,
-    RegularExpressionSP symbol, bool first_instruction_only,
-    Mangled::NamePreference mangling_preference) {
+    RegularExpressionSP symbol, Mangled::NamePreference symbol_mangling,
+    bool first_instruction_only) {
   m_recognizers.push_front({(uint32_t)m_recognizers.size(), recognizer, true,
                             ConstString(), module, std::vector<ConstString>(),
-                            symbol, first_instruction_only,
-                            mangling_preference});
+                            symbol, symbol_mangling, first_instruction_only});
   BumpGeneration();
 }
 
 void StackFrameRecognizerManager::ForEach(
-    const std::function<void(uint32_t, std::string, std::string,
-                             llvm::ArrayRef<ConstString>, bool)> &callback) {
+    const std::function<
+        void(uint32_t, std::string, std::string, llvm::ArrayRef<ConstString>,
+             Mangled::NamePreference name_reference, bool)> &callback) {
   for (auto entry : m_recognizers) {
     if (entry.is_regexp) {
       std::string module_name;
@@ -95,11 +96,13 @@ void StackFrameRecognizerManager::ForEach(
         symbol_name = entry.symbol_regexp->GetText().str();
 
       callback(entry.recognizer_id, entry.recognizer->GetName(), module_name,
-               llvm::ArrayRef(ConstString(symbol_name)), true);
+               llvm::ArrayRef(ConstString(symbol_name)), entry.symbol_mangling,
+               true);
 
     } else {
       callback(entry.recognizer_id, entry.recognizer->GetName(),
-               entry.module.GetCString(), entry.symbols, false);
+               entry.module.GetCString(), entry.symbols, entry.symbol_mangling,
+               false);
     }
   }
 }
@@ -147,16 +150,7 @@ StackFrameRecognizerManager::GetRecognizerForFrame(StackFrameSP frame) {
       if (!entry.module_regexp->Execute(module_name.GetStringRef()))
         continue;
 
-    ConstString function_name = [&]() {
-      switch (entry.mangling_preference) {
-      case Mangled::ePreferMangled:
-        return symctx.GetFunctionName(entry.mangling_preference);
-      case Mangled::ePreferDemangled:
-        return symctx.GetFunctionName(entry.mangling_preference);
-      case Mangled::ePreferDemangledWithoutArguments:
-        return symctx.GetFunctionName(entry.mangling_preference);
-      }
-    }();
+    ConstString function_name = symctx.GetFunctionName(entry.symbol_mangling);
 
     if (!entry.symbols.empty())
       if (!llvm::is_contained(entry.symbols, function_name))
diff --git a/lldb/source/Target/VerboseTrapFrameRecognizer.cpp b/lldb/source/Target/VerboseTrapFrameRecognizer.cpp
index fe72c8aec570d3..de710fcda54064 100644
--- a/lldb/source/Target/VerboseTrapFrameRecognizer.cpp
+++ b/lldb/source/Target/VerboseTrapFrameRecognizer.cpp
@@ -116,7 +116,8 @@ void RegisterVerboseTrapFrameRecognizer(Process &process) {
       std::make_shared<VerboseTrapFrameRecognizer>();
 
   process.GetTarget().GetFrameRecognizerManager().AddRecognizer(
-      srf_recognizer_sp, module_regex_sp, symbol_regex_sp, false);
+      srf_recognizer_sp, module_regex_sp, symbol_regex_sp,
+      Mangled::ePreferDemangled, false);
 }
 
 } // namespace lldb_private
diff --git a/lldb/test/API/commands/frame/recognizer/TestFrameRecognizer.py b/lldb/test/API/commands/frame/recognizer/TestFrameRecognizer.py
index 6174ac61a709dd..e25df2b6cdc245 100644
--- a/lldb/test/API/commands/frame/recognizer/TestFrameRecognizer.py
+++ b/lldb/test/API/commands/frame/recognizer/TestFrameRecognizer.py
@@ -35,7 +35,9 @@ def test_frame_recognizer_1(self):
 
         self.expect(
             "frame recognizer list",
-            substrs=["0: recognizer.MyFrameRecognizer, module a.out, symbol foo"],
+            substrs=[
+                "0: recognizer.MyFrameRecognizer, module a.out, demangled symbol foo"
+            ],
         )
 
         self.runCmd(
@@ -45,8 +47,8 @@ def test_frame_recognizer_1(self):
         self.expect(
             "frame recognizer list",
             substrs=[
-                "1: recognizer.MyOtherFrameRecognizer, module a.out, symbol bar (regexp)",
-                "0: recognizer.MyFrameRecognizer, module a.out, symbol foo",
+                "1: recognizer.MyOtherFrameRecognizer, module a.out, demangled symbol regex bar",
+                "0: recognizer.MyFrameRecognizer, module a.out, demangled symbol foo",
             ],
         )
 
@@ -56,7 +58,7 @@ def test_frame_recognizer_1(self):
         self.expect(
             "frame recognizer list",
             substrs=[
-                "1: recognizer.MyOtherFrameRecognizer, module a.out, symbol bar (regexp)"
+                "1: recognizer.MyOtherFrameRecognizer, module a.out, demangled symbol bar (regexp)"
             ],
         )
         self.expect(
@@ -79,7 +81,7 @@ def test_frame_recognizer_1(self):
         self.expect(
             "frame recognizer list",
             substrs=[
-                "1: recognizer.MyOtherFrameRecognizer, module a.out, symbol bar (regexp)"
+                "1: recognizer.MyOtherFrameRecognizer, module a.out, demangled symbol regexp bar"
             ],
         )
         self.expect(
@@ -224,7 +226,7 @@ def test_frame_recognizer_multi_symbol(self):
         self.expect(
             "frame recognizer list",
             substrs=[
-                "recognizer.MyFrameRecognizer, module a.out, symbol foo, symbol bar"
+                "recognizer.MyFrameRecognizer, module a.out, demangled symbol foo, bar"
             ],
         )
 
@@ -279,7 +281,7 @@ def test_frame_recognizer_target_specific(self):
         self.expect(
             "frame recognizer list",
             substrs=[
-                "recognizer.MyFrameRecognizer, module a.out, symbol foo, symbol bar"
+                "recognizer.MyFrameRecognizer, module a.out, demangled symbol foo, bar"
             ],
         )
 
@@ -305,7 +307,9 @@ def test_frame_recognizer_target_specific(self):
 
         self.expect(
             "frame recognizer list",
-            substrs=["recognizer.MyFrameRecognizer, module a.out, symbol bar"],
+            substrs=[
+                "recognizer.MyFrameRecognizer, module a.out, demangled symbol bar"
+            ],
         )
 
         # Now the new target should also recognize the frame.
diff --git a/lldb/test/API/functionalities/completion/TestCompletion.py b/lldb/test/API/functionalities/completion/TestCompletion.py
index 95873405eab84e..bf19a990cf6e30 100644
--- a/lldb/test/API/functionalities/completion/TestCompletion.py
+++ b/lldb/test/API/functionalities/completion/TestCompletion.py
@@ -708,7 +708,7 @@ def test_frame_recognizer_delete(self):
         )
         self.check_completion_with_desc(
             "frame recognizer delete ",
-            [["0", "py_class, module module_name, symbol recognizer_name"]],
+            [["0", "py_class, module module_name, demangled symbol recognizer_name"]],
         )
 
     def test_platform_install_local_file(self):
diff --git a/lldb/test/API/lang/cpp/std-function-recognizer/TestStdFunctionRecognizer.py b/lldb/test/API/lang/cpp/std-function-recognizer/TestStdFunctionRecognizer.py
index fa7a4f379e92b4..d1cb8214d658ff 100644
--- a/lldb/test/API/lang/cpp/std-function-recognizer/TestStdFunctionRecognizer.py
+++ b/lldb/test/API/lang/cpp/std-function-recognizer/TestStdFunctionRecognizer.py
@@ -17,10 +17,15 @@ def test_frame_recognizer(self):
         self.assertIn("foo", thread.GetFrameAtIndex(0).GetFunctionName())
         # Skip all hidden frames
         frame_id = 1
-        while frame_id < thread.GetNumFrames() and thread.GetFrameAtIndex(frame_id).IsHidden():
+        while (
+            frame_id < thread.GetNumFrames()
+            and thread.GetFrameAtIndex(frame_id).IsHidden()
+        ):
             frame_id = frame_id + 1
         # Expect `std::function<...>::operator()` to be the direct parent of `foo`
-        self.assertIn("::operator()", thread.GetFrameAtIndex(frame_id).GetFunctionName())
+        self.assertIn(
+            "::operator()", thread.GetFrameAtIndex(frame_id).GetFunctionName()
+        )
         # And right above that, there should be the `main` frame
         self.assertIn("main", thread.GetFrameAtIndex(frame_id + 1).GetFunctionName())
 
diff --git a/lldb/test/API/lang/cpp/std-invoke-recognizer/TestStdInvokeRecognizer.py b/lldb/test/API/lang/cpp/std-invoke-recognizer/TestStdInvokeRecognizer.py
index ef75e1afd9cba5..e3112a6539e766 100644
--- a/lldb/test/API/lang/cpp/std-invoke-recognizer/TestStdInvokeRecognizer.py
+++ b/lldb/test/API/lang/cpp/std-invoke-recognizer/TestStdInvokeRecognizer.py
@@ -16,16 +16,28 @@ def test_frame_recognizer(self):
         )
 
         while process.GetState() != lldb.eStateExited:
-            self.assertTrue(any(f in thread.GetFrameAtIndex(0).GetFunctionName() for f in ["print_num", "add", "PrintAdder"]))
+            self.assertTrue(
+                any(
+                    f in thread.GetFrameAtIndex(0).GetFunctionName()
+                    for f in ["print_num", "add", "PrintAdder"]
+                )
+            )
             print(thread.GetFrameAtIndex(0).GetFunctionName())
             # Skip all hidden frames
             frame_id = 1
-            while frame_id < thread.GetNumFrames() and thread.GetFrameAtIndex(frame_id).IsHidden():
+            while (
+                frame_id < thread.GetNumFrames()
+                and thread.GetFrameAtIndex(frame_id).IsHidden()
+            ):
                 print(thread.GetFrameAtIndex(frame_id).GetFunctionName())
                 frame_id = frame_id + 1
             print(thread.GetFrameAtIndex(frame_id).GetFunctionName())
             # Expect `std::invoke` to be the direct parent
-            self.assertIn("::invoke", thread.GetFrameAtIndex(frame_id).GetFunctionName())
+            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())
+            self.assertIn(
+                "main", thread.GetFrameAtIndex(frame_id + 1).GetFunctionName()
+            )
             process.Continue()
diff --git a/lldb/unittests/Target/StackFrameRecognizerTest.cpp b/lldb/unittests/Target/StackFrameRecognizerTest.cpp
index 695f091227d6a0..df4458e3138c49 100644
--- a/lldb/unittests/Target/StackFrameRecognizerTest.cpp
+++ b/lldb/unittests/Target/StackFrameRecognizerTest.cpp
@@ -55,7 +55,7 @@ void RegisterDummyStackFrameRecognizer(StackFrameRecognizerManager &manager) {
   StackFrameRecognizerSP dummy_recognizer_sp(new DummyStackFrameRecognizer());
 
   manager.AddRecognizer(dummy_recognizer_sp, module_regex_sp, symbol_regex_sp,
-                        false);
+                        Mangled::NamePreference::ePreferDemangled, false);
 }
 
 } // namespace
@@ -72,6 +72,7 @@ TEST_F(StackFrameRecognizerTest, NullModuleRegex) {
   manager.ForEach([&any_printed](uint32_t recognizer_id, std::string name,
                                  std::string function,
                                  llvm::ArrayRef<ConstString> symbols,
+                                 Mangled::NamePreference symbol_mangling,
                                  bool regexp) { any_printed = true; });
 
   EXPECT_TRUE(any_printed);

>From 51eb02e978493f4f020a58b6ca68aaf95c7bb032 Mon Sep 17 00:00:00 2001
From: Adrian Vogelsgesang <avogelsgesang at salesforce.com>
Date: Mon, 26 Aug 2024 05:16:53 +0000
Subject: [PATCH 4/5] Fix libc++ ABI v2

---
 .../LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp     | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp
index a9204d9f8857df..089a8477c50317 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, 3> m_hidden_regex;
+  std::array<RegularExpression, 4> m_hidden_regex;
   RecognizedStackFrameSP m_hidden_frame;
 
   struct LibCXXHiddenFrame : public RecognizedStackFrame {
@@ -64,6 +64,13 @@ class LibCXXFrameRecognizer : public StackFrameRecognizer {
               R"(__function::.*::operator\(\))"
               R"((\[.*\])?)"    // ABI tag.
               R"(( const)?$)"}, // const.
+            // 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)"
+              R"((\[.*\])?)"  // ABI tag.
+              R"(<.*>)"},     // template argument.
             // internal implementation details of std::invoke
             //   std::__1::__invoke[abi:ne200000]<void (*&)()>
             RegularExpression{

>From 44059b8f58c1c6d3e711a11dc824c32743405df8 Mon Sep 17 00:00:00 2001
From: Adrian Vogelsgesang <avogelsgesang at salesforce.com>
Date: Mon, 26 Aug 2024 11:09:50 +0000
Subject: [PATCH 5/5] Address simple review comments

---
 .../MacOSX/AbortWithPayloadFrameRecognizer.cpp              | 6 +++---
 .../cpp/std-invoke-recognizer/TestStdInvokeRecognizer.py    | 5 +----
 2 files changed, 4 insertions(+), 7 deletions(-)

diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/AbortWithPayloadFrameRecognizer.cpp b/lldb/source/Plugins/SystemRuntime/MacOSX/AbortWithPayloadFrameRecognizer.cpp
index cd9260a27719ba..fd04db7807a4a0 100644
--- a/lldb/source/Plugins/SystemRuntime/MacOSX/AbortWithPayloadFrameRecognizer.cpp
+++ b/lldb/source/Plugins/SystemRuntime/MacOSX/AbortWithPayloadFrameRecognizer.cpp
@@ -56,7 +56,7 @@ AbortWithPayloadFrameRecognizer::RecognizeFrame(lldb::StackFrameSP frame_sp) {
   static constexpr llvm::StringLiteral info_key("abort_with_payload");
 
   Log *log = GetLog(LLDBLog::SystemRuntime);
-
+  
   if (!frame_sp) {
     LLDB_LOG(log, "abort_with_payload recognizer: invalid frame.");
     return {};
@@ -197,8 +197,8 @@ AbortWithPayloadFrameRecognizer::RecognizeFrame(lldb::StackFrameSP frame_sp) {
   abort_dict_sp->AddStringItem(reason_key, reason_string);
   abort_dict_sp->AddIntegerItem(flags_key, flags_val);
 
-  // This will overwrite the abort_with_payload information in the dictionary
-  // already.  But we can only crash on abort_with_payload once, so that
+  // This will overwrite the abort_with_payload information in the dictionary  
+  // already.  But we can only crash on abort_with_payload once, so that 
   // shouldn't matter.
   process->GetExtendedCrashInfoDict()->AddItem(info_key, abort_dict_sp);
 
diff --git a/lldb/test/API/lang/cpp/std-invoke-recognizer/TestStdInvokeRecognizer.py b/lldb/test/API/lang/cpp/std-invoke-recognizer/TestStdInvokeRecognizer.py
index e3112a6539e766..ddf3fb607d7786 100644
--- a/lldb/test/API/lang/cpp/std-invoke-recognizer/TestStdInvokeRecognizer.py
+++ b/lldb/test/API/lang/cpp/std-invoke-recognizer/TestStdInvokeRecognizer.py
@@ -9,7 +9,7 @@ class LibCxxStdFunctionRecognizerTestCase(TestBase):
 
     @add_test_categories(["libc++"])
     def test_frame_recognizer(self):
-        """Test that implementation details details of `std::invoke`"""
+        """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")
@@ -22,16 +22,13 @@ def test_frame_recognizer(self):
                     for f in ["print_num", "add", "PrintAdder"]
                 )
             )
-            print(thread.GetFrameAtIndex(0).GetFunctionName())
             # Skip all hidden frames
             frame_id = 1
             while (
                 frame_id < thread.GetNumFrames()
                 and thread.GetFrameAtIndex(frame_id).IsHidden()
             ):
-                print(thread.GetFrameAtIndex(frame_id).GetFunctionName())
                 frame_id = frame_id + 1
-            print(thread.GetFrameAtIndex(frame_id).GetFunctionName())
             # Expect `std::invoke` to be the direct parent
             self.assertIn(
                 "::invoke", thread.GetFrameAtIndex(frame_id).GetFunctionName()



More information about the lldb-commits mailing list