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(valobj_sp->GetChildMemberWithName("_M_node")); 114 if (!_M_node_sp) 115 return false; 116 117 m_pair_address = _M_node_sp->GetValueAsUnsigned(0); 118 if (m_pair_address == 0) 119 return false; 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 false; 128 m_pair_type = pair_type; 129 } else 130 return false; 131 132 return true; 133 } 134 135 size_t LibstdcppMapIteratorSyntheticFrontEnd::CalculateNumChildren() { 136 return 2; 137 } 138 139 lldb::ValueObjectSP 140 LibstdcppMapIteratorSyntheticFrontEnd::GetChildAtIndex(size_t idx) { 141 if (m_pair_address != 0 && m_pair_type) { 142 if (!m_pair_sp) 143 m_pair_sp = CreateValueObjectFromAddress("pair", m_pair_address, 144 m_exe_ctx_ref, m_pair_type); 145 if (m_pair_sp) 146 return m_pair_sp->GetChildAtIndex(idx); 147 } 148 return lldb::ValueObjectSP(); 149 } 150 151 bool LibstdcppMapIteratorSyntheticFrontEnd::MightHaveChildren() { return true; } 152 153 size_t LibstdcppMapIteratorSyntheticFrontEnd::GetIndexOfChildWithName( 154 ConstString name) { 155 if (name == "first") 156 return 0; 157 if (name == "second") 158 return 1; 159 return UINT32_MAX; 160 } 161 162 SyntheticChildrenFrontEnd * 163 lldb_private::formatters::LibstdcppMapIteratorSyntheticFrontEndCreator( 164 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 165 return (valobj_sp ? new LibstdcppMapIteratorSyntheticFrontEnd(valobj_sp) 166 : nullptr); 167 } 168 169 /* 170 (lldb) fr var ibeg --ptr-depth 1 171 (__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > >) 172 ibeg = { 173 _M_current = 0x00000001001037a0 { 174 *_M_current = 1 175 } 176 } 177 */ 178 179 SyntheticChildrenFrontEnd * 180 lldb_private::formatters::LibStdcppVectorIteratorSyntheticFrontEndCreator( 181 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 182 return (valobj_sp ? new VectorIteratorSyntheticFrontEnd( 183 valobj_sp, {ConstString("_M_current")}) 184 : nullptr); 185 } 186 187 lldb_private::formatters::VectorIteratorSyntheticFrontEnd:: 188 VectorIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp, 189 llvm::ArrayRef<ConstString> item_names) 190 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), 191 m_item_names(item_names), m_item_sp() { 192 if (valobj_sp) 193 Update(); 194 } 195 196 bool VectorIteratorSyntheticFrontEnd::Update() { 197 m_item_sp.reset(); 198 199 ValueObjectSP valobj_sp = m_backend.GetSP(); 200 if (!valobj_sp) 201 return false; 202 203 if (!valobj_sp) 204 return false; 205 206 ValueObjectSP item_ptr = 207 formatters::GetChildMemberWithName(*valobj_sp, m_item_names); 208 if (!item_ptr) 209 return false; 210 if (item_ptr->GetValueAsUnsigned(0) == 0) 211 return false; 212 Status err; 213 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 214 m_item_sp = CreateValueObjectFromAddress( 215 "item", item_ptr->GetValueAsUnsigned(0), m_exe_ctx_ref, 216 item_ptr->GetCompilerType().GetPointeeType()); 217 if (err.Fail()) 218 m_item_sp.reset(); 219 return false; 220 } 221 222 size_t VectorIteratorSyntheticFrontEnd::CalculateNumChildren() { return 1; } 223 224 lldb::ValueObjectSP 225 VectorIteratorSyntheticFrontEnd::GetChildAtIndex(size_t idx) { 226 if (idx == 0) 227 return m_item_sp; 228 return lldb::ValueObjectSP(); 229 } 230 231 bool VectorIteratorSyntheticFrontEnd::MightHaveChildren() { return true; } 232 233 size_t VectorIteratorSyntheticFrontEnd::GetIndexOfChildWithName( 234 ConstString name) { 235 if (name == "item") 236 return 0; 237 return UINT32_MAX; 238 } 239 240 bool lldb_private::formatters::LibStdcppStringSummaryProvider( 241 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { 242 const bool scalar_is_load_addr = true; 243 AddressType addr_type; 244 lldb::addr_t addr_of_string = LLDB_INVALID_ADDRESS; 245 if (valobj.IsPointerOrReferenceType()) { 246 Status error; 247 ValueObjectSP pointee_sp = valobj.Dereference(error); 248 if (pointee_sp && error.Success()) 249 addr_of_string = pointee_sp->GetAddressOf(scalar_is_load_addr, &addr_type); 250 } else 251 addr_of_string = 252 valobj.GetAddressOf(scalar_is_load_addr, &addr_type); 253 if (addr_of_string != LLDB_INVALID_ADDRESS) { 254 switch (addr_type) { 255 case eAddressTypeLoad: { 256 ProcessSP process_sp(valobj.GetProcessSP()); 257 if (!process_sp) 258 return false; 259 260 StringPrinter::ReadStringAndDumpToStreamOptions options(valobj); 261 Status error; 262 lldb::addr_t addr_of_data = 263 process_sp->ReadPointerFromMemory(addr_of_string, error); 264 if (error.Fail() || addr_of_data == 0 || 265 addr_of_data == LLDB_INVALID_ADDRESS) 266 return false; 267 options.SetLocation(addr_of_data); 268 options.SetTargetSP(valobj.GetTargetSP()); 269 options.SetStream(&stream); 270 options.SetNeedsZeroTermination(false); 271 options.SetBinaryZeroIsTerminator(true); 272 lldb::addr_t size_of_data = process_sp->ReadPointerFromMemory( 273 addr_of_string + process_sp->GetAddressByteSize(), error); 274 if (error.Fail()) 275 return false; 276 options.SetSourceSize(size_of_data); 277 options.SetHasSourceSize(true); 278 279 if (!StringPrinter::ReadStringAndDumpToStream< 280 StringPrinter::StringElementType::UTF8>(options)) { 281 stream.Printf("Summary Unavailable"); 282 return true; 283 } else 284 return true; 285 } break; 286 case eAddressTypeHost: 287 break; 288 case eAddressTypeInvalid: 289 case eAddressTypeFile: 290 break; 291 } 292 } 293 return false; 294 } 295 296 bool lldb_private::formatters::LibStdcppWStringSummaryProvider( 297 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { 298 const bool scalar_is_load_addr = true; 299 AddressType addr_type; 300 lldb::addr_t addr_of_string = 301 valobj.GetAddressOf(scalar_is_load_addr, &addr_type); 302 if (addr_of_string != LLDB_INVALID_ADDRESS) { 303 switch (addr_type) { 304 case eAddressTypeLoad: { 305 ProcessSP process_sp(valobj.GetProcessSP()); 306 if (!process_sp) 307 return false; 308 309 CompilerType wchar_compiler_type = 310 valobj.GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeWChar); 311 312 if (!wchar_compiler_type) 313 return false; 314 315 // Safe to pass nullptr for exe_scope here. 316 std::optional<uint64_t> size = wchar_compiler_type.GetBitSize(nullptr); 317 if (!size) 318 return false; 319 const uint32_t wchar_size = *size; 320 321 StringPrinter::ReadStringAndDumpToStreamOptions options(valobj); 322 Status error; 323 lldb::addr_t addr_of_data = 324 process_sp->ReadPointerFromMemory(addr_of_string, error); 325 if (error.Fail() || addr_of_data == 0 || 326 addr_of_data == LLDB_INVALID_ADDRESS) 327 return false; 328 options.SetLocation(addr_of_data); 329 options.SetTargetSP(valobj.GetTargetSP()); 330 options.SetStream(&stream); 331 options.SetNeedsZeroTermination(false); 332 options.SetBinaryZeroIsTerminator(false); 333 lldb::addr_t size_of_data = process_sp->ReadPointerFromMemory( 334 addr_of_string + process_sp->GetAddressByteSize(), error); 335 if (error.Fail()) 336 return false; 337 options.SetSourceSize(size_of_data); 338 options.SetHasSourceSize(true); 339 options.SetPrefixToken("L"); 340 341 switch (wchar_size) { 342 case 8: 343 return StringPrinter::ReadStringAndDumpToStream< 344 StringPrinter::StringElementType::UTF8>(options); 345 case 16: 346 return StringPrinter::ReadStringAndDumpToStream< 347 StringPrinter::StringElementType::UTF16>(options); 348 case 32: 349 return StringPrinter::ReadStringAndDumpToStream< 350 StringPrinter::StringElementType::UTF32>(options); 351 default: 352 stream.Printf("size for wchar_t is not valid"); 353 return true; 354 } 355 return true; 356 } break; 357 case eAddressTypeHost: 358 break; 359 case eAddressTypeInvalid: 360 case eAddressTypeFile: 361 break; 362 } 363 } 364 return false; 365 } 366 367 LibStdcppSharedPtrSyntheticFrontEnd::LibStdcppSharedPtrSyntheticFrontEnd( 368 lldb::ValueObjectSP valobj_sp) 369 : SyntheticChildrenFrontEnd(*valobj_sp) { 370 if (valobj_sp) 371 Update(); 372 } 373 374 size_t LibStdcppSharedPtrSyntheticFrontEnd::CalculateNumChildren() { return 1; } 375 376 lldb::ValueObjectSP 377 LibStdcppSharedPtrSyntheticFrontEnd::GetChildAtIndex(size_t idx) { 378 if (idx == 0) 379 return m_ptr_obj->GetSP(); 380 if (idx == 1) 381 return m_obj_obj->GetSP(); 382 383 return lldb::ValueObjectSP(); 384 } 385 386 bool LibStdcppSharedPtrSyntheticFrontEnd::Update() { 387 auto backend = m_backend.GetSP(); 388 if (!backend) 389 return false; 390 391 auto valobj_sp = backend->GetNonSyntheticValue(); 392 if (!valobj_sp) 393 return false; 394 395 auto ptr_obj_sp = valobj_sp->GetChildMemberWithName("_M_ptr"); 396 if (!ptr_obj_sp) 397 return false; 398 399 m_ptr_obj = ptr_obj_sp->Clone(ConstString("pointer")).get(); 400 401 if (m_ptr_obj) { 402 Status error; 403 ValueObjectSP obj_obj = m_ptr_obj->Dereference(error); 404 if (error.Success()) { 405 m_obj_obj = obj_obj->Clone(ConstString("object")).get(); 406 } 407 } 408 409 return false; 410 } 411 412 bool LibStdcppSharedPtrSyntheticFrontEnd::MightHaveChildren() { return true; } 413 414 size_t LibStdcppSharedPtrSyntheticFrontEnd::GetIndexOfChildWithName( 415 ConstString name) { 416 if (name == "pointer") 417 return 0; 418 if (name == "object" || name == "$$dereference$$") 419 return 1; 420 return UINT32_MAX; 421 } 422 423 SyntheticChildrenFrontEnd * 424 lldb_private::formatters::LibStdcppSharedPtrSyntheticFrontEndCreator( 425 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 426 return (valobj_sp ? new LibStdcppSharedPtrSyntheticFrontEnd(valobj_sp) 427 : nullptr); 428 } 429 430 bool lldb_private::formatters::LibStdcppSmartPointerSummaryProvider( 431 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { 432 ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue()); 433 if (!valobj_sp) 434 return false; 435 436 ValueObjectSP ptr_sp(valobj_sp->GetChildMemberWithName("_M_ptr")); 437 if (!ptr_sp) 438 return false; 439 440 ValueObjectSP usecount_sp( 441 valobj_sp->GetChildAtNamePath({"_M_refcount", "_M_pi", "_M_use_count"})); 442 if (!usecount_sp) 443 return false; 444 445 if (ptr_sp->GetValueAsUnsigned(0) == 0 || 446 usecount_sp->GetValueAsUnsigned(0) == 0) { 447 stream.Printf("nullptr"); 448 return true; 449 } 450 451 Status error; 452 ValueObjectSP pointee_sp = ptr_sp->Dereference(error); 453 if (pointee_sp && error.Success()) { 454 if (pointee_sp->DumpPrintableRepresentation( 455 stream, ValueObject::eValueObjectRepresentationStyleSummary, 456 lldb::eFormatInvalid, 457 ValueObject::PrintableRepresentationSpecialCases::eDisable, 458 false)) { 459 return true; 460 } 461 } 462 463 stream.Printf("ptr = 0x%" PRIx64, ptr_sp->GetValueAsUnsigned(0)); 464 return true; 465 } 466