510 lines
17 KiB
C++
510 lines
17 KiB
C++
//===-- DWARFASTParserJava.cpp ----------------------------------*- C++ -*-===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "DWARFASTParserJava.h"
|
|
#include "DWARFAttribute.h"
|
|
#include "DWARFCompileUnit.h"
|
|
#include "DWARFDebugInfoEntry.h"
|
|
#include "DWARFDebugInfoEntry.h"
|
|
#include "DWARFDeclContext.h"
|
|
#include "SymbolFileDWARF.h"
|
|
|
|
#include "lldb/Core/Module.h"
|
|
#include "lldb/Symbol/CompileUnit.h"
|
|
#include "lldb/Symbol/SymbolContextScope.h"
|
|
#include "lldb/Symbol/TypeList.h"
|
|
|
|
using namespace lldb;
|
|
using namespace lldb_private;
|
|
|
|
DWARFASTParserJava::DWARFASTParserJava(JavaASTContext &ast) : m_ast(ast) {}
|
|
|
|
DWARFASTParserJava::~DWARFASTParserJava() {}
|
|
|
|
TypeSP DWARFASTParserJava::ParseBaseTypeFromDIE(const DWARFDIE &die) {
|
|
SymbolFileDWARF *dwarf = die.GetDWARF();
|
|
dwarf->m_die_to_type[die.GetDIE()] = DIE_IS_BEING_PARSED;
|
|
|
|
ConstString type_name;
|
|
uint64_t byte_size = 0;
|
|
|
|
DWARFAttributes attributes;
|
|
const size_t num_attributes = die.GetAttributes(attributes);
|
|
for (uint32_t i = 0; i < num_attributes; ++i) {
|
|
DWARFFormValue form_value;
|
|
dw_attr_t attr = attributes.AttributeAtIndex(i);
|
|
if (attributes.ExtractFormValueAtIndex(i, form_value)) {
|
|
switch (attr) {
|
|
case DW_AT_name:
|
|
type_name.SetCString(form_value.AsCString());
|
|
break;
|
|
case DW_AT_byte_size:
|
|
byte_size = form_value.Unsigned();
|
|
break;
|
|
case DW_AT_encoding:
|
|
break;
|
|
default:
|
|
assert(false && "Unsupported attribute for DW_TAG_base_type");
|
|
}
|
|
}
|
|
}
|
|
|
|
Declaration decl;
|
|
CompilerType compiler_type = m_ast.CreateBaseType(type_name);
|
|
return std::make_shared<Type>(die.GetID(), dwarf, type_name, byte_size,
|
|
nullptr, LLDB_INVALID_UID, Type::eEncodingIsUID,
|
|
decl, compiler_type, Type::eResolveStateFull);
|
|
}
|
|
|
|
TypeSP DWARFASTParserJava::ParseArrayTypeFromDIE(const DWARFDIE &die) {
|
|
SymbolFileDWARF *dwarf = die.GetDWARF();
|
|
dwarf->m_die_to_type[die.GetDIE()] = DIE_IS_BEING_PARSED;
|
|
|
|
ConstString linkage_name;
|
|
DWARFFormValue type_attr_value;
|
|
lldb::addr_t data_offset = LLDB_INVALID_ADDRESS;
|
|
DWARFExpression length_expression(die.GetCU());
|
|
|
|
DWARFAttributes attributes;
|
|
const size_t num_attributes = die.GetAttributes(attributes);
|
|
for (uint32_t i = 0; i < num_attributes; ++i) {
|
|
DWARFFormValue form_value;
|
|
dw_attr_t attr = attributes.AttributeAtIndex(i);
|
|
if (attributes.ExtractFormValueAtIndex(i, form_value)) {
|
|
switch (attr) {
|
|
case DW_AT_linkage_name:
|
|
linkage_name.SetCString(form_value.AsCString());
|
|
break;
|
|
case DW_AT_type:
|
|
type_attr_value = form_value;
|
|
break;
|
|
case DW_AT_data_member_location:
|
|
data_offset = form_value.Unsigned();
|
|
break;
|
|
case DW_AT_declaration:
|
|
break;
|
|
default:
|
|
assert(false && "Unsupported attribute for DW_TAG_array_type");
|
|
}
|
|
}
|
|
}
|
|
|
|
for (DWARFDIE child_die = die.GetFirstChild(); child_die.IsValid();
|
|
child_die = child_die.GetSibling()) {
|
|
if (child_die.Tag() == DW_TAG_subrange_type) {
|
|
DWARFAttributes attributes;
|
|
const size_t num_attributes = child_die.GetAttributes(attributes);
|
|
for (uint32_t i = 0; i < num_attributes; ++i) {
|
|
DWARFFormValue form_value;
|
|
dw_attr_t attr = attributes.AttributeAtIndex(i);
|
|
if (attributes.ExtractFormValueAtIndex(i, form_value)) {
|
|
switch (attr) {
|
|
case DW_AT_count:
|
|
if (form_value.BlockData())
|
|
length_expression.CopyOpcodeData(
|
|
form_value.BlockData(), form_value.Unsigned(),
|
|
child_die.GetCU()->GetByteOrder(),
|
|
child_die.GetCU()->GetAddressByteSize());
|
|
break;
|
|
default:
|
|
assert(false && "Unsupported attribute for DW_TAG_subrange_type");
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
assert(false && "Unsupported child for DW_TAG_array_type");
|
|
}
|
|
}
|
|
|
|
DIERef type_die_ref(type_attr_value);
|
|
Type *element_type = dwarf->ResolveTypeUID(type_die_ref);
|
|
if (!element_type)
|
|
return nullptr;
|
|
|
|
CompilerType element_compiler_type = element_type->GetForwardCompilerType();
|
|
CompilerType array_compiler_type = 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, type_die_ref.GetUID(dwarf),
|
|
Type::eEncodingIsUID, &decl, array_compiler_type,
|
|
Type::eResolveStateFull));
|
|
type_sp->SetEncodingType(element_type);
|
|
return type_sp;
|
|
}
|
|
|
|
TypeSP DWARFASTParserJava::ParseReferenceTypeFromDIE(const DWARFDIE &die) {
|
|
SymbolFileDWARF *dwarf = die.GetDWARF();
|
|
dwarf->m_die_to_type[die.GetDIE()] = DIE_IS_BEING_PARSED;
|
|
|
|
Declaration decl;
|
|
DWARFFormValue type_attr_value;
|
|
|
|
DWARFAttributes attributes;
|
|
const size_t num_attributes = die.GetAttributes(attributes);
|
|
for (uint32_t i = 0; i < num_attributes; ++i) {
|
|
DWARFFormValue form_value;
|
|
dw_attr_t attr = attributes.AttributeAtIndex(i);
|
|
if (attributes.ExtractFormValueAtIndex(i, form_value)) {
|
|
switch (attr) {
|
|
case DW_AT_type:
|
|
type_attr_value = form_value;
|
|
break;
|
|
default:
|
|
assert(false && "Unsupported attribute for DW_TAG_array_type");
|
|
}
|
|
}
|
|
}
|
|
|
|
DIERef type_die_ref(type_attr_value);
|
|
Type *pointee_type = dwarf->ResolveTypeUID(type_die_ref);
|
|
if (!pointee_type)
|
|
return nullptr;
|
|
|
|
CompilerType pointee_compiler_type = pointee_type->GetForwardCompilerType();
|
|
CompilerType reference_compiler_type =
|
|
m_ast.CreateReferenceType(pointee_compiler_type);
|
|
TypeSP type_sp(
|
|
new Type(die.GetID(), dwarf, reference_compiler_type.GetTypeName(), -1,
|
|
nullptr, type_die_ref.GetUID(dwarf), Type::eEncodingIsUID, &decl,
|
|
reference_compiler_type, Type::eResolveStateFull));
|
|
type_sp->SetEncodingType(pointee_type);
|
|
return type_sp;
|
|
}
|
|
|
|
lldb::TypeSP DWARFASTParserJava::ParseClassTypeFromDIE(const DWARFDIE &die,
|
|
bool &is_new_type) {
|
|
SymbolFileDWARF *dwarf = die.GetDWARF();
|
|
dwarf->m_die_to_type[die.GetDIE()] = DIE_IS_BEING_PARSED;
|
|
|
|
Declaration decl;
|
|
ConstString name;
|
|
ConstString linkage_name;
|
|
bool is_forward_declaration = false;
|
|
uint32_t byte_size = 0;
|
|
|
|
DWARFAttributes attributes;
|
|
const size_t num_attributes = die.GetAttributes(attributes);
|
|
for (uint32_t i = 0; i < num_attributes; ++i) {
|
|
DWARFFormValue form_value;
|
|
dw_attr_t attr = attributes.AttributeAtIndex(i);
|
|
if (attributes.ExtractFormValueAtIndex(i, form_value)) {
|
|
switch (attr) {
|
|
case DW_AT_name:
|
|
name.SetCString(form_value.AsCString());
|
|
break;
|
|
case DW_AT_declaration:
|
|
is_forward_declaration = form_value.Boolean();
|
|
break;
|
|
case DW_AT_byte_size:
|
|
byte_size = form_value.Unsigned();
|
|
break;
|
|
case DW_AT_linkage_name:
|
|
linkage_name.SetCString(form_value.AsCString());
|
|
break;
|
|
default:
|
|
assert(false && "Unsupported attribute for DW_TAG_class_type");
|
|
}
|
|
}
|
|
}
|
|
|
|
UniqueDWARFASTType unique_ast_entry;
|
|
if (name) {
|
|
std::string qualified_name;
|
|
if (die.GetQualifiedName(qualified_name)) {
|
|
name.SetCString(qualified_name.c_str());
|
|
if (dwarf->GetUniqueDWARFASTTypeMap().Find(name, die, Declaration(), -1,
|
|
unique_ast_entry)) {
|
|
if (unique_ast_entry.m_type_sp) {
|
|
dwarf->GetDIEToType()[die.GetDIE()] =
|
|
unique_ast_entry.m_type_sp.get();
|
|
is_new_type = false;
|
|
return unique_ast_entry.m_type_sp;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (is_forward_declaration) {
|
|
DWARFDeclContext die_decl_ctx;
|
|
die.GetDWARFDeclContext(die_decl_ctx);
|
|
|
|
TypeSP type_sp = dwarf->FindDefinitionTypeForDWARFDeclContext(die_decl_ctx);
|
|
if (type_sp) {
|
|
// We found a real definition for this type elsewhere so lets use it
|
|
dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get();
|
|
is_new_type = false;
|
|
return type_sp;
|
|
}
|
|
}
|
|
|
|
CompilerType compiler_type(
|
|
&m_ast, dwarf->GetForwardDeclDieToClangType().lookup(die.GetDIE()));
|
|
if (!compiler_type)
|
|
compiler_type = m_ast.CreateObjectType(name, linkage_name, byte_size);
|
|
|
|
is_new_type = true;
|
|
TypeSP type_sp(new Type(die.GetID(), dwarf, name,
|
|
-1, // byte size isn't specified
|
|
nullptr, LLDB_INVALID_UID, Type::eEncodingIsUID,
|
|
&decl, compiler_type, Type::eResolveStateForward));
|
|
|
|
// Add our type to the unique type map
|
|
unique_ast_entry.m_type_sp = type_sp;
|
|
unique_ast_entry.m_die = die;
|
|
unique_ast_entry.m_declaration = decl;
|
|
unique_ast_entry.m_byte_size = -1;
|
|
dwarf->GetUniqueDWARFASTTypeMap().Insert(name, unique_ast_entry);
|
|
|
|
if (!is_forward_declaration) {
|
|
// Leave this as a forward declaration until we need to know the details of
|
|
// the type
|
|
dwarf->GetForwardDeclDieToClangType()[die.GetDIE()] =
|
|
compiler_type.GetOpaqueQualType();
|
|
dwarf->GetForwardDeclClangTypeToDie()[compiler_type.GetOpaqueQualType()] =
|
|
die.GetDIERef();
|
|
}
|
|
return type_sp;
|
|
}
|
|
|
|
lldb::TypeSP DWARFASTParserJava::ParseTypeFromDWARF(
|
|
const lldb_private::SymbolContext &sc, const DWARFDIE &die,
|
|
lldb_private::Log *log, bool *type_is_new_ptr) {
|
|
if (type_is_new_ptr)
|
|
*type_is_new_ptr = false;
|
|
|
|
if (!die)
|
|
return nullptr;
|
|
|
|
SymbolFileDWARF *dwarf = die.GetDWARF();
|
|
|
|
Type *type_ptr = dwarf->m_die_to_type.lookup(die.GetDIE());
|
|
if (type_ptr == DIE_IS_BEING_PARSED)
|
|
return nullptr;
|
|
if (type_ptr != nullptr)
|
|
return type_ptr->shared_from_this();
|
|
|
|
TypeSP type_sp;
|
|
if (type_is_new_ptr)
|
|
*type_is_new_ptr = true;
|
|
|
|
switch (die.Tag()) {
|
|
case DW_TAG_base_type: {
|
|
type_sp = ParseBaseTypeFromDIE(die);
|
|
break;
|
|
}
|
|
case DW_TAG_array_type: {
|
|
type_sp = ParseArrayTypeFromDIE(die);
|
|
break;
|
|
}
|
|
case DW_TAG_class_type: {
|
|
bool is_new_type = false;
|
|
type_sp = ParseClassTypeFromDIE(die, is_new_type);
|
|
if (!is_new_type)
|
|
return type_sp;
|
|
break;
|
|
}
|
|
case DW_TAG_reference_type: {
|
|
type_sp = ParseReferenceTypeFromDIE(die);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!type_sp)
|
|
return nullptr;
|
|
|
|
DWARFDIE sc_parent_die = SymbolFileDWARF::GetParentSymbolContextDIE(die);
|
|
dw_tag_t sc_parent_tag = sc_parent_die.Tag();
|
|
|
|
SymbolContextScope *symbol_context_scope = nullptr;
|
|
if (sc_parent_tag == DW_TAG_compile_unit) {
|
|
symbol_context_scope = sc.comp_unit;
|
|
} else if (sc.function != nullptr && sc_parent_die) {
|
|
symbol_context_scope =
|
|
sc.function->GetBlock(true).FindBlockByID(sc_parent_die.GetID());
|
|
if (symbol_context_scope == nullptr)
|
|
symbol_context_scope = sc.function;
|
|
}
|
|
|
|
if (symbol_context_scope != nullptr)
|
|
type_sp->SetSymbolContextScope(symbol_context_scope);
|
|
|
|
dwarf->GetTypeList()->Insert(type_sp);
|
|
dwarf->m_die_to_type[die.GetDIE()] = type_sp.get();
|
|
|
|
return type_sp;
|
|
}
|
|
|
|
lldb_private::Function *DWARFASTParserJava::ParseFunctionFromDWARF(
|
|
const lldb_private::SymbolContext &sc, const DWARFDIE &die) {
|
|
assert(die.Tag() == DW_TAG_subprogram);
|
|
|
|
const char *name = nullptr;
|
|
const char *mangled = nullptr;
|
|
int decl_file = 0;
|
|
int decl_line = 0;
|
|
int decl_column = 0;
|
|
int call_file = 0;
|
|
int call_line = 0;
|
|
int call_column = 0;
|
|
DWARFRangeList func_ranges;
|
|
DWARFExpression frame_base(die.GetCU());
|
|
|
|
if (die.GetDIENamesAndRanges(name, mangled, func_ranges, decl_file, decl_line,
|
|
decl_column, call_file, call_line, call_column,
|
|
&frame_base)) {
|
|
// Union of all ranges in the function DIE (if the function is
|
|
// discontiguous)
|
|
AddressRange func_range;
|
|
lldb::addr_t lowest_func_addr = func_ranges.GetMinRangeBase(0);
|
|
lldb::addr_t highest_func_addr = func_ranges.GetMaxRangeEnd(0);
|
|
if (lowest_func_addr != LLDB_INVALID_ADDRESS &&
|
|
lowest_func_addr <= highest_func_addr) {
|
|
ModuleSP module_sp(die.GetModule());
|
|
func_range.GetBaseAddress().ResolveAddressUsingFileSections(
|
|
lowest_func_addr, module_sp->GetSectionList());
|
|
if (func_range.GetBaseAddress().IsValid())
|
|
func_range.SetByteSize(highest_func_addr - lowest_func_addr);
|
|
}
|
|
|
|
if (func_range.GetBaseAddress().IsValid()) {
|
|
std::unique_ptr<Declaration> decl_ap;
|
|
if (decl_file != 0 || decl_line != 0 || decl_column != 0)
|
|
decl_ap.reset(new Declaration(
|
|
sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(decl_file),
|
|
decl_line, decl_column));
|
|
|
|
if (die.GetDWARF()->FixupAddress(func_range.GetBaseAddress())) {
|
|
FunctionSP func_sp(new Function(sc.comp_unit, die.GetID(), die.GetID(),
|
|
Mangled(ConstString(name), false),
|
|
nullptr, // No function types in java
|
|
func_range));
|
|
if (frame_base.IsValid())
|
|
func_sp->GetFrameBaseExpression() = frame_base;
|
|
sc.comp_unit->AddFunction(func_sp);
|
|
|
|
return func_sp.get();
|
|
}
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
bool DWARFASTParserJava::CompleteTypeFromDWARF(
|
|
const DWARFDIE &die, lldb_private::Type *type,
|
|
lldb_private::CompilerType &java_type) {
|
|
switch (die.Tag()) {
|
|
case DW_TAG_class_type: {
|
|
if (die.GetAttributeValueAsUnsigned(DW_AT_declaration, 0) == 0) {
|
|
if (die.HasChildren())
|
|
ParseChildMembers(die, java_type);
|
|
m_ast.CompleteObjectType(java_type);
|
|
return java_type.IsValid();
|
|
}
|
|
} break;
|
|
default:
|
|
assert(false && "Not a forward java type declaration!");
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void DWARFASTParserJava::ParseChildMembers(const DWARFDIE &parent_die,
|
|
CompilerType &compiler_type) {
|
|
DWARFCompileUnit *dwarf_cu = parent_die.GetCU();
|
|
for (DWARFDIE die = parent_die.GetFirstChild(); die.IsValid();
|
|
die = die.GetSibling()) {
|
|
switch (die.Tag()) {
|
|
case DW_TAG_member: {
|
|
const char *name = nullptr;
|
|
DWARFFormValue encoding_uid;
|
|
uint32_t member_byte_offset = UINT32_MAX;
|
|
DWARFExpression member_location_expression(dwarf_cu);
|
|
|
|
DWARFAttributes attributes;
|
|
size_t num_attributes = die.GetAttributes(attributes);
|
|
for (size_t i = 0; i < num_attributes; ++i) {
|
|
DWARFFormValue form_value;
|
|
if (attributes.ExtractFormValueAtIndex(i, form_value)) {
|
|
switch (attributes.AttributeAtIndex(i)) {
|
|
case DW_AT_name:
|
|
name = form_value.AsCString();
|
|
break;
|
|
case DW_AT_type:
|
|
encoding_uid = form_value;
|
|
break;
|
|
case DW_AT_data_member_location:
|
|
if (form_value.BlockData())
|
|
member_location_expression.CopyOpcodeData(
|
|
form_value.BlockData(), form_value.Unsigned(),
|
|
dwarf_cu->GetByteOrder(), dwarf_cu->GetAddressByteSize());
|
|
else
|
|
member_byte_offset = form_value.Unsigned();
|
|
break;
|
|
case DW_AT_artificial:
|
|
static_cast<void>(form_value.Boolean());
|
|
break;
|
|
case DW_AT_accessibility:
|
|
// TODO: Handle when needed
|
|
break;
|
|
default:
|
|
assert(false && "Unhandled attribute for DW_TAG_member");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (strcmp(name, ".dynamic_type") == 0)
|
|
m_ast.SetDynamicTypeId(compiler_type, member_location_expression);
|
|
else {
|
|
if (Type *member_type = die.ResolveTypeUID(DIERef(encoding_uid)))
|
|
m_ast.AddMemberToObject(compiler_type, ConstString(name),
|
|
member_type->GetFullCompilerType(),
|
|
member_byte_offset);
|
|
}
|
|
break;
|
|
}
|
|
case DW_TAG_inheritance: {
|
|
DWARFFormValue encoding_uid;
|
|
uint32_t member_byte_offset = UINT32_MAX;
|
|
|
|
DWARFAttributes attributes;
|
|
size_t num_attributes = die.GetAttributes(attributes);
|
|
for (size_t i = 0; i < num_attributes; ++i) {
|
|
DWARFFormValue form_value;
|
|
if (attributes.ExtractFormValueAtIndex(i, form_value)) {
|
|
switch (attributes.AttributeAtIndex(i)) {
|
|
case DW_AT_type:
|
|
encoding_uid = form_value;
|
|
break;
|
|
case DW_AT_data_member_location:
|
|
member_byte_offset = form_value.Unsigned();
|
|
break;
|
|
case DW_AT_accessibility:
|
|
// In java all base class is public so we can ignore this attribute
|
|
break;
|
|
default:
|
|
assert(false && "Unhandled attribute for DW_TAG_member");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (Type *base_type = die.ResolveTypeUID(DIERef(encoding_uid)))
|
|
m_ast.AddBaseClassToObject(compiler_type,
|
|
base_type->GetFullCompilerType(),
|
|
member_byte_offset);
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|