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 "lldb/Core/DataBufferHeap.h"
17 #include "lldb/Core/Error.h"
18 #include "lldb/Core/Stream.h"
19 #include "lldb/Core/ValueObject.h"
20 #include "lldb/Core/ValueObjectConstResult.h"
21 #include "lldb/DataFormatters/FormattersHelpers.h"
22 #include "lldb/Host/Endian.h"
23 #include "lldb/Symbol/ClangASTContext.h"
24 #include "lldb/Target/Language.h"
25 #include "lldb/Target/ObjCLanguageRuntime.h"
26 #include "lldb/Target/Target.h"
29 using namespace lldb_private;
30 using namespace lldb_private::formatters;
32 std::map<ConstString, CXXFunctionSummaryFormat::Callback> &
33 NSSet_Additionals::GetAdditionalSummaries() {
34 static std::map<ConstString, CXXFunctionSummaryFormat::Callback> g_map;
38 std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback> &
39 NSSet_Additionals::GetAdditionalSynthetics() {
40 static std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback>
45 namespace lldb_private {
46 namespace formatters {
47 class NSSetISyntheticFrontEnd : public SyntheticChildrenFrontEnd {
49 NSSetISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
51 ~NSSetISyntheticFrontEnd() override;
53 size_t CalculateNumChildren() override;
55 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
57 bool Update() override;
59 bool MightHaveChildren() override;
61 size_t GetIndexOfChildWithName(const ConstString &name) override;
64 struct DataDescriptor_32 {
69 struct DataDescriptor_64 {
74 struct SetItemDescriptor {
75 lldb::addr_t item_ptr;
76 lldb::ValueObjectSP valobj_sp;
79 ExecutionContextRef m_exe_ctx_ref;
81 DataDescriptor_32 *m_data_32;
82 DataDescriptor_64 *m_data_64;
83 lldb::addr_t m_data_ptr;
84 std::vector<SetItemDescriptor> m_children;
87 class NSSetMSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
89 NSSetMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
91 ~NSSetMSyntheticFrontEnd() override;
93 size_t CalculateNumChildren() override;
95 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
97 bool Update() override;
99 bool MightHaveChildren() override;
101 size_t GetIndexOfChildWithName(const ConstString &name) override;
104 struct DataDescriptor_32 {
111 struct DataDescriptor_64 {
118 struct SetItemDescriptor {
119 lldb::addr_t item_ptr;
120 lldb::ValueObjectSP valobj_sp;
123 ExecutionContextRef m_exe_ctx_ref;
125 DataDescriptor_32 *m_data_32;
126 DataDescriptor_64 *m_data_64;
127 std::vector<SetItemDescriptor> m_children;
130 class NSSetCodeRunningSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
132 NSSetCodeRunningSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
134 ~NSSetCodeRunningSyntheticFrontEnd() override;
136 size_t CalculateNumChildren() override;
138 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
140 bool Update() override;
142 bool MightHaveChildren() override;
144 size_t GetIndexOfChildWithName(const ConstString &name) override;
146 } // namespace formatters
147 } // namespace lldb_private
149 template <bool cf_style>
150 bool lldb_private::formatters::NSSetSummaryProvider(
151 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
152 static ConstString g_TypeHint("NSSet");
154 ProcessSP process_sp = valobj.GetProcessSP();
158 ObjCLanguageRuntime *runtime =
159 (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
160 lldb::eLanguageTypeObjC);
165 ObjCLanguageRuntime::ClassDescriptorSP descriptor(
166 runtime->GetClassDescriptor(valobj));
168 if (!descriptor || !descriptor->IsValid())
171 uint32_t ptr_size = process_sp->GetAddressByteSize();
172 bool is_64bit = (ptr_size == 8);
174 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
181 ConstString class_name_cs = descriptor->GetClassName();
182 const char *class_name = class_name_cs.GetCString();
184 if (!class_name || !*class_name)
187 if (!strcmp(class_name, "__NSSetI")) {
189 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
193 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
194 } else if (!strcmp(class_name, "__NSSetM")) {
196 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
200 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
202 /*else if (!strcmp(class_name,"__NSCFSet"))
205 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + (is_64bit ?
206 20 : 12), 4, 0, error);
210 value &= ~0x1fff000000000000UL;
212 else if (!strcmp(class_name,"NSCountedSet"))
215 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
219 value = process_sp->ReadUnsignedIntegerFromMemory(value + (is_64bit ? 20 :
224 value &= ~0x1fff000000000000UL;
227 auto &map(NSSet_Additionals::GetAdditionalSummaries());
228 auto iter = map.find(class_name_cs), end = map.end();
230 return iter->second(valobj, stream, options);
235 std::string prefix, suffix;
236 if (Language *language = Language::FindPlugin(options.GetLanguage())) {
237 if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
244 stream.Printf("%s%" PRIu64 " %s%s%s", prefix.c_str(), value, "element",
245 value == 1 ? "" : "s", suffix.c_str());
249 SyntheticChildrenFrontEnd *
250 lldb_private::formatters::NSSetSyntheticFrontEndCreator(
251 CXXSyntheticChildren *synth, lldb::ValueObjectSP valobj_sp) {
252 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
255 ObjCLanguageRuntime *runtime =
256 (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
257 lldb::eLanguageTypeObjC);
261 CompilerType valobj_type(valobj_sp->GetCompilerType());
262 Flags flags(valobj_type.GetTypeInfo());
264 if (flags.IsClear(eTypeIsPointer)) {
266 valobj_sp = valobj_sp->AddressOf(error);
267 if (error.Fail() || !valobj_sp)
271 ObjCLanguageRuntime::ClassDescriptorSP descriptor(
272 runtime->GetClassDescriptor(*valobj_sp));
274 if (!descriptor || !descriptor->IsValid())
277 ConstString class_name_cs = descriptor->GetClassName();
278 const char *class_name = class_name_cs.GetCString();
280 if (!class_name || !*class_name)
283 if (!strcmp(class_name, "__NSSetI")) {
284 return (new NSSetISyntheticFrontEnd(valobj_sp));
285 } else if (!strcmp(class_name, "__NSSetM")) {
286 return (new NSSetMSyntheticFrontEnd(valobj_sp));
288 auto &map(NSSet_Additionals::GetAdditionalSynthetics());
289 auto iter = map.find(class_name_cs), end = map.end();
291 return iter->second(synth, valobj_sp);
296 lldb_private::formatters::NSSetISyntheticFrontEnd::NSSetISyntheticFrontEnd(
297 lldb::ValueObjectSP valobj_sp)
298 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
299 m_data_32(nullptr), m_data_64(nullptr) {
304 lldb_private::formatters::NSSetISyntheticFrontEnd::~NSSetISyntheticFrontEnd() {
312 lldb_private::formatters::NSSetISyntheticFrontEnd::GetIndexOfChildWithName(
313 const ConstString &name) {
314 const char *item_name = name.GetCString();
315 uint32_t idx = ExtractIndexFromString(item_name);
316 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
322 lldb_private::formatters::NSSetISyntheticFrontEnd::CalculateNumChildren() {
323 if (!m_data_32 && !m_data_64)
325 return (m_data_32 ? m_data_32->_used : m_data_64->_used);
328 bool lldb_private::formatters::NSSetISyntheticFrontEnd::Update() {
335 ValueObjectSP valobj_sp = m_backend.GetSP();
340 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
342 if (valobj_sp->IsPointerType()) {
343 valobj_sp = valobj_sp->Dereference(error);
344 if (error.Fail() || !valobj_sp)
348 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
351 m_ptr_size = process_sp->GetAddressByteSize();
352 uint64_t data_location = valobj_sp->GetAddressOf() + m_ptr_size;
353 if (m_ptr_size == 4) {
354 m_data_32 = new DataDescriptor_32();
355 process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32),
358 m_data_64 = new DataDescriptor_64();
359 process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64),
364 m_data_ptr = data_location + m_ptr_size;
368 bool lldb_private::formatters::NSSetISyntheticFrontEnd::MightHaveChildren() {
373 lldb_private::formatters::NSSetISyntheticFrontEnd::GetChildAtIndex(size_t idx) {
374 uint32_t num_children = CalculateNumChildren();
376 if (idx >= num_children)
377 return lldb::ValueObjectSP();
379 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
381 return lldb::ValueObjectSP();
383 if (m_children.empty()) {
385 lldb::addr_t obj_at_idx = 0;
388 uint32_t test_idx = 0;
390 while (tries < num_children) {
391 obj_at_idx = m_data_ptr + (test_idx * m_ptr_size);
393 return lldb::ValueObjectSP();
395 obj_at_idx = process_sp->ReadPointerFromMemory(obj_at_idx, error);
397 return lldb::ValueObjectSP();
405 SetItemDescriptor descriptor = {obj_at_idx, lldb::ValueObjectSP()};
407 m_children.push_back(descriptor);
411 if (idx >= m_children.size()) // should never happen
412 return lldb::ValueObjectSP();
414 SetItemDescriptor &set_item = m_children[idx];
415 if (!set_item.valobj_sp) {
416 auto ptr_size = process_sp->GetAddressByteSize();
417 DataBufferHeap buffer(ptr_size, 0);
419 case 0: // architecture has no clue?? - fail
420 return lldb::ValueObjectSP();
422 *((uint32_t *)buffer.GetBytes()) = (uint32_t)set_item.item_ptr;
425 *((uint64_t *)buffer.GetBytes()) = (uint64_t)set_item.item_ptr;
428 assert(false && "pointer size is not 4 nor 8 - get out of here ASAP");
430 StreamString idx_name;
431 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
433 DataExtractor data(buffer.GetBytes(), buffer.GetByteSize(),
434 process_sp->GetByteOrder(),
435 process_sp->GetAddressByteSize());
437 set_item.valobj_sp = CreateValueObjectFromData(
438 idx_name.GetString(), data, m_exe_ctx_ref,
439 m_backend.GetCompilerType().GetBasicTypeFromAST(
440 lldb::eBasicTypeObjCID));
442 return set_item.valobj_sp;
445 lldb_private::formatters::NSSetMSyntheticFrontEnd::NSSetMSyntheticFrontEnd(
446 lldb::ValueObjectSP valobj_sp)
447 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
448 m_data_32(nullptr), m_data_64(nullptr) {
453 lldb_private::formatters::NSSetMSyntheticFrontEnd::~NSSetMSyntheticFrontEnd() {
461 lldb_private::formatters::NSSetMSyntheticFrontEnd::GetIndexOfChildWithName(
462 const ConstString &name) {
463 const char *item_name = name.GetCString();
464 uint32_t idx = ExtractIndexFromString(item_name);
465 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
471 lldb_private::formatters::NSSetMSyntheticFrontEnd::CalculateNumChildren() {
472 if (!m_data_32 && !m_data_64)
474 return (m_data_32 ? m_data_32->_used : m_data_64->_used);
477 bool lldb_private::formatters::NSSetMSyntheticFrontEnd::Update() {
479 ValueObjectSP valobj_sp = m_backend.GetSP();
489 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
491 if (valobj_sp->IsPointerType()) {
492 valobj_sp = valobj_sp->Dereference(error);
493 if (error.Fail() || !valobj_sp)
497 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
500 m_ptr_size = process_sp->GetAddressByteSize();
501 uint64_t data_location = valobj_sp->GetAddressOf() + m_ptr_size;
502 if (m_ptr_size == 4) {
503 m_data_32 = new DataDescriptor_32();
504 process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32),
507 m_data_64 = new DataDescriptor_64();
508 process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64),
516 bool lldb_private::formatters::NSSetMSyntheticFrontEnd::MightHaveChildren() {
521 lldb_private::formatters::NSSetMSyntheticFrontEnd::GetChildAtIndex(size_t idx) {
522 lldb::addr_t m_objs_addr =
523 (m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr);
525 uint32_t num_children = CalculateNumChildren();
527 if (idx >= num_children)
528 return lldb::ValueObjectSP();
530 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
532 return lldb::ValueObjectSP();
534 if (m_children.empty()) {
536 lldb::addr_t obj_at_idx = 0;
539 uint32_t test_idx = 0;
541 while (tries < num_children) {
542 obj_at_idx = m_objs_addr + (test_idx * m_ptr_size);
544 return lldb::ValueObjectSP();
546 obj_at_idx = process_sp->ReadPointerFromMemory(obj_at_idx, error);
548 return lldb::ValueObjectSP();
556 SetItemDescriptor descriptor = {obj_at_idx, lldb::ValueObjectSP()};
558 m_children.push_back(descriptor);
562 if (idx >= m_children.size()) // should never happen
563 return lldb::ValueObjectSP();
565 SetItemDescriptor &set_item = m_children[idx];
566 if (!set_item.valobj_sp) {
567 auto ptr_size = process_sp->GetAddressByteSize();
568 DataBufferHeap buffer(ptr_size, 0);
570 case 0: // architecture has no clue?? - fail
571 return lldb::ValueObjectSP();
573 *((uint32_t *)buffer.GetBytes()) = (uint32_t)set_item.item_ptr;
576 *((uint64_t *)buffer.GetBytes()) = (uint64_t)set_item.item_ptr;
579 assert(false && "pointer size is not 4 nor 8 - get out of here ASAP");
581 StreamString idx_name;
582 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
584 DataExtractor data(buffer.GetBytes(), buffer.GetByteSize(),
585 process_sp->GetByteOrder(),
586 process_sp->GetAddressByteSize());
588 set_item.valobj_sp = CreateValueObjectFromData(
589 idx_name.GetString(), data, m_exe_ctx_ref,
590 m_backend.GetCompilerType().GetBasicTypeFromAST(
591 lldb::eBasicTypeObjCID));
593 return set_item.valobj_sp;
596 template bool lldb_private::formatters::NSSetSummaryProvider<true>(
597 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options);
599 template bool lldb_private::formatters::NSSetSummaryProvider<false>(
600 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options);