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("__NSCFDictionary"); 412 static const ConstString g_DictionaryCFRef("CFDictionaryRef"); 413 414 if (class_name.IsEmpty()) 415 return false; 416 417 if (class_name == g_DictionaryI || class_name == g_DictionaryMImmutable) { 418 Status error; 419 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 420 ptr_size, 0, error); 421 if (error.Fail()) 422 return false; 423 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U); 424 } else if (class_name == g_DictionaryM || class_name == g_DictionaryMLegacy) { 425 AppleObjCRuntime *apple_runtime = 426 llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime); 427 Status error; 428 if (apple_runtime && apple_runtime->GetFoundationVersion() >= 1437) { 429 value = Foundation1437::__NSDictionaryMSize(*process_sp, valobj_addr, 430 error); 431 } else { 432 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 433 ptr_size, 0, error); 434 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U); 435 } 436 if (error.Fail()) 437 return false; 438 } else if (class_name == g_Dictionary1) { 439 value = 1; 440 } else if (class_name == g_Dictionary0) { 441 value = 0; 442 } else if (class_name == g_DictionaryCF || class_name == g_DictionaryCFRef) { 443 ExecutionContext exe_ctx(process_sp); 444 CFBasicHash cfbh; 445 if (!cfbh.Update(valobj_addr, exe_ctx)) 446 return false; 447 value = cfbh.GetCount(); 448 } else { 449 auto &map(NSDictionary_Additionals::GetAdditionalSummaries()); 450 for (auto &candidate : map) { 451 if (candidate.first && candidate.first->Match(class_name)) 452 return candidate.second(valobj, stream, options); 453 } 454 return false; 455 } 456 457 std::string prefix, suffix; 458 if (Language *language = Language::FindPlugin(options.GetLanguage())) { 459 if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix, 460 suffix)) { 461 prefix.clear(); 462 suffix.clear(); 463 } 464 } 465 466 stream.Printf("%s%" PRIu64 " %s%s%s", prefix.c_str(), value, "key/value pair", 467 value == 1 ? "" : "s", suffix.c_str()); 468 return true; 469 } 470 471 SyntheticChildrenFrontEnd * 472 lldb_private::formatters::NSDictionarySyntheticFrontEndCreator( 473 CXXSyntheticChildren *synth, lldb::ValueObjectSP valobj_sp) { 474 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 475 if (!process_sp) 476 return nullptr; 477 AppleObjCRuntime *runtime = llvm::dyn_cast_or_null<AppleObjCRuntime>( 478 ObjCLanguageRuntime::Get(*process_sp)); 479 if (!runtime) 480 return nullptr; 481 482 CompilerType valobj_type(valobj_sp->GetCompilerType()); 483 Flags flags(valobj_type.GetTypeInfo()); 484 485 if (flags.IsClear(eTypeIsPointer)) { 486 Status error; 487 valobj_sp = valobj_sp->AddressOf(error); 488 if (error.Fail() || !valobj_sp) 489 return nullptr; 490 } 491 492 ObjCLanguageRuntime::ClassDescriptorSP descriptor( 493 runtime->GetClassDescriptor(*valobj_sp)); 494 495 if (!descriptor || !descriptor->IsValid()) 496 return nullptr; 497 498 ConstString class_name(descriptor->GetClassName()); 499 500 static const ConstString g_DictionaryI("__NSDictionaryI"); 501 static const ConstString g_DictionaryM("__NSDictionaryM"); 502 static const ConstString g_Dictionary1("__NSSingleEntryDictionaryI"); 503 static const ConstString g_DictionaryImmutable("__NSDictionaryM_Immutable"); 504 static const ConstString g_DictionaryMLegacy("__NSDictionaryM_Legacy"); 505 static const ConstString g_Dictionary0("__NSDictionary0"); 506 static const ConstString g_DictionaryCF("__NSCFDictionary"); 507 static const ConstString g_DictionaryCFRef("CFDictionaryRef"); 508 509 if (class_name.IsEmpty()) 510 return nullptr; 511 512 if (class_name == g_DictionaryI) { 513 return (new NSDictionaryISyntheticFrontEnd(valobj_sp)); 514 } else if (class_name == g_DictionaryM) { 515 if (runtime->GetFoundationVersion() >= 1437) { 516 return (new Foundation1437::NSDictionaryMSyntheticFrontEnd(valobj_sp)); 517 } else if (runtime->GetFoundationVersion() >= 1428) { 518 return (new Foundation1428::NSDictionaryMSyntheticFrontEnd(valobj_sp)); 519 } else { 520 return (new Foundation1100::NSDictionaryMSyntheticFrontEnd(valobj_sp)); 521 } 522 } else if (class_name == g_DictionaryMLegacy) { 523 return (new Foundation1100::NSDictionaryMSyntheticFrontEnd(valobj_sp)); 524 } else if (class_name == g_Dictionary1) { 525 return (new NSDictionary1SyntheticFrontEnd(valobj_sp)); 526 } else if (class_name == g_DictionaryCF || class_name == g_DictionaryCFRef) { 527 return (new NSCFDictionarySyntheticFrontEnd(valobj_sp)); 528 } else { 529 auto &map(NSDictionary_Additionals::GetAdditionalSynthetics()); 530 for (auto &candidate : map) { 531 if (candidate.first && candidate.first->Match((class_name))) 532 return candidate.second(synth, valobj_sp); 533 } 534 } 535 536 return nullptr; 537 } 538 539 lldb_private::formatters::NSDictionaryISyntheticFrontEnd:: 540 NSDictionaryISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 541 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8), 542 m_order(lldb::eByteOrderInvalid), m_data_32(nullptr), m_data_64(nullptr), 543 m_pair_type() {} 544 545 lldb_private::formatters::NSDictionaryISyntheticFrontEnd:: 546 ~NSDictionaryISyntheticFrontEnd() { 547 delete m_data_32; 548 m_data_32 = nullptr; 549 delete m_data_64; 550 m_data_64 = nullptr; 551 } 552 553 size_t lldb_private::formatters::NSDictionaryISyntheticFrontEnd:: 554 GetIndexOfChildWithName(ConstString name) { 555 const char *item_name = name.GetCString(); 556 uint32_t idx = ExtractIndexFromString(item_name); 557 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 558 return UINT32_MAX; 559 return idx; 560 } 561 562 size_t lldb_private::formatters::NSDictionaryISyntheticFrontEnd:: 563 CalculateNumChildren() { 564 if (!m_data_32 && !m_data_64) 565 return 0; 566 return (m_data_32 ? m_data_32->_used : m_data_64->_used); 567 } 568 569 bool lldb_private::formatters::NSDictionaryISyntheticFrontEnd::Update() { 570 m_children.clear(); 571 delete m_data_32; 572 m_data_32 = nullptr; 573 delete m_data_64; 574 m_data_64 = nullptr; 575 m_ptr_size = 0; 576 ValueObjectSP valobj_sp = m_backend.GetSP(); 577 if (!valobj_sp) 578 return false; 579 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 580 Status error; 581 error.Clear(); 582 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 583 if (!process_sp) 584 return false; 585 m_ptr_size = process_sp->GetAddressByteSize(); 586 m_order = process_sp->GetByteOrder(); 587 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size; 588 if (m_ptr_size == 4) { 589 m_data_32 = new DataDescriptor_32(); 590 process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32), 591 error); 592 } else { 593 m_data_64 = new DataDescriptor_64(); 594 process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64), 595 error); 596 } 597 if (error.Fail()) 598 return false; 599 m_data_ptr = data_location + m_ptr_size; 600 return false; 601 } 602 603 bool lldb_private::formatters::NSDictionaryISyntheticFrontEnd:: 604 MightHaveChildren() { 605 return true; 606 } 607 608 lldb::ValueObjectSP 609 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::GetChildAtIndex( 610 size_t idx) { 611 uint32_t num_children = CalculateNumChildren(); 612 613 if (idx >= num_children) 614 return lldb::ValueObjectSP(); 615 616 if (m_children.empty()) { 617 // do the scan phase 618 lldb::addr_t key_at_idx = 0, val_at_idx = 0; 619 620 uint32_t tries = 0; 621 uint32_t test_idx = 0; 622 623 while (tries < num_children) { 624 key_at_idx = m_data_ptr + (2 * test_idx * m_ptr_size); 625 val_at_idx = key_at_idx + m_ptr_size; 626 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); 627 if (!process_sp) 628 return lldb::ValueObjectSP(); 629 Status error; 630 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error); 631 if (error.Fail()) 632 return lldb::ValueObjectSP(); 633 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error); 634 if (error.Fail()) 635 return lldb::ValueObjectSP(); 636 637 test_idx++; 638 639 if (!key_at_idx || !val_at_idx) 640 continue; 641 tries++; 642 643 DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx, 644 lldb::ValueObjectSP()}; 645 646 m_children.push_back(descriptor); 647 } 648 } 649 650 if (idx >= m_children.size()) // should never happen 651 return lldb::ValueObjectSP(); 652 653 DictionaryItemDescriptor &dict_item = m_children[idx]; 654 if (!dict_item.valobj_sp) { 655 if (!m_pair_type.IsValid()) { 656 TargetSP target_sp(m_backend.GetTargetSP()); 657 if (!target_sp) 658 return ValueObjectSP(); 659 m_pair_type = GetLLDBNSPairType(target_sp); 660 } 661 if (!m_pair_type.IsValid()) 662 return ValueObjectSP(); 663 664 DataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0)); 665 666 if (m_ptr_size == 8) { 667 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes(); 668 *data_ptr = dict_item.key_ptr; 669 *(data_ptr + 1) = dict_item.val_ptr; 670 } else { 671 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes(); 672 *data_ptr = dict_item.key_ptr; 673 *(data_ptr + 1) = dict_item.val_ptr; 674 } 675 676 StreamString idx_name; 677 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); 678 DataExtractor data(buffer_sp, m_order, m_ptr_size); 679 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data, 680 m_exe_ctx_ref, m_pair_type); 681 } 682 return dict_item.valobj_sp; 683 } 684 685 lldb_private::formatters::NSCFDictionarySyntheticFrontEnd:: 686 NSCFDictionarySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 687 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8), 688 m_order(lldb::eByteOrderInvalid), m_hashtable(), m_pair_type() {} 689 690 size_t lldb_private::formatters::NSCFDictionarySyntheticFrontEnd:: 691 GetIndexOfChildWithName(ConstString name) { 692 const char *item_name = name.GetCString(); 693 const uint32_t idx = ExtractIndexFromString(item_name); 694 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 695 return UINT32_MAX; 696 return idx; 697 } 698 699 size_t lldb_private::formatters::NSCFDictionarySyntheticFrontEnd:: 700 CalculateNumChildren() { 701 if (!m_hashtable.IsValid()) 702 return 0; 703 return m_hashtable.GetCount(); 704 } 705 706 bool lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::Update() { 707 m_children.clear(); 708 ValueObjectSP valobj_sp = m_backend.GetSP(); 709 m_ptr_size = 0; 710 if (!valobj_sp) 711 return false; 712 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 713 714 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 715 if (!process_sp) 716 return false; 717 m_ptr_size = process_sp->GetAddressByteSize(); 718 m_order = process_sp->GetByteOrder(); 719 return m_hashtable.Update(valobj_sp->GetValueAsUnsigned(0), m_exe_ctx_ref); 720 } 721 722 bool lldb_private::formatters::NSCFDictionarySyntheticFrontEnd:: 723 MightHaveChildren() { 724 return true; 725 } 726 727 lldb::ValueObjectSP 728 lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::GetChildAtIndex( 729 size_t idx) { 730 lldb::addr_t m_keys_ptr = m_hashtable.GetKeyPointer(); 731 lldb::addr_t m_values_ptr = m_hashtable.GetValuePointer(); 732 733 const uint32_t num_children = CalculateNumChildren(); 734 735 if (idx >= num_children) 736 return lldb::ValueObjectSP(); 737 738 if (m_children.empty()) { 739 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); 740 if (!process_sp) 741 return lldb::ValueObjectSP(); 742 743 Status error; 744 lldb::addr_t key_at_idx = 0, val_at_idx = 0; 745 746 uint32_t tries = 0; 747 uint32_t test_idx = 0; 748 749 // Iterate over inferior memory, reading key/value pointers by shifting each 750 // cursor by test_index * m_ptr_size. Returns an empty ValueObject if a read 751 // fails, otherwise, continue until the number of tries matches the number 752 // of childen. 753 while (tries < num_children) { 754 key_at_idx = m_keys_ptr + (test_idx * m_ptr_size); 755 val_at_idx = m_values_ptr + (test_idx * m_ptr_size); 756 757 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error); 758 if (error.Fail()) 759 return lldb::ValueObjectSP(); 760 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error); 761 if (error.Fail()) 762 return lldb::ValueObjectSP(); 763 764 test_idx++; 765 766 if (!key_at_idx || !val_at_idx) 767 continue; 768 tries++; 769 770 DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx, 771 lldb::ValueObjectSP()}; 772 773 m_children.push_back(descriptor); 774 } 775 } 776 777 if (idx >= m_children.size()) // should never happen 778 return lldb::ValueObjectSP(); 779 780 DictionaryItemDescriptor &dict_item = m_children[idx]; 781 if (!dict_item.valobj_sp) { 782 if (!m_pair_type.IsValid()) { 783 TargetSP target_sp(m_backend.GetTargetSP()); 784 if (!target_sp) 785 return ValueObjectSP(); 786 m_pair_type = GetLLDBNSPairType(target_sp); 787 } 788 if (!m_pair_type.IsValid()) 789 return ValueObjectSP(); 790 791 DataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0)); 792 793 switch (m_ptr_size) { 794 case 0: // architecture has no clue - fail 795 return lldb::ValueObjectSP(); 796 case 4: { 797 uint32_t *data_ptr = reinterpret_cast<uint32_t *>(buffer_sp->GetBytes()); 798 *data_ptr = dict_item.key_ptr; 799 *(data_ptr + 1) = dict_item.val_ptr; 800 } break; 801 case 8: { 802 uint64_t *data_ptr = reinterpret_cast<uint64_t *>(buffer_sp->GetBytes()); 803 *data_ptr = dict_item.key_ptr; 804 *(data_ptr + 1) = dict_item.val_ptr; 805 } break; 806 default: 807 lldbassert(false && "pointer size is not 4 nor 8"); 808 } 809 810 StreamString idx_name; 811 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); 812 DataExtractor data(buffer_sp, m_order, m_ptr_size); 813 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data, 814 m_exe_ctx_ref, m_pair_type); 815 } 816 return dict_item.valobj_sp; 817 } 818 819 lldb_private::formatters::NSDictionary1SyntheticFrontEnd:: 820 NSDictionary1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 821 : SyntheticChildrenFrontEnd(*valobj_sp.get()), m_pair(nullptr) {} 822 823 size_t lldb_private::formatters::NSDictionary1SyntheticFrontEnd:: 824 GetIndexOfChildWithName(ConstString name) { 825 static const ConstString g_zero("[0]"); 826 return name == g_zero ? 0 : UINT32_MAX; 827 } 828 829 size_t lldb_private::formatters::NSDictionary1SyntheticFrontEnd:: 830 CalculateNumChildren() { 831 return 1; 832 } 833 834 bool lldb_private::formatters::NSDictionary1SyntheticFrontEnd::Update() { 835 m_pair.reset(); 836 return false; 837 } 838 839 bool lldb_private::formatters::NSDictionary1SyntheticFrontEnd:: 840 MightHaveChildren() { 841 return true; 842 } 843 844 lldb::ValueObjectSP 845 lldb_private::formatters::NSDictionary1SyntheticFrontEnd::GetChildAtIndex( 846 size_t idx) { 847 if (idx != 0) 848 return lldb::ValueObjectSP(); 849 850 if (m_pair.get()) 851 return m_pair; 852 853 auto process_sp(m_backend.GetProcessSP()); 854 if (!process_sp) 855 return nullptr; 856 857 auto ptr_size = process_sp->GetAddressByteSize(); 858 859 lldb::addr_t key_ptr = 860 m_backend.GetValueAsUnsigned(LLDB_INVALID_ADDRESS) + ptr_size; 861 lldb::addr_t value_ptr = key_ptr + ptr_size; 862 863 Status error; 864 865 lldb::addr_t value_at_idx = process_sp->ReadPointerFromMemory(key_ptr, error); 866 if (error.Fail()) 867 return nullptr; 868 lldb::addr_t key_at_idx = process_sp->ReadPointerFromMemory(value_ptr, error); 869 if (error.Fail()) 870 return nullptr; 871 872 auto pair_type = 873 GetLLDBNSPairType(process_sp->GetTarget().shared_from_this()); 874 875 DataBufferSP buffer_sp(new DataBufferHeap(2 * ptr_size, 0)); 876 877 if (ptr_size == 8) { 878 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes(); 879 *data_ptr = key_at_idx; 880 *(data_ptr + 1) = value_at_idx; 881 } else { 882 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes(); 883 *data_ptr = key_at_idx; 884 *(data_ptr + 1) = value_at_idx; 885 } 886 887 DataExtractor data(buffer_sp, process_sp->GetByteOrder(), ptr_size); 888 m_pair = CreateValueObjectFromData( 889 "[0]", data, m_backend.GetExecutionContextRef(), pair_type); 890 891 return m_pair; 892 } 893 894 template <typename D32, typename D64> 895 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>:: 896 GenericNSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 897 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8), 898 m_order(lldb::eByteOrderInvalid), m_data_32(nullptr), m_data_64(nullptr), 899 m_pair_type() {} 900 901 template <typename D32, typename D64> 902 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>:: 903 ~GenericNSDictionaryMSyntheticFrontEnd<D32,D64>() { 904 delete m_data_32; 905 m_data_32 = nullptr; 906 delete m_data_64; 907 m_data_64 = nullptr; 908 } 909 910 template <typename D32, typename D64> 911 size_t lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd< 912 D32, D64>::GetIndexOfChildWithName(ConstString name) { 913 const char *item_name = name.GetCString(); 914 uint32_t idx = ExtractIndexFromString(item_name); 915 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 916 return UINT32_MAX; 917 return idx; 918 } 919 920 template <typename D32, typename D64> 921 size_t 922 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>::CalculateNumChildren() { 923 if (!m_data_32 && !m_data_64) 924 return 0; 925 return (m_data_32 ? m_data_32->_used : m_data_64->_used); 926 } 927 928 template <typename D32, typename D64> 929 bool 930 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>:: 931 Update() { 932 m_children.clear(); 933 ValueObjectSP valobj_sp = m_backend.GetSP(); 934 m_ptr_size = 0; 935 delete m_data_32; 936 m_data_32 = nullptr; 937 delete m_data_64; 938 m_data_64 = nullptr; 939 if (!valobj_sp) 940 return false; 941 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 942 Status error; 943 error.Clear(); 944 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 945 if (!process_sp) 946 return false; 947 m_ptr_size = process_sp->GetAddressByteSize(); 948 m_order = process_sp->GetByteOrder(); 949 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size; 950 if (m_ptr_size == 4) { 951 m_data_32 = new D32(); 952 process_sp->ReadMemory(data_location, m_data_32, sizeof(D32), 953 error); 954 } else { 955 m_data_64 = new D64(); 956 process_sp->ReadMemory(data_location, m_data_64, sizeof(D64), 957 error); 958 } 959 if (error.Fail()) 960 return false; 961 return true; 962 } 963 964 template <typename D32, typename D64> 965 bool 966 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>:: 967 MightHaveChildren() { 968 return true; 969 } 970 971 template <typename D32, typename D64> 972 lldb::ValueObjectSP 973 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd< 974 D32, D64>::GetChildAtIndex(size_t idx) { 975 lldb::addr_t m_keys_ptr; 976 lldb::addr_t m_values_ptr; 977 if (m_data_32) { 978 uint32_t size = m_data_32->GetSize(); 979 m_keys_ptr = m_data_32->_buffer; 980 m_values_ptr = m_data_32->_buffer + (m_ptr_size * size); 981 } else { 982 uint32_t size = m_data_64->GetSize(); 983 m_keys_ptr = m_data_64->_buffer; 984 m_values_ptr = m_data_64->_buffer + (m_ptr_size * size); 985 } 986 987 uint32_t num_children = CalculateNumChildren(); 988 989 if (idx >= num_children) 990 return lldb::ValueObjectSP(); 991 992 if (m_children.empty()) { 993 // do the scan phase 994 lldb::addr_t key_at_idx = 0, val_at_idx = 0; 995 996 uint32_t tries = 0; 997 uint32_t test_idx = 0; 998 999 while (tries < num_children) { 1000 key_at_idx = m_keys_ptr + (test_idx * m_ptr_size); 1001 val_at_idx = m_values_ptr + (test_idx * m_ptr_size); 1002 ; 1003 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); 1004 if (!process_sp) 1005 return lldb::ValueObjectSP(); 1006 Status error; 1007 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error); 1008 if (error.Fail()) 1009 return lldb::ValueObjectSP(); 1010 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error); 1011 if (error.Fail()) 1012 return lldb::ValueObjectSP(); 1013 1014 test_idx++; 1015 1016 if (!key_at_idx || !val_at_idx) 1017 continue; 1018 tries++; 1019 1020 DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx, 1021 lldb::ValueObjectSP()}; 1022 1023 m_children.push_back(descriptor); 1024 } 1025 } 1026 1027 if (idx >= m_children.size()) // should never happen 1028 return lldb::ValueObjectSP(); 1029 1030 DictionaryItemDescriptor &dict_item = m_children[idx]; 1031 if (!dict_item.valobj_sp) { 1032 if (!m_pair_type.IsValid()) { 1033 TargetSP target_sp(m_backend.GetTargetSP()); 1034 if (!target_sp) 1035 return ValueObjectSP(); 1036 m_pair_type = GetLLDBNSPairType(target_sp); 1037 } 1038 if (!m_pair_type.IsValid()) 1039 return ValueObjectSP(); 1040 1041 DataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0)); 1042 1043 if (m_ptr_size == 8) { 1044 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes(); 1045 *data_ptr = dict_item.key_ptr; 1046 *(data_ptr + 1) = dict_item.val_ptr; 1047 } else { 1048 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes(); 1049 *data_ptr = dict_item.key_ptr; 1050 *(data_ptr + 1) = dict_item.val_ptr; 1051 } 1052 1053 StreamString idx_name; 1054 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); 1055 DataExtractor data(buffer_sp, m_order, m_ptr_size); 1056 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data, 1057 m_exe_ctx_ref, m_pair_type); 1058 } 1059 return dict_item.valobj_sp; 1060 } 1061 1062 lldb_private::formatters::Foundation1100:: 1063 NSDictionaryMSyntheticFrontEnd:: 1064 NSDictionaryMSyntheticFrontEnd(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 lldb_private::formatters::Foundation1100:: 1070 NSDictionaryMSyntheticFrontEnd::~NSDictionaryMSyntheticFrontEnd() { 1071 delete m_data_32; 1072 m_data_32 = nullptr; 1073 delete m_data_64; 1074 m_data_64 = nullptr; 1075 } 1076 1077 size_t 1078 lldb_private::formatters::Foundation1100:: 1079 NSDictionaryMSyntheticFrontEnd::GetIndexOfChildWithName(ConstString name) { 1080 const char *item_name = name.GetCString(); 1081 uint32_t idx = ExtractIndexFromString(item_name); 1082 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 1083 return UINT32_MAX; 1084 return idx; 1085 } 1086 1087 size_t 1088 lldb_private::formatters::Foundation1100:: 1089 NSDictionaryMSyntheticFrontEnd::CalculateNumChildren() { 1090 if (!m_data_32 && !m_data_64) 1091 return 0; 1092 return (m_data_32 ? m_data_32->_used : m_data_64->_used); 1093 } 1094 1095 bool 1096 lldb_private::formatters::Foundation1100:: 1097 NSDictionaryMSyntheticFrontEnd::Update() { 1098 m_children.clear(); 1099 ValueObjectSP valobj_sp = m_backend.GetSP(); 1100 m_ptr_size = 0; 1101 delete m_data_32; 1102 m_data_32 = nullptr; 1103 delete m_data_64; 1104 m_data_64 = nullptr; 1105 if (!valobj_sp) 1106 return false; 1107 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 1108 Status error; 1109 error.Clear(); 1110 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 1111 if (!process_sp) 1112 return false; 1113 m_ptr_size = process_sp->GetAddressByteSize(); 1114 m_order = process_sp->GetByteOrder(); 1115 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size; 1116 if (m_ptr_size == 4) { 1117 m_data_32 = new DataDescriptor_32(); 1118 process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32), 1119 error); 1120 } else { 1121 m_data_64 = new DataDescriptor_64(); 1122 process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64), 1123 error); 1124 } 1125 if (error.Fail()) 1126 return false; 1127 return false; 1128 } 1129 1130 bool 1131 lldb_private::formatters::Foundation1100:: 1132 NSDictionaryMSyntheticFrontEnd::MightHaveChildren() { 1133 return true; 1134 } 1135 1136 lldb::ValueObjectSP 1137 lldb_private::formatters::Foundation1100:: 1138 NSDictionaryMSyntheticFrontEnd::GetChildAtIndex(size_t idx) { 1139 lldb::addr_t m_keys_ptr = 1140 (m_data_32 ? m_data_32->_keys_addr : m_data_64->_keys_addr); 1141 lldb::addr_t m_values_ptr = 1142 (m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr); 1143 1144 uint32_t num_children = CalculateNumChildren(); 1145 1146 if (idx >= num_children) 1147 return lldb::ValueObjectSP(); 1148 1149 if (m_children.empty()) { 1150 // do the scan phase 1151 lldb::addr_t key_at_idx = 0, val_at_idx = 0; 1152 1153 uint32_t tries = 0; 1154 uint32_t test_idx = 0; 1155 1156 while (tries < num_children) { 1157 key_at_idx = m_keys_ptr + (test_idx * m_ptr_size); 1158 val_at_idx = m_values_ptr + (test_idx * m_ptr_size); 1159 ; 1160 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); 1161 if (!process_sp) 1162 return lldb::ValueObjectSP(); 1163 Status error; 1164 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error); 1165 if (error.Fail()) 1166 return lldb::ValueObjectSP(); 1167 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error); 1168 if (error.Fail()) 1169 return lldb::ValueObjectSP(); 1170 1171 test_idx++; 1172 1173 if (!key_at_idx || !val_at_idx) 1174 continue; 1175 tries++; 1176 1177 DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx, 1178 lldb::ValueObjectSP()}; 1179 1180 m_children.push_back(descriptor); 1181 } 1182 } 1183 1184 if (idx >= m_children.size()) // should never happen 1185 return lldb::ValueObjectSP(); 1186 1187 DictionaryItemDescriptor &dict_item = m_children[idx]; 1188 if (!dict_item.valobj_sp) { 1189 if (!m_pair_type.IsValid()) { 1190 TargetSP target_sp(m_backend.GetTargetSP()); 1191 if (!target_sp) 1192 return ValueObjectSP(); 1193 m_pair_type = GetLLDBNSPairType(target_sp); 1194 } 1195 if (!m_pair_type.IsValid()) 1196 return ValueObjectSP(); 1197 1198 DataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0)); 1199 1200 if (m_ptr_size == 8) { 1201 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes(); 1202 *data_ptr = dict_item.key_ptr; 1203 *(data_ptr + 1) = dict_item.val_ptr; 1204 } else { 1205 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes(); 1206 *data_ptr = dict_item.key_ptr; 1207 *(data_ptr + 1) = dict_item.val_ptr; 1208 } 1209 1210 StreamString idx_name; 1211 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); 1212 DataExtractor data(buffer_sp, m_order, m_ptr_size); 1213 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data, 1214 m_exe_ctx_ref, m_pair_type); 1215 } 1216 return dict_item.valobj_sp; 1217 } 1218 1219 template bool lldb_private::formatters::NSDictionarySummaryProvider<true>( 1220 ValueObject &, Stream &, const TypeSummaryOptions &); 1221 1222 template bool lldb_private::formatters::NSDictionarySummaryProvider<false>( 1223 ValueObject &, Stream &, const TypeSummaryOptions &); 1224