1dda28197Spatrick //===-- CPPLanguageRuntime.cpp---------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9be691f3bSpatrick #include <cstring>
10061da546Spatrick
11061da546Spatrick #include <memory>
12061da546Spatrick
13061da546Spatrick #include "CPPLanguageRuntime.h"
14061da546Spatrick
15061da546Spatrick #include "llvm/ADT/StringRef.h"
16061da546Spatrick
17061da546Spatrick #include "lldb/Symbol/Block.h"
18061da546Spatrick #include "lldb/Symbol/Variable.h"
19061da546Spatrick #include "lldb/Symbol/VariableList.h"
20061da546Spatrick
21061da546Spatrick #include "lldb/Core/PluginManager.h"
22061da546Spatrick #include "lldb/Core/UniqueCStringMap.h"
23061da546Spatrick #include "lldb/Symbol/CompileUnit.h"
24061da546Spatrick #include "lldb/Target/ABI.h"
25061da546Spatrick #include "lldb/Target/ExecutionContext.h"
26061da546Spatrick #include "lldb/Target/RegisterContext.h"
27061da546Spatrick #include "lldb/Target/SectionLoadList.h"
28061da546Spatrick #include "lldb/Target/StackFrame.h"
29061da546Spatrick #include "lldb/Target/ThreadPlanRunToAddress.h"
30061da546Spatrick #include "lldb/Target/ThreadPlanStepInRange.h"
31061da546Spatrick #include "lldb/Utility/Timer.h"
32061da546Spatrick
33061da546Spatrick using namespace lldb;
34061da546Spatrick using namespace lldb_private;
35061da546Spatrick
36061da546Spatrick static ConstString g_this = ConstString("this");
37061da546Spatrick
38061da546Spatrick char CPPLanguageRuntime::ID = 0;
39061da546Spatrick
CPPLanguageRuntime(Process * process)40061da546Spatrick CPPLanguageRuntime::CPPLanguageRuntime(Process *process)
41061da546Spatrick : LanguageRuntime(process) {}
42061da546Spatrick
IsAllowedRuntimeValue(ConstString name)43dda28197Spatrick bool CPPLanguageRuntime::IsAllowedRuntimeValue(ConstString name) {
44061da546Spatrick return name == g_this;
45061da546Spatrick }
46061da546Spatrick
GetObjectDescription(Stream & str,ValueObject & object)47061da546Spatrick bool CPPLanguageRuntime::GetObjectDescription(Stream &str,
48061da546Spatrick ValueObject &object) {
49061da546Spatrick // C++ has no generic way to do this.
50061da546Spatrick return false;
51061da546Spatrick }
52061da546Spatrick
GetObjectDescription(Stream & str,Value & value,ExecutionContextScope * exe_scope)53061da546Spatrick bool CPPLanguageRuntime::GetObjectDescription(
54061da546Spatrick Stream &str, Value &value, ExecutionContextScope *exe_scope) {
55061da546Spatrick // C++ has no generic way to do this.
56061da546Spatrick return false;
57061da546Spatrick }
58061da546Spatrick
contains_lambda_identifier(llvm::StringRef & str_ref)59061da546Spatrick bool contains_lambda_identifier(llvm::StringRef &str_ref) {
60061da546Spatrick return str_ref.contains("$_") || str_ref.contains("'lambda'");
61061da546Spatrick }
62061da546Spatrick
63061da546Spatrick CPPLanguageRuntime::LibCppStdFunctionCallableInfo
line_entry_helper(Target & target,const SymbolContext & sc,Symbol * symbol,llvm::StringRef first_template_param_sref,bool has_invoke)64061da546Spatrick line_entry_helper(Target &target, const SymbolContext &sc, Symbol *symbol,
65061da546Spatrick llvm::StringRef first_template_param_sref,
66*f6aab3d8Srobert bool has_invoke) {
67061da546Spatrick
68061da546Spatrick CPPLanguageRuntime::LibCppStdFunctionCallableInfo optional_info;
69061da546Spatrick
70061da546Spatrick AddressRange range;
71061da546Spatrick sc.GetAddressRange(eSymbolContextEverything, 0, false, range);
72061da546Spatrick
73061da546Spatrick Address address = range.GetBaseAddress();
74061da546Spatrick
75061da546Spatrick Address addr;
76061da546Spatrick if (target.ResolveLoadAddress(address.GetCallableLoadAddress(&target),
77061da546Spatrick addr)) {
78061da546Spatrick LineEntry line_entry;
79061da546Spatrick addr.CalculateSymbolContextLineEntry(line_entry);
80061da546Spatrick
81*f6aab3d8Srobert if (contains_lambda_identifier(first_template_param_sref) || has_invoke) {
82061da546Spatrick // Case 1 and 2
83061da546Spatrick optional_info.callable_case = lldb_private::CPPLanguageRuntime::
84061da546Spatrick LibCppStdFunctionCallableCase::Lambda;
85061da546Spatrick } else {
86061da546Spatrick // Case 3
87061da546Spatrick optional_info.callable_case = lldb_private::CPPLanguageRuntime::
88061da546Spatrick LibCppStdFunctionCallableCase::CallableObject;
89061da546Spatrick }
90061da546Spatrick
91061da546Spatrick optional_info.callable_symbol = *symbol;
92061da546Spatrick optional_info.callable_line_entry = line_entry;
93061da546Spatrick optional_info.callable_address = addr;
94061da546Spatrick }
95061da546Spatrick
96061da546Spatrick return optional_info;
97061da546Spatrick }
98061da546Spatrick
99061da546Spatrick CPPLanguageRuntime::LibCppStdFunctionCallableInfo
FindLibCppStdFunctionCallableInfo(lldb::ValueObjectSP & valobj_sp)100061da546Spatrick CPPLanguageRuntime::FindLibCppStdFunctionCallableInfo(
101061da546Spatrick lldb::ValueObjectSP &valobj_sp) {
102be691f3bSpatrick LLDB_SCOPED_TIMER();
103061da546Spatrick
104061da546Spatrick LibCppStdFunctionCallableInfo optional_info;
105061da546Spatrick
106061da546Spatrick if (!valobj_sp)
107061da546Spatrick return optional_info;
108061da546Spatrick
109061da546Spatrick // Member __f_ has type __base*, the contents of which will hold:
110061da546Spatrick // 1) a vtable entry which may hold type information needed to discover the
111061da546Spatrick // lambda being called
112061da546Spatrick // 2) possibly hold a pointer to the callable object
113061da546Spatrick // e.g.
114061da546Spatrick //
115061da546Spatrick // (lldb) frame var -R f_display
116061da546Spatrick // (std::__1::function<void (int)>) f_display = {
117061da546Spatrick // __buf_ = {
118061da546Spatrick // …
119061da546Spatrick // }
120061da546Spatrick // __f_ = 0x00007ffeefbffa00
121061da546Spatrick // }
122061da546Spatrick // (lldb) memory read -fA 0x00007ffeefbffa00
123061da546Spatrick // 0x7ffeefbffa00: ... `vtable for std::__1::__function::__func<void (*) ...
124061da546Spatrick // 0x7ffeefbffa08: ... `print_num(int) at std_function_cppreference_exam ...
125061da546Spatrick //
126061da546Spatrick // We will be handling five cases below, std::function is wrapping:
127061da546Spatrick //
128061da546Spatrick // 1) a lambda we know at compile time. We will obtain the name of the lambda
129061da546Spatrick // from the first template pameter from __func's vtable. We will look up
130061da546Spatrick // the lambda's operator()() and obtain the line table entry.
131061da546Spatrick // 2) a lambda we know at runtime. A pointer to the lambdas __invoke method
132061da546Spatrick // will be stored after the vtable. We will obtain the lambdas name from
133061da546Spatrick // this entry and lookup operator()() and obtain the line table entry.
134061da546Spatrick // 3) a callable object via operator()(). We will obtain the name of the
135061da546Spatrick // object from the first template parameter from __func's vtable. We will
136061da546Spatrick // look up the objects operator()() and obtain the line table entry.
137061da546Spatrick // 4) a member function. A pointer to the function will stored after the
138061da546Spatrick // we will obtain the name from this pointer.
139061da546Spatrick // 5) a free function. A pointer to the function will stored after the vtable
140061da546Spatrick // we will obtain the name from this pointer.
141*f6aab3d8Srobert ValueObjectSP member_f_(
142061da546Spatrick valobj_sp->GetChildMemberWithName(ConstString("__f_"), true));
143061da546Spatrick
144*f6aab3d8Srobert if (member_f_) {
145*f6aab3d8Srobert ValueObjectSP sub_member_f_(
146*f6aab3d8Srobert member_f_->GetChildMemberWithName(ConstString("__f_"), true));
147061da546Spatrick
148*f6aab3d8Srobert if (sub_member_f_)
149*f6aab3d8Srobert member_f_ = sub_member_f_;
150061da546Spatrick }
151061da546Spatrick
152*f6aab3d8Srobert if (!member_f_)
153be691f3bSpatrick return optional_info;
154be691f3bSpatrick
155*f6aab3d8Srobert lldb::addr_t member_f_pointer_value = member_f_->GetValueAsUnsigned(0);
156061da546Spatrick
157*f6aab3d8Srobert optional_info.member_f_pointer_value = member_f_pointer_value;
158061da546Spatrick
159*f6aab3d8Srobert if (!member_f_pointer_value)
160061da546Spatrick return optional_info;
161061da546Spatrick
162061da546Spatrick ExecutionContext exe_ctx(valobj_sp->GetExecutionContextRef());
163061da546Spatrick Process *process = exe_ctx.GetProcessPtr();
164061da546Spatrick
165061da546Spatrick if (process == nullptr)
166061da546Spatrick return optional_info;
167061da546Spatrick
168061da546Spatrick uint32_t address_size = process->GetAddressByteSize();
169061da546Spatrick Status status;
170061da546Spatrick
171061da546Spatrick // First item pointed to by __f_ should be the pointer to the vtable for
172061da546Spatrick // a __base object.
173061da546Spatrick lldb::addr_t vtable_address =
174*f6aab3d8Srobert process->ReadPointerFromMemory(member_f_pointer_value, status);
175061da546Spatrick
176061da546Spatrick if (status.Fail())
177061da546Spatrick return optional_info;
178061da546Spatrick
179061da546Spatrick lldb::addr_t vtable_address_first_entry =
180061da546Spatrick process->ReadPointerFromMemory(vtable_address + address_size, status);
181061da546Spatrick
182061da546Spatrick if (status.Fail())
183061da546Spatrick return optional_info;
184061da546Spatrick
185*f6aab3d8Srobert lldb::addr_t address_after_vtable = member_f_pointer_value + address_size;
186061da546Spatrick // As commented above we may not have a function pointer but if we do we will
187061da546Spatrick // need it.
188061da546Spatrick lldb::addr_t possible_function_address =
189061da546Spatrick process->ReadPointerFromMemory(address_after_vtable, status);
190061da546Spatrick
191061da546Spatrick if (status.Fail())
192061da546Spatrick return optional_info;
193061da546Spatrick
194061da546Spatrick Target &target = process->GetTarget();
195061da546Spatrick
196061da546Spatrick if (target.GetSectionLoadList().IsEmpty())
197061da546Spatrick return optional_info;
198061da546Spatrick
199061da546Spatrick Address vtable_first_entry_resolved;
200061da546Spatrick
201061da546Spatrick if (!target.GetSectionLoadList().ResolveLoadAddress(
202061da546Spatrick vtable_address_first_entry, vtable_first_entry_resolved))
203061da546Spatrick return optional_info;
204061da546Spatrick
205061da546Spatrick Address vtable_addr_resolved;
206061da546Spatrick SymbolContext sc;
207061da546Spatrick Symbol *symbol = nullptr;
208061da546Spatrick
209061da546Spatrick if (!target.GetSectionLoadList().ResolveLoadAddress(vtable_address,
210061da546Spatrick vtable_addr_resolved))
211061da546Spatrick return optional_info;
212061da546Spatrick
213061da546Spatrick target.GetImages().ResolveSymbolContextForAddress(
214061da546Spatrick vtable_addr_resolved, eSymbolContextEverything, sc);
215061da546Spatrick symbol = sc.symbol;
216061da546Spatrick
217061da546Spatrick if (symbol == nullptr)
218061da546Spatrick return optional_info;
219061da546Spatrick
220061da546Spatrick llvm::StringRef vtable_name(symbol->GetName().GetStringRef());
221061da546Spatrick bool found_expected_start_string =
222061da546Spatrick vtable_name.startswith("vtable for std::__1::__function::__func<");
223061da546Spatrick
224061da546Spatrick if (!found_expected_start_string)
225061da546Spatrick return optional_info;
226061da546Spatrick
227061da546Spatrick // Given case 1 or 3 we have a vtable name, we are want to extract the first
228061da546Spatrick // template parameter
229061da546Spatrick //
230061da546Spatrick // ... __func<main::$_0, std::__1::allocator<main::$_0> ...
231061da546Spatrick // ^^^^^^^^^
232061da546Spatrick //
233061da546Spatrick // We could see names such as:
234061da546Spatrick // main::$_0
235061da546Spatrick // Bar::add_num2(int)::'lambda'(int)
236061da546Spatrick // Bar
237061da546Spatrick //
238061da546Spatrick // We do this by find the first < and , and extracting in between.
239061da546Spatrick //
240061da546Spatrick // This covers the case of the lambda known at compile time.
241061da546Spatrick size_t first_open_angle_bracket = vtable_name.find('<') + 1;
242061da546Spatrick size_t first_comma = vtable_name.find(',');
243061da546Spatrick
244061da546Spatrick llvm::StringRef first_template_parameter =
245061da546Spatrick vtable_name.slice(first_open_angle_bracket, first_comma);
246061da546Spatrick
247061da546Spatrick Address function_address_resolved;
248061da546Spatrick
249061da546Spatrick // Setup for cases 2, 4 and 5 we have a pointer to a function after the
250061da546Spatrick // vtable. We will use a process of elimination to drop through each case
251061da546Spatrick // and obtain the data we need.
252061da546Spatrick if (target.GetSectionLoadList().ResolveLoadAddress(
253061da546Spatrick possible_function_address, function_address_resolved)) {
254061da546Spatrick target.GetImages().ResolveSymbolContextForAddress(
255061da546Spatrick function_address_resolved, eSymbolContextEverything, sc);
256061da546Spatrick symbol = sc.symbol;
257061da546Spatrick }
258061da546Spatrick
259061da546Spatrick // These conditions are used several times to simplify statements later on.
260*f6aab3d8Srobert bool has_invoke =
261061da546Spatrick (symbol ? symbol->GetName().GetStringRef().contains("__invoke") : false);
262061da546Spatrick auto calculate_symbol_context_helper = [](auto &t,
263061da546Spatrick SymbolContextList &sc_list) {
264061da546Spatrick SymbolContext sc;
265061da546Spatrick t->CalculateSymbolContext(&sc);
266061da546Spatrick sc_list.Append(sc);
267061da546Spatrick };
268061da546Spatrick
269061da546Spatrick // Case 2
270*f6aab3d8Srobert if (has_invoke) {
271061da546Spatrick SymbolContextList scl;
272061da546Spatrick calculate_symbol_context_helper(symbol, scl);
273061da546Spatrick
274061da546Spatrick return line_entry_helper(target, scl[0], symbol, first_template_parameter,
275*f6aab3d8Srobert has_invoke);
276061da546Spatrick }
277061da546Spatrick
278061da546Spatrick // Case 4 or 5
279061da546Spatrick if (symbol && !symbol->GetName().GetStringRef().startswith("vtable for") &&
280*f6aab3d8Srobert !contains_lambda_identifier(first_template_parameter) && !has_invoke) {
281061da546Spatrick optional_info.callable_case =
282061da546Spatrick LibCppStdFunctionCallableCase::FreeOrMemberFunction;
283061da546Spatrick optional_info.callable_address = function_address_resolved;
284061da546Spatrick optional_info.callable_symbol = *symbol;
285061da546Spatrick
286061da546Spatrick return optional_info;
287061da546Spatrick }
288061da546Spatrick
289061da546Spatrick std::string func_to_match = first_template_parameter.str();
290061da546Spatrick
291061da546Spatrick auto it = CallableLookupCache.find(func_to_match);
292061da546Spatrick if (it != CallableLookupCache.end())
293061da546Spatrick return it->second;
294061da546Spatrick
295061da546Spatrick SymbolContextList scl;
296061da546Spatrick
297061da546Spatrick CompileUnit *vtable_cu =
298061da546Spatrick vtable_first_entry_resolved.CalculateSymbolContextCompileUnit();
299061da546Spatrick llvm::StringRef name_to_use = func_to_match;
300061da546Spatrick
301061da546Spatrick // Case 3, we have a callable object instead of a lambda
302061da546Spatrick //
303061da546Spatrick // TODO
304061da546Spatrick // We currently don't support this case a callable object may have multiple
305061da546Spatrick // operator()() varying on const/non-const and number of arguments and we
306061da546Spatrick // don't have a way to currently distinguish them so we will bail out now.
307061da546Spatrick if (!contains_lambda_identifier(name_to_use))
308061da546Spatrick return optional_info;
309061da546Spatrick
310*f6aab3d8Srobert if (vtable_cu && !has_invoke) {
311061da546Spatrick lldb::FunctionSP func_sp =
312061da546Spatrick vtable_cu->FindFunction([name_to_use](const FunctionSP &f) {
313061da546Spatrick auto name = f->GetName().GetStringRef();
314061da546Spatrick if (name.startswith(name_to_use) && name.contains("operator"))
315061da546Spatrick return true;
316061da546Spatrick
317061da546Spatrick return false;
318061da546Spatrick });
319061da546Spatrick
320061da546Spatrick if (func_sp) {
321061da546Spatrick calculate_symbol_context_helper(func_sp, scl);
322061da546Spatrick }
323061da546Spatrick }
324061da546Spatrick
325be691f3bSpatrick if (symbol == nullptr)
326be691f3bSpatrick return optional_info;
327be691f3bSpatrick
328061da546Spatrick // Case 1 or 3
329061da546Spatrick if (scl.GetSize() >= 1) {
330061da546Spatrick optional_info = line_entry_helper(target, scl[0], symbol,
331*f6aab3d8Srobert first_template_parameter, has_invoke);
332061da546Spatrick }
333061da546Spatrick
334061da546Spatrick CallableLookupCache[func_to_match] = optional_info;
335061da546Spatrick
336061da546Spatrick return optional_info;
337061da546Spatrick }
338061da546Spatrick
339061da546Spatrick lldb::ThreadPlanSP
GetStepThroughTrampolinePlan(Thread & thread,bool stop_others)340061da546Spatrick CPPLanguageRuntime::GetStepThroughTrampolinePlan(Thread &thread,
341061da546Spatrick bool stop_others) {
342061da546Spatrick ThreadPlanSP ret_plan_sp;
343061da546Spatrick
344061da546Spatrick lldb::addr_t curr_pc = thread.GetRegisterContext()->GetPC();
345061da546Spatrick
346061da546Spatrick TargetSP target_sp(thread.CalculateTarget());
347061da546Spatrick
348061da546Spatrick if (target_sp->GetSectionLoadList().IsEmpty())
349061da546Spatrick return ret_plan_sp;
350061da546Spatrick
351061da546Spatrick Address pc_addr_resolved;
352061da546Spatrick SymbolContext sc;
353061da546Spatrick Symbol *symbol;
354061da546Spatrick
355061da546Spatrick if (!target_sp->GetSectionLoadList().ResolveLoadAddress(curr_pc,
356061da546Spatrick pc_addr_resolved))
357061da546Spatrick return ret_plan_sp;
358061da546Spatrick
359061da546Spatrick target_sp->GetImages().ResolveSymbolContextForAddress(
360061da546Spatrick pc_addr_resolved, eSymbolContextEverything, sc);
361061da546Spatrick symbol = sc.symbol;
362061da546Spatrick
363061da546Spatrick if (symbol == nullptr)
364061da546Spatrick return ret_plan_sp;
365061da546Spatrick
366061da546Spatrick llvm::StringRef function_name(symbol->GetName().GetCString());
367061da546Spatrick
368061da546Spatrick // Handling the case where we are attempting to step into std::function.
369061da546Spatrick // The behavior will be that we will attempt to obtain the wrapped
370061da546Spatrick // callable via FindLibCppStdFunctionCallableInfo() and if we find it we
371061da546Spatrick // will return a ThreadPlanRunToAddress to the callable. Therefore we will
372061da546Spatrick // step into the wrapped callable.
373061da546Spatrick //
374061da546Spatrick bool found_expected_start_string =
375061da546Spatrick function_name.startswith("std::__1::function<");
376061da546Spatrick
377061da546Spatrick if (!found_expected_start_string)
378061da546Spatrick return ret_plan_sp;
379061da546Spatrick
380061da546Spatrick AddressRange range_of_curr_func;
381061da546Spatrick sc.GetAddressRange(eSymbolContextEverything, 0, false, range_of_curr_func);
382061da546Spatrick
383061da546Spatrick StackFrameSP frame = thread.GetStackFrameAtIndex(0);
384061da546Spatrick
385061da546Spatrick if (frame) {
386061da546Spatrick ValueObjectSP value_sp = frame->FindVariable(g_this);
387061da546Spatrick
388061da546Spatrick CPPLanguageRuntime::LibCppStdFunctionCallableInfo callable_info =
389061da546Spatrick FindLibCppStdFunctionCallableInfo(value_sp);
390061da546Spatrick
391061da546Spatrick if (callable_info.callable_case != LibCppStdFunctionCallableCase::Invalid &&
392061da546Spatrick value_sp->GetValueIsValid()) {
393061da546Spatrick // We found the std::function wrapped callable and we have its address.
394061da546Spatrick // We now create a ThreadPlan to run to the callable.
395061da546Spatrick ret_plan_sp = std::make_shared<ThreadPlanRunToAddress>(
396061da546Spatrick thread, callable_info.callable_address, stop_others);
397061da546Spatrick return ret_plan_sp;
398061da546Spatrick } else {
399061da546Spatrick // We are in std::function but we could not obtain the callable.
400061da546Spatrick // We create a ThreadPlan to keep stepping through using the address range
401061da546Spatrick // of the current function.
402061da546Spatrick ret_plan_sp = std::make_shared<ThreadPlanStepInRange>(
403be691f3bSpatrick thread, range_of_curr_func, sc, nullptr, eOnlyThisThread,
404be691f3bSpatrick eLazyBoolYes, eLazyBoolYes);
405061da546Spatrick return ret_plan_sp;
406061da546Spatrick }
407061da546Spatrick }
408061da546Spatrick
409061da546Spatrick return ret_plan_sp;
410061da546Spatrick }
411