[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