| //===-- DWARFASTParserGo.cpp ---------------------------------*- C++ -*-===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "DWARFASTParserGo.h" |
| |
| #include "DWARFASTParserGo.h" |
| #include "DWARFCompileUnit.h" |
| #include "DWARFDebugInfo.h" |
| #include "DWARFDeclContext.h" |
| #include "DWARFDefines.h" |
| #include "DWARFDIE.h" |
| #include "DWARFDIECollection.h" |
| #include "SymbolFileDWARF.h" |
| #include "SymbolFileDWARFDebugMap.h" |
| #include "UniqueDWARFASTType.h" |
| |
| #include "clang/Basic/Specifiers.h" |
| |
| #include "lldb/Core/Module.h" |
| #include "lldb/Core/Value.h" |
| #include "lldb/Symbol/CompileUnit.h" |
| #include "lldb/Symbol/Function.h" |
| #include "lldb/Symbol/ObjectFile.h" |
| #include "lldb/Symbol/TypeList.h" |
| |
| //#define ENABLE_DEBUG_PRINTF // COMMENT OUT THIS LINE PRIOR TO CHECKIN |
| |
| #ifdef ENABLE_DEBUG_PRINTF |
| #include <stdio.h> |
| #define DEBUG_PRINTF(fmt, ...) printf(fmt, __VA_ARGS__) |
| #else |
| #define DEBUG_PRINTF(fmt, ...) |
| #endif |
| |
| #define DW_AT_go_kind 0x2900 |
| #define DW_AT_go_key 0x2901 |
| #define DW_AT_go_elem 0x2902 |
| |
| using namespace lldb; |
| using namespace lldb_private; |
| DWARFASTParserGo::DWARFASTParserGo(GoASTContext &ast) |
| : m_ast(ast) |
| { |
| } |
| |
| DWARFASTParserGo::~DWARFASTParserGo() |
| { |
| } |
| |
| TypeSP |
| DWARFASTParserGo::ParseTypeFromDWARF(const lldb_private::SymbolContext &sc, const DWARFDIE &die, lldb_private::Log *log, |
| bool *type_is_new_ptr) |
| { |
| TypeSP type_sp; |
| |
| if (type_is_new_ptr) |
| *type_is_new_ptr = false; |
| |
| if (die) |
| { |
| SymbolFileDWARF *dwarf = die.GetDWARF(); |
| if (log) |
| { |
| dwarf->GetObjectFile()->GetModule()->LogMessage( |
| log, "DWARFASTParserGo::ParseTypeFromDWARF (die = 0x%8.8x) %s name = '%s')", die.GetOffset(), |
| DW_TAG_value_to_name(die.Tag()), die.GetName()); |
| } |
| |
| Type *type_ptr = dwarf->m_die_to_type.lookup(die.GetDIE()); |
| TypeList *type_list = dwarf->GetTypeList(); |
| if (type_ptr == NULL) |
| { |
| if (type_is_new_ptr) |
| *type_is_new_ptr = true; |
| |
| const dw_tag_t tag = die.Tag(); |
| |
| bool is_forward_declaration = false; |
| DWARFAttributes attributes; |
| const char *type_name_cstr = NULL; |
| ConstString type_name_const_str; |
| Type::ResolveState resolve_state = Type::eResolveStateUnresolved; |
| uint64_t byte_size = 0; |
| uint64_t go_kind = 0; |
| Declaration decl; |
| |
| Type::EncodingDataType encoding_data_type = Type::eEncodingIsUID; |
| CompilerType compiler_type; |
| DWARFFormValue form_value; |
| |
| dw_attr_t attr; |
| |
| switch (tag) |
| { |
| case DW_TAG_base_type: |
| case DW_TAG_pointer_type: |
| case DW_TAG_typedef: |
| case DW_TAG_unspecified_type: |
| { |
| // Set a bit that lets us know that we are currently parsing this |
| dwarf->m_die_to_type[die.GetDIE()] = DIE_IS_BEING_PARSED; |
| |
| const size_t num_attributes = die.GetAttributes(attributes); |
| lldb::user_id_t encoding_uid = LLDB_INVALID_UID; |
| |
| if (num_attributes > 0) |
| { |
| uint32_t i; |
| for (i = 0; i < num_attributes; ++i) |
| { |
| attr = attributes.AttributeAtIndex(i); |
| if (attributes.ExtractFormValueAtIndex(i, form_value)) |
| { |
| switch (attr) |
| { |
| case DW_AT_name: |
| type_name_cstr = form_value.AsCString(); |
| if (type_name_cstr) |
| type_name_const_str.SetCString(type_name_cstr); |
| break; |
| case DW_AT_byte_size: |
| byte_size = form_value.Unsigned(); |
| break; |
| case DW_AT_encoding: |
| // = form_value.Unsigned(); |
| break; |
| case DW_AT_type: |
| encoding_uid = form_value.Reference(); |
| break; |
| case DW_AT_go_kind: |
| go_kind = form_value.Unsigned(); |
| break; |
| default: |
| // Do we care about DW_AT_go_key or DW_AT_go_elem? |
| break; |
| } |
| } |
| } |
| } |
| |
| DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\") type => 0x%8.8lx\n", dwarf->MakeUserID(die.GetOffset()), |
| DW_TAG_value_to_name(tag), type_name_cstr, encoding_uid); |
| |
| switch (tag) |
| { |
| default: |
| break; |
| |
| case DW_TAG_unspecified_type: |
| resolve_state = Type::eResolveStateFull; |
| compiler_type = m_ast.CreateVoidType(type_name_const_str); |
| break; |
| |
| case DW_TAG_base_type: |
| resolve_state = Type::eResolveStateFull; |
| compiler_type = m_ast.CreateBaseType(go_kind, type_name_const_str, byte_size); |
| break; |
| |
| case DW_TAG_pointer_type: |
| encoding_data_type = Type::eEncodingIsPointerUID; |
| break; |
| case DW_TAG_typedef: |
| encoding_data_type = Type::eEncodingIsTypedefUID; |
| CompilerType impl; |
| Type *type = dwarf->ResolveTypeUID(encoding_uid); |
| if (type) |
| { |
| if (go_kind == 0 && type->GetName() == type_name_const_str) |
| { |
| // Go emits extra typedefs as a forward declaration. Ignore these. |
| dwarf->m_die_to_type[die.GetDIE()] = type; |
| return type->shared_from_this(); |
| } |
| impl = type->GetForwardCompilerType(); |
| compiler_type = m_ast.CreateTypedefType (go_kind, type_name_const_str, impl); |
| } |
| break; |
| } |
| |
| type_sp.reset(new Type(dwarf->MakeUserID(die.GetOffset()), dwarf, type_name_const_str, byte_size, |
| NULL, encoding_uid, encoding_data_type, &decl, compiler_type, resolve_state)); |
| |
| dwarf->m_die_to_type[die.GetDIE()] = type_sp.get(); |
| } |
| break; |
| |
| case DW_TAG_structure_type: |
| { |
| // Set a bit that lets us know that we are currently parsing this |
| dwarf->m_die_to_type[die.GetDIE()] = DIE_IS_BEING_PARSED; |
| bool byte_size_valid = false; |
| |
| const size_t num_attributes = die.GetAttributes(attributes); |
| if (num_attributes > 0) |
| { |
| uint32_t i; |
| for (i = 0; i < num_attributes; ++i) |
| { |
| attr = attributes.AttributeAtIndex(i); |
| if (attributes.ExtractFormValueAtIndex(i, form_value)) |
| { |
| switch (attr) |
| { |
| case DW_AT_name: |
| type_name_cstr = form_value.AsCString(); |
| type_name_const_str.SetCString(type_name_cstr); |
| break; |
| |
| case DW_AT_byte_size: |
| byte_size = form_value.Unsigned(); |
| byte_size_valid = true; |
| break; |
| |
| case DW_AT_go_kind: |
| go_kind = form_value.Unsigned(); |
| break; |
| |
| // TODO: Should we use SLICETYPE's DW_AT_go_elem? |
| default: |
| break; |
| } |
| } |
| } |
| } |
| |
| // TODO(ribrdb): Do we need this? |
| |
| // UniqueDWARFASTType is large, so don't create a local variables on the |
| // stack, put it on the heap. This function is often called recursively |
| // and clang isn't good and sharing the stack space for variables in different blocks. |
| std::unique_ptr<UniqueDWARFASTType> unique_ast_entry_ap(new UniqueDWARFASTType()); |
| |
| // Only try and unique the type if it has a name. |
| if (type_name_const_str && |
| dwarf->GetUniqueDWARFASTTypeMap().Find(type_name_const_str, die, decl, |
| byte_size_valid ? byte_size : -1, *unique_ast_entry_ap)) |
| { |
| // We have already parsed this type or from another |
| // compile unit. GCC loves to use the "one definition |
| // rule" which can result in multiple definitions |
| // of the same class over and over in each compile |
| // unit. |
| type_sp = unique_ast_entry_ap->m_type_sp; |
| if (type_sp) |
| { |
| dwarf->m_die_to_type[die.GetDIE()] = type_sp.get(); |
| return type_sp; |
| } |
| } |
| |
| DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\")\n", dwarf->MakeUserID(die.GetOffset()), |
| DW_TAG_value_to_name(tag), type_name_cstr); |
| |
| bool compiler_type_was_created = false; |
| compiler_type.SetCompilerType(&m_ast, dwarf->m_forward_decl_die_to_clang_type.lookup(die.GetDIE())); |
| if (!compiler_type) |
| { |
| compiler_type_was_created = true; |
| compiler_type = m_ast.CreateStructType(go_kind, type_name_const_str, byte_size); |
| } |
| |
| type_sp.reset(new Type(dwarf->MakeUserID(die.GetOffset()), dwarf, type_name_const_str, byte_size, |
| NULL, LLDB_INVALID_UID, Type::eEncodingIsUID, &decl, compiler_type, |
| Type::eResolveStateForward)); |
| |
| // Add our type to the unique type map so we don't |
| // end up creating many copies of the same type over |
| // and over in the ASTContext for our module |
| unique_ast_entry_ap->m_type_sp = type_sp; |
| unique_ast_entry_ap->m_die = die; |
| unique_ast_entry_ap->m_declaration = decl; |
| unique_ast_entry_ap->m_byte_size = byte_size; |
| dwarf->GetUniqueDWARFASTTypeMap().Insert(type_name_const_str, *unique_ast_entry_ap); |
| |
| if (!is_forward_declaration) |
| { |
| // Always start the definition for a class type so that |
| // if the class has child classes or types that require |
| // the class to be created for use as their decl contexts |
| // the class will be ready to accept these child definitions. |
| if (die.HasChildren() == false) |
| { |
| // No children for this struct/union/class, lets finish it |
| m_ast.CompleteStructType(compiler_type); |
| } |
| else if (compiler_type_was_created) |
| { |
| // Leave this as a forward declaration until we need |
| // to know the details of the type. lldb_private::Type |
| // will automatically call the SymbolFile virtual function |
| // "SymbolFileDWARF::CompleteType(Type *)" |
| // When the definition needs to be defined. |
| dwarf->m_forward_decl_die_to_clang_type[die.GetDIE()] = compiler_type.GetOpaqueQualType(); |
| dwarf->m_forward_decl_clang_type_to_die[compiler_type.GetOpaqueQualType()] = die.GetDIERef(); |
| // SetHasExternalStorage (compiler_type.GetOpaqueQualType(), true); |
| } |
| } |
| } |
| break; |
| |
| case DW_TAG_subprogram: |
| case DW_TAG_subroutine_type: |
| { |
| // Set a bit that lets us know that we are currently parsing this |
| dwarf->m_die_to_type[die.GetDIE()] = DIE_IS_BEING_PARSED; |
| |
| bool is_variadic = false; |
| clang::StorageClass storage = clang::SC_None; //, Extern, Static, PrivateExtern |
| |
| const size_t num_attributes = die.GetAttributes(attributes); |
| if (num_attributes > 0) |
| { |
| uint32_t i; |
| for (i = 0; i < num_attributes; ++i) |
| { |
| attr = attributes.AttributeAtIndex(i); |
| if (attributes.ExtractFormValueAtIndex(i, form_value)) |
| { |
| switch (attr) |
| { |
| case DW_AT_name: |
| type_name_cstr = form_value.AsCString(); |
| type_name_const_str.SetCString(type_name_cstr); |
| break; |
| |
| case DW_AT_external: |
| if (form_value.Unsigned()) |
| { |
| if (storage == clang::SC_None) |
| storage = clang::SC_Extern; |
| else |
| storage = clang::SC_PrivateExtern; |
| } |
| break; |
| |
| case DW_AT_high_pc: |
| case DW_AT_low_pc: |
| break; |
| } |
| } |
| } |
| } |
| |
| DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\")\n", dwarf->MakeUserID(die.GetOffset()), |
| DW_TAG_value_to_name(tag), type_name_cstr); |
| |
| std::vector<CompilerType> function_param_types; |
| |
| // Parse the function children for the parameters |
| |
| if (die.HasChildren()) |
| { |
| ParseChildParameters(sc, die, is_variadic, function_param_types); |
| } |
| |
| // compiler_type will get the function prototype clang type after this call |
| compiler_type = m_ast.CreateFunctionType(type_name_const_str, function_param_types.data(), |
| function_param_types.size(), is_variadic); |
| |
| type_sp.reset(new Type(dwarf->MakeUserID(die.GetOffset()), dwarf, type_name_const_str, 0, NULL, |
| LLDB_INVALID_UID, Type::eEncodingIsUID, &decl, compiler_type, |
| Type::eResolveStateFull)); |
| assert(type_sp.get()); |
| } |
| break; |
| |
| case DW_TAG_array_type: |
| { |
| // Set a bit that lets us know that we are currently parsing this |
| dwarf->m_die_to_type[die.GetDIE()] = DIE_IS_BEING_PARSED; |
| |
| lldb::user_id_t type_die_offset = DW_INVALID_OFFSET; |
| int64_t first_index = 0; |
| uint32_t byte_stride = 0; |
| uint32_t bit_stride = 0; |
| const size_t num_attributes = die.GetAttributes(attributes); |
| |
| if (num_attributes > 0) |
| { |
| uint32_t i; |
| for (i = 0; i < num_attributes; ++i) |
| { |
| attr = attributes.AttributeAtIndex(i); |
| if (attributes.ExtractFormValueAtIndex(i, form_value)) |
| { |
| switch (attr) |
| { |
| case DW_AT_name: |
| type_name_cstr = form_value.AsCString(); |
| type_name_const_str.SetCString(type_name_cstr); |
| break; |
| |
| case DW_AT_type: |
| type_die_offset = form_value.Reference(); |
| break; |
| case DW_AT_byte_size: |
| break; // byte_size = form_value.Unsigned(); break; |
| case DW_AT_go_kind: |
| go_kind = form_value.Unsigned(); |
| break; |
| default: |
| break; |
| } |
| } |
| } |
| |
| DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\")\n", dwarf->MakeUserID(die.GetOffset()), |
| DW_TAG_value_to_name(tag), type_name_cstr); |
| |
| Type *element_type = dwarf->ResolveTypeUID(type_die_offset); |
| |
| if (element_type) |
| { |
| std::vector<uint64_t> element_orders; |
| ParseChildArrayInfo(sc, die, first_index, element_orders, byte_stride, bit_stride); |
| if (byte_stride == 0) |
| byte_stride = element_type->GetByteSize(); |
| CompilerType array_element_type = element_type->GetForwardCompilerType(); |
| if (element_orders.size() > 0) |
| { |
| if (element_orders.size() > 1) |
| printf("golang: unsupported multi-dimensional array %s\n", type_name_cstr); |
| compiler_type = |
| m_ast.CreateArrayType(type_name_const_str, array_element_type, element_orders[0]); |
| } |
| else |
| { |
| compiler_type = m_ast.CreateArrayType(type_name_const_str, array_element_type, 0); |
| } |
| type_sp.reset(new Type(dwarf->MakeUserID(die.GetOffset()), dwarf, type_name_const_str, |
| byte_stride, NULL, type_die_offset, Type::eEncodingIsUID, &decl, |
| compiler_type, Type::eResolveStateFull)); |
| type_sp->SetEncodingType(element_type); |
| } |
| } |
| } |
| break; |
| |
| default: |
| dwarf->GetObjectFile()->GetModule()->ReportError("{0x%8.8x}: unhandled type tag 0x%4.4x (%s), " |
| "please file a bug and attach the file at the " |
| "start of this error message", |
| die.GetOffset(), tag, DW_TAG_value_to_name(tag)); |
| break; |
| } |
| |
| if (type_sp.get()) |
| { |
| DWARFDIE sc_parent_die = SymbolFileDWARF::GetParentSymbolContextDIE(die); |
| dw_tag_t sc_parent_tag = sc_parent_die.Tag(); |
| |
| SymbolContextScope *symbol_context_scope = NULL; |
| if (sc_parent_tag == DW_TAG_compile_unit) |
| { |
| symbol_context_scope = sc.comp_unit; |
| } |
| else if (sc.function != NULL && sc_parent_die) |
| { |
| symbol_context_scope = |
| sc.function->GetBlock(true).FindBlockByID(dwarf->MakeUserID(sc_parent_die.GetOffset())); |
| if (symbol_context_scope == NULL) |
| symbol_context_scope = sc.function; |
| } |
| |
| if (symbol_context_scope != NULL) |
| { |
| type_sp->SetSymbolContextScope(symbol_context_scope); |
| } |
| |
| // We are ready to put this type into the uniqued list up at the module level |
| type_list->Insert(type_sp); |
| |
| dwarf->m_die_to_type[die.GetDIE()] = type_sp.get(); |
| } |
| } |
| else if (type_ptr != DIE_IS_BEING_PARSED) |
| { |
| type_sp = type_ptr->shared_from_this(); |
| } |
| } |
| return type_sp; |
| } |
| |
| size_t |
| DWARFASTParserGo::ParseChildParameters(const SymbolContext &sc, |
| |
| const DWARFDIE &parent_die, bool &is_variadic, |
| std::vector<CompilerType> &function_param_types) |
| { |
| if (!parent_die) |
| return 0; |
| |
| size_t arg_idx = 0; |
| for (DWARFDIE die = parent_die.GetFirstChild(); die.IsValid(); die = die.GetSibling()) |
| { |
| |
| dw_tag_t tag = die.Tag(); |
| switch (tag) |
| { |
| case DW_TAG_formal_parameter: |
| { |
| DWARFAttributes attributes; |
| const size_t num_attributes = die.GetAttributes(attributes); |
| if (num_attributes > 0) |
| { |
| Declaration decl; |
| dw_offset_t param_type_die_offset = DW_INVALID_OFFSET; |
| |
| uint32_t i; |
| for (i = 0; i < num_attributes; ++i) |
| { |
| const dw_attr_t attr = attributes.AttributeAtIndex(i); |
| DWARFFormValue form_value; |
| if (attributes.ExtractFormValueAtIndex(i, form_value)) |
| { |
| switch (attr) |
| { |
| case DW_AT_name: |
| // = form_value.AsCString(); |
| break; |
| case DW_AT_type: |
| param_type_die_offset = form_value.Reference(); |
| break; |
| case DW_AT_location: |
| // if (form_value.BlockData()) |
| // { |
| // const DWARFDataExtractor& debug_info_data = |
| // debug_info(); |
| // uint32_t block_length = form_value.Unsigned(); |
| // DWARFDataExtractor location(debug_info_data, |
| // form_value.BlockData() - debug_info_data.GetDataStart(), |
| // block_length); |
| // } |
| // else |
| // { |
| // } |
| // break; |
| default: |
| break; |
| } |
| } |
| } |
| |
| Type *type = parent_die.ResolveTypeUID(param_type_die_offset); |
| if (type) |
| { |
| function_param_types.push_back(type->GetForwardCompilerType()); |
| } |
| } |
| arg_idx++; |
| } |
| break; |
| |
| case DW_TAG_unspecified_parameters: |
| is_variadic = true; |
| break; |
| |
| default: |
| break; |
| } |
| } |
| return arg_idx; |
| } |
| |
| void |
| DWARFASTParserGo::ParseChildArrayInfo(const SymbolContext &sc, const DWARFDIE &parent_die, int64_t &first_index, |
| std::vector<uint64_t> &element_orders, uint32_t &byte_stride, |
| uint32_t &bit_stride) |
| { |
| if (!parent_die) |
| return; |
| |
| for (DWARFDIE die = parent_die.GetFirstChild(); die.IsValid(); die = die.GetSibling()) |
| { |
| const dw_tag_t tag = die.Tag(); |
| switch (tag) |
| { |
| case DW_TAG_subrange_type: |
| { |
| DWARFAttributes attributes; |
| const size_t num_child_attributes = die.GetAttributes(attributes); |
| if (num_child_attributes > 0) |
| { |
| uint64_t num_elements = 0; |
| uint32_t i; |
| for (i = 0; i < num_child_attributes; ++i) |
| { |
| const dw_attr_t attr = attributes.AttributeAtIndex(i); |
| DWARFFormValue form_value; |
| if (attributes.ExtractFormValueAtIndex(i, form_value)) |
| { |
| switch (attr) |
| { |
| case DW_AT_count: |
| num_elements = form_value.Unsigned(); |
| break; |
| |
| default: |
| case DW_AT_type: |
| break; |
| } |
| } |
| } |
| |
| element_orders.push_back(num_elements); |
| } |
| } |
| break; |
| } |
| } |
| } |
| |
| bool |
| DWARFASTParserGo::CompleteTypeFromDWARF(const DWARFDIE &die, lldb_private::Type *type, CompilerType &compiler_type) |
| { |
| if (!die) |
| return false; |
| |
| const dw_tag_t tag = die.Tag(); |
| |
| SymbolFileDWARF *dwarf = die.GetDWARF(); |
| Log *log = nullptr; // (LogChannelDWARF::GetLogIfAny(DWARF_LOG_DEBUG_INFO|DWARF_LOG_TYPE_COMPLETION)); |
| if (log) |
| dwarf->GetObjectFile()->GetModule()->LogMessageVerboseBacktrace( |
| log, "0x%8.8" PRIx64 ": %s '%s' resolving forward declaration...", dwarf->MakeUserID(die.GetOffset()), |
| DW_TAG_value_to_name(tag), type->GetName().AsCString()); |
| assert(compiler_type); |
| DWARFAttributes attributes; |
| |
| switch (tag) |
| { |
| case DW_TAG_structure_type: |
| { |
| { |
| if (die.HasChildren()) |
| { |
| SymbolContext sc(die.GetLLDBCompileUnit()); |
| |
| ParseChildMembers(sc, die, compiler_type); |
| } |
| } |
| m_ast.CompleteStructType(compiler_type); |
| return (bool)compiler_type; |
| } |
| |
| default: |
| assert(false && "not a forward go type decl!"); |
| break; |
| } |
| |
| return false; |
| } |
| |
| size_t |
| DWARFASTParserGo::ParseChildMembers(const SymbolContext &sc, const DWARFDIE &parent_die, CompilerType &class_compiler_type) |
| { |
| size_t count = 0; |
| uint32_t member_idx = 0; |
| |
| ModuleSP module_sp = parent_die.GetDWARF()->GetObjectFile()->GetModule(); |
| GoASTContext *ast = llvm::dyn_cast_or_null<GoASTContext>(class_compiler_type.GetTypeSystem()); |
| if (ast == nullptr) |
| return 0; |
| |
| for (DWARFDIE die = parent_die.GetFirstChild(); die.IsValid(); die = die.GetSibling()) |
| { |
| dw_tag_t tag = die.Tag(); |
| |
| switch (tag) |
| { |
| case DW_TAG_member: |
| { |
| DWARFAttributes attributes; |
| const size_t num_attributes = die.GetAttributes(attributes); |
| if (num_attributes > 0) |
| { |
| Declaration decl; |
| const char *name = NULL; |
| |
| lldb::user_id_t encoding_uid = LLDB_INVALID_UID; |
| uint32_t member_byte_offset = UINT32_MAX; |
| uint32_t i; |
| for (i = 0; i < num_attributes; ++i) |
| { |
| const dw_attr_t attr = attributes.AttributeAtIndex(i); |
| DWARFFormValue form_value; |
| if (attributes.ExtractFormValueAtIndex(i, form_value)) |
| { |
| switch (attr) |
| { |
| case DW_AT_name: |
| name = form_value.AsCString(); |
| break; |
| case DW_AT_type: |
| encoding_uid = form_value.Reference(); |
| break; |
| case DW_AT_data_member_location: |
| if (form_value.BlockData()) |
| { |
| Value initialValue(0); |
| Value memberOffset(0); |
| const DWARFDataExtractor &debug_info_data = |
| die.GetDWARF()->get_debug_info_data(); |
| uint32_t block_length = form_value.Unsigned(); |
| uint32_t block_offset = form_value.BlockData() - debug_info_data.GetDataStart(); |
| if (DWARFExpression::Evaluate(NULL, // ExecutionContext * |
| NULL, // ClangExpressionVariableList * |
| NULL, // ClangExpressionDeclMap * |
| NULL, // RegisterContext * |
| module_sp, debug_info_data, die.GetCU(), |
| block_offset, block_length, eRegisterKindDWARF, |
| &initialValue, NULL, memberOffset, NULL)) |
| { |
| member_byte_offset = memberOffset.ResolveValue(NULL).UInt(); |
| } |
| } |
| else |
| { |
| // With DWARF 3 and later, if the value is an integer constant, |
| // this form value is the offset in bytes from the beginning |
| // of the containing entity. |
| member_byte_offset = form_value.Unsigned(); |
| } |
| break; |
| |
| default: |
| break; |
| } |
| } |
| } |
| |
| Type *member_type = die.ResolveTypeUID(encoding_uid); |
| if (member_type) |
| { |
| CompilerType member_go_type = member_type->GetFullCompilerType(); |
| ConstString name_const_str(name); |
| m_ast.AddFieldToStruct(class_compiler_type, name_const_str, member_go_type, member_byte_offset); |
| } |
| } |
| ++member_idx; |
| } |
| break; |
| |
| default: |
| break; |
| } |
| } |
| |
| return count; |
| } |
| |
| Function * |
| DWARFASTParserGo::ParseFunctionFromDWARF(const SymbolContext &sc, const DWARFDIE &die) |
| { |
| DWARFRangeList func_ranges; |
| const char *name = NULL; |
| const char *mangled = NULL; |
| int decl_file = 0; |
| int decl_line = 0; |
| int decl_column = 0; |
| int call_file = 0; |
| int call_line = 0; |
| int call_column = 0; |
| DWARFExpression frame_base(die.GetCU()); |
| |
| assert(die.Tag() == DW_TAG_subprogram); |
| |
| if (die.Tag() != DW_TAG_subprogram) |
| return NULL; |
| |
| 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()) |
| { |
| Mangled func_name; |
| func_name.SetValue(ConstString(name), false); |
| |
| FunctionSP func_sp; |
| 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)); |
| |
| SymbolFileDWARF *dwarf = die.GetDWARF(); |
| // Supply the type _only_ if it has already been parsed |
| Type *func_type = dwarf->m_die_to_type.lookup(die.GetDIE()); |
| |
| assert(func_type == NULL || func_type != DIE_IS_BEING_PARSED); |
| |
| if (dwarf->FixupAddress(func_range.GetBaseAddress())) |
| { |
| const user_id_t func_user_id = dwarf->MakeUserID(die.GetOffset()); |
| func_sp.reset(new Function(sc.comp_unit, |
| dwarf->MakeUserID(func_user_id), // UserID is the DIE offset |
| dwarf->MakeUserID(func_user_id), func_name, func_type, |
| func_range)); // first address range |
| |
| if (func_sp.get() != NULL) |
| { |
| if (frame_base.IsValid()) |
| func_sp->GetFrameBaseExpression() = frame_base; |
| sc.comp_unit->AddFunction(func_sp); |
| return func_sp.get(); |
| } |
| } |
| } |
| } |
| return NULL; |
| } |