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