Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[lldb] Add frame recognizers for libc++ std::invoke #105695

Merged
merged 7 commits into from
Aug 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion lldb/include/lldb/Target/StackFrameRecognizer.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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;
};

Expand Down
68 changes: 44 additions & 24 deletions lldb/source/Commands/CommandObjectFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)));
}
Expand Down Expand Up @@ -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

Expand All @@ -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)
Expand All @@ -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());
});
Expand Down Expand Up @@ -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();
Expand Down
2 changes: 1 addition & 1 deletion lldb/source/Commands/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -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">;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can just push this as an NFC separately

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have direct push-access and piggy-backing it in this PR is less effort for me

}

let Command = "thread step scope" in {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//

#include <cstring>
#include <iostream>

#include <memory>

Expand Down Expand Up @@ -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 {
Expand All @@ -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
vogelsgesang marked this conversation as resolved.
Show resolved Hide resolved
// 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"; }
Expand All @@ -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 {};
}
Expand All @@ -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) {
Expand All @@ -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;

Expand Down Expand Up @@ -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_)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions lldb/source/Target/AssertFrameRecognizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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);
}

Expand Down
25 changes: 16 additions & 9 deletions lldb/source/Target/StackFrameRecognizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
}
}
}
Expand Down Expand Up @@ -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();
Expand All @@ -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;
Expand Down
3 changes: 2 additions & 1 deletion lldb/source/Target/VerboseTrapFrameRecognizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Loading
Loading