1 //===-- LibCxxList.cpp -------------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "lldb/DataFormatters/CXXFormatterFunctions.h"
12 #include "lldb/Core/DataBufferHeap.h"
13 #include "lldb/Core/Error.h"
14 #include "lldb/Core/Stream.h"
15 #include "lldb/Core/ValueObject.h"
16 #include "lldb/Core/ValueObjectConstResult.h"
17 #include "lldb/Host/Endian.h"
18 #include "lldb/Symbol/ClangASTContext.h"
19 #include "lldb/Target/ObjCLanguageRuntime.h"
20 #include "lldb/Target/Target.h"
23 using namespace lldb_private;
24 using namespace lldb_private::formatters;
26 namespace lldb_private {
27 namespace formatters {
28 class LibcxxStdListSyntheticFrontEnd : public SyntheticChildrenFrontEnd
31 LibcxxStdListSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
34 CalculateNumChildren ();
36 virtual lldb::ValueObjectSP
37 GetChildAtIndex (size_t idx);
46 GetIndexOfChildWithName (const ConstString &name);
49 ~LibcxxStdListSyntheticFrontEnd ();
54 size_t m_list_capping_size;
55 static const bool g_use_loop_detect = true;
56 size_t m_loop_detected;
57 lldb::addr_t m_node_address;
60 ClangASTType m_element_type;
62 std::map<size_t,lldb::ValueObjectSP> m_children;
71 ListEntry (ValueObjectSP entry_sp) : m_entry_sp(entry_sp) {}
72 ListEntry (const ListEntry& rhs) : m_entry_sp(rhs.m_entry_sp) {}
73 ListEntry (ValueObject* entry) : m_entry_sp(entry ? entry->GetSP() : ValueObjectSP()) {}
80 return ListEntry(m_entry_sp->GetChildMemberWithName(ConstString("__next_"), true));
88 return ListEntry(m_entry_sp->GetChildMemberWithName(ConstString("__prev_"), true));
96 return m_entry_sp->GetValueAsUnsigned(0);
102 return (value() == 0);
105 explicit operator bool ()
107 return GetEntry().get() != nullptr && null() == false;
117 SetEntry (ValueObjectSP entry)
123 operator == (const ListEntry& rhs) const
125 return (rhs.m_entry_sp.get() == m_entry_sp.get());
129 ValueObjectSP m_entry_sp;
136 ListIterator (ListEntry entry) : m_entry(entry) {}
137 ListIterator (ValueObjectSP entry) : m_entry(entry) {}
138 ListIterator (const ListIterator& rhs) : m_entry(rhs.m_entry) {}
139 ListIterator (ValueObject* entry) : m_entry(entry) {}
144 return m_entry.GetEntry();
148 advance (size_t count)
151 return m_entry.GetEntry();
155 return m_entry.GetEntry();
162 return lldb::ValueObjectSP();
164 return m_entry.GetEntry();
168 operator == (const ListIterator& rhs) const
170 return (rhs.m_entry == m_entry);
177 m_entry = m_entry.next();
183 m_entry = m_entry.prev();
189 lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::LibcxxStdListSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
190 SyntheticChildrenFrontEnd(*valobj_sp.get()),
191 m_list_capping_size(0),
205 lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::HasLoop(size_t count)
207 if (g_use_loop_detect == false)
209 // don't bother checking for a loop if we won't actually need to jump nodes
212 auto steps_left = std::min(count,m_count);
213 auto steps_left_save = steps_left;
214 ListEntry slow(m_head);
215 ListEntry fast(m_head);
216 while (steps_left-- > 0)
221 fast = fast.next().next();
229 m_loop_detected = steps_left_save;
234 lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::CalculateNumChildren ()
236 if (m_count != UINT32_MAX)
238 if (!m_head || !m_tail || m_node_address == 0)
240 ValueObjectSP size_alloc(m_backend.GetChildMemberWithName(ConstString("__size_alloc_"), true));
243 ValueObjectSP first(size_alloc->GetChildMemberWithName(ConstString("__first_"), true));
246 m_count = first->GetValueAsUnsigned(UINT32_MAX);
249 if (m_count != UINT32_MAX)
255 uint64_t next_val = m_head->GetValueAsUnsigned(0);
256 uint64_t prev_val = m_tail->GetValueAsUnsigned(0);
257 if (next_val == 0 || prev_val == 0)
259 if (next_val == m_node_address)
261 if (next_val == prev_val)
264 ListEntry current(m_head);
265 while (current.next() && current.next().value() != m_node_address)
268 current = current.next();
269 if (size > m_list_capping_size)
272 return m_count = (size-1);
277 lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::GetChildAtIndex (size_t idx)
279 if (idx >= CalculateNumChildren())
280 return lldb::ValueObjectSP();
282 if (!m_head || !m_tail || m_node_address == 0)
283 return lldb::ValueObjectSP();
285 auto cached = m_children.find(idx);
286 if (cached != m_children.end())
287 return cached->second;
289 if (m_loop_detected <= idx)
291 return lldb::ValueObjectSP();
293 ListIterator current(m_head);
294 ValueObjectSP current_sp(current.advance(idx));
296 return lldb::ValueObjectSP();
297 current_sp = current_sp->GetChildMemberWithName(ConstString("__value_"), true);
299 return lldb::ValueObjectSP();
300 // we need to copy current_sp into a new object otherwise we will end up with all items named __value_
303 current_sp->GetData(data, error);
305 return lldb::ValueObjectSP();
308 name.Printf("[%" PRIu64 "]", (uint64_t)idx);
309 return (m_children[idx] = CreateValueObjectFromData(name.GetData(), data, m_backend.GetExecutionContextRef(), m_element_type));
313 lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::Update()
315 m_head = m_tail = NULL;
317 m_count = UINT32_MAX;
318 m_loop_detected = false;
320 ValueObjectSP backend_addr(m_backend.AddressOf(err));
321 m_list_capping_size = 0;
322 if (m_backend.GetTargetSP())
323 m_list_capping_size = m_backend.GetTargetSP()->GetMaximumNumberOfChildrenToDisplay();
324 if (m_list_capping_size == 0)
325 m_list_capping_size = 255;
326 if (err.Fail() || backend_addr.get() == NULL)
328 m_node_address = backend_addr->GetValueAsUnsigned(0);
329 if (!m_node_address || m_node_address == LLDB_INVALID_ADDRESS)
331 ValueObjectSP impl_sp(m_backend.GetChildMemberWithName(ConstString("__end_"),true));
334 ClangASTType list_type = m_backend.GetClangType();
335 if (list_type.IsReferenceType())
336 list_type = list_type.GetNonReferenceType();
338 if (list_type.GetNumTemplateArguments() == 0)
340 lldb::TemplateArgumentKind kind;
341 m_element_type = list_type.GetTemplateArgument(0, kind);
342 m_head = impl_sp->GetChildMemberWithName(ConstString("__next_"), true).get();
343 m_tail = impl_sp->GetChildMemberWithName(ConstString("__prev_"), true).get();
348 lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::MightHaveChildren ()
354 lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
356 return ExtractIndexFromString(name.GetCString());
359 lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::~LibcxxStdListSyntheticFrontEnd ()
362 SyntheticChildrenFrontEnd*
363 lldb_private::formatters::LibcxxStdListSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
367 return (new LibcxxStdListSyntheticFrontEnd(valobj_sp));