Author: Thrrreeee
Date: 2026-06-09T11:50:55+08:00
New Revision: a581124cd4b332d04ba1e7824066f41ae8a31b42

URL: 
https://github.com/llvm/llvm-project/commit/a581124cd4b332d04ba1e7824066f41ae8a31b42
DIFF: 
https://github.com/llvm/llvm-project/commit/a581124cd4b332d04ba1e7824066f41ae8a31b42.diff

LOG: [LLDB] Fix DW_OP_implicit_value GetOpcodeDataSize() error (#201344)

LLDB does not handle `DW_OP_implicit_value` right, causing a "cannot get
opcode data size for Unknown DW_OP constant" error when LLDB parses
location expressions containing this opcode.

`DW_OP_implicit_value` takes two operands: a ULEB128-encoded length
followed by a byte sequence of that length. The current
`GetOpcodeDataSize` implementation has no case for this opcode, only
skip. This prevents LLDB from correctly determining opcode boundaries
when scanning multi-operation location expressions.

>From DWARFv5
> The DW_OP_implicit_value operation specifies an immediate value using
two operands: an unsigned LEB128 length, followed by a sequence of bytes
of the given length that contain the value.

Although the evaluation path (`DWARFExpression::Evaluate`) handles this
opcode correctly and produces the right result, the validation/parsing
path emits a confusing error message to the user.

Added: 
    lldb/test/Shell/SymbolFile/DWARF/x86/DW_OP_impilict_value.s

Modified: 
    lldb/source/Expression/DWARFExpression.cpp
    lldb/unittests/Expression/DWARFExpressionTest.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/source/Expression/DWARFExpression.cpp 
b/lldb/source/Expression/DWARFExpression.cpp
index 106e3b4d59283..dd436e0c8afd9 100644
--- a/lldb/source/Expression/DWARFExpression.cpp
+++ b/lldb/source/Expression/DWARFExpression.cpp
@@ -414,7 +414,7 @@ GetOpcodeDataSize(const DataExtractor &data, const 
lldb::offset_t data_offset,
   case DW_OP_implicit_value: // 0x9e ULEB128 size followed by block of that 
size
                              // (DWARF4)
   {
-    uint64_t block_len = data.Skip_LEB128(&offset);
+    uint64_t block_len = data.GetULEB128(&offset);
     offset += block_len;
     return offset - data_offset;
   }

diff  --git a/lldb/test/Shell/SymbolFile/DWARF/x86/DW_OP_impilict_value.s 
b/lldb/test/Shell/SymbolFile/DWARF/x86/DW_OP_impilict_value.s
new file mode 100644
index 0000000000000..caa45e4131c51
--- /dev/null
+++ b/lldb/test/Shell/SymbolFile/DWARF/x86/DW_OP_impilict_value.s
@@ -0,0 +1,166 @@
+# Test that LLDB correctly handles DW_OP_implicit_value for scalar
+# and aggregate types.
+#
+# RUN: llvm-mc -filetype=obj -o %t -triple x86_64-pc-linux %s
+# RUN: %lldb %t \
+# RUN:   -o "target variable int_val" \
+# RUN:   -o "target variable point" \
+# RUN:   -o "target variable char_val" \
+# RUN:   -b 2>&1 | FileCheck %s
+
+# CHECK:      (lldb) target variable int_val
+# CHECK-NOT: error:
+# CHECK-NEXT: (int) int_val = 42
+
+# CHECK:      (lldb) target variable point
+# CHECK-NOT: error:
+# CHECK-NEXT: (Point) point = {
+# CHECK-NEXT:   x = 10
+# CHECK-NEXT:   y = 20
+# CHECK-NEXT: }
+
+# CHECK:      (lldb) target variable char_val
+# CHECK-NOT: error:
+# CHECK-NEXT: (char) char_val = 'A'
+
+        .section        .debug_abbrev,"",@progbits
+        .byte   1                       # Abbrev [1] DW_TAG_compile_unit
+        .byte   17                      # DW_TAG_compile_unit
+        .byte   1                       # DW_CHILDREN_yes
+        .byte   19                      # DW_AT_language
+        .byte   11                      # DW_FORM_data1
+        .byte   0
+        .byte   0
+
+        .byte   2                       # Abbrev [2] DW_TAG_variable
+        .byte   52                      # DW_TAG_variable
+        .byte   0                       # DW_CHILDREN_no
+        .byte   3                       # DW_AT_name
+        .byte   8                       # DW_FORM_string
+        .byte   73                      # DW_AT_type
+        .byte   19                      # DW_FORM_ref4
+        .byte   2                       # DW_AT_location
+        .byte   24                      # DW_FORM_exprloc
+        .byte   0
+        .byte   0
+
+        .byte   3                       # Abbrev [3] DW_TAG_base_type
+        .byte   36                      # DW_TAG_base_type
+        .byte   0                       # DW_CHILDREN_no
+        .byte   3                       # DW_AT_name
+        .byte   8                       # DW_FORM_string
+        .byte   62                      # DW_AT_encoding
+        .byte   11                      # DW_FORM_data1
+        .byte   11                      # DW_AT_byte_size
+        .byte   11                      # DW_FORM_data1
+        .byte   0
+        .byte   0
+
+        .byte   4                       # Abbrev [4] DW_TAG_structure_type
+        .byte   19                      # DW_TAG_structure_type
+        .byte   1                       # DW_CHILDREN_yes
+        .byte   3                       # DW_AT_name
+        .byte   8                       # DW_FORM_string
+        .byte   11                      # DW_AT_byte_size
+        .byte   11                      # DW_FORM_data1
+        .byte   0
+        .byte   0
+
+        .byte   5                       # Abbrev [5] DW_TAG_member
+        .byte   13                      # DW_TAG_member
+        .byte   0                       # DW_CHILDREN_no
+        .byte   3                       # DW_AT_name
+        .byte   8                       # DW_FORM_string
+        .byte   73                      # DW_AT_type
+        .byte   19                      # DW_FORM_ref4
+        .byte   56                      # DW_AT_data_member_location
+        .byte   11                      # DW_FORM_data1
+        .byte   0
+        .byte   0
+
+        .byte   0                       # End of abbrev table
+
+        .section        .debug_info,"",@progbits
+.Lcu_begin0:
+        .long   .Lcu_end0 - .Lcu_start0
+.Lcu_start0:
+        .short  5                       # DWARF version 5
+        .byte   1                       # DW_UT_compile
+        .byte   8                       # Address size
+        .long   .debug_abbrev
+
+        .byte   1                       # DW_TAG_compile_unit
+        .byte   12                      # DW_LANG_C99
+
+# ---- Base types ----
+.Lint_type:
+        .byte   3                       # DW_TAG_base_type
+        .asciz  "int"
+        .byte   5                       # DW_ATE_signed
+        .byte   4                       # 4 bytes
+
+.Lchar_type:
+        .byte   3                       # DW_TAG_base_type
+        .asciz  "char"
+        .byte   6                       # DW_ATE_signed_char
+        .byte   1                       # 1 byte
+
+.Llong_type:
+        .byte   3                       # DW_TAG_base_type
+        .asciz  "long"
+        .byte   5                       # DW_ATE_signed
+        .byte   8                       # 8 bytes
+
+.Lstruct_type:
+        .byte   4                       # DW_TAG_structure_type
+        .asciz  "Point"
+        .byte   8                       # byte_size = 8
+
+        .byte   5                       # DW_TAG_member: x
+        .asciz  "x"
+        .long   .Lint_type - .Lcu_begin0
+        .byte   0                       # offset 0
+
+        .byte   5                       # DW_TAG_member: y
+        .asciz  "y"
+        .long   .Lint_type - .Lcu_begin0
+        .byte   4                       # offset 4
+
+        .byte   0                       # end of struct children
+
+# int int_val = 42
+        .byte   2                       # DW_TAG_variable
+        .asciz  "int_val"
+        .long   .Lint_type - .Lcu_begin0
+        .byte   .Lint_loc_end - .Lint_loc_start
+.Lint_loc_start:
+        .byte   0x9e                    # DW_OP_implicit_value
+        .uleb128 4                      # length = 4 bytes
+        .long   42                      # value = 42
+.Lint_loc_end:
+
+# Point point = {10, 20}
+        .byte   2                       # DW_TAG_variable
+        .asciz  "point"
+        .long   .Lstruct_type - .Lcu_begin0
+        .byte   .Lpoint_loc_end - .Lpoint_loc_start
+.Lpoint_loc_start:
+        .byte   0x9e                    # DW_OP_implicit_value
+        .uleb128 8                      # length = 8 bytes (two ints)
+        .long   10                      # x = 10
+        .long   20                      # y = 20
+.Lpoint_loc_end:
+
+# char char_val = 'A'
+        .byte   2                       # DW_TAG_variable
+        .asciz  "char_val"
+        .long   .Lchar_type - .Lcu_begin0
+        .byte   .Lchar_loc_end - .Lchar_loc_start
+.Lchar_loc_start:
+        .byte   0x9e                    # DW_OP_implicit_value
+        .uleb128 1                      # length = 1 byte
+        .byte   0x41                    # value = 'A'
+.Lchar_loc_end:
+
+        .byte   0                       # End of compile unit children
+.Lcu_end0:

diff  --git a/lldb/unittests/Expression/DWARFExpressionTest.cpp 
b/lldb/unittests/Expression/DWARFExpressionTest.cpp
index 00ee6b13ad93c..c636f2837c506 100644
--- a/lldb/unittests/Expression/DWARFExpressionTest.cpp
+++ b/lldb/unittests/Expression/DWARFExpressionTest.cpp
@@ -623,6 +623,16 @@ TEST(DWARFExpression, DW_OP_implicit_value) {
   EXPECT_THAT_EXPECTED(
       Evaluate({DW_OP_implicit_value, bytes, 0x11, 0x22, 0x33, 0x44}),
       ExpectHostAddress({0x11, 0x22, 0x33, 0x44}));
+
+  // Verify that GetOpcodeDataSize correctly skips DW_OP_implicit_value
+  // (ULEB128 length + 1-byte data block)
+  std::vector<uint8_t> expr = {
+      DW_OP_implicit_value, 1, 0x11, DW_OP_addr, 0x10, 0x20, 0x30, 0x40};
+  DataExtractor extractor(expr.data(), expr.size(), lldb::eByteOrderLittle,
+                          /*addr_size*/ 4);
+  DWARFExpression dwarf_expr(extractor);
+  EXPECT_THAT_EXPECTED(dwarf_expr.GetLocation_DW_OP_addr(nullptr),
+                       llvm::HasValue(0x40302010u));
 }
 
 TEST(DWARFExpression, DW_OP_unknown) {


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

Reply via email to