]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/llvm/tools/lldb/source/DataFormatters/LibCxxList.cpp
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / llvm / tools / lldb / source / DataFormatters / LibCxxList.cpp
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