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