void addTypeServerHandler(TypeServerHandler &Handler);
+ Error visitTypeRecord(CVType &Record, TypeIndex Index);
Error visitTypeRecord(CVType &Record);
Error visitMemberRecord(CVMemberRecord &Record);
Error visitFieldListMemberStream(BinaryStreamReader Reader);
private:
+ Expected<bool> handleTypeServer(CVType &Record);
+ Error finishVisitation(CVType &Record);
+
/// The interface to the class that gets notified of each visitation.
TypeVisitorCallbacks &Callbacks;
#ifndef LLVM_DEBUGINFO_CODEVIEW_TYPEDATABASE_H
#define LLVM_DEBUGINFO_CODEVIEW_TYPEDATABASE_H
+#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
namespace llvm {
namespace codeview {
class TypeDatabase {
+ friend class RandomAccessTypeVisitor;
+
public:
explicit TypeDatabase(uint32_t ExpectedSize);
uint32_t size() const;
-private:
+protected:
+ uint32_t toArrayIndex(TypeIndex Index) const;
+
BumpPtrAllocator Allocator;
/// All user defined type records in .debug$T live in here. Type indices
StringSaver TypeNameStorage;
};
+
+class RandomAccessTypeDatabase : private TypeDatabase {
+public:
+ explicit RandomAccessTypeDatabase(uint32_t ExpectedSize);
+
+ /// Records the name of a type, and reserves its type index.
+ void recordType(StringRef Name, TypeIndex Index, const CVType &Data);
+
+ using TypeDatabase::saveTypeName;
+
+ StringRef getTypeName(TypeIndex Index) const;
+
+ const CVType &getTypeRecord(TypeIndex Index) const;
+ CVType &getTypeRecord(TypeIndex Index);
+
+ bool containsTypeIndex(TypeIndex Index) const;
+
+ uint32_t size() const;
+
+private:
+ BitVector ValidRecords;
+};
}
}
#ifndef LLVM_DEBUGINFO_CODEVIEW_TYPEDATABASEVISITOR_H
#define LLVM_DEBUGINFO_CODEVIEW_TYPEDATABASEVISITOR_H
+#include "llvm/ADT/PointerUnion.h"
+
#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
/// Dumper for CodeView type streams found in COFF object files and PDB files.
class TypeDatabaseVisitor : public TypeVisitorCallbacks {
public:
- explicit TypeDatabaseVisitor(TypeDatabase &TypeDB) : TypeDB(TypeDB) {}
+ explicit TypeDatabaseVisitor(TypeDatabase &TypeDB) : TypeDB(&TypeDB) {}
+ explicit TypeDatabaseVisitor(RandomAccessTypeDatabase &TypeDB)
+ : TypeDB(&TypeDB) {}
/// Paired begin/end actions for all types. Receives all record data,
/// including the fixed-length record prefix.
Error visitTypeBegin(CVType &Record) override;
+ Error visitTypeBegin(CVType &Record, TypeIndex Index) override;
Error visitTypeEnd(CVType &Record) override;
Error visitMemberBegin(CVMemberRecord &Record) override;
Error visitMemberEnd(CVMemberRecord &Record) override;
#include "TypeRecords.def"
private:
+ StringRef getTypeName(TypeIndex Index) const;
+ StringRef saveTypeName(StringRef Name);
+
bool IsInFieldList = false;
/// Name of the current type. Only valid before visitTypeEnd.
StringRef Name;
+ /// Current type index. Only valid before visitTypeEnd, and if we are
+ /// visiting a random access type database.
+ TypeIndex CurrentTypeIndex;
- TypeDatabase &TypeDB;
+ PointerUnion<TypeDatabase *, RandomAccessTypeDatabase *> TypeDB;
};
} // end namespace codeview
return Error::success();
}
+ Error visitTypeBegin(CVType &Record, TypeIndex Index) override {
+ for (auto Visitor : Pipeline) {
+ if (auto EC = Visitor->visitTypeBegin(Record, Index))
+ return EC;
+ }
+ return Error::success();
+ }
+
Error visitTypeEnd(CVType &Record) override {
for (auto Visitor : Pipeline) {
if (auto EC = Visitor->visitTypeEnd(Record))
virtual Error visitUnknownType(CVType &Record) { return Error::success(); }
/// Paired begin/end actions for all types. Receives all record data,
/// including the fixed-length record prefix. visitTypeBegin() should return
- /// the type of the Record, or an error if it cannot be determined.
+ /// the type of the Record, or an error if it cannot be determined. Exactly
+ /// one of the two visitTypeBegin methods will be called, depending on whether
+ /// records are being visited sequentially or randomly. An implementation
+ /// should be prepared to handle both (or assert if it can't handle random
+ /// access visitation).
virtual Error visitTypeBegin(CVType &Record) { return Error::success(); }
+ virtual Error visitTypeBegin(CVType &Record, TypeIndex Index) {
+ return Error::success();
+ }
virtual Error visitTypeEnd(CVType &Record) { return Error::success(); }
virtual Error visitUnknownMember(CVMemberRecord &Record) {
Handlers.push_back(&Handler);
}
-Error CVTypeVisitor::visitTypeRecord(CVType &Record) {
+Expected<bool> CVTypeVisitor::handleTypeServer(CVType &Record) {
if (Record.Type == TypeLeafKind::LF_TYPESERVER2 && !Handlers.empty()) {
auto TS = deserializeTypeServerRecord(Record);
if (!TS)
// If the handler processed the record, return success.
if (*ExpectedResult)
- return Error::success();
+ return true;
// Otherwise keep searching for a handler, eventually falling out and
// using the default record handler.
}
}
+ return false;
+}
- if (auto EC = Callbacks.visitTypeBegin(Record))
- return EC;
-
+Error CVTypeVisitor::finishVisitation(CVType &Record) {
switch (Record.Type) {
default:
if (auto EC = Callbacks.visitUnknownType(Record))
return Error::success();
}
+Error CVTypeVisitor::visitTypeRecord(CVType &Record, TypeIndex Index) {
+ auto ExpectedResult = handleTypeServer(Record);
+ if (!ExpectedResult)
+ return ExpectedResult.takeError();
+ if (*ExpectedResult)
+ return Error::success();
+
+ if (auto EC = Callbacks.visitTypeBegin(Record, Index))
+ return EC;
+
+ return finishVisitation(Record);
+}
+
+Error CVTypeVisitor::visitTypeRecord(CVType &Record) {
+ auto ExpectedResult = handleTypeServer(Record);
+ if (!ExpectedResult)
+ return ExpectedResult.takeError();
+ if (*ExpectedResult)
+ return Error::success();
+
+ if (auto EC = Callbacks.visitTypeBegin(Record))
+ return EC;
+
+ return finishVisitation(Record);
+}
+
static Error visitMemberRecord(CVMemberRecord &Record,
TypeVisitorCallbacks &Callbacks) {
if (auto EC = Callbacks.visitMemberBegin(Record))
}
const CVType &TypeDatabase::getTypeRecord(TypeIndex Index) const {
- return TypeRecords[Index.getIndex() - TypeIndex::FirstNonSimpleIndex];
+ return TypeRecords[toArrayIndex(Index)];
}
CVType &TypeDatabase::getTypeRecord(TypeIndex Index) {
- return TypeRecords[Index.getIndex() - TypeIndex::FirstNonSimpleIndex];
+ return TypeRecords[toArrayIndex(Index)];
}
bool TypeDatabase::containsTypeIndex(TypeIndex Index) const {
- uint32_t I = Index.getIndex() - TypeIndex::FirstNonSimpleIndex;
- return I < CVUDTNames.size();
+ return toArrayIndex(Index) < CVUDTNames.size();
}
uint32_t TypeDatabase::size() const { return CVUDTNames.size(); }
+
+uint32_t TypeDatabase::toArrayIndex(TypeIndex Index) const {
+ assert(Index.getIndex() >= TypeIndex::FirstNonSimpleIndex);
+ return Index.getIndex() - TypeIndex::FirstNonSimpleIndex;
+}
+
+RandomAccessTypeDatabase::RandomAccessTypeDatabase(uint32_t ExpectedSize)
+ : TypeDatabase(ExpectedSize) {
+ ValidRecords.resize(ExpectedSize);
+ CVUDTNames.resize(ExpectedSize);
+ TypeRecords.resize(ExpectedSize);
+}
+
+void RandomAccessTypeDatabase::recordType(StringRef Name, TypeIndex Index,
+ const CVType &Data) {
+ assert(!containsTypeIndex(Index));
+ uint32_t ZI = Index.getIndex() - TypeIndex::FirstNonSimpleIndex;
+
+ CVUDTNames[ZI] = Name;
+ TypeRecords[ZI] = Data;
+ ValidRecords.set(ZI);
+}
+
+StringRef RandomAccessTypeDatabase::getTypeName(TypeIndex Index) const {
+ assert(containsTypeIndex(Index));
+ return TypeDatabase::getTypeName(Index);
+}
+
+const CVType &RandomAccessTypeDatabase::getTypeRecord(TypeIndex Index) const {
+ assert(containsTypeIndex(Index));
+ return TypeDatabase::getTypeRecord(Index);
+}
+
+CVType &RandomAccessTypeDatabase::getTypeRecord(TypeIndex Index) {
+ assert(containsTypeIndex(Index));
+ return TypeDatabase::getTypeRecord(Index);
+}
+
+bool RandomAccessTypeDatabase::containsTypeIndex(TypeIndex Index) const {
+ if (Index.isSimple())
+ return true;
+
+ return ValidRecords.test(toArrayIndex(Index));
+}
+
+uint32_t RandomAccessTypeDatabase::size() const { return ValidRecords.count(); }
using namespace llvm::codeview;
-Error TypeDatabaseVisitor::visitTypeBegin(CVRecord<TypeLeafKind> &Record) {
+Error TypeDatabaseVisitor::visitTypeBegin(CVType &Record) {
+ assert(TypeDB.is<TypeDatabase *>());
+
assert(!IsInFieldList);
// Reset Name to the empty string. If the visitor sets it, we know it.
Name = "";
return Error::success();
}
+StringRef TypeDatabaseVisitor::getTypeName(TypeIndex Index) const {
+ if (auto DB = TypeDB.get<TypeDatabase *>())
+ return DB->getTypeName(Index);
+ else if (auto DB = TypeDB.get<RandomAccessTypeDatabase *>())
+ return DB->getTypeName(Index);
+
+ llvm_unreachable("Invalid TypeDB Kind!");
+}
+
+StringRef TypeDatabaseVisitor::saveTypeName(StringRef Name) {
+ if (auto DB = TypeDB.get<TypeDatabase *>())
+ return DB->saveTypeName(Name);
+ else if (auto DB = TypeDB.get<RandomAccessTypeDatabase *>())
+ return DB->saveTypeName(Name);
+
+ llvm_unreachable("Invalid TypeDB Kind!");
+}
+
+Error TypeDatabaseVisitor::visitTypeBegin(CVType &Record, TypeIndex Index) {
+ assert(TypeDB.is<RandomAccessTypeDatabase *>());
+
+ if (auto EC = visitTypeBegin(Record))
+ return EC;
+
+ CurrentTypeIndex = Index;
+ return Error::success();
+}
+
Error TypeDatabaseVisitor::visitTypeEnd(CVType &CVR) {
if (CVR.Type == LF_FIELDLIST) {
assert(IsInFieldList);
// CVUDTNames is indexed by type index, and must have one entry for every
// type. Field list members are not recorded, and are only referenced by
// their containing field list record.
- TypeDB.recordType(Name, CVR);
+ if (auto DB = TypeDB.get<TypeDatabase *>())
+ DB->recordType(Name, CVR);
+ else if (auto DB = TypeDB.get<RandomAccessTypeDatabase *>())
+ DB->recordType(Name, CurrentTypeIndex, CVR);
+
return Error::success();
}
uint32_t Size = Indices.size();
SmallString<256> TypeName("(");
for (uint32_t I = 0; I < Size; ++I) {
- StringRef ArgTypeName = TypeDB.getTypeName(Indices[I]);
+ StringRef ArgTypeName = getTypeName(Indices[I]);
TypeName.append(ArgTypeName);
if (I + 1 != Size)
TypeName.append(", ");
}
TypeName.push_back(')');
- Name = TypeDB.saveTypeName(TypeName);
+ Name = saveTypeName(TypeName);
return Error::success();
}
uint32_t Size = Indices.size();
SmallString<256> TypeName("\"");
for (uint32_t I = 0; I < Size; ++I) {
- StringRef ArgTypeName = TypeDB.getTypeName(Indices[I]);
+ StringRef ArgTypeName = getTypeName(Indices[I]);
TypeName.append(ArgTypeName);
if (I + 1 != Size)
TypeName.append("\" \"");
}
TypeName.push_back('\"');
- Name = TypeDB.saveTypeName(TypeName);
+ Name = saveTypeName(TypeName);
return Error::success();
}
Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR,
ProcedureRecord &Proc) {
- StringRef ReturnTypeName = TypeDB.getTypeName(Proc.getReturnType());
- StringRef ArgListTypeName = TypeDB.getTypeName(Proc.getArgumentList());
+ StringRef ReturnTypeName = getTypeName(Proc.getReturnType());
+ StringRef ArgListTypeName = getTypeName(Proc.getArgumentList());
SmallString<256> TypeName(ReturnTypeName);
TypeName.push_back(' ');
TypeName.append(ArgListTypeName);
- Name = TypeDB.saveTypeName(TypeName);
+ Name = saveTypeName(TypeName);
return Error::success();
}
Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR,
MemberFunctionRecord &MF) {
- StringRef ReturnTypeName = TypeDB.getTypeName(MF.getReturnType());
- StringRef ClassTypeName = TypeDB.getTypeName(MF.getClassType());
- StringRef ArgListTypeName = TypeDB.getTypeName(MF.getArgumentList());
+ StringRef ReturnTypeName = getTypeName(MF.getReturnType());
+ StringRef ClassTypeName = getTypeName(MF.getClassType());
+ StringRef ArgListTypeName = getTypeName(MF.getArgumentList());
SmallString<256> TypeName(ReturnTypeName);
TypeName.push_back(' ');
TypeName.append(ClassTypeName);
TypeName.append("::");
TypeName.append(ArgListTypeName);
- Name = TypeDB.saveTypeName(TypeName);
+ Name = saveTypeName(TypeName);
return Error::success();
}
if (Ptr.isPointerToMember()) {
const MemberPointerInfo &MI = Ptr.getMemberInfo();
- StringRef PointeeName = TypeDB.getTypeName(Ptr.getReferentType());
- StringRef ClassName = TypeDB.getTypeName(MI.getContainingType());
+ StringRef PointeeName = getTypeName(Ptr.getReferentType());
+ StringRef ClassName = getTypeName(MI.getContainingType());
SmallString<256> TypeName(PointeeName);
TypeName.push_back(' ');
TypeName.append(ClassName);
TypeName.append("::*");
- Name = TypeDB.saveTypeName(TypeName);
+ Name = saveTypeName(TypeName);
} else {
SmallString<256> TypeName;
if (Ptr.isConst())
if (Ptr.isUnaligned())
TypeName.append("__unaligned ");
- TypeName.append(TypeDB.getTypeName(Ptr.getReferentType()));
+ TypeName.append(getTypeName(Ptr.getReferentType()));
if (Ptr.getMode() == PointerMode::LValueReference)
TypeName.append("&");
TypeName.append("*");
if (!TypeName.empty())
- Name = TypeDB.saveTypeName(TypeName);
+ Name = saveTypeName(TypeName);
}
return Error::success();
}
Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, ModifierRecord &Mod) {
uint16_t Mods = static_cast<uint16_t>(Mod.getModifiers());
- StringRef ModifiedName = TypeDB.getTypeName(Mod.getModifiedType());
+ StringRef ModifiedName = getTypeName(Mod.getModifiedType());
SmallString<256> TypeName;
if (Mods & uint16_t(ModifierOptions::Const))
TypeName.append("const ");
if (Mods & uint16_t(ModifierOptions::Unaligned))
TypeName.append("__unaligned ");
TypeName.append(ModifiedName);
- Name = TypeDB.saveTypeName(TypeName);
+ Name = saveTypeName(TypeName);
return Error::success();
}
Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR,
VFTableShapeRecord &Shape) {
- Name = TypeDB.saveTypeName("<vftable " + utostr(Shape.getEntryCount()) +
- " methods>");
+ Name =
+ saveTypeName("<vftable " + utostr(Shape.getEntryCount()) + " methods>");
return Error::success();
}