| //===-- 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 "DWARFUnit.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 || |
| sc_parent_tag == DW_TAG_partial_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) { |
| DWARFUnit *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; |
| } |
| } |
| } |