180814287SRaphael Isemann //===-- CPPLanguageRuntime.cpp---------------------------------------------===//
2e0678ca5SAlex Langford //
3e0678ca5SAlex Langford // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e0678ca5SAlex Langford // See https://llvm.org/LICENSE.txt for license information.
5e0678ca5SAlex Langford // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e0678ca5SAlex Langford //
7e0678ca5SAlex Langford //===----------------------------------------------------------------------===//
8e0678ca5SAlex Langford 
976e47d48SRaphael Isemann #include <cstring>
10e0678ca5SAlex Langford 
11e0678ca5SAlex Langford #include <memory>
12e0678ca5SAlex Langford 
13e0678ca5SAlex Langford #include "CPPLanguageRuntime.h"
14e0678ca5SAlex Langford 
15e0678ca5SAlex Langford #include "llvm/ADT/StringRef.h"
16e0678ca5SAlex Langford 
17e0678ca5SAlex Langford #include "lldb/Symbol/Block.h"
18e0678ca5SAlex Langford #include "lldb/Symbol/Variable.h"
19e0678ca5SAlex Langford #include "lldb/Symbol/VariableList.h"
20e0678ca5SAlex Langford 
21e0678ca5SAlex Langford #include "lldb/Core/PluginManager.h"
22e0678ca5SAlex Langford #include "lldb/Core/UniqueCStringMap.h"
2391e94a70Sshafik #include "lldb/Symbol/CompileUnit.h"
24e0678ca5SAlex Langford #include "lldb/Target/ABI.h"
25e0678ca5SAlex Langford #include "lldb/Target/ExecutionContext.h"
26e0678ca5SAlex Langford #include "lldb/Target/RegisterContext.h"
27e0678ca5SAlex Langford #include "lldb/Target/SectionLoadList.h"
28e0678ca5SAlex Langford #include "lldb/Target/StackFrame.h"
29e0678ca5SAlex Langford #include "lldb/Target/ThreadPlanRunToAddress.h"
30e0678ca5SAlex Langford #include "lldb/Target/ThreadPlanStepInRange.h"
3191e94a70Sshafik #include "lldb/Utility/Timer.h"
32e0678ca5SAlex Langford 
33e0678ca5SAlex Langford using namespace lldb;
34e0678ca5SAlex Langford using namespace lldb_private;
35e0678ca5SAlex Langford 
36e0678ca5SAlex Langford static ConstString g_this = ConstString("this");
37e0678ca5SAlex Langford 
38e0678ca5SAlex Langford char CPPLanguageRuntime::ID = 0;
39e0678ca5SAlex Langford 
CPPLanguageRuntime(Process * process)40e0678ca5SAlex Langford CPPLanguageRuntime::CPPLanguageRuntime(Process *process)
41e0678ca5SAlex Langford     : LanguageRuntime(process) {}
42e0678ca5SAlex Langford 
IsAllowedRuntimeValue(ConstString name)43efb328f6SEric Christopher bool CPPLanguageRuntime::IsAllowedRuntimeValue(ConstString name) {
44e0678ca5SAlex Langford   return name == g_this;
45e0678ca5SAlex Langford }
46e0678ca5SAlex Langford 
GetObjectDescription(Stream & str,ValueObject & object)47e0678ca5SAlex Langford bool CPPLanguageRuntime::GetObjectDescription(Stream &str,
48e0678ca5SAlex Langford                                               ValueObject &object) {
49e0678ca5SAlex Langford   // C++ has no generic way to do this.
50e0678ca5SAlex Langford   return false;
51e0678ca5SAlex Langford }
52e0678ca5SAlex Langford 
GetObjectDescription(Stream & str,Value & value,ExecutionContextScope * exe_scope)53e0678ca5SAlex Langford bool CPPLanguageRuntime::GetObjectDescription(
54e0678ca5SAlex Langford     Stream &str, Value &value, ExecutionContextScope *exe_scope) {
55e0678ca5SAlex Langford   // C++ has no generic way to do this.
56e0678ca5SAlex Langford   return false;
57e0678ca5SAlex Langford }
58e0678ca5SAlex Langford 
contains_lambda_identifier(llvm::StringRef & str_ref)5991e94a70Sshafik bool contains_lambda_identifier(llvm::StringRef &str_ref) {
6091e94a70Sshafik   return str_ref.contains("$_") || str_ref.contains("'lambda'");
616612fabcSPavel Labath }
6291e94a70Sshafik 
6391e94a70Sshafik CPPLanguageRuntime::LibCppStdFunctionCallableInfo
line_entry_helper(Target & target,const SymbolContext & sc,Symbol * symbol,llvm::StringRef first_template_param_sref,bool has_invoke)6491e94a70Sshafik line_entry_helper(Target &target, const SymbolContext &sc, Symbol *symbol,
6591e94a70Sshafik                   llvm::StringRef first_template_param_sref,
66*80a11e08SShafik Yaghmour                   bool has_invoke) {
6791e94a70Sshafik 
6891e94a70Sshafik   CPPLanguageRuntime::LibCppStdFunctionCallableInfo optional_info;
6991e94a70Sshafik 
7091e94a70Sshafik   AddressRange range;
7191e94a70Sshafik   sc.GetAddressRange(eSymbolContextEverything, 0, false, range);
7291e94a70Sshafik 
7391e94a70Sshafik   Address address = range.GetBaseAddress();
7491e94a70Sshafik 
7591e94a70Sshafik   Address addr;
7691e94a70Sshafik   if (target.ResolveLoadAddress(address.GetCallableLoadAddress(&target),
7791e94a70Sshafik                                 addr)) {
7891e94a70Sshafik     LineEntry line_entry;
7991e94a70Sshafik     addr.CalculateSymbolContextLineEntry(line_entry);
8091e94a70Sshafik 
81*80a11e08SShafik Yaghmour     if (contains_lambda_identifier(first_template_param_sref) || has_invoke) {
8291e94a70Sshafik       // Case 1 and 2
8391e94a70Sshafik       optional_info.callable_case = lldb_private::CPPLanguageRuntime::
8491e94a70Sshafik           LibCppStdFunctionCallableCase::Lambda;
8591e94a70Sshafik     } else {
8691e94a70Sshafik       // Case 3
8791e94a70Sshafik       optional_info.callable_case = lldb_private::CPPLanguageRuntime::
8891e94a70Sshafik           LibCppStdFunctionCallableCase::CallableObject;
8991e94a70Sshafik     }
9091e94a70Sshafik 
9191e94a70Sshafik     optional_info.callable_symbol = *symbol;
9291e94a70Sshafik     optional_info.callable_line_entry = line_entry;
9391e94a70Sshafik     optional_info.callable_address = addr;
9491e94a70Sshafik   }
9591e94a70Sshafik 
9691e94a70Sshafik   return optional_info;
9791e94a70Sshafik }
9891e94a70Sshafik 
99e0678ca5SAlex Langford CPPLanguageRuntime::LibCppStdFunctionCallableInfo
FindLibCppStdFunctionCallableInfo(lldb::ValueObjectSP & valobj_sp)100e0678ca5SAlex Langford CPPLanguageRuntime::FindLibCppStdFunctionCallableInfo(
101e0678ca5SAlex Langford     lldb::ValueObjectSP &valobj_sp) {
1025c1c8443SJonas Devlieghere   LLDB_SCOPED_TIMER();
10391e94a70Sshafik 
104e0678ca5SAlex Langford   LibCppStdFunctionCallableInfo optional_info;
105e0678ca5SAlex Langford 
106e0678ca5SAlex Langford   if (!valobj_sp)
107e0678ca5SAlex Langford     return optional_info;
108e0678ca5SAlex Langford 
109e0678ca5SAlex Langford   // Member __f_ has type __base*, the contents of which will hold:
110e0678ca5SAlex Langford   // 1) a vtable entry which may hold type information needed to discover the
111e0678ca5SAlex Langford   //    lambda being called
112e0678ca5SAlex Langford   // 2) possibly hold a pointer to the callable object
113e0678ca5SAlex Langford   // e.g.
114e0678ca5SAlex Langford   //
115e0678ca5SAlex Langford   // (lldb) frame var -R  f_display
116e0678ca5SAlex Langford   // (std::__1::function<void (int)>) f_display = {
117e0678ca5SAlex Langford   //  __buf_ = {
118e0678ca5SAlex Langford   //  …
119e0678ca5SAlex Langford   // }
120e0678ca5SAlex Langford   //  __f_ = 0x00007ffeefbffa00
121e0678ca5SAlex Langford   // }
122e0678ca5SAlex Langford   // (lldb) memory read -fA 0x00007ffeefbffa00
123e0678ca5SAlex Langford   // 0x7ffeefbffa00: ... `vtable for std::__1::__function::__func<void (*) ...
124e0678ca5SAlex Langford   // 0x7ffeefbffa08: ... `print_num(int) at std_function_cppreference_exam ...
125e0678ca5SAlex Langford   //
126e0678ca5SAlex Langford   // We will be handling five cases below, std::function is wrapping:
127e0678ca5SAlex Langford   //
128e0678ca5SAlex Langford   // 1) a lambda we know at compile time. We will obtain the name of the lambda
129e0678ca5SAlex Langford   //    from the first template pameter from __func's vtable. We will look up
130e0678ca5SAlex Langford   //    the lambda's operator()() and obtain the line table entry.
131e0678ca5SAlex Langford   // 2) a lambda we know at runtime. A pointer to the lambdas __invoke method
132e0678ca5SAlex Langford   //    will be stored after the vtable. We will obtain the lambdas name from
133e0678ca5SAlex Langford   //    this entry and lookup operator()() and obtain the line table entry.
134e0678ca5SAlex Langford   // 3) a callable object via operator()(). We will obtain the name of the
135e0678ca5SAlex Langford   //    object from the first template parameter from __func's vtable. We will
13691e94a70Sshafik   //    look up the objects operator()() and obtain the line table entry.
137e0678ca5SAlex Langford   // 4) a member function. A pointer to the function will stored after the
138e0678ca5SAlex Langford   //    we will obtain the name from this pointer.
139e0678ca5SAlex Langford   // 5) a free function. A pointer to the function will stored after the vtable
140e0678ca5SAlex Langford   //    we will obtain the name from this pointer.
141*80a11e08SShafik Yaghmour   ValueObjectSP member_f_(
142e0678ca5SAlex Langford       valobj_sp->GetChildMemberWithName(ConstString("__f_"), true));
143e0678ca5SAlex Langford 
144*80a11e08SShafik Yaghmour   if (member_f_) {
145*80a11e08SShafik Yaghmour     ValueObjectSP sub_member_f_(
146*80a11e08SShafik Yaghmour        member_f_->GetChildMemberWithName(ConstString("__f_"), true));
147e0678ca5SAlex Langford 
148*80a11e08SShafik Yaghmour     if (sub_member_f_)
149*80a11e08SShafik Yaghmour         member_f_ = sub_member_f_;
150e0678ca5SAlex Langford   }
151e0678ca5SAlex Langford 
152*80a11e08SShafik Yaghmour   if (!member_f_)
153a079f619Sshafik     return optional_info;
154a079f619Sshafik 
155*80a11e08SShafik Yaghmour   lldb::addr_t member_f_pointer_value = member_f_->GetValueAsUnsigned(0);
156e0678ca5SAlex Langford 
157*80a11e08SShafik Yaghmour   optional_info.member_f_pointer_value = member_f_pointer_value;
158e0678ca5SAlex Langford 
159*80a11e08SShafik Yaghmour   if (!member_f_pointer_value)
16091e94a70Sshafik     return optional_info;
16191e94a70Sshafik 
162e0678ca5SAlex Langford   ExecutionContext exe_ctx(valobj_sp->GetExecutionContextRef());
163e0678ca5SAlex Langford   Process *process = exe_ctx.GetProcessPtr();
164e0678ca5SAlex Langford 
165e0678ca5SAlex Langford   if (process == nullptr)
166e0678ca5SAlex Langford     return optional_info;
167e0678ca5SAlex Langford 
168e0678ca5SAlex Langford   uint32_t address_size = process->GetAddressByteSize();
169e0678ca5SAlex Langford   Status status;
170e0678ca5SAlex Langford 
171e0678ca5SAlex Langford   // First item pointed to by __f_ should be the pointer to the vtable for
172e0678ca5SAlex Langford   // a __base object.
173e0678ca5SAlex Langford   lldb::addr_t vtable_address =
174*80a11e08SShafik Yaghmour       process->ReadPointerFromMemory(member_f_pointer_value, status);
175e0678ca5SAlex Langford 
176e0678ca5SAlex Langford   if (status.Fail())
177e0678ca5SAlex Langford     return optional_info;
178e0678ca5SAlex Langford 
17991e94a70Sshafik   lldb::addr_t vtable_address_first_entry =
18091e94a70Sshafik       process->ReadPointerFromMemory(vtable_address + address_size, status);
18191e94a70Sshafik 
18291e94a70Sshafik   if (status.Fail())
18391e94a70Sshafik     return optional_info;
18491e94a70Sshafik 
185*80a11e08SShafik Yaghmour   lldb::addr_t address_after_vtable = member_f_pointer_value + address_size;
18691e94a70Sshafik   // As commented above we may not have a function pointer but if we do we will
187e0678ca5SAlex Langford   // need it.
188e0678ca5SAlex Langford   lldb::addr_t possible_function_address =
189e0678ca5SAlex Langford       process->ReadPointerFromMemory(address_after_vtable, status);
190e0678ca5SAlex Langford 
191e0678ca5SAlex Langford   if (status.Fail())
192e0678ca5SAlex Langford     return optional_info;
193e0678ca5SAlex Langford 
194e0678ca5SAlex Langford   Target &target = process->GetTarget();
195e0678ca5SAlex Langford 
196e0678ca5SAlex Langford   if (target.GetSectionLoadList().IsEmpty())
197e0678ca5SAlex Langford     return optional_info;
198e0678ca5SAlex Langford 
19991e94a70Sshafik   Address vtable_first_entry_resolved;
20091e94a70Sshafik 
20191e94a70Sshafik   if (!target.GetSectionLoadList().ResolveLoadAddress(
20291e94a70Sshafik           vtable_address_first_entry, vtable_first_entry_resolved))
20391e94a70Sshafik     return optional_info;
20491e94a70Sshafik 
205e0678ca5SAlex Langford   Address vtable_addr_resolved;
206e0678ca5SAlex Langford   SymbolContext sc;
20791e94a70Sshafik   Symbol *symbol = nullptr;
208e0678ca5SAlex Langford 
209e0678ca5SAlex Langford   if (!target.GetSectionLoadList().ResolveLoadAddress(vtable_address,
210e0678ca5SAlex Langford                                                       vtable_addr_resolved))
211e0678ca5SAlex Langford     return optional_info;
212e0678ca5SAlex Langford 
213e0678ca5SAlex Langford   target.GetImages().ResolveSymbolContextForAddress(
214e0678ca5SAlex Langford       vtable_addr_resolved, eSymbolContextEverything, sc);
215e0678ca5SAlex Langford   symbol = sc.symbol;
216e0678ca5SAlex Langford 
217e0678ca5SAlex Langford   if (symbol == nullptr)
218e0678ca5SAlex Langford     return optional_info;
219e0678ca5SAlex Langford 
22091e94a70Sshafik   llvm::StringRef vtable_name(symbol->GetName().GetStringRef());
221e0678ca5SAlex Langford   bool found_expected_start_string =
222e0678ca5SAlex Langford       vtable_name.startswith("vtable for std::__1::__function::__func<");
223e0678ca5SAlex Langford 
224e0678ca5SAlex Langford   if (!found_expected_start_string)
225e0678ca5SAlex Langford     return optional_info;
226e0678ca5SAlex Langford 
227e0678ca5SAlex Langford   // Given case 1 or 3 we have a vtable name, we are want to extract the first
228e0678ca5SAlex Langford   // template parameter
229e0678ca5SAlex Langford   //
230e0678ca5SAlex Langford   //  ... __func<main::$_0, std::__1::allocator<main::$_0> ...
231e0678ca5SAlex Langford   //             ^^^^^^^^^
232e0678ca5SAlex Langford   //
23391e94a70Sshafik   // We could see names such as:
23491e94a70Sshafik   //    main::$_0
23591e94a70Sshafik   //    Bar::add_num2(int)::'lambda'(int)
23691e94a70Sshafik   //    Bar
23791e94a70Sshafik   //
238e0678ca5SAlex Langford   // We do this by find the first < and , and extracting in between.
239e0678ca5SAlex Langford   //
240e0678ca5SAlex Langford   // This covers the case of the lambda known at compile time.
241e0678ca5SAlex Langford   size_t first_open_angle_bracket = vtable_name.find('<') + 1;
242e0678ca5SAlex Langford   size_t first_comma = vtable_name.find(',');
243e0678ca5SAlex Langford 
244e0678ca5SAlex Langford   llvm::StringRef first_template_parameter =
245e0678ca5SAlex Langford       vtable_name.slice(first_open_angle_bracket, first_comma);
246e0678ca5SAlex Langford 
247e0678ca5SAlex Langford   Address function_address_resolved;
248e0678ca5SAlex Langford 
249e0678ca5SAlex Langford   // Setup for cases 2, 4 and 5 we have a pointer to a function after the
250e0678ca5SAlex Langford   // vtable. We will use a process of elimination to drop through each case
251e0678ca5SAlex Langford   // and obtain the data we need.
252e0678ca5SAlex Langford   if (target.GetSectionLoadList().ResolveLoadAddress(
253e0678ca5SAlex Langford           possible_function_address, function_address_resolved)) {
254e0678ca5SAlex Langford     target.GetImages().ResolveSymbolContextForAddress(
255e0678ca5SAlex Langford         function_address_resolved, eSymbolContextEverything, sc);
256e0678ca5SAlex Langford     symbol = sc.symbol;
257e0678ca5SAlex Langford   }
258e0678ca5SAlex Langford 
25991e94a70Sshafik   // These conditions are used several times to simplify statements later on.
260*80a11e08SShafik Yaghmour   bool has_invoke =
26191e94a70Sshafik       (symbol ? symbol->GetName().GetStringRef().contains("__invoke") : false);
26291e94a70Sshafik   auto calculate_symbol_context_helper = [](auto &t,
26391e94a70Sshafik                                             SymbolContextList &sc_list) {
26491e94a70Sshafik     SymbolContext sc;
26591e94a70Sshafik     t->CalculateSymbolContext(&sc);
26691e94a70Sshafik     sc_list.Append(sc);
267e18f4db2Sshafik   };
268e18f4db2Sshafik 
26991e94a70Sshafik   // Case 2
270*80a11e08SShafik Yaghmour   if (has_invoke) {
27191e94a70Sshafik     SymbolContextList scl;
27291e94a70Sshafik     calculate_symbol_context_helper(symbol, scl);
27391e94a70Sshafik 
27491e94a70Sshafik     return line_entry_helper(target, scl[0], symbol, first_template_parameter,
275*80a11e08SShafik Yaghmour                              has_invoke);
27691e94a70Sshafik   }
27791e94a70Sshafik 
278e18f4db2Sshafik   // Case 4 or 5
279e18f4db2Sshafik   if (symbol && !symbol->GetName().GetStringRef().startswith("vtable for") &&
280*80a11e08SShafik Yaghmour       !contains_lambda_identifier(first_template_parameter) && !has_invoke) {
281e18f4db2Sshafik     optional_info.callable_case =
282e18f4db2Sshafik         LibCppStdFunctionCallableCase::FreeOrMemberFunction;
283e18f4db2Sshafik     optional_info.callable_address = function_address_resolved;
284e18f4db2Sshafik     optional_info.callable_symbol = *symbol;
285e18f4db2Sshafik 
286e18f4db2Sshafik     return optional_info;
287e18f4db2Sshafik   }
288e18f4db2Sshafik 
28991e94a70Sshafik   std::string func_to_match = first_template_parameter.str();
290e0678ca5SAlex Langford 
291e18f4db2Sshafik   auto it = CallableLookupCache.find(func_to_match);
292e18f4db2Sshafik   if (it != CallableLookupCache.end())
293e18f4db2Sshafik     return it->second;
294e18f4db2Sshafik 
295e0678ca5SAlex Langford   SymbolContextList scl;
296e0678ca5SAlex Langford 
29791e94a70Sshafik   CompileUnit *vtable_cu =
29891e94a70Sshafik       vtable_first_entry_resolved.CalculateSymbolContextCompileUnit();
29991e94a70Sshafik   llvm::StringRef name_to_use = func_to_match;
300e0678ca5SAlex Langford 
30191e94a70Sshafik   // Case 3, we have a callable object instead of a lambda
30291e94a70Sshafik   //
30391e94a70Sshafik   // TODO
30491e94a70Sshafik   // We currently don't support this case a callable object may have multiple
30591e94a70Sshafik   // operator()() varying on const/non-const and number of arguments and we
30691e94a70Sshafik   // don't have a way to currently distinguish them so we will bail out now.
30791e94a70Sshafik   if (!contains_lambda_identifier(name_to_use))
30891e94a70Sshafik     return optional_info;
30991e94a70Sshafik 
310*80a11e08SShafik Yaghmour   if (vtable_cu && !has_invoke) {
31191e94a70Sshafik     lldb::FunctionSP func_sp =
31291e94a70Sshafik         vtable_cu->FindFunction([name_to_use](const FunctionSP &f) {
31391e94a70Sshafik           auto name = f->GetName().GetStringRef();
31491e94a70Sshafik           if (name.startswith(name_to_use) && name.contains("operator"))
31591e94a70Sshafik             return true;
31691e94a70Sshafik 
31791e94a70Sshafik           return false;
31891e94a70Sshafik         });
31991e94a70Sshafik 
32091e94a70Sshafik     if (func_sp) {
32191e94a70Sshafik       calculate_symbol_context_helper(func_sp, scl);
32291e94a70Sshafik     }
32391e94a70Sshafik   }
32491e94a70Sshafik 
325ebee4571SShafik Yaghmour   if (symbol == nullptr)
326ebee4571SShafik Yaghmour     return optional_info;
327ebee4571SShafik Yaghmour 
32891e94a70Sshafik   // Case 1 or 3
329e0678ca5SAlex Langford   if (scl.GetSize() >= 1) {
33091e94a70Sshafik     optional_info = line_entry_helper(target, scl[0], symbol,
331*80a11e08SShafik Yaghmour                                       first_template_parameter, has_invoke);
332e0678ca5SAlex Langford   }
333e0678ca5SAlex Langford 
334e18f4db2Sshafik   CallableLookupCache[func_to_match] = optional_info;
335e0678ca5SAlex Langford 
336e0678ca5SAlex Langford   return optional_info;
337e0678ca5SAlex Langford }
338e0678ca5SAlex Langford 
339e0678ca5SAlex Langford lldb::ThreadPlanSP
GetStepThroughTrampolinePlan(Thread & thread,bool stop_others)340e0678ca5SAlex Langford CPPLanguageRuntime::GetStepThroughTrampolinePlan(Thread &thread,
341e0678ca5SAlex Langford                                                  bool stop_others) {
342e0678ca5SAlex Langford   ThreadPlanSP ret_plan_sp;
343e0678ca5SAlex Langford 
344e0678ca5SAlex Langford   lldb::addr_t curr_pc = thread.GetRegisterContext()->GetPC();
345e0678ca5SAlex Langford 
346e0678ca5SAlex Langford   TargetSP target_sp(thread.CalculateTarget());
347e0678ca5SAlex Langford 
348e0678ca5SAlex Langford   if (target_sp->GetSectionLoadList().IsEmpty())
349e0678ca5SAlex Langford     return ret_plan_sp;
350e0678ca5SAlex Langford 
351e0678ca5SAlex Langford   Address pc_addr_resolved;
352e0678ca5SAlex Langford   SymbolContext sc;
353e0678ca5SAlex Langford   Symbol *symbol;
354e0678ca5SAlex Langford 
355e0678ca5SAlex Langford   if (!target_sp->GetSectionLoadList().ResolveLoadAddress(curr_pc,
356e0678ca5SAlex Langford                                                           pc_addr_resolved))
357e0678ca5SAlex Langford     return ret_plan_sp;
358e0678ca5SAlex Langford 
359e0678ca5SAlex Langford   target_sp->GetImages().ResolveSymbolContextForAddress(
360e0678ca5SAlex Langford       pc_addr_resolved, eSymbolContextEverything, sc);
361e0678ca5SAlex Langford   symbol = sc.symbol;
362e0678ca5SAlex Langford 
363e0678ca5SAlex Langford   if (symbol == nullptr)
364e0678ca5SAlex Langford     return ret_plan_sp;
365e0678ca5SAlex Langford 
366e0678ca5SAlex Langford   llvm::StringRef function_name(symbol->GetName().GetCString());
367e0678ca5SAlex Langford 
368e0678ca5SAlex Langford   // Handling the case where we are attempting to step into std::function.
369e0678ca5SAlex Langford   // The behavior will be that we will attempt to obtain the wrapped
370e0678ca5SAlex Langford   // callable via FindLibCppStdFunctionCallableInfo() and if we find it we
371e0678ca5SAlex Langford   // will return a ThreadPlanRunToAddress to the callable. Therefore we will
372e0678ca5SAlex Langford   // step into the wrapped callable.
373e0678ca5SAlex Langford   //
374e0678ca5SAlex Langford   bool found_expected_start_string =
375e0678ca5SAlex Langford       function_name.startswith("std::__1::function<");
376e0678ca5SAlex Langford 
377e0678ca5SAlex Langford   if (!found_expected_start_string)
378e0678ca5SAlex Langford     return ret_plan_sp;
379e0678ca5SAlex Langford 
380e0678ca5SAlex Langford   AddressRange range_of_curr_func;
381e0678ca5SAlex Langford   sc.GetAddressRange(eSymbolContextEverything, 0, false, range_of_curr_func);
382e0678ca5SAlex Langford 
383e0678ca5SAlex Langford   StackFrameSP frame = thread.GetStackFrameAtIndex(0);
384e0678ca5SAlex Langford 
385e0678ca5SAlex Langford   if (frame) {
386e0678ca5SAlex Langford     ValueObjectSP value_sp = frame->FindVariable(g_this);
387e0678ca5SAlex Langford 
388e0678ca5SAlex Langford     CPPLanguageRuntime::LibCppStdFunctionCallableInfo callable_info =
389e0678ca5SAlex Langford         FindLibCppStdFunctionCallableInfo(value_sp);
390e0678ca5SAlex Langford 
391e0678ca5SAlex Langford     if (callable_info.callable_case != LibCppStdFunctionCallableCase::Invalid &&
392e0678ca5SAlex Langford         value_sp->GetValueIsValid()) {
393e0678ca5SAlex Langford       // We found the std::function wrapped callable and we have its address.
394e0678ca5SAlex Langford       // We now create a ThreadPlan to run to the callable.
395e0678ca5SAlex Langford       ret_plan_sp = std::make_shared<ThreadPlanRunToAddress>(
396e0678ca5SAlex Langford           thread, callable_info.callable_address, stop_others);
397e0678ca5SAlex Langford       return ret_plan_sp;
398e0678ca5SAlex Langford     } else {
399e0678ca5SAlex Langford       // We are in std::function but we could not obtain the callable.
400e0678ca5SAlex Langford       // We create a ThreadPlan to keep stepping through using the address range
401e0678ca5SAlex Langford       // of the current function.
402e0678ca5SAlex Langford       ret_plan_sp = std::make_shared<ThreadPlanStepInRange>(
403a5ab1dc4SDave Lee           thread, range_of_curr_func, sc, nullptr, eOnlyThisThread,
404a5ab1dc4SDave Lee           eLazyBoolYes, eLazyBoolYes);
405e0678ca5SAlex Langford       return ret_plan_sp;
406e0678ca5SAlex Langford     }
407e0678ca5SAlex Langford   }
408e0678ca5SAlex Langford 
409e0678ca5SAlex Langford   return ret_plan_sp;
410e0678ca5SAlex Langford }
411