Skip to content

Commit dd060bd

Browse files
[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 <[email protected]>
1 parent 4baf29e commit dd060bd

File tree

16 files changed

+234
-63
lines changed

16 files changed

+234
-63
lines changed

lldb/include/lldb/Target/StackFrameRecognizer.h

+13-1
Original file line numberDiff line numberDiff line change
@@ -105,19 +105,30 @@ class ScriptedStackFrameRecognizer : public StackFrameRecognizer {
105105
/// Class that provides a registry of known stack frame recognizers.
106106
class StackFrameRecognizerManager {
107107
public:
108+
/// Add a new recognizer that triggers on a given symbol name.
109+
///
110+
/// \param symbol_mangling controls whether the symbol name should be
111+
/// compared to the mangled or demangled name.
108112
void AddRecognizer(lldb::StackFrameRecognizerSP recognizer,
109113
ConstString module, llvm::ArrayRef<ConstString> symbols,
114+
Mangled::NamePreference symbol_mangling,
110115
bool first_instruction_only = true);
111116

117+
/// Add a new recognizer that triggers on a symbol regex.
118+
///
119+
/// \param symbol_mangling controls whether the regex should apply
120+
/// to the mangled or demangled name.
112121
void AddRecognizer(lldb::StackFrameRecognizerSP recognizer,
113122
lldb::RegularExpressionSP module,
114123
lldb::RegularExpressionSP symbol,
124+
Mangled::NamePreference symbol_mangling,
115125
bool first_instruction_only = true);
116126

117127
void ForEach(std::function<
118128
void(uint32_t recognizer_id, std::string recognizer_name,
119129
std::string module, llvm::ArrayRef<ConstString> symbols,
120-
bool regexp)> const &callback);
130+
Mangled::NamePreference name_reference, bool regexp)> const
131+
&callback);
121132

122133
bool RemoveRecognizerWithID(uint32_t recognizer_id);
123134

@@ -142,6 +153,7 @@ class StackFrameRecognizerManager {
142153
lldb::RegularExpressionSP module_regexp;
143154
std::vector<ConstString> symbols;
144155
lldb::RegularExpressionSP symbol_regexp;
156+
Mangled::NamePreference symbol_mangling;
145157
bool first_instruction_only;
146158
};
147159

lldb/source/Commands/CommandObjectFrame.cpp

+44-24
Original file line numberDiff line numberDiff line change
@@ -168,8 +168,7 @@ class CommandObjectFrameDiagnose : public CommandObjectParsed {
168168
// We've already handled the case where the value object sp is null, so
169169
// this is just to make sure future changes don't skip that:
170170
assert(valobj_sp.get() && "Must have a valid ValueObject to print");
171-
ValueObjectPrinter printer(*valobj_sp, &result.GetOutputStream(),
172-
options);
171+
ValueObjectPrinter printer(*valobj_sp, &result.GetOutputStream(), options);
173172
if (llvm::Error error = printer.PrintValueObject())
174173
result.AppendError(toString(std::move(error)));
175174
}
@@ -899,13 +898,16 @@ void CommandObjectFrameRecognizerAdd::DoExecute(Args &command,
899898
auto func =
900899
RegularExpressionSP(new RegularExpression(m_options.m_symbols.front()));
901900
GetTarget().GetFrameRecognizerManager().AddRecognizer(
902-
recognizer_sp, module, func, m_options.m_first_instruction_only);
901+
recognizer_sp, module, func, Mangled::NamePreference::ePreferDemangled,
902+
m_options.m_first_instruction_only);
903903
} else {
904904
auto module = ConstString(m_options.m_module);
905905
std::vector<ConstString> symbols(m_options.m_symbols.begin(),
906906
m_options.m_symbols.end());
907907
GetTarget().GetFrameRecognizerManager().AddRecognizer(
908-
recognizer_sp, module, symbols, m_options.m_first_instruction_only);
908+
recognizer_sp, module, symbols,
909+
Mangled::NamePreference::ePreferDemangled,
910+
m_options.m_first_instruction_only);
909911
}
910912
#endif
911913

@@ -927,6 +929,34 @@ class CommandObjectFrameRecognizerClear : public CommandObjectParsed {
927929
}
928930
};
929931

932+
static void
933+
PrintRecognizerDetails(Stream &strm, const std::string &name,
934+
const std::string &module,
935+
llvm::ArrayRef<lldb_private::ConstString> symbols,
936+
Mangled::NamePreference symbol_mangling, bool regexp) {
937+
strm << name << ", ";
938+
939+
if (!module.empty())
940+
strm << "module " << module << ", ";
941+
942+
switch (symbol_mangling) {
943+
case Mangled::NamePreference ::ePreferMangled:
944+
strm << "mangled symbol ";
945+
break;
946+
case Mangled::NamePreference ::ePreferDemangled:
947+
strm << "demangled symbol ";
948+
break;
949+
case Mangled::NamePreference ::ePreferDemangledWithoutArguments:
950+
strm << "demangled (no args) symbol ";
951+
break;
952+
}
953+
954+
if (regexp)
955+
strm << "regex ";
956+
957+
llvm::interleaveComma(symbols, strm);
958+
}
959+
930960
class CommandObjectFrameRecognizerDelete : public CommandObjectParsed {
931961
public:
932962
CommandObjectFrameRecognizerDelete(CommandInterpreter &interpreter)
@@ -947,19 +977,13 @@ class CommandObjectFrameRecognizerDelete : public CommandObjectParsed {
947977
GetTarget().GetFrameRecognizerManager().ForEach(
948978
[&request](uint32_t rid, std::string rname, std::string module,
949979
llvm::ArrayRef<lldb_private::ConstString> symbols,
950-
bool regexp) {
980+
Mangled::NamePreference symbol_mangling, bool regexp) {
951981
StreamString strm;
952982
if (rname.empty())
953983
rname = "(internal)";
954984

955-
strm << rname;
956-
if (!module.empty())
957-
strm << ", module " << module;
958-
if (!symbols.empty())
959-
for (auto &symbol : symbols)
960-
strm << ", symbol " << symbol;
961-
if (regexp)
962-
strm << " (regexp)";
985+
PrintRecognizerDetails(strm, rname, module, symbols, symbol_mangling,
986+
regexp);
963987

964988
request.TryCompleteCurrentArg(std::to_string(rid), strm.GetString());
965989
});
@@ -1016,22 +1040,18 @@ class CommandObjectFrameRecognizerList : public CommandObjectParsed {
10161040
void DoExecute(Args &command, CommandReturnObject &result) override {
10171041
bool any_printed = false;
10181042
GetTarget().GetFrameRecognizerManager().ForEach(
1019-
[&result, &any_printed](
1020-
uint32_t recognizer_id, std::string name, std::string module,
1021-
llvm::ArrayRef<ConstString> symbols, bool regexp) {
1043+
[&result,
1044+
&any_printed](uint32_t recognizer_id, std::string name,
1045+
std::string module, llvm::ArrayRef<ConstString> symbols,
1046+
Mangled::NamePreference symbol_mangling, bool regexp) {
10221047
Stream &stream = result.GetOutputStream();
10231048

10241049
if (name.empty())
10251050
name = "(internal)";
10261051

1027-
stream << std::to_string(recognizer_id) << ": " << name;
1028-
if (!module.empty())
1029-
stream << ", module " << module;
1030-
if (!symbols.empty())
1031-
for (auto &symbol : symbols)
1032-
stream << ", symbol " << symbol;
1033-
if (regexp)
1034-
stream << " (regexp)";
1052+
stream << std::to_string(recognizer_id) << ": ";
1053+
PrintRecognizerDetails(stream, name, module, symbols, symbol_mangling,
1054+
regexp);
10351055

10361056
stream.EOL();
10371057
stream.Flush();

lldb/source/Commands/Options.td

+1-1
Original file line numberDiff line numberDiff line change
@@ -1049,7 +1049,7 @@ let Command = "thread backtrace" in {
10491049
def thread_backtrace_extended : Option<"extended", "e">, Group<1>,
10501050
Arg<"Boolean">, Desc<"Show the extended backtrace, if available">;
10511051
def thread_backtrace_unfiltered : Option<"unfiltered", "u">, Group<1>,
1052-
Desc<"Filter out frames according to installed frame recognizers">;
1052+
Desc<"Do not filter out frames according to installed frame recognizers">;
10531053
}
10541054

10551055
let Command = "thread step scope" in {

lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp

+34-12
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
//===----------------------------------------------------------------------===//
88

99
#include <cstring>
10+
#include <iostream>
1011

1112
#include <memory>
1213

@@ -44,7 +45,7 @@ char CPPLanguageRuntime::ID = 0;
4445
/// A frame recognizer that is installed to hide libc++ implementation
4546
/// details from the backtrace.
4647
class LibCXXFrameRecognizer : public StackFrameRecognizer {
47-
RegularExpression m_hidden_function_regex;
48+
std::array<RegularExpression, 4> m_hidden_regex;
4849
RecognizedStackFrameSP m_hidden_frame;
4950

5051
struct LibCXXHiddenFrame : public RecognizedStackFrame {
@@ -53,10 +54,30 @@ class LibCXXFrameRecognizer : public StackFrameRecognizer {
5354

5455
public:
5556
LibCXXFrameRecognizer()
56-
: m_hidden_function_regex(
57-
R"(^std::__.*::(__function.*::operator\(\)|__invoke))"
58-
R"((\[.*\])?)" // ABI tag.
59-
R"(( const)?$)"), // const.
57+
: m_hidden_regex{
58+
// internal implementation details of std::function
59+
// std::__1::__function::__alloc_func<void (*)(), std::__1::allocator<void (*)()>, void ()>::operator()[abi:ne200000]
60+
// std::__1::__function::__func<void (*)(), std::__1::allocator<void (*)()>, void ()>::operator()
61+
// std::__1::__function::__value_func<void ()>::operator()[abi:ne200000]() const
62+
RegularExpression{""
63+
R"(^std::__[^:]*::)" // Namespace.
64+
R"(__function::.*::operator\(\))"},
65+
// internal implementation details of std::function in ABI v2
66+
// std::__2::__function::__policy_invoker<void (int, int)>::__call_impl[abi:ne200000]<std::__2::__function::__default_alloc_func<int (*)(int, int), int (int, int)>>
67+
RegularExpression{""
68+
R"(^std::__[^:]*::)" // Namespace.
69+
R"(__function::.*::__call_impl)"},
70+
// internal implementation details of std::invoke
71+
// std::__1::__invoke[abi:ne200000]<void (*&)()>
72+
RegularExpression{
73+
R"(^std::__[^:]*::)" // Namespace.
74+
R"(__invoke)"},
75+
// internal implementation details of std::invoke
76+
// std::__1::__invoke_void_return_wrapper<void, true>::__call[abi:ne200000]<void (*&)()>
77+
RegularExpression{
78+
R"(^std::__[^:]*::)" // Namespace.
79+
R"(__invoke_void_return_wrapper<.*>::__call)"}
80+
},
6081
m_hidden_frame(new LibCXXHiddenFrame()) {}
6182

6283
std::string GetName() override { return "libc++ frame recognizer"; }
@@ -69,8 +90,9 @@ class LibCXXFrameRecognizer : public StackFrameRecognizer {
6990
if (!sc.function)
7091
return {};
7192

72-
if (m_hidden_function_regex.Execute(sc.function->GetNameNoArguments()))
73-
return m_hidden_frame;
93+
for (RegularExpression &r : m_hidden_regex)
94+
if (r.Execute(sc.function->GetNameNoArguments()))
95+
return m_hidden_frame;
7496

7597
return {};
7698
}
@@ -81,8 +103,9 @@ CPPLanguageRuntime::CPPLanguageRuntime(Process *process)
81103
if (process)
82104
process->GetTarget().GetFrameRecognizerManager().AddRecognizer(
83105
StackFrameRecognizerSP(new LibCXXFrameRecognizer()), {},
84-
std::make_shared<RegularExpression>("^std::__.*::"),
85-
/*first_instruction_only*/ false);
106+
std::make_shared<RegularExpression>("^std::__[^:]*::"),
107+
/*mangling_preference=*/Mangled::ePreferDemangledWithoutArguments,
108+
/*first_instruction_only=*/false);
86109
}
87110

88111
bool CPPLanguageRuntime::IsAllowedRuntimeValue(ConstString name) {
@@ -108,8 +131,7 @@ bool contains_lambda_identifier(llvm::StringRef &str_ref) {
108131

109132
CPPLanguageRuntime::LibCppStdFunctionCallableInfo
110133
line_entry_helper(Target &target, const SymbolContext &sc, Symbol *symbol,
111-
llvm::StringRef first_template_param_sref,
112-
bool has_invoke) {
134+
llvm::StringRef first_template_param_sref, bool has_invoke) {
113135

114136
CPPLanguageRuntime::LibCppStdFunctionCallableInfo optional_info;
115137

@@ -190,7 +212,7 @@ CPPLanguageRuntime::FindLibCppStdFunctionCallableInfo(
190212
ValueObjectSP sub_member_f_(member_f_->GetChildMemberWithName("__f_"));
191213

192214
if (sub_member_f_)
193-
member_f_ = sub_member_f_;
215+
member_f_ = sub_member_f_;
194216
}
195217

196218
if (!member_f_)

lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -3465,6 +3465,6 @@ static void RegisterObjCExceptionRecognizer(Process *process) {
34653465

34663466
process->GetTarget().GetFrameRecognizerManager().AddRecognizer(
34673467
StackFrameRecognizerSP(new ObjCExceptionThrowFrameRecognizer()),
3468-
module.GetFilename(), symbols,
3468+
module.GetFilename(), symbols, Mangled::NamePreference::ePreferDemangled,
34693469
/*first_instruction_only*/ true);
34703470
}

lldb/source/Plugins/SystemRuntime/MacOSX/AbortWithPayloadFrameRecognizer.cpp

+3-2
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,9 @@ void RegisterAbortWithPayloadFrameRecognizer(Process *process) {
3636
return;
3737

3838
process->GetTarget().GetFrameRecognizerManager().AddRecognizer(
39-
std::make_shared<AbortWithPayloadFrameRecognizer>(), module_name,
40-
sym_name, /*first_instruction_only*/ false);
39+
std::make_shared<AbortWithPayloadFrameRecognizer>(), module_name,
40+
sym_name, Mangled::NamePreference::ePreferDemangled,
41+
/*first_instruction_only*/ false);
4142
}
4243

4344
RecognizedStackFrameSP

lldb/source/Target/AssertFrameRecognizer.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ void RegisterAssertFrameRecognizer(Process *process) {
8989
target.GetFrameRecognizerManager().AddRecognizer(
9090
std::make_shared<AssertFrameRecognizer>(),
9191
location.module_spec.GetFilename(), location.symbols,
92+
Mangled::ePreferDemangled,
9293
/*first_instruction_only*/ false);
9394
return;
9495
}
@@ -112,6 +113,7 @@ void RegisterAssertFrameRecognizer(Process *process) {
112113
std::make_shared<AssertFrameRecognizer>(),
113114
std::make_shared<RegularExpression>(std::move(module_re)),
114115
std::make_shared<RegularExpression>(std::move(symbol_re)),
116+
Mangled::ePreferDemangled,
115117
/*first_instruction_only*/ false);
116118
}
117119

lldb/source/Target/StackFrameRecognizer.cpp

+16-9
Original file line numberDiff line numberDiff line change
@@ -62,25 +62,29 @@ void StackFrameRecognizerManager::BumpGeneration() {
6262

6363
void StackFrameRecognizerManager::AddRecognizer(
6464
StackFrameRecognizerSP recognizer, ConstString module,
65-
llvm::ArrayRef<ConstString> symbols, bool first_instruction_only) {
65+
llvm::ArrayRef<ConstString> symbols,
66+
Mangled::NamePreference symbol_mangling, bool first_instruction_only) {
6667
m_recognizers.push_front({(uint32_t)m_recognizers.size(), recognizer, false,
6768
module, RegularExpressionSP(), symbols,
68-
RegularExpressionSP(), first_instruction_only});
69+
RegularExpressionSP(), symbol_mangling,
70+
first_instruction_only});
6971
BumpGeneration();
7072
}
7173

7274
void StackFrameRecognizerManager::AddRecognizer(
7375
StackFrameRecognizerSP recognizer, RegularExpressionSP module,
74-
RegularExpressionSP symbol, bool first_instruction_only) {
76+
RegularExpressionSP symbol, Mangled::NamePreference symbol_mangling,
77+
bool first_instruction_only) {
7578
m_recognizers.push_front({(uint32_t)m_recognizers.size(), recognizer, true,
7679
ConstString(), module, std::vector<ConstString>(),
77-
symbol, first_instruction_only});
80+
symbol, symbol_mangling, first_instruction_only});
7881
BumpGeneration();
7982
}
8083

8184
void StackFrameRecognizerManager::ForEach(
82-
const std::function<void(uint32_t, std::string, std::string,
83-
llvm::ArrayRef<ConstString>, bool)> &callback) {
85+
const std::function<
86+
void(uint32_t, std::string, std::string, llvm::ArrayRef<ConstString>,
87+
Mangled::NamePreference name_reference, bool)> &callback) {
8488
for (auto entry : m_recognizers) {
8589
if (entry.is_regexp) {
8690
std::string module_name;
@@ -92,11 +96,13 @@ void StackFrameRecognizerManager::ForEach(
9296
symbol_name = entry.symbol_regexp->GetText().str();
9397

9498
callback(entry.recognizer_id, entry.recognizer->GetName(), module_name,
95-
llvm::ArrayRef(ConstString(symbol_name)), true);
99+
llvm::ArrayRef(ConstString(symbol_name)), entry.symbol_mangling,
100+
true);
96101

97102
} else {
98103
callback(entry.recognizer_id, entry.recognizer->GetName(),
99-
entry.module.GetCString(), entry.symbols, false);
104+
entry.module.GetCString(), entry.symbols, entry.symbol_mangling,
105+
false);
100106
}
101107
}
102108
}
@@ -125,7 +131,6 @@ StackFrameRecognizerSP
125131
StackFrameRecognizerManager::GetRecognizerForFrame(StackFrameSP frame) {
126132
const SymbolContext &symctx = frame->GetSymbolContext(
127133
eSymbolContextModule | eSymbolContextFunction | eSymbolContextSymbol);
128-
ConstString function_name = symctx.GetFunctionName();
129134
ModuleSP module_sp = symctx.module_sp;
130135
if (!module_sp)
131136
return StackFrameRecognizerSP();
@@ -145,6 +150,8 @@ StackFrameRecognizerManager::GetRecognizerForFrame(StackFrameSP frame) {
145150
if (!entry.module_regexp->Execute(module_name.GetStringRef()))
146151
continue;
147152

153+
ConstString function_name = symctx.GetFunctionName(entry.symbol_mangling);
154+
148155
if (!entry.symbols.empty())
149156
if (!llvm::is_contained(entry.symbols, function_name))
150157
continue;

lldb/source/Target/VerboseTrapFrameRecognizer.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,8 @@ void RegisterVerboseTrapFrameRecognizer(Process &process) {
116116
std::make_shared<VerboseTrapFrameRecognizer>();
117117

118118
process.GetTarget().GetFrameRecognizerManager().AddRecognizer(
119-
srf_recognizer_sp, module_regex_sp, symbol_regex_sp, false);
119+
srf_recognizer_sp, module_regex_sp, symbol_regex_sp,
120+
Mangled::ePreferDemangled, false);
120121
}
121122

122123
} // namespace lldb_private

0 commit comments

Comments
 (0)