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