[lldb] [llvm] [LLVM] [LLDB] Emit and handle `lf_alias` nodes (PR #152484)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Aug 7 05:16:57 PDT 2025
https://github.com/Walnut356 created https://github.com/llvm/llvm-project/pull/152484
This patch causes LLVM to emit `lf_alias` nodes for typedefs, allowing typedefs to be represented in the type data stream. Typedef `S_UDT` nodes are still created for the symbol stream. This strictly generates additional information and points to that additional information when possible.
This is important because local variable symbols store *type* indexes. Without this change, it is impossible for a local variable to convey its typedefed type to the debugger.
<details>
<summary>Sample program</summary>
```cpp
#include <iostream>
#include <inttypes.h>
struct Point {
float x = 0.0;
float y = 0.0;
};
typedef Point Coord;
int main() {
unsigned char uc = 0;
uint8_t u8 = 1;
Point p = Point{5, 10};
Coord c = Coord{15, 20};
std::cout << "Hello World!\n";
}
```
</details>
Before (LLVM 20.1.8):
<img width="261" height="191" alt="image" src="https://github.com/user-attachments/assets/cb9e9e7e-3ad0-4e3a-81c7-5edb4248d2db" />
After:
<img width="221" height="179" alt="image" src="https://github.com/user-attachments/assets/d6035b33-ce5c-4b22-a6c0-aa38b2495fb3" />
Please use extra scrutiny when looking over the LLDB-related changes. I have a bit of experience working with `SymbolFileNativePDB` and `PdbAstBuilder`, but I'm not super familiar with clang's `QualType` and such. In particular, I'm using a default `CompilerDeclContext` for the typedef type because I wasn't sure what else to use.
>From a5e517684e1f9e588226a17cb53551f54472860e Mon Sep 17 00:00:00 2001
From: Walnut <39544927+Walnut356 at users.noreply.github.com>
Date: Thu, 7 Aug 2025 05:25:14 -0500
Subject: [PATCH 1/2] add AliasRecord and emit it for type aliases
---
.../llvm/DebugInfo/CodeView/CodeViewTypes.def | 2 +-
llvm/include/llvm/DebugInfo/CodeView/TypeRecord.h | 13 +++++++++++++
.../LogicalView/Readers/LVCodeViewVisitor.h | 2 ++
llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp | 13 ++++---------
llvm/lib/DebugInfo/CodeView/RecordName.cpp | 5 +++++
llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp | 6 ++++++
llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp | 7 +++++++
.../LogicalView/Readers/LVCodeViewVisitor.cpp | 12 ++++++++++++
llvm/lib/ObjectYAML/CodeViewYAMLTypes.cpp | 5 +++++
llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp | 7 +++++++
10 files changed, 62 insertions(+), 10 deletions(-)
diff --git a/llvm/include/llvm/DebugInfo/CodeView/CodeViewTypes.def b/llvm/include/llvm/DebugInfo/CodeView/CodeViewTypes.def
index a31111eb80a4e..aa3beea75c75b 100644
--- a/llvm/include/llvm/DebugInfo/CodeView/CodeViewTypes.def
+++ b/llvm/include/llvm/DebugInfo/CodeView/CodeViewTypes.def
@@ -53,6 +53,7 @@ TYPE_RECORD(LF_ENUM, 0x1507, Enum)
TYPE_RECORD(LF_TYPESERVER2, 0x1515, TypeServer2)
TYPE_RECORD(LF_VFTABLE, 0x151d, VFTable)
TYPE_RECORD(LF_VTSHAPE, 0x000a, VFTableShape)
+TYPE_RECORD(LF_ALIAS, 0x150a, Alias)
TYPE_RECORD(LF_BITFIELD, 0x1205, BitField)
@@ -181,7 +182,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..0e739650bd089 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
+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 eb6371e911be4..164ea990336e0 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.h
@@ -418,6 +418,8 @@ class LVLogicalVisitor final {
LVElement *Element);
Error visitKnownRecord(CVType &Record, EndPrecompRecord &EndPrecomp,
TypeIndex TI, LVElement *Element);
+ Error visitKnownRecord(CVType &Record, AliasRecord &Alias,
+ TypeIndex TI, LVElement *Element);
Error visitUnknownMember(CVMemberRecord &Record, TypeIndex TI);
Error visitKnownMember(CVMemberRecord &Record, BaseClassRecord &Base,
diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
index c5d6e40eb7c1e..29978c9e5270f 100644
--- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
@@ -1728,6 +1728,9 @@ TypeIndex CodeViewDebug::lowerTypeAlias(const DIDerivedType *Ty) {
addToUDTs(Ty);
+ AliasRecord AR(UnderlyingTypeIndex, TypeName);
+ auto alias_index = TypeTable.writeLeafType(AR);
+
if (UnderlyingTypeIndex == TypeIndex(SimpleTypeKind::Int32Long) &&
TypeName == "HRESULT")
return TypeIndex(SimpleTypeKind::HResult);
@@ -1735,7 +1738,7 @@ TypeIndex CodeViewDebug::lowerTypeAlias(const DIDerivedType *Ty) {
TypeName == "wchar_t")
return TypeIndex(SimpleTypeKind::WideCharacter);
- return UnderlyingTypeIndex;
+ return alias_index;
}
TypeIndex CodeViewDebug::lowerTypeArray(const DICompositeType *Ty) {
@@ -2750,14 +2753,6 @@ TypeIndex CodeViewDebug::getCompleteTypeIndex(const DIType *Ty) {
if (!Ty)
return TypeIndex::Void();
- // Look through typedefs when getting the complete type index. Call
- // getTypeIndex on the typdef to ensure that any UDTs are accumulated and are
- // emitted only once.
- if (Ty->getTag() == dwarf::DW_TAG_typedef)
- (void)getTypeIndex(Ty);
- while (Ty->getTag() == dwarf::DW_TAG_typedef)
- Ty = cast<DIDerivedType>(Ty)->getBaseType();
-
// If this is a non-record type, the complete type index is the same as the
// normal type index. Just call getTypeIndex.
switch (Ty->getTag()) {
diff --git a/llvm/lib/DebugInfo/CodeView/RecordName.cpp b/llvm/lib/DebugInfo/CodeView/RecordName.cpp
index e06b036ede63a..80c9cfa2253fb 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 776676410e782..629b7e5746ff4 100644
--- a/llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp
+++ b/llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp
@@ -568,3 +568,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/TypeRecordMapping.cpp b/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp
index 0bc65f8d0359a..530a119de85fe 100644
--- a/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp
+++ b/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp
@@ -752,3 +752,10 @@ 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 24eaa1234727d..6cd53d42a43cd 100644
--- a/llvm/lib/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.cpp
@@ -2623,6 +2623,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/ObjectYAML/CodeViewYAMLTypes.cpp b/llvm/lib/ObjectYAML/CodeViewYAMLTypes.cpp
index f4ca1b22eafa0..84f33a3fea6a8 100644
--- a/llvm/lib/ObjectYAML/CodeViewYAMLTypes.cpp
+++ b/llvm/lib/ObjectYAML/CodeViewYAMLTypes.cpp
@@ -614,6 +614,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/tools/llvm-pdbutil/MinimalTypeDumper.cpp b/llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp
index db3a752d58165..7931d606a7bf8 100644
--- a/llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp
+++ b/llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp
@@ -523,6 +523,13 @@ Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
return Error::success();
}
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVT,
+ AliasRecord &Alias) {
+ P.format("alias = {0}, underlying type = {1}", Alias.Name,
+ Alias.UnderlyingType);
+ return Error::success();
+}
+
Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
NestedTypeRecord &Nested) {
P.format(" [name = `{0}`, parent = {1}]", Nested.Name, Nested.Type);
>From 3652c756341050acc0c50cb5e6f44e31538285d4 Mon Sep 17 00:00:00 2001
From: Walnut <39544927+Walnut356 at users.noreply.github.com>
Date: Thu, 7 Aug 2025 05:37:32 -0500
Subject: [PATCH 2/2] consume `lf_alias` nodes in `TypeSystemClang`
---
.../SymbolFile/NativePDB/PdbAstBuilder.cpp | 14 ++++++++++++++
.../SymbolFile/NativePDB/SymbolFileNativePDB.cpp | 15 +++++++++++++++
.../SymbolFile/NativePDB/SymbolFileNativePDB.h | 3 +++
3 files changed, 32 insertions(+)
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
index f01fba3c48ce9..db29c96b6194a 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
@@ -805,6 +805,20 @@ clang::QualType PdbAstBuilder::CreateType(PdbTypeSymId type) {
return CreateFunctionType(mfr.ArgumentList, mfr.ReturnType, mfr.CallConv);
}
+ if (cvt.kind() == LF_ALIAS) {
+ AliasRecord ar;
+ llvm::cantFail(TypeDeserializer::deserializeAs<AliasRecord>(cvt, ar));
+
+ auto underlying_type = ToCompilerType(GetOrCreateType(ar.UnderlyingType));
+
+ std::string name = std::string(DropNameScope(ar.Name));
+
+ CompilerType ct = underlying_type.CreateTypedef(
+ name.c_str(), CompilerDeclContext(), 0);
+
+ return m_clang.GetQualType(ct.GetOpaqueQualType());
+ }
+
return {};
}
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
index dcea33dd9f854..57a4c29a037e6 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
@@ -709,6 +709,15 @@ TypeSP SymbolFileNativePDB::CreateProcedureType(PdbTypeSymId type_id,
ct, lldb_private::Type::ResolveState::Full);
}
+TypeSP SymbolFileNativePDB::CreateAliasType(PdbTypeSymId type_id,
+ const AliasRecord &ar,
+ CompilerType ct) {
+
+ return MakeType(toOpaqueUid(type_id), ct.GetTypeName(), llvm::expectedToOptional(ct.GetByteSize(nullptr)), nullptr, LLDB_INVALID_UID,
+ lldb_private::Type::eEncodingIsUID, Declaration(), ct,
+ lldb_private::Type::ResolveState::Full);
+}
+
TypeSP SymbolFileNativePDB::CreateType(PdbTypeSymId type_id, CompilerType ct) {
if (type_id.index.isSimple())
return CreateSimpleType(type_id.index, ct);
@@ -765,6 +774,12 @@ TypeSP SymbolFileNativePDB::CreateType(PdbTypeSymId type_id, CompilerType ct) {
return CreateFunctionType(type_id, mfr, ct);
}
+ if (cvt.kind() == LF_ALIAS) {
+ AliasRecord ar;
+ llvm::cantFail(TypeDeserializer::deserializeAs<AliasRecord>(cvt, ar));
+ return CreateAliasType(type_id, ar, ct);
+ }
+
return nullptr;
}
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
index eda375d4cebe7..1ed2f22293b43 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
@@ -216,6 +216,9 @@ class SymbolFileNativePDB : public SymbolFileCommon {
lldb::TypeSP CreateProcedureType(PdbTypeSymId type_id,
const llvm::codeview::ProcedureRecord &pr,
CompilerType ct);
+ lldb::TypeSP CreateAliasType(PdbTypeSymId type_id,
+ const llvm::codeview::AliasRecord &ar,
+ CompilerType ct);
lldb::TypeSP CreateClassStructUnion(PdbTypeSymId type_id,
const llvm::codeview::TagRecord &record,
size_t size, CompilerType ct);
More information about the llvm-commits
mailing list