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/Core/ValueObject.h" 14 #include "lldb/Core/ValueObjectConstResult.h" 15 #include "lldb/DataFormatters/StringPrinter.h" 16 #include "lldb/DataFormatters/VectorIterator.h" 17 #include "lldb/Target/Target.h" 18 #include "lldb/Utility/DataBufferHeap.h" 19 #include "lldb/Utility/Endian.h" 20 #include "lldb/Utility/Status.h" 21 #include "lldb/Utility/Stream.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 size_t CalculateNumChildren() override; 47 48 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; 49 50 bool 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 size_t CalculateNumChildren() override; 68 69 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; 70 71 bool 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 bool LibstdcppMapIteratorSyntheticFrontEnd::Update() { 98 ValueObjectSP valobj_sp = m_backend.GetSP(); 99 if (!valobj_sp) 100 return false; 101 102 TargetSP target_sp(valobj_sp->GetTargetSP()); 103 104 if (!target_sp) 105 return false; 106 107 bool is_64bit = (target_sp->GetArchitecture().GetAddressByteSize() == 8); 108 109 if (!valobj_sp) 110 return false; 111 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 112 113 ValueObjectSP _M_node_sp( 114 valobj_sp->GetChildMemberWithName(ConstString("_M_node"), true)); 115 if (!_M_node_sp) 116 return false; 117 118 m_pair_address = _M_node_sp->GetValueAsUnsigned(0); 119 if (m_pair_address == 0) 120 return false; 121 122 m_pair_address += (is_64bit ? 32 : 16); 123 124 CompilerType my_type(valobj_sp->GetCompilerType()); 125 if (my_type.GetNumTemplateArguments() >= 1) { 126 CompilerType pair_type = my_type.GetTypeTemplateArgument(0); 127 if (!pair_type) 128 return false; 129 m_pair_type = pair_type; 130 } else 131 return false; 132 133 return true; 134 } 135 136 size_t LibstdcppMapIteratorSyntheticFrontEnd::CalculateNumChildren() { 137 return 2; 138 } 139 140 lldb::ValueObjectSP 141 LibstdcppMapIteratorSyntheticFrontEnd::GetChildAtIndex(size_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, true); 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 bool VectorIteratorSyntheticFrontEnd::Update() { 198 m_item_sp.reset(); 199 200 ValueObjectSP valobj_sp = m_backend.GetSP(); 201 if (!valobj_sp) 202 return false; 203 204 if (!valobj_sp) 205 return false; 206 207 ValueObjectSP item_ptr = 208 formatters::GetChildMemberWithName(*valobj_sp, m_item_names); 209 if (!item_ptr) 210 return false; 211 if (item_ptr->GetValueAsUnsigned(0) == 0) 212 return false; 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 false; 221 } 222 223 size_t VectorIteratorSyntheticFrontEnd::CalculateNumChildren() { return 1; } 224 225 lldb::ValueObjectSP 226 VectorIteratorSyntheticFrontEnd::GetChildAtIndex(size_t idx) { 227 if (idx == 0) 228 return m_item_sp; 229 return lldb::ValueObjectSP(); 230 } 231 232 bool VectorIteratorSyntheticFrontEnd::MightHaveChildren() { return true; } 233 234 size_t VectorIteratorSyntheticFrontEnd::GetIndexOfChildWithName( 235 ConstString name) { 236 if (name == "item") 237 return 0; 238 return UINT32_MAX; 239 } 240 241 bool lldb_private::formatters::LibStdcppStringSummaryProvider( 242 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { 243 const bool scalar_is_load_addr = true; 244 AddressType addr_type; 245 lldb::addr_t addr_of_string = LLDB_INVALID_ADDRESS; 246 if (valobj.IsPointerOrReferenceType()) { 247 Status error; 248 ValueObjectSP pointee_sp = valobj.Dereference(error); 249 if (pointee_sp && error.Success()) 250 addr_of_string = pointee_sp->GetAddressOf(scalar_is_load_addr, &addr_type); 251 } else 252 addr_of_string = 253 valobj.GetAddressOf(scalar_is_load_addr, &addr_type); 254 if (addr_of_string != LLDB_INVALID_ADDRESS) { 255 switch (addr_type) { 256 case eAddressTypeLoad: { 257 ProcessSP process_sp(valobj.GetProcessSP()); 258 if (!process_sp) 259 return false; 260 261 StringPrinter::ReadStringAndDumpToStreamOptions options(valobj); 262 Status error; 263 lldb::addr_t addr_of_data = 264 process_sp->ReadPointerFromMemory(addr_of_string, error); 265 if (error.Fail() || addr_of_data == 0 || 266 addr_of_data == LLDB_INVALID_ADDRESS) 267 return false; 268 options.SetLocation(addr_of_data); 269 options.SetTargetSP(valobj.GetTargetSP()); 270 options.SetStream(&stream); 271 options.SetNeedsZeroTermination(false); 272 options.SetBinaryZeroIsTerminator(true); 273 lldb::addr_t size_of_data = process_sp->ReadPointerFromMemory( 274 addr_of_string + process_sp->GetAddressByteSize(), error); 275 if (error.Fail()) 276 return false; 277 options.SetSourceSize(size_of_data); 278 options.SetHasSourceSize(true); 279 280 if (!StringPrinter::ReadStringAndDumpToStream< 281 StringPrinter::StringElementType::UTF8>(options)) { 282 stream.Printf("Summary Unavailable"); 283 return true; 284 } else 285 return true; 286 } break; 287 case eAddressTypeHost: 288 break; 289 case eAddressTypeInvalid: 290 case eAddressTypeFile: 291 break; 292 } 293 } 294 return false; 295 } 296 297 bool lldb_private::formatters::LibStdcppWStringSummaryProvider( 298 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { 299 const bool scalar_is_load_addr = true; 300 AddressType addr_type; 301 lldb::addr_t addr_of_string = 302 valobj.GetAddressOf(scalar_is_load_addr, &addr_type); 303 if (addr_of_string != LLDB_INVALID_ADDRESS) { 304 switch (addr_type) { 305 case eAddressTypeLoad: { 306 ProcessSP process_sp(valobj.GetProcessSP()); 307 if (!process_sp) 308 return false; 309 310 CompilerType wchar_compiler_type = 311 valobj.GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeWChar); 312 313 if (!wchar_compiler_type) 314 return false; 315 316 // Safe to pass nullptr for exe_scope here. 317 std::optional<uint64_t> size = wchar_compiler_type.GetBitSize(nullptr); 318 if (!size) 319 return false; 320 const uint32_t wchar_size = *size; 321 322 StringPrinter::ReadStringAndDumpToStreamOptions options(valobj); 323 Status error; 324 lldb::addr_t addr_of_data = 325 process_sp->ReadPointerFromMemory(addr_of_string, error); 326 if (error.Fail() || addr_of_data == 0 || 327 addr_of_data == LLDB_INVALID_ADDRESS) 328 return false; 329 options.SetLocation(addr_of_data); 330 options.SetTargetSP(valobj.GetTargetSP()); 331 options.SetStream(&stream); 332 options.SetNeedsZeroTermination(false); 333 options.SetBinaryZeroIsTerminator(false); 334 lldb::addr_t size_of_data = process_sp->ReadPointerFromMemory( 335 addr_of_string + process_sp->GetAddressByteSize(), error); 336 if (error.Fail()) 337 return false; 338 options.SetSourceSize(size_of_data); 339 options.SetHasSourceSize(true); 340 options.SetPrefixToken("L"); 341 342 switch (wchar_size) { 343 case 8: 344 return StringPrinter::ReadStringAndDumpToStream< 345 StringPrinter::StringElementType::UTF8>(options); 346 case 16: 347 return StringPrinter::ReadStringAndDumpToStream< 348 StringPrinter::StringElementType::UTF16>(options); 349 case 32: 350 return StringPrinter::ReadStringAndDumpToStream< 351 StringPrinter::StringElementType::UTF32>(options); 352 default: 353 stream.Printf("size for wchar_t is not valid"); 354 return true; 355 } 356 return true; 357 } break; 358 case eAddressTypeHost: 359 break; 360 case eAddressTypeInvalid: 361 case eAddressTypeFile: 362 break; 363 } 364 } 365 return false; 366 } 367 368 LibStdcppSharedPtrSyntheticFrontEnd::LibStdcppSharedPtrSyntheticFrontEnd( 369 lldb::ValueObjectSP valobj_sp) 370 : SyntheticChildrenFrontEnd(*valobj_sp) { 371 if (valobj_sp) 372 Update(); 373 } 374 375 size_t LibStdcppSharedPtrSyntheticFrontEnd::CalculateNumChildren() { return 1; } 376 377 lldb::ValueObjectSP 378 LibStdcppSharedPtrSyntheticFrontEnd::GetChildAtIndex(size_t idx) { 379 if (idx == 0) 380 return m_ptr_obj->GetSP(); 381 if (idx == 1) 382 return m_obj_obj->GetSP(); 383 384 return lldb::ValueObjectSP(); 385 } 386 387 bool LibStdcppSharedPtrSyntheticFrontEnd::Update() { 388 auto backend = m_backend.GetSP(); 389 if (!backend) 390 return false; 391 392 auto valobj_sp = backend->GetNonSyntheticValue(); 393 if (!valobj_sp) 394 return false; 395 396 auto ptr_obj_sp = valobj_sp->GetChildMemberWithName(ConstString("_M_ptr"), true); 397 if (!ptr_obj_sp) 398 return false; 399 400 m_ptr_obj = ptr_obj_sp->Clone(ConstString("pointer")).get(); 401 402 if (m_ptr_obj) { 403 Status error; 404 ValueObjectSP obj_obj = m_ptr_obj->Dereference(error); 405 if (error.Success()) { 406 m_obj_obj = obj_obj->Clone(ConstString("object")).get(); 407 } 408 } 409 410 return false; 411 } 412 413 bool LibStdcppSharedPtrSyntheticFrontEnd::MightHaveChildren() { return true; } 414 415 size_t LibStdcppSharedPtrSyntheticFrontEnd::GetIndexOfChildWithName( 416 ConstString name) { 417 if (name == "pointer") 418 return 0; 419 if (name == "object" || name == "$$dereference$$") 420 return 1; 421 return UINT32_MAX; 422 } 423 424 SyntheticChildrenFrontEnd * 425 lldb_private::formatters::LibStdcppSharedPtrSyntheticFrontEndCreator( 426 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 427 return (valobj_sp ? new LibStdcppSharedPtrSyntheticFrontEnd(valobj_sp) 428 : nullptr); 429 } 430 431 bool lldb_private::formatters::LibStdcppSmartPointerSummaryProvider( 432 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { 433 ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue()); 434 if (!valobj_sp) 435 return false; 436 437 ValueObjectSP ptr_sp( 438 valobj_sp->GetChildMemberWithName(ConstString("_M_ptr"), true)); 439 if (!ptr_sp) 440 return false; 441 442 ValueObjectSP usecount_sp(valobj_sp->GetChildAtNamePath( 443 {ConstString("_M_refcount"), ConstString("_M_pi"), 444 ConstString("_M_use_count")})); 445 if (!usecount_sp) 446 return false; 447 448 if (ptr_sp->GetValueAsUnsigned(0) == 0 || 449 usecount_sp->GetValueAsUnsigned(0) == 0) { 450 stream.Printf("nullptr"); 451 return true; 452 } 453 454 Status error; 455 ValueObjectSP pointee_sp = ptr_sp->Dereference(error); 456 if (pointee_sp && error.Success()) { 457 if (pointee_sp->DumpPrintableRepresentation( 458 stream, ValueObject::eValueObjectRepresentationStyleSummary, 459 lldb::eFormatInvalid, 460 ValueObject::PrintableRepresentationSpecialCases::eDisable, 461 false)) { 462 return true; 463 } 464 } 465 466 stream.Printf("ptr = 0x%" PRIx64, ptr_sp->GetValueAsUnsigned(0)); 467 return true; 468 } 469