diff options
author | Enrico Granata <egranata@apple.com> | 2015-09-04 21:01:18 +0000 |
---|---|---|
committer | Enrico Granata <egranata@apple.com> | 2015-09-04 21:01:18 +0000 |
commit | 33e97e63a5928ee6884f41ef8d609653ac1b375f (patch) | |
tree | df5ad6e9f8495f779efadf1d4bd883a4c9620389 /lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp | |
parent | 7a518c3dabe75faece2b9b38f466c936dd3decda (diff) | |
download | bcm5719-llvm-33e97e63a5928ee6884f41ef8d609653ac1b375f.tar.gz bcm5719-llvm-33e97e63a5928ee6884f41ef8d609653ac1b375f.zip |
Move the C++ data formatters to the C++ language plugin
llvm-svn: 246873
Diffstat (limited to 'lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp')
-rw-r--r-- | lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp | 370 |
1 files changed, 370 insertions, 0 deletions
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp new file mode 100644 index 00000000000..7da1b7a128f --- /dev/null +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp @@ -0,0 +1,370 @@ +//===-- LibCxxList.cpp -------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "LibCxx.h" + +#include "lldb/Core/DataBufferHeap.h" +#include "lldb/Core/Error.h" +#include "lldb/Core/Stream.h" +#include "lldb/Core/ValueObject.h" +#include "lldb/Core/ValueObjectConstResult.h" +#include "lldb/DataFormatters/FormattersHelpers.h" +#include "lldb/Host/Endian.h" +#include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Target/Target.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::formatters; + +namespace lldb_private { + namespace formatters { + class LibcxxStdListSyntheticFrontEnd : public SyntheticChildrenFrontEnd + { + public: + LibcxxStdListSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp); + + virtual size_t + CalculateNumChildren (); + + virtual lldb::ValueObjectSP + GetChildAtIndex (size_t idx); + + virtual bool + Update(); + + virtual bool + MightHaveChildren (); + + virtual size_t + GetIndexOfChildWithName (const ConstString &name); + + virtual + ~LibcxxStdListSyntheticFrontEnd (); + private: + bool + HasLoop(size_t); + + size_t m_list_capping_size; + static const bool g_use_loop_detect = true; + size_t m_loop_detected; + lldb::addr_t m_node_address; + ValueObject* m_head; + ValueObject* m_tail; + CompilerType m_element_type; + size_t m_count; + std::map<size_t,lldb::ValueObjectSP> m_children; + }; + } +} + +class ListEntry +{ +public: + ListEntry () {} + ListEntry (ValueObjectSP entry_sp) : m_entry_sp(entry_sp) {} + ListEntry (const ListEntry& rhs) : m_entry_sp(rhs.m_entry_sp) {} + ListEntry (ValueObject* entry) : m_entry_sp(entry ? entry->GetSP() : ValueObjectSP()) {} + + ListEntry + next () + { + if (!m_entry_sp) + return ListEntry(); + return ListEntry(m_entry_sp->GetChildMemberWithName(ConstString("__next_"), true)); + } + + ListEntry + prev () + { + if (!m_entry_sp) + return ListEntry(); + return ListEntry(m_entry_sp->GetChildMemberWithName(ConstString("__prev_"), true)); + } + + uint64_t + value () + { + if (!m_entry_sp) + return 0; + return m_entry_sp->GetValueAsUnsigned(0); + } + + bool + null() + { + return (value() == 0); + } + + explicit operator bool () + { + return GetEntry().get() != nullptr && null() == false; + } + + ValueObjectSP + GetEntry () + { + return m_entry_sp; + } + + void + SetEntry (ValueObjectSP entry) + { + m_entry_sp = entry; + } + + bool + operator == (const ListEntry& rhs) const + { + return (rhs.m_entry_sp.get() == m_entry_sp.get()); + } + +private: + ValueObjectSP m_entry_sp; +}; + +class ListIterator +{ +public: + ListIterator () {} + ListIterator (ListEntry entry) : m_entry(entry) {} + ListIterator (ValueObjectSP entry) : m_entry(entry) {} + ListIterator (const ListIterator& rhs) : m_entry(rhs.m_entry) {} + ListIterator (ValueObject* entry) : m_entry(entry) {} + + ValueObjectSP + value () + { + return m_entry.GetEntry(); + } + + ValueObjectSP + advance (size_t count) + { + if (count == 0) + return m_entry.GetEntry(); + if (count == 1) + { + next (); + return m_entry.GetEntry(); + } + while (count > 0) + { + next (); + count--; + if (m_entry.null()) + return lldb::ValueObjectSP(); + } + return m_entry.GetEntry(); + } + + bool + operator == (const ListIterator& rhs) const + { + return (rhs.m_entry == m_entry); + } + +protected: + void + next () + { + m_entry = m_entry.next(); + } + + void + prev () + { + m_entry = m_entry.prev(); + } +private: + ListEntry m_entry; +}; + +lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::LibcxxStdListSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) : +SyntheticChildrenFrontEnd(*valobj_sp.get()), +m_list_capping_size(0), +m_loop_detected(0), +m_node_address(), +m_head(NULL), +m_tail(NULL), +m_element_type(), +m_count(UINT32_MAX), +m_children() +{ + if (valobj_sp) + Update(); +} + +bool +lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::HasLoop(size_t count) +{ + if (g_use_loop_detect == false) + return false; + // don't bother checking for a loop if we won't actually need to jump nodes + if (m_count < 2) + return false; + auto steps_left = std::min(count,m_count); + auto steps_left_save = steps_left; + ListEntry slow(m_head); + ListEntry fast(m_head); + while (steps_left-- > 0) + { + slow = slow.next(); + fast = fast.next(); + if (fast.next()) + fast = fast.next().next(); + else + fast = nullptr; + if (!slow || !fast) + return false; + if (slow == fast) + return true; + } + m_loop_detected = steps_left_save; + return false; +} + +size_t +lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::CalculateNumChildren () +{ + if (m_count != UINT32_MAX) + return m_count; + if (!m_head || !m_tail || m_node_address == 0) + return 0; + ValueObjectSP size_alloc(m_backend.GetChildMemberWithName(ConstString("__size_alloc_"), true)); + if (size_alloc) + { + ValueObjectSP first(size_alloc->GetChildMemberWithName(ConstString("__first_"), true)); + if (first) + { + m_count = first->GetValueAsUnsigned(UINT32_MAX); + } + } + if (m_count != UINT32_MAX) + { + return m_count; + } + else + { + uint64_t next_val = m_head->GetValueAsUnsigned(0); + uint64_t prev_val = m_tail->GetValueAsUnsigned(0); + if (next_val == 0 || prev_val == 0) + return 0; + if (next_val == m_node_address) + return 0; + if (next_val == prev_val) + return 1; + uint64_t size = 2; + ListEntry current(m_head); + while (current.next() && current.next().value() != m_node_address) + { + size++; + current = current.next(); + if (size > m_list_capping_size) + break; + } + return m_count = (size-1); + } +} + +lldb::ValueObjectSP +lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::GetChildAtIndex (size_t idx) +{ + if (idx >= CalculateNumChildren()) + return lldb::ValueObjectSP(); + + if (!m_head || !m_tail || m_node_address == 0) + return lldb::ValueObjectSP(); + + auto cached = m_children.find(idx); + if (cached != m_children.end()) + return cached->second; + + if (m_loop_detected <= idx) + if (HasLoop(idx)) + return lldb::ValueObjectSP(); + + ListIterator current(m_head); + ValueObjectSP current_sp(current.advance(idx)); + if (!current_sp) + return lldb::ValueObjectSP(); + current_sp = current_sp->GetChildMemberWithName(ConstString("__value_"), true); + if (!current_sp) + return lldb::ValueObjectSP(); + // we need to copy current_sp into a new object otherwise we will end up with all items named __value_ + DataExtractor data; + Error error; + current_sp->GetData(data, error); + if (error.Fail()) + return lldb::ValueObjectSP(); + + StreamString name; + name.Printf("[%" PRIu64 "]", (uint64_t)idx); + return (m_children[idx] = CreateValueObjectFromData(name.GetData(), data, m_backend.GetExecutionContextRef(), m_element_type)); +} + +bool +lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::Update() +{ + m_children.clear(); + m_head = m_tail = NULL; + m_node_address = 0; + m_count = UINT32_MAX; + m_loop_detected = false; + Error err; + ValueObjectSP backend_addr(m_backend.AddressOf(err)); + m_list_capping_size = 0; + if (m_backend.GetTargetSP()) + m_list_capping_size = m_backend.GetTargetSP()->GetMaximumNumberOfChildrenToDisplay(); + if (m_list_capping_size == 0) + m_list_capping_size = 255; + if (err.Fail() || backend_addr.get() == NULL) + return false; + m_node_address = backend_addr->GetValueAsUnsigned(0); + if (!m_node_address || m_node_address == LLDB_INVALID_ADDRESS) + return false; + ValueObjectSP impl_sp(m_backend.GetChildMemberWithName(ConstString("__end_"),true)); + if (!impl_sp) + return false; + CompilerType list_type = m_backend.GetCompilerType(); + if (list_type.IsReferenceType()) + list_type = list_type.GetNonReferenceType(); + + if (list_type.GetNumTemplateArguments() == 0) + return false; + lldb::TemplateArgumentKind kind; + m_element_type = list_type.GetTemplateArgument(0, kind); + m_head = impl_sp->GetChildMemberWithName(ConstString("__next_"), true).get(); + m_tail = impl_sp->GetChildMemberWithName(ConstString("__prev_"), true).get(); + return false; +} + +bool +lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::MightHaveChildren () +{ + return true; +} + +size_t +lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name) +{ + return ExtractIndexFromString(name.GetCString()); +} + +lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::~LibcxxStdListSyntheticFrontEnd () +{} + +SyntheticChildrenFrontEnd* +lldb_private::formatters::LibcxxStdListSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp) +{ + if (!valobj_sp) + return NULL; + return (new LibcxxStdListSyntheticFrontEnd(valobj_sp)); +} + |