xref: /openbsd-src/gnu/llvm/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
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