https://github.com/Iasonaskrpr updated https://github.com/llvm/llvm-project/pull/223406
>From a41ea60ce903dc6c53ccfbcd97654380e8b44014 Mon Sep 17 00:00:00 2001 From: Iasonaskrpr <[email protected]> Date: Mon, 14 Sep 2026 16:28:33 +0300 Subject: [PATCH] [lldb][Fortran] Added support for base types to DWARFASTParserFortran, tests for DWARFASTParserFortran and a method to get the parser from TypeSystemFortran --- .../DWARF/DWARFASTParserFortran.cpp | 131 ++++++++++- .../SymbolFile/DWARF/DWARFASTParserFortran.h | 18 +- .../TypeSystem/Fortran/TypeSystemFortran.cpp | 8 + .../TypeSystem/Fortran/TypeSystemFortran.h | 3 + .../unittests/SymbolFile/DWARF/CMakeLists.txt | 2 + .../DWARF/DWARFASTParserFortranTests.cpp | 209 ++++++++++++++++++ 6 files changed, 366 insertions(+), 5 deletions(-) create mode 100644 lldb/unittests/SymbolFile/DWARF/DWARFASTParserFortranTests.cpp diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserFortran.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserFortran.cpp index b0606a4e9ca81..c40ce396b1377 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserFortran.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserFortran.cpp @@ -12,20 +12,143 @@ //===----------------------------------------------------------------------===// #include "DWARFASTParserFortran.h" +#include "DWARFDIE.h" +#include "DWARFDebugInfo.h" +#include "DWARFDeclContext.h" +#include "DWARFDefines.h" +#include "LogChannelDWARF.h" +#include "SymbolFileDWARF.h" +#include "SymbolFileDWARFDebugMap.h" +#include "UniqueDWARFASTType.h" + +#include "lldb/Symbol/CompileUnit.h" +#include "lldb/Utility/Log.h" +#include "lldb/ValueObject/ValueObject.h" using namespace lldb; using namespace lldb_private; +using namespace lldb_private::plugin::dwarf; +using namespace llvm::dwarf; -DWARFASTParserFortran::DWARFASTParserFortran() - : lldb_private::plugin::dwarf::DWARFASTParser(Kind::DWARFASTParserFortran) { -} +DWARFASTParserFortran::DWARFASTParserFortran( + lldb_private::TypeSystemFortran &m_ast) + : lldb_private::plugin::dwarf::DWARFASTParser(Kind::DWARFASTParserFortran), + m_ast(m_ast) {} DWARFASTParserFortran::~DWARFASTParserFortran() {} +TypeSP DWARFASTParserFortran::UpdateSymbolContextScopeForType( + const SymbolContext &sc, const DWARFDIE &die, TypeSP type_sp) { + if (!type_sp) + return type_sp; + + 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; + } else { + symbol_context_scope = sc.module_sp.get(); + } + + if (symbol_context_scope != nullptr) + type_sp->SetSymbolContextScope(symbol_context_scope); + return type_sp; +} + lldb::TypeSP DWARFASTParserFortran::ParseTypeFromDWARF( const lldb_private::SymbolContext &sc, const lldb_private::plugin::dwarf::DWARFDIE &die, bool *type_is_new_ptr) { - return lldb::TypeSP(); + TypeSP type_sp; + if (type_is_new_ptr) + *type_is_new_ptr = false; + Log *log = GetLog(DWARFLog::TypeCompletion | DWARFLog::Lookups); + + if (die) { + SymbolFileDWARF *dwarf = die.GetDWARF(); + if (log) { + dwarf->GetObjectFile()->GetModule()->LogMessage( + log, + "DWARFASTParserFortran::ParseTypeFromDWARF (die = 0x%8.8x) %s name" + "= " + "'%s')", + die.GetOffset(), plugin::dwarf::DW_TAG_value_to_name(die.Tag()), + die.GetName()); + } + Type *type_ptr = dwarf->GetDIEToType().lookup(die.GetDIE()); + if (!type_ptr) { + if (type_is_new_ptr) + *type_is_new_ptr = true; + + const dw_tag_t tag = die.Tag(); + ConstString type_name; + const char *type_name_cstr = nullptr; + CompilerType compiler_type; + DWARFAttributes attributes; + DWARFFormValue form_value; + Declaration decl; + uint32_t encoding = 0; + switch (tag) { + case DW_TAG_base_type: { + dwarf->GetDIEToType()[die.GetDIE()] = DIE_IS_BEING_PARSED; + attributes = die.GetAttributes(); + uint64_t bit_size = 0; + for (size_t idx = 0; idx < attributes.Size(); idx++) { + if (attributes.ExtractFormValueAtIndex(idx, form_value)) { + switch (attributes.AttributeAtIndex(idx)) { + case DW_AT_name: + type_name_cstr = form_value.AsCString(); + if (type_name_cstr && + type_name_cstr[0]) { // Check for null AND empty string + type_name.SetString(llvm::StringRef(type_name_cstr).upper()); + } else { + type_name.SetCString("UNKNOWN_FORTRAN_TYPE"); + } + break; + case DW_AT_encoding: + encoding = form_value.Unsigned(); + break; + case DW_AT_byte_size: + bit_size = form_value.Unsigned() * 8; + break; + case DW_AT_bit_size: + bit_size = form_value.Unsigned(); + break; + default: + break; + } + } + } + compiler_type = m_ast.CreateBaseType(encoding, bit_size, type_name); + type_sp = + dwarf->MakeType(die.GetID(), type_name, (bit_size + 7) / 8, nullptr, + LLDB_INVALID_UID, Type::eEncodingIsUID, decl, + compiler_type, Type::ResolveState::Full); + } break; + default: + if (log) { + dwarf->GetObjectFile()->GetModule()->LogMessage( + log, "[{0:x16}]: unhandled type tag {1:x4} ({2})", + die.GetOffset(), tag, DW_TAG_value_to_name(tag)); + } + break; + } + UpdateSymbolContextScopeForType(sc, die, type_sp); + if (type_sp.get()) + dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); + + } else if (type_ptr != DIE_IS_BEING_PARSED) { + type_sp = type_ptr->shared_from_this(); + } + } + return type_sp; } lldb_private::Function *DWARFASTParserFortran::ParseFunctionFromDWARF( diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserFortran.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserFortran.h index 4fbbd76ad4cb2..2afa12ae232ed 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserFortran.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserFortran.h @@ -26,10 +26,23 @@ class ExecutionContext; class DWARFASTParserFortran : public lldb_private::plugin::dwarf::DWARFASTParser { public: - DWARFASTParserFortran(); + DWARFASTParserFortran(lldb_private::TypeSystemFortran &m_ast); ~DWARFASTParserFortran() override; + // LLVM RTTI support + static bool classof(const DWARFASTParser *Parser) { + return Parser->GetKind() == Kind::DWARFASTParserFortran; + } + + /// If \p type_sp is valid, calculate and set its symbol context scope, and + /// update the type list for its backing symbol file. + /// + /// Returns \p type_sp. + lldb::TypeSP UpdateSymbolContextScopeForType( + const lldb_private::SymbolContext &sc, + const lldb_private::plugin::dwarf::DWARFDIE &die, lldb::TypeSP type_sp); + lldb::TypeSP ParseTypeFromDWARF(const lldb_private::SymbolContext &sc, const lldb_private::plugin::dwarf::DWARFDIE &die, @@ -72,6 +85,9 @@ class DWARFASTParserFortran lldb_private::plugin::dwarf::DWARFDIE die) override { return {}; } + +private: + lldb_private::TypeSystemFortran &m_ast; }; #endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFASTPARSERFORTRAN_H diff --git a/lldb/source/Plugins/TypeSystem/Fortran/TypeSystemFortran.cpp b/lldb/source/Plugins/TypeSystem/Fortran/TypeSystemFortran.cpp index 007029757c9a5..d7f5a0437d1dc 100644 --- a/lldb/source/Plugins/TypeSystem/Fortran/TypeSystemFortran.cpp +++ b/lldb/source/Plugins/TypeSystem/Fortran/TypeSystemFortran.cpp @@ -9,6 +9,8 @@ #include "TypeSystemFortran.h" #include "FortranTypes.h" +#include "Plugins/SymbolFile/DWARF/DWARFASTParserFortran.h" + #include "lldb/Core/DumpDataExtractor.h" #include "lldb/Core/PluginManager.h" #include "lldb/Symbol/SymbolFile.h" @@ -38,6 +40,12 @@ void TypeSystemFortran::Terminate() { PluginManager::UnregisterPlugin(CreateInstance); } +plugin::dwarf::DWARFASTParser *TypeSystemFortran::GetDWARFParser() { + if (!m_dwarf_ast_parser_up) + m_dwarf_ast_parser_up = std::make_unique<DWARFASTParserFortran>(*this); + return m_dwarf_ast_parser_up.get(); +} + TypeSystemSP TypeSystemFortran::CreateInstance(LanguageType language, Module *module, Target *target) { if (Language::LanguageIsFortran(language)) diff --git a/lldb/source/Plugins/TypeSystem/Fortran/TypeSystemFortran.h b/lldb/source/Plugins/TypeSystem/Fortran/TypeSystemFortran.h index 46a4a4a74c584..5be3d3c170331 100644 --- a/lldb/source/Plugins/TypeSystem/Fortran/TypeSystemFortran.h +++ b/lldb/source/Plugins/TypeSystem/Fortran/TypeSystemFortran.h @@ -35,6 +35,8 @@ class TypeSystemFortran : public TypeSystem { static void Terminate(); + plugin::dwarf::DWARFASTParser *GetDWARFParser() override; + static lldb::TypeSystemSP CreateInstance(lldb::LanguageType language, Module *module, Target *target); @@ -474,6 +476,7 @@ class TypeSystemFortran : public TypeSystem { // of the types mutable llvm::SmallVector<std::unique_ptr<plugin::fortran::FortranType>> m_types; + std::unique_ptr<plugin::dwarf::DWARFASTParser> m_dwarf_ast_parser_up; TypeSystemFortran(const TypeSystemFortran &) = delete; const TypeSystemFortran &operator=(const TypeSystemFortran &) = delete; diff --git a/lldb/unittests/SymbolFile/DWARF/CMakeLists.txt b/lldb/unittests/SymbolFile/DWARF/CMakeLists.txt index 185cad60f74d9..09d9032252b65 100644 --- a/lldb/unittests/SymbolFile/DWARF/CMakeLists.txt +++ b/lldb/unittests/SymbolFile/DWARF/CMakeLists.txt @@ -1,5 +1,6 @@ add_lldb_unittest(SymbolFileDWARFTests DWARFASTParserClangTests.cpp + DWARFASTParserFortranTests.cpp DWARFDebugNamesIndexTest.cpp DWARFDIETest.cpp DWARFIndexCachingTest.cpp @@ -19,6 +20,7 @@ add_lldb_unittest(SymbolFileDWARFTests lldbPluginSymbolFileDWARF lldbPluginSymbolFilePDB lldbPluginTypeSystemClang + lldbPluginTypeSystemFortran lldbPluginPlatformMacOSX lldbUtilityHelpers lldbSymbolHelpers diff --git a/lldb/unittests/SymbolFile/DWARF/DWARFASTParserFortranTests.cpp b/lldb/unittests/SymbolFile/DWARF/DWARFASTParserFortranTests.cpp new file mode 100644 index 0000000000000..4189a43d7a374 --- /dev/null +++ b/lldb/unittests/SymbolFile/DWARF/DWARFASTParserFortranTests.cpp @@ -0,0 +1,209 @@ +//===-- DWARFASTParserFortranTests.cpp ------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "Plugins/SymbolFile/DWARF/DWARFASTParserFortran.h" +#include "Plugins/SymbolFile/DWARF/DWARFCompileUnit.h" +#include "Plugins/SymbolFile/DWARF/DWARFDIE.h" +#include "TestingSupport/Symbol/YAMLModuleTester.h" +#include "TestingSupport/TestUtilities.h" +#include "lldb/Core/Debugger.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::plugin::dwarf; +using namespace llvm::dwarf; + +namespace { + +class TypeSystemFortranHolder { + std::shared_ptr<TypeSystemFortran> m_ast; + +public: + TypeSystemFortranHolder() : m_ast(std::make_shared<TypeSystemFortran>()) {} + TypeSystemFortran *GetAST() const { return m_ast.get(); } +}; + +class DWARFASTParserFortranTests : public testing::Test { + void SetUp() override { + std::call_once(TestUtilities::g_debugger_initialize_flag, []() { + Debugger::Initialize(nullptr); + TypeSystemFortran::Initialize(); + }); + } +}; + +/// Helper structure for DWARFASTParserFortran tests that want to parse DWARF +/// generated using yaml2obj. On construction parses the supplied YAML data +/// into a DWARF module and thereafter vends a DWARFASTParserFortran and +/// TypeSystemFortran that are guaranteed to live for the duration of this +/// object. +class DWARFASTParserFortranYAMLTester { +public: + DWARFASTParserFortranYAMLTester(llvm::StringRef yaml_data) + : m_module_tester(yaml_data) {} + + DWARFDIE GetCUDIE() { + DWARFUnit *unit = m_module_tester.GetDwarfUnit(); + assert(unit); + + const DWARFDebugInfoEntry *cu_entry = unit->DIE().GetDIE(); + assert(cu_entry->Tag() == DW_TAG_compile_unit); + + return DWARFDIE(unit, cu_entry); + } + + DWARFASTParserFortran &GetParser() { + auto *parser = GetTypeSystem().GetDWARFParser(); + + assert(llvm::isa_and_nonnull<DWARFASTParserFortran>(parser)); + + return *llvm::cast<DWARFASTParserFortran>(parser); + } + + TypeSystemFortran &GetTypeSystem() { + ModuleSP module_sp = m_module_tester.GetModule(); + assert(module_sp); + + SymbolFile *symfile = module_sp->GetSymbolFile(); + assert(symfile); + + TypeSystemSP ts_sp = llvm::cantFail(symfile->GetTypeSystemForLanguage( + lldb::LanguageType::eLanguageTypeFortran90)); + + assert(llvm::isa_and_nonnull<TypeSystemFortran>(ts_sp.get())); + + return llvm::cast<TypeSystemFortran>(*ts_sp); + } + +private: + YAMLModuleTester m_module_tester; +}; +} // namespace + +TEST_F(DWARFASTParserFortranTests, EnsureBaseTypeParsingWorks) { + const char *yamldata = R"( +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +DWARF: + debug_abbrev: + - Table: + - Code: 0x00000001 + Tag: DW_TAG_compile_unit + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_language + Form: DW_FORM_data2 + - Code: 0x00000002 + Tag: DW_TAG_base_type + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Attribute: DW_AT_encoding + Form: DW_FORM_data1 + - Attribute: DW_AT_byte_size + Form: DW_FORM_data1 + debug_info: + - Version: 4 + AddrSize: 8 + Entries: + - AbbrCode: 0x00000001 + Values: + - Value: 0x000000000000000E # DW_LANG_Fortran95 + # integer(kind=4) + - AbbrCode: 0x00000002 + Values: + - CStr: 'integer(kind=4)' + - Value: 0x0000000000000005 # DW_ATE_signed + - Value: 0x0000000000000004 + # integer(kind=8) + - AbbrCode: 0x00000002 + Values: + - CStr: 'integer(kind=8)' + - Value: 0x0000000000000005 # DW_ATE_signed + - Value: 0x0000000000000008 + # real(kind=4) + - AbbrCode: 0x00000002 + Values: + - CStr: 'real(kind=4)' + - Value: 0x0000000000000004 # DW_ATE_float + - Value: 0x0000000000000004 + # complex(kind=4) + - AbbrCode: 0x00000002 + Values: + - CStr: 'complex(kind=4)' + - Value: 0x0000000000000003 # DW_ATE_complex_float + - Value: 0x0000000000000008 + # logical(kind=4) + - AbbrCode: 0x00000002 + Values: + - CStr: 'logical(kind=4)' + - Value: 0x0000000000000002 # DW_ATE_boolean + - Value: 0x0000000000000004 +)"; + + DWARFASTParserFortranYAMLTester tester(yamldata); + DWARFDIE cu_die = tester.GetCUDIE(); + + struct ExpectedTypeInfo { + const char *name; + uint64_t byte_size; + lldb::BasicType basic_type; + }; + + const std::vector<ExpectedTypeInfo> expected_types = { + {"INTEGER", 4, lldb::eBasicTypeInt}, + {"INTEGER(KIND=8)", 8, lldb::eBasicTypeLongLong}, + {"REAL", 4, lldb::eBasicTypeFloat}, + {"COMPLEX", 8, lldb::eBasicTypeFloatComplex}, + {"LOGICAL", 4, lldb::eBasicTypeBool}, + }; + + size_t type_idx = 0; + for (DWARFDIE child_die : cu_die.children()) { + ASSERT_EQ(child_die.Tag(), DW_TAG_base_type); + ASSERT_LT(type_idx, expected_types.size()); + + const auto &expected = expected_types[type_idx++]; + SymbolContext sc; + + bool is_new_type = false; + lldb::TypeSP type_sp = + tester.GetParser().ParseTypeFromDWARF(sc, child_die, &is_new_type); + + ASSERT_NE(type_sp, nullptr); + EXPECT_TRUE(is_new_type); + + EXPECT_EQ(type_sp->GetForwardCompilerType().GetTypeName().GetString(), + expected.name); + + llvm::Expected<uint64_t> size_or_err = type_sp->GetByteSize(nullptr); + ASSERT_FALSE(!size_or_err); + EXPECT_EQ(*size_or_err, expected.byte_size); + + EXPECT_EQ(type_sp->GetForwardCompilerType().GetBasicTypeEnumeration(), + expected.basic_type); + + bool is_new_type_cached = true; + lldb::TypeSP cached_type_sp = tester.GetParser().ParseTypeFromDWARF( + sc, child_die, &is_new_type_cached); + + ASSERT_NE(cached_type_sp, nullptr); + EXPECT_FALSE(is_new_type_cached); + EXPECT_EQ(type_sp, cached_type_sp); + } + + // Ensure all expected DIEs were iterated + EXPECT_EQ(type_idx, expected_types.size()); +} _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
