diff --git a/llvm/include/llvm/DebugInfo/CodeView/CodeView.h b/llvm/include/llvm/DebugInfo/CodeView/CodeView.h index 0bfd06e05bd8..85752f1ebcda 100644 --- a/llvm/include/llvm/DebugInfo/CodeView/CodeView.h +++ b/llvm/include/llvm/DebugInfo/CodeView/CodeView.h @@ -220,6 +220,23 @@ enum class ClassOptions : uint16_t { }; CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(ClassOptions) +enum class ClassOptions2 : uint32_t { + None = 0x0000, + Packed = 0x0001, + HasConstructorOrDestructor = 0x0002, + HasOverloadedOperator = 0x0004, + Nested = 0x0008, + ContainsNestedClass = 0x0010, + HasOverloadedAssignmentOperator = 0x0020, + HasConversionOperator = 0x0040, + ForwardReference = 0x0080, + Scoped = 0x0100, + HasUniqueName = 0x0200, + Sealed = 0x0400, + Intrinsic = 0x2000 +}; +CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(ClassOptions2) + enum class FrameProcedureOptions : uint32_t { None = 0x00000000, HasAlloca = 0x00000001, diff --git a/llvm/include/llvm/DebugInfo/CodeView/CodeViewTypes.def b/llvm/include/llvm/DebugInfo/CodeView/CodeViewTypes.def index a31111eb80a4..e274cadaf4e5 100644 --- a/llvm/include/llvm/DebugInfo/CodeView/CodeViewTypes.def +++ b/llvm/include/llvm/DebugInfo/CodeView/CodeViewTypes.def @@ -46,8 +46,11 @@ TYPE_RECORD(LF_FIELDLIST, 0x1203, FieldList) TYPE_RECORD(LF_ARRAY, 0x1503, Array) TYPE_RECORD(LF_CLASS, 0x1504, Class) +TYPE_RECORD(LF_CLASS2, 0x1608, Class2) TYPE_RECORD_ALIAS(LF_STRUCTURE, 0x1505, Struct, Class) +TYPE_RECORD_ALIAS(LF_STRUCTURE2, 0x1609, Struct2, Class2) TYPE_RECORD_ALIAS(LF_INTERFACE, 0x1519, Interface, Class) +TYPE_RECORD_ALIAS(LF_INTERFACE2, 0x160b, Interface2, Class2) TYPE_RECORD(LF_UNION, 0x1506, Union) TYPE_RECORD(LF_ENUM, 0x1507, Enum) TYPE_RECORD(LF_TYPESERVER2, 0x1515, TypeServer2) diff --git a/llvm/include/llvm/DebugInfo/CodeView/TypeRecord.h b/llvm/include/llvm/DebugInfo/CodeView/TypeRecord.h index 24a4accab845..6f888360db1b 100644 --- a/llvm/include/llvm/DebugInfo/CodeView/TypeRecord.h +++ b/llvm/include/llvm/DebugInfo/CodeView/TypeRecord.h @@ -494,6 +494,89 @@ class ClassRecord : public TagRecord { uint64_t Size = 0; }; +class Tag2Record : public TypeRecord { +protected: + Tag2Record() = default; + explicit Tag2Record(TypeRecordKind Kind) : TypeRecord(Kind) {} + Tag2Record(TypeRecordKind Kind, ClassOptions2 Options, + TypeIndex FieldList, StringRef Name, StringRef UniqueName) + : TypeRecord(Kind), Options(Options), + FieldList(FieldList), Name(Name), UniqueName(UniqueName) {} + +public: + static const int HfaKindShift = 11; + static const int HfaKindMask = 0x1800; + static const int WinRTKindShift = 14; + static const int WinRTKindMask = 0xC000; + + bool hasUniqueName() const { + return (getOptions() & ClassOptions2::HasUniqueName) != ClassOptions2::None; + } + + bool isNested() const { + return (getOptions() & ClassOptions2::Nested) != ClassOptions2::None; + } + + bool isForwardRef() const { + return (getOptions() & ClassOptions2::ForwardReference) != + ClassOptions2::None; + } + + bool containsNestedClass() const { + return (getOptions() & ClassOptions2::ContainsNestedClass) != + ClassOptions2::None; + } + + bool isScoped() const { + return (getOptions() & ClassOptions2::Scoped) != ClassOptions2::None; + } + + ClassOptions2 getOptions() const { return Options; } + TypeIndex getFieldList() const { return FieldList; } + StringRef getName() const { return Name; } + StringRef getUniqueName() const { return UniqueName; } + + ClassOptions2 Options = ClassOptions2::None; + TypeIndex FieldList; + StringRef Name; + StringRef UniqueName; +}; + +// LF_CLASS2, LF_STRUCTURE2, LF_INTERFACE2 +class Class2Record : public Tag2Record { +public: + Class2Record() = default; + explicit Class2Record(TypeRecordKind Kind) : Tag2Record(Kind) {} + Class2Record(TypeRecordKind Kind, ClassOptions2 Options, + TypeIndex FieldList, TypeIndex DerivationList, + TypeIndex VTableShape, uint64_t Size, StringRef Name, + StringRef UniqueName) + : Tag2Record(Kind, Options, FieldList, Name, UniqueName), + DerivationList(DerivationList), VTableShape(VTableShape), Size(Size) {} + + HfaKind getHfa() const { + uint16_t Value = static_cast(Options); + Value = (Value & HfaKindMask) >> HfaKindShift; + return static_cast(Value); + } + + WindowsRTClassKind getWinRTKind() const { + uint16_t Value = static_cast(Options); + Value = (Value & WinRTKindMask) >> WinRTKindShift; + return static_cast(Value); + } + + TypeIndex getDerivationList() const { return DerivationList; } + TypeIndex getVTableShape() const { return VTableShape; } + uint64_t getCount() const { return Count; } + uint64_t getSize() const { return Size; } + + TypeIndex DerivationList; + TypeIndex VTableShape; + uint64_t Count = 0; + uint64_t Size = 0; +}; + // LF_UNION struct UnionRecord : public TagRecord { UnionRecord() = default; diff --git a/llvm/include/llvm/DebugInfo/CodeView/TypeRecordHelpers.h b/llvm/include/llvm/DebugInfo/CodeView/TypeRecordHelpers.h index aa183cd7d19d..1bf980d69586 100644 --- a/llvm/include/llvm/DebugInfo/CodeView/TypeRecordHelpers.h +++ b/llvm/include/llvm/DebugInfo/CodeView/TypeRecordHelpers.h @@ -48,6 +48,9 @@ inline bool isAggregate(CVType CVT) { case LF_STRUCTURE: case LF_CLASS: case LF_INTERFACE: + case LF_STRUCTURE2: + case LF_CLASS2: + case LF_INTERFACE2: case LF_UNION: return true; default: diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.h b/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.h index eb6371e911be..dfb9510bdd72 100644 --- a/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.h +++ b/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.h @@ -73,6 +73,7 @@ class LVTypeVisitor final : public TypeVisitorCallbacks { Error visitKnownRecord(CVType &Record, BuildInfoRecord &Args) override; Error visitKnownRecord(CVType &Record, ClassRecord &Class) override; + Error visitKnownRecord(CVType &Record, Class2Record &Class) override; Error visitKnownRecord(CVType &Record, EnumRecord &Enum) override; Error visitKnownRecord(CVType &Record, FuncIdRecord &Func) override; Error visitKnownRecord(CVType &Record, ProcedureRecord &Proc) override; @@ -378,6 +379,8 @@ class LVLogicalVisitor final { LVElement *Element); Error visitKnownRecord(CVType &Record, ClassRecord &Class, TypeIndex TI, LVElement *Element); + Error visitKnownRecord(CVType &Record, Class2Record &Class, TypeIndex TI, + LVElement *Element); Error visitKnownRecord(CVType &Record, EnumRecord &Enum, TypeIndex TI, LVElement *Element); Error visitKnownRecord(CVType &Record, FieldListRecord &FieldList, diff --git a/llvm/include/llvm/DebugInfo/PDB/Native/NativeTypeUDT.h b/llvm/include/llvm/DebugInfo/PDB/Native/NativeTypeUDT.h index 79924a78cd21..3da89074739d 100644 --- a/llvm/include/llvm/DebugInfo/PDB/Native/NativeTypeUDT.h +++ b/llvm/include/llvm/DebugInfo/PDB/Native/NativeTypeUDT.h @@ -26,6 +26,9 @@ class NativeTypeUDT : public NativeRawSymbol { NativeTypeUDT(NativeSession &Session, SymIndexId Id, codeview::TypeIndex TI, codeview::ClassRecord Class); + NativeTypeUDT(NativeSession &Session, SymIndexId Id, codeview::TypeIndex TI, + codeview::Class2Record Class); + NativeTypeUDT(NativeSession &Session, SymIndexId Id, codeview::TypeIndex TI, codeview::UnionRecord Union); @@ -64,9 +67,11 @@ class NativeTypeUDT : public NativeRawSymbol { codeview::TypeIndex Index; std::optional Class; + std::optional Class2; std::optional Union; NativeTypeUDT *UnmodifiedType = nullptr; codeview::TagRecord *Tag = nullptr; + codeview::Tag2Record *Tag2 = nullptr; std::optional Modifiers; }; diff --git a/llvm/include/llvm/DebugInfo/PDB/Native/TpiHashing.h b/llvm/include/llvm/DebugInfo/PDB/Native/TpiHashing.h index 3cdb890d81d3..ff22a850a332 100644 --- a/llvm/include/llvm/DebugInfo/PDB/Native/TpiHashing.h +++ b/llvm/include/llvm/DebugInfo/PDB/Native/TpiHashing.h @@ -23,7 +23,11 @@ struct TagRecordHash { : FullRecordHash(Full), ForwardDeclHash(Forward), Class(std::move(CR)) { State = 0; } - + explicit TagRecordHash(codeview::Class2Record CR, uint32_t Full, + uint32_t Forward) + : FullRecordHash(Full), ForwardDeclHash(Forward), Class2(std::move(CR)) { + State = 3; + } explicit TagRecordHash(codeview::EnumRecord ER, uint32_t Full, uint32_t Forward) : FullRecordHash(Full), ForwardDeclHash(Forward), Enum(std::move(ER)) { @@ -39,6 +43,11 @@ struct TagRecordHash { uint32_t FullRecordHash; uint32_t ForwardDeclHash; + bool isTag2Record() const + { + return State == 3 ? true : false; + } + codeview::TagRecord &getRecord() { switch (State) { case 0: @@ -51,9 +60,18 @@ struct TagRecordHash { llvm_unreachable("unreachable!"); } + codeview::Tag2Record &getTag2Record() { + switch (State) { + case 3: + return Class2; + } + llvm_unreachable("unreachable!"); + } + private: union { codeview::ClassRecord Class; + codeview::Class2Record Class2; codeview::EnumRecord Enum; codeview::UnionRecord Union; }; diff --git a/llvm/lib/DebugInfo/CodeView/EnumTables.cpp b/llvm/lib/DebugInfo/CodeView/EnumTables.cpp index 7e3087373bfa..17cc66a25a5c 100644 --- a/llvm/lib/DebugInfo/CodeView/EnumTables.cpp +++ b/llvm/lib/DebugInfo/CodeView/EnumTables.cpp @@ -327,6 +327,21 @@ static const EnumEntry ClassOptionNames[] = { CV_ENUM_CLASS_ENT(ClassOptions, Intrinsic), }; +static const EnumEntry ClassOption2Names[] = { + CV_ENUM_CLASS_ENT(ClassOptions2, Packed), + CV_ENUM_CLASS_ENT(ClassOptions2, HasConstructorOrDestructor), + CV_ENUM_CLASS_ENT(ClassOptions2, HasOverloadedOperator), + CV_ENUM_CLASS_ENT(ClassOptions2, Nested), + CV_ENUM_CLASS_ENT(ClassOptions2, ContainsNestedClass), + CV_ENUM_CLASS_ENT(ClassOptions2, HasOverloadedAssignmentOperator), + CV_ENUM_CLASS_ENT(ClassOptions2, HasConversionOperator), + CV_ENUM_CLASS_ENT(ClassOptions2, ForwardReference), + CV_ENUM_CLASS_ENT(ClassOptions2, Scoped), + CV_ENUM_CLASS_ENT(ClassOptions2, HasUniqueName), + CV_ENUM_CLASS_ENT(ClassOptions2, Sealed), + CV_ENUM_CLASS_ENT(ClassOptions2, Intrinsic), +}; + static const EnumEntry MemberAccessNames[] = { CV_ENUM_CLASS_ENT(MemberAccess, None), CV_ENUM_CLASS_ENT(MemberAccess, Private), @@ -533,6 +548,10 @@ ArrayRef> getClassOptionNames() { return ArrayRef(ClassOptionNames); } +ArrayRef> getClassOption2Names() { + return ArrayRef(ClassOption2Names); +} + ArrayRef> getMemberAccessNames() { return ArrayRef(MemberAccessNames); } diff --git a/llvm/lib/DebugInfo/CodeView/RecordName.cpp b/llvm/lib/DebugInfo/CodeView/RecordName.cpp index e06b036ede63..2ad5866084db 100644 --- a/llvm/lib/DebugInfo/CodeView/RecordName.cpp +++ b/llvm/lib/DebugInfo/CodeView/RecordName.cpp @@ -112,6 +112,11 @@ Error TypeNameComputer::visitKnownRecord(CVType &CVR, ClassRecord &Class) { return Error::success(); } +Error TypeNameComputer::visitKnownRecord(CVType &CVR, Class2Record &Class) { + Name = Class.getName(); + return Error::success(); +} + Error TypeNameComputer::visitKnownRecord(CVType &CVR, UnionRecord &Union) { Name = Union.getName(); return Error::success(); diff --git a/llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp b/llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp index df7e42df1afc..036862d56eba 100644 --- a/llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp +++ b/llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp @@ -44,6 +44,21 @@ static const EnumEntry ClassOptionNames[] = { ENUM_ENTRY(ClassOptions, Intrinsic), }; +static const EnumEntry ClassOption2Names[] = { + ENUM_ENTRY(ClassOptions2, Packed), + ENUM_ENTRY(ClassOptions2, HasConstructorOrDestructor), + ENUM_ENTRY(ClassOptions2, HasOverloadedOperator), + ENUM_ENTRY(ClassOptions2, Nested), + ENUM_ENTRY(ClassOptions2, ContainsNestedClass), + ENUM_ENTRY(ClassOptions2, HasOverloadedAssignmentOperator), + ENUM_ENTRY(ClassOptions2, HasConversionOperator), + ENUM_ENTRY(ClassOptions2, ForwardReference), + ENUM_ENTRY(ClassOptions2, Scoped), + ENUM_ENTRY(ClassOptions2, HasUniqueName), + ENUM_ENTRY(ClassOptions2, Sealed), + ENUM_ENTRY(ClassOptions2, Intrinsic), +}; + static const EnumEntry MemberAccessNames[] = { ENUM_ENTRY(MemberAccess, None), ENUM_ENTRY(MemberAccess, Private), ENUM_ENTRY(MemberAccess, Protected), ENUM_ENTRY(MemberAccess, Public), @@ -257,6 +272,19 @@ Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, ClassRecord &Class) { return Error::success(); } +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, Class2Record &Class) { + uint32_t Props = static_cast(Class.getOptions()); + W->printFlags("Properties", Props, ArrayRef(ClassOption2Names)); + printTypeIndex("FieldList", Class.getFieldList()); + printTypeIndex("DerivedFrom", Class.getDerivationList()); + printTypeIndex("VShape", Class.getVTableShape()); + W->printNumber("SizeOf", Class.getSize()); + W->printString("Name", Class.getName()); + if (Props & uint32_t(ClassOptions2::HasUniqueName)) + W->printString("LinkageName", Class.getUniqueName()); + return Error::success(); +} + Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, UnionRecord &Union) { uint16_t Props = static_cast(Union.getOptions()); W->printNumber("MemberCount", Union.getMemberCount()); diff --git a/llvm/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp b/llvm/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp index 59e2a85c4d4c..03c67427fdfb 100644 --- a/llvm/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp +++ b/llvm/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp @@ -329,6 +329,11 @@ static void discoverTypeIndices(ArrayRef Content, TypeLeafKind Kind, case TypeLeafKind::LF_INTERFACE: Refs.push_back({TiRefKind::TypeRef, 4, 3}); break; + case TypeLeafKind::LF_CLASS2: + case TypeLeafKind::LF_STRUCTURE2: + case TypeLeafKind::LF_INTERFACE2: + Refs.push_back({TiRefKind::TypeRef, 4, 3}); + break; case TypeLeafKind::LF_UNION: Refs.push_back({TiRefKind::TypeRef, 4, 1}); break; diff --git a/llvm/lib/DebugInfo/CodeView/TypeRecordHelpers.cpp b/llvm/lib/DebugInfo/CodeView/TypeRecordHelpers.cpp index 046b660abfab..0508e8c1ba46 100644 --- a/llvm/lib/DebugInfo/CodeView/TypeRecordHelpers.cpp +++ b/llvm/lib/DebugInfo/CodeView/TypeRecordHelpers.cpp @@ -21,7 +21,7 @@ template static ClassOptions getUdtOptions(CVType CVT) { consumeError(std::move(EC)); return ClassOptions::None; } - return Record.getOptions(); + return (ClassOptions)Record.getOptions(); } bool llvm::codeview::isUdtForwardRef(CVType CVT) { @@ -32,6 +32,11 @@ bool llvm::codeview::isUdtForwardRef(CVType CVT) { case LF_INTERFACE: UdtOptions = getUdtOptions(std::move(CVT)); break; + case LF_STRUCTURE2: + case LF_CLASS2: + case LF_INTERFACE2: + UdtOptions = getUdtOptions(std::move(CVT)); + break; case LF_ENUM: UdtOptions = getUdtOptions(std::move(CVT)); break; @@ -174,6 +179,10 @@ uint64_t llvm::codeview::getSizeInBytesForTypeRecord(CVType CVT) { case LF_CLASS: case LF_INTERFACE: return getUdtSize(std::move(CVT)); + case LF_STRUCTURE2: + case LF_CLASS2: + case LF_INTERFACE2: + return getUdtSize(std::move(CVT)); case LF_UNION: return getUdtSize(std::move(CVT)); default: diff --git a/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp b/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp index 0bc65f8d0359..18ac36e33aac 100644 --- a/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp +++ b/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp @@ -457,6 +457,26 @@ Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ClassRecord &Record) { return Error::success(); } +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, Class2Record &Record) { + assert((CVR.kind() == TypeLeafKind::LF_STRUCTURE2) || + (CVR.kind() == TypeLeafKind::LF_CLASS2)); + + std::string PropertiesNames = + getFlagNames(IO, static_cast(Record.Options), + ArrayRef(getClassOptionNames())); + //error(IO.mapInteger(Record.MemberCount, "MemberCount")); + error(IO.mapEnum(Record.Options, "Properties" + PropertiesNames)); + error(IO.mapInteger(Record.FieldList, "FieldList")); + error(IO.mapInteger(Record.DerivationList, "DerivedFrom")); + error(IO.mapInteger(Record.VTableShape, "VShape")); + error(IO.mapEncodedInteger(Record.Count, "Count")); + error(IO.mapEncodedInteger(Record.Size, "SizeOf")); + error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName, + Record.hasUniqueName())); + + return Error::success(); +} + Error TypeRecordMapping::visitKnownRecord(CVType &CVR, UnionRecord &Record) { std::string PropertiesNames = getFlagNames(IO, static_cast(Record.Options), diff --git a/llvm/lib/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.cpp b/llvm/lib/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.cpp index 1d0178532882..3595021eb98e 100644 --- a/llvm/lib/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.cpp +++ b/llvm/lib/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.cpp @@ -99,6 +99,8 @@ static StringRef getRecordName(LazyRandomTypeCollection &Types, TypeIndex TI) { TypeRecordKind RK = static_cast(CVReference.kind()); if (RK == TypeRecordKind::Class || RK == TypeRecordKind::Struct) GetName(ClassRecord(RK)); + if (RK == TypeRecordKind::Class2 || RK == TypeRecordKind::Struct2) + GetName(Class2Record(RK)); else if (RK == TypeRecordKind::Union) GetName(UnionRecord(RK)); else if (RK == TypeRecordKind::Enum) @@ -585,6 +587,24 @@ Error LVTypeVisitor::visitKnownRecord(CVType &Record, ClassRecord &Class) { return Error::success(); } +// LF_CLASS2, LF_STRUCTURE2 (TPI) +Error LVTypeVisitor::visitKnownRecord(CVType &Record, Class2Record &Class) { + LLVM_DEBUG({ + printTypeIndex("TypeIndex", CurrentTypeIndex, StreamTPI); + printTypeIndex("FieldListType", Class.getFieldList(), StreamTPI); + W.printString("Name", Class.getName()); + }); + + // Collect class name for scope deduction. + Shared->NamespaceDeduction.add(Class.getName()); + Shared->ForwardReferences.record(Class.isForwardRef(), Class.getName(), + CurrentTypeIndex); + + // Collect class name for contained scopes deduction. + Shared->TypeRecords.add(StreamIdx, CurrentTypeIndex, Class.getName()); + return Error::success(); +} + // LF_ENUM (TPI) Error LVTypeVisitor::visitKnownRecord(CVType &Record, EnumRecord &Enum) { LLVM_DEBUG({ @@ -2043,6 +2063,76 @@ Error LVLogicalVisitor::visitKnownRecord(CVType &Record, ClassRecord &Class, return Error::success(); } +// LF_CLASS2, LF_STRUCTURE2, LF_INTERFACE2 +Error LVLogicalVisitor::visitKnownRecord(CVType &Record, Class2Record &Class, + TypeIndex TI, LVElement *Element) { + LLVM_DEBUG({ + printTypeBegin(Record, TI, Element, StreamTPI); + printTypeIndex("FieldList", Class.getFieldList(), StreamTPI); + printTypeIndex("DerivedFrom", Class.getDerivationList(), StreamTPI); + printTypeIndex("VShape", Class.getVTableShape(), StreamTPI); + W.printNumber("Count", Class.getCount()); + W.printNumber("SizeOf", Class.getSize()); + W.printString("Name", Class.getName()); + if (Class.hasUniqueName()) + W.printString("UniqueName", Class.getUniqueName()); + printTypeEnd(Record); + }); + + if (Element->getIsFinalized()) + return Error::success(); + Element->setIsFinalized(); + + LVScopeAggregate *Scope = static_cast(Element); + if (!Scope) + return Error::success(); + + Scope->setName(Class.getName()); + if (Class.hasUniqueName()) + Scope->setLinkageName(Class.getUniqueName()); + + if (Class.isNested()) { + Scope->setIsNested(); + createParents(Class.getName(), Scope); + } + + if (Class.isScoped()) + Scope->setIsScoped(); + + // Nested types will be added to their parents at creation. The forward + // references are only processed to finish the referenced element creation. + if (!(Class.isNested() || Class.isScoped())) { + if (LVScope *Namespace = Shared->NamespaceDeduction.get(Class.getName())) + Namespace->addElement(Scope); + else + Reader->getCompileUnit()->addElement(Scope); + } + + LazyRandomTypeCollection &Types = types(); + TypeIndex TIFieldList = Class.getFieldList(); + if (TIFieldList.isNoneType()) { + TypeIndex ForwardType = Shared->ForwardReferences.find(Class.getName()); + if (!ForwardType.isNoneType()) { + CVType CVReference = Types.getType(ForwardType); + TypeRecordKind RK = static_cast(CVReference.kind()); + Class2Record ReferenceRecord(RK); + if (Error Err = TypeDeserializer::deserializeAs( + const_cast(CVReference), ReferenceRecord)) + return Err; + TIFieldList = ReferenceRecord.getFieldList(); + } + } + + if (!TIFieldList.isNoneType()) { + // Pass down the TypeIndex 'TI' for the aggregate containing the field list. + CVType CVFieldList = Types.getType(TIFieldList); + if (Error Err = finishVisitation(CVFieldList, TI, Scope)) + return Err; + } + + return Error::success(); +} + // LF_ENUM (TPI) Error LVLogicalVisitor::visitKnownRecord(CVType &Record, EnumRecord &Enum, TypeIndex TI, LVElement *Element) { @@ -3035,6 +3125,11 @@ LVElement *LVLogicalVisitor::createElement(TypeLeafKind Kind) { CurrentScope->setTag(dwarf::DW_TAG_class_type); CurrentScope->setIsClass(); return CurrentScope; + case TypeLeafKind::LF_CLASS2: + CurrentScope = Reader->createScopeAggregate(); + CurrentScope->setTag(dwarf::DW_TAG_class_type); + CurrentScope->setIsClass(); + return CurrentScope; case TypeLeafKind::LF_ENUM: CurrentScope = Reader->createScopeEnumeration(); CurrentScope->setTag(dwarf::DW_TAG_enumeration_type); @@ -3051,6 +3146,11 @@ LVElement *LVLogicalVisitor::createElement(TypeLeafKind Kind) { CurrentScope->setIsStructure(); CurrentScope->setTag(dwarf::DW_TAG_structure_type); return CurrentScope; + case TypeLeafKind::LF_STRUCTURE2: + CurrentScope = Reader->createScopeAggregate(); + CurrentScope->setIsStructure(); + CurrentScope->setTag(dwarf::DW_TAG_structure_type); + return CurrentScope; case TypeLeafKind::LF_UNION: CurrentScope = Reader->createScopeAggregate(); CurrentScope->setIsUnion(); diff --git a/llvm/lib/DebugInfo/PDB/Native/NativeExeSymbol.cpp b/llvm/lib/DebugInfo/PDB/Native/NativeExeSymbol.cpp index ae0f66c31fde..97cd97f0d992 100644 --- a/llvm/lib/DebugInfo/PDB/Native/NativeExeSymbol.cpp +++ b/llvm/lib/DebugInfo/PDB/Native/NativeExeSymbol.cpp @@ -49,7 +49,8 @@ NativeExeSymbol::findChildren(PDB_SymType Type) const { case PDB_SymType::UDT: return Session.getSymbolCache().createTypeEnumerator( {codeview::LF_STRUCTURE, codeview::LF_CLASS, codeview::LF_UNION, - codeview::LF_INTERFACE}); + codeview::LF_INTERFACE, codeview::LF_STRUCTURE2, codeview::LF_CLASS2, + codeview::LF_INTERFACE2}); case PDB_SymType::VTableShape: return Session.getSymbolCache().createTypeEnumerator(codeview::LF_VTSHAPE); case PDB_SymType::FunctionSig: diff --git a/llvm/lib/DebugInfo/PDB/Native/NativeTypeUDT.cpp b/llvm/lib/DebugInfo/PDB/Native/NativeTypeUDT.cpp index 18811a880691..9608a7b8d002 100644 --- a/llvm/lib/DebugInfo/PDB/Native/NativeTypeUDT.cpp +++ b/llvm/lib/DebugInfo/PDB/Native/NativeTypeUDT.cpp @@ -22,6 +22,11 @@ NativeTypeUDT::NativeTypeUDT(NativeSession &Session, SymIndexId Id, : NativeRawSymbol(Session, PDB_SymType::UDT, Id), Index(TI), Class(std::move(CR)), Tag(&*Class) {} +NativeTypeUDT::NativeTypeUDT(NativeSession &Session, SymIndexId Id, + codeview::TypeIndex TI, codeview::Class2Record CR) + : NativeRawSymbol(Session, PDB_SymType::UDT, Id), Index(TI), + Class2(std::move(CR)), Tag2(&*Class2) {} + NativeTypeUDT::NativeTypeUDT(NativeSession &Session, SymIndexId Id, codeview::TypeIndex TI, codeview::UnionRecord UR) : NativeRawSymbol(Session, PDB_SymType::UDT, Id), Index(TI), @@ -75,6 +80,9 @@ std::string NativeTypeUDT::getName() const { if (UnmodifiedType) return UnmodifiedType->getName(); + if (Tag2) + return std::string(Tag2->getName()); + return std::string(Tag->getName()); } @@ -91,6 +99,9 @@ SymIndexId NativeTypeUDT::getVirtualTableShapeId() const { if (UnmodifiedType) return UnmodifiedType->getVirtualTableShapeId(); + if (Class2) + return Session.getSymbolCache().findSymbolByTypeIndex(Class2->VTableShape); + if (Class) return Session.getSymbolCache().findSymbolByTypeIndex(Class->VTableShape); @@ -101,6 +112,9 @@ uint64_t NativeTypeUDT::getLength() const { if (UnmodifiedType) return UnmodifiedType->getLength(); + if (Class2) + return Class2->getSize(); + if (Class) return Class->getSize(); @@ -111,24 +125,56 @@ PDB_UdtType NativeTypeUDT::getUdtKind() const { if (UnmodifiedType) return UnmodifiedType->getUdtKind(); - switch (Tag->Kind) { - case TypeRecordKind::Class: - return PDB_UdtType::Class; - case TypeRecordKind::Union: - return PDB_UdtType::Union; - case TypeRecordKind::Struct: - return PDB_UdtType::Struct; - case TypeRecordKind::Interface: - return PDB_UdtType::Interface; - default: - llvm_unreachable("Unexpected udt kind"); + if (Tag2) { + switch (Tag2->Kind) { + case TypeRecordKind::Class2: + return PDB_UdtType::Class; + case TypeRecordKind::Struct2: + return PDB_UdtType::Struct; + + case TypeRecordKind::Class: + return PDB_UdtType::Class; + case TypeRecordKind::Union: + return PDB_UdtType::Union; + case TypeRecordKind::Struct: + return PDB_UdtType::Struct; + case TypeRecordKind::Interface: + return PDB_UdtType::Interface; + default: + llvm_unreachable("Unexpected udt kind"); + } } + + if (Tag) { + switch (Tag->Kind) { + case TypeRecordKind::Class2: + return PDB_UdtType::Class; + case TypeRecordKind::Struct2: + return PDB_UdtType::Struct; + + case TypeRecordKind::Class: + return PDB_UdtType::Class; + case TypeRecordKind::Union: + return PDB_UdtType::Union; + case TypeRecordKind::Struct: + return PDB_UdtType::Struct; + case TypeRecordKind::Interface: + return PDB_UdtType::Interface; + default: + llvm_unreachable("Unexpected udt kind"); + } + } + llvm_unreachable("Unexpected udt kind"); } bool NativeTypeUDT::hasConstructor() const { if (UnmodifiedType) return UnmodifiedType->hasConstructor(); + if (Tag2) { + return (Tag2->Options & ClassOptions2::HasConstructorOrDestructor) != ClassOptions2::None; + } + return (Tag->Options & ClassOptions::HasConstructorOrDestructor) != ClassOptions::None; } @@ -144,30 +190,43 @@ bool NativeTypeUDT::hasAssignmentOperator() const { if (UnmodifiedType) return UnmodifiedType->hasAssignmentOperator(); - return (Tag->Options & ClassOptions::HasOverloadedAssignmentOperator) != - ClassOptions::None; + if (Tag2) { + return (Tag2->Options & ClassOptions2::HasOverloadedAssignmentOperator) != ClassOptions2::None; + } + + return (Tag->Options & ClassOptions::HasOverloadedAssignmentOperator) != ClassOptions::None; } bool NativeTypeUDT::hasCastOperator() const { if (UnmodifiedType) return UnmodifiedType->hasCastOperator(); - return (Tag->Options & ClassOptions::HasConversionOperator) != - ClassOptions::None; + if (Tag2) { + return (Tag2->Options & ClassOptions2::HasConversionOperator) != ClassOptions2::None; + } + + return (Tag->Options & ClassOptions::HasConversionOperator) != ClassOptions::None; } bool NativeTypeUDT::hasNestedTypes() const { if (UnmodifiedType) return UnmodifiedType->hasNestedTypes(); - return (Tag->Options & ClassOptions::ContainsNestedClass) != - ClassOptions::None; + if (Tag2) { + return (Tag2->Options & ClassOptions2::ContainsNestedClass) != ClassOptions2::None; + } + + return (Tag->Options & ClassOptions::ContainsNestedClass) != ClassOptions::None; } bool NativeTypeUDT::hasOverloadedOperator() const { if (UnmodifiedType) return UnmodifiedType->hasOverloadedOperator(); + if (Tag2) { + return (Tag2->Options & ClassOptions2::HasOverloadedOperator) != ClassOptions2::None; + } + return (Tag->Options & ClassOptions::HasOverloadedOperator) != ClassOptions::None; } @@ -178,6 +237,9 @@ bool NativeTypeUDT::isIntrinsic() const { if (UnmodifiedType) return UnmodifiedType->isIntrinsic(); + if (Tag2) { + return (Tag2->Options & ClassOptions2::Intrinsic) != ClassOptions2::None; + } return (Tag->Options & ClassOptions::Intrinsic) != ClassOptions::None; } @@ -185,6 +247,9 @@ bool NativeTypeUDT::isNested() const { if (UnmodifiedType) return UnmodifiedType->isNested(); + if (Tag2) { + return (Tag2->Options & ClassOptions2::Nested) != ClassOptions2::None; + } return (Tag->Options & ClassOptions::Nested) != ClassOptions::None; } @@ -192,6 +257,9 @@ bool NativeTypeUDT::isPacked() const { if (UnmodifiedType) return UnmodifiedType->isPacked(); + if (Tag2) { + return (Tag2->Options & ClassOptions2::Packed) != ClassOptions2::None; + } return (Tag->Options & ClassOptions::Packed) != ClassOptions::None; } @@ -201,6 +269,9 @@ bool NativeTypeUDT::isScoped() const { if (UnmodifiedType) return UnmodifiedType->isScoped(); + if (Tag2) { + return (Tag2->Options & ClassOptions2::Scoped) != ClassOptions2::None; + } return (Tag->Options & ClassOptions::Scoped) != ClassOptions::None; } diff --git a/llvm/lib/DebugInfo/PDB/Native/SymbolCache.cpp b/llvm/lib/DebugInfo/PDB/Native/SymbolCache.cpp index f89f09aa3399..775f18b66fb3 100644 --- a/llvm/lib/DebugInfo/PDB/Native/SymbolCache.cpp +++ b/llvm/lib/DebugInfo/PDB/Native/SymbolCache.cpp @@ -210,6 +210,11 @@ SymIndexId SymbolCache::findSymbolByTypeIndex(codeview::TypeIndex Index) const { case codeview::LF_INTERFACE: Id = createSymbolForType(Index, std::move(CVT)); break; + case codeview::LF_CLASS2: + case codeview::LF_STRUCTURE2: + case codeview::LF_INTERFACE2: + Id = createSymbolForType(Index, std::move(CVT)); + break; case codeview::LF_UNION: Id = createSymbolForType(Index, std::move(CVT)); break; diff --git a/llvm/lib/DebugInfo/PDB/Native/TpiHashing.cpp b/llvm/lib/DebugInfo/PDB/Native/TpiHashing.cpp index 941ce78027a2..c18c4d3bef67 100644 --- a/llvm/lib/DebugInfo/PDB/Native/TpiHashing.cpp +++ b/llvm/lib/DebugInfo/PDB/Native/TpiHashing.cpp @@ -39,6 +39,21 @@ static uint32_t getHashForUdt(const TagRecord &Rec, return hashBufferV8(FullRecord); } +static uint32_t getHashForUdt(const Tag2Record &Rec, + ArrayRef FullRecord) { + ClassOptions2 Opts = Rec.getOptions(); + bool ForwardRef = bool(Opts & ClassOptions2::ForwardReference); + bool Scoped = bool(Opts & ClassOptions2::Scoped); + bool HasUniqueName = bool(Opts & ClassOptions2::HasUniqueName); + bool IsAnon = HasUniqueName && isAnonymous(Rec.getName()); + + if (!ForwardRef && !Scoped && !IsAnon) + return hashStringV1(Rec.getName()); + if (!ForwardRef && HasUniqueName && !IsAnon) + return hashStringV1(Rec.getUniqueName()); + return hashBufferV8(FullRecord); +} + template static Expected getHashForUdt(const CVType &Rec) { T Deserialized; @@ -55,7 +70,7 @@ static Expected getTagRecordHashForUdt(const CVType &Rec) { Deserialized)) return std::move(E); - ClassOptions Opts = Deserialized.getOptions(); + ClassOptions Opts = (ClassOptions)Deserialized.getOptions(); bool ForwardRef = bool(Opts & ClassOptions::ForwardReference); @@ -91,6 +106,10 @@ Expected llvm::pdb::hashTagRecord(const codeview::CVType &Type) { case LF_STRUCTURE: case LF_INTERFACE: return getTagRecordHashForUdt(Type); + case LF_CLASS2: + case LF_STRUCTURE2: + case LF_INTERFACE2: + return getTagRecordHashForUdt(Type); case LF_UNION: return getTagRecordHashForUdt(Type); case LF_ENUM: @@ -108,6 +127,10 @@ Expected llvm::pdb::hashTypeRecord(const CVType &Rec) { case LF_STRUCTURE: case LF_INTERFACE: return getHashForUdt(Rec); + case LF_CLASS2: + case LF_STRUCTURE2: + case LF_INTERFACE2: + return getHashForUdt(Rec); case LF_UNION: return getHashForUdt(Rec); case LF_ENUM: diff --git a/llvm/lib/DebugInfo/PDB/Native/TpiStream.cpp b/llvm/lib/DebugInfo/PDB/Native/TpiStream.cpp index ac19db03fab2..9683dd43cbae 100644 --- a/llvm/lib/DebugInfo/PDB/Native/TpiStream.cpp +++ b/llvm/lib/DebugInfo/PDB/Native/TpiStream.cpp @@ -201,19 +201,40 @@ TpiStream::findFullDeclForForwardRef(TypeIndex ForwardRefTI) const { return FullTRH.takeError(); if (ForwardTRH->FullRecordHash != FullTRH->FullRecordHash) continue; - TagRecord &ForwardTR = ForwardTRH->getRecord(); - TagRecord &FullTR = FullTRH->getRecord(); - if (!ForwardTR.hasUniqueName()) { - if (ForwardTR.getName() == FullTR.getName()) + if (ForwardTRH->isTag2Record()) + { + Tag2Record &ForwardTR2 = ForwardTRH->getTag2Record(); + Tag2Record &FullTR2 = FullTRH->getTag2Record(); + + if (!ForwardTR2.hasUniqueName()) { + if (ForwardTR2.getName() == FullTR2.getName()) + return TI; + continue; + } + + if (!FullTR2.hasUniqueName()) + continue; + if (ForwardTR2.getUniqueName() == FullTR2.getUniqueName()) return TI; - continue; } - - if (!FullTR.hasUniqueName()) - continue; - if (ForwardTR.getUniqueName() == FullTR.getUniqueName()) - return TI; + else + { + TagRecord &ForwardTR = ForwardTRH->getRecord(); + TagRecord &FullTR = FullTRH->getRecord(); + + if (!ForwardTR.hasUniqueName()) { + if (ForwardTR.getName() == FullTR.getName()) + return TI; + continue; + } + + if (!FullTR.hasUniqueName()) + continue; + if (ForwardTR.getUniqueName() == FullTR.getUniqueName()) + return TI; + } + } return ForwardRefTI; } diff --git a/llvm/lib/ObjectYAML/CodeViewYAMLTypes.cpp b/llvm/lib/ObjectYAML/CodeViewYAMLTypes.cpp index 99689786a13c..e5328aa24411 100644 --- a/llvm/lib/ObjectYAML/CodeViewYAMLTypes.cpp +++ b/llvm/lib/ObjectYAML/CodeViewYAMLTypes.cpp @@ -66,6 +66,7 @@ LLVM_YAML_DECLARE_BITSET_TRAITS(PointerOptions) LLVM_YAML_DECLARE_BITSET_TRAITS(ModifierOptions) LLVM_YAML_DECLARE_BITSET_TRAITS(FunctionOptions) LLVM_YAML_DECLARE_BITSET_TRAITS(ClassOptions) +LLVM_YAML_DECLARE_BITSET_TRAITS(ClassOptions2) LLVM_YAML_DECLARE_BITSET_TRAITS(MethodOptions) LLVM_YAML_DECLARE_MAPPING_TRAITS(OneMethodRecord) @@ -378,6 +379,26 @@ void ScalarBitSetTraits::bitset(IO &IO, ClassOptions &Options) { IO.bitSetCase(Options, "Intrinsic", ClassOptions::Intrinsic); } +void ScalarBitSetTraits::bitset(IO &IO, ClassOptions2 &Options) { + IO.bitSetCase(Options, "None", ClassOptions2::None); + IO.bitSetCase(Options, "HasConstructorOrDestructor", + ClassOptions2::HasConstructorOrDestructor); + IO.bitSetCase(Options, "HasOverloadedOperator", + ClassOptions2::HasOverloadedOperator); + IO.bitSetCase(Options, "Nested", ClassOptions2::Nested); + IO.bitSetCase(Options, "ContainsNestedClass", + ClassOptions2::ContainsNestedClass); + IO.bitSetCase(Options, "HasOverloadedAssignmentOperator", + ClassOptions2::HasOverloadedAssignmentOperator); + IO.bitSetCase(Options, "HasConversionOperator", + ClassOptions2::HasConversionOperator); + IO.bitSetCase(Options, "ForwardReference", ClassOptions2::ForwardReference); + IO.bitSetCase(Options, "Scoped", ClassOptions2::Scoped); + IO.bitSetCase(Options, "HasUniqueName", ClassOptions2::HasUniqueName); + IO.bitSetCase(Options, "Sealed", ClassOptions2::Sealed); + IO.bitSetCase(Options, "Intrinsic", ClassOptions2::Intrinsic); +} + void ScalarBitSetTraits::bitset(IO &IO, MethodOptions &Options) { IO.bitSetCase(Options, "None", MethodOptions::None); IO.bitSetCase(Options, "Pseudo", MethodOptions::Pseudo); @@ -529,6 +550,17 @@ template <> void LeafRecordImpl::map(IO &IO) { IO.mapRequired("Size", Record.Size); } +template <> void LeafRecordImpl::map(IO &IO) { + IO.mapRequired("Options", Record.Options); + IO.mapRequired("FieldList", Record.FieldList); + IO.mapRequired("Name", Record.Name); + IO.mapRequired("UniqueName", Record.UniqueName); + IO.mapRequired("DerivationList", Record.DerivationList); + IO.mapRequired("VTableShape", Record.VTableShape); + IO.mapRequired("Count", Record.Count); + IO.mapRequired("Size", Record.Size); +} + template <> void LeafRecordImpl::map(IO &IO) { IO.mapRequired("MemberCount", Record.MemberCount); IO.mapRequired("Options", Record.Options); diff --git a/llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp b/llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp index aaa430a9572e..3d36042758d7 100644 --- a/llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp +++ b/llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp @@ -78,6 +78,52 @@ static std::string formatClassOptions(uint32_t IndentLevel, return typesetItemList(Opts, 4, IndentLevel, " | "); } +static std::string formatClassOptions2(uint32_t IndentLevel, + ClassOptions2 Options, TpiStream *Stream, + TypeIndex CurrentTypeIndex) { + std::vector Opts; + + if (Stream && Stream->supportsTypeLookup() && + !opts::dump::DontResolveForwardRefs && + ((Options & ClassOptions2::ForwardReference) != ClassOptions2::None)) { + // If we're able to resolve forward references, do that. + Expected ETI = + Stream->findFullDeclForForwardRef(CurrentTypeIndex); + if (!ETI) { + consumeError(ETI.takeError()); + PUSH_FLAG(ClassOptions2, ForwardReference, Options, "forward ref (??\?)"); + } else { + const char *Direction = (*ETI == CurrentTypeIndex) + ? "=" + : ((*ETI < CurrentTypeIndex) ? "<-" : "->"); + std::string Formatted = + formatv("forward ref ({0} {1})", Direction, *ETI).str(); + PUSH_FLAG(ClassOptions2, ForwardReference, Options, std::move(Formatted)); + } + } else { + PUSH_FLAG(ClassOptions2, ForwardReference, Options, "forward ref"); + } + + PUSH_FLAG(ClassOptions2, HasConstructorOrDestructor, Options, + "has ctor / dtor"); + PUSH_FLAG(ClassOptions2, ContainsNestedClass, Options, + "contains nested class"); + PUSH_FLAG(ClassOptions2, HasConversionOperator, Options, + "conversion operator"); + PUSH_FLAG(ClassOptions2, HasUniqueName, Options, "has unique name"); + PUSH_FLAG(ClassOptions2, Intrinsic, Options, "intrin"); + PUSH_FLAG(ClassOptions2, Nested, Options, "is nested"); + PUSH_FLAG(ClassOptions2, HasOverloadedOperator, Options, + "overloaded operator"); + PUSH_FLAG(ClassOptions2, HasOverloadedAssignmentOperator, Options, + "overloaded operator="); + PUSH_FLAG(ClassOptions2, Packed, Options, "packed"); + PUSH_FLAG(ClassOptions2, Scoped, Options, "scoped"); + PUSH_FLAG(ClassOptions2, Sealed, Options, "sealed"); + + return typesetItemList(Opts, 4, IndentLevel, " | "); +} + static std::string pointerOptions(PointerOptions Options) { std::vector Opts; PUSH_FLAG(PointerOptions, Flat32, Options, "flat32"); @@ -341,10 +387,26 @@ Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, P.formatLine("options: {0}, sizeof {1}", formatClassOptions(P.getIndentLevel(), Class.Options, Stream, CurrentTypeIndex), - Class.Size); + Class.Size); return Error::success(); } +Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, + Class2Record &Class) { + P.format(" `{0}`", Class.Name); + if (Class.hasUniqueName()) + P.formatLine("unique name: `{0}`", Class.UniqueName); + P.formatLine("vtable: {0}, base list: {1}, field list: {2}", + Class.VTableShape, Class.DerivationList, Class.FieldList); + P.formatLine("options: {0}, count {1}, sizeof {2}", + formatClassOptions2(P.getIndentLevel(), Class.Options, Stream, + CurrentTypeIndex), + Class.Count, + Class.Size); + return Error::success(); +} + + Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, UnionRecord &Union) { P.format(" `{0}`", Union.Name); diff --git a/llvm/tools/llvm-pdbutil/TypeReferenceTracker.cpp b/llvm/tools/llvm-pdbutil/TypeReferenceTracker.cpp index c7653b7c06d4..51a245100cb2 100644 --- a/llvm/tools/llvm-pdbutil/TypeReferenceTracker.cpp +++ b/llvm/tools/llvm-pdbutil/TypeReferenceTracker.cpp @@ -152,6 +152,9 @@ void TypeReferenceTracker::markReferencedTypes() { case LF_CLASS: case LF_INTERFACE: case LF_STRUCTURE: + case LF_CLASS2: + case LF_STRUCTURE2: + case LF_INTERFACE2: case LF_UNION: case LF_ENUM: addOneTypeRef(TiRefKind::TypeRef,