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> 10dd060bdeSAdrian Vogelsgesang #include <iostream> 11e0678ca5SAlex Langford 12e0678ca5SAlex Langford #include <memory> 13e0678ca5SAlex Langford 14e0678ca5SAlex Langford #include "CPPLanguageRuntime.h" 15e0678ca5SAlex Langford 16e0678ca5SAlex Langford #include "llvm/ADT/StringRef.h" 17e0678ca5SAlex Langford 18e0678ca5SAlex Langford #include "lldb/Symbol/Block.h" 19e0678ca5SAlex Langford #include "lldb/Symbol/Variable.h" 20e0678ca5SAlex Langford #include "lldb/Symbol/VariableList.h" 21e0678ca5SAlex Langford 22e0678ca5SAlex Langford #include "lldb/Core/PluginManager.h" 23e0678ca5SAlex Langford #include "lldb/Core/UniqueCStringMap.h" 2491e94a70Sshafik #include "lldb/Symbol/CompileUnit.h" 25e0678ca5SAlex Langford #include "lldb/Target/ABI.h" 26e0678ca5SAlex Langford #include "lldb/Target/ExecutionContext.h" 27e0678ca5SAlex Langford #include "lldb/Target/RegisterContext.h" 28e0678ca5SAlex Langford #include "lldb/Target/SectionLoadList.h" 29e0678ca5SAlex Langford #include "lldb/Target/StackFrame.h" 303c0fba4fSAdrian Prantl #include "lldb/Target/StackFrameRecognizer.h" 31e0678ca5SAlex Langford #include "lldb/Target/ThreadPlanRunToAddress.h" 32e0678ca5SAlex Langford #include "lldb/Target/ThreadPlanStepInRange.h" 3391e94a70Sshafik #include "lldb/Utility/Timer.h" 34e0678ca5SAlex Langford 35e0678ca5SAlex Langford using namespace lldb; 36e0678ca5SAlex Langford using namespace lldb_private; 37e0678ca5SAlex Langford 38e0678ca5SAlex Langford static ConstString g_this = ConstString("this"); 39b837361bSHaojian Wu // Artificial coroutine-related variables emitted by clang. 40b837361bSHaojian Wu static ConstString g_promise = ConstString("__promise"); 41b837361bSHaojian Wu static ConstString g_coro_frame = ConstString("__coro_frame"); 42e0678ca5SAlex Langford 43e0678ca5SAlex Langford char CPPLanguageRuntime::ID = 0; 44e0678ca5SAlex Langford 453c0fba4fSAdrian Prantl /// A frame recognizer that is installed to hide libc++ implementation 463c0fba4fSAdrian Prantl /// details from the backtrace. 473c0fba4fSAdrian Prantl class LibCXXFrameRecognizer : public StackFrameRecognizer { 487e16571eSAdrian Vogelsgesang std::array<RegularExpression, 2> m_hidden_regex; 493c0fba4fSAdrian Prantl RecognizedStackFrameSP m_hidden_frame; 503c0fba4fSAdrian Prantl 513c0fba4fSAdrian Prantl struct LibCXXHiddenFrame : public RecognizedStackFrame { 523c0fba4fSAdrian Prantl bool ShouldHide() override { return true; } 533c0fba4fSAdrian Prantl }; 543c0fba4fSAdrian Prantl 553c0fba4fSAdrian Prantl public: 563c0fba4fSAdrian Prantl LibCXXFrameRecognizer() 57dd060bdeSAdrian Vogelsgesang : m_hidden_regex{ 587e16571eSAdrian Vogelsgesang // internal implementation details in the `std::` namespace 59dd060bdeSAdrian Vogelsgesang // std::__1::__function::__alloc_func<void (*)(), std::__1::allocator<void (*)()>, void ()>::operator()[abi:ne200000] 60dd060bdeSAdrian Vogelsgesang // std::__1::__function::__func<void (*)(), std::__1::allocator<void (*)()>, void ()>::operator() 61dd060bdeSAdrian Vogelsgesang // std::__1::__function::__value_func<void ()>::operator()[abi:ne200000]() const 62dd060bdeSAdrian Vogelsgesang // std::__2::__function::__policy_invoker<void (int, int)>::__call_impl[abi:ne200000]<std::__2::__function::__default_alloc_func<int (*)(int, int), int (int, int)>> 63dd060bdeSAdrian Vogelsgesang // std::__1::__invoke[abi:ne200000]<void (*&)()> 64dd060bdeSAdrian Vogelsgesang // std::__1::__invoke_void_return_wrapper<void, true>::__call[abi:ne200000]<void (*&)()> 657e16571eSAdrian Vogelsgesang RegularExpression{R"(^std::__[^:]*::__)"}, 667e16571eSAdrian Vogelsgesang // internal implementation details in the `std::ranges` namespace 677e16571eSAdrian Vogelsgesang // std::__1::ranges::__sort::__sort_fn_impl[abi:ne200000]<std::__1::__wrap_iter<int*>, std::__1::__wrap_iter<int*>, bool (*)(int, int), std::__1::identity> 687e16571eSAdrian Vogelsgesang RegularExpression{R"(^std::__[^:]*::ranges::__)"}, 69dd060bdeSAdrian Vogelsgesang }, 703c0fba4fSAdrian Prantl m_hidden_frame(new LibCXXHiddenFrame()) {} 713c0fba4fSAdrian Prantl 723c0fba4fSAdrian Prantl std::string GetName() override { return "libc++ frame recognizer"; } 733c0fba4fSAdrian Prantl 743c0fba4fSAdrian Prantl lldb::RecognizedStackFrameSP 753c0fba4fSAdrian Prantl RecognizeFrame(lldb::StackFrameSP frame_sp) override { 763c0fba4fSAdrian Prantl if (!frame_sp) 773c0fba4fSAdrian Prantl return {}; 783c0fba4fSAdrian Prantl const auto &sc = frame_sp->GetSymbolContext(lldb::eSymbolContextFunction); 793c0fba4fSAdrian Prantl if (!sc.function) 803c0fba4fSAdrian Prantl return {}; 813c0fba4fSAdrian Prantl 827e16571eSAdrian Vogelsgesang // Check if we have a regex match 837e16571eSAdrian Vogelsgesang for (RegularExpression &r : m_hidden_regex) { 847e16571eSAdrian Vogelsgesang if (!r.Execute(sc.function->GetNameNoArguments())) 857e16571eSAdrian Vogelsgesang continue; 867e16571eSAdrian Vogelsgesang 877e16571eSAdrian Vogelsgesang // Only hide this frame if the immediate caller is also within libc++. 887e16571eSAdrian Vogelsgesang lldb::ThreadSP thread_sp = frame_sp->GetThread(); 897e16571eSAdrian Vogelsgesang if (!thread_sp) 907e16571eSAdrian Vogelsgesang return {}; 917e16571eSAdrian Vogelsgesang lldb::StackFrameSP parent_frame_sp = 927e16571eSAdrian Vogelsgesang thread_sp->GetStackFrameAtIndex(frame_sp->GetFrameIndex() + 1); 937e16571eSAdrian Vogelsgesang if (!parent_frame_sp) 947e16571eSAdrian Vogelsgesang return {}; 957e16571eSAdrian Vogelsgesang const auto &parent_sc = 967e16571eSAdrian Vogelsgesang parent_frame_sp->GetSymbolContext(lldb::eSymbolContextFunction); 977e16571eSAdrian Vogelsgesang if (!parent_sc.function) 987e16571eSAdrian Vogelsgesang return {}; 997e16571eSAdrian Vogelsgesang if (parent_sc.function->GetNameNoArguments().GetStringRef().starts_with( 1007e16571eSAdrian Vogelsgesang "std::")) 1013c0fba4fSAdrian Prantl return m_hidden_frame; 1027e16571eSAdrian Vogelsgesang } 1033c0fba4fSAdrian Prantl 1043c0fba4fSAdrian Prantl return {}; 1053c0fba4fSAdrian Prantl } 1063c0fba4fSAdrian Prantl }; 1073c0fba4fSAdrian Prantl 108e0678ca5SAlex Langford CPPLanguageRuntime::CPPLanguageRuntime(Process *process) 1093c0fba4fSAdrian Prantl : LanguageRuntime(process) { 1103c0fba4fSAdrian Prantl if (process) 1113c0fba4fSAdrian Prantl process->GetTarget().GetFrameRecognizerManager().AddRecognizer( 1123c0fba4fSAdrian Prantl StackFrameRecognizerSP(new LibCXXFrameRecognizer()), {}, 113dd060bdeSAdrian Vogelsgesang std::make_shared<RegularExpression>("^std::__[^:]*::"), 114dd060bdeSAdrian Vogelsgesang /*mangling_preference=*/Mangled::ePreferDemangledWithoutArguments, 115dd060bdeSAdrian Vogelsgesang /*first_instruction_only=*/false); 1163c0fba4fSAdrian Prantl } 117e0678ca5SAlex Langford 118efb328f6SEric Christopher bool CPPLanguageRuntime::IsAllowedRuntimeValue(ConstString name) { 119b837361bSHaojian Wu return name == g_this || name == g_promise || name == g_coro_frame; 120e0678ca5SAlex Langford } 121e0678ca5SAlex Langford 122f900644aSAdrian Prantl llvm::Error CPPLanguageRuntime::GetObjectDescription(Stream &str, 123e0678ca5SAlex Langford ValueObject &object) { 124e0678ca5SAlex Langford // C++ has no generic way to do this. 125f900644aSAdrian Prantl return llvm::createStringError("C++ does not support object descriptions"); 126e0678ca5SAlex Langford } 127e0678ca5SAlex Langford 128f900644aSAdrian Prantl llvm::Error 129f900644aSAdrian Prantl CPPLanguageRuntime::GetObjectDescription(Stream &str, Value &value, 130f900644aSAdrian Prantl ExecutionContextScope *exe_scope) { 131e0678ca5SAlex Langford // C++ has no generic way to do this. 132f900644aSAdrian Prantl return llvm::createStringError("C++ does not support object descriptions"); 133e0678ca5SAlex Langford } 134e0678ca5SAlex Langford 13591e94a70Sshafik bool contains_lambda_identifier(llvm::StringRef &str_ref) { 13691e94a70Sshafik return str_ref.contains("$_") || str_ref.contains("'lambda'"); 1376612fabcSPavel Labath } 13891e94a70Sshafik 13991e94a70Sshafik CPPLanguageRuntime::LibCppStdFunctionCallableInfo 14091e94a70Sshafik line_entry_helper(Target &target, const SymbolContext &sc, Symbol *symbol, 141dd060bdeSAdrian Vogelsgesang llvm::StringRef first_template_param_sref, bool has_invoke) { 14291e94a70Sshafik 14391e94a70Sshafik CPPLanguageRuntime::LibCppStdFunctionCallableInfo optional_info; 14491e94a70Sshafik 14591e94a70Sshafik AddressRange range; 14691e94a70Sshafik sc.GetAddressRange(eSymbolContextEverything, 0, false, range); 14791e94a70Sshafik 14891e94a70Sshafik Address address = range.GetBaseAddress(); 14991e94a70Sshafik 15091e94a70Sshafik Address addr; 15191e94a70Sshafik if (target.ResolveLoadAddress(address.GetCallableLoadAddress(&target), 15291e94a70Sshafik addr)) { 15391e94a70Sshafik LineEntry line_entry; 15491e94a70Sshafik addr.CalculateSymbolContextLineEntry(line_entry); 15591e94a70Sshafik 15680a11e08SShafik Yaghmour if (contains_lambda_identifier(first_template_param_sref) || has_invoke) { 15791e94a70Sshafik // Case 1 and 2 15891e94a70Sshafik optional_info.callable_case = lldb_private::CPPLanguageRuntime:: 15991e94a70Sshafik LibCppStdFunctionCallableCase::Lambda; 16091e94a70Sshafik } else { 16191e94a70Sshafik // Case 3 16291e94a70Sshafik optional_info.callable_case = lldb_private::CPPLanguageRuntime:: 16391e94a70Sshafik LibCppStdFunctionCallableCase::CallableObject; 16491e94a70Sshafik } 16591e94a70Sshafik 16691e94a70Sshafik optional_info.callable_symbol = *symbol; 16791e94a70Sshafik optional_info.callable_line_entry = line_entry; 16891e94a70Sshafik optional_info.callable_address = addr; 16991e94a70Sshafik } 17091e94a70Sshafik 17191e94a70Sshafik return optional_info; 17291e94a70Sshafik } 17391e94a70Sshafik 174e0678ca5SAlex Langford CPPLanguageRuntime::LibCppStdFunctionCallableInfo 175e0678ca5SAlex Langford CPPLanguageRuntime::FindLibCppStdFunctionCallableInfo( 176e0678ca5SAlex Langford lldb::ValueObjectSP &valobj_sp) { 1775c1c8443SJonas Devlieghere LLDB_SCOPED_TIMER(); 17891e94a70Sshafik 179e0678ca5SAlex Langford LibCppStdFunctionCallableInfo optional_info; 180e0678ca5SAlex Langford 181e0678ca5SAlex Langford if (!valobj_sp) 182e0678ca5SAlex Langford return optional_info; 183e0678ca5SAlex Langford 184e0678ca5SAlex Langford // Member __f_ has type __base*, the contents of which will hold: 185e0678ca5SAlex Langford // 1) a vtable entry which may hold type information needed to discover the 186e0678ca5SAlex Langford // lambda being called 187e0678ca5SAlex Langford // 2) possibly hold a pointer to the callable object 188e0678ca5SAlex Langford // e.g. 189e0678ca5SAlex Langford // 190e0678ca5SAlex Langford // (lldb) frame var -R f_display 191e0678ca5SAlex Langford // (std::__1::function<void (int)>) f_display = { 192e0678ca5SAlex Langford // __buf_ = { 193e0678ca5SAlex Langford // … 194e0678ca5SAlex Langford // } 195e0678ca5SAlex Langford // __f_ = 0x00007ffeefbffa00 196e0678ca5SAlex Langford // } 197e0678ca5SAlex Langford // (lldb) memory read -fA 0x00007ffeefbffa00 198e0678ca5SAlex Langford // 0x7ffeefbffa00: ... `vtable for std::__1::__function::__func<void (*) ... 199e0678ca5SAlex Langford // 0x7ffeefbffa08: ... `print_num(int) at std_function_cppreference_exam ... 200e0678ca5SAlex Langford // 201e0678ca5SAlex Langford // We will be handling five cases below, std::function is wrapping: 202e0678ca5SAlex Langford // 203e0678ca5SAlex Langford // 1) a lambda we know at compile time. We will obtain the name of the lambda 204e0678ca5SAlex Langford // from the first template pameter from __func's vtable. We will look up 205e0678ca5SAlex Langford // the lambda's operator()() and obtain the line table entry. 206e0678ca5SAlex Langford // 2) a lambda we know at runtime. A pointer to the lambdas __invoke method 207e0678ca5SAlex Langford // will be stored after the vtable. We will obtain the lambdas name from 208e0678ca5SAlex Langford // this entry and lookup operator()() and obtain the line table entry. 209e0678ca5SAlex Langford // 3) a callable object via operator()(). We will obtain the name of the 210e0678ca5SAlex Langford // object from the first template parameter from __func's vtable. We will 21191e94a70Sshafik // look up the objects operator()() and obtain the line table entry. 212e0678ca5SAlex Langford // 4) a member function. A pointer to the function will stored after the 213e0678ca5SAlex Langford // we will obtain the name from this pointer. 214e0678ca5SAlex Langford // 5) a free function. A pointer to the function will stored after the vtable 215e0678ca5SAlex Langford // we will obtain the name from this pointer. 2167d4fcd41SDave Lee ValueObjectSP member_f_(valobj_sp->GetChildMemberWithName("__f_")); 217e0678ca5SAlex Langford 21880a11e08SShafik Yaghmour if (member_f_) { 2197d4fcd41SDave Lee ValueObjectSP sub_member_f_(member_f_->GetChildMemberWithName("__f_")); 220e0678ca5SAlex Langford 22180a11e08SShafik Yaghmour if (sub_member_f_) 22280a11e08SShafik Yaghmour member_f_ = sub_member_f_; 223e0678ca5SAlex Langford } 224e0678ca5SAlex Langford 22580a11e08SShafik Yaghmour if (!member_f_) 226a079f619Sshafik return optional_info; 227a079f619Sshafik 22880a11e08SShafik Yaghmour lldb::addr_t member_f_pointer_value = member_f_->GetValueAsUnsigned(0); 229e0678ca5SAlex Langford 23080a11e08SShafik Yaghmour optional_info.member_f_pointer_value = member_f_pointer_value; 231e0678ca5SAlex Langford 23280a11e08SShafik Yaghmour if (!member_f_pointer_value) 23391e94a70Sshafik return optional_info; 23491e94a70Sshafik 235e0678ca5SAlex Langford ExecutionContext exe_ctx(valobj_sp->GetExecutionContextRef()); 236e0678ca5SAlex Langford Process *process = exe_ctx.GetProcessPtr(); 237e0678ca5SAlex Langford 238e0678ca5SAlex Langford if (process == nullptr) 239e0678ca5SAlex Langford return optional_info; 240e0678ca5SAlex Langford 241e0678ca5SAlex Langford uint32_t address_size = process->GetAddressByteSize(); 242e0678ca5SAlex Langford Status status; 243e0678ca5SAlex Langford 244e0678ca5SAlex Langford // First item pointed to by __f_ should be the pointer to the vtable for 245e0678ca5SAlex Langford // a __base object. 246e0678ca5SAlex Langford lldb::addr_t vtable_address = 24780a11e08SShafik Yaghmour process->ReadPointerFromMemory(member_f_pointer_value, status); 248e0678ca5SAlex Langford 249e0678ca5SAlex Langford if (status.Fail()) 250e0678ca5SAlex Langford return optional_info; 251e0678ca5SAlex Langford 25291e94a70Sshafik lldb::addr_t vtable_address_first_entry = 25391e94a70Sshafik process->ReadPointerFromMemory(vtable_address + address_size, status); 25491e94a70Sshafik 25591e94a70Sshafik if (status.Fail()) 25691e94a70Sshafik return optional_info; 25791e94a70Sshafik 25880a11e08SShafik Yaghmour lldb::addr_t address_after_vtable = member_f_pointer_value + address_size; 25991e94a70Sshafik // As commented above we may not have a function pointer but if we do we will 260e0678ca5SAlex Langford // need it. 261e0678ca5SAlex Langford lldb::addr_t possible_function_address = 262e0678ca5SAlex Langford process->ReadPointerFromMemory(address_after_vtable, status); 263e0678ca5SAlex Langford 264e0678ca5SAlex Langford if (status.Fail()) 265e0678ca5SAlex Langford return optional_info; 266e0678ca5SAlex Langford 267e0678ca5SAlex Langford Target &target = process->GetTarget(); 268e0678ca5SAlex Langford 269*c4fb7180SGreg Clayton if (!target.HasLoadedSections()) 270e0678ca5SAlex Langford return optional_info; 271e0678ca5SAlex Langford 27291e94a70Sshafik Address vtable_first_entry_resolved; 27391e94a70Sshafik 274*c4fb7180SGreg Clayton if (!target.ResolveLoadAddress(vtable_address_first_entry, 275*c4fb7180SGreg Clayton vtable_first_entry_resolved)) 27691e94a70Sshafik return optional_info; 27791e94a70Sshafik 278e0678ca5SAlex Langford Address vtable_addr_resolved; 279e0678ca5SAlex Langford SymbolContext sc; 28091e94a70Sshafik Symbol *symbol = nullptr; 281e0678ca5SAlex Langford 282*c4fb7180SGreg Clayton if (!target.ResolveLoadAddress(vtable_address, vtable_addr_resolved)) 283e0678ca5SAlex Langford return optional_info; 284e0678ca5SAlex Langford 285e0678ca5SAlex Langford target.GetImages().ResolveSymbolContextForAddress( 286e0678ca5SAlex Langford vtable_addr_resolved, eSymbolContextEverything, sc); 287e0678ca5SAlex Langford symbol = sc.symbol; 288e0678ca5SAlex Langford 289e0678ca5SAlex Langford if (symbol == nullptr) 290e0678ca5SAlex Langford return optional_info; 291e0678ca5SAlex Langford 29291e94a70Sshafik llvm::StringRef vtable_name(symbol->GetName().GetStringRef()); 293e0678ca5SAlex Langford bool found_expected_start_string = 294744f3891SKazu Hirata vtable_name.starts_with("vtable for std::__1::__function::__func<"); 295e0678ca5SAlex Langford 296e0678ca5SAlex Langford if (!found_expected_start_string) 297e0678ca5SAlex Langford return optional_info; 298e0678ca5SAlex Langford 299e0678ca5SAlex Langford // Given case 1 or 3 we have a vtable name, we are want to extract the first 300e0678ca5SAlex Langford // template parameter 301e0678ca5SAlex Langford // 302e0678ca5SAlex Langford // ... __func<main::$_0, std::__1::allocator<main::$_0> ... 303e0678ca5SAlex Langford // ^^^^^^^^^ 304e0678ca5SAlex Langford // 30591e94a70Sshafik // We could see names such as: 30691e94a70Sshafik // main::$_0 30791e94a70Sshafik // Bar::add_num2(int)::'lambda'(int) 30891e94a70Sshafik // Bar 30991e94a70Sshafik // 310e0678ca5SAlex Langford // We do this by find the first < and , and extracting in between. 311e0678ca5SAlex Langford // 312e0678ca5SAlex Langford // This covers the case of the lambda known at compile time. 313e0678ca5SAlex Langford size_t first_open_angle_bracket = vtable_name.find('<') + 1; 314e0678ca5SAlex Langford size_t first_comma = vtable_name.find(','); 315e0678ca5SAlex Langford 316e0678ca5SAlex Langford llvm::StringRef first_template_parameter = 317e0678ca5SAlex Langford vtable_name.slice(first_open_angle_bracket, first_comma); 318e0678ca5SAlex Langford 319e0678ca5SAlex Langford Address function_address_resolved; 320e0678ca5SAlex Langford 321e0678ca5SAlex Langford // Setup for cases 2, 4 and 5 we have a pointer to a function after the 322e0678ca5SAlex Langford // vtable. We will use a process of elimination to drop through each case 323e0678ca5SAlex Langford // and obtain the data we need. 324*c4fb7180SGreg Clayton if (target.ResolveLoadAddress(possible_function_address, 325*c4fb7180SGreg Clayton function_address_resolved)) { 326e0678ca5SAlex Langford target.GetImages().ResolveSymbolContextForAddress( 327e0678ca5SAlex Langford function_address_resolved, eSymbolContextEverything, sc); 328e0678ca5SAlex Langford symbol = sc.symbol; 329e0678ca5SAlex Langford } 330e0678ca5SAlex Langford 33191e94a70Sshafik // These conditions are used several times to simplify statements later on. 33280a11e08SShafik Yaghmour bool has_invoke = 33391e94a70Sshafik (symbol ? symbol->GetName().GetStringRef().contains("__invoke") : false); 33491e94a70Sshafik auto calculate_symbol_context_helper = [](auto &t, 33591e94a70Sshafik SymbolContextList &sc_list) { 33691e94a70Sshafik SymbolContext sc; 33791e94a70Sshafik t->CalculateSymbolContext(&sc); 33891e94a70Sshafik sc_list.Append(sc); 339e18f4db2Sshafik }; 340e18f4db2Sshafik 34191e94a70Sshafik // Case 2 34280a11e08SShafik Yaghmour if (has_invoke) { 34391e94a70Sshafik SymbolContextList scl; 34491e94a70Sshafik calculate_symbol_context_helper(symbol, scl); 34591e94a70Sshafik 34691e94a70Sshafik return line_entry_helper(target, scl[0], symbol, first_template_parameter, 34780a11e08SShafik Yaghmour has_invoke); 34891e94a70Sshafik } 34991e94a70Sshafik 350e18f4db2Sshafik // Case 4 or 5 351744f3891SKazu Hirata if (symbol && !symbol->GetName().GetStringRef().starts_with("vtable for") && 35280a11e08SShafik Yaghmour !contains_lambda_identifier(first_template_parameter) && !has_invoke) { 353e18f4db2Sshafik optional_info.callable_case = 354e18f4db2Sshafik LibCppStdFunctionCallableCase::FreeOrMemberFunction; 355e18f4db2Sshafik optional_info.callable_address = function_address_resolved; 356e18f4db2Sshafik optional_info.callable_symbol = *symbol; 357e18f4db2Sshafik 358e18f4db2Sshafik return optional_info; 359e18f4db2Sshafik } 360e18f4db2Sshafik 36191e94a70Sshafik std::string func_to_match = first_template_parameter.str(); 362e0678ca5SAlex Langford 363e18f4db2Sshafik auto it = CallableLookupCache.find(func_to_match); 364e18f4db2Sshafik if (it != CallableLookupCache.end()) 365e18f4db2Sshafik return it->second; 366e18f4db2Sshafik 367e0678ca5SAlex Langford SymbolContextList scl; 368e0678ca5SAlex Langford 36991e94a70Sshafik CompileUnit *vtable_cu = 37091e94a70Sshafik vtable_first_entry_resolved.CalculateSymbolContextCompileUnit(); 37191e94a70Sshafik llvm::StringRef name_to_use = func_to_match; 372e0678ca5SAlex Langford 37391e94a70Sshafik // Case 3, we have a callable object instead of a lambda 37491e94a70Sshafik // 37591e94a70Sshafik // TODO 37691e94a70Sshafik // We currently don't support this case a callable object may have multiple 37791e94a70Sshafik // operator()() varying on const/non-const and number of arguments and we 37891e94a70Sshafik // don't have a way to currently distinguish them so we will bail out now. 37991e94a70Sshafik if (!contains_lambda_identifier(name_to_use)) 38091e94a70Sshafik return optional_info; 38191e94a70Sshafik 38280a11e08SShafik Yaghmour if (vtable_cu && !has_invoke) { 38391e94a70Sshafik lldb::FunctionSP func_sp = 38491e94a70Sshafik vtable_cu->FindFunction([name_to_use](const FunctionSP &f) { 38591e94a70Sshafik auto name = f->GetName().GetStringRef(); 386744f3891SKazu Hirata if (name.starts_with(name_to_use) && name.contains("operator")) 38791e94a70Sshafik return true; 38891e94a70Sshafik 38991e94a70Sshafik return false; 39091e94a70Sshafik }); 39191e94a70Sshafik 39291e94a70Sshafik if (func_sp) { 39391e94a70Sshafik calculate_symbol_context_helper(func_sp, scl); 39491e94a70Sshafik } 39591e94a70Sshafik } 39691e94a70Sshafik 397ebee4571SShafik Yaghmour if (symbol == nullptr) 398ebee4571SShafik Yaghmour return optional_info; 399ebee4571SShafik Yaghmour 40091e94a70Sshafik // Case 1 or 3 401e0678ca5SAlex Langford if (scl.GetSize() >= 1) { 40291e94a70Sshafik optional_info = line_entry_helper(target, scl[0], symbol, 40380a11e08SShafik Yaghmour first_template_parameter, has_invoke); 404e0678ca5SAlex Langford } 405e0678ca5SAlex Langford 406e18f4db2Sshafik CallableLookupCache[func_to_match] = optional_info; 407e0678ca5SAlex Langford 408e0678ca5SAlex Langford return optional_info; 409e0678ca5SAlex Langford } 410e0678ca5SAlex Langford 411e0678ca5SAlex Langford lldb::ThreadPlanSP 412e0678ca5SAlex Langford CPPLanguageRuntime::GetStepThroughTrampolinePlan(Thread &thread, 413e0678ca5SAlex Langford bool stop_others) { 414e0678ca5SAlex Langford ThreadPlanSP ret_plan_sp; 415e0678ca5SAlex Langford 416e0678ca5SAlex Langford lldb::addr_t curr_pc = thread.GetRegisterContext()->GetPC(); 417e0678ca5SAlex Langford 418e0678ca5SAlex Langford TargetSP target_sp(thread.CalculateTarget()); 419e0678ca5SAlex Langford 420*c4fb7180SGreg Clayton if (!target_sp->HasLoadedSections()) 421e0678ca5SAlex Langford return ret_plan_sp; 422e0678ca5SAlex Langford 423e0678ca5SAlex Langford Address pc_addr_resolved; 424e0678ca5SAlex Langford SymbolContext sc; 425e0678ca5SAlex Langford Symbol *symbol; 426e0678ca5SAlex Langford 427*c4fb7180SGreg Clayton if (!target_sp->ResolveLoadAddress(curr_pc, pc_addr_resolved)) 428e0678ca5SAlex Langford return ret_plan_sp; 429e0678ca5SAlex Langford 430e0678ca5SAlex Langford target_sp->GetImages().ResolveSymbolContextForAddress( 431e0678ca5SAlex Langford pc_addr_resolved, eSymbolContextEverything, sc); 432e0678ca5SAlex Langford symbol = sc.symbol; 433e0678ca5SAlex Langford 434e0678ca5SAlex Langford if (symbol == nullptr) 435e0678ca5SAlex Langford return ret_plan_sp; 436e0678ca5SAlex Langford 437e0678ca5SAlex Langford llvm::StringRef function_name(symbol->GetName().GetCString()); 438e0678ca5SAlex Langford 439e0678ca5SAlex Langford // Handling the case where we are attempting to step into std::function. 440e0678ca5SAlex Langford // The behavior will be that we will attempt to obtain the wrapped 441e0678ca5SAlex Langford // callable via FindLibCppStdFunctionCallableInfo() and if we find it we 442e0678ca5SAlex Langford // will return a ThreadPlanRunToAddress to the callable. Therefore we will 443e0678ca5SAlex Langford // step into the wrapped callable. 444e0678ca5SAlex Langford // 445e0678ca5SAlex Langford bool found_expected_start_string = 446744f3891SKazu Hirata function_name.starts_with("std::__1::function<"); 447e0678ca5SAlex Langford 448e0678ca5SAlex Langford if (!found_expected_start_string) 449e0678ca5SAlex Langford return ret_plan_sp; 450e0678ca5SAlex Langford 451e0678ca5SAlex Langford AddressRange range_of_curr_func; 452e0678ca5SAlex Langford sc.GetAddressRange(eSymbolContextEverything, 0, false, range_of_curr_func); 453e0678ca5SAlex Langford 454e0678ca5SAlex Langford StackFrameSP frame = thread.GetStackFrameAtIndex(0); 455e0678ca5SAlex Langford 456e0678ca5SAlex Langford if (frame) { 457e0678ca5SAlex Langford ValueObjectSP value_sp = frame->FindVariable(g_this); 458e0678ca5SAlex Langford 459e0678ca5SAlex Langford CPPLanguageRuntime::LibCppStdFunctionCallableInfo callable_info = 460e0678ca5SAlex Langford FindLibCppStdFunctionCallableInfo(value_sp); 461e0678ca5SAlex Langford 462e0678ca5SAlex Langford if (callable_info.callable_case != LibCppStdFunctionCallableCase::Invalid && 463e0678ca5SAlex Langford value_sp->GetValueIsValid()) { 464e0678ca5SAlex Langford // We found the std::function wrapped callable and we have its address. 465e0678ca5SAlex Langford // We now create a ThreadPlan to run to the callable. 466e0678ca5SAlex Langford ret_plan_sp = std::make_shared<ThreadPlanRunToAddress>( 467e0678ca5SAlex Langford thread, callable_info.callable_address, stop_others); 468e0678ca5SAlex Langford return ret_plan_sp; 469e0678ca5SAlex Langford } else { 470e0678ca5SAlex Langford // We are in std::function but we could not obtain the callable. 471e0678ca5SAlex Langford // We create a ThreadPlan to keep stepping through using the address range 472e0678ca5SAlex Langford // of the current function. 473e0678ca5SAlex Langford ret_plan_sp = std::make_shared<ThreadPlanStepInRange>( 474a5ab1dc4SDave Lee thread, range_of_curr_func, sc, nullptr, eOnlyThisThread, 475a5ab1dc4SDave Lee eLazyBoolYes, eLazyBoolYes); 476e0678ca5SAlex Langford return ret_plan_sp; 477e0678ca5SAlex Langford } 478e0678ca5SAlex Langford } 479e0678ca5SAlex Langford 480e0678ca5SAlex Langford return ret_plan_sp; 481e0678ca5SAlex Langford } 482