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