[llvm] [Docs][CodeView] Document `S_LOCAL` and `S_DEFRANGE*` (PR #190156)
via llvm-commits
llvm-commits at lists.llvm.org
Sat Jul 4 03:33:33 PDT 2026
https://github.com/Nerixyz updated https://github.com/llvm/llvm-project/pull/190156
>From 0176c84ff865b1dfae95c4e2f9bfe6e6cd6ed77e Mon Sep 17 00:00:00 2001
From: Nerixyz <nerixdev at outlook.de>
Date: Thu, 26 Mar 2026 18:29:01 +0100
Subject: [PATCH 1/3] [Docs][CodeView] Document `S_LOCAL` and `S_DEFRANGE*`
---
llvm/docs/PDB/CodeViewSymbols.rst | 129 ++++++++++++++++++++++++++++++
1 file changed, 129 insertions(+)
diff --git a/llvm/docs/PDB/CodeViewSymbols.rst b/llvm/docs/PDB/CodeViewSymbols.rst
index 9eaf5adfb7812..6d621ef794886 100644
--- a/llvm/docs/PDB/CodeViewSymbols.rst
+++ b/llvm/docs/PDB/CodeViewSymbols.rst
@@ -184,27 +184,156 @@ S_ENVBLOCK (0x113d)
S_LOCAL (0x113e)
^^^^^^^^^^^^^^^^
+Defines a local variable.
+This record is followed by a series of ``S_DEFRANGE*`` records that define the
+live range of this variable.
+
+All ``S_DEFRANGE*`` records consist of a header followed by
+``LocalVariableAddrRange`` and a list of ``LocalVariableAddrGap`` (until the
+record length is reached).
+
+.. code:: cpp
+
+ /// A live range of a variable.
+ struct LocalVariableAddrRange {
+ /// Starting offset in the section
+ uint32_t OffsetStart;
+ /// Index of the section
+ uint16_t ISectStart;
+ /// Size of the range
+ uint16_t Range;
+ };
+ /// A subrange of a `LocalVariableAddrRange` where a variable is _not_ live.
+ struct LocalVariableAddrGap {
+ /// Start of the range, relative to `LocalVariableAddrRange::OffsetStart`
+ uint16_t GapStartOffset;
+ /// Size of the range
+ uint16_t Range;
+ };
+
+The following records only describe the header.
+
S_DEFRANGE (0x113f)
^^^^^^^^^^^^^^^^^^^
+.. code:: cpp
+
+ struct DefrangeSymHeader {
+ /// DIA program to evaluate the value of the symbol
+ uint32_t Program;
+ };
+
S_DEFRANGE_SUBFIELD (0x1140)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+A live range of sub field of variable (e.g. ``local.i``).
+
+.. code:: cpp
+
+ struct DefrangeSubfieldSymHeader {
+ /// DIA program to evaluate the value of the symbol
+ uint32_t Program;
+ /// Offset in parent variable.
+ uint32_t OffsetInParent;
+ };
+
S_DEFRANGE_REGISTER (0x1141)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+A live range of en-registed variable.
+
+.. code:: cpp
+
+ struct DefrangeRegisterSymHeader {
+ /// Register to hold the value of the symbol
+ uint16_t Register;
+ /// May have no user name on one of control flow path
+ uint16_t MayHaveNoName : 1;
+ uint16_t Padding : 15;
+ };
+
S_DEFRANGE_FRAMEPOINTER_REL (0x1142)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+A live range of frame variable. The register for the frame pointer is specified in ``S_FRAMEPROC``.
+
+.. code:: cpp
+
+ struct DefrangeFramepointerSymHeader {
+ /// Offset from the frame pointer
+ int32_t Offset;
+ };
+
S_DEFRANGE_SUBFIELD_REGISTER (0x1143)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+A live range of sub field of variable (e.g. ``local.i``).
+
+.. code:: cpp
+
+ struct DefrangeSubfieldSymHeader {
+ /// Register to hold the value of the symbol
+ uint16_t Register;
+ /// May have no user name on one of control flow path
+ uint16_t MayHaveNoName : 1;
+ uint16_t Padding1 : 15;
+ /// Offset in parent variable
+ uint32_t OffsetInParent : 12;
+ uint32_t Padding2 : 20;
+ };
+
S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE (0x1144)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+A frame variable valid in all function scope.
+
+.. code:: cpp
+
+ struct DefrangeFramepointerRelFullScopeSymHeader {
+ /// Offset from the frame pointer
+ int32_t Offset;
+ };
+
S_DEFRANGE_REGISTER_REL (0x1145)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+A live range of variable relative to a register (range version of ``S_REGREL32``).
+
+.. code:: cpp
+
+ struct DefrangeRegisterRelSymHeader {
+ /// Register to hold the base pointer of the symbol
+ uint16_t Register;
+ /// Spilled member for s.i
+ uint16_t SpilledUdtMember : 1;
+ uint16_t Padding : 3;
+ /// Offset in parent variable.
+ uint16_t OffsetInParent : 12;
+ /// Offset to register
+ int32_t BasePointerOffset;
+ };
+
+S_DEFRANGE_REGISTER_REL_INDIR (0x1177)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+A live range of variable indirectly relative to a register (range version of ``S_REGREL32_INDIR``).
+
+.. code:: cpp
+
+ struct DefrangeRegisterRelIndirSymHeader {
+ /// Register to hold the base pointer of the symbol
+ uint16_t Register;
+ /// Spilled member for s.i
+ uint16_t SpilledUdtMember : 1;
+ uint16_t Padding : 3;
+ /// Offset in parent variable.
+ uint16_t OffsetInParent : 12;
+ /// Offset to add after dereferencing `Register + BasePointerOffset`
+ int32_t OffsetInUdt;
+ /// Offset to register
+ int32_t BasePointerOffset;
+ };
+
S_LPROC32_ID (0x1146)
^^^^^^^^^^^^^^^^^^^^^
>From 3267992a6f980a005ba25ed67e909dda859f6bb5 Mon Sep 17 00:00:00 2001
From: Nerixyz <nerixdev at outlook.de>
Date: Sat, 4 Jul 2026 12:11:24 +0200
Subject: [PATCH 2/3] fix: apply review suggestions
---
llvm/docs/PDB/CodeViewSymbols.rst | 49 ++++++++++++++++++++++++++-----
1 file changed, 42 insertions(+), 7 deletions(-)
diff --git a/llvm/docs/PDB/CodeViewSymbols.rst b/llvm/docs/PDB/CodeViewSymbols.rst
index 6d621ef794886..55270ea6fa41c 100644
--- a/llvm/docs/PDB/CodeViewSymbols.rst
+++ b/llvm/docs/PDB/CodeViewSymbols.rst
@@ -181,6 +181,8 @@ S_COMPILE3 (0x113c)
S_ENVBLOCK (0x113d)
^^^^^^^^^^^^^^^^^^^
+.. _s_local:
+
S_LOCAL (0x113e)
^^^^^^^^^^^^^^^^
@@ -188,9 +190,37 @@ Defines a local variable.
This record is followed by a series of ``S_DEFRANGE*`` records that define the
live range of this variable.
+.. code:: cpp
+
+ struct LocalSym {
+ /// The type of this variable (TPI type index).
+ uint32_t Type;
+ /// See enum below.
+ uint16_t Flags;
+ /// Name of the variable. A zero terminated string.
+ char Name[];
+ };
+ enum class LocalSymFlags : uint16_t {
+ None = 0,
+ IsParameter = 1 << 0,
+ IsAddressTaken = 1 << 1,
+ IsCompilerGenerated = 1 << 2,
+ IsAggregate = 1 << 3,
+ IsAggregated = 1 << 4,
+ IsAliased = 1 << 5,
+ IsAlias = 1 << 6,
+ IsReturnValue = 1 << 7,
+ IsOptimizedOut = 1 << 8,
+ IsEnregisteredGlobal = 1 << 9,
+ IsEnregisteredStatic = 1 << 10,
+ };
+
+
All ``S_DEFRANGE*`` records consist of a header followed by
``LocalVariableAddrRange`` and a list of ``LocalVariableAddrGap`` (until the
-record length is reached).
+record length is reached) except for the
+`S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE <_defrange_framepointer_rel_full_scope>`_
+record.
.. code:: cpp
@@ -216,6 +246,9 @@ The following records only describe the header.
S_DEFRANGE (0x113f)
^^^^^^^^^^^^^^^^^^^
+.. FIXME: Document the DIA programs. Are these the same as FPO programs?
+A live range expressed as a DIA program.
+
.. code:: cpp
struct DefrangeSymHeader {
@@ -240,14 +273,14 @@ A live range of sub field of variable (e.g. ``local.i``).
S_DEFRANGE_REGISTER (0x1141)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-A live range of en-registed variable.
+A live range of a variable living in a register.
.. code:: cpp
struct DefrangeRegisterSymHeader {
/// Register to hold the value of the symbol
uint16_t Register;
- /// May have no user name on one of control flow path
+ /// May have no user name on one control flow path
uint16_t MayHaveNoName : 1;
uint16_t Padding : 15;
};
@@ -271,7 +304,7 @@ A live range of sub field of variable (e.g. ``local.i``).
.. code:: cpp
- struct DefrangeSubfieldSymHeader {
+ struct DefrangeSubfieldRegisterSymHeader {
/// Register to hold the value of the symbol
uint16_t Register;
/// May have no user name on one of control flow path
@@ -282,6 +315,8 @@ A live range of sub field of variable (e.g. ``local.i``).
uint32_t Padding2 : 20;
};
+.. _defrange_framepointer_rel_full_scope:
+
S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE (0x1144)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -327,11 +362,11 @@ A live range of variable indirectly relative to a register (range version of ``S
uint16_t SpilledUdtMember : 1;
uint16_t Padding : 3;
/// Offset in parent variable.
- uint16_t OffsetInParent : 12;
- /// Offset to add after dereferencing `Register + BasePointerOffset`
- int32_t OffsetInUdt;
+ uint16_t OffsetInParent : 12;
/// Offset to register
int32_t BasePointerOffset;
+ /// Offset to add after dereferencing `Register + BasePointerOffset`
+ int32_t OffsetInUdt;
};
S_LPROC32_ID (0x1146)
>From 8b06ca69373e25589bd0bd9287f7c17bde20f604 Mon Sep 17 00:00:00 2001
From: Nerixyz <nerixdev at outlook.de>
Date: Sat, 4 Jul 2026 12:33:20 +0200
Subject: [PATCH 3/3] fix: newline
---
llvm/docs/PDB/CodeViewSymbols.rst | 1 +
1 file changed, 1 insertion(+)
diff --git a/llvm/docs/PDB/CodeViewSymbols.rst b/llvm/docs/PDB/CodeViewSymbols.rst
index 55270ea6fa41c..b278b71c47f0b 100644
--- a/llvm/docs/PDB/CodeViewSymbols.rst
+++ b/llvm/docs/PDB/CodeViewSymbols.rst
@@ -247,6 +247,7 @@ S_DEFRANGE (0x113f)
^^^^^^^^^^^^^^^^^^^
.. FIXME: Document the DIA programs. Are these the same as FPO programs?
+
A live range expressed as a DIA program.
.. code:: cpp
More information about the llvm-commits
mailing list