|
@@ -9,7 +9,9 @@
|
|
|
|
|
|
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
|
|
|
|
|
|
+#include "llvm/ADT/TinyPtrVector.h"
|
|
|
#include "llvm/DebugInfo/CodeView/CodeViewError.h"
|
|
|
+#include "llvm/DebugInfo/CodeView/TypeCollection.h"
|
|
|
#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
|
|
|
#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h"
|
|
|
#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
|
|
@@ -22,8 +24,6 @@
|
|
|
using namespace llvm;
|
|
|
using namespace llvm::codeview;
|
|
|
|
|
|
-CVTypeVisitor::CVTypeVisitor(TypeVisitorCallbacks &Callbacks)
|
|
|
- : Callbacks(Callbacks) {}
|
|
|
|
|
|
template <typename T>
|
|
|
static Error visitKnownRecord(CVType &Record, TypeVisitorCallbacks &Callbacks) {
|
|
@@ -66,6 +66,67 @@ static Expected<TypeServer2Record> deserializeTypeServerRecord(CVType &Record) {
|
|
|
return R;
|
|
|
}
|
|
|
|
|
|
+static Error visitMemberRecord(CVMemberRecord &Record,
|
|
|
+ TypeVisitorCallbacks &Callbacks) {
|
|
|
+ if (auto EC = Callbacks.visitMemberBegin(Record))
|
|
|
+ return EC;
|
|
|
+
|
|
|
+ switch (Record.Kind) {
|
|
|
+ default:
|
|
|
+ if (auto EC = Callbacks.visitUnknownMember(Record))
|
|
|
+ return EC;
|
|
|
+ break;
|
|
|
+#define MEMBER_RECORD(EnumName, EnumVal, Name) \
|
|
|
+ case EnumName: { \
|
|
|
+ if (auto EC = visitKnownMember<Name##Record>(Record, Callbacks)) \
|
|
|
+ return EC; \
|
|
|
+ break; \
|
|
|
+ }
|
|
|
+#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \
|
|
|
+ MEMBER_RECORD(EnumVal, EnumVal, AliasName)
|
|
|
+#define TYPE_RECORD(EnumName, EnumVal, Name)
|
|
|
+#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
|
|
|
+#include "llvm/DebugInfo/CodeView/TypeRecords.def"
|
|
|
+ }
|
|
|
+
|
|
|
+ if (auto EC = Callbacks.visitMemberEnd(Record))
|
|
|
+ return EC;
|
|
|
+
|
|
|
+ return Error::success();
|
|
|
+}
|
|
|
+
|
|
|
+namespace {
|
|
|
+
|
|
|
+class CVTypeVisitor {
|
|
|
+public:
|
|
|
+ explicit CVTypeVisitor(TypeVisitorCallbacks &Callbacks);
|
|
|
+
|
|
|
+ void addTypeServerHandler(TypeServerHandler &Handler);
|
|
|
+
|
|
|
+ Error visitTypeRecord(CVType &Record, TypeIndex Index);
|
|
|
+ Error visitTypeRecord(CVType &Record);
|
|
|
+
|
|
|
+ /// Visits the type records in Data. Sets the error flag on parse failures.
|
|
|
+ Error visitTypeStream(const CVTypeArray &Types);
|
|
|
+ Error visitTypeStream(CVTypeRange Types);
|
|
|
+ Error visitTypeStream(TypeCollection &Types);
|
|
|
+
|
|
|
+ Error visitMemberRecord(CVMemberRecord Record);
|
|
|
+ Error visitFieldListMemberStream(BinaryStreamReader &Stream);
|
|
|
+
|
|
|
+private:
|
|
|
+ Expected<bool> handleTypeServer(CVType &Record);
|
|
|
+ Error finishVisitation(CVType &Record);
|
|
|
+
|
|
|
+ /// The interface to the class that gets notified of each visitation.
|
|
|
+ TypeVisitorCallbacks &Callbacks;
|
|
|
+
|
|
|
+ TinyPtrVector<TypeServerHandler *> Handlers;
|
|
|
+};
|
|
|
+
|
|
|
+CVTypeVisitor::CVTypeVisitor(TypeVisitorCallbacks &Callbacks)
|
|
|
+ : Callbacks(Callbacks) {}
|
|
|
+
|
|
|
void CVTypeVisitor::addTypeServerHandler(TypeServerHandler &Handler) {
|
|
|
Handlers.push_back(&Handler);
|
|
|
}
|
|
@@ -144,35 +205,6 @@ Error CVTypeVisitor::visitTypeRecord(CVType &Record) {
|
|
|
return finishVisitation(Record);
|
|
|
}
|
|
|
|
|
|
-static Error visitMemberRecord(CVMemberRecord &Record,
|
|
|
- TypeVisitorCallbacks &Callbacks) {
|
|
|
- if (auto EC = Callbacks.visitMemberBegin(Record))
|
|
|
- return EC;
|
|
|
-
|
|
|
- switch (Record.Kind) {
|
|
|
- default:
|
|
|
- if (auto EC = Callbacks.visitUnknownMember(Record))
|
|
|
- return EC;
|
|
|
- break;
|
|
|
-#define MEMBER_RECORD(EnumName, EnumVal, Name) \
|
|
|
- case EnumName: { \
|
|
|
- if (auto EC = visitKnownMember<Name##Record>(Record, Callbacks)) \
|
|
|
- return EC; \
|
|
|
- break; \
|
|
|
- }
|
|
|
-#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \
|
|
|
- MEMBER_RECORD(EnumVal, EnumVal, AliasName)
|
|
|
-#define TYPE_RECORD(EnumName, EnumVal, Name)
|
|
|
-#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
|
|
|
-#include "llvm/DebugInfo/CodeView/TypeRecords.def"
|
|
|
- }
|
|
|
-
|
|
|
- if (auto EC = Callbacks.visitMemberEnd(Record))
|
|
|
- return EC;
|
|
|
-
|
|
|
- return Error::success();
|
|
|
-}
|
|
|
-
|
|
|
Error CVTypeVisitor::visitMemberRecord(CVMemberRecord Record) {
|
|
|
return ::visitMemberRecord(Record, Callbacks);
|
|
|
}
|
|
@@ -194,12 +226,18 @@ Error CVTypeVisitor::visitTypeStream(CVTypeRange Types) {
|
|
|
return Error::success();
|
|
|
}
|
|
|
|
|
|
-Error CVTypeVisitor::visitFieldListMemberStream(BinaryStreamReader Reader) {
|
|
|
- FieldListDeserializer Deserializer(Reader);
|
|
|
- TypeVisitorCallbackPipeline Pipeline;
|
|
|
- Pipeline.addCallbackToPipeline(Deserializer);
|
|
|
- Pipeline.addCallbackToPipeline(Callbacks);
|
|
|
+Error CVTypeVisitor::visitTypeStream(TypeCollection &Types) {
|
|
|
+ Optional<TypeIndex> I = Types.getFirst();
|
|
|
+ while (I) {
|
|
|
+ CVType Type = Types.getType(*I);
|
|
|
+ if (auto EC = visitTypeRecord(Type, *I))
|
|
|
+ return EC;
|
|
|
+ I = Types.getNext(*I);
|
|
|
+ }
|
|
|
+ return Error::success();
|
|
|
+}
|
|
|
|
|
|
+Error CVTypeVisitor::visitFieldListMemberStream(BinaryStreamReader &Reader) {
|
|
|
TypeLeafKind Leaf;
|
|
|
while (!Reader.empty()) {
|
|
|
if (auto EC = Reader.readEnum(Leaf))
|
|
@@ -207,20 +245,13 @@ Error CVTypeVisitor::visitFieldListMemberStream(BinaryStreamReader Reader) {
|
|
|
|
|
|
CVMemberRecord Record;
|
|
|
Record.Kind = Leaf;
|
|
|
- if (auto EC = ::visitMemberRecord(Record, Pipeline))
|
|
|
+ if (auto EC = ::visitMemberRecord(Record, Callbacks))
|
|
|
return EC;
|
|
|
}
|
|
|
|
|
|
return Error::success();
|
|
|
}
|
|
|
|
|
|
-Error CVTypeVisitor::visitFieldListMemberStream(ArrayRef<uint8_t> Data) {
|
|
|
- BinaryByteStream S(Data, llvm::support::little);
|
|
|
- BinaryStreamReader SR(S);
|
|
|
- return visitFieldListMemberStream(SR);
|
|
|
-}
|
|
|
-
|
|
|
-namespace {
|
|
|
struct FieldListVisitHelper {
|
|
|
FieldListVisitHelper(TypeVisitorCallbacks &Callbacks, ArrayRef<uint8_t> Data,
|
|
|
VisitorDataSource Source)
|
|
@@ -241,11 +272,8 @@ struct FieldListVisitHelper {
|
|
|
};
|
|
|
|
|
|
struct VisitHelper {
|
|
|
- VisitHelper(TypeVisitorCallbacks &Callbacks, VisitorDataSource Source,
|
|
|
- TypeServerHandler *TS)
|
|
|
+ VisitHelper(TypeVisitorCallbacks &Callbacks, VisitorDataSource Source)
|
|
|
: Visitor((Source == VDS_BytesPresent) ? Pipeline : Callbacks) {
|
|
|
- if (TS)
|
|
|
- Visitor.addTypeServerHandler(*TS);
|
|
|
if (Source == VDS_BytesPresent) {
|
|
|
Pipeline.addCallbackToPipeline(Deserializer);
|
|
|
Pipeline.addCallbackToPipeline(Callbacks);
|
|
@@ -262,29 +290,57 @@ Error llvm::codeview::visitTypeRecord(CVType &Record, TypeIndex Index,
|
|
|
TypeVisitorCallbacks &Callbacks,
|
|
|
VisitorDataSource Source,
|
|
|
TypeServerHandler *TS) {
|
|
|
- VisitHelper Helper(Callbacks, Source, TS);
|
|
|
- return Helper.Visitor.visitTypeRecord(Record, Index);
|
|
|
+ VisitHelper V(Callbacks, Source);
|
|
|
+ if (TS)
|
|
|
+ V.Visitor.addTypeServerHandler(*TS);
|
|
|
+ return V.Visitor.visitTypeRecord(Record, Index);
|
|
|
}
|
|
|
|
|
|
Error llvm::codeview::visitTypeRecord(CVType &Record,
|
|
|
TypeVisitorCallbacks &Callbacks,
|
|
|
VisitorDataSource Source,
|
|
|
TypeServerHandler *TS) {
|
|
|
- VisitHelper Helper(Callbacks, Source, TS);
|
|
|
- return Helper.Visitor.visitTypeRecord(Record);
|
|
|
+ VisitHelper V(Callbacks, Source);
|
|
|
+ if (TS)
|
|
|
+ V.Visitor.addTypeServerHandler(*TS);
|
|
|
+ return V.Visitor.visitTypeRecord(Record);
|
|
|
}
|
|
|
|
|
|
-Error llvm::codeview::visitMemberRecordStream(ArrayRef<uint8_t> FieldList,
|
|
|
- TypeVisitorCallbacks &Callbacks) {
|
|
|
- CVTypeVisitor Visitor(Callbacks);
|
|
|
- return Visitor.visitFieldListMemberStream(FieldList);
|
|
|
+Error llvm::codeview::visitTypeStream(const CVTypeArray &Types,
|
|
|
+ TypeVisitorCallbacks &Callbacks,
|
|
|
+ TypeServerHandler *TS) {
|
|
|
+ VisitHelper V(Callbacks, VDS_BytesPresent);
|
|
|
+ if (TS)
|
|
|
+ V.Visitor.addTypeServerHandler(*TS);
|
|
|
+ return V.Visitor.visitTypeStream(Types);
|
|
|
+}
|
|
|
+
|
|
|
+Error llvm::codeview::visitTypeStream(CVTypeRange Types,
|
|
|
+ TypeVisitorCallbacks &Callbacks,
|
|
|
+ TypeServerHandler *TS) {
|
|
|
+ VisitHelper V(Callbacks, VDS_BytesPresent);
|
|
|
+ if (TS)
|
|
|
+ V.Visitor.addTypeServerHandler(*TS);
|
|
|
+ return V.Visitor.visitTypeStream(Types);
|
|
|
+}
|
|
|
+
|
|
|
+Error llvm::codeview::visitTypeStream(TypeCollection &Types,
|
|
|
+ TypeVisitorCallbacks &Callbacks,
|
|
|
+ TypeServerHandler *TS) {
|
|
|
+ // When the internal visitor calls Types.getType(Index) the interface is
|
|
|
+ // required to return a CVType with the bytes filled out. So we can assume
|
|
|
+ // that the bytes will be present when individual records are visited.
|
|
|
+ VisitHelper V(Callbacks, VDS_BytesPresent);
|
|
|
+ if (TS)
|
|
|
+ V.Visitor.addTypeServerHandler(*TS);
|
|
|
+ return V.Visitor.visitTypeStream(Types);
|
|
|
}
|
|
|
|
|
|
Error llvm::codeview::visitMemberRecord(CVMemberRecord Record,
|
|
|
TypeVisitorCallbacks &Callbacks,
|
|
|
VisitorDataSource Source) {
|
|
|
- FieldListVisitHelper Helper(Callbacks, Record.Data, Source);
|
|
|
- return Helper.Visitor.visitMemberRecord(Record);
|
|
|
+ FieldListVisitHelper V(Callbacks, Record.Data, Source);
|
|
|
+ return V.Visitor.visitMemberRecord(Record);
|
|
|
}
|
|
|
|
|
|
Error llvm::codeview::visitMemberRecord(TypeLeafKind Kind,
|
|
@@ -296,16 +352,8 @@ Error llvm::codeview::visitMemberRecord(TypeLeafKind Kind,
|
|
|
return visitMemberRecord(R, Callbacks, VDS_BytesPresent);
|
|
|
}
|
|
|
|
|
|
-Error llvm::codeview::visitTypeStream(const CVTypeArray &Types,
|
|
|
- TypeVisitorCallbacks &Callbacks,
|
|
|
- TypeServerHandler *TS) {
|
|
|
- VisitHelper Helper(Callbacks, VDS_BytesPresent, TS);
|
|
|
- return Helper.Visitor.visitTypeStream(Types);
|
|
|
-}
|
|
|
-
|
|
|
-Error llvm::codeview::visitTypeStream(CVTypeRange Types,
|
|
|
- TypeVisitorCallbacks &Callbacks,
|
|
|
- TypeServerHandler *TS) {
|
|
|
- VisitHelper Helper(Callbacks, VDS_BytesPresent, TS);
|
|
|
- return Helper.Visitor.visitTypeStream(Types);
|
|
|
+Error llvm::codeview::visitMemberRecordStream(ArrayRef<uint8_t> FieldList,
|
|
|
+ TypeVisitorCallbacks &Callbacks) {
|
|
|
+ FieldListVisitHelper V(Callbacks, FieldList, VDS_BytesPresent);
|
|
|
+ return V.Visitor.visitFieldListMemberStream(V.Reader);
|
|
|
}
|