Home | History | Annotate | Download | only in DataFormatters
      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     m_backend.GetTargetSP()->EvaluateExpression(object_fetcher_expr.GetData(), m_backend.GetFrameSP().get(), child_sp,
    222                                                 EvaluateExpressionOptions().SetKeepInMemory(true));
    223     if (child_sp)
    224         child_sp->SetName(ConstString(idx_name.GetData()));
    225     return child_sp;
    226 }
    227 
    228 bool
    229 lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::Update()
    230 {
    231     return false;
    232 }
    233 
    234 bool
    235 lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::MightHaveChildren ()
    236 {
    237     return true;
    238 }
    239 
    240 size_t
    241 lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
    242 {
    243     return 0;
    244 }
    245 
    246 lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::~NSDictionaryCodeRunningSyntheticFrontEnd ()
    247 {}
    248 
    249 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::NSDictionaryISyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
    250 SyntheticChildrenFrontEnd(*valobj_sp.get()),
    251 m_exe_ctx_ref(),
    252 m_ptr_size(8),
    253 m_order(lldb::eByteOrderInvalid),
    254 m_data_32(NULL),
    255 m_data_64(NULL),
    256 m_pair_type()
    257 {
    258 }
    259 
    260 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::~NSDictionaryISyntheticFrontEnd ()
    261 {
    262     delete m_data_32;
    263     m_data_32 = NULL;
    264     delete m_data_64;
    265     m_data_64 = NULL;
    266 }
    267 
    268 size_t
    269 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
    270 {
    271     const char* item_name = name.GetCString();
    272     uint32_t idx = ExtractIndexFromString(item_name);
    273     if (idx < UINT32_MAX && idx >= CalculateNumChildren())
    274         return UINT32_MAX;
    275     return idx;
    276 }
    277 
    278 size_t
    279 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::CalculateNumChildren ()
    280 {
    281     if (!m_data_32 && !m_data_64)
    282         return 0;
    283     return (m_data_32 ? m_data_32->_used : m_data_64->_used);
    284 }
    285 
    286 bool
    287 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::Update()
    288 {
    289     m_children.clear();
    290     delete m_data_32;
    291     m_data_32 = NULL;
    292     delete m_data_64;
    293     m_data_64 = NULL;
    294     m_ptr_size = 0;
    295     ValueObjectSP valobj_sp = m_backend.GetSP();
    296     if (!valobj_sp)
    297         return false;
    298     m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
    299     Error error;
    300     error.Clear();
    301     lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
    302     if (!process_sp)
    303         return false;
    304     m_ptr_size = process_sp->GetAddressByteSize();
    305     m_order = process_sp->GetByteOrder();
    306     uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
    307     if (m_ptr_size == 4)
    308     {
    309         m_data_32 = new DataDescriptor_32();
    310         process_sp->ReadMemory (data_location, m_data_32, sizeof(DataDescriptor_32), error);
    311     }
    312     else
    313     {
    314         m_data_64 = new DataDescriptor_64();
    315         process_sp->ReadMemory (data_location, m_data_64, sizeof(DataDescriptor_64), error);
    316     }
    317     if (error.Fail())
    318         return false;
    319     m_data_ptr = data_location + m_ptr_size;
    320     return false;
    321 }
    322 
    323 bool
    324 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::MightHaveChildren ()
    325 {
    326     return true;
    327 }
    328 
    329 lldb::ValueObjectSP
    330 lldb_private::formatters::NSDictionaryISyntheticFrontEnd::GetChildAtIndex (size_t idx)
    331 {
    332     uint32_t num_children = CalculateNumChildren();
    333 
    334     if (idx >= num_children)
    335         return lldb::ValueObjectSP();
    336 
    337     if (m_children.empty())
    338     {
    339         // do the scan phase
    340         lldb::addr_t key_at_idx = 0, val_at_idx = 0;
    341 
    342         uint32_t tries = 0;
    343         uint32_t test_idx = 0;
    344 
    345         while(tries < num_children)
    346         {
    347             key_at_idx = m_data_ptr + (2*test_idx * m_ptr_size);
    348             val_at_idx = key_at_idx + m_ptr_size;
    349             ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
    350             if (!process_sp)
    351                 return lldb::ValueObjectSP();
    352             Error error;
    353             key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
    354             if (error.Fail())
    355                 return lldb::ValueObjectSP();
    356             val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
    357             if (error.Fail())
    358                 return lldb::ValueObjectSP();
    359 
    360             test_idx++;
    361 
    362             if (!key_at_idx || !val_at_idx)
    363                 continue;
    364             tries++;
    365 
    366             DictionaryItemDescriptor descriptor = {key_at_idx,val_at_idx,lldb::ValueObjectSP()};
    367 
    368             m_children.push_back(descriptor);
    369         }
    370     }
    371 
    372     if (idx >= m_children.size()) // should never happen
    373         return lldb::ValueObjectSP();
    374 
    375     DictionaryItemDescriptor &dict_item = m_children[idx];
    376     if (!dict_item.valobj_sp)
    377     {
    378         if (!m_pair_type.IsValid())
    379         {
    380             TargetSP target_sp(m_backend.GetTargetSP());
    381             if (!target_sp)
    382                 return ValueObjectSP();
    383             m_pair_type = GetLLDBNSPairType(target_sp);
    384         }
    385         if (!m_pair_type.IsValid())
    386             return ValueObjectSP();
    387 
    388         DataBufferSP buffer_sp(new DataBufferHeap(2*m_ptr_size,0));
    389 
    390         if (m_ptr_size == 8)
    391         {
    392             uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
    393             *data_ptr = dict_item.key_ptr;
    394             *(data_ptr+1) = dict_item.val_ptr;
    395         }
    396         else
    397         {
    398             uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
    399             *data_ptr = dict_item.key_ptr;
    400             *(data_ptr+1) = dict_item.val_ptr;
    401         }
    402 
    403         StreamString idx_name;
    404         idx_name.Printf("[%zu]",idx);
    405         DataExtractor data(buffer_sp, m_order, m_ptr_size);
    406         dict_item.valobj_sp = ValueObject::CreateValueObjectFromData(idx_name.GetData(), data, m_exe_ctx_ref, m_pair_type);
    407     }
    408     return dict_item.valobj_sp;
    409 }
    410 
    411 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::NSDictionaryMSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
    412 SyntheticChildrenFrontEnd(*valobj_sp.get()),
    413 m_exe_ctx_ref(),
    414 m_ptr_size(8),
    415 m_order(lldb::eByteOrderInvalid),
    416 m_data_32(NULL),
    417 m_data_64(NULL),
    418 m_pair_type()
    419 {
    420 }
    421 
    422 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::~NSDictionaryMSyntheticFrontEnd ()
    423 {
    424     delete m_data_32;
    425     m_data_32 = NULL;
    426     delete m_data_64;
    427     m_data_64 = NULL;
    428 }
    429 
    430 size_t
    431 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
    432 {
    433     const char* item_name = name.GetCString();
    434     uint32_t idx = ExtractIndexFromString(item_name);
    435     if (idx < UINT32_MAX && idx >= CalculateNumChildren())
    436         return UINT32_MAX;
    437     return idx;
    438 }
    439 
    440 size_t
    441 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::CalculateNumChildren ()
    442 {
    443     if (!m_data_32 && !m_data_64)
    444         return 0;
    445     return (m_data_32 ? m_data_32->_used : m_data_64->_used);
    446 }
    447 
    448 bool
    449 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::Update()
    450 {
    451     m_children.clear();
    452     ValueObjectSP valobj_sp = m_backend.GetSP();
    453     m_ptr_size = 0;
    454     delete m_data_32;
    455     m_data_32 = NULL;
    456     delete m_data_64;
    457     m_data_64 = NULL;
    458     if (!valobj_sp)
    459         return false;
    460     m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
    461     Error error;
    462     error.Clear();
    463     lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
    464     if (!process_sp)
    465         return false;
    466     m_ptr_size = process_sp->GetAddressByteSize();
    467     m_order = process_sp->GetByteOrder();
    468     uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
    469     if (m_ptr_size == 4)
    470     {
    471         m_data_32 = new DataDescriptor_32();
    472         process_sp->ReadMemory (data_location, m_data_32, sizeof(DataDescriptor_32), error);
    473     }
    474     else
    475     {
    476         m_data_64 = new DataDescriptor_64();
    477         process_sp->ReadMemory (data_location, m_data_64, sizeof(DataDescriptor_64), error);
    478     }
    479     if (error.Fail())
    480         return false;
    481     return false;
    482 }
    483 
    484 bool
    485 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::MightHaveChildren ()
    486 {
    487     return true;
    488 }
    489 
    490 lldb::ValueObjectSP
    491 lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::GetChildAtIndex (size_t idx)
    492 {
    493     lldb::addr_t m_keys_ptr = (m_data_32 ? m_data_32->_keys_addr : m_data_64->_keys_addr);
    494     lldb::addr_t m_values_ptr = (m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr);
    495 
    496     uint32_t num_children = CalculateNumChildren();
    497 
    498     if (idx >= num_children)
    499         return lldb::ValueObjectSP();
    500 
    501     if (m_children.empty())
    502     {
    503         // do the scan phase
    504         lldb::addr_t key_at_idx = 0, val_at_idx = 0;
    505 
    506         uint32_t tries = 0;
    507         uint32_t test_idx = 0;
    508 
    509         while(tries < num_children)
    510         {
    511             key_at_idx = m_keys_ptr + (test_idx * m_ptr_size);
    512             val_at_idx = m_values_ptr + (test_idx * m_ptr_size);;
    513             ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
    514             if (!process_sp)
    515                 return lldb::ValueObjectSP();
    516             Error error;
    517             key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
    518             if (error.Fail())
    519                 return lldb::ValueObjectSP();
    520             val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
    521             if (error.Fail())
    522                 return lldb::ValueObjectSP();
    523 
    524             test_idx++;
    525 
    526             if (!key_at_idx || !val_at_idx)
    527                 continue;
    528             tries++;
    529 
    530             DictionaryItemDescriptor descriptor = {key_at_idx,val_at_idx,lldb::ValueObjectSP()};
    531 
    532             m_children.push_back(descriptor);
    533         }
    534     }
    535 
    536     if (idx >= m_children.size()) // should never happen
    537         return lldb::ValueObjectSP();
    538 
    539     DictionaryItemDescriptor &dict_item = m_children[idx];
    540     if (!dict_item.valobj_sp)
    541     {
    542         if (!m_pair_type.IsValid())
    543         {
    544             TargetSP target_sp(m_backend.GetTargetSP());
    545             if (!target_sp)
    546                 return ValueObjectSP();
    547             m_pair_type = GetLLDBNSPairType(target_sp);
    548         }
    549         if (!m_pair_type.IsValid())
    550             return ValueObjectSP();
    551 
    552         DataBufferSP buffer_sp(new DataBufferHeap(2*m_ptr_size,0));
    553 
    554         if (m_ptr_size == 8)
    555         {
    556             uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
    557             *data_ptr = dict_item.key_ptr;
    558             *(data_ptr+1) = dict_item.val_ptr;
    559         }
    560         else
    561         {
    562             uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
    563             *data_ptr = dict_item.key_ptr;
    564             *(data_ptr+1) = dict_item.val_ptr;
    565         }
    566 
    567         StreamString idx_name;
    568         idx_name.Printf("[%zu]",idx);
    569         DataExtractor data(buffer_sp, m_order, m_ptr_size);
    570         dict_item.valobj_sp = ValueObject::CreateValueObjectFromData(idx_name.GetData(), data, m_exe_ctx_ref, m_pair_type);
    571     }
    572     return dict_item.valobj_sp;
    573 }
    574 
    575 template bool
    576 lldb_private::formatters::NSDictionarySummaryProvider<true> (ValueObject&, Stream&) ;
    577 
    578 template bool
    579 lldb_private::formatters::NSDictionarySummaryProvider<false> (ValueObject&, Stream&) ;
    580