[Lldb-commits] [lldb] [LLDB] Support reading size of constant values from DWARF directly (PR #198392)

Adrian Prantl via lldb-commits lldb-commits at lists.llvm.org
Mon May 18 13:04:18 PDT 2026


https://github.com/adrian-prantl created https://github.com/llvm/llvm-project/pull/198392

Some type systems (such as Swift) cannot determine a type's byte size without an execution context (e.g. types whose layout depends on runtime metadata). In those cases the debug info might still carry the static size of the value's box, which is enough if the value is a constant.

This patch adds a unit test that mocks up an analogous situation using TypeSystemClang.

Assisted-by: claude

>From 197229b75790a643014c04d6f0dd437c90544b03 Mon Sep 17 00:00:00 2001
From: Adrian Prantl <aprantl at apple.com>
Date: Mon, 18 May 2026 11:57:36 -0700
Subject: [PATCH] [LLDB] Support reading size of constant values from DWARF
 directly

Some type systems (such as Swift) cannot determine a type's byte size
without an execution context (e.g. types whose layout depends on
runtime metadata). In those cases the debug info might still carry the
static size of the value's box, which is enough if the value is a
constant.

This patch adds a unit test that mocks up an analogous situation using
TypeSystemClang.

Assisted-by: claude
---
 .../SymbolFile/DWARF/SymbolFileDWARF.cpp      |  52 +++++++--
 .../SymbolFile/DWARF/DWARFDIETest.cpp         | 107 ++++++++++++++++++
 2 files changed, 152 insertions(+), 7 deletions(-)

diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index aca36b45d69ca..841eb7d606714 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -3465,6 +3465,33 @@ VariableSP SymbolFileDWARF::ParseVariableDIECached(const SymbolContext &sc,
   return var_sp;
 }
 
+/// Walks transparent type wrappers following DW_AT_type and returns
+/// the first DW_AT_byte_size encountered along the chain.
+static std::optional<uint64_t> GetByteSizeFromTypeDIE(DWARFDIE die,
+                                                     unsigned max_depth = 64) {
+  // Bound the walk to guard against malformed/cyclic DWARF.
+  if (!die || !max_depth)
+    return std::nullopt;
+
+  if (std::optional<uint64_t> byte_size =
+          die.GetAttributeValueAsOptionalUnsigned(DW_AT_byte_size))
+    return byte_size;
+
+  switch (die.Tag()) {
+  case DW_TAG_const_type:
+  case DW_TAG_volatile_type:
+  case DW_TAG_restrict_type:
+  case DW_TAG_atomic_type:
+  case DW_TAG_typedef:
+    if (DWARFDIE next = die.GetAttributeValueAsReferenceDIE(DW_AT_type))
+      return GetByteSizeFromTypeDIE(next, max_depth - 1);
+    break;
+  default:
+    break;
+  }
+  return std::nullopt;
+}
+
 /// Creates a DWARFExpressionList from an DW_AT_location form_value.
 static DWARFExpressionList GetExprListFromAtLocation(DWARFFormValue form_value,
                                                      ModuleSP module,
@@ -3816,13 +3843,24 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc,
   bool use_type_size_for_value =
       location_is_const_value_data &&
       DWARFFormValue::IsDataForm(const_value_form.Form());
-  if (use_type_size_for_value && type_sp->GetType()) {
-    DWARFExpression *location = location_list.GetMutableExpressionAtAddress();
-    location->UpdateValue(
-        const_value_form.Unsigned(),
-        llvm::expectedToOptional(type_sp->GetType()->GetByteSize(nullptr))
-            .value_or(0),
-        die.GetCU()->GetAddressByteSize());
+  if (use_type_size_for_value) {
+    std::optional<uint64_t> byte_size;
+    if (Type *t = type_sp->GetType())
+      byte_size = llvm::expectedToOptional(t->GetByteSize(nullptr));
+
+    // Some TypeSystems (such as Swift) cannot determine a type's byte
+    // size without an execution context (e.g. types whose layout
+    // depends on runtime metadata). In those cases the debug info
+    // might still carry the static size of the value's box, which is
+    // enough if the value is a constant.
+    if (!byte_size)
+      byte_size = GetByteSizeFromTypeDIE(type_die_form.Reference());
+
+    if (byte_size) {
+      DWARFExpression *location = location_list.GetMutableExpressionAtAddress();
+      location->UpdateValue(const_value_form.Unsigned(), *byte_size,
+                            die.GetCU()->GetAddressByteSize());
+    }
   }
 
   return std::make_shared<Variable>(
diff --git a/lldb/unittests/SymbolFile/DWARF/DWARFDIETest.cpp b/lldb/unittests/SymbolFile/DWARF/DWARFDIETest.cpp
index e285ef24dad64..2611d105e286f 100644
--- a/lldb/unittests/SymbolFile/DWARF/DWARFDIETest.cpp
+++ b/lldb/unittests/SymbolFile/DWARF/DWARFDIETest.cpp
@@ -10,8 +10,15 @@
 #include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h"
 #include "Plugins/SymbolFile/DWARF/DWARFDeclContext.h"
 #include "TestingSupport/Symbol/YAMLModuleTester.h"
+#include "TestingSupport/TestUtilities.h"
+#include "lldb/Core/Debugger.h"
 #include "lldb/Core/dwarf.h"
+#include "lldb/Expression/DWARFExpression.h"
+#include "lldb/Expression/DWARFExpressionList.h"
+#include "lldb/Symbol/SymbolFile.h"
 #include "lldb/Symbol/Type.h"
+#include "lldb/Symbol/Variable.h"
+#include "lldb/Symbol/VariableList.h"
 #include "lldb/lldb-private-enumerations.h"
 #include "llvm/ADT/STLExtras.h"
 #include "gmock/gmock.h"
@@ -1092,3 +1099,103 @@ TEST(DWARFDIETest, TestGetAttributes_Worklist) {
 INSTANTIATE_TEST_SUITE_P(GetAttributeTests, GetAttributesTestFixture,
                          testing::Values(DW_AT_specification,
                                          DW_AT_abstract_origin));
+
+// Exercises fallback in SymbolFileDWARF::ParseVariableDIE (added for
+// Swift) that walks the type chain for DW_AT_byte_size when the
+// TypeSystem cannot determine the size of a variable's storage. The
+// test uses a Fortran DW_TAG_string_type, which TypeSystemClang
+// doesn't know about.  Type::GetByteSize() will fails but since
+// DW_AT_string_type has a DW_AT_byte_size, so we should still be able
+// to extract the constant value.
+TEST(DWARFDIETest, ParseVariableDIE_ConstValueByteSizeFromTypeChain) {
+  const char *yamldata = R"(
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_EXEC
+  Machine: EM_X86_64
+DWARF:
+  debug_abbrev:
+    - Table:
+        - Code:            0x1
+          Tag:             DW_TAG_compile_unit
+          Children:        DW_CHILDREN_yes
+          Attributes:
+            - Attribute:       DW_AT_language
+              Form:            DW_FORM_data2
+        - Code:            0x2
+          Tag:             DW_TAG_string_type
+          Children:        DW_CHILDREN_no
+          Attributes:
+            - Attribute:       DW_AT_byte_size
+              Form:            DW_FORM_data1
+        - Code:            0x3
+          Tag:             DW_TAG_const_type
+          Children:        DW_CHILDREN_no
+          Attributes:
+            - Attribute:       DW_AT_type
+              Form:            DW_FORM_ref4
+        - Code:            0x4
+          Tag:             DW_TAG_variable
+          Children:        DW_CHILDREN_no
+          Attributes:
+            - Attribute:       DW_AT_name
+              Form:            DW_FORM_string
+            - Attribute:       DW_AT_type
+              Form:            DW_FORM_ref4
+            - Attribute:       DW_AT_const_value
+              Form:            DW_FORM_data8
+  debug_info:
+    - Version:         4
+      AddrSize:        8
+      Entries:
+        - AbbrCode:        0x1
+          Values:
+            - Value:           0xC          # DW_LANG_C99
+        - AbbrCode:        0x2
+          Values:
+            - Value:           0x8          # DW_AT_byte_size
+        - AbbrCode:        0x3
+          Values:
+            - Value:           0xE          # -> string_type
+        - AbbrCode:        0x4
+          Values:
+            - CStr:            g
+            - Value:           0x10         # -> const_type
+            - Value:           0x1122334455667788  # DW_AT_const_value
+        - AbbrCode:        0x0
+)";
+
+  YAMLModuleTester t(yamldata);
+  ModuleSP module_sp = t.GetModule();
+  ASSERT_TRUE(module_sp);
+
+  // FindGlobalVariables uses the ManualDWARFIndex which needs the
+  // Debugger's thread pool.
+  std::call_once(TestUtilities::g_debugger_initialize_flag,
+                 []() { Debugger::Initialize(nullptr); });
+
+  VariableList vars;
+  module_sp->GetSymbolFile()->FindGlobalVariables(
+      ConstString("g"), CompilerDeclContext(), /*max_matches=*/1, vars);
+  ASSERT_EQ(vars.GetSize(), 1u);
+  VariableSP var_sp = vars.GetVariableAtIndex(0);
+  ASSERT_TRUE(var_sp);
+  EXPECT_TRUE(var_sp->GetLocationIsConstantValueData());
+
+  // The fallback should have laid out the const-value bytes using
+  // DW_AT_byte_size from the DW_TAG_string_type at the end of the
+  // type chain.
+  const DWARFExpression *expr =
+      var_sp->LocationExpressionList().GetExpressionAtAddress(
+          LLDB_INVALID_ADDRESS, 0);
+  ASSERT_NE(expr, nullptr);
+  EXPECT_TRUE(expr->IsValid());
+
+  DataExtractor data;
+  ASSERT_TRUE(expr->GetExpressionData(data));
+  EXPECT_EQ(data.GetByteSize(), 8u);
+  lldb::offset_t off = 0;
+  EXPECT_EQ(data.GetU64(&off), 0x1122334455667788u);
+}



More information about the lldb-commits mailing list