[Lldb-commits] [lldb] Reland: [lldb][Fortran] Added support for base types to DWARFASTParserFortran (PR #234214)

via lldb-commits lldb-commits at lists.llvm.org
Wed Oct 21 06:55:11 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-lldb

Author: Iasonas Karaprodromidis (Iasonaskrpr)

<details>
<summary>Changes</summary>

Relands #<!-- -->223406.
(Reason for the breakage was a UB in DWARFASTParserFortran regarding the initialization of the TypeSystemFortran instance with `std::call_once`).

This PR adds support for base types to DWARFASTParserFortran, introduces a method to retrieve the parser from TypeSystemFortran, and adds unit tests for type parsing.

Changes:

- Added DW_TAG_base_type handling to ParseType.

- Added scope resolution for parsed types.

- Added a method to return the parser from TypeSystemFortran.

- Added unit tests to verify that base types are parsed correctly.

Relates to #<!-- -->109119.

---
Full diff: https://github.com/llvm/llvm-project/pull/234214.diff


6 Files Affected:

- (modified) lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserFortran.cpp (+140-4) 
- (modified) lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserFortran.h (+17-1) 
- (modified) lldb/source/Plugins/TypeSystem/Fortran/TypeSystemFortran.cpp (+8) 
- (modified) lldb/source/Plugins/TypeSystem/Fortran/TypeSystemFortran.h (+3) 
- (modified) lldb/unittests/SymbolFile/DWARF/CMakeLists.txt (+2) 
- (added) lldb/unittests/SymbolFile/DWARF/DWARFASTParserFortranTests.cpp (+211) 


``````````diff
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserFortran.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserFortran.cpp
index b0606a4e9ca81f..d9caa194291183 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserFortran.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserFortran.cpp
@@ -12,20 +12,156 @@
 //===----------------------------------------------------------------------===//
 
 #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 && 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)
+    return type_sp;
+  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_ptr != DIE_IS_BEING_PARSED)
+      return type_ptr->shared_from_this();
+    else
+      return TypeSP();
+  }
+
+  if (type_is_new_ptr)
+    *type_is_new_ptr = true;
+
+  ConstString type_name;
+  const char *type_name_cstr = nullptr;
+  CompilerType compiler_type;
+  DWARFAttributes attributes;
+  DWARFFormValue form_value;
+  Declaration decl;
+  // We use 0x00 as a sentinel value, it doesn't map to any DW_ATE attribute
+  llvm::dwarf::TypeKind encoding = static_cast<llvm::dwarf::TypeKind>(0x00);
+
+  switch (const dw_tag_t tag = die.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] != '\0')
+            type_name.SetString(llvm::StringRef(type_name_cstr).upper());
+          else
+            type_name.SetCString("UNKNOWN_FORTRAN_TYPE");
+
+          break;
+        case DW_AT_encoding:
+          encoding = static_cast<llvm::dwarf::TypeKind>(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, llvm::divideCeil(bit_size, 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();
+
+  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 4fbbd76ad4cb21..2afa12ae232edd 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 13406c19fcb83d..0454d4cc192c7e 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 46a4a4a74c5840..5be3d3c1703314 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 185cad60f74d9b..09d9032252b65e 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 00000000000000..a8d37709d14770
--- /dev/null
+++ b/lldb/unittests/SymbolFile/DWARF/DWARFASTParserFortranTests.cpp
@@ -0,0 +1,211 @@
+//===-- 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 {
+
+std::once_flag g_type_system_initialize_flag;
+
+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); });
+    std::call_once(g_type_system_initialize_flag,
+                   []() { 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. Thereafter vends a DWARFASTParserFortran and
+/// TypeSystemFortran instances 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(KIND=4)", 4, lldb::eBasicTypeInt},
+      {"INTEGER(KIND=8)", 8, lldb::eBasicTypeLongLong},
+      {"REAL(KIND=4)", 4, lldb::eBasicTypeFloat},
+      {"COMPLEX(KIND=4)", 8, lldb::eBasicTypeFloatComplex},
+      {"LOGICAL(KIND=4)", 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());
+}

``````````

</details>


https://github.com/llvm/llvm-project/pull/234214


More information about the lldb-commits mailing list