Files
llvm/lldb/source/DataFormatters/LibCxxMap.cpp
Greg Clayton 57ee306789 Huge change to clean up types.
A long time ago we start with clang types that were created by the symbol files and there were many functions in lldb_private::ClangASTContext that helped. Later we create ClangASTType which contains a clang::ASTContext and an opauque QualType, but we didn't switch over to fully using it. There were a lot of places where we would pass around a raw clang_type_t and also pass along a clang::ASTContext separately. This left room for error.

This checkin change all type code over to use ClangASTType everywhere and I cleaned up the interfaces quite a bit. Any code that was in ClangASTContext that was type related, was moved over into ClangASTType. All code that used these types was switched over to use all of the new goodness.

llvm-svn: 186130
2013-07-11 22:46:58 +00:00

410 lines
11 KiB
C++

//===-- 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));
}