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