[llvm] 1ceada6 - [Docs][CodeView] Document `S_LOCAL` and `S_DEFRANGE*` (#190156)

via llvm-commits llvm-commits at lists.llvm.org
Sat Jul 4 09:57:50 PDT 2026


Author: Nerixyz
Date: 2026-07-04T18:57:46+02:00
New Revision: 1ceada6b6466d09c73c367ea8c664df47570efb8

URL: https://github.com/llvm/llvm-project/commit/1ceada6b6466d09c73c367ea8c664df47570efb8
DIFF: https://github.com/llvm/llvm-project/commit/1ceada6b6466d09c73c367ea8c664df47570efb8.diff

LOG: [Docs][CodeView] Document `S_LOCAL` and `S_DEFRANGE*` (#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.

Added: 
    

Modified: 
    llvm/docs/PDB/CodeViewSymbols.rst

Removed: 
    


################################################################################
diff  --git a/llvm/docs/PDB/CodeViewSymbols.rst b/llvm/docs/PDB/CodeViewSymbols.rst
index 9eaf5adfb7812..b278b71c47f0b 100644
--- a/llvm/docs/PDB/CodeViewSymbols.rst
+++ b/llvm/docs/PDB/CodeViewSymbols.rst
@@ -181,30 +181,195 @@ S_COMPILE3 (0x113c)
 S_ENVBLOCK (0x113d)
 ^^^^^^^^^^^^^^^^^^^
 
+.. _s_local:
+
 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.
+
+.. 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) except for the
+`S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE <_defrange_framepointer_rel_full_scope>`_
+record.
+
+.. 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)
 ^^^^^^^^^^^^^^^^^^^
 
+.. FIXME: Document the DIA programs. Are these the same as FPO programs?
+
+A live range expressed as a DIA program.
+
+.. 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 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 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 DefrangeSubfieldRegisterSymHeader {
+     /// 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;
+   };
+
+.. _defrange_framepointer_rel_full_scope:
+
 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 register
+     int32_t BasePointerOffset;
+     /// Offset to add after dereferencing `Register + BasePointerOffset`
+     int32_t OffsetInUdt;
+   };
+
 S_LPROC32_ID (0x1146)
 ^^^^^^^^^^^^^^^^^^^^^
 


        


More information about the llvm-commits mailing list