|  | //===-- 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(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); | 
|  | bool artificial = true; | 
|  |  | 
|  | 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: | 
|  | artificial = 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; | 
|  | } | 
|  | } | 
|  | } |