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