Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / lldb / source / Plugins / Language / ObjC / NSSet.cpp
blob44097ee0c42b855ecab3465ce7961243d274cfd8
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-exception
6 //
7 //===----------------------------------------------------------------------===//
9 #include "NSSet.h"
10 #include "CFBasicHash.h"
12 #include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h"
13 #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
14 #include "lldb/Core/ValueObject.h"
15 #include "lldb/Core/ValueObjectConstResult.h"
16 #include "lldb/DataFormatters/FormattersHelpers.h"
17 #include "lldb/Target/Language.h"
18 #include "lldb/Target/Target.h"
19 #include "lldb/Utility/DataBufferHeap.h"
20 #include "lldb/Utility/Endian.h"
21 #include "lldb/Utility/Status.h"
22 #include "lldb/Utility/Stream.h"
24 using namespace lldb;
25 using namespace lldb_private;
26 using namespace lldb_private::formatters;
28 std::map<ConstString, CXXFunctionSummaryFormat::Callback> &
29 NSSet_Additionals::GetAdditionalSummaries() {
30 static std::map<ConstString, CXXFunctionSummaryFormat::Callback> g_map;
31 return g_map;
34 std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback> &
35 NSSet_Additionals::GetAdditionalSynthetics() {
36 static std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback>
37 g_map;
38 return g_map;
41 namespace lldb_private {
42 namespace formatters {
43 class NSSetISyntheticFrontEnd : public SyntheticChildrenFrontEnd {
44 public:
45 NSSetISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
47 ~NSSetISyntheticFrontEnd() override;
49 size_t CalculateNumChildren() override;
51 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
53 bool Update() override;
55 bool MightHaveChildren() override;
57 size_t GetIndexOfChildWithName(ConstString name) override;
59 private:
60 struct DataDescriptor_32 {
61 uint32_t _used : 26;
62 uint32_t _szidx : 6;
65 struct DataDescriptor_64 {
66 uint64_t _used : 58;
67 uint32_t _szidx : 6;
70 struct SetItemDescriptor {
71 lldb::addr_t item_ptr;
72 lldb::ValueObjectSP valobj_sp;
75 ExecutionContextRef m_exe_ctx_ref;
76 uint8_t m_ptr_size = 8;
77 DataDescriptor_32 *m_data_32 = nullptr;
78 DataDescriptor_64 *m_data_64 = nullptr;
79 lldb::addr_t m_data_ptr = LLDB_INVALID_ADDRESS;
80 std::vector<SetItemDescriptor> m_children;
83 class NSCFSetSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
84 public:
85 NSCFSetSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
87 size_t CalculateNumChildren() override;
89 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
91 bool Update() override;
93 bool MightHaveChildren() override;
95 size_t GetIndexOfChildWithName(ConstString name) override;
97 private:
98 struct SetItemDescriptor {
99 lldb::addr_t item_ptr;
100 lldb::ValueObjectSP valobj_sp;
103 ExecutionContextRef m_exe_ctx_ref;
104 uint8_t m_ptr_size = 8;
105 lldb::ByteOrder m_order = lldb::eByteOrderInvalid;
107 CFBasicHash m_hashtable;
109 CompilerType m_pair_type;
110 std::vector<SetItemDescriptor> m_children;
113 template <typename D32, typename D64>
114 class GenericNSSetMSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
115 public:
116 GenericNSSetMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
118 ~GenericNSSetMSyntheticFrontEnd() override;
120 size_t CalculateNumChildren() override;
122 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
124 bool Update() override;
126 bool MightHaveChildren() override;
128 size_t GetIndexOfChildWithName(ConstString name) override;
130 private:
132 struct SetItemDescriptor {
133 lldb::addr_t item_ptr;
134 lldb::ValueObjectSP valobj_sp;
137 ExecutionContextRef m_exe_ctx_ref;
138 uint8_t m_ptr_size = 8;
139 D32 *m_data_32;
140 D64 *m_data_64;
141 std::vector<SetItemDescriptor> m_children;
144 namespace Foundation1300 {
145 struct DataDescriptor_32 {
146 uint32_t _used : 26;
147 uint32_t _size;
148 uint32_t _mutations;
149 uint32_t _objs_addr;
152 struct DataDescriptor_64 {
153 uint64_t _used : 58;
154 uint64_t _size;
155 uint64_t _mutations;
156 uint64_t _objs_addr;
159 using NSSetMSyntheticFrontEnd =
160 GenericNSSetMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
163 namespace Foundation1428 {
164 struct DataDescriptor_32 {
165 uint32_t _used : 26;
166 uint32_t _size;
167 uint32_t _objs_addr;
168 uint32_t _mutations;
171 struct DataDescriptor_64 {
172 uint64_t _used : 58;
173 uint64_t _size;
174 uint64_t _objs_addr;
175 uint64_t _mutations;
178 using NSSetMSyntheticFrontEnd =
179 GenericNSSetMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
182 namespace Foundation1437 {
183 struct DataDescriptor_32 {
184 uint32_t _cow;
185 // __table storage
186 uint32_t _objs_addr;
187 uint32_t _muts;
188 uint32_t _used : 26;
189 uint32_t _szidx : 6;
192 struct DataDescriptor_64 {
193 uint64_t _cow;
194 // __Table storage
195 uint64_t _objs_addr;
196 uint32_t _muts;
197 uint32_t _used : 26;
198 uint32_t _szidx : 6;
201 using NSSetMSyntheticFrontEnd =
202 GenericNSSetMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
204 template <typename DD>
205 uint64_t
206 __NSSetMSize_Impl(lldb_private::Process &process, lldb::addr_t valobj_addr,
207 Status &error) {
208 const lldb::addr_t start_of_descriptor =
209 valobj_addr + process.GetAddressByteSize();
210 DD descriptor = DD();
211 process.ReadMemory(start_of_descriptor, &descriptor, sizeof(descriptor),
212 error);
213 if (error.Fail()) {
214 return 0;
216 return descriptor._used;
219 uint64_t
220 __NSSetMSize(lldb_private::Process &process, lldb::addr_t valobj_addr,
221 Status &error) {
222 if (process.GetAddressByteSize() == 4) {
223 return __NSSetMSize_Impl<DataDescriptor_32>(process, valobj_addr, error);
224 } else {
225 return __NSSetMSize_Impl<DataDescriptor_64>(process, valobj_addr, error);
230 class NSSetCodeRunningSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
231 public:
232 NSSetCodeRunningSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
234 ~NSSetCodeRunningSyntheticFrontEnd() override;
236 size_t CalculateNumChildren() override;
238 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
240 bool Update() override;
242 bool MightHaveChildren() override;
244 size_t GetIndexOfChildWithName(ConstString name) override;
246 } // namespace formatters
247 } // namespace lldb_private
249 template <bool cf_style>
250 bool lldb_private::formatters::NSSetSummaryProvider(
251 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
252 static constexpr llvm::StringLiteral g_TypeHint("NSSet");
254 ProcessSP process_sp = valobj.GetProcessSP();
255 if (!process_sp)
256 return false;
258 ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
260 if (!runtime)
261 return false;
263 ObjCLanguageRuntime::ClassDescriptorSP descriptor(
264 runtime->GetClassDescriptor(valobj));
266 if (!descriptor || !descriptor->IsValid())
267 return false;
269 uint32_t ptr_size = process_sp->GetAddressByteSize();
270 bool is_64bit = (ptr_size == 8);
272 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
274 if (!valobj_addr)
275 return false;
277 uint64_t value = 0;
279 ConstString class_name(descriptor->GetClassName());
281 static const ConstString g_SetI("__NSSetI");
282 static const ConstString g_OrderedSetI("__NSOrderedSetI");
283 static const ConstString g_SetM("__NSSetM");
284 static const ConstString g_SetCF("__NSCFSet");
285 static const ConstString g_SetCFRef("CFSetRef");
287 if (class_name.IsEmpty())
288 return false;
290 if (class_name == g_SetI || class_name == g_OrderedSetI) {
291 Status error;
292 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
293 ptr_size, 0, error);
294 if (error.Fail())
295 return false;
296 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
297 } else if (class_name == g_SetM) {
298 AppleObjCRuntime *apple_runtime =
299 llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime);
300 Status error;
301 if (apple_runtime && apple_runtime->GetFoundationVersion() >= 1437) {
302 value = Foundation1437::__NSSetMSize(*process_sp, valobj_addr, error);
303 } else {
304 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
305 ptr_size, 0, error);
306 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
308 if (error.Fail())
309 return false;
310 } else if (class_name == g_SetCF || class_name == g_SetCFRef) {
311 ExecutionContext exe_ctx(process_sp);
312 CFBasicHash cfbh;
313 if (!cfbh.Update(valobj_addr, exe_ctx))
314 return false;
315 value = cfbh.GetCount();
316 } else {
317 auto &map(NSSet_Additionals::GetAdditionalSummaries());
318 auto iter = map.find(class_name), end = map.end();
319 if (iter != end)
320 return iter->second(valobj, stream, options);
321 else
322 return false;
325 llvm::StringRef prefix, suffix;
326 if (Language *language = Language::FindPlugin(options.GetLanguage()))
327 std::tie(prefix, suffix) = language->GetFormatterPrefixSuffix(g_TypeHint);
329 stream << prefix;
330 stream.Printf("%" PRIu64 " %s%s", value, "element", value == 1 ? "" : "s");
331 stream << suffix;
332 return true;
335 SyntheticChildrenFrontEnd *
336 lldb_private::formatters::NSSetSyntheticFrontEndCreator(
337 CXXSyntheticChildren *synth, lldb::ValueObjectSP valobj_sp) {
338 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
339 if (!process_sp)
340 return nullptr;
341 ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
342 if (!runtime)
343 return nullptr;
345 CompilerType valobj_type(valobj_sp->GetCompilerType());
346 Flags flags(valobj_type.GetTypeInfo());
348 if (flags.IsClear(eTypeIsPointer)) {
349 Status error;
350 valobj_sp = valobj_sp->AddressOf(error);
351 if (error.Fail() || !valobj_sp)
352 return nullptr;
355 ObjCLanguageRuntime::ClassDescriptorSP descriptor(
356 runtime->GetClassDescriptor(*valobj_sp));
358 if (!descriptor || !descriptor->IsValid())
359 return nullptr;
361 ConstString class_name = descriptor->GetClassName();
363 static const ConstString g_SetI("__NSSetI");
364 static const ConstString g_OrderedSetI("__NSOrderedSetI");
365 static const ConstString g_SetM("__NSSetM");
366 static const ConstString g_SetCF("__NSCFSet");
367 static const ConstString g_SetCFRef("CFSetRef");
369 if (class_name.IsEmpty())
370 return nullptr;
372 if (class_name == g_SetI || class_name == g_OrderedSetI) {
373 return (new NSSetISyntheticFrontEnd(valobj_sp));
374 } else if (class_name == g_SetM) {
375 AppleObjCRuntime *apple_runtime =
376 llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime);
377 if (apple_runtime) {
378 if (apple_runtime->GetFoundationVersion() >= 1437)
379 return (new Foundation1437::NSSetMSyntheticFrontEnd(valobj_sp));
380 else if (apple_runtime->GetFoundationVersion() >= 1428)
381 return (new Foundation1428::NSSetMSyntheticFrontEnd(valobj_sp));
382 else
383 return (new Foundation1300::NSSetMSyntheticFrontEnd(valobj_sp));
384 } else {
385 return (new Foundation1300::NSSetMSyntheticFrontEnd(valobj_sp));
387 } else if (class_name == g_SetCF || class_name == g_SetCFRef) {
388 return (new NSCFSetSyntheticFrontEnd(valobj_sp));
389 } else {
390 auto &map(NSSet_Additionals::GetAdditionalSynthetics());
391 auto iter = map.find(class_name), end = map.end();
392 if (iter != end)
393 return iter->second(synth, valobj_sp);
394 return nullptr;
398 lldb_private::formatters::NSSetISyntheticFrontEnd::NSSetISyntheticFrontEnd(
399 lldb::ValueObjectSP valobj_sp)
400 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref() {
401 if (valobj_sp)
402 Update();
405 lldb_private::formatters::NSSetISyntheticFrontEnd::~NSSetISyntheticFrontEnd() {
406 delete m_data_32;
407 m_data_32 = nullptr;
408 delete m_data_64;
409 m_data_64 = nullptr;
412 size_t
413 lldb_private::formatters::NSSetISyntheticFrontEnd::GetIndexOfChildWithName(
414 ConstString name) {
415 const char *item_name = name.GetCString();
416 uint32_t idx = ExtractIndexFromString(item_name);
417 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
418 return UINT32_MAX;
419 return idx;
422 size_t
423 lldb_private::formatters::NSSetISyntheticFrontEnd::CalculateNumChildren() {
424 if (!m_data_32 && !m_data_64)
425 return 0;
426 return (m_data_32 ? m_data_32->_used : m_data_64->_used);
429 bool lldb_private::formatters::NSSetISyntheticFrontEnd::Update() {
430 m_children.clear();
431 delete m_data_32;
432 m_data_32 = nullptr;
433 delete m_data_64;
434 m_data_64 = nullptr;
435 m_ptr_size = 0;
436 ValueObjectSP valobj_sp = m_backend.GetSP();
437 if (!valobj_sp)
438 return false;
439 if (!valobj_sp)
440 return false;
441 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
442 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
443 if (!process_sp)
444 return false;
445 m_ptr_size = process_sp->GetAddressByteSize();
446 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
447 Status error;
448 if (m_ptr_size == 4) {
449 m_data_32 = new DataDescriptor_32();
450 process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32),
451 error);
452 } else {
453 m_data_64 = new DataDescriptor_64();
454 process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64),
455 error);
457 if (error.Fail())
458 return false;
459 m_data_ptr = data_location + m_ptr_size;
460 return true;
463 bool lldb_private::formatters::NSSetISyntheticFrontEnd::MightHaveChildren() {
464 return true;
467 lldb::ValueObjectSP
468 lldb_private::formatters::NSSetISyntheticFrontEnd::GetChildAtIndex(size_t idx) {
469 uint32_t num_children = CalculateNumChildren();
471 if (idx >= num_children)
472 return lldb::ValueObjectSP();
474 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
475 if (!process_sp)
476 return lldb::ValueObjectSP();
478 if (m_children.empty()) {
479 // do the scan phase
480 lldb::addr_t obj_at_idx = 0;
482 uint32_t tries = 0;
483 uint32_t test_idx = 0;
485 while (tries < num_children) {
486 obj_at_idx = m_data_ptr + (test_idx * m_ptr_size);
487 if (!process_sp)
488 return lldb::ValueObjectSP();
489 Status error;
490 obj_at_idx = process_sp->ReadPointerFromMemory(obj_at_idx, error);
491 if (error.Fail())
492 return lldb::ValueObjectSP();
494 test_idx++;
496 if (!obj_at_idx)
497 continue;
498 tries++;
500 SetItemDescriptor descriptor = {obj_at_idx, lldb::ValueObjectSP()};
502 m_children.push_back(descriptor);
506 if (idx >= m_children.size()) // should never happen
507 return lldb::ValueObjectSP();
509 SetItemDescriptor &set_item = m_children[idx];
510 if (!set_item.valobj_sp) {
511 auto ptr_size = process_sp->GetAddressByteSize();
512 DataBufferHeap buffer(ptr_size, 0);
513 switch (ptr_size) {
514 case 0: // architecture has no clue - fail
515 return lldb::ValueObjectSP();
516 case 4:
517 *reinterpret_cast<uint32_t *>(buffer.GetBytes()) =
518 static_cast<uint32_t>(set_item.item_ptr);
519 break;
520 case 8:
521 *reinterpret_cast<uint64_t *>(buffer.GetBytes()) =
522 static_cast<uint64_t>(set_item.item_ptr);
523 break;
524 default:
525 lldbassert(false && "pointer size is not 4 nor 8");
527 StreamString idx_name;
528 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
530 DataExtractor data(buffer.GetBytes(), buffer.GetByteSize(),
531 process_sp->GetByteOrder(),
532 process_sp->GetAddressByteSize());
534 set_item.valobj_sp = CreateValueObjectFromData(
535 idx_name.GetString(), data, m_exe_ctx_ref,
536 m_backend.GetCompilerType().GetBasicTypeFromAST(
537 lldb::eBasicTypeObjCID));
539 return set_item.valobj_sp;
542 lldb_private::formatters::NSCFSetSyntheticFrontEnd::NSCFSetSyntheticFrontEnd(
543 lldb::ValueObjectSP valobj_sp)
544 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_hashtable(),
545 m_pair_type() {}
547 size_t
548 lldb_private::formatters::NSCFSetSyntheticFrontEnd::GetIndexOfChildWithName(
549 ConstString name) {
550 const char *item_name = name.GetCString();
551 const uint32_t idx = ExtractIndexFromString(item_name);
552 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
553 return UINT32_MAX;
554 return idx;
557 size_t
558 lldb_private::formatters::NSCFSetSyntheticFrontEnd::CalculateNumChildren() {
559 if (!m_hashtable.IsValid())
560 return 0;
561 return m_hashtable.GetCount();
564 bool lldb_private::formatters::NSCFSetSyntheticFrontEnd::Update() {
565 m_children.clear();
566 ValueObjectSP valobj_sp = m_backend.GetSP();
567 m_ptr_size = 0;
568 if (!valobj_sp)
569 return false;
570 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
572 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
573 if (!process_sp)
574 return false;
575 m_ptr_size = process_sp->GetAddressByteSize();
576 m_order = process_sp->GetByteOrder();
577 return m_hashtable.Update(valobj_sp->GetValueAsUnsigned(0), m_exe_ctx_ref);
580 bool lldb_private::formatters::NSCFSetSyntheticFrontEnd::MightHaveChildren() {
581 return true;
584 lldb::ValueObjectSP
585 lldb_private::formatters::NSCFSetSyntheticFrontEnd::GetChildAtIndex(
586 size_t idx) {
587 lldb::addr_t m_values_ptr = m_hashtable.GetValuePointer();
589 const uint32_t num_children = CalculateNumChildren();
591 if (idx >= num_children)
592 return lldb::ValueObjectSP();
594 if (m_children.empty()) {
595 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
596 if (!process_sp)
597 return lldb::ValueObjectSP();
599 Status error;
600 lldb::addr_t val_at_idx = 0;
602 uint32_t tries = 0;
603 uint32_t test_idx = 0;
605 // Iterate over inferior memory, reading value pointers by shifting the
606 // cursor by test_index * m_ptr_size. Returns an empty ValueObject if a read
607 // fails, otherwise, continue until the number of tries matches the number
608 // of childen.
609 while (tries < num_children) {
610 val_at_idx = m_values_ptr + (test_idx * m_ptr_size);
612 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
613 if (error.Fail())
614 return lldb::ValueObjectSP();
616 test_idx++;
618 if (!val_at_idx)
619 continue;
620 tries++;
622 SetItemDescriptor descriptor = {val_at_idx, lldb::ValueObjectSP()};
624 m_children.push_back(descriptor);
628 if (idx >= m_children.size()) // should never happen
629 return lldb::ValueObjectSP();
631 SetItemDescriptor &set_item = m_children[idx];
632 if (!set_item.valobj_sp) {
634 WritableDataBufferSP buffer_sp(new DataBufferHeap(m_ptr_size, 0));
636 switch (m_ptr_size) {
637 case 0: // architecture has no clue - fail
638 return lldb::ValueObjectSP();
639 case 4:
640 *reinterpret_cast<uint32_t *>(buffer_sp->GetBytes()) =
641 static_cast<uint32_t>(set_item.item_ptr);
642 break;
643 case 8:
644 *reinterpret_cast<uint64_t *>(buffer_sp->GetBytes()) =
645 static_cast<uint64_t>(set_item.item_ptr);
646 break;
647 default:
648 lldbassert(false && "pointer size is not 4 nor 8");
650 StreamString idx_name;
651 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
653 DataExtractor data(buffer_sp, m_order, m_ptr_size);
655 set_item.valobj_sp = CreateValueObjectFromData(
656 idx_name.GetString(), data, m_exe_ctx_ref,
657 m_backend.GetCompilerType().GetBasicTypeFromAST(
658 lldb::eBasicTypeObjCID));
661 return set_item.valobj_sp;
664 template <typename D32, typename D64>
665 lldb_private::formatters::GenericNSSetMSyntheticFrontEnd<
666 D32, D64>::GenericNSSetMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
667 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(),
668 m_data_32(nullptr), m_data_64(nullptr) {
669 if (valobj_sp)
670 Update();
673 template <typename D32, typename D64>
674 lldb_private::formatters::
675 GenericNSSetMSyntheticFrontEnd<D32, D64>::~GenericNSSetMSyntheticFrontEnd<D32, D64>() {
676 delete m_data_32;
677 m_data_32 = nullptr;
678 delete m_data_64;
679 m_data_64 = nullptr;
682 template <typename D32, typename D64>
683 size_t
684 lldb_private::formatters::
685 GenericNSSetMSyntheticFrontEnd<D32, D64>::GetIndexOfChildWithName(
686 ConstString name) {
687 const char *item_name = name.GetCString();
688 uint32_t idx = ExtractIndexFromString(item_name);
689 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
690 return UINT32_MAX;
691 return idx;
694 template <typename D32, typename D64>
695 size_t
696 lldb_private::formatters::
697 GenericNSSetMSyntheticFrontEnd<D32, D64>::CalculateNumChildren() {
698 if (!m_data_32 && !m_data_64)
699 return 0;
700 return (m_data_32 ? m_data_32->_used : m_data_64->_used);
703 template <typename D32, typename D64>
704 bool
705 lldb_private::formatters::
706 GenericNSSetMSyntheticFrontEnd<D32, D64>::Update() {
707 m_children.clear();
708 ValueObjectSP valobj_sp = m_backend.GetSP();
709 m_ptr_size = 0;
710 delete m_data_32;
711 m_data_32 = nullptr;
712 delete m_data_64;
713 m_data_64 = nullptr;
714 if (!valobj_sp)
715 return false;
716 if (!valobj_sp)
717 return false;
718 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
719 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
720 if (!process_sp)
721 return false;
722 m_ptr_size = process_sp->GetAddressByteSize();
723 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
724 Status error;
725 if (m_ptr_size == 4) {
726 m_data_32 = new D32();
727 process_sp->ReadMemory(data_location, m_data_32, sizeof(D32),
728 error);
729 } else {
730 m_data_64 = new D64();
731 process_sp->ReadMemory(data_location, m_data_64, sizeof(D64),
732 error);
734 return error.Success();
737 template <typename D32, typename D64>
738 bool
739 lldb_private::formatters::
740 GenericNSSetMSyntheticFrontEnd<D32, D64>::MightHaveChildren() {
741 return true;
744 template <typename D32, typename D64>
745 lldb::ValueObjectSP
746 lldb_private::formatters::
747 GenericNSSetMSyntheticFrontEnd<D32, D64>::GetChildAtIndex(size_t idx) {
748 lldb::addr_t m_objs_addr =
749 (m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr);
751 uint32_t num_children = CalculateNumChildren();
753 if (idx >= num_children)
754 return lldb::ValueObjectSP();
756 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
757 if (!process_sp)
758 return lldb::ValueObjectSP();
760 if (m_children.empty()) {
761 // do the scan phase
762 lldb::addr_t obj_at_idx = 0;
764 uint32_t tries = 0;
765 uint32_t test_idx = 0;
767 while (tries < num_children) {
768 obj_at_idx = m_objs_addr + (test_idx * m_ptr_size);
769 if (!process_sp)
770 return lldb::ValueObjectSP();
771 Status error;
772 obj_at_idx = process_sp->ReadPointerFromMemory(obj_at_idx, error);
773 if (error.Fail())
774 return lldb::ValueObjectSP();
776 test_idx++;
778 if (!obj_at_idx)
779 continue;
780 tries++;
782 SetItemDescriptor descriptor = {obj_at_idx, lldb::ValueObjectSP()};
784 m_children.push_back(descriptor);
788 if (idx >= m_children.size()) // should never happen
789 return lldb::ValueObjectSP();
791 SetItemDescriptor &set_item = m_children[idx];
792 if (!set_item.valobj_sp) {
793 auto ptr_size = process_sp->GetAddressByteSize();
794 DataBufferHeap buffer(ptr_size, 0);
795 switch (ptr_size) {
796 case 0: // architecture has no clue?? - fail
797 return lldb::ValueObjectSP();
798 case 4:
799 *((uint32_t *)buffer.GetBytes()) = (uint32_t)set_item.item_ptr;
800 break;
801 case 8:
802 *((uint64_t *)buffer.GetBytes()) = (uint64_t)set_item.item_ptr;
803 break;
804 default:
805 assert(false && "pointer size is not 4 nor 8 - get out of here ASAP");
807 StreamString idx_name;
808 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
810 DataExtractor data(buffer.GetBytes(), buffer.GetByteSize(),
811 process_sp->GetByteOrder(),
812 process_sp->GetAddressByteSize());
814 set_item.valobj_sp = CreateValueObjectFromData(
815 idx_name.GetString(), data, m_exe_ctx_ref,
816 m_backend.GetCompilerType().GetBasicTypeFromAST(
817 lldb::eBasicTypeObjCID));
819 return set_item.valobj_sp;
822 template bool lldb_private::formatters::NSSetSummaryProvider<true>(
823 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options);
825 template bool lldb_private::formatters::NSSetSummaryProvider<false>(
826 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options);