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