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 } // namespace formatters 194 } // namespace lldb_private 195 196 template<bool name_entries> 197 bool 198 lldb_private::formatters::NSDictionarySummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) 199 { 200 static ConstString g_TypeHint("NSDictionary"); 201 ProcessSP process_sp = valobj.GetProcessSP(); 202 if (!process_sp) 203 return false; 204 205 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 206 207 if (!runtime) 208 return false; 209 210 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 211 212 if (!descriptor.get() || !descriptor->IsValid()) 213 return false; 214 215 uint32_t ptr_size = process_sp->GetAddressByteSize(); 216 bool is_64bit = (ptr_size == 8); 217 218 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 219 220 if (!valobj_addr) 221 return false; 222 223 uint64_t value = 0; 224 225 ConstString class_name_cs = descriptor->GetClassName(); 226 const char* class_name = class_name_cs.GetCString(); 227 228 if (!class_name || !*class_name) 229 return false; 230 231 if (!strcmp(class_name,"__NSDictionaryI")) 232 { 233 Error error; 234 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error); 235 if (error.Fail()) 236 return false; 237 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U); 238 } 239 else if (!strcmp(class_name,"__NSDictionaryM")) 240 { 241 Error error; 242 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error); 243 if (error.Fail()) 244 return false; 245 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U); 246 } 247 /*else if (!strcmp(class_name,"__NSCFDictionary")) 248 { 249 Error error; 250 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + (is_64bit ? 20 : 12), 4, 0, error); 251 if (error.Fail()) 252 return false; 253 if (is_64bit) 254 value &= ~0x0f1f000000000000UL; 255 }*/ 256 else 257 { 258 auto& map(NSDictionary_Additionals::GetAdditionalSummaries()); 259 auto iter = map.find(class_name_cs), end = map.end(); 260 if (iter != end) 261 return iter->second(valobj, stream, options); 262 else 263 return false; 264 } 265 266 std::string prefix,suffix; 267 if (Language* language = Language::FindPlugin(options.GetLanguage())) 268 { 269 if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix, suffix)) 270 { 271 prefix.clear(); 272 suffix.clear(); 273 } 274 } 275 276 stream.Printf("%s%" PRIu64 " %s%s%s", 277 prefix.c_str(), 278 value, 279 "key/value pair", 280 value == 1 ? "" : "s", 281 suffix.c_str()); 282 return true; 283 } 284 285 SyntheticChildrenFrontEnd* lldb_private::formatters::NSDictionarySyntheticFrontEndCreator (CXXSyntheticChildren* synth, lldb::ValueObjectSP valobj_sp) 286 { 287 lldb::ProcessSP process_sp (valobj_sp->GetProcessSP()); 288 if (!process_sp) 289 return NULL; 290 ObjCLanguageRuntime *runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 291 if (!runtime) 292 return NULL; 293 294 CompilerType valobj_type(valobj_sp->GetCompilerType()); 295 Flags flags(valobj_type.GetTypeInfo()); 296 297 if (flags.IsClear(eTypeIsPointer)) 298 { 299 Error error; 300 valobj_sp = valobj_sp->AddressOf(error); 301 if (error.Fail() || !valobj_sp) 302 return NULL; 303 } 304 305 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(*valobj_sp.get())); 306 307 if (!descriptor.get() || !descriptor->IsValid()) 308 return NULL; 309 310 ConstString class_name_cs = descriptor->GetClassName(); 311 const char* class_name = class_name_cs.GetCString(); 312 313 if (!class_name || !*class_name) 314 return NULL; 315 316 if (!strcmp(class_name,"__NSDictionaryI")) 317 { 318 return (new NSDictionaryISyntheticFrontEnd(valobj_sp)); 319 } 320 else if (!strcmp(class_name,"__NSDictionaryM")) 321 { 322 return (new NSDictionaryMSyntheticFrontEnd(valobj_sp)); 323 } 324 else 325 { 326 auto& map(NSDictionary_Additionals::GetAdditionalSynthetics()); 327 auto iter = map.find(class_name_cs), end = map.end(); 328 if (iter != end) 329 return iter->second(synth, valobj_sp); 330 } 331 332 return nullptr; 333 } 334 335 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::NSDictionaryISyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) : 336 SyntheticChildrenFrontEnd(*valobj_sp.get()), 337 m_exe_ctx_ref(), 338 m_ptr_size(8), 339 m_order(lldb::eByteOrderInvalid), 340 m_data_32(NULL), 341 m_data_64(NULL), 342 m_pair_type() 343 { 344 } 345 346 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::~NSDictionaryISyntheticFrontEnd () 347 { 348 delete m_data_32; 349 m_data_32 = NULL; 350 delete m_data_64; 351 m_data_64 = NULL; 352 } 353 354 size_t 355 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name) 356 { 357 const char* item_name = name.GetCString(); 358 uint32_t idx = ExtractIndexFromString(item_name); 359 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 360 return UINT32_MAX; 361 return idx; 362 } 363 364 size_t 365 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::CalculateNumChildren () 366 { 367 if (!m_data_32 && !m_data_64) 368 return 0; 369 return (m_data_32 ? m_data_32->_used : m_data_64->_used); 370 } 371 372 bool 373 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::Update() 374 { 375 m_children.clear(); 376 delete m_data_32; 377 m_data_32 = NULL; 378 delete m_data_64; 379 m_data_64 = NULL; 380 m_ptr_size = 0; 381 ValueObjectSP valobj_sp = m_backend.GetSP(); 382 if (!valobj_sp) 383 return false; 384 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 385 Error error; 386 error.Clear(); 387 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 388 if (!process_sp) 389 return false; 390 m_ptr_size = process_sp->GetAddressByteSize(); 391 m_order = process_sp->GetByteOrder(); 392 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size; 393 if (m_ptr_size == 4) 394 { 395 m_data_32 = new DataDescriptor_32(); 396 process_sp->ReadMemory (data_location, m_data_32, sizeof(DataDescriptor_32), error); 397 } 398 else 399 { 400 m_data_64 = new DataDescriptor_64(); 401 process_sp->ReadMemory (data_location, m_data_64, sizeof(DataDescriptor_64), error); 402 } 403 if (error.Fail()) 404 return false; 405 m_data_ptr = data_location + m_ptr_size; 406 return false; 407 } 408 409 bool 410 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::MightHaveChildren () 411 { 412 return true; 413 } 414 415 lldb::ValueObjectSP 416 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::GetChildAtIndex (size_t idx) 417 { 418 uint32_t num_children = CalculateNumChildren(); 419 420 if (idx >= num_children) 421 return lldb::ValueObjectSP(); 422 423 if (m_children.empty()) 424 { 425 // do the scan phase 426 lldb::addr_t key_at_idx = 0, val_at_idx = 0; 427 428 uint32_t tries = 0; 429 uint32_t test_idx = 0; 430 431 while(tries < num_children) 432 { 433 key_at_idx = m_data_ptr + (2*test_idx * m_ptr_size); 434 val_at_idx = key_at_idx + m_ptr_size; 435 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); 436 if (!process_sp) 437 return lldb::ValueObjectSP(); 438 Error error; 439 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error); 440 if (error.Fail()) 441 return lldb::ValueObjectSP(); 442 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error); 443 if (error.Fail()) 444 return lldb::ValueObjectSP(); 445 446 test_idx++; 447 448 if (!key_at_idx || !val_at_idx) 449 continue; 450 tries++; 451 452 DictionaryItemDescriptor descriptor = {key_at_idx,val_at_idx,lldb::ValueObjectSP()}; 453 454 m_children.push_back(descriptor); 455 } 456 } 457 458 if (idx >= m_children.size()) // should never happen 459 return lldb::ValueObjectSP(); 460 461 DictionaryItemDescriptor &dict_item = m_children[idx]; 462 if (!dict_item.valobj_sp) 463 { 464 if (!m_pair_type.IsValid()) 465 { 466 TargetSP target_sp(m_backend.GetTargetSP()); 467 if (!target_sp) 468 return ValueObjectSP(); 469 m_pair_type = GetLLDBNSPairType(target_sp); 470 } 471 if (!m_pair_type.IsValid()) 472 return ValueObjectSP(); 473 474 DataBufferSP buffer_sp(new DataBufferHeap(2*m_ptr_size,0)); 475 476 if (m_ptr_size == 8) 477 { 478 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes(); 479 *data_ptr = dict_item.key_ptr; 480 *(data_ptr+1) = dict_item.val_ptr; 481 } 482 else 483 { 484 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes(); 485 *data_ptr = dict_item.key_ptr; 486 *(data_ptr+1) = dict_item.val_ptr; 487 } 488 489 StreamString idx_name; 490 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); 491 DataExtractor data(buffer_sp, m_order, m_ptr_size); 492 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetData(), 493 data, 494 m_exe_ctx_ref, 495 m_pair_type); 496 } 497 return dict_item.valobj_sp; 498 } 499 500 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::NSDictionaryMSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) : 501 SyntheticChildrenFrontEnd(*valobj_sp.get()), 502 m_exe_ctx_ref(), 503 m_ptr_size(8), 504 m_order(lldb::eByteOrderInvalid), 505 m_data_32(NULL), 506 m_data_64(NULL), 507 m_pair_type() 508 { 509 } 510 511 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::~NSDictionaryMSyntheticFrontEnd () 512 { 513 delete m_data_32; 514 m_data_32 = NULL; 515 delete m_data_64; 516 m_data_64 = NULL; 517 } 518 519 size_t 520 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name) 521 { 522 const char* item_name = name.GetCString(); 523 uint32_t idx = ExtractIndexFromString(item_name); 524 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 525 return UINT32_MAX; 526 return idx; 527 } 528 529 size_t 530 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::CalculateNumChildren () 531 { 532 if (!m_data_32 && !m_data_64) 533 return 0; 534 return (m_data_32 ? m_data_32->_used : m_data_64->_used); 535 } 536 537 bool 538 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::Update() 539 { 540 m_children.clear(); 541 ValueObjectSP valobj_sp = m_backend.GetSP(); 542 m_ptr_size = 0; 543 delete m_data_32; 544 m_data_32 = NULL; 545 delete m_data_64; 546 m_data_64 = NULL; 547 if (!valobj_sp) 548 return false; 549 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 550 Error error; 551 error.Clear(); 552 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 553 if (!process_sp) 554 return false; 555 m_ptr_size = process_sp->GetAddressByteSize(); 556 m_order = process_sp->GetByteOrder(); 557 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size; 558 if (m_ptr_size == 4) 559 { 560 m_data_32 = new DataDescriptor_32(); 561 process_sp->ReadMemory (data_location, m_data_32, sizeof(DataDescriptor_32), error); 562 } 563 else 564 { 565 m_data_64 = new DataDescriptor_64(); 566 process_sp->ReadMemory (data_location, m_data_64, sizeof(DataDescriptor_64), error); 567 } 568 if (error.Fail()) 569 return false; 570 return false; 571 } 572 573 bool 574 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::MightHaveChildren () 575 { 576 return true; 577 } 578 579 lldb::ValueObjectSP 580 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::GetChildAtIndex (size_t idx) 581 { 582 lldb::addr_t m_keys_ptr = (m_data_32 ? m_data_32->_keys_addr : m_data_64->_keys_addr); 583 lldb::addr_t m_values_ptr = (m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr); 584 585 uint32_t num_children = CalculateNumChildren(); 586 587 if (idx >= num_children) 588 return lldb::ValueObjectSP(); 589 590 if (m_children.empty()) 591 { 592 // do the scan phase 593 lldb::addr_t key_at_idx = 0, val_at_idx = 0; 594 595 uint32_t tries = 0; 596 uint32_t test_idx = 0; 597 598 while(tries < num_children) 599 { 600 key_at_idx = m_keys_ptr + (test_idx * m_ptr_size); 601 val_at_idx = m_values_ptr + (test_idx * m_ptr_size);; 602 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); 603 if (!process_sp) 604 return lldb::ValueObjectSP(); 605 Error error; 606 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error); 607 if (error.Fail()) 608 return lldb::ValueObjectSP(); 609 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error); 610 if (error.Fail()) 611 return lldb::ValueObjectSP(); 612 613 test_idx++; 614 615 if (!key_at_idx || !val_at_idx) 616 continue; 617 tries++; 618 619 DictionaryItemDescriptor descriptor = {key_at_idx,val_at_idx,lldb::ValueObjectSP()}; 620 621 m_children.push_back(descriptor); 622 } 623 } 624 625 if (idx >= m_children.size()) // should never happen 626 return lldb::ValueObjectSP(); 627 628 DictionaryItemDescriptor &dict_item = m_children[idx]; 629 if (!dict_item.valobj_sp) 630 { 631 if (!m_pair_type.IsValid()) 632 { 633 TargetSP target_sp(m_backend.GetTargetSP()); 634 if (!target_sp) 635 return ValueObjectSP(); 636 m_pair_type = GetLLDBNSPairType(target_sp); 637 } 638 if (!m_pair_type.IsValid()) 639 return ValueObjectSP(); 640 641 DataBufferSP buffer_sp(new DataBufferHeap(2*m_ptr_size,0)); 642 643 if (m_ptr_size == 8) 644 { 645 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes(); 646 *data_ptr = dict_item.key_ptr; 647 *(data_ptr+1) = dict_item.val_ptr; 648 } 649 else 650 { 651 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes(); 652 *data_ptr = dict_item.key_ptr; 653 *(data_ptr+1) = dict_item.val_ptr; 654 } 655 656 StreamString idx_name; 657 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); 658 DataExtractor data(buffer_sp, m_order, m_ptr_size); 659 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetData(), 660 data, 661 m_exe_ctx_ref, 662 m_pair_type); 663 } 664 return dict_item.valobj_sp; 665 } 666 667 template bool 668 lldb_private::formatters::NSDictionarySummaryProvider<true> (ValueObject&, Stream&, const TypeSummaryOptions&); 669 670 template bool 671 lldb_private::formatters::NSDictionarySummaryProvider<false> (ValueObject&, Stream&, const TypeSummaryOptions&); 672