1 //===-- NSSet.cpp -----------------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
12 // Other libraries and framework includes
16 #include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h"
17 #include "lldb/Core/ValueObject.h"
18 #include "lldb/Core/ValueObjectConstResult.h"
19 #include "lldb/DataFormatters/FormattersHelpers.h"
20 #include "lldb/Symbol/ClangASTContext.h"
21 #include "lldb/Target/Language.h"
22 #include "lldb/Target/ObjCLanguageRuntime.h"
23 #include "lldb/Target/Target.h"
24 #include "lldb/Utility/DataBufferHeap.h"
25 #include "lldb/Utility/Endian.h"
26 #include "lldb/Utility/Status.h"
27 #include "lldb/Utility/Stream.h"
30 using namespace lldb_private;
31 using namespace lldb_private::formatters;
33 std::map<ConstString, CXXFunctionSummaryFormat::Callback> &
34 NSSet_Additionals::GetAdditionalSummaries() {
35 static std::map<ConstString, CXXFunctionSummaryFormat::Callback> g_map;
39 std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback> &
40 NSSet_Additionals::GetAdditionalSynthetics() {
41 static std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback>
46 namespace lldb_private {
47 namespace formatters {
48 class NSSetISyntheticFrontEnd : public SyntheticChildrenFrontEnd {
50 NSSetISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
52 ~NSSetISyntheticFrontEnd() override;
54 size_t CalculateNumChildren() override;
56 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
58 bool Update() override;
60 bool MightHaveChildren() override;
62 size_t GetIndexOfChildWithName(const ConstString &name) override;
65 struct DataDescriptor_32 {
70 struct DataDescriptor_64 {
75 struct SetItemDescriptor {
76 lldb::addr_t item_ptr;
77 lldb::ValueObjectSP valobj_sp;
80 ExecutionContextRef m_exe_ctx_ref;
82 DataDescriptor_32 *m_data_32;
83 DataDescriptor_64 *m_data_64;
84 lldb::addr_t m_data_ptr;
85 std::vector<SetItemDescriptor> m_children;
88 template <typename D32, typename D64>
89 class GenericNSSetMSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
91 GenericNSSetMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
93 ~GenericNSSetMSyntheticFrontEnd() override;
95 size_t CalculateNumChildren() override;
97 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
99 bool Update() override;
101 bool MightHaveChildren() override;
103 size_t GetIndexOfChildWithName(const ConstString &name) override;
107 struct SetItemDescriptor {
108 lldb::addr_t item_ptr;
109 lldb::ValueObjectSP valobj_sp;
112 ExecutionContextRef m_exe_ctx_ref;
116 std::vector<SetItemDescriptor> m_children;
119 namespace Foundation1300 {
120 struct DataDescriptor_32 {
127 struct DataDescriptor_64 {
134 using NSSetMSyntheticFrontEnd =
135 GenericNSSetMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
138 namespace Foundation1428 {
139 struct DataDescriptor_32 {
146 struct DataDescriptor_64 {
153 using NSSetMSyntheticFrontEnd =
154 GenericNSSetMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
157 namespace Foundation1437 {
158 struct DataDescriptor_32 {
172 struct DataDescriptor_64 {
186 using NSSetMSyntheticFrontEnd =
187 GenericNSSetMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
189 template <typename DD>
191 __NSSetMSize_Impl(lldb_private::Process &process, lldb::addr_t valobj_addr,
193 const lldb::addr_t start_of_descriptor =
194 valobj_addr + process.GetAddressByteSize();
195 DD descriptor = DD();
196 process.ReadMemory(start_of_descriptor, &descriptor, sizeof(descriptor),
201 return descriptor._used;
205 __NSSetMSize(lldb_private::Process &process, lldb::addr_t valobj_addr,
207 if (process.GetAddressByteSize() == 4) {
208 return __NSSetMSize_Impl<DataDescriptor_32>(process, valobj_addr, error);
210 return __NSSetMSize_Impl<DataDescriptor_64>(process, valobj_addr, error);
215 class NSSetCodeRunningSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
217 NSSetCodeRunningSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
219 ~NSSetCodeRunningSyntheticFrontEnd() override;
221 size_t CalculateNumChildren() override;
223 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
225 bool Update() override;
227 bool MightHaveChildren() override;
229 size_t GetIndexOfChildWithName(const ConstString &name) override;
231 } // namespace formatters
232 } // namespace lldb_private
234 template <bool cf_style>
235 bool lldb_private::formatters::NSSetSummaryProvider(
236 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
237 static ConstString g_TypeHint("NSSet");
239 ProcessSP process_sp = valobj.GetProcessSP();
243 ObjCLanguageRuntime *runtime =
244 (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
245 lldb::eLanguageTypeObjC);
250 ObjCLanguageRuntime::ClassDescriptorSP descriptor(
251 runtime->GetClassDescriptor(valobj));
253 if (!descriptor || !descriptor->IsValid())
256 uint32_t ptr_size = process_sp->GetAddressByteSize();
257 bool is_64bit = (ptr_size == 8);
259 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
266 ConstString class_name_cs = descriptor->GetClassName();
267 const char *class_name = class_name_cs.GetCString();
269 if (!class_name || !*class_name)
272 if (!strcmp(class_name, "__NSSetI") ||
273 !strcmp(class_name, "__NSOrderedSetI")) {
275 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
279 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
280 } else if (!strcmp(class_name, "__NSSetM")) {
281 AppleObjCRuntime *apple_runtime =
282 llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime);
284 if (apple_runtime && apple_runtime->GetFoundationVersion() >= 1437) {
285 value = Foundation1437::__NSSetMSize(*process_sp, valobj_addr, error);
287 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
289 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
294 auto &map(NSSet_Additionals::GetAdditionalSummaries());
295 auto iter = map.find(class_name_cs), end = map.end();
297 return iter->second(valobj, stream, options);
302 std::string prefix, suffix;
303 if (Language *language = Language::FindPlugin(options.GetLanguage())) {
304 if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
311 stream.Printf("%s%" PRIu64 " %s%s%s", prefix.c_str(), value, "element",
312 value == 1 ? "" : "s", suffix.c_str());
316 SyntheticChildrenFrontEnd *
317 lldb_private::formatters::NSSetSyntheticFrontEndCreator(
318 CXXSyntheticChildren *synth, lldb::ValueObjectSP valobj_sp) {
319 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
322 ObjCLanguageRuntime *runtime =
323 (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
324 lldb::eLanguageTypeObjC);
328 CompilerType valobj_type(valobj_sp->GetCompilerType());
329 Flags flags(valobj_type.GetTypeInfo());
331 if (flags.IsClear(eTypeIsPointer)) {
333 valobj_sp = valobj_sp->AddressOf(error);
334 if (error.Fail() || !valobj_sp)
338 ObjCLanguageRuntime::ClassDescriptorSP descriptor(
339 runtime->GetClassDescriptor(*valobj_sp));
341 if (!descriptor || !descriptor->IsValid())
344 ConstString class_name_cs = descriptor->GetClassName();
345 const char *class_name = class_name_cs.GetCString();
347 if (!class_name || !*class_name)
350 if (!strcmp(class_name, "__NSSetI") ||
351 !strcmp(class_name, "__NSOrderedSetI")) {
352 return (new NSSetISyntheticFrontEnd(valobj_sp));
353 } else if (!strcmp(class_name, "__NSSetM")) {
354 AppleObjCRuntime *apple_runtime =
355 llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime);
357 if (apple_runtime->GetFoundationVersion() >= 1437)
358 return (new Foundation1437::NSSetMSyntheticFrontEnd(valobj_sp));
359 else if (apple_runtime->GetFoundationVersion() >= 1428)
360 return (new Foundation1428::NSSetMSyntheticFrontEnd(valobj_sp));
362 return (new Foundation1300::NSSetMSyntheticFrontEnd(valobj_sp));
364 return (new Foundation1300::NSSetMSyntheticFrontEnd(valobj_sp));
367 auto &map(NSSet_Additionals::GetAdditionalSynthetics());
368 auto iter = map.find(class_name_cs), end = map.end();
370 return iter->second(synth, valobj_sp);
375 lldb_private::formatters::NSSetISyntheticFrontEnd::NSSetISyntheticFrontEnd(
376 lldb::ValueObjectSP valobj_sp)
377 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
378 m_data_32(nullptr), m_data_64(nullptr) {
383 lldb_private::formatters::NSSetISyntheticFrontEnd::~NSSetISyntheticFrontEnd() {
391 lldb_private::formatters::NSSetISyntheticFrontEnd::GetIndexOfChildWithName(
392 const ConstString &name) {
393 const char *item_name = name.GetCString();
394 uint32_t idx = ExtractIndexFromString(item_name);
395 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
401 lldb_private::formatters::NSSetISyntheticFrontEnd::CalculateNumChildren() {
402 if (!m_data_32 && !m_data_64)
404 return (m_data_32 ? m_data_32->_used : m_data_64->_used);
407 bool lldb_private::formatters::NSSetISyntheticFrontEnd::Update() {
414 ValueObjectSP valobj_sp = m_backend.GetSP();
419 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
421 if (valobj_sp->IsPointerType()) {
422 valobj_sp = valobj_sp->Dereference(error);
423 if (error.Fail() || !valobj_sp)
427 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
430 m_ptr_size = process_sp->GetAddressByteSize();
431 uint64_t data_location = valobj_sp->GetAddressOf() + m_ptr_size;
432 if (m_ptr_size == 4) {
433 m_data_32 = new DataDescriptor_32();
434 process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32),
437 m_data_64 = new DataDescriptor_64();
438 process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64),
443 m_data_ptr = data_location + m_ptr_size;
447 bool lldb_private::formatters::NSSetISyntheticFrontEnd::MightHaveChildren() {
452 lldb_private::formatters::NSSetISyntheticFrontEnd::GetChildAtIndex(size_t idx) {
453 uint32_t num_children = CalculateNumChildren();
455 if (idx >= num_children)
456 return lldb::ValueObjectSP();
458 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
460 return lldb::ValueObjectSP();
462 if (m_children.empty()) {
464 lldb::addr_t obj_at_idx = 0;
467 uint32_t test_idx = 0;
469 while (tries < num_children) {
470 obj_at_idx = m_data_ptr + (test_idx * m_ptr_size);
472 return lldb::ValueObjectSP();
474 obj_at_idx = process_sp->ReadPointerFromMemory(obj_at_idx, error);
476 return lldb::ValueObjectSP();
484 SetItemDescriptor descriptor = {obj_at_idx, lldb::ValueObjectSP()};
486 m_children.push_back(descriptor);
490 if (idx >= m_children.size()) // should never happen
491 return lldb::ValueObjectSP();
493 SetItemDescriptor &set_item = m_children[idx];
494 if (!set_item.valobj_sp) {
495 auto ptr_size = process_sp->GetAddressByteSize();
496 DataBufferHeap buffer(ptr_size, 0);
498 case 0: // architecture has no clue?? - fail
499 return lldb::ValueObjectSP();
501 *((uint32_t *)buffer.GetBytes()) = (uint32_t)set_item.item_ptr;
504 *((uint64_t *)buffer.GetBytes()) = (uint64_t)set_item.item_ptr;
507 assert(false && "pointer size is not 4 nor 8 - get out of here ASAP");
509 StreamString idx_name;
510 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
512 DataExtractor data(buffer.GetBytes(), buffer.GetByteSize(),
513 process_sp->GetByteOrder(),
514 process_sp->GetAddressByteSize());
516 set_item.valobj_sp = CreateValueObjectFromData(
517 idx_name.GetString(), data, m_exe_ctx_ref,
518 m_backend.GetCompilerType().GetBasicTypeFromAST(
519 lldb::eBasicTypeObjCID));
521 return set_item.valobj_sp;
524 template <typename D32, typename D64>
525 lldb_private::formatters::
526 GenericNSSetMSyntheticFrontEnd<D32, D64>::GenericNSSetMSyntheticFrontEnd(
527 lldb::ValueObjectSP valobj_sp)
528 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
529 m_data_32(nullptr), m_data_64(nullptr) {
534 template <typename D32, typename D64>
535 lldb_private::formatters::
536 GenericNSSetMSyntheticFrontEnd<D32, D64>::~GenericNSSetMSyntheticFrontEnd() {
543 template <typename D32, typename D64>
545 lldb_private::formatters::
546 GenericNSSetMSyntheticFrontEnd<D32, D64>::GetIndexOfChildWithName(
547 const ConstString &name) {
548 const char *item_name = name.GetCString();
549 uint32_t idx = ExtractIndexFromString(item_name);
550 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
555 template <typename D32, typename D64>
557 lldb_private::formatters::
558 GenericNSSetMSyntheticFrontEnd<D32, D64>::CalculateNumChildren() {
559 if (!m_data_32 && !m_data_64)
561 return (m_data_32 ? m_data_32->_used : m_data_64->_used);
564 template <typename D32, typename D64>
566 lldb_private::formatters::
567 GenericNSSetMSyntheticFrontEnd<D32, D64>::Update() {
569 ValueObjectSP valobj_sp = m_backend.GetSP();
579 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
581 if (valobj_sp->IsPointerType()) {
582 valobj_sp = valobj_sp->Dereference(error);
583 if (error.Fail() || !valobj_sp)
587 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
590 m_ptr_size = process_sp->GetAddressByteSize();
591 uint64_t data_location = valobj_sp->GetAddressOf() + m_ptr_size;
592 if (m_ptr_size == 4) {
593 m_data_32 = new D32();
594 process_sp->ReadMemory(data_location, m_data_32, sizeof(D32),
597 m_data_64 = new D64();
598 process_sp->ReadMemory(data_location, m_data_64, sizeof(D64),
606 template <typename D32, typename D64>
608 lldb_private::formatters::
609 GenericNSSetMSyntheticFrontEnd<D32, D64>::MightHaveChildren() {
613 template <typename D32, typename D64>
615 lldb_private::formatters::
616 GenericNSSetMSyntheticFrontEnd<D32, D64>::GetChildAtIndex(size_t idx) {
617 lldb::addr_t m_objs_addr =
618 (m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr);
620 uint32_t num_children = CalculateNumChildren();
622 if (idx >= num_children)
623 return lldb::ValueObjectSP();
625 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
627 return lldb::ValueObjectSP();
629 if (m_children.empty()) {
631 lldb::addr_t obj_at_idx = 0;
634 uint32_t test_idx = 0;
636 while (tries < num_children) {
637 obj_at_idx = m_objs_addr + (test_idx * m_ptr_size);
639 return lldb::ValueObjectSP();
641 obj_at_idx = process_sp->ReadPointerFromMemory(obj_at_idx, error);
643 return lldb::ValueObjectSP();
651 SetItemDescriptor descriptor = {obj_at_idx, lldb::ValueObjectSP()};
653 m_children.push_back(descriptor);
657 if (idx >= m_children.size()) // should never happen
658 return lldb::ValueObjectSP();
660 SetItemDescriptor &set_item = m_children[idx];
661 if (!set_item.valobj_sp) {
662 auto ptr_size = process_sp->GetAddressByteSize();
663 DataBufferHeap buffer(ptr_size, 0);
665 case 0: // architecture has no clue?? - fail
666 return lldb::ValueObjectSP();
668 *((uint32_t *)buffer.GetBytes()) = (uint32_t)set_item.item_ptr;
671 *((uint64_t *)buffer.GetBytes()) = (uint64_t)set_item.item_ptr;
674 assert(false && "pointer size is not 4 nor 8 - get out of here ASAP");
676 StreamString idx_name;
677 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
679 DataExtractor data(buffer.GetBytes(), buffer.GetByteSize(),
680 process_sp->GetByteOrder(),
681 process_sp->GetAddressByteSize());
683 set_item.valobj_sp = CreateValueObjectFromData(
684 idx_name.GetString(), data, m_exe_ctx_ref,
685 m_backend.GetCompilerType().GetBasicTypeFromAST(
686 lldb::eBasicTypeObjCID));
688 return set_item.valobj_sp;
691 template bool lldb_private::formatters::NSSetSummaryProvider<true>(
692 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options);
694 template bool lldb_private::formatters::NSSetSummaryProvider<false>(
695 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options);