mirror of
https://github.com/intel/llvm.git
synced 2026-01-19 09:31:59 +08:00
[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 <aprantl@apple.com>
This commit is contained in:
committed by
GitHub
parent
4baf29e81e
commit
dd060bdede
@@ -105,19 +105,30 @@ private:
|
||||
/// 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 @@ private:
|
||||
lldb::RegularExpressionSP module_regexp;
|
||||
std::vector<ConstString> symbols;
|
||||
lldb::RegularExpressionSP symbol_regexp;
|
||||
Mangled::NamePreference symbol_mangling;
|
||||
bool first_instruction_only;
|
||||
};
|
||||
|
||||
|
||||
@@ -168,8 +168,7 @@ protected:
|
||||
// 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 @@ protected:
|
||||
}
|
||||
};
|
||||
|
||||
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 @@ public:
|
||||
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 @@ protected:
|
||||
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();
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 @@ public:
|
||||
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_)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -35,7 +35,9 @@ class FrameRecognizerTestCase(TestBase):
|
||||
|
||||
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 @@ class FrameRecognizerTestCase(TestBase):
|
||||
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 @@ class FrameRecognizerTestCase(TestBase):
|
||||
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 @@ class FrameRecognizerTestCase(TestBase):
|
||||
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 @@ class FrameRecognizerTestCase(TestBase):
|
||||
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 @@ class FrameRecognizerTestCase(TestBase):
|
||||
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 @@ class FrameRecognizerTestCase(TestBase):
|
||||
|
||||
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.
|
||||
|
||||
@@ -708,7 +708,7 @@ class CommandLineCompletionTestCase(TestBase):
|
||||
)
|
||||
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):
|
||||
|
||||
@@ -7,6 +7,28 @@ from lldbsuite.test import lldbutil
|
||||
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 @@ class LibCxxStdFunctionRecognizerTestCase(TestBase):
|
||||
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++"])
|
||||
|
||||
5
lldb/test/API/lang/cpp/std-invoke-recognizer/Makefile
Normal file
5
lldb/test/API/lang/cpp/std-invoke-recognizer/Makefile
Normal file
@@ -0,0 +1,5 @@
|
||||
CXX_SOURCES := main.cpp
|
||||
USE_LIBCPP := 1
|
||||
CXXFLAGS_EXTRAS := -std=c++17
|
||||
|
||||
include Makefile.rules
|
||||
@@ -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)
|
||||
30
lldb/test/API/lang/cpp/std-invoke-recognizer/main.cpp
Normal file
30
lldb/test/API/lang/cpp/std-invoke-recognizer/main.cpp
Normal file
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user