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