]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/llvm/tools/lldb/source/DataFormatters/NSDictionary.cpp
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / llvm / tools / lldb / source / DataFormatters / NSDictionary.cpp
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 #include "lldb/lldb-python.h"
11
12 #include "lldb/DataFormatters/CXXFormatterFunctions.h"
13
14 #include "lldb/Core/DataBufferHeap.h"
15 #include "lldb/Core/Error.h"
16 #include "lldb/Core/Stream.h"
17 #include "lldb/Core/ValueObject.h"
18 #include "lldb/Core/ValueObjectConstResult.h"
19 #include "lldb/Host/Endian.h"
20 #include "lldb/Symbol/ClangASTContext.h"
21 #include "lldb/Target/ObjCLanguageRuntime.h"
22 #include "lldb/Target/Target.h"
23
24 #include "clang/AST/DeclCXX.h"
25
26 using namespace lldb;
27 using namespace lldb_private;
28 using namespace lldb_private::formatters;
29
30 static ClangASTType
31 GetLLDBNSPairType (TargetSP target_sp)
32 {
33     ClangASTType clang_type;
34
35     ClangASTContext *target_ast_context = target_sp->GetScratchClangASTContext();
36
37     if (target_ast_context)
38     {
39         clang::ASTContext *ast = target_ast_context->getASTContext();
40
41         if (ast)
42         {
43             const char* type_name = "__lldb_autogen_nspair";
44             
45             clang::IdentifierInfo &myIdent = ast->Idents.get(type_name);
46             clang::DeclarationName myName = ast->DeclarationNames.getIdentifier(&myIdent);
47
48             clang::DeclContext::lookup_const_result result = ast->getTranslationUnitDecl()->lookup(myName);
49
50             for (clang::NamedDecl *named_decl : result)
51             {
52                 if (const clang::CXXRecordDecl *record_decl = llvm::dyn_cast<clang::CXXRecordDecl>(named_decl))
53                 {
54                     clang_type.SetClangType(ast, clang::QualType(record_decl->getTypeForDecl(), 0));
55                     break;
56                 }
57                 else
58                 {
59                     // somebody else (the user?) has defined a type with the magic name already - fail!!!
60                     return clang_type;
61                 }
62             }
63
64             if (!clang_type)
65             {
66                 clang_type = target_ast_context->CreateRecordType(NULL, lldb::eAccessPublic, type_name, clang::TTK_Struct, lldb::eLanguageTypeC);
67                 
68                 if (clang_type)
69                 {
70                     clang_type.StartTagDeclarationDefinition();
71                     ClangASTType id_clang_type = target_ast_context->GetBasicType (eBasicTypeObjCID);
72                     clang_type.AddFieldToRecordType("key", id_clang_type, lldb::eAccessPublic, 0);
73                     clang_type.AddFieldToRecordType("value", id_clang_type, lldb::eAccessPublic, 0);
74                     clang_type.CompleteTagDeclarationDefinition();
75                 }
76             }
77         }
78     }
79     return clang_type;
80 }
81
82 template<bool name_entries>
83 bool
84 lldb_private::formatters::NSDictionarySummaryProvider (ValueObject& valobj, Stream& stream)
85 {
86     ProcessSP process_sp = valobj.GetProcessSP();
87     if (!process_sp)
88         return false;
89     
90     ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
91     
92     if (!runtime)
93         return false;
94     
95     ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
96     
97     if (!descriptor.get() || !descriptor->IsValid())
98         return false;
99     
100     uint32_t ptr_size = process_sp->GetAddressByteSize();
101     bool is_64bit = (ptr_size == 8);
102     
103     lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
104     
105     if (!valobj_addr)
106         return false;
107     
108     uint64_t value = 0;
109     
110     const char* class_name = descriptor->GetClassName().GetCString();
111     
112     if (!class_name || !*class_name)
113         return false;
114     
115     if (!strcmp(class_name,"__NSDictionaryI"))
116     {
117         Error error;
118         value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error);
119         if (error.Fail())
120             return false;
121         value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
122     }
123     else if (!strcmp(class_name,"__NSDictionaryM"))
124     {
125         Error error;
126         value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error);
127         if (error.Fail())
128             return false;
129         value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
130     }
131     /*else if (!strcmp(class_name,"__NSCFDictionary"))
132     {
133         Error error;
134         value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + (is_64bit ? 20 : 12), 4, 0, error);
135         if (error.Fail())
136             return false;
137         if (is_64bit)
138             value &= ~0x0f1f000000000000UL;
139     }*/
140     else
141     {
142         if (!ExtractValueFromObjCExpression(valobj, "int", "count", value))
143             return false;
144     }
145     
146     stream.Printf("%s%" PRIu64 " %s%s",
147                   (name_entries ? "@\"" : ""),
148                   value,
149                   (name_entries ? (value == 1 ? "entry" : "entries") : (value == 1 ? "key/value pair" : "key/value pairs")),
150                   (name_entries ? "\"" : ""));
151     return true;
152 }
153
154 SyntheticChildrenFrontEnd* lldb_private::formatters::NSDictionarySyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
155 {
156     
157     lldb::ProcessSP process_sp (valobj_sp->GetProcessSP());
158     if (!process_sp)
159         return NULL;
160     ObjCLanguageRuntime *runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
161     if (!runtime)
162         return NULL;
163     
164     if (!valobj_sp->IsPointerType())
165     {
166         Error error;
167         valobj_sp = valobj_sp->AddressOf(error);
168         if (error.Fail() || !valobj_sp)
169             return NULL;
170     }
171     
172     ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(*valobj_sp.get()));
173     
174     if (!descriptor.get() || !descriptor->IsValid())
175         return NULL;
176     
177     const char* class_name = descriptor->GetClassName().GetCString();
178     
179     if (!class_name || !*class_name)
180         return NULL;
181     
182     if (!strcmp(class_name,"__NSDictionaryI"))
183     {
184         return (new NSDictionaryISyntheticFrontEnd(valobj_sp));
185     }
186     else if (!strcmp(class_name,"__NSDictionaryM"))
187     {
188         return (new NSDictionaryMSyntheticFrontEnd(valobj_sp));
189     }
190     else
191     {
192         return (new NSDictionaryCodeRunningSyntheticFrontEnd(valobj_sp));
193     }
194 }
195
196 lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::NSDictionaryCodeRunningSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
197 SyntheticChildrenFrontEnd(*valobj_sp.get())
198 {}
199
200 size_t
201 lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::CalculateNumChildren ()
202 {
203     uint64_t count = 0;
204     if (ExtractValueFromObjCExpression(m_backend, "int", "count", count))
205         return count;
206     return 0;
207 }
208
209 lldb::ValueObjectSP
210 lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::GetChildAtIndex (size_t idx)
211 {
212     StreamString idx_name;
213     idx_name.Printf("[%zu]",idx);
214     StreamString key_fetcher_expr;
215     key_fetcher_expr.Printf("(id)[(NSArray*)[(id)0x%" PRIx64 " allKeys] objectAtIndex:%zu]",m_backend.GetPointerValue(),idx);
216     StreamString value_fetcher_expr;
217     value_fetcher_expr.Printf("(id)[(id)0x%" PRIx64 " objectForKey:(%s)]",m_backend.GetPointerValue(),key_fetcher_expr.GetData());
218     StreamString object_fetcher_expr;
219     object_fetcher_expr.Printf("struct __lldb_autogen_nspair { id key; id value; } _lldb_valgen_item; _lldb_valgen_item.key = %s; _lldb_valgen_item.value = %s; _lldb_valgen_item;",key_fetcher_expr.GetData(),value_fetcher_expr.GetData());
220     lldb::ValueObjectSP child_sp;
221     EvaluateExpressionOptions options;
222     options.SetKeepInMemory(true);
223     m_backend.GetTargetSP()->EvaluateExpression(object_fetcher_expr.GetData(), m_backend.GetFrameSP().get(), child_sp,
224                                                 options);
225     if (child_sp)
226         child_sp->SetName(ConstString(idx_name.GetData()));
227     return child_sp;
228 }
229
230 bool
231 lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::Update()
232 {
233     return false;
234 }
235
236 bool
237 lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::MightHaveChildren ()
238 {
239     return true;
240 }
241
242 size_t
243 lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
244 {
245     return 0;
246 }
247
248 lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::~NSDictionaryCodeRunningSyntheticFrontEnd ()
249 {}
250
251 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::NSDictionaryISyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
252 SyntheticChildrenFrontEnd(*valobj_sp.get()),
253 m_exe_ctx_ref(),
254 m_ptr_size(8),
255 m_order(lldb::eByteOrderInvalid),
256 m_data_32(NULL),
257 m_data_64(NULL),
258 m_pair_type()
259 {
260 }
261
262 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::~NSDictionaryISyntheticFrontEnd ()
263 {
264     delete m_data_32;
265     m_data_32 = NULL;
266     delete m_data_64;
267     m_data_64 = NULL;
268 }
269
270 size_t
271 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
272 {
273     const char* item_name = name.GetCString();
274     uint32_t idx = ExtractIndexFromString(item_name);
275     if (idx < UINT32_MAX && idx >= CalculateNumChildren())
276         return UINT32_MAX;
277     return idx;
278 }
279
280 size_t
281 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::CalculateNumChildren ()
282 {
283     if (!m_data_32 && !m_data_64)
284         return 0;
285     return (m_data_32 ? m_data_32->_used : m_data_64->_used);
286 }
287
288 bool
289 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::Update()
290 {
291     m_children.clear();
292     delete m_data_32;
293     m_data_32 = NULL;
294     delete m_data_64;
295     m_data_64 = NULL;
296     m_ptr_size = 0;
297     ValueObjectSP valobj_sp = m_backend.GetSP();
298     if (!valobj_sp)
299         return false;
300     m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
301     Error error;
302     error.Clear();
303     lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
304     if (!process_sp)
305         return false;
306     m_ptr_size = process_sp->GetAddressByteSize();
307     m_order = process_sp->GetByteOrder();
308     uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
309     if (m_ptr_size == 4)
310     {
311         m_data_32 = new DataDescriptor_32();
312         process_sp->ReadMemory (data_location, m_data_32, sizeof(DataDescriptor_32), error);
313     }
314     else
315     {
316         m_data_64 = new DataDescriptor_64();
317         process_sp->ReadMemory (data_location, m_data_64, sizeof(DataDescriptor_64), error);
318     }
319     if (error.Fail())
320         return false;
321     m_data_ptr = data_location + m_ptr_size;
322     return false;
323 }
324
325 bool
326 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::MightHaveChildren ()
327 {
328     return true;
329 }
330
331 lldb::ValueObjectSP
332 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::GetChildAtIndex (size_t idx)
333 {
334     uint32_t num_children = CalculateNumChildren();
335     
336     if (idx >= num_children)
337         return lldb::ValueObjectSP();
338     
339     if (m_children.empty())
340     {
341         // do the scan phase
342         lldb::addr_t key_at_idx = 0, val_at_idx = 0;
343         
344         uint32_t tries = 0;
345         uint32_t test_idx = 0;
346         
347         while(tries < num_children)
348         {
349             key_at_idx = m_data_ptr + (2*test_idx * m_ptr_size);
350             val_at_idx = key_at_idx + m_ptr_size;
351             ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
352             if (!process_sp)
353                 return lldb::ValueObjectSP();
354             Error error;
355             key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
356             if (error.Fail())
357                 return lldb::ValueObjectSP();
358             val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
359             if (error.Fail())
360                 return lldb::ValueObjectSP();
361             
362             test_idx++;
363             
364             if (!key_at_idx || !val_at_idx)
365                 continue;
366             tries++;
367             
368             DictionaryItemDescriptor descriptor = {key_at_idx,val_at_idx,lldb::ValueObjectSP()};
369             
370             m_children.push_back(descriptor);
371         }
372     }
373     
374     if (idx >= m_children.size()) // should never happen
375         return lldb::ValueObjectSP();
376     
377     DictionaryItemDescriptor &dict_item = m_children[idx];
378     if (!dict_item.valobj_sp)
379     {
380         if (!m_pair_type.IsValid())
381         {
382             TargetSP target_sp(m_backend.GetTargetSP());
383             if (!target_sp)
384                 return ValueObjectSP();
385             m_pair_type = GetLLDBNSPairType(target_sp);
386         }
387         if (!m_pair_type.IsValid())
388             return ValueObjectSP();
389         
390         DataBufferSP buffer_sp(new DataBufferHeap(2*m_ptr_size,0));
391         
392         if (m_ptr_size == 8)
393         {
394             uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
395             *data_ptr = dict_item.key_ptr;
396             *(data_ptr+1) = dict_item.val_ptr;
397         }
398         else
399         {
400             uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
401             *data_ptr = dict_item.key_ptr;
402             *(data_ptr+1) = dict_item.val_ptr;
403         }
404         
405         StreamString idx_name;
406         idx_name.Printf("[%zu]",idx);
407         DataExtractor data(buffer_sp, m_order, m_ptr_size);
408         dict_item.valobj_sp = ValueObject::CreateValueObjectFromData(idx_name.GetData(), data, m_exe_ctx_ref, m_pair_type);
409     }
410     return dict_item.valobj_sp;
411 }
412
413 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::NSDictionaryMSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
414 SyntheticChildrenFrontEnd(*valobj_sp.get()),
415 m_exe_ctx_ref(),
416 m_ptr_size(8),
417 m_order(lldb::eByteOrderInvalid),
418 m_data_32(NULL),
419 m_data_64(NULL),
420 m_pair_type()
421 {
422 }
423
424 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::~NSDictionaryMSyntheticFrontEnd ()
425 {
426     delete m_data_32;
427     m_data_32 = NULL;
428     delete m_data_64;
429     m_data_64 = NULL;
430 }
431
432 size_t
433 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
434 {
435     const char* item_name = name.GetCString();
436     uint32_t idx = ExtractIndexFromString(item_name);
437     if (idx < UINT32_MAX && idx >= CalculateNumChildren())
438         return UINT32_MAX;
439     return idx;
440 }
441
442 size_t
443 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::CalculateNumChildren ()
444 {
445     if (!m_data_32 && !m_data_64)
446         return 0;
447     return (m_data_32 ? m_data_32->_used : m_data_64->_used);
448 }
449
450 bool
451 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::Update()
452 {
453     m_children.clear();
454     ValueObjectSP valobj_sp = m_backend.GetSP();
455     m_ptr_size = 0;
456     delete m_data_32;
457     m_data_32 = NULL;
458     delete m_data_64;
459     m_data_64 = NULL;
460     if (!valobj_sp)
461         return false;
462     m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
463     Error error;
464     error.Clear();
465     lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
466     if (!process_sp)
467         return false;
468     m_ptr_size = process_sp->GetAddressByteSize();
469     m_order = process_sp->GetByteOrder();
470     uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
471     if (m_ptr_size == 4)
472     {
473         m_data_32 = new DataDescriptor_32();
474         process_sp->ReadMemory (data_location, m_data_32, sizeof(DataDescriptor_32), error);
475     }
476     else
477     {
478         m_data_64 = new DataDescriptor_64();
479         process_sp->ReadMemory (data_location, m_data_64, sizeof(DataDescriptor_64), error);
480     }
481     if (error.Fail())
482         return false;
483     return false;
484 }
485
486 bool
487 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::MightHaveChildren ()
488 {
489     return true;
490 }
491
492 lldb::ValueObjectSP
493 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::GetChildAtIndex (size_t idx)
494 {
495     lldb::addr_t m_keys_ptr = (m_data_32 ? m_data_32->_keys_addr : m_data_64->_keys_addr);
496     lldb::addr_t m_values_ptr = (m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr);
497     
498     uint32_t num_children = CalculateNumChildren();
499     
500     if (idx >= num_children)
501         return lldb::ValueObjectSP();
502     
503     if (m_children.empty())
504     {
505         // do the scan phase
506         lldb::addr_t key_at_idx = 0, val_at_idx = 0;
507         
508         uint32_t tries = 0;
509         uint32_t test_idx = 0;
510         
511         while(tries < num_children)
512         {
513             key_at_idx = m_keys_ptr + (test_idx * m_ptr_size);
514             val_at_idx = m_values_ptr + (test_idx * m_ptr_size);;
515             ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
516             if (!process_sp)
517                 return lldb::ValueObjectSP();
518             Error error;
519             key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
520             if (error.Fail())
521                 return lldb::ValueObjectSP();
522             val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
523             if (error.Fail())
524                 return lldb::ValueObjectSP();
525             
526             test_idx++;
527             
528             if (!key_at_idx || !val_at_idx)
529                 continue;
530             tries++;
531             
532             DictionaryItemDescriptor descriptor = {key_at_idx,val_at_idx,lldb::ValueObjectSP()};
533             
534             m_children.push_back(descriptor);
535         }
536     }
537     
538     if (idx >= m_children.size()) // should never happen
539         return lldb::ValueObjectSP();
540     
541     DictionaryItemDescriptor &dict_item = m_children[idx];
542     if (!dict_item.valobj_sp)
543     {
544         if (!m_pair_type.IsValid())
545         {
546             TargetSP target_sp(m_backend.GetTargetSP());
547             if (!target_sp)
548                 return ValueObjectSP();
549             m_pair_type = GetLLDBNSPairType(target_sp);
550         }
551         if (!m_pair_type.IsValid())
552             return ValueObjectSP();
553         
554         DataBufferSP buffer_sp(new DataBufferHeap(2*m_ptr_size,0));
555         
556         if (m_ptr_size == 8)
557         {
558             uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
559             *data_ptr = dict_item.key_ptr;
560             *(data_ptr+1) = dict_item.val_ptr;
561         }
562         else
563         {
564             uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
565             *data_ptr = dict_item.key_ptr;
566             *(data_ptr+1) = dict_item.val_ptr;
567         }
568         
569         StreamString idx_name;
570         idx_name.Printf("[%zu]",idx);
571         DataExtractor data(buffer_sp, m_order, m_ptr_size);
572         dict_item.valobj_sp = ValueObject::CreateValueObjectFromData(idx_name.GetData(), data, m_exe_ctx_ref, m_pair_type);
573     }
574     return dict_item.valobj_sp;
575 }
576
577 template bool
578 lldb_private::formatters::NSDictionarySummaryProvider<true> (ValueObject&, Stream&) ;
579
580 template bool
581 lldb_private::formatters::NSDictionarySummaryProvider<false> (ValueObject&, Stream&) ;