805 lines · cpp
1//===-- NSSet.cpp ---------------------------------------------------------===//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-exception6//7//===----------------------------------------------------------------------===//8 9#include "NSSet.h"10#include "CFBasicHash.h"11 12#include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h"13#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"14#include "lldb/DataFormatters/FormattersHelpers.h"15#include "lldb/Target/Language.h"16#include "lldb/Target/Target.h"17#include "lldb/Utility/DataBufferHeap.h"18#include "lldb/Utility/Endian.h"19#include "lldb/Utility/Status.h"20#include "lldb/Utility/Stream.h"21#include "lldb/ValueObject/ValueObject.h"22#include "lldb/ValueObject/ValueObjectConstResult.h"23 24using namespace lldb;25using namespace lldb_private;26using namespace lldb_private::formatters;27 28std::map<ConstString, CXXFunctionSummaryFormat::Callback> &29NSSet_Additionals::GetAdditionalSummaries() {30 static std::map<ConstString, CXXFunctionSummaryFormat::Callback> g_map;31 return g_map;32}33 34std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback> &35NSSet_Additionals::GetAdditionalSynthetics() {36 static std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback>37 g_map;38 return g_map;39}40 41namespace lldb_private {42namespace formatters {43class NSSetISyntheticFrontEnd : public SyntheticChildrenFrontEnd {44public:45 NSSetISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);46 47 ~NSSetISyntheticFrontEnd() override;48 49 llvm::Expected<uint32_t> CalculateNumChildren() override;50 51 lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;52 53 lldb::ChildCacheState Update() override;54 55 llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;56 57private:58 struct DataDescriptor_32 {59 uint32_t _used : 26;60 uint32_t _szidx : 6;61 };62 63 struct DataDescriptor_64 {64 uint64_t _used : 58;65 uint32_t _szidx : 6;66 };67 68 struct SetItemDescriptor {69 lldb::addr_t item_ptr;70 lldb::ValueObjectSP valobj_sp;71 };72 73 ExecutionContextRef m_exe_ctx_ref;74 uint8_t m_ptr_size = 8;75 DataDescriptor_32 *m_data_32 = nullptr;76 DataDescriptor_64 *m_data_64 = nullptr;77 lldb::addr_t m_data_ptr = LLDB_INVALID_ADDRESS;78 std::vector<SetItemDescriptor> m_children;79};80 81class NSCFSetSyntheticFrontEnd : public SyntheticChildrenFrontEnd {82public:83 NSCFSetSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);84 85 llvm::Expected<uint32_t> CalculateNumChildren() override;86 87 lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;88 89 lldb::ChildCacheState Update() override;90 91 llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;92 93private:94 struct SetItemDescriptor {95 lldb::addr_t item_ptr;96 lldb::ValueObjectSP valobj_sp;97 };98 99 ExecutionContextRef m_exe_ctx_ref;100 uint8_t m_ptr_size = 8;101 lldb::ByteOrder m_order = lldb::eByteOrderInvalid;102 103 CFBasicHash m_hashtable;104 105 CompilerType m_pair_type;106 std::vector<SetItemDescriptor> m_children;107};108 109template <typename D32, typename D64>110class GenericNSSetMSyntheticFrontEnd : public SyntheticChildrenFrontEnd {111public:112 GenericNSSetMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);113 114 ~GenericNSSetMSyntheticFrontEnd() override;115 116 llvm::Expected<uint32_t> CalculateNumChildren() override;117 118 lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;119 120 lldb::ChildCacheState Update() override;121 122 llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;123 124private:125 126 struct SetItemDescriptor {127 lldb::addr_t item_ptr;128 lldb::ValueObjectSP valobj_sp;129 };130 131 ExecutionContextRef m_exe_ctx_ref;132 uint8_t m_ptr_size = 8;133 D32 *m_data_32;134 D64 *m_data_64;135 std::vector<SetItemDescriptor> m_children;136};137 138namespace Foundation1300 {139 struct DataDescriptor_32 {140 uint32_t _used : 26;141 uint32_t _size;142 uint32_t _mutations;143 uint32_t _objs_addr;144 };145 146 struct DataDescriptor_64 {147 uint64_t _used : 58;148 uint64_t _size;149 uint64_t _mutations;150 uint64_t _objs_addr;151 };152 153 using NSSetMSyntheticFrontEnd =154 GenericNSSetMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;155}156 157namespace Foundation1428 {158 struct DataDescriptor_32 {159 uint32_t _used : 26;160 uint32_t _size;161 uint32_t _objs_addr;162 uint32_t _mutations;163 };164 165 struct DataDescriptor_64 {166 uint64_t _used : 58;167 uint64_t _size;168 uint64_t _objs_addr;169 uint64_t _mutations;170 };171 172 using NSSetMSyntheticFrontEnd =173 GenericNSSetMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;174}175 176namespace Foundation1437 {177 struct DataDescriptor_32 {178 uint32_t _cow;179 // __table storage180 uint32_t _objs_addr;181 uint32_t _muts;182 uint32_t _used : 26;183 uint32_t _szidx : 6;184 };185 186 struct DataDescriptor_64 {187 uint64_t _cow;188 // __Table storage189 uint64_t _objs_addr;190 uint32_t _muts;191 uint32_t _used : 26;192 uint32_t _szidx : 6;193 };194 195 using NSSetMSyntheticFrontEnd =196 GenericNSSetMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;197 198 template <typename DD>199 uint64_t200 __NSSetMSize_Impl(lldb_private::Process &process, lldb::addr_t valobj_addr,201 Status &error) {202 const lldb::addr_t start_of_descriptor =203 valobj_addr + process.GetAddressByteSize();204 DD descriptor = DD();205 process.ReadMemory(start_of_descriptor, &descriptor, sizeof(descriptor),206 error);207 if (error.Fail()) {208 return 0;209 }210 return descriptor._used;211 }212 213 uint64_t214 __NSSetMSize(lldb_private::Process &process, lldb::addr_t valobj_addr,215 Status &error) {216 if (process.GetAddressByteSize() == 4) {217 return __NSSetMSize_Impl<DataDescriptor_32>(process, valobj_addr, error);218 } else {219 return __NSSetMSize_Impl<DataDescriptor_64>(process, valobj_addr, error);220 }221 }222 } // namespace Foundation1437223} // namespace formatters224} // namespace lldb_private225 226template <bool cf_style>227bool lldb_private::formatters::NSSetSummaryProvider(228 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {229 static constexpr llvm::StringLiteral g_TypeHint("NSSet");230 231 ProcessSP process_sp = valobj.GetProcessSP();232 if (!process_sp)233 return false;234 235 ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);236 237 if (!runtime)238 return false;239 240 ObjCLanguageRuntime::ClassDescriptorSP descriptor(241 runtime->GetClassDescriptor(valobj));242 243 if (!descriptor || !descriptor->IsValid())244 return false;245 246 uint32_t ptr_size = process_sp->GetAddressByteSize();247 bool is_64bit = (ptr_size == 8);248 249 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);250 251 if (!valobj_addr)252 return false;253 254 uint64_t value = 0;255 256 ConstString class_name(descriptor->GetClassName());257 258 static const ConstString g_SetI("__NSSetI");259 static const ConstString g_OrderedSetI("__NSOrderedSetI");260 static const ConstString g_SetM("__NSSetM");261 static const ConstString g_SetCF("__NSCFSet");262 static const ConstString g_SetCFRef("CFSetRef");263 264 if (class_name.IsEmpty())265 return false;266 267 if (class_name == g_SetI || class_name == g_OrderedSetI) {268 Status error;269 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,270 ptr_size, 0, error);271 if (error.Fail())272 return false;273 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);274 } else if (class_name == g_SetM) {275 AppleObjCRuntime *apple_runtime =276 llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime);277 Status error;278 if (apple_runtime && apple_runtime->GetFoundationVersion() >= 1437) {279 value = Foundation1437::__NSSetMSize(*process_sp, valobj_addr, error);280 } else {281 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,282 ptr_size, 0, error);283 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);284 }285 if (error.Fail())286 return false;287 } else if (class_name == g_SetCF || class_name == g_SetCFRef) {288 ExecutionContext exe_ctx(process_sp);289 CFBasicHash cfbh;290 if (!cfbh.Update(valobj_addr, exe_ctx))291 return false;292 value = cfbh.GetCount();293 } else {294 auto &map(NSSet_Additionals::GetAdditionalSummaries());295 auto iter = map.find(class_name), end = map.end();296 if (iter != end)297 return iter->second(valobj, stream, options);298 else299 return false;300 }301 302 llvm::StringRef prefix, suffix;303 if (Language *language = Language::FindPlugin(options.GetLanguage()))304 std::tie(prefix, suffix) = language->GetFormatterPrefixSuffix(g_TypeHint);305 306 stream << prefix;307 stream.Printf("%" PRIu64 " %s%s", value, "element", value == 1 ? "" : "s");308 stream << suffix;309 return true;310}311 312SyntheticChildrenFrontEnd *313lldb_private::formatters::NSSetSyntheticFrontEndCreator(314 CXXSyntheticChildren *synth, lldb::ValueObjectSP valobj_sp) {315 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());316 if (!process_sp)317 return nullptr;318 ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);319 if (!runtime)320 return nullptr;321 322 CompilerType valobj_type(valobj_sp->GetCompilerType());323 Flags flags(valobj_type.GetTypeInfo());324 325 if (flags.IsClear(eTypeIsPointer)) {326 Status error;327 valobj_sp = valobj_sp->AddressOf(error);328 if (error.Fail() || !valobj_sp)329 return nullptr;330 }331 332 ObjCLanguageRuntime::ClassDescriptorSP descriptor(333 runtime->GetClassDescriptor(*valobj_sp));334 335 if (!descriptor || !descriptor->IsValid())336 return nullptr;337 338 ConstString class_name = descriptor->GetClassName();339 340 static const ConstString g_SetI("__NSSetI");341 static const ConstString g_OrderedSetI("__NSOrderedSetI");342 static const ConstString g_SetM("__NSSetM");343 static const ConstString g_SetCF("__NSCFSet");344 static const ConstString g_SetCFRef("CFSetRef");345 346 if (class_name.IsEmpty())347 return nullptr;348 349 if (class_name == g_SetI || class_name == g_OrderedSetI) {350 return (new NSSetISyntheticFrontEnd(valobj_sp));351 } else if (class_name == g_SetM) {352 AppleObjCRuntime *apple_runtime =353 llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime);354 if (apple_runtime) {355 if (apple_runtime->GetFoundationVersion() >= 1437)356 return (new Foundation1437::NSSetMSyntheticFrontEnd(valobj_sp));357 else if (apple_runtime->GetFoundationVersion() >= 1428)358 return (new Foundation1428::NSSetMSyntheticFrontEnd(valobj_sp));359 else360 return (new Foundation1300::NSSetMSyntheticFrontEnd(valobj_sp));361 } else {362 return (new Foundation1300::NSSetMSyntheticFrontEnd(valobj_sp));363 }364 } else if (class_name == g_SetCF || class_name == g_SetCFRef) {365 return (new NSCFSetSyntheticFrontEnd(valobj_sp));366 } else {367 auto &map(NSSet_Additionals::GetAdditionalSynthetics());368 auto iter = map.find(class_name), end = map.end();369 if (iter != end)370 return iter->second(synth, valobj_sp);371 return nullptr;372 }373}374 375lldb_private::formatters::NSSetISyntheticFrontEnd::NSSetISyntheticFrontEnd(376 lldb::ValueObjectSP valobj_sp)377 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref() {378 if (valobj_sp)379 Update();380}381 382lldb_private::formatters::NSSetISyntheticFrontEnd::~NSSetISyntheticFrontEnd() {383 delete m_data_32;384 m_data_32 = nullptr;385 delete m_data_64;386 m_data_64 = nullptr;387}388 389llvm::Expected<size_t>390lldb_private::formatters::NSSetISyntheticFrontEnd::GetIndexOfChildWithName(391 ConstString name) {392 auto optional_idx = ExtractIndexFromString(name.AsCString());393 if (!optional_idx) {394 return llvm::createStringError("Type has no child named '%s'",395 name.AsCString());396 }397 uint32_t idx = *optional_idx;398 if (idx >= CalculateNumChildrenIgnoringErrors())399 return llvm::createStringError("Type has no child named '%s'",400 name.AsCString());401 return idx;402}403 404llvm::Expected<uint32_t>405lldb_private::formatters::NSSetISyntheticFrontEnd::CalculateNumChildren() {406 if (!m_data_32 && !m_data_64)407 return 0;408 return (m_data_32 ? m_data_32->_used : m_data_64->_used);409}410 411lldb::ChildCacheState412lldb_private::formatters::NSSetISyntheticFrontEnd::Update() {413 m_children.clear();414 delete m_data_32;415 m_data_32 = nullptr;416 delete m_data_64;417 m_data_64 = nullptr;418 m_ptr_size = 0;419 ValueObjectSP valobj_sp = m_backend.GetSP();420 if (!valobj_sp)421 return lldb::ChildCacheState::eRefetch;422 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();423 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());424 if (!process_sp)425 return lldb::ChildCacheState::eRefetch;426 m_ptr_size = process_sp->GetAddressByteSize();427 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;428 Status error;429 if (m_ptr_size == 4) {430 m_data_32 = new DataDescriptor_32();431 process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32),432 error);433 } else {434 m_data_64 = new DataDescriptor_64();435 process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64),436 error);437 }438 if (error.Fail())439 return lldb::ChildCacheState::eRefetch;440 m_data_ptr = data_location + m_ptr_size;441 return lldb::ChildCacheState::eReuse;442}443 444lldb::ValueObjectSP445lldb_private::formatters::NSSetISyntheticFrontEnd::GetChildAtIndex(446 uint32_t idx) {447 uint32_t num_children = CalculateNumChildrenIgnoringErrors();448 449 if (idx >= num_children)450 return lldb::ValueObjectSP();451 452 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();453 if (!process_sp)454 return lldb::ValueObjectSP();455 456 if (m_children.empty()) {457 // do the scan phase458 lldb::addr_t obj_at_idx = 0;459 460 uint32_t tries = 0;461 uint32_t test_idx = 0;462 463 while (tries < num_children) {464 obj_at_idx = m_data_ptr + (test_idx * m_ptr_size);465 if (!process_sp)466 return lldb::ValueObjectSP();467 Status error;468 obj_at_idx = process_sp->ReadPointerFromMemory(obj_at_idx, error);469 if (error.Fail())470 return lldb::ValueObjectSP();471 472 test_idx++;473 474 if (!obj_at_idx)475 continue;476 tries++;477 478 SetItemDescriptor descriptor = {obj_at_idx, lldb::ValueObjectSP()};479 480 m_children.push_back(descriptor);481 }482 }483 484 if (idx >= m_children.size()) // should never happen485 return lldb::ValueObjectSP();486 487 SetItemDescriptor &set_item = m_children[idx];488 if (!set_item.valobj_sp) {489 auto ptr_size = process_sp->GetAddressByteSize();490 DataBufferHeap buffer(ptr_size, 0);491 switch (ptr_size) {492 case 0: // architecture has no clue - fail493 return lldb::ValueObjectSP();494 case 4:495 *reinterpret_cast<uint32_t *>(buffer.GetBytes()) =496 static_cast<uint32_t>(set_item.item_ptr);497 break;498 case 8:499 *reinterpret_cast<uint64_t *>(buffer.GetBytes()) =500 static_cast<uint64_t>(set_item.item_ptr);501 break;502 default:503 lldbassert(false && "pointer size is not 4 nor 8");504 }505 StreamString idx_name;506 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);507 508 DataExtractor data(buffer.GetBytes(), buffer.GetByteSize(),509 process_sp->GetByteOrder(),510 process_sp->GetAddressByteSize());511 512 set_item.valobj_sp = CreateValueObjectFromData(513 idx_name.GetString(), data, m_exe_ctx_ref,514 m_backend.GetCompilerType().GetBasicTypeFromAST(515 lldb::eBasicTypeObjCID));516 }517 return set_item.valobj_sp;518}519 520lldb_private::formatters::NSCFSetSyntheticFrontEnd::NSCFSetSyntheticFrontEnd(521 lldb::ValueObjectSP valobj_sp)522 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_hashtable(),523 m_pair_type() {}524 525llvm::Expected<size_t>526lldb_private::formatters::NSCFSetSyntheticFrontEnd::GetIndexOfChildWithName(527 ConstString name) {528 auto optional_idx = ExtractIndexFromString(name.AsCString());529 if (!optional_idx) {530 return llvm::createStringError("Type has no child named '%s'",531 name.AsCString());532 }533 uint32_t idx = *optional_idx;534 if (idx >= CalculateNumChildrenIgnoringErrors())535 return llvm::createStringError("Type has no child named '%s'",536 name.AsCString());537 return idx;538}539 540llvm::Expected<uint32_t>541lldb_private::formatters::NSCFSetSyntheticFrontEnd::CalculateNumChildren() {542 if (!m_hashtable.IsValid())543 return 0;544 return m_hashtable.GetCount();545}546 547lldb::ChildCacheState548lldb_private::formatters::NSCFSetSyntheticFrontEnd::Update() {549 m_children.clear();550 ValueObjectSP valobj_sp = m_backend.GetSP();551 m_ptr_size = 0;552 if (!valobj_sp)553 return lldb::ChildCacheState::eRefetch;554 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();555 556 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());557 if (!process_sp)558 return lldb::ChildCacheState::eRefetch;559 m_ptr_size = process_sp->GetAddressByteSize();560 m_order = process_sp->GetByteOrder();561 return m_hashtable.Update(valobj_sp->GetValueAsUnsigned(0), m_exe_ctx_ref)562 ? lldb::ChildCacheState::eReuse563 : lldb::ChildCacheState::eRefetch;564}565 566lldb::ValueObjectSP567lldb_private::formatters::NSCFSetSyntheticFrontEnd::GetChildAtIndex(568 uint32_t idx) {569 lldb::addr_t m_values_ptr = m_hashtable.GetValuePointer();570 571 const uint32_t num_children = CalculateNumChildrenIgnoringErrors();572 573 if (idx >= num_children)574 return lldb::ValueObjectSP();575 576 if (m_children.empty()) {577 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();578 if (!process_sp)579 return lldb::ValueObjectSP();580 581 Status error;582 lldb::addr_t val_at_idx = 0;583 584 uint32_t tries = 0;585 uint32_t test_idx = 0;586 587 // Iterate over inferior memory, reading value pointers by shifting the588 // cursor by test_index * m_ptr_size. Returns an empty ValueObject if a read589 // fails, otherwise, continue until the number of tries matches the number590 // of childen.591 while (tries < num_children) {592 val_at_idx = m_values_ptr + (test_idx * m_ptr_size);593 594 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);595 if (error.Fail())596 return lldb::ValueObjectSP();597 598 test_idx++;599 600 if (!val_at_idx)601 continue;602 tries++;603 604 SetItemDescriptor descriptor = {val_at_idx, lldb::ValueObjectSP()};605 606 m_children.push_back(descriptor);607 }608 }609 610 if (idx >= m_children.size()) // should never happen611 return lldb::ValueObjectSP();612 613 SetItemDescriptor &set_item = m_children[idx];614 if (!set_item.valobj_sp) {615 616 WritableDataBufferSP buffer_sp(new DataBufferHeap(m_ptr_size, 0));617 618 switch (m_ptr_size) {619 case 0: // architecture has no clue - fail620 return lldb::ValueObjectSP();621 case 4:622 *reinterpret_cast<uint32_t *>(buffer_sp->GetBytes()) =623 static_cast<uint32_t>(set_item.item_ptr);624 break;625 case 8:626 *reinterpret_cast<uint64_t *>(buffer_sp->GetBytes()) =627 static_cast<uint64_t>(set_item.item_ptr);628 break;629 default:630 lldbassert(false && "pointer size is not 4 nor 8");631 }632 StreamString idx_name;633 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);634 635 DataExtractor data(buffer_sp, m_order, m_ptr_size);636 637 set_item.valobj_sp = CreateValueObjectFromData(638 idx_name.GetString(), data, m_exe_ctx_ref,639 m_backend.GetCompilerType().GetBasicTypeFromAST(640 lldb::eBasicTypeObjCID));641 }642 643 return set_item.valobj_sp;644}645 646template <typename D32, typename D64>647lldb_private::formatters::GenericNSSetMSyntheticFrontEnd<648 D32, D64>::GenericNSSetMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)649 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(),650 m_data_32(nullptr), m_data_64(nullptr) {651 if (valobj_sp)652 Update();653}654 655template <typename D32, typename D64>656lldb_private::formatters::GenericNSSetMSyntheticFrontEnd<D32, D64>::657 GenericNSSetMSyntheticFrontEnd::~GenericNSSetMSyntheticFrontEnd() {658 delete m_data_32;659 m_data_32 = nullptr;660 delete m_data_64;661 m_data_64 = nullptr;662}663 664template <typename D32, typename D64>665llvm::Expected<size_t> lldb_private::formatters::GenericNSSetMSyntheticFrontEnd<666 D32, D64>::GetIndexOfChildWithName(ConstString name) {667 auto optional_idx = ExtractIndexFromString(name.AsCString());668 if (!optional_idx) {669 return llvm::createStringError("Type has no child named '%s'",670 name.AsCString());671 }672 uint32_t idx = *optional_idx;673 if (idx >= CalculateNumChildrenIgnoringErrors())674 return llvm::createStringError("Type has no child named '%s'",675 name.AsCString());676 return idx;677}678 679template <typename D32, typename D64>680llvm::Expected<uint32_t>681lldb_private::formatters::GenericNSSetMSyntheticFrontEnd<682 D32, D64>::CalculateNumChildren() {683 if (!m_data_32 && !m_data_64)684 return 0;685 return (m_data_32 ? (uint32_t)m_data_32->_used : (uint32_t)m_data_64->_used);686}687 688template <typename D32, typename D64>689lldb::ChildCacheState690lldb_private::formatters::GenericNSSetMSyntheticFrontEnd<D32, D64>::Update() {691 m_children.clear();692 ValueObjectSP valobj_sp = m_backend.GetSP();693 m_ptr_size = 0;694 delete m_data_32;695 m_data_32 = nullptr;696 delete m_data_64;697 m_data_64 = nullptr;698 if (!valobj_sp)699 return lldb::ChildCacheState::eRefetch;700 if (!valobj_sp)701 return lldb::ChildCacheState::eRefetch;702 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();703 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());704 if (!process_sp)705 return lldb::ChildCacheState::eRefetch;706 m_ptr_size = process_sp->GetAddressByteSize();707 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;708 Status error;709 if (m_ptr_size == 4) {710 m_data_32 = new D32();711 process_sp->ReadMemory(data_location, m_data_32, sizeof(D32),712 error);713 } else {714 m_data_64 = new D64();715 process_sp->ReadMemory(data_location, m_data_64, sizeof(D64),716 error);717 }718 return error.Success() ? lldb::ChildCacheState::eReuse719 : lldb::ChildCacheState::eRefetch;720}721 722template <typename D32, typename D64>723lldb::ValueObjectSP724lldb_private::formatters::725 GenericNSSetMSyntheticFrontEnd<D32, D64>::GetChildAtIndex(uint32_t idx) {726 lldb::addr_t m_objs_addr =727 (m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr);728 729 uint32_t num_children = CalculateNumChildrenIgnoringErrors();730 731 if (idx >= num_children)732 return lldb::ValueObjectSP();733 734 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();735 if (!process_sp)736 return lldb::ValueObjectSP();737 738 if (m_children.empty()) {739 // do the scan phase740 lldb::addr_t obj_at_idx = 0;741 742 uint32_t tries = 0;743 uint32_t test_idx = 0;744 745 while (tries < num_children) {746 obj_at_idx = m_objs_addr + (test_idx * m_ptr_size);747 if (!process_sp)748 return lldb::ValueObjectSP();749 Status error;750 obj_at_idx = process_sp->ReadPointerFromMemory(obj_at_idx, error);751 if (error.Fail())752 return lldb::ValueObjectSP();753 754 test_idx++;755 756 if (!obj_at_idx)757 continue;758 tries++;759 760 SetItemDescriptor descriptor = {obj_at_idx, lldb::ValueObjectSP()};761 762 m_children.push_back(descriptor);763 }764 }765 766 if (idx >= m_children.size()) // should never happen767 return lldb::ValueObjectSP();768 769 SetItemDescriptor &set_item = m_children[idx];770 if (!set_item.valobj_sp) {771 auto ptr_size = process_sp->GetAddressByteSize();772 DataBufferHeap buffer(ptr_size, 0);773 switch (ptr_size) {774 case 0: // architecture has no clue?? - fail775 return lldb::ValueObjectSP();776 case 4:777 *((uint32_t *)buffer.GetBytes()) = (uint32_t)set_item.item_ptr;778 break;779 case 8:780 *((uint64_t *)buffer.GetBytes()) = (uint64_t)set_item.item_ptr;781 break;782 default:783 assert(false && "pointer size is not 4 nor 8 - get out of here ASAP");784 }785 StreamString idx_name;786 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);787 788 DataExtractor data(buffer.GetBytes(), buffer.GetByteSize(),789 process_sp->GetByteOrder(),790 process_sp->GetAddressByteSize());791 792 set_item.valobj_sp = CreateValueObjectFromData(793 idx_name.GetString(), data, m_exe_ctx_ref,794 m_backend.GetCompilerType().GetBasicTypeFromAST(795 lldb::eBasicTypeObjCID));796 }797 return set_item.valobj_sp;798}799 800template bool lldb_private::formatters::NSSetSummaryProvider<true>(801 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options);802 803template bool lldb_private::formatters::NSSetSummaryProvider<false>(804 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options);805