Add support for displaying Java array types on Andorid

Differential revision: http://reviews.llvm.org/D19540

llvm-svn: 268622
This commit is contained in:
Tamas Berghammer 2016-05-05 11:18:21 +00:00
parent d00698f4c1
commit 2ff833060c
7 changed files with 260 additions and 72 deletions

View File

@ -335,8 +335,8 @@ public:
CreateObjectType(const ConstString &name, const ConstString &linkage_name, uint32_t byte_size);
CompilerType
CreateArrayType(const CompilerType &element_type, const DWARFExpression &length_expression,
const lldb::addr_t data_offset);
CreateArrayType(const ConstString &linkage_name, const CompilerType &element_type,
const DWARFExpression &length_expression, const lldb::addr_t data_offset);
CompilerType
CreateReferenceType(const CompilerType &pointee_type);
@ -360,6 +360,12 @@ public:
static ConstString
GetLinkageName(const CompilerType &type);
static uint32_t
CalculateArraySize(const CompilerType &type, ValueObject &in_value);
static uint64_t
CalculateArrayElementOffset(const CompilerType &type, size_t index);
//------------------------------------------------------------------
// llvm casting support
//------------------------------------------------------------------

View File

@ -14,11 +14,100 @@
#include "JavaFormatterFunctions.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
#include "lldb/DataFormatters/StringPrinter.h"
#include "lldb/Symbol/JavaASTContext.h"
using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::formatters;
namespace
{
class JavaArraySyntheticFrontEnd : public SyntheticChildrenFrontEnd
{
public:
JavaArraySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) :
SyntheticChildrenFrontEnd(*valobj_sp)
{
if (valobj_sp)
Update();
}
size_t
CalculateNumChildren() override
{
ValueObjectSP valobj = GetDereferencedValueObject();
if (!valobj)
return 0;
CompilerType type = valobj->GetCompilerType();
uint32_t size = JavaASTContext::CalculateArraySize(type, *valobj);
if (size == UINT32_MAX)
return 0;
return size;
}
lldb::ValueObjectSP
GetChildAtIndex(size_t idx) override
{
ValueObjectSP valobj = GetDereferencedValueObject();
if (!valobj)
return nullptr;
ProcessSP process_sp = valobj->GetProcessSP();
if (!process_sp)
return nullptr;
CompilerType type = valobj->GetCompilerType();
CompilerType element_type = type.GetArrayElementType();
lldb::addr_t address = valobj->GetAddressOf() + JavaASTContext::CalculateArrayElementOffset(type, idx);
Error error;
size_t byte_size = element_type.GetByteSize(nullptr);
DataBufferSP buffer_sp(new DataBufferHeap(byte_size, 0));
size_t bytes_read = process_sp->ReadMemory(address, buffer_sp->GetBytes(), byte_size, error);
if (error.Fail() || byte_size != bytes_read)
return nullptr;
StreamString name;
name.Printf("[%" PRIu64 "]", (uint64_t)idx);
DataExtractor data(buffer_sp, process_sp->GetByteOrder(), process_sp->GetAddressByteSize());
return CreateValueObjectFromData(name.GetData(), data, valobj->GetExecutionContextRef(),
element_type);
}
bool
Update() override
{
return false;
}
bool
MightHaveChildren() override
{
return true;
}
size_t
GetIndexOfChildWithName(const ConstString &name) override
{
return ExtractIndexFromString(name.GetCString());
}
private:
ValueObjectSP
GetDereferencedValueObject()
{
if (!m_backend.IsPointerOrReferenceType())
m_backend.GetSP();
Error error;
return m_backend.Dereference(error);
}
};
} // end of anonymous namespace
bool
lldb_private::formatters::JavaStringSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &opts)
{
@ -69,3 +158,29 @@ lldb_private::formatters::JavaStringSummaryProvider(ValueObject &valobj, Stream
stream.Printf("Summary Unavailable");
return true;
}
bool
lldb_private::formatters::JavaArraySummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
{
if (valobj.IsPointerOrReferenceType())
{
Error error;
ValueObjectSP deref = valobj.Dereference(error);
if (error.Fail())
return false;
return JavaArraySummaryProvider(*deref, stream, options);
}
CompilerType type = valobj.GetCompilerType();
uint32_t size = JavaASTContext::CalculateArraySize(type, valobj);
if (size == UINT32_MAX)
return false;
stream.Printf("[%u]{...}", size);
return true;
}
SyntheticChildrenFrontEnd*
lldb_private::formatters::JavaArraySyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
{
return valobj_sp ? new JavaArraySyntheticFrontEnd(valobj_sp) : nullptr;
}

View File

@ -24,6 +24,12 @@ namespace formatters
bool
JavaStringSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options);
bool
JavaArraySummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options);
SyntheticChildrenFrontEnd*
JavaArraySyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp);
} // namespace formatters
} // namespace lldb_private

View File

@ -88,11 +88,22 @@ JavaLanguage::GetFormatters()
DataVisualization::Categories::GetCategory(GetPluginName(), g_category);
if (g_category)
{
const char* array_regexp = "^.*\\[\\]&?$";
lldb::TypeSummaryImplSP string_summary_sp(new CXXFunctionSummaryFormat(
TypeSummaryImpl::Flags().SetDontShowChildren(true), lldb_private::formatters::JavaStringSummaryProvider,
"java.lang.String summary provider"));
g_category->GetTypeSummariesContainer()->Add(ConstString("java::lang::String"), string_summary_sp);
lldb::TypeSummaryImplSP array_summary_sp(new CXXFunctionSummaryFormat(
TypeSummaryImpl::Flags().SetDontShowChildren(true), lldb_private::formatters::JavaArraySummaryProvider,
"Java array summary provider"));
g_category->GetRegexTypeSummariesContainer()->Add(RegularExpressionSP(new RegularExpression(array_regexp)),
array_summary_sp);
AddCXXSynthetic(g_category, lldb_private::formatters::JavaArraySyntheticFrontEndCreator,
"Java array synthetic children", ConstString(array_regexp),
SyntheticChildren::Flags().SetCascades(true), true);
}
});
return g_category;

View File

@ -147,7 +147,7 @@ DWARFASTParserJava::ParseArrayTypeFromDIE(const DWARFDIE &die)
CompilerType element_compiler_type = element_type->GetForwardCompilerType();
CompilerType array_compiler_type =
m_ast.CreateArrayType(element_compiler_type, length_expression, data_offset);
m_ast.CreateArrayType(linkage_name, element_compiler_type, length_expression, data_offset);
Declaration decl;
TypeSP type_sp(new Type(die.GetID(), dwarf, array_compiler_type.GetTypeName(), -1, nullptr,

View File

@ -755,20 +755,21 @@ DWARFCompileUnit::IndexPrivate (DWARFCompileUnit* dwarf_cu,
switch (tag)
{
case DW_TAG_subprogram:
case DW_TAG_inlined_subroutine:
case DW_TAG_array_type:
case DW_TAG_base_type:
case DW_TAG_class_type:
case DW_TAG_constant:
case DW_TAG_enumeration_type:
case DW_TAG_string_type:
case DW_TAG_subroutine_type:
case DW_TAG_structure_type:
case DW_TAG_union_type:
case DW_TAG_typedef:
case DW_TAG_inlined_subroutine:
case DW_TAG_namespace:
case DW_TAG_variable:
case DW_TAG_string_type:
case DW_TAG_structure_type:
case DW_TAG_subprogram:
case DW_TAG_subroutine_type:
case DW_TAG_typedef:
case DW_TAG_union_type:
case DW_TAG_unspecified_type:
case DW_TAG_variable:
break;
default:
@ -980,15 +981,16 @@ DWARFCompileUnit::IndexPrivate (DWARFCompileUnit* dwarf_cu,
}
break;
case DW_TAG_array_type:
case DW_TAG_base_type:
case DW_TAG_class_type:
case DW_TAG_constant:
case DW_TAG_enumeration_type:
case DW_TAG_string_type:
case DW_TAG_subroutine_type:
case DW_TAG_structure_type:
case DW_TAG_union_type:
case DW_TAG_subroutine_type:
case DW_TAG_typedef:
case DW_TAG_union_type:
case DW_TAG_unspecified_type:
if (name && !is_declaration)
types.Insert (ConstString(name), DIERef(cu_offset, die.GetOffset()));

View File

@ -141,7 +141,60 @@ private:
const TypeKind m_type_kind;
};
class JavaObjectType : public JavaASTContext::JavaType
class JavaDynamicType : public JavaASTContext::JavaType
{
public:
JavaDynamicType(LLVMCastKind kind, const ConstString &linkage_name) :
JavaType(kind),
m_linkage_name(linkage_name),
m_dynamic_type_id(nullptr)
{
}
ConstString
GetLinkageName() const
{
return m_linkage_name;
}
void
SetDynamicTypeId(const DWARFExpression &type_id)
{
m_dynamic_type_id = type_id;
}
uint64_t
CalculateDynamicTypeId(ExecutionContext *exe_ctx, ValueObject &value_obj)
{
if (!m_dynamic_type_id.IsValid())
return UINT64_MAX;
Value obj_load_address = value_obj.GetValue();
obj_load_address.ResolveValue(exe_ctx);
obj_load_address.SetValueType(Value::eValueTypeLoadAddress);
Value result;
if (m_dynamic_type_id.Evaluate(exe_ctx->GetBestExecutionContextScope(), nullptr, nullptr, 0, &obj_load_address,
nullptr, result, nullptr))
{
Error error;
lldb::addr_t type_id_addr = result.GetScalar().UInt();
lldb::ProcessSP process_sp = exe_ctx->GetProcessSP();
if (process_sp)
return process_sp->ReadUnsignedIntegerFromMemory(type_id_addr, process_sp->GetAddressByteSize(),
UINT64_MAX, error);
}
return UINT64_MAX;
}
public:
ConstString m_linkage_name;
DWARFExpression m_dynamic_type_id;
};
class JavaObjectType : public JavaDynamicType
{
public:
struct Field
@ -152,13 +205,11 @@ public:
};
JavaObjectType(const ConstString &name, const ConstString &linkage_name, uint32_t byte_size)
: JavaType(JavaType::eKindObject),
: JavaDynamicType(JavaType::eKindObject, linkage_name),
m_name(name),
m_linkage_name(linkage_name),
m_byte_size(byte_size),
m_base_class_offset(0),
m_is_complete(false),
m_dynamic_type_id(nullptr)
m_is_complete(false)
{
}
@ -168,12 +219,6 @@ public:
return m_name;
}
ConstString
GetLinkageName() const
{
return m_linkage_name;
}
uint32_t
GetByteSize() const
{
@ -270,38 +315,6 @@ public:
m_fields.push_back({name, type, offset});
}
void
SetDynamicTypeId(const DWARFExpression &type_id)
{
m_dynamic_type_id = type_id;
}
uint64_t
CalculateDynamicTypeId(ExecutionContext *exe_ctx, ValueObject &value_obj)
{
if (!m_dynamic_type_id.IsValid())
return UINT64_MAX;
Value obj_load_address = value_obj.GetValue();
obj_load_address.ResolveValue(exe_ctx);
obj_load_address.SetValueType(Value::eValueTypeLoadAddress);
Value result;
if (m_dynamic_type_id.Evaluate(exe_ctx->GetBestExecutionContextScope(), nullptr, nullptr, 0, &obj_load_address,
nullptr, result, nullptr))
{
Error error;
lldb::addr_t type_id_addr = result.GetScalar().UInt();
lldb::ProcessSP process_sp = exe_ctx->GetProcessSP();
if (process_sp)
return process_sp->ReadUnsignedIntegerFromMemory(type_id_addr, process_sp->GetAddressByteSize(),
UINT64_MAX, error);
}
return UINT64_MAX;
}
static bool
classof(const JavaType *jt)
{
@ -310,14 +323,12 @@ public:
private:
ConstString m_name;
ConstString m_linkage_name;
uint32_t m_byte_size;
CompilerType m_base_class;
uint32_t m_base_class_offset;
std::vector<CompilerType> m_interfaces;
std::vector<Field> m_fields;
bool m_is_complete;
DWARFExpression m_dynamic_type_id;
};
class JavaReferenceType : public JavaASTContext::JavaType
@ -360,13 +371,15 @@ private:
CompilerType m_pointee_type;
};
class JavaArrayType : public JavaASTContext::JavaType
class JavaArrayType : public JavaDynamicType
{
public:
JavaArrayType(CompilerType element_type, const DWARFExpression &length_expression, const lldb::addr_t data_offset)
: JavaType(JavaType::eKindArray),
JavaArrayType(const ConstString& linkage_name, CompilerType element_type, const DWARFExpression &length_expression,
lldb::addr_t data_offset)
: JavaDynamicType(JavaType::eKindArray, linkage_name),
m_element_type(element_type),
m_length_expression(length_expression)
m_length_expression(length_expression),
m_data_offset(data_offset)
{
}
@ -402,25 +415,37 @@ public:
}
uint32_t
GetNumElements(const ValueObject *value_obj)
GetNumElements(ValueObject *value_obj)
{
if (!m_length_expression.IsValid())
return false;
return UINT32_MAX;
Value obj_load_address = value_obj->GetValue();
Error error;
ValueObjectSP address_obj = value_obj->AddressOf(error);
if (error.Fail())
return UINT32_MAX;
Value obj_load_address = address_obj->GetValue();
obj_load_address.SetValueType(Value::eValueTypeLoadAddress);
Value result;
if (m_length_expression.Evaluate(nullptr, nullptr, nullptr, nullptr, 0, nullptr, &obj_load_address, result,
nullptr))
ExecutionContextScope* exec_ctx_scope = value_obj->GetExecutionContextRef().Lock(true).GetBestExecutionContextScope();
if (m_length_expression.Evaluate(exec_ctx_scope, nullptr, nullptr, 0, nullptr, &obj_load_address, result, nullptr))
return result.GetScalar().UInt();
return 0;
return UINT32_MAX;
}
uint64_t
GetElementOffset(size_t idx)
{
return m_data_offset + idx * m_element_type.GetByteSize(nullptr);
}
private:
CompilerType m_element_type;
DWARFExpression m_length_expression;
lldb::addr_t m_data_offset;
};
} // end of anonymous namespace
@ -998,6 +1023,10 @@ JavaASTContext::GetBitSize(lldb::opaque_compiler_type_t type, ExecutionContextSc
{
return 32; // References are always 4 byte long in java
}
else if (llvm::isa<JavaArrayType>(static_cast<JavaType *>(type)))
{
return 64;
}
else if (JavaObjectType *obj = llvm::dyn_cast<JavaObjectType>(static_cast<JavaType *>(type)))
{
return obj->GetByteSize() * 8;
@ -1450,14 +1479,15 @@ JavaASTContext::CreateObjectType(const ConstString &name, const ConstString &lin
}
CompilerType
JavaASTContext::CreateArrayType(const CompilerType &element_type, const DWARFExpression &length_expression,
const lldb::addr_t data_offset)
JavaASTContext::CreateArrayType(const ConstString &linkage_name, const CompilerType &element_type,
const DWARFExpression &length_expression, const lldb::addr_t data_offset)
{
ConstString name = element_type.GetTypeName();
auto it = m_array_type_map.find(name);
if (it == m_array_type_map.end())
{
std::unique_ptr<JavaType> array_type(new JavaArrayType(element_type, length_expression, data_offset));
std::unique_ptr<JavaType> array_type(new JavaArrayType(linkage_name, element_type, length_expression,
data_offset));
it = m_array_type_map.emplace(name, std::move(array_type)).first;
}
return CompilerType(this, it->second.get());
@ -1512,6 +1542,24 @@ JavaASTContext::CalculateDynamicTypeId(ExecutionContext *exe_ctx, const Compiler
{
if (JavaObjectType *obj = llvm::dyn_cast<JavaObjectType>(static_cast<JavaType *>(type.GetOpaqueQualType())))
return obj->CalculateDynamicTypeId(exe_ctx, in_value);
if (JavaArrayType *arr = llvm::dyn_cast<JavaArrayType>(static_cast<JavaType *>(type.GetOpaqueQualType())))
return arr->CalculateDynamicTypeId(exe_ctx, in_value);
return UINT64_MAX;
}
uint32_t
JavaASTContext::CalculateArraySize(const CompilerType &type, ValueObject &in_value)
{
if (JavaArrayType *arr = llvm::dyn_cast<JavaArrayType>(static_cast<JavaType *>(type.GetOpaqueQualType())))
return arr->GetNumElements(&in_value);
return UINT32_MAX;
}
uint64_t
JavaASTContext::CalculateArrayElementOffset(const CompilerType &type, size_t index)
{
if (JavaArrayType *arr = llvm::dyn_cast<JavaArrayType>(static_cast<JavaType *>(type.GetOpaqueQualType())))
return arr->GetElementOffset(index);
return UINT64_MAX;
}