[Lldb-commits] [lldb] [lldb][NativePDB] Handle `S_DEFRANGE_REGISTER_REL_INDIR` (PR #190336)

via lldb-commits lldb-commits at lists.llvm.org
Fri Apr 3 04:55:55 PDT 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-lldb

Author: Nerixyz (Nerixyz)

<details>
<summary>Changes</summary>

Since #<!-- -->189401, LLVM and Clang generate `S_DEFRANGE_REGISTER_REL_INDIR` for indirect locations. This adds support in LLDB.

The offset added after dereferencing is signed here - unlike in `S_REGREL32_INDIR` (at least that's the assumption). So I updated `MakeRegisterBasedIndirectLocationExpressionInternal` to handle the signedness. This is the reason the MSVC test was changed here.

I didn't find a test case where LLVM emits the record with the `VFRAME` register. Other than that, the clang test is similar to the MSVC one except that the locations are slightly different.

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


5 Files Affected:

- (modified) lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.cpp (+27-1) 
- (modified) lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.h (+4) 
- (modified) lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp (+31) 
- (added) lldb/test/Shell/SymbolFile/NativePDB/structured-bindings-clang.test (+45) 
- (modified) lldb/test/Shell/SymbolFile/NativePDB/structured-bindings-msvc.test (+2-2) 


``````````diff
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.cpp
index 0b7e2e31c1414..fb37a8138d88d 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.cpp
@@ -166,8 +166,9 @@ static bool MakeRegisterBasedIndirectLocationExpressionInternal(
     return false;
 
   stream.PutHex8(llvm::dwarf::DW_OP_deref);
-  stream.PutHex8(llvm::dwarf::DW_OP_plus_uconst);
+  stream.PutHex8(llvm::dwarf::DW_OP_consts);
   stream.PutSLEB128(offset);
+  stream.PutHex8(llvm::dwarf::DW_OP_plus);
 
   return true;
 }
@@ -229,6 +230,31 @@ DWARFExpression lldb_private::npdb::MakeVFrameRelLocationExpression(
       });
 }
 
+DWARFExpression lldb_private::npdb::MakeVFrameRelIndirLocationExpression(
+    llvm::StringRef fpo_program, int32_t offset, int32_t offset_in_udt,
+    lldb::ModuleSP module) {
+  return MakeLocationExpressionInternal(
+      module, [&](Stream &stream, RegisterKind &register_kind) -> bool {
+        const ArchSpec &architecture = module->GetArchitecture();
+
+        if (!EmitVFrameEvaluationDWARFExpression(
+                fpo_program, architecture.GetMachine(), stream))
+          return false;
+
+        stream.PutHex8(llvm::dwarf::DW_OP_consts);
+        stream.PutSLEB128(offset);
+        stream.PutHex8(llvm::dwarf::DW_OP_plus);
+        stream.PutHex8(llvm::dwarf::DW_OP_deref);
+        stream.PutHex8(llvm::dwarf::DW_OP_consts);
+        stream.PutSLEB128(offset_in_udt);
+        stream.PutHex8(llvm::dwarf::DW_OP_plus);
+
+        register_kind = eRegisterKindLLDB;
+
+        return true;
+      });
+}
+
 DWARFExpression lldb_private::npdb::MakeGlobalLocationExpression(
     uint16_t section, uint32_t offset, ModuleSP module) {
   assert(section > 0);
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.h b/lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.h
index 81a47d6dad0f2..e1478db6ce9f6 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.h
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.h
@@ -47,6 +47,10 @@ MakeRegRelIndirLocationExpression(llvm::codeview::RegisterId reg,
 DWARFExpression MakeVFrameRelLocationExpression(llvm::StringRef fpo_program,
                                                 int32_t offset,
                                                 lldb::ModuleSP module);
+DWARFExpression
+MakeVFrameRelIndirLocationExpression(llvm::StringRef fpo_program,
+                                     int32_t offset, int32_t offset_in_udt,
+                                     lldb::ModuleSP module);
 DWARFExpression MakeGlobalLocationExpression(uint16_t section, uint32_t offset,
                                              lldb::ModuleSP module);
 llvm::Expected<DWARFExpression> MakeConstantLocationExpression(
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp
index a90ca32fffac7..5860d90eca689 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp
@@ -888,6 +888,37 @@ VariableInfo lldb_private::npdb::GetVariableLocationInfo(
           AddDwarfRange(location_map, expr, raw_ranges);
         break;
       }
+      case S_DEFRANGE_REGISTER_REL_INDIR: {
+        DefRangeRegisterRelIndirSym loc(
+            SymbolRecordKind::DefRangeRegisterRelIndirSym);
+        if (llvm::Error error =
+                SymbolDeserializer::deserializeAs<DefRangeRegisterRelIndirSym>(
+                    loc_specifier_cvs, loc)) {
+          llvm::consumeError(std::move(error));
+          return result;
+        }
+        Variable::RangeList raw_ranges =
+            MakeRangeList(index, loc.Range, loc.Gaps);
+        RegisterId reg_id = (RegisterId)(uint16_t)loc.Hdr.Register;
+        DWARFExpression expr;
+        if (reg_id == RegisterId::VFRAME) {
+          llvm::StringRef program;
+          if (GetFrameDataProgram(index, raw_ranges, program))
+            expr = MakeVFrameRelIndirLocationExpression(
+                program, loc.Hdr.BasePointerOffset, loc.Hdr.OffsetInUdt,
+                module);
+          else {
+            // invalid variable
+          }
+        } else {
+          expr = MakeRegRelIndirLocationExpression(
+              reg_id, loc.Hdr.BasePointerOffset, loc.Hdr.OffsetInUdt, module);
+        }
+        // FIXME: If it's UDT, we need to know the size of the value in byte.
+        if (!loc.hasSpilledUDTMember())
+          AddDwarfRange(location_map, expr, raw_ranges);
+        break;
+      }
       case S_DEFRANGE_SUBFIELD_REGISTER: {
         DefRangeSubfieldRegisterSym loc(
             SymbolRecordKind::DefRangeSubfieldRegisterSym);
diff --git a/lldb/test/Shell/SymbolFile/NativePDB/structured-bindings-clang.test b/lldb/test/Shell/SymbolFile/NativePDB/structured-bindings-clang.test
new file mode 100644
index 0000000000000..254015ff198fa
--- /dev/null
+++ b/lldb/test/Shell/SymbolFile/NativePDB/structured-bindings-clang.test
@@ -0,0 +1,45 @@
+# REQUIRES: lld, target-windows
+
+# Test that LLDB can show variables introduced in C++ 17 structured bindings
+# when compiled with clang-cl.
+
+# RUN: split-file %s %t
+
+# RUN: %build --compiler=clang-cl --arch=64 --std=c++17 --nodefaultlib -o %t.exe -- %t/main.cpp
+# RUN: lldb-test symbols %t.exe | FileCheck %s --check-prefix=SYMBOLS
+# RUN: %lldb -f %t.exe -s %t/commands.input | FileCheck %s --check-prefix=LLDB
+
+#--- main.cpp
+
+struct Foo { int a; int b; };
+
+int main() {
+    Foo f{1, 2};
+
+    auto&[a, b] = f;
+    return a + b; // break here
+}
+
+#--- commands.input
+
+br set -p "break here"
+r
+v f
+v a
+v b
+q
+
+# SYMBOLS:      Function{{.*}}, demangled = main, type =
+# SYMBOLS-NEXT: Block{{.*}}, ranges = 
+# SYMBOLS-DAG:   Variable{{.*}}, name = "f", type = {{.*}} (Foo), scope = local, location =
+# SYMBOLS-DAG:   Variable{{.*}}, name = "a", type = {{.*}} (int), scope = local, location = 0x00000000:
+# SYMBOLS-NEXT:     [{{.*}}): DW_OP_breg{{.*}}, DW_OP_deref, DW_OP_consts +0, DW_OP_plus
+# SYMBOLS-DAG:   Variable{{.*}}, name = "b", type = {{.*}} (int), scope = local, location = 0x00000000:
+# SYMBOLS-NEXT:     [{{.*}}): DW_OP_breg{{.*}}, DW_OP_deref, DW_OP_consts {{[+-][0-9]+}}, DW_OP_plus
+
+# LLDB:      (lldb) v f
+# LLDB-NEXT: (Foo) f = (a = 1, b = 2)
+# LLDB-NEXT: (lldb) v a
+# LLDB-NEXT: (int) a = 1
+# LLDB-NEXT: (lldb) v b
+# LLDB-NEXT: (int) b = 2
diff --git a/lldb/test/Shell/SymbolFile/NativePDB/structured-bindings-msvc.test b/lldb/test/Shell/SymbolFile/NativePDB/structured-bindings-msvc.test
index ebe6cceda7ea6..a4d162248e6d2 100644
--- a/lldb/test/Shell/SymbolFile/NativePDB/structured-bindings-msvc.test
+++ b/lldb/test/Shell/SymbolFile/NativePDB/structured-bindings-msvc.test
@@ -32,8 +32,8 @@ q
 # SYMBOLS:      Function{{.*}}, demangled = main, type =
 # SYMBOLS-NEXT: Block{{.*}}, ranges = 
 # SYMBOLS-NEXT:   Variable{{.*}}, name = "f", type = {{.*}} (Foo), scope = local, location =
-# SYMBOLS-NEXT:   Variable{{.*}}, name = "b", type = {{.*}} (int), scope = local, location = DW_OP_breg{{.*}}, DW_OP_deref, DW_OP_plus_uconst 0x{{[0-9]+}}
-# SYMBOLS-NEXT:   Variable{{.*}}, name = "a", type = {{.*}} (int), scope = local, location = DW_OP_breg{{.*}}, DW_OP_deref, DW_OP_plus_uconst 0x0
+# SYMBOLS-NEXT:   Variable{{.*}}, name = "b", type = {{.*}} (int), scope = local, location = DW_OP_breg{{.*}}, DW_OP_deref, DW_OP_consts {{[+-][0-9]+}}, DW_OP_plus
+# SYMBOLS-NEXT:   Variable{{.*}}, name = "a", type = {{.*}} (int), scope = local, location = DW_OP_breg{{.*}}, DW_OP_deref, DW_OP_consts +0, DW_OP_plus
 
 # LLDB:      (lldb) v f
 # LLDB-NEXT: (Foo) f = (a = 1, b = 2)

``````````

</details>


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


More information about the lldb-commits mailing list