[llvm] [CodeView] Add `CoroutineKind` to `S_FRAMEPROC` flags (PR #223018)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Sep 11 12:11:20 PDT 2026
https://github.com/Nerixyz created https://github.com/llvm/llvm-project/pull/223018
[`IDiaSymbol8`](https://learn.microsoft.com/en-us/visualstudio/debugger/debug-interface-access/idiasymbol8?view=visualstudio) adds coroutine related getters. I added the associated symbols in #221034. This adds the coroutine kind (what's behind `get_coroutineKind`).
It's stored in three bits inside the flags of `S_FRAMEPROC`. The values are identical to those of [`CV_CoroutineKind_e`](https://learn.microsoft.com/en-us/visualstudio/debugger/debug-interface-access/cv-coroutinekind-e?view=visualstudio).
I tested this on an MSVC generated PDB.
>From 71ab67220e1125e5e6e83142fe2b40a83cf402c4 Mon Sep 17 00:00:00 2001
From: Nerixyz <nerixdev at outlook.de>
Date: Fri, 11 Sep 2026 21:01:36 +0200
Subject: [PATCH] [CodeView] Add `CoroutineKind` to `S_FRAMEPROC` flags
---
.../llvm/DebugInfo/CodeView/CodeView.h | 19 ++-
.../llvm/DebugInfo/CodeView/EnumTables.h | 1 +
.../llvm/DebugInfo/CodeView/SymbolRecord.h | 9 +
llvm/lib/DebugInfo/CodeView/EnumTables.cpp | 13 ++
llvm/lib/ObjectYAML/CodeViewYAMLSymbols.cpp | 12 ++
.../llvm-pdbutil/frameproc-coro-kind.yaml | 156 ++++++++++++++++++
.../llvm-pdbutil/MinimalSymbolDumper.cpp | 15 ++
7 files changed, 224 insertions(+), 1 deletion(-)
create mode 100644 llvm/test/tools/llvm-pdbutil/frameproc-coro-kind.yaml
diff --git a/llvm/include/llvm/DebugInfo/CodeView/CodeView.h b/llvm/include/llvm/DebugInfo/CodeView/CodeView.h
index 3ce3d538d0adc..bb0af5165e3c9 100644
--- a/llvm/include/llvm/DebugInfo/CodeView/CodeView.h
+++ b/llvm/include/llvm/DebugInfo/CodeView/CodeView.h
@@ -223,7 +223,8 @@ enum class FrameProcedureOptions : uint32_t {
ValidProfileCounts = 0x00080000,
OptimizedForSpeed = 0x00100000,
GuardCfg = 0x00200000,
- GuardCfw = 0x00400000
+ GuardCfw = 0x00400000,
+ CoroutineKindMask = 0x0E000000,
};
CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(FrameProcedureOptions)
@@ -630,6 +631,22 @@ enum class AssociationKind : uint16_t {
/// Associated symbol is the primary coroutine function.
Coroutine,
};
+
+/// Three bit value indicating the coroutine kind of a function.
+///
+/// From `CV_CoroutineKind_e` (cvconst.h)
+enum class CoroutineKind : uint8_t {
+ /// Not a coroutine.
+ None = 0,
+ /// The original coroutine function.
+ Primary = 1,
+ /// Initialization function, sets up the coroutine frame.
+ Init = 2,
+ /// Resume function, contains the coroutine body code.
+ Resume = 3,
+ /// Destroy function, tears down the coroutine frame.
+ Destroy = 4,
+};
}
}
diff --git a/llvm/include/llvm/DebugInfo/CodeView/EnumTables.h b/llvm/include/llvm/DebugInfo/CodeView/EnumTables.h
index 3e128f70381ce..e957c72882dcf 100644
--- a/llvm/include/llvm/DebugInfo/CodeView/EnumTables.h
+++ b/llvm/include/llvm/DebugInfo/CodeView/EnumTables.h
@@ -51,6 +51,7 @@ LLVM_ABI EnumStrings<uint8_t, 1> getFunctionOptionEnum();
LLVM_ABI EnumStrings<uint16_t, 1> getLabelTypeEnum();
LLVM_ABI EnumStrings<uint16_t, 1> getJumpTableEntrySizeNames();
LLVM_ABI EnumStrings<uint16_t, 1> getAssociationKindNames();
+LLVM_ABI EnumStrings<uint16_t, 1> getCoroutineKindNames();
} // end namespace codeview
} // end namespace llvm
diff --git a/llvm/include/llvm/DebugInfo/CodeView/SymbolRecord.h b/llvm/include/llvm/DebugInfo/CodeView/SymbolRecord.h
index fe8e66f067553..45a33b3c6b4c3 100644
--- a/llvm/include/llvm/DebugInfo/CodeView/SymbolRecord.h
+++ b/llvm/include/llvm/DebugInfo/CodeView/SymbolRecord.h
@@ -902,6 +902,15 @@ class FrameProcSym : public SymbolRecord {
return decodeFramePtrReg(getEncodedParamFramePtrReg(), CPU);
}
+ CoroutineKind getCoroutineKind() const {
+ return CoroutineKind((uint32_t(Flags) >> 25U) & 7U);
+ }
+
+ void setCoroutineKind(CoroutineKind K) {
+ FrameProcedureOptions CoroFlags{(static_cast<uint32_t>(K) & 7U) << 25U};
+ Flags = (Flags & ~FrameProcedureOptions::CoroutineKindMask) | CoroFlags;
+ }
+
uint32_t RecordOffset = 0;
private:
diff --git a/llvm/lib/DebugInfo/CodeView/EnumTables.cpp b/llvm/lib/DebugInfo/CodeView/EnumTables.cpp
index 92fa1ad8beff9..d5a496a688cf0 100644
--- a/llvm/lib/DebugInfo/CodeView/EnumTables.cpp
+++ b/llvm/lib/DebugInfo/CodeView/EnumTables.cpp
@@ -644,5 +644,18 @@ EnumStrings<uint16_t> getAssociationKindNames() {
return AssociationKindNames;
}
+EnumStrings<uint16_t> getCoroutineKindNames() {
+ constexpr EnumStringDef<uint16_t> CoroutineKindNameDefs[] = {
+ CV_ENUM_CLASS_ENT(CoroutineKind, None),
+ CV_ENUM_CLASS_ENT(CoroutineKind, Primary),
+ CV_ENUM_CLASS_ENT(CoroutineKind, Init),
+ CV_ENUM_CLASS_ENT(CoroutineKind, Resume),
+ CV_ENUM_CLASS_ENT(CoroutineKind, Destroy),
+ };
+ static constexpr auto CoroutineKindNames =
+ BUILD_ENUM_STRINGS(CoroutineKindNameDefs);
+ return CoroutineKindNames;
+}
+
} // end namespace codeview
} // end namespace llvm
diff --git a/llvm/lib/ObjectYAML/CodeViewYAMLSymbols.cpp b/llvm/lib/ObjectYAML/CodeViewYAMLSymbols.cpp
index 9acb38f5f33ed..2ba6e4f91ccbe 100644
--- a/llvm/lib/ObjectYAML/CodeViewYAMLSymbols.cpp
+++ b/llvm/lib/ObjectYAML/CodeViewYAMLSymbols.cpp
@@ -65,6 +65,7 @@ LLVM_YAML_DECLARE_ENUM_TRAITS(JumpTableEntrySize)
LLVM_YAML_DECLARE_ENUM_TRAITS(SourceLanguage)
LLVM_YAML_DECLARE_ENUM_TRAITS(EncodedFramePtrReg)
LLVM_YAML_DECLARE_ENUM_TRAITS(AssociationKind)
+LLVM_YAML_DECLARE_ENUM_TRAITS(CoroutineKind)
LLVM_YAML_STRONG_TYPEDEF(StringRef, TypeName)
@@ -234,6 +235,14 @@ void ScalarEnumerationTraits<AssociationKind>::enumeration(
IO.enumFallback<Hex16>(Kind);
}
+void ScalarEnumerationTraits<CoroutineKind>::enumeration(IO &IO,
+ CoroutineKind &Kind) {
+ auto Names = getCoroutineKindNames();
+ for (const auto &E : Names) {
+ IO.enumCase(Kind, E.name(), static_cast<CoroutineKind>(E.value()));
+ }
+}
+
namespace llvm {
namespace yaml {
template <> struct MappingTraits<LocalVariableAddrRange> {
@@ -545,13 +554,16 @@ template <> void SymbolRecordImpl<FrameProcSym>::map(IO &IO) {
FrameProcedureOptions Flags = Symbol.getFlags();
EncodedFramePtrReg LocalFP = Symbol.getEncodedLocalFramePtrReg();
EncodedFramePtrReg ParamFP = Symbol.getEncodedParamFramePtrReg();
+ CoroutineKind CoroKind = Symbol.getCoroutineKind();
IO.mapRequired("Flags", Flags);
IO.mapOptional("LocalFramePtrReg", LocalFP, EncodedFramePtrReg::None);
IO.mapOptional("ParamFramePtrReg", ParamFP, EncodedFramePtrReg::None);
+ IO.mapOptional("CoroutineKind", CoroKind, CoroutineKind::None);
if (!IO.outputting()) {
Symbol.setFlags(Flags);
Symbol.setEncodedLocalFramePtrReg(LocalFP);
Symbol.setEncodedParamFramePtrReg(ParamFP);
+ Symbol.setCoroutineKind(CoroKind);
}
}
diff --git a/llvm/test/tools/llvm-pdbutil/frameproc-coro-kind.yaml b/llvm/test/tools/llvm-pdbutil/frameproc-coro-kind.yaml
new file mode 100644
index 0000000000000..7730b1b8061ca
--- /dev/null
+++ b/llvm/test/tools/llvm-pdbutil/frameproc-coro-kind.yaml
@@ -0,0 +1,156 @@
+# 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 --minimal %t.pdb > %t.yaml
+# RUN: FileCheck --input-file=%t.yaml --check-prefix=PDB2YAML %s
+
+# YAML2PDB: 4 | S_FRAMEPROC [size = 32]
+# YAML2PDB-NEXT: size = 1, 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 = RSP
+# YAML2PDB-NEXT: flags = has async eh | opt speed
+# YAML2PDB-NEXT: 36 | S_FRAMEPROC [size = 32]
+# YAML2PDB-NEXT: size = 2, 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 = RSP
+# YAML2PDB-NEXT: flags = has async eh | opt speed
+# YAML2PDB-NEXT: 68 | S_FRAMEPROC [size = 32]
+# YAML2PDB-NEXT: size = 3, 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 = RSP
+# YAML2PDB-NEXT: flags = has async eh | opt speed, coroutine kind = primary
+# YAML2PDB-NEXT: 100 | S_FRAMEPROC [size = 32]
+# YAML2PDB-NEXT: size = 4, 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 = RSP
+# YAML2PDB-NEXT: flags = has async eh | opt speed, coroutine kind = init
+# YAML2PDB-NEXT: 132 | S_FRAMEPROC [size = 32]
+# YAML2PDB-NEXT: size = 5, 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 = RSP
+# YAML2PDB-NEXT: flags = has async eh | opt speed, coroutine kind = resume
+# YAML2PDB-NEXT: 164 | S_FRAMEPROC [size = 32]
+# YAML2PDB-NEXT: size = 6, 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 = RSP
+# YAML2PDB-NEXT: flags = has async eh | opt speed, coroutine kind = destroy
+
+# PDB2YAML: - Kind: S_FRAMEPROC
+# PDB2YAML: FrameProcSym:
+# PDB2YAML: TotalFrameBytes: 1
+# Created with --minimal and None is the default.
+# PDB2YAML-NOT: CoroutineKind: None
+
+# PDB2YAML: - Kind: S_FRAMEPROC
+# PDB2YAML: FrameProcSym:
+# PDB2YAML: TotalFrameBytes: 2
+# Created with --minimal and None is the default.
+# PDB2YAML-NOT: CoroutineKind: None
+
+# PDB2YAML: - Kind: S_FRAMEPROC
+# PDB2YAML: FrameProcSym:
+# PDB2YAML: TotalFrameBytes: 3
+# PDB2YAML: CoroutineKind: Primary
+
+# PDB2YAML: - Kind: S_FRAMEPROC
+# PDB2YAML: FrameProcSym:
+# PDB2YAML: TotalFrameBytes: 4
+# PDB2YAML: CoroutineKind: Init
+
+# PDB2YAML: - Kind: S_FRAMEPROC
+# PDB2YAML: FrameProcSym:
+# PDB2YAML: TotalFrameBytes: 5
+# PDB2YAML: CoroutineKind: Resume
+
+# PDB2YAML: - Kind: S_FRAMEPROC
+# PDB2YAML: FrameProcSym:
+# PDB2YAML: TotalFrameBytes: 6
+# PDB2YAML: CoroutineKind: Destroy
+
+---
+DbiStream:
+ VerHeader: V70
+ Age: 1
+ BuildNumber: 36403
+ PdbDllVersion: 36257
+ PdbDllRbld: 0
+ Flags: 1
+ MachineType: Amd64
+ Modules:
+ - Module: '/tmp/test.obj'
+ ObjFile: '/tmp/test.obj'
+ Modi:
+ Signature: 4
+ Records:
+ - Kind: S_FRAMEPROC
+ FrameProcSym:
+ TotalFrameBytes: 1
+ PaddingFrameBytes: 0
+ OffsetToPadding: 0
+ BytesOfCalleeSavedRegisters: 0
+ OffsetOfExceptionHandler: 0
+ SectionIdOfExceptionHandler: 0
+ Flags: [ AsynchronousExceptionHandling, OptimizedForSpeed ]
+ LocalFramePtrReg: StackPtr
+ ParamFramePtrReg: StackPtr
+ - Kind: S_FRAMEPROC
+ FrameProcSym:
+ TotalFrameBytes: 2
+ PaddingFrameBytes: 0
+ OffsetToPadding: 0
+ BytesOfCalleeSavedRegisters: 0
+ OffsetOfExceptionHandler: 0
+ SectionIdOfExceptionHandler: 0
+ Flags: [ AsynchronousExceptionHandling, OptimizedForSpeed ]
+ LocalFramePtrReg: StackPtr
+ ParamFramePtrReg: StackPtr
+ CoroutineKind: None
+ - Kind: S_FRAMEPROC
+ FrameProcSym:
+ TotalFrameBytes: 3
+ PaddingFrameBytes: 0
+ OffsetToPadding: 0
+ BytesOfCalleeSavedRegisters: 0
+ OffsetOfExceptionHandler: 0
+ SectionIdOfExceptionHandler: 0
+ Flags: [ AsynchronousExceptionHandling, OptimizedForSpeed ]
+ LocalFramePtrReg: StackPtr
+ ParamFramePtrReg: StackPtr
+ CoroutineKind: Primary
+ - Kind: S_FRAMEPROC
+ FrameProcSym:
+ TotalFrameBytes: 4
+ PaddingFrameBytes: 0
+ OffsetToPadding: 0
+ BytesOfCalleeSavedRegisters: 0
+ OffsetOfExceptionHandler: 0
+ SectionIdOfExceptionHandler: 0
+ Flags: [ AsynchronousExceptionHandling, OptimizedForSpeed ]
+ LocalFramePtrReg: StackPtr
+ ParamFramePtrReg: StackPtr
+ CoroutineKind: Init
+ - Kind: S_FRAMEPROC
+ FrameProcSym:
+ TotalFrameBytes: 5
+ PaddingFrameBytes: 0
+ OffsetToPadding: 0
+ BytesOfCalleeSavedRegisters: 0
+ OffsetOfExceptionHandler: 0
+ SectionIdOfExceptionHandler: 0
+ Flags: [ AsynchronousExceptionHandling, OptimizedForSpeed ]
+ LocalFramePtrReg: StackPtr
+ ParamFramePtrReg: StackPtr
+ CoroutineKind: Resume
+ - Kind: S_FRAMEPROC
+ FrameProcSym:
+ TotalFrameBytes: 6
+ PaddingFrameBytes: 0
+ OffsetToPadding: 0
+ BytesOfCalleeSavedRegisters: 0
+ OffsetOfExceptionHandler: 0
+ SectionIdOfExceptionHandler: 0
+ Flags: [ AsynchronousExceptionHandling, OptimizedForSpeed ]
+ LocalFramePtrReg: StackPtr
+ ParamFramePtrReg: StackPtr
+ CoroutineKind: Destroy
+...
diff --git a/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.cpp b/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.cpp
index f3abc000430e2..6e83249efe2be 100644
--- a/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.cpp
+++ b/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.cpp
@@ -138,6 +138,17 @@ static std::string formatFrameProcedureOptions(uint32_t IndentLevel,
return typesetItemList(Opts, 4, IndentLevel, " | ");
}
+static std::string formatCoroutineKind(CoroutineKind Kind) {
+ switch (Kind) {
+ RETURN_CASE(CoroutineKind, None, "none");
+ RETURN_CASE(CoroutineKind, Primary, "primary");
+ RETURN_CASE(CoroutineKind, Init, "init");
+ RETURN_CASE(CoroutineKind, Resume, "resume");
+ RETURN_CASE(CoroutineKind, Destroy, "destroy");
+ }
+ return formatUnknownEnum(Kind);
+}
+
static std::string formatPublicSymFlags(uint32_t IndentLevel,
PublicSymFlags Flags) {
std::vector<std::string> Opts;
@@ -727,6 +738,10 @@ Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, FrameProcSym &FP) {
formatRegisterId(FP.getParamFramePtrReg(CompilationCPU), CompilationCPU));
P.formatLine("flags = {0}",
formatFrameProcedureOptions(P.getIndentLevel() + 9, FP.Flags));
+ if (FP.getCoroutineKind() != CoroutineKind::None) {
+ P.format(", coroutine kind = {0}",
+ formatCoroutineKind(FP.getCoroutineKind()));
+ }
return Error::success();
}
More information about the llvm-commits
mailing list