1 //===-- NSDictionary.cpp ----------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 // C Includes 11 // C++ Includes 12 #include <mutex> 13 14 // Other libraries and framework includes 15 #include "clang/AST/DeclCXX.h" 16 17 // Project includes 18 #include "NSDictionary.h" 19 20 #include "lldb/Core/DataBufferHeap.h" 21 #include "lldb/Core/Error.h" 22 #include "lldb/Core/Stream.h" 23 #include "lldb/Core/ValueObject.h" 24 #include "lldb/Core/ValueObjectConstResult.h" 25 #include "lldb/DataFormatters/FormattersHelpers.h" 26 #include "lldb/Host/Endian.h" 27 #include "lldb/Symbol/ClangASTContext.h" 28 #include "lldb/Target/Language.h" 29 #include "lldb/Target/ObjCLanguageRuntime.h" 30 #include "lldb/Target/StackFrame.h" 31 #include "lldb/Target/Target.h" 32 33 using namespace lldb; 34 using namespace lldb_private; 35 using namespace lldb_private::formatters; 36 37 std::map<ConstString, CXXFunctionSummaryFormat::Callback> & 38 NSDictionary_Additionals::GetAdditionalSummaries() { 39 static std::map<ConstString, CXXFunctionSummaryFormat::Callback> g_map; 40 return g_map; 41 } 42 43 std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback> & 44 NSDictionary_Additionals::GetAdditionalSynthetics() { 45 static std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback> 46 g_map; 47 return g_map; 48 } 49 50 static CompilerType GetLLDBNSPairType(TargetSP target_sp) { 51 CompilerType compiler_type; 52 53 ClangASTContext *target_ast_context = target_sp->GetScratchClangASTContext(); 54 55 if (target_ast_context) { 56 ConstString g___lldb_autogen_nspair("__lldb_autogen_nspair"); 57 58 compiler_type = 59 target_ast_context->GetTypeForIdentifier<clang::CXXRecordDecl>( 60 g___lldb_autogen_nspair); 61 62 if (!compiler_type) { 63 compiler_type = target_ast_context->CreateRecordType( 64 nullptr, lldb::eAccessPublic, g___lldb_autogen_nspair.GetCString(), 65 clang::TTK_Struct, lldb::eLanguageTypeC); 66 67 if (compiler_type) { 68 ClangASTContext::StartTagDeclarationDefinition(compiler_type); 69 CompilerType id_compiler_type = 70 target_ast_context->GetBasicType(eBasicTypeObjCID); 71 ClangASTContext::AddFieldToRecordType( 72 compiler_type, "key", id_compiler_type, lldb::eAccessPublic, 0); 73 ClangASTContext::AddFieldToRecordType( 74 compiler_type, "value", id_compiler_type, lldb::eAccessPublic, 0); 75 ClangASTContext::CompleteTagDeclarationDefinition(compiler_type); 76 } 77 } 78 } 79 return compiler_type; 80 } 81 82 namespace lldb_private { 83 namespace formatters { 84 class NSDictionaryISyntheticFrontEnd : public SyntheticChildrenFrontEnd { 85 public: 86 NSDictionaryISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); 87 88 ~NSDictionaryISyntheticFrontEnd() override; 89 90 size_t CalculateNumChildren() override; 91 92 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; 93 94 bool Update() override; 95 96 bool MightHaveChildren() override; 97 98 size_t GetIndexOfChildWithName(const ConstString &name) override; 99 100 private: 101 struct DataDescriptor_32 { 102 uint32_t _used : 26; 103 uint32_t _szidx : 6; 104 }; 105 106 struct DataDescriptor_64 { 107 uint64_t _used : 58; 108 uint32_t _szidx : 6; 109 }; 110 111 struct DictionaryItemDescriptor { 112 lldb::addr_t key_ptr; 113 lldb::addr_t val_ptr; 114 lldb::ValueObjectSP valobj_sp; 115 }; 116 117 ExecutionContextRef m_exe_ctx_ref; 118 uint8_t m_ptr_size; 119 lldb::ByteOrder m_order; 120 DataDescriptor_32 *m_data_32; 121 DataDescriptor_64 *m_data_64; 122 lldb::addr_t m_data_ptr; 123 CompilerType m_pair_type; 124 std::vector<DictionaryItemDescriptor> m_children; 125 }; 126 127 class NSDictionary1SyntheticFrontEnd : public SyntheticChildrenFrontEnd { 128 public: 129 NSDictionary1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); 130 131 ~NSDictionary1SyntheticFrontEnd() override = default; 132 133 size_t CalculateNumChildren() override; 134 135 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; 136 137 bool Update() override; 138 139 bool MightHaveChildren() override; 140 141 size_t GetIndexOfChildWithName(const ConstString &name) override; 142 143 private: 144 ValueObjectSP m_pair; 145 }; 146 147 class NSDictionaryMSyntheticFrontEnd : public SyntheticChildrenFrontEnd { 148 public: 149 NSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); 150 151 ~NSDictionaryMSyntheticFrontEnd() override; 152 153 size_t CalculateNumChildren() override; 154 155 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; 156 157 bool Update() override; 158 159 bool MightHaveChildren() override; 160 161 size_t GetIndexOfChildWithName(const ConstString &name) override; 162 163 private: 164 struct DataDescriptor_32 { 165 uint32_t _used : 26; 166 uint32_t _kvo : 1; 167 uint32_t _size; 168 uint32_t _mutations; 169 uint32_t _objs_addr; 170 uint32_t _keys_addr; 171 }; 172 173 struct DataDescriptor_64 { 174 uint64_t _used : 58; 175 uint32_t _kvo : 1; 176 uint64_t _size; 177 uint64_t _mutations; 178 uint64_t _objs_addr; 179 uint64_t _keys_addr; 180 }; 181 182 struct DictionaryItemDescriptor { 183 lldb::addr_t key_ptr; 184 lldb::addr_t val_ptr; 185 lldb::ValueObjectSP valobj_sp; 186 }; 187 188 ExecutionContextRef m_exe_ctx_ref; 189 uint8_t m_ptr_size; 190 lldb::ByteOrder m_order; 191 DataDescriptor_32 *m_data_32; 192 DataDescriptor_64 *m_data_64; 193 CompilerType m_pair_type; 194 std::vector<DictionaryItemDescriptor> m_children; 195 }; 196 } // namespace formatters 197 } // namespace lldb_private 198 199 template <bool name_entries> 200 bool lldb_private::formatters::NSDictionarySummaryProvider( 201 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { 202 static ConstString g_TypeHint("NSDictionary"); 203 ProcessSP process_sp = valobj.GetProcessSP(); 204 if (!process_sp) 205 return false; 206 207 ObjCLanguageRuntime *runtime = 208 (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime( 209 lldb::eLanguageTypeObjC); 210 211 if (!runtime) 212 return false; 213 214 ObjCLanguageRuntime::ClassDescriptorSP descriptor( 215 runtime->GetClassDescriptor(valobj)); 216 217 if (!descriptor || !descriptor->IsValid()) 218 return false; 219 220 uint32_t ptr_size = process_sp->GetAddressByteSize(); 221 bool is_64bit = (ptr_size == 8); 222 223 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 224 225 if (!valobj_addr) 226 return false; 227 228 uint64_t value = 0; 229 230 ConstString class_name(descriptor->GetClassName()); 231 232 static const ConstString g_DictionaryI("__NSDictionaryI"); 233 static const ConstString g_DictionaryM("__NSDictionaryM"); 234 static const ConstString g_Dictionary1("__NSSingleEntryDictionaryI"); 235 236 if (class_name.IsEmpty()) 237 return false; 238 239 if (class_name == g_DictionaryI) { 240 Error error; 241 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 242 ptr_size, 0, error); 243 if (error.Fail()) 244 return false; 245 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U); 246 } else if (class_name == g_DictionaryM) { 247 Error error; 248 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 249 ptr_size, 0, error); 250 if (error.Fail()) 251 return false; 252 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U); 253 } else if (class_name == g_Dictionary1) { 254 value = 1; 255 } 256 /*else if (!strcmp(class_name,"__NSCFDictionary")) 257 { 258 Error error; 259 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + (is_64bit ? 260 20 : 12), 4, 0, error); 261 if (error.Fail()) 262 return false; 263 if (is_64bit) 264 value &= ~0x0f1f000000000000UL; 265 }*/ 266 else { 267 auto &map(NSDictionary_Additionals::GetAdditionalSummaries()); 268 auto iter = map.find(class_name), end = map.end(); 269 if (iter != end) 270 return iter->second(valobj, stream, options); 271 else 272 return false; 273 } 274 275 std::string prefix, suffix; 276 if (Language *language = Language::FindPlugin(options.GetLanguage())) { 277 if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix, 278 suffix)) { 279 prefix.clear(); 280 suffix.clear(); 281 } 282 } 283 284 stream.Printf("%s%" PRIu64 " %s%s%s", prefix.c_str(), value, "key/value pair", 285 value == 1 ? "" : "s", suffix.c_str()); 286 return true; 287 } 288 289 SyntheticChildrenFrontEnd * 290 lldb_private::formatters::NSDictionarySyntheticFrontEndCreator( 291 CXXSyntheticChildren *synth, lldb::ValueObjectSP valobj_sp) { 292 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 293 if (!process_sp) 294 return nullptr; 295 ObjCLanguageRuntime *runtime = 296 (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime( 297 lldb::eLanguageTypeObjC); 298 if (!runtime) 299 return nullptr; 300 301 CompilerType valobj_type(valobj_sp->GetCompilerType()); 302 Flags flags(valobj_type.GetTypeInfo()); 303 304 if (flags.IsClear(eTypeIsPointer)) { 305 Error error; 306 valobj_sp = valobj_sp->AddressOf(error); 307 if (error.Fail() || !valobj_sp) 308 return nullptr; 309 } 310 311 ObjCLanguageRuntime::ClassDescriptorSP descriptor( 312 runtime->GetClassDescriptor(*valobj_sp)); 313 314 if (!descriptor || !descriptor->IsValid()) 315 return nullptr; 316 317 ConstString class_name(descriptor->GetClassName()); 318 319 static const ConstString g_DictionaryI("__NSDictionaryI"); 320 static const ConstString g_DictionaryM("__NSDictionaryM"); 321 static const ConstString g_Dictionary1("__NSSingleEntryDictionaryI"); 322 323 if (class_name.IsEmpty()) 324 return nullptr; 325 326 if (class_name == g_DictionaryI) { 327 return (new NSDictionaryISyntheticFrontEnd(valobj_sp)); 328 } else if (class_name == g_DictionaryM) { 329 return (new NSDictionaryMSyntheticFrontEnd(valobj_sp)); 330 } else if (class_name == g_Dictionary1) { 331 return (new NSDictionary1SyntheticFrontEnd(valobj_sp)); 332 } else { 333 auto &map(NSDictionary_Additionals::GetAdditionalSynthetics()); 334 auto iter = map.find(class_name), end = map.end(); 335 if (iter != end) 336 return iter->second(synth, valobj_sp); 337 } 338 339 return nullptr; 340 } 341 342 lldb_private::formatters::NSDictionaryISyntheticFrontEnd:: 343 NSDictionaryISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 344 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8), 345 m_order(lldb::eByteOrderInvalid), m_data_32(nullptr), m_data_64(nullptr), 346 m_pair_type() {} 347 348 lldb_private::formatters::NSDictionaryISyntheticFrontEnd:: 349 ~NSDictionaryISyntheticFrontEnd() { 350 delete m_data_32; 351 m_data_32 = nullptr; 352 delete m_data_64; 353 m_data_64 = nullptr; 354 } 355 356 size_t lldb_private::formatters::NSDictionaryISyntheticFrontEnd:: 357 GetIndexOfChildWithName(const ConstString &name) { 358 const char *item_name = name.GetCString(); 359 uint32_t idx = ExtractIndexFromString(item_name); 360 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 361 return UINT32_MAX; 362 return idx; 363 } 364 365 size_t lldb_private::formatters::NSDictionaryISyntheticFrontEnd:: 366 CalculateNumChildren() { 367 if (!m_data_32 && !m_data_64) 368 return 0; 369 return (m_data_32 ? m_data_32->_used : m_data_64->_used); 370 } 371 372 bool lldb_private::formatters::NSDictionaryISyntheticFrontEnd::Update() { 373 m_children.clear(); 374 delete m_data_32; 375 m_data_32 = nullptr; 376 delete m_data_64; 377 m_data_64 = nullptr; 378 m_ptr_size = 0; 379 ValueObjectSP valobj_sp = m_backend.GetSP(); 380 if (!valobj_sp) 381 return false; 382 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 383 Error error; 384 error.Clear(); 385 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 386 if (!process_sp) 387 return false; 388 m_ptr_size = process_sp->GetAddressByteSize(); 389 m_order = process_sp->GetByteOrder(); 390 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size; 391 if (m_ptr_size == 4) { 392 m_data_32 = new DataDescriptor_32(); 393 process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32), 394 error); 395 } else { 396 m_data_64 = new DataDescriptor_64(); 397 process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64), 398 error); 399 } 400 if (error.Fail()) 401 return false; 402 m_data_ptr = data_location + m_ptr_size; 403 return false; 404 } 405 406 bool lldb_private::formatters::NSDictionaryISyntheticFrontEnd:: 407 MightHaveChildren() { 408 return true; 409 } 410 411 lldb::ValueObjectSP 412 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::GetChildAtIndex( 413 size_t idx) { 414 uint32_t num_children = CalculateNumChildren(); 415 416 if (idx >= num_children) 417 return lldb::ValueObjectSP(); 418 419 if (m_children.empty()) { 420 // do the scan phase 421 lldb::addr_t key_at_idx = 0, val_at_idx = 0; 422 423 uint32_t tries = 0; 424 uint32_t test_idx = 0; 425 426 while (tries < num_children) { 427 key_at_idx = m_data_ptr + (2 * test_idx * m_ptr_size); 428 val_at_idx = key_at_idx + m_ptr_size; 429 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); 430 if (!process_sp) 431 return lldb::ValueObjectSP(); 432 Error error; 433 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error); 434 if (error.Fail()) 435 return lldb::ValueObjectSP(); 436 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error); 437 if (error.Fail()) 438 return lldb::ValueObjectSP(); 439 440 test_idx++; 441 442 if (!key_at_idx || !val_at_idx) 443 continue; 444 tries++; 445 446 DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx, 447 lldb::ValueObjectSP()}; 448 449 m_children.push_back(descriptor); 450 } 451 } 452 453 if (idx >= m_children.size()) // should never happen 454 return lldb::ValueObjectSP(); 455 456 DictionaryItemDescriptor &dict_item = m_children[idx]; 457 if (!dict_item.valobj_sp) { 458 if (!m_pair_type.IsValid()) { 459 TargetSP target_sp(m_backend.GetTargetSP()); 460 if (!target_sp) 461 return ValueObjectSP(); 462 m_pair_type = GetLLDBNSPairType(target_sp); 463 } 464 if (!m_pair_type.IsValid()) 465 return ValueObjectSP(); 466 467 DataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0)); 468 469 if (m_ptr_size == 8) { 470 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes(); 471 *data_ptr = dict_item.key_ptr; 472 *(data_ptr + 1) = dict_item.val_ptr; 473 } else { 474 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes(); 475 *data_ptr = dict_item.key_ptr; 476 *(data_ptr + 1) = dict_item.val_ptr; 477 } 478 479 StreamString idx_name; 480 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); 481 DataExtractor data(buffer_sp, m_order, m_ptr_size); 482 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetData(), data, 483 m_exe_ctx_ref, m_pair_type); 484 } 485 return dict_item.valobj_sp; 486 } 487 488 lldb_private::formatters::NSDictionary1SyntheticFrontEnd:: 489 NSDictionary1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 490 : SyntheticChildrenFrontEnd(*valobj_sp.get()), m_pair(nullptr) {} 491 492 size_t lldb_private::formatters::NSDictionary1SyntheticFrontEnd:: 493 GetIndexOfChildWithName(const ConstString &name) { 494 static const ConstString g_zero("[0]"); 495 496 if (name == g_zero) 497 return 0; 498 499 return UINT32_MAX; 500 } 501 502 size_t lldb_private::formatters::NSDictionary1SyntheticFrontEnd:: 503 CalculateNumChildren() { 504 return 1; 505 } 506 507 bool lldb_private::formatters::NSDictionary1SyntheticFrontEnd::Update() { 508 m_pair.reset(); 509 return false; 510 } 511 512 bool lldb_private::formatters::NSDictionary1SyntheticFrontEnd:: 513 MightHaveChildren() { 514 return true; 515 } 516 517 lldb::ValueObjectSP 518 lldb_private::formatters::NSDictionary1SyntheticFrontEnd::GetChildAtIndex( 519 size_t idx) { 520 if (idx != 0) 521 return lldb::ValueObjectSP(); 522 523 if (m_pair.get()) 524 return m_pair; 525 526 auto process_sp(m_backend.GetProcessSP()); 527 if (!process_sp) 528 return nullptr; 529 530 auto ptr_size = process_sp->GetAddressByteSize(); 531 532 lldb::addr_t key_ptr = 533 m_backend.GetValueAsUnsigned(LLDB_INVALID_ADDRESS) + ptr_size; 534 lldb::addr_t value_ptr = key_ptr + ptr_size; 535 536 Error error; 537 538 lldb::addr_t value_at_idx = process_sp->ReadPointerFromMemory(key_ptr, error); 539 if (error.Fail()) 540 return nullptr; 541 lldb::addr_t key_at_idx = process_sp->ReadPointerFromMemory(value_ptr, error); 542 if (error.Fail()) 543 return nullptr; 544 545 auto pair_type = 546 GetLLDBNSPairType(process_sp->GetTarget().shared_from_this()); 547 548 DataBufferSP buffer_sp(new DataBufferHeap(2 * ptr_size, 0)); 549 550 if (ptr_size == 8) { 551 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes(); 552 *data_ptr = key_at_idx; 553 *(data_ptr + 1) = value_at_idx; 554 } else { 555 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes(); 556 *data_ptr = key_ptr; 557 *(data_ptr + 1) = value_ptr; 558 } 559 560 DataExtractor data(buffer_sp, process_sp->GetByteOrder(), ptr_size); 561 m_pair = CreateValueObjectFromData( 562 "[0]", data, m_backend.GetExecutionContextRef(), pair_type); 563 564 return m_pair; 565 } 566 567 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd:: 568 NSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 569 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8), 570 m_order(lldb::eByteOrderInvalid), m_data_32(nullptr), m_data_64(nullptr), 571 m_pair_type() {} 572 573 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd:: 574 ~NSDictionaryMSyntheticFrontEnd() { 575 delete m_data_32; 576 m_data_32 = nullptr; 577 delete m_data_64; 578 m_data_64 = nullptr; 579 } 580 581 size_t lldb_private::formatters::NSDictionaryMSyntheticFrontEnd:: 582 GetIndexOfChildWithName(const ConstString &name) { 583 const char *item_name = name.GetCString(); 584 uint32_t idx = ExtractIndexFromString(item_name); 585 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 586 return UINT32_MAX; 587 return idx; 588 } 589 590 size_t lldb_private::formatters::NSDictionaryMSyntheticFrontEnd:: 591 CalculateNumChildren() { 592 if (!m_data_32 && !m_data_64) 593 return 0; 594 return (m_data_32 ? m_data_32->_used : m_data_64->_used); 595 } 596 597 bool lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::Update() { 598 m_children.clear(); 599 ValueObjectSP valobj_sp = m_backend.GetSP(); 600 m_ptr_size = 0; 601 delete m_data_32; 602 m_data_32 = nullptr; 603 delete m_data_64; 604 m_data_64 = nullptr; 605 if (!valobj_sp) 606 return false; 607 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 608 Error error; 609 error.Clear(); 610 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 611 if (!process_sp) 612 return false; 613 m_ptr_size = process_sp->GetAddressByteSize(); 614 m_order = process_sp->GetByteOrder(); 615 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size; 616 if (m_ptr_size == 4) { 617 m_data_32 = new DataDescriptor_32(); 618 process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32), 619 error); 620 } else { 621 m_data_64 = new DataDescriptor_64(); 622 process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64), 623 error); 624 } 625 if (error.Fail()) 626 return false; 627 return false; 628 } 629 630 bool lldb_private::formatters::NSDictionaryMSyntheticFrontEnd:: 631 MightHaveChildren() { 632 return true; 633 } 634 635 lldb::ValueObjectSP 636 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::GetChildAtIndex( 637 size_t idx) { 638 lldb::addr_t m_keys_ptr = 639 (m_data_32 ? m_data_32->_keys_addr : m_data_64->_keys_addr); 640 lldb::addr_t m_values_ptr = 641 (m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr); 642 643 uint32_t num_children = CalculateNumChildren(); 644 645 if (idx >= num_children) 646 return lldb::ValueObjectSP(); 647 648 if (m_children.empty()) { 649 // do the scan phase 650 lldb::addr_t key_at_idx = 0, val_at_idx = 0; 651 652 uint32_t tries = 0; 653 uint32_t test_idx = 0; 654 655 while (tries < num_children) { 656 key_at_idx = m_keys_ptr + (test_idx * m_ptr_size); 657 val_at_idx = m_values_ptr + (test_idx * m_ptr_size); 658 ; 659 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); 660 if (!process_sp) 661 return lldb::ValueObjectSP(); 662 Error error; 663 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error); 664 if (error.Fail()) 665 return lldb::ValueObjectSP(); 666 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error); 667 if (error.Fail()) 668 return lldb::ValueObjectSP(); 669 670 test_idx++; 671 672 if (!key_at_idx || !val_at_idx) 673 continue; 674 tries++; 675 676 DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx, 677 lldb::ValueObjectSP()}; 678 679 m_children.push_back(descriptor); 680 } 681 } 682 683 if (idx >= m_children.size()) // should never happen 684 return lldb::ValueObjectSP(); 685 686 DictionaryItemDescriptor &dict_item = m_children[idx]; 687 if (!dict_item.valobj_sp) { 688 if (!m_pair_type.IsValid()) { 689 TargetSP target_sp(m_backend.GetTargetSP()); 690 if (!target_sp) 691 return ValueObjectSP(); 692 m_pair_type = GetLLDBNSPairType(target_sp); 693 } 694 if (!m_pair_type.IsValid()) 695 return ValueObjectSP(); 696 697 DataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0)); 698 699 if (m_ptr_size == 8) { 700 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes(); 701 *data_ptr = dict_item.key_ptr; 702 *(data_ptr + 1) = dict_item.val_ptr; 703 } else { 704 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes(); 705 *data_ptr = dict_item.key_ptr; 706 *(data_ptr + 1) = dict_item.val_ptr; 707 } 708 709 StreamString idx_name; 710 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); 711 DataExtractor data(buffer_sp, m_order, m_ptr_size); 712 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetData(), data, 713 m_exe_ctx_ref, m_pair_type); 714 } 715 return dict_item.valobj_sp; 716 } 717 718 template bool lldb_private::formatters::NSDictionarySummaryProvider<true>( 719 ValueObject &, Stream &, const TypeSummaryOptions &); 720 721 template bool lldb_private::formatters::NSDictionarySummaryProvider<false>( 722 ValueObject &, Stream &, const TypeSummaryOptions &); 723