https://github.com/firmiana402 updated 
https://github.com/llvm/llvm-project/pull/204119

>From 5d3376e5ea09768fc39451d17ada7424fe988885 Mon Sep 17 00:00:00 2001
From: firmiana402 <[email protected]>
Date: Tue, 16 Jun 2026 18:45:25 +0800
Subject: [PATCH 1/3] [lldb] Evaluate exprloc array bounds

---
 .../SymbolFile/DWARF/DWARFASTParser.cpp       |  78 ++++++--
 .../DWARF/x86/array-upper-bound-exprloc.s     | 180 ++++++++++++++++++
 2 files changed, 247 insertions(+), 11 deletions(-)
 create mode 100644 
lldb/test/Shell/SymbolFile/DWARF/x86/array-upper-bound-exprloc.s

diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.cpp 
b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.cpp
index a8eafc94215dc..fe67dadf1b072 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.cpp
@@ -9,10 +9,16 @@
 #include "DWARFASTParser.h"
 #include "DWARFAttribute.h"
 #include "DWARFDIE.h"
+#include "DWARFFormValue.h"
+#include "DWARFUnit.h"
 #include "SymbolFileDWARF.h"
 
+#include "lldb/Core/Value.h"
+#include "lldb/Expression/DWARFExpression.h"
+#include "lldb/Symbol/ObjectFile.h"
 #include "lldb/Symbol/SymbolFile.h"
 #include "lldb/Target/StackFrame.h"
+#include "lldb/Utility/DataExtractor.h"
 #include "lldb/ValueObject/ValueObject.h"
 #include <optional>
 
@@ -21,6 +27,49 @@ using namespace lldb_private;
 using namespace lldb_private::plugin::dwarf;
 using namespace llvm::dwarf;
 
+static std::optional<uint64_t>
+EvaluateUnsignedArrayProperty(const DWARFFormValue &form_value,
+                              const DWARFDIE &parent_die,
+                              const ExecutionContext *exe_ctx) {
+  // Array properties may be encoded directly as constants.
+  if (std::optional<uint64_t> value = form_value.getAsUnsignedConstant())
+    return value;
+  if (std::optional<int64_t> value = form_value.getAsSignedConstant())
+    if (*value >= 0)
+      return *value;
+
+  // Otherwise, evaluate expression blocks in the current execution context.
+  // Without a context there is no frame/register state to use for operations
+  // such as DW_OP_fbreg.
+  if (!DWARFFormValue::IsBlockForm(form_value.Form()) || !exe_ctx)
+    return std::nullopt;
+
+  DWARFUnit *unit = parent_die.GetCU();
+  SymbolFileDWARF *dwarf = parent_die.GetDWARF();
+  if (!unit || !dwarf || !dwarf->GetObjectFile())
+    return std::nullopt;
+
+  lldb::RegisterContextSP reg_ctx_sp;
+  if (lldb::StackFrameSP frame_sp = exe_ctx->GetFrameSP())
+    reg_ctx_sp = frame_sp->GetRegisterContext();
+
+  DataExtractor data(form_value.BlockData(), form_value.Unsigned(),
+                     unit->GetByteOrder(), unit->GetAddressByteSize());
+  ExecutionContext exe_ctx_copy(*exe_ctx);
+
+  // Evaluate the DWARF expression to obtain the dynamic property value.
+  llvm::Expected<Value> result = DWARFExpression::Evaluate(
+      &exe_ctx_copy, reg_ctx_sp.get(), dwarf->GetObjectFile()->GetModule(),
+      data, unit, eRegisterKindDWARF,
+      /*initial_value_ptr=*/nullptr, /*object_address_ptr=*/nullptr);
+  if (!result) {
+    llvm::consumeError(result.takeError());
+    return std::nullopt;
+  }
+
+  return result->GetScalar().ULongLong();
+}
+
 std::optional<SymbolFile::ArrayInfo>
 DWARFASTParser::ParseChildArrayInfo(const DWARFDIE &parent_die,
                                     const ExecutionContext *exe_ctx) {
@@ -38,9 +87,8 @@ DWARFASTParser::ParseChildArrayInfo(const DWARFDIE 
&parent_die,
       continue;
 
     std::optional<uint64_t> num_elements;
-    uint64_t lower_bound = 0;
-    uint64_t upper_bound = 0;
-    bool upper_bound_valid = false;
+    std::optional<uint64_t> lower_bound = 0;
+    std::optional<uint64_t> upper_bound;
     for (size_t i = 0; i < attributes.Size(); ++i) {
       const dw_attr_t attr = attributes.AttributeAtIndex(i);
       DWARFFormValue form_value;
@@ -65,24 +113,32 @@ DWARFASTParser::ParseChildArrayInfo(const DWARFDIE 
&parent_die,
                 }
               }
           } else
-            num_elements = form_value.Unsigned();
+            num_elements =
+                EvaluateUnsignedArrayProperty(form_value, parent_die, exe_ctx);
           break;
 
         case DW_AT_bit_stride:
-          array_info.bit_stride = form_value.Unsigned();
+          if (std::optional<uint64_t> bit_stride =
+                  EvaluateUnsignedArrayProperty(form_value, parent_die,
+                                                exe_ctx))
+            array_info.bit_stride = *bit_stride;
           break;
 
         case DW_AT_byte_stride:
-          array_info.byte_stride = form_value.Unsigned();
+          if (std::optional<uint64_t> byte_stride =
+                  EvaluateUnsignedArrayProperty(form_value, parent_die,
+                                                exe_ctx))
+            array_info.byte_stride = *byte_stride;
           break;
 
         case DW_AT_lower_bound:
-          lower_bound = form_value.Unsigned();
+          lower_bound =
+              EvaluateUnsignedArrayProperty(form_value, parent_die, exe_ctx);
           break;
 
         case DW_AT_upper_bound:
-          upper_bound_valid = true;
-          upper_bound = form_value.Unsigned();
+          upper_bound =
+              EvaluateUnsignedArrayProperty(form_value, parent_die, exe_ctx);
           break;
 
         default:
@@ -92,8 +148,8 @@ DWARFASTParser::ParseChildArrayInfo(const DWARFDIE 
&parent_die,
     }
 
     if (!num_elements || *num_elements == 0) {
-      if (upper_bound_valid && upper_bound >= lower_bound)
-        num_elements = upper_bound - lower_bound + 1;
+      if (lower_bound && upper_bound && *upper_bound >= *lower_bound)
+        num_elements = *upper_bound - *lower_bound + 1;
     }
 
     array_info.element_orders.push_back(num_elements);
diff --git a/lldb/test/Shell/SymbolFile/DWARF/x86/array-upper-bound-exprloc.s 
b/lldb/test/Shell/SymbolFile/DWARF/x86/array-upper-bound-exprloc.s
new file mode 100644
index 0000000000000..2582b3c89d72d
--- /dev/null
+++ b/lldb/test/Shell/SymbolFile/DWARF/x86/array-upper-bound-exprloc.s
@@ -0,0 +1,180 @@
+# Test that exprloc-valued subrange bounds are evaluated instead of being
+# treated as static constants.
+
+# REQUIRES: lld, native, target-x86_64, system-linux
+
+# RUN: llvm-mc -triple x86_64-unknown-linux-gnu %s -filetype=obj -o %t.o
+# RUN: ld.lld %t.o -o %t -e main
+# RUN: %lldb %t -b -o "breakpoint set -n after_init" -o run \
+# RUN:   -o "frame variable --show-all-children array" -o exit | FileCheck %s
+
+# CHECK-LABEL: frame variable --show-all-children array
+# CHECK: (unsigned int[]) array = ([0] = 1, [1] = 3, [2] = 170, [3] = 187, [4] 
= 204, [5] = 221)
+
+        .text
+        .globl          main
+        .type           main,@function
+main:
+.Lfunc_begin:
+        .cfi_startproc
+        pushq           %rbp
+        .cfi_def_cfa_offset 16
+        .cfi_offset     %rbp, -16
+        movq            %rsp, %rbp
+        .cfi_def_cfa_register %rbp
+        subq            $64, %rsp
+        movq            $5, -8(%rbp)
+        movl            $1, -48(%rbp)
+        movl            $3, -44(%rbp)
+        movl            $170, -40(%rbp)
+        movl            $187, -36(%rbp)
+        movl            $204, -32(%rbp)
+        movl            $221, -28(%rbp)
+        .globl          after_init
+after_init:
+        nop
+        xorl            %eax, %eax
+        addq            $64, %rsp
+        popq            %rbp
+        .cfi_def_cfa    %rsp, 8
+        retq
+.Lfunc_end:
+        .cfi_endproc
+        .size           main, .Lfunc_end-main
+
+        .section        .debug_info,"",@progbits
+.Lcu_begin:
+        .4byte          .Lcu_end-.Lcu_start
+.Lcu_start:
+        .2byte          4                       # DWARF version
+        .4byte          .Labbrev_begin
+        .byte           8                       # Address size
+
+        .uleb128        1                       # DW_TAG_compile_unit
+        .ascii          "exprloc-array.c\0"     # DW_AT_name
+        .ascii          "hand-written DWARF\0"  # DW_AT_producer
+        .byte           0x0c                    # DW_AT_language
+        .quad           .Lfunc_begin            # DW_AT_low_pc
+        .4byte          .Lfunc_end-.Lfunc_begin # DW_AT_high_pc
+
+        .uleb128        2                       # DW_TAG_subprogram
+        .ascii          "main\0"                # DW_AT_name
+        .quad           .Lfunc_begin            # DW_AT_low_pc
+        .4byte          .Lfunc_end-.Lfunc_begin # DW_AT_high_pc
+        .byte           .Lframe_base_end-.Lframe_base_begin # DW_AT_frame_base 
exprloc size
+.Lframe_base_begin:
+        .byte           0x56                    # DW_OP_reg6
+.Lframe_base_end:
+
+        .uleb128        3                       # DW_TAG_variable
+        .ascii          "array\0"               # DW_AT_name
+        .4byte          .Larray_type-.Lcu_begin # DW_AT_type
+        .uleb128        .Larray_loc_end-.Larray_loc_begin # DW_AT_location 
exprloc size
+.Larray_loc_begin:
+        .byte           0x91                    # DW_OP_fbreg
+        .sleb128        -48                     # offset
+.Larray_loc_end:
+
+.Lu32_type:
+        .uleb128        4                       # DW_TAG_base_type
+        .ascii          "unsigned int\0"        # DW_AT_name
+        .byte           4                       # DW_AT_byte_size
+        .byte           7                       # DW_ATE_unsigned
+
+.Larray_type:
+        .uleb128        5                       # DW_TAG_array_type
+        .4byte          .Lu32_type-.Lcu_begin   # DW_AT_type
+        .uleb128        6                       # DW_TAG_subrange_type
+        .4byte          .Lu32_type-.Lcu_begin   # DW_AT_type
+        .byte           0                       # DW_AT_lower_bound
+        .uleb128        .Lupper_bound_end-.Lupper_bound_begin # 
DW_AT_upper_bound exprloc size
+.Lupper_bound_begin:
+        .byte           0x91                    # DW_OP_fbreg
+        .sleb128        -8                      # offset
+        .byte           0x06                    # DW_OP_deref
+.Lupper_bound_end:
+        .byte           0                       # End of array type children
+
+        .byte           0                       # End of subprogram children
+        .byte           0                       # End of compile unit children
+.Lcu_end:
+
+        .section        .debug_abbrev,"",@progbits
+.Labbrev_begin:
+        .uleb128        1                       # Abbreviation code
+        .uleb128        0x11                    # DW_TAG_compile_unit
+        .byte           1                       # DW_CHILDREN_yes
+        .uleb128        0x03                    # DW_AT_name
+        .uleb128        0x08                    # DW_FORM_string
+        .uleb128        0x25                    # DW_AT_producer
+        .uleb128        0x08                    # DW_FORM_string
+        .uleb128        0x13                    # DW_AT_language
+        .uleb128        0x0b                    # DW_FORM_data1
+        .uleb128        0x11                    # DW_AT_low_pc
+        .uleb128        0x01                    # DW_FORM_addr
+        .uleb128        0x12                    # DW_AT_high_pc
+        .uleb128        0x06                    # DW_FORM_data4
+        .byte           0
+        .byte           0
+
+        .uleb128        2                       # Abbreviation code
+        .uleb128        0x2e                    # DW_TAG_subprogram
+        .byte           1                       # DW_CHILDREN_yes
+        .uleb128        0x03                    # DW_AT_name
+        .uleb128        0x08                    # DW_FORM_string
+        .uleb128        0x11                    # DW_AT_low_pc
+        .uleb128        0x01                    # DW_FORM_addr
+        .uleb128        0x12                    # DW_AT_high_pc
+        .uleb128        0x06                    # DW_FORM_data4
+        .uleb128        0x40                    # DW_AT_frame_base
+        .uleb128        0x18                    # DW_FORM_exprloc
+        .byte           0
+        .byte           0
+
+        .uleb128        3                       # Abbreviation code
+        .uleb128        0x34                    # DW_TAG_variable
+        .byte           0                       # DW_CHILDREN_no
+        .uleb128        0x03                    # DW_AT_name
+        .uleb128        0x08                    # DW_FORM_string
+        .uleb128        0x49                    # DW_AT_type
+        .uleb128        0x13                    # DW_FORM_ref4
+        .uleb128        0x02                    # DW_AT_location
+        .uleb128        0x18                    # DW_FORM_exprloc
+        .byte           0
+        .byte           0
+
+        .uleb128        4                       # Abbreviation code
+        .uleb128        0x24                    # DW_TAG_base_type
+        .byte           0                       # DW_CHILDREN_no
+        .uleb128        0x03                    # DW_AT_name
+        .uleb128        0x08                    # DW_FORM_string
+        .uleb128        0x0b                    # DW_AT_byte_size
+        .uleb128        0x0b                    # DW_FORM_data1
+        .uleb128        0x3e                    # DW_AT_encoding
+        .uleb128        0x0b                    # DW_FORM_data1
+        .byte           0
+        .byte           0
+
+        .uleb128        5                       # Abbreviation code
+        .uleb128        0x01                    # DW_TAG_array_type
+        .byte           1                       # DW_CHILDREN_yes
+        .uleb128        0x49                    # DW_AT_type
+        .uleb128        0x13                    # DW_FORM_ref4
+        .byte           0
+        .byte           0
+
+        .uleb128        6                       # Abbreviation code
+        .uleb128        0x21                    # DW_TAG_subrange_type
+        .byte           0                       # DW_CHILDREN_no
+        .uleb128        0x49                    # DW_AT_type
+        .uleb128        0x13                    # DW_FORM_ref4
+        .uleb128        0x22                    # DW_AT_lower_bound
+        .uleb128        0x0b                    # DW_FORM_data1
+        .uleb128        0x2f                    # DW_AT_upper_bound
+        .uleb128        0x18                    # DW_FORM_exprloc
+        .byte           0
+        .byte           0
+
+        .byte           0
+
+        .section        .note.GNU-stack,"",@progbits

>From 0455be6889445db0d4427f92cfec99ebafbfa8e6 Mon Sep 17 00:00:00 2001
From: firmiana402 <[email protected]>
Date: Fri, 10 Jul 2026 00:53:45 +0800
Subject: [PATCH 2/3] [lldb] Refine array property evaluation

---
 .../SymbolFile/DWARF/DWARFASTParser.cpp       | 91 ++++++++++---------
 .../DWARF/DWARFASTParserClangTests.cpp        | 80 ++++++++++++++++
 2 files changed, 128 insertions(+), 43 deletions(-)

diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.cpp 
b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.cpp
index fe67dadf1b072..466f7b9241593 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.cpp
@@ -11,6 +11,7 @@
 #include "DWARFDIE.h"
 #include "DWARFFormValue.h"
 #include "DWARFUnit.h"
+#include "LogChannelDWARF.h"
 #include "SymbolFileDWARF.h"
 
 #include "lldb/Core/Value.h"
@@ -27,47 +28,51 @@ using namespace lldb_private;
 using namespace lldb_private::plugin::dwarf;
 using namespace llvm::dwarf;
 
+// Array properties can be encoded directly as constants, or as DWARF
+// expression blocks whose values need to be evaluated in an execution context.
 static std::optional<uint64_t>
-EvaluateUnsignedArrayProperty(const DWARFFormValue &form_value,
-                              const DWARFDIE &parent_die,
-                              const ExecutionContext *exe_ctx) {
-  // Array properties may be encoded directly as constants.
+EvaluateArrayPropertyAsUnsigned(const DWARFFormValue &form_value,
+                                const DWARFDIE &parent_die,
+                                const ExecutionContext *exe_ctx) {
+  if (DWARFFormValue::IsBlockForm(form_value.Form())) {
+    // Block-form values carry their byte length as the stored unsigned value.
+    // Evaluate the block instead of treating that length as the property 
value.
+    if (!exe_ctx)
+      return std::nullopt;
+
+    DWARFUnit *unit = parent_die.GetCU();
+    SymbolFileDWARF *dwarf = parent_die.GetDWARF();
+    if (!unit || !dwarf || !dwarf->GetObjectFile())
+      return std::nullopt;
+
+    lldb::RegisterContextSP reg_ctx_sp;
+    if (lldb::StackFrameSP frame_sp = exe_ctx->GetFrameSP())
+      reg_ctx_sp = frame_sp->GetRegisterContext();
+
+    DataExtractor data(form_value.BlockData(), form_value.Unsigned(),
+                       unit->GetByteOrder(), unit->GetAddressByteSize());
+    ExecutionContext exe_ctx_copy(*exe_ctx);
+
+    // Evaluate the DWARF expression to obtain the dynamic property value.
+    llvm::Expected<Value> result = DWARFExpression::Evaluate(
+        &exe_ctx_copy, reg_ctx_sp.get(), dwarf->GetObjectFile()->GetModule(),
+        data, unit, eRegisterKindDWARF,
+        /*initial_value_ptr=*/nullptr, /*object_address_ptr=*/nullptr);
+    if (!result) {
+      LLDB_LOG_ERROR(GetLog(DWARFLog::DebugInfo), result.takeError(),
+                     "failed to evaluate array property expression: {0}");
+      return std::nullopt;
+    }
+
+    return result->GetScalar().ULongLong();
+  }
+
   if (std::optional<uint64_t> value = form_value.getAsUnsignedConstant())
     return value;
   if (std::optional<int64_t> value = form_value.getAsSignedConstant())
     if (*value >= 0)
       return *value;
-
-  // Otherwise, evaluate expression blocks in the current execution context.
-  // Without a context there is no frame/register state to use for operations
-  // such as DW_OP_fbreg.
-  if (!DWARFFormValue::IsBlockForm(form_value.Form()) || !exe_ctx)
-    return std::nullopt;
-
-  DWARFUnit *unit = parent_die.GetCU();
-  SymbolFileDWARF *dwarf = parent_die.GetDWARF();
-  if (!unit || !dwarf || !dwarf->GetObjectFile())
-    return std::nullopt;
-
-  lldb::RegisterContextSP reg_ctx_sp;
-  if (lldb::StackFrameSP frame_sp = exe_ctx->GetFrameSP())
-    reg_ctx_sp = frame_sp->GetRegisterContext();
-
-  DataExtractor data(form_value.BlockData(), form_value.Unsigned(),
-                     unit->GetByteOrder(), unit->GetAddressByteSize());
-  ExecutionContext exe_ctx_copy(*exe_ctx);
-
-  // Evaluate the DWARF expression to obtain the dynamic property value.
-  llvm::Expected<Value> result = DWARFExpression::Evaluate(
-      &exe_ctx_copy, reg_ctx_sp.get(), dwarf->GetObjectFile()->GetModule(),
-      data, unit, eRegisterKindDWARF,
-      /*initial_value_ptr=*/nullptr, /*object_address_ptr=*/nullptr);
-  if (!result) {
-    llvm::consumeError(result.takeError());
-    return std::nullopt;
-  }
-
-  return result->GetScalar().ULongLong();
+  return std::nullopt;
 }
 
 std::optional<SymbolFile::ArrayInfo>
@@ -113,32 +118,32 @@ DWARFASTParser::ParseChildArrayInfo(const DWARFDIE 
&parent_die,
                 }
               }
           } else
-            num_elements =
-                EvaluateUnsignedArrayProperty(form_value, parent_die, exe_ctx);
+            num_elements = EvaluateArrayPropertyAsUnsigned(form_value,
+                                                           parent_die, 
exe_ctx);
           break;
 
         case DW_AT_bit_stride:
           if (std::optional<uint64_t> bit_stride =
-                  EvaluateUnsignedArrayProperty(form_value, parent_die,
-                                                exe_ctx))
+                  EvaluateArrayPropertyAsUnsigned(form_value, parent_die,
+                                                  exe_ctx))
             array_info.bit_stride = *bit_stride;
           break;
 
         case DW_AT_byte_stride:
           if (std::optional<uint64_t> byte_stride =
-                  EvaluateUnsignedArrayProperty(form_value, parent_die,
-                                                exe_ctx))
+                  EvaluateArrayPropertyAsUnsigned(form_value, parent_die,
+                                                  exe_ctx))
             array_info.byte_stride = *byte_stride;
           break;
 
         case DW_AT_lower_bound:
           lower_bound =
-              EvaluateUnsignedArrayProperty(form_value, parent_die, exe_ctx);
+              EvaluateArrayPropertyAsUnsigned(form_value, parent_die, exe_ctx);
           break;
 
         case DW_AT_upper_bound:
           upper_bound =
-              EvaluateUnsignedArrayProperty(form_value, parent_die, exe_ctx);
+              EvaluateArrayPropertyAsUnsigned(form_value, parent_die, exe_ctx);
           break;
 
         default:
diff --git a/lldb/unittests/SymbolFile/DWARF/DWARFASTParserClangTests.cpp 
b/lldb/unittests/SymbolFile/DWARF/DWARFASTParserClangTests.cpp
index a95d6ecfab790..951d30cf3b7e1 100644
--- a/lldb/unittests/SymbolFile/DWARF/DWARFASTParserClangTests.cpp
+++ b/lldb/unittests/SymbolFile/DWARF/DWARFASTParserClangTests.cpp
@@ -15,6 +15,7 @@
 #include "lldb/Core/Debugger.h"
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
+#include <optional>
 
 using namespace lldb;
 using namespace lldb_private;
@@ -174,6 +175,85 @@ TEST_F(DWARFASTParserClangTests,
               testing::UnorderedElementsAre(decl_ctxs[0], decl_ctxs[3]));
 }
 
+TEST_F(DWARFASTParserClangTests, ParseChildArrayInfoStaticProperties) {
+  const char *yamldata = R"(
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_EXEC
+  Machine: EM_386
+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_array_type
+          Children:        DW_CHILDREN_yes
+        - Code:            0x00000003
+          Tag:             DW_TAG_subrange_type
+          Children:        DW_CHILDREN_no
+          Attributes:
+            - Attribute:       DW_AT_lower_bound
+              Form:            DW_FORM_sdata
+            - Attribute:       DW_AT_upper_bound
+              Form:            DW_FORM_sdata
+            - Attribute:       DW_AT_byte_stride
+              Form:            DW_FORM_data1
+            - Attribute:       DW_AT_bit_stride
+              Form:            DW_FORM_data1
+        - Code:            0x00000004
+          Tag:             DW_TAG_subrange_type
+          Children:        DW_CHILDREN_no
+          Attributes:
+            - Attribute:       DW_AT_count
+              Form:            DW_FORM_data1
+  debug_info:
+    - Version:         4
+      AddrSize:        8
+      Entries:
+        - AbbrCode:        0x00000001
+          Values:
+            - Value:           0x000000000000000C
+        - AbbrCode:        0x00000002
+        - AbbrCode:        0x00000003
+          Values:
+            - Value:           0x0000000000000002
+            - Value:           0x0000000000000005
+            - Value:           0x0000000000000004
+            - Value:           0x0000000000000020
+        - AbbrCode:        0x00000004
+          Values:
+            - Value:           0x0000000000000003
+        - AbbrCode:        0x00000000
+        - AbbrCode:        0x00000000
+)";
+
+  YAMLModuleTester t(yamldata);
+  DWARFUnit *unit = t.GetDwarfUnit();
+  ASSERT_NE(unit, nullptr);
+
+  DWARFDIE array_die = unit->DIE().GetFirstChild();
+  ASSERT_TRUE(array_die.IsValid());
+
+  std::optional<SymbolFile::ArrayInfo> array_info =
+      DWARFASTParser::ParseChildArrayInfo(array_die);
+  ASSERT_TRUE(array_info);
+
+  ASSERT_EQ(array_info->element_orders.size(), 2u);
+  ASSERT_TRUE(array_info->element_orders[0]);
+  EXPECT_EQ(*array_info->element_orders[0], 4u);
+  ASSERT_TRUE(array_info->element_orders[1]);
+  EXPECT_EQ(*array_info->element_orders[1], 3u);
+  EXPECT_EQ(array_info->byte_stride, 4u);
+  EXPECT_EQ(array_info->bit_stride, 32u);
+}
+
 TEST_F(DWARFASTParserClangTests, TestCallingConventionParsing) {
   // Tests parsing DW_AT_calling_convention values.
 

>From 14cb19f2454519226062679a557ada3ca797b10e Mon Sep 17 00:00:00 2001
From: firmiana402 <[email protected]>
Date: Fri, 10 Jul 2026 14:00:20 +0800
Subject: [PATCH 3/3] [lldb] Evaluate array properties with language lower
 bounds

Use llvm::dwarf::LanguageLowerBound when DW_AT_lower_bound is omitted instead 
of assuming all languages default array lower bounds to zero. This preserves 
C-like behavior while handling languages such as Fortran whose default lower 
bound is one.

Also return targeted errors from array property evaluation and keep coverage 
for static array properties.
---
 .../SymbolFile/DWARF/DWARFASTParser.cpp       | 77 +++++++++++++------
 .../DWARF/DWARFASTParserClangTests.cpp        | 15 +++-
 2 files changed, 66 insertions(+), 26 deletions(-)

diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.cpp 
b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.cpp
index 466f7b9241593..70b0a880f49db 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.cpp
@@ -21,6 +21,10 @@
 #include "lldb/Target/StackFrame.h"
 #include "lldb/Utility/DataExtractor.h"
 #include "lldb/ValueObject/ValueObject.h"
+
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/Support/Error.h"
+
 #include <optional>
 
 using namespace lldb;
@@ -28,9 +32,9 @@ using namespace lldb_private;
 using namespace lldb_private::plugin::dwarf;
 using namespace llvm::dwarf;
 
-// Array properties can be encoded directly as constants, or as DWARF
-// expression blocks whose values need to be evaluated in an execution context.
-static std::optional<uint64_t>
+/// Array properties can be encoded directly as constants, or as DWARF
+/// expression blocks whose values need to be evaluated in an execution 
context.
+static llvm::Expected<uint64_t>
 EvaluateArrayPropertyAsUnsigned(const DWARFFormValue &form_value,
                                 const DWARFDIE &parent_die,
                                 const ExecutionContext *exe_ctx) {
@@ -38,12 +42,15 @@ EvaluateArrayPropertyAsUnsigned(const DWARFFormValue 
&form_value,
     // Block-form values carry their byte length as the stored unsigned value.
     // Evaluate the block instead of treating that length as the property 
value.
     if (!exe_ctx)
-      return std::nullopt;
+      return llvm::createStringError(
+          "cannot evaluate array property expression without an execution "
+          "context");
 
     DWARFUnit *unit = parent_die.GetCU();
     SymbolFileDWARF *dwarf = parent_die.GetDWARF();
     if (!unit || !dwarf || !dwarf->GetObjectFile())
-      return std::nullopt;
+      return llvm::createStringError(
+          "cannot evaluate array property expression without DWARF context");
 
     lldb::RegisterContextSP reg_ctx_sp;
     if (lldb::StackFrameSP frame_sp = exe_ctx->GetFrameSP())
@@ -58,21 +65,35 @@ EvaluateArrayPropertyAsUnsigned(const DWARFFormValue 
&form_value,
         &exe_ctx_copy, reg_ctx_sp.get(), dwarf->GetObjectFile()->GetModule(),
         data, unit, eRegisterKindDWARF,
         /*initial_value_ptr=*/nullptr, /*object_address_ptr=*/nullptr);
-    if (!result) {
-      LLDB_LOG_ERROR(GetLog(DWARFLog::DebugInfo), result.takeError(),
-                     "failed to evaluate array property expression: {0}");
-      return std::nullopt;
-    }
+    if (!result)
+      return result.takeError();
 
     return result->GetScalar().ULongLong();
   }
 
   if (std::optional<uint64_t> value = form_value.getAsUnsignedConstant())
-    return value;
-  if (std::optional<int64_t> value = form_value.getAsSignedConstant())
+    return *value;
+  if (std::optional<int64_t> value = form_value.getAsSignedConstant()) {
     if (*value >= 0)
       return *value;
-  return std::nullopt;
+    return llvm::createStringError("array property value is negative: %lld",
+                                   static_cast<long long>(*value));
+  }
+  return llvm::createStringError("unsupported array property form");
+}
+
+static std::optional<uint64_t>
+GetDefaultArrayLowerBound(const DWARFDIE &parent_die) {
+  DWARFUnit *unit = parent_die.GetCU();
+  if (!unit)
+    return std::nullopt;
+
+  std::optional<unsigned> lower_bound = LanguageLowerBound(
+      static_cast<llvm::dwarf::SourceLanguage>(unit->GetDWARFLanguageType()));
+  if (!lower_bound)
+    return std::nullopt;
+
+  return *lower_bound;
 }
 
 std::optional<SymbolFile::ArrayInfo>
@@ -92,8 +113,21 @@ DWARFASTParser::ParseChildArrayInfo(const DWARFDIE 
&parent_die,
       continue;
 
     std::optional<uint64_t> num_elements;
-    std::optional<uint64_t> lower_bound = 0;
+    std::optional<uint64_t> lower_bound = 
GetDefaultArrayLowerBound(parent_die);
     std::optional<uint64_t> upper_bound;
+
+    auto evaluate_array_property =
+        [&](const DWARFFormValue &form_value) -> std::optional<uint64_t> {
+      llvm::Expected<uint64_t> value =
+          EvaluateArrayPropertyAsUnsigned(form_value, parent_die, exe_ctx);
+      if (!value) {
+        LLDB_LOG_ERROR(GetLog(DWARFLog::DebugInfo), value.takeError(),
+                       "failed to evaluate array property: {0}");
+        return std::nullopt;
+      }
+      return value.get();
+    };
+
     for (size_t i = 0; i < attributes.Size(); ++i) {
       const dw_attr_t attr = attributes.AttributeAtIndex(i);
       DWARFFormValue form_value;
@@ -118,32 +152,27 @@ DWARFASTParser::ParseChildArrayInfo(const DWARFDIE 
&parent_die,
                 }
               }
           } else
-            num_elements = EvaluateArrayPropertyAsUnsigned(form_value,
-                                                           parent_die, 
exe_ctx);
+            num_elements = evaluate_array_property(form_value);
           break;
 
         case DW_AT_bit_stride:
           if (std::optional<uint64_t> bit_stride =
-                  EvaluateArrayPropertyAsUnsigned(form_value, parent_die,
-                                                  exe_ctx))
+                  evaluate_array_property(form_value))
             array_info.bit_stride = *bit_stride;
           break;
 
         case DW_AT_byte_stride:
           if (std::optional<uint64_t> byte_stride =
-                  EvaluateArrayPropertyAsUnsigned(form_value, parent_die,
-                                                  exe_ctx))
+                  evaluate_array_property(form_value))
             array_info.byte_stride = *byte_stride;
           break;
 
         case DW_AT_lower_bound:
-          lower_bound =
-              EvaluateArrayPropertyAsUnsigned(form_value, parent_die, exe_ctx);
+          lower_bound = evaluate_array_property(form_value);
           break;
 
         case DW_AT_upper_bound:
-          upper_bound =
-              EvaluateArrayPropertyAsUnsigned(form_value, parent_die, exe_ctx);
+          upper_bound = evaluate_array_property(form_value);
           break;
 
         default:
diff --git a/lldb/unittests/SymbolFile/DWARF/DWARFASTParserClangTests.cpp 
b/lldb/unittests/SymbolFile/DWARF/DWARFASTParserClangTests.cpp
index 951d30cf3b7e1..51112930ebe21 100644
--- a/lldb/unittests/SymbolFile/DWARF/DWARFASTParserClangTests.cpp
+++ b/lldb/unittests/SymbolFile/DWARF/DWARFASTParserClangTests.cpp
@@ -213,13 +213,19 @@ TEST_F(DWARFASTParserClangTests, 
ParseChildArrayInfoStaticProperties) {
           Attributes:
             - Attribute:       DW_AT_count
               Form:            DW_FORM_data1
+        - Code:            0x00000005
+          Tag:             DW_TAG_subrange_type
+          Children:        DW_CHILDREN_no
+          Attributes:
+            - Attribute:       DW_AT_upper_bound
+              Form:            DW_FORM_data1
   debug_info:
     - Version:         4
       AddrSize:        8
       Entries:
         - AbbrCode:        0x00000001
           Values:
-            - Value:           0x000000000000000C
+            - Value:           0x0000000000000008
         - AbbrCode:        0x00000002
         - AbbrCode:        0x00000003
           Values:
@@ -230,6 +236,9 @@ TEST_F(DWARFASTParserClangTests, 
ParseChildArrayInfoStaticProperties) {
         - AbbrCode:        0x00000004
           Values:
             - Value:           0x0000000000000003
+        - AbbrCode:        0x00000005
+          Values:
+            - Value:           0x0000000000000005
         - AbbrCode:        0x00000000
         - AbbrCode:        0x00000000
 )";
@@ -245,11 +254,13 @@ TEST_F(DWARFASTParserClangTests, 
ParseChildArrayInfoStaticProperties) {
       DWARFASTParser::ParseChildArrayInfo(array_die);
   ASSERT_TRUE(array_info);
 
-  ASSERT_EQ(array_info->element_orders.size(), 2u);
+  ASSERT_EQ(array_info->element_orders.size(), 3u);
   ASSERT_TRUE(array_info->element_orders[0]);
   EXPECT_EQ(*array_info->element_orders[0], 4u);
   ASSERT_TRUE(array_info->element_orders[1]);
   EXPECT_EQ(*array_info->element_orders[1], 3u);
+  ASSERT_TRUE(array_info->element_orders[2]);
+  EXPECT_EQ(*array_info->element_orders[2], 5u);
   EXPECT_EQ(array_info->byte_stride, 4u);
   EXPECT_EQ(array_info->bit_stride, 32u);
 }

_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to