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