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