[llvm-branch-commits] [lldb] [lldb][Fortran] Added support for base types to DWARFASTParserFortran (PR #223406)

Iasonas Karaprodromidis via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Fri Sep 18 07:59:55 PDT 2026


https://github.com/Iasonaskrpr updated https://github.com/llvm/llvm-project/pull/223406

>From a41ea60ce903dc6c53ccfbcd97654380e8b44014 Mon Sep 17 00:00:00 2001
From: Iasonaskrpr <iaskarapro at gmail.com>
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());
+}



More information about the llvm-branch-commits mailing list