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; }
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; }