1 //===-- NSDictionary.cpp ----------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 // C Includes 11 // C++ Includes 12 #include <mutex> 13 14 // Other libraries and framework includes 15 #include "clang/AST/DeclCXX.h" 16 17 // Project includes 18 #include "NSDictionary.h" 19 20 #include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h" 21 22 #include "lldb/Core/ValueObject.h" 23 #include "lldb/Core/ValueObjectConstResult.h" 24 #include "lldb/DataFormatters/FormattersHelpers.h" 25 #include "lldb/Symbol/ClangASTContext.h" 26 #include "lldb/Target/Language.h" 27 #include "lldb/Target/ObjCLanguageRuntime.h" 28 #include "lldb/Target/StackFrame.h" 29 #include "lldb/Target/Target.h" 30 #include "lldb/Utility/DataBufferHeap.h" 31 #include "lldb/Utility/Endian.h" 32 #include "lldb/Utility/Status.h" 33 #include "lldb/Utility/Stream.h" 34 35 using namespace lldb; 36 using namespace lldb_private; 37 using namespace lldb_private::formatters; 38 39 NSDictionary_Additionals::AdditionalFormatterMatching::Prefix::Prefix( 40 ConstString p) 41 : m_prefix(p) {} 42 43 bool NSDictionary_Additionals::AdditionalFormatterMatching::Prefix::Match( 44 ConstString class_name) { 45 return class_name.GetStringRef().startswith(m_prefix.GetStringRef()); 46 } 47 48 NSDictionary_Additionals::AdditionalFormatterMatching::Full::Full(ConstString n) 49 : m_name(n) {} 50 51 bool NSDictionary_Additionals::AdditionalFormatterMatching::Full::Match( 52 ConstString class_name) { 53 return (class_name == m_name); 54 } 55 56 NSDictionary_Additionals::AdditionalFormatters< 57 CXXFunctionSummaryFormat::Callback> & 58 NSDictionary_Additionals::GetAdditionalSummaries() { 59 static AdditionalFormatters<CXXFunctionSummaryFormat::Callback> g_map; 60 return g_map; 61 } 62 63 NSDictionary_Additionals::AdditionalFormatters< 64 CXXSyntheticChildren::CreateFrontEndCallback> & 65 NSDictionary_Additionals::GetAdditionalSynthetics() { 66 static AdditionalFormatters<CXXSyntheticChildren::CreateFrontEndCallback> 67 g_map; 68 return g_map; 69 } 70 71 static CompilerType GetLLDBNSPairType(TargetSP target_sp) { 72 CompilerType compiler_type; 73 74 ClangASTContext *target_ast_context = target_sp->GetScratchClangASTContext(); 75 76 if (target_ast_context) { 77 ConstString g___lldb_autogen_nspair("__lldb_autogen_nspair"); 78 79 compiler_type = 80 target_ast_context->GetTypeForIdentifier<clang::CXXRecordDecl>( 81 g___lldb_autogen_nspair); 82 83 if (!compiler_type) { 84 compiler_type = target_ast_context->CreateRecordType( 85 nullptr, lldb::eAccessPublic, g___lldb_autogen_nspair.GetCString(), 86 clang::TTK_Struct, lldb::eLanguageTypeC); 87 88 if (compiler_type) { 89 ClangASTContext::StartTagDeclarationDefinition(compiler_type); 90 CompilerType id_compiler_type = 91 target_ast_context->GetBasicType(eBasicTypeObjCID); 92 ClangASTContext::AddFieldToRecordType( 93 compiler_type, "key", id_compiler_type, lldb::eAccessPublic, 0); 94 ClangASTContext::AddFieldToRecordType( 95 compiler_type, "value", id_compiler_type, lldb::eAccessPublic, 0); 96 ClangASTContext::CompleteTagDeclarationDefinition(compiler_type); 97 } 98 } 99 } 100 return compiler_type; 101 } 102 103 namespace lldb_private { 104 namespace formatters { 105 class NSDictionaryISyntheticFrontEnd : public SyntheticChildrenFrontEnd { 106 public: 107 NSDictionaryISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); 108 109 ~NSDictionaryISyntheticFrontEnd() override; 110 111 size_t CalculateNumChildren() override; 112 113 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; 114 115 bool Update() override; 116 117 bool MightHaveChildren() override; 118 119 size_t GetIndexOfChildWithName(const ConstString &name) override; 120 121 private: 122 struct DataDescriptor_32 { 123 uint32_t _used : 26; 124 uint32_t _szidx : 6; 125 }; 126 127 struct DataDescriptor_64 { 128 uint64_t _used : 58; 129 uint32_t _szidx : 6; 130 }; 131 132 struct DictionaryItemDescriptor { 133 lldb::addr_t key_ptr; 134 lldb::addr_t val_ptr; 135 lldb::ValueObjectSP valobj_sp; 136 }; 137 138 ExecutionContextRef m_exe_ctx_ref; 139 uint8_t m_ptr_size; 140 lldb::ByteOrder m_order; 141 DataDescriptor_32 *m_data_32; 142 DataDescriptor_64 *m_data_64; 143 lldb::addr_t m_data_ptr; 144 CompilerType m_pair_type; 145 std::vector<DictionaryItemDescriptor> m_children; 146 }; 147 148 class NSDictionary1SyntheticFrontEnd : public SyntheticChildrenFrontEnd { 149 public: 150 NSDictionary1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); 151 152 ~NSDictionary1SyntheticFrontEnd() override = default; 153 154 size_t CalculateNumChildren() override; 155 156 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; 157 158 bool Update() override; 159 160 bool MightHaveChildren() override; 161 162 size_t GetIndexOfChildWithName(const ConstString &name) override; 163 164 private: 165 ValueObjectSP m_pair; 166 }; 167 168 template <typename D32, typename D64> 169 class GenericNSDictionaryMSyntheticFrontEnd : public SyntheticChildrenFrontEnd { 170 public: 171 GenericNSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); 172 173 ~GenericNSDictionaryMSyntheticFrontEnd() override; 174 175 size_t CalculateNumChildren() override; 176 177 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; 178 179 bool Update() override; 180 181 bool MightHaveChildren() override; 182 183 size_t GetIndexOfChildWithName(const ConstString &name) override; 184 185 private: 186 struct DictionaryItemDescriptor { 187 lldb::addr_t key_ptr; 188 lldb::addr_t val_ptr; 189 lldb::ValueObjectSP valobj_sp; 190 }; 191 192 ExecutionContextRef m_exe_ctx_ref; 193 uint8_t m_ptr_size; 194 lldb::ByteOrder m_order; 195 D32 *m_data_32; 196 D64 *m_data_64; 197 CompilerType m_pair_type; 198 std::vector<DictionaryItemDescriptor> m_children; 199 }; 200 201 namespace Foundation1100 { 202 class NSDictionaryMSyntheticFrontEnd : public SyntheticChildrenFrontEnd { 203 public: 204 NSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); 205 206 ~NSDictionaryMSyntheticFrontEnd() override; 207 208 size_t CalculateNumChildren() override; 209 210 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; 211 212 bool Update() override; 213 214 bool MightHaveChildren() override; 215 216 size_t GetIndexOfChildWithName(const ConstString &name) override; 217 218 private: 219 struct DataDescriptor_32 { 220 uint32_t _used : 26; 221 uint32_t _kvo : 1; 222 uint32_t _size; 223 uint32_t _mutations; 224 uint32_t _objs_addr; 225 uint32_t _keys_addr; 226 }; 227 228 struct DataDescriptor_64 { 229 uint64_t _used : 58; 230 uint32_t _kvo : 1; 231 uint64_t _size; 232 uint64_t _mutations; 233 uint64_t _objs_addr; 234 uint64_t _keys_addr; 235 }; 236 237 struct DictionaryItemDescriptor { 238 lldb::addr_t key_ptr; 239 lldb::addr_t val_ptr; 240 lldb::ValueObjectSP valobj_sp; 241 }; 242 243 ExecutionContextRef m_exe_ctx_ref; 244 uint8_t m_ptr_size; 245 lldb::ByteOrder m_order; 246 DataDescriptor_32 *m_data_32; 247 DataDescriptor_64 *m_data_64; 248 CompilerType m_pair_type; 249 std::vector<DictionaryItemDescriptor> m_children; 250 }; 251 } 252 253 namespace Foundation1428 { 254 struct DataDescriptor_32 { 255 uint32_t _used : 26; 256 uint32_t _kvo : 1; 257 uint32_t _size; 258 uint32_t _buffer; 259 uint64_t GetSize() { return _size; } 260 }; 261 262 struct DataDescriptor_64 { 263 uint64_t _used : 58; 264 uint32_t _kvo : 1; 265 uint64_t _size; 266 uint64_t _buffer; 267 uint64_t GetSize() { return _size; } 268 }; 269 270 271 272 using NSDictionaryMSyntheticFrontEnd = 273 GenericNSDictionaryMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>; 274 } 275 276 namespace Foundation1437 { 277 static const uint64_t NSDictionaryCapacities[] = { 278 0, 3, 7, 13, 23, 41, 71, 127, 191, 251, 383, 631, 1087, 1723, 279 2803, 4523, 7351, 11959, 19447, 31231, 50683, 81919, 132607, 280 214519, 346607, 561109, 907759, 1468927, 2376191, 3845119, 281 6221311, 10066421, 16287743, 26354171, 42641881, 68996069, 282 111638519, 180634607, 292272623, 472907251 283 }; 284 285 static const size_t NSDictionaryNumSizeBuckets = sizeof(NSDictionaryCapacities) / sizeof(uint64_t); 286 287 struct DataDescriptor_32 { 288 uint32_t _buffer; 289 union { 290 struct { 291 uint32_t _mutations; 292 }; 293 struct { 294 uint32_t _muts; 295 uint32_t _used:25; 296 uint32_t _kvo:1; 297 uint32_t _szidx:6; 298 }; 299 }; 300 301 uint64_t GetSize() { 302 return (_szidx) >= NSDictionaryNumSizeBuckets ? 303 0 : NSDictionaryCapacities[_szidx]; 304 } 305 }; 306 307 struct DataDescriptor_64 { 308 uint64_t _buffer; 309 union { 310 struct { 311 uint64_t _mutations; 312 }; 313 struct { 314 uint32_t _muts; 315 uint32_t _used:25; 316 uint32_t _kvo:1; 317 uint32_t _szidx:6; 318 }; 319 }; 320 321 uint64_t GetSize() { 322 return (_szidx) >= NSDictionaryNumSizeBuckets ? 323 0 : NSDictionaryCapacities[_szidx]; 324 } 325 }; 326 327 using NSDictionaryMSyntheticFrontEnd = 328 GenericNSDictionaryMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>; 329 330 template <typename DD> 331 uint64_t 332 __NSDictionaryMSize_Impl(lldb_private::Process &process, 333 lldb::addr_t valobj_addr, Status &error) { 334 const lldb::addr_t start_of_descriptor = 335 valobj_addr + process.GetAddressByteSize(); 336 DD descriptor = DD(); 337 process.ReadMemory(start_of_descriptor, &descriptor, sizeof(descriptor), 338 error); 339 if (error.Fail()) { 340 return 0; 341 } 342 return descriptor._used; 343 } 344 345 uint64_t 346 __NSDictionaryMSize(lldb_private::Process &process, lldb::addr_t valobj_addr, 347 Status &error) { 348 if (process.GetAddressByteSize() == 4) { 349 return __NSDictionaryMSize_Impl<DataDescriptor_32>(process, valobj_addr, 350 error); 351 } else { 352 return __NSDictionaryMSize_Impl<DataDescriptor_64>(process, valobj_addr, 353 error); 354 } 355 } 356 357 } 358 } // namespace formatters 359 } // namespace lldb_private 360 361 template <bool name_entries> 362 bool lldb_private::formatters::NSDictionarySummaryProvider( 363 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { 364 static ConstString g_TypeHint("NSDictionary"); 365 ProcessSP process_sp = valobj.GetProcessSP(); 366 if (!process_sp) 367 return false; 368 369 ObjCLanguageRuntime *runtime = 370 (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime( 371 lldb::eLanguageTypeObjC); 372 373 if (!runtime) 374 return false; 375 376 ObjCLanguageRuntime::ClassDescriptorSP descriptor( 377 runtime->GetClassDescriptor(valobj)); 378 379 if (!descriptor || !descriptor->IsValid()) 380 return false; 381 382 uint32_t ptr_size = process_sp->GetAddressByteSize(); 383 bool is_64bit = (ptr_size == 8); 384 385 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 386 387 if (!valobj_addr) 388 return false; 389 390 uint64_t value = 0; 391 392 ConstString class_name(descriptor->GetClassName()); 393 394 static const ConstString g_DictionaryI("__NSDictionaryI"); 395 static const ConstString g_DictionaryM("__NSDictionaryM"); 396 static const ConstString g_DictionaryMLegacy("__NSDictionaryM_Legacy"); 397 static const ConstString g_DictionaryMImmutable("__NSDictionaryM_Immutable"); 398 static const ConstString g_Dictionary1("__NSSingleEntryDictionaryI"); 399 400 if (class_name.IsEmpty()) 401 return false; 402 403 if (class_name == g_DictionaryI || class_name == g_DictionaryMImmutable) { 404 Status error; 405 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 406 ptr_size, 0, error); 407 if (error.Fail()) 408 return false; 409 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U); 410 } else if (class_name == g_DictionaryM || class_name == g_DictionaryMLegacy) { 411 AppleObjCRuntime *apple_runtime = 412 llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime); 413 Status error; 414 if (apple_runtime && apple_runtime->GetFoundationVersion() >= 1437) { 415 value = Foundation1437::__NSDictionaryMSize(*process_sp, valobj_addr, 416 error); 417 } else { 418 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 419 ptr_size, 0, error); 420 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U); 421 } 422 if (error.Fail()) 423 return false; 424 } else if (class_name == g_Dictionary1) { 425 value = 1; 426 } 427 /*else if (!strcmp(class_name,"__NSCFDictionary")) 428 { 429 Status error; 430 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + (is_64bit ? 431 20 : 12), 4, 0, error); 432 if (error.Fail()) 433 return false; 434 if (is_64bit) 435 value &= ~0x0f1f000000000000UL; 436 }*/ 437 else { 438 auto &map(NSDictionary_Additionals::GetAdditionalSummaries()); 439 for (auto &candidate : map) { 440 if (candidate.first && candidate.first->Match(class_name)) 441 return candidate.second(valobj, stream, options); 442 } 443 return false; 444 } 445 446 std::string prefix, suffix; 447 if (Language *language = Language::FindPlugin(options.GetLanguage())) { 448 if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix, 449 suffix)) { 450 prefix.clear(); 451 suffix.clear(); 452 } 453 } 454 455 stream.Printf("%s%" PRIu64 " %s%s%s", prefix.c_str(), value, "key/value pair", 456 value == 1 ? "" : "s", suffix.c_str()); 457 return true; 458 } 459 460 SyntheticChildrenFrontEnd * 461 lldb_private::formatters::NSDictionarySyntheticFrontEndCreator( 462 CXXSyntheticChildren *synth, lldb::ValueObjectSP valobj_sp) { 463 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 464 if (!process_sp) 465 return nullptr; 466 AppleObjCRuntime *runtime = 467 llvm::dyn_cast_or_null<AppleObjCRuntime>(process_sp->GetObjCLanguageRuntime()); 468 if (!runtime) 469 return nullptr; 470 471 CompilerType valobj_type(valobj_sp->GetCompilerType()); 472 Flags flags(valobj_type.GetTypeInfo()); 473 474 if (flags.IsClear(eTypeIsPointer)) { 475 Status error; 476 valobj_sp = valobj_sp->AddressOf(error); 477 if (error.Fail() || !valobj_sp) 478 return nullptr; 479 } 480 481 ObjCLanguageRuntime::ClassDescriptorSP descriptor( 482 runtime->GetClassDescriptor(*valobj_sp)); 483 484 if (!descriptor || !descriptor->IsValid()) 485 return nullptr; 486 487 ConstString class_name(descriptor->GetClassName()); 488 489 static const ConstString g_DictionaryI("__NSDictionaryI"); 490 static const ConstString g_DictionaryM("__NSDictionaryM"); 491 static const ConstString g_Dictionary1("__NSSingleEntryDictionaryI"); 492 static const ConstString g_DictionaryImmutable("__NSDictionaryM_Immutable"); 493 static const ConstString g_DictionaryMLegacy("__NSDictionaryM_Legacy"); 494 495 if (class_name.IsEmpty()) 496 return nullptr; 497 498 if (class_name == g_DictionaryI) { 499 return (new NSDictionaryISyntheticFrontEnd(valobj_sp)); 500 } else if (class_name == g_DictionaryM) { 501 if (runtime->GetFoundationVersion() >= 1437) { 502 return (new Foundation1437::NSDictionaryMSyntheticFrontEnd(valobj_sp)); 503 } else if (runtime->GetFoundationVersion() >= 1428) { 504 return (new Foundation1428::NSDictionaryMSyntheticFrontEnd(valobj_sp)); 505 } else { 506 return (new Foundation1100::NSDictionaryMSyntheticFrontEnd(valobj_sp)); 507 } 508 } else if (class_name == g_DictionaryMLegacy) { 509 return (new Foundation1100::NSDictionaryMSyntheticFrontEnd(valobj_sp)); 510 } else if (class_name == g_Dictionary1) { 511 return (new NSDictionary1SyntheticFrontEnd(valobj_sp)); 512 } else { 513 auto &map(NSDictionary_Additionals::GetAdditionalSynthetics()); 514 for (auto &candidate : map) { 515 if (candidate.first && candidate.first->Match((class_name))) 516 return candidate.second(synth, valobj_sp); 517 } 518 } 519 520 return nullptr; 521 } 522 523 lldb_private::formatters::NSDictionaryISyntheticFrontEnd:: 524 NSDictionaryISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 525 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8), 526 m_order(lldb::eByteOrderInvalid), m_data_32(nullptr), m_data_64(nullptr), 527 m_pair_type() {} 528 529 lldb_private::formatters::NSDictionaryISyntheticFrontEnd:: 530 ~NSDictionaryISyntheticFrontEnd() { 531 delete m_data_32; 532 m_data_32 = nullptr; 533 delete m_data_64; 534 m_data_64 = nullptr; 535 } 536 537 size_t lldb_private::formatters::NSDictionaryISyntheticFrontEnd:: 538 GetIndexOfChildWithName(const ConstString &name) { 539 const char *item_name = name.GetCString(); 540 uint32_t idx = ExtractIndexFromString(item_name); 541 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 542 return UINT32_MAX; 543 return idx; 544 } 545 546 size_t lldb_private::formatters::NSDictionaryISyntheticFrontEnd:: 547 CalculateNumChildren() { 548 if (!m_data_32 && !m_data_64) 549 return 0; 550 return (m_data_32 ? m_data_32->_used : m_data_64->_used); 551 } 552 553 bool lldb_private::formatters::NSDictionaryISyntheticFrontEnd::Update() { 554 m_children.clear(); 555 delete m_data_32; 556 m_data_32 = nullptr; 557 delete m_data_64; 558 m_data_64 = nullptr; 559 m_ptr_size = 0; 560 ValueObjectSP valobj_sp = m_backend.GetSP(); 561 if (!valobj_sp) 562 return false; 563 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 564 Status error; 565 error.Clear(); 566 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 567 if (!process_sp) 568 return false; 569 m_ptr_size = process_sp->GetAddressByteSize(); 570 m_order = process_sp->GetByteOrder(); 571 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size; 572 if (m_ptr_size == 4) { 573 m_data_32 = new DataDescriptor_32(); 574 process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32), 575 error); 576 } else { 577 m_data_64 = new DataDescriptor_64(); 578 process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64), 579 error); 580 } 581 if (error.Fail()) 582 return false; 583 m_data_ptr = data_location + m_ptr_size; 584 return false; 585 } 586 587 bool lldb_private::formatters::NSDictionaryISyntheticFrontEnd:: 588 MightHaveChildren() { 589 return true; 590 } 591 592 lldb::ValueObjectSP 593 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::GetChildAtIndex( 594 size_t idx) { 595 uint32_t num_children = CalculateNumChildren(); 596 597 if (idx >= num_children) 598 return lldb::ValueObjectSP(); 599 600 if (m_children.empty()) { 601 // do the scan phase 602 lldb::addr_t key_at_idx = 0, val_at_idx = 0; 603 604 uint32_t tries = 0; 605 uint32_t test_idx = 0; 606 607 while (tries < num_children) { 608 key_at_idx = m_data_ptr + (2 * test_idx * m_ptr_size); 609 val_at_idx = key_at_idx + m_ptr_size; 610 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); 611 if (!process_sp) 612 return lldb::ValueObjectSP(); 613 Status error; 614 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error); 615 if (error.Fail()) 616 return lldb::ValueObjectSP(); 617 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error); 618 if (error.Fail()) 619 return lldb::ValueObjectSP(); 620 621 test_idx++; 622 623 if (!key_at_idx || !val_at_idx) 624 continue; 625 tries++; 626 627 DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx, 628 lldb::ValueObjectSP()}; 629 630 m_children.push_back(descriptor); 631 } 632 } 633 634 if (idx >= m_children.size()) // should never happen 635 return lldb::ValueObjectSP(); 636 637 DictionaryItemDescriptor &dict_item = m_children[idx]; 638 if (!dict_item.valobj_sp) { 639 if (!m_pair_type.IsValid()) { 640 TargetSP target_sp(m_backend.GetTargetSP()); 641 if (!target_sp) 642 return ValueObjectSP(); 643 m_pair_type = GetLLDBNSPairType(target_sp); 644 } 645 if (!m_pair_type.IsValid()) 646 return ValueObjectSP(); 647 648 DataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0)); 649 650 if (m_ptr_size == 8) { 651 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes(); 652 *data_ptr = dict_item.key_ptr; 653 *(data_ptr + 1) = dict_item.val_ptr; 654 } else { 655 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes(); 656 *data_ptr = dict_item.key_ptr; 657 *(data_ptr + 1) = dict_item.val_ptr; 658 } 659 660 StreamString idx_name; 661 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); 662 DataExtractor data(buffer_sp, m_order, m_ptr_size); 663 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data, 664 m_exe_ctx_ref, m_pair_type); 665 } 666 return dict_item.valobj_sp; 667 } 668 669 lldb_private::formatters::NSDictionary1SyntheticFrontEnd:: 670 NSDictionary1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 671 : SyntheticChildrenFrontEnd(*valobj_sp.get()), m_pair(nullptr) {} 672 673 size_t lldb_private::formatters::NSDictionary1SyntheticFrontEnd:: 674 GetIndexOfChildWithName(const ConstString &name) { 675 static const ConstString g_zero("[0]"); 676 677 if (name == g_zero) 678 return 0; 679 680 return UINT32_MAX; 681 } 682 683 size_t lldb_private::formatters::NSDictionary1SyntheticFrontEnd:: 684 CalculateNumChildren() { 685 return 1; 686 } 687 688 bool lldb_private::formatters::NSDictionary1SyntheticFrontEnd::Update() { 689 m_pair.reset(); 690 return false; 691 } 692 693 bool lldb_private::formatters::NSDictionary1SyntheticFrontEnd:: 694 MightHaveChildren() { 695 return true; 696 } 697 698 lldb::ValueObjectSP 699 lldb_private::formatters::NSDictionary1SyntheticFrontEnd::GetChildAtIndex( 700 size_t idx) { 701 if (idx != 0) 702 return lldb::ValueObjectSP(); 703 704 if (m_pair.get()) 705 return m_pair; 706 707 auto process_sp(m_backend.GetProcessSP()); 708 if (!process_sp) 709 return nullptr; 710 711 auto ptr_size = process_sp->GetAddressByteSize(); 712 713 lldb::addr_t key_ptr = 714 m_backend.GetValueAsUnsigned(LLDB_INVALID_ADDRESS) + ptr_size; 715 lldb::addr_t value_ptr = key_ptr + ptr_size; 716 717 Status error; 718 719 lldb::addr_t value_at_idx = process_sp->ReadPointerFromMemory(key_ptr, error); 720 if (error.Fail()) 721 return nullptr; 722 lldb::addr_t key_at_idx = process_sp->ReadPointerFromMemory(value_ptr, error); 723 if (error.Fail()) 724 return nullptr; 725 726 auto pair_type = 727 GetLLDBNSPairType(process_sp->GetTarget().shared_from_this()); 728 729 DataBufferSP buffer_sp(new DataBufferHeap(2 * ptr_size, 0)); 730 731 if (ptr_size == 8) { 732 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes(); 733 *data_ptr = key_at_idx; 734 *(data_ptr + 1) = value_at_idx; 735 } else { 736 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes(); 737 *data_ptr = key_at_idx; 738 *(data_ptr + 1) = value_at_idx; 739 } 740 741 DataExtractor data(buffer_sp, process_sp->GetByteOrder(), ptr_size); 742 m_pair = CreateValueObjectFromData( 743 "[0]", data, m_backend.GetExecutionContextRef(), pair_type); 744 745 return m_pair; 746 } 747 748 template <typename D32, typename D64> 749 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>:: 750 GenericNSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 751 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8), 752 m_order(lldb::eByteOrderInvalid), m_data_32(nullptr), m_data_64(nullptr), 753 m_pair_type() {} 754 755 template <typename D32, typename D64> 756 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>:: 757 ~GenericNSDictionaryMSyntheticFrontEnd() { 758 delete m_data_32; 759 m_data_32 = nullptr; 760 delete m_data_64; 761 m_data_64 = nullptr; 762 } 763 764 template <typename D32, typename D64> 765 size_t 766 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>:: GetIndexOfChildWithName(const ConstString &name) { 767 const char *item_name = name.GetCString(); 768 uint32_t idx = ExtractIndexFromString(item_name); 769 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 770 return UINT32_MAX; 771 return idx; 772 } 773 774 template <typename D32, typename D64> 775 size_t 776 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>::CalculateNumChildren() { 777 if (!m_data_32 && !m_data_64) 778 return 0; 779 return (m_data_32 ? m_data_32->_used : m_data_64->_used); 780 } 781 782 template <typename D32, typename D64> 783 bool 784 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>:: 785 Update() { 786 m_children.clear(); 787 ValueObjectSP valobj_sp = m_backend.GetSP(); 788 m_ptr_size = 0; 789 delete m_data_32; 790 m_data_32 = nullptr; 791 delete m_data_64; 792 m_data_64 = nullptr; 793 if (!valobj_sp) 794 return false; 795 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 796 Status error; 797 error.Clear(); 798 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 799 if (!process_sp) 800 return false; 801 m_ptr_size = process_sp->GetAddressByteSize(); 802 m_order = process_sp->GetByteOrder(); 803 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size; 804 if (m_ptr_size == 4) { 805 m_data_32 = new D32(); 806 process_sp->ReadMemory(data_location, m_data_32, sizeof(D32), 807 error); 808 } else { 809 m_data_64 = new D64(); 810 process_sp->ReadMemory(data_location, m_data_64, sizeof(D64), 811 error); 812 } 813 if (error.Fail()) 814 return false; 815 return false; 816 } 817 818 template <typename D32, typename D64> 819 bool 820 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>:: 821 MightHaveChildren() { 822 return true; 823 } 824 825 template <typename D32, typename D64> 826 lldb::ValueObjectSP 827 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>:: 828 GetChildAtIndex( 829 size_t idx) { 830 lldb::addr_t m_keys_ptr; 831 lldb::addr_t m_values_ptr; 832 if (m_data_32) { 833 uint32_t size = m_data_32->GetSize(); 834 m_keys_ptr = m_data_32->_buffer; 835 m_values_ptr = m_data_32->_buffer + (m_ptr_size * size); 836 } else { 837 uint32_t size = m_data_64->GetSize(); 838 m_keys_ptr = m_data_64->_buffer; 839 m_values_ptr = m_data_64->_buffer + (m_ptr_size * size); 840 } 841 842 uint32_t num_children = CalculateNumChildren(); 843 844 if (idx >= num_children) 845 return lldb::ValueObjectSP(); 846 847 if (m_children.empty()) { 848 // do the scan phase 849 lldb::addr_t key_at_idx = 0, val_at_idx = 0; 850 851 uint32_t tries = 0; 852 uint32_t test_idx = 0; 853 854 while (tries < num_children) { 855 key_at_idx = m_keys_ptr + (test_idx * m_ptr_size); 856 val_at_idx = m_values_ptr + (test_idx * m_ptr_size); 857 ; 858 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); 859 if (!process_sp) 860 return lldb::ValueObjectSP(); 861 Status error; 862 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error); 863 if (error.Fail()) 864 return lldb::ValueObjectSP(); 865 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error); 866 if (error.Fail()) 867 return lldb::ValueObjectSP(); 868 869 test_idx++; 870 871 if (!key_at_idx || !val_at_idx) 872 continue; 873 tries++; 874 875 DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx, 876 lldb::ValueObjectSP()}; 877 878 m_children.push_back(descriptor); 879 } 880 } 881 882 if (idx >= m_children.size()) // should never happen 883 return lldb::ValueObjectSP(); 884 885 DictionaryItemDescriptor &dict_item = m_children[idx]; 886 if (!dict_item.valobj_sp) { 887 if (!m_pair_type.IsValid()) { 888 TargetSP target_sp(m_backend.GetTargetSP()); 889 if (!target_sp) 890 return ValueObjectSP(); 891 m_pair_type = GetLLDBNSPairType(target_sp); 892 } 893 if (!m_pair_type.IsValid()) 894 return ValueObjectSP(); 895 896 DataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0)); 897 898 if (m_ptr_size == 8) { 899 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes(); 900 *data_ptr = dict_item.key_ptr; 901 *(data_ptr + 1) = dict_item.val_ptr; 902 } else { 903 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes(); 904 *data_ptr = dict_item.key_ptr; 905 *(data_ptr + 1) = dict_item.val_ptr; 906 } 907 908 StreamString idx_name; 909 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); 910 DataExtractor data(buffer_sp, m_order, m_ptr_size); 911 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data, 912 m_exe_ctx_ref, m_pair_type); 913 } 914 return dict_item.valobj_sp; 915 } 916 917 918 lldb_private::formatters::Foundation1100:: 919 NSDictionaryMSyntheticFrontEnd:: 920 NSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 921 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8), 922 m_order(lldb::eByteOrderInvalid), m_data_32(nullptr), m_data_64(nullptr), 923 m_pair_type() {} 924 925 lldb_private::formatters::Foundation1100:: 926 NSDictionaryMSyntheticFrontEnd::~NSDictionaryMSyntheticFrontEnd() { 927 delete m_data_32; 928 m_data_32 = nullptr; 929 delete m_data_64; 930 m_data_64 = nullptr; 931 } 932 933 size_t 934 lldb_private::formatters::Foundation1100:: 935 NSDictionaryMSyntheticFrontEnd::GetIndexOfChildWithName(const ConstString &name) { 936 const char *item_name = name.GetCString(); 937 uint32_t idx = ExtractIndexFromString(item_name); 938 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 939 return UINT32_MAX; 940 return idx; 941 } 942 943 size_t 944 lldb_private::formatters::Foundation1100:: 945 NSDictionaryMSyntheticFrontEnd::CalculateNumChildren() { 946 if (!m_data_32 && !m_data_64) 947 return 0; 948 return (m_data_32 ? m_data_32->_used : m_data_64->_used); 949 } 950 951 bool 952 lldb_private::formatters::Foundation1100:: 953 NSDictionaryMSyntheticFrontEnd::Update() { 954 m_children.clear(); 955 ValueObjectSP valobj_sp = m_backend.GetSP(); 956 m_ptr_size = 0; 957 delete m_data_32; 958 m_data_32 = nullptr; 959 delete m_data_64; 960 m_data_64 = nullptr; 961 if (!valobj_sp) 962 return false; 963 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 964 Status error; 965 error.Clear(); 966 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 967 if (!process_sp) 968 return false; 969 m_ptr_size = process_sp->GetAddressByteSize(); 970 m_order = process_sp->GetByteOrder(); 971 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size; 972 if (m_ptr_size == 4) { 973 m_data_32 = new DataDescriptor_32(); 974 process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32), 975 error); 976 } else { 977 m_data_64 = new DataDescriptor_64(); 978 process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64), 979 error); 980 } 981 if (error.Fail()) 982 return false; 983 return false; 984 } 985 986 bool 987 lldb_private::formatters::Foundation1100:: 988 NSDictionaryMSyntheticFrontEnd::MightHaveChildren() { 989 return true; 990 } 991 992 lldb::ValueObjectSP 993 lldb_private::formatters::Foundation1100:: 994 NSDictionaryMSyntheticFrontEnd::GetChildAtIndex(size_t idx) { 995 lldb::addr_t m_keys_ptr = 996 (m_data_32 ? m_data_32->_keys_addr : m_data_64->_keys_addr); 997 lldb::addr_t m_values_ptr = 998 (m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr); 999 1000 uint32_t num_children = CalculateNumChildren(); 1001 1002 if (idx >= num_children) 1003 return lldb::ValueObjectSP(); 1004 1005 if (m_children.empty()) { 1006 // do the scan phase 1007 lldb::addr_t key_at_idx = 0, val_at_idx = 0; 1008 1009 uint32_t tries = 0; 1010 uint32_t test_idx = 0; 1011 1012 while (tries < num_children) { 1013 key_at_idx = m_keys_ptr + (test_idx * m_ptr_size); 1014 val_at_idx = m_values_ptr + (test_idx * m_ptr_size); 1015 ; 1016 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); 1017 if (!process_sp) 1018 return lldb::ValueObjectSP(); 1019 Status error; 1020 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error); 1021 if (error.Fail()) 1022 return lldb::ValueObjectSP(); 1023 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error); 1024 if (error.Fail()) 1025 return lldb::ValueObjectSP(); 1026 1027 test_idx++; 1028 1029 if (!key_at_idx || !val_at_idx) 1030 continue; 1031 tries++; 1032 1033 DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx, 1034 lldb::ValueObjectSP()}; 1035 1036 m_children.push_back(descriptor); 1037 } 1038 } 1039 1040 if (idx >= m_children.size()) // should never happen 1041 return lldb::ValueObjectSP(); 1042 1043 DictionaryItemDescriptor &dict_item = m_children[idx]; 1044 if (!dict_item.valobj_sp) { 1045 if (!m_pair_type.IsValid()) { 1046 TargetSP target_sp(m_backend.GetTargetSP()); 1047 if (!target_sp) 1048 return ValueObjectSP(); 1049 m_pair_type = GetLLDBNSPairType(target_sp); 1050 } 1051 if (!m_pair_type.IsValid()) 1052 return ValueObjectSP(); 1053 1054 DataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0)); 1055 1056 if (m_ptr_size == 8) { 1057 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes(); 1058 *data_ptr = dict_item.key_ptr; 1059 *(data_ptr + 1) = dict_item.val_ptr; 1060 } else { 1061 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes(); 1062 *data_ptr = dict_item.key_ptr; 1063 *(data_ptr + 1) = dict_item.val_ptr; 1064 } 1065 1066 StreamString idx_name; 1067 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); 1068 DataExtractor data(buffer_sp, m_order, m_ptr_size); 1069 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data, 1070 m_exe_ctx_ref, m_pair_type); 1071 } 1072 return dict_item.valobj_sp; 1073 } 1074 1075 template bool lldb_private::formatters::NSDictionarySummaryProvider<true>( 1076 ValueObject &, Stream &, const TypeSummaryOptions &); 1077 1078 template bool lldb_private::formatters::NSDictionarySummaryProvider<false>( 1079 ValueObject &, Stream &, const TypeSummaryOptions &); 1080