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 class NSDictionaryMSyntheticFrontEnd : public SyntheticChildrenFrontEnd { 169 public: 170 NSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); 171 172 ~NSDictionaryMSyntheticFrontEnd() override; 173 174 size_t CalculateNumChildren() override; 175 176 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; 177 178 bool Update() override; 179 180 bool MightHaveChildren() override; 181 182 size_t GetIndexOfChildWithName(const ConstString &name) override; 183 184 private: 185 struct DataDescriptor_32 { 186 uint32_t used : 26; 187 uint32_t kvo : 1; 188 uint32_t size; 189 uint32_t buffer; 190 }; 191 192 struct DataDescriptor_64 { 193 uint64_t used : 58; 194 uint32_t kvo : 1; 195 uint64_t size; 196 uint64_t buffer; 197 }; 198 199 struct DictionaryItemDescriptor { 200 lldb::addr_t key_ptr; 201 lldb::addr_t val_ptr; 202 lldb::ValueObjectSP valobj_sp; 203 }; 204 205 ExecutionContextRef m_exe_ctx_ref; 206 uint8_t m_ptr_size; 207 lldb::ByteOrder m_order; 208 DataDescriptor_32 *m_data_32; 209 DataDescriptor_64 *m_data_64; 210 CompilerType m_pair_type; 211 std::vector<DictionaryItemDescriptor> m_children; 212 }; 213 214 class NSDictionaryMLegacySyntheticFrontEnd : public SyntheticChildrenFrontEnd { 215 public: 216 NSDictionaryMLegacySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); 217 218 ~NSDictionaryMLegacySyntheticFrontEnd() override; 219 220 size_t CalculateNumChildren() override; 221 222 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; 223 224 bool Update() override; 225 226 bool MightHaveChildren() override; 227 228 size_t GetIndexOfChildWithName(const ConstString &name) override; 229 230 private: 231 struct DataDescriptor_32 { 232 uint32_t _used : 26; 233 uint32_t _kvo : 1; 234 uint32_t _size; 235 uint32_t _mutations; 236 uint32_t _objs_addr; 237 uint32_t _keys_addr; 238 }; 239 240 struct DataDescriptor_64 { 241 uint64_t _used : 58; 242 uint32_t _kvo : 1; 243 uint64_t _size; 244 uint64_t _mutations; 245 uint64_t _objs_addr; 246 uint64_t _keys_addr; 247 }; 248 249 struct DictionaryItemDescriptor { 250 lldb::addr_t key_ptr; 251 lldb::addr_t val_ptr; 252 lldb::ValueObjectSP valobj_sp; 253 }; 254 255 ExecutionContextRef m_exe_ctx_ref; 256 uint8_t m_ptr_size; 257 lldb::ByteOrder m_order; 258 DataDescriptor_32 *m_data_32; 259 DataDescriptor_64 *m_data_64; 260 CompilerType m_pair_type; 261 std::vector<DictionaryItemDescriptor> m_children; 262 }; 263 } // namespace formatters 264 } // namespace lldb_private 265 266 template <bool name_entries> 267 bool lldb_private::formatters::NSDictionarySummaryProvider( 268 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { 269 static ConstString g_TypeHint("NSDictionary"); 270 ProcessSP process_sp = valobj.GetProcessSP(); 271 if (!process_sp) 272 return false; 273 274 ObjCLanguageRuntime *runtime = 275 (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime( 276 lldb::eLanguageTypeObjC); 277 278 if (!runtime) 279 return false; 280 281 ObjCLanguageRuntime::ClassDescriptorSP descriptor( 282 runtime->GetClassDescriptor(valobj)); 283 284 if (!descriptor || !descriptor->IsValid()) 285 return false; 286 287 uint32_t ptr_size = process_sp->GetAddressByteSize(); 288 bool is_64bit = (ptr_size == 8); 289 290 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 291 292 if (!valobj_addr) 293 return false; 294 295 uint64_t value = 0; 296 297 ConstString class_name(descriptor->GetClassName()); 298 299 static const ConstString g_DictionaryI("__NSDictionaryI"); 300 static const ConstString g_DictionaryM("__NSDictionaryM"); 301 static const ConstString g_DictionaryMLegacy("__NSDictionaryM_Legacy"); 302 static const ConstString g_DictionaryMImmutable("__NSDictionaryM_Immutable"); 303 static const ConstString g_Dictionary1("__NSSingleEntryDictionaryI"); 304 305 if (class_name.IsEmpty()) 306 return false; 307 308 if (class_name == g_DictionaryI || class_name == g_DictionaryMImmutable) { 309 Status error; 310 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 311 ptr_size, 0, error); 312 if (error.Fail()) 313 return false; 314 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U); 315 } else if (class_name == g_DictionaryM || class_name == g_DictionaryMLegacy) { 316 Status error; 317 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 318 ptr_size, 0, error); 319 if (error.Fail()) 320 return false; 321 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U); 322 } else if (class_name == g_Dictionary1) { 323 value = 1; 324 } 325 /*else if (!strcmp(class_name,"__NSCFDictionary")) 326 { 327 Status error; 328 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + (is_64bit ? 329 20 : 12), 4, 0, error); 330 if (error.Fail()) 331 return false; 332 if (is_64bit) 333 value &= ~0x0f1f000000000000UL; 334 }*/ 335 else { 336 auto &map(NSDictionary_Additionals::GetAdditionalSummaries()); 337 for (auto &candidate : map) { 338 if (candidate.first && candidate.first->Match(class_name)) 339 return candidate.second(valobj, stream, options); 340 } 341 return false; 342 } 343 344 std::string prefix, suffix; 345 if (Language *language = Language::FindPlugin(options.GetLanguage())) { 346 if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix, 347 suffix)) { 348 prefix.clear(); 349 suffix.clear(); 350 } 351 } 352 353 stream.Printf("%s%" PRIu64 " %s%s%s", prefix.c_str(), value, "key/value pair", 354 value == 1 ? "" : "s", suffix.c_str()); 355 return true; 356 } 357 358 SyntheticChildrenFrontEnd * 359 lldb_private::formatters::NSDictionarySyntheticFrontEndCreator( 360 CXXSyntheticChildren *synth, lldb::ValueObjectSP valobj_sp) { 361 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 362 if (!process_sp) 363 return nullptr; 364 AppleObjCRuntime *runtime = 365 llvm::dyn_cast_or_null<AppleObjCRuntime>(process_sp->GetObjCLanguageRuntime()); 366 if (!runtime) 367 return nullptr; 368 369 CompilerType valobj_type(valobj_sp->GetCompilerType()); 370 Flags flags(valobj_type.GetTypeInfo()); 371 372 if (flags.IsClear(eTypeIsPointer)) { 373 Status error; 374 valobj_sp = valobj_sp->AddressOf(error); 375 if (error.Fail() || !valobj_sp) 376 return nullptr; 377 } 378 379 ObjCLanguageRuntime::ClassDescriptorSP descriptor( 380 runtime->GetClassDescriptor(*valobj_sp)); 381 382 if (!descriptor || !descriptor->IsValid()) 383 return nullptr; 384 385 ConstString class_name(descriptor->GetClassName()); 386 387 static const ConstString g_DictionaryI("__NSDictionaryI"); 388 static const ConstString g_DictionaryM("__NSDictionaryM"); 389 static const ConstString g_Dictionary1("__NSSingleEntryDictionaryI"); 390 static const ConstString g_DictionaryImmutable("__NSDictionaryM_Immutable"); 391 static const ConstString g_DictionaryMLegacy("__NSDictionaryM_Legacy"); 392 393 if (class_name.IsEmpty()) 394 return nullptr; 395 396 if (class_name == g_DictionaryI) { 397 return (new NSDictionaryISyntheticFrontEnd(valobj_sp)); 398 } else if (class_name == g_DictionaryM) { 399 if (runtime->GetFoundationVersion() > 1400) { 400 return (new NSDictionaryMSyntheticFrontEnd(valobj_sp)); 401 } else { 402 return (new NSDictionaryMLegacySyntheticFrontEnd(valobj_sp)); 403 } 404 } else if (class_name == g_DictionaryMLegacy) { 405 return (new NSDictionaryMLegacySyntheticFrontEnd(valobj_sp)); 406 } else if (class_name == g_Dictionary1) { 407 return (new NSDictionary1SyntheticFrontEnd(valobj_sp)); 408 } else { 409 auto &map(NSDictionary_Additionals::GetAdditionalSynthetics()); 410 for (auto &candidate : map) { 411 if (candidate.first && candidate.first->Match((class_name))) 412 return candidate.second(synth, valobj_sp); 413 } 414 } 415 416 return nullptr; 417 } 418 419 lldb_private::formatters::NSDictionaryISyntheticFrontEnd:: 420 NSDictionaryISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 421 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8), 422 m_order(lldb::eByteOrderInvalid), m_data_32(nullptr), m_data_64(nullptr), 423 m_pair_type() {} 424 425 lldb_private::formatters::NSDictionaryISyntheticFrontEnd:: 426 ~NSDictionaryISyntheticFrontEnd() { 427 delete m_data_32; 428 m_data_32 = nullptr; 429 delete m_data_64; 430 m_data_64 = nullptr; 431 } 432 433 size_t lldb_private::formatters::NSDictionaryISyntheticFrontEnd:: 434 GetIndexOfChildWithName(const ConstString &name) { 435 const char *item_name = name.GetCString(); 436 uint32_t idx = ExtractIndexFromString(item_name); 437 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 438 return UINT32_MAX; 439 return idx; 440 } 441 442 size_t lldb_private::formatters::NSDictionaryISyntheticFrontEnd:: 443 CalculateNumChildren() { 444 if (!m_data_32 && !m_data_64) 445 return 0; 446 return (m_data_32 ? m_data_32->_used : m_data_64->_used); 447 } 448 449 bool lldb_private::formatters::NSDictionaryISyntheticFrontEnd::Update() { 450 m_children.clear(); 451 delete m_data_32; 452 m_data_32 = nullptr; 453 delete m_data_64; 454 m_data_64 = nullptr; 455 m_ptr_size = 0; 456 ValueObjectSP valobj_sp = m_backend.GetSP(); 457 if (!valobj_sp) 458 return false; 459 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 460 Status error; 461 error.Clear(); 462 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 463 if (!process_sp) 464 return false; 465 m_ptr_size = process_sp->GetAddressByteSize(); 466 m_order = process_sp->GetByteOrder(); 467 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size; 468 if (m_ptr_size == 4) { 469 m_data_32 = new DataDescriptor_32(); 470 process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32), 471 error); 472 } else { 473 m_data_64 = new DataDescriptor_64(); 474 process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64), 475 error); 476 } 477 if (error.Fail()) 478 return false; 479 m_data_ptr = data_location + m_ptr_size; 480 return false; 481 } 482 483 bool lldb_private::formatters::NSDictionaryISyntheticFrontEnd:: 484 MightHaveChildren() { 485 return true; 486 } 487 488 lldb::ValueObjectSP 489 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::GetChildAtIndex( 490 size_t idx) { 491 uint32_t num_children = CalculateNumChildren(); 492 493 if (idx >= num_children) 494 return lldb::ValueObjectSP(); 495 496 if (m_children.empty()) { 497 // do the scan phase 498 lldb::addr_t key_at_idx = 0, val_at_idx = 0; 499 500 uint32_t tries = 0; 501 uint32_t test_idx = 0; 502 503 while (tries < num_children) { 504 key_at_idx = m_data_ptr + (2 * test_idx * m_ptr_size); 505 val_at_idx = key_at_idx + m_ptr_size; 506 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); 507 if (!process_sp) 508 return lldb::ValueObjectSP(); 509 Status error; 510 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error); 511 if (error.Fail()) 512 return lldb::ValueObjectSP(); 513 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error); 514 if (error.Fail()) 515 return lldb::ValueObjectSP(); 516 517 test_idx++; 518 519 if (!key_at_idx || !val_at_idx) 520 continue; 521 tries++; 522 523 DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx, 524 lldb::ValueObjectSP()}; 525 526 m_children.push_back(descriptor); 527 } 528 } 529 530 if (idx >= m_children.size()) // should never happen 531 return lldb::ValueObjectSP(); 532 533 DictionaryItemDescriptor &dict_item = m_children[idx]; 534 if (!dict_item.valobj_sp) { 535 if (!m_pair_type.IsValid()) { 536 TargetSP target_sp(m_backend.GetTargetSP()); 537 if (!target_sp) 538 return ValueObjectSP(); 539 m_pair_type = GetLLDBNSPairType(target_sp); 540 } 541 if (!m_pair_type.IsValid()) 542 return ValueObjectSP(); 543 544 DataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0)); 545 546 if (m_ptr_size == 8) { 547 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes(); 548 *data_ptr = dict_item.key_ptr; 549 *(data_ptr + 1) = dict_item.val_ptr; 550 } else { 551 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes(); 552 *data_ptr = dict_item.key_ptr; 553 *(data_ptr + 1) = dict_item.val_ptr; 554 } 555 556 StreamString idx_name; 557 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); 558 DataExtractor data(buffer_sp, m_order, m_ptr_size); 559 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data, 560 m_exe_ctx_ref, m_pair_type); 561 } 562 return dict_item.valobj_sp; 563 } 564 565 lldb_private::formatters::NSDictionary1SyntheticFrontEnd:: 566 NSDictionary1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 567 : SyntheticChildrenFrontEnd(*valobj_sp.get()), m_pair(nullptr) {} 568 569 size_t lldb_private::formatters::NSDictionary1SyntheticFrontEnd:: 570 GetIndexOfChildWithName(const ConstString &name) { 571 static const ConstString g_zero("[0]"); 572 573 if (name == g_zero) 574 return 0; 575 576 return UINT32_MAX; 577 } 578 579 size_t lldb_private::formatters::NSDictionary1SyntheticFrontEnd:: 580 CalculateNumChildren() { 581 return 1; 582 } 583 584 bool lldb_private::formatters::NSDictionary1SyntheticFrontEnd::Update() { 585 m_pair.reset(); 586 return false; 587 } 588 589 bool lldb_private::formatters::NSDictionary1SyntheticFrontEnd:: 590 MightHaveChildren() { 591 return true; 592 } 593 594 lldb::ValueObjectSP 595 lldb_private::formatters::NSDictionary1SyntheticFrontEnd::GetChildAtIndex( 596 size_t idx) { 597 if (idx != 0) 598 return lldb::ValueObjectSP(); 599 600 if (m_pair.get()) 601 return m_pair; 602 603 auto process_sp(m_backend.GetProcessSP()); 604 if (!process_sp) 605 return nullptr; 606 607 auto ptr_size = process_sp->GetAddressByteSize(); 608 609 lldb::addr_t key_ptr = 610 m_backend.GetValueAsUnsigned(LLDB_INVALID_ADDRESS) + ptr_size; 611 lldb::addr_t value_ptr = key_ptr + ptr_size; 612 613 Status error; 614 615 lldb::addr_t value_at_idx = process_sp->ReadPointerFromMemory(key_ptr, error); 616 if (error.Fail()) 617 return nullptr; 618 lldb::addr_t key_at_idx = process_sp->ReadPointerFromMemory(value_ptr, error); 619 if (error.Fail()) 620 return nullptr; 621 622 auto pair_type = 623 GetLLDBNSPairType(process_sp->GetTarget().shared_from_this()); 624 625 DataBufferSP buffer_sp(new DataBufferHeap(2 * ptr_size, 0)); 626 627 if (ptr_size == 8) { 628 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes(); 629 *data_ptr = key_at_idx; 630 *(data_ptr + 1) = value_at_idx; 631 } else { 632 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes(); 633 *data_ptr = key_at_idx; 634 *(data_ptr + 1) = value_at_idx; 635 } 636 637 DataExtractor data(buffer_sp, process_sp->GetByteOrder(), ptr_size); 638 m_pair = CreateValueObjectFromData( 639 "[0]", data, m_backend.GetExecutionContextRef(), pair_type); 640 641 return m_pair; 642 } 643 644 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd:: 645 NSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 646 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8), 647 m_order(lldb::eByteOrderInvalid), m_data_32(nullptr), m_data_64(nullptr), 648 m_pair_type() {} 649 650 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd:: 651 ~NSDictionaryMSyntheticFrontEnd() { 652 delete m_data_32; 653 m_data_32 = nullptr; 654 delete m_data_64; 655 m_data_64 = nullptr; 656 } 657 658 size_t lldb_private::formatters::NSDictionaryMSyntheticFrontEnd:: 659 GetIndexOfChildWithName(const ConstString &name) { 660 const char *item_name = name.GetCString(); 661 uint32_t idx = ExtractIndexFromString(item_name); 662 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 663 return UINT32_MAX; 664 return idx; 665 } 666 667 size_t lldb_private::formatters::NSDictionaryMSyntheticFrontEnd:: 668 CalculateNumChildren() { 669 if (!m_data_32 && !m_data_64) 670 return 0; 671 return (m_data_32 ? m_data_32->used : m_data_64->used); 672 } 673 674 bool lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::Update() { 675 m_children.clear(); 676 ValueObjectSP valobj_sp = m_backend.GetSP(); 677 m_ptr_size = 0; 678 delete m_data_32; 679 m_data_32 = nullptr; 680 delete m_data_64; 681 m_data_64 = nullptr; 682 if (!valobj_sp) 683 return false; 684 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 685 Status error; 686 error.Clear(); 687 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 688 if (!process_sp) 689 return false; 690 m_ptr_size = process_sp->GetAddressByteSize(); 691 m_order = process_sp->GetByteOrder(); 692 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size; 693 if (m_ptr_size == 4) { 694 m_data_32 = new DataDescriptor_32(); 695 process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32), 696 error); 697 } else { 698 m_data_64 = new DataDescriptor_64(); 699 process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64), 700 error); 701 } 702 if (error.Fail()) 703 return false; 704 return false; 705 } 706 707 bool lldb_private::formatters::NSDictionaryMSyntheticFrontEnd:: 708 MightHaveChildren() { 709 return true; 710 } 711 712 lldb::ValueObjectSP 713 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::GetChildAtIndex( 714 size_t idx) { 715 lldb::addr_t m_keys_ptr; 716 lldb::addr_t m_values_ptr; 717 if (m_data_32) { 718 uint32_t size = m_data_32->size; 719 m_keys_ptr = m_data_32->buffer; 720 m_values_ptr = m_data_32->buffer + (m_ptr_size * size); 721 } else { 722 uint32_t size = m_data_64->size; 723 m_keys_ptr = m_data_64->buffer; 724 m_values_ptr = m_data_64->buffer + (m_ptr_size * size); 725 } 726 727 uint32_t num_children = CalculateNumChildren(); 728 729 if (idx >= num_children) 730 return lldb::ValueObjectSP(); 731 732 if (m_children.empty()) { 733 // do the scan phase 734 lldb::addr_t key_at_idx = 0, val_at_idx = 0; 735 736 uint32_t tries = 0; 737 uint32_t test_idx = 0; 738 739 while (tries < num_children) { 740 key_at_idx = m_keys_ptr + (test_idx * m_ptr_size); 741 val_at_idx = m_values_ptr + (test_idx * m_ptr_size); 742 ; 743 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); 744 if (!process_sp) 745 return lldb::ValueObjectSP(); 746 Status error; 747 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error); 748 if (error.Fail()) 749 return lldb::ValueObjectSP(); 750 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error); 751 if (error.Fail()) 752 return lldb::ValueObjectSP(); 753 754 test_idx++; 755 756 if (!key_at_idx || !val_at_idx) 757 continue; 758 tries++; 759 760 DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx, 761 lldb::ValueObjectSP()}; 762 763 m_children.push_back(descriptor); 764 } 765 } 766 767 if (idx >= m_children.size()) // should never happen 768 return lldb::ValueObjectSP(); 769 770 DictionaryItemDescriptor &dict_item = m_children[idx]; 771 if (!dict_item.valobj_sp) { 772 if (!m_pair_type.IsValid()) { 773 TargetSP target_sp(m_backend.GetTargetSP()); 774 if (!target_sp) 775 return ValueObjectSP(); 776 m_pair_type = GetLLDBNSPairType(target_sp); 777 } 778 if (!m_pair_type.IsValid()) 779 return ValueObjectSP(); 780 781 DataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0)); 782 783 if (m_ptr_size == 8) { 784 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes(); 785 *data_ptr = dict_item.key_ptr; 786 *(data_ptr + 1) = dict_item.val_ptr; 787 } else { 788 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes(); 789 *data_ptr = dict_item.key_ptr; 790 *(data_ptr + 1) = dict_item.val_ptr; 791 } 792 793 StreamString idx_name; 794 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); 795 DataExtractor data(buffer_sp, m_order, m_ptr_size); 796 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data, 797 m_exe_ctx_ref, m_pair_type); 798 } 799 return dict_item.valobj_sp; 800 } 801 802 803 lldb_private::formatters::NSDictionaryMLegacySyntheticFrontEnd:: 804 NSDictionaryMLegacySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 805 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8), 806 m_order(lldb::eByteOrderInvalid), m_data_32(nullptr), m_data_64(nullptr), 807 m_pair_type() {} 808 809 lldb_private::formatters::NSDictionaryMLegacySyntheticFrontEnd:: 810 ~NSDictionaryMLegacySyntheticFrontEnd() { 811 delete m_data_32; 812 m_data_32 = nullptr; 813 delete m_data_64; 814 m_data_64 = nullptr; 815 } 816 817 size_t lldb_private::formatters::NSDictionaryMLegacySyntheticFrontEnd:: 818 GetIndexOfChildWithName(const ConstString &name) { 819 const char *item_name = name.GetCString(); 820 uint32_t idx = ExtractIndexFromString(item_name); 821 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 822 return UINT32_MAX; 823 return idx; 824 } 825 826 size_t lldb_private::formatters::NSDictionaryMLegacySyntheticFrontEnd:: 827 CalculateNumChildren() { 828 if (!m_data_32 && !m_data_64) 829 return 0; 830 return (m_data_32 ? m_data_32->_used : m_data_64->_used); 831 } 832 833 bool lldb_private::formatters::NSDictionaryMLegacySyntheticFrontEnd::Update() { 834 m_children.clear(); 835 ValueObjectSP valobj_sp = m_backend.GetSP(); 836 m_ptr_size = 0; 837 delete m_data_32; 838 m_data_32 = nullptr; 839 delete m_data_64; 840 m_data_64 = nullptr; 841 if (!valobj_sp) 842 return false; 843 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 844 Status error; 845 error.Clear(); 846 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 847 if (!process_sp) 848 return false; 849 m_ptr_size = process_sp->GetAddressByteSize(); 850 m_order = process_sp->GetByteOrder(); 851 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size; 852 if (m_ptr_size == 4) { 853 m_data_32 = new DataDescriptor_32(); 854 process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32), 855 error); 856 } else { 857 m_data_64 = new DataDescriptor_64(); 858 process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64), 859 error); 860 } 861 if (error.Fail()) 862 return false; 863 return false; 864 } 865 866 bool lldb_private::formatters::NSDictionaryMLegacySyntheticFrontEnd:: 867 MightHaveChildren() { 868 return true; 869 } 870 871 lldb::ValueObjectSP 872 lldb_private::formatters::NSDictionaryMLegacySyntheticFrontEnd::GetChildAtIndex( 873 size_t idx) { 874 lldb::addr_t m_keys_ptr = 875 (m_data_32 ? m_data_32->_keys_addr : m_data_64->_keys_addr); 876 lldb::addr_t m_values_ptr = 877 (m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr); 878 879 uint32_t num_children = CalculateNumChildren(); 880 881 if (idx >= num_children) 882 return lldb::ValueObjectSP(); 883 884 if (m_children.empty()) { 885 // do the scan phase 886 lldb::addr_t key_at_idx = 0, val_at_idx = 0; 887 888 uint32_t tries = 0; 889 uint32_t test_idx = 0; 890 891 while (tries < num_children) { 892 key_at_idx = m_keys_ptr + (test_idx * m_ptr_size); 893 val_at_idx = m_values_ptr + (test_idx * m_ptr_size); 894 ; 895 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); 896 if (!process_sp) 897 return lldb::ValueObjectSP(); 898 Status error; 899 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error); 900 if (error.Fail()) 901 return lldb::ValueObjectSP(); 902 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error); 903 if (error.Fail()) 904 return lldb::ValueObjectSP(); 905 906 test_idx++; 907 908 if (!key_at_idx || !val_at_idx) 909 continue; 910 tries++; 911 912 DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx, 913 lldb::ValueObjectSP()}; 914 915 m_children.push_back(descriptor); 916 } 917 } 918 919 if (idx >= m_children.size()) // should never happen 920 return lldb::ValueObjectSP(); 921 922 DictionaryItemDescriptor &dict_item = m_children[idx]; 923 if (!dict_item.valobj_sp) { 924 if (!m_pair_type.IsValid()) { 925 TargetSP target_sp(m_backend.GetTargetSP()); 926 if (!target_sp) 927 return ValueObjectSP(); 928 m_pair_type = GetLLDBNSPairType(target_sp); 929 } 930 if (!m_pair_type.IsValid()) 931 return ValueObjectSP(); 932 933 DataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0)); 934 935 if (m_ptr_size == 8) { 936 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes(); 937 *data_ptr = dict_item.key_ptr; 938 *(data_ptr + 1) = dict_item.val_ptr; 939 } else { 940 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes(); 941 *data_ptr = dict_item.key_ptr; 942 *(data_ptr + 1) = dict_item.val_ptr; 943 } 944 945 StreamString idx_name; 946 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); 947 DataExtractor data(buffer_sp, m_order, m_ptr_size); 948 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data, 949 m_exe_ctx_ref, m_pair_type); 950 } 951 return dict_item.valobj_sp; 952 } 953 954 template bool lldb_private::formatters::NSDictionarySummaryProvider<true>( 955 ValueObject &, Stream &, const TypeSummaryOptions &); 956 957 template bool lldb_private::formatters::NSDictionarySummaryProvider<false>( 958 ValueObject &, Stream &, const TypeSummaryOptions &); 959