[llvm] [Docs][CodeView] Document `S_LOCAL` and `S_DEFRANGE*` (PR #190156)

via llvm-commits llvm-commits at lists.llvm.org
Thu Apr 2 05:04:53 PDT 2026


https://github.com/Nerixyz created https://github.com/llvm/llvm-project/pull/190156

As suggested in https://github.com/llvm/llvm-project/pull/187709#issuecomment-4120922355, this adds documentation for both `S_LOCAL` and the known `S_DEFRANGE*` records.

In all descriptions, I put struct definition with comments, because it describes both the layout and the function of each member. Some comments are from the original PDB repo (https://github.com/microsoft/microsoft-pdb/blob/805655a28bd8198004be2ac27e6e0290121a5e89/include/cvinfo.h#L4209-L4291).

Many structs in LLVM itself don't have these comments. I think we should also add them there.

>From 7d50acba6df68e48446abb6e34dcabdc33f243d8 Mon Sep 17 00:00:00 2001
From: Nerixyz <nerixdev at outlook.de>
Date: Thu, 26 Mar 2026 18:29:01 +0100
Subject: [PATCH] [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)
 ^^^^^^^^^^^^^^^^^^^^^
 



More information about the llvm-commits mailing list