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