Home | History | Annotate | Download | only in DataFormatters
      1 //===-- LibCxxList.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 class MapEntry
     29 {
     30 public:
     31     MapEntry () {}
     32     MapEntry (ValueObjectSP entry_sp) : m_entry_sp(entry_sp) {}
     33     MapEntry (const MapEntry& rhs) : m_entry_sp(rhs.m_entry_sp) {}
     34     MapEntry (ValueObject* entry) : m_entry_sp(entry ? entry->GetSP() : ValueObjectSP()) {}
     35 
     36     ValueObjectSP
     37     left ()
     38     {
     39         if (!m_entry_sp)
     40             return m_entry_sp;
     41         return m_entry_sp->GetChildMemberWithName(ConstString("__left_"), true);
     42     }
     43 
     44     ValueObjectSP
     45     right ()
     46     {
     47         if (!m_entry_sp)
     48             return m_entry_sp;
     49         return m_entry_sp->GetChildMemberWithName(ConstString("__right_"), true);
     50     }
     51 
     52     ValueObjectSP
     53     parent ()
     54     {
     55         if (!m_entry_sp)
     56             return m_entry_sp;
     57         return m_entry_sp->GetChildMemberWithName(ConstString("__parent_"), true);
     58     }
     59 
     60     uint64_t
     61     value ()
     62     {
     63         if (!m_entry_sp)
     64             return 0;
     65         return m_entry_sp->GetValueAsUnsigned(0);
     66     }
     67 
     68     bool
     69     error ()
     70     {
     71         if (!m_entry_sp)
     72             return true;
     73         return m_entry_sp->GetError().Fail();
     74     }
     75 
     76     bool
     77     null()
     78     {
     79         return (value() == 0);
     80     }
     81 
     82     ValueObjectSP
     83     GetEntry ()
     84     {
     85         return m_entry_sp;
     86     }
     87 
     88     void
     89     SetEntry (ValueObjectSP entry)
     90     {
     91         m_entry_sp = entry;
     92     }
     93 
     94     bool
     95     operator == (const MapEntry& rhs) const
     96     {
     97         return (rhs.m_entry_sp.get() == m_entry_sp.get());
     98     }
     99 
    100 private:
    101     ValueObjectSP m_entry_sp;
    102 };
    103 
    104 class MapIterator
    105 {
    106 public:
    107     MapIterator () {}
    108     MapIterator (MapEntry entry, size_t depth = 0) : m_entry(entry), m_max_depth(depth), m_error(false) {}
    109     MapIterator (ValueObjectSP entry, size_t depth = 0) : m_entry(entry), m_max_depth(depth), m_error(false) {}
    110     MapIterator (const MapIterator& rhs) : m_entry(rhs.m_entry),m_max_depth(rhs.m_max_depth), m_error(false) {}
    111     MapIterator (ValueObject* entry, size_t depth = 0) : m_entry(entry), m_max_depth(depth), m_error(false) {}
    112 
    113     ValueObjectSP
    114     value ()
    115     {
    116         return m_entry.GetEntry();
    117     }
    118 
    119     ValueObjectSP
    120     advance (size_t count)
    121     {
    122         if (m_error)
    123             return lldb::ValueObjectSP();
    124         if (count == 0)
    125             return m_entry.GetEntry();
    126         if (count == 1)
    127         {
    128             next ();
    129             return m_entry.GetEntry();
    130         }
    131         size_t steps = 0;
    132         while (count > 0)
    133         {
    134             if (m_error)
    135                 return lldb::ValueObjectSP();
    136             next ();
    137             count--;
    138             if (m_entry.null())
    139                 return lldb::ValueObjectSP();
    140             steps++;
    141             if (steps > m_max_depth)
    142                 return lldb::ValueObjectSP();
    143         }
    144         return m_entry.GetEntry();
    145     }
    146 protected:
    147     void
    148     next ()
    149     {
    150         m_entry.SetEntry(increment(m_entry.GetEntry()));
    151     }
    152 
    153 private:
    154     ValueObjectSP
    155     tree_min (ValueObjectSP x_sp)
    156     {
    157         MapEntry x(x_sp);
    158         if (x.null())
    159             return ValueObjectSP();
    160         MapEntry left(x.left());
    161         size_t steps = 0;
    162         while (left.null() == false)
    163         {
    164             if (left.error())
    165             {
    166                 m_error = true;
    167                 return lldb::ValueObjectSP();
    168             }
    169             x.SetEntry(left.GetEntry());
    170             left.SetEntry(x.left());
    171             steps++;
    172             if (steps > m_max_depth)
    173                 return lldb::ValueObjectSP();
    174         }
    175         return x.GetEntry();
    176     }
    177 
    178     ValueObjectSP
    179     tree_max (ValueObjectSP x_sp)
    180     {
    181         MapEntry x(x_sp);
    182         if (x.null())
    183             return ValueObjectSP();
    184         MapEntry right(x.right());
    185         size_t steps = 0;
    186         while (right.null() == false)
    187         {
    188             if (right.error())
    189                 return lldb::ValueObjectSP();
    190             x.SetEntry(right.GetEntry());
    191             right.SetEntry(x.right());
    192             steps++;
    193             if (steps > m_max_depth)
    194                 return lldb::ValueObjectSP();
    195         }
    196         return x.GetEntry();
    197     }
    198 
    199     bool
    200     is_left_child (ValueObjectSP x_sp)
    201     {
    202         MapEntry x(x_sp);
    203         if (x.null())
    204             return false;
    205         MapEntry rhs(x.parent());
    206         rhs.SetEntry(rhs.left());
    207         return x.value() == rhs.value();
    208     }
    209 
    210     ValueObjectSP
    211     increment (ValueObjectSP x_sp)
    212     {
    213         MapEntry node(x_sp);
    214         if (node.null())
    215             return ValueObjectSP();
    216         MapEntry right(node.right());
    217         if (right.null() == false)
    218             return tree_min(right.GetEntry());
    219         size_t steps = 0;
    220         while (!is_left_child(node.GetEntry()))
    221         {
    222             if (node.error())
    223             {
    224                 m_error = true;
    225                 return lldb::ValueObjectSP();
    226             }
    227             node.SetEntry(node.parent());
    228             steps++;
    229             if (steps > m_max_depth)
    230                 return lldb::ValueObjectSP();
    231         }
    232         return node.parent();
    233     }
    234 
    235     MapEntry m_entry;
    236     size_t m_max_depth;
    237     bool m_error;
    238 };
    239 
    240 lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::LibcxxStdMapSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
    241 SyntheticChildrenFrontEnd(*valobj_sp.get()),
    242 m_tree(NULL),
    243 m_root_node(NULL),
    244 m_element_type(),
    245 m_skip_size(UINT32_MAX),
    246 m_count(UINT32_MAX),
    247 m_children()
    248 {
    249     if (valobj_sp)
    250         Update();
    251 }
    252 
    253 size_t
    254 lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::CalculateNumChildren ()
    255 {
    256     if (m_count != UINT32_MAX)
    257         return m_count;
    258     if (m_tree == NULL)
    259         return 0;
    260     ValueObjectSP m_item(m_tree->GetChildMemberWithName(ConstString("__pair3_"), true));
    261     if (!m_item)
    262         return 0;
    263     m_item = m_item->GetChildMemberWithName(ConstString("__first_"), true);
    264     if (!m_item)
    265         return 0;
    266     m_count = m_item->GetValueAsUnsigned(0);
    267     return m_count;
    268 }
    269 
    270 bool
    271 lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetDataType()
    272 {
    273     if (m_element_type.GetOpaqueQualType() && m_element_type.GetASTContext())
    274         return true;
    275     m_element_type.Clear();
    276     ValueObjectSP deref;
    277     Error error;
    278     deref = m_root_node->Dereference(error);
    279     if (!deref || error.Fail())
    280         return false;
    281     deref = deref->GetChildMemberWithName(ConstString("__value_"), true);
    282     if (!deref)
    283         return false;
    284     m_element_type = deref->GetClangType();
    285     return true;
    286 }
    287 
    288 void
    289 lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetValueOffset (const lldb::ValueObjectSP& node)
    290 {
    291     if (m_skip_size != UINT32_MAX)
    292         return;
    293     if (!node)
    294         return;
    295     ClangASTType node_type(node->GetClangType());
    296     uint64_t bit_offset;
    297     if (node_type.GetIndexOfFieldWithName("__value_", NULL, &bit_offset) == UINT32_MAX)
    298         return;
    299     m_skip_size = bit_offset / 8u;
    300 }
    301 
    302 lldb::ValueObjectSP
    303 lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetChildAtIndex (size_t idx)
    304 {
    305     if (idx >= CalculateNumChildren())
    306         return lldb::ValueObjectSP();
    307     if (m_tree == NULL || m_root_node == NULL)
    308         return lldb::ValueObjectSP();
    309 
    310     auto cached = m_children.find(idx);
    311     if (cached != m_children.end())
    312         return cached->second;
    313 
    314     bool need_to_skip = (idx > 0);
    315     MapIterator iterator(m_root_node, CalculateNumChildren());
    316     ValueObjectSP iterated_sp(iterator.advance(idx));
    317     if (iterated_sp.get() == NULL)
    318     {
    319         // this tree is garbage - stop
    320         m_tree = NULL; // this will stop all future searches until an Update() happens
    321         return iterated_sp;
    322     }
    323     if (GetDataType())
    324     {
    325         if (!need_to_skip)
    326         {
    327             Error error;
    328             iterated_sp = iterated_sp->Dereference(error);
    329             if (!iterated_sp || error.Fail())
    330             {
    331                 m_tree = NULL;
    332                 return lldb::ValueObjectSP();
    333             }
    334             GetValueOffset(iterated_sp);
    335             iterated_sp = iterated_sp->GetChildMemberWithName(ConstString("__value_"), true);
    336             if (!iterated_sp)
    337             {
    338                 m_tree = NULL;
    339                 return lldb::ValueObjectSP();
    340             }
    341         }
    342         else
    343         {
    344             // because of the way our debug info is made, we need to read item 0 first
    345             // so that we can cache information used to generate other elements
    346             if (m_skip_size == UINT32_MAX)
    347                 GetChildAtIndex(0);
    348             if (m_skip_size == UINT32_MAX)
    349             {
    350                 m_tree = NULL;
    351                 return lldb::ValueObjectSP();
    352             }
    353             iterated_sp = iterated_sp->GetSyntheticChildAtOffset(m_skip_size, m_element_type, true);
    354             if (!iterated_sp)
    355             {
    356                 m_tree = NULL;
    357                 return lldb::ValueObjectSP();
    358             }
    359         }
    360     }
    361     else
    362     {
    363         m_tree = NULL;
    364         return lldb::ValueObjectSP();
    365     }
    366     // at this point we have a valid
    367     // we need to copy current_sp into a new object otherwise we will end up with all items named __value_
    368     DataExtractor data;
    369     iterated_sp->GetData(data);
    370     StreamString name;
    371     name.Printf("[%zu]",idx);
    372     return (m_children[idx] = ValueObject::CreateValueObjectFromData(name.GetData(), data, m_backend.GetExecutionContextRef(), m_element_type));
    373 }
    374 
    375 bool
    376 lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::Update()
    377 {
    378     m_count = UINT32_MAX;
    379     m_tree = m_root_node = NULL;
    380     m_children.clear();
    381     m_tree = m_backend.GetChildMemberWithName(ConstString("__tree_"), true).get();
    382     if (!m_tree)
    383         return false;
    384     m_root_node = m_tree->GetChildMemberWithName(ConstString("__begin_node_"), true).get();
    385     return false;
    386 }
    387 
    388 bool
    389 lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::MightHaveChildren ()
    390 {
    391     return true;
    392 }
    393 
    394 size_t
    395 lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
    396 {
    397     return ExtractIndexFromString(name.GetCString());
    398 }
    399 
    400 lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::~LibcxxStdMapSyntheticFrontEnd ()
    401 {}
    402 
    403 SyntheticChildrenFrontEnd*
    404 lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
    405 {
    406     if (!valobj_sp)
    407         return NULL;
    408     return (new LibcxxStdMapSyntheticFrontEnd(valobj_sp));
    409 }
    410