Author: Adrian Vogelsgesang Date: 2024-08-27T19:15:42+02:00 New Revision: dd060bdede8edec18ad5ca122e15cc24a821e3fe
URL: https://github.com/llvm/llvm-project/commit/dd060bdede8edec18ad5ca122e15cc24a821e3fe DIFF: https://github.com/llvm/llvm-project/commit/dd060bdede8edec18ad5ca122e15cc24a821e3fe.diff LOG: [lldb] Add frame recognizers for libc++ `std::invoke` (#105695) 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 `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 to `AddRecognizer` for matching 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. Co-authored-by: Adrian Prantl <apra...@apple.com> Added: lldb/test/API/lang/cpp/std-invoke-recognizer/Makefile lldb/test/API/lang/cpp/std-invoke-recognizer/TestStdInvokeRecognizer.py lldb/test/API/lang/cpp/std-invoke-recognizer/main.cpp Modified: lldb/include/lldb/Target/StackFrameRecognizer.h lldb/source/Commands/CommandObjectFrame.cpp lldb/source/Commands/Options.td lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp lldb/source/Plugins/SystemRuntime/MacOSX/AbortWithPayloadFrameRecognizer.cpp lldb/source/Target/AssertFrameRecognizer.cpp lldb/source/Target/StackFrameRecognizer.cpp lldb/source/Target/VerboseTrapFrameRecognizer.cpp lldb/test/API/commands/frame/recognizer/TestFrameRecognizer.py lldb/test/API/functionalities/completion/TestCompletion.py lldb/test/API/lang/cpp/std-function-recognizer/TestStdFunctionRecognizer.py lldb/unittests/Target/StackFrameRecognizerTest.cpp Removed: ################################################################################ diff --git a/lldb/include/lldb/Target/StackFrameRecognizer.h b/lldb/include/lldb/Target/StackFrameRecognizer.h index 2f5c5caa6a4561..617b1617d404a1 100644 --- a/lldb/include/lldb/Target/StackFrameRecognizer.h +++ b/lldb/include/lldb/Target/StackFrameRecognizer.h @@ -105,19 +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, + 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, + 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); @@ -142,6 +153,7 @@ class StackFrameRecognizerManager { lldb::RegularExpressionSP module_regexp; std::vector<ConstString> symbols; lldb::RegularExpressionSP symbol_regexp; + Mangled::NamePreference symbol_mangling; bool first_instruction_only; }; 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/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..faa05e8f834ea1 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, 4> m_hidden_regex; RecognizedStackFrameSP m_hidden_frame; struct LibCXXHiddenFrame : public RecognizedStackFrame { @@ -53,10 +54,30 @@ 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\(\))"}, + // 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)"} + }, m_hidden_frame(new LibCXXHiddenFrame()) {} std::string GetName() override { return "libc++ frame recognizer"; } @@ -69,8 +90,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 +103,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::__[^:]*::"), + /*mangling_preference=*/Mangled::ePreferDemangledWithoutArguments, + /*first_instruction_only=*/false); } bool CPPLanguageRuntime::IsAllowedRuntimeValue(ConstString name) { @@ -108,8 +131,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 +212,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/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..fd04db7807a4a0 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 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 44411afc65dda9..fa24253320a3f2 100644 --- a/lldb/source/Target/StackFrameRecognizer.cpp +++ b/lldb/source/Target/StackFrameRecognizer.cpp @@ -62,25 +62,29 @@ void StackFrameRecognizerManager::BumpGeneration() { void StackFrameRecognizerManager::AddRecognizer( StackFrameRecognizerSP recognizer, ConstString module, - llvm::ArrayRef<ConstString> symbols, bool first_instruction_only) { + 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) { + 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}); + 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; @@ -92,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); } } } @@ -125,7 +131,6 @@ StackFrameRecognizerSP StackFrameRecognizerManager::GetRecognizerForFrame(StackFrameSP frame) { const SymbolContext &symctx = frame->GetSymbolContext( eSymbolContextModule | eSymbolContextFunction | eSymbolContextSymbol); - ConstString function_name = symctx.GetFunctionName(); ModuleSP module_sp = symctx.module_sp; if (!module_sp) return StackFrameRecognizerSP(); @@ -145,6 +150,8 @@ StackFrameRecognizerManager::GetRecognizerForFrame(StackFrameSP frame) { if (!entry.module_regexp->Execute(module_name.GetStringRef())) continue; + ConstString function_name = symctx.GetFunctionName(entry.symbol_mangling); + if (!entry.symbols.empty()) if (!llvm::is_contained(entry.symbols, function_name)) continue; 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 8d4b6bfe17166e..d1cb8214d658ff 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,28 @@ 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 +49,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..dbe29610bf7982 --- /dev/null +++ b/lldb/test/API/lang/cpp/std-invoke-recognizer/TestStdInvokeRecognizer.py @@ -0,0 +1,44 @@ +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 new file mode 100644 index 00000000000000..bafbbd28386e8b --- /dev/null +++ b/lldb/test/API/lang/cpp/std-invoke-recognizer/main.cpp @@ -0,0 +1,30 @@ +#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); +} 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); _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits