1 | //===-- CPPLanguageRuntime.cpp---------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include <cstring> |
10 | |
11 | #include <memory> |
12 | |
13 | #include "CPPLanguageRuntime.h" |
14 | |
15 | #include "llvm/ADT/StringRef.h" |
16 | |
17 | #include "lldb/Symbol/Block.h" |
18 | #include "lldb/Symbol/Variable.h" |
19 | #include "lldb/Symbol/VariableList.h" |
20 | |
21 | #include "lldb/Core/PluginManager.h" |
22 | #include "lldb/Core/UniqueCStringMap.h" |
23 | #include "lldb/Symbol/CompileUnit.h" |
24 | #include "lldb/Target/ABI.h" |
25 | #include "lldb/Target/ExecutionContext.h" |
26 | #include "lldb/Target/RegisterContext.h" |
27 | #include "lldb/Target/SectionLoadList.h" |
28 | #include "lldb/Target/StackFrame.h" |
29 | #include "lldb/Target/ThreadPlanRunToAddress.h" |
30 | #include "lldb/Target/ThreadPlanStepInRange.h" |
31 | #include "lldb/Utility/Timer.h" |
32 | |
33 | using namespace lldb; |
34 | using namespace lldb_private; |
35 | |
36 | static ConstString g_this = ConstString("this" ); |
37 | // Artificial coroutine-related variables emitted by clang. |
38 | static ConstString g_promise = ConstString("__promise" ); |
39 | static ConstString g_coro_frame = ConstString("__coro_frame" ); |
40 | |
41 | char CPPLanguageRuntime::ID = 0; |
42 | |
43 | CPPLanguageRuntime::CPPLanguageRuntime(Process *process) |
44 | : LanguageRuntime(process) {} |
45 | |
46 | bool CPPLanguageRuntime::IsAllowedRuntimeValue(ConstString name) { |
47 | return name == g_this || name == g_promise || name == g_coro_frame; |
48 | } |
49 | |
50 | bool CPPLanguageRuntime::GetObjectDescription(Stream &str, |
51 | ValueObject &object) { |
52 | // C++ has no generic way to do this. |
53 | return false; |
54 | } |
55 | |
56 | bool CPPLanguageRuntime::GetObjectDescription( |
57 | Stream &str, Value &value, ExecutionContextScope *exe_scope) { |
58 | // C++ has no generic way to do this. |
59 | return false; |
60 | } |
61 | |
62 | bool contains_lambda_identifier(llvm::StringRef &str_ref) { |
63 | return str_ref.contains(Other: "$_" ) || str_ref.contains(Other: "'lambda'" ); |
64 | } |
65 | |
66 | CPPLanguageRuntime::LibCppStdFunctionCallableInfo |
67 | line_entry_helper(Target &target, const SymbolContext &sc, Symbol *symbol, |
68 | llvm::StringRef first_template_param_sref, |
69 | bool has_invoke) { |
70 | |
71 | CPPLanguageRuntime::LibCppStdFunctionCallableInfo optional_info; |
72 | |
73 | AddressRange range; |
74 | sc.GetAddressRange(scope: eSymbolContextEverything, range_idx: 0, use_inline_block_range: false, range); |
75 | |
76 | Address address = range.GetBaseAddress(); |
77 | |
78 | Address addr; |
79 | if (target.ResolveLoadAddress(load_addr: address.GetCallableLoadAddress(target: &target), |
80 | so_addr&: addr)) { |
81 | LineEntry line_entry; |
82 | addr.CalculateSymbolContextLineEntry(line_entry); |
83 | |
84 | if (contains_lambda_identifier(str_ref&: first_template_param_sref) || has_invoke) { |
85 | // Case 1 and 2 |
86 | optional_info.callable_case = lldb_private::CPPLanguageRuntime:: |
87 | LibCppStdFunctionCallableCase::Lambda; |
88 | } else { |
89 | // Case 3 |
90 | optional_info.callable_case = lldb_private::CPPLanguageRuntime:: |
91 | LibCppStdFunctionCallableCase::CallableObject; |
92 | } |
93 | |
94 | optional_info.callable_symbol = *symbol; |
95 | optional_info.callable_line_entry = line_entry; |
96 | optional_info.callable_address = addr; |
97 | } |
98 | |
99 | return optional_info; |
100 | } |
101 | |
102 | CPPLanguageRuntime::LibCppStdFunctionCallableInfo |
103 | CPPLanguageRuntime::FindLibCppStdFunctionCallableInfo( |
104 | lldb::ValueObjectSP &valobj_sp) { |
105 | LLDB_SCOPED_TIMER(); |
106 | |
107 | LibCppStdFunctionCallableInfo optional_info; |
108 | |
109 | if (!valobj_sp) |
110 | return optional_info; |
111 | |
112 | // Member __f_ has type __base*, the contents of which will hold: |
113 | // 1) a vtable entry which may hold type information needed to discover the |
114 | // lambda being called |
115 | // 2) possibly hold a pointer to the callable object |
116 | // e.g. |
117 | // |
118 | // (lldb) frame var -R f_display |
119 | // (std::__1::function<void (int)>) f_display = { |
120 | // __buf_ = { |
121 | // … |
122 | // } |
123 | // __f_ = 0x00007ffeefbffa00 |
124 | // } |
125 | // (lldb) memory read -fA 0x00007ffeefbffa00 |
126 | // 0x7ffeefbffa00: ... `vtable for std::__1::__function::__func<void (*) ... |
127 | // 0x7ffeefbffa08: ... `print_num(int) at std_function_cppreference_exam ... |
128 | // |
129 | // We will be handling five cases below, std::function is wrapping: |
130 | // |
131 | // 1) a lambda we know at compile time. We will obtain the name of the lambda |
132 | // from the first template pameter from __func's vtable. We will look up |
133 | // the lambda's operator()() and obtain the line table entry. |
134 | // 2) a lambda we know at runtime. A pointer to the lambdas __invoke method |
135 | // will be stored after the vtable. We will obtain the lambdas name from |
136 | // this entry and lookup operator()() and obtain the line table entry. |
137 | // 3) a callable object via operator()(). We will obtain the name of the |
138 | // object from the first template parameter from __func's vtable. We will |
139 | // look up the objects operator()() and obtain the line table entry. |
140 | // 4) a member function. A pointer to the function will stored after the |
141 | // we will obtain the name from this pointer. |
142 | // 5) a free function. A pointer to the function will stored after the vtable |
143 | // we will obtain the name from this pointer. |
144 | ValueObjectSP member_f_(valobj_sp->GetChildMemberWithName(name: "__f_" )); |
145 | |
146 | if (member_f_) { |
147 | ValueObjectSP sub_member_f_(member_f_->GetChildMemberWithName(name: "__f_" )); |
148 | |
149 | if (sub_member_f_) |
150 | member_f_ = sub_member_f_; |
151 | } |
152 | |
153 | if (!member_f_) |
154 | return optional_info; |
155 | |
156 | lldb::addr_t member_f_pointer_value = member_f_->GetValueAsUnsigned(fail_value: 0); |
157 | |
158 | optional_info.member_f_pointer_value = member_f_pointer_value; |
159 | |
160 | if (!member_f_pointer_value) |
161 | return optional_info; |
162 | |
163 | ExecutionContext exe_ctx(valobj_sp->GetExecutionContextRef()); |
164 | Process *process = exe_ctx.GetProcessPtr(); |
165 | |
166 | if (process == nullptr) |
167 | return optional_info; |
168 | |
169 | uint32_t address_size = process->GetAddressByteSize(); |
170 | Status status; |
171 | |
172 | // First item pointed to by __f_ should be the pointer to the vtable for |
173 | // a __base object. |
174 | lldb::addr_t vtable_address = |
175 | process->ReadPointerFromMemory(vm_addr: member_f_pointer_value, error&: status); |
176 | |
177 | if (status.Fail()) |
178 | return optional_info; |
179 | |
180 | lldb::addr_t vtable_address_first_entry = |
181 | process->ReadPointerFromMemory(vm_addr: vtable_address + address_size, error&: status); |
182 | |
183 | if (status.Fail()) |
184 | return optional_info; |
185 | |
186 | lldb::addr_t address_after_vtable = member_f_pointer_value + address_size; |
187 | // As commented above we may not have a function pointer but if we do we will |
188 | // need it. |
189 | lldb::addr_t possible_function_address = |
190 | process->ReadPointerFromMemory(vm_addr: address_after_vtable, error&: status); |
191 | |
192 | if (status.Fail()) |
193 | return optional_info; |
194 | |
195 | Target &target = process->GetTarget(); |
196 | |
197 | if (target.GetSectionLoadList().IsEmpty()) |
198 | return optional_info; |
199 | |
200 | Address vtable_first_entry_resolved; |
201 | |
202 | if (!target.GetSectionLoadList().ResolveLoadAddress( |
203 | load_addr: vtable_address_first_entry, so_addr&: vtable_first_entry_resolved)) |
204 | return optional_info; |
205 | |
206 | Address vtable_addr_resolved; |
207 | SymbolContext sc; |
208 | Symbol *symbol = nullptr; |
209 | |
210 | if (!target.GetSectionLoadList().ResolveLoadAddress(load_addr: vtable_address, |
211 | so_addr&: vtable_addr_resolved)) |
212 | return optional_info; |
213 | |
214 | target.GetImages().ResolveSymbolContextForAddress( |
215 | so_addr: vtable_addr_resolved, resolve_scope: eSymbolContextEverything, sc); |
216 | symbol = sc.symbol; |
217 | |
218 | if (symbol == nullptr) |
219 | return optional_info; |
220 | |
221 | llvm::StringRef vtable_name(symbol->GetName().GetStringRef()); |
222 | bool found_expected_start_string = |
223 | vtable_name.starts_with(Prefix: "vtable for std::__1::__function::__func<" ); |
224 | |
225 | if (!found_expected_start_string) |
226 | return optional_info; |
227 | |
228 | // Given case 1 or 3 we have a vtable name, we are want to extract the first |
229 | // template parameter |
230 | // |
231 | // ... __func<main::$_0, std::__1::allocator<main::$_0> ... |
232 | // ^^^^^^^^^ |
233 | // |
234 | // We could see names such as: |
235 | // main::$_0 |
236 | // Bar::add_num2(int)::'lambda'(int) |
237 | // Bar |
238 | // |
239 | // We do this by find the first < and , and extracting in between. |
240 | // |
241 | // This covers the case of the lambda known at compile time. |
242 | size_t first_open_angle_bracket = vtable_name.find(C: '<') + 1; |
243 | size_t first_comma = vtable_name.find(C: ','); |
244 | |
245 | llvm::StringRef first_template_parameter = |
246 | vtable_name.slice(Start: first_open_angle_bracket, End: first_comma); |
247 | |
248 | Address function_address_resolved; |
249 | |
250 | // Setup for cases 2, 4 and 5 we have a pointer to a function after the |
251 | // vtable. We will use a process of elimination to drop through each case |
252 | // and obtain the data we need. |
253 | if (target.GetSectionLoadList().ResolveLoadAddress( |
254 | load_addr: possible_function_address, so_addr&: function_address_resolved)) { |
255 | target.GetImages().ResolveSymbolContextForAddress( |
256 | so_addr: function_address_resolved, resolve_scope: eSymbolContextEverything, sc); |
257 | symbol = sc.symbol; |
258 | } |
259 | |
260 | // These conditions are used several times to simplify statements later on. |
261 | bool has_invoke = |
262 | (symbol ? symbol->GetName().GetStringRef().contains(Other: "__invoke" ) : false); |
263 | auto calculate_symbol_context_helper = [](auto &t, |
264 | SymbolContextList &sc_list) { |
265 | SymbolContext sc; |
266 | t->CalculateSymbolContext(&sc); |
267 | sc_list.Append(sc); |
268 | }; |
269 | |
270 | // Case 2 |
271 | if (has_invoke) { |
272 | SymbolContextList scl; |
273 | calculate_symbol_context_helper(symbol, scl); |
274 | |
275 | return line_entry_helper(target, sc: scl[0], symbol, first_template_param_sref: first_template_parameter, |
276 | has_invoke); |
277 | } |
278 | |
279 | // Case 4 or 5 |
280 | if (symbol && !symbol->GetName().GetStringRef().starts_with(Prefix: "vtable for" ) && |
281 | !contains_lambda_identifier(str_ref&: first_template_parameter) && !has_invoke) { |
282 | optional_info.callable_case = |
283 | LibCppStdFunctionCallableCase::FreeOrMemberFunction; |
284 | optional_info.callable_address = function_address_resolved; |
285 | optional_info.callable_symbol = *symbol; |
286 | |
287 | return optional_info; |
288 | } |
289 | |
290 | std::string func_to_match = first_template_parameter.str(); |
291 | |
292 | auto it = CallableLookupCache.find(Key: func_to_match); |
293 | if (it != CallableLookupCache.end()) |
294 | return it->second; |
295 | |
296 | SymbolContextList scl; |
297 | |
298 | CompileUnit *vtable_cu = |
299 | vtable_first_entry_resolved.CalculateSymbolContextCompileUnit(); |
300 | llvm::StringRef name_to_use = func_to_match; |
301 | |
302 | // Case 3, we have a callable object instead of a lambda |
303 | // |
304 | // TODO |
305 | // We currently don't support this case a callable object may have multiple |
306 | // operator()() varying on const/non-const and number of arguments and we |
307 | // don't have a way to currently distinguish them so we will bail out now. |
308 | if (!contains_lambda_identifier(str_ref&: name_to_use)) |
309 | return optional_info; |
310 | |
311 | if (vtable_cu && !has_invoke) { |
312 | lldb::FunctionSP func_sp = |
313 | vtable_cu->FindFunction(matching_lambda: [name_to_use](const FunctionSP &f) { |
314 | auto name = f->GetName().GetStringRef(); |
315 | if (name.starts_with(Prefix: name_to_use) && name.contains(Other: "operator" )) |
316 | return true; |
317 | |
318 | return false; |
319 | }); |
320 | |
321 | if (func_sp) { |
322 | calculate_symbol_context_helper(func_sp, scl); |
323 | } |
324 | } |
325 | |
326 | if (symbol == nullptr) |
327 | return optional_info; |
328 | |
329 | // Case 1 or 3 |
330 | if (scl.GetSize() >= 1) { |
331 | optional_info = line_entry_helper(target, sc: scl[0], symbol, |
332 | first_template_param_sref: first_template_parameter, has_invoke); |
333 | } |
334 | |
335 | CallableLookupCache[func_to_match] = optional_info; |
336 | |
337 | return optional_info; |
338 | } |
339 | |
340 | lldb::ThreadPlanSP |
341 | CPPLanguageRuntime::GetStepThroughTrampolinePlan(Thread &thread, |
342 | bool stop_others) { |
343 | ThreadPlanSP ret_plan_sp; |
344 | |
345 | lldb::addr_t curr_pc = thread.GetRegisterContext()->GetPC(); |
346 | |
347 | TargetSP target_sp(thread.CalculateTarget()); |
348 | |
349 | if (target_sp->GetSectionLoadList().IsEmpty()) |
350 | return ret_plan_sp; |
351 | |
352 | Address pc_addr_resolved; |
353 | SymbolContext sc; |
354 | Symbol *symbol; |
355 | |
356 | if (!target_sp->GetSectionLoadList().ResolveLoadAddress(load_addr: curr_pc, |
357 | so_addr&: pc_addr_resolved)) |
358 | return ret_plan_sp; |
359 | |
360 | target_sp->GetImages().ResolveSymbolContextForAddress( |
361 | so_addr: pc_addr_resolved, resolve_scope: eSymbolContextEverything, sc); |
362 | symbol = sc.symbol; |
363 | |
364 | if (symbol == nullptr) |
365 | return ret_plan_sp; |
366 | |
367 | llvm::StringRef function_name(symbol->GetName().GetCString()); |
368 | |
369 | // Handling the case where we are attempting to step into std::function. |
370 | // The behavior will be that we will attempt to obtain the wrapped |
371 | // callable via FindLibCppStdFunctionCallableInfo() and if we find it we |
372 | // will return a ThreadPlanRunToAddress to the callable. Therefore we will |
373 | // step into the wrapped callable. |
374 | // |
375 | bool found_expected_start_string = |
376 | function_name.starts_with(Prefix: "std::__1::function<" ); |
377 | |
378 | if (!found_expected_start_string) |
379 | return ret_plan_sp; |
380 | |
381 | AddressRange range_of_curr_func; |
382 | sc.GetAddressRange(scope: eSymbolContextEverything, range_idx: 0, use_inline_block_range: false, range&: range_of_curr_func); |
383 | |
384 | StackFrameSP frame = thread.GetStackFrameAtIndex(idx: 0); |
385 | |
386 | if (frame) { |
387 | ValueObjectSP value_sp = frame->FindVariable(name: g_this); |
388 | |
389 | CPPLanguageRuntime::LibCppStdFunctionCallableInfo callable_info = |
390 | FindLibCppStdFunctionCallableInfo(valobj_sp&: value_sp); |
391 | |
392 | if (callable_info.callable_case != LibCppStdFunctionCallableCase::Invalid && |
393 | value_sp->GetValueIsValid()) { |
394 | // We found the std::function wrapped callable and we have its address. |
395 | // We now create a ThreadPlan to run to the callable. |
396 | ret_plan_sp = std::make_shared<ThreadPlanRunToAddress>( |
397 | args&: thread, args&: callable_info.callable_address, args&: stop_others); |
398 | return ret_plan_sp; |
399 | } else { |
400 | // We are in std::function but we could not obtain the callable. |
401 | // We create a ThreadPlan to keep stepping through using the address range |
402 | // of the current function. |
403 | ret_plan_sp = std::make_shared<ThreadPlanStepInRange>( |
404 | args&: thread, args&: range_of_curr_func, args&: sc, args: nullptr, args: eOnlyThisThread, |
405 | args: eLazyBoolYes, args: eLazyBoolYes); |
406 | return ret_plan_sp; |
407 | } |
408 | } |
409 | |
410 | return ret_plan_sp; |
411 | } |
412 | |