[PDB] Add native reading support for UDT / class types.

This allows the native reader to find records of class/struct/
union type and dump them.  This behavior is tested by using the
diadump subcommand against golden output produced by actual DIA
SDK on the same PDB file, and again using pretty -native to
confirm that we actually dump the classes.  We don't find class
members or anything like that yet, for now it's just the class
itself.

llvm-svn: 342779
This commit is contained in:
Zachary Turner 2018-09-21 22:36:04 +00:00
parent 10febb0779
commit 355ffb0032
19 changed files with 1086 additions and 141 deletions

View File

@ -923,6 +923,7 @@ public:
uint32_t Signature; uint32_t Signature;
}; };
} // end namespace codeview } // end namespace codeview
} // end namespace llvm } // end namespace llvm

View File

@ -0,0 +1,28 @@
//===- TypeRecordHelpers.h --------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_DEBUGINFO_CODEVIEW_TYPERECORDHELPERS_H
#define LLVM_DEBUGINFO_CODEVIEW_TYPERECORDHELPERS_H
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
namespace llvm {
namespace codeview {
/// Given an arbitrary codeview type, determine if it is an LF_STRUCTURE,
/// LF_CLASS, LF_INTERFACE, LF_UNION, or LF_ENUM with the forward ref class
/// option.
bool isUdtForwardRef(CVType CVT);
/// Given a CVType which is assumed to be an LF_MODIFIER, return the
/// TypeIndex of the type that the LF_MODIFIER modifies.
TypeIndex getModifiedType(const CVType &CVT);
}
}
#endif

View File

@ -35,11 +35,9 @@ class NullEnumerator : public IPDBEnumChildren<ChildType> {
virtual uint32_t getChildCount() const override { return 0; } virtual uint32_t getChildCount() const override { return 0; }
virtual std::unique_ptr<ChildType> virtual std::unique_ptr<ChildType>
getChildAtIndex(uint32_t Index) const override { getChildAtIndex(uint32_t Index) const override {
assert(false);
return nullptr; return nullptr;
} }
virtual std::unique_ptr<ChildType> getNext() override { virtual std::unique_ptr<ChildType> getNext() override {
assert(false);
return nullptr; return nullptr;
} }
virtual void reset() override {} virtual void reset() override {}

View File

@ -26,7 +26,7 @@ class NativeEnumTypes : public IPDBEnumChildren<PDBSymbol> {
public: public:
NativeEnumTypes(NativeSession &Session, NativeEnumTypes(NativeSession &Session,
codeview::LazyRandomTypeCollection &TypeCollection, codeview::LazyRandomTypeCollection &TypeCollection,
codeview::TypeLeafKind Kind); std::vector<codeview::TypeLeafKind> Kinds);
uint32_t getChildCount() const override; uint32_t getChildCount() const override;
std::unique_ptr<PDBSymbol> getChildAtIndex(uint32_t Index) const override; std::unique_ptr<PDBSymbol> getChildAtIndex(uint32_t Index) const override;
@ -34,10 +34,6 @@ public:
void reset() override; void reset() override;
private: private:
NativeEnumTypes(NativeSession &Session,
const std::vector<codeview::TypeIndex> &Matches,
codeview::TypeLeafKind Kind);
std::vector<codeview::TypeIndex> Matches; std::vector<codeview::TypeIndex> Matches;
uint32_t Index; uint32_t Index;
NativeSession &Session; NativeSession &Session;

View File

@ -10,6 +10,7 @@
#ifndef LLVM_DEBUGINFO_PDB_NATIVE_NATIVETYPEENUM_H #ifndef LLVM_DEBUGINFO_PDB_NATIVE_NATIVETYPEENUM_H
#define LLVM_DEBUGINFO_PDB_NATIVE_NATIVETYPEENUM_H #define LLVM_DEBUGINFO_PDB_NATIVE_NATIVETYPEENUM_H
#include "llvm/ADT/Optional.h"
#include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/CodeView/CodeView.h"
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
#include "llvm/DebugInfo/PDB/Native/NativeRawSymbol.h" #include "llvm/DebugInfo/PDB/Native/NativeRawSymbol.h"
@ -26,9 +27,8 @@ public:
codeview::EnumRecord Record); codeview::EnumRecord Record);
NativeTypeEnum(NativeSession &Session, SymIndexId Id, NativeTypeEnum(NativeSession &Session, SymIndexId Id,
codeview::TypeIndex ModifierTI, NativeTypeEnum &UnmodifiedType,
codeview::ModifierRecord Modifier, codeview::ModifierRecord Modifier);
codeview::EnumRecord EnumRecord);
~NativeTypeEnum() override; ~NativeTypeEnum() override;
void dump(raw_ostream &OS, int Indent, PdbSymbolIdField ShowIdFields, void dump(raw_ostream &OS, int Indent, PdbSymbolIdField ShowIdFields,
@ -60,10 +60,12 @@ public:
bool isInterfaceUdt() const override; bool isInterfaceUdt() const override;
const NativeTypeBuiltin &getUnderlyingBuiltinType() const; const NativeTypeBuiltin &getUnderlyingBuiltinType() const;
const codeview::EnumRecord &getEnumRecord() const { return *Record; }
protected: protected:
codeview::TypeIndex Index; codeview::TypeIndex Index;
codeview::EnumRecord Record; Optional<codeview::EnumRecord> Record;
NativeTypeEnum *UnmodifiedType = nullptr;
Optional<codeview::ModifierRecord> Modifiers; Optional<codeview::ModifierRecord> Modifiers;
}; };

View File

@ -0,0 +1,74 @@
//===- NativeTypeUDT.h - info about class/struct type ------------*- C++-*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_DEBUGINFO_PDB_NATIVE_NATIVETYPEUDT_H
#define LLVM_DEBUGINFO_PDB_NATIVE_NATIVETYPEUDT_H
#include "llvm/ADT/Optional.h"
#include "llvm/DebugInfo/CodeView/CodeView.h"
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
#include "llvm/DebugInfo/PDB/Native/NativeRawSymbol.h"
#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
namespace llvm {
namespace pdb {
class NativeTypeUDT : public NativeRawSymbol {
public:
NativeTypeUDT(NativeSession &Session, SymIndexId Id, codeview::TypeIndex TI,
codeview::ClassRecord Class);
NativeTypeUDT(NativeSession &Session, SymIndexId Id, codeview::TypeIndex TI,
codeview::UnionRecord Union);
NativeTypeUDT(NativeSession &Session, SymIndexId Id,
NativeTypeUDT &UnmodifiedType,
codeview::ModifierRecord Modifier);
~NativeTypeUDT() override;
void dump(raw_ostream &OS, int Indent, PdbSymbolIdField ShowIdFields,
PdbSymbolIdField RecurseIdFields) const override;
std::string getName() const override;
SymIndexId getLexicalParentId() const override;
SymIndexId getUnmodifiedTypeId() const override;
SymIndexId getVirtualTableShapeId() const override;
uint64_t getLength() const override;
PDB_UdtType getUdtKind() const override;
bool hasConstructor() const override;
bool isConstType() const override;
bool hasAssignmentOperator() const override;
bool hasCastOperator() const override;
bool hasNestedTypes() const override;
bool hasOverloadedOperator() const override;
bool isInterfaceUdt() const override;
bool isIntrinsic() const override;
bool isNested() const override;
bool isPacked() const override;
bool isRefUdt() const override;
bool isScoped() const override;
bool isValueUdt() const override;
bool isUnalignedType() const override;
bool isVolatileType() const override;
protected:
codeview::TypeIndex Index;
Optional<codeview::ClassRecord> Class;
Optional<codeview::UnionRecord> Union;
NativeTypeUDT *UnmodifiedType = nullptr;
codeview::TagRecord *Tag = nullptr;
Optional<codeview::ModifierRecord> Modifiers;
};
} // namespace pdb
} // namespace llvm
#endif // LLVM_DEBUGINFO_PDB_NATIVE_NATIVETYPEUDT_H

View File

@ -77,6 +77,9 @@ public:
std::unique_ptr<IPDBEnumSymbols> std::unique_ptr<IPDBEnumSymbols>
createTypeEnumerator(codeview::TypeLeafKind Kind); createTypeEnumerator(codeview::TypeLeafKind Kind);
std::unique_ptr<IPDBEnumSymbols>
createTypeEnumerator(std::vector<codeview::TypeLeafKind> Kinds);
SymIndexId findSymbolByTypeIndex(codeview::TypeIndex TI); SymIndexId findSymbolByTypeIndex(codeview::TypeIndex TI);
template <typename ConcreteSymbolT, typename... Args> template <typename ConcreteSymbolT, typename... Args>

View File

@ -34,6 +34,7 @@ add_llvm_library(LLVMDebugInfoCodeView
TypeIndex.cpp TypeIndex.cpp
TypeIndexDiscovery.cpp TypeIndexDiscovery.cpp
TypeHashing.cpp TypeHashing.cpp
TypeRecordHelpers.cpp
TypeRecordMapping.cpp TypeRecordMapping.cpp
TypeStreamMerger.cpp TypeStreamMerger.cpp
TypeTableCollection.cpp TypeTableCollection.cpp

View File

@ -0,0 +1,53 @@
//===- TypeRecordHelpers.cpp ------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/CodeView/TypeRecordHelpers.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"
#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
using namespace llvm;
using namespace llvm::codeview;
template <typename RecordT> static ClassOptions getUdtOptions(CVType CVT) {
RecordT Record;
if (auto EC = TypeDeserializer::deserializeAs<RecordT>(CVT, Record)) {
consumeError(std::move(EC));
return ClassOptions::None;
}
return Record.getOptions();
}
bool llvm::codeview::isUdtForwardRef(CVType CVT) {
ClassOptions UdtOptions = ClassOptions::None;
switch (CVT.kind()) {
case LF_STRUCTURE:
case LF_CLASS:
case LF_INTERFACE:
UdtOptions = getUdtOptions<ClassRecord>(std::move(CVT));
break;
case LF_ENUM:
UdtOptions = getUdtOptions<EnumRecord>(std::move(CVT));
break;
case LF_UNION:
UdtOptions = getUdtOptions<UnionRecord>(std::move(CVT));
break;
default:
return false;
}
return (UdtOptions & ClassOptions::ForwardReference) != ClassOptions::None;
}
TypeIndex llvm::codeview::getModifiedType(const CVType &CVT) {
assert(CVT.kind() == LF_MODIFIER);
SmallVector<TypeIndex, 1> Refs;
discoverTypeIndices(CVT, Refs);
return Refs.front();
}

View File

@ -55,6 +55,7 @@ add_pdb_impl_folder(Native
Native/NativeTypeBuiltin.cpp Native/NativeTypeBuiltin.cpp
Native/NativeTypeEnum.cpp Native/NativeTypeEnum.cpp
Native/NativeTypePointer.cpp Native/NativeTypePointer.cpp
Native/NativeTypeUDT.cpp
Native/NamedStreamMap.cpp Native/NamedStreamMap.cpp
Native/NativeSession.cpp Native/NativeSession.cpp
Native/PDBFile.cpp Native/PDBFile.cpp

View File

@ -10,6 +10,7 @@
#include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h" #include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h"
#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" #include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
#include "llvm/DebugInfo/CodeView/TypeRecordHelpers.h"
#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"
#include "llvm/DebugInfo/PDB/Native/NativeSession.h" #include "llvm/DebugInfo/PDB/Native/NativeSession.h"
#include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h" #include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h"
@ -22,21 +23,24 @@ using namespace llvm::pdb;
NativeEnumTypes::NativeEnumTypes(NativeSession &PDBSession, NativeEnumTypes::NativeEnumTypes(NativeSession &PDBSession,
LazyRandomTypeCollection &Types, LazyRandomTypeCollection &Types,
TypeLeafKind Kind) std::vector<codeview::TypeLeafKind> Kinds)
: Matches(), Index(0), Session(PDBSession) { : Matches(), Index(0), Session(PDBSession) {
Optional<TypeIndex> TI = Types.getFirst(); Optional<TypeIndex> TI = Types.getFirst();
while (TI) { while (TI) {
CVType CVT = Types.getType(*TI); CVType CVT = Types.getType(*TI);
TypeLeafKind K = CVT.kind(); TypeLeafKind K = CVT.kind();
if (K == Kind) if (llvm::is_contained(Kinds, K)) {
// Don't add forward refs, we'll find those later while enumerating.
if (!isUdtForwardRef(CVT))
Matches.push_back(*TI); Matches.push_back(*TI);
else if (K == TypeLeafKind::LF_MODIFIER) { } else if (K == TypeLeafKind::LF_MODIFIER) {
ModifierRecord MR; TypeIndex ModifiedTI = getModifiedType(CVT);
if (auto EC = TypeDeserializer::deserializeAs<ModifierRecord>(CVT, MR)) { if (!ModifiedTI.isSimple()) {
consumeError(std::move(EC)); CVType UnmodifiedCVT = Types.getType(ModifiedTI);
} else if (!MR.ModifiedType.isSimple()) { // LF_MODIFIERs point to forward refs, but don't worry about that
CVType UnmodifiedCVT = Types.getType(MR.ModifiedType); // here. We're pushing the TypeIndex of the LF_MODIFIER itself,
if (UnmodifiedCVT.kind() == Kind) // so we'll worry about resolving forward refs later.
if (llvm::is_contained(Kinds, UnmodifiedCVT.kind()))
Matches.push_back(*TI); Matches.push_back(*TI);
} }
} }
@ -44,11 +48,6 @@ NativeEnumTypes::NativeEnumTypes(NativeSession &PDBSession,
} }
} }
NativeEnumTypes::NativeEnumTypes(NativeSession &PDBSession,
const std::vector<TypeIndex> &Matches,
TypeLeafKind Kind)
: Matches(Matches), Index(0), Session(PDBSession) {}
uint32_t NativeEnumTypes::getChildCount() const { uint32_t NativeEnumTypes::getChildCount() const {
return static_cast<uint32_t>(Matches.size()); return static_cast<uint32_t>(Matches.size());
} }

View File

@ -45,6 +45,10 @@ NativeExeSymbol::findChildren(PDB_SymType Type) const {
return Session.getSymbolCache().createTypeEnumerator(codeview::LF_ENUM); return Session.getSymbolCache().createTypeEnumerator(codeview::LF_ENUM);
case PDB_SymType::PointerType: case PDB_SymType::PointerType:
return Session.getSymbolCache().createTypeEnumerator(codeview::LF_POINTER); return Session.getSymbolCache().createTypeEnumerator(codeview::LF_POINTER);
case PDB_SymType::UDT:
return Session.getSymbolCache().createTypeEnumerator(
{codeview::LF_STRUCTURE, codeview::LF_CLASS, codeview::LF_UNION,
codeview::LF_INTERFACE});
default: default:
break; break;
} }

View File

@ -31,68 +31,68 @@ void NativeRawSymbol::dump(raw_ostream &OS, int Indent,
std::unique_ptr<IPDBEnumSymbols> std::unique_ptr<IPDBEnumSymbols>
NativeRawSymbol::findChildren(PDB_SymType Type) const { NativeRawSymbol::findChildren(PDB_SymType Type) const {
return nullptr; return llvm::make_unique<NullEnumerator<PDBSymbol>>();
} }
std::unique_ptr<IPDBEnumSymbols> std::unique_ptr<IPDBEnumSymbols>
NativeRawSymbol::findChildren(PDB_SymType Type, StringRef Name, NativeRawSymbol::findChildren(PDB_SymType Type, StringRef Name,
PDB_NameSearchFlags Flags) const { PDB_NameSearchFlags Flags) const {
return nullptr; return llvm::make_unique<NullEnumerator<PDBSymbol>>();
} }
std::unique_ptr<IPDBEnumSymbols> std::unique_ptr<IPDBEnumSymbols>
NativeRawSymbol::findChildrenByAddr(PDB_SymType Type, StringRef Name, NativeRawSymbol::findChildrenByAddr(PDB_SymType Type, StringRef Name,
PDB_NameSearchFlags Flags, uint32_t Section, uint32_t Offset) const { PDB_NameSearchFlags Flags, uint32_t Section, uint32_t Offset) const {
return nullptr; return llvm::make_unique<NullEnumerator<PDBSymbol>>();
} }
std::unique_ptr<IPDBEnumSymbols> std::unique_ptr<IPDBEnumSymbols>
NativeRawSymbol::findChildrenByVA(PDB_SymType Type, StringRef Name, NativeRawSymbol::findChildrenByVA(PDB_SymType Type, StringRef Name,
PDB_NameSearchFlags Flags, uint64_t VA) const { PDB_NameSearchFlags Flags, uint64_t VA) const {
return nullptr; return llvm::make_unique<NullEnumerator<PDBSymbol>>();
} }
std::unique_ptr<IPDBEnumSymbols> std::unique_ptr<IPDBEnumSymbols>
NativeRawSymbol::findChildrenByRVA(PDB_SymType Type, StringRef Name, NativeRawSymbol::findChildrenByRVA(PDB_SymType Type, StringRef Name,
PDB_NameSearchFlags Flags, uint32_t RVA) const { PDB_NameSearchFlags Flags, uint32_t RVA) const {
return nullptr; return llvm::make_unique<NullEnumerator<PDBSymbol>>();
} }
std::unique_ptr<IPDBEnumSymbols> std::unique_ptr<IPDBEnumSymbols>
NativeRawSymbol::findInlineFramesByAddr(uint32_t Section, NativeRawSymbol::findInlineFramesByAddr(uint32_t Section,
uint32_t Offset) const { uint32_t Offset) const {
return nullptr; return llvm::make_unique<NullEnumerator<PDBSymbol>>();
} }
std::unique_ptr<IPDBEnumSymbols> std::unique_ptr<IPDBEnumSymbols>
NativeRawSymbol::findInlineFramesByRVA(uint32_t RVA) const { NativeRawSymbol::findInlineFramesByRVA(uint32_t RVA) const {
return nullptr; return llvm::make_unique<NullEnumerator<PDBSymbol>>();
} }
std::unique_ptr<IPDBEnumSymbols> std::unique_ptr<IPDBEnumSymbols>
NativeRawSymbol::findInlineFramesByVA(uint64_t VA) const { NativeRawSymbol::findInlineFramesByVA(uint64_t VA) const {
return nullptr; return llvm::make_unique<NullEnumerator<PDBSymbol>>();
} }
std::unique_ptr<IPDBEnumLineNumbers> std::unique_ptr<IPDBEnumLineNumbers>
NativeRawSymbol::findInlineeLines() const { NativeRawSymbol::findInlineeLines() const {
return nullptr; return llvm::make_unique<NullEnumerator<IPDBLineNumber>>();
} }
std::unique_ptr<IPDBEnumLineNumbers> std::unique_ptr<IPDBEnumLineNumbers>
NativeRawSymbol::findInlineeLinesByAddr(uint32_t Section, uint32_t Offset, NativeRawSymbol::findInlineeLinesByAddr(uint32_t Section, uint32_t Offset,
uint32_t Length) const { uint32_t Length) const {
return nullptr; return llvm::make_unique<NullEnumerator<IPDBLineNumber>>();
} }
std::unique_ptr<IPDBEnumLineNumbers> std::unique_ptr<IPDBEnumLineNumbers>
NativeRawSymbol::findInlineeLinesByRVA(uint32_t RVA, uint32_t Length) const { NativeRawSymbol::findInlineeLinesByRVA(uint32_t RVA, uint32_t Length) const {
return nullptr; return llvm::make_unique<NullEnumerator<IPDBLineNumber>>();
} }
std::unique_ptr<IPDBEnumLineNumbers> std::unique_ptr<IPDBEnumLineNumbers>
NativeRawSymbol::findInlineeLinesByVA(uint64_t VA, uint32_t Length) const { NativeRawSymbol::findInlineeLinesByVA(uint64_t VA, uint32_t Length) const {
return nullptr; return llvm::make_unique<NullEnumerator<IPDBLineNumber>>();
} }
void NativeRawSymbol::getDataBytes(SmallVector<uint8_t, 32> &bytes) const { void NativeRawSymbol::getDataBytes(SmallVector<uint8_t, 32> &bytes) const {

View File

@ -40,8 +40,7 @@ namespace {
class NativeEnumEnumEnumerators : public IPDBEnumSymbols, TypeVisitorCallbacks { class NativeEnumEnumEnumerators : public IPDBEnumSymbols, TypeVisitorCallbacks {
public: public:
NativeEnumEnumEnumerators(NativeSession &Session, NativeEnumEnumEnumerators(NativeSession &Session,
const NativeTypeEnum &ClassParent, const NativeTypeEnum &ClassParent);
const codeview::EnumRecord &CVEnum);
uint32_t getChildCount() const override; uint32_t getChildCount() const override;
std::unique_ptr<PDBSymbol> getChildAtIndex(uint32_t Index) const override; std::unique_ptr<PDBSymbol> getChildAtIndex(uint32_t Index) const override;
@ -56,7 +55,6 @@ private:
NativeSession &Session; NativeSession &Session;
const NativeTypeEnum &ClassParent; const NativeTypeEnum &ClassParent;
const codeview::EnumRecord &CVEnum;
std::vector<EnumeratorRecord> Enumerators; std::vector<EnumeratorRecord> Enumerators;
Optional<TypeIndex> ContinuationIndex; Optional<TypeIndex> ContinuationIndex;
uint32_t Index = 0; uint32_t Index = 0;
@ -64,13 +62,12 @@ private:
} // namespace } // namespace
NativeEnumEnumEnumerators::NativeEnumEnumEnumerators( NativeEnumEnumEnumerators::NativeEnumEnumEnumerators(
NativeSession &Session, const NativeTypeEnum &ClassParent, NativeSession &Session, const NativeTypeEnum &ClassParent)
const codeview::EnumRecord &CVEnum) : Session(Session), ClassParent(ClassParent) {
: Session(Session), ClassParent(ClassParent), CVEnum(CVEnum) {
TpiStream &Tpi = cantFail(Session.getPDBFile().getPDBTpiStream()); TpiStream &Tpi = cantFail(Session.getPDBFile().getPDBTpiStream());
LazyRandomTypeCollection &Types = Tpi.typeCollection(); LazyRandomTypeCollection &Types = Tpi.typeCollection();
ContinuationIndex = CVEnum.FieldList; ContinuationIndex = ClassParent.getEnumRecord().FieldList;
while (ContinuationIndex) { while (ContinuationIndex) {
CVType FieldList = Types.getType(*ContinuationIndex); CVType FieldList = Types.getType(*ContinuationIndex);
assert(FieldList.kind() == LF_FIELDLIST); assert(FieldList.kind() == LF_FIELDLIST);
@ -100,10 +97,10 @@ NativeEnumEnumEnumerators::getChildAtIndex(uint32_t Index) const {
if (Index >= getChildCount()) if (Index >= getChildCount())
return nullptr; return nullptr;
SymIndexId Id = SymIndexId Id = Session.getSymbolCache()
Session.getSymbolCache()
.getOrCreateFieldListMember<NativeSymbolEnumerator>( .getOrCreateFieldListMember<NativeSymbolEnumerator>(
CVEnum.FieldList, Index, ClassParent, Enumerators[Index]); ClassParent.getEnumRecord().FieldList, Index,
ClassParent, Enumerators[Index]);
return Session.getSymbolCache().getSymbolById(Id); return Session.getSymbolCache().getSymbolById(Id);
} }
@ -122,11 +119,10 @@ NativeTypeEnum::NativeTypeEnum(NativeSession &Session, SymIndexId Id,
Record(std::move(Record)) {} Record(std::move(Record)) {}
NativeTypeEnum::NativeTypeEnum(NativeSession &Session, SymIndexId Id, NativeTypeEnum::NativeTypeEnum(NativeSession &Session, SymIndexId Id,
codeview::TypeIndex ModifierTI, NativeTypeEnum &UnmodifiedType,
codeview::ModifierRecord Modifier, codeview::ModifierRecord Modifier)
codeview::EnumRecord EnumRecord) : NativeRawSymbol(Session, PDB_SymType::Enum, Id),
: NativeRawSymbol(Session, PDB_SymType::Enum, Id), Index(ModifierTI), UnmodifiedType(&UnmodifiedType), Modifiers(std::move(Modifier)) {}
Record(std::move(EnumRecord)), Modifiers(std::move(Modifier)) {}
NativeTypeEnum::~NativeTypeEnum() {} NativeTypeEnum::~NativeTypeEnum() {}
@ -173,22 +169,20 @@ NativeTypeEnum::findChildren(PDB_SymType Type) const {
const NativeTypeEnum *ClassParent = nullptr; const NativeTypeEnum *ClassParent = nullptr;
if (!Modifiers) if (!Modifiers)
ClassParent = this; ClassParent = this;
else { else
NativeRawSymbol &NRS = ClassParent = UnmodifiedType;
Session.getSymbolCache().getNativeSymbolById(getUnmodifiedTypeId()); return llvm::make_unique<NativeEnumEnumEnumerators>(Session, *ClassParent);
assert(NRS.getSymTag() == PDB_SymType::Enum);
ClassParent = static_cast<NativeTypeEnum *>(&NRS);
}
return llvm::make_unique<NativeEnumEnumEnumerators>(Session, *ClassParent,
Record);
} }
PDB_SymType NativeTypeEnum::getSymTag() const { return PDB_SymType::Enum; } PDB_SymType NativeTypeEnum::getSymTag() const { return PDB_SymType::Enum; }
PDB_BuiltinType NativeTypeEnum::getBuiltinType() const { PDB_BuiltinType NativeTypeEnum::getBuiltinType() const {
Session.getSymbolCache().findSymbolByTypeIndex(Record.getUnderlyingType()); if (UnmodifiedType)
return UnmodifiedType->getBuiltinType();
codeview::TypeIndex Underlying = Record.getUnderlyingType(); Session.getSymbolCache().findSymbolByTypeIndex(Record->getUnderlyingType());
codeview::TypeIndex Underlying = Record->getUnderlyingType();
// This indicates a corrupt record. // This indicates a corrupt record.
if (!Underlying.isSimple() || if (!Underlying.isSimple() ||
@ -255,67 +249,101 @@ PDB_BuiltinType NativeTypeEnum::getBuiltinType() const {
} }
SymIndexId NativeTypeEnum::getUnmodifiedTypeId() const { SymIndexId NativeTypeEnum::getUnmodifiedTypeId() const {
if (!Modifiers) return UnmodifiedType ? UnmodifiedType->getSymIndexId() : 0;
return 0;
return Session.getSymbolCache().findSymbolByTypeIndex(
Modifiers->ModifiedType);
} }
bool NativeTypeEnum::hasConstructor() const { bool NativeTypeEnum::hasConstructor() const {
return bool(Record.getOptions() & if (UnmodifiedType)
return UnmodifiedType->hasConstructor();
return bool(Record->getOptions() &
codeview::ClassOptions::HasConstructorOrDestructor); codeview::ClassOptions::HasConstructorOrDestructor);
} }
bool NativeTypeEnum::hasAssignmentOperator() const { bool NativeTypeEnum::hasAssignmentOperator() const {
return bool(Record.getOptions() & if (UnmodifiedType)
return UnmodifiedType->hasAssignmentOperator();
return bool(Record->getOptions() &
codeview::ClassOptions::HasOverloadedAssignmentOperator); codeview::ClassOptions::HasOverloadedAssignmentOperator);
} }
bool NativeTypeEnum::hasNestedTypes() const { bool NativeTypeEnum::hasNestedTypes() const {
return bool(Record.getOptions() & if (UnmodifiedType)
return UnmodifiedType->hasNestedTypes();
return bool(Record->getOptions() &
codeview::ClassOptions::ContainsNestedClass); codeview::ClassOptions::ContainsNestedClass);
} }
bool NativeTypeEnum::isIntrinsic() const { bool NativeTypeEnum::isIntrinsic() const {
return bool(Record.getOptions() & codeview::ClassOptions::Intrinsic); if (UnmodifiedType)
return UnmodifiedType->isIntrinsic();
return bool(Record->getOptions() & codeview::ClassOptions::Intrinsic);
} }
bool NativeTypeEnum::hasCastOperator() const { bool NativeTypeEnum::hasCastOperator() const {
return bool(Record.getOptions() & if (UnmodifiedType)
return UnmodifiedType->hasCastOperator();
return bool(Record->getOptions() &
codeview::ClassOptions::HasConversionOperator); codeview::ClassOptions::HasConversionOperator);
} }
uint64_t NativeTypeEnum::getLength() const { uint64_t NativeTypeEnum::getLength() const {
if (UnmodifiedType)
return UnmodifiedType->getLength();
const auto Id = Session.getSymbolCache().findSymbolByTypeIndex( const auto Id = Session.getSymbolCache().findSymbolByTypeIndex(
Record.getUnderlyingType()); Record->getUnderlyingType());
const auto UnderlyingType = const auto UnderlyingType =
Session.getConcreteSymbolById<PDBSymbolTypeBuiltin>(Id); Session.getConcreteSymbolById<PDBSymbolTypeBuiltin>(Id);
return UnderlyingType ? UnderlyingType->getLength() : 0; return UnderlyingType ? UnderlyingType->getLength() : 0;
} }
std::string NativeTypeEnum::getName() const { return Record.getName(); } std::string NativeTypeEnum::getName() const {
if (UnmodifiedType)
return UnmodifiedType->getName();
return Record->getName();
}
bool NativeTypeEnum::isNested() const { bool NativeTypeEnum::isNested() const {
return bool(Record.getOptions() & codeview::ClassOptions::Nested); if (UnmodifiedType)
return UnmodifiedType->isNested();
return bool(Record->getOptions() & codeview::ClassOptions::Nested);
} }
bool NativeTypeEnum::hasOverloadedOperator() const { bool NativeTypeEnum::hasOverloadedOperator() const {
return bool(Record.getOptions() & if (UnmodifiedType)
return UnmodifiedType->hasOverloadedOperator();
return bool(Record->getOptions() &
codeview::ClassOptions::HasOverloadedOperator); codeview::ClassOptions::HasOverloadedOperator);
} }
bool NativeTypeEnum::isPacked() const { bool NativeTypeEnum::isPacked() const {
return bool(Record.getOptions() & codeview::ClassOptions::Packed); if (UnmodifiedType)
return UnmodifiedType->isPacked();
return bool(Record->getOptions() & codeview::ClassOptions::Packed);
} }
bool NativeTypeEnum::isScoped() const { bool NativeTypeEnum::isScoped() const {
return bool(Record.getOptions() & codeview::ClassOptions::Scoped); if (UnmodifiedType)
return UnmodifiedType->isScoped();
return bool(Record->getOptions() & codeview::ClassOptions::Scoped);
} }
SymIndexId NativeTypeEnum::getTypeId() const { SymIndexId NativeTypeEnum::getTypeId() const {
if (UnmodifiedType)
return UnmodifiedType->getTypeId();
return Session.getSymbolCache().findSymbolByTypeIndex( return Session.getSymbolCache().findSymbolByTypeIndex(
Record.getUnderlyingType()); Record->getUnderlyingType());
} }
bool NativeTypeEnum::isRefUdt() const { return false; } bool NativeTypeEnum::isRefUdt() const { return false; }
@ -346,6 +374,9 @@ bool NativeTypeEnum::isUnalignedType() const {
} }
const NativeTypeBuiltin &NativeTypeEnum::getUnderlyingBuiltinType() const { const NativeTypeBuiltin &NativeTypeEnum::getUnderlyingBuiltinType() const {
if (UnmodifiedType)
return UnmodifiedType->getUnderlyingBuiltinType();
return Session.getSymbolCache().getNativeSymbolById<NativeTypeBuiltin>( return Session.getSymbolCache().getNativeSymbolById<NativeTypeBuiltin>(
getTypeId()); getTypeId());
} }

View File

@ -0,0 +1,221 @@
//===- NativeTypeUDT.cpp - info about class/struct type ---------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/PDB/Native/NativeTypeUDT.h"
#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
#include <cassert>
using namespace llvm;
using namespace llvm::codeview;
using namespace llvm::pdb;
NativeTypeUDT::NativeTypeUDT(NativeSession &Session, SymIndexId Id,
codeview::TypeIndex TI, codeview::ClassRecord CR)
: NativeRawSymbol(Session, PDB_SymType::UDT, Id), Index(TI),
Class(std::move(CR)), Tag(Class.getPointer()) {}
NativeTypeUDT::NativeTypeUDT(NativeSession &Session, SymIndexId Id,
codeview::TypeIndex TI, codeview::UnionRecord UR)
: NativeRawSymbol(Session, PDB_SymType::UDT, Id), Index(TI),
Union(std::move(UR)), Tag(Union.getPointer()) {}
NativeTypeUDT::NativeTypeUDT(NativeSession &Session, SymIndexId Id,
NativeTypeUDT &UnmodifiedType,
codeview::ModifierRecord Modifier)
: NativeRawSymbol(Session, PDB_SymType::UDT, Id),
UnmodifiedType(&UnmodifiedType), Modifiers(std::move(Modifier)) {}
NativeTypeUDT::~NativeTypeUDT() {}
void NativeTypeUDT::dump(raw_ostream &OS, int Indent,
PdbSymbolIdField ShowIdFields,
PdbSymbolIdField RecurseIdFields) const {
NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields);
dumpSymbolField(OS, "name", getName(), Indent);
dumpSymbolIdField(OS, "lexicalParentId", 0, Indent, Session,
PdbSymbolIdField::LexicalParent, ShowIdFields,
RecurseIdFields);
if (Modifiers.hasValue())
dumpSymbolIdField(OS, "unmodifiedTypeId", getUnmodifiedTypeId(), Indent,
Session, PdbSymbolIdField::UnmodifiedType, ShowIdFields,
RecurseIdFields);
if (getUdtKind() != PDB_UdtType::Union)
dumpSymbolField(OS, "virtualTableShapeId", getVirtualTableShapeId(),
Indent);
dumpSymbolField(OS, "length", getLength(), Indent);
dumpSymbolField(OS, "udtKind", getUdtKind(), Indent);
dumpSymbolField(OS, "constructor", hasConstructor(), Indent);
dumpSymbolField(OS, "constType", isConstType(), Indent);
dumpSymbolField(OS, "hasAssignmentOperator", hasAssignmentOperator(), Indent);
dumpSymbolField(OS, "hasCastOperator", hasCastOperator(), Indent);
dumpSymbolField(OS, "hasNestedTypes", hasNestedTypes(), Indent);
dumpSymbolField(OS, "overloadedOperator", hasOverloadedOperator(), Indent);
dumpSymbolField(OS, "isInterfaceUdt", isInterfaceUdt(), Indent);
dumpSymbolField(OS, "intrinsic", isIntrinsic(), Indent);
dumpSymbolField(OS, "nested", isNested(), Indent);
dumpSymbolField(OS, "packed", isPacked(), Indent);
dumpSymbolField(OS, "isRefUdt", isRefUdt(), Indent);
dumpSymbolField(OS, "scoped", isScoped(), Indent);
dumpSymbolField(OS, "unalignedType", isUnalignedType(), Indent);
dumpSymbolField(OS, "isValueUdt", isValueUdt(), Indent);
dumpSymbolField(OS, "volatileType", isVolatileType(), Indent);
}
std::string NativeTypeUDT::getName() const {
if (UnmodifiedType)
return UnmodifiedType->getName();
return Tag->getName();
}
SymIndexId NativeTypeUDT::getLexicalParentId() const { return 0; }
SymIndexId NativeTypeUDT::getUnmodifiedTypeId() const {
if (UnmodifiedType)
return UnmodifiedType->getSymIndexId();
return 0;
}
SymIndexId NativeTypeUDT::getVirtualTableShapeId() const {
if (UnmodifiedType)
return UnmodifiedType->getVirtualTableShapeId();
if (Class)
return Session.getSymbolCache().findSymbolByTypeIndex(Class->VTableShape);
return 0;
}
uint64_t NativeTypeUDT::getLength() const {
if (UnmodifiedType)
return UnmodifiedType->getLength();
if (Class)
return Class->getSize();
return Union->getSize();
}
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("Unexected udt kind");
}
}
bool NativeTypeUDT::hasConstructor() const {
if (UnmodifiedType)
return UnmodifiedType->hasConstructor();
return (Tag->Options & ClassOptions::HasConstructorOrDestructor) !=
ClassOptions::None;
}
bool NativeTypeUDT::isConstType() const {
if (!Modifiers)
return false;
return (Modifiers->Modifiers & ModifierOptions::Const) !=
ModifierOptions::None;
}
bool NativeTypeUDT::hasAssignmentOperator() const {
if (UnmodifiedType)
return UnmodifiedType->hasAssignmentOperator();
return (Tag->Options & ClassOptions::HasOverloadedAssignmentOperator) !=
ClassOptions::None;
}
bool NativeTypeUDT::hasCastOperator() const {
if (UnmodifiedType)
return UnmodifiedType->hasCastOperator();
return (Tag->Options & ClassOptions::HasConversionOperator) !=
ClassOptions::None;
}
bool NativeTypeUDT::hasNestedTypes() const {
if (UnmodifiedType)
return UnmodifiedType->hasNestedTypes();
return (Tag->Options & ClassOptions::ContainsNestedClass) !=
ClassOptions::None;
}
bool NativeTypeUDT::hasOverloadedOperator() const {
if (UnmodifiedType)
return UnmodifiedType->hasOverloadedOperator();
return (Tag->Options & ClassOptions::HasOverloadedOperator) !=
ClassOptions::None;
}
bool NativeTypeUDT::isInterfaceUdt() const { return false; }
bool NativeTypeUDT::isIntrinsic() const {
if (UnmodifiedType)
return UnmodifiedType->isIntrinsic();
return (Tag->Options & ClassOptions::Intrinsic) != ClassOptions::None;
}
bool NativeTypeUDT::isNested() const {
if (UnmodifiedType)
return UnmodifiedType->isNested();
return (Tag->Options & ClassOptions::Nested) != ClassOptions::None;
}
bool NativeTypeUDT::isPacked() const {
if (UnmodifiedType)
return UnmodifiedType->isPacked();
return (Tag->Options & ClassOptions::Packed) != ClassOptions::None;
}
bool NativeTypeUDT::isRefUdt() const { return false; }
bool NativeTypeUDT::isScoped() const {
if (UnmodifiedType)
return UnmodifiedType->isScoped();
return (Tag->Options & ClassOptions::Scoped) != ClassOptions::None;
}
bool NativeTypeUDT::isValueUdt() const { return false; }
bool NativeTypeUDT::isUnalignedType() const {
if (!Modifiers)
return false;
return (Modifiers->Modifiers & ModifierOptions::Unaligned) !=
ModifierOptions::None;
}
bool NativeTypeUDT::isVolatileType() const {
if (!Modifiers)
return false;
return (Modifiers->Modifiers & ModifierOptions::Volatile) !=
ModifierOptions::None;
}

View File

@ -1,6 +1,7 @@
#include "llvm/DebugInfo/PDB/Native/SymbolCache.h" #include "llvm/DebugInfo/PDB/Native/SymbolCache.h"
#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" #include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
#include "llvm/DebugInfo/CodeView/TypeRecordHelpers.h"
#include "llvm/DebugInfo/PDB/Native/DbiStream.h" #include "llvm/DebugInfo/PDB/Native/DbiStream.h"
#include "llvm/DebugInfo/PDB/Native/NativeCompilandSymbol.h" #include "llvm/DebugInfo/PDB/Native/NativeCompilandSymbol.h"
#include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h" #include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h"
@ -9,6 +10,7 @@
#include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h" #include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h"
#include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h" #include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h"
#include "llvm/DebugInfo/PDB/Native/NativeTypePointer.h" #include "llvm/DebugInfo/PDB/Native/NativeTypePointer.h"
#include "llvm/DebugInfo/PDB/Native/NativeTypeUDT.h"
#include "llvm/DebugInfo/PDB/Native/PDBFile.h" #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
#include "llvm/DebugInfo/PDB/Native/TpiStream.h" #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
#include "llvm/DebugInfo/PDB/PDBSymbol.h" #include "llvm/DebugInfo/PDB/PDBSymbol.h"
@ -50,10 +52,18 @@ SymbolCache::SymbolCache(NativeSession &Session, DbiStream *Dbi)
if (Dbi) if (Dbi)
Compilands.resize(Dbi->modules().getModuleCount()); Compilands.resize(Dbi->modules().getModuleCount());
auto &Tpi = cantFail(Session.getPDBFile().getPDBTpiStream());
Tpi.buildHashMap();
} }
std::unique_ptr<IPDBEnumSymbols> std::unique_ptr<IPDBEnumSymbols>
SymbolCache::createTypeEnumerator(codeview::TypeLeafKind Kind) { SymbolCache::createTypeEnumerator(TypeLeafKind Kind) {
return createTypeEnumerator(std::vector<TypeLeafKind>{Kind});
}
std::unique_ptr<IPDBEnumSymbols>
SymbolCache::createTypeEnumerator(std::vector<TypeLeafKind> Kinds) {
auto Tpi = Session.getPDBFile().getPDBTpiStream(); auto Tpi = Session.getPDBFile().getPDBTpiStream();
if (!Tpi) { if (!Tpi) {
consumeError(Tpi.takeError()); consumeError(Tpi.takeError());
@ -61,7 +71,7 @@ SymbolCache::createTypeEnumerator(codeview::TypeLeafKind Kind) {
} }
auto &Types = Tpi->typeCollection(); auto &Types = Tpi->typeCollection();
return std::unique_ptr<IPDBEnumSymbols>( return std::unique_ptr<IPDBEnumSymbols>(
new NativeEnumTypes(Session, Types, Kind)); new NativeEnumTypes(Session, Types, std::move(Kinds)));
} }
SymIndexId SymbolCache::createSimpleType(TypeIndex Index, SymIndexId SymbolCache::createSimpleType(TypeIndex Index,
@ -98,38 +108,24 @@ SymbolCache::createSymbolForModifiedType(codeview::TypeIndex ModifierTI,
if (Record.ModifiedType.isSimple()) if (Record.ModifiedType.isSimple())
return createSimpleType(Record.ModifiedType, Record.Modifiers); return createSimpleType(Record.ModifiedType, Record.Modifiers);
auto Tpi = Session.getPDBFile().getPDBTpiStream(); // Make sure we create and cache a record for the unmodified type.
if (!Tpi) { SymIndexId UnmodifiedId = findSymbolByTypeIndex(Record.ModifiedType);
consumeError(Tpi.takeError()); NativeRawSymbol &UnmodifiedNRS = *Cache[UnmodifiedId];
return 0;
}
codeview::LazyRandomTypeCollection &Types = Tpi->typeCollection();
codeview::CVType UnmodifiedType = Types.getType(Record.ModifiedType); switch (UnmodifiedNRS.getSymTag()) {
case PDB_SymType::Enum:
switch (UnmodifiedType.kind()) { return createSymbol<NativeTypeEnum>(
case LF_ENUM: { static_cast<NativeTypeEnum &>(UnmodifiedNRS), std::move(Record));
EnumRecord ER; case PDB_SymType::UDT:
if (auto EC = return createSymbol<NativeTypeUDT>(
TypeDeserializer::deserializeAs<EnumRecord>(UnmodifiedType, ER)) { static_cast<NativeTypeUDT &>(UnmodifiedNRS), std::move(Record));
consumeError(std::move(EC));
return 0;
}
return createSymbol<NativeTypeEnum>(Record.ModifiedType, std::move(Record),
std::move(ER));
}
case LF_STRUCTURE:
case LF_UNION:
case LF_CLASS:
// FIXME: Handle these
break;
default: default:
// No other types can be modified. (LF_POINTER, for example, records // No other types can be modified. (LF_POINTER, for example, records
// its modifiers a different way. // its modifiers a different way.
assert(false && "Invalid LF_MODIFIER record"); assert(false && "Invalid LF_MODIFIER record");
break; break;
} }
return createSymbolPlaceholder(); return 0;
} }
SymIndexId SymbolCache::findSymbolByTypeIndex(codeview::TypeIndex Index) { SymIndexId SymbolCache::findSymbolByTypeIndex(codeview::TypeIndex Index) {
@ -150,13 +146,37 @@ SymIndexId SymbolCache::findSymbolByTypeIndex(codeview::TypeIndex Index) {
} }
codeview::LazyRandomTypeCollection &Types = Tpi->typeCollection(); codeview::LazyRandomTypeCollection &Types = Tpi->typeCollection();
codeview::CVType CVT = Types.getType(Index); codeview::CVType CVT = Types.getType(Index);
// TODO(amccarth): Make this handle all types.
SymIndexId Id = 0;
if (isUdtForwardRef(CVT)) {
Expected<TypeIndex> EFD = Tpi->findFullDeclForForwardRef(Index);
if (!EFD)
consumeError(EFD.takeError());
else if (*EFD != Index) {
assert(!isUdtForwardRef(Types.getType(*EFD)));
SymIndexId Result = findSymbolByTypeIndex(*EFD);
// Record a mapping from ForwardRef -> SymIndex of complete type so that
// we'll take the fast path next time.
TypeIndexToSymbolId[Index] = Result;
return Result;
}
}
// At this point if we still have a forward ref udt it means the full decl was
// not in the PDB. We just have to deal with it and use the forward ref.
SymIndexId Id = 0;
switch (CVT.kind()) { switch (CVT.kind()) {
case codeview::LF_ENUM: case codeview::LF_ENUM:
Id = createSymbolForType<NativeTypeEnum, EnumRecord>(Index, std::move(CVT)); Id = createSymbolForType<NativeTypeEnum, EnumRecord>(Index, std::move(CVT));
break; break;
case codeview::LF_CLASS:
case codeview::LF_STRUCTURE:
case codeview::LF_INTERFACE:
Id = createSymbolForType<NativeTypeUDT, ClassRecord>(Index, std::move(CVT));
break;
case codeview::LF_UNION:
Id = createSymbolForType<NativeTypeUDT, UnionRecord>(Index, std::move(CVT));
break;
case codeview::LF_POINTER: case codeview::LF_POINTER:
Id = createSymbolForType<NativeTypePointer, PointerRecord>(Index, Id = createSymbolForType<NativeTypePointer, PointerRecord>(Index,
std::move(CVT)); std::move(CVT));

View File

@ -11,9 +11,8 @@
#include "llvm/ADT/iterator_range.h" #include "llvm/ADT/iterator_range.h"
#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
#include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"
#include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h"
#include "llvm/DebugInfo/CodeView/TypeRecordHelpers.h"
#include "llvm/DebugInfo/MSF/MappedBlockStream.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
#include "llvm/DebugInfo/PDB/Native/Hash.h" #include "llvm/DebugInfo/PDB/Native/Hash.h"
#include "llvm/DebugInfo/PDB/Native/PDBFile.h" #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
@ -161,35 +160,6 @@ void TpiStream::buildHashMap() {
bool TpiStream::supportsTypeLookup() const { return !HashMap.empty(); } bool TpiStream::supportsTypeLookup() const { return !HashMap.empty(); }
template <typename RecordT> static ClassOptions getUdtOptions(CVType CVT) {
RecordT Record;
if (auto EC = TypeDeserializer::deserializeAs<RecordT>(CVT, Record)) {
consumeError(std::move(EC));
return ClassOptions::None;
}
return Record.getOptions();
}
static bool isUdtForwardRef(CVType CVT) {
ClassOptions UdtOptions = ClassOptions::None;
switch (CVT.kind()) {
case LF_STRUCTURE:
case LF_CLASS:
case LF_INTERFACE:
UdtOptions = getUdtOptions<ClassRecord>(std::move(CVT));
break;
case LF_ENUM:
UdtOptions = getUdtOptions<EnumRecord>(std::move(CVT));
break;
case LF_UNION:
UdtOptions = getUdtOptions<UnionRecord>(std::move(CVT));
break;
default:
return false;
}
return (UdtOptions & ClassOptions::ForwardReference) != ClassOptions::None;
}
Expected<TypeIndex> Expected<TypeIndex>
TpiStream::findFullDeclForForwardRef(TypeIndex ForwardRefTI) const { TpiStream::findFullDeclForForwardRef(TypeIndex ForwardRefTI) const {
CVType F = Types->getType(ForwardRefTI); CVType F = Types->getType(ForwardRefTI);

View File

@ -0,0 +1,539 @@
; RUN: llvm-pdbutil pretty -native -classes %p/../Inputs/every-class.pdb \
; RUN: | FileCheck -check-prefix=PRETTY %s
; RUN: llvm-pdbutil diadump -native -udts %p/../Inputs/every-class.pdb \
; RUN: | FileCheck -check-prefix=DUMP %s
PRETTY: struct main::__l2::<unnamed-type-Anonymous> [sizeof = 1]
PRETTY: struct main::__l2::Scoped [sizeof = 1]
PRETTY: struct __vc_attributes::event_sourceAttribute [sizeof = 12]
PRETTY: struct __vc_attributes::helper_attributes::v1_alttypeAttribute [sizeof = 4]
PRETTY: struct __vc_attributes::helper_attributes::usageAttribute [sizeof = 4]
PRETTY: struct __vc_attributes::threadingAttribute [sizeof = 4]
PRETTY: struct __vc_attributes::aggregatableAttribute [sizeof = 4]
PRETTY: struct __vc_attributes::event_receiverAttribute [sizeof = 8]
PRETTY: struct __vc_attributes::moduleAttribute [sizeof = 96]
PRETTY: struct Nested [sizeof = 1]
PRETTY: struct Nested::F [sizeof = 1]
PRETTY: struct Constructor [sizeof = 1]
PRETTY: class Class [sizeof = 1]
PRETTY: union Union [sizeof = 1]
PRETTY: struct Operator [sizeof = 1]
PRETTY: struct Cast [sizeof = 1]
PRETTY: struct Nothing [sizeof = 1]
PRETTY: struct Assignment [sizeof = 1]
PRETTY: const struct Nothing
PRETTY: volatile struct Nothing
PRETTY: const volatile struct Nothing
PRETTY: unaligned struct Nothing
; DUMP: {
; DUMP-NEXT: symIndexId: 2
; DUMP-NEXT: symTag: UDT
; DUMP-NEXT: name: main::__l2::<unnamed-type-Anonymous>
; DUMP-NEXT: virtualTableShapeId: 3
; DUMP-NEXT: length: 1
; DUMP-NEXT: udtKind: struct
; DUMP-NEXT: constructor: 0
; DUMP-NEXT: constType: 0
; DUMP-NEXT: hasAssignmentOperator: 0
; DUMP-NEXT: hasCastOperator: 0
; DUMP-NEXT: hasNestedTypes: 0
; DUMP-NEXT: overloadedOperator: 0
; DUMP-NEXT: isInterfaceUdt: 0
; DUMP-NEXT: intrinsic: 0
; DUMP-NEXT: nested: 0
; DUMP-NEXT: packed: 0
; DUMP-NEXT: isRefUdt: 0
; DUMP-NEXT: scoped: 1
; DUMP-NEXT: unalignedType: 0
; DUMP-NEXT: isValueUdt: 0
; DUMP-NEXT: volatileType: 0
; DUMP-NEXT: }
; DUMP-NEXT: {
; DUMP-NEXT: symIndexId: 4
; DUMP-NEXT: symTag: UDT
; DUMP-NEXT: name: main::__l2::Scoped
; DUMP-NEXT: virtualTableShapeId: 3
; DUMP-NEXT: length: 1
; DUMP-NEXT: udtKind: struct
; DUMP-NEXT: constructor: 0
; DUMP-NEXT: constType: 0
; DUMP-NEXT: hasAssignmentOperator: 0
; DUMP-NEXT: hasCastOperator: 0
; DUMP-NEXT: hasNestedTypes: 0
; DUMP-NEXT: overloadedOperator: 0
; DUMP-NEXT: isInterfaceUdt: 0
; DUMP-NEXT: intrinsic: 0
; DUMP-NEXT: nested: 0
; DUMP-NEXT: packed: 0
; DUMP-NEXT: isRefUdt: 0
; DUMP-NEXT: scoped: 1
; DUMP-NEXT: unalignedType: 0
; DUMP-NEXT: isValueUdt: 0
; DUMP-NEXT: volatileType: 0
; DUMP-NEXT: }
; DUMP-NEXT: {
; DUMP-NEXT: symIndexId: 5
; DUMP-NEXT: symTag: UDT
; DUMP-NEXT: name: __vc_attributes::event_sourceAttribute
; DUMP-NEXT: virtualTableShapeId: 3
; DUMP-NEXT: length: 12
; DUMP-NEXT: udtKind: struct
; DUMP-NEXT: constructor: 1
; DUMP-NEXT: constType: 0
; DUMP-NEXT: hasAssignmentOperator: 0
; DUMP-NEXT: hasCastOperator: 0
; DUMP-NEXT: hasNestedTypes: 1
; DUMP-NEXT: overloadedOperator: 0
; DUMP-NEXT: isInterfaceUdt: 0
; DUMP-NEXT: intrinsic: 0
; DUMP-NEXT: nested: 0
; DUMP-NEXT: packed: 0
; DUMP-NEXT: isRefUdt: 0
; DUMP-NEXT: scoped: 0
; DUMP-NEXT: unalignedType: 0
; DUMP-NEXT: isValueUdt: 0
; DUMP-NEXT: volatileType: 0
; DUMP-NEXT: }
; DUMP-NEXT: {
; DUMP-NEXT: symIndexId: 6
; DUMP-NEXT: symTag: UDT
; DUMP-NEXT: name: __vc_attributes::helper_attributes::v1_alttypeAttribute
; DUMP-NEXT: virtualTableShapeId: 3
; DUMP-NEXT: length: 4
; DUMP-NEXT: udtKind: struct
; DUMP-NEXT: constructor: 1
; DUMP-NEXT: constType: 0
; DUMP-NEXT: hasAssignmentOperator: 0
; DUMP-NEXT: hasCastOperator: 0
; DUMP-NEXT: hasNestedTypes: 1
; DUMP-NEXT: overloadedOperator: 0
; DUMP-NEXT: isInterfaceUdt: 0
; DUMP-NEXT: intrinsic: 0
; DUMP-NEXT: nested: 0
; DUMP-NEXT: packed: 0
; DUMP-NEXT: isRefUdt: 0
; DUMP-NEXT: scoped: 0
; DUMP-NEXT: unalignedType: 0
; DUMP-NEXT: isValueUdt: 0
; DUMP-NEXT: volatileType: 0
; DUMP-NEXT: }
; DUMP-NEXT: {
; DUMP-NEXT: symIndexId: 7
; DUMP-NEXT: symTag: UDT
; DUMP-NEXT: name: __vc_attributes::helper_attributes::usageAttribute
; DUMP-NEXT: virtualTableShapeId: 3
; DUMP-NEXT: length: 4
; DUMP-NEXT: udtKind: struct
; DUMP-NEXT: constructor: 1
; DUMP-NEXT: constType: 0
; DUMP-NEXT: hasAssignmentOperator: 0
; DUMP-NEXT: hasCastOperator: 0
; DUMP-NEXT: hasNestedTypes: 1
; DUMP-NEXT: overloadedOperator: 0
; DUMP-NEXT: isInterfaceUdt: 0
; DUMP-NEXT: intrinsic: 0
; DUMP-NEXT: nested: 0
; DUMP-NEXT: packed: 0
; DUMP-NEXT: isRefUdt: 0
; DUMP-NEXT: scoped: 0
; DUMP-NEXT: unalignedType: 0
; DUMP-NEXT: isValueUdt: 0
; DUMP-NEXT: volatileType: 0
; DUMP-NEXT: }
; DUMP-NEXT: {
; DUMP-NEXT: symIndexId: 8
; DUMP-NEXT: symTag: UDT
; DUMP-NEXT: name: __vc_attributes::threadingAttribute
; DUMP-NEXT: virtualTableShapeId: 3
; DUMP-NEXT: length: 4
; DUMP-NEXT: udtKind: struct
; DUMP-NEXT: constructor: 1
; DUMP-NEXT: constType: 0
; DUMP-NEXT: hasAssignmentOperator: 0
; DUMP-NEXT: hasCastOperator: 0
; DUMP-NEXT: hasNestedTypes: 1
; DUMP-NEXT: overloadedOperator: 0
; DUMP-NEXT: isInterfaceUdt: 0
; DUMP-NEXT: intrinsic: 0
; DUMP-NEXT: nested: 0
; DUMP-NEXT: packed: 0
; DUMP-NEXT: isRefUdt: 0
; DUMP-NEXT: scoped: 0
; DUMP-NEXT: unalignedType: 0
; DUMP-NEXT: isValueUdt: 0
; DUMP-NEXT: volatileType: 0
; DUMP-NEXT: }
; DUMP-NEXT: {
; DUMP-NEXT: symIndexId: 9
; DUMP-NEXT: symTag: UDT
; DUMP-NEXT: name: __vc_attributes::aggregatableAttribute
; DUMP-NEXT: virtualTableShapeId: 3
; DUMP-NEXT: length: 4
; DUMP-NEXT: udtKind: struct
; DUMP-NEXT: constructor: 1
; DUMP-NEXT: constType: 0
; DUMP-NEXT: hasAssignmentOperator: 0
; DUMP-NEXT: hasCastOperator: 0
; DUMP-NEXT: hasNestedTypes: 1
; DUMP-NEXT: overloadedOperator: 0
; DUMP-NEXT: isInterfaceUdt: 0
; DUMP-NEXT: intrinsic: 0
; DUMP-NEXT: nested: 0
; DUMP-NEXT: packed: 0
; DUMP-NEXT: isRefUdt: 0
; DUMP-NEXT: scoped: 0
; DUMP-NEXT: unalignedType: 0
; DUMP-NEXT: isValueUdt: 0
; DUMP-NEXT: volatileType: 0
; DUMP-NEXT: }
; DUMP-NEXT: {
; DUMP-NEXT: symIndexId: 10
; DUMP-NEXT: symTag: UDT
; DUMP-NEXT: name: __vc_attributes::event_receiverAttribute
; DUMP-NEXT: virtualTableShapeId: 3
; DUMP-NEXT: length: 8
; DUMP-NEXT: udtKind: struct
; DUMP-NEXT: constructor: 1
; DUMP-NEXT: constType: 0
; DUMP-NEXT: hasAssignmentOperator: 0
; DUMP-NEXT: hasCastOperator: 0
; DUMP-NEXT: hasNestedTypes: 1
; DUMP-NEXT: overloadedOperator: 0
; DUMP-NEXT: isInterfaceUdt: 0
; DUMP-NEXT: intrinsic: 0
; DUMP-NEXT: nested: 0
; DUMP-NEXT: packed: 0
; DUMP-NEXT: isRefUdt: 0
; DUMP-NEXT: scoped: 0
; DUMP-NEXT: unalignedType: 0
; DUMP-NEXT: isValueUdt: 0
; DUMP-NEXT: volatileType: 0
; DUMP-NEXT: }
; DUMP-NEXT: {
; DUMP-NEXT: symIndexId: 11
; DUMP-NEXT: symTag: UDT
; DUMP-NEXT: name: __vc_attributes::moduleAttribute
; DUMP-NEXT: virtualTableShapeId: 3
; DUMP-NEXT: length: 96
; DUMP-NEXT: udtKind: struct
; DUMP-NEXT: constructor: 1
; DUMP-NEXT: constType: 0
; DUMP-NEXT: hasAssignmentOperator: 0
; DUMP-NEXT: hasCastOperator: 0
; DUMP-NEXT: hasNestedTypes: 1
; DUMP-NEXT: overloadedOperator: 0
; DUMP-NEXT: isInterfaceUdt: 0
; DUMP-NEXT: intrinsic: 0
; DUMP-NEXT: nested: 0
; DUMP-NEXT: packed: 0
; DUMP-NEXT: isRefUdt: 0
; DUMP-NEXT: scoped: 0
; DUMP-NEXT: unalignedType: 0
; DUMP-NEXT: isValueUdt: 0
; DUMP-NEXT: volatileType: 0
; DUMP-NEXT: }
; DUMP-NEXT: {
; DUMP-NEXT: symIndexId: 12
; DUMP-NEXT: symTag: UDT
; DUMP-NEXT: name: Nested
; DUMP-NEXT: virtualTableShapeId: 3
; DUMP-NEXT: length: 1
; DUMP-NEXT: udtKind: struct
; DUMP-NEXT: constructor: 0
; DUMP-NEXT: constType: 0
; DUMP-NEXT: hasAssignmentOperator: 0
; DUMP-NEXT: hasCastOperator: 0
; DUMP-NEXT: hasNestedTypes: 1
; DUMP-NEXT: overloadedOperator: 0
; DUMP-NEXT: isInterfaceUdt: 0
; DUMP-NEXT: intrinsic: 0
; DUMP-NEXT: nested: 0
; DUMP-NEXT: packed: 0
; DUMP-NEXT: isRefUdt: 0
; DUMP-NEXT: scoped: 0
; DUMP-NEXT: unalignedType: 0
; DUMP-NEXT: isValueUdt: 0
; DUMP-NEXT: volatileType: 0
; DUMP-NEXT: }
; DUMP-NEXT: {
; DUMP-NEXT: symIndexId: 13
; DUMP-NEXT: symTag: UDT
; DUMP-NEXT: name: Nested::F
; DUMP-NEXT: virtualTableShapeId: 3
; DUMP-NEXT: length: 1
; DUMP-NEXT: udtKind: struct
; DUMP-NEXT: constructor: 0
; DUMP-NEXT: constType: 0
; DUMP-NEXT: hasAssignmentOperator: 0
; DUMP-NEXT: hasCastOperator: 0
; DUMP-NEXT: hasNestedTypes: 0
; DUMP-NEXT: overloadedOperator: 0
; DUMP-NEXT: isInterfaceUdt: 0
; DUMP-NEXT: intrinsic: 0
; DUMP-NEXT: nested: 1
; DUMP-NEXT: packed: 0
; DUMP-NEXT: isRefUdt: 0
; DUMP-NEXT: scoped: 0
; DUMP-NEXT: unalignedType: 0
; DUMP-NEXT: isValueUdt: 0
; DUMP-NEXT: volatileType: 0
; DUMP-NEXT: }
; DUMP-NEXT: {
; DUMP-NEXT: symIndexId: 14
; DUMP-NEXT: symTag: UDT
; DUMP-NEXT: name: Constructor
; DUMP-NEXT: virtualTableShapeId: 3
; DUMP-NEXT: length: 1
; DUMP-NEXT: udtKind: struct
; DUMP-NEXT: constructor: 1
; DUMP-NEXT: constType: 0
; DUMP-NEXT: hasAssignmentOperator: 0
; DUMP-NEXT: hasCastOperator: 0
; DUMP-NEXT: hasNestedTypes: 0
; DUMP-NEXT: overloadedOperator: 0
; DUMP-NEXT: isInterfaceUdt: 0
; DUMP-NEXT: intrinsic: 0
; DUMP-NEXT: nested: 0
; DUMP-NEXT: packed: 0
; DUMP-NEXT: isRefUdt: 0
; DUMP-NEXT: scoped: 0
; DUMP-NEXT: unalignedType: 0
; DUMP-NEXT: isValueUdt: 0
; DUMP-NEXT: volatileType: 0
; DUMP-NEXT: }
; DUMP-NEXT: {
; DUMP-NEXT: symIndexId: 15
; DUMP-NEXT: symTag: UDT
; DUMP-NEXT: name: Class
; DUMP-NEXT: virtualTableShapeId: 3
; DUMP-NEXT: length: 1
; DUMP-NEXT: udtKind: class
; DUMP-NEXT: constructor: 0
; DUMP-NEXT: constType: 0
; DUMP-NEXT: hasAssignmentOperator: 0
; DUMP-NEXT: hasCastOperator: 0
; DUMP-NEXT: hasNestedTypes: 0
; DUMP-NEXT: overloadedOperator: 0
; DUMP-NEXT: isInterfaceUdt: 0
; DUMP-NEXT: intrinsic: 0
; DUMP-NEXT: nested: 0
; DUMP-NEXT: packed: 0
; DUMP-NEXT: isRefUdt: 0
; DUMP-NEXT: scoped: 0
; DUMP-NEXT: unalignedType: 0
; DUMP-NEXT: isValueUdt: 0
; DUMP-NEXT: volatileType: 0
; DUMP-NEXT: }
; DUMP-NEXT: {
; DUMP-NEXT: symIndexId: 16
; DUMP-NEXT: symTag: UDT
; DUMP-NEXT: name: Union
; DUMP-NEXT: length: 1
; DUMP-NEXT: udtKind: union
; DUMP-NEXT: constructor: 0
; DUMP-NEXT: constType: 0
; DUMP-NEXT: hasAssignmentOperator: 0
; DUMP-NEXT: hasCastOperator: 0
; DUMP-NEXT: hasNestedTypes: 0
; DUMP-NEXT: overloadedOperator: 0
; DUMP-NEXT: isInterfaceUdt: 0
; DUMP-NEXT: intrinsic: 0
; DUMP-NEXT: nested: 0
; DUMP-NEXT: packed: 0
; DUMP-NEXT: isRefUdt: 0
; DUMP-NEXT: scoped: 0
; DUMP-NEXT: unalignedType: 0
; DUMP-NEXT: isValueUdt: 0
; DUMP-NEXT: volatileType: 0
; DUMP-NEXT: }
; DUMP-NEXT: {
; DUMP-NEXT: symIndexId: 17
; DUMP-NEXT: symTag: UDT
; DUMP-NEXT: name: Operator
; DUMP-NEXT: virtualTableShapeId: 3
; DUMP-NEXT: length: 1
; DUMP-NEXT: udtKind: struct
; DUMP-NEXT: constructor: 0
; DUMP-NEXT: constType: 0
; DUMP-NEXT: hasAssignmentOperator: 0
; DUMP-NEXT: hasCastOperator: 0
; DUMP-NEXT: hasNestedTypes: 0
; DUMP-NEXT: overloadedOperator: 1
; DUMP-NEXT: isInterfaceUdt: 0
; DUMP-NEXT: intrinsic: 0
; DUMP-NEXT: nested: 0
; DUMP-NEXT: packed: 0
; DUMP-NEXT: isRefUdt: 0
; DUMP-NEXT: scoped: 0
; DUMP-NEXT: unalignedType: 0
; DUMP-NEXT: isValueUdt: 0
; DUMP-NEXT: volatileType: 0
; DUMP-NEXT: }
; DUMP-NEXT: {
; DUMP-NEXT: symIndexId: 18
; DUMP-NEXT: symTag: UDT
; DUMP-NEXT: name: Cast
; DUMP-NEXT: virtualTableShapeId: 3
; DUMP-NEXT: length: 1
; DUMP-NEXT: udtKind: struct
; DUMP-NEXT: constructor: 0
; DUMP-NEXT: constType: 0
; DUMP-NEXT: hasAssignmentOperator: 0
; DUMP-NEXT: hasCastOperator: 1
; DUMP-NEXT: hasNestedTypes: 0
; DUMP-NEXT: overloadedOperator: 1
; DUMP-NEXT: isInterfaceUdt: 0
; DUMP-NEXT: intrinsic: 0
; DUMP-NEXT: nested: 0
; DUMP-NEXT: packed: 0
; DUMP-NEXT: isRefUdt: 0
; DUMP-NEXT: scoped: 0
; DUMP-NEXT: unalignedType: 0
; DUMP-NEXT: isValueUdt: 0
; DUMP-NEXT: volatileType: 0
; DUMP-NEXT: }
; DUMP-NEXT: {
; DUMP-NEXT: symIndexId: 19
; DUMP-NEXT: symTag: UDT
; DUMP-NEXT: name: Nothing
; DUMP-NEXT: virtualTableShapeId: 3
; DUMP-NEXT: length: 1
; DUMP-NEXT: udtKind: struct
; DUMP-NEXT: constructor: 0
; DUMP-NEXT: constType: 0
; DUMP-NEXT: hasAssignmentOperator: 0
; DUMP-NEXT: hasCastOperator: 0
; DUMP-NEXT: hasNestedTypes: 0
; DUMP-NEXT: overloadedOperator: 0
; DUMP-NEXT: isInterfaceUdt: 0
; DUMP-NEXT: intrinsic: 0
; DUMP-NEXT: nested: 0
; DUMP-NEXT: packed: 0
; DUMP-NEXT: isRefUdt: 0
; DUMP-NEXT: scoped: 0
; DUMP-NEXT: unalignedType: 0
; DUMP-NEXT: isValueUdt: 0
; DUMP-NEXT: volatileType: 0
; DUMP-NEXT: }
; DUMP-NEXT: {
; DUMP-NEXT: symIndexId: 20
; DUMP-NEXT: symTag: UDT
; DUMP-NEXT: name: Assignment
; DUMP-NEXT: virtualTableShapeId: 3
; DUMP-NEXT: length: 1
; DUMP-NEXT: udtKind: struct
; DUMP-NEXT: constructor: 0
; DUMP-NEXT: constType: 0
; DUMP-NEXT: hasAssignmentOperator: 1
; DUMP-NEXT: hasCastOperator: 0
; DUMP-NEXT: hasNestedTypes: 0
; DUMP-NEXT: overloadedOperator: 1
; DUMP-NEXT: isInterfaceUdt: 0
; DUMP-NEXT: intrinsic: 0
; DUMP-NEXT: nested: 0
; DUMP-NEXT: packed: 0
; DUMP-NEXT: isRefUdt: 0
; DUMP-NEXT: scoped: 0
; DUMP-NEXT: unalignedType: 0
; DUMP-NEXT: isValueUdt: 0
; DUMP-NEXT: volatileType: 0
; DUMP-NEXT: }
; DUMP-NEXT: {
; DUMP-NEXT: symIndexId: 21
; DUMP-NEXT: symTag: UDT
; DUMP-NEXT: name: Nothing
; DUMP-NEXT: unmodifiedTypeId: 19
; DUMP-NEXT: virtualTableShapeId: 3
; DUMP-NEXT: length: 1
; DUMP-NEXT: udtKind: struct
; DUMP-NEXT: constructor: 0
; DUMP-NEXT: constType: 1
; DUMP-NEXT: hasAssignmentOperator: 0
; DUMP-NEXT: hasCastOperator: 0
; DUMP-NEXT: hasNestedTypes: 0
; DUMP-NEXT: overloadedOperator: 0
; DUMP-NEXT: isInterfaceUdt: 0
; DUMP-NEXT: intrinsic: 0
; DUMP-NEXT: nested: 0
; DUMP-NEXT: packed: 0
; DUMP-NEXT: isRefUdt: 0
; DUMP-NEXT: scoped: 0
; DUMP-NEXT: unalignedType: 0
; DUMP-NEXT: isValueUdt: 0
; DUMP-NEXT: volatileType: 0
; DUMP-NEXT: }
; DUMP-NEXT: {
; DUMP-NEXT: symIndexId: 22
; DUMP-NEXT: symTag: UDT
; DUMP-NEXT: name: Nothing
; DUMP-NEXT: unmodifiedTypeId: 19
; DUMP-NEXT: virtualTableShapeId: 3
; DUMP-NEXT: length: 1
; DUMP-NEXT: udtKind: struct
; DUMP-NEXT: constructor: 0
; DUMP-NEXT: constType: 0
; DUMP-NEXT: hasAssignmentOperator: 0
; DUMP-NEXT: hasCastOperator: 0
; DUMP-NEXT: hasNestedTypes: 0
; DUMP-NEXT: overloadedOperator: 0
; DUMP-NEXT: isInterfaceUdt: 0
; DUMP-NEXT: intrinsic: 0
; DUMP-NEXT: nested: 0
; DUMP-NEXT: packed: 0
; DUMP-NEXT: isRefUdt: 0
; DUMP-NEXT: scoped: 0
; DUMP-NEXT: unalignedType: 0
; DUMP-NEXT: isValueUdt: 0
; DUMP-NEXT: volatileType: 1
; DUMP-NEXT: }
; DUMP-NEXT: {
; DUMP-NEXT: symIndexId: 23
; DUMP-NEXT: symTag: UDT
; DUMP-NEXT: name: Nothing
; DUMP-NEXT: unmodifiedTypeId: 19
; DUMP-NEXT: virtualTableShapeId: 3
; DUMP-NEXT: length: 1
; DUMP-NEXT: udtKind: struct
; DUMP-NEXT: constructor: 0
; DUMP-NEXT: constType: 1
; DUMP-NEXT: hasAssignmentOperator: 0
; DUMP-NEXT: hasCastOperator: 0
; DUMP-NEXT: hasNestedTypes: 0
; DUMP-NEXT: overloadedOperator: 0
; DUMP-NEXT: isInterfaceUdt: 0
; DUMP-NEXT: intrinsic: 0
; DUMP-NEXT: nested: 0
; DUMP-NEXT: packed: 0
; DUMP-NEXT: isRefUdt: 0
; DUMP-NEXT: scoped: 0
; DUMP-NEXT: unalignedType: 0
; DUMP-NEXT: isValueUdt: 0
; DUMP-NEXT: volatileType: 1
; DUMP-NEXT: }
; DUMP-NEXT: {
; DUMP-NEXT: symIndexId: 24
; DUMP-NEXT: symTag: UDT
; DUMP-NEXT: name: Nothing
; DUMP-NEXT: unmodifiedTypeId: 19
; DUMP-NEXT: virtualTableShapeId: 3
; DUMP-NEXT: length: 1
; DUMP-NEXT: udtKind: struct
; DUMP-NEXT: constructor: 0
; DUMP-NEXT: constType: 0
; DUMP-NEXT: hasAssignmentOperator: 0
; DUMP-NEXT: hasCastOperator: 0
; DUMP-NEXT: hasNestedTypes: 0
; DUMP-NEXT: overloadedOperator: 0
; DUMP-NEXT: isInterfaceUdt: 0
; DUMP-NEXT: intrinsic: 0
; DUMP-NEXT: nested: 0
; DUMP-NEXT: packed: 0
; DUMP-NEXT: isRefUdt: 0
; DUMP-NEXT: scoped: 0
; DUMP-NEXT: unalignedType: 1
; DUMP-NEXT: isValueUdt: 0
; DUMP-NEXT: volatileType: 0
; DUMP-NEXT: }

View File

@ -986,6 +986,8 @@ static void dumpDia(StringRef Path) {
SymTypes.push_back(PDB_SymType::Enum); SymTypes.push_back(PDB_SymType::Enum);
if (opts::diadump::Pointers) if (opts::diadump::Pointers)
SymTypes.push_back(PDB_SymType::PointerType); SymTypes.push_back(PDB_SymType::PointerType);
if (opts::diadump::UDTs)
SymTypes.push_back(PDB_SymType::UDT);
PdbSymbolIdField Ids = opts::diadump::NoSymIndexIds ? PdbSymbolIdField::None PdbSymbolIdField Ids = opts::diadump::NoSymIndexIds ? PdbSymbolIdField::None
: PdbSymbolIdField::All; : PdbSymbolIdField::All;
@ -1011,6 +1013,8 @@ static void dumpDia(StringRef Path) {
outs() << "\n}\n"; outs() << "\n}\n";
} }
} }
auto Child = Session->getSymbolById(3);
Child->defaultDump(outs(), 2, PdbSymbolIdField::All, PdbSymbolIdField::None);
} }
static void dumpPretty(StringRef Path) { static void dumpPretty(StringRef Path) {