15ffd83dbSDimitry Andric //===-- CPPLanguageRuntime.cpp---------------------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 9fe6060f1SDimitry Andric #include <cstring> 100b57cec5SDimitry Andric 110b57cec5SDimitry Andric #include <memory> 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric #include "CPPLanguageRuntime.h" 140b57cec5SDimitry Andric 150b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h" 160b57cec5SDimitry Andric 170b57cec5SDimitry Andric #include "lldb/Symbol/Block.h" 180b57cec5SDimitry Andric #include "lldb/Symbol/Variable.h" 190b57cec5SDimitry Andric #include "lldb/Symbol/VariableList.h" 200b57cec5SDimitry Andric 210b57cec5SDimitry Andric #include "lldb/Core/PluginManager.h" 220b57cec5SDimitry Andric #include "lldb/Core/UniqueCStringMap.h" 23480093f4SDimitry Andric #include "lldb/Symbol/CompileUnit.h" 240b57cec5SDimitry Andric #include "lldb/Target/ABI.h" 250b57cec5SDimitry Andric #include "lldb/Target/ExecutionContext.h" 260b57cec5SDimitry Andric #include "lldb/Target/RegisterContext.h" 270b57cec5SDimitry Andric #include "lldb/Target/SectionLoadList.h" 280b57cec5SDimitry Andric #include "lldb/Target/StackFrame.h" 290b57cec5SDimitry Andric #include "lldb/Target/ThreadPlanRunToAddress.h" 300b57cec5SDimitry Andric #include "lldb/Target/ThreadPlanStepInRange.h" 31480093f4SDimitry Andric #include "lldb/Utility/Timer.h" 320b57cec5SDimitry Andric 330b57cec5SDimitry Andric using namespace lldb; 340b57cec5SDimitry Andric using namespace lldb_private; 350b57cec5SDimitry Andric 360b57cec5SDimitry Andric static ConstString g_this = ConstString("this"); 375f757f3fSDimitry Andric // Artificial coroutine-related variables emitted by clang. 385f757f3fSDimitry Andric static ConstString g_promise = ConstString("__promise"); 395f757f3fSDimitry Andric static ConstString g_coro_frame = ConstString("__coro_frame"); 400b57cec5SDimitry Andric 410b57cec5SDimitry Andric char CPPLanguageRuntime::ID = 0; 420b57cec5SDimitry Andric 430b57cec5SDimitry Andric CPPLanguageRuntime::CPPLanguageRuntime(Process *process) 440b57cec5SDimitry Andric : LanguageRuntime(process) {} 450b57cec5SDimitry Andric 465ffd83dbSDimitry Andric bool CPPLanguageRuntime::IsAllowedRuntimeValue(ConstString name) { 475f757f3fSDimitry Andric return name == g_this || name == g_promise || name == g_coro_frame; 480b57cec5SDimitry Andric } 490b57cec5SDimitry Andric 50*0fca6ea1SDimitry Andric llvm::Error CPPLanguageRuntime::GetObjectDescription(Stream &str, 510b57cec5SDimitry Andric ValueObject &object) { 520b57cec5SDimitry Andric // C++ has no generic way to do this. 53*0fca6ea1SDimitry Andric return llvm::createStringError("C++ does not support object descriptions"); 540b57cec5SDimitry Andric } 550b57cec5SDimitry Andric 56*0fca6ea1SDimitry Andric llvm::Error 57*0fca6ea1SDimitry Andric CPPLanguageRuntime::GetObjectDescription(Stream &str, Value &value, 58*0fca6ea1SDimitry Andric ExecutionContextScope *exe_scope) { 590b57cec5SDimitry Andric // C++ has no generic way to do this. 60*0fca6ea1SDimitry Andric return llvm::createStringError("C++ does not support object descriptions"); 610b57cec5SDimitry Andric } 620b57cec5SDimitry Andric 63480093f4SDimitry Andric bool contains_lambda_identifier(llvm::StringRef &str_ref) { 64480093f4SDimitry Andric return str_ref.contains("$_") || str_ref.contains("'lambda'"); 65480093f4SDimitry Andric } 66480093f4SDimitry Andric 67480093f4SDimitry Andric CPPLanguageRuntime::LibCppStdFunctionCallableInfo 68480093f4SDimitry Andric line_entry_helper(Target &target, const SymbolContext &sc, Symbol *symbol, 69480093f4SDimitry Andric llvm::StringRef first_template_param_sref, 7081ad6265SDimitry Andric bool has_invoke) { 71480093f4SDimitry Andric 72480093f4SDimitry Andric CPPLanguageRuntime::LibCppStdFunctionCallableInfo optional_info; 73480093f4SDimitry Andric 74480093f4SDimitry Andric AddressRange range; 75480093f4SDimitry Andric sc.GetAddressRange(eSymbolContextEverything, 0, false, range); 76480093f4SDimitry Andric 77480093f4SDimitry Andric Address address = range.GetBaseAddress(); 78480093f4SDimitry Andric 79480093f4SDimitry Andric Address addr; 80480093f4SDimitry Andric if (target.ResolveLoadAddress(address.GetCallableLoadAddress(&target), 81480093f4SDimitry Andric addr)) { 82480093f4SDimitry Andric LineEntry line_entry; 83480093f4SDimitry Andric addr.CalculateSymbolContextLineEntry(line_entry); 84480093f4SDimitry Andric 8581ad6265SDimitry Andric if (contains_lambda_identifier(first_template_param_sref) || has_invoke) { 86480093f4SDimitry Andric // Case 1 and 2 87480093f4SDimitry Andric optional_info.callable_case = lldb_private::CPPLanguageRuntime:: 88480093f4SDimitry Andric LibCppStdFunctionCallableCase::Lambda; 89480093f4SDimitry Andric } else { 90480093f4SDimitry Andric // Case 3 91480093f4SDimitry Andric optional_info.callable_case = lldb_private::CPPLanguageRuntime:: 92480093f4SDimitry Andric LibCppStdFunctionCallableCase::CallableObject; 93480093f4SDimitry Andric } 94480093f4SDimitry Andric 95480093f4SDimitry Andric optional_info.callable_symbol = *symbol; 96480093f4SDimitry Andric optional_info.callable_line_entry = line_entry; 97480093f4SDimitry Andric optional_info.callable_address = addr; 98480093f4SDimitry Andric } 99480093f4SDimitry Andric 100480093f4SDimitry Andric return optional_info; 101480093f4SDimitry Andric } 102480093f4SDimitry Andric 1030b57cec5SDimitry Andric CPPLanguageRuntime::LibCppStdFunctionCallableInfo 1040b57cec5SDimitry Andric CPPLanguageRuntime::FindLibCppStdFunctionCallableInfo( 1050b57cec5SDimitry Andric lldb::ValueObjectSP &valobj_sp) { 106e8d8bef9SDimitry Andric LLDB_SCOPED_TIMER(); 107480093f4SDimitry Andric 1080b57cec5SDimitry Andric LibCppStdFunctionCallableInfo optional_info; 1090b57cec5SDimitry Andric 1100b57cec5SDimitry Andric if (!valobj_sp) 1110b57cec5SDimitry Andric return optional_info; 1120b57cec5SDimitry Andric 1130b57cec5SDimitry Andric // Member __f_ has type __base*, the contents of which will hold: 1140b57cec5SDimitry Andric // 1) a vtable entry which may hold type information needed to discover the 1150b57cec5SDimitry Andric // lambda being called 1160b57cec5SDimitry Andric // 2) possibly hold a pointer to the callable object 1170b57cec5SDimitry Andric // e.g. 1180b57cec5SDimitry Andric // 1190b57cec5SDimitry Andric // (lldb) frame var -R f_display 1200b57cec5SDimitry Andric // (std::__1::function<void (int)>) f_display = { 1210b57cec5SDimitry Andric // __buf_ = { 1220b57cec5SDimitry Andric // … 1230b57cec5SDimitry Andric // } 1240b57cec5SDimitry Andric // __f_ = 0x00007ffeefbffa00 1250b57cec5SDimitry Andric // } 1260b57cec5SDimitry Andric // (lldb) memory read -fA 0x00007ffeefbffa00 1270b57cec5SDimitry Andric // 0x7ffeefbffa00: ... `vtable for std::__1::__function::__func<void (*) ... 1280b57cec5SDimitry Andric // 0x7ffeefbffa08: ... `print_num(int) at std_function_cppreference_exam ... 1290b57cec5SDimitry Andric // 1300b57cec5SDimitry Andric // We will be handling five cases below, std::function is wrapping: 1310b57cec5SDimitry Andric // 1320b57cec5SDimitry Andric // 1) a lambda we know at compile time. We will obtain the name of the lambda 1330b57cec5SDimitry Andric // from the first template pameter from __func's vtable. We will look up 1340b57cec5SDimitry Andric // the lambda's operator()() and obtain the line table entry. 1350b57cec5SDimitry Andric // 2) a lambda we know at runtime. A pointer to the lambdas __invoke method 1360b57cec5SDimitry Andric // will be stored after the vtable. We will obtain the lambdas name from 1370b57cec5SDimitry Andric // this entry and lookup operator()() and obtain the line table entry. 1380b57cec5SDimitry Andric // 3) a callable object via operator()(). We will obtain the name of the 1390b57cec5SDimitry Andric // object from the first template parameter from __func's vtable. We will 140480093f4SDimitry Andric // look up the objects operator()() and obtain the line table entry. 1410b57cec5SDimitry Andric // 4) a member function. A pointer to the function will stored after the 1420b57cec5SDimitry Andric // we will obtain the name from this pointer. 1430b57cec5SDimitry Andric // 5) a free function. A pointer to the function will stored after the vtable 1440b57cec5SDimitry Andric // we will obtain the name from this pointer. 14506c3fb27SDimitry Andric ValueObjectSP member_f_(valobj_sp->GetChildMemberWithName("__f_")); 1460b57cec5SDimitry Andric 14781ad6265SDimitry Andric if (member_f_) { 14806c3fb27SDimitry Andric ValueObjectSP sub_member_f_(member_f_->GetChildMemberWithName("__f_")); 1490b57cec5SDimitry Andric 15081ad6265SDimitry Andric if (sub_member_f_) 15181ad6265SDimitry Andric member_f_ = sub_member_f_; 1520b57cec5SDimitry Andric } 1530b57cec5SDimitry Andric 15481ad6265SDimitry Andric if (!member_f_) 155e8d8bef9SDimitry Andric return optional_info; 156e8d8bef9SDimitry Andric 15781ad6265SDimitry Andric lldb::addr_t member_f_pointer_value = member_f_->GetValueAsUnsigned(0); 1580b57cec5SDimitry Andric 15981ad6265SDimitry Andric optional_info.member_f_pointer_value = member_f_pointer_value; 1600b57cec5SDimitry Andric 16181ad6265SDimitry Andric if (!member_f_pointer_value) 162480093f4SDimitry Andric return optional_info; 163480093f4SDimitry Andric 1640b57cec5SDimitry Andric ExecutionContext exe_ctx(valobj_sp->GetExecutionContextRef()); 1650b57cec5SDimitry Andric Process *process = exe_ctx.GetProcessPtr(); 1660b57cec5SDimitry Andric 1670b57cec5SDimitry Andric if (process == nullptr) 1680b57cec5SDimitry Andric return optional_info; 1690b57cec5SDimitry Andric 1700b57cec5SDimitry Andric uint32_t address_size = process->GetAddressByteSize(); 1710b57cec5SDimitry Andric Status status; 1720b57cec5SDimitry Andric 1730b57cec5SDimitry Andric // First item pointed to by __f_ should be the pointer to the vtable for 1740b57cec5SDimitry Andric // a __base object. 1750b57cec5SDimitry Andric lldb::addr_t vtable_address = 17681ad6265SDimitry Andric process->ReadPointerFromMemory(member_f_pointer_value, status); 1770b57cec5SDimitry Andric 1780b57cec5SDimitry Andric if (status.Fail()) 1790b57cec5SDimitry Andric return optional_info; 1800b57cec5SDimitry Andric 181480093f4SDimitry Andric lldb::addr_t vtable_address_first_entry = 182480093f4SDimitry Andric process->ReadPointerFromMemory(vtable_address + address_size, status); 183480093f4SDimitry Andric 184480093f4SDimitry Andric if (status.Fail()) 185480093f4SDimitry Andric return optional_info; 186480093f4SDimitry Andric 18781ad6265SDimitry Andric lldb::addr_t address_after_vtable = member_f_pointer_value + address_size; 188480093f4SDimitry Andric // As commented above we may not have a function pointer but if we do we will 1890b57cec5SDimitry Andric // need it. 1900b57cec5SDimitry Andric lldb::addr_t possible_function_address = 1910b57cec5SDimitry Andric process->ReadPointerFromMemory(address_after_vtable, status); 1920b57cec5SDimitry Andric 1930b57cec5SDimitry Andric if (status.Fail()) 1940b57cec5SDimitry Andric return optional_info; 1950b57cec5SDimitry Andric 1960b57cec5SDimitry Andric Target &target = process->GetTarget(); 1970b57cec5SDimitry Andric 1980b57cec5SDimitry Andric if (target.GetSectionLoadList().IsEmpty()) 1990b57cec5SDimitry Andric return optional_info; 2000b57cec5SDimitry Andric 201480093f4SDimitry Andric Address vtable_first_entry_resolved; 202480093f4SDimitry Andric 203480093f4SDimitry Andric if (!target.GetSectionLoadList().ResolveLoadAddress( 204480093f4SDimitry Andric vtable_address_first_entry, vtable_first_entry_resolved)) 205480093f4SDimitry Andric return optional_info; 206480093f4SDimitry Andric 2070b57cec5SDimitry Andric Address vtable_addr_resolved; 2080b57cec5SDimitry Andric SymbolContext sc; 209480093f4SDimitry Andric Symbol *symbol = nullptr; 2100b57cec5SDimitry Andric 2110b57cec5SDimitry Andric if (!target.GetSectionLoadList().ResolveLoadAddress(vtable_address, 2120b57cec5SDimitry Andric vtable_addr_resolved)) 2130b57cec5SDimitry Andric return optional_info; 2140b57cec5SDimitry Andric 2150b57cec5SDimitry Andric target.GetImages().ResolveSymbolContextForAddress( 2160b57cec5SDimitry Andric vtable_addr_resolved, eSymbolContextEverything, sc); 2170b57cec5SDimitry Andric symbol = sc.symbol; 2180b57cec5SDimitry Andric 2190b57cec5SDimitry Andric if (symbol == nullptr) 2200b57cec5SDimitry Andric return optional_info; 2210b57cec5SDimitry Andric 222480093f4SDimitry Andric llvm::StringRef vtable_name(symbol->GetName().GetStringRef()); 2230b57cec5SDimitry Andric bool found_expected_start_string = 2245f757f3fSDimitry Andric vtable_name.starts_with("vtable for std::__1::__function::__func<"); 2250b57cec5SDimitry Andric 2260b57cec5SDimitry Andric if (!found_expected_start_string) 2270b57cec5SDimitry Andric return optional_info; 2280b57cec5SDimitry Andric 2290b57cec5SDimitry Andric // Given case 1 or 3 we have a vtable name, we are want to extract the first 2300b57cec5SDimitry Andric // template parameter 2310b57cec5SDimitry Andric // 2320b57cec5SDimitry Andric // ... __func<main::$_0, std::__1::allocator<main::$_0> ... 2330b57cec5SDimitry Andric // ^^^^^^^^^ 2340b57cec5SDimitry Andric // 235480093f4SDimitry Andric // We could see names such as: 236480093f4SDimitry Andric // main::$_0 237480093f4SDimitry Andric // Bar::add_num2(int)::'lambda'(int) 238480093f4SDimitry Andric // Bar 239480093f4SDimitry Andric // 2400b57cec5SDimitry Andric // We do this by find the first < and , and extracting in between. 2410b57cec5SDimitry Andric // 2420b57cec5SDimitry Andric // This covers the case of the lambda known at compile time. 2430b57cec5SDimitry Andric size_t first_open_angle_bracket = vtable_name.find('<') + 1; 2440b57cec5SDimitry Andric size_t first_comma = vtable_name.find(','); 2450b57cec5SDimitry Andric 2460b57cec5SDimitry Andric llvm::StringRef first_template_parameter = 2470b57cec5SDimitry Andric vtable_name.slice(first_open_angle_bracket, first_comma); 2480b57cec5SDimitry Andric 2490b57cec5SDimitry Andric Address function_address_resolved; 2500b57cec5SDimitry Andric 2510b57cec5SDimitry Andric // Setup for cases 2, 4 and 5 we have a pointer to a function after the 2520b57cec5SDimitry Andric // vtable. We will use a process of elimination to drop through each case 2530b57cec5SDimitry Andric // and obtain the data we need. 2540b57cec5SDimitry Andric if (target.GetSectionLoadList().ResolveLoadAddress( 2550b57cec5SDimitry Andric possible_function_address, function_address_resolved)) { 2560b57cec5SDimitry Andric target.GetImages().ResolveSymbolContextForAddress( 2570b57cec5SDimitry Andric function_address_resolved, eSymbolContextEverything, sc); 2580b57cec5SDimitry Andric symbol = sc.symbol; 2590b57cec5SDimitry Andric } 2600b57cec5SDimitry Andric 261480093f4SDimitry Andric // These conditions are used several times to simplify statements later on. 26281ad6265SDimitry Andric bool has_invoke = 263480093f4SDimitry Andric (symbol ? symbol->GetName().GetStringRef().contains("__invoke") : false); 264480093f4SDimitry Andric auto calculate_symbol_context_helper = [](auto &t, 265480093f4SDimitry Andric SymbolContextList &sc_list) { 266480093f4SDimitry Andric SymbolContext sc; 267480093f4SDimitry Andric t->CalculateSymbolContext(&sc); 268480093f4SDimitry Andric sc_list.Append(sc); 2690b57cec5SDimitry Andric }; 2700b57cec5SDimitry Andric 271480093f4SDimitry Andric // Case 2 27281ad6265SDimitry Andric if (has_invoke) { 2730b57cec5SDimitry Andric SymbolContextList scl; 274480093f4SDimitry Andric calculate_symbol_context_helper(symbol, scl); 2750b57cec5SDimitry Andric 276480093f4SDimitry Andric return line_entry_helper(target, scl[0], symbol, first_template_parameter, 27781ad6265SDimitry Andric has_invoke); 2780b57cec5SDimitry Andric } 2790b57cec5SDimitry Andric 2800b57cec5SDimitry Andric // Case 4 or 5 2815f757f3fSDimitry Andric if (symbol && !symbol->GetName().GetStringRef().starts_with("vtable for") && 28281ad6265SDimitry Andric !contains_lambda_identifier(first_template_parameter) && !has_invoke) { 2830b57cec5SDimitry Andric optional_info.callable_case = 2840b57cec5SDimitry Andric LibCppStdFunctionCallableCase::FreeOrMemberFunction; 2850b57cec5SDimitry Andric optional_info.callable_address = function_address_resolved; 2860b57cec5SDimitry Andric optional_info.callable_symbol = *symbol; 2870b57cec5SDimitry Andric 2880b57cec5SDimitry Andric return optional_info; 2890b57cec5SDimitry Andric } 2900b57cec5SDimitry Andric 291480093f4SDimitry Andric std::string func_to_match = first_template_parameter.str(); 292480093f4SDimitry Andric 293480093f4SDimitry Andric auto it = CallableLookupCache.find(func_to_match); 294480093f4SDimitry Andric if (it != CallableLookupCache.end()) 295480093f4SDimitry Andric return it->second; 296480093f4SDimitry Andric 297480093f4SDimitry Andric SymbolContextList scl; 298480093f4SDimitry Andric 299480093f4SDimitry Andric CompileUnit *vtable_cu = 300480093f4SDimitry Andric vtable_first_entry_resolved.CalculateSymbolContextCompileUnit(); 301480093f4SDimitry Andric llvm::StringRef name_to_use = func_to_match; 302480093f4SDimitry Andric 303480093f4SDimitry Andric // Case 3, we have a callable object instead of a lambda 304480093f4SDimitry Andric // 305480093f4SDimitry Andric // TODO 306480093f4SDimitry Andric // We currently don't support this case a callable object may have multiple 307480093f4SDimitry Andric // operator()() varying on const/non-const and number of arguments and we 308480093f4SDimitry Andric // don't have a way to currently distinguish them so we will bail out now. 309480093f4SDimitry Andric if (!contains_lambda_identifier(name_to_use)) 310480093f4SDimitry Andric return optional_info; 311480093f4SDimitry Andric 31281ad6265SDimitry Andric if (vtable_cu && !has_invoke) { 313480093f4SDimitry Andric lldb::FunctionSP func_sp = 314480093f4SDimitry Andric vtable_cu->FindFunction([name_to_use](const FunctionSP &f) { 315480093f4SDimitry Andric auto name = f->GetName().GetStringRef(); 3165f757f3fSDimitry Andric if (name.starts_with(name_to_use) && name.contains("operator")) 317480093f4SDimitry Andric return true; 318480093f4SDimitry Andric 319480093f4SDimitry Andric return false; 320480093f4SDimitry Andric }); 321480093f4SDimitry Andric 322480093f4SDimitry Andric if (func_sp) { 323480093f4SDimitry Andric calculate_symbol_context_helper(func_sp, scl); 324480093f4SDimitry Andric } 325480093f4SDimitry Andric } 326480093f4SDimitry Andric 327fe6060f1SDimitry Andric if (symbol == nullptr) 328fe6060f1SDimitry Andric return optional_info; 329fe6060f1SDimitry Andric 330480093f4SDimitry Andric // Case 1 or 3 331480093f4SDimitry Andric if (scl.GetSize() >= 1) { 332480093f4SDimitry Andric optional_info = line_entry_helper(target, scl[0], symbol, 33381ad6265SDimitry Andric first_template_parameter, has_invoke); 334480093f4SDimitry Andric } 335480093f4SDimitry Andric 336480093f4SDimitry Andric CallableLookupCache[func_to_match] = optional_info; 337480093f4SDimitry Andric 3380b57cec5SDimitry Andric return optional_info; 3390b57cec5SDimitry Andric } 3400b57cec5SDimitry Andric 3410b57cec5SDimitry Andric lldb::ThreadPlanSP 3420b57cec5SDimitry Andric CPPLanguageRuntime::GetStepThroughTrampolinePlan(Thread &thread, 3430b57cec5SDimitry Andric bool stop_others) { 3440b57cec5SDimitry Andric ThreadPlanSP ret_plan_sp; 3450b57cec5SDimitry Andric 3460b57cec5SDimitry Andric lldb::addr_t curr_pc = thread.GetRegisterContext()->GetPC(); 3470b57cec5SDimitry Andric 3480b57cec5SDimitry Andric TargetSP target_sp(thread.CalculateTarget()); 3490b57cec5SDimitry Andric 3500b57cec5SDimitry Andric if (target_sp->GetSectionLoadList().IsEmpty()) 3510b57cec5SDimitry Andric return ret_plan_sp; 3520b57cec5SDimitry Andric 3530b57cec5SDimitry Andric Address pc_addr_resolved; 3540b57cec5SDimitry Andric SymbolContext sc; 3550b57cec5SDimitry Andric Symbol *symbol; 3560b57cec5SDimitry Andric 3570b57cec5SDimitry Andric if (!target_sp->GetSectionLoadList().ResolveLoadAddress(curr_pc, 3580b57cec5SDimitry Andric pc_addr_resolved)) 3590b57cec5SDimitry Andric return ret_plan_sp; 3600b57cec5SDimitry Andric 3610b57cec5SDimitry Andric target_sp->GetImages().ResolveSymbolContextForAddress( 3620b57cec5SDimitry Andric pc_addr_resolved, eSymbolContextEverything, sc); 3630b57cec5SDimitry Andric symbol = sc.symbol; 3640b57cec5SDimitry Andric 3650b57cec5SDimitry Andric if (symbol == nullptr) 3660b57cec5SDimitry Andric return ret_plan_sp; 3670b57cec5SDimitry Andric 3680b57cec5SDimitry Andric llvm::StringRef function_name(symbol->GetName().GetCString()); 3690b57cec5SDimitry Andric 3700b57cec5SDimitry Andric // Handling the case where we are attempting to step into std::function. 3710b57cec5SDimitry Andric // The behavior will be that we will attempt to obtain the wrapped 3720b57cec5SDimitry Andric // callable via FindLibCppStdFunctionCallableInfo() and if we find it we 3730b57cec5SDimitry Andric // will return a ThreadPlanRunToAddress to the callable. Therefore we will 3740b57cec5SDimitry Andric // step into the wrapped callable. 3750b57cec5SDimitry Andric // 3760b57cec5SDimitry Andric bool found_expected_start_string = 3775f757f3fSDimitry Andric function_name.starts_with("std::__1::function<"); 3780b57cec5SDimitry Andric 3790b57cec5SDimitry Andric if (!found_expected_start_string) 3800b57cec5SDimitry Andric return ret_plan_sp; 3810b57cec5SDimitry Andric 3820b57cec5SDimitry Andric AddressRange range_of_curr_func; 3830b57cec5SDimitry Andric sc.GetAddressRange(eSymbolContextEverything, 0, false, range_of_curr_func); 3840b57cec5SDimitry Andric 3850b57cec5SDimitry Andric StackFrameSP frame = thread.GetStackFrameAtIndex(0); 3860b57cec5SDimitry Andric 3870b57cec5SDimitry Andric if (frame) { 3880b57cec5SDimitry Andric ValueObjectSP value_sp = frame->FindVariable(g_this); 3890b57cec5SDimitry Andric 3900b57cec5SDimitry Andric CPPLanguageRuntime::LibCppStdFunctionCallableInfo callable_info = 3910b57cec5SDimitry Andric FindLibCppStdFunctionCallableInfo(value_sp); 3920b57cec5SDimitry Andric 3930b57cec5SDimitry Andric if (callable_info.callable_case != LibCppStdFunctionCallableCase::Invalid && 3940b57cec5SDimitry Andric value_sp->GetValueIsValid()) { 3950b57cec5SDimitry Andric // We found the std::function wrapped callable and we have its address. 3960b57cec5SDimitry Andric // We now create a ThreadPlan to run to the callable. 3970b57cec5SDimitry Andric ret_plan_sp = std::make_shared<ThreadPlanRunToAddress>( 3980b57cec5SDimitry Andric thread, callable_info.callable_address, stop_others); 3990b57cec5SDimitry Andric return ret_plan_sp; 4000b57cec5SDimitry Andric } else { 4010b57cec5SDimitry Andric // We are in std::function but we could not obtain the callable. 4020b57cec5SDimitry Andric // We create a ThreadPlan to keep stepping through using the address range 4030b57cec5SDimitry Andric // of the current function. 4040b57cec5SDimitry Andric ret_plan_sp = std::make_shared<ThreadPlanStepInRange>( 405fe6060f1SDimitry Andric thread, range_of_curr_func, sc, nullptr, eOnlyThisThread, 406fe6060f1SDimitry Andric eLazyBoolYes, eLazyBoolYes); 4070b57cec5SDimitry Andric return ret_plan_sp; 4080b57cec5SDimitry Andric } 4090b57cec5SDimitry Andric } 4100b57cec5SDimitry Andric 4110b57cec5SDimitry Andric return ret_plan_sp; 4120b57cec5SDimitry Andric } 413