blob: 9a231ad6d11f3213806d025e3ded565b546a5748 [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{
Enrico Granata340fa532014-09-12 00:55:37 +0000305 static ConstString g___cc("__cc");
306 static ConstString g___nc("__nc");
307
308
Enrico Granata92373532013-03-19 22:58:48 +0000309 if (idx >= CalculateNumChildren())
310 return lldb::ValueObjectSP();
311 if (m_tree == NULL || m_root_node == NULL)
312 return lldb::ValueObjectSP();
313
314 auto cached = m_children.find(idx);
315 if (cached != m_children.end())
316 return cached->second;
317
318 bool need_to_skip = (idx > 0);
319 MapIterator iterator(m_root_node, CalculateNumChildren());
320 ValueObjectSP iterated_sp(iterator.advance(idx));
321 if (iterated_sp.get() == NULL)
322 {
323 // this tree is garbage - stop
324 m_tree = NULL; // this will stop all future searches until an Update() happens
325 return iterated_sp;
326 }
327 if (GetDataType())
328 {
329 if (!need_to_skip)
330 {
331 Error error;
332 iterated_sp = iterated_sp->Dereference(error);
333 if (!iterated_sp || error.Fail())
334 {
335 m_tree = NULL;
336 return lldb::ValueObjectSP();
337 }
338 GetValueOffset(iterated_sp);
339 iterated_sp = iterated_sp->GetChildMemberWithName(ConstString("__value_"), true);
340 if (!iterated_sp)
341 {
342 m_tree = NULL;
343 return lldb::ValueObjectSP();
344 }
345 }
346 else
347 {
348 // because of the way our debug info is made, we need to read item 0 first
349 // so that we can cache information used to generate other elements
350 if (m_skip_size == UINT32_MAX)
351 GetChildAtIndex(0);
352 if (m_skip_size == UINT32_MAX)
353 {
354 m_tree = NULL;
355 return lldb::ValueObjectSP();
356 }
357 iterated_sp = iterated_sp->GetSyntheticChildAtOffset(m_skip_size, m_element_type, true);
358 if (!iterated_sp)
359 {
360 m_tree = NULL;
361 return lldb::ValueObjectSP();
362 }
363 }
364 }
365 else
366 {
367 m_tree = NULL;
368 return lldb::ValueObjectSP();
369 }
370 // at this point we have a valid
371 // we need to copy current_sp into a new object otherwise we will end up with all items named __value_
372 DataExtractor data;
Sean Callanan866e91c2014-02-28 22:27:53 +0000373 Error error;
374 iterated_sp->GetData(data, error);
375 if (error.Fail())
376 {
377 m_tree = NULL;
378 return lldb::ValueObjectSP();
379 }
Enrico Granata92373532013-03-19 22:58:48 +0000380 StreamString name;
Deepak Panickal99fbc072014-03-03 15:39:47 +0000381 name.Printf("[%" PRIu64 "]", (uint64_t)idx);
Enrico Granata340fa532014-09-12 00:55:37 +0000382 auto potential_child_sp = ValueObject::CreateValueObjectFromData(name.GetData(), data, m_backend.GetExecutionContextRef(), m_element_type);
383 if (potential_child_sp)
384 {
385 switch (potential_child_sp->GetNumChildren())
386 {
387 case 1:
388 {
389 auto child0_sp = potential_child_sp->GetChildAtIndex(0, true);
390 if (child0_sp && child0_sp->GetName() == g___cc)
391 potential_child_sp = child0_sp;
392 break;
393 }
394 case 2:
395 {
396 auto child0_sp = potential_child_sp->GetChildAtIndex(0, true);
397 auto child1_sp = potential_child_sp->GetChildAtIndex(1, true);
398 if (child0_sp && child0_sp->GetName() == g___cc &&
399 child1_sp && child1_sp->GetName() == g___nc)
400 potential_child_sp = child0_sp;
401 break;
402 }
403 }
404 potential_child_sp->SetName(ConstString(name.GetData()));
405 }
406 return (m_children[idx] = potential_child_sp);
Enrico Granata92373532013-03-19 22:58:48 +0000407}
408
409bool
410lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::Update()
411{
412 m_count = UINT32_MAX;
413 m_tree = m_root_node = NULL;
414 m_children.clear();
415 m_tree = m_backend.GetChildMemberWithName(ConstString("__tree_"), true).get();
416 if (!m_tree)
Matt Kopecef143712013-06-03 18:00:07 +0000417 return false;
Enrico Granata92373532013-03-19 22:58:48 +0000418 m_root_node = m_tree->GetChildMemberWithName(ConstString("__begin_node_"), true).get();
419 return false;
420}
421
422bool
423lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::MightHaveChildren ()
424{
425 return true;
426}
427
428size_t
429lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
430{
431 return ExtractIndexFromString(name.GetCString());
432}
433
434lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::~LibcxxStdMapSyntheticFrontEnd ()
435{}
436
437SyntheticChildrenFrontEnd*
438lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
439{
440 if (!valobj_sp)
441 return NULL;
442 return (new LibcxxStdMapSyntheticFrontEnd(valobj_sp));
443}