Author: Jonas Devlieghere
Date: 2026-06-26T08:53:12-07:00
New Revision: 4a924c0b839a5019b4ff7356fd732c2dbcd12fd2

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

LOG: [lldb] Fix reading global variables on WebAssembly (#205913)

Reading a global or static variable on a Wasm target produced a wrong
value (or none at all). Two Wasm-only bugs combined to break it, both of
which need to be fixed to support `target variable` / `frame var`.

1. DWARFExpression::Evaluate special-cased DW_OP_addr and
DW_OP_addrx/DW_OP_GNU_addr_index on Wasm to push a LoadAddress, based on
the theory that "Wasm file sections aren't mapped into memory". But a
DW_OP_addr operand denotes a location in the module's address space,
i.e. a file address like on every other target. Forcing a load address
breaks the static (no-process) read path, since a file section cannot be
read as a load address.

2. ObjectFileWasm::SetLoadAddress mapped every section with
`load_address | GetFileOffset()`. For an active data segment that
Object-tags the address (top bit = code space) and uses the file offset
instead of the segment's linear-memory address, so a live read of a data
global resolved to a garbage address in the wrong space.

Address (1) by dropping the incorrect special casing. Address (2) by
mapping data sections into the Memory space at their linear VM address
while preserving the module id. Code and other sections keep their
Object-space module-offset addressing.

Added: 
    lldb/test/Shell/ObjectFile/wasm/wasm-data-section-load-address.yaml

Modified: 
    lldb/source/Expression/DWARFExpression.cpp
    lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp
    lldb/unittests/Expression/DWARFExpressionTest.cpp
    llvm/docs/ReleaseNotes.md

Removed: 
    


################################################################################
diff  --git a/lldb/source/Expression/DWARFExpression.cpp 
b/lldb/source/Expression/DWARFExpression.cpp
index 3e650c8d6afb2..5a3c99caeb1bb 100644
--- a/lldb/source/Expression/DWARFExpression.cpp
+++ b/lldb/source/Expression/DWARFExpression.cpp
@@ -1359,14 +1359,7 @@ llvm::Expected<Value> DWARFExpression::Evaluate(
     switch (opcode) {
     case DW_OP_addr:
       stack.push_back(Scalar(op->getRawOperand(0)));
-      if (eval_ctx.target && eval_ctx.target->GetArchitecture().GetCore() ==
-                                 ArchSpec::eCore_wasm32) {
-        // wasm file sections aren't mapped into memory, therefore addresses 
can
-        // never point into a file section and are always LoadAddresses.
-        stack.back().SetValueType(Value::ValueType::LoadAddress);
-      } else {
-        stack.back().SetValueType(Value::ValueType::FileAddress);
-      }
+      stack.back().SetValueType(Value::ValueType::FileAddress);
       break;
 
     case DW_OP_deref: {
@@ -1902,14 +1895,7 @@ llvm::Expected<Value> DWARFExpression::Evaluate(
       lldb::addr_t value =
           eval_ctx.dwarf_cu->ReadAddressFromDebugAddrSection(index);
       stack.push_back(Scalar(value));
-      if (eval_ctx.target && eval_ctx.target->GetArchitecture().GetCore() ==
-                                 ArchSpec::eCore_wasm32) {
-        // wasm file sections aren't mapped into memory, therefore addresses 
can
-        // never point into a file section and are always LoadAddresses.
-        stack.back().SetValueType(Value::ValueType::LoadAddress);
-      } else {
-        stack.back().SetValueType(Value::ValueType::FileAddress);
-      }
+      stack.back().SetValueType(Value::ValueType::FileAddress);
     } break;
 
     case DW_OP_GNU_const_index: {

diff  --git a/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp 
b/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp
index 205e549b66a22..9895044cd29bc 100644
--- a/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp
+++ b/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp
@@ -803,10 +803,22 @@ bool ObjectFileWasm::SetLoadAddress(Target &target, 
lldb::addr_t load_address,
   const size_t num_sections = section_list->GetSize();
   for (size_t sect_idx = 0; sect_idx < num_sections; ++sect_idx) {
     SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx));
-    if (target.SetSectionLoadAddress(
-            section_sp, load_address | section_sp->GetFileOffset())) {
-      ++num_loaded_sections;
+    lldb::addr_t section_load_addr;
+    if (section_sp->GetType() == eSectionTypeData) {
+      // Active data segments are mapped into the module's linear memory at
+      // their virtual address. Linear memory is a separate address space from
+      // code (the top two bits of the 64-bit address encode the space: 0 for
+      // Memory, 1 for Object/code), so place the segment at its linear VM
+      // address in the Memory space while preserving the module id.
+      section_load_addr = (load_address & ~(uint64_t(0b11) << 62)) |
+                          section_sp->GetFileAddress();
+    } else {
+      // Code (and other) sections are addressed by their offset within the
+      // module in the Object address space.
+      section_load_addr = load_address | section_sp->GetFileOffset();
     }
+    if (target.SetSectionLoadAddress(section_sp, section_load_addr))
+      ++num_loaded_sections;
   }
 
   return num_loaded_sections > 0;

diff  --git 
a/lldb/test/Shell/ObjectFile/wasm/wasm-data-section-load-address.yaml 
b/lldb/test/Shell/ObjectFile/wasm/wasm-data-section-load-address.yaml
new file mode 100644
index 0000000000000..0681344de2cb7
--- /dev/null
+++ b/lldb/test/Shell/ObjectFile/wasm/wasm-data-section-load-address.yaml
@@ -0,0 +1,66 @@
+# REQUIRES: webassembly
+
+# An active data segment is mapped into the module's linear memory at the
+# virtual address given by its init expression. Linear memory is a separate
+# address space from code: a wasm 64-bit address encodes the space in its top
+# two bits (0 = Memory, 1 = Object/code). Code is addressed in the Object space
+# by its module offset; data must be addressed in the Memory space at its
+# linear address.
+#
+# Here the data segment's init expr places it at linear address 0x10000.
+
+# RUN: yaml2obj %s -o %t.wasm
+# RUN: %lldb %t.wasm \
+# RUN:   -o "target modules dump sections" \
+# RUN:   -o "target modules load --file %t.wasm --slide 0x4000000000000000" \
+# RUN:   -o "target modules dump sections" \
+# RUN:   -o exit 2>&1 | FileCheck %s
+
+# Before loading, sections carry their file addresses. The data segment's file
+# address is its linear-memory address (from the init expr), not its offset in
+# the wasm file.
+# CHECK-LABEL: File Address
+# CHECK:       code  {{.*}}[0x0000000000000000-
+# CHECK:       data  {{.*}}[0x0000000000010000-0x0000000000010004)
+
+# After loading the module in the Object space (top bit set), the code section
+# is placed in the Object space at its module offset, while the data segment is
+# placed in the Memory space at its linear address. It is *not* Object-tagged.
+# CHECK-LABEL: Load Address
+# CHECK:       code  {{.*}}[0x40000000{{[0-9a-f]+}}-
+# CHECK:       data  {{.*}}[0x0000000000010000-0x0000000000010004)
+
+--- !WASM
+FileHeader:
+  Version: 0x1
+Sections:
+  - Type: TYPE
+    Signatures:
+      - Index: 0
+        ParamTypes: []
+        ReturnTypes:
+          - I32
+  - Type: FUNCTION
+    FunctionTypes: [ 0 ]
+  - Type: MEMORY
+    Memories:
+      - Minimum: 0x2
+  - Type: CODE
+    Functions:
+      - Index: 0
+        Locals: []
+        Body: 412A0F0B
+  - Type: DATA
+    Segments:
+      - SectionOffset:   6
+        InitFlags:       0
+        Offset:
+          Opcode:          I32_CONST
+          Value:           65536
+        Content:          'DEADBEEF'
+  - Type: CUSTOM
+    Name: name
+    FunctionNames:
+      - Index: 0
+        Name: get_42
+...

diff  --git a/lldb/unittests/Expression/DWARFExpressionTest.cpp 
b/lldb/unittests/Expression/DWARFExpressionTest.cpp
index 5e8ad3d348c5d..305c4af2582db 100644
--- a/lldb/unittests/Expression/DWARFExpressionTest.cpp
+++ b/lldb/unittests/Expression/DWARFExpressionTest.cpp
@@ -1195,10 +1195,11 @@ TEST_F(DWARFExpressionMockProcessTest, WASM_DW_OP_addr) 
{
   ASSERT_TRUE(CreateTestContext(&test_ctx, "wasm32-unknown-unknown-wasm"));
 
   ExecutionContext exe_ctx(test_ctx.target_sp, false);
-  // DW_OP_addr takes a single operand of address size width:
+  // DW_OP_addr takes a single operand of address size width. It denotes a
+  // location in the module's address space, i.e. a file address.
   EXPECT_THAT_EXPECTED(
       Evaluate({DW_OP_addr, 0x40, 0x0, 0x0, 0x0}, {}, {}, &exe_ctx),
-      ExpectLoadAddress(0x40));
+      ExpectFileAddress(0x40));
 }
 
 TEST_F(DWARFExpressionMockProcessTest, WASM_DW_OP_addr_index) {
@@ -1271,11 +1272,11 @@ TEST_F(DWARFExpressionMockProcessTest, 
WASM_DW_OP_addr_index) {
   DWARFExpression expr(extractor);
 
   llvm::Expected<Value> result = evaluate(expr);
-  EXPECT_THAT_EXPECTED(result, ExpectLoadAddress(0x5678u));
+  EXPECT_THAT_EXPECTED(result, ExpectFileAddress(0x5678u));
 
   ASSERT_TRUE(expr.Update_DW_OP_addr(dwarf_cu, 0xdeadbeef));
   result = evaluate(expr);
-  EXPECT_THAT_EXPECTED(result, ExpectLoadAddress(0xdeadbeefu));
+  EXPECT_THAT_EXPECTED(result, ExpectFileAddress(0xdeadbeefu));
 }
 
 class CustomSymbolFileDWARF : public SymbolFileDWARF {

diff  --git a/llvm/docs/ReleaseNotes.md b/llvm/docs/ReleaseNotes.md
index 24b8604ca11d8..d1448eb469614 100644
--- a/llvm/docs/ReleaseNotes.md
+++ b/llvm/docs/ReleaseNotes.md
@@ -384,6 +384,8 @@ Makes programs 10x faster by doing Special New Thing.
   * Highlights matching keywords in its output when color is enabled.
   * Searches the components of settings paths. For example `apropos qemu-user` 
will now
     show `platform.plugin.qemu-user` as one of the results.
+* Reading global and static variables on WebAssembly targets now works 
correctly. Previously their
+  values could not be read because data sections were mapped to the wrong 
address space.
 
 #### Deprecated APIs
 


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

Reply via email to