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