@@ -35,7 +35,7 @@ static ValueObjectSP GetCoroFramePtrFromHandle(ValueObject &valobj) {
35
35
return ptr_sp;
36
36
}
37
37
38
- static Function *ExtractDestroyFunction (ValueObjectSP &frame_ptr_sp) {
38
+ static Function *ExtractFunction (ValueObjectSP &frame_ptr_sp, int offset ) {
39
39
lldb::TargetSP target_sp = frame_ptr_sp->GetTargetSP ();
40
40
lldb::ProcessSP process_sp = frame_ptr_sp->GetProcessSP ();
41
41
auto ptr_size = process_sp->GetAddressByteSize ();
@@ -47,24 +47,64 @@ static Function *ExtractDestroyFunction(ValueObjectSP &frame_ptr_sp) {
47
47
lldbassert (addr_type == AddressType::eAddressTypeLoad);
48
48
49
49
Status error;
50
- // The destroy pointer is the 2nd pointer inside the compiler-generated
51
- // `pair<resumePtr,destroyPtr>`.
52
- auto destroy_func_ptr_addr = frame_ptr_addr + ptr_size;
53
- lldb::addr_t destroy_func_addr =
54
- process_sp->ReadPointerFromMemory (destroy_func_ptr_addr, error);
50
+ auto func_ptr_addr = frame_ptr_addr + offset * ptr_size;
51
+ lldb::addr_t func_addr =
52
+ process_sp->ReadPointerFromMemory (func_ptr_addr, error);
55
53
if (error.Fail ())
56
54
return nullptr ;
57
55
58
- Address destroy_func_address ;
59
- if (!target_sp->ResolveLoadAddress (destroy_func_addr, destroy_func_address ))
56
+ Address func_address ;
57
+ if (!target_sp->ResolveLoadAddress (func_addr, func_address ))
60
58
return nullptr ;
61
59
62
- Function *destroy_func =
63
- destroy_func_address.CalculateSymbolContextFunction ();
64
- if (!destroy_func)
65
- return nullptr ;
60
+ return func_address.CalculateSymbolContextFunction ();
61
+ }
62
+
63
+ static Function *ExtractResumeFunction (ValueObjectSP &frame_ptr_sp) {
64
+ return ExtractFunction (frame_ptr_sp, 0 );
65
+ }
66
+
67
+ static Function *ExtractDestroyFunction (ValueObjectSP &frame_ptr_sp) {
68
+ return ExtractFunction (frame_ptr_sp, 1 );
69
+ }
70
+
71
+ static bool IsNoopCoroFunction (Function *f) {
72
+ if (!f)
73
+ return false ;
66
74
67
- return destroy_func;
75
+ // clang's `__builtin_coro_noop` gets lowered to
76
+ // `_NoopCoro_ResumeDestroy`. This is used by libc++
77
+ // on clang.
78
+ auto mangledName = f->GetMangled ().GetMangledName ();
79
+ if (mangledName == " __NoopCoro_ResumeDestroy" )
80
+ return true ;
81
+
82
+ // libc++ uses the following name as a fallback on
83
+ // compilers without `__builtin_coro_noop`.
84
+ auto name = f->GetNameNoArguments ();
85
+ static RegularExpression libcxxRegex (
86
+ " ^std::coroutine_handle<std::noop_coroutine_promise>::"
87
+ " __noop_coroutine_frame_ty_::__dummy_resume_destroy_func$" );
88
+ lldbassert (libcxxRegex.IsValid ());
89
+ if (libcxxRegex.Execute (name.GetStringRef ()))
90
+ return true ;
91
+ static RegularExpression libcxxRegexAbiNS (
92
+ " ^std::__[[:alnum:]]+::coroutine_handle<std::__[[:alnum:]]+::"
93
+ " noop_coroutine_promise>::__noop_coroutine_frame_ty_::"
94
+ " __dummy_resume_destroy_func$" );
95
+ lldbassert (libcxxRegexAbiNS.IsValid ());
96
+ if (libcxxRegexAbiNS.Execute (name.GetStringRef ()))
97
+ return true ;
98
+
99
+ // libstdc++ uses the following name on both gcc and clang.
100
+ static RegularExpression libstdcppRegex (
101
+ " ^std::__[[:alnum:]]+::coroutine_handle<std::__[[:alnum:]]+::"
102
+ " noop_coroutine_promise>::__frame::__dummy_resume_destroy$" );
103
+ lldbassert (libstdcppRegex.IsValid ());
104
+ if (libstdcppRegex.Execute (name.GetStringRef ()))
105
+ return true ;
106
+
107
+ return false ;
68
108
}
69
109
70
110
static CompilerType InferPromiseType (Function &destroy_func) {
@@ -113,9 +153,15 @@ bool lldb_private::formatters::StdlibCoroutineHandleSummaryProvider(
113
153
114
154
if (!ptr_sp->GetValueAsUnsigned (0 )) {
115
155
stream << " nullptr" ;
116
- } else {
117
- stream.Printf (" coro frame = 0x%" PRIx64, ptr_sp->GetValueAsUnsigned (0 ));
156
+ return true ;
118
157
}
158
+ if (IsNoopCoroFunction (ExtractResumeFunction (ptr_sp)) &&
159
+ IsNoopCoroFunction (ExtractDestroyFunction (ptr_sp))) {
160
+ stream << " noop_coroutine" ;
161
+ return true ;
162
+ }
163
+
164
+ stream.Printf (" coro frame = 0x%" PRIx64, ptr_sp->GetValueAsUnsigned (0 ));
119
165
return true ;
120
166
}
121
167
@@ -158,6 +204,14 @@ bool lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEnd::
158
204
if (!ptr_sp)
159
205
return false ;
160
206
207
+ Function *resume_func = ExtractResumeFunction (ptr_sp);
208
+ Function *destroy_func = ExtractDestroyFunction (ptr_sp);
209
+
210
+ if (IsNoopCoroFunction (resume_func) && IsNoopCoroFunction (destroy_func)) {
211
+ // For `std::noop_coroutine()`, we don't want to display any child nodes.
212
+ return false ;
213
+ }
214
+
161
215
// Get the `promise_type` from the template argument
162
216
CompilerType promise_type (
163
217
valobj_sp->GetCompilerType ().GetTypeTemplateArgument (0 ));
@@ -169,12 +223,10 @@ bool lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEnd::
169
223
auto ast_ctx = ts.dyn_cast_or_null <TypeSystemClang>();
170
224
if (!ast_ctx)
171
225
return false ;
172
- if (promise_type.IsVoidType ()) {
173
- if (Function *destroy_func = ExtractDestroyFunction (ptr_sp)) {
174
- if (CompilerType inferred_type = InferPromiseType (*destroy_func)) {
175
- // Copy the type over to the correct `TypeSystemClang` instance
176
- promise_type = m_ast_importer->CopyType (*ast_ctx, inferred_type);
177
- }
226
+ if (promise_type.IsVoidType () && destroy_func) {
227
+ if (CompilerType inferred_type = InferPromiseType (*destroy_func)) {
228
+ // Copy the type over to the correct `TypeSystemClang` instance
229
+ promise_type = m_ast_importer->CopyType (*ast_ctx, inferred_type);
178
230
}
179
231
}
180
232
0 commit comments