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