180814287SRaphael Isemann //===-- LibCxxList.cpp ----------------------------------------------------===//
233e97e63SEnrico Granata //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
633e97e63SEnrico Granata //
733e97e63SEnrico Granata //===----------------------------------------------------------------------===//
833e97e63SEnrico Granata 
933e97e63SEnrico Granata #include "LibCxx.h"
1033e97e63SEnrico Granata 
118be30215SAlex Langford #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
1233e97e63SEnrico Granata #include "lldb/Core/ValueObject.h"
1333e97e63SEnrico Granata #include "lldb/Core/ValueObjectConstResult.h"
1433e97e63SEnrico Granata #include "lldb/DataFormatters/FormattersHelpers.h"
1533e97e63SEnrico Granata #include "lldb/Target/Target.h"
16666cc0b2SZachary Turner #include "lldb/Utility/DataBufferHeap.h"
1701c3243fSZachary Turner #include "lldb/Utility/Endian.h"
1897206d57SZachary Turner #include "lldb/Utility/Status.h"
19bf9a7730SZachary Turner #include "lldb/Utility/Stream.h"
2033e97e63SEnrico Granata 
2133e97e63SEnrico Granata using namespace lldb;
2233e97e63SEnrico Granata using namespace lldb_private;
2333e97e63SEnrico Granata using namespace lldb_private::formatters;
2433e97e63SEnrico Granata 
2565a16e56SPavel Labath namespace {
2633e97e63SEnrico Granata 
27b9c1b51eSKate Stone class ListEntry {
2833e97e63SEnrico Granata public:
298d15f33bSEugene Zelenko   ListEntry() = default;
ListEntry(ValueObjectSP entry_sp)306dc2a6a8SDavid Blaikie   ListEntry(ValueObjectSP entry_sp) : m_entry_sp(std::move(entry_sp)) {}
ListEntry(ValueObject * entry)31b9c1b51eSKate Stone   ListEntry(ValueObject *entry)
32b9c1b51eSKate Stone       : m_entry_sp(entry ? entry->GetSP() : ValueObjectSP()) {}
3333e97e63SEnrico Granata 
next()34b9c1b51eSKate Stone   ListEntry next() {
35e555763fSEnrico Granata     static ConstString g_next("__next_");
36e555763fSEnrico Granata 
3733e97e63SEnrico Granata     if (!m_entry_sp)
3833e97e63SEnrico Granata       return ListEntry();
39e555763fSEnrico Granata     return ListEntry(m_entry_sp->GetChildMemberWithName(g_next, true));
4033e97e63SEnrico Granata   }
4133e97e63SEnrico Granata 
prev()42b9c1b51eSKate Stone   ListEntry prev() {
43e555763fSEnrico Granata     static ConstString g_prev("__prev_");
44e555763fSEnrico Granata 
4533e97e63SEnrico Granata     if (!m_entry_sp)
4633e97e63SEnrico Granata       return ListEntry();
47e555763fSEnrico Granata     return ListEntry(m_entry_sp->GetChildMemberWithName(g_prev, true));
4833e97e63SEnrico Granata   }
4933e97e63SEnrico Granata 
value() const50b9c1b51eSKate Stone   uint64_t value() const {
5133e97e63SEnrico Granata     if (!m_entry_sp)
5233e97e63SEnrico Granata       return 0;
5333e97e63SEnrico Granata     return m_entry_sp->GetValueAsUnsigned(0);
5433e97e63SEnrico Granata   }
5533e97e63SEnrico Granata 
null()56b9c1b51eSKate Stone   bool null() { return (value() == 0); }
5733e97e63SEnrico Granata 
operator bool()58b9c1b51eSKate Stone   explicit operator bool() { return GetEntry() && !null(); }
5933e97e63SEnrico Granata 
GetEntry()60b9c1b51eSKate Stone   ValueObjectSP GetEntry() { return m_entry_sp; }
6133e97e63SEnrico Granata 
SetEntry(ValueObjectSP entry)62b9c1b51eSKate Stone   void SetEntry(ValueObjectSP entry) { m_entry_sp = entry; }
6333e97e63SEnrico Granata 
operator ==(const ListEntry & rhs) const64b9c1b51eSKate Stone   bool operator==(const ListEntry &rhs) const { return value() == rhs.value(); }
6565a16e56SPavel Labath 
operator !=(const ListEntry & rhs) const66b9c1b51eSKate Stone   bool operator!=(const ListEntry &rhs) const { return !(*this == rhs); }
6733e97e63SEnrico Granata 
6833e97e63SEnrico Granata private:
6933e97e63SEnrico Granata   ValueObjectSP m_entry_sp;
7033e97e63SEnrico Granata };
7133e97e63SEnrico Granata 
72b9c1b51eSKate Stone class ListIterator {
7333e97e63SEnrico Granata public:
748d15f33bSEugene Zelenko   ListIterator() = default;
ListIterator(ListEntry entry)756dc2a6a8SDavid Blaikie   ListIterator(ListEntry entry) : m_entry(std::move(entry)) {}
ListIterator(ValueObjectSP entry)766dc2a6a8SDavid Blaikie   ListIterator(ValueObjectSP entry) : m_entry(std::move(entry)) {}
ListIterator(ValueObject * entry)7733e97e63SEnrico Granata   ListIterator(ValueObject *entry) : m_entry(entry) {}
7833e97e63SEnrico Granata 
value()79b9c1b51eSKate Stone   ValueObjectSP value() { return m_entry.GetEntry(); }
8033e97e63SEnrico Granata 
advance(size_t count)81b9c1b51eSKate Stone   ValueObjectSP advance(size_t count) {
8233e97e63SEnrico Granata     if (count == 0)
8333e97e63SEnrico Granata       return m_entry.GetEntry();
84b9c1b51eSKate Stone     if (count == 1) {
8533e97e63SEnrico Granata       next();
8633e97e63SEnrico Granata       return m_entry.GetEntry();
8733e97e63SEnrico Granata     }
88b9c1b51eSKate Stone     while (count > 0) {
8933e97e63SEnrico Granata       next();
9033e97e63SEnrico Granata       count--;
9133e97e63SEnrico Granata       if (m_entry.null())
9233e97e63SEnrico Granata         return lldb::ValueObjectSP();
9333e97e63SEnrico Granata     }
9433e97e63SEnrico Granata     return m_entry.GetEntry();
9533e97e63SEnrico Granata   }
9633e97e63SEnrico Granata 
operator ==(const ListIterator & rhs) const97b9c1b51eSKate Stone   bool operator==(const ListIterator &rhs) const {
9833e97e63SEnrico Granata     return (rhs.m_entry == m_entry);
9933e97e63SEnrico Granata   }
10033e97e63SEnrico Granata 
10133e97e63SEnrico Granata protected:
next()102b9c1b51eSKate Stone   void next() { m_entry = m_entry.next(); }
10333e97e63SEnrico Granata 
prev()104b9c1b51eSKate Stone   void prev() { m_entry = m_entry.prev(); }
1058d15f33bSEugene Zelenko 
10633e97e63SEnrico Granata private:
10733e97e63SEnrico Granata   ListEntry m_entry;
10833e97e63SEnrico Granata };
10933e97e63SEnrico Granata 
11089ac0c7dSPavel Labath class AbstractListFrontEnd : public SyntheticChildrenFrontEnd {
11126935d9aSEnrico Granata public:
GetIndexOfChildWithName(ConstString name)1120e4c4821SAdrian Prantl   size_t GetIndexOfChildWithName(ConstString name) override {
11389ac0c7dSPavel Labath     return ExtractIndexFromString(name.GetCString());
11489ac0c7dSPavel Labath   }
MightHaveChildren()11589ac0c7dSPavel Labath   bool MightHaveChildren() override { return true; }
11689ac0c7dSPavel Labath   bool Update() override;
11726935d9aSEnrico Granata 
11889ac0c7dSPavel Labath protected:
AbstractListFrontEnd(ValueObject & valobj)11989ac0c7dSPavel Labath   AbstractListFrontEnd(ValueObject &valobj)
12089ac0c7dSPavel Labath       : SyntheticChildrenFrontEnd(valobj) {}
12189ac0c7dSPavel Labath 
122*459cfa5eSSlava Gurevich   size_t m_count = 0;
123*459cfa5eSSlava Gurevich   ValueObject *m_head = nullptr;
12489ac0c7dSPavel Labath 
12589ac0c7dSPavel Labath   static constexpr bool g_use_loop_detect = true;
126*459cfa5eSSlava Gurevich   size_t m_loop_detected = 0; // The number of elements that have had loop
127*459cfa5eSSlava Gurevich                               // detection run over them.
12889ac0c7dSPavel Labath   ListEntry m_slow_runner; // Used for loop detection
12989ac0c7dSPavel Labath   ListEntry m_fast_runner; // Used for loop detection
13089ac0c7dSPavel Labath 
131*459cfa5eSSlava Gurevich   size_t m_list_capping_size = 0;
13289ac0c7dSPavel Labath   CompilerType m_element_type;
13389ac0c7dSPavel Labath   std::map<size_t, ListIterator> m_iterators;
13489ac0c7dSPavel Labath 
13589ac0c7dSPavel Labath   bool HasLoop(size_t count);
13689ac0c7dSPavel Labath   ValueObjectSP GetItem(size_t idx);
13789ac0c7dSPavel Labath };
13889ac0c7dSPavel Labath 
13989ac0c7dSPavel Labath class ForwardListFrontEnd : public AbstractListFrontEnd {
14089ac0c7dSPavel Labath public:
14189ac0c7dSPavel Labath   ForwardListFrontEnd(ValueObject &valobj);
14289ac0c7dSPavel Labath 
14389ac0c7dSPavel Labath   size_t CalculateNumChildren() override;
14489ac0c7dSPavel Labath   ValueObjectSP GetChildAtIndex(size_t idx) override;
14589ac0c7dSPavel Labath   bool Update() override;
14689ac0c7dSPavel Labath };
14789ac0c7dSPavel Labath 
14889ac0c7dSPavel Labath class ListFrontEnd : public AbstractListFrontEnd {
14989ac0c7dSPavel Labath public:
15089ac0c7dSPavel Labath   ListFrontEnd(lldb::ValueObjectSP valobj_sp);
15189ac0c7dSPavel Labath 
15289ac0c7dSPavel Labath   ~ListFrontEnd() override = default;
15326935d9aSEnrico Granata 
154b9c1b51eSKate Stone   size_t CalculateNumChildren() override;
15526935d9aSEnrico Granata 
156b9c1b51eSKate Stone   lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
15726935d9aSEnrico Granata 
158b9c1b51eSKate Stone   bool Update() override;
15926935d9aSEnrico Granata 
16026935d9aSEnrico Granata private:
16128c878aeSShafik Yaghmour   lldb::addr_t m_node_address = 0;
16228c878aeSShafik Yaghmour   ValueObject *m_tail = nullptr;
16326935d9aSEnrico Granata };
16426935d9aSEnrico Granata 
16589ac0c7dSPavel Labath } // end anonymous namespace
16689ac0c7dSPavel Labath 
Update()16789ac0c7dSPavel Labath bool AbstractListFrontEnd::Update() {
16889ac0c7dSPavel Labath   m_loop_detected = 0;
16989ac0c7dSPavel Labath   m_count = UINT32_MAX;
17089ac0c7dSPavel Labath   m_head = nullptr;
17189ac0c7dSPavel Labath   m_list_capping_size = 0;
17289ac0c7dSPavel Labath   m_slow_runner.SetEntry(nullptr);
17389ac0c7dSPavel Labath   m_fast_runner.SetEntry(nullptr);
17489ac0c7dSPavel Labath   m_iterators.clear();
17589ac0c7dSPavel Labath 
17689ac0c7dSPavel Labath   if (m_backend.GetTargetSP())
17789ac0c7dSPavel Labath     m_list_capping_size =
17889ac0c7dSPavel Labath         m_backend.GetTargetSP()->GetMaximumNumberOfChildrenToDisplay();
17989ac0c7dSPavel Labath   if (m_list_capping_size == 0)
18089ac0c7dSPavel Labath     m_list_capping_size = 255;
18189ac0c7dSPavel Labath 
18289ac0c7dSPavel Labath   CompilerType list_type = m_backend.GetCompilerType();
18389ac0c7dSPavel Labath   if (list_type.IsReferenceType())
18489ac0c7dSPavel Labath     list_type = list_type.GetNonReferenceType();
18589ac0c7dSPavel Labath 
18689ac0c7dSPavel Labath   if (list_type.GetNumTemplateArguments() == 0)
18789ac0c7dSPavel Labath     return false;
188769b21eaSPavel Labath   m_element_type = list_type.GetTypeTemplateArgument(0);
18989ac0c7dSPavel Labath 
19089ac0c7dSPavel Labath   return false;
19133e97e63SEnrico Granata }
19233e97e63SEnrico Granata 
HasLoop(size_t count)19389ac0c7dSPavel Labath bool AbstractListFrontEnd::HasLoop(size_t count) {
194bbd16815SEugene Zelenko   if (!g_use_loop_detect)
19533e97e63SEnrico Granata     return false;
19633e97e63SEnrico Granata   // don't bother checking for a loop if we won't actually need to jump nodes
19733e97e63SEnrico Granata   if (m_count < 2)
19833e97e63SEnrico Granata     return false;
19965a16e56SPavel Labath 
200b9c1b51eSKate Stone   if (m_loop_detected == 0) {
201b9c1b51eSKate Stone     // This is the first time we are being run (after the last update). Set up
20205097246SAdrian Prantl     // the loop invariant for the first element.
20365a16e56SPavel Labath     m_slow_runner = ListEntry(m_head).next();
20465a16e56SPavel Labath     m_fast_runner = m_slow_runner.next();
20565a16e56SPavel Labath     m_loop_detected = 1;
20633e97e63SEnrico Granata   }
20765a16e56SPavel Labath 
20865a16e56SPavel Labath   // Loop invariant:
209b9c1b51eSKate Stone   // Loop detection has been run over the first m_loop_detected elements. If
21005097246SAdrian Prantl   // m_slow_runner == m_fast_runner then the loop has been detected after
21105097246SAdrian Prantl   // m_loop_detected elements.
21265a16e56SPavel Labath   const size_t steps_to_run = std::min(count, m_count);
213b9c1b51eSKate Stone   while (m_loop_detected < steps_to_run && m_slow_runner && m_fast_runner &&
214b9c1b51eSKate Stone          m_slow_runner != m_fast_runner) {
21565a16e56SPavel Labath 
21665a16e56SPavel Labath     m_slow_runner = m_slow_runner.next();
21765a16e56SPavel Labath     m_fast_runner = m_fast_runner.next().next();
21865a16e56SPavel Labath     m_loop_detected++;
21965a16e56SPavel Labath   }
22065a16e56SPavel Labath   if (count <= m_loop_detected)
22165a16e56SPavel Labath     return false; // No loop in the first m_loop_detected elements.
22265a16e56SPavel Labath   if (!m_slow_runner || !m_fast_runner)
22365a16e56SPavel Labath     return false; // Reached the end of the list. Definitely no loops.
22465a16e56SPavel Labath   return m_slow_runner == m_fast_runner;
22533e97e63SEnrico Granata }
22633e97e63SEnrico Granata 
GetItem(size_t idx)22789ac0c7dSPavel Labath ValueObjectSP AbstractListFrontEnd::GetItem(size_t idx) {
22889ac0c7dSPavel Labath   size_t advance = idx;
22989ac0c7dSPavel Labath   ListIterator current(m_head);
23089ac0c7dSPavel Labath   if (idx > 0) {
23189ac0c7dSPavel Labath     auto cached_iterator = m_iterators.find(idx - 1);
23289ac0c7dSPavel Labath     if (cached_iterator != m_iterators.end()) {
23389ac0c7dSPavel Labath       current = cached_iterator->second;
23489ac0c7dSPavel Labath       advance = 1;
23589ac0c7dSPavel Labath     }
23689ac0c7dSPavel Labath   }
23789ac0c7dSPavel Labath   ValueObjectSP value_sp = current.advance(advance);
23889ac0c7dSPavel Labath   m_iterators[idx] = current;
23989ac0c7dSPavel Labath   return value_sp;
24089ac0c7dSPavel Labath }
24189ac0c7dSPavel Labath 
ForwardListFrontEnd(ValueObject & valobj)24289ac0c7dSPavel Labath ForwardListFrontEnd::ForwardListFrontEnd(ValueObject &valobj)
24389ac0c7dSPavel Labath     : AbstractListFrontEnd(valobj) {
24489ac0c7dSPavel Labath   Update();
24589ac0c7dSPavel Labath }
24689ac0c7dSPavel Labath 
CalculateNumChildren()24789ac0c7dSPavel Labath size_t ForwardListFrontEnd::CalculateNumChildren() {
24889ac0c7dSPavel Labath   if (m_count != UINT32_MAX)
24989ac0c7dSPavel Labath     return m_count;
25089ac0c7dSPavel Labath 
25189ac0c7dSPavel Labath   ListEntry current(m_head);
25289ac0c7dSPavel Labath   m_count = 0;
25389ac0c7dSPavel Labath   while (current && m_count < m_list_capping_size) {
25489ac0c7dSPavel Labath     ++m_count;
25589ac0c7dSPavel Labath     current = current.next();
25689ac0c7dSPavel Labath   }
25789ac0c7dSPavel Labath   return m_count;
25889ac0c7dSPavel Labath }
25989ac0c7dSPavel Labath 
GetChildAtIndex(size_t idx)26089ac0c7dSPavel Labath ValueObjectSP ForwardListFrontEnd::GetChildAtIndex(size_t idx) {
26189ac0c7dSPavel Labath   if (idx >= CalculateNumChildren())
26289ac0c7dSPavel Labath     return nullptr;
26389ac0c7dSPavel Labath 
26489ac0c7dSPavel Labath   if (!m_head)
26589ac0c7dSPavel Labath     return nullptr;
26689ac0c7dSPavel Labath 
26789ac0c7dSPavel Labath   if (HasLoop(idx + 1))
26889ac0c7dSPavel Labath     return nullptr;
26989ac0c7dSPavel Labath 
27089ac0c7dSPavel Labath   ValueObjectSP current_sp = GetItem(idx);
27189ac0c7dSPavel Labath   if (!current_sp)
27289ac0c7dSPavel Labath     return nullptr;
27389ac0c7dSPavel Labath 
27489ac0c7dSPavel Labath   current_sp = current_sp->GetChildAtIndex(1, true); // get the __value_ child
27589ac0c7dSPavel Labath   if (!current_sp)
27689ac0c7dSPavel Labath     return nullptr;
27789ac0c7dSPavel Labath 
27889ac0c7dSPavel Labath   // we need to copy current_sp into a new object otherwise we will end up with
27989ac0c7dSPavel Labath   // all items named __value_
28089ac0c7dSPavel Labath   DataExtractor data;
28189ac0c7dSPavel Labath   Status error;
28289ac0c7dSPavel Labath   current_sp->GetData(data, error);
28389ac0c7dSPavel Labath   if (error.Fail())
28489ac0c7dSPavel Labath     return nullptr;
28589ac0c7dSPavel Labath 
28689ac0c7dSPavel Labath   return CreateValueObjectFromData(llvm::formatv("[{0}]", idx).str(), data,
28789ac0c7dSPavel Labath                                    m_backend.GetExecutionContextRef(),
28889ac0c7dSPavel Labath                                    m_element_type);
28989ac0c7dSPavel Labath }
29089ac0c7dSPavel Labath 
Update()29189ac0c7dSPavel Labath bool ForwardListFrontEnd::Update() {
29289ac0c7dSPavel Labath   AbstractListFrontEnd::Update();
29389ac0c7dSPavel Labath 
29489ac0c7dSPavel Labath   Status err;
29589ac0c7dSPavel Labath   ValueObjectSP backend_addr(m_backend.AddressOf(err));
29689ac0c7dSPavel Labath   if (err.Fail() || !backend_addr)
29789ac0c7dSPavel Labath     return false;
29889ac0c7dSPavel Labath 
29989ac0c7dSPavel Labath   ValueObjectSP impl_sp(
30089ac0c7dSPavel Labath       m_backend.GetChildMemberWithName(ConstString("__before_begin_"), true));
30189ac0c7dSPavel Labath   if (!impl_sp)
30289ac0c7dSPavel Labath     return false;
303a567d680Sshafik   impl_sp = GetValueOfLibCXXCompressedPair(*impl_sp);
30489ac0c7dSPavel Labath   if (!impl_sp)
30589ac0c7dSPavel Labath     return false;
30689ac0c7dSPavel Labath   m_head = impl_sp->GetChildMemberWithName(ConstString("__next_"), true).get();
30789ac0c7dSPavel Labath   return false;
30889ac0c7dSPavel Labath }
30989ac0c7dSPavel Labath 
ListFrontEnd(lldb::ValueObjectSP valobj_sp)31089ac0c7dSPavel Labath ListFrontEnd::ListFrontEnd(lldb::ValueObjectSP valobj_sp)
31128c878aeSShafik Yaghmour     : AbstractListFrontEnd(*valobj_sp) {
31289ac0c7dSPavel Labath   if (valobj_sp)
31389ac0c7dSPavel Labath     Update();
31489ac0c7dSPavel Labath }
31589ac0c7dSPavel Labath 
CalculateNumChildren()31689ac0c7dSPavel Labath size_t ListFrontEnd::CalculateNumChildren() {
31733e97e63SEnrico Granata   if (m_count != UINT32_MAX)
31833e97e63SEnrico Granata     return m_count;
31933e97e63SEnrico Granata   if (!m_head || !m_tail || m_node_address == 0)
32033e97e63SEnrico Granata     return 0;
321b9c1b51eSKate Stone   ValueObjectSP size_alloc(
322b9c1b51eSKate Stone       m_backend.GetChildMemberWithName(ConstString("__size_alloc_"), true));
323b9c1b51eSKate Stone   if (size_alloc) {
324a567d680Sshafik     ValueObjectSP value = GetValueOfLibCXXCompressedPair(*size_alloc);
3254c0461f8SPavel Labath     if (value) {
3264c0461f8SPavel Labath       m_count = value->GetValueAsUnsigned(UINT32_MAX);
32733e97e63SEnrico Granata     }
32833e97e63SEnrico Granata   }
329b9c1b51eSKate Stone   if (m_count != UINT32_MAX) {
33033e97e63SEnrico Granata     return m_count;
331b9c1b51eSKate Stone   } else {
33233e97e63SEnrico Granata     uint64_t next_val = m_head->GetValueAsUnsigned(0);
33333e97e63SEnrico Granata     uint64_t prev_val = m_tail->GetValueAsUnsigned(0);
33433e97e63SEnrico Granata     if (next_val == 0 || prev_val == 0)
33533e97e63SEnrico Granata       return 0;
33633e97e63SEnrico Granata     if (next_val == m_node_address)
33733e97e63SEnrico Granata       return 0;
33833e97e63SEnrico Granata     if (next_val == prev_val)
33933e97e63SEnrico Granata       return 1;
34033e97e63SEnrico Granata     uint64_t size = 2;
34133e97e63SEnrico Granata     ListEntry current(m_head);
342b9c1b51eSKate Stone     while (current.next() && current.next().value() != m_node_address) {
34333e97e63SEnrico Granata       size++;
34433e97e63SEnrico Granata       current = current.next();
34533e97e63SEnrico Granata       if (size > m_list_capping_size)
34633e97e63SEnrico Granata         break;
34733e97e63SEnrico Granata     }
34833e97e63SEnrico Granata     return m_count = (size - 1);
34933e97e63SEnrico Granata   }
35033e97e63SEnrico Granata }
35133e97e63SEnrico Granata 
GetChildAtIndex(size_t idx)35289ac0c7dSPavel Labath lldb::ValueObjectSP ListFrontEnd::GetChildAtIndex(size_t idx) {
353e555763fSEnrico Granata   static ConstString g_value("__value_");
354e555763fSEnrico Granata   static ConstString g_next("__next_");
355e555763fSEnrico Granata 
35633e97e63SEnrico Granata   if (idx >= CalculateNumChildren())
35733e97e63SEnrico Granata     return lldb::ValueObjectSP();
35833e97e63SEnrico Granata 
35933e97e63SEnrico Granata   if (!m_head || !m_tail || m_node_address == 0)
36033e97e63SEnrico Granata     return lldb::ValueObjectSP();
36133e97e63SEnrico Granata 
36265a16e56SPavel Labath   if (HasLoop(idx + 1))
36333e97e63SEnrico Granata     return lldb::ValueObjectSP();
36433e97e63SEnrico Granata 
36589ac0c7dSPavel Labath   ValueObjectSP current_sp = GetItem(idx);
36633e97e63SEnrico Granata   if (!current_sp)
36733e97e63SEnrico Granata     return lldb::ValueObjectSP();
36826935d9aSEnrico Granata 
369367e2fe1SEnrico Granata   current_sp = current_sp->GetChildAtIndex(1, true); // get the __value_ child
37033e97e63SEnrico Granata   if (!current_sp)
37133e97e63SEnrico Granata     return lldb::ValueObjectSP();
372e555763fSEnrico Granata 
373b9c1b51eSKate Stone   if (current_sp->GetName() == g_next) {
374e555763fSEnrico Granata     ProcessSP process_sp(current_sp->GetProcessSP());
375e555763fSEnrico Granata     if (!process_sp)
376027bf760SJim Ingham       return lldb::ValueObjectSP();
377e555763fSEnrico Granata 
378e555763fSEnrico Granata     // if we grabbed the __next_ pointer, then the child is one pointer deep-er
379e555763fSEnrico Granata     lldb::addr_t addr = current_sp->GetParent()->GetPointerValue();
380e555763fSEnrico Granata     addr = addr + 2 * process_sp->GetAddressByteSize();
381e555763fSEnrico Granata     ExecutionContext exe_ctx(process_sp);
382b9c1b51eSKate Stone     current_sp =
383b9c1b51eSKate Stone         CreateValueObjectFromAddress("__value_", addr, exe_ctx, m_element_type);
384027bf760SJim Ingham     if (!current_sp)
385027bf760SJim Ingham       return lldb::ValueObjectSP();
386e555763fSEnrico Granata   }
387e555763fSEnrico Granata 
388b9c1b51eSKate Stone   // we need to copy current_sp into a new object otherwise we will end up with
389b9c1b51eSKate Stone   // all items named __value_
39033e97e63SEnrico Granata   DataExtractor data;
39197206d57SZachary Turner   Status error;
39233e97e63SEnrico Granata   current_sp->GetData(data, error);
39333e97e63SEnrico Granata   if (error.Fail())
39433e97e63SEnrico Granata     return lldb::ValueObjectSP();
39533e97e63SEnrico Granata 
39633e97e63SEnrico Granata   StreamString name;
39733e97e63SEnrico Granata   name.Printf("[%" PRIu64 "]", (uint64_t)idx);
398c156427dSZachary Turner   return CreateValueObjectFromData(name.GetString(), data,
399c156427dSZachary Turner                                    m_backend.GetExecutionContextRef(),
400c156427dSZachary Turner                                    m_element_type);
40133e97e63SEnrico Granata }
40233e97e63SEnrico Granata 
Update()40389ac0c7dSPavel Labath bool ListFrontEnd::Update() {
40489ac0c7dSPavel Labath   AbstractListFrontEnd::Update();
40589ac0c7dSPavel Labath   m_tail = nullptr;
40633e97e63SEnrico Granata   m_node_address = 0;
40765a16e56SPavel Labath 
40897206d57SZachary Turner   Status err;
40933e97e63SEnrico Granata   ValueObjectSP backend_addr(m_backend.AddressOf(err));
410bbd16815SEugene Zelenko   if (err.Fail() || !backend_addr)
41133e97e63SEnrico Granata     return false;
41233e97e63SEnrico Granata   m_node_address = backend_addr->GetValueAsUnsigned(0);
41333e97e63SEnrico Granata   if (!m_node_address || m_node_address == LLDB_INVALID_ADDRESS)
41433e97e63SEnrico Granata     return false;
415b9c1b51eSKate Stone   ValueObjectSP impl_sp(
416b9c1b51eSKate Stone       m_backend.GetChildMemberWithName(ConstString("__end_"), true));
41733e97e63SEnrico Granata   if (!impl_sp)
41833e97e63SEnrico Granata     return false;
41933e97e63SEnrico Granata   m_head = impl_sp->GetChildMemberWithName(ConstString("__next_"), true).get();
42033e97e63SEnrico Granata   m_tail = impl_sp->GetChildMemberWithName(ConstString("__prev_"), true).get();
42133e97e63SEnrico Granata   return false;
42233e97e63SEnrico Granata }
42333e97e63SEnrico Granata 
LibcxxStdListSyntheticFrontEndCreator(CXXSyntheticChildren *,lldb::ValueObjectSP valobj_sp)42489ac0c7dSPavel Labath SyntheticChildrenFrontEnd *formatters::LibcxxStdListSyntheticFrontEndCreator(
42589ac0c7dSPavel Labath     CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
42689ac0c7dSPavel Labath   return (valobj_sp ? new ListFrontEnd(valobj_sp) : nullptr);
42733e97e63SEnrico Granata }
42833e97e63SEnrico Granata 
42933e97e63SEnrico Granata SyntheticChildrenFrontEnd *
LibcxxStdForwardListSyntheticFrontEndCreator(CXXSyntheticChildren *,lldb::ValueObjectSP valobj_sp)43089ac0c7dSPavel Labath formatters::LibcxxStdForwardListSyntheticFrontEndCreator(
431b9c1b51eSKate Stone     CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
43289ac0c7dSPavel Labath   return valobj_sp ? new ForwardListFrontEnd(*valobj_sp) : nullptr;
43333e97e63SEnrico Granata }
434