1 //===-- LibStdcpp.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 "LibStdcpp.h" 10 #include "LibCxx.h" 11 12 #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" 13 #include "lldb/DataFormatters/StringPrinter.h" 14 #include "lldb/DataFormatters/VectorIterator.h" 15 #include "lldb/Target/Target.h" 16 #include "lldb/Utility/DataBufferHeap.h" 17 #include "lldb/Utility/Endian.h" 18 #include "lldb/Utility/Status.h" 19 #include "lldb/Utility/Stream.h" 20 #include "lldb/ValueObject/ValueObject.h" 21 #include "lldb/ValueObject/ValueObjectConstResult.h" 22 #include <optional> 23 24 using namespace lldb; 25 using namespace lldb_private; 26 using namespace lldb_private::formatters; 27 28 namespace { 29 30 class LibstdcppMapIteratorSyntheticFrontEnd : public SyntheticChildrenFrontEnd { 31 /* 32 (std::_Rb_tree_iterator<std::pair<const int, std::basic_string<char, 33 std::char_traits<char>, std::allocator<char> > > >) ibeg = { 34 (_Base_ptr) _M_node = 0x0000000100103910 { 35 (std::_Rb_tree_color) _M_color = _S_black 36 (std::_Rb_tree_node_base::_Base_ptr) _M_parent = 0x00000001001038c0 37 (std::_Rb_tree_node_base::_Base_ptr) _M_left = 0x0000000000000000 38 (std::_Rb_tree_node_base::_Base_ptr) _M_right = 0x0000000000000000 39 } 40 } 41 */ 42 43 public: 44 explicit LibstdcppMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); 45 46 llvm::Expected<uint32_t> CalculateNumChildren() override; 47 48 lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; 49 50 lldb::ChildCacheState Update() override; 51 52 bool MightHaveChildren() override; 53 54 size_t GetIndexOfChildWithName(ConstString name) override; 55 56 private: 57 ExecutionContextRef m_exe_ctx_ref; 58 lldb::addr_t m_pair_address = 0; 59 CompilerType m_pair_type; 60 lldb::ValueObjectSP m_pair_sp; 61 }; 62 63 class LibStdcppSharedPtrSyntheticFrontEnd : public SyntheticChildrenFrontEnd { 64 public: 65 explicit LibStdcppSharedPtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); 66 67 llvm::Expected<uint32_t> CalculateNumChildren() override; 68 69 lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; 70 71 lldb::ChildCacheState Update() override; 72 73 bool MightHaveChildren() override; 74 75 size_t GetIndexOfChildWithName(ConstString name) override; 76 private: 77 78 // The lifetime of a ValueObject and all its derivative ValueObjects 79 // (children, clones, etc.) is managed by a ClusterManager. These 80 // objects are only destroyed when every shared pointer to any of them 81 // is destroyed, so we must not store a shared pointer to any ValueObject 82 // derived from our backend ValueObject (since we're in the same cluster). 83 ValueObject* m_ptr_obj = nullptr; // Underlying pointer (held, not owned) 84 ValueObject* m_obj_obj = nullptr; // Underlying object (held, not owned) 85 }; 86 87 } // end of anonymous namespace 88 89 LibstdcppMapIteratorSyntheticFrontEnd::LibstdcppMapIteratorSyntheticFrontEnd( 90 lldb::ValueObjectSP valobj_sp) 91 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_pair_type(), 92 m_pair_sp() { 93 if (valobj_sp) 94 Update(); 95 } 96 97 lldb::ChildCacheState LibstdcppMapIteratorSyntheticFrontEnd::Update() { 98 ValueObjectSP valobj_sp = m_backend.GetSP(); 99 if (!valobj_sp) 100 return lldb::ChildCacheState::eRefetch; 101 102 TargetSP target_sp(valobj_sp->GetTargetSP()); 103 104 if (!target_sp) 105 return lldb::ChildCacheState::eRefetch; 106 107 bool is_64bit = (target_sp->GetArchitecture().GetAddressByteSize() == 8); 108 109 if (!valobj_sp) 110 return lldb::ChildCacheState::eRefetch; 111 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 112 113 ValueObjectSP _M_node_sp(valobj_sp->GetChildMemberWithName("_M_node")); 114 if (!_M_node_sp) 115 return lldb::ChildCacheState::eRefetch; 116 117 m_pair_address = _M_node_sp->GetValueAsUnsigned(0); 118 if (m_pair_address == 0) 119 return lldb::ChildCacheState::eRefetch; 120 121 m_pair_address += (is_64bit ? 32 : 16); 122 123 CompilerType my_type(valobj_sp->GetCompilerType()); 124 if (my_type.GetNumTemplateArguments() >= 1) { 125 CompilerType pair_type = my_type.GetTypeTemplateArgument(0); 126 if (!pair_type) 127 return lldb::ChildCacheState::eRefetch; 128 m_pair_type = pair_type; 129 } else 130 return lldb::ChildCacheState::eRefetch; 131 132 return lldb::ChildCacheState::eReuse; 133 } 134 135 llvm::Expected<uint32_t> 136 LibstdcppMapIteratorSyntheticFrontEnd::CalculateNumChildren() { 137 return 2; 138 } 139 140 lldb::ValueObjectSP 141 LibstdcppMapIteratorSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) { 142 if (m_pair_address != 0 && m_pair_type) { 143 if (!m_pair_sp) 144 m_pair_sp = CreateValueObjectFromAddress("pair", m_pair_address, 145 m_exe_ctx_ref, m_pair_type); 146 if (m_pair_sp) 147 return m_pair_sp->GetChildAtIndex(idx); 148 } 149 return lldb::ValueObjectSP(); 150 } 151 152 bool LibstdcppMapIteratorSyntheticFrontEnd::MightHaveChildren() { return true; } 153 154 size_t LibstdcppMapIteratorSyntheticFrontEnd::GetIndexOfChildWithName( 155 ConstString name) { 156 if (name == "first") 157 return 0; 158 if (name == "second") 159 return 1; 160 return UINT32_MAX; 161 } 162 163 SyntheticChildrenFrontEnd * 164 lldb_private::formatters::LibstdcppMapIteratorSyntheticFrontEndCreator( 165 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 166 return (valobj_sp ? new LibstdcppMapIteratorSyntheticFrontEnd(valobj_sp) 167 : nullptr); 168 } 169 170 /* 171 (lldb) fr var ibeg --ptr-depth 1 172 (__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > >) 173 ibeg = { 174 _M_current = 0x00000001001037a0 { 175 *_M_current = 1 176 } 177 } 178 */ 179 180 SyntheticChildrenFrontEnd * 181 lldb_private::formatters::LibStdcppVectorIteratorSyntheticFrontEndCreator( 182 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 183 return (valobj_sp ? new VectorIteratorSyntheticFrontEnd( 184 valobj_sp, {ConstString("_M_current")}) 185 : nullptr); 186 } 187 188 lldb_private::formatters::VectorIteratorSyntheticFrontEnd:: 189 VectorIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp, 190 llvm::ArrayRef<ConstString> item_names) 191 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), 192 m_item_names(item_names), m_item_sp() { 193 if (valobj_sp) 194 Update(); 195 } 196 197 lldb::ChildCacheState VectorIteratorSyntheticFrontEnd::Update() { 198 m_item_sp.reset(); 199 200 ValueObjectSP valobj_sp = m_backend.GetSP(); 201 if (!valobj_sp) 202 return lldb::ChildCacheState::eRefetch; 203 204 if (!valobj_sp) 205 return lldb::ChildCacheState::eRefetch; 206 207 ValueObjectSP item_ptr = 208 formatters::GetChildMemberWithName(*valobj_sp, m_item_names); 209 if (!item_ptr) 210 return lldb::ChildCacheState::eRefetch; 211 if (item_ptr->GetValueAsUnsigned(0) == 0) 212 return lldb::ChildCacheState::eRefetch; 213 Status err; 214 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 215 m_item_sp = CreateValueObjectFromAddress( 216 "item", item_ptr->GetValueAsUnsigned(0), m_exe_ctx_ref, 217 item_ptr->GetCompilerType().GetPointeeType()); 218 if (err.Fail()) 219 m_item_sp.reset(); 220 return lldb::ChildCacheState::eRefetch; 221 } 222 223 llvm::Expected<uint32_t> 224 VectorIteratorSyntheticFrontEnd::CalculateNumChildren() { 225 return 1; 226 } 227 228 lldb::ValueObjectSP 229 VectorIteratorSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) { 230 if (idx == 0) 231 return m_item_sp; 232 return lldb::ValueObjectSP(); 233 } 234 235 bool VectorIteratorSyntheticFrontEnd::MightHaveChildren() { return true; } 236 237 size_t VectorIteratorSyntheticFrontEnd::GetIndexOfChildWithName( 238 ConstString name) { 239 if (name == "item") 240 return 0; 241 return UINT32_MAX; 242 } 243 244 bool lldb_private::formatters::LibStdcppStringSummaryProvider( 245 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { 246 const bool scalar_is_load_addr = true; 247 AddressType addr_type; 248 lldb::addr_t addr_of_string = LLDB_INVALID_ADDRESS; 249 if (valobj.IsPointerOrReferenceType()) { 250 Status error; 251 ValueObjectSP pointee_sp = valobj.Dereference(error); 252 if (pointee_sp && error.Success()) 253 addr_of_string = pointee_sp->GetAddressOf(scalar_is_load_addr, &addr_type); 254 } else 255 addr_of_string = 256 valobj.GetAddressOf(scalar_is_load_addr, &addr_type); 257 if (addr_of_string != LLDB_INVALID_ADDRESS) { 258 switch (addr_type) { 259 case eAddressTypeLoad: { 260 ProcessSP process_sp(valobj.GetProcessSP()); 261 if (!process_sp) 262 return false; 263 264 StringPrinter::ReadStringAndDumpToStreamOptions options(valobj); 265 Status error; 266 lldb::addr_t addr_of_data = 267 process_sp->ReadPointerFromMemory(addr_of_string, error); 268 if (error.Fail() || addr_of_data == 0 || 269 addr_of_data == LLDB_INVALID_ADDRESS) 270 return false; 271 options.SetLocation(addr_of_data); 272 options.SetTargetSP(valobj.GetTargetSP()); 273 options.SetStream(&stream); 274 options.SetNeedsZeroTermination(false); 275 options.SetBinaryZeroIsTerminator(true); 276 lldb::addr_t size_of_data = process_sp->ReadPointerFromMemory( 277 addr_of_string + process_sp->GetAddressByteSize(), error); 278 if (error.Fail()) 279 return false; 280 options.SetSourceSize(size_of_data); 281 options.SetHasSourceSize(true); 282 283 if (!StringPrinter::ReadStringAndDumpToStream< 284 StringPrinter::StringElementType::UTF8>(options)) { 285 stream.Printf("Summary Unavailable"); 286 return true; 287 } else 288 return true; 289 } break; 290 case eAddressTypeHost: 291 break; 292 case eAddressTypeInvalid: 293 case eAddressTypeFile: 294 break; 295 } 296 } 297 return false; 298 } 299 300 bool lldb_private::formatters::LibStdcppWStringSummaryProvider( 301 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { 302 const bool scalar_is_load_addr = true; 303 AddressType addr_type; 304 lldb::addr_t addr_of_string = 305 valobj.GetAddressOf(scalar_is_load_addr, &addr_type); 306 if (addr_of_string != LLDB_INVALID_ADDRESS) { 307 switch (addr_type) { 308 case eAddressTypeLoad: { 309 ProcessSP process_sp(valobj.GetProcessSP()); 310 if (!process_sp) 311 return false; 312 313 CompilerType wchar_compiler_type = 314 valobj.GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeWChar); 315 316 if (!wchar_compiler_type) 317 return false; 318 319 // Safe to pass nullptr for exe_scope here. 320 std::optional<uint64_t> size = wchar_compiler_type.GetBitSize(nullptr); 321 if (!size) 322 return false; 323 const uint32_t wchar_size = *size; 324 325 StringPrinter::ReadStringAndDumpToStreamOptions options(valobj); 326 Status error; 327 lldb::addr_t addr_of_data = 328 process_sp->ReadPointerFromMemory(addr_of_string, error); 329 if (error.Fail() || addr_of_data == 0 || 330 addr_of_data == LLDB_INVALID_ADDRESS) 331 return false; 332 options.SetLocation(addr_of_data); 333 options.SetTargetSP(valobj.GetTargetSP()); 334 options.SetStream(&stream); 335 options.SetNeedsZeroTermination(false); 336 options.SetBinaryZeroIsTerminator(false); 337 lldb::addr_t size_of_data = process_sp->ReadPointerFromMemory( 338 addr_of_string + process_sp->GetAddressByteSize(), error); 339 if (error.Fail()) 340 return false; 341 options.SetSourceSize(size_of_data); 342 options.SetHasSourceSize(true); 343 options.SetPrefixToken("L"); 344 345 switch (wchar_size) { 346 case 8: 347 return StringPrinter::ReadStringAndDumpToStream< 348 StringPrinter::StringElementType::UTF8>(options); 349 case 16: 350 return StringPrinter::ReadStringAndDumpToStream< 351 StringPrinter::StringElementType::UTF16>(options); 352 case 32: 353 return StringPrinter::ReadStringAndDumpToStream< 354 StringPrinter::StringElementType::UTF32>(options); 355 default: 356 stream.Printf("size for wchar_t is not valid"); 357 return true; 358 } 359 return true; 360 } break; 361 case eAddressTypeHost: 362 break; 363 case eAddressTypeInvalid: 364 case eAddressTypeFile: 365 break; 366 } 367 } 368 return false; 369 } 370 371 LibStdcppSharedPtrSyntheticFrontEnd::LibStdcppSharedPtrSyntheticFrontEnd( 372 lldb::ValueObjectSP valobj_sp) 373 : SyntheticChildrenFrontEnd(*valobj_sp) { 374 if (valobj_sp) 375 Update(); 376 } 377 378 llvm::Expected<uint32_t> 379 LibStdcppSharedPtrSyntheticFrontEnd::CalculateNumChildren() { 380 return 1; 381 } 382 383 lldb::ValueObjectSP 384 LibStdcppSharedPtrSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) { 385 if (idx == 0) 386 return m_ptr_obj->GetSP(); 387 if (idx == 1) { 388 if (m_ptr_obj && !m_obj_obj) { 389 Status error; 390 ValueObjectSP obj_obj = m_ptr_obj->Dereference(error); 391 if (error.Success()) 392 m_obj_obj = obj_obj->Clone(ConstString("object")).get(); 393 } 394 if (m_obj_obj) 395 return m_obj_obj->GetSP(); 396 } 397 return lldb::ValueObjectSP(); 398 } 399 400 lldb::ChildCacheState LibStdcppSharedPtrSyntheticFrontEnd::Update() { 401 auto backend = m_backend.GetSP(); 402 if (!backend) 403 return lldb::ChildCacheState::eRefetch; 404 405 auto valobj_sp = backend->GetNonSyntheticValue(); 406 if (!valobj_sp) 407 return lldb::ChildCacheState::eRefetch; 408 409 auto ptr_obj_sp = valobj_sp->GetChildMemberWithName("_M_ptr"); 410 if (!ptr_obj_sp) 411 return lldb::ChildCacheState::eRefetch; 412 413 m_ptr_obj = ptr_obj_sp->Clone(ConstString("pointer")).get(); 414 m_obj_obj = nullptr; 415 416 return lldb::ChildCacheState::eRefetch; 417 } 418 419 bool LibStdcppSharedPtrSyntheticFrontEnd::MightHaveChildren() { return true; } 420 421 size_t LibStdcppSharedPtrSyntheticFrontEnd::GetIndexOfChildWithName( 422 ConstString name) { 423 if (name == "pointer") 424 return 0; 425 if (name == "object" || name == "$$dereference$$") 426 return 1; 427 return UINT32_MAX; 428 } 429 430 SyntheticChildrenFrontEnd * 431 lldb_private::formatters::LibStdcppSharedPtrSyntheticFrontEndCreator( 432 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 433 return (valobj_sp ? new LibStdcppSharedPtrSyntheticFrontEnd(valobj_sp) 434 : nullptr); 435 } 436 437 bool lldb_private::formatters::LibStdcppSmartPointerSummaryProvider( 438 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { 439 ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue()); 440 if (!valobj_sp) 441 return false; 442 443 ValueObjectSP ptr_sp(valobj_sp->GetChildMemberWithName("_M_ptr")); 444 if (!ptr_sp) 445 return false; 446 447 ValueObjectSP usecount_sp( 448 valobj_sp->GetChildAtNamePath({"_M_refcount", "_M_pi", "_M_use_count"})); 449 if (!usecount_sp) 450 return false; 451 452 if (ptr_sp->GetValueAsUnsigned(0) == 0 || 453 usecount_sp->GetValueAsUnsigned(0) == 0) { 454 stream.Printf("nullptr"); 455 return true; 456 } 457 458 Status error; 459 ValueObjectSP pointee_sp = ptr_sp->Dereference(error); 460 if (pointee_sp && error.Success()) { 461 if (pointee_sp->DumpPrintableRepresentation( 462 stream, ValueObject::eValueObjectRepresentationStyleSummary, 463 lldb::eFormatInvalid, 464 ValueObject::PrintableRepresentationSpecialCases::eDisable, 465 false)) { 466 return true; 467 } 468 } 469 470 stream.Printf("ptr = 0x%" PRIx64, ptr_sp->GetValueAsUnsigned(0)); 471 return true; 472 } 473