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