1 //===-- CPPLanguageRuntime.cpp 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include <string.h> 10 11 #include <memory> 12 13 #include "CPPLanguageRuntime.h" 14 15 #include "llvm/ADT/StringRef.h" 16 17 #include "lldb/Symbol/Block.h" 18 #include "lldb/Symbol/Variable.h" 19 #include "lldb/Symbol/VariableList.h" 20 21 #include "lldb/Core/PluginManager.h" 22 #include "lldb/Core/UniqueCStringMap.h" 23 #include "lldb/Symbol/ClangASTContext.h" 24 #include "lldb/Target/ABI.h" 25 #include "lldb/Target/ExecutionContext.h" 26 #include "lldb/Target/RegisterContext.h" 27 #include "lldb/Target/SectionLoadList.h" 28 #include "lldb/Target/StackFrame.h" 29 #include "lldb/Target/ThreadPlanRunToAddress.h" 30 #include "lldb/Target/ThreadPlanStepInRange.h" 31 32 using namespace lldb; 33 using namespace lldb_private; 34 35 static ConstString g_this = ConstString("this"); 36 37 char CPPLanguageRuntime::ID = 0; 38 39 // Destructor 40 CPPLanguageRuntime::~CPPLanguageRuntime() {} 41 42 CPPLanguageRuntime::CPPLanguageRuntime(Process *process) 43 : LanguageRuntime(process) {} 44 45 bool CPPLanguageRuntime::IsWhitelistedRuntimeValue(ConstString name) { 46 return name == g_this; 47 } 48 49 bool CPPLanguageRuntime::GetObjectDescription(Stream &str, 50 ValueObject &object) { 51 // C++ has no generic way to do this. 52 return false; 53 } 54 55 bool CPPLanguageRuntime::GetObjectDescription( 56 Stream &str, Value &value, ExecutionContextScope *exe_scope) { 57 // C++ has no generic way to do this. 58 return false; 59 } 60 61 CPPLanguageRuntime::LibCppStdFunctionCallableInfo 62 CPPLanguageRuntime::FindLibCppStdFunctionCallableInfo( 63 lldb::ValueObjectSP &valobj_sp) { 64 LibCppStdFunctionCallableInfo optional_info; 65 66 if (!valobj_sp) 67 return optional_info; 68 69 // Member __f_ has type __base*, the contents of which will hold: 70 // 1) a vtable entry which may hold type information needed to discover the 71 // lambda being called 72 // 2) possibly hold a pointer to the callable object 73 // e.g. 74 // 75 // (lldb) frame var -R f_display 76 // (std::__1::function<void (int)>) f_display = { 77 // __buf_ = { 78 // … 79 // } 80 // __f_ = 0x00007ffeefbffa00 81 // } 82 // (lldb) memory read -fA 0x00007ffeefbffa00 83 // 0x7ffeefbffa00: ... `vtable for std::__1::__function::__func<void (*) ... 84 // 0x7ffeefbffa08: ... `print_num(int) at std_function_cppreference_exam ... 85 // 86 // We will be handling five cases below, std::function is wrapping: 87 // 88 // 1) a lambda we know at compile time. We will obtain the name of the lambda 89 // from the first template pameter from __func's vtable. We will look up 90 // the lambda's operator()() and obtain the line table entry. 91 // 2) a lambda we know at runtime. A pointer to the lambdas __invoke method 92 // will be stored after the vtable. We will obtain the lambdas name from 93 // this entry and lookup operator()() and obtain the line table entry. 94 // 3) a callable object via operator()(). We will obtain the name of the 95 // object from the first template parameter from __func's vtable. We will 96 // look up the objectc operator()() and obtain the line table entry. 97 // 4) a member function. A pointer to the function will stored after the 98 // we will obtain the name from this pointer. 99 // 5) a free function. A pointer to the function will stored after the vtable 100 // we will obtain the name from this pointer. 101 ValueObjectSP member__f_( 102 valobj_sp->GetChildMemberWithName(ConstString("__f_"), true)); 103 104 if (member__f_) { 105 ValueObjectSP sub_member__f_( 106 member__f_->GetChildMemberWithName(ConstString("__f_"), true)); 107 108 if (sub_member__f_) 109 member__f_ = sub_member__f_; 110 } 111 112 lldb::addr_t member__f_pointer_value = member__f_->GetValueAsUnsigned(0); 113 114 optional_info.member__f_pointer_value = member__f_pointer_value; 115 116 ExecutionContext exe_ctx(valobj_sp->GetExecutionContextRef()); 117 Process *process = exe_ctx.GetProcessPtr(); 118 119 if (process == nullptr) 120 return optional_info; 121 122 uint32_t address_size = process->GetAddressByteSize(); 123 Status status; 124 125 // First item pointed to by __f_ should be the pointer to the vtable for 126 // a __base object. 127 lldb::addr_t vtable_address = 128 process->ReadPointerFromMemory(member__f_pointer_value, status); 129 130 if (status.Fail()) 131 return optional_info; 132 133 lldb::addr_t address_after_vtable = member__f_pointer_value + address_size; 134 // As commened above we may not have a function pointer but if we do we will 135 // need it. 136 lldb::addr_t possible_function_address = 137 process->ReadPointerFromMemory(address_after_vtable, status); 138 139 if (status.Fail()) 140 return optional_info; 141 142 Target &target = process->GetTarget(); 143 144 if (target.GetSectionLoadList().IsEmpty()) 145 return optional_info; 146 147 Address vtable_addr_resolved; 148 SymbolContext sc; 149 Symbol *symbol; 150 151 if (!target.GetSectionLoadList().ResolveLoadAddress(vtable_address, 152 vtable_addr_resolved)) 153 return optional_info; 154 155 target.GetImages().ResolveSymbolContextForAddress( 156 vtable_addr_resolved, eSymbolContextEverything, sc); 157 symbol = sc.symbol; 158 159 if (symbol == nullptr) 160 return optional_info; 161 162 llvm::StringRef vtable_name(symbol->GetName().GetCString()); 163 bool found_expected_start_string = 164 vtable_name.startswith("vtable for std::__1::__function::__func<"); 165 166 if (!found_expected_start_string) 167 return optional_info; 168 169 // Given case 1 or 3 we have a vtable name, we are want to extract the first 170 // template parameter 171 // 172 // ... __func<main::$_0, std::__1::allocator<main::$_0> ... 173 // ^^^^^^^^^ 174 // 175 // We do this by find the first < and , and extracting in between. 176 // 177 // This covers the case of the lambda known at compile time. 178 size_t first_open_angle_bracket = vtable_name.find('<') + 1; 179 size_t first_comma = vtable_name.find(','); 180 181 llvm::StringRef first_template_parameter = 182 vtable_name.slice(first_open_angle_bracket, first_comma); 183 184 Address function_address_resolved; 185 186 // Setup for cases 2, 4 and 5 we have a pointer to a function after the 187 // vtable. We will use a process of elimination to drop through each case 188 // and obtain the data we need. 189 if (target.GetSectionLoadList().ResolveLoadAddress( 190 possible_function_address, function_address_resolved)) { 191 target.GetImages().ResolveSymbolContextForAddress( 192 function_address_resolved, eSymbolContextEverything, sc); 193 symbol = sc.symbol; 194 } 195 196 auto get_name = [&first_template_parameter, &symbol]() { 197 // Given case 1: 198 // 199 // main::$_0 200 // 201 // we want to append ::operator()() 202 if (first_template_parameter.contains("$_")) 203 return llvm::Regex::escape(first_template_parameter.str()) + 204 R"(::operator\(\)\(.*\))"; 205 206 if (symbol != nullptr && 207 symbol->GetName().GetStringRef().contains("__invoke")) { 208 209 llvm::StringRef symbol_name = symbol->GetName().GetStringRef(); 210 size_t pos2 = symbol_name.find_last_of(':'); 211 212 // Given case 2: 213 // 214 // main::$_1::__invoke(...) 215 // 216 // We want to slice off __invoke(...) and append operator()() 217 std::string lambda_operator = 218 llvm::Regex::escape(symbol_name.slice(0, pos2 + 1).str()) + 219 R"(operator\(\)\(.*\))"; 220 221 return lambda_operator; 222 } 223 224 // Case 3 225 return first_template_parameter.str() + R"(::operator\(\)\(.*\))"; 226 ; 227 }; 228 229 std::string func_to_match = get_name(); 230 231 SymbolContextList scl; 232 233 target.GetImages().FindSymbolsMatchingRegExAndType( 234 RegularExpression{R"(^)" + func_to_match}, eSymbolTypeAny, scl, true); 235 236 // Case 1,2 or 3 237 if (scl.GetSize() >= 1) { 238 SymbolContext sc2 = scl[0]; 239 240 AddressRange range; 241 sc2.GetAddressRange(eSymbolContextEverything, 0, false, range); 242 243 Address address = range.GetBaseAddress(); 244 245 Address addr; 246 if (target.ResolveLoadAddress(address.GetCallableLoadAddress(&target), 247 addr)) { 248 LineEntry line_entry; 249 addr.CalculateSymbolContextLineEntry(line_entry); 250 251 if (first_template_parameter.contains("$_") || 252 (symbol != nullptr && 253 symbol->GetName().GetStringRef().contains("__invoke"))) { 254 // Case 1 and 2 255 optional_info.callable_case = LibCppStdFunctionCallableCase::Lambda; 256 } else { 257 // Case 3 258 optional_info.callable_case = 259 LibCppStdFunctionCallableCase::CallableObject; 260 } 261 262 optional_info.callable_symbol = *symbol; 263 optional_info.callable_line_entry = line_entry; 264 optional_info.callable_address = addr; 265 return optional_info; 266 } 267 } 268 269 // Case 4 or 5 270 if (symbol && !symbol->GetName().GetStringRef().startswith("vtable for")) { 271 optional_info.callable_case = 272 LibCppStdFunctionCallableCase::FreeOrMemberFunction; 273 optional_info.callable_address = function_address_resolved; 274 optional_info.callable_symbol = *symbol; 275 276 return optional_info; 277 } 278 279 return optional_info; 280 } 281 282 lldb::ThreadPlanSP 283 CPPLanguageRuntime::GetStepThroughTrampolinePlan(Thread &thread, 284 bool stop_others) { 285 ThreadPlanSP ret_plan_sp; 286 287 lldb::addr_t curr_pc = thread.GetRegisterContext()->GetPC(); 288 289 TargetSP target_sp(thread.CalculateTarget()); 290 291 if (target_sp->GetSectionLoadList().IsEmpty()) 292 return ret_plan_sp; 293 294 Address pc_addr_resolved; 295 SymbolContext sc; 296 Symbol *symbol; 297 298 if (!target_sp->GetSectionLoadList().ResolveLoadAddress(curr_pc, 299 pc_addr_resolved)) 300 return ret_plan_sp; 301 302 target_sp->GetImages().ResolveSymbolContextForAddress( 303 pc_addr_resolved, eSymbolContextEverything, sc); 304 symbol = sc.symbol; 305 306 if (symbol == nullptr) 307 return ret_plan_sp; 308 309 llvm::StringRef function_name(symbol->GetName().GetCString()); 310 311 // Handling the case where we are attempting to step into std::function. 312 // The behavior will be that we will attempt to obtain the wrapped 313 // callable via FindLibCppStdFunctionCallableInfo() and if we find it we 314 // will return a ThreadPlanRunToAddress to the callable. Therefore we will 315 // step into the wrapped callable. 316 // 317 bool found_expected_start_string = 318 function_name.startswith("std::__1::function<"); 319 320 if (!found_expected_start_string) 321 return ret_plan_sp; 322 323 AddressRange range_of_curr_func; 324 sc.GetAddressRange(eSymbolContextEverything, 0, false, range_of_curr_func); 325 326 StackFrameSP frame = thread.GetStackFrameAtIndex(0); 327 328 if (frame) { 329 ValueObjectSP value_sp = frame->FindVariable(g_this); 330 331 CPPLanguageRuntime::LibCppStdFunctionCallableInfo callable_info = 332 FindLibCppStdFunctionCallableInfo(value_sp); 333 334 if (callable_info.callable_case != LibCppStdFunctionCallableCase::Invalid && 335 value_sp->GetValueIsValid()) { 336 // We found the std::function wrapped callable and we have its address. 337 // We now create a ThreadPlan to run to the callable. 338 ret_plan_sp = std::make_shared<ThreadPlanRunToAddress>( 339 thread, callable_info.callable_address, stop_others); 340 return ret_plan_sp; 341 } else { 342 // We are in std::function but we could not obtain the callable. 343 // We create a ThreadPlan to keep stepping through using the address range 344 // of the current function. 345 ret_plan_sp = std::make_shared<ThreadPlanStepInRange>( 346 thread, range_of_curr_func, sc, eOnlyThisThread, eLazyBoolYes, 347 eLazyBoolYes); 348 return ret_plan_sp; 349 } 350 } 351 352 return ret_plan_sp; 353 } 354