blob: 7bedd8f5d8482c01f31e5c4ec1291cc783905e02 [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()),
145m_node_address(),
146m_head(NULL),
147m_tail(NULL),
148m_element_type(),
149m_element_size(0),
150m_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;
184 uint64_t next_val = m_head->GetValueAsUnsigned(0);
185 uint64_t prev_val = m_tail->GetValueAsUnsigned(0);
186 if (next_val == 0 || prev_val == 0)
187 return 0;
188 if (next_val == m_node_address)
189 return 0;
190 if (next_val == prev_val)
191 return 1;
192 if (HasLoop())
193 return 0;
194 uint64_t size = 2;
195 ListEntry current(m_head);
196 while (current.next() && current.next()->GetValueAsUnsigned(0) != m_node_address)
197 {
198 size++;
199 current.SetEntry(current.next());
200 if (size > g_list_capping_size)
201 break;
202 }
203 return m_count = (size-1);
204}
205
206lldb::ValueObjectSP
207lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::GetChildAtIndex (size_t idx)
208{
209 if (idx >= CalculateNumChildren())
210 return lldb::ValueObjectSP();
211
212 if (!m_head || !m_tail || m_node_address == 0)
213 return lldb::ValueObjectSP();
214
215 auto cached = m_children.find(idx);
216 if (cached != m_children.end())
217 return cached->second;
218
219 ListIterator current(m_head);
220 ValueObjectSP current_sp(current.advance(idx));
221 if (!current_sp)
222 return lldb::ValueObjectSP();
223 current_sp = current_sp->GetChildMemberWithName(ConstString("__value_"), true);
224 if (!current_sp)
225 return lldb::ValueObjectSP();
226 // we need to copy current_sp into a new object otherwise we will end up with all items named __value_
227 DataExtractor data;
228 current_sp->GetData(data);
229 StreamString name;
230 name.Printf("[%zu]",idx);
231 return (m_children[idx] = ValueObject::CreateValueObjectFromData(name.GetData(), data, m_backend.GetExecutionContextRef(), m_element_type));
232}
233
234bool
235lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::Update()
236{
237 m_head = m_tail = NULL;
238 m_node_address = 0;
239 m_count = UINT32_MAX;
240 Error err;
241 ValueObjectSP backend_addr(m_backend.AddressOf(err));
242 if (err.Fail() || backend_addr.get() == NULL)
243 return false;
244 m_node_address = backend_addr->GetValueAsUnsigned(0);
245 if (!m_node_address || m_node_address == LLDB_INVALID_ADDRESS)
246 return false;
247 ValueObjectSP impl_sp(m_backend.GetChildMemberWithName(ConstString("__end_"),true));
248 if (!impl_sp)
249 return false;
250 auto list_type = m_backend.GetClangType();
251 if (ClangASTContext::IsReferenceType(list_type))
252 {
253 clang::QualType qt = clang::QualType::getFromOpaquePtr(list_type);
254 list_type = qt.getNonReferenceType().getAsOpaquePtr();
255 }
256 if (ClangASTContext::GetNumTemplateArguments(m_backend.GetClangAST(), list_type) == 0)
257 return false;
258 lldb::TemplateArgumentKind kind;
259 m_element_type = ClangASTType(m_backend.GetClangAST(), ClangASTContext::GetTemplateArgument(m_backend.GetClangAST(), list_type, 0, kind));
260 m_element_size = m_element_type.GetTypeByteSize();
261 m_head = impl_sp->GetChildMemberWithName(ConstString("__next_"), true).get();
262 m_tail = impl_sp->GetChildMemberWithName(ConstString("__prev_"), true).get();
263 return false;
264}
265
266bool
267lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::MightHaveChildren ()
268{
269 return true;
270}
271
272size_t
273lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
274{
275 return ExtractIndexFromString(name.GetCString());
276}
277
278lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::~LibcxxStdListSyntheticFrontEnd ()
279{}
280
281SyntheticChildrenFrontEnd*
282lldb_private::formatters::LibcxxStdListSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
283{
284 if (!valobj_sp)
285 return NULL;
286 return (new LibcxxStdListSyntheticFrontEnd(valobj_sp));
287}
288