[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