1 //===-- NSDictionary.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 <mutex> 10 11 #include "clang/AST/DeclCXX.h" 12 13 #include "CFBasicHash.h" 14 #include "NSDictionary.h" 15 16 #include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h" 17 #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" 18 19 #include "lldb/Core/ValueObject.h" 20 #include "lldb/Core/ValueObjectConstResult.h" 21 #include "lldb/DataFormatters/FormattersHelpers.h" 22 #include "lldb/Target/Language.h" 23 #include "lldb/Target/StackFrame.h" 24 #include "lldb/Target/Target.h" 25 #include "lldb/Utility/DataBufferHeap.h" 26 #include "lldb/Utility/Endian.h" 27 #include "lldb/Utility/Status.h" 28 #include "lldb/Utility/Stream.h" 29 30 using namespace lldb; 31 using namespace lldb_private; 32 using namespace lldb_private::formatters; 33 34 NSDictionary_Additionals::AdditionalFormatterMatching::Prefix::Prefix( 35 ConstString p) 36 : m_prefix(p) {} 37 38 bool NSDictionary_Additionals::AdditionalFormatterMatching::Prefix::Match( 39 ConstString class_name) { 40 return class_name.GetStringRef().startswith(m_prefix.GetStringRef()); 41 } 42 43 NSDictionary_Additionals::AdditionalFormatterMatching::Full::Full(ConstString n) 44 : m_name(n) {} 45 46 bool NSDictionary_Additionals::AdditionalFormatterMatching::Full::Match( 47 ConstString class_name) { 48 return (class_name == m_name); 49 } 50 51 NSDictionary_Additionals::AdditionalFormatters< 52 CXXFunctionSummaryFormat::Callback> & 53 NSDictionary_Additionals::GetAdditionalSummaries() { 54 static AdditionalFormatters<CXXFunctionSummaryFormat::Callback> g_map; 55 return g_map; 56 } 57 58 NSDictionary_Additionals::AdditionalFormatters< 59 CXXSyntheticChildren::CreateFrontEndCallback> & 60 NSDictionary_Additionals::GetAdditionalSynthetics() { 61 static AdditionalFormatters<CXXSyntheticChildren::CreateFrontEndCallback> 62 g_map; 63 return g_map; 64 } 65 66 static CompilerType GetLLDBNSPairType(TargetSP target_sp) { 67 CompilerType compiler_type; 68 69 TypeSystemClang *target_ast_context = 70 ScratchTypeSystemClang::GetForTarget(*target_sp); 71 72 if (target_ast_context) { 73 ConstString g_lldb_autogen_nspair("__lldb_autogen_nspair"); 74 75 compiler_type = 76 target_ast_context->GetTypeForIdentifier<clang::CXXRecordDecl>( 77 g_lldb_autogen_nspair); 78 79 if (!compiler_type) { 80 compiler_type = target_ast_context->CreateRecordType( 81 nullptr, OptionalClangModuleID(), lldb::eAccessPublic, 82 g_lldb_autogen_nspair.GetCString(), clang::TTK_Struct, 83 lldb::eLanguageTypeC); 84 85 if (compiler_type) { 86 TypeSystemClang::StartTagDeclarationDefinition(compiler_type); 87 CompilerType id_compiler_type = 88 target_ast_context->GetBasicType(eBasicTypeObjCID); 89 TypeSystemClang::AddFieldToRecordType( 90 compiler_type, "key", id_compiler_type, lldb::eAccessPublic, 0); 91 TypeSystemClang::AddFieldToRecordType( 92 compiler_type, "value", id_compiler_type, lldb::eAccessPublic, 0); 93 TypeSystemClang::CompleteTagDeclarationDefinition(compiler_type); 94 } 95 } 96 } 97 return compiler_type; 98 } 99 100 namespace lldb_private { 101 namespace formatters { 102 class NSDictionaryISyntheticFrontEnd : public SyntheticChildrenFrontEnd { 103 public: 104 NSDictionaryISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); 105 106 ~NSDictionaryISyntheticFrontEnd() override; 107 108 size_t CalculateNumChildren() override; 109 110 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; 111 112 bool Update() override; 113 114 bool MightHaveChildren() override; 115 116 size_t GetIndexOfChildWithName(ConstString name) override; 117 118 private: 119 struct DataDescriptor_32 { 120 uint32_t _used : 26; 121 uint32_t _szidx : 6; 122 }; 123 124 struct DataDescriptor_64 { 125 uint64_t _used : 58; 126 uint32_t _szidx : 6; 127 }; 128 129 struct DictionaryItemDescriptor { 130 lldb::addr_t key_ptr; 131 lldb::addr_t val_ptr; 132 lldb::ValueObjectSP valobj_sp; 133 }; 134 135 ExecutionContextRef m_exe_ctx_ref; 136 uint8_t m_ptr_size = 8; 137 lldb::ByteOrder m_order = lldb::eByteOrderInvalid; 138 DataDescriptor_32 *m_data_32 = nullptr; 139 DataDescriptor_64 *m_data_64 = nullptr; 140 lldb::addr_t m_data_ptr = LLDB_INVALID_ADDRESS; 141 CompilerType m_pair_type; 142 std::vector<DictionaryItemDescriptor> m_children; 143 }; 144 145 class NSConstantDictionarySyntheticFrontEnd : public SyntheticChildrenFrontEnd { 146 public: 147 NSConstantDictionarySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); 148 149 size_t CalculateNumChildren() override; 150 151 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; 152 153 bool Update() override; 154 155 bool MightHaveChildren() override; 156 157 size_t GetIndexOfChildWithName(ConstString name) override; 158 159 private: 160 ExecutionContextRef m_exe_ctx_ref; 161 CompilerType m_pair_type; 162 uint8_t m_ptr_size = 8; 163 lldb::ByteOrder m_order = lldb::eByteOrderInvalid; 164 unsigned int m_size = 0; 165 lldb::addr_t m_keys_ptr = LLDB_INVALID_ADDRESS; 166 lldb::addr_t m_objects_ptr = LLDB_INVALID_ADDRESS; 167 168 struct DictionaryItemDescriptor { 169 lldb::addr_t key_ptr; 170 lldb::addr_t val_ptr; 171 lldb::ValueObjectSP valobj_sp; 172 }; 173 174 std::vector<DictionaryItemDescriptor> m_children; 175 }; 176 177 class NSCFDictionarySyntheticFrontEnd : public SyntheticChildrenFrontEnd { 178 public: 179 NSCFDictionarySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); 180 181 size_t CalculateNumChildren() override; 182 183 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; 184 185 bool Update() override; 186 187 bool MightHaveChildren() override; 188 189 size_t GetIndexOfChildWithName(ConstString name) override; 190 191 private: 192 struct DictionaryItemDescriptor { 193 lldb::addr_t key_ptr; 194 lldb::addr_t val_ptr; 195 lldb::ValueObjectSP valobj_sp; 196 }; 197 198 ExecutionContextRef m_exe_ctx_ref; 199 uint8_t m_ptr_size = 8; 200 lldb::ByteOrder m_order = lldb::eByteOrderInvalid; 201 202 CFBasicHash m_hashtable; 203 204 CompilerType m_pair_type; 205 std::vector<DictionaryItemDescriptor> m_children; 206 }; 207 208 class NSDictionary1SyntheticFrontEnd : public SyntheticChildrenFrontEnd { 209 public: 210 NSDictionary1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); 211 212 ~NSDictionary1SyntheticFrontEnd() override = default; 213 214 size_t CalculateNumChildren() override; 215 216 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; 217 218 bool Update() override; 219 220 bool MightHaveChildren() override; 221 222 size_t GetIndexOfChildWithName(ConstString name) override; 223 224 private: 225 ValueObjectSP m_pair; 226 }; 227 228 template <typename D32, typename D64> 229 class GenericNSDictionaryMSyntheticFrontEnd : public SyntheticChildrenFrontEnd { 230 public: 231 GenericNSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); 232 233 ~GenericNSDictionaryMSyntheticFrontEnd() override; 234 235 size_t CalculateNumChildren() override; 236 237 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; 238 239 bool Update() override; 240 241 bool MightHaveChildren() override; 242 243 size_t GetIndexOfChildWithName(ConstString name) override; 244 245 private: 246 struct DictionaryItemDescriptor { 247 lldb::addr_t key_ptr; 248 lldb::addr_t val_ptr; 249 lldb::ValueObjectSP valobj_sp; 250 }; 251 252 ExecutionContextRef m_exe_ctx_ref; 253 uint8_t m_ptr_size = 8; 254 lldb::ByteOrder m_order = lldb::eByteOrderInvalid; 255 D32 *m_data_32; 256 D64 *m_data_64; 257 CompilerType m_pair_type; 258 std::vector<DictionaryItemDescriptor> m_children; 259 }; 260 261 namespace Foundation1100 { 262 class NSDictionaryMSyntheticFrontEnd : public SyntheticChildrenFrontEnd { 263 public: 264 NSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); 265 266 ~NSDictionaryMSyntheticFrontEnd() override; 267 268 size_t CalculateNumChildren() override; 269 270 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; 271 272 bool Update() override; 273 274 bool MightHaveChildren() override; 275 276 size_t GetIndexOfChildWithName(ConstString name) override; 277 278 private: 279 struct DataDescriptor_32 { 280 uint32_t _used : 26; 281 uint32_t _kvo : 1; 282 uint32_t _size; 283 uint32_t _mutations; 284 uint32_t _objs_addr; 285 uint32_t _keys_addr; 286 }; 287 288 struct DataDescriptor_64 { 289 uint64_t _used : 58; 290 uint32_t _kvo : 1; 291 uint64_t _size; 292 uint64_t _mutations; 293 uint64_t _objs_addr; 294 uint64_t _keys_addr; 295 }; 296 297 struct DictionaryItemDescriptor { 298 lldb::addr_t key_ptr; 299 lldb::addr_t val_ptr; 300 lldb::ValueObjectSP valobj_sp; 301 }; 302 303 ExecutionContextRef m_exe_ctx_ref; 304 uint8_t m_ptr_size = 8; 305 lldb::ByteOrder m_order = lldb::eByteOrderInvalid; 306 DataDescriptor_32 *m_data_32 = nullptr; 307 DataDescriptor_64 *m_data_64 = nullptr; 308 CompilerType m_pair_type; 309 std::vector<DictionaryItemDescriptor> m_children; 310 }; 311 } 312 313 namespace Foundation1428 { 314 namespace { 315 struct DataDescriptor_32 { 316 uint32_t _used : 26; 317 uint32_t _kvo : 1; 318 uint32_t _size; 319 uint32_t _buffer; 320 uint64_t GetSize() { return _size; } 321 }; 322 323 struct DataDescriptor_64 { 324 uint64_t _used : 58; 325 uint32_t _kvo : 1; 326 uint64_t _size; 327 uint64_t _buffer; 328 uint64_t GetSize() { return _size; } 329 }; 330 } 331 332 using NSDictionaryMSyntheticFrontEnd = 333 GenericNSDictionaryMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>; 334 } 335 336 namespace Foundation1437 { 337 static const uint64_t NSDictionaryCapacities[] = { 338 0, 3, 7, 13, 23, 41, 71, 127, 191, 251, 383, 631, 1087, 1723, 339 2803, 4523, 7351, 11959, 19447, 31231, 50683, 81919, 132607, 340 214519, 346607, 561109, 907759, 1468927, 2376191, 3845119, 341 6221311, 10066421, 16287743, 26354171, 42641881, 68996069, 342 111638519, 180634607, 292272623, 472907251 343 }; 344 345 static const size_t NSDictionaryNumSizeBuckets = 346 sizeof(NSDictionaryCapacities) / sizeof(uint64_t); 347 348 namespace { 349 struct DataDescriptor_32 { 350 uint32_t _buffer; 351 uint32_t _muts; 352 uint32_t _used : 25; 353 uint32_t _kvo : 1; 354 uint32_t _szidx : 6; 355 356 uint64_t GetSize() { 357 return (_szidx) >= NSDictionaryNumSizeBuckets ? 358 0 : NSDictionaryCapacities[_szidx]; 359 } 360 }; 361 362 struct DataDescriptor_64 { 363 uint64_t _buffer; 364 uint32_t _muts; 365 uint32_t _used : 25; 366 uint32_t _kvo : 1; 367 uint32_t _szidx : 6; 368 369 uint64_t GetSize() { 370 return (_szidx) >= NSDictionaryNumSizeBuckets ? 371 0 : NSDictionaryCapacities[_szidx]; 372 } 373 }; 374 } // namespace 375 376 using NSDictionaryMSyntheticFrontEnd = 377 GenericNSDictionaryMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>; 378 379 template <typename DD> 380 uint64_t 381 __NSDictionaryMSize_Impl(lldb_private::Process &process, 382 lldb::addr_t valobj_addr, Status &error) { 383 const lldb::addr_t start_of_descriptor = 384 valobj_addr + process.GetAddressByteSize(); 385 DD descriptor = DD(); 386 process.ReadMemory(start_of_descriptor, &descriptor, sizeof(descriptor), 387 error); 388 if (error.Fail()) { 389 return 0; 390 } 391 return descriptor._used; 392 } 393 394 uint64_t 395 __NSDictionaryMSize(lldb_private::Process &process, lldb::addr_t valobj_addr, 396 Status &error) { 397 if (process.GetAddressByteSize() == 4) { 398 return __NSDictionaryMSize_Impl<DataDescriptor_32>(process, valobj_addr, 399 error); 400 } else { 401 return __NSDictionaryMSize_Impl<DataDescriptor_64>(process, valobj_addr, 402 error); 403 } 404 } 405 406 } 407 } // namespace formatters 408 } // namespace lldb_private 409 410 template <bool name_entries> 411 bool lldb_private::formatters::NSDictionarySummaryProvider( 412 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { 413 static ConstString g_TypeHint("NSDictionary"); 414 ProcessSP process_sp = valobj.GetProcessSP(); 415 if (!process_sp) 416 return false; 417 418 ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp); 419 420 if (!runtime) 421 return false; 422 423 ObjCLanguageRuntime::ClassDescriptorSP descriptor( 424 runtime->GetNonKVOClassDescriptor(valobj)); 425 426 if (!descriptor || !descriptor->IsValid()) 427 return false; 428 429 uint32_t ptr_size = process_sp->GetAddressByteSize(); 430 bool is_64bit = (ptr_size == 8); 431 432 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 433 434 if (!valobj_addr) 435 return false; 436 437 uint64_t value = 0; 438 439 ConstString class_name(descriptor->GetClassName()); 440 441 static const ConstString g_DictionaryI("__NSDictionaryI"); 442 static const ConstString g_DictionaryM("__NSDictionaryM"); 443 static const ConstString g_DictionaryMLegacy("__NSDictionaryM_Legacy"); 444 static const ConstString g_DictionaryMImmutable("__NSDictionaryM_Immutable"); 445 static const ConstString g_DictionaryMFrozen("__NSFrozenDictionaryM"); 446 static const ConstString g_Dictionary1("__NSSingleEntryDictionaryI"); 447 static const ConstString g_Dictionary0("__NSDictionary0"); 448 static const ConstString g_DictionaryCF("__CFDictionary"); 449 static const ConstString g_DictionaryNSCF("__NSCFDictionary"); 450 static const ConstString g_DictionaryCFRef("CFDictionaryRef"); 451 static const ConstString g_ConstantDictionary("NSConstantDictionary"); 452 453 if (class_name.IsEmpty()) 454 return false; 455 456 if (class_name == g_DictionaryI || class_name == g_DictionaryMImmutable) { 457 Status error; 458 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 459 ptr_size, 0, error); 460 if (error.Fail()) 461 return false; 462 463 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U); 464 } else if (class_name == g_ConstantDictionary) { 465 Status error; 466 value = process_sp->ReadUnsignedIntegerFromMemory( 467 valobj_addr + 2 * ptr_size, ptr_size, 0, error); 468 if (error.Fail()) 469 return false; 470 } else if (class_name == g_DictionaryM || class_name == g_DictionaryMLegacy || 471 class_name == g_DictionaryMFrozen) { 472 AppleObjCRuntime *apple_runtime = 473 llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime); 474 Status error; 475 if (apple_runtime && apple_runtime->GetFoundationVersion() >= 1437) { 476 value = Foundation1437::__NSDictionaryMSize(*process_sp, valobj_addr, 477 error); 478 } else { 479 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 480 ptr_size, 0, error); 481 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U); 482 } 483 if (error.Fail()) 484 return false; 485 } else if (class_name == g_Dictionary1) { 486 value = 1; 487 } else if (class_name == g_Dictionary0) { 488 value = 0; 489 } else if (class_name == g_DictionaryCF || class_name == g_DictionaryNSCF || 490 class_name == g_DictionaryCFRef) { 491 ExecutionContext exe_ctx(process_sp); 492 CFBasicHash cfbh; 493 if (!cfbh.Update(valobj_addr, exe_ctx)) 494 return false; 495 value = cfbh.GetCount(); 496 } else { 497 auto &map(NSDictionary_Additionals::GetAdditionalSummaries()); 498 for (auto &candidate : map) { 499 if (candidate.first && candidate.first->Match(class_name)) 500 return candidate.second(valobj, stream, options); 501 } 502 return false; 503 } 504 505 std::string prefix, suffix; 506 if (Language *language = Language::FindPlugin(options.GetLanguage())) { 507 if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix, 508 suffix)) { 509 prefix.clear(); 510 suffix.clear(); 511 } 512 } 513 514 stream.Printf("%s%" PRIu64 " %s%s%s", prefix.c_str(), value, "key/value pair", 515 value == 1 ? "" : "s", suffix.c_str()); 516 return true; 517 } 518 519 SyntheticChildrenFrontEnd * 520 lldb_private::formatters::NSDictionarySyntheticFrontEndCreator( 521 CXXSyntheticChildren *synth, lldb::ValueObjectSP valobj_sp) { 522 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 523 if (!process_sp) 524 return nullptr; 525 AppleObjCRuntime *runtime = llvm::dyn_cast_or_null<AppleObjCRuntime>( 526 ObjCLanguageRuntime::Get(*process_sp)); 527 if (!runtime) 528 return nullptr; 529 530 CompilerType valobj_type(valobj_sp->GetCompilerType()); 531 Flags flags(valobj_type.GetTypeInfo()); 532 533 if (flags.IsClear(eTypeIsPointer)) { 534 Status error; 535 valobj_sp = valobj_sp->AddressOf(error); 536 if (error.Fail() || !valobj_sp) 537 return nullptr; 538 } 539 540 ObjCLanguageRuntime::ClassDescriptorSP descriptor( 541 runtime->GetClassDescriptor(*valobj_sp)); 542 543 if (!descriptor || !descriptor->IsValid()) 544 return nullptr; 545 546 ConstString class_name(descriptor->GetClassName()); 547 548 static const ConstString g_DictionaryI("__NSDictionaryI"); 549 static const ConstString g_DictionaryM("__NSDictionaryM"); 550 static const ConstString g_Dictionary1("__NSSingleEntryDictionaryI"); 551 static const ConstString g_DictionaryImmutable("__NSDictionaryM_Immutable"); 552 static const ConstString g_DictionaryMFrozen("__NSFrozenDictionaryM"); 553 static const ConstString g_DictionaryMLegacy("__NSDictionaryM_Legacy"); 554 static const ConstString g_Dictionary0("__NSDictionary0"); 555 static const ConstString g_DictionaryCF("__CFDictionary"); 556 static const ConstString g_DictionaryNSCF("__NSCFDictionary"); 557 static const ConstString g_DictionaryCFRef("CFDictionaryRef"); 558 static const ConstString g_ConstantDictionary("NSConstantDictionary"); 559 560 if (class_name.IsEmpty()) 561 return nullptr; 562 563 if (class_name == g_DictionaryI) { 564 return (new NSDictionaryISyntheticFrontEnd(valobj_sp)); 565 } else if (class_name == g_ConstantDictionary) { 566 return (new NSConstantDictionarySyntheticFrontEnd(valobj_sp)); 567 } else if (class_name == g_DictionaryM || class_name == g_DictionaryMFrozen) { 568 if (runtime->GetFoundationVersion() >= 1437) { 569 return (new Foundation1437::NSDictionaryMSyntheticFrontEnd(valobj_sp)); 570 } else if (runtime->GetFoundationVersion() >= 1428) { 571 return (new Foundation1428::NSDictionaryMSyntheticFrontEnd(valobj_sp)); 572 } else { 573 return (new Foundation1100::NSDictionaryMSyntheticFrontEnd(valobj_sp)); 574 } 575 } else if (class_name == g_DictionaryMLegacy) { 576 return (new Foundation1100::NSDictionaryMSyntheticFrontEnd(valobj_sp)); 577 } else if (class_name == g_Dictionary1) { 578 return (new NSDictionary1SyntheticFrontEnd(valobj_sp)); 579 } else if (class_name == g_DictionaryCF || class_name == g_DictionaryNSCF || 580 class_name == g_DictionaryCFRef) { 581 return (new NSCFDictionarySyntheticFrontEnd(valobj_sp)); 582 } else { 583 auto &map(NSDictionary_Additionals::GetAdditionalSynthetics()); 584 for (auto &candidate : map) { 585 if (candidate.first && candidate.first->Match((class_name))) 586 return candidate.second(synth, valobj_sp); 587 } 588 } 589 590 return nullptr; 591 } 592 593 lldb_private::formatters::NSDictionaryISyntheticFrontEnd:: 594 NSDictionaryISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 595 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_pair_type() {} 596 597 lldb_private::formatters::NSDictionaryISyntheticFrontEnd:: 598 ~NSDictionaryISyntheticFrontEnd() { 599 delete m_data_32; 600 m_data_32 = nullptr; 601 delete m_data_64; 602 m_data_64 = nullptr; 603 } 604 605 size_t lldb_private::formatters::NSDictionaryISyntheticFrontEnd:: 606 GetIndexOfChildWithName(ConstString name) { 607 const char *item_name = name.GetCString(); 608 uint32_t idx = ExtractIndexFromString(item_name); 609 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 610 return UINT32_MAX; 611 return idx; 612 } 613 614 size_t lldb_private::formatters::NSDictionaryISyntheticFrontEnd:: 615 CalculateNumChildren() { 616 if (!m_data_32 && !m_data_64) 617 return 0; 618 return (m_data_32 ? m_data_32->_used : m_data_64->_used); 619 } 620 621 bool lldb_private::formatters::NSDictionaryISyntheticFrontEnd::Update() { 622 m_children.clear(); 623 delete m_data_32; 624 m_data_32 = nullptr; 625 delete m_data_64; 626 m_data_64 = nullptr; 627 m_ptr_size = 0; 628 ValueObjectSP valobj_sp = m_backend.GetSP(); 629 if (!valobj_sp) 630 return false; 631 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 632 Status error; 633 error.Clear(); 634 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 635 if (!process_sp) 636 return false; 637 m_ptr_size = process_sp->GetAddressByteSize(); 638 m_order = process_sp->GetByteOrder(); 639 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size; 640 if (m_ptr_size == 4) { 641 m_data_32 = new DataDescriptor_32(); 642 process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32), 643 error); 644 } else { 645 m_data_64 = new DataDescriptor_64(); 646 process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64), 647 error); 648 } 649 if (error.Fail()) 650 return false; 651 m_data_ptr = data_location + m_ptr_size; 652 return false; 653 } 654 655 bool lldb_private::formatters::NSDictionaryISyntheticFrontEnd:: 656 MightHaveChildren() { 657 return true; 658 } 659 660 lldb::ValueObjectSP 661 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::GetChildAtIndex( 662 size_t idx) { 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_data_ptr + (2 * test_idx * m_ptr_size); 677 val_at_idx = key_at_idx + m_ptr_size; 678 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); 679 if (!process_sp) 680 return lldb::ValueObjectSP(); 681 Status error; 682 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error); 683 if (error.Fail()) 684 return lldb::ValueObjectSP(); 685 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error); 686 if (error.Fail()) 687 return lldb::ValueObjectSP(); 688 689 test_idx++; 690 691 if (!key_at_idx || !val_at_idx) 692 continue; 693 tries++; 694 695 DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx, 696 lldb::ValueObjectSP()}; 697 698 m_children.push_back(descriptor); 699 } 700 } 701 702 if (idx >= m_children.size()) // should never happen 703 return lldb::ValueObjectSP(); 704 705 DictionaryItemDescriptor &dict_item = m_children[idx]; 706 if (!dict_item.valobj_sp) { 707 if (!m_pair_type.IsValid()) { 708 TargetSP target_sp(m_backend.GetTargetSP()); 709 if (!target_sp) 710 return ValueObjectSP(); 711 m_pair_type = GetLLDBNSPairType(target_sp); 712 } 713 if (!m_pair_type.IsValid()) 714 return ValueObjectSP(); 715 716 WritableDataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0)); 717 718 if (m_ptr_size == 8) { 719 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes(); 720 *data_ptr = dict_item.key_ptr; 721 *(data_ptr + 1) = dict_item.val_ptr; 722 } else { 723 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes(); 724 *data_ptr = dict_item.key_ptr; 725 *(data_ptr + 1) = dict_item.val_ptr; 726 } 727 728 StreamString idx_name; 729 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); 730 DataExtractor data(buffer_sp, m_order, m_ptr_size); 731 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data, 732 m_exe_ctx_ref, m_pair_type); 733 } 734 return dict_item.valobj_sp; 735 } 736 737 lldb_private::formatters::NSCFDictionarySyntheticFrontEnd:: 738 NSCFDictionarySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 739 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_hashtable(), 740 m_pair_type() {} 741 742 size_t lldb_private::formatters::NSCFDictionarySyntheticFrontEnd:: 743 GetIndexOfChildWithName(ConstString name) { 744 const char *item_name = name.GetCString(); 745 const uint32_t idx = ExtractIndexFromString(item_name); 746 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 747 return UINT32_MAX; 748 return idx; 749 } 750 751 size_t lldb_private::formatters::NSCFDictionarySyntheticFrontEnd:: 752 CalculateNumChildren() { 753 if (!m_hashtable.IsValid()) 754 return 0; 755 return m_hashtable.GetCount(); 756 } 757 758 bool lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::Update() { 759 m_children.clear(); 760 ValueObjectSP valobj_sp = m_backend.GetSP(); 761 m_ptr_size = 0; 762 if (!valobj_sp) 763 return false; 764 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 765 766 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 767 if (!process_sp) 768 return false; 769 m_ptr_size = process_sp->GetAddressByteSize(); 770 m_order = process_sp->GetByteOrder(); 771 return m_hashtable.Update(valobj_sp->GetValueAsUnsigned(0), m_exe_ctx_ref); 772 } 773 774 bool lldb_private::formatters::NSCFDictionarySyntheticFrontEnd:: 775 MightHaveChildren() { 776 return true; 777 } 778 779 lldb::ValueObjectSP 780 lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::GetChildAtIndex( 781 size_t idx) { 782 lldb::addr_t m_keys_ptr = m_hashtable.GetKeyPointer(); 783 lldb::addr_t m_values_ptr = m_hashtable.GetValuePointer(); 784 785 const uint32_t num_children = CalculateNumChildren(); 786 787 if (idx >= num_children) 788 return lldb::ValueObjectSP(); 789 790 if (m_children.empty()) { 791 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); 792 if (!process_sp) 793 return lldb::ValueObjectSP(); 794 795 Status error; 796 lldb::addr_t key_at_idx = 0, val_at_idx = 0; 797 798 uint32_t tries = 0; 799 uint32_t test_idx = 0; 800 801 // Iterate over inferior memory, reading key/value pointers by shifting each 802 // cursor by test_index * m_ptr_size. Returns an empty ValueObject if a read 803 // fails, otherwise, continue until the number of tries matches the number 804 // of childen. 805 while (tries < num_children) { 806 key_at_idx = m_keys_ptr + (test_idx * m_ptr_size); 807 val_at_idx = m_values_ptr + (test_idx * m_ptr_size); 808 809 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error); 810 if (error.Fail()) 811 return lldb::ValueObjectSP(); 812 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error); 813 if (error.Fail()) 814 return lldb::ValueObjectSP(); 815 816 test_idx++; 817 818 if (!key_at_idx || !val_at_idx) 819 continue; 820 tries++; 821 822 DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx, 823 lldb::ValueObjectSP()}; 824 825 m_children.push_back(descriptor); 826 } 827 } 828 829 if (idx >= m_children.size()) // should never happen 830 return lldb::ValueObjectSP(); 831 832 DictionaryItemDescriptor &dict_item = m_children[idx]; 833 if (!dict_item.valobj_sp) { 834 if (!m_pair_type.IsValid()) { 835 TargetSP target_sp(m_backend.GetTargetSP()); 836 if (!target_sp) 837 return ValueObjectSP(); 838 m_pair_type = GetLLDBNSPairType(target_sp); 839 } 840 if (!m_pair_type.IsValid()) 841 return ValueObjectSP(); 842 843 WritableDataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0)); 844 845 switch (m_ptr_size) { 846 case 0: // architecture has no clue - fail 847 return lldb::ValueObjectSP(); 848 case 4: { 849 uint32_t *data_ptr = reinterpret_cast<uint32_t *>(buffer_sp->GetBytes()); 850 *data_ptr = dict_item.key_ptr; 851 *(data_ptr + 1) = dict_item.val_ptr; 852 } break; 853 case 8: { 854 uint64_t *data_ptr = reinterpret_cast<uint64_t *>(buffer_sp->GetBytes()); 855 *data_ptr = dict_item.key_ptr; 856 *(data_ptr + 1) = dict_item.val_ptr; 857 } break; 858 default: 859 lldbassert(false && "pointer size is not 4 nor 8"); 860 } 861 862 StreamString idx_name; 863 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); 864 DataExtractor data(buffer_sp, m_order, m_ptr_size); 865 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data, 866 m_exe_ctx_ref, m_pair_type); 867 } 868 return dict_item.valobj_sp; 869 } 870 871 lldb_private::formatters::NSConstantDictionarySyntheticFrontEnd:: 872 NSConstantDictionarySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 873 : SyntheticChildrenFrontEnd(*valobj_sp) {} 874 875 size_t lldb_private::formatters::NSConstantDictionarySyntheticFrontEnd:: 876 GetIndexOfChildWithName(ConstString name) { 877 const char *item_name = name.GetCString(); 878 uint32_t idx = ExtractIndexFromString(item_name); 879 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 880 return UINT32_MAX; 881 return idx; 882 } 883 884 size_t lldb_private::formatters::NSConstantDictionarySyntheticFrontEnd:: 885 CalculateNumChildren() { 886 return m_size; 887 } 888 889 bool lldb_private::formatters::NSConstantDictionarySyntheticFrontEnd::Update() { 890 ValueObjectSP valobj_sp = m_backend.GetSP(); 891 if (!valobj_sp) 892 return false; 893 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 894 Status error; 895 error.Clear(); 896 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 897 if (!process_sp) 898 return false; 899 m_ptr_size = process_sp->GetAddressByteSize(); 900 m_order = process_sp->GetByteOrder(); 901 uint64_t valobj_addr = valobj_sp->GetValueAsUnsigned(0); 902 m_size = process_sp->ReadUnsignedIntegerFromMemory( 903 valobj_addr + 2 * m_ptr_size, m_ptr_size, 0, error); 904 if (error.Fail()) 905 return false; 906 m_keys_ptr = 907 process_sp->ReadPointerFromMemory(valobj_addr + 3 * m_ptr_size, error); 908 if (error.Fail()) 909 return false; 910 m_objects_ptr = 911 process_sp->ReadPointerFromMemory(valobj_addr + 4 * m_ptr_size, error); 912 return !error.Fail(); 913 } 914 915 bool lldb_private::formatters::NSConstantDictionarySyntheticFrontEnd:: 916 MightHaveChildren() { 917 return true; 918 } 919 920 lldb::ValueObjectSP lldb_private::formatters:: 921 NSConstantDictionarySyntheticFrontEnd::GetChildAtIndex(size_t idx) { 922 uint32_t num_children = CalculateNumChildren(); 923 924 if (idx >= num_children) 925 return lldb::ValueObjectSP(); 926 927 if (m_children.empty()) { 928 // do the scan phase 929 lldb::addr_t key_at_idx = 0, val_at_idx = 0; 930 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); 931 if (!process_sp) 932 return lldb::ValueObjectSP(); 933 934 for (unsigned int child = 0; child < num_children; ++child) { 935 Status error; 936 key_at_idx = process_sp->ReadPointerFromMemory( 937 m_keys_ptr + child * m_ptr_size, error); 938 if (error.Fail()) 939 return lldb::ValueObjectSP(); 940 val_at_idx = process_sp->ReadPointerFromMemory( 941 m_objects_ptr + child * m_ptr_size, error); 942 if (error.Fail()) 943 return lldb::ValueObjectSP(); 944 DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx, 945 lldb::ValueObjectSP()}; 946 m_children.push_back(descriptor); 947 } 948 } 949 950 if (idx >= m_children.size()) // should never happen 951 return lldb::ValueObjectSP(); 952 953 DictionaryItemDescriptor &dict_item = m_children[idx]; 954 if (!dict_item.valobj_sp) { 955 if (!m_pair_type.IsValid()) { 956 TargetSP target_sp(m_backend.GetTargetSP()); 957 if (!target_sp) 958 return ValueObjectSP(); 959 m_pair_type = GetLLDBNSPairType(target_sp); 960 } 961 if (!m_pair_type.IsValid()) 962 return ValueObjectSP(); 963 964 WritableDataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0)); 965 966 if (m_ptr_size == 8) { 967 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes(); 968 *data_ptr = dict_item.key_ptr; 969 *(data_ptr + 1) = dict_item.val_ptr; 970 } else { 971 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes(); 972 *data_ptr = dict_item.key_ptr; 973 *(data_ptr + 1) = dict_item.val_ptr; 974 } 975 976 StreamString idx_name; 977 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); 978 DataExtractor data(buffer_sp, m_order, m_ptr_size); 979 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data, 980 m_exe_ctx_ref, m_pair_type); 981 } 982 return dict_item.valobj_sp; 983 } 984 985 lldb_private::formatters::NSDictionary1SyntheticFrontEnd:: 986 NSDictionary1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 987 : SyntheticChildrenFrontEnd(*valobj_sp.get()), m_pair(nullptr) {} 988 989 size_t lldb_private::formatters::NSDictionary1SyntheticFrontEnd:: 990 GetIndexOfChildWithName(ConstString name) { 991 static const ConstString g_zero("[0]"); 992 return name == g_zero ? 0 : UINT32_MAX; 993 } 994 995 size_t lldb_private::formatters::NSDictionary1SyntheticFrontEnd:: 996 CalculateNumChildren() { 997 return 1; 998 } 999 1000 bool lldb_private::formatters::NSDictionary1SyntheticFrontEnd::Update() { 1001 m_pair.reset(); 1002 return false; 1003 } 1004 1005 bool lldb_private::formatters::NSDictionary1SyntheticFrontEnd:: 1006 MightHaveChildren() { 1007 return true; 1008 } 1009 1010 lldb::ValueObjectSP 1011 lldb_private::formatters::NSDictionary1SyntheticFrontEnd::GetChildAtIndex( 1012 size_t idx) { 1013 if (idx != 0) 1014 return lldb::ValueObjectSP(); 1015 1016 if (m_pair.get()) 1017 return m_pair; 1018 1019 auto process_sp(m_backend.GetProcessSP()); 1020 if (!process_sp) 1021 return nullptr; 1022 1023 auto ptr_size = process_sp->GetAddressByteSize(); 1024 1025 lldb::addr_t key_ptr = 1026 m_backend.GetValueAsUnsigned(LLDB_INVALID_ADDRESS) + ptr_size; 1027 lldb::addr_t value_ptr = key_ptr + ptr_size; 1028 1029 Status error; 1030 1031 lldb::addr_t value_at_idx = process_sp->ReadPointerFromMemory(key_ptr, error); 1032 if (error.Fail()) 1033 return nullptr; 1034 lldb::addr_t key_at_idx = process_sp->ReadPointerFromMemory(value_ptr, error); 1035 if (error.Fail()) 1036 return nullptr; 1037 1038 auto pair_type = 1039 GetLLDBNSPairType(process_sp->GetTarget().shared_from_this()); 1040 1041 WritableDataBufferSP buffer_sp(new DataBufferHeap(2 * ptr_size, 0)); 1042 1043 if (ptr_size == 8) { 1044 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes(); 1045 *data_ptr = key_at_idx; 1046 *(data_ptr + 1) = value_at_idx; 1047 } else { 1048 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes(); 1049 *data_ptr = key_at_idx; 1050 *(data_ptr + 1) = value_at_idx; 1051 } 1052 1053 DataExtractor data(buffer_sp, process_sp->GetByteOrder(), ptr_size); 1054 m_pair = CreateValueObjectFromData( 1055 "[0]", data, m_backend.GetExecutionContextRef(), pair_type); 1056 1057 return m_pair; 1058 } 1059 1060 template <typename D32, typename D64> 1061 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32, D64>:: 1062 GenericNSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 1063 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), 1064 m_data_32(nullptr), m_data_64(nullptr), m_pair_type() {} 1065 1066 template <typename D32, typename D64> 1067 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>:: 1068 ~GenericNSDictionaryMSyntheticFrontEnd<D32,D64>() { 1069 delete m_data_32; 1070 m_data_32 = nullptr; 1071 delete m_data_64; 1072 m_data_64 = nullptr; 1073 } 1074 1075 template <typename D32, typename D64> 1076 size_t lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd< 1077 D32, D64>::GetIndexOfChildWithName(ConstString name) { 1078 const char *item_name = name.GetCString(); 1079 uint32_t idx = ExtractIndexFromString(item_name); 1080 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 1081 return UINT32_MAX; 1082 return idx; 1083 } 1084 1085 template <typename D32, typename D64> 1086 size_t 1087 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>::CalculateNumChildren() { 1088 if (!m_data_32 && !m_data_64) 1089 return 0; 1090 return (m_data_32 ? m_data_32->_used : m_data_64->_used); 1091 } 1092 1093 template <typename D32, typename D64> 1094 bool 1095 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>:: 1096 Update() { 1097 m_children.clear(); 1098 ValueObjectSP valobj_sp = m_backend.GetSP(); 1099 m_ptr_size = 0; 1100 delete m_data_32; 1101 m_data_32 = nullptr; 1102 delete m_data_64; 1103 m_data_64 = nullptr; 1104 if (!valobj_sp) 1105 return false; 1106 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 1107 Status error; 1108 error.Clear(); 1109 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 1110 if (!process_sp) 1111 return false; 1112 m_ptr_size = process_sp->GetAddressByteSize(); 1113 m_order = process_sp->GetByteOrder(); 1114 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size; 1115 if (m_ptr_size == 4) { 1116 m_data_32 = new D32(); 1117 process_sp->ReadMemory(data_location, m_data_32, sizeof(D32), 1118 error); 1119 } else { 1120 m_data_64 = new D64(); 1121 process_sp->ReadMemory(data_location, m_data_64, sizeof(D64), 1122 error); 1123 } 1124 if (error.Fail()) 1125 return false; 1126 return true; 1127 } 1128 1129 template <typename D32, typename D64> 1130 bool 1131 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>:: 1132 MightHaveChildren() { 1133 return true; 1134 } 1135 1136 template <typename D32, typename D64> 1137 lldb::ValueObjectSP 1138 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd< 1139 D32, D64>::GetChildAtIndex(size_t idx) { 1140 lldb::addr_t m_keys_ptr; 1141 lldb::addr_t m_values_ptr; 1142 if (m_data_32) { 1143 uint32_t size = m_data_32->GetSize(); 1144 m_keys_ptr = m_data_32->_buffer; 1145 m_values_ptr = m_data_32->_buffer + (m_ptr_size * size); 1146 } else { 1147 uint32_t size = m_data_64->GetSize(); 1148 m_keys_ptr = m_data_64->_buffer; 1149 m_values_ptr = m_data_64->_buffer + (m_ptr_size * size); 1150 } 1151 1152 uint32_t num_children = CalculateNumChildren(); 1153 1154 if (idx >= num_children) 1155 return lldb::ValueObjectSP(); 1156 1157 if (m_children.empty()) { 1158 // do the scan phase 1159 lldb::addr_t key_at_idx = 0, val_at_idx = 0; 1160 1161 uint32_t tries = 0; 1162 uint32_t test_idx = 0; 1163 1164 while (tries < num_children) { 1165 key_at_idx = m_keys_ptr + (test_idx * m_ptr_size); 1166 val_at_idx = m_values_ptr + (test_idx * m_ptr_size); 1167 ; 1168 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); 1169 if (!process_sp) 1170 return lldb::ValueObjectSP(); 1171 Status error; 1172 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error); 1173 if (error.Fail()) 1174 return lldb::ValueObjectSP(); 1175 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error); 1176 if (error.Fail()) 1177 return lldb::ValueObjectSP(); 1178 1179 test_idx++; 1180 1181 if (!key_at_idx || !val_at_idx) 1182 continue; 1183 tries++; 1184 1185 DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx, 1186 lldb::ValueObjectSP()}; 1187 1188 m_children.push_back(descriptor); 1189 } 1190 } 1191 1192 if (idx >= m_children.size()) // should never happen 1193 return lldb::ValueObjectSP(); 1194 1195 DictionaryItemDescriptor &dict_item = m_children[idx]; 1196 if (!dict_item.valobj_sp) { 1197 if (!m_pair_type.IsValid()) { 1198 TargetSP target_sp(m_backend.GetTargetSP()); 1199 if (!target_sp) 1200 return ValueObjectSP(); 1201 m_pair_type = GetLLDBNSPairType(target_sp); 1202 } 1203 if (!m_pair_type.IsValid()) 1204 return ValueObjectSP(); 1205 1206 WritableDataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0)); 1207 1208 if (m_ptr_size == 8) { 1209 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes(); 1210 *data_ptr = dict_item.key_ptr; 1211 *(data_ptr + 1) = dict_item.val_ptr; 1212 } else { 1213 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes(); 1214 *data_ptr = dict_item.key_ptr; 1215 *(data_ptr + 1) = dict_item.val_ptr; 1216 } 1217 1218 StreamString idx_name; 1219 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); 1220 DataExtractor data(buffer_sp, m_order, m_ptr_size); 1221 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data, 1222 m_exe_ctx_ref, m_pair_type); 1223 } 1224 return dict_item.valobj_sp; 1225 } 1226 1227 lldb_private::formatters::Foundation1100::NSDictionaryMSyntheticFrontEnd:: 1228 NSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 1229 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_pair_type() {} 1230 1231 lldb_private::formatters::Foundation1100:: 1232 NSDictionaryMSyntheticFrontEnd::~NSDictionaryMSyntheticFrontEnd() { 1233 delete m_data_32; 1234 m_data_32 = nullptr; 1235 delete m_data_64; 1236 m_data_64 = nullptr; 1237 } 1238 1239 size_t 1240 lldb_private::formatters::Foundation1100:: 1241 NSDictionaryMSyntheticFrontEnd::GetIndexOfChildWithName(ConstString name) { 1242 const char *item_name = name.GetCString(); 1243 uint32_t idx = ExtractIndexFromString(item_name); 1244 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 1245 return UINT32_MAX; 1246 return idx; 1247 } 1248 1249 size_t 1250 lldb_private::formatters::Foundation1100:: 1251 NSDictionaryMSyntheticFrontEnd::CalculateNumChildren() { 1252 if (!m_data_32 && !m_data_64) 1253 return 0; 1254 return (m_data_32 ? m_data_32->_used : m_data_64->_used); 1255 } 1256 1257 bool 1258 lldb_private::formatters::Foundation1100:: 1259 NSDictionaryMSyntheticFrontEnd::Update() { 1260 m_children.clear(); 1261 ValueObjectSP valobj_sp = m_backend.GetSP(); 1262 m_ptr_size = 0; 1263 delete m_data_32; 1264 m_data_32 = nullptr; 1265 delete m_data_64; 1266 m_data_64 = nullptr; 1267 if (!valobj_sp) 1268 return false; 1269 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 1270 Status error; 1271 error.Clear(); 1272 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 1273 if (!process_sp) 1274 return false; 1275 m_ptr_size = process_sp->GetAddressByteSize(); 1276 m_order = process_sp->GetByteOrder(); 1277 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size; 1278 if (m_ptr_size == 4) { 1279 m_data_32 = new DataDescriptor_32(); 1280 process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32), 1281 error); 1282 } else { 1283 m_data_64 = new DataDescriptor_64(); 1284 process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64), 1285 error); 1286 } 1287 if (error.Fail()) 1288 return false; 1289 return false; 1290 } 1291 1292 bool 1293 lldb_private::formatters::Foundation1100:: 1294 NSDictionaryMSyntheticFrontEnd::MightHaveChildren() { 1295 return true; 1296 } 1297 1298 lldb::ValueObjectSP 1299 lldb_private::formatters::Foundation1100:: 1300 NSDictionaryMSyntheticFrontEnd::GetChildAtIndex(size_t idx) { 1301 lldb::addr_t m_keys_ptr = 1302 (m_data_32 ? m_data_32->_keys_addr : m_data_64->_keys_addr); 1303 lldb::addr_t m_values_ptr = 1304 (m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr); 1305 1306 uint32_t num_children = CalculateNumChildren(); 1307 1308 if (idx >= num_children) 1309 return lldb::ValueObjectSP(); 1310 1311 if (m_children.empty()) { 1312 // do the scan phase 1313 lldb::addr_t key_at_idx = 0, val_at_idx = 0; 1314 1315 uint32_t tries = 0; 1316 uint32_t test_idx = 0; 1317 1318 while (tries < num_children) { 1319 key_at_idx = m_keys_ptr + (test_idx * m_ptr_size); 1320 val_at_idx = m_values_ptr + (test_idx * m_ptr_size); 1321 ; 1322 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); 1323 if (!process_sp) 1324 return lldb::ValueObjectSP(); 1325 Status error; 1326 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error); 1327 if (error.Fail()) 1328 return lldb::ValueObjectSP(); 1329 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error); 1330 if (error.Fail()) 1331 return lldb::ValueObjectSP(); 1332 1333 test_idx++; 1334 1335 if (!key_at_idx || !val_at_idx) 1336 continue; 1337 tries++; 1338 1339 DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx, 1340 lldb::ValueObjectSP()}; 1341 1342 m_children.push_back(descriptor); 1343 } 1344 } 1345 1346 if (idx >= m_children.size()) // should never happen 1347 return lldb::ValueObjectSP(); 1348 1349 DictionaryItemDescriptor &dict_item = m_children[idx]; 1350 if (!dict_item.valobj_sp) { 1351 if (!m_pair_type.IsValid()) { 1352 TargetSP target_sp(m_backend.GetTargetSP()); 1353 if (!target_sp) 1354 return ValueObjectSP(); 1355 m_pair_type = GetLLDBNSPairType(target_sp); 1356 } 1357 if (!m_pair_type.IsValid()) 1358 return ValueObjectSP(); 1359 1360 WritableDataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0)); 1361 1362 if (m_ptr_size == 8) { 1363 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes(); 1364 *data_ptr = dict_item.key_ptr; 1365 *(data_ptr + 1) = dict_item.val_ptr; 1366 } else { 1367 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes(); 1368 *data_ptr = dict_item.key_ptr; 1369 *(data_ptr + 1) = dict_item.val_ptr; 1370 } 1371 1372 StreamString idx_name; 1373 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); 1374 DataExtractor data(buffer_sp, m_order, m_ptr_size); 1375 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data, 1376 m_exe_ctx_ref, m_pair_type); 1377 } 1378 return dict_item.valobj_sp; 1379 } 1380 1381 template bool lldb_private::formatters::NSDictionarySummaryProvider<true>( 1382 ValueObject &, Stream &, const TypeSummaryOptions &); 1383 1384 template bool lldb_private::formatters::NSDictionarySummaryProvider<false>( 1385 ValueObject &, Stream &, const TypeSummaryOptions &); 1386