diff options
Diffstat (limited to 'source/DataFormatters/LibCxxMap.cpp')
-rw-r--r-- | source/DataFormatters/LibCxxMap.cpp | 409 |
1 files changed, 409 insertions, 0 deletions
diff --git a/source/DataFormatters/LibCxxMap.cpp b/source/DataFormatters/LibCxxMap.cpp new file mode 100644 index 000000000000..5daa40f15f3d --- /dev/null +++ b/source/DataFormatters/LibCxxMap.cpp @@ -0,0 +1,409 @@ +//===-- 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 "lldb/lldb-python.h" + +#include "lldb/DataFormatters/CXXFormatterFunctions.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/Host/Endian.h" +#include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Target/ObjCLanguageRuntime.h" +#include "lldb/Target/Target.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::formatters; + +class MapEntry +{ +public: + MapEntry () {} + MapEntry (ValueObjectSP entry_sp) : m_entry_sp(entry_sp) {} + MapEntry (const MapEntry& rhs) : m_entry_sp(rhs.m_entry_sp) {} + MapEntry (ValueObject* entry) : m_entry_sp(entry ? entry->GetSP() : ValueObjectSP()) {} + + ValueObjectSP + left () + { + if (!m_entry_sp) + return m_entry_sp; + return m_entry_sp->GetChildMemberWithName(ConstString("__left_"), true); + } + + ValueObjectSP + right () + { + if (!m_entry_sp) + return m_entry_sp; + return m_entry_sp->GetChildMemberWithName(ConstString("__right_"), true); + } + + ValueObjectSP + parent () + { + if (!m_entry_sp) + return m_entry_sp; + return m_entry_sp->GetChildMemberWithName(ConstString("__parent_"), true); + } + + uint64_t + value () + { + if (!m_entry_sp) + return 0; + return m_entry_sp->GetValueAsUnsigned(0); + } + + bool + error () + { + if (!m_entry_sp) + return true; + return m_entry_sp->GetError().Fail(); + } + + bool + null() + { + return (value() == 0); + } + + ValueObjectSP + GetEntry () + { + return m_entry_sp; + } + + void + SetEntry (ValueObjectSP entry) + { + m_entry_sp = entry; + } + + bool + operator == (const MapEntry& rhs) const + { + return (rhs.m_entry_sp.get() == m_entry_sp.get()); + } + +private: + ValueObjectSP m_entry_sp; +}; + +class MapIterator +{ +public: + MapIterator () {} + MapIterator (MapEntry entry, size_t depth = 0) : m_entry(entry), m_max_depth(depth), m_error(false) {} + MapIterator (ValueObjectSP entry, size_t depth = 0) : m_entry(entry), m_max_depth(depth), m_error(false) {} + MapIterator (const MapIterator& rhs) : m_entry(rhs.m_entry),m_max_depth(rhs.m_max_depth), m_error(false) {} + MapIterator (ValueObject* entry, size_t depth = 0) : m_entry(entry), m_max_depth(depth), m_error(false) {} + + ValueObjectSP + value () + { + return m_entry.GetEntry(); + } + + ValueObjectSP + advance (size_t count) + { + if (m_error) + return lldb::ValueObjectSP(); + if (count == 0) + return m_entry.GetEntry(); + if (count == 1) + { + next (); + return m_entry.GetEntry(); + } + size_t steps = 0; + while (count > 0) + { + if (m_error) + return lldb::ValueObjectSP(); + next (); + count--; + if (m_entry.null()) + return lldb::ValueObjectSP(); + steps++; + if (steps > m_max_depth) + return lldb::ValueObjectSP(); + } + return m_entry.GetEntry(); + } +protected: + void + next () + { + m_entry.SetEntry(increment(m_entry.GetEntry())); + } + +private: + ValueObjectSP + tree_min (ValueObjectSP x_sp) + { + MapEntry x(x_sp); + if (x.null()) + return ValueObjectSP(); + MapEntry left(x.left()); + size_t steps = 0; + while (left.null() == false) + { + if (left.error()) + { + m_error = true; + return lldb::ValueObjectSP(); + } + x.SetEntry(left.GetEntry()); + left.SetEntry(x.left()); + steps++; + if (steps > m_max_depth) + return lldb::ValueObjectSP(); + } + return x.GetEntry(); + } + + ValueObjectSP + tree_max (ValueObjectSP x_sp) + { + MapEntry x(x_sp); + if (x.null()) + return ValueObjectSP(); + MapEntry right(x.right()); + size_t steps = 0; + while (right.null() == false) + { + if (right.error()) + return lldb::ValueObjectSP(); + x.SetEntry(right.GetEntry()); + right.SetEntry(x.right()); + steps++; + if (steps > m_max_depth) + return lldb::ValueObjectSP(); + } + return x.GetEntry(); + } + + bool + is_left_child (ValueObjectSP x_sp) + { + MapEntry x(x_sp); + if (x.null()) + return false; + MapEntry rhs(x.parent()); + rhs.SetEntry(rhs.left()); + return x.value() == rhs.value(); + } + + ValueObjectSP + increment (ValueObjectSP x_sp) + { + MapEntry node(x_sp); + if (node.null()) + return ValueObjectSP(); + MapEntry right(node.right()); + if (right.null() == false) + return tree_min(right.GetEntry()); + size_t steps = 0; + while (!is_left_child(node.GetEntry())) + { + if (node.error()) + { + m_error = true; + return lldb::ValueObjectSP(); + } + node.SetEntry(node.parent()); + steps++; + if (steps > m_max_depth) + return lldb::ValueObjectSP(); + } + return node.parent(); + } + + MapEntry m_entry; + size_t m_max_depth; + bool m_error; +}; + +lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::LibcxxStdMapSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) : +SyntheticChildrenFrontEnd(*valobj_sp.get()), +m_tree(NULL), +m_root_node(NULL), +m_element_type(), +m_skip_size(UINT32_MAX), +m_count(UINT32_MAX), +m_children() +{ + if (valobj_sp) + Update(); +} + +size_t +lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::CalculateNumChildren () +{ + if (m_count != UINT32_MAX) + return m_count; + if (m_tree == NULL) + return 0; + ValueObjectSP m_item(m_tree->GetChildMemberWithName(ConstString("__pair3_"), true)); + if (!m_item) + return 0; + m_item = m_item->GetChildMemberWithName(ConstString("__first_"), true); + if (!m_item) + return 0; + m_count = m_item->GetValueAsUnsigned(0); + return m_count; +} + +bool +lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetDataType() +{ + if (m_element_type.GetOpaqueQualType() && m_element_type.GetASTContext()) + return true; + m_element_type.Clear(); + ValueObjectSP deref; + Error error; + deref = m_root_node->Dereference(error); + if (!deref || error.Fail()) + return false; + deref = deref->GetChildMemberWithName(ConstString("__value_"), true); + if (!deref) + return false; + m_element_type = deref->GetClangType(); + return true; +} + +void +lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetValueOffset (const lldb::ValueObjectSP& node) +{ + if (m_skip_size != UINT32_MAX) + return; + if (!node) + return; + ClangASTType node_type(node->GetClangType()); + uint64_t bit_offset; + if (node_type.GetIndexOfFieldWithName("__value_", NULL, &bit_offset) == UINT32_MAX) + return; + m_skip_size = bit_offset / 8u; +} + +lldb::ValueObjectSP +lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetChildAtIndex (size_t idx) +{ + if (idx >= CalculateNumChildren()) + return lldb::ValueObjectSP(); + if (m_tree == NULL || m_root_node == NULL) + return lldb::ValueObjectSP(); + + auto cached = m_children.find(idx); + if (cached != m_children.end()) + return cached->second; + + bool need_to_skip = (idx > 0); + MapIterator iterator(m_root_node, CalculateNumChildren()); + ValueObjectSP iterated_sp(iterator.advance(idx)); + if (iterated_sp.get() == NULL) + { + // this tree is garbage - stop + m_tree = NULL; // this will stop all future searches until an Update() happens + return iterated_sp; + } + if (GetDataType()) + { + if (!need_to_skip) + { + Error error; + iterated_sp = iterated_sp->Dereference(error); + if (!iterated_sp || error.Fail()) + { + m_tree = NULL; + return lldb::ValueObjectSP(); + } + GetValueOffset(iterated_sp); + iterated_sp = iterated_sp->GetChildMemberWithName(ConstString("__value_"), true); + if (!iterated_sp) + { + m_tree = NULL; + return lldb::ValueObjectSP(); + } + } + else + { + // because of the way our debug info is made, we need to read item 0 first + // so that we can cache information used to generate other elements + if (m_skip_size == UINT32_MAX) + GetChildAtIndex(0); + if (m_skip_size == UINT32_MAX) + { + m_tree = NULL; + return lldb::ValueObjectSP(); + } + iterated_sp = iterated_sp->GetSyntheticChildAtOffset(m_skip_size, m_element_type, true); + if (!iterated_sp) + { + m_tree = NULL; + return lldb::ValueObjectSP(); + } + } + } + else + { + m_tree = NULL; + return lldb::ValueObjectSP(); + } + // at this point we have a valid + // we need to copy current_sp into a new object otherwise we will end up with all items named __value_ + DataExtractor data; + iterated_sp->GetData(data); + StreamString name; + name.Printf("[%zu]",idx); + return (m_children[idx] = ValueObject::CreateValueObjectFromData(name.GetData(), data, m_backend.GetExecutionContextRef(), m_element_type)); +} + +bool +lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::Update() +{ + m_count = UINT32_MAX; + m_tree = m_root_node = NULL; + m_children.clear(); + m_tree = m_backend.GetChildMemberWithName(ConstString("__tree_"), true).get(); + if (!m_tree) + return false; + m_root_node = m_tree->GetChildMemberWithName(ConstString("__begin_node_"), true).get(); + return false; +} + +bool +lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::MightHaveChildren () +{ + return true; +} + +size_t +lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name) +{ + return ExtractIndexFromString(name.GetCString()); +} + +lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::~LibcxxStdMapSyntheticFrontEnd () +{} + +SyntheticChildrenFrontEnd* +lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp) +{ + if (!valobj_sp) + return NULL; + return (new LibcxxStdMapSyntheticFrontEnd(valobj_sp)); +} |