[llvm] [llvm-pdbutil] Map enums in bitflags for symbols in YAML (PR #215887)

via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 12 13:21:18 PDT 2026


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

Both `S_COMPILE3` and `S_FRAMEPROC` have bitflags that also contain non-bitflag enums. For `S_COMPILE3`, the lower eight bits represent the language and for `S_FRAMEPROC` there are bits in the middle representing the frame pointer registers for variables and parameters.

In both cases, the values of the enums were not present in the generated YAML. 
Mapping this in YAML is a bit complicated, because we can't give `yaml::IO` a reference to the flags. I used local variables and a check if we're reading to re-assemble the flags.

>From e0ec8cba660a9723566747f14853ddb3b24d54d3 Mon Sep 17 00:00:00 2001
From: Nerixyz <nerixdev at outlook.de>
Date: Wed, 12 Aug 2026 21:24:10 +0200
Subject: [PATCH 1/2] [llvm-pdbutil] Map source language in YAML for S_COMPILE3

---
 llvm/lib/ObjectYAML/CodeViewYAMLSymbols.cpp   |  18 ++-
 llvm/test/tools/llvm-pdbutil/compile3sym.yaml | 109 ++++++++++++++++++
 2 files changed, 126 insertions(+), 1 deletion(-)
 create mode 100644 llvm/test/tools/llvm-pdbutil/compile3sym.yaml

diff --git a/llvm/lib/ObjectYAML/CodeViewYAMLSymbols.cpp b/llvm/lib/ObjectYAML/CodeViewYAMLSymbols.cpp
index b985adaea9cee..0c57deffb96b3 100644
--- a/llvm/lib/ObjectYAML/CodeViewYAMLSymbols.cpp
+++ b/llvm/lib/ObjectYAML/CodeViewYAMLSymbols.cpp
@@ -62,6 +62,7 @@ LLVM_YAML_DECLARE_ENUM_TRAITS(RegisterId)
 LLVM_YAML_DECLARE_ENUM_TRAITS(TrampolineType)
 LLVM_YAML_DECLARE_ENUM_TRAITS(ThunkOrdinal)
 LLVM_YAML_DECLARE_ENUM_TRAITS(JumpTableEntrySize)
+LLVM_YAML_DECLARE_ENUM_TRAITS(SourceLanguage)
 
 LLVM_YAML_STRONG_TYPEDEF(StringRef, TypeName)
 
@@ -206,6 +207,14 @@ void ScalarEnumerationTraits<JumpTableEntrySize>::enumeration(
   }
 }
 
+void ScalarEnumerationTraits<SourceLanguage>::enumeration(IO &IO,
+                                                          SourceLanguage &L) {
+  auto Names = getSourceLanguageNames();
+  for (const auto &E : Names) {
+    IO.enumCase(L, E.name(), static_cast<SourceLanguage>(E.value()));
+  }
+}
+
 namespace llvm {
 namespace yaml {
 template <> struct MappingTraits<LocalVariableAddrRange> {
@@ -485,7 +494,14 @@ template <> void SymbolRecordImpl<Compile2Sym>::map(IO &IO) {
 }
 
 template <> void SymbolRecordImpl<Compile3Sym>::map(IO &IO) {
-  IO.mapRequired("Flags", Symbol.Flags);
+  CompileSym3Flags Flags = Symbol.getFlags();
+  SourceLanguage Lang = Symbol.getLanguage();
+  IO.mapRequired("Flags", Flags);
+  IO.mapOptional("Language", Lang, SourceLanguage::C);
+  if (!IO.outputting()) {
+    Symbol.Flags = Flags;
+    Symbol.setLanguage(Lang);
+  }
   IO.mapRequired("Machine", Symbol.Machine);
   IO.mapRequired("FrontendMajor", Symbol.VersionFrontendMajor);
   IO.mapRequired("FrontendMinor", Symbol.VersionFrontendMinor);
diff --git a/llvm/test/tools/llvm-pdbutil/compile3sym.yaml b/llvm/test/tools/llvm-pdbutil/compile3sym.yaml
new file mode 100644
index 0000000000000..a0702863e3699
--- /dev/null
+++ b/llvm/test/tools/llvm-pdbutil/compile3sym.yaml
@@ -0,0 +1,109 @@
+# RUN: llvm-pdbutil yaml2pdb %s --pdb=%t.pdb
+# RUN: llvm-pdbutil dump --symbols %t.pdb | FileCheck --check-prefix=YAML2PDB %s
+
+# RUN: llvm-pdbutil pdb2yaml --module-syms %t.pdb > %t.yaml
+# RUN: FileCheck --input-file=%t.yaml --check-prefix=PDB2YAML %s
+
+# YAML2PDB:         Mod 0000 | `C:\Users\johannes\AppData\Local\Temp\main-7524b3.obj`: 
+# YAML2PDB-NEXT:         4 | S_OBJNAME [size = 64] sig=0, `C:\Users\johannes\AppData\Local\Temp\main-7524b3.obj`
+# YAML2PDB-NEXT:        68 | S_COMPILE3 [size = 32]
+# YAML2PDB-NEXT:             machine = intel x86-x64, Ver = clang, language = c++
+# YAML2PDB-NEXT:             frontend = 22.1.4.0, backend = 22014.0.0.0
+# YAML2PDB-NEXT:             flags = no dbg info | hot patchable
+# YAML2PDB-NEXT:    Mod 0001 | `* Linker *`: 
+# YAML2PDB-NEXT:         4 | S_OBJNAME [size = 20] sig=0, `* Linker *`
+# YAML2PDB-NEXT:        24 | S_COMPILE3 [size = 40]
+# YAML2PDB-NEXT:             machine = intel x86-x64, Ver = LLVM Linker, language = link
+# YAML2PDB-NEXT:             frontend = 0.0.0.0, backend = 14.10.25019.0
+# YAML2PDB-NEXT:             flags = none
+
+
+# PDB2YAML:                - Kind:            S_COMPILE3
+# PDB2YAML-NEXT:             Compile3Sym:
+# PDB2YAML-NEXT:               Flags:           [ NoDbgInfo, HotPatch ]
+# PDB2YAML-NEXT:               Language:        Cpp
+# PDB2YAML-NEXT:               Machine:         X64
+# PDB2YAML-NEXT:               FrontendMajor:   22
+# PDB2YAML-NEXT:               FrontendMinor:   1
+# PDB2YAML-NEXT:               FrontendBuild:   4
+# PDB2YAML-NEXT:               FrontendQFE:     0
+# PDB2YAML-NEXT:               BackendMajor:    22014
+# PDB2YAML-NEXT:               BackendMinor:    0
+# PDB2YAML-NEXT:               BackendBuild:    0
+# PDB2YAML-NEXT:               BackendQFE:      0
+# PDB2YAML-NEXT:               Version:         clang
+
+# PDB2YAML:                - Kind:            S_COMPILE3
+# PDB2YAML-NEXT:             Compile3Sym:
+# PDB2YAML-NEXT:               Flags:           [  ]
+# PDB2YAML-NEXT:               Language:        Link
+# PDB2YAML-NEXT:               Machine:         X64
+# PDB2YAML-NEXT:               FrontendMajor:   0
+# PDB2YAML-NEXT:               FrontendMinor:   0
+# PDB2YAML-NEXT:               FrontendBuild:   0
+# PDB2YAML-NEXT:               FrontendQFE:     0
+# PDB2YAML-NEXT:               BackendMajor:    14
+# PDB2YAML-NEXT:               BackendMinor:    10
+# PDB2YAML-NEXT:               BackendBuild:    25019
+# PDB2YAML-NEXT:               BackendQFE:      0
+# PDB2YAML-NEXT:               Version:         LLVM Linker
+
+---
+DbiStream:
+  VerHeader:       V70
+  Age:             1
+  BuildNumber:     36363
+  PdbDllVersion:   0
+  PdbDllRbld:      0
+  Flags:           0
+  MachineType:     Amd64
+  Modules:
+    - Module:          'C:\Users\johannes\AppData\Local\Temp\main-7524b3.obj'
+      ObjFile:         'C:\Users\johannes\AppData\Local\Temp\main-7524b3.obj'
+      SourceFiles:
+        - 'F:\Dev\dummy\lldb-repro\main.cpp'
+      Modi:
+        Signature:       4
+        Records:
+          - Kind:            S_OBJNAME
+            ObjNameSym:
+              Signature:       0
+              ObjectName:      'C:\Users\johannes\AppData\Local\Temp\main-7524b3.obj'
+          - Kind:            S_COMPILE3
+            Compile3Sym:
+              Flags:           [ NoDbgInfo, HotPatch ]
+              Language:        Cpp
+              Machine:         X64
+              FrontendMajor:   22
+              FrontendMinor:   1
+              FrontendBuild:   4
+              FrontendQFE:     0
+              BackendMajor:    22014
+              BackendMinor:    0
+              BackendBuild:    0
+              BackendQFE:      0
+              Version:         clang
+    - Module:          '* Linker *'
+      ObjFile:         ''
+      Modi:
+        Signature:       4
+        Records:
+          - Kind:            S_OBJNAME
+            ObjNameSym:
+              Signature:       0
+              ObjectName:      '* Linker *'
+          - Kind:            S_COMPILE3
+            Compile3Sym:
+              Flags:           [  ]
+              Language:        Link
+              Machine:         X64
+              FrontendMajor:   0
+              FrontendMinor:   0
+              FrontendBuild:   0
+              FrontendQFE:     0
+              BackendMajor:    14
+              BackendMinor:    10
+              BackendBuild:    25019
+              BackendQFE:      0
+              Version:         LLVM Linker
+...

>From a48002c3aa5b260350ac94f488d8051068cc9ea0 Mon Sep 17 00:00:00 2001
From: Nerixyz <nerixdev at outlook.de>
Date: Wed, 12 Aug 2026 22:12:02 +0200
Subject: [PATCH 2/2] [llvm-pdbutil] Add missing Registers for S_FRAMEPROC

---
 .../llvm/DebugInfo/CodeView/CodeView.h        |  2 +
 .../llvm/DebugInfo/CodeView/EnumTables.h      |  1 +
 .../llvm/DebugInfo/CodeView/SymbolRecord.h    | 43 +++++++++++++--
 llvm/lib/DebugInfo/CodeView/EnumTables.cpp    | 12 +++++
 llvm/lib/ObjectYAML/CodeViewYAMLSymbols.cpp   | 21 +++++++-
 .../test/tools/llvm-pdbutil/frameprocsym.yaml | 54 +++++++++++++++++++
 6 files changed, 128 insertions(+), 5 deletions(-)
 create mode 100644 llvm/test/tools/llvm-pdbutil/frameprocsym.yaml

diff --git a/llvm/include/llvm/DebugInfo/CodeView/CodeView.h b/llvm/include/llvm/DebugInfo/CodeView/CodeView.h
index 7a1008689296d..2b6431f74b0e2 100644
--- a/llvm/include/llvm/DebugInfo/CodeView/CodeView.h
+++ b/llvm/include/llvm/DebugInfo/CodeView/CodeView.h
@@ -217,6 +217,8 @@ enum class FrameProcedureOptions : uint32_t {
   SafeBuffers = 0x00002000,
   EncodedLocalBasePointerMask = 0x0000C000,
   EncodedParamBasePointerMask = 0x00030000,
+  EncodedPointersMask =
+      EncodedLocalBasePointerMask | EncodedParamBasePointerMask,
   ProfileGuidedOptimization = 0x00040000,
   ValidProfileCounts = 0x00080000,
   OptimizedForSpeed = 0x00100000,
diff --git a/llvm/include/llvm/DebugInfo/CodeView/EnumTables.h b/llvm/include/llvm/DebugInfo/CodeView/EnumTables.h
index 0dfa3d5b0942a..e1a84834d6bfe 100644
--- a/llvm/include/llvm/DebugInfo/CodeView/EnumTables.h
+++ b/llvm/include/llvm/DebugInfo/CodeView/EnumTables.h
@@ -34,6 +34,7 @@ LLVM_ABI EnumStrings<uint32_t, 1> getFrameProcSymFlagNames();
 LLVM_ABI EnumStrings<uint16_t, 1> getExportSymFlagNames();
 LLVM_ABI EnumStrings<uint32_t, 1> getModuleSubstreamKindNames();
 LLVM_ABI EnumStrings<uint8_t, 1> getThunkOrdinalNames();
+LLVM_ABI EnumStrings<uint8_t, 1> getEncodedFramePtrRegNames();
 LLVM_ABI EnumStrings<uint16_t, 1> getTrampolineNames();
 LLVM_ABI EnumStrings<COFF::SectionCharacteristics, 1>
 getImageSectionCharacteristicNames();
diff --git a/llvm/include/llvm/DebugInfo/CodeView/SymbolRecord.h b/llvm/include/llvm/DebugInfo/CodeView/SymbolRecord.h
index 9652e71b19e61..e543f4f7dfdca 100644
--- a/llvm/include/llvm/DebugInfo/CodeView/SymbolRecord.h
+++ b/llvm/include/llvm/DebugInfo/CodeView/SymbolRecord.h
@@ -855,16 +855,51 @@ class FrameProcSym : public SymbolRecord {
   uint16_t SectionIdOfExceptionHandler = 0;
   FrameProcedureOptions Flags = FrameProcedureOptions::None;
 
+  FrameProcedureOptions getFlags() const {
+    return Flags & ~FrameProcedureOptions::EncodedPointersMask;
+  }
+
+  void setFlags(FrameProcedureOptions O) {
+    Flags = (Flags & FrameProcedureOptions::EncodedPointersMask) |
+            (O & ~FrameProcedureOptions::EncodedPointersMask);
+  }
+
+  void setEncodedLocalFramePtrReg(EncodedFramePtrReg R) {
+    FrameProcedureOptions RegFlags{(static_cast<uint32_t>(R) & 3U) << 14U};
+    Flags = (Flags & ~FrameProcedureOptions::EncodedLocalBasePointerMask) |
+            RegFlags;
+  }
+
+  void setLocalFramePtrReg(RegisterId Reg, CPUType CPU) {
+    setEncodedLocalFramePtrReg(encodeFramePtrReg(Reg, CPU));
+  }
+
+  void setEncodedParamFramePtrReg(EncodedFramePtrReg R) {
+    FrameProcedureOptions RegFlags{(static_cast<uint32_t>(R) & 3U) << 16U};
+    Flags = (Flags & ~FrameProcedureOptions::EncodedParamBasePointerMask) |
+            RegFlags;
+  }
+
+  void setParamFramePtrReg(RegisterId Reg, CPUType CPU) {
+    setEncodedParamFramePtrReg(encodeFramePtrReg(Reg, CPU));
+  }
+
+  EncodedFramePtrReg getEncodedLocalFramePtrReg() const {
+    return EncodedFramePtrReg((uint32_t(Flags) >> 14U) & 0x3U);
+  }
+
   /// Extract the register this frame uses to refer to local variables.
   RegisterId getLocalFramePtrReg(CPUType CPU) const {
-    return decodeFramePtrReg(
-        EncodedFramePtrReg((uint32_t(Flags) >> 14U) & 0x3U), CPU);
+    return decodeFramePtrReg(getEncodedLocalFramePtrReg(), CPU);
+  }
+
+  EncodedFramePtrReg getEncodedParamFramePtrReg() const {
+    return EncodedFramePtrReg((uint32_t(Flags) >> 16U) & 0x3U);
   }
 
   /// Extract the register this frame uses to refer to parameters.
   RegisterId getParamFramePtrReg(CPUType CPU) const {
-    return decodeFramePtrReg(
-        EncodedFramePtrReg((uint32_t(Flags) >> 16U) & 0x3U), CPU);
+    return decodeFramePtrReg(getEncodedParamFramePtrReg(), CPU);
   }
 
   uint32_t RecordOffset = 0;
diff --git a/llvm/lib/DebugInfo/CodeView/EnumTables.cpp b/llvm/lib/DebugInfo/CodeView/EnumTables.cpp
index 383922d5c6ff7..4b44f02dc369e 100644
--- a/llvm/lib/DebugInfo/CodeView/EnumTables.cpp
+++ b/llvm/lib/DebugInfo/CodeView/EnumTables.cpp
@@ -373,6 +373,18 @@ EnumStrings<uint8_t> getThunkOrdinalNames() {
   return ThunkOrdinalNames;
 }
 
+EnumStrings<uint8_t> getEncodedFramePtrRegNames() {
+  constexpr EnumStringDef<uint8_t> EncodedFramePtrRegNameDefs[] = {
+      CV_ENUM_CLASS_ENT(EncodedFramePtrReg, None),
+      CV_ENUM_CLASS_ENT(EncodedFramePtrReg, StackPtr),
+      CV_ENUM_CLASS_ENT(EncodedFramePtrReg, FramePtr),
+      CV_ENUM_CLASS_ENT(EncodedFramePtrReg, BasePtr),
+  };
+  static constexpr auto EncodedFramePtrRegNames =
+      BUILD_ENUM_STRINGS(EncodedFramePtrRegNameDefs);
+  return EncodedFramePtrRegNames;
+}
+
 EnumStrings<uint16_t> getTrampolineNames() {
   constexpr EnumStringDef<uint16_t> TrampolineNameDefs[] = {
       CV_ENUM_CLASS_ENT(TrampolineType, TrampIncremental),
diff --git a/llvm/lib/ObjectYAML/CodeViewYAMLSymbols.cpp b/llvm/lib/ObjectYAML/CodeViewYAMLSymbols.cpp
index 0c57deffb96b3..b6541ad2e626c 100644
--- a/llvm/lib/ObjectYAML/CodeViewYAMLSymbols.cpp
+++ b/llvm/lib/ObjectYAML/CodeViewYAMLSymbols.cpp
@@ -63,6 +63,7 @@ LLVM_YAML_DECLARE_ENUM_TRAITS(TrampolineType)
 LLVM_YAML_DECLARE_ENUM_TRAITS(ThunkOrdinal)
 LLVM_YAML_DECLARE_ENUM_TRAITS(JumpTableEntrySize)
 LLVM_YAML_DECLARE_ENUM_TRAITS(SourceLanguage)
+LLVM_YAML_DECLARE_ENUM_TRAITS(EncodedFramePtrReg)
 
 LLVM_YAML_STRONG_TYPEDEF(StringRef, TypeName)
 
@@ -215,6 +216,14 @@ void ScalarEnumerationTraits<SourceLanguage>::enumeration(IO &IO,
   }
 }
 
+void ScalarEnumerationTraits<EncodedFramePtrReg>::enumeration(
+    IO &IO, EncodedFramePtrReg &R) {
+  auto Names = getEncodedFramePtrRegNames();
+  for (const auto &E : Names) {
+    IO.enumCase(R, E.name(), static_cast<EncodedFramePtrReg>(E.value()));
+  }
+}
+
 namespace llvm {
 namespace yaml {
 template <> struct MappingTraits<LocalVariableAddrRange> {
@@ -523,7 +532,17 @@ template <> void SymbolRecordImpl<FrameProcSym>::map(IO &IO) {
   IO.mapRequired("OffsetOfExceptionHandler", Symbol.OffsetOfExceptionHandler);
   IO.mapRequired("SectionIdOfExceptionHandler",
                  Symbol.SectionIdOfExceptionHandler);
-  IO.mapRequired("Flags", Symbol.Flags);
+  FrameProcedureOptions Flags = Symbol.getFlags();
+  EncodedFramePtrReg LocalFP = Symbol.getEncodedLocalFramePtrReg();
+  EncodedFramePtrReg ParamFP = Symbol.getEncodedParamFramePtrReg();
+  IO.mapRequired("Flags", Flags);
+  IO.mapOptional("LocalFramePtrReg", LocalFP, EncodedFramePtrReg::None);
+  IO.mapOptional("ParamFramePtrReg", ParamFP, EncodedFramePtrReg::None);
+  if (!IO.outputting()) {
+    Symbol.setFlags(Flags);
+    Symbol.setEncodedLocalFramePtrReg(LocalFP);
+    Symbol.setEncodedParamFramePtrReg(ParamFP);
+  }
 }
 
 template <> void SymbolRecordImpl<CallSiteInfoSym>::map(IO &IO) {
diff --git a/llvm/test/tools/llvm-pdbutil/frameprocsym.yaml b/llvm/test/tools/llvm-pdbutil/frameprocsym.yaml
new file mode 100644
index 0000000000000..84d20d08f032d
--- /dev/null
+++ b/llvm/test/tools/llvm-pdbutil/frameprocsym.yaml
@@ -0,0 +1,54 @@
+# RUN: llvm-pdbutil yaml2pdb %s --pdb=%t.pdb
+# RUN: llvm-pdbutil dump --symbols %t.pdb | FileCheck --check-prefix=YAML2PDB %s
+
+# RUN: llvm-pdbutil pdb2yaml --module-syms %t.pdb > %t.yaml
+# RUN: FileCheck --input-file=%t.yaml --check-prefix=PDB2YAML %s
+
+# YAML2PDB:         Mod 0000 | `C:\Users\johannes\AppData\Local\Temp\main-7524b3.obj`: 
+# YAML2PDB-NEXT:        4 | S_FRAMEPROC [size = 32]
+# YAML2PDB-NEXT:            size = 56, padding size = 0, offset to padding = 0
+# YAML2PDB-NEXT:            bytes of callee saved registers = 0, exception handler addr = 0000:0000
+# YAML2PDB-NEXT:            local fp reg = RSP, param fp reg = R13
+# YAML2PDB-NEXT:            flags = has longjmp | inlined | safe buffers | pgo
+
+# PDB2YAML:               - Kind:            S_FRAMEPROC
+# PDB2YAML-NEXT:            FrameProcSym:
+# PDB2YAML-NEXT:              TotalFrameBytes: 56
+# PDB2YAML-NEXT:              PaddingFrameBytes: 0
+# PDB2YAML-NEXT:              OffsetToPadding: 0
+# PDB2YAML-NEXT:              BytesOfCalleeSavedRegisters: 0
+# PDB2YAML-NEXT:              OffsetOfExceptionHandler: 0
+# PDB2YAML-NEXT:              SectionIdOfExceptionHandler: 0
+# PDB2YAML-NEXT:              Flags:           [ HasLongJmp, Inlined, SafeBuffers, ProfileGuidedOptimization ]
+# PDB2YAML-NEXT:              LocalFramePtrReg: StackPtr
+# PDB2YAML-NEXT:              ParamFramePtrReg: BasePtr
+
+---
+DbiStream:
+  VerHeader:       V70
+  Age:             1
+  BuildNumber:     36363
+  PdbDllVersion:   0
+  PdbDllRbld:      0
+  Flags:           0
+  MachineType:     Amd64
+  Modules:
+    - Module:          'C:\Users\johannes\AppData\Local\Temp\main-7524b3.obj'
+      ObjFile:         'C:\Users\johannes\AppData\Local\Temp\main-7524b3.obj'
+      SourceFiles:
+        - 'F:\Dev\dummy\lldb-repro\main.cpp'
+      Modi:
+        Signature:       4
+        Records:
+          - Kind:            S_FRAMEPROC
+            FrameProcSym:
+              TotalFrameBytes: 56
+              PaddingFrameBytes: 0
+              OffsetToPadding: 0
+              BytesOfCalleeSavedRegisters: 0
+              OffsetOfExceptionHandler: 0
+              SectionIdOfExceptionHandler: 0
+              Flags:           [ HasLongJmp, Inlined, SafeBuffers, ProfileGuidedOptimization ]
+              LocalFramePtrReg: StackPtr
+              ParamFramePtrReg: BasePtr
+...



More information about the llvm-commits mailing list