Skip to content

Conversation

@sivadeilra
Copy link
Contributor

This PR provides more information to debuggers and analysis tools on Windows. It adds S_LABEL32 symbols for each target BB of each jump table. This allows debuggers to insert symbolic labels when disassembling code. S_LABEL32 symbol records indicate that a location is definitely code, and can optionally associate a string label with the code location. BBs generated for jump tables may or may not have string labels, so it is acceptable for the "name" field within S_LABEL32 symbols to be an empty string.

More importantly, this PR allows Windows analysis tools, such as those that generate hot-patches for the Windows kernel, to use these labels to distinguish code basic blocks from data blocks. Microsoft's analysis tools (similar to Bolt) rely on being able to identify all code blocks, so that the tools can traverse all instructions and verify that important requirements for hot-patching are met.

This PR has no effect on code generation. It only affects the CodeView symbols that are emitted into OBJ files, which the linker then repackages into PDB files.

@llvmbot
Copy link
Member

llvmbot commented Jun 27, 2025

@llvm/pr-subscribers-platform-windows

@llvm/pr-subscribers-debuginfo

Author: None (sivadeilra)

Changes

This PR provides more information to debuggers and analysis tools on Windows. It adds S_LABEL32 symbols for each target BB of each jump table. This allows debuggers to insert symbolic labels when disassembling code. S_LABEL32 symbol records indicate that a location is definitely code, and can optionally associate a string label with the code location. BBs generated for jump tables may or may not have string labels, so it is acceptable for the "name" field within S_LABEL32 symbols to be an empty string.

More importantly, this PR allows Windows analysis tools, such as those that generate hot-patches for the Windows kernel, to use these labels to distinguish code basic blocks from data blocks. Microsoft's analysis tools (similar to Bolt) rely on being able to identify all code blocks, so that the tools can traverse all instructions and verify that important requirements for hot-patching are met.

This PR has no effect on code generation. It only affects the CodeView symbols that are emitted into OBJ files, which the linker then repackages into PDB files.


Full diff: https://github.com/llvm/llvm-project/pull/146121.diff

3 Files Affected:

  • (modified) llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp (+28-5)
  • (modified) llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h (+1)
  • (modified) llvm/test/DebugInfo/COFF/jump-table.ll (+9)
diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
index 5e1b313b4d2fa..91cf7c17f7cb0 100644
--- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
@@ -3566,15 +3566,38 @@ void CodeViewDebug::collectDebugInfoForJumpTables(const MachineFunction *MF,
           break;
         }
 
-        CurFn->JumpTables.push_back(
-            {EntrySize, Base, BaseOffset, Branch,
-             MF->getJTISymbol(JumpTableIndex, MMI->getContext()),
-             JTI.getJumpTables()[JumpTableIndex].MBBs.size()});
+        const MachineJumpTableEntry &JTE = JTI.getJumpTables()[JumpTableIndex];
+
+        JumpTableInfo CVJTI{EntrySize,
+                            Base,
+                            BaseOffset,
+                            Branch,
+                            MF->getJTISymbol(JumpTableIndex, MMI->getContext()),
+                            JTE.MBBs.size()};
+
+        for (const auto &MBB : JTE.MBBs) {
+          CVJTI.Cases.push_back(MBB->getSymbol());
+        }
+
+        CurFn->JumpTables.push_back(std::move(CVJTI));
       });
 }
 
 void CodeViewDebug::emitDebugInfoForJumpTables(const FunctionInfo &FI) {
-  for (auto JumpTable : FI.JumpTables) {
+  // Emit S_LABEL32 records for each jump target
+  for (const auto &JumpTable : FI.JumpTables) {
+    for (const auto &CaseSym : JumpTable.Cases) {
+      MCSymbol *LabelEnd = beginSymbolRecord(SymbolKind::S_LABEL32);
+      OS.AddComment("Offset and segment");
+      OS.emitCOFFSecRel32(CaseSym, 0);
+      OS.AddComment("Flags");
+      OS.emitInt8(0);
+      emitNullTerminatedSymbolName(OS, CaseSym->getName());
+      endSymbolRecord(LabelEnd);
+    }
+  }
+
+  for (const auto &JumpTable : FI.JumpTables) {
     MCSymbol *JumpTableEnd = beginSymbolRecord(SymbolKind::S_ARMSWITCHTABLE);
     if (JumpTable.Base) {
       OS.AddComment("Base offset");
diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h
index c862802d835d7..c2b878e52e1c3 100644
--- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h
+++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h
@@ -146,6 +146,7 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase {
     const MCSymbol *Branch;
     const MCSymbol *Table;
     size_t TableSize;
+    std::vector<const MCSymbol *> Cases;
   };
 
   // For each function, store a vector of labels to its instructions, as well as
diff --git a/llvm/test/DebugInfo/COFF/jump-table.ll b/llvm/test/DebugInfo/COFF/jump-table.ll
index 3eda2438ea88a..be1de2be55788 100644
--- a/llvm/test/DebugInfo/COFF/jump-table.ll
+++ b/llvm/test/DebugInfo/COFF/jump-table.ll
@@ -118,6 +118,15 @@
 ; CV:         GlobalProcIdSym {
 ; CV:           DisplayName: func
 ; CV-NOT:     GlobalProcIdSym
+; CV:           LabelSym {
+; CV-NEXT:        Kind: S_LABEL32 (0x1105)
+; CV-NEXT:        CodeOffset: 0xC0
+; CV-NEXT:        Segment: 0x0
+; CV-NEXT:        Flags: 0x0
+; CV-NEXT:        Flags [ (0x0)
+; CV-NEXT:        ]
+; CV-NEXT:        DisplayName:
+; CV-NEXT:      }
 ; CV:           JumpTableSym {
 ; CV-NEXT:        Kind: S_ARMSWITCHTABLE (0x1159)
 ; CV-NEXT:        BaseOffset: 0x0

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We usually don't add blank lines after variable declarations.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks; updated.

PR feedback, style
@sivadeilra sivadeilra force-pushed the user/ardavis/jump-table-labels branch from f3881a5 to 1beede6 Compare July 1, 2025 21:36
@sivadeilra
Copy link
Contributor Author

@MaskRay Any more feedback on this PR?

@dpaoliello dpaoliello merged commit 9923565 into llvm:main Jul 7, 2025
7 checks passed
@sivadeilra
Copy link
Contributor Author

Post-build jobs show a warning in CodeViewDebug.cpp. It's a one-line fix; PR for fix in just a few minutes.

dpaoliello pushed a commit that referenced this pull request Jul 7, 2025
#146121 caused a build warning in a post-CI job. The fix should be
trivial; provide an extra initializer element when initializing a class,
for the additional field.
bonsthie pushed a commit to bonsthie/llvm-project that referenced this pull request Jul 22, 2025
llvm#146121 caused a build warning in a post-CI job. The fix should be
trivial; provide an extra initializer element when initializing a class,
for the additional field.
steven-studio pushed a commit to steven-studio/llvm-project that referenced this pull request Sep 11, 2025
llvm#146121 caused a build warning in a post-CI job. The fix should be
trivial; provide an extra initializer element when initializing a class,
for the additional field.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants