Home | History | Annotate | Download | only in DataFormatters
      1 //===-- NSSet.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 template<bool cf_style>
     29 bool
     30 lldb_private::formatters::NSSetSummaryProvider (ValueObject& valobj, Stream& stream)
     31 {
     32     ProcessSP process_sp = valobj.GetProcessSP();
     33     if (!process_sp)
     34         return false;
     35 
     36     ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
     37 
     38     if (!runtime)
     39         return false;
     40 
     41     ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
     42 
     43     if (!descriptor.get() || !descriptor->IsValid())
     44         return false;
     45 
     46     uint32_t ptr_size = process_sp->GetAddressByteSize();
     47     bool is_64bit = (ptr_size == 8);
     48 
     49     lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
     50 
     51     if (!valobj_addr)
     52         return false;
     53 
     54     uint64_t value = 0;
     55 
     56     const char* class_name = descriptor->GetClassName().GetCString();
     57 
     58     if (!class_name || !*class_name)
     59         return false;
     60 
     61     if (!strcmp(class_name,"__NSSetI"))
     62     {
     63         Error error;
     64         value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error);
     65         if (error.Fail())
     66             return false;
     67         value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
     68     }
     69     else if (!strcmp(class_name,"__NSSetM"))
     70     {
     71         Error error;
     72         value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error);
     73         if (error.Fail())
     74             return false;
     75         value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
     76     }
     77     /*else if (!strcmp(class_name,"__NSCFSet"))
     78     {
     79         Error error;
     80         value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + (is_64bit ? 20 : 12), 4, 0, error);
     81         if (error.Fail())
     82             return false;
     83         if (is_64bit)
     84             value &= ~0x1fff000000000000UL;
     85     }
     86     else if (!strcmp(class_name,"NSCountedSet"))
     87     {
     88         Error error;
     89         value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error);
     90         if (error.Fail())
     91             return false;
     92         value = process_sp->ReadUnsignedIntegerFromMemory(value + (is_64bit ? 20 : 12), 4, 0, error);
     93         if (error.Fail())
     94             return false;
     95         if (is_64bit)
     96             value &= ~0x1fff000000000000UL;
     97     }*/
     98     else
     99     {
    100         if (!ExtractValueFromObjCExpression(valobj, "int", "count", value))
    101             return false;
    102     }
    103 
    104     stream.Printf("%s%" PRIu64 " %s%s",
    105                   (cf_style ? "@\"" : ""),
    106                   value,
    107                   (cf_style ? (value == 1 ? "value" : "values") : (value == 1 ? "object" : "objects")),
    108                   (cf_style ? "\"" : ""));
    109     return true;
    110 }
    111 
    112 SyntheticChildrenFrontEnd* lldb_private::formatters::NSSetSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
    113 {
    114     lldb::ProcessSP process_sp (valobj_sp->GetProcessSP());
    115     if (!process_sp)
    116         return NULL;
    117     ObjCLanguageRuntime *runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
    118     if (!runtime)
    119         return NULL;
    120 
    121     if (!valobj_sp->IsPointerType())
    122     {
    123         Error error;
    124         valobj_sp = valobj_sp->AddressOf(error);
    125         if (error.Fail() || !valobj_sp)
    126             return NULL;
    127     }
    128 
    129     ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(*valobj_sp.get()));
    130 
    131     if (!descriptor.get() || !descriptor->IsValid())
    132         return NULL;
    133 
    134     const char* class_name = descriptor->GetClassName().GetCString();
    135 
    136     if (!class_name || !*class_name)
    137         return NULL;
    138 
    139     if (!strcmp(class_name,"__NSSetI"))
    140     {
    141         return (new NSSetISyntheticFrontEnd(valobj_sp));
    142     }
    143     else if (!strcmp(class_name,"__NSSetM"))
    144     {
    145         return (new NSSetMSyntheticFrontEnd(valobj_sp));
    146     }
    147     else if ((!strcmp(class_name,"__NSOrderedSetI")) || (!strcmp(class_name,"__NSOrderedSetM")))
    148     {
    149         return new NSOrderedSetSyntheticFrontEnd(valobj_sp); // this runs code
    150     }
    151     else
    152     {
    153         return /*(new NSSetCodeRunningSyntheticFrontEnd(valobj_sp))*/ NULL;
    154     }
    155 }
    156 
    157 lldb_private::formatters::NSSetISyntheticFrontEnd::NSSetISyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
    158 SyntheticChildrenFrontEnd(*valobj_sp.get()),
    159 m_exe_ctx_ref(),
    160 m_ptr_size(8),
    161 m_data_32(NULL),
    162 m_data_64(NULL)
    163 {
    164     if (valobj_sp)
    165         Update();
    166 }
    167 
    168 lldb_private::formatters::NSSetISyntheticFrontEnd::~NSSetISyntheticFrontEnd ()
    169 {
    170     delete m_data_32;
    171     m_data_32 = NULL;
    172     delete m_data_64;
    173     m_data_64 = NULL;
    174 }
    175 
    176 size_t
    177 lldb_private::formatters::NSSetISyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
    178 {
    179     const char* item_name = name.GetCString();
    180     uint32_t idx = ExtractIndexFromString(item_name);
    181     if (idx < UINT32_MAX && idx >= CalculateNumChildren())
    182         return UINT32_MAX;
    183     return idx;
    184 }
    185 
    186 size_t
    187 lldb_private::formatters::NSSetISyntheticFrontEnd::CalculateNumChildren ()
    188 {
    189     if (!m_data_32 && !m_data_64)
    190         return 0;
    191     return (m_data_32 ? m_data_32->_used : m_data_64->_used);
    192 }
    193 
    194 bool
    195 lldb_private::formatters::NSSetISyntheticFrontEnd::Update()
    196 {
    197     m_children.clear();
    198     delete m_data_32;
    199     m_data_32 = NULL;
    200     delete m_data_64;
    201     m_data_64 = NULL;
    202     m_ptr_size = 0;
    203     ValueObjectSP valobj_sp = m_backend.GetSP();
    204     if (!valobj_sp)
    205         return false;
    206     if (!valobj_sp)
    207         return false;
    208     m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
    209     Error error;
    210     if (valobj_sp->IsPointerType())
    211     {
    212         valobj_sp = valobj_sp->Dereference(error);
    213         if (error.Fail() || !valobj_sp)
    214             return false;
    215     }
    216     error.Clear();
    217     lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
    218     if (!process_sp)
    219         return false;
    220     m_ptr_size = process_sp->GetAddressByteSize();
    221     uint64_t data_location = valobj_sp->GetAddressOf() + m_ptr_size;
    222     if (m_ptr_size == 4)
    223     {
    224         m_data_32 = new DataDescriptor_32();
    225         process_sp->ReadMemory (data_location, m_data_32, sizeof(DataDescriptor_32), error);
    226     }
    227     else
    228     {
    229         m_data_64 = new DataDescriptor_64();
    230         process_sp->ReadMemory (data_location, m_data_64, sizeof(DataDescriptor_64), error);
    231     }
    232     if (error.Fail())
    233         return false;
    234     m_data_ptr = data_location + m_ptr_size;
    235     return false;
    236 }
    237 
    238 bool
    239 lldb_private::formatters::NSSetISyntheticFrontEnd::MightHaveChildren ()
    240 {
    241     return true;
    242 }
    243 
    244 lldb::ValueObjectSP
    245 lldb_private::formatters::NSSetISyntheticFrontEnd::GetChildAtIndex (size_t idx)
    246 {
    247     uint32_t num_children = CalculateNumChildren();
    248 
    249     if (idx >= num_children)
    250         return lldb::ValueObjectSP();
    251 
    252     if (m_children.empty())
    253     {
    254         // do the scan phase
    255         lldb::addr_t obj_at_idx = 0;
    256 
    257         uint32_t tries = 0;
    258         uint32_t test_idx = 0;
    259 
    260         while(tries < num_children)
    261         {
    262             obj_at_idx = m_data_ptr + (test_idx * m_ptr_size);
    263             ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
    264             if (!process_sp)
    265                 return lldb::ValueObjectSP();
    266             Error error;
    267             obj_at_idx = process_sp->ReadPointerFromMemory(obj_at_idx, error);
    268             if (error.Fail())
    269                 return lldb::ValueObjectSP();
    270 
    271             test_idx++;
    272 
    273             if (!obj_at_idx)
    274                 continue;
    275             tries++;
    276 
    277             SetItemDescriptor descriptor = {obj_at_idx,lldb::ValueObjectSP()};
    278 
    279             m_children.push_back(descriptor);
    280         }
    281     }
    282 
    283     if (idx >= m_children.size()) // should never happen
    284         return lldb::ValueObjectSP();
    285 
    286     SetItemDescriptor &set_item = m_children[idx];
    287     if (!set_item.valobj_sp)
    288     {
    289         // make the new ValueObject
    290         StreamString expr;
    291         expr.Printf("(id)%" PRIu64,set_item.item_ptr);
    292         StreamString idx_name;
    293         idx_name.Printf("[%zu]",idx);
    294         set_item.valobj_sp = ValueObject::CreateValueObjectFromExpression(idx_name.GetData(), expr.GetData(), m_exe_ctx_ref);
    295     }
    296     return set_item.valobj_sp;
    297 }
    298 
    299 lldb_private::formatters::NSSetMSyntheticFrontEnd::NSSetMSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
    300 SyntheticChildrenFrontEnd(*valobj_sp.get()),
    301 m_exe_ctx_ref(),
    302 m_ptr_size(8),
    303 m_data_32(NULL),
    304 m_data_64(NULL)
    305 {
    306     if (valobj_sp)
    307         Update ();
    308 }
    309 
    310 lldb_private::formatters::NSSetMSyntheticFrontEnd::~NSSetMSyntheticFrontEnd ()
    311 {
    312     delete m_data_32;
    313     m_data_32 = NULL;
    314     delete m_data_64;
    315     m_data_64 = NULL;
    316 }
    317 
    318 size_t
    319 lldb_private::formatters::NSSetMSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
    320 {
    321     const char* item_name = name.GetCString();
    322     uint32_t idx = ExtractIndexFromString(item_name);
    323     if (idx < UINT32_MAX && idx >= CalculateNumChildren())
    324         return UINT32_MAX;
    325     return idx;
    326 }
    327 
    328 size_t
    329 lldb_private::formatters::NSSetMSyntheticFrontEnd::CalculateNumChildren ()
    330 {
    331     if (!m_data_32 && !m_data_64)
    332         return 0;
    333     return (m_data_32 ? m_data_32->_used : m_data_64->_used);
    334 }
    335 
    336 bool
    337 lldb_private::formatters::NSSetMSyntheticFrontEnd::Update()
    338 {
    339     m_children.clear();
    340     ValueObjectSP valobj_sp = m_backend.GetSP();
    341     m_ptr_size = 0;
    342     delete m_data_32;
    343     m_data_32 = NULL;
    344     delete m_data_64;
    345     m_data_64 = NULL;
    346     if (!valobj_sp)
    347         return false;
    348     if (!valobj_sp)
    349         return false;
    350     m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
    351     Error error;
    352     if (valobj_sp->IsPointerType())
    353     {
    354         valobj_sp = valobj_sp->Dereference(error);
    355         if (error.Fail() || !valobj_sp)
    356             return false;
    357     }
    358     error.Clear();
    359     lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
    360     if (!process_sp)
    361         return false;
    362     m_ptr_size = process_sp->GetAddressByteSize();
    363     uint64_t data_location = valobj_sp->GetAddressOf() + m_ptr_size;
    364     if (m_ptr_size == 4)
    365     {
    366         m_data_32 = new DataDescriptor_32();
    367         process_sp->ReadMemory (data_location, m_data_32, sizeof(DataDescriptor_32), error);
    368     }
    369     else
    370     {
    371         m_data_64 = new DataDescriptor_64();
    372         process_sp->ReadMemory (data_location, m_data_64, sizeof(DataDescriptor_64), error);
    373     }
    374     if (error.Fail())
    375         return false;
    376     return false;
    377 }
    378 
    379 bool
    380 lldb_private::formatters::NSSetMSyntheticFrontEnd::MightHaveChildren ()
    381 {
    382     return true;
    383 }
    384 
    385 lldb::ValueObjectSP
    386 lldb_private::formatters::NSSetMSyntheticFrontEnd::GetChildAtIndex (size_t idx)
    387 {
    388     lldb::addr_t m_objs_addr = (m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr);
    389 
    390     uint32_t num_children = CalculateNumChildren();
    391 
    392     if (idx >= num_children)
    393         return lldb::ValueObjectSP();
    394 
    395     if (m_children.empty())
    396     {
    397         // do the scan phase
    398         lldb::addr_t obj_at_idx = 0;
    399 
    400         uint32_t tries = 0;
    401         uint32_t test_idx = 0;
    402 
    403         while(tries < num_children)
    404         {
    405             obj_at_idx = m_objs_addr + (test_idx * m_ptr_size);
    406             ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
    407             if (!process_sp)
    408                 return lldb::ValueObjectSP();
    409             Error error;
    410             obj_at_idx = process_sp->ReadPointerFromMemory(obj_at_idx, error);
    411             if (error.Fail())
    412                 return lldb::ValueObjectSP();
    413 
    414             test_idx++;
    415 
    416             if (!obj_at_idx)
    417                 continue;
    418             tries++;
    419 
    420             SetItemDescriptor descriptor = {obj_at_idx,lldb::ValueObjectSP()};
    421 
    422             m_children.push_back(descriptor);
    423         }
    424     }
    425 
    426     if (idx >= m_children.size()) // should never happen
    427         return lldb::ValueObjectSP();
    428 
    429     SetItemDescriptor &set_item = m_children[idx];
    430     if (!set_item.valobj_sp)
    431     {
    432         // make the new ValueObject
    433         StreamString expr;
    434         expr.Printf("(id)%" PRIu64,set_item.item_ptr);
    435         StreamString idx_name;
    436         idx_name.Printf("[%zu]",idx);
    437         set_item.valobj_sp = ValueObject::CreateValueObjectFromExpression(idx_name.GetData(), expr.GetData(), m_exe_ctx_ref);
    438     }
    439     return set_item.valobj_sp;
    440 }
    441 
    442 lldb_private::formatters::NSOrderedSetSyntheticFrontEnd::NSOrderedSetSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
    443 SyntheticChildrenFrontEnd(*valobj_sp.get()),
    444 m_count(UINT32_MAX),
    445 m_children()
    446 {}
    447 
    448 size_t
    449 lldb_private::formatters::NSOrderedSetSyntheticFrontEnd::CalculateNumChildren ()
    450 {
    451     if (m_count != UINT32_MAX)
    452         return m_count;
    453     uint64_t count_temp;
    454     if (ExtractValueFromObjCExpression(m_backend,"unsigned int","count",count_temp))
    455         return (m_count = count_temp);
    456     return (m_count = 0);
    457 }
    458 
    459 lldb::ValueObjectSP
    460 lldb_private::formatters::NSOrderedSetSyntheticFrontEnd::GetChildAtIndex (size_t idx)
    461 {
    462     auto iter = m_children.find(idx);
    463     if (iter == m_children.end())
    464     {
    465         lldb::ValueObjectSP retval_sp;
    466         if (idx <= m_count)
    467         {
    468             retval_sp = CallSelectorOnObject(m_backend, "id", "objectAtIndex", idx);
    469             if (retval_sp)
    470             {
    471                 StreamString idx_name;
    472                 idx_name.Printf("[%zu]",idx);
    473                 retval_sp->SetName(ConstString(idx_name.GetData()));
    474             }
    475             m_children[idx] = retval_sp;
    476         }
    477         return retval_sp;
    478     }
    479     else
    480         return iter->second;
    481 }
    482 
    483 bool
    484 lldb_private::formatters::NSOrderedSetSyntheticFrontEnd::Update()
    485 {
    486     return false;
    487 }
    488 
    489 bool
    490 lldb_private::formatters::NSOrderedSetSyntheticFrontEnd::MightHaveChildren ()
    491 {
    492     return true;
    493 }
    494 
    495 size_t
    496 lldb_private::formatters::NSOrderedSetSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
    497 {
    498     const char* item_name = name.GetCString();
    499     uint32_t idx = ExtractIndexFromString(item_name);
    500     if (idx < UINT32_MAX && idx >= CalculateNumChildren())
    501         return UINT32_MAX;
    502     return idx;
    503 }
    504 
    505 lldb_private::formatters::NSOrderedSetSyntheticFrontEnd::~NSOrderedSetSyntheticFrontEnd ()
    506 {
    507 }
    508 
    509 template bool
    510 lldb_private::formatters::NSSetSummaryProvider<true> (ValueObject& valobj, Stream& stream);
    511 
    512 template bool
    513 lldb_private::formatters::NSSetSummaryProvider<false> (ValueObject& valobj, Stream& stream);
    514