[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