mirror of
https://github.com/intel/llvm.git
synced 2026-01-17 23:45:25 +08:00
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
410 lines
11 KiB
C++
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));
|
|
}
|