[Lldb-commits] [lldb] [LLDB][NativePDB] Add support for `S_REGREL32_INDIR` (PR #186124)
via lldb-commits
lldb-commits at lists.llvm.org
Thu Mar 12 07:15:13 PDT 2026
https://github.com/Nerixyz created https://github.com/llvm/llvm-project/pull/186124
In #183172, I added support for reading `S_REGREL32_INDIR` records. This adds support in LLDB. The record is emitted by MSVC for structured bindings and in the compiler generated coroutine stubs.
It describes a location at `*(Register + Offset) + OffsetInUdt`. Equivalent to
```
DW_OP_breg{reg} {Offset}
DW_OP_deref
DW_OP_plus_uconst {OffsetInUdt}
```
LLVM doesn't create this record - it only creates `S_LOCAL`s for local variables. We'll probably need `S_DEFRANGE_REGISTER_REL_INDIR` for this - should be simple to figure out the structure, but I haven't seen that record emitted yet.
>From 6ac0070b5baf38ffbe950af2a8e2e16c88293b26 Mon Sep 17 00:00:00 2001
From: Nerixyz <nerixdev at outlook.de>
Date: Wed, 25 Feb 2026 15:07:57 +0100
Subject: [PATCH] [LLDB][NativePDB] Add support for `S_REGREL32_INDIR`
---
.../NativePDB/DWARFLocationExpression.cpp | 25 +++++++++++
.../NativePDB/DWARFLocationExpression.h | 4 ++
.../NativePDB/PdbAstBuilderClang.cpp | 9 ++++
.../Plugins/SymbolFile/NativePDB/PdbUtil.cpp | 20 +++++++++
.../NativePDB/SymbolFileNativePDB.cpp | 1 +
.../NativePDB/structured-bindings-msvc.test | 43 +++++++++++++++++++
6 files changed, 102 insertions(+)
create mode 100644 lldb/test/Shell/SymbolFile/NativePDB/structured-bindings-msvc.test
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.cpp
index 3e66c58df693e..28bd2f076b680 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.cpp
@@ -153,6 +153,21 @@ static bool MakeRegisterBasedLocationExpressionInternal(
return true;
}
+/// *(reg + indir_offset) + offset
+static bool MakeRegisterBasedIndirectLocationExpressionInternal(
+ Stream &stream, llvm::codeview::RegisterId reg, RegisterKind ®ister_kind,
+ int32_t indir_offset, int32_t offset, lldb::ModuleSP module) {
+ if (!MakeRegisterBasedLocationExpressionInternal(stream, reg, register_kind,
+ indir_offset, module))
+ return false;
+
+ stream.PutHex8(llvm::dwarf::DW_OP_deref);
+ stream.PutHex8(llvm::dwarf::DW_OP_plus_uconst);
+ stream.PutSLEB128(offset);
+
+ return true;
+}
+
static DWARFExpression MakeRegisterBasedLocationExpressionInternal(
llvm::codeview::RegisterId reg, std::optional<int32_t> relative_offset,
lldb::ModuleSP module) {
@@ -173,6 +188,16 @@ DWARFExpression lldb_private::npdb::MakeRegRelLocationExpression(
return MakeRegisterBasedLocationExpressionInternal(reg, offset, module);
}
+DWARFExpression lldb_private::npdb::MakeRegRelIndirLocationExpression(
+ llvm::codeview::RegisterId reg, int32_t offset, int32_t offset_in_udt,
+ lldb::ModuleSP module) {
+ return MakeLocationExpressionInternal(
+ module, [&](Stream &stream, RegisterKind ®ister_kind) -> bool {
+ return MakeRegisterBasedIndirectLocationExpressionInternal(
+ stream, reg, register_kind, offset, offset_in_udt, module);
+ });
+}
+
static bool EmitVFrameEvaluationDWARFExpression(
llvm::StringRef program, llvm::Triple::ArchType arch_type, Stream &stream) {
// VFrame value always stored in $TO pseudo-register
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.h b/lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.h
index 2f12d8bf0dd78..4a024dbd7e1e0 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.h
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.h
@@ -39,6 +39,10 @@ MakeEnregisteredLocationExpression(llvm::codeview::RegisterId reg,
DWARFExpression MakeRegRelLocationExpression(llvm::codeview::RegisterId reg,
int32_t offset,
lldb::ModuleSP module);
+DWARFExpression
+MakeRegRelIndirLocationExpression(llvm::codeview::RegisterId reg,
+ int32_t offset, int32_t offset_in_udt,
+ lldb::ModuleSP module);
DWARFExpression MakeVFrameRelLocationExpression(llvm::StringRef fpo_program,
int32_t offset,
lldb::ModuleSP module);
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilderClang.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilderClang.cpp
index de0d46cc1c9a2..b07302bc7c7bf 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilderClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilderClang.cpp
@@ -231,6 +231,7 @@ static bool isLocalVariableType(SymbolKind K) {
switch (K) {
case S_REGISTER:
case S_REGREL32:
+ case S_REGREL32_INDIR:
case S_LOCAL:
return true;
default:
@@ -1141,6 +1142,14 @@ void PdbAstBuilderClang::CreateFunctionParameters(
param_name = reg.Name;
break;
}
+ case S_REGREL32_INDIR: {
+ RegRelativeIndirSym reg(SymbolRecordKind::RegRelativeIndirSym);
+ cantFail(
+ SymbolDeserializer::deserializeAs<RegRelativeIndirSym>(sym, reg));
+ param_type = reg.Type;
+ param_name = reg.Name;
+ break;
+ }
case S_REGISTER: {
RegisterSym reg(SymbolRecordKind::RegisterSym);
cantFail(SymbolDeserializer::deserializeAs<RegisterSym>(sym, reg));
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp
index 6c66d86d3e645..a90ca32fffac7 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp
@@ -252,6 +252,7 @@ PDB_SymType lldb_private::npdb::CVSymToPDBSym(SymbolKind kind) {
case S_LOCAL:
case S_BPREL32:
case S_REGREL32:
+ case S_REGREL32_INDIR:
case S_MANCONSTANT:
case S_CONSTANT:
case S_LDATA32:
@@ -611,6 +612,14 @@ VariableInfo lldb_private::npdb::GetVariableNameInfo(CVSymbol sym) {
return result;
}
+ if (sym.kind() == S_REGREL32_INDIR) {
+ RegRelativeIndirSym reg(SymbolRecordKind::RegRelativeIndirSym);
+ cantFail(SymbolDeserializer::deserializeAs<RegRelativeIndirSym>(sym, reg));
+ result.type = reg.Type;
+ result.name = reg.Name;
+ return result;
+ }
+
if (sym.kind() == S_REGISTER) {
RegisterSym reg(SymbolRecordKind::RegisterSym);
cantFail(SymbolDeserializer::deserializeAs<RegisterSym>(sym, reg));
@@ -748,6 +757,17 @@ VariableInfo lldb_private::npdb::GetVariableLocationInfo(
return result;
}
+ if (sym.kind() == S_REGREL32_INDIR) {
+ RegRelativeIndirSym reg(SymbolRecordKind::RegRelativeIndirSym);
+ cantFail(SymbolDeserializer::deserializeAs<RegRelativeIndirSym>(sym, reg));
+ result.location = DWARFExpressionList(
+ module,
+ MakeRegRelIndirLocationExpression(reg.Register, reg.Offset,
+ reg.OffsetInUdt, module),
+ nullptr);
+ return result;
+ }
+
if (sym.kind() == S_REGISTER) {
RegisterSym reg(SymbolRecordKind::RegisterSym);
cantFail(SymbolDeserializer::deserializeAs<RegisterSym>(sym, reg));
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
index bed15839be1cd..22c4f19242c4d 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
@@ -2405,6 +2405,7 @@ size_t SymbolFileNativePDB::ParseVariablesForBlock(PdbCompilandSymId block_id) {
VariableSP variable;
switch (variable_cvs.kind()) {
case S_REGREL32:
+ case S_REGREL32_INDIR:
case S_REGISTER:
case S_LOCAL:
variable = GetOrCreateLocalVariable(block_id, child_sym_id, is_param);
diff --git a/lldb/test/Shell/SymbolFile/NativePDB/structured-bindings-msvc.test b/lldb/test/Shell/SymbolFile/NativePDB/structured-bindings-msvc.test
new file mode 100644
index 0000000000000..678931475d0f1
--- /dev/null
+++ b/lldb/test/Shell/SymbolFile/NativePDB/structured-bindings-msvc.test
@@ -0,0 +1,43 @@
+# REQUIRES: lld
+
+# Test that LLDB can show variables introduced in C++ 17 structured bindings
+# when compiled with MSVC.
+
+# RUN: split-file %s %t
+
+# RUN: %build --compiler=msvc --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-NEXT: Variable{{.*}}, name = "f", type = {{.*}} (Foo), scope = local, location =
+# SYMBOLS-NEXT: Variable{{.*}}, name = "b", type = {{.*}} (int), scope = local, location =
+# SYMBOLS-NEXT: Variable{{.*}}, name = "a", type = {{.*}} (int), scope = local, location =
+
+# 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
More information about the lldb-commits
mailing list