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