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 <cstring> 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/CompileUnit.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 #include "lldb/Utility/Timer.h" 32 33 using namespace lldb; 34 using namespace lldb_private; 35 36 static ConstString g_this = ConstString("this"); 37 // Artificial coroutine-related variables emitted by clang. 38 static ConstString g_promise = ConstString("__promise"); 39 static ConstString g_coro_frame = ConstString("__coro_frame"); 40 41 char CPPLanguageRuntime::ID = 0; 42 43 CPPLanguageRuntime::CPPLanguageRuntime(Process *process) 44 : LanguageRuntime(process) {} 45 46 bool CPPLanguageRuntime::IsAllowedRuntimeValue(ConstString name) { 47 return name == g_this || name == g_promise || name == g_coro_frame; 48 } 49 50 bool CPPLanguageRuntime::GetObjectDescription(Stream &str, 51 ValueObject &object) { 52 // C++ has no generic way to do this. 53 return false; 54 } 55 56 bool CPPLanguageRuntime::GetObjectDescription( 57 Stream &str, Value &value, ExecutionContextScope *exe_scope) { 58 // C++ has no generic way to do this. 59 return false; 60 } 61 62 bool contains_lambda_identifier(llvm::StringRef &str_ref) { 63 return str_ref.contains("$_") || str_ref.contains("'lambda'"); 64 } 65 66 CPPLanguageRuntime::LibCppStdFunctionCallableInfo 67 line_entry_helper(Target &target, const SymbolContext &sc, Symbol *symbol, 68 llvm::StringRef first_template_param_sref, 69 bool has_invoke) { 70 71 CPPLanguageRuntime::LibCppStdFunctionCallableInfo optional_info; 72 73 AddressRange range; 74 sc.GetAddressRange(eSymbolContextEverything, 0, false, range); 75 76 Address address = range.GetBaseAddress(); 77 78 Address addr; 79 if (target.ResolveLoadAddress(address.GetCallableLoadAddress(&target), 80 addr)) { 81 LineEntry line_entry; 82 addr.CalculateSymbolContextLineEntry(line_entry); 83 84 if (contains_lambda_identifier(first_template_param_sref) || has_invoke) { 85 // Case 1 and 2 86 optional_info.callable_case = lldb_private::CPPLanguageRuntime:: 87 LibCppStdFunctionCallableCase::Lambda; 88 } else { 89 // Case 3 90 optional_info.callable_case = lldb_private::CPPLanguageRuntime:: 91 LibCppStdFunctionCallableCase::CallableObject; 92 } 93 94 optional_info.callable_symbol = *symbol; 95 optional_info.callable_line_entry = line_entry; 96 optional_info.callable_address = addr; 97 } 98 99 return optional_info; 100 } 101 102 CPPLanguageRuntime::LibCppStdFunctionCallableInfo 103 CPPLanguageRuntime::FindLibCppStdFunctionCallableInfo( 104 lldb::ValueObjectSP &valobj_sp) { 105 LLDB_SCOPED_TIMER(); 106 107 LibCppStdFunctionCallableInfo optional_info; 108 109 if (!valobj_sp) 110 return optional_info; 111 112 // Member __f_ has type __base*, the contents of which will hold: 113 // 1) a vtable entry which may hold type information needed to discover the 114 // lambda being called 115 // 2) possibly hold a pointer to the callable object 116 // e.g. 117 // 118 // (lldb) frame var -R f_display 119 // (std::__1::function<void (int)>) f_display = { 120 // __buf_ = { 121 // … 122 // } 123 // __f_ = 0x00007ffeefbffa00 124 // } 125 // (lldb) memory read -fA 0x00007ffeefbffa00 126 // 0x7ffeefbffa00: ... `vtable for std::__1::__function::__func<void (*) ... 127 // 0x7ffeefbffa08: ... `print_num(int) at std_function_cppreference_exam ... 128 // 129 // We will be handling five cases below, std::function is wrapping: 130 // 131 // 1) a lambda we know at compile time. We will obtain the name of the lambda 132 // from the first template pameter from __func's vtable. We will look up 133 // the lambda's operator()() and obtain the line table entry. 134 // 2) a lambda we know at runtime. A pointer to the lambdas __invoke method 135 // will be stored after the vtable. We will obtain the lambdas name from 136 // this entry and lookup operator()() and obtain the line table entry. 137 // 3) a callable object via operator()(). We will obtain the name of the 138 // object from the first template parameter from __func's vtable. We will 139 // look up the objects operator()() and obtain the line table entry. 140 // 4) a member function. A pointer to the function will stored after the 141 // we will obtain the name from this pointer. 142 // 5) a free function. A pointer to the function will stored after the vtable 143 // we will obtain the name from this pointer. 144 ValueObjectSP member_f_(valobj_sp->GetChildMemberWithName("__f_")); 145 146 if (member_f_) { 147 ValueObjectSP sub_member_f_(member_f_->GetChildMemberWithName("__f_")); 148 149 if (sub_member_f_) 150 member_f_ = sub_member_f_; 151 } 152 153 if (!member_f_) 154 return optional_info; 155 156 lldb::addr_t member_f_pointer_value = member_f_->GetValueAsUnsigned(0); 157 158 optional_info.member_f_pointer_value = member_f_pointer_value; 159 160 if (!member_f_pointer_value) 161 return optional_info; 162 163 ExecutionContext exe_ctx(valobj_sp->GetExecutionContextRef()); 164 Process *process = exe_ctx.GetProcessPtr(); 165 166 if (process == nullptr) 167 return optional_info; 168 169 uint32_t address_size = process->GetAddressByteSize(); 170 Status status; 171 172 // First item pointed to by __f_ should be the pointer to the vtable for 173 // a __base object. 174 lldb::addr_t vtable_address = 175 process->ReadPointerFromMemory(member_f_pointer_value, status); 176 177 if (status.Fail()) 178 return optional_info; 179 180 lldb::addr_t vtable_address_first_entry = 181 process->ReadPointerFromMemory(vtable_address + address_size, status); 182 183 if (status.Fail()) 184 return optional_info; 185 186 lldb::addr_t address_after_vtable = member_f_pointer_value + address_size; 187 // As commented above we may not have a function pointer but if we do we will 188 // need it. 189 lldb::addr_t possible_function_address = 190 process->ReadPointerFromMemory(address_after_vtable, status); 191 192 if (status.Fail()) 193 return optional_info; 194 195 Target &target = process->GetTarget(); 196 197 if (target.GetSectionLoadList().IsEmpty()) 198 return optional_info; 199 200 Address vtable_first_entry_resolved; 201 202 if (!target.GetSectionLoadList().ResolveLoadAddress( 203 vtable_address_first_entry, vtable_first_entry_resolved)) 204 return optional_info; 205 206 Address vtable_addr_resolved; 207 SymbolContext sc; 208 Symbol *symbol = nullptr; 209 210 if (!target.GetSectionLoadList().ResolveLoadAddress(vtable_address, 211 vtable_addr_resolved)) 212 return optional_info; 213 214 target.GetImages().ResolveSymbolContextForAddress( 215 vtable_addr_resolved, eSymbolContextEverything, sc); 216 symbol = sc.symbol; 217 218 if (symbol == nullptr) 219 return optional_info; 220 221 llvm::StringRef vtable_name(symbol->GetName().GetStringRef()); 222 bool found_expected_start_string = 223 vtable_name.starts_with("vtable for std::__1::__function::__func<"); 224 225 if (!found_expected_start_string) 226 return optional_info; 227 228 // Given case 1 or 3 we have a vtable name, we are want to extract the first 229 // template parameter 230 // 231 // ... __func<main::$_0, std::__1::allocator<main::$_0> ... 232 // ^^^^^^^^^ 233 // 234 // We could see names such as: 235 // main::$_0 236 // Bar::add_num2(int)::'lambda'(int) 237 // Bar 238 // 239 // We do this by find the first < and , and extracting in between. 240 // 241 // This covers the case of the lambda known at compile time. 242 size_t first_open_angle_bracket = vtable_name.find('<') + 1; 243 size_t first_comma = vtable_name.find(','); 244 245 llvm::StringRef first_template_parameter = 246 vtable_name.slice(first_open_angle_bracket, first_comma); 247 248 Address function_address_resolved; 249 250 // Setup for cases 2, 4 and 5 we have a pointer to a function after the 251 // vtable. We will use a process of elimination to drop through each case 252 // and obtain the data we need. 253 if (target.GetSectionLoadList().ResolveLoadAddress( 254 possible_function_address, function_address_resolved)) { 255 target.GetImages().ResolveSymbolContextForAddress( 256 function_address_resolved, eSymbolContextEverything, sc); 257 symbol = sc.symbol; 258 } 259 260 // These conditions are used several times to simplify statements later on. 261 bool has_invoke = 262 (symbol ? symbol->GetName().GetStringRef().contains("__invoke") : false); 263 auto calculate_symbol_context_helper = [](auto &t, 264 SymbolContextList &sc_list) { 265 SymbolContext sc; 266 t->CalculateSymbolContext(&sc); 267 sc_list.Append(sc); 268 }; 269 270 // Case 2 271 if (has_invoke) { 272 SymbolContextList scl; 273 calculate_symbol_context_helper(symbol, scl); 274 275 return line_entry_helper(target, scl[0], symbol, first_template_parameter, 276 has_invoke); 277 } 278 279 // Case 4 or 5 280 if (symbol && !symbol->GetName().GetStringRef().starts_with("vtable for") && 281 !contains_lambda_identifier(first_template_parameter) && !has_invoke) { 282 optional_info.callable_case = 283 LibCppStdFunctionCallableCase::FreeOrMemberFunction; 284 optional_info.callable_address = function_address_resolved; 285 optional_info.callable_symbol = *symbol; 286 287 return optional_info; 288 } 289 290 std::string func_to_match = first_template_parameter.str(); 291 292 auto it = CallableLookupCache.find(func_to_match); 293 if (it != CallableLookupCache.end()) 294 return it->second; 295 296 SymbolContextList scl; 297 298 CompileUnit *vtable_cu = 299 vtable_first_entry_resolved.CalculateSymbolContextCompileUnit(); 300 llvm::StringRef name_to_use = func_to_match; 301 302 // Case 3, we have a callable object instead of a lambda 303 // 304 // TODO 305 // We currently don't support this case a callable object may have multiple 306 // operator()() varying on const/non-const and number of arguments and we 307 // don't have a way to currently distinguish them so we will bail out now. 308 if (!contains_lambda_identifier(name_to_use)) 309 return optional_info; 310 311 if (vtable_cu && !has_invoke) { 312 lldb::FunctionSP func_sp = 313 vtable_cu->FindFunction([name_to_use](const FunctionSP &f) { 314 auto name = f->GetName().GetStringRef(); 315 if (name.starts_with(name_to_use) && name.contains("operator")) 316 return true; 317 318 return false; 319 }); 320 321 if (func_sp) { 322 calculate_symbol_context_helper(func_sp, scl); 323 } 324 } 325 326 if (symbol == nullptr) 327 return optional_info; 328 329 // Case 1 or 3 330 if (scl.GetSize() >= 1) { 331 optional_info = line_entry_helper(target, scl[0], symbol, 332 first_template_parameter, has_invoke); 333 } 334 335 CallableLookupCache[func_to_match] = optional_info; 336 337 return optional_info; 338 } 339 340 lldb::ThreadPlanSP 341 CPPLanguageRuntime::GetStepThroughTrampolinePlan(Thread &thread, 342 bool stop_others) { 343 ThreadPlanSP ret_plan_sp; 344 345 lldb::addr_t curr_pc = thread.GetRegisterContext()->GetPC(); 346 347 TargetSP target_sp(thread.CalculateTarget()); 348 349 if (target_sp->GetSectionLoadList().IsEmpty()) 350 return ret_plan_sp; 351 352 Address pc_addr_resolved; 353 SymbolContext sc; 354 Symbol *symbol; 355 356 if (!target_sp->GetSectionLoadList().ResolveLoadAddress(curr_pc, 357 pc_addr_resolved)) 358 return ret_plan_sp; 359 360 target_sp->GetImages().ResolveSymbolContextForAddress( 361 pc_addr_resolved, eSymbolContextEverything, sc); 362 symbol = sc.symbol; 363 364 if (symbol == nullptr) 365 return ret_plan_sp; 366 367 llvm::StringRef function_name(symbol->GetName().GetCString()); 368 369 // Handling the case where we are attempting to step into std::function. 370 // The behavior will be that we will attempt to obtain the wrapped 371 // callable via FindLibCppStdFunctionCallableInfo() and if we find it we 372 // will return a ThreadPlanRunToAddress to the callable. Therefore we will 373 // step into the wrapped callable. 374 // 375 bool found_expected_start_string = 376 function_name.starts_with("std::__1::function<"); 377 378 if (!found_expected_start_string) 379 return ret_plan_sp; 380 381 AddressRange range_of_curr_func; 382 sc.GetAddressRange(eSymbolContextEverything, 0, false, range_of_curr_func); 383 384 StackFrameSP frame = thread.GetStackFrameAtIndex(0); 385 386 if (frame) { 387 ValueObjectSP value_sp = frame->FindVariable(g_this); 388 389 CPPLanguageRuntime::LibCppStdFunctionCallableInfo callable_info = 390 FindLibCppStdFunctionCallableInfo(value_sp); 391 392 if (callable_info.callable_case != LibCppStdFunctionCallableCase::Invalid && 393 value_sp->GetValueIsValid()) { 394 // We found the std::function wrapped callable and we have its address. 395 // We now create a ThreadPlan to run to the callable. 396 ret_plan_sp = std::make_shared<ThreadPlanRunToAddress>( 397 thread, callable_info.callable_address, stop_others); 398 return ret_plan_sp; 399 } else { 400 // We are in std::function but we could not obtain the callable. 401 // We create a ThreadPlan to keep stepping through using the address range 402 // of the current function. 403 ret_plan_sp = std::make_shared<ThreadPlanStepInRange>( 404 thread, range_of_curr_func, sc, nullptr, eOnlyThisThread, 405 eLazyBoolYes, eLazyBoolYes); 406 return ret_plan_sp; 407 } 408 } 409 410 return ret_plan_sp; 411 } 412