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