[PDB] Make the native reader support modified types.

Previously for cv-qualified types, we would just ignore them
and they would never get printed.  Now we can enumerate them
and cache them like any other symbol type.

llvm-svn: 342414
This commit is contained in:
Zachary Turner 2018-09-17 21:07:48 +00:00
parent 8639c5d565
commit 4727ac2394
9 changed files with 194 additions and 61 deletions

View File

@ -21,7 +21,8 @@ class NativeSession;
class NativeTypeBuiltin : public NativeRawSymbol {
public:
NativeTypeBuiltin(NativeSession &PDBSession, SymIndexId Id, PDB_BuiltinType T,
NativeTypeBuiltin(NativeSession &PDBSession, SymIndexId Id,
codeview::ModifierOptions Mods, PDB_BuiltinType T,
uint64_t L);
~NativeTypeBuiltin() override;
@ -37,6 +38,7 @@ public:
protected:
NativeSession &Session;
codeview::ModifierOptions Mods;
PDB_BuiltinType Type;
uint64_t Length;
};

View File

@ -18,11 +18,15 @@
namespace llvm {
namespace pdb {
class NativeTypeEnum : public NativeRawSymbol,
public codeview::TypeVisitorCallbacks {
class NativeTypeEnum : public NativeRawSymbol {
public:
NativeTypeEnum(NativeSession &Session, SymIndexId Id, codeview::TypeIndex TI,
codeview::EnumRecord Record);
NativeTypeEnum(NativeSession &Session, SymIndexId Id,
codeview::TypeIndex ModifierTI,
codeview::ModifierRecord Modifier,
codeview::EnumRecord EnumRecord);
~NativeTypeEnum() override;
void dump(raw_ostream &OS, int Indent) const override;
@ -30,11 +34,6 @@ public:
std::unique_ptr<IPDBEnumSymbols>
findChildren(PDB_SymType Type) const override;
Error visitKnownRecord(codeview::CVType &CVR,
codeview::EnumRecord &Record) override;
Error visitKnownMember(codeview::CVMemberRecord &CVM,
codeview::EnumeratorRecord &Record) override;
PDB_BuiltinType getBuiltinType() const override;
PDB_SymType getSymTag() const override;
SymIndexId getUnmodifiedTypeId() const override;
@ -43,6 +42,9 @@ public:
bool hasCastOperator() const override;
uint64_t getLength() const override;
std::string getName() const override;
bool isConstType() const override;
bool isVolatileType() const override;
bool isUnalignedType() const override;
bool isNested() const override;
bool hasOverloadedOperator() const override;
bool hasNestedTypes() const override;
@ -57,6 +59,7 @@ public:
protected:
codeview::TypeIndex Index;
codeview::EnumRecord Record;
Optional<codeview::ModifierRecord> Modifiers;
};
} // namespace pdb

View File

@ -53,6 +53,12 @@ class SymbolCache {
TI, std::move(Record), std::forward<Args>(ConstructorArgs)...);
}
SymIndexId createSymbolForModifiedType(codeview::TypeIndex ModifierTI,
codeview::CVType CVT);
SymIndexId createSimpleType(codeview::TypeIndex TI,
codeview::ModifierOptions Mods);
public:
SymbolCache(NativeSession &Session, DbiStream *Dbi);

View File

@ -9,29 +9,44 @@
#include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h"
#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"
#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
#include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h"
#include "llvm/DebugInfo/PDB/PDBSymbol.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
namespace llvm {
namespace pdb {
using namespace llvm;
using namespace llvm::codeview;
using namespace llvm::pdb;
NativeEnumTypes::NativeEnumTypes(NativeSession &PDBSession,
codeview::LazyRandomTypeCollection &Types,
codeview::TypeLeafKind Kind)
LazyRandomTypeCollection &Types,
TypeLeafKind Kind)
: Matches(), Index(0), Session(PDBSession) {
for (auto Index = Types.getFirst(); Index;
Index = Types.getNext(Index.getValue())) {
if (Types.getType(Index.getValue()).kind() == Kind)
Matches.push_back(Index.getValue());
Optional<TypeIndex> TI = Types.getFirst();
while (TI) {
CVType CVT = Types.getType(*TI);
TypeLeafKind K = CVT.kind();
if (K == Kind)
Matches.push_back(*TI);
else if (K == TypeLeafKind::LF_MODIFIER) {
ModifierRecord MR;
if (auto EC = TypeDeserializer::deserializeAs<ModifierRecord>(CVT, MR)) {
consumeError(std::move(EC));
} else if (!MR.ModifiedType.isSimple()) {
CVType UnmodifiedCVT = Types.getType(MR.ModifiedType);
if (UnmodifiedCVT.kind() == Kind)
Matches.push_back(*TI);
}
}
TI = Types.getNext(*TI);
}
}
NativeEnumTypes::NativeEnumTypes(
NativeSession &PDBSession, const std::vector<codeview::TypeIndex> &Matches,
codeview::TypeLeafKind Kind)
NativeEnumTypes::NativeEnumTypes(NativeSession &PDBSession,
const std::vector<TypeIndex> &Matches,
TypeLeafKind Kind)
: Matches(Matches), Index(0), Session(PDBSession) {}
uint32_t NativeEnumTypes::getChildCount() const {
@ -53,6 +68,3 @@ std::unique_ptr<PDBSymbol> NativeEnumTypes::getNext() {
}
void NativeEnumTypes::reset() { Index = 0; }
} // namespace pdb
} // namespace llvm

View File

@ -14,9 +14,10 @@ namespace llvm {
namespace pdb {
NativeTypeBuiltin::NativeTypeBuiltin(NativeSession &PDBSession, SymIndexId Id,
codeview::ModifierOptions Mods,
PDB_BuiltinType T, uint64_t L)
: NativeRawSymbol(PDBSession, PDB_SymType::BuiltinType, Id),
Session(PDBSession), Type(T), Length(L) {}
Session(PDBSession), Mods(Mods), Type(T), Length(L) {}
NativeTypeBuiltin::~NativeTypeBuiltin() {}

View File

@ -28,6 +28,13 @@ NativeTypeEnum::NativeTypeEnum(NativeSession &Session, SymIndexId Id,
: NativeRawSymbol(Session, PDB_SymType::Enum, Id), Index(Index),
Record(std::move(Record)) {}
NativeTypeEnum::NativeTypeEnum(NativeSession &Session, SymIndexId Id,
codeview::TypeIndex ModifierTI,
codeview::ModifierRecord Modifier,
codeview::EnumRecord EnumRecord)
: NativeRawSymbol(Session, PDB_SymType::Enum, Id), Index(ModifierTI),
Record(std::move(EnumRecord)), Modifiers(std::move(Modifier)) {}
NativeTypeEnum::~NativeTypeEnum() {}
void NativeTypeEnum::dump(raw_ostream &OS, int Indent) const {
@ -38,6 +45,8 @@ void NativeTypeEnum::dump(raw_ostream &OS, int Indent) const {
dumpSymbolField(OS, "lexicalParentId", 0, Indent);
dumpSymbolField(OS, "name", getName(), Indent);
dumpSymbolField(OS, "typeId", getTypeId(), Indent);
if (Modifiers.hasValue())
dumpSymbolField(OS, "unmodifiedTypeId", getUnmodifiedTypeId(), Indent);
dumpSymbolField(OS, "length", getLength(), Indent);
dumpSymbolField(OS, "constructor", hasConstructor(), Indent);
dumpSymbolField(OS, "constType", isConstType(), Indent);
@ -68,17 +77,6 @@ NativeTypeEnum::findChildren(PDB_SymType Type) const {
}
}
Error NativeTypeEnum::visitKnownRecord(codeview::CVType &CVR,
codeview::EnumRecord &ER) {
Record = ER;
return Error::success();
}
Error NativeTypeEnum::visitKnownMember(codeview::CVMemberRecord &CVM,
codeview::EnumeratorRecord &R) {
return Error::success();
}
PDB_SymType NativeTypeEnum::getSymTag() const { return PDB_SymType::Enum; }
PDB_BuiltinType NativeTypeEnum::getBuiltinType() const {
@ -149,9 +147,10 @@ PDB_BuiltinType NativeTypeEnum::getBuiltinType() const {
}
SymIndexId NativeTypeEnum::getUnmodifiedTypeId() const {
// FIXME: If this is const, volatile, or unaligned, we should return the
// SymIndexId of the unmodified type here.
return 0;
if (!Modifiers)
return 0;
return Session.getSymbolCache().findSymbolByTypeIndex(
Modifiers->ModifiedType);
}
bool NativeTypeEnum::hasConstructor() const {
@ -215,3 +214,24 @@ bool NativeTypeEnum::isRefUdt() const { return false; }
bool NativeTypeEnum::isValueUdt() const { return false; }
bool NativeTypeEnum::isInterfaceUdt() const { return false; }
bool NativeTypeEnum::isConstType() const {
if (!Modifiers)
return false;
return ((Modifiers->getModifiers() & ModifierOptions::Const) !=
ModifierOptions::None);
}
bool NativeTypeEnum::isVolatileType() const {
if (!Modifiers)
return false;
return ((Modifiers->getModifiers() & ModifierOptions::Volatile) !=
ModifierOptions::None);
}
bool NativeTypeEnum::isUnalignedType() const {
if (!Modifiers)
return false;
return ((Modifiers->getModifiers() & ModifierOptions::Unaligned) !=
ModifierOptions::None);
}

View File

@ -42,8 +42,6 @@ void NativeTypePointer::dump(raw_ostream &OS, int Indent) const {
dumpSymbolField(OS, "volatileType", isVolatileType(), Indent);
}
bool NativeTypePointer::isConstType() const { return false; }
uint64_t NativeTypePointer::getLength() const { return Record.getSize(); }
SymIndexId NativeTypePointer::getTypeId() const {
@ -68,8 +66,21 @@ bool NativeTypePointer::isPointerToMemberFunction() const {
return Record.getMode() == PointerMode::PointerToMemberFunction;
}
bool NativeTypePointer::isRestrictedType() const { return false; }
bool NativeTypePointer::isConstType() const {
return (Record.getOptions() & PointerOptions::Const) != PointerOptions::None;
}
bool NativeTypePointer::isVolatileType() const { return false; }
bool NativeTypePointer::isRestrictedType() const {
return (Record.getOptions() & PointerOptions::Restrict) !=
PointerOptions::None;
}
bool NativeTypePointer::isUnalignedType() const { return false; }
bool NativeTypePointer::isVolatileType() const {
return (Record.getOptions() & PointerOptions::Volatile) !=
PointerOptions::None;
}
bool NativeTypePointer::isUnalignedType() const {
return (Record.getOptions() & PointerOptions::Unaligned) !=
PointerOptions::None;
}

View File

@ -60,6 +60,72 @@ SymbolCache::createTypeEnumerator(codeview::TypeLeafKind Kind) {
new NativeEnumTypes(Session, Types, Kind));
}
SymIndexId SymbolCache::createSimpleType(TypeIndex Index,
ModifierOptions Mods) {
// FIXME: We will eventually need to handle pointers to other simple types,
// which are still simple types in the world of CodeView TypeIndexes.
if (Index.getSimpleMode() != codeview::SimpleTypeMode::Direct)
return 0;
const auto Kind = Index.getSimpleKind();
const auto It = std::find_if(
std::begin(BuiltinTypes), std::end(BuiltinTypes),
[Kind](const BuiltinTypeEntry &Builtin) { return Builtin.Kind == Kind; });
if (It == std::end(BuiltinTypes))
return 0;
SymIndexId Id = Cache.size();
Cache.emplace_back(llvm::make_unique<NativeTypeBuiltin>(Session, Id, Mods,
It->Type, It->Size));
TypeIndexToSymbolId[Index] = Id;
return Id;
}
SymIndexId
SymbolCache::createSymbolForModifiedType(codeview::TypeIndex ModifierTI,
codeview::CVType CVT) {
ModifierRecord Record;
if (auto EC = TypeDeserializer::deserializeAs<ModifierRecord>(CVT, Record)) {
consumeError(std::move(EC));
return 0;
}
if (Record.ModifiedType.isSimple())
return createSimpleType(Record.ModifiedType, Record.Modifiers);
auto Tpi = Session.getPDBFile().getPDBTpiStream();
if (!Tpi) {
consumeError(Tpi.takeError());
return 0;
}
codeview::LazyRandomTypeCollection &Types = Tpi->typeCollection();
codeview::CVType UnmodifiedType = Types.getType(Record.ModifiedType);
switch (UnmodifiedType.kind()) {
case LF_ENUM: {
EnumRecord ER;
if (auto EC =
TypeDeserializer::deserializeAs<EnumRecord>(UnmodifiedType, ER)) {
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:
// No other types can be modified. (LF_POINTER, for example, records
// its modifiers a different way.
assert(false && "Invalid LF_MODIFIER record");
break;
}
return createSymbolPlaceholder();
}
SymIndexId SymbolCache::findSymbolByTypeIndex(codeview::TypeIndex Index) {
// First see if it's already in our cache.
const auto Entry = TypeIndexToSymbolId.find(Index);
@ -67,25 +133,8 @@ SymIndexId SymbolCache::findSymbolByTypeIndex(codeview::TypeIndex Index) {
return Entry->second;
// Symbols for built-in types are created on the fly.
if (Index.isSimple()) {
// FIXME: We will eventually need to handle pointers to other simple types,
// which are still simple types in the world of CodeView TypeIndexes.
if (Index.getSimpleMode() != codeview::SimpleTypeMode::Direct)
return 0;
const auto Kind = Index.getSimpleKind();
const auto It =
std::find_if(std::begin(BuiltinTypes), std::end(BuiltinTypes),
[Kind](const BuiltinTypeEntry &Builtin) {
return Builtin.Kind == Kind;
});
if (It == std::end(BuiltinTypes))
return 0;
SymIndexId Id = Cache.size();
Cache.emplace_back(
llvm::make_unique<NativeTypeBuiltin>(Session, Id, It->Type, It->Size));
TypeIndexToSymbolId[Index] = Id;
return Id;
}
if (Index.isSimple())
return createSimpleType(Index, ModifierOptions::None);
// We need to instantiate and cache the desired type symbol.
auto Tpi = Session.getPDBFile().getPDBTpiStream();
@ -97,6 +146,7 @@ SymIndexId SymbolCache::findSymbolByTypeIndex(codeview::TypeIndex Index) {
codeview::CVType CVT = Types.getType(Index);
// TODO(amccarth): Make this handle all types.
SymIndexId Id = 0;
switch (CVT.kind()) {
case codeview::LF_ENUM:
Id = createSymbolForType<NativeTypeEnum, EnumRecord>(Index, std::move(CVT));
@ -105,6 +155,9 @@ SymIndexId SymbolCache::findSymbolByTypeIndex(codeview::TypeIndex Index) {
Id = createSymbolForType<NativeTypePointer, PointerRecord>(Index,
std::move(CVT));
break;
case codeview::LF_MODIFIER:
Id = createSymbolForModifiedType(Index, std::move(CVT));
break;
default:
Id = createSymbolPlaceholder();
break;

View File

@ -6,6 +6,7 @@
ENUMS: enum FooClass::NestedEnum {
ENUMS-NEXT: }
ENUMS: const volatile enum FooClass::NestedEnum
DUMP: {
DUMP-NEXT: symIndexId: 2
@ -223,3 +224,27 @@ DUMP-NEXT: unalignedType: 0
DUMP-NEXT: isValueUdt: 0
DUMP-NEXT: volatileType: 0
DUMP-NEXT: }
DUMP-NEXT: {
DUMP-NEXT: symIndexId: 12
DUMP-NEXT: symTag: 12
DUMP-NEXT: baseType: 6
DUMP-NEXT: lexicalParentId: 0
DUMP-NEXT: name: FooClass::NestedEnum
DUMP-NEXT: typeId: 3
DUMP-NEXT: length: 4
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: 1
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: }