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