21
21
#include " lldb/Core/PluginManager.h"
22
22
#include " lldb/Core/UniqueCStringMap.h"
23
23
#include " lldb/Symbol/ClangASTContext.h"
24
+ #include " lldb/Symbol/CompileUnit.h"
24
25
#include " lldb/Target/ABI.h"
25
26
#include " lldb/Target/ExecutionContext.h"
26
27
#include " lldb/Target/RegisterContext.h"
27
28
#include " lldb/Target/SectionLoadList.h"
28
29
#include " lldb/Target/StackFrame.h"
29
30
#include " lldb/Target/ThreadPlanRunToAddress.h"
30
31
#include " lldb/Target/ThreadPlanStepInRange.h"
32
+ #include " lldb/Utility/Timer.h"
31
33
32
34
using namespace lldb ;
33
35
using namespace lldb_private ;
@@ -58,9 +60,53 @@ bool CPPLanguageRuntime::GetObjectDescription(
58
60
return false ;
59
61
}
60
62
63
+ bool contains_lambda_identifier (llvm::StringRef &str_ref) {
64
+ return str_ref.contains (" $_" ) || str_ref.contains (" 'lambda'" );
65
+ };
66
+
67
+ CPPLanguageRuntime::LibCppStdFunctionCallableInfo
68
+ line_entry_helper (Target &target, const SymbolContext &sc, Symbol *symbol,
69
+ llvm::StringRef first_template_param_sref,
70
+ bool has___invoke) {
71
+
72
+ CPPLanguageRuntime::LibCppStdFunctionCallableInfo optional_info;
73
+
74
+ AddressRange range;
75
+ sc.GetAddressRange (eSymbolContextEverything, 0 , false , range);
76
+
77
+ Address address = range.GetBaseAddress ();
78
+
79
+ Address addr;
80
+ if (target.ResolveLoadAddress (address.GetCallableLoadAddress (&target),
81
+ addr)) {
82
+ LineEntry line_entry;
83
+ addr.CalculateSymbolContextLineEntry (line_entry);
84
+
85
+ if (contains_lambda_identifier (first_template_param_sref) || has___invoke) {
86
+ // Case 1 and 2
87
+ optional_info.callable_case = lldb_private::CPPLanguageRuntime::
88
+ LibCppStdFunctionCallableCase::Lambda;
89
+ } else {
90
+ // Case 3
91
+ optional_info.callable_case = lldb_private::CPPLanguageRuntime::
92
+ LibCppStdFunctionCallableCase::CallableObject;
93
+ }
94
+
95
+ optional_info.callable_symbol = *symbol;
96
+ optional_info.callable_line_entry = line_entry;
97
+ optional_info.callable_address = addr;
98
+ }
99
+
100
+ return optional_info;
101
+ }
102
+
61
103
CPPLanguageRuntime::LibCppStdFunctionCallableInfo
62
104
CPPLanguageRuntime::FindLibCppStdFunctionCallableInfo (
63
105
lldb::ValueObjectSP &valobj_sp) {
106
+ static Timer::Category func_cat (LLVM_PRETTY_FUNCTION);
107
+ Timer scoped_timer (func_cat,
108
+ " CPPLanguageRuntime::FindLibCppStdFunctionCallableInfo" );
109
+
64
110
LibCppStdFunctionCallableInfo optional_info;
65
111
66
112
if (!valobj_sp)
@@ -93,7 +139,7 @@ CPPLanguageRuntime::FindLibCppStdFunctionCallableInfo(
93
139
// this entry and lookup operator()() and obtain the line table entry.
94
140
// 3) a callable object via operator()(). We will obtain the name of the
95
141
// object from the first template parameter from __func's vtable. We will
96
- // look up the objectc operator()() and obtain the line table entry.
142
+ // look up the objects operator()() and obtain the line table entry.
97
143
// 4) a member function. A pointer to the function will stored after the
98
144
// we will obtain the name from this pointer.
99
145
// 5) a free function. A pointer to the function will stored after the vtable
@@ -113,6 +159,9 @@ CPPLanguageRuntime::FindLibCppStdFunctionCallableInfo(
113
159
114
160
optional_info.member__f_pointer_value = member__f_pointer_value;
115
161
162
+ if (!member__f_pointer_value)
163
+ return optional_info;
164
+
116
165
ExecutionContext exe_ctx (valobj_sp->GetExecutionContextRef ());
117
166
Process *process = exe_ctx.GetProcessPtr ();
118
167
@@ -130,8 +179,14 @@ CPPLanguageRuntime::FindLibCppStdFunctionCallableInfo(
130
179
if (status.Fail ())
131
180
return optional_info;
132
181
182
+ lldb::addr_t vtable_address_first_entry =
183
+ process->ReadPointerFromMemory (vtable_address + address_size, status);
184
+
185
+ if (status.Fail ())
186
+ return optional_info;
187
+
133
188
lldb::addr_t address_after_vtable = member__f_pointer_value + address_size;
134
- // As commened above we may not have a function pointer but if we do we will
189
+ // As commented above we may not have a function pointer but if we do we will
135
190
// need it.
136
191
lldb::addr_t possible_function_address =
137
192
process->ReadPointerFromMemory (address_after_vtable, status);
@@ -144,9 +199,15 @@ CPPLanguageRuntime::FindLibCppStdFunctionCallableInfo(
144
199
if (target.GetSectionLoadList ().IsEmpty ())
145
200
return optional_info;
146
201
202
+ Address vtable_first_entry_resolved;
203
+
204
+ if (!target.GetSectionLoadList ().ResolveLoadAddress (
205
+ vtable_address_first_entry, vtable_first_entry_resolved))
206
+ return optional_info;
207
+
147
208
Address vtable_addr_resolved;
148
209
SymbolContext sc;
149
- Symbol *symbol;
210
+ Symbol *symbol = nullptr ;
150
211
151
212
if (!target.GetSectionLoadList ().ResolveLoadAddress (vtable_address,
152
213
vtable_addr_resolved))
@@ -159,7 +220,7 @@ CPPLanguageRuntime::FindLibCppStdFunctionCallableInfo(
159
220
if (symbol == nullptr )
160
221
return optional_info;
161
222
162
- llvm::StringRef vtable_name (symbol->GetName ().GetCString ());
223
+ llvm::StringRef vtable_name (symbol->GetName ().GetStringRef ());
163
224
bool found_expected_start_string =
164
225
vtable_name.startswith (" vtable for std::__1::__function::__func<" );
165
226
@@ -172,6 +233,11 @@ CPPLanguageRuntime::FindLibCppStdFunctionCallableInfo(
172
233
// ... __func<main::$_0, std::__1::allocator<main::$_0> ...
173
234
// ^^^^^^^^^
174
235
//
236
+ // We could see names such as:
237
+ // main::$_0
238
+ // Bar::add_num2(int)::'lambda'(int)
239
+ // Bar
240
+ //
175
241
// We do this by find the first < and , and extracting in between.
176
242
//
177
243
// This covers the case of the lambda known at compile time.
@@ -192,17 +258,29 @@ CPPLanguageRuntime::FindLibCppStdFunctionCallableInfo(
192
258
function_address_resolved, eSymbolContextEverything, sc);
193
259
symbol = sc.symbol ;
194
260
}
195
-
196
- auto contains_lambda_identifier = []( llvm::StringRef & str_ref ) {
197
- return str_ref.contains (" $_" ) || str_ref.contains (" 'lambda'" );
198
- };
261
+
262
+ // These conditions are used several times to simplify statements later on.
263
+ bool has___invoke =
264
+ (symbol ? symbol->GetName ().GetStringRef ().contains (" __invoke" ) : false );
265
+ auto calculate_symbol_context_helper = [](auto &t,
266
+ SymbolContextList &sc_list) {
267
+ SymbolContext sc;
268
+ t->CalculateSymbolContext (&sc);
269
+ sc_list.Append (sc);
270
+ };
271
+
272
+ // Case 2
273
+ if (has___invoke) {
274
+ SymbolContextList scl;
275
+ calculate_symbol_context_helper (symbol, scl);
276
+
277
+ return line_entry_helper (target, scl[0 ], symbol, first_template_parameter,
278
+ has___invoke);
279
+ }
199
280
200
281
// Case 4 or 5
201
- // We eliminate these cases early because they don't need the potentially
202
- // expensive lookup through the symbol table.
203
282
if (symbol && !symbol->GetName ().GetStringRef ().startswith (" vtable for" ) &&
204
- !contains_lambda_identifier (first_template_parameter) &&
205
- !symbol->GetName ().GetStringRef ().contains (" __invoke" )) {
283
+ !contains_lambda_identifier (first_template_parameter) && !has___invoke) {
206
284
optional_info.callable_case =
207
285
LibCppStdFunctionCallableCase::FreeOrMemberFunction;
208
286
optional_info.callable_address = function_address_resolved;
@@ -211,83 +289,48 @@ CPPLanguageRuntime::FindLibCppStdFunctionCallableInfo(
211
289
return optional_info;
212
290
}
213
291
214
- auto get_name = [&first_template_parameter, &symbol, contains_lambda_identifier]() {
215
- // Given case 1:
216
- //
217
- // main::$_0
218
- // Bar::add_num2(int)::'lambda'(int)
219
- //
220
- // we want to append ::operator()()
221
- if (contains_lambda_identifier (first_template_parameter))
222
- return llvm::Regex::escape (first_template_parameter.str ()) +
223
- R"( ::operator\(\)\(.*\))" ;
224
-
225
- if (symbol != nullptr &&
226
- symbol->GetName ().GetStringRef ().contains (" __invoke" )) {
227
-
228
- llvm::StringRef symbol_name = symbol->GetName ().GetStringRef ();
229
- size_t pos2 = symbol_name.find_last_of (' :' );
230
-
231
- // Given case 2:
232
- //
233
- // main::$_1::__invoke(...)
234
- //
235
- // We want to slice off __invoke(...) and append operator()()
236
- std::string lambda_operator =
237
- llvm::Regex::escape (symbol_name.slice (0 , pos2 + 1 ).str ()) +
238
- R"( operator\(\)\(.*\))" ;
239
-
240
- return lambda_operator;
241
- }
242
-
243
- // Case 3
244
- return first_template_parameter.str () + R"( ::operator\(\)\(.*\))" ;
245
- ;
246
- };
247
-
248
- std::string func_to_match = get_name ();
292
+ std::string func_to_match = first_template_parameter.str ();
249
293
250
294
auto it = CallableLookupCache.find (func_to_match);
251
295
if (it != CallableLookupCache.end ())
252
296
return it->second ;
253
297
254
298
SymbolContextList scl;
255
299
256
- target.GetImages ().FindSymbolsMatchingRegExAndType (
257
- RegularExpression{R"( ^)" + func_to_match}, eSymbolTypeAny, scl);
300
+ CompileUnit *vtable_cu =
301
+ vtable_first_entry_resolved.CalculateSymbolContextCompileUnit ();
302
+ llvm::StringRef name_to_use = func_to_match;
258
303
259
- // Case 1,2 or 3
260
- if (scl.GetSize () >= 1 ) {
261
- SymbolContext sc2 = scl[0 ];
262
-
263
- AddressRange range;
264
- sc2.GetAddressRange (eSymbolContextEverything, 0 , false , range);
265
-
266
- Address address = range.GetBaseAddress ();
267
-
268
- Address addr;
269
- if (target.ResolveLoadAddress (address.GetCallableLoadAddress (&target),
270
- addr)) {
271
- LineEntry line_entry;
272
- addr.CalculateSymbolContextLineEntry (line_entry);
273
-
274
- if (contains_lambda_identifier (first_template_parameter) ||
275
- (symbol != nullptr &&
276
- symbol->GetName ().GetStringRef ().contains (" __invoke" ))) {
277
- // Case 1 and 2
278
- optional_info.callable_case = LibCppStdFunctionCallableCase::Lambda;
279
- } else {
280
- // Case 3
281
- optional_info.callable_case =
282
- LibCppStdFunctionCallableCase::CallableObject;
283
- }
284
-
285
- optional_info.callable_symbol = *symbol;
286
- optional_info.callable_line_entry = line_entry;
287
- optional_info.callable_address = addr;
304
+ // Case 3, we have a callable object instead of a lambda
305
+ //
306
+ // TODO
307
+ // We currently don't support this case a callable object may have multiple
308
+ // operator()() varying on const/non-const and number of arguments and we
309
+ // don't have a way to currently distinguish them so we will bail out now.
310
+ if (!contains_lambda_identifier (name_to_use))
311
+ return optional_info;
312
+
313
+ if (vtable_cu && !has___invoke) {
314
+ lldb::FunctionSP func_sp =
315
+ vtable_cu->FindFunction ([name_to_use](const FunctionSP &f) {
316
+ auto name = f->GetName ().GetStringRef ();
317
+ if (name.startswith (name_to_use) && name.contains (" operator" ))
318
+ return true ;
319
+
320
+ return false ;
321
+ });
322
+
323
+ if (func_sp) {
324
+ calculate_symbol_context_helper (func_sp, scl);
288
325
}
289
326
}
290
327
328
+ // Case 1 or 3
329
+ if (scl.GetSize () >= 1 ) {
330
+ optional_info = line_entry_helper (target, scl[0 ], symbol,
331
+ first_template_parameter, has___invoke);
332
+ }
333
+
291
334
CallableLookupCache[func_to_match] = optional_info;
292
335
293
336
return optional_info;
0 commit comments