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 return name == g_zero ? 0 : UINT32_MAX; 671 } 672 673 size_t lldb_private::formatters::NSDictionary1SyntheticFrontEnd:: 674 CalculateNumChildren() { 675 return 1; 676 } 677 678 bool lldb_private::formatters::NSDictionary1SyntheticFrontEnd::Update() { 679 m_pair.reset(); 680 return false; 681 } 682 683 bool lldb_private::formatters::NSDictionary1SyntheticFrontEnd:: 684 MightHaveChildren() { 685 return true; 686 } 687 688 lldb::ValueObjectSP 689 lldb_private::formatters::NSDictionary1SyntheticFrontEnd::GetChildAtIndex( 690 size_t idx) { 691 if (idx != 0) 692 return lldb::ValueObjectSP(); 693 694 if (m_pair.get()) 695 return m_pair; 696 697 auto process_sp(m_backend.GetProcessSP()); 698 if (!process_sp) 699 return nullptr; 700 701 auto ptr_size = process_sp->GetAddressByteSize(); 702 703 lldb::addr_t key_ptr = 704 m_backend.GetValueAsUnsigned(LLDB_INVALID_ADDRESS) + ptr_size; 705 lldb::addr_t value_ptr = key_ptr + ptr_size; 706 707 Status error; 708 709 lldb::addr_t value_at_idx = process_sp->ReadPointerFromMemory(key_ptr, error); 710 if (error.Fail()) 711 return nullptr; 712 lldb::addr_t key_at_idx = process_sp->ReadPointerFromMemory(value_ptr, error); 713 if (error.Fail()) 714 return nullptr; 715 716 auto pair_type = 717 GetLLDBNSPairType(process_sp->GetTarget().shared_from_this()); 718 719 DataBufferSP buffer_sp(new DataBufferHeap(2 * ptr_size, 0)); 720 721 if (ptr_size == 8) { 722 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes(); 723 *data_ptr = key_at_idx; 724 *(data_ptr + 1) = value_at_idx; 725 } else { 726 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes(); 727 *data_ptr = key_at_idx; 728 *(data_ptr + 1) = value_at_idx; 729 } 730 731 DataExtractor data(buffer_sp, process_sp->GetByteOrder(), ptr_size); 732 m_pair = CreateValueObjectFromData( 733 "[0]", data, m_backend.GetExecutionContextRef(), pair_type); 734 735 return m_pair; 736 } 737 738 template <typename D32, typename D64> 739 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>:: 740 GenericNSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 741 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8), 742 m_order(lldb::eByteOrderInvalid), m_data_32(nullptr), m_data_64(nullptr), 743 m_pair_type() {} 744 745 template <typename D32, typename D64> 746 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>:: 747 ~GenericNSDictionaryMSyntheticFrontEnd() { 748 delete m_data_32; 749 m_data_32 = nullptr; 750 delete m_data_64; 751 m_data_64 = nullptr; 752 } 753 754 template <typename D32, typename D64> 755 size_t 756 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>:: GetIndexOfChildWithName(const ConstString &name) { 757 const char *item_name = name.GetCString(); 758 uint32_t idx = ExtractIndexFromString(item_name); 759 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 760 return UINT32_MAX; 761 return idx; 762 } 763 764 template <typename D32, typename D64> 765 size_t 766 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>::CalculateNumChildren() { 767 if (!m_data_32 && !m_data_64) 768 return 0; 769 return (m_data_32 ? m_data_32->_used : m_data_64->_used); 770 } 771 772 template <typename D32, typename D64> 773 bool 774 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>:: 775 Update() { 776 m_children.clear(); 777 ValueObjectSP valobj_sp = m_backend.GetSP(); 778 m_ptr_size = 0; 779 delete m_data_32; 780 m_data_32 = nullptr; 781 delete m_data_64; 782 m_data_64 = nullptr; 783 if (!valobj_sp) 784 return false; 785 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 786 Status error; 787 error.Clear(); 788 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 789 if (!process_sp) 790 return false; 791 m_ptr_size = process_sp->GetAddressByteSize(); 792 m_order = process_sp->GetByteOrder(); 793 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size; 794 if (m_ptr_size == 4) { 795 m_data_32 = new D32(); 796 process_sp->ReadMemory(data_location, m_data_32, sizeof(D32), 797 error); 798 } else { 799 m_data_64 = new D64(); 800 process_sp->ReadMemory(data_location, m_data_64, sizeof(D64), 801 error); 802 } 803 if (error.Fail()) 804 return false; 805 return false; 806 } 807 808 template <typename D32, typename D64> 809 bool 810 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>:: 811 MightHaveChildren() { 812 return true; 813 } 814 815 template <typename D32, typename D64> 816 lldb::ValueObjectSP 817 lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>:: 818 GetChildAtIndex( 819 size_t idx) { 820 lldb::addr_t m_keys_ptr; 821 lldb::addr_t m_values_ptr; 822 if (m_data_32) { 823 uint32_t size = m_data_32->GetSize(); 824 m_keys_ptr = m_data_32->_buffer; 825 m_values_ptr = m_data_32->_buffer + (m_ptr_size * size); 826 } else { 827 uint32_t size = m_data_64->GetSize(); 828 m_keys_ptr = m_data_64->_buffer; 829 m_values_ptr = m_data_64->_buffer + (m_ptr_size * size); 830 } 831 832 uint32_t num_children = CalculateNumChildren(); 833 834 if (idx >= num_children) 835 return lldb::ValueObjectSP(); 836 837 if (m_children.empty()) { 838 // do the scan phase 839 lldb::addr_t key_at_idx = 0, val_at_idx = 0; 840 841 uint32_t tries = 0; 842 uint32_t test_idx = 0; 843 844 while (tries < num_children) { 845 key_at_idx = m_keys_ptr + (test_idx * m_ptr_size); 846 val_at_idx = m_values_ptr + (test_idx * m_ptr_size); 847 ; 848 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); 849 if (!process_sp) 850 return lldb::ValueObjectSP(); 851 Status error; 852 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error); 853 if (error.Fail()) 854 return lldb::ValueObjectSP(); 855 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error); 856 if (error.Fail()) 857 return lldb::ValueObjectSP(); 858 859 test_idx++; 860 861 if (!key_at_idx || !val_at_idx) 862 continue; 863 tries++; 864 865 DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx, 866 lldb::ValueObjectSP()}; 867 868 m_children.push_back(descriptor); 869 } 870 } 871 872 if (idx >= m_children.size()) // should never happen 873 return lldb::ValueObjectSP(); 874 875 DictionaryItemDescriptor &dict_item = m_children[idx]; 876 if (!dict_item.valobj_sp) { 877 if (!m_pair_type.IsValid()) { 878 TargetSP target_sp(m_backend.GetTargetSP()); 879 if (!target_sp) 880 return ValueObjectSP(); 881 m_pair_type = GetLLDBNSPairType(target_sp); 882 } 883 if (!m_pair_type.IsValid()) 884 return ValueObjectSP(); 885 886 DataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0)); 887 888 if (m_ptr_size == 8) { 889 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes(); 890 *data_ptr = dict_item.key_ptr; 891 *(data_ptr + 1) = dict_item.val_ptr; 892 } else { 893 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes(); 894 *data_ptr = dict_item.key_ptr; 895 *(data_ptr + 1) = dict_item.val_ptr; 896 } 897 898 StreamString idx_name; 899 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); 900 DataExtractor data(buffer_sp, m_order, m_ptr_size); 901 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data, 902 m_exe_ctx_ref, m_pair_type); 903 } 904 return dict_item.valobj_sp; 905 } 906 907 908 lldb_private::formatters::Foundation1100:: 909 NSDictionaryMSyntheticFrontEnd:: 910 NSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 911 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8), 912 m_order(lldb::eByteOrderInvalid), m_data_32(nullptr), m_data_64(nullptr), 913 m_pair_type() {} 914 915 lldb_private::formatters::Foundation1100:: 916 NSDictionaryMSyntheticFrontEnd::~NSDictionaryMSyntheticFrontEnd() { 917 delete m_data_32; 918 m_data_32 = nullptr; 919 delete m_data_64; 920 m_data_64 = nullptr; 921 } 922 923 size_t 924 lldb_private::formatters::Foundation1100:: 925 NSDictionaryMSyntheticFrontEnd::GetIndexOfChildWithName(const ConstString &name) { 926 const char *item_name = name.GetCString(); 927 uint32_t idx = ExtractIndexFromString(item_name); 928 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 929 return UINT32_MAX; 930 return idx; 931 } 932 933 size_t 934 lldb_private::formatters::Foundation1100:: 935 NSDictionaryMSyntheticFrontEnd::CalculateNumChildren() { 936 if (!m_data_32 && !m_data_64) 937 return 0; 938 return (m_data_32 ? m_data_32->_used : m_data_64->_used); 939 } 940 941 bool 942 lldb_private::formatters::Foundation1100:: 943 NSDictionaryMSyntheticFrontEnd::Update() { 944 m_children.clear(); 945 ValueObjectSP valobj_sp = m_backend.GetSP(); 946 m_ptr_size = 0; 947 delete m_data_32; 948 m_data_32 = nullptr; 949 delete m_data_64; 950 m_data_64 = nullptr; 951 if (!valobj_sp) 952 return false; 953 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 954 Status error; 955 error.Clear(); 956 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 957 if (!process_sp) 958 return false; 959 m_ptr_size = process_sp->GetAddressByteSize(); 960 m_order = process_sp->GetByteOrder(); 961 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size; 962 if (m_ptr_size == 4) { 963 m_data_32 = new DataDescriptor_32(); 964 process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32), 965 error); 966 } else { 967 m_data_64 = new DataDescriptor_64(); 968 process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64), 969 error); 970 } 971 if (error.Fail()) 972 return false; 973 return false; 974 } 975 976 bool 977 lldb_private::formatters::Foundation1100:: 978 NSDictionaryMSyntheticFrontEnd::MightHaveChildren() { 979 return true; 980 } 981 982 lldb::ValueObjectSP 983 lldb_private::formatters::Foundation1100:: 984 NSDictionaryMSyntheticFrontEnd::GetChildAtIndex(size_t idx) { 985 lldb::addr_t m_keys_ptr = 986 (m_data_32 ? m_data_32->_keys_addr : m_data_64->_keys_addr); 987 lldb::addr_t m_values_ptr = 988 (m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr); 989 990 uint32_t num_children = CalculateNumChildren(); 991 992 if (idx >= num_children) 993 return lldb::ValueObjectSP(); 994 995 if (m_children.empty()) { 996 // do the scan phase 997 lldb::addr_t key_at_idx = 0, val_at_idx = 0; 998 999 uint32_t tries = 0; 1000 uint32_t test_idx = 0; 1001 1002 while (tries < num_children) { 1003 key_at_idx = m_keys_ptr + (test_idx * m_ptr_size); 1004 val_at_idx = m_values_ptr + (test_idx * m_ptr_size); 1005 ; 1006 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); 1007 if (!process_sp) 1008 return lldb::ValueObjectSP(); 1009 Status error; 1010 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error); 1011 if (error.Fail()) 1012 return lldb::ValueObjectSP(); 1013 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error); 1014 if (error.Fail()) 1015 return lldb::ValueObjectSP(); 1016 1017 test_idx++; 1018 1019 if (!key_at_idx || !val_at_idx) 1020 continue; 1021 tries++; 1022 1023 DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx, 1024 lldb::ValueObjectSP()}; 1025 1026 m_children.push_back(descriptor); 1027 } 1028 } 1029 1030 if (idx >= m_children.size()) // should never happen 1031 return lldb::ValueObjectSP(); 1032 1033 DictionaryItemDescriptor &dict_item = m_children[idx]; 1034 if (!dict_item.valobj_sp) { 1035 if (!m_pair_type.IsValid()) { 1036 TargetSP target_sp(m_backend.GetTargetSP()); 1037 if (!target_sp) 1038 return ValueObjectSP(); 1039 m_pair_type = GetLLDBNSPairType(target_sp); 1040 } 1041 if (!m_pair_type.IsValid()) 1042 return ValueObjectSP(); 1043 1044 DataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0)); 1045 1046 if (m_ptr_size == 8) { 1047 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes(); 1048 *data_ptr = dict_item.key_ptr; 1049 *(data_ptr + 1) = dict_item.val_ptr; 1050 } else { 1051 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes(); 1052 *data_ptr = dict_item.key_ptr; 1053 *(data_ptr + 1) = dict_item.val_ptr; 1054 } 1055 1056 StreamString idx_name; 1057 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); 1058 DataExtractor data(buffer_sp, m_order, m_ptr_size); 1059 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data, 1060 m_exe_ctx_ref, m_pair_type); 1061 } 1062 return dict_item.valobj_sp; 1063 } 1064 1065 template bool lldb_private::formatters::NSDictionarySummaryProvider<true>( 1066 ValueObject &, Stream &, const TypeSummaryOptions &); 1067 1068 template bool lldb_private::formatters::NSDictionarySummaryProvider<false>( 1069 ValueObject &, Stream &, const TypeSummaryOptions &); 1070