blob: 2ba8846f3c74d8f03a72236a05215a338cb1c80e [file] [log] [blame]
Eugene Zelenko8d15f332015-10-20 01:10:59 +00001//===-- LibCxxList.cpp ------------------------------------------*- C++ -*-===//
Enrico Granata92373532013-03-19 22:58:48 +00002//
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
Eugene Zelenko8d15f332015-10-20 01:10:59 +000010// C Includes
11// C++ Includes
12// Other libraries and framework includes
13// Project includes
Enrico Granata33e97e62015-09-04 21:01:18 +000014#include "LibCxx.h"
Enrico Granata92373532013-03-19 22:58:48 +000015
16#include "lldb/Core/DataBufferHeap.h"
17#include "lldb/Core/Error.h"
18#include "lldb/Core/Stream.h"
19#include "lldb/Core/ValueObject.h"
20#include "lldb/Core/ValueObjectConstResult.h"
Enrico Granata419d7912015-09-04 00:33:51 +000021#include "lldb/DataFormatters/FormattersHelpers.h"
Enrico Granata92373532013-03-19 22:58:48 +000022#include "lldb/Host/Endian.h"
23#include "lldb/Symbol/ClangASTContext.h"
Enrico Granata92373532013-03-19 22:58:48 +000024#include "lldb/Target/Target.h"
25
26using namespace lldb;
27using namespace lldb_private;
28using namespace lldb_private::formatters;
29
Enrico Granatae85fe3a2014-10-22 20:34:38 +000030namespace lldb_private {
31 namespace formatters {
32 class LibcxxStdMapSyntheticFrontEnd : public SyntheticChildrenFrontEnd
33 {
34 public:
35 LibcxxStdMapSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
Eugene Zelenko8d15f332015-10-20 01:10:59 +000036
37 ~LibcxxStdMapSyntheticFrontEnd() override = default;
38
39 size_t
40 CalculateNumChildren() override;
Enrico Granatae85fe3a2014-10-22 20:34:38 +000041
Eugene Zelenko8d15f332015-10-20 01:10:59 +000042 lldb::ValueObjectSP
43 GetChildAtIndex(size_t idx) override;
Enrico Granatae85fe3a2014-10-22 20:34:38 +000044
Eugene Zelenko8d15f332015-10-20 01:10:59 +000045 bool
46 Update() override;
Enrico Granatae85fe3a2014-10-22 20:34:38 +000047
Eugene Zelenko8d15f332015-10-20 01:10:59 +000048 bool
49 MightHaveChildren() override;
Enrico Granatae85fe3a2014-10-22 20:34:38 +000050
Eugene Zelenko8d15f332015-10-20 01:10:59 +000051 size_t
52 GetIndexOfChildWithName(const ConstString &name) override;
Enrico Granatae85fe3a2014-10-22 20:34:38 +000053
Enrico Granatae85fe3a2014-10-22 20:34:38 +000054 private:
55 bool
56 GetDataType();
57
58 void
59 GetValueOffset (const lldb::ValueObjectSP& node);
60
61 ValueObject* m_tree;
62 ValueObject* m_root_node;
Greg Claytona1e5dc82015-08-11 22:53:00 +000063 CompilerType m_element_type;
Enrico Granatae85fe3a2014-10-22 20:34:38 +000064 uint32_t m_skip_size;
65 size_t m_count;
66 std::map<size_t,lldb::ValueObjectSP> m_children;
67 };
Eugene Zelenko8d15f332015-10-20 01:10:59 +000068 } // namespace formatters
69} // namespace lldb_private
Enrico Granatae85fe3a2014-10-22 20:34:38 +000070
Enrico Granata92373532013-03-19 22:58:48 +000071class MapEntry
72{
73public:
Eugene Zelenko8d15f332015-10-20 01:10:59 +000074 MapEntry() = default;
Enrico Granata395939a2014-12-16 21:28:16 +000075 explicit MapEntry (ValueObjectSP entry_sp) : m_entry_sp(entry_sp) {}
Enrico Granata92373532013-03-19 22:58:48 +000076 MapEntry (const MapEntry& rhs) : m_entry_sp(rhs.m_entry_sp) {}
Enrico Granata395939a2014-12-16 21:28:16 +000077 explicit MapEntry (ValueObject* entry) : m_entry_sp(entry ? entry->GetSP() : ValueObjectSP()) {}
Enrico Granata92373532013-03-19 22:58:48 +000078
79 ValueObjectSP
Enrico Granata395939a2014-12-16 21:28:16 +000080 left () const
Enrico Granata92373532013-03-19 22:58:48 +000081 {
Enrico Granata395939a2014-12-16 21:28:16 +000082 static ConstString g_left("__left_");
Enrico Granata92373532013-03-19 22:58:48 +000083 if (!m_entry_sp)
84 return m_entry_sp;
Enrico Granata395939a2014-12-16 21:28:16 +000085 return m_entry_sp->GetChildMemberWithName(g_left, true);
Enrico Granata92373532013-03-19 22:58:48 +000086 }
87
88 ValueObjectSP
Enrico Granata395939a2014-12-16 21:28:16 +000089 right () const
Enrico Granata92373532013-03-19 22:58:48 +000090 {
Enrico Granata395939a2014-12-16 21:28:16 +000091 static ConstString g_right("__right_");
Enrico Granata92373532013-03-19 22:58:48 +000092 if (!m_entry_sp)
93 return m_entry_sp;
Enrico Granata395939a2014-12-16 21:28:16 +000094 return m_entry_sp->GetChildMemberWithName(g_right, true);
Enrico Granata92373532013-03-19 22:58:48 +000095 }
96
97 ValueObjectSP
Enrico Granata395939a2014-12-16 21:28:16 +000098 parent () const
Enrico Granata92373532013-03-19 22:58:48 +000099 {
Enrico Granata395939a2014-12-16 21:28:16 +0000100 static ConstString g_parent("__parent_");
Enrico Granata92373532013-03-19 22:58:48 +0000101 if (!m_entry_sp)
102 return m_entry_sp;
Enrico Granata395939a2014-12-16 21:28:16 +0000103 return m_entry_sp->GetChildMemberWithName(g_parent, true);
Enrico Granata92373532013-03-19 22:58:48 +0000104 }
105
106 uint64_t
Enrico Granata395939a2014-12-16 21:28:16 +0000107 value () const
Enrico Granata92373532013-03-19 22:58:48 +0000108 {
109 if (!m_entry_sp)
110 return 0;
111 return m_entry_sp->GetValueAsUnsigned(0);
112 }
113
114 bool
Enrico Granata395939a2014-12-16 21:28:16 +0000115 error () const
Enrico Granatad03a2732013-05-03 19:04:35 +0000116 {
Enrico Granata4ffff272013-05-03 19:07:20 +0000117 if (!m_entry_sp)
118 return true;
Enrico Granatad03a2732013-05-03 19:04:35 +0000119 return m_entry_sp->GetError().Fail();
120 }
121
122 bool
Enrico Granata395939a2014-12-16 21:28:16 +0000123 null() const
Enrico Granata92373532013-03-19 22:58:48 +0000124 {
125 return (value() == 0);
126 }
127
128 ValueObjectSP
Enrico Granata395939a2014-12-16 21:28:16 +0000129 GetEntry () const
Enrico Granata92373532013-03-19 22:58:48 +0000130 {
131 return m_entry_sp;
132 }
133
134 void
135 SetEntry (ValueObjectSP entry)
136 {
137 m_entry_sp = entry;
138 }
139
140 bool
141 operator == (const MapEntry& rhs) const
142 {
143 return (rhs.m_entry_sp.get() == m_entry_sp.get());
144 }
145
146private:
147 ValueObjectSP m_entry_sp;
148};
149
150class MapIterator
151{
152public:
Eugene Zelenko8d15f332015-10-20 01:10:59 +0000153 MapIterator() = default;
Enrico Granatad03a2732013-05-03 19:04:35 +0000154 MapIterator (MapEntry entry, size_t depth = 0) : m_entry(entry), m_max_depth(depth), m_error(false) {}
155 MapIterator (ValueObjectSP entry, size_t depth = 0) : m_entry(entry), m_max_depth(depth), m_error(false) {}
156 MapIterator (const MapIterator& rhs) : m_entry(rhs.m_entry),m_max_depth(rhs.m_max_depth), m_error(false) {}
157 MapIterator (ValueObject* entry, size_t depth = 0) : m_entry(entry), m_max_depth(depth), m_error(false) {}
Enrico Granata92373532013-03-19 22:58:48 +0000158
159 ValueObjectSP
160 value ()
161 {
162 return m_entry.GetEntry();
163 }
164
165 ValueObjectSP
166 advance (size_t count)
167 {
Enrico Granata395939a2014-12-16 21:28:16 +0000168 ValueObjectSP fail(nullptr);
Enrico Granatad03a2732013-05-03 19:04:35 +0000169 if (m_error)
Enrico Granata395939a2014-12-16 21:28:16 +0000170 return fail;
Enrico Granata92373532013-03-19 22:58:48 +0000171 size_t steps = 0;
172 while (count > 0)
173 {
Enrico Granata395939a2014-12-16 21:28:16 +0000174 next();
175 count--, steps++;
176 if (m_error ||
177 m_entry.null() ||
178 (steps > m_max_depth))
179 return fail;
Enrico Granata92373532013-03-19 22:58:48 +0000180 }
181 return m_entry.GetEntry();
182 }
Eugene Zelenko8d15f332015-10-20 01:10:59 +0000183
Enrico Granata92373532013-03-19 22:58:48 +0000184protected:
185 void
186 next ()
187 {
Enrico Granata395939a2014-12-16 21:28:16 +0000188 if (m_entry.null())
189 return;
190 MapEntry right(m_entry.right());
191 if (right.null() == false)
192 {
193 m_entry = tree_min(std::move(right));
194 return;
195 }
196 size_t steps = 0;
197 while (!is_left_child(m_entry))
198 {
199 if (m_entry.error())
200 {
201 m_error = true;
202 return;
203 }
204 m_entry.SetEntry(m_entry.parent());
205 steps++;
206 if (steps > m_max_depth)
207 {
208 m_entry = MapEntry();
209 return;
210 }
211 }
212 m_entry = MapEntry(m_entry.parent());
Enrico Granata92373532013-03-19 22:58:48 +0000213 }
214
215private:
Enrico Granata395939a2014-12-16 21:28:16 +0000216 MapEntry
217 tree_min (MapEntry&& x)
Enrico Granata92373532013-03-19 22:58:48 +0000218 {
Enrico Granata92373532013-03-19 22:58:48 +0000219 if (x.null())
Enrico Granata395939a2014-12-16 21:28:16 +0000220 return MapEntry();
Enrico Granata92373532013-03-19 22:58:48 +0000221 MapEntry left(x.left());
222 size_t steps = 0;
223 while (left.null() == false)
224 {
Enrico Granatad03a2732013-05-03 19:04:35 +0000225 if (left.error())
226 {
227 m_error = true;
Enrico Granata395939a2014-12-16 21:28:16 +0000228 return MapEntry();
Enrico Granatad03a2732013-05-03 19:04:35 +0000229 }
Enrico Granata395939a2014-12-16 21:28:16 +0000230 x = left;
Enrico Granata92373532013-03-19 22:58:48 +0000231 left.SetEntry(x.left());
232 steps++;
233 if (steps > m_max_depth)
Enrico Granata395939a2014-12-16 21:28:16 +0000234 return MapEntry();
Enrico Granata92373532013-03-19 22:58:48 +0000235 }
Enrico Granata395939a2014-12-16 21:28:16 +0000236 return x;
Enrico Granata92373532013-03-19 22:58:48 +0000237 }
Enrico Granata395939a2014-12-16 21:28:16 +0000238
Enrico Granata92373532013-03-19 22:58:48 +0000239 bool
Enrico Granata395939a2014-12-16 21:28:16 +0000240 is_left_child (const MapEntry& x)
Enrico Granata92373532013-03-19 22:58:48 +0000241 {
Enrico Granata92373532013-03-19 22:58:48 +0000242 if (x.null())
243 return false;
244 MapEntry rhs(x.parent());
245 rhs.SetEntry(rhs.left());
246 return x.value() == rhs.value();
247 }
248
Enrico Granata92373532013-03-19 22:58:48 +0000249 MapEntry m_entry;
250 size_t m_max_depth;
Enrico Granatad03a2732013-05-03 19:04:35 +0000251 bool m_error;
Enrico Granata92373532013-03-19 22:58:48 +0000252};
253
254lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::LibcxxStdMapSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
255SyntheticChildrenFrontEnd(*valobj_sp.get()),
256m_tree(NULL),
257m_root_node(NULL),
258m_element_type(),
Enrico Granata92373532013-03-19 22:58:48 +0000259m_skip_size(UINT32_MAX),
260m_count(UINT32_MAX),
261m_children()
262{
263 if (valobj_sp)
264 Update();
265}
266
267size_t
268lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::CalculateNumChildren ()
269{
270 if (m_count != UINT32_MAX)
271 return m_count;
272 if (m_tree == NULL)
273 return 0;
274 ValueObjectSP m_item(m_tree->GetChildMemberWithName(ConstString("__pair3_"), true));
275 if (!m_item)
276 return 0;
277 m_item = m_item->GetChildMemberWithName(ConstString("__first_"), true);
278 if (!m_item)
279 return 0;
280 m_count = m_item->GetValueAsUnsigned(0);
281 return m_count;
282}
283
284bool
285lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetDataType()
286{
Greg Claytond8d4a572015-08-11 21:38:15 +0000287 if (m_element_type.GetOpaqueQualType() && m_element_type.GetTypeSystem())
Enrico Granata92373532013-03-19 22:58:48 +0000288 return true;
289 m_element_type.Clear();
290 ValueObjectSP deref;
291 Error error;
292 deref = m_root_node->Dereference(error);
293 if (!deref || error.Fail())
294 return false;
295 deref = deref->GetChildMemberWithName(ConstString("__value_"), true);
296 if (!deref)
297 return false;
Greg Clayton99558cc42015-08-24 23:46:31 +0000298 m_element_type = deref->GetCompilerType();
Enrico Granata92373532013-03-19 22:58:48 +0000299 return true;
300}
301
302void
303lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetValueOffset (const lldb::ValueObjectSP& node)
304{
305 if (m_skip_size != UINT32_MAX)
306 return;
307 if (!node)
308 return;
Greg Clayton99558cc42015-08-24 23:46:31 +0000309 CompilerType node_type(node->GetCompilerType());
Enrico Granata92373532013-03-19 22:58:48 +0000310 uint64_t bit_offset;
Greg Clayton57ee3062013-07-11 22:46:58 +0000311 if (node_type.GetIndexOfFieldWithName("__value_", NULL, &bit_offset) == UINT32_MAX)
Enrico Granata92373532013-03-19 22:58:48 +0000312 return;
313 m_skip_size = bit_offset / 8u;
314}
315
316lldb::ValueObjectSP
317lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetChildAtIndex (size_t idx)
318{
Enrico Granata340fa532014-09-12 00:55:37 +0000319 static ConstString g___cc("__cc");
320 static ConstString g___nc("__nc");
321
322
Enrico Granata92373532013-03-19 22:58:48 +0000323 if (idx >= CalculateNumChildren())
324 return lldb::ValueObjectSP();
325 if (m_tree == NULL || m_root_node == NULL)
326 return lldb::ValueObjectSP();
327
328 auto cached = m_children.find(idx);
329 if (cached != m_children.end())
330 return cached->second;
331
332 bool need_to_skip = (idx > 0);
333 MapIterator iterator(m_root_node, CalculateNumChildren());
334 ValueObjectSP iterated_sp(iterator.advance(idx));
335 if (iterated_sp.get() == NULL)
336 {
337 // this tree is garbage - stop
338 m_tree = NULL; // this will stop all future searches until an Update() happens
339 return iterated_sp;
340 }
341 if (GetDataType())
342 {
343 if (!need_to_skip)
344 {
345 Error error;
346 iterated_sp = iterated_sp->Dereference(error);
347 if (!iterated_sp || error.Fail())
348 {
349 m_tree = NULL;
350 return lldb::ValueObjectSP();
351 }
352 GetValueOffset(iterated_sp);
353 iterated_sp = iterated_sp->GetChildMemberWithName(ConstString("__value_"), true);
354 if (!iterated_sp)
355 {
356 m_tree = NULL;
357 return lldb::ValueObjectSP();
358 }
359 }
360 else
361 {
362 // because of the way our debug info is made, we need to read item 0 first
363 // so that we can cache information used to generate other elements
364 if (m_skip_size == UINT32_MAX)
365 GetChildAtIndex(0);
366 if (m_skip_size == UINT32_MAX)
367 {
368 m_tree = NULL;
369 return lldb::ValueObjectSP();
370 }
371 iterated_sp = iterated_sp->GetSyntheticChildAtOffset(m_skip_size, m_element_type, true);
372 if (!iterated_sp)
373 {
374 m_tree = NULL;
375 return lldb::ValueObjectSP();
376 }
377 }
378 }
379 else
380 {
381 m_tree = NULL;
382 return lldb::ValueObjectSP();
383 }
384 // at this point we have a valid
385 // we need to copy current_sp into a new object otherwise we will end up with all items named __value_
386 DataExtractor data;
Sean Callanan866e91c2014-02-28 22:27:53 +0000387 Error error;
388 iterated_sp->GetData(data, error);
389 if (error.Fail())
390 {
391 m_tree = NULL;
392 return lldb::ValueObjectSP();
393 }
Enrico Granata92373532013-03-19 22:58:48 +0000394 StreamString name;
Deepak Panickal99fbc072014-03-03 15:39:47 +0000395 name.Printf("[%" PRIu64 "]", (uint64_t)idx);
Enrico Granatae29df232014-12-09 19:51:20 +0000396 auto potential_child_sp = CreateValueObjectFromData(name.GetData(), data, m_backend.GetExecutionContextRef(), m_element_type);
Enrico Granata340fa532014-09-12 00:55:37 +0000397 if (potential_child_sp)
398 {
399 switch (potential_child_sp->GetNumChildren())
400 {
401 case 1:
402 {
403 auto child0_sp = potential_child_sp->GetChildAtIndex(0, true);
404 if (child0_sp && child0_sp->GetName() == g___cc)
405 potential_child_sp = child0_sp;
406 break;
407 }
408 case 2:
409 {
410 auto child0_sp = potential_child_sp->GetChildAtIndex(0, true);
411 auto child1_sp = potential_child_sp->GetChildAtIndex(1, true);
412 if (child0_sp && child0_sp->GetName() == g___cc &&
413 child1_sp && child1_sp->GetName() == g___nc)
414 potential_child_sp = child0_sp;
415 break;
416 }
417 }
418 potential_child_sp->SetName(ConstString(name.GetData()));
419 }
420 return (m_children[idx] = potential_child_sp);
Enrico Granata92373532013-03-19 22:58:48 +0000421}
422
423bool
424lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::Update()
425{
426 m_count = UINT32_MAX;
427 m_tree = m_root_node = NULL;
428 m_children.clear();
429 m_tree = m_backend.GetChildMemberWithName(ConstString("__tree_"), true).get();
430 if (!m_tree)
Matt Kopecef143712013-06-03 18:00:07 +0000431 return false;
Enrico Granata92373532013-03-19 22:58:48 +0000432 m_root_node = m_tree->GetChildMemberWithName(ConstString("__begin_node_"), true).get();
433 return false;
434}
435
436bool
437lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::MightHaveChildren ()
438{
439 return true;
440}
441
442size_t
443lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
444{
445 return ExtractIndexFromString(name.GetCString());
446}
447
Enrico Granata92373532013-03-19 22:58:48 +0000448SyntheticChildrenFrontEnd*
449lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
450{
451 if (!valobj_sp)
452 return NULL;
453 return (new LibcxxStdMapSyntheticFrontEnd(valobj_sp));
454}