blob: c4aaad3e7a0766c048d4f8ffe4b060cc50f5a872 [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
Enrico Granatae85fe3a2014-10-22 20:34:38 +000028namespace lldb_private {
29 namespace formatters {
30 class LibcxxStdMapSyntheticFrontEnd : public SyntheticChildrenFrontEnd
31 {
32 public:
33 LibcxxStdMapSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
34
35 virtual size_t
36 CalculateNumChildren ();
37
38 virtual lldb::ValueObjectSP
39 GetChildAtIndex (size_t idx);
40
41 virtual bool
42 Update();
43
44 virtual bool
45 MightHaveChildren ();
46
47 virtual size_t
48 GetIndexOfChildWithName (const ConstString &name);
49
50 virtual
51 ~LibcxxStdMapSyntheticFrontEnd ();
52 private:
53 bool
54 GetDataType();
55
56 void
57 GetValueOffset (const lldb::ValueObjectSP& node);
58
59 ValueObject* m_tree;
60 ValueObject* m_root_node;
61 ClangASTType m_element_type;
62 uint32_t m_skip_size;
63 size_t m_count;
64 std::map<size_t,lldb::ValueObjectSP> m_children;
65 };
66 }
67}
68
Enrico Granata92373532013-03-19 22:58:48 +000069class MapEntry
70{
71public:
72 MapEntry () {}
73 MapEntry (ValueObjectSP entry_sp) : m_entry_sp(entry_sp) {}
74 MapEntry (const MapEntry& rhs) : m_entry_sp(rhs.m_entry_sp) {}
75 MapEntry (ValueObject* entry) : m_entry_sp(entry ? entry->GetSP() : ValueObjectSP()) {}
76
77 ValueObjectSP
78 left ()
79 {
80 if (!m_entry_sp)
81 return m_entry_sp;
82 return m_entry_sp->GetChildMemberWithName(ConstString("__left_"), true);
83 }
84
85 ValueObjectSP
86 right ()
87 {
88 if (!m_entry_sp)
89 return m_entry_sp;
90 return m_entry_sp->GetChildMemberWithName(ConstString("__right_"), true);
91 }
92
93 ValueObjectSP
94 parent ()
95 {
96 if (!m_entry_sp)
97 return m_entry_sp;
98 return m_entry_sp->GetChildMemberWithName(ConstString("__parent_"), true);
99 }
100
101 uint64_t
102 value ()
103 {
104 if (!m_entry_sp)
105 return 0;
106 return m_entry_sp->GetValueAsUnsigned(0);
107 }
108
109 bool
Enrico Granatad03a2732013-05-03 19:04:35 +0000110 error ()
111 {
Enrico Granata4ffff272013-05-03 19:07:20 +0000112 if (!m_entry_sp)
113 return true;
Enrico Granatad03a2732013-05-03 19:04:35 +0000114 return m_entry_sp->GetError().Fail();
115 }
116
117 bool
Enrico Granata92373532013-03-19 22:58:48 +0000118 null()
119 {
120 return (value() == 0);
121 }
122
123 ValueObjectSP
124 GetEntry ()
125 {
126 return m_entry_sp;
127 }
128
129 void
130 SetEntry (ValueObjectSP entry)
131 {
132 m_entry_sp = entry;
133 }
134
135 bool
136 operator == (const MapEntry& rhs) const
137 {
138 return (rhs.m_entry_sp.get() == m_entry_sp.get());
139 }
140
141private:
142 ValueObjectSP m_entry_sp;
143};
144
145class MapIterator
146{
147public:
148 MapIterator () {}
Enrico Granatad03a2732013-05-03 19:04:35 +0000149 MapIterator (MapEntry entry, size_t depth = 0) : m_entry(entry), m_max_depth(depth), m_error(false) {}
150 MapIterator (ValueObjectSP entry, size_t depth = 0) : m_entry(entry), m_max_depth(depth), m_error(false) {}
151 MapIterator (const MapIterator& rhs) : m_entry(rhs.m_entry),m_max_depth(rhs.m_max_depth), m_error(false) {}
152 MapIterator (ValueObject* entry, size_t depth = 0) : m_entry(entry), m_max_depth(depth), m_error(false) {}
Enrico Granata92373532013-03-19 22:58:48 +0000153
154 ValueObjectSP
155 value ()
156 {
157 return m_entry.GetEntry();
158 }
159
160 ValueObjectSP
161 advance (size_t count)
162 {
Enrico Granatad03a2732013-05-03 19:04:35 +0000163 if (m_error)
164 return lldb::ValueObjectSP();
Enrico Granata92373532013-03-19 22:58:48 +0000165 if (count == 0)
166 return m_entry.GetEntry();
167 if (count == 1)
168 {
169 next ();
170 return m_entry.GetEntry();
171 }
172 size_t steps = 0;
173 while (count > 0)
174 {
Enrico Granatad03a2732013-05-03 19:04:35 +0000175 if (m_error)
176 return lldb::ValueObjectSP();
Enrico Granata92373532013-03-19 22:58:48 +0000177 next ();
178 count--;
179 if (m_entry.null())
180 return lldb::ValueObjectSP();
181 steps++;
182 if (steps > m_max_depth)
183 return lldb::ValueObjectSP();
184 }
185 return m_entry.GetEntry();
186 }
187protected:
188 void
189 next ()
190 {
191 m_entry.SetEntry(increment(m_entry.GetEntry()));
192 }
193
194private:
195 ValueObjectSP
196 tree_min (ValueObjectSP x_sp)
197 {
198 MapEntry x(x_sp);
199 if (x.null())
200 return ValueObjectSP();
201 MapEntry left(x.left());
202 size_t steps = 0;
203 while (left.null() == false)
204 {
Enrico Granatad03a2732013-05-03 19:04:35 +0000205 if (left.error())
206 {
207 m_error = true;
208 return lldb::ValueObjectSP();
209 }
Enrico Granata92373532013-03-19 22:58:48 +0000210 x.SetEntry(left.GetEntry());
211 left.SetEntry(x.left());
212 steps++;
213 if (steps > m_max_depth)
214 return lldb::ValueObjectSP();
215 }
216 return x.GetEntry();
217 }
218
219 ValueObjectSP
220 tree_max (ValueObjectSP x_sp)
221 {
222 MapEntry x(x_sp);
223 if (x.null())
224 return ValueObjectSP();
225 MapEntry right(x.right());
226 size_t steps = 0;
227 while (right.null() == false)
228 {
Enrico Granatad03a2732013-05-03 19:04:35 +0000229 if (right.error())
230 return lldb::ValueObjectSP();
Enrico Granata92373532013-03-19 22:58:48 +0000231 x.SetEntry(right.GetEntry());
232 right.SetEntry(x.right());
233 steps++;
234 if (steps > m_max_depth)
235 return lldb::ValueObjectSP();
236 }
237 return x.GetEntry();
238 }
239
240 bool
241 is_left_child (ValueObjectSP x_sp)
242 {
243 MapEntry x(x_sp);
244 if (x.null())
245 return false;
246 MapEntry rhs(x.parent());
247 rhs.SetEntry(rhs.left());
248 return x.value() == rhs.value();
249 }
250
251 ValueObjectSP
252 increment (ValueObjectSP x_sp)
253 {
254 MapEntry node(x_sp);
255 if (node.null())
256 return ValueObjectSP();
257 MapEntry right(node.right());
258 if (right.null() == false)
259 return tree_min(right.GetEntry());
260 size_t steps = 0;
261 while (!is_left_child(node.GetEntry()))
262 {
Enrico Granatad03a2732013-05-03 19:04:35 +0000263 if (node.error())
264 {
265 m_error = true;
266 return lldb::ValueObjectSP();
267 }
Enrico Granata92373532013-03-19 22:58:48 +0000268 node.SetEntry(node.parent());
269 steps++;
270 if (steps > m_max_depth)
271 return lldb::ValueObjectSP();
272 }
273 return node.parent();
274 }
275
276 MapEntry m_entry;
277 size_t m_max_depth;
Enrico Granatad03a2732013-05-03 19:04:35 +0000278 bool m_error;
Enrico Granata92373532013-03-19 22:58:48 +0000279};
280
281lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::LibcxxStdMapSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
282SyntheticChildrenFrontEnd(*valobj_sp.get()),
283m_tree(NULL),
284m_root_node(NULL),
285m_element_type(),
Enrico Granata92373532013-03-19 22:58:48 +0000286m_skip_size(UINT32_MAX),
287m_count(UINT32_MAX),
288m_children()
289{
290 if (valobj_sp)
291 Update();
292}
293
294size_t
295lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::CalculateNumChildren ()
296{
297 if (m_count != UINT32_MAX)
298 return m_count;
299 if (m_tree == NULL)
300 return 0;
301 ValueObjectSP m_item(m_tree->GetChildMemberWithName(ConstString("__pair3_"), true));
302 if (!m_item)
303 return 0;
304 m_item = m_item->GetChildMemberWithName(ConstString("__first_"), true);
305 if (!m_item)
306 return 0;
307 m_count = m_item->GetValueAsUnsigned(0);
308 return m_count;
309}
310
311bool
312lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetDataType()
313{
314 if (m_element_type.GetOpaqueQualType() && m_element_type.GetASTContext())
315 return true;
316 m_element_type.Clear();
317 ValueObjectSP deref;
318 Error error;
319 deref = m_root_node->Dereference(error);
320 if (!deref || error.Fail())
321 return false;
322 deref = deref->GetChildMemberWithName(ConstString("__value_"), true);
323 if (!deref)
324 return false;
Greg Clayton57ee3062013-07-11 22:46:58 +0000325 m_element_type = deref->GetClangType();
Enrico Granata92373532013-03-19 22:58:48 +0000326 return true;
327}
328
329void
330lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetValueOffset (const lldb::ValueObjectSP& node)
331{
332 if (m_skip_size != UINT32_MAX)
333 return;
334 if (!node)
335 return;
Greg Clayton57ee3062013-07-11 22:46:58 +0000336 ClangASTType node_type(node->GetClangType());
Enrico Granata92373532013-03-19 22:58:48 +0000337 uint64_t bit_offset;
Greg Clayton57ee3062013-07-11 22:46:58 +0000338 if (node_type.GetIndexOfFieldWithName("__value_", NULL, &bit_offset) == UINT32_MAX)
Enrico Granata92373532013-03-19 22:58:48 +0000339 return;
340 m_skip_size = bit_offset / 8u;
341}
342
343lldb::ValueObjectSP
344lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetChildAtIndex (size_t idx)
345{
Enrico Granata340fa532014-09-12 00:55:37 +0000346 static ConstString g___cc("__cc");
347 static ConstString g___nc("__nc");
348
349
Enrico Granata92373532013-03-19 22:58:48 +0000350 if (idx >= CalculateNumChildren())
351 return lldb::ValueObjectSP();
352 if (m_tree == NULL || m_root_node == NULL)
353 return lldb::ValueObjectSP();
354
355 auto cached = m_children.find(idx);
356 if (cached != m_children.end())
357 return cached->second;
358
359 bool need_to_skip = (idx > 0);
360 MapIterator iterator(m_root_node, CalculateNumChildren());
361 ValueObjectSP iterated_sp(iterator.advance(idx));
362 if (iterated_sp.get() == NULL)
363 {
364 // this tree is garbage - stop
365 m_tree = NULL; // this will stop all future searches until an Update() happens
366 return iterated_sp;
367 }
368 if (GetDataType())
369 {
370 if (!need_to_skip)
371 {
372 Error error;
373 iterated_sp = iterated_sp->Dereference(error);
374 if (!iterated_sp || error.Fail())
375 {
376 m_tree = NULL;
377 return lldb::ValueObjectSP();
378 }
379 GetValueOffset(iterated_sp);
380 iterated_sp = iterated_sp->GetChildMemberWithName(ConstString("__value_"), true);
381 if (!iterated_sp)
382 {
383 m_tree = NULL;
384 return lldb::ValueObjectSP();
385 }
386 }
387 else
388 {
389 // because of the way our debug info is made, we need to read item 0 first
390 // so that we can cache information used to generate other elements
391 if (m_skip_size == UINT32_MAX)
392 GetChildAtIndex(0);
393 if (m_skip_size == UINT32_MAX)
394 {
395 m_tree = NULL;
396 return lldb::ValueObjectSP();
397 }
398 iterated_sp = iterated_sp->GetSyntheticChildAtOffset(m_skip_size, m_element_type, true);
399 if (!iterated_sp)
400 {
401 m_tree = NULL;
402 return lldb::ValueObjectSP();
403 }
404 }
405 }
406 else
407 {
408 m_tree = NULL;
409 return lldb::ValueObjectSP();
410 }
411 // at this point we have a valid
412 // we need to copy current_sp into a new object otherwise we will end up with all items named __value_
413 DataExtractor data;
Sean Callanan866e91c2014-02-28 22:27:53 +0000414 Error error;
415 iterated_sp->GetData(data, error);
416 if (error.Fail())
417 {
418 m_tree = NULL;
419 return lldb::ValueObjectSP();
420 }
Enrico Granata92373532013-03-19 22:58:48 +0000421 StreamString name;
Deepak Panickal99fbc072014-03-03 15:39:47 +0000422 name.Printf("[%" PRIu64 "]", (uint64_t)idx);
Enrico Granatae29df232014-12-09 19:51:20 +0000423 auto potential_child_sp = CreateValueObjectFromData(name.GetData(), data, m_backend.GetExecutionContextRef(), m_element_type);
Enrico Granata340fa532014-09-12 00:55:37 +0000424 if (potential_child_sp)
425 {
426 switch (potential_child_sp->GetNumChildren())
427 {
428 case 1:
429 {
430 auto child0_sp = potential_child_sp->GetChildAtIndex(0, true);
431 if (child0_sp && child0_sp->GetName() == g___cc)
432 potential_child_sp = child0_sp;
433 break;
434 }
435 case 2:
436 {
437 auto child0_sp = potential_child_sp->GetChildAtIndex(0, true);
438 auto child1_sp = potential_child_sp->GetChildAtIndex(1, true);
439 if (child0_sp && child0_sp->GetName() == g___cc &&
440 child1_sp && child1_sp->GetName() == g___nc)
441 potential_child_sp = child0_sp;
442 break;
443 }
444 }
445 potential_child_sp->SetName(ConstString(name.GetData()));
446 }
447 return (m_children[idx] = potential_child_sp);
Enrico Granata92373532013-03-19 22:58:48 +0000448}
449
450bool
451lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::Update()
452{
453 m_count = UINT32_MAX;
454 m_tree = m_root_node = NULL;
455 m_children.clear();
456 m_tree = m_backend.GetChildMemberWithName(ConstString("__tree_"), true).get();
457 if (!m_tree)
Matt Kopecef143712013-06-03 18:00:07 +0000458 return false;
Enrico Granata92373532013-03-19 22:58:48 +0000459 m_root_node = m_tree->GetChildMemberWithName(ConstString("__begin_node_"), true).get();
460 return false;
461}
462
463bool
464lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::MightHaveChildren ()
465{
466 return true;
467}
468
469size_t
470lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
471{
472 return ExtractIndexFromString(name.GetCString());
473}
474
475lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::~LibcxxStdMapSyntheticFrontEnd ()
476{}
477
478SyntheticChildrenFrontEnd*
479lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
480{
481 if (!valobj_sp)
482 return NULL;
483 return (new LibcxxStdMapSyntheticFrontEnd(valobj_sp));
484}