[Lldb-commits] [lldb] a4561d9 - [lldb][CPlusPlusLanguage] Respect the step-avoid-regex for functions with auto return types

Michael Buch via lldb-commits lldb-commits at lists.llvm.org
Mon Oct 10 04:50:43 PDT 2022


Author: Michael Buch
Date: 2022-10-10T12:50:15+01:00
New Revision: a4561d934877fbba5cfb3cac3195a41707ba6043

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

LOG: [lldb][CPlusPlusLanguage] Respect the step-avoid-regex for functions with auto return types

**Summary**

The primary motivation for this patch is to make sure we handle
the step-in behaviour for functions in the `std` namespace which
have an `auto` return type. Currently the default `step-avoid-regex`
setting is `^std::` but LLDB will still step into template functions
with `auto` return types in the `std` namespace.

**Details**
When we hit a breakpoint and check whether we should stop, we call
into `ThreadPlanStepInRange::FrameMatchesAvoidCriteria`. We then ask
for the frame function name via `SymbolContext::GetFunctionName(Mangled::ePreferDemangledWithoutArguments)`.
This ends up trying to parse the function name using `CPlusPlusLanguage::MethodName::GetBasename` which
parses the raw demangled name string.

`CPlusPlusNameParser::ParseFunctionImpl` calls `ConsumeTypename` to skip
the (in our case auto) return type of the demangled name (according to the
Itanium ABI this is a valid thing to encode into the mangled name). However,
`ConsumeTypename` doesn't strip out a plain `auto` identifier
(it will strip a `decltype(auto) return type though). So we are now left with
a basename that still has the return type in it, thus failing to match the `^std::`
regex.

Example frame where the return type is still part of the function name:
```
Process 1234 stopped
* thread #1, stop reason = step in
    frame #0: 0x12345678 repro`auto std::test_return_auto<int>() at main.cpp:12:5
   9
   10   template <class>
   11   auto test_return_auto() {
-> 12       return 42;
   13   }
```

This is another case where the `CPlusPlusNameParser` breaks us in subtle ways
due to evolving C++ syntax. There are longer-term plans of replacing the hand-rolled
C++ parser with an alternative that uses the mangle tree API to do the parsing for us.

**Testing**

* Added API and unit-tests
* Adding support for ABI tags into the parser is a larger undertaking
  which we would rather solve properly by using libcxxabi's mangle tree
  parser

Differential Revision: https://reviews.llvm.org/D135413

Added: 
    lldb/test/API/functionalities/step-avoids-regexp/Makefile
    lldb/test/API/functionalities/step-avoids-regexp/TestStepAvoidsRegexp.py
    lldb/test/API/functionalities/step-avoids-regexp/main.cpp

Modified: 
    lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp
    lldb/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp
index bc3b42a4ef07a..ac70226ca2a4d 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp
@@ -9,6 +9,7 @@
 #include "CPlusPlusNameParser.h"
 
 #include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/TokenKinds.h"
 #include "llvm/ADT/StringMap.h"
 #include "llvm/Support/Threading.h"
 
@@ -106,7 +107,7 @@ CPlusPlusNameParser::ParseFunctionImpl(bool expect_return_type) {
   Bookmark start_position = SetBookmark();
   if (expect_return_type) {
     // Consume return type if it's expected.
-    if (!ConsumeTypename())
+    if (!ConsumeToken(tok::kw_auto) && !ConsumeTypename())
       return None;
   }
 

diff  --git a/lldb/test/API/functionalities/step-avoids-regexp/Makefile b/lldb/test/API/functionalities/step-avoids-regexp/Makefile
new file mode 100644
index 0000000000000..4f79c0a900c3a
--- /dev/null
+++ b/lldb/test/API/functionalities/step-avoids-regexp/Makefile
@@ -0,0 +1,4 @@
+CXX_SOURCES := main.cpp
+CXXFLAGS_EXTRAS := -std=c++20
+
+include Makefile.rules

diff  --git a/lldb/test/API/functionalities/step-avoids-regexp/TestStepAvoidsRegexp.py b/lldb/test/API/functionalities/step-avoids-regexp/TestStepAvoidsRegexp.py
new file mode 100644
index 0000000000000..a3de53e3c4b91
--- /dev/null
+++ b/lldb/test/API/functionalities/step-avoids-regexp/TestStepAvoidsRegexp.py
@@ -0,0 +1,47 @@
+"""
+Test thread step-in ignores frames according to the "Avoid regexp" option.
+"""
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+class StepAvoidsRegexTestCase(TestBase):
+    def hit_correct_function(self, pattern):
+        name = self.thread.frames[0].GetFunctionName()
+        self.assertTrue(
+            pattern in name, "Got to '%s' not the expected function '%s'." %
+            (name, pattern))
+
+    def setUp(self):
+        TestBase.setUp(self)
+        self.dbg.HandleCommand(
+                "settings set target.process.thread.step-avoid-regexp ^ignore::")
+
+    def test_step_avoid_regex(self):
+        """Tests stepping into a function which matches the avoid regex"""
+        self.build()
+        (_, _, self.thread, _) = lldbutil.run_to_source_breakpoint(self, "main", lldb.SBFileSpec('main.cpp'))
+
+        # Try to step into ignore::auto_ret
+        self.thread.StepInto()
+        self.hit_correct_function("main")
+
+        # Try to step into ignore::with_tag
+        self.thread.StepInto()
+        self.hit_correct_function("main")
+
+        # Try to step into ignore::decltype_auto_ret
+        self.thread.StepInto()
+        self.hit_correct_function("main")
+
+    @expectedFailureAll(bugnumber="rdar://100645742")
+    def test_step_avoid_regex_abi_tagged_template(self):
+        """Tests stepping into an ABI tagged function that matches the avoid regex"""
+        self.build()
+        (_, _, self.thread, _) = lldbutil.run_to_source_breakpoint(self, "with_tag_template", lldb.SBFileSpec('main.cpp'))
+
+        # Try to step into ignore::with_tag_template
+        self.thread.StepInto()
+        self.hit_correct_function("main")

diff  --git a/lldb/test/API/functionalities/step-avoids-regexp/main.cpp b/lldb/test/API/functionalities/step-avoids-regexp/main.cpp
new file mode 100644
index 0000000000000..20671188bd58e
--- /dev/null
+++ b/lldb/test/API/functionalities/step-avoids-regexp/main.cpp
@@ -0,0 +1,16 @@
+namespace ignore {
+template <typename T> auto auto_ret(T x) { return 0; }
+[[gnu::abi_tag("test")]] int with_tag() { return 0; }
+template <typename T> [[gnu::abi_tag("test")]] int with_tag_template() {
+  return 0;
+}
+
+template <typename T> decltype(auto) decltype_auto_ret(T x) { return 0; }
+} // namespace ignore
+
+int main() {
+  auto v1 = ignore::auto_ret<int>(5);
+  auto v2 = ignore::with_tag();
+  auto v3 = ignore::decltype_auto_ret<int>(5);
+  auto v4 = ignore::with_tag_template<int>();
+}

diff  --git a/lldb/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp b/lldb/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp
index 8ec4b5492fa5c..9a7e9a792f5b9 100644
--- a/lldb/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp
+++ b/lldb/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp
@@ -65,8 +65,10 @@ TEST(CPlusPlusLanguage, MethodNameParsing) {
        "XX::(anonymous namespace)::anon_class::anon_func"},
 
       // Lambda
-      {"main::{lambda()#1}::operator()() const::{lambda()#1}::operator()() const",
-       "main::{lambda()#1}::operator()() const::{lambda()#1}", "operator()", "()", "const",
+      {"main::{lambda()#1}::operator()() const::{lambda()#1}::operator()() "
+       "const",
+       "main::{lambda()#1}::operator()() const::{lambda()#1}", "operator()",
+       "()", "const",
        "main::{lambda()#1}::operator()() const::{lambda()#1}::operator()"},
 
       // Function pointers
@@ -110,8 +112,15 @@ TEST(CPlusPlusLanguage, MethodNameParsing) {
        "f<A<operator<(X,Y)::Subclass>, sizeof(B)<sizeof(C)>", "()", "",
        "f<A<operator<(X,Y)::Subclass>, sizeof(B)<sizeof(C)>"},
       {"llvm::Optional<llvm::MCFixupKind>::operator*() const volatile &&",
-       "llvm::Optional<llvm::MCFixupKind>", "operator*", "()", "const volatile &&",
-       "llvm::Optional<llvm::MCFixupKind>::operator*"}};
+       "llvm::Optional<llvm::MCFixupKind>", "operator*", "()",
+       "const volatile &&", "llvm::Optional<llvm::MCFixupKind>::operator*"},
+
+      // auto return type
+      {"auto std::test_return_auto<int>() const", "std",
+       "test_return_auto<int>", "()", "const", "std::test_return_auto<int>"},
+      {"decltype(auto) std::test_return_auto<int>(int) const", "std",
+       "test_return_auto<int>", "(int)", "const",
+       "std::test_return_auto<int>"}};
 
   for (const auto &test : test_cases) {
     CPlusPlusLanguage::MethodName method(ConstString(test.input));


        


More information about the lldb-commits mailing list