[llvm] [CodeView] Read and dump LF_ALIAS (PR #218243)

via llvm-commits llvm-commits at lists.llvm.org
Sun Aug 23 06:55:54 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-platform-windows

Author: Nerixyz (Nerixyz)

<details>
<summary>Changes</summary>

Most of this is taken from #<!-- -->153936. It only implements the read/dump/reconstruct part of #<!-- -->153936 - it doesn't change the generated debug info.

`LF_ALIAS` represents a typedef `typedef UnderlyingType Name`. MSVC 19.52.36615 (currently the preview version) can generate it by passing `/d1typeAliasDebugRecords`. I used that version to test my change. From what I can tell, MSVC only generates that record for integer types (not even pointers to integers). No clue why.

In
```cpp
typedef char16_t MyByte;
using U16 = char16_t;
struct Foo {
  int bar = 1;
};
using Baz = Foo;
int main() {
  using Inner = char;
  using InnerPtr = char *;
  const MyByte *something = u"a string";
  const U16 *another = u"abc";
  Inner a = '+';
  const Inner *inner = "abc";
  InnerPtr ip = &a;
  Baz baz;
  Baz *bp = &baz;
}
```
`Foo` and `InnerPtr` won't get an `LF_ALIAS`. The type of `baz` will be `Foo` and `ip` will be `char*`.
Furthermore, Visual Studio's debugger will fail to inspect `a`. The others show fine. I think it can only handle aliases when they go through a pointer/reference.

The following additions were made compared to #<!-- -->153936:

- Changed the hash for `LF_ALIAS` to only include the name - it's considered a UDT, so only the name is hashed: https://github.com/microsoft/microsoft-pdb/blob/805655a28bd8198004be2ac27e6e0290121a5e89/PDB/dbi/tpi.cpp#L1888-L1890
- Discover the type index inside the record for remapping when linking.

---

Co-authored-by: Walnut <ant_b356@<!-- -->me.com>

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


13 Files Affected:

- (modified) llvm/include/llvm/DebugInfo/CodeView/CodeViewTypes.def (+1-1) 
- (modified) llvm/include/llvm/DebugInfo/CodeView/TypeRecord.h (+13) 
- (modified) llvm/include/llvm/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.h (+2) 
- (modified) llvm/lib/DebugInfo/CodeView/RecordName.cpp (+5) 
- (modified) llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp (+6) 
- (modified) llvm/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp (+3) 
- (modified) llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp (+6) 
- (modified) llvm/lib/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.cpp (+12) 
- (modified) llvm/lib/DebugInfo/PDB/Native/TpiHashing.cpp (+11-1) 
- (modified) llvm/lib/ObjectYAML/CodeViewYAMLTypes.cpp (+5) 
- (added) llvm/test/tools/llvm-pdbutil/alias-record.test (+45) 
- (modified) llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp (+5) 
- (modified) llvm/unittests/DebugInfo/CodeView/TypeIndexDiscoveryTest.cpp (+6) 


``````````diff
diff --git a/llvm/include/llvm/DebugInfo/CodeView/CodeViewTypes.def b/llvm/include/llvm/DebugInfo/CodeView/CodeViewTypes.def
index 86a74292dbb11..be0e81edbbb34 100644
--- a/llvm/include/llvm/DebugInfo/CodeView/CodeViewTypes.def
+++ b/llvm/include/llvm/DebugInfo/CodeView/CodeViewTypes.def
@@ -50,6 +50,7 @@ TYPE_RECORD_ALIAS(LF_STRUCTURE, 0x1505, Struct, Class)
 TYPE_RECORD_ALIAS(LF_INTERFACE, 0x1519, Interface, Class)
 TYPE_RECORD(LF_UNION, 0x1506, Union)
 TYPE_RECORD(LF_ENUM, 0x1507, Enum)
+TYPE_RECORD(LF_ALIAS, 0x150a, Alias)
 TYPE_RECORD(LF_TYPESERVER2, 0x1515, TypeServer2)
 TYPE_RECORD(LF_VFTABLE, 0x151d, VFTable)
 TYPE_RECORD(LF_VTSHAPE, 0x000a, VFTableShape)
@@ -187,7 +188,6 @@ CV_TYPE(LF_MANAGED_ST, 0x140f)
 CV_TYPE(LF_ST_MAX, 0x1500)
 CV_TYPE(LF_TYPESERVER, 0x1501)
 CV_TYPE(LF_DIMARRAY, 0x1508)
-CV_TYPE(LF_ALIAS, 0x150a)
 CV_TYPE(LF_DEFARG, 0x150b)
 CV_TYPE(LF_FRIENDFCN, 0x150c)
 CV_TYPE(LF_NESTTYPEEX, 0x1512)
diff --git a/llvm/include/llvm/DebugInfo/CodeView/TypeRecord.h b/llvm/include/llvm/DebugInfo/CodeView/TypeRecord.h
index 5a84fac5f5903..1b937a8621f7a 100644
--- a/llvm/include/llvm/DebugInfo/CodeView/TypeRecord.h
+++ b/llvm/include/llvm/DebugInfo/CodeView/TypeRecord.h
@@ -952,6 +952,19 @@ class EndPrecompRecord : public TypeRecord {
   uint32_t Signature = 0;
 };
 
+/// `LF_ALIAS` - A typedef where `Name` is typedef'd to `UnderlyingType`.
+class AliasRecord : public TypeRecord {
+public:
+  AliasRecord() = default;
+  explicit AliasRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
+  AliasRecord(TypeIndex UnderlyingType, StringRef Name)
+      : TypeRecord(TypeRecordKind::Alias), UnderlyingType(UnderlyingType),
+        Name(Name) {}
+
+  TypeIndex UnderlyingType;
+  StringRef Name;
+};
+
 } // end namespace codeview
 } // end namespace llvm
 
diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.h b/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.h
index 2d1bfa6f8dcb9..bd02829c28cbe 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.h
@@ -428,6 +428,8 @@ class LVLogicalVisitor final {
                                   TypeIndex TI, LVElement *Element);
   LLVM_ABI Error visitKnownRecord(CVType &Record, EndPrecompRecord &EndPrecomp,
                                   TypeIndex TI, LVElement *Element);
+  LLVM_ABI Error visitKnownRecord(CVType &Record, AliasRecord &Alias,
+                                  TypeIndex TI, LVElement *Element);
 
   LLVM_ABI Error visitUnknownMember(CVMemberRecord &Record, TypeIndex TI);
   LLVM_ABI Error visitKnownMember(CVMemberRecord &Record, BaseClassRecord &Base,
diff --git a/llvm/lib/DebugInfo/CodeView/RecordName.cpp b/llvm/lib/DebugInfo/CodeView/RecordName.cpp
index 476f9bb935379..32b2267c06b3b 100644
--- a/llvm/lib/DebugInfo/CodeView/RecordName.cpp
+++ b/llvm/lib/DebugInfo/CodeView/RecordName.cpp
@@ -251,6 +251,11 @@ Error TypeNameComputer::visitKnownRecord(CVType &CVR,
   return Error::success();
 }
 
+Error TypeNameComputer::visitKnownRecord(CVType &CVR, AliasRecord &Alias) {
+  Name = Alias.Name;
+  return Error::success();
+}
+
 std::string llvm::codeview::computeTypeName(TypeCollection &Types,
                                             TypeIndex Index) {
   TypeNameComputer Computer(Types);
diff --git a/llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp b/llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp
index 7dd2bad7da2e1..00f309ce45446 100644
--- a/llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp
+++ b/llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp
@@ -439,3 +439,9 @@ Error TypeDumpVisitor::visitKnownRecord(CVType &CVR,
   W->printHex("Signature", EndPrecomp.getSignature());
   return Error::success();
 }
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, AliasRecord &Alias) {
+  printTypeIndex("UnderlyingType", Alias.UnderlyingType);
+  W->printString("Name", Alias.Name);
+  return Error::success();
+}
diff --git a/llvm/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp b/llvm/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp
index c19e72187fc9c..38264aa12b3d6 100644
--- a/llvm/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp
+++ b/llvm/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp
@@ -352,6 +352,9 @@ static void discoverTypeIndices(ArrayRef<uint8_t> Content, TypeLeafKind Kind,
   case TypeLeafKind::LF_POINTER:
     handlePointer(Content, Refs);
     break;
+  case TypeLeafKind::LF_ALIAS:
+    Refs.push_back({TiRefKind::TypeRef, 0, 1}); // UnderlyingType
+    break;
   default:
     break;
   }
diff --git a/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp b/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp
index e8c9744935bf7..ea436e846e0ee 100644
--- a/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp
+++ b/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp
@@ -721,3 +721,9 @@ Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
   error(IO.mapInteger(EndPrecomp.Signature, "Signature"));
   return Error::success();
 }
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR, AliasRecord &Alias) {
+  error(IO.mapInteger(Alias.UnderlyingType, "UnderlyingType"));
+  error(IO.mapStringZ(Alias.Name, "Name"));
+  return Error::success();
+}
diff --git a/llvm/lib/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.cpp b/llvm/lib/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.cpp
index 7320a188051bb..5f6b0f513d37d 100644
--- a/llvm/lib/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.cpp
@@ -2671,6 +2671,18 @@ Error LVLogicalVisitor::visitKnownRecord(CVType &Record,
   return Error::success();
 }
 
+// LF_ALIAS (TPI)
+Error LVLogicalVisitor::visitKnownRecord(CVType &Record, AliasRecord &Alias,
+                                         TypeIndex TI, LVElement *Element) {
+  LLVM_DEBUG({
+    printTypeBegin(Record, TI, Element, StreamTPI);
+    printTypeIndex("UnderlyingType", Alias.UnderlyingType, StreamTPI);
+    W.printString("Name", Alias.Name);
+    printTypeEnd(Record);
+  });
+  return Error::success();
+}
+
 Error LVLogicalVisitor::visitUnknownMember(CVMemberRecord &Record,
                                            TypeIndex TI) {
   LLVM_DEBUG({ W.printHex("UnknownMember", unsigned(Record.Kind)); });
diff --git a/llvm/lib/DebugInfo/PDB/Native/TpiHashing.cpp b/llvm/lib/DebugInfo/PDB/Native/TpiHashing.cpp
index 941ce78027a21..28967d55324c0 100644
--- a/llvm/lib/DebugInfo/PDB/Native/TpiHashing.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/TpiHashing.cpp
@@ -85,6 +85,15 @@ static Expected<uint32_t> getSourceLineHash(const CVType &Rec) {
   return hashStringV1(StringRef(Buf, 4));
 }
 
+// LF_ALIAS is considered a UDT, so only the name is hashed.
+static Expected<uint32_t> getHashForAlias(const CVType &Rec) {
+  AliasRecord Deserialized;
+  if (auto E = TypeDeserializer::deserializeAs(const_cast<CVType &>(Rec),
+                                               Deserialized))
+    return std::move(E);
+  return hashStringV1(Deserialized.Name);
+}
+
 Expected<TagRecordHash> llvm::pdb::hashTagRecord(const codeview::CVType &Type) {
   switch (Type.kind()) {
   case LF_CLASS:
@@ -112,7 +121,8 @@ Expected<uint32_t> llvm::pdb::hashTypeRecord(const CVType &Rec) {
     return getHashForUdt<UnionRecord>(Rec);
   case LF_ENUM:
     return getHashForUdt<EnumRecord>(Rec);
-
+  case LF_ALIAS:
+    return getHashForAlias(Rec);
   case LF_UDT_SRC_LINE:
     return getSourceLineHash<UdtSourceLineRecord>(Rec);
   case LF_UDT_MOD_SRC_LINE:
diff --git a/llvm/lib/ObjectYAML/CodeViewYAMLTypes.cpp b/llvm/lib/ObjectYAML/CodeViewYAMLTypes.cpp
index 1542017d9d7e6..0470ec6f8056c 100644
--- a/llvm/lib/ObjectYAML/CodeViewYAMLTypes.cpp
+++ b/llvm/lib/ObjectYAML/CodeViewYAMLTypes.cpp
@@ -654,6 +654,11 @@ template <> void LeafRecordImpl<EndPrecompRecord>::map(IO &IO) {
   IO.mapRequired("Signature", Record.Signature);
 }
 
+template <> void LeafRecordImpl<AliasRecord>::map(IO &IO) {
+  IO.mapRequired("UnderlyingType", Record.UnderlyingType);
+  IO.mapRequired("Name", Record.Name);
+}
+
 template <> void MemberRecordImpl<OneMethodRecord>::map(IO &IO) {
   MappingTraits<OneMethodRecord>::mapping(IO, Record);
 }
diff --git a/llvm/test/tools/llvm-pdbutil/alias-record.test b/llvm/test/tools/llvm-pdbutil/alias-record.test
new file mode 100644
index 0000000000000..88a979ed5e659
--- /dev/null
+++ b/llvm/test/tools/llvm-pdbutil/alias-record.test
@@ -0,0 +1,45 @@
+# RUN: llvm-pdbutil yaml2pdb %s --pdb=%t.pdb
+# RUN: llvm-pdbutil dump --types --type-extras %t.pdb | FileCheck --check-prefix=CHECK-YAML2PDB %s
+
+# RUN: llvm-pdbutil pdb2yaml --tpi-stream %t.pdb > %t.yaml
+# RUN: FileCheck --input-file=%t.yaml --check-prefix=CHECK-PDB2YAML %s
+
+# CHECK-YAML2PDB:       0x1000 | LF_ALIAS [size = 16, hash = 0x1876E]
+# CHECK-YAML2PDB-NEXT:           underlying type = 0x0070 (char), name = MyByte
+# CHECK-YAML2PDB-NEXT:  0x1001 | LF_ALIAS [size = 12, hash = 0x1D4A]
+# CHECK-YAML2PDB-NEXT:           underlying type = 0x007A (char16_t), name = U16
+# CHECK-YAML2PDB-NEXT:  0x1002 | LF_ALIAS [size = 16, hash = 0x1876E]
+# CHECK-YAML2PDB-NEXT:           underlying type = 0x007A (char16_t), name = MyByte
+
+# CHECK-PDB2YAML:        Records:
+# CHECK-PDB2YAML-NEXT:     - Kind:            LF_ALIAS
+# CHECK-PDB2YAML-NEXT:       Alias:
+# CHECK-PDB2YAML-NEXT:         UnderlyingType:  112
+# CHECK-PDB2YAML-NEXT:         Name:            MyByte
+# CHECK-PDB2YAML-NEXT:     - Kind:            LF_ALIAS
+# CHECK-PDB2YAML-NEXT:       Alias:
+# CHECK-PDB2YAML-NEXT:         UnderlyingType:  122
+# CHECK-PDB2YAML-NEXT:         Name:            U16
+# CHECK-PDB2YAML-NEXT:     - Kind:            LF_ALIAS
+# CHECK-PDB2YAML-NEXT:       Alias:
+# CHECK-PDB2YAML-NEXT:         UnderlyingType:  122
+# CHECK-PDB2YAML-NEXT:         Name:            MyByte
+# CHECK-PDB2YAML-NEXT: ...
+
+---
+TpiStream:
+  Version:         VC80
+  Records:
+    - Kind:            LF_ALIAS
+      Alias:
+        UnderlyingType:  112
+        Name:            MyByte
+    - Kind:            LF_ALIAS
+      Alias:
+        UnderlyingType:  122
+        Name:            U16
+    - Kind:            LF_ALIAS
+      Alias:
+        UnderlyingType:  122
+        Name:            MyByte
+...
diff --git a/llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp b/llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp
index fc29ec46180c4..13677bce09b75 100644
--- a/llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp
+++ b/llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp
@@ -535,6 +535,11 @@ Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
   return Error::success();
 }
 
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, AliasRecord &AR) {
+  P.formatLine("underlying type = {0}, name = {1}", AR.UnderlyingType, AR.Name);
+  return Error::success();
+}
+
 Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
                                                NestedTypeRecord &Nested) {
   P.format(" [name = `{0}`, parent = {1}]", Nested.Name, Nested.Type);
diff --git a/llvm/unittests/DebugInfo/CodeView/TypeIndexDiscoveryTest.cpp b/llvm/unittests/DebugInfo/CodeView/TypeIndexDiscoveryTest.cpp
index 810aeada33da7..5f11de113c747 100644
--- a/llvm/unittests/DebugInfo/CodeView/TypeIndexDiscoveryTest.cpp
+++ b/llvm/unittests/DebugInfo/CodeView/TypeIndexDiscoveryTest.cpp
@@ -613,3 +613,9 @@ TEST_F(TypeIndexIteratorTest, RegRelativeIndir) {
   writeSymbolRecords(RR);
   checkTypeReferences(0, RR.Type);
 }
+
+TEST_F(TypeIndexIteratorTest, AliasRecord) {
+  AliasRecord AR(TypeIndex::Int32(), "SomeName");
+  writeTypeRecords(AR);
+  checkTypeReferences(0, AR.UnderlyingType);
+}

``````````

</details>


https://github.com/llvm/llvm-project/pull/218243


More information about the llvm-commits mailing list