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 ListEntry
     29 {
     30 public:
     31     ListEntry () {}
     32     ListEntry (ValueObjectSP entry_sp) : m_entry_sp(entry_sp) {}
     33     ListEntry (const ListEntry& rhs) : m_entry_sp(rhs.m_entry_sp) {}
     34     ListEntry (ValueObject* entry) : m_entry_sp(entry ? entry->GetSP() : ValueObjectSP()) {}
     35 
     36     ValueObjectSP
     37     next ()
     38     {
     39         if (!m_entry_sp)
     40             return m_entry_sp;
     41         return m_entry_sp->GetChildMemberWithName(ConstString("__next_"), true);
     42     }
     43 
     44     ValueObjectSP
     45     prev ()
     46     {
     47         if (!m_entry_sp)
     48             return m_entry_sp;
     49         return m_entry_sp->GetChildMemberWithName(ConstString("__prev_"), true);
     50     }
     51 
     52     uint64_t
     53     value ()
     54     {
     55         if (!m_entry_sp)
     56             return 0;
     57         return m_entry_sp->GetValueAsUnsigned(0);
     58     }
     59 
     60     bool
     61     null()
     62     {
     63         return (value() == 0);
     64     }
     65 
     66     ValueObjectSP
     67     GetEntry ()
     68     {
     69         return m_entry_sp;
     70     }
     71 
     72     void
     73     SetEntry (ValueObjectSP entry)
     74     {
     75         m_entry_sp = entry;
     76     }
     77 
     78     bool
     79     operator == (const ListEntry& rhs) const
     80     {
     81         return (rhs.m_entry_sp.get() == m_entry_sp.get());
     82     }
     83 
     84 private:
     85     ValueObjectSP m_entry_sp;
     86 };
     87 
     88 class ListIterator
     89 {
     90 public:
     91     ListIterator () {}
     92     ListIterator (ListEntry entry) : m_entry(entry) {}
     93     ListIterator (ValueObjectSP entry) : m_entry(entry) {}
     94     ListIterator (const ListIterator& rhs) : m_entry(rhs.m_entry) {}
     95     ListIterator (ValueObject* entry) : m_entry(entry) {}
     96 
     97     ValueObjectSP
     98     value ()
     99     {
    100         return m_entry.GetEntry();
    101     }
    102 
    103     ValueObjectSP
    104     advance (size_t count)
    105     {
    106         if (count == 0)
    107             return m_entry.GetEntry();
    108         if (count == 1)
    109         {
    110             next ();
    111             return m_entry.GetEntry();
    112         }
    113         while (count > 0)
    114         {
    115             next ();
    116             count--;
    117             if (m_entry.null())
    118                 return lldb::ValueObjectSP();
    119         }
    120         return m_entry.GetEntry();
    121     }
    122 
    123     bool
    124     operator == (const ListIterator& rhs) const
    125     {
    126         return (rhs.m_entry == m_entry);
    127     }
    128 
    129 protected:
    130     void
    131     next ()
    132     {
    133         m_entry.SetEntry(m_entry.next());
    134     }
    135 
    136     void
    137     prev ()
    138     {
    139         m_entry.SetEntry(m_entry.prev());
    140     }
    141 private:
    142     ListEntry m_entry;
    143 };
    144 
    145 lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::LibcxxStdListSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
    146 SyntheticChildrenFrontEnd(*valobj_sp.get()),
    147 m_list_capping_size(0),
    148 m_node_address(),
    149 m_head(NULL),
    150 m_tail(NULL),
    151 m_element_type(),
    152 m_count(UINT32_MAX),
    153 m_children()
    154 {
    155     if (valobj_sp)
    156         Update();
    157 }
    158 
    159 bool
    160 lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::HasLoop()
    161 {
    162     if (g_use_loop_detect == false)
    163         return false;
    164     ListEntry slow(m_head);
    165     ListEntry fast1(m_head);
    166     ListEntry fast2(m_head);
    167     while (slow.next() && slow.next()->GetValueAsUnsigned(0) != m_node_address)
    168     {
    169         auto slow_value = slow.value();
    170         fast1.SetEntry(fast2.next());
    171         fast2.SetEntry(fast1.next());
    172         if (fast1.value() == slow_value || fast2.value() == slow_value)
    173             return true;
    174         slow.SetEntry(slow.next());
    175     }
    176     return false;
    177 }
    178 
    179 size_t
    180 lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::CalculateNumChildren ()
    181 {
    182     if (m_count != UINT32_MAX)
    183         return m_count;
    184     if (!m_head || !m_tail || m_node_address == 0)
    185         return 0;
    186     ValueObjectSP size_alloc(m_backend.GetChildMemberWithName(ConstString("__size_alloc_"), true));
    187     if (size_alloc)
    188     {
    189         ValueObjectSP first(size_alloc->GetChildMemberWithName(ConstString("__first_"), true));
    190         if (first)
    191         {
    192             m_count = first->GetValueAsUnsigned(UINT32_MAX);
    193         }
    194     }
    195     if (m_count != UINT32_MAX)
    196     {
    197         if (!HasLoop())
    198             return m_count;
    199         return m_count = 0;
    200     }
    201     else
    202     {
    203         uint64_t next_val = m_head->GetValueAsUnsigned(0);
    204         uint64_t prev_val = m_tail->GetValueAsUnsigned(0);
    205         if (next_val == 0 || prev_val == 0)
    206             return 0;
    207         if (next_val == m_node_address)
    208             return 0;
    209         if (next_val == prev_val)
    210             return 1;
    211         if (HasLoop())
    212             return 0;
    213         uint64_t size = 2;
    214         ListEntry current(m_head);
    215         while (current.next() && current.next()->GetValueAsUnsigned(0) != m_node_address)
    216         {
    217             size++;
    218             current.SetEntry(current.next());
    219             if (size > m_list_capping_size)
    220                 break;
    221         }
    222         return m_count = (size-1);
    223     }
    224 }
    225 
    226 lldb::ValueObjectSP
    227 lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::GetChildAtIndex (size_t idx)
    228 {
    229     if (idx >= CalculateNumChildren())
    230         return lldb::ValueObjectSP();
    231 
    232     if (!m_head || !m_tail || m_node_address == 0)
    233         return lldb::ValueObjectSP();
    234 
    235     auto cached = m_children.find(idx);
    236     if (cached != m_children.end())
    237         return cached->second;
    238 
    239     ListIterator current(m_head);
    240     ValueObjectSP current_sp(current.advance(idx));
    241     if (!current_sp)
    242         return lldb::ValueObjectSP();
    243     current_sp = current_sp->GetChildMemberWithName(ConstString("__value_"), true);
    244     if (!current_sp)
    245         return lldb::ValueObjectSP();
    246     // we need to copy current_sp into a new object otherwise we will end up with all items named __value_
    247     DataExtractor data;
    248     current_sp->GetData(data);
    249     StreamString name;
    250     name.Printf("[%zu]",idx);
    251     return (m_children[idx] = ValueObject::CreateValueObjectFromData(name.GetData(), data, m_backend.GetExecutionContextRef(), m_element_type));
    252 }
    253 
    254 bool
    255 lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::Update()
    256 {
    257     m_head = m_tail = NULL;
    258     m_node_address = 0;
    259     m_count = UINT32_MAX;
    260     Error err;
    261     ValueObjectSP backend_addr(m_backend.AddressOf(err));
    262     m_list_capping_size = 0;
    263     if (m_backend.GetTargetSP())
    264         m_list_capping_size = m_backend.GetTargetSP()->GetMaximumNumberOfChildrenToDisplay();
    265     if (m_list_capping_size == 0)
    266         m_list_capping_size = 255;
    267     if (err.Fail() || backend_addr.get() == NULL)
    268         return false;
    269     m_node_address = backend_addr->GetValueAsUnsigned(0);
    270     if (!m_node_address || m_node_address == LLDB_INVALID_ADDRESS)
    271         return false;
    272     ValueObjectSP impl_sp(m_backend.GetChildMemberWithName(ConstString("__end_"),true));
    273     if (!impl_sp)
    274         return false;
    275     ClangASTType list_type = m_backend.GetClangType();
    276     if (list_type.IsReferenceType())
    277         list_type = list_type.GetNonReferenceType();
    278 
    279     if (list_type.GetNumTemplateArguments() == 0)
    280         return false;
    281     lldb::TemplateArgumentKind kind;
    282     m_element_type = list_type.GetTemplateArgument(0, kind);
    283     m_head = impl_sp->GetChildMemberWithName(ConstString("__next_"), true).get();
    284     m_tail = impl_sp->GetChildMemberWithName(ConstString("__prev_"), true).get();
    285     return false;
    286 }
    287 
    288 bool
    289 lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::MightHaveChildren ()
    290 {
    291     return true;
    292 }
    293 
    294 size_t
    295 lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
    296 {
    297     return ExtractIndexFromString(name.GetCString());
    298 }
    299 
    300 lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::~LibcxxStdListSyntheticFrontEnd ()
    301 {}
    302 
    303 SyntheticChildrenFrontEnd*
    304 lldb_private::formatters::LibcxxStdListSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
    305 {
    306     if (!valobj_sp)
    307         return NULL;
    308     return (new LibcxxStdListSyntheticFrontEnd(valobj_sp));
    309 }
    310 
    311