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