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