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; 137 lldb::ByteOrder m_order; 138 DataDescriptor_32 *m_data_32; 139 DataDescriptor_64 *m_data_64; 140 lldb::addr_t m_data_ptr; 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; 200 lldb::ByteOrder m_order; 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; 254 lldb::ByteOrder m_order; 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; 305 lldb::ByteOrder m_order; 306 DataDescriptor_32 *m_data_32; 307 DataDescriptor_64 *m_data_64; 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_ptr_size(8), 596 m_order(lldb::eByteOrderInvalid), m_data_32(nullptr), m_data_64(nullptr), 597 m_pair_type() {} 598 599 lldb_private::formatters::NSDictionaryISyntheticFrontEnd:: 600 ~NSDictionaryISyntheticFrontEnd() { 601 delete m_data_32; 602 m_data_32 = nullptr; 603 delete m_data_64; 604 m_data_64 = nullptr; 605 } 606 607 size_t lldb_private::formatters::NSDictionaryISyntheticFrontEnd:: 608 GetIndexOfChildWithName(ConstString name) { 609 const char *item_name = name.GetCString(); 610 uint32_t idx = ExtractIndexFromString(item_name); 611 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 612 return UINT32_MAX; 613 return idx; 614 } 615 616 size_t lldb_private::formatters::NSDictionaryISyntheticFrontEnd:: 617 CalculateNumChildren() { 618 if (!m_data_32 && !m_data_64) 619 return 0; 620 return (m_data_32 ? m_data_32->_used : m_data_64->_used); 621 } 622 623 bool lldb_private::formatters::NSDictionaryISyntheticFrontEnd::Update() { 624 m_children.clear(); 625 delete m_data_32; 626 m_data_32 = nullptr; 627 delete m_data_64; 628 m_data_64 = nullptr; 629 m_ptr_size = 0; 630 ValueObjectSP valobj_sp = m_backend.GetSP(); 631 if (!valobj_sp) 632 return false; 633 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 634 Status error; 635 error.Clear(); 636 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 637 if (!process_sp) 638 return false; 639 m_ptr_size = process_sp->GetAddressByteSize(); 640 m_order = process_sp->GetByteOrder(); 641 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size; 642 if (m_ptr_size == 4) { 643 m_data_32 = new DataDescriptor_32(); 644 process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32), 645 error); 646 } else { 647 m_data_64 = new DataDescriptor_64(); 648 process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64), 649 error); 650 } 651 if (error.Fail()) 652 return false; 653 m_data_ptr = data_location + m_ptr_size; 654 return false; 655 } 656 657 bool lldb_private::formatters::NSDictionaryISyntheticFrontEnd:: 658 MightHaveChildren() { 659 return true; 660 } 661 662 lldb::ValueObjectSP 663 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::GetChildAtIndex( 664 size_t idx) { 665 uint32_t num_children = CalculateNumChildren(); 666 667 if (idx >= num_children) 668 return lldb::ValueObjectSP(); 669 670 if (m_children.empty()) { 671 // do the scan phase 672 lldb::addr_t key_at_idx = 0, val_at_idx = 0; 673 674 uint32_t tries = 0; 675 uint32_t test_idx = 0; 676 677 while (tries < num_children) { 678 key_at_idx = m_data_ptr + (2 * test_idx * m_ptr_size); 679 val_at_idx = key_at_idx + m_ptr_size; 680 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); 681 if (!process_sp) 682 return lldb::ValueObjectSP(); 683 Status error; 684 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error); 685 if (error.Fail()) 686 return lldb::ValueObjectSP(); 687 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error); 688 if (error.Fail()) 689 return lldb::ValueObjectSP(); 690 691 test_idx++; 692 693 if (!key_at_idx || !val_at_idx) 694 continue; 695 tries++; 696 697 DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx, 698 lldb::ValueObjectSP()}; 699 700 m_children.push_back(descriptor); 701 } 702 } 703 704 if (idx >= m_children.size()) // should never happen 705 return lldb::ValueObjectSP(); 706 707 DictionaryItemDescriptor &dict_item = m_children[idx]; 708 if (!dict_item.valobj_sp) { 709 if (!m_pair_type.IsValid()) { 710 TargetSP target_sp(m_backend.GetTargetSP()); 711 if (!target_sp) 712 return ValueObjectSP(); 713 m_pair_type = GetLLDBNSPairType(target_sp); 714 } 715 if (!m_pair_type.IsValid()) 716 return ValueObjectSP(); 717 718 DataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0)); 719 720 if (m_ptr_size == 8) { 721 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes(); 722 *data_ptr = dict_item.key_ptr; 723 *(data_ptr + 1) = dict_item.val_ptr; 724 } else { 725 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes(); 726 *data_ptr = dict_item.key_ptr; 727 *(data_ptr + 1) = dict_item.val_ptr; 728 } 729 730 StreamString idx_name; 731 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); 732 DataExtractor data(buffer_sp, m_order, m_ptr_size); 733 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data, 734 m_exe_ctx_ref, m_pair_type); 735 } 736 return dict_item.valobj_sp; 737 } 738 739 lldb_private::formatters::NSCFDictionarySyntheticFrontEnd:: 740 NSCFDictionarySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 741 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8), 742 m_order(lldb::eByteOrderInvalid), m_hashtable(), m_pair_type() {} 743 744 size_t lldb_private::formatters::NSCFDictionarySyntheticFrontEnd:: 745 GetIndexOfChildWithName(ConstString name) { 746 const char *item_name = name.GetCString(); 747 const uint32_t idx = ExtractIndexFromString(item_name); 748 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 749 return UINT32_MAX; 750 return idx; 751 } 752 753 size_t lldb_private::formatters::NSCFDictionarySyntheticFrontEnd:: 754 CalculateNumChildren() { 755 if (!m_hashtable.IsValid()) 756 return 0; 757 return m_hashtable.GetCount(); 758 } 759 760 bool lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::Update() { 761 m_children.clear(); 762 ValueObjectSP valobj_sp = m_backend.GetSP(); 763 m_ptr_size = 0; 764 if (!valobj_sp) 765 return false; 766 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 767 768 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 769 if (!process_sp) 770 return false; 771 m_ptr_size = process_sp->GetAddressByteSize(); 772 m_order = process_sp->GetByteOrder(); 773 return m_hashtable.Update(valobj_sp->GetValueAsUnsigned(0), m_exe_ctx_ref); 774 } 775 776 bool lldb_private::formatters::NSCFDictionarySyntheticFrontEnd:: 777 MightHaveChildren() { 778 return true; 779 } 780 781 lldb::ValueObjectSP 782 lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::GetChildAtIndex( 783 size_t idx) { 784 lldb::addr_t m_keys_ptr = m_hashtable.GetKeyPointer(); 785 lldb::addr_t m_values_ptr = m_hashtable.GetValuePointer(); 786 787 const uint32_t num_children = CalculateNumChildren(); 788 789 if (idx >= num_children) 790 return lldb::ValueObjectSP(); 791 792 if (m_children.empty()) { 793 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); 794 if (!process_sp) 795 return lldb::ValueObjectSP(); 796 797 Status error; 798 lldb::addr_t key_at_idx = 0, val_at_idx = 0; 799 800 uint32_t tries = 0; 801 uint32_t test_idx = 0; 802 803 // Iterate over inferior memory, reading key/value pointers by shifting each 804 // cursor by test_index * m_ptr_size. Returns an empty ValueObject if a read 805 // fails, otherwise, continue until the number of tries matches the number 806 // of childen. 807 while (tries < num_children) { 808 key_at_idx = m_keys_ptr + (test_idx * m_ptr_size); 809 val_at_idx = m_values_ptr + (test_idx * m_ptr_size); 810 811 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error); 812 if (error.Fail()) 813 return lldb::ValueObjectSP(); 814 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error); 815 if (error.Fail()) 816 return lldb::ValueObjectSP(); 817 818 test_idx++; 819 820 if (!key_at_idx || !val_at_idx) 821 continue; 822 tries++; 823 824 DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx, 825 lldb::ValueObjectSP()}; 826 827 m_children.push_back(descriptor); 828 } 829 } 830 831 if (idx >= m_children.size()) // should never happen 832 return lldb::ValueObjectSP(); 833 834 DictionaryItemDescriptor &dict_item = m_children[idx]; 835 if (!dict_item.valobj_sp) { 836 if (!m_pair_type.IsValid()) { 837 TargetSP target_sp(m_backend.GetTargetSP()); 838 if (!target_sp) 839 return ValueObjectSP(); 840 m_pair_type = GetLLDBNSPairType(target_sp); 841 } 842 if (!m_pair_type.IsValid()) 843 return ValueObjectSP(); 844 845 DataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0)); 846 847 switch (m_ptr_size) { 848 case 0: // architecture has no clue - fail 849 return lldb::ValueObjectSP(); 850 case 4: { 851 uint32_t *data_ptr = reinterpret_cast<uint32_t *>(buffer_sp->GetBytes()); 852 *data_ptr = dict_item.key_ptr; 853 *(data_ptr + 1) = dict_item.val_ptr; 854 } break; 855 case 8: { 856 uint64_t *data_ptr = reinterpret_cast<uint64_t *>(buffer_sp->GetBytes()); 857 *data_ptr = dict_item.key_ptr; 858 *(data_ptr + 1) = dict_item.val_ptr; 859 } break; 860 default: 861 lldbassert(false && "pointer size is not 4 nor 8"); 862 } 863 864 StreamString idx_name; 865 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); 866 DataExtractor data(buffer_sp, m_order, m_ptr_size); 867 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data, 868 m_exe_ctx_ref, m_pair_type); 869 } 870 return dict_item.valobj_sp; 871 } 872 873 lldb_private::formatters::NSConstantDictionarySyntheticFrontEnd:: 874 NSConstantDictionarySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 875 : SyntheticChildrenFrontEnd(*valobj_sp) {} 876 877 size_t lldb_private::formatters::NSConstantDictionarySyntheticFrontEnd:: 878 GetIndexOfChildWithName(ConstString name) { 879 const char *item_name = name.GetCString(); 880 uint32_t idx = ExtractIndexFromString(item_name); 881 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 882 return UINT32_MAX; 883 return idx; 884 } 885 886 size_t lldb_private::formatters::NSConstantDictionarySyntheticFrontEnd:: 887 CalculateNumChildren() { 888 return m_size; 889 } 890 891 bool lldb_private::formatters::NSConstantDictionarySyntheticFrontEnd::Update() { 892 ValueObjectSP valobj_sp = m_backend.GetSP(); 893 if (!valobj_sp) 894 return false; 895 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 896 Status error; 897 error.Clear(); 898 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 899 if (!process_sp) 900 return false; 901 m_ptr_size = process_sp->GetAddressByteSize(); 902 m_order = process_sp->GetByteOrder(); 903 uint64_t valobj_addr = valobj_sp->GetValueAsUnsigned(0); 904 m_size = process_sp->ReadUnsignedIntegerFromMemory( 905 valobj_addr + 2 * m_ptr_size, m_ptr_size, 0, error); 906 if (error.Fail()) 907 return false; 908 m_keys_ptr = 909 process_sp->ReadPointerFromMemory(valobj_addr + 3 * m_ptr_size, error); 910 if (error.Fail()) 911 return false; 912 m_objects_ptr = 913 process_sp->ReadPointerFromMemory(valobj_addr + 4 * m_ptr_size, error); 914 return !error.Fail(); 915 } 916 917 bool lldb_private::formatters::NSConstantDictionarySyntheticFrontEnd:: 918 MightHaveChildren() { 919 return true; 920 } 921 922 lldb::ValueObjectSP lldb_private::formatters:: 923 NSConstantDictionarySyntheticFrontEnd::GetChildAtIndex(size_t idx) { 924 uint32_t num_children = CalculateNumChildren(); 925 926 if (idx >= num_children) 927 return lldb::ValueObjectSP(); 928 929 if (m_children.empty()) { 930 // do the scan phase 931 lldb::addr_t key_at_idx = 0, val_at_idx = 0; 932 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); 933 if (!process_sp) 934 return lldb::ValueObjectSP(); 935 936 for (unsigned int child = 0; child < num_children; ++child) { 937 Status error; 938 key_at_idx = process_sp->ReadPointerFromMemory( 939 m_keys_ptr + child * m_ptr_size, error); 940 if (error.Fail()) 941 return lldb::ValueObjectSP(); 942 val_at_idx = process_sp->ReadPointerFromMemory( 943 m_objects_ptr + child * m_ptr_size, error); 944 if (error.Fail()) 945 return lldb::ValueObjectSP(); 946 DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx, 947 lldb::ValueObjectSP()}; 948 m_children.push_back(descriptor); 949 } 950 } 951 952 if (idx >= m_children.size()) // should never happen 953 return lldb::ValueObjectSP(); 954 955 DictionaryItemDescriptor &dict_item = m_children[idx]; 956 if (!dict_item.valobj_sp) { 957 if (!m_pair_type.IsValid()) { 958 TargetSP target_sp(m_backend.GetTargetSP()); 959 if (!target_sp) 960 return ValueObjectSP(); 961 m_pair_type = GetLLDBNSPairType(target_sp); 962 } 963 if (!m_pair_type.IsValid()) 964 return ValueObjectSP(); 965 966 DataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0)); 967 968 if (m_ptr_size == 8) { 969 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes(); 970 *data_ptr = dict_item.key_ptr; 971 *(data_ptr + 1) = dict_item.val_ptr; 972 } else { 973 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes(); 974 *data_ptr = dict_item.key_ptr; 975 *(data_ptr + 1) = dict_item.val_ptr; 976 } 977 978 StreamString idx_name; 979 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); 980 DataExtractor data(buffer_sp, m_order, m_ptr_size); 981 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data, 982 m_exe_ctx_ref, m_pair_type); 983 } 984 return dict_item.valobj_sp; 985 } 986 987 lldb_private::formatters::NSDictionary1SyntheticFrontEnd:: 988 NSDictionary1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 989 : SyntheticChildrenFrontEnd(*valobj_sp.get()), m_pair(nullptr) {} 990 991 size_t lldb_private::formatters::NSDictionary1SyntheticFrontEnd:: 992 GetIndexOfChildWithName(ConstString name) { 993 static const ConstString g_zero("[0]"); 994 return name == g_zero ? 0 : UINT32_MAX; 995 } 996 997 size_t lldb_private::formatters::NSDictionary1SyntheticFrontEnd:: 998 CalculateNumChildren() { 999 return 1; 1000 } 1001 1002 bool lldb_private::formatters::NSDictionary1SyntheticFrontEnd::Update() { 1003 m_pair.reset(); 1004 return false; 1005 } 1006 1007 bool lldb_private::formatters::NSDictionary1SyntheticFrontEnd:: 1008 MightHaveChildren() { 1009 return true; 1010 } 1011 1012 lldb::ValueObjectSP 1013 lldb_private::formatters::NSDictionary1SyntheticFrontEnd::GetChildAtIndex( 1014 size_t idx) { 1015 if (idx != 0) 1016 return lldb::ValueObjectSP(); 1017 1018 if (m_pair.get()) 1019 return m_pair; 1020 1021 auto process_sp(m_backend.GetProcessSP()); 1022 if (!process_sp) 1023 return nullptr; 1024 1025 auto ptr_size = process_sp->GetAddressByteSize(); 1026 1027 lldb::addr_t key_ptr = 1028 m_backend.GetValueAsUnsigned(LLDB_INVALID_ADDRESS) + ptr_size; 1029 lldb::addr_t value_ptr = key_ptr + ptr_size; 1030 1031 Status error; 1032 1033 lldb::addr_t value_at_idx = process_sp->ReadPointerFromMemory(key_ptr, error); 1034 if (error.Fail()) 1035 return nullptr; 1036 lldb::addr_t key_at_idx = process_sp->ReadPointerFromMemory(value_ptr, error); 1037 if (error.Fail()) 1038 return nullptr; 1039 1040 auto pair_type = 1041 GetLLDBNSPairType(process_sp->GetTarget().shared_from_this()); 1042 1043 DataBufferSP buffer_sp(new DataBufferHeap(2 * ptr_size, 0)); 1044 1045 if (ptr_size == 8) { 1046 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes(); 1047 *data_ptr = key_at_idx; 1048 *(data_ptr + 1) = value_at_idx; 1049 } else { 1050 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes(); 1051 *data_ptr = key_at_idx; 1052 *(data_ptr + 1) = value_at_idx; 1053 } 1054 1055 DataExtractor data(buffer_sp, process_sp->GetByteOrder(), ptr_size); 1056 m_pair = CreateValueObjectFromData( 1057 "[0]", data, m_backend.GetExecutionContextRef(), pair_type); 1058 1059 return m_pair; 1060 } 1061 1062 template <typename D32, typename D64> 1063 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>:: 1064 GenericNSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 1065 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8), 1066 m_order(lldb::eByteOrderInvalid), m_data_32(nullptr), m_data_64(nullptr), 1067 m_pair_type() {} 1068 1069 template <typename D32, typename D64> 1070 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>:: 1071 ~GenericNSDictionaryMSyntheticFrontEnd<D32,D64>() { 1072 delete m_data_32; 1073 m_data_32 = nullptr; 1074 delete m_data_64; 1075 m_data_64 = nullptr; 1076 } 1077 1078 template <typename D32, typename D64> 1079 size_t lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd< 1080 D32, D64>::GetIndexOfChildWithName(ConstString name) { 1081 const char *item_name = name.GetCString(); 1082 uint32_t idx = ExtractIndexFromString(item_name); 1083 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 1084 return UINT32_MAX; 1085 return idx; 1086 } 1087 1088 template <typename D32, typename D64> 1089 size_t 1090 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>::CalculateNumChildren() { 1091 if (!m_data_32 && !m_data_64) 1092 return 0; 1093 return (m_data_32 ? m_data_32->_used : m_data_64->_used); 1094 } 1095 1096 template <typename D32, typename D64> 1097 bool 1098 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>:: 1099 Update() { 1100 m_children.clear(); 1101 ValueObjectSP valobj_sp = m_backend.GetSP(); 1102 m_ptr_size = 0; 1103 delete m_data_32; 1104 m_data_32 = nullptr; 1105 delete m_data_64; 1106 m_data_64 = nullptr; 1107 if (!valobj_sp) 1108 return false; 1109 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 1110 Status error; 1111 error.Clear(); 1112 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 1113 if (!process_sp) 1114 return false; 1115 m_ptr_size = process_sp->GetAddressByteSize(); 1116 m_order = process_sp->GetByteOrder(); 1117 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size; 1118 if (m_ptr_size == 4) { 1119 m_data_32 = new D32(); 1120 process_sp->ReadMemory(data_location, m_data_32, sizeof(D32), 1121 error); 1122 } else { 1123 m_data_64 = new D64(); 1124 process_sp->ReadMemory(data_location, m_data_64, sizeof(D64), 1125 error); 1126 } 1127 if (error.Fail()) 1128 return false; 1129 return true; 1130 } 1131 1132 template <typename D32, typename D64> 1133 bool 1134 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>:: 1135 MightHaveChildren() { 1136 return true; 1137 } 1138 1139 template <typename D32, typename D64> 1140 lldb::ValueObjectSP 1141 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd< 1142 D32, D64>::GetChildAtIndex(size_t idx) { 1143 lldb::addr_t m_keys_ptr; 1144 lldb::addr_t m_values_ptr; 1145 if (m_data_32) { 1146 uint32_t size = m_data_32->GetSize(); 1147 m_keys_ptr = m_data_32->_buffer; 1148 m_values_ptr = m_data_32->_buffer + (m_ptr_size * size); 1149 } else { 1150 uint32_t size = m_data_64->GetSize(); 1151 m_keys_ptr = m_data_64->_buffer; 1152 m_values_ptr = m_data_64->_buffer + (m_ptr_size * size); 1153 } 1154 1155 uint32_t num_children = CalculateNumChildren(); 1156 1157 if (idx >= num_children) 1158 return lldb::ValueObjectSP(); 1159 1160 if (m_children.empty()) { 1161 // do the scan phase 1162 lldb::addr_t key_at_idx = 0, val_at_idx = 0; 1163 1164 uint32_t tries = 0; 1165 uint32_t test_idx = 0; 1166 1167 while (tries < num_children) { 1168 key_at_idx = m_keys_ptr + (test_idx * m_ptr_size); 1169 val_at_idx = m_values_ptr + (test_idx * m_ptr_size); 1170 ; 1171 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); 1172 if (!process_sp) 1173 return lldb::ValueObjectSP(); 1174 Status error; 1175 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error); 1176 if (error.Fail()) 1177 return lldb::ValueObjectSP(); 1178 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error); 1179 if (error.Fail()) 1180 return lldb::ValueObjectSP(); 1181 1182 test_idx++; 1183 1184 if (!key_at_idx || !val_at_idx) 1185 continue; 1186 tries++; 1187 1188 DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx, 1189 lldb::ValueObjectSP()}; 1190 1191 m_children.push_back(descriptor); 1192 } 1193 } 1194 1195 if (idx >= m_children.size()) // should never happen 1196 return lldb::ValueObjectSP(); 1197 1198 DictionaryItemDescriptor &dict_item = m_children[idx]; 1199 if (!dict_item.valobj_sp) { 1200 if (!m_pair_type.IsValid()) { 1201 TargetSP target_sp(m_backend.GetTargetSP()); 1202 if (!target_sp) 1203 return ValueObjectSP(); 1204 m_pair_type = GetLLDBNSPairType(target_sp); 1205 } 1206 if (!m_pair_type.IsValid()) 1207 return ValueObjectSP(); 1208 1209 DataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0)); 1210 1211 if (m_ptr_size == 8) { 1212 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes(); 1213 *data_ptr = dict_item.key_ptr; 1214 *(data_ptr + 1) = dict_item.val_ptr; 1215 } else { 1216 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes(); 1217 *data_ptr = dict_item.key_ptr; 1218 *(data_ptr + 1) = dict_item.val_ptr; 1219 } 1220 1221 StreamString idx_name; 1222 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); 1223 DataExtractor data(buffer_sp, m_order, m_ptr_size); 1224 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data, 1225 m_exe_ctx_ref, m_pair_type); 1226 } 1227 return dict_item.valobj_sp; 1228 } 1229 1230 lldb_private::formatters::Foundation1100:: 1231 NSDictionaryMSyntheticFrontEnd:: 1232 NSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 1233 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8), 1234 m_order(lldb::eByteOrderInvalid), m_data_32(nullptr), m_data_64(nullptr), 1235 m_pair_type() {} 1236 1237 lldb_private::formatters::Foundation1100:: 1238 NSDictionaryMSyntheticFrontEnd::~NSDictionaryMSyntheticFrontEnd() { 1239 delete m_data_32; 1240 m_data_32 = nullptr; 1241 delete m_data_64; 1242 m_data_64 = nullptr; 1243 } 1244 1245 size_t 1246 lldb_private::formatters::Foundation1100:: 1247 NSDictionaryMSyntheticFrontEnd::GetIndexOfChildWithName(ConstString name) { 1248 const char *item_name = name.GetCString(); 1249 uint32_t idx = ExtractIndexFromString(item_name); 1250 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 1251 return UINT32_MAX; 1252 return idx; 1253 } 1254 1255 size_t 1256 lldb_private::formatters::Foundation1100:: 1257 NSDictionaryMSyntheticFrontEnd::CalculateNumChildren() { 1258 if (!m_data_32 && !m_data_64) 1259 return 0; 1260 return (m_data_32 ? m_data_32->_used : m_data_64->_used); 1261 } 1262 1263 bool 1264 lldb_private::formatters::Foundation1100:: 1265 NSDictionaryMSyntheticFrontEnd::Update() { 1266 m_children.clear(); 1267 ValueObjectSP valobj_sp = m_backend.GetSP(); 1268 m_ptr_size = 0; 1269 delete m_data_32; 1270 m_data_32 = nullptr; 1271 delete m_data_64; 1272 m_data_64 = nullptr; 1273 if (!valobj_sp) 1274 return false; 1275 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 1276 Status error; 1277 error.Clear(); 1278 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 1279 if (!process_sp) 1280 return false; 1281 m_ptr_size = process_sp->GetAddressByteSize(); 1282 m_order = process_sp->GetByteOrder(); 1283 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size; 1284 if (m_ptr_size == 4) { 1285 m_data_32 = new DataDescriptor_32(); 1286 process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32), 1287 error); 1288 } else { 1289 m_data_64 = new DataDescriptor_64(); 1290 process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64), 1291 error); 1292 } 1293 if (error.Fail()) 1294 return false; 1295 return false; 1296 } 1297 1298 bool 1299 lldb_private::formatters::Foundation1100:: 1300 NSDictionaryMSyntheticFrontEnd::MightHaveChildren() { 1301 return true; 1302 } 1303 1304 lldb::ValueObjectSP 1305 lldb_private::formatters::Foundation1100:: 1306 NSDictionaryMSyntheticFrontEnd::GetChildAtIndex(size_t idx) { 1307 lldb::addr_t m_keys_ptr = 1308 (m_data_32 ? m_data_32->_keys_addr : m_data_64->_keys_addr); 1309 lldb::addr_t m_values_ptr = 1310 (m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr); 1311 1312 uint32_t num_children = CalculateNumChildren(); 1313 1314 if (idx >= num_children) 1315 return lldb::ValueObjectSP(); 1316 1317 if (m_children.empty()) { 1318 // do the scan phase 1319 lldb::addr_t key_at_idx = 0, val_at_idx = 0; 1320 1321 uint32_t tries = 0; 1322 uint32_t test_idx = 0; 1323 1324 while (tries < num_children) { 1325 key_at_idx = m_keys_ptr + (test_idx * m_ptr_size); 1326 val_at_idx = m_values_ptr + (test_idx * m_ptr_size); 1327 ; 1328 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); 1329 if (!process_sp) 1330 return lldb::ValueObjectSP(); 1331 Status error; 1332 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error); 1333 if (error.Fail()) 1334 return lldb::ValueObjectSP(); 1335 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error); 1336 if (error.Fail()) 1337 return lldb::ValueObjectSP(); 1338 1339 test_idx++; 1340 1341 if (!key_at_idx || !val_at_idx) 1342 continue; 1343 tries++; 1344 1345 DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx, 1346 lldb::ValueObjectSP()}; 1347 1348 m_children.push_back(descriptor); 1349 } 1350 } 1351 1352 if (idx >= m_children.size()) // should never happen 1353 return lldb::ValueObjectSP(); 1354 1355 DictionaryItemDescriptor &dict_item = m_children[idx]; 1356 if (!dict_item.valobj_sp) { 1357 if (!m_pair_type.IsValid()) { 1358 TargetSP target_sp(m_backend.GetTargetSP()); 1359 if (!target_sp) 1360 return ValueObjectSP(); 1361 m_pair_type = GetLLDBNSPairType(target_sp); 1362 } 1363 if (!m_pair_type.IsValid()) 1364 return ValueObjectSP(); 1365 1366 DataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0)); 1367 1368 if (m_ptr_size == 8) { 1369 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes(); 1370 *data_ptr = dict_item.key_ptr; 1371 *(data_ptr + 1) = dict_item.val_ptr; 1372 } else { 1373 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes(); 1374 *data_ptr = dict_item.key_ptr; 1375 *(data_ptr + 1) = dict_item.val_ptr; 1376 } 1377 1378 StreamString idx_name; 1379 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); 1380 DataExtractor data(buffer_sp, m_order, m_ptr_size); 1381 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data, 1382 m_exe_ctx_ref, m_pair_type); 1383 } 1384 return dict_item.valobj_sp; 1385 } 1386 1387 template bool lldb_private::formatters::NSDictionarySummaryProvider<true>( 1388 ValueObject &, Stream &, const TypeSummaryOptions &); 1389 1390 template bool lldb_private::formatters::NSDictionarySummaryProvider<false>( 1391 ValueObject &, Stream &, const TypeSummaryOptions &); 1392