1 //===-- 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 // C Includes
11 // C++ Includes
12 // Other libraries and framework includes
13 // Project includes
14 #include "LibCxx.h"
15 
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"
21 #include "lldb/DataFormatters/FormattersHelpers.h"
22 #include "lldb/Host/Endian.h"
23 #include "lldb/Symbol/ClangASTContext.h"
24 #include "lldb/Target/Target.h"
25 
26 using namespace lldb;
27 using namespace lldb_private;
28 using namespace lldb_private::formatters;
29 
30 class MapEntry
31 {
32 public:
33     MapEntry() = default;
34     explicit MapEntry (ValueObjectSP entry_sp) : m_entry_sp(entry_sp) {}
35     MapEntry(const MapEntry& rhs) = default;
36     explicit MapEntry (ValueObject* entry) : m_entry_sp(entry ? entry->GetSP() : ValueObjectSP()) {}
37 
38     ValueObjectSP
39     left () const
40     {
41         static ConstString g_left("__left_");
42         if (!m_entry_sp)
43             return m_entry_sp;
44         return m_entry_sp->GetChildMemberWithName(g_left, true);
45     }
46 
47     ValueObjectSP
48     right () const
49     {
50         static ConstString g_right("__right_");
51         if (!m_entry_sp)
52             return m_entry_sp;
53         return m_entry_sp->GetChildMemberWithName(g_right, true);
54     }
55 
56     ValueObjectSP
57     parent () const
58     {
59         static ConstString g_parent("__parent_");
60         if (!m_entry_sp)
61             return m_entry_sp;
62         return m_entry_sp->GetChildMemberWithName(g_parent, true);
63     }
64 
65     uint64_t
66     value () const
67     {
68         if (!m_entry_sp)
69             return 0;
70         return m_entry_sp->GetValueAsUnsigned(0);
71     }
72 
73     bool
74     error () const
75     {
76         if (!m_entry_sp)
77             return true;
78         return m_entry_sp->GetError().Fail();
79     }
80 
81     bool
82     null() const
83     {
84         return (value() == 0);
85     }
86 
87     ValueObjectSP
88     GetEntry () const
89     {
90         return m_entry_sp;
91     }
92 
93     void
94     SetEntry (ValueObjectSP entry)
95     {
96         m_entry_sp = entry;
97     }
98 
99     bool
100     operator == (const MapEntry& rhs) const
101     {
102         return (rhs.m_entry_sp.get() == m_entry_sp.get());
103     }
104 
105 private:
106     ValueObjectSP m_entry_sp;
107 };
108 
109 class MapIterator
110 {
111 public:
112     MapIterator() = default;
113     MapIterator (MapEntry entry, size_t depth = 0) : m_entry(entry), m_max_depth(depth), m_error(false) {}
114     MapIterator (ValueObjectSP entry, size_t depth = 0) : m_entry(entry), m_max_depth(depth), m_error(false) {}
115     MapIterator (const MapIterator& rhs) : m_entry(rhs.m_entry),m_max_depth(rhs.m_max_depth), m_error(false) {}
116     MapIterator (ValueObject* entry, size_t depth = 0) : m_entry(entry), m_max_depth(depth), m_error(false) {}
117 
118     ValueObjectSP
119     value ()
120     {
121         return m_entry.GetEntry();
122     }
123 
124     ValueObjectSP
125     advance (size_t count)
126     {
127         ValueObjectSP fail;
128         if (m_error)
129             return fail;
130         size_t steps = 0;
131         while (count > 0)
132         {
133             next();
134             count--, steps++;
135             if (m_error ||
136                 m_entry.null() ||
137                 (steps > m_max_depth))
138                 return fail;
139         }
140         return m_entry.GetEntry();
141     }
142 
143 protected:
144     void
145     next ()
146     {
147         if (m_entry.null())
148             return;
149         MapEntry right(m_entry.right());
150         if (!right.null())
151         {
152             m_entry = tree_min(std::move(right));
153             return;
154         }
155         size_t steps = 0;
156         while (!is_left_child(m_entry))
157         {
158             if (m_entry.error())
159             {
160                 m_error = true;
161                 return;
162             }
163             m_entry.SetEntry(m_entry.parent());
164             steps++;
165             if (steps > m_max_depth)
166             {
167                 m_entry = MapEntry();
168                 return;
169             }
170         }
171         m_entry = MapEntry(m_entry.parent());
172     }
173 
174 private:
175     MapEntry
176     tree_min (MapEntry&& x)
177     {
178         if (x.null())
179             return MapEntry();
180         MapEntry left(x.left());
181         size_t steps = 0;
182         while (!left.null())
183         {
184             if (left.error())
185             {
186                 m_error = true;
187                 return MapEntry();
188             }
189             x = left;
190             left.SetEntry(x.left());
191             steps++;
192             if (steps > m_max_depth)
193                 return MapEntry();
194         }
195         return x;
196     }
197 
198     bool
199     is_left_child (const MapEntry& x)
200     {
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     MapEntry m_entry;
209     size_t m_max_depth;
210     bool m_error;
211 };
212 
213 namespace lldb_private {
214     namespace formatters {
215         class LibcxxStdMapSyntheticFrontEnd : public SyntheticChildrenFrontEnd
216         {
217         public:
218             LibcxxStdMapSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
219 
220             ~LibcxxStdMapSyntheticFrontEnd() override = default;
221 
222             size_t
223             CalculateNumChildren() override;
224 
225             lldb::ValueObjectSP
226             GetChildAtIndex(size_t idx) override;
227 
228             bool
229             Update() override;
230 
231             bool
232             MightHaveChildren() override;
233 
234             size_t
235             GetIndexOfChildWithName(const ConstString &name) override;
236 
237         private:
238             bool
239             GetDataType();
240 
241             void
242             GetValueOffset (const lldb::ValueObjectSP& node);
243 
244             ValueObject* m_tree;
245             ValueObject* m_root_node;
246             CompilerType m_element_type;
247             uint32_t m_skip_size;
248             size_t m_count;
249             std::map<size_t, MapIterator> m_iterators;
250         };
251     } // namespace formatters
252 } // namespace lldb_private
253 
254 lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::LibcxxStdMapSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
255     SyntheticChildrenFrontEnd(*valobj_sp),
256     m_tree(nullptr),
257     m_root_node(nullptr),
258     m_element_type(),
259     m_skip_size(UINT32_MAX),
260     m_count(UINT32_MAX),
261     m_iterators()
262 {
263     if (valobj_sp)
264         Update();
265 }
266 
267 size_t
268 lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::CalculateNumChildren ()
269 {
270     static ConstString g___pair3_("__pair3_");
271     static ConstString g___first_("__first_");
272 
273     if (m_count != UINT32_MAX)
274         return m_count;
275     if (m_tree == nullptr)
276         return 0;
277     ValueObjectSP m_item(m_tree->GetChildMemberWithName(g___pair3_, true));
278     if (!m_item)
279         return 0;
280     m_item = m_item->GetChildMemberWithName(g___first_, true);
281     if (!m_item)
282         return 0;
283     m_count = m_item->GetValueAsUnsigned(0);
284     return m_count;
285 }
286 
287 bool
288 lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetDataType()
289 {
290     static ConstString g___value_("__value_");
291 
292     if (m_element_type.GetOpaqueQualType() && m_element_type.GetTypeSystem())
293         return true;
294     m_element_type.Clear();
295     ValueObjectSP deref;
296     Error error;
297     deref = m_root_node->Dereference(error);
298     if (!deref || error.Fail())
299         return false;
300     deref = deref->GetChildMemberWithName(g___value_, true);
301     if (!deref)
302         return false;
303     m_element_type = deref->GetCompilerType();
304     return true;
305 }
306 
307 void
308 lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetValueOffset (const lldb::ValueObjectSP& node)
309 {
310     if (m_skip_size != UINT32_MAX)
311         return;
312     if (!node)
313         return;
314     CompilerType node_type(node->GetCompilerType());
315     uint64_t bit_offset;
316     if (node_type.GetIndexOfFieldWithName("__value_", nullptr, &bit_offset) == UINT32_MAX)
317         return;
318     m_skip_size = bit_offset / 8u;
319 }
320 
321 lldb::ValueObjectSP
322 lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetChildAtIndex (size_t idx)
323 {
324     static ConstString g___cc("__cc");
325     static ConstString g___nc("__nc");
326     static ConstString g___value_("__value_");
327 
328     if (idx >= CalculateNumChildren())
329         return lldb::ValueObjectSP();
330     if (m_tree == nullptr || m_root_node == nullptr)
331         return lldb::ValueObjectSP();
332 
333     MapIterator iterator(m_root_node, CalculateNumChildren());
334 
335     const bool need_to_skip = (idx > 0);
336     size_t actual_advancde = idx;
337     if (need_to_skip)
338     {
339         auto cached_iterator = m_iterators.find(idx-1);
340         if (cached_iterator != m_iterators.end())
341         {
342             iterator = cached_iterator->second;
343             actual_advancde = 1;
344         }
345     }
346 
347     ValueObjectSP iterated_sp(iterator.advance(actual_advancde));
348     if (!iterated_sp)
349     {
350         // this tree is garbage - stop
351         m_tree = nullptr; // this will stop all future searches until an Update() happens
352         return iterated_sp;
353     }
354     if (GetDataType())
355     {
356         if (!need_to_skip)
357         {
358             Error error;
359             iterated_sp = iterated_sp->Dereference(error);
360             if (!iterated_sp || error.Fail())
361             {
362                 m_tree = nullptr;
363                 return lldb::ValueObjectSP();
364             }
365             GetValueOffset(iterated_sp);
366             iterated_sp = iterated_sp->GetChildMemberWithName(g___value_, true);
367             if (!iterated_sp)
368             {
369                 m_tree = nullptr;
370                 return lldb::ValueObjectSP();
371             }
372         }
373         else
374         {
375             // because of the way our debug info is made, we need to read item 0 first
376             // so that we can cache information used to generate other elements
377             if (m_skip_size == UINT32_MAX)
378                 GetChildAtIndex(0);
379             if (m_skip_size == UINT32_MAX)
380             {
381                 m_tree = nullptr;
382                 return lldb::ValueObjectSP();
383             }
384             iterated_sp = iterated_sp->GetSyntheticChildAtOffset(m_skip_size, m_element_type, true);
385             if (!iterated_sp)
386             {
387                 m_tree = nullptr;
388                 return lldb::ValueObjectSP();
389             }
390         }
391     }
392     else
393     {
394         m_tree = nullptr;
395         return lldb::ValueObjectSP();
396     }
397     // at this point we have a valid
398     // we need to copy current_sp into a new object otherwise we will end up with all items named __value_
399     DataExtractor data;
400     Error error;
401     iterated_sp->GetData(data, error);
402     if (error.Fail())
403     {
404         m_tree = nullptr;
405         return lldb::ValueObjectSP();
406     }
407     StreamString name;
408     name.Printf("[%" PRIu64 "]", (uint64_t)idx);
409     auto potential_child_sp = CreateValueObjectFromData(name.GetData(), data, m_backend.GetExecutionContextRef(), m_element_type);
410     if (potential_child_sp)
411     {
412         switch (potential_child_sp->GetNumChildren())
413         {
414             case 1:
415             {
416                 auto child0_sp = potential_child_sp->GetChildAtIndex(0, true);
417                 if (child0_sp && child0_sp->GetName() == g___cc)
418                     potential_child_sp = child0_sp;
419                 break;
420             }
421             case 2:
422             {
423                 auto child0_sp = potential_child_sp->GetChildAtIndex(0, true);
424                 auto child1_sp = potential_child_sp->GetChildAtIndex(1, true);
425                 if (child0_sp && child0_sp->GetName() == g___cc &&
426                     child1_sp && child1_sp->GetName() == g___nc)
427                     potential_child_sp = child0_sp;
428                 break;
429             }
430         }
431         potential_child_sp->SetName(ConstString(name.GetData()));
432     }
433     m_iterators[idx] = iterator;
434     return potential_child_sp;
435 }
436 
437 bool
438 lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::Update()
439 {
440     static ConstString g___tree_("__tree_");
441     static ConstString g___begin_node_("__begin_node_");
442     m_count = UINT32_MAX;
443     m_tree = m_root_node = nullptr;
444     m_iterators.clear();
445     m_tree = m_backend.GetChildMemberWithName(g___tree_, true).get();
446     if (!m_tree)
447         return false;
448     m_root_node = m_tree->GetChildMemberWithName(g___begin_node_, true).get();
449     return false;
450 }
451 
452 bool
453 lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::MightHaveChildren ()
454 {
455     return true;
456 }
457 
458 size_t
459 lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
460 {
461     return ExtractIndexFromString(name.GetCString());
462 }
463 
464 SyntheticChildrenFrontEnd*
465 lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
466 {
467     return (valobj_sp ? new LibcxxStdMapSyntheticFrontEnd(valobj_sp) : nullptr);
468 }
469