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