[llvm] 93d256b - [llvm-pdbutil] Hash type records in yaml2pdb (#187593)

via llvm-commits llvm-commits at lists.llvm.org
Sat Mar 21 09:38:58 PDT 2026


Author: Nerixyz
Date: 2026-03-21T17:38:52+01:00
New Revision: 93d256b076b12bf30e546910d9ae473ec93146c0

URL: https://github.com/llvm/llvm-project/commit/93d256b076b12bf30e546910d9ae473ec93146c0
DIFF: https://github.com/llvm/llvm-project/commit/93d256b076b12bf30e546910d9ae473ec93146c0.diff

LOG: [llvm-pdbutil] Hash type records in yaml2pdb (#187593)

The TPI and IPI streams didn't include a hash map for the generated
types, because the types never got hashes. A hash map is necessary to
resolve forward references when dumping the PDB (checks for
`TpiStream::supportsTypeLookup` which checks the hash map).

With this PR, the hashes are generated. There's no good test that we do
this for the IPI stream as well, because it doesn't have forward
references.

Added: 
    llvm/test/tools/llvm-pdbutil/Inputs/forward-refs1.yaml
    llvm/test/tools/llvm-pdbutil/Inputs/forward-refs2.yaml
    llvm/test/tools/llvm-pdbutil/merged-forward-refs.test

Modified: 
    llvm/include/llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h
    llvm/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp
    llvm/test/DebugInfo/PDB/pdbdump-mergetypes.test
    llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h b/llvm/include/llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h
index 255abb0e3e8d4..85d47a9229d3a 100644
--- a/llvm/include/llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h
+++ b/llvm/include/llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h
@@ -46,8 +46,7 @@ class TpiStreamBuilder {
   TpiStreamBuilder &operator=(const TpiStreamBuilder &) = delete;
 
   LLVM_ABI void setVersionHeader(PdbRaw_TpiVer Version);
-  LLVM_ABI void addTypeRecord(ArrayRef<uint8_t> Type,
-                              std::optional<uint32_t> Hash);
+  LLVM_ABI void addTypeRecord(ArrayRef<uint8_t> Type, uint32_t Hash);
   LLVM_ABI void addTypeRecords(ArrayRef<uint8_t> Types,
                                ArrayRef<uint16_t> Sizes,
                                ArrayRef<uint32_t> Hashes);

diff  --git a/llvm/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp b/llvm/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp
index a33f147ffd051..9e95a75257396 100644
--- a/llvm/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp
@@ -54,8 +54,7 @@ void TpiStreamBuilder::updateTypeIndexOffsets(ArrayRef<uint16_t> Sizes) {
   }
 }
 
-void TpiStreamBuilder::addTypeRecord(ArrayRef<uint8_t> Record,
-                                     std::optional<uint32_t> Hash) {
+void TpiStreamBuilder::addTypeRecord(ArrayRef<uint8_t> Record, uint32_t Hash) {
   assert(((Record.size() & 3) == 0) &&
          "The type record's size is not a multiple of 4 bytes which will "
          "cause misalignment in the output TPI stream!");
@@ -64,9 +63,7 @@ void TpiStreamBuilder::addTypeRecord(ArrayRef<uint8_t> Record,
   updateTypeIndexOffsets(ArrayRef(&OneSize, 1));
 
   TypeRecBuffers.push_back(Record);
-  // FIXME: Require it.
-  if (Hash)
-    TypeHashes.push_back(*Hash);
+  TypeHashes.push_back(Hash);
 }
 
 void TpiStreamBuilder::addTypeRecords(ArrayRef<uint8_t> Types,

diff  --git a/llvm/test/DebugInfo/PDB/pdbdump-mergetypes.test b/llvm/test/DebugInfo/PDB/pdbdump-mergetypes.test
index 60cf4a172aa2a..04ae0755566b7 100644
--- a/llvm/test/DebugInfo/PDB/pdbdump-mergetypes.test
+++ b/llvm/test/DebugInfo/PDB/pdbdump-mergetypes.test
@@ -14,7 +14,7 @@ MERGED-NEXT:            referent = 0x0076 (__int64), mode = pointer, opts = None
 MERGED-NEXT:   0x1002 | LF_STRUCTURE [size = 48] `OnlyInMerge1`
 MERGED-NEXT:            unique name: `OnlyInMerge1`
 MERGED-NEXT:            vtable: <no type>, base list: <no type>, field list: <no type>
-MERGED-NEXT:            options: forward ref | has unique name
+MERGED-NEXT:            options: forward ref (= 0x1002) | has unique name
 MERGED-NEXT:   0x1003 | LF_POINTER [size = 12]
 MERGED-NEXT:            referent = 0x1000, mode = pointer, opts = None, kind = ptr32
 MERGED-NEXT:   0x1004 | LF_POINTER [size = 12]
@@ -31,4 +31,4 @@ MERGED-NEXT:            calling conv = cdecl, options = None
 MERGED-NEXT:   0x1008 | LF_STRUCTURE [size = 48] `OnlyInMerge2`
 MERGED-NEXT:            unique name: `OnlyInMerge2`
 MERGED-NEXT:            vtable: <no type>, base list: <no type>, field list: <no type>
-MERGED-NEXT:            options: forward ref | has unique name
+MERGED-NEXT:            options: forward ref (= 0x1008) | has unique name

diff  --git a/llvm/test/tools/llvm-pdbutil/Inputs/forward-refs1.yaml b/llvm/test/tools/llvm-pdbutil/Inputs/forward-refs1.yaml
new file mode 100644
index 0000000000000..f403485d529bf
--- /dev/null
+++ b/llvm/test/tools/llvm-pdbutil/Inputs/forward-refs1.yaml
@@ -0,0 +1,63 @@
+---
+TpiStream:
+  Version:         VC80
+  Records:
+    - Kind:            LF_ARGLIST
+      ArgList:
+        ArgIndices:      [  ]
+    - Kind:            LF_PROCEDURE
+      Procedure:
+        ReturnType:      116
+        CallConv:        NearC
+        Options:         [ None ]
+        ParameterCount:  0
+        ArgumentList:    4096
+    - Kind:            LF_STRUCTURE
+      Class:
+        MemberCount:     0
+        Options:         [ None, ForwardReference, HasUniqueName ]
+        FieldList:       0
+        Name:            Foo
+        UniqueName:      '.?AUFoo@@'
+        DerivationList:  0
+        VTableShape:     0
+        Size:            0
+    - Kind:            LF_POINTER
+      Pointer:
+        ReferentType:    4098
+        Attrs:           65548
+    - Kind:            LF_MFUNCTION
+      MemberFunction:
+        ReturnType:      3
+        ClassType:       4098
+        ThisType:        4099
+        CallConv:        NearC
+        Options:         [ None, Constructor ]
+        ParameterCount:  0
+        ArgumentList:    4096
+        ThisPointerAdjustment: 0
+    - Kind:            LF_FIELDLIST
+      FieldList:
+        - Kind:            LF_MEMBER
+          DataMember:
+            Attrs:           3
+            Type:            116
+            FieldOffset:     0
+            Name:            a
+        - Kind:            LF_ONEMETHOD
+          OneMethod:
+            Type:            4100
+            Attrs:           259
+            VFTableOffset:   -1
+            Name:            Foo
+    - Kind:            LF_STRUCTURE
+      Class:
+        MemberCount:     2
+        Options:         [ None, HasConstructorOrDestructor, HasUniqueName ]
+        FieldList:       4101
+        Name:            Foo
+        UniqueName:      '.?AUFoo@@'
+        DerivationList:  0
+        VTableShape:     0
+        Size:            4
+...

diff  --git a/llvm/test/tools/llvm-pdbutil/Inputs/forward-refs2.yaml b/llvm/test/tools/llvm-pdbutil/Inputs/forward-refs2.yaml
new file mode 100644
index 0000000000000..23f0a70c433b3
--- /dev/null
+++ b/llvm/test/tools/llvm-pdbutil/Inputs/forward-refs2.yaml
@@ -0,0 +1,64 @@
+---
+# Essentially the same as forward-refs1.yaml but with struct Bar { int b; };
+TpiStream:
+  Version:         VC80
+  Records:
+    - Kind:            LF_ARGLIST
+      ArgList:
+        ArgIndices:      [  ]
+    - Kind:            LF_PROCEDURE
+      Procedure:
+        ReturnType:      116
+        CallConv:        NearC
+        Options:         [ None ]
+        ParameterCount:  0
+        ArgumentList:    4096
+    - Kind:            LF_STRUCTURE
+      Class:
+        MemberCount:     0
+        Options:         [ None, ForwardReference, HasUniqueName ]
+        FieldList:       0
+        Name:            Bar
+        UniqueName:      '.?AUBar@@'
+        DerivationList:  0
+        VTableShape:     0
+        Size:            0
+    - Kind:            LF_POINTER
+      Pointer:
+        ReferentType:    4098
+        Attrs:           65548
+    - Kind:            LF_MFUNCTION
+      MemberFunction:
+        ReturnType:      3
+        ClassType:       4098
+        ThisType:        4099
+        CallConv:        NearC
+        Options:         [ None, Constructor ]
+        ParameterCount:  0
+        ArgumentList:    4096
+        ThisPointerAdjustment: 0
+    - Kind:            LF_FIELDLIST
+      FieldList:
+        - Kind:            LF_MEMBER
+          DataMember:
+            Attrs:           3
+            Type:            116
+            FieldOffset:     0
+            Name:            b
+        - Kind:            LF_ONEMETHOD
+          OneMethod:
+            Type:            4100
+            Attrs:           259
+            VFTableOffset:   -1
+            Name:            Bar
+    - Kind:            LF_STRUCTURE
+      Class:
+        MemberCount:     2
+        Options:         [ None, HasConstructorOrDestructor, HasUniqueName ]
+        FieldList:       4101
+        Name:            Bar
+        UniqueName:      '.?AUBar@@'
+        DerivationList:  0
+        VTableShape:     0
+        Size:            4
+...

diff  --git a/llvm/test/tools/llvm-pdbutil/merged-forward-refs.test b/llvm/test/tools/llvm-pdbutil/merged-forward-refs.test
new file mode 100644
index 0000000000000..425d7f6edd0b6
--- /dev/null
+++ b/llvm/test/tools/llvm-pdbutil/merged-forward-refs.test
@@ -0,0 +1,35 @@
+# RUN: llvm-pdbutil yaml2pdb %p/Inputs/forward-refs1.yaml --pdb=%t.1.pdb
+# RUN: llvm-pdbutil yaml2pdb %p/Inputs/forward-refs2.yaml --pdb=%t.2.pdb
+# RUN: llvm-pdbutil merge %t.1.pdb %t.2.pdb --pdb=%t.pdb
+# RUN: llvm-pdbutil dump --types %t.1.pdb | FileCheck %s --check-prefix=ONE
+# RUN: llvm-pdbutil dump --types %t.2.pdb | FileCheck %s --check-prefix=TWO
+# RUN: llvm-pdbutil dump --types %t.pdb | FileCheck %s --check-prefix=MERGED
+
+# Test that forward references can be found after merging (requires type hashes).
+
+# ONE:       0x1002 | LF_STRUCTURE [size = 36] `Foo`
+# ONE-NEXT:           unique name: `.?AUFoo@@`
+# ONE-NEXT:           vtable: <no type>, base list: <no type>, field list: <no type>
+# ONE-NEXT:           options: forward ref (-> 0x1006) | has unique name, sizeof 0
+# ONE:       0x1006 | LF_STRUCTURE [size = 36] `Foo`
+# ONE-NEXT:           unique name: `.?AUFoo@@`
+
+# TWO:       0x1002 | LF_STRUCTURE [size = 36] `Bar`
+# TWO-NEXT:           unique name: `.?AUBar@@`
+# TWO-NEXT:           vtable: <no type>, base list: <no type>, field list: <no type>
+# TWO-NEXT:           options: forward ref (-> 0x1006) | has unique name, sizeof 0
+# TWO:       0x1006 | LF_STRUCTURE [size = 36] `Bar`
+# TWO-NEXT:           unique name: `.?AUBar@@`
+
+# MERGED:       0x1002 | LF_STRUCTURE [size = 36] `Foo`
+# MERGED-NEXT:           unique name: `.?AUFoo@@`
+# MERGED-NEXT:           vtable: <no type>, base list: <no type>, field list: <no type>
+# MERGED-NEXT:           options: forward ref (-> 0x1006) | has unique name, sizeof 0
+# MERGED:       0x1006 | LF_STRUCTURE [size = 36] `Foo`
+# MERGED-NEXT:           unique name: `.?AUFoo@@`
+# MERGED:       0x1007 | LF_STRUCTURE [size = 36] `Bar`
+# MERGED-NEXT:           unique name: `.?AUBar@@`
+# MERGED-NEXT:           vtable: <no type>, base list: <no type>, field list: <no type>
+# MERGED-NEXT:           options: forward ref (-> 0x100B) | has unique name, sizeof 0
+# MERGED:       0x100B | LF_STRUCTURE [size = 36] `Bar`
+# MERGED-NEXT:           unique name: `.?AUBar@@`

diff  --git a/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp b/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp
index befd33171ed0a..16ecc59b0db87 100644
--- a/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp
+++ b/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp
@@ -60,6 +60,7 @@
 #include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h"
 #include "llvm/DebugInfo/PDB/Native/RawConstants.h"
 #include "llvm/DebugInfo/PDB/Native/RawError.h"
+#include "llvm/DebugInfo/PDB/Native/TpiHashing.h"
 #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
 #include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h"
 #include "llvm/DebugInfo/PDB/PDB.h"
@@ -889,7 +890,8 @@ static void yamlToPdb(StringRef Path) {
   AppendingTypeTableBuilder TS(Allocator);
   for (const auto &R : Tpi.Records) {
     CVType Type = R.toCodeViewRecord(TS);
-    TpiBuilder.addTypeRecord(Type.RecordData, std::nullopt);
+    uint32_t Hash = ExitOnErr(llvm::pdb::hashTypeRecord(Type));
+    TpiBuilder.addTypeRecord(Type.RecordData, Hash);
   }
 
   const auto &Ipi = YamlObj.IpiStream.value_or(DefaultIpiStream);
@@ -897,7 +899,8 @@ static void yamlToPdb(StringRef Path) {
   IpiBuilder.setVersionHeader(Ipi.Version);
   for (const auto &R : Ipi.Records) {
     CVType Type = R.toCodeViewRecord(TS);
-    IpiBuilder.addTypeRecord(Type.RecordData, std::nullopt);
+    uint32_t Hash = ExitOnErr(llvm::pdb::hashTypeRecord(Type));
+    IpiBuilder.addTypeRecord(Type.RecordData, Hash);
   }
 
   if (YamlObj.PublicsStream) {
@@ -1395,10 +1398,12 @@ static void mergePdbs() {
   auto &DestTpi = Builder.getTpiBuilder();
   auto &DestIpi = Builder.getIpiBuilder();
   MergedTpi.ForEachRecord([&DestTpi](TypeIndex TI, const CVType &Type) {
-    DestTpi.addTypeRecord(Type.RecordData, std::nullopt);
+    uint32_t Hash = ExitOnErr(llvm::pdb::hashTypeRecord(Type));
+    DestTpi.addTypeRecord(Type.RecordData, Hash);
   });
   MergedIpi.ForEachRecord([&DestIpi](TypeIndex TI, const CVType &Type) {
-    DestIpi.addTypeRecord(Type.RecordData, std::nullopt);
+    uint32_t Hash = ExitOnErr(llvm::pdb::hashTypeRecord(Type));
+    DestIpi.addTypeRecord(Type.RecordData, Hash);
   });
   Builder.getInfoBuilder().addFeature(PdbRaw_FeatureSig::VC140);
 


        


More information about the llvm-commits mailing list