1 //===- CVTypeVisitor.cpp ----------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
12 #include "llvm/DebugInfo/CodeView/CodeViewError.h"
13 #include "llvm/DebugInfo/CodeView/TypeDatabase.h"
14 #include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h"
15 #include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
16 #include "llvm/DebugInfo/CodeView/TypeRecordMapping.h"
17 #include "llvm/DebugInfo/CodeView/TypeServerHandler.h"
18 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
19 #include "llvm/Support/BinaryByteStream.h"
20 #include "llvm/Support/BinaryStreamReader.h"
23 using namespace llvm::codeview;
25 CVTypeVisitor::CVTypeVisitor(TypeVisitorCallbacks &Callbacks)
26 : Callbacks(Callbacks) {}
29 static Error visitKnownRecord(CVTypeVisitor &Visitor, CVType &Record,
30 TypeVisitorCallbacks &Callbacks) {
31 TypeRecordKind RK = static_cast<TypeRecordKind>(Record.Type);
33 if (auto EC = Callbacks.visitKnownRecord(Record, KnownRecord))
35 return Error::success();
39 static Error visitKnownMember(CVMemberRecord &Record,
40 TypeVisitorCallbacks &Callbacks) {
41 TypeRecordKind RK = static_cast<TypeRecordKind>(Record.Kind);
43 if (auto EC = Callbacks.visitKnownMember(Record, KnownRecord))
45 return Error::success();
48 static Expected<TypeServer2Record> deserializeTypeServerRecord(CVType &Record) {
49 class StealTypeServerVisitor : public TypeVisitorCallbacks {
51 explicit StealTypeServerVisitor(TypeServer2Record &TR) : TR(TR) {}
53 Error visitKnownRecord(CVType &CVR, TypeServer2Record &Record) override {
55 return Error::success();
59 TypeServer2Record &TR;
62 TypeServer2Record R(TypeRecordKind::TypeServer2);
63 TypeDeserializer Deserializer;
64 StealTypeServerVisitor Thief(R);
65 TypeVisitorCallbackPipeline Pipeline;
66 Pipeline.addCallbackToPipeline(Deserializer);
67 Pipeline.addCallbackToPipeline(Thief);
68 CVTypeVisitor Visitor(Pipeline);
69 if (auto EC = Visitor.visitTypeRecord(Record))
75 void CVTypeVisitor::addTypeServerHandler(TypeServerHandler &Handler) {
76 Handlers.push_back(&Handler);
79 Error CVTypeVisitor::visitTypeRecord(CVType &Record) {
80 if (Record.Type == TypeLeafKind::LF_TYPESERVER2 && !Handlers.empty()) {
81 auto TS = deserializeTypeServerRecord(Record);
83 return TS.takeError();
85 for (auto Handler : Handlers) {
86 auto ExpectedResult = Handler->handle(*TS, Callbacks);
87 // If there was an error, return the error.
89 return ExpectedResult.takeError();
91 // If the handler processed the record, return success.
93 return Error::success();
95 // Otherwise keep searching for a handler, eventually falling out and
96 // using the default record handler.
100 if (auto EC = Callbacks.visitTypeBegin(Record))
103 switch (Record.Type) {
105 if (auto EC = Callbacks.visitUnknownType(Record))
108 #define TYPE_RECORD(EnumName, EnumVal, Name) \
110 if (auto EC = visitKnownRecord<Name##Record>(*this, Record, Callbacks)) \
114 #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \
115 TYPE_RECORD(EnumVal, EnumVal, AliasName)
116 #define MEMBER_RECORD(EnumName, EnumVal, Name)
117 #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
118 #include "llvm/DebugInfo/CodeView/TypeRecords.def"
121 if (auto EC = Callbacks.visitTypeEnd(Record))
124 return Error::success();
127 static Error visitMemberRecord(CVMemberRecord &Record,
128 TypeVisitorCallbacks &Callbacks) {
129 if (auto EC = Callbacks.visitMemberBegin(Record))
132 switch (Record.Kind) {
134 if (auto EC = Callbacks.visitUnknownMember(Record))
137 #define MEMBER_RECORD(EnumName, EnumVal, Name) \
139 if (auto EC = visitKnownMember<Name##Record>(Record, Callbacks)) \
143 #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \
144 MEMBER_RECORD(EnumVal, EnumVal, AliasName)
145 #define TYPE_RECORD(EnumName, EnumVal, Name)
146 #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
147 #include "llvm/DebugInfo/CodeView/TypeRecords.def"
150 if (auto EC = Callbacks.visitMemberEnd(Record))
153 return Error::success();
156 Error CVTypeVisitor::visitMemberRecord(CVMemberRecord &Record) {
157 return ::visitMemberRecord(Record, Callbacks);
160 /// Visits the type records in Data. Sets the error flag on parse failures.
161 Error CVTypeVisitor::visitTypeStream(const CVTypeArray &Types) {
162 for (auto I : Types) {
163 if (auto EC = visitTypeRecord(I))
166 return Error::success();
169 Error CVTypeVisitor::visitTypeStream(CVTypeRange Types) {
170 for (auto I : Types) {
171 if (auto EC = visitTypeRecord(I))
174 return Error::success();
177 Error CVTypeVisitor::visitFieldListMemberStream(BinaryStreamReader Reader) {
178 FieldListDeserializer Deserializer(Reader);
179 TypeVisitorCallbackPipeline Pipeline;
180 Pipeline.addCallbackToPipeline(Deserializer);
181 Pipeline.addCallbackToPipeline(Callbacks);
184 while (!Reader.empty()) {
185 if (auto EC = Reader.readEnum(Leaf))
188 CVMemberRecord Record;
190 if (auto EC = ::visitMemberRecord(Record, Pipeline))
194 return Error::success();
197 Error CVTypeVisitor::visitFieldListMemberStream(ArrayRef<uint8_t> Data) {
198 BinaryByteStream S(Data, llvm::support::little);
199 BinaryStreamReader SR(S);
200 return visitFieldListMemberStream(SR);