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