Home | History | Annotate | Download | only in DataFormatters
      1 //===-- NSArray.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 using namespace lldb;
     25 using namespace lldb_private;
     26 using namespace lldb_private::formatters;
     27 
     28 bool
     29 lldb_private::formatters::NSArraySummaryProvider (ValueObject& valobj, Stream& stream)
     30 {
     31     ProcessSP process_sp = valobj.GetProcessSP();
     32     if (!process_sp)
     33         return false;
     34 
     35     ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
     36 
     37     if (!runtime)
     38         return false;
     39 
     40     ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
     41 
     42     if (!descriptor.get() || !descriptor->IsValid())
     43         return false;
     44 
     45     uint32_t ptr_size = process_sp->GetAddressByteSize();
     46 
     47     lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
     48 
     49     if (!valobj_addr)
     50         return false;
     51 
     52     uint64_t value = 0;
     53 
     54     const char* class_name = descriptor->GetClassName().GetCString();
     55 
     56     if (!class_name || !*class_name)
     57         return false;
     58 
     59     if (!strcmp(class_name,"__NSArrayI"))
     60     {
     61         Error error;
     62         value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error);
     63         if (error.Fail())
     64             return false;
     65     }
     66     else if (!strcmp(class_name,"__NSArrayM"))
     67     {
     68         Error error;
     69         value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error);
     70         if (error.Fail())
     71             return false;
     72     }
     73     else if (!strcmp(class_name,"__NSCFArray"))
     74     {
     75         Error error;
     76         value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + 2 * ptr_size, ptr_size, 0, error);
     77         if (error.Fail())
     78             return false;
     79     }
     80     else
     81     {
     82         if (!ExtractValueFromObjCExpression(valobj, "int", "count", value))
     83             return false;
     84     }
     85 
     86     stream.Printf("@\"%" PRIu64 " object%s\"",
     87                   value,
     88                   value == 1 ? "" : "s");
     89     return true;
     90 }
     91 
     92 lldb_private::formatters::NSArrayMSyntheticFrontEnd::NSArrayMSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
     93     SyntheticChildrenFrontEnd(*valobj_sp.get()),
     94     m_exe_ctx_ref(),
     95     m_ptr_size(8),
     96     m_data_32(NULL),
     97     m_data_64(NULL)
     98 {
     99     if (valobj_sp)
    100     {
    101         clang::ASTContext *ast = valobj_sp->GetClangType().GetASTContext();
    102         if (ast)
    103             m_id_type = ClangASTType(ast, ast->ObjCBuiltinIdTy);
    104     }
    105 }
    106 
    107 size_t
    108 lldb_private::formatters::NSArrayMSyntheticFrontEnd::CalculateNumChildren ()
    109 {
    110     if (m_data_32)
    111         return m_data_32->_used;
    112     if (m_data_64)
    113         return m_data_64->_used;
    114     return 0;
    115 }
    116 
    117 lldb::ValueObjectSP
    118 lldb_private::formatters::NSArrayMSyntheticFrontEnd::GetChildAtIndex (size_t idx)
    119 {
    120     if (!m_data_32 && !m_data_64)
    121         return lldb::ValueObjectSP();
    122     if (idx >= CalculateNumChildren())
    123         return lldb::ValueObjectSP();
    124     lldb::addr_t object_at_idx = (m_data_32 ? m_data_32->_data : m_data_64->_data);
    125     size_t pyhs_idx = idx;
    126     pyhs_idx += (m_data_32 ? m_data_32->offset : m_data_64->offset);
    127     if ((m_data_32 ? m_data_32->_size : m_data_64->_size) <= pyhs_idx)
    128         pyhs_idx -= (m_data_32 ? m_data_32->_size : m_data_64->_size);
    129     object_at_idx += (pyhs_idx * m_ptr_size);
    130     StreamString idx_name;
    131     idx_name.Printf("[%zu]",idx);
    132     lldb::ValueObjectSP retval_sp = ValueObject::CreateValueObjectFromAddress(idx_name.GetData(),
    133                                                                               object_at_idx,
    134                                                                               m_exe_ctx_ref,
    135                                                                               m_id_type);
    136     m_children.push_back(retval_sp);
    137     return retval_sp;
    138 }
    139 
    140 bool
    141 lldb_private::formatters::NSArrayMSyntheticFrontEnd::Update()
    142 {
    143     m_children.clear();
    144     ValueObjectSP valobj_sp = m_backend.GetSP();
    145     m_ptr_size = 0;
    146     delete m_data_32;
    147     m_data_32 = NULL;
    148     delete m_data_64;
    149     m_data_64 = NULL;
    150     if (!valobj_sp)
    151         return false;
    152     m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
    153     Error error;
    154     error.Clear();
    155     lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
    156     if (!process_sp)
    157         return false;
    158     m_ptr_size = process_sp->GetAddressByteSize();
    159     uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
    160     if (m_ptr_size == 4)
    161     {
    162         m_data_32 = new DataDescriptor_32();
    163         process_sp->ReadMemory (data_location, m_data_32, sizeof(DataDescriptor_32), error);
    164     }
    165     else
    166     {
    167         m_data_64 = new DataDescriptor_64();
    168         process_sp->ReadMemory (data_location, m_data_64, sizeof(DataDescriptor_64), error);
    169     }
    170     if (error.Fail())
    171         return false;
    172     return false;
    173 }
    174 
    175 bool
    176 lldb_private::formatters::NSArrayMSyntheticFrontEnd::MightHaveChildren ()
    177 {
    178     return true;
    179 }
    180 
    181 size_t
    182 lldb_private::formatters::NSArrayMSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
    183 {
    184     if (!m_data_32 && !m_data_64)
    185         return UINT32_MAX;
    186     const char* item_name = name.GetCString();
    187     uint32_t idx = ExtractIndexFromString(item_name);
    188     if (idx < UINT32_MAX && idx >= CalculateNumChildren())
    189         return UINT32_MAX;
    190     return idx;
    191 }
    192 
    193 lldb_private::formatters::NSArrayMSyntheticFrontEnd::~NSArrayMSyntheticFrontEnd ()
    194 {
    195     delete m_data_32;
    196     m_data_32 = NULL;
    197     delete m_data_64;
    198     m_data_64 = NULL;
    199 }
    200 
    201 lldb_private::formatters::NSArrayISyntheticFrontEnd::NSArrayISyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
    202     SyntheticChildrenFrontEnd (*valobj_sp.get()),
    203     m_exe_ctx_ref (),
    204     m_ptr_size (8),
    205     m_items (0),
    206     m_data_ptr (0)
    207 {
    208     if (valobj_sp)
    209     {
    210         clang::ASTContext *ast = valobj_sp->GetClangType().GetASTContext();
    211         if (ast)
    212             m_id_type = ClangASTType(ast, ast->ObjCBuiltinIdTy);
    213     }
    214 }
    215 
    216 lldb_private::formatters::NSArrayISyntheticFrontEnd::~NSArrayISyntheticFrontEnd ()
    217 {
    218 }
    219 
    220 size_t
    221 lldb_private::formatters::NSArrayISyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
    222 {
    223     const char* item_name = name.GetCString();
    224     uint32_t idx = ExtractIndexFromString(item_name);
    225     if (idx < UINT32_MAX && idx >= CalculateNumChildren())
    226         return UINT32_MAX;
    227     return idx;
    228 }
    229 
    230 size_t
    231 lldb_private::formatters::NSArrayISyntheticFrontEnd::CalculateNumChildren ()
    232 {
    233     return m_items;
    234 }
    235 
    236 bool
    237 lldb_private::formatters::NSArrayISyntheticFrontEnd::Update()
    238 {
    239     m_ptr_size = 0;
    240     m_items = 0;
    241     m_data_ptr = 0;
    242     m_children.clear();
    243     ValueObjectSP valobj_sp = m_backend.GetSP();
    244     if (!valobj_sp)
    245         return false;
    246     m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
    247     Error error;
    248     error.Clear();
    249     lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
    250     if (!process_sp)
    251         return false;
    252     m_ptr_size = process_sp->GetAddressByteSize();
    253     uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
    254     m_items = process_sp->ReadPointerFromMemory(data_location, error);
    255     if (error.Fail())
    256         return false;
    257     m_data_ptr = data_location+m_ptr_size;
    258     return false;
    259 }
    260 
    261 bool
    262 lldb_private::formatters::NSArrayISyntheticFrontEnd::MightHaveChildren ()
    263 {
    264     return true;
    265 }
    266 
    267 lldb::ValueObjectSP
    268 lldb_private::formatters::NSArrayISyntheticFrontEnd::GetChildAtIndex (size_t idx)
    269 {
    270     if (idx >= CalculateNumChildren())
    271         return lldb::ValueObjectSP();
    272     lldb::addr_t object_at_idx = m_data_ptr;
    273     object_at_idx += (idx * m_ptr_size);
    274     ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
    275     if (!process_sp)
    276         return lldb::ValueObjectSP();
    277     Error error;
    278     if (error.Fail())
    279         return lldb::ValueObjectSP();
    280     StreamString idx_name;
    281     idx_name.Printf("[%zu]",idx);
    282     lldb::ValueObjectSP retval_sp = ValueObject::CreateValueObjectFromAddress(idx_name.GetData(), object_at_idx, m_exe_ctx_ref, m_id_type);
    283     m_children.push_back(retval_sp);
    284     return retval_sp;
    285 }
    286 
    287 SyntheticChildrenFrontEnd* lldb_private::formatters::NSArraySyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
    288 {
    289     lldb::ProcessSP process_sp (valobj_sp->GetProcessSP());
    290     if (!process_sp)
    291         return NULL;
    292     ObjCLanguageRuntime *runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
    293     if (!runtime)
    294         return NULL;
    295 
    296     if (!valobj_sp->IsPointerType())
    297     {
    298         Error error;
    299         valobj_sp = valobj_sp->AddressOf(error);
    300         if (error.Fail() || !valobj_sp)
    301             return NULL;
    302     }
    303 
    304     ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(*valobj_sp.get()));
    305 
    306     if (!descriptor.get() || !descriptor->IsValid())
    307         return NULL;
    308 
    309     const char* class_name = descriptor->GetClassName().GetCString();
    310 
    311     if (!class_name || !*class_name)
    312         return NULL;
    313 
    314     if (!strcmp(class_name,"__NSArrayI"))
    315     {
    316         return (new NSArrayISyntheticFrontEnd(valobj_sp));
    317     }
    318     else if (!strcmp(class_name,"__NSArrayM"))
    319     {
    320         return (new NSArrayMSyntheticFrontEnd(valobj_sp));
    321     }
    322     else
    323     {
    324         return (new NSArrayCodeRunningSyntheticFrontEnd(valobj_sp));
    325     }
    326 }
    327 
    328 lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::NSArrayCodeRunningSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
    329 SyntheticChildrenFrontEnd(*valobj_sp.get())
    330 {}
    331 
    332 size_t
    333 lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::CalculateNumChildren ()
    334 {
    335     uint64_t count = 0;
    336     if (ExtractValueFromObjCExpression(m_backend, "int", "count", count))
    337         return count;
    338     return 0;
    339 }
    340 
    341 lldb::ValueObjectSP
    342 lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::GetChildAtIndex (size_t idx)
    343 {
    344     StreamString idx_name;
    345     idx_name.Printf("[%zu]",idx);
    346     lldb::ValueObjectSP valobj_sp = CallSelectorOnObject(m_backend,"id","objectAtIndex:",idx);
    347     if (valobj_sp)
    348         valobj_sp->SetName(ConstString(idx_name.GetData()));
    349     return valobj_sp;
    350 }
    351 
    352 bool
    353 lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::Update()
    354 {
    355     return false;
    356 }
    357 
    358 bool
    359 lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::MightHaveChildren ()
    360 {
    361     return true;
    362 }
    363 
    364 size_t
    365 lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
    366 {
    367     return 0;
    368 }
    369 
    370 lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::~NSArrayCodeRunningSyntheticFrontEnd ()
    371 {}
    372