]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp
Merge clang 7.0.1 and several follow-up changes
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / lldb / source / Plugins / Language / CPlusPlus / LibCxxList.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 // C Includes
11 // C++ Includes
12 // Other libraries and framework includes
13 // Project includes
14 #include "LibCxx.h"
15
16 #include "lldb/Core/ValueObject.h"
17 #include "lldb/Core/ValueObjectConstResult.h"
18 #include "lldb/DataFormatters/FormattersHelpers.h"
19 #include "lldb/Symbol/ClangASTContext.h"
20 #include "lldb/Target/Target.h"
21 #include "lldb/Utility/DataBufferHeap.h"
22 #include "lldb/Utility/Endian.h"
23 #include "lldb/Utility/Status.h"
24 #include "lldb/Utility/Stream.h"
25
26 using namespace lldb;
27 using namespace lldb_private;
28 using namespace lldb_private::formatters;
29
30 namespace {
31
32 class ListEntry {
33 public:
34   ListEntry() = default;
35   ListEntry(ValueObjectSP entry_sp) : m_entry_sp(entry_sp) {}
36   ListEntry(const ListEntry &rhs) = default;
37   ListEntry(ValueObject *entry)
38       : m_entry_sp(entry ? entry->GetSP() : ValueObjectSP()) {}
39
40   ListEntry next() {
41     static ConstString g_next("__next_");
42
43     if (!m_entry_sp)
44       return ListEntry();
45     return ListEntry(m_entry_sp->GetChildMemberWithName(g_next, true));
46   }
47
48   ListEntry prev() {
49     static ConstString g_prev("__prev_");
50
51     if (!m_entry_sp)
52       return ListEntry();
53     return ListEntry(m_entry_sp->GetChildMemberWithName(g_prev, true));
54   }
55
56   uint64_t value() const {
57     if (!m_entry_sp)
58       return 0;
59     return m_entry_sp->GetValueAsUnsigned(0);
60   }
61
62   bool null() { return (value() == 0); }
63
64   explicit operator bool() { return GetEntry() && !null(); }
65
66   ValueObjectSP GetEntry() { return m_entry_sp; }
67
68   void SetEntry(ValueObjectSP entry) { m_entry_sp = entry; }
69
70   bool operator==(const ListEntry &rhs) const { return value() == rhs.value(); }
71
72   bool operator!=(const ListEntry &rhs) const { return !(*this == rhs); }
73
74 private:
75   ValueObjectSP m_entry_sp;
76 };
77
78 class ListIterator {
79 public:
80   ListIterator() = default;
81   ListIterator(ListEntry entry) : m_entry(entry) {}
82   ListIterator(ValueObjectSP entry) : m_entry(entry) {}
83   ListIterator(const ListIterator &rhs) = default;
84   ListIterator(ValueObject *entry) : m_entry(entry) {}
85
86   ValueObjectSP value() { return m_entry.GetEntry(); }
87
88   ValueObjectSP advance(size_t count) {
89     if (count == 0)
90       return m_entry.GetEntry();
91     if (count == 1) {
92       next();
93       return m_entry.GetEntry();
94     }
95     while (count > 0) {
96       next();
97       count--;
98       if (m_entry.null())
99         return lldb::ValueObjectSP();
100     }
101     return m_entry.GetEntry();
102   }
103
104   bool operator==(const ListIterator &rhs) const {
105     return (rhs.m_entry == m_entry);
106   }
107
108 protected:
109   void next() { m_entry = m_entry.next(); }
110
111   void prev() { m_entry = m_entry.prev(); }
112
113 private:
114   ListEntry m_entry;
115 };
116
117 class AbstractListFrontEnd : public SyntheticChildrenFrontEnd {
118 public:
119   size_t GetIndexOfChildWithName(const ConstString &name) override {
120     return ExtractIndexFromString(name.GetCString());
121   }
122   bool MightHaveChildren() override { return true; }
123   bool Update() override;
124
125 protected:
126   AbstractListFrontEnd(ValueObject &valobj)
127       : SyntheticChildrenFrontEnd(valobj) {}
128
129   size_t m_count;
130   ValueObject *m_head;
131
132   static constexpr bool g_use_loop_detect = true;
133   size_t m_loop_detected; // The number of elements that have had loop detection
134                           // run over them.
135   ListEntry m_slow_runner; // Used for loop detection
136   ListEntry m_fast_runner; // Used for loop detection
137
138   size_t m_list_capping_size;
139   CompilerType m_element_type;
140   std::map<size_t, ListIterator> m_iterators;
141
142   bool HasLoop(size_t count);
143   ValueObjectSP GetItem(size_t idx);
144 };
145
146 class ForwardListFrontEnd : public AbstractListFrontEnd {
147 public:
148   ForwardListFrontEnd(ValueObject &valobj);
149
150   size_t CalculateNumChildren() override;
151   ValueObjectSP GetChildAtIndex(size_t idx) override;
152   bool Update() override;
153 };
154
155 class ListFrontEnd : public AbstractListFrontEnd {
156 public:
157   ListFrontEnd(lldb::ValueObjectSP valobj_sp);
158
159   ~ListFrontEnd() override = default;
160
161   size_t CalculateNumChildren() override;
162
163   lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
164
165   bool Update() override;
166
167 private:
168   lldb::addr_t m_node_address;
169   ValueObject *m_tail;
170 };
171
172 } // end anonymous namespace
173
174 bool AbstractListFrontEnd::Update() {
175   m_loop_detected = 0;
176   m_count = UINT32_MAX;
177   m_head = nullptr;
178   m_list_capping_size = 0;
179   m_slow_runner.SetEntry(nullptr);
180   m_fast_runner.SetEntry(nullptr);
181   m_iterators.clear();
182
183   if (m_backend.GetTargetSP())
184     m_list_capping_size =
185         m_backend.GetTargetSP()->GetMaximumNumberOfChildrenToDisplay();
186   if (m_list_capping_size == 0)
187     m_list_capping_size = 255;
188
189   CompilerType list_type = m_backend.GetCompilerType();
190   if (list_type.IsReferenceType())
191     list_type = list_type.GetNonReferenceType();
192
193   if (list_type.GetNumTemplateArguments() == 0)
194     return false;
195   m_element_type = list_type.GetTypeTemplateArgument(0);
196
197   return false;
198 }
199
200 bool AbstractListFrontEnd::HasLoop(size_t count) {
201   if (!g_use_loop_detect)
202     return false;
203   // don't bother checking for a loop if we won't actually need to jump nodes
204   if (m_count < 2)
205     return false;
206
207   if (m_loop_detected == 0) {
208     // This is the first time we are being run (after the last update). Set up
209     // the loop invariant for the first element.
210     m_slow_runner = ListEntry(m_head).next();
211     m_fast_runner = m_slow_runner.next();
212     m_loop_detected = 1;
213   }
214
215   // Loop invariant:
216   // Loop detection has been run over the first m_loop_detected elements. If
217   // m_slow_runner == m_fast_runner then the loop has been detected after
218   // m_loop_detected elements.
219   const size_t steps_to_run = std::min(count, m_count);
220   while (m_loop_detected < steps_to_run && m_slow_runner && m_fast_runner &&
221          m_slow_runner != m_fast_runner) {
222
223     m_slow_runner = m_slow_runner.next();
224     m_fast_runner = m_fast_runner.next().next();
225     m_loop_detected++;
226   }
227   if (count <= m_loop_detected)
228     return false; // No loop in the first m_loop_detected elements.
229   if (!m_slow_runner || !m_fast_runner)
230     return false; // Reached the end of the list. Definitely no loops.
231   return m_slow_runner == m_fast_runner;
232 }
233
234 ValueObjectSP AbstractListFrontEnd::GetItem(size_t idx) {
235   size_t advance = idx;
236   ListIterator current(m_head);
237   if (idx > 0) {
238     auto cached_iterator = m_iterators.find(idx - 1);
239     if (cached_iterator != m_iterators.end()) {
240       current = cached_iterator->second;
241       advance = 1;
242     }
243   }
244   ValueObjectSP value_sp = current.advance(advance);
245   m_iterators[idx] = current;
246   return value_sp;
247 }
248
249 ForwardListFrontEnd::ForwardListFrontEnd(ValueObject &valobj)
250     : AbstractListFrontEnd(valobj) {
251   Update();
252 }
253
254 size_t ForwardListFrontEnd::CalculateNumChildren() {
255   if (m_count != UINT32_MAX)
256     return m_count;
257
258   ListEntry current(m_head);
259   m_count = 0;
260   while (current && m_count < m_list_capping_size) {
261     ++m_count;
262     current = current.next();
263   }
264   return m_count;
265 }
266
267 ValueObjectSP ForwardListFrontEnd::GetChildAtIndex(size_t idx) {
268   if (idx >= CalculateNumChildren())
269     return nullptr;
270
271   if (!m_head)
272     return nullptr;
273
274   if (HasLoop(idx + 1))
275     return nullptr;
276
277   ValueObjectSP current_sp = GetItem(idx);
278   if (!current_sp)
279     return nullptr;
280
281   current_sp = current_sp->GetChildAtIndex(1, true); // get the __value_ child
282   if (!current_sp)
283     return nullptr;
284
285   // we need to copy current_sp into a new object otherwise we will end up with
286   // all items named __value_
287   DataExtractor data;
288   Status error;
289   current_sp->GetData(data, error);
290   if (error.Fail())
291     return nullptr;
292
293   return CreateValueObjectFromData(llvm::formatv("[{0}]", idx).str(), data,
294                                    m_backend.GetExecutionContextRef(),
295                                    m_element_type);
296 }
297
298 static ValueObjectSP GetValueOfCompressedPair(ValueObject &pair) {
299   ValueObjectSP value = pair.GetChildMemberWithName(ConstString("__value_"), true);
300   if (! value) {
301     // pre-r300140 member name
302     value = pair.GetChildMemberWithName(ConstString("__first_"), true);
303   }
304   return value;
305 }
306
307 bool ForwardListFrontEnd::Update() {
308   AbstractListFrontEnd::Update();
309
310   Status err;
311   ValueObjectSP backend_addr(m_backend.AddressOf(err));
312   if (err.Fail() || !backend_addr)
313     return false;
314
315   ValueObjectSP impl_sp(
316       m_backend.GetChildMemberWithName(ConstString("__before_begin_"), true));
317   if (!impl_sp)
318     return false;
319   impl_sp = GetValueOfCompressedPair(*impl_sp);
320   if (!impl_sp)
321     return false;
322   m_head = impl_sp->GetChildMemberWithName(ConstString("__next_"), true).get();
323   return false;
324 }
325
326 ListFrontEnd::ListFrontEnd(lldb::ValueObjectSP valobj_sp)
327     : AbstractListFrontEnd(*valobj_sp), m_node_address(), m_tail(nullptr) {
328   if (valobj_sp)
329     Update();
330 }
331
332 size_t ListFrontEnd::CalculateNumChildren() {
333   if (m_count != UINT32_MAX)
334     return m_count;
335   if (!m_head || !m_tail || m_node_address == 0)
336     return 0;
337   ValueObjectSP size_alloc(
338       m_backend.GetChildMemberWithName(ConstString("__size_alloc_"), true));
339   if (size_alloc) {
340     ValueObjectSP value = GetValueOfCompressedPair(*size_alloc);
341     if (value) {
342       m_count = value->GetValueAsUnsigned(UINT32_MAX);
343     }
344   }
345   if (m_count != UINT32_MAX) {
346     return m_count;
347   } else {
348     uint64_t next_val = m_head->GetValueAsUnsigned(0);
349     uint64_t prev_val = m_tail->GetValueAsUnsigned(0);
350     if (next_val == 0 || prev_val == 0)
351       return 0;
352     if (next_val == m_node_address)
353       return 0;
354     if (next_val == prev_val)
355       return 1;
356     uint64_t size = 2;
357     ListEntry current(m_head);
358     while (current.next() && current.next().value() != m_node_address) {
359       size++;
360       current = current.next();
361       if (size > m_list_capping_size)
362         break;
363     }
364     return m_count = (size - 1);
365   }
366 }
367
368 lldb::ValueObjectSP ListFrontEnd::GetChildAtIndex(size_t idx) {
369   static ConstString g_value("__value_");
370   static ConstString g_next("__next_");
371
372   if (idx >= CalculateNumChildren())
373     return lldb::ValueObjectSP();
374
375   if (!m_head || !m_tail || m_node_address == 0)
376     return lldb::ValueObjectSP();
377
378   if (HasLoop(idx + 1))
379     return lldb::ValueObjectSP();
380
381   ValueObjectSP current_sp = GetItem(idx);
382   if (!current_sp)
383     return lldb::ValueObjectSP();
384
385   current_sp = current_sp->GetChildAtIndex(1, true); // get the __value_ child
386   if (!current_sp)
387     return lldb::ValueObjectSP();
388
389   if (current_sp->GetName() == g_next) {
390     ProcessSP process_sp(current_sp->GetProcessSP());
391     if (!process_sp)
392       return nullptr;
393
394     // if we grabbed the __next_ pointer, then the child is one pointer deep-er
395     lldb::addr_t addr = current_sp->GetParent()->GetPointerValue();
396     addr = addr + 2 * process_sp->GetAddressByteSize();
397     ExecutionContext exe_ctx(process_sp);
398     current_sp =
399         CreateValueObjectFromAddress("__value_", addr, exe_ctx, m_element_type);
400   }
401
402   // we need to copy current_sp into a new object otherwise we will end up with
403   // all items named __value_
404   DataExtractor data;
405   Status error;
406   current_sp->GetData(data, error);
407   if (error.Fail())
408     return lldb::ValueObjectSP();
409
410   StreamString name;
411   name.Printf("[%" PRIu64 "]", (uint64_t)idx);
412   return CreateValueObjectFromData(name.GetString(), data,
413                                    m_backend.GetExecutionContextRef(),
414                                    m_element_type);
415 }
416
417 bool ListFrontEnd::Update() {
418   AbstractListFrontEnd::Update();
419   m_tail = nullptr;
420   m_node_address = 0;
421
422   Status err;
423   ValueObjectSP backend_addr(m_backend.AddressOf(err));
424   if (err.Fail() || !backend_addr)
425     return false;
426   m_node_address = backend_addr->GetValueAsUnsigned(0);
427   if (!m_node_address || m_node_address == LLDB_INVALID_ADDRESS)
428     return false;
429   ValueObjectSP impl_sp(
430       m_backend.GetChildMemberWithName(ConstString("__end_"), true));
431   if (!impl_sp)
432     return false;
433   m_head = impl_sp->GetChildMemberWithName(ConstString("__next_"), true).get();
434   m_tail = impl_sp->GetChildMemberWithName(ConstString("__prev_"), true).get();
435   return false;
436 }
437
438 SyntheticChildrenFrontEnd *formatters::LibcxxStdListSyntheticFrontEndCreator(
439     CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
440   return (valobj_sp ? new ListFrontEnd(valobj_sp) : nullptr);
441 }
442
443 SyntheticChildrenFrontEnd *
444 formatters::LibcxxStdForwardListSyntheticFrontEndCreator(
445     CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
446   return valobj_sp ? new ForwardListFrontEnd(*valobj_sp) : nullptr;
447 }