1 //===-- NSDictionary.cpp ----------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 // C Includes 11 // C++ Includes 12 #include <mutex> 13 14 // Other libraries and framework includes 15 #include "clang/AST/DeclCXX.h" 16 17 // Project includes 18 #include "NSDictionary.h" 19 20 #include "lldb/Core/DataBufferHeap.h" 21 #include "lldb/Core/Error.h" 22 #include "lldb/Core/Stream.h" 23 #include "lldb/Core/ValueObject.h" 24 #include "lldb/Core/ValueObjectConstResult.h" 25 #include "lldb/DataFormatters/FormattersHelpers.h" 26 #include "lldb/Host/Endian.h" 27 #include "lldb/Symbol/ClangASTContext.h" 28 #include "lldb/Target/Language.h" 29 #include "lldb/Target/ObjCLanguageRuntime.h" 30 #include "lldb/Target/Target.h" 31 32 using namespace lldb; 33 using namespace lldb_private; 34 using namespace lldb_private::formatters; 35 36 std::map<ConstString, CXXFunctionSummaryFormat::Callback>& 37 NSDictionary_Additionals::GetAdditionalSummaries () 38 { 39 static std::map<ConstString, CXXFunctionSummaryFormat::Callback> g_map; 40 return g_map; 41 } 42 43 std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback>& 44 NSDictionary_Additionals::GetAdditionalSynthetics () 45 { 46 static std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback> g_map; 47 return g_map; 48 } 49 50 static CompilerType 51 GetLLDBNSPairType (TargetSP target_sp) 52 { 53 CompilerType compiler_type; 54 55 ClangASTContext *target_ast_context = target_sp->GetScratchClangASTContext(); 56 57 if (target_ast_context) 58 { 59 ConstString g___lldb_autogen_nspair("__lldb_autogen_nspair"); 60 61 compiler_type = target_ast_context->GetTypeForIdentifier<clang::CXXRecordDecl>(g___lldb_autogen_nspair); 62 63 if (!compiler_type) 64 { 65 compiler_type = target_ast_context->CreateRecordType(NULL, lldb::eAccessPublic, g___lldb_autogen_nspair.GetCString(), clang::TTK_Struct, lldb::eLanguageTypeC); 66 67 if (compiler_type) 68 { 69 ClangASTContext::StartTagDeclarationDefinition(compiler_type); 70 CompilerType id_compiler_type = target_ast_context->GetBasicType (eBasicTypeObjCID); 71 ClangASTContext::AddFieldToRecordType(compiler_type, "key", id_compiler_type, lldb::eAccessPublic, 0); 72 ClangASTContext::AddFieldToRecordType(compiler_type, "value", id_compiler_type, lldb::eAccessPublic, 0); 73 ClangASTContext::CompleteTagDeclarationDefinition(compiler_type); 74 } 75 } 76 } 77 return compiler_type; 78 } 79 80 namespace lldb_private { 81 namespace formatters { 82 class NSDictionaryISyntheticFrontEnd : public SyntheticChildrenFrontEnd 83 { 84 public: 85 NSDictionaryISyntheticFrontEnd (lldb::ValueObjectSP valobj_sp); 86 87 ~NSDictionaryISyntheticFrontEnd() override; 88 89 size_t 90 CalculateNumChildren() override; 91 92 lldb::ValueObjectSP 93 GetChildAtIndex(size_t idx) override; 94 95 bool 96 Update() override; 97 98 bool 99 MightHaveChildren() override; 100 101 size_t 102 GetIndexOfChildWithName(const ConstString &name) override; 103 104 private: 105 struct DataDescriptor_32 106 { 107 uint32_t _used : 26; 108 uint32_t _szidx : 6; 109 }; 110 111 struct DataDescriptor_64 112 { 113 uint64_t _used : 58; 114 uint32_t _szidx : 6; 115 }; 116 117 struct DictionaryItemDescriptor 118 { 119 lldb::addr_t key_ptr; 120 lldb::addr_t val_ptr; 121 lldb::ValueObjectSP valobj_sp; 122 }; 123 124 ExecutionContextRef m_exe_ctx_ref; 125 uint8_t m_ptr_size; 126 lldb::ByteOrder m_order; 127 DataDescriptor_32 *m_data_32; 128 DataDescriptor_64 *m_data_64; 129 lldb::addr_t m_data_ptr; 130 CompilerType m_pair_type; 131 std::vector<DictionaryItemDescriptor> m_children; 132 }; 133 134 class NSDictionaryMSyntheticFrontEnd : public SyntheticChildrenFrontEnd 135 { 136 public: 137 NSDictionaryMSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp); 138 139 ~NSDictionaryMSyntheticFrontEnd() override; 140 141 size_t 142 CalculateNumChildren() override; 143 144 lldb::ValueObjectSP 145 GetChildAtIndex(size_t idx) override; 146 147 bool 148 Update() override; 149 150 bool 151 MightHaveChildren() override; 152 153 size_t 154 GetIndexOfChildWithName(const ConstString &name) override; 155 156 private: 157 struct DataDescriptor_32 158 { 159 uint32_t _used : 26; 160 uint32_t _kvo : 1; 161 uint32_t _size; 162 uint32_t _mutations; 163 uint32_t _objs_addr; 164 uint32_t _keys_addr; 165 }; 166 167 struct DataDescriptor_64 168 { 169 uint64_t _used : 58; 170 uint32_t _kvo : 1; 171 uint64_t _size; 172 uint64_t _mutations; 173 uint64_t _objs_addr; 174 uint64_t _keys_addr; 175 }; 176 177 struct DictionaryItemDescriptor 178 { 179 lldb::addr_t key_ptr; 180 lldb::addr_t val_ptr; 181 lldb::ValueObjectSP valobj_sp; 182 }; 183 184 ExecutionContextRef m_exe_ctx_ref; 185 uint8_t m_ptr_size; 186 lldb::ByteOrder m_order; 187 DataDescriptor_32 *m_data_32; 188 DataDescriptor_64 *m_data_64; 189 CompilerType m_pair_type; 190 std::vector<DictionaryItemDescriptor> m_children; 191 }; 192 193 class NSDictionaryCodeRunningSyntheticFrontEnd : public SyntheticChildrenFrontEnd 194 { 195 public: 196 NSDictionaryCodeRunningSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp); 197 198 ~NSDictionaryCodeRunningSyntheticFrontEnd() override = default; 199 200 size_t 201 CalculateNumChildren() override; 202 203 lldb::ValueObjectSP 204 GetChildAtIndex(size_t idx) override; 205 206 bool 207 Update() override; 208 209 bool 210 MightHaveChildren() override; 211 212 size_t 213 GetIndexOfChildWithName(const ConstString &name) override; 214 }; 215 } // namespace formatters 216 } // namespace lldb_private 217 218 template<bool name_entries> 219 bool 220 lldb_private::formatters::NSDictionarySummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) 221 { 222 static ConstString g_TypeHint("NSDictionary"); 223 ProcessSP process_sp = valobj.GetProcessSP(); 224 if (!process_sp) 225 return false; 226 227 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 228 229 if (!runtime) 230 return false; 231 232 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 233 234 if (!descriptor.get() || !descriptor->IsValid()) 235 return false; 236 237 uint32_t ptr_size = process_sp->GetAddressByteSize(); 238 bool is_64bit = (ptr_size == 8); 239 240 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 241 242 if (!valobj_addr) 243 return false; 244 245 uint64_t value = 0; 246 247 ConstString class_name_cs = descriptor->GetClassName(); 248 const char* class_name = class_name_cs.GetCString(); 249 250 if (!class_name || !*class_name) 251 return false; 252 253 if (!strcmp(class_name,"__NSDictionaryI")) 254 { 255 Error error; 256 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error); 257 if (error.Fail()) 258 return false; 259 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U); 260 } 261 else if (!strcmp(class_name,"__NSDictionaryM")) 262 { 263 Error error; 264 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error); 265 if (error.Fail()) 266 return false; 267 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U); 268 } 269 /*else if (!strcmp(class_name,"__NSCFDictionary")) 270 { 271 Error error; 272 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + (is_64bit ? 20 : 12), 4, 0, error); 273 if (error.Fail()) 274 return false; 275 if (is_64bit) 276 value &= ~0x0f1f000000000000UL; 277 }*/ 278 else 279 { 280 auto& map(NSDictionary_Additionals::GetAdditionalSummaries()); 281 auto iter = map.find(class_name_cs), end = map.end(); 282 if (iter != end) 283 return iter->second(valobj, stream, options); 284 if (!ExtractValueFromObjCExpression(valobj, "int", "count", value)) 285 return false; 286 } 287 288 std::string prefix,suffix; 289 if (Language* language = Language::FindPlugin(options.GetLanguage())) 290 { 291 if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix, suffix)) 292 { 293 prefix.clear(); 294 suffix.clear(); 295 } 296 } 297 298 stream.Printf("%s%" PRIu64 " %s%s%s", 299 prefix.c_str(), 300 value, 301 "key/value pair", 302 value == 1 ? "" : "s", 303 suffix.c_str()); 304 return true; 305 } 306 307 SyntheticChildrenFrontEnd* lldb_private::formatters::NSDictionarySyntheticFrontEndCreator (CXXSyntheticChildren* synth, lldb::ValueObjectSP valobj_sp) 308 { 309 lldb::ProcessSP process_sp (valobj_sp->GetProcessSP()); 310 if (!process_sp) 311 return NULL; 312 ObjCLanguageRuntime *runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 313 if (!runtime) 314 return NULL; 315 316 CompilerType valobj_type(valobj_sp->GetCompilerType()); 317 Flags flags(valobj_type.GetTypeInfo()); 318 319 if (flags.IsClear(eTypeIsPointer)) 320 { 321 Error error; 322 valobj_sp = valobj_sp->AddressOf(error); 323 if (error.Fail() || !valobj_sp) 324 return NULL; 325 } 326 327 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(*valobj_sp.get())); 328 329 if (!descriptor.get() || !descriptor->IsValid()) 330 return NULL; 331 332 ConstString class_name_cs = descriptor->GetClassName(); 333 const char* class_name = class_name_cs.GetCString(); 334 335 if (!class_name || !*class_name) 336 return NULL; 337 338 if (!strcmp(class_name,"__NSDictionaryI")) 339 { 340 return (new NSDictionaryISyntheticFrontEnd(valobj_sp)); 341 } 342 else if (!strcmp(class_name,"__NSDictionaryM")) 343 { 344 return (new NSDictionaryMSyntheticFrontEnd(valobj_sp)); 345 } 346 else 347 { 348 auto& map(NSDictionary_Additionals::GetAdditionalSynthetics()); 349 auto iter = map.find(class_name_cs), end = map.end(); 350 if (iter != end) 351 return iter->second(synth, valobj_sp); 352 return (new NSDictionaryCodeRunningSyntheticFrontEnd(valobj_sp)); 353 } 354 } 355 356 lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::NSDictionaryCodeRunningSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) : 357 SyntheticChildrenFrontEnd(*valobj_sp.get()) 358 {} 359 360 size_t 361 lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::CalculateNumChildren () 362 { 363 uint64_t count = 0; 364 if (ExtractValueFromObjCExpression(m_backend, "int", "count", count)) 365 return count; 366 return 0; 367 } 368 369 lldb::ValueObjectSP 370 lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::GetChildAtIndex (size_t idx) 371 { 372 StreamString idx_name; 373 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); 374 StreamString key_fetcher_expr; 375 key_fetcher_expr.Printf("(id)[(NSArray*)[(id)0x%" PRIx64 " allKeys] objectAtIndex:%" PRIu64 "]", m_backend.GetPointerValue(), (uint64_t)idx); 376 StreamString value_fetcher_expr; 377 value_fetcher_expr.Printf("(id)[(id)0x%" PRIx64 " objectForKey:(%s)]",m_backend.GetPointerValue(),key_fetcher_expr.GetData()); 378 StreamString object_fetcher_expr; 379 object_fetcher_expr.Printf("struct __lldb_autogen_nspair { id key; id value; } _lldb_valgen_item; _lldb_valgen_item.key = %s; _lldb_valgen_item.value = %s; _lldb_valgen_item;",key_fetcher_expr.GetData(),value_fetcher_expr.GetData()); 380 lldb::ValueObjectSP child_sp; 381 EvaluateExpressionOptions options; 382 options.SetKeepInMemory(true); 383 options.SetLanguage(lldb::eLanguageTypeObjC_plus_plus); 384 options.SetResultIsInternal(true); 385 m_backend.GetTargetSP()->EvaluateExpression(object_fetcher_expr.GetData(), 386 GetViableFrame(m_backend.GetTargetSP().get()), 387 child_sp, 388 options); 389 if (child_sp) 390 child_sp->SetName(ConstString(idx_name.GetData())); 391 return child_sp; 392 } 393 394 bool 395 lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::Update() 396 { 397 return false; 398 } 399 400 bool 401 lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::MightHaveChildren () 402 { 403 return true; 404 } 405 406 size_t 407 lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name) 408 { 409 return 0; 410 } 411 412 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::NSDictionaryISyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) : 413 SyntheticChildrenFrontEnd(*valobj_sp.get()), 414 m_exe_ctx_ref(), 415 m_ptr_size(8), 416 m_order(lldb::eByteOrderInvalid), 417 m_data_32(NULL), 418 m_data_64(NULL), 419 m_pair_type() 420 { 421 } 422 423 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::~NSDictionaryISyntheticFrontEnd () 424 { 425 delete m_data_32; 426 m_data_32 = NULL; 427 delete m_data_64; 428 m_data_64 = NULL; 429 } 430 431 size_t 432 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name) 433 { 434 const char* item_name = name.GetCString(); 435 uint32_t idx = ExtractIndexFromString(item_name); 436 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 437 return UINT32_MAX; 438 return idx; 439 } 440 441 size_t 442 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::CalculateNumChildren () 443 { 444 if (!m_data_32 && !m_data_64) 445 return 0; 446 return (m_data_32 ? m_data_32->_used : m_data_64->_used); 447 } 448 449 bool 450 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::Update() 451 { 452 m_children.clear(); 453 delete m_data_32; 454 m_data_32 = NULL; 455 delete m_data_64; 456 m_data_64 = NULL; 457 m_ptr_size = 0; 458 ValueObjectSP valobj_sp = m_backend.GetSP(); 459 if (!valobj_sp) 460 return false; 461 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 462 Error error; 463 error.Clear(); 464 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 465 if (!process_sp) 466 return false; 467 m_ptr_size = process_sp->GetAddressByteSize(); 468 m_order = process_sp->GetByteOrder(); 469 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size; 470 if (m_ptr_size == 4) 471 { 472 m_data_32 = new DataDescriptor_32(); 473 process_sp->ReadMemory (data_location, m_data_32, sizeof(DataDescriptor_32), error); 474 } 475 else 476 { 477 m_data_64 = new DataDescriptor_64(); 478 process_sp->ReadMemory (data_location, m_data_64, sizeof(DataDescriptor_64), error); 479 } 480 if (error.Fail()) 481 return false; 482 m_data_ptr = data_location + m_ptr_size; 483 return false; 484 } 485 486 bool 487 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::MightHaveChildren () 488 { 489 return true; 490 } 491 492 lldb::ValueObjectSP 493 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::GetChildAtIndex (size_t idx) 494 { 495 uint32_t num_children = CalculateNumChildren(); 496 497 if (idx >= num_children) 498 return lldb::ValueObjectSP(); 499 500 if (m_children.empty()) 501 { 502 // do the scan phase 503 lldb::addr_t key_at_idx = 0, val_at_idx = 0; 504 505 uint32_t tries = 0; 506 uint32_t test_idx = 0; 507 508 while(tries < num_children) 509 { 510 key_at_idx = m_data_ptr + (2*test_idx * m_ptr_size); 511 val_at_idx = key_at_idx + m_ptr_size; 512 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); 513 if (!process_sp) 514 return lldb::ValueObjectSP(); 515 Error error; 516 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error); 517 if (error.Fail()) 518 return lldb::ValueObjectSP(); 519 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error); 520 if (error.Fail()) 521 return lldb::ValueObjectSP(); 522 523 test_idx++; 524 525 if (!key_at_idx || !val_at_idx) 526 continue; 527 tries++; 528 529 DictionaryItemDescriptor descriptor = {key_at_idx,val_at_idx,lldb::ValueObjectSP()}; 530 531 m_children.push_back(descriptor); 532 } 533 } 534 535 if (idx >= m_children.size()) // should never happen 536 return lldb::ValueObjectSP(); 537 538 DictionaryItemDescriptor &dict_item = m_children[idx]; 539 if (!dict_item.valobj_sp) 540 { 541 if (!m_pair_type.IsValid()) 542 { 543 TargetSP target_sp(m_backend.GetTargetSP()); 544 if (!target_sp) 545 return ValueObjectSP(); 546 m_pair_type = GetLLDBNSPairType(target_sp); 547 } 548 if (!m_pair_type.IsValid()) 549 return ValueObjectSP(); 550 551 DataBufferSP buffer_sp(new DataBufferHeap(2*m_ptr_size,0)); 552 553 if (m_ptr_size == 8) 554 { 555 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes(); 556 *data_ptr = dict_item.key_ptr; 557 *(data_ptr+1) = dict_item.val_ptr; 558 } 559 else 560 { 561 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes(); 562 *data_ptr = dict_item.key_ptr; 563 *(data_ptr+1) = dict_item.val_ptr; 564 } 565 566 StreamString idx_name; 567 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); 568 DataExtractor data(buffer_sp, m_order, m_ptr_size); 569 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetData(), 570 data, 571 m_exe_ctx_ref, 572 m_pair_type); 573 } 574 return dict_item.valobj_sp; 575 } 576 577 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::NSDictionaryMSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) : 578 SyntheticChildrenFrontEnd(*valobj_sp.get()), 579 m_exe_ctx_ref(), 580 m_ptr_size(8), 581 m_order(lldb::eByteOrderInvalid), 582 m_data_32(NULL), 583 m_data_64(NULL), 584 m_pair_type() 585 { 586 } 587 588 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::~NSDictionaryMSyntheticFrontEnd () 589 { 590 delete m_data_32; 591 m_data_32 = NULL; 592 delete m_data_64; 593 m_data_64 = NULL; 594 } 595 596 size_t 597 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name) 598 { 599 const char* item_name = name.GetCString(); 600 uint32_t idx = ExtractIndexFromString(item_name); 601 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 602 return UINT32_MAX; 603 return idx; 604 } 605 606 size_t 607 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::CalculateNumChildren () 608 { 609 if (!m_data_32 && !m_data_64) 610 return 0; 611 return (m_data_32 ? m_data_32->_used : m_data_64->_used); 612 } 613 614 bool 615 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::Update() 616 { 617 m_children.clear(); 618 ValueObjectSP valobj_sp = m_backend.GetSP(); 619 m_ptr_size = 0; 620 delete m_data_32; 621 m_data_32 = NULL; 622 delete m_data_64; 623 m_data_64 = NULL; 624 if (!valobj_sp) 625 return false; 626 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 627 Error error; 628 error.Clear(); 629 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 630 if (!process_sp) 631 return false; 632 m_ptr_size = process_sp->GetAddressByteSize(); 633 m_order = process_sp->GetByteOrder(); 634 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size; 635 if (m_ptr_size == 4) 636 { 637 m_data_32 = new DataDescriptor_32(); 638 process_sp->ReadMemory (data_location, m_data_32, sizeof(DataDescriptor_32), error); 639 } 640 else 641 { 642 m_data_64 = new DataDescriptor_64(); 643 process_sp->ReadMemory (data_location, m_data_64, sizeof(DataDescriptor_64), error); 644 } 645 if (error.Fail()) 646 return false; 647 return false; 648 } 649 650 bool 651 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::MightHaveChildren () 652 { 653 return true; 654 } 655 656 lldb::ValueObjectSP 657 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::GetChildAtIndex (size_t idx) 658 { 659 lldb::addr_t m_keys_ptr = (m_data_32 ? m_data_32->_keys_addr : m_data_64->_keys_addr); 660 lldb::addr_t m_values_ptr = (m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr); 661 662 uint32_t num_children = CalculateNumChildren(); 663 664 if (idx >= num_children) 665 return lldb::ValueObjectSP(); 666 667 if (m_children.empty()) 668 { 669 // do the scan phase 670 lldb::addr_t key_at_idx = 0, val_at_idx = 0; 671 672 uint32_t tries = 0; 673 uint32_t test_idx = 0; 674 675 while(tries < num_children) 676 { 677 key_at_idx = m_keys_ptr + (test_idx * m_ptr_size); 678 val_at_idx = m_values_ptr + (test_idx * m_ptr_size);; 679 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); 680 if (!process_sp) 681 return lldb::ValueObjectSP(); 682 Error error; 683 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error); 684 if (error.Fail()) 685 return lldb::ValueObjectSP(); 686 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error); 687 if (error.Fail()) 688 return lldb::ValueObjectSP(); 689 690 test_idx++; 691 692 if (!key_at_idx || !val_at_idx) 693 continue; 694 tries++; 695 696 DictionaryItemDescriptor descriptor = {key_at_idx,val_at_idx,lldb::ValueObjectSP()}; 697 698 m_children.push_back(descriptor); 699 } 700 } 701 702 if (idx >= m_children.size()) // should never happen 703 return lldb::ValueObjectSP(); 704 705 DictionaryItemDescriptor &dict_item = m_children[idx]; 706 if (!dict_item.valobj_sp) 707 { 708 if (!m_pair_type.IsValid()) 709 { 710 TargetSP target_sp(m_backend.GetTargetSP()); 711 if (!target_sp) 712 return ValueObjectSP(); 713 m_pair_type = GetLLDBNSPairType(target_sp); 714 } 715 if (!m_pair_type.IsValid()) 716 return ValueObjectSP(); 717 718 DataBufferSP buffer_sp(new DataBufferHeap(2*m_ptr_size,0)); 719 720 if (m_ptr_size == 8) 721 { 722 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes(); 723 *data_ptr = dict_item.key_ptr; 724 *(data_ptr+1) = dict_item.val_ptr; 725 } 726 else 727 { 728 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes(); 729 *data_ptr = dict_item.key_ptr; 730 *(data_ptr+1) = dict_item.val_ptr; 731 } 732 733 StreamString idx_name; 734 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); 735 DataExtractor data(buffer_sp, m_order, m_ptr_size); 736 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetData(), 737 data, 738 m_exe_ctx_ref, 739 m_pair_type); 740 } 741 return dict_item.valobj_sp; 742 } 743 744 template bool 745 lldb_private::formatters::NSDictionarySummaryProvider<true> (ValueObject&, Stream&, const TypeSummaryOptions&); 746 747 template bool 748 lldb_private::formatters::NSDictionarySummaryProvider<false> (ValueObject&, Stream&, const TypeSummaryOptions&); 749