10b57cec5SDimitry Andric //===- CVTypeVisitor.cpp ----------------------------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric
90b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
100b57cec5SDimitry Andric
110b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/TypeCollection.h"
120b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
1381ad6265SDimitry Andric #include "llvm/DebugInfo/CodeView/TypeIndex.h"
1481ad6265SDimitry Andric #include "llvm/DebugInfo/CodeView/TypeRecord.h"
150b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
1681ad6265SDimitry Andric #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
170b57cec5SDimitry Andric #include "llvm/Support/BinaryByteStream.h"
180b57cec5SDimitry Andric #include "llvm/Support/BinaryStreamReader.h"
190b57cec5SDimitry Andric
200b57cec5SDimitry Andric using namespace llvm;
210b57cec5SDimitry Andric using namespace llvm::codeview;
220b57cec5SDimitry Andric
230b57cec5SDimitry Andric
240b57cec5SDimitry Andric template <typename T>
visitKnownRecord(CVType & Record,TypeVisitorCallbacks & Callbacks)250b57cec5SDimitry Andric static Error visitKnownRecord(CVType &Record, TypeVisitorCallbacks &Callbacks) {
260b57cec5SDimitry Andric TypeRecordKind RK = static_cast<TypeRecordKind>(Record.kind());
270b57cec5SDimitry Andric T KnownRecord(RK);
280b57cec5SDimitry Andric if (auto EC = Callbacks.visitKnownRecord(Record, KnownRecord))
290b57cec5SDimitry Andric return EC;
300b57cec5SDimitry Andric return Error::success();
310b57cec5SDimitry Andric }
320b57cec5SDimitry Andric
330b57cec5SDimitry Andric template <typename T>
visitKnownMember(CVMemberRecord & Record,TypeVisitorCallbacks & Callbacks)340b57cec5SDimitry Andric static Error visitKnownMember(CVMemberRecord &Record,
350b57cec5SDimitry Andric TypeVisitorCallbacks &Callbacks) {
360b57cec5SDimitry Andric TypeRecordKind RK = static_cast<TypeRecordKind>(Record.Kind);
370b57cec5SDimitry Andric T KnownRecord(RK);
380b57cec5SDimitry Andric if (auto EC = Callbacks.visitKnownMember(Record, KnownRecord))
390b57cec5SDimitry Andric return EC;
400b57cec5SDimitry Andric return Error::success();
410b57cec5SDimitry Andric }
420b57cec5SDimitry Andric
visitMemberRecord(CVMemberRecord & Record,TypeVisitorCallbacks & Callbacks)430b57cec5SDimitry Andric static Error visitMemberRecord(CVMemberRecord &Record,
440b57cec5SDimitry Andric TypeVisitorCallbacks &Callbacks) {
450b57cec5SDimitry Andric if (auto EC = Callbacks.visitMemberBegin(Record))
460b57cec5SDimitry Andric return EC;
470b57cec5SDimitry Andric
480b57cec5SDimitry Andric switch (Record.Kind) {
490b57cec5SDimitry Andric default:
500b57cec5SDimitry Andric if (auto EC = Callbacks.visitUnknownMember(Record))
510b57cec5SDimitry Andric return EC;
520b57cec5SDimitry Andric break;
530b57cec5SDimitry Andric #define MEMBER_RECORD(EnumName, EnumVal, Name) \
540b57cec5SDimitry Andric case EnumName: { \
550b57cec5SDimitry Andric if (auto EC = visitKnownMember<Name##Record>(Record, Callbacks)) \
560b57cec5SDimitry Andric return EC; \
570b57cec5SDimitry Andric break; \
580b57cec5SDimitry Andric }
590b57cec5SDimitry Andric #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \
600b57cec5SDimitry Andric MEMBER_RECORD(EnumVal, EnumVal, AliasName)
610b57cec5SDimitry Andric #define TYPE_RECORD(EnumName, EnumVal, Name)
620b57cec5SDimitry Andric #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
630b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
640b57cec5SDimitry Andric }
650b57cec5SDimitry Andric
660b57cec5SDimitry Andric if (auto EC = Callbacks.visitMemberEnd(Record))
670b57cec5SDimitry Andric return EC;
680b57cec5SDimitry Andric
690b57cec5SDimitry Andric return Error::success();
700b57cec5SDimitry Andric }
710b57cec5SDimitry Andric
720b57cec5SDimitry Andric namespace {
730b57cec5SDimitry Andric
740b57cec5SDimitry Andric class CVTypeVisitor {
750b57cec5SDimitry Andric public:
760b57cec5SDimitry Andric explicit CVTypeVisitor(TypeVisitorCallbacks &Callbacks);
770b57cec5SDimitry Andric
780b57cec5SDimitry Andric Error visitTypeRecord(CVType &Record, TypeIndex Index);
790b57cec5SDimitry Andric Error visitTypeRecord(CVType &Record);
800b57cec5SDimitry Andric
810b57cec5SDimitry Andric /// Visits the type records in Data. Sets the error flag on parse failures.
820b57cec5SDimitry Andric Error visitTypeStream(const CVTypeArray &Types);
830b57cec5SDimitry Andric Error visitTypeStream(CVTypeRange Types);
840b57cec5SDimitry Andric Error visitTypeStream(TypeCollection &Types);
850b57cec5SDimitry Andric
860b57cec5SDimitry Andric Error visitMemberRecord(CVMemberRecord Record);
870b57cec5SDimitry Andric Error visitFieldListMemberStream(BinaryStreamReader &Stream);
880b57cec5SDimitry Andric
890b57cec5SDimitry Andric private:
900b57cec5SDimitry Andric Error finishVisitation(CVType &Record);
910b57cec5SDimitry Andric
920b57cec5SDimitry Andric /// The interface to the class that gets notified of each visitation.
930b57cec5SDimitry Andric TypeVisitorCallbacks &Callbacks;
940b57cec5SDimitry Andric };
950b57cec5SDimitry Andric
CVTypeVisitor(TypeVisitorCallbacks & Callbacks)960b57cec5SDimitry Andric CVTypeVisitor::CVTypeVisitor(TypeVisitorCallbacks &Callbacks)
970b57cec5SDimitry Andric : Callbacks(Callbacks) {}
980b57cec5SDimitry Andric
finishVisitation(CVType & Record)990b57cec5SDimitry Andric Error CVTypeVisitor::finishVisitation(CVType &Record) {
1000b57cec5SDimitry Andric switch (Record.kind()) {
1010b57cec5SDimitry Andric default:
1020b57cec5SDimitry Andric if (auto EC = Callbacks.visitUnknownType(Record))
1030b57cec5SDimitry Andric return EC;
1040b57cec5SDimitry Andric break;
1050b57cec5SDimitry Andric #define TYPE_RECORD(EnumName, EnumVal, Name) \
1060b57cec5SDimitry Andric case EnumName: { \
1070b57cec5SDimitry Andric if (auto EC = visitKnownRecord<Name##Record>(Record, Callbacks)) \
1080b57cec5SDimitry Andric return EC; \
1090b57cec5SDimitry Andric break; \
1100b57cec5SDimitry Andric }
1110b57cec5SDimitry Andric #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \
1120b57cec5SDimitry Andric TYPE_RECORD(EnumVal, EnumVal, AliasName)
1130b57cec5SDimitry Andric #define MEMBER_RECORD(EnumName, EnumVal, Name)
1140b57cec5SDimitry Andric #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
1150b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
1160b57cec5SDimitry Andric }
1170b57cec5SDimitry Andric
1180b57cec5SDimitry Andric if (auto EC = Callbacks.visitTypeEnd(Record))
1190b57cec5SDimitry Andric return EC;
1200b57cec5SDimitry Andric
1210b57cec5SDimitry Andric return Error::success();
1220b57cec5SDimitry Andric }
1230b57cec5SDimitry Andric
visitTypeRecord(CVType & Record,TypeIndex Index)1240b57cec5SDimitry Andric Error CVTypeVisitor::visitTypeRecord(CVType &Record, TypeIndex Index) {
1250b57cec5SDimitry Andric if (auto EC = Callbacks.visitTypeBegin(Record, Index))
1260b57cec5SDimitry Andric return EC;
1270b57cec5SDimitry Andric
1280b57cec5SDimitry Andric return finishVisitation(Record);
1290b57cec5SDimitry Andric }
1300b57cec5SDimitry Andric
visitTypeRecord(CVType & Record)1310b57cec5SDimitry Andric Error CVTypeVisitor::visitTypeRecord(CVType &Record) {
1320b57cec5SDimitry Andric if (auto EC = Callbacks.visitTypeBegin(Record))
1330b57cec5SDimitry Andric return EC;
1340b57cec5SDimitry Andric
1350b57cec5SDimitry Andric return finishVisitation(Record);
1360b57cec5SDimitry Andric }
1370b57cec5SDimitry Andric
visitMemberRecord(CVMemberRecord Record)1380b57cec5SDimitry Andric Error CVTypeVisitor::visitMemberRecord(CVMemberRecord Record) {
1390b57cec5SDimitry Andric return ::visitMemberRecord(Record, Callbacks);
1400b57cec5SDimitry Andric }
1410b57cec5SDimitry Andric
1420b57cec5SDimitry Andric /// Visits the type records in Data. Sets the error flag on parse failures.
visitTypeStream(const CVTypeArray & Types)1430b57cec5SDimitry Andric Error CVTypeVisitor::visitTypeStream(const CVTypeArray &Types) {
1440b57cec5SDimitry Andric for (auto I : Types) {
1450b57cec5SDimitry Andric if (auto EC = visitTypeRecord(I))
1460b57cec5SDimitry Andric return EC;
1470b57cec5SDimitry Andric }
1480b57cec5SDimitry Andric return Error::success();
1490b57cec5SDimitry Andric }
1500b57cec5SDimitry Andric
visitTypeStream(CVTypeRange Types)1510b57cec5SDimitry Andric Error CVTypeVisitor::visitTypeStream(CVTypeRange Types) {
1520b57cec5SDimitry Andric for (auto I : Types) {
1530b57cec5SDimitry Andric if (auto EC = visitTypeRecord(I))
1540b57cec5SDimitry Andric return EC;
1550b57cec5SDimitry Andric }
1560b57cec5SDimitry Andric return Error::success();
1570b57cec5SDimitry Andric }
1580b57cec5SDimitry Andric
visitTypeStream(TypeCollection & Types)1590b57cec5SDimitry Andric Error CVTypeVisitor::visitTypeStream(TypeCollection &Types) {
160bdd1243dSDimitry Andric std::optional<TypeIndex> I = Types.getFirst();
1610b57cec5SDimitry Andric while (I) {
1620b57cec5SDimitry Andric CVType Type = Types.getType(*I);
1630b57cec5SDimitry Andric if (auto EC = visitTypeRecord(Type, *I))
1640b57cec5SDimitry Andric return EC;
1650b57cec5SDimitry Andric I = Types.getNext(*I);
1660b57cec5SDimitry Andric }
1670b57cec5SDimitry Andric return Error::success();
1680b57cec5SDimitry Andric }
1690b57cec5SDimitry Andric
visitFieldListMemberStream(BinaryStreamReader & Reader)1700b57cec5SDimitry Andric Error CVTypeVisitor::visitFieldListMemberStream(BinaryStreamReader &Reader) {
1710b57cec5SDimitry Andric TypeLeafKind Leaf;
1720b57cec5SDimitry Andric while (!Reader.empty()) {
1730b57cec5SDimitry Andric if (auto EC = Reader.readEnum(Leaf))
1740b57cec5SDimitry Andric return EC;
1750b57cec5SDimitry Andric
1760b57cec5SDimitry Andric CVMemberRecord Record;
1770b57cec5SDimitry Andric Record.Kind = Leaf;
1780b57cec5SDimitry Andric if (auto EC = ::visitMemberRecord(Record, Callbacks))
1790b57cec5SDimitry Andric return EC;
1800b57cec5SDimitry Andric }
1810b57cec5SDimitry Andric
1820b57cec5SDimitry Andric return Error::success();
1830b57cec5SDimitry Andric }
1840b57cec5SDimitry Andric
1850b57cec5SDimitry Andric struct FieldListVisitHelper {
FieldListVisitHelper__anone25af6ca0111::FieldListVisitHelper1860b57cec5SDimitry Andric FieldListVisitHelper(TypeVisitorCallbacks &Callbacks, ArrayRef<uint8_t> Data,
1870b57cec5SDimitry Andric VisitorDataSource Source)
1885f757f3fSDimitry Andric : Stream(Data, llvm::endianness::little), Reader(Stream),
1890b57cec5SDimitry Andric Deserializer(Reader),
1900b57cec5SDimitry Andric Visitor((Source == VDS_BytesPresent) ? Pipeline : Callbacks) {
1910b57cec5SDimitry Andric if (Source == VDS_BytesPresent) {
1920b57cec5SDimitry Andric Pipeline.addCallbackToPipeline(Deserializer);
1930b57cec5SDimitry Andric Pipeline.addCallbackToPipeline(Callbacks);
1940b57cec5SDimitry Andric }
1950b57cec5SDimitry Andric }
1960b57cec5SDimitry Andric
1970b57cec5SDimitry Andric BinaryByteStream Stream;
1980b57cec5SDimitry Andric BinaryStreamReader Reader;
1990b57cec5SDimitry Andric FieldListDeserializer Deserializer;
2000b57cec5SDimitry Andric TypeVisitorCallbackPipeline Pipeline;
2010b57cec5SDimitry Andric CVTypeVisitor Visitor;
2020b57cec5SDimitry Andric };
2030b57cec5SDimitry Andric
2040b57cec5SDimitry Andric struct VisitHelper {
VisitHelper__anone25af6ca0111::VisitHelper2050b57cec5SDimitry Andric VisitHelper(TypeVisitorCallbacks &Callbacks, VisitorDataSource Source)
2060b57cec5SDimitry Andric : Visitor((Source == VDS_BytesPresent) ? Pipeline : Callbacks) {
2070b57cec5SDimitry Andric if (Source == VDS_BytesPresent) {
2080b57cec5SDimitry Andric Pipeline.addCallbackToPipeline(Deserializer);
2090b57cec5SDimitry Andric Pipeline.addCallbackToPipeline(Callbacks);
2100b57cec5SDimitry Andric }
2110b57cec5SDimitry Andric }
2120b57cec5SDimitry Andric
2130b57cec5SDimitry Andric TypeDeserializer Deserializer;
2140b57cec5SDimitry Andric TypeVisitorCallbackPipeline Pipeline;
2150b57cec5SDimitry Andric CVTypeVisitor Visitor;
2160b57cec5SDimitry Andric };
2170b57cec5SDimitry Andric }
2180b57cec5SDimitry Andric
visitTypeRecord(CVType & Record,TypeIndex Index,TypeVisitorCallbacks & Callbacks,VisitorDataSource Source)2190b57cec5SDimitry Andric Error llvm::codeview::visitTypeRecord(CVType &Record, TypeIndex Index,
2200b57cec5SDimitry Andric TypeVisitorCallbacks &Callbacks,
2210b57cec5SDimitry Andric VisitorDataSource Source) {
2220b57cec5SDimitry Andric VisitHelper V(Callbacks, Source);
2230b57cec5SDimitry Andric return V.Visitor.visitTypeRecord(Record, Index);
2240b57cec5SDimitry Andric }
2250b57cec5SDimitry Andric
visitTypeRecord(CVType & Record,TypeVisitorCallbacks & Callbacks,VisitorDataSource Source)2260b57cec5SDimitry Andric Error llvm::codeview::visitTypeRecord(CVType &Record,
2270b57cec5SDimitry Andric TypeVisitorCallbacks &Callbacks,
2280b57cec5SDimitry Andric VisitorDataSource Source) {
2290b57cec5SDimitry Andric VisitHelper V(Callbacks, Source);
2300b57cec5SDimitry Andric return V.Visitor.visitTypeRecord(Record);
2310b57cec5SDimitry Andric }
2320b57cec5SDimitry Andric
visitTypeStream(const CVTypeArray & Types,TypeVisitorCallbacks & Callbacks,VisitorDataSource Source)2330b57cec5SDimitry Andric Error llvm::codeview::visitTypeStream(const CVTypeArray &Types,
2340b57cec5SDimitry Andric TypeVisitorCallbacks &Callbacks,
2350b57cec5SDimitry Andric VisitorDataSource Source) {
2360b57cec5SDimitry Andric VisitHelper V(Callbacks, Source);
2370b57cec5SDimitry Andric return V.Visitor.visitTypeStream(Types);
2380b57cec5SDimitry Andric }
2390b57cec5SDimitry Andric
visitTypeStream(CVTypeRange Types,TypeVisitorCallbacks & Callbacks)2400b57cec5SDimitry Andric Error llvm::codeview::visitTypeStream(CVTypeRange Types,
2410b57cec5SDimitry Andric TypeVisitorCallbacks &Callbacks) {
2420b57cec5SDimitry Andric VisitHelper V(Callbacks, VDS_BytesPresent);
2430b57cec5SDimitry Andric return V.Visitor.visitTypeStream(Types);
2440b57cec5SDimitry Andric }
2450b57cec5SDimitry Andric
visitTypeStream(TypeCollection & Types,TypeVisitorCallbacks & Callbacks)2460b57cec5SDimitry Andric Error llvm::codeview::visitTypeStream(TypeCollection &Types,
2470b57cec5SDimitry Andric TypeVisitorCallbacks &Callbacks) {
2480b57cec5SDimitry Andric // When the internal visitor calls Types.getType(Index) the interface is
2490b57cec5SDimitry Andric // required to return a CVType with the bytes filled out. So we can assume
2500b57cec5SDimitry Andric // that the bytes will be present when individual records are visited.
2510b57cec5SDimitry Andric VisitHelper V(Callbacks, VDS_BytesPresent);
2520b57cec5SDimitry Andric return V.Visitor.visitTypeStream(Types);
2530b57cec5SDimitry Andric }
2540b57cec5SDimitry Andric
visitMemberRecord(CVMemberRecord Record,TypeVisitorCallbacks & Callbacks,VisitorDataSource Source)2550b57cec5SDimitry Andric Error llvm::codeview::visitMemberRecord(CVMemberRecord Record,
2560b57cec5SDimitry Andric TypeVisitorCallbacks &Callbacks,
2570b57cec5SDimitry Andric VisitorDataSource Source) {
2580b57cec5SDimitry Andric FieldListVisitHelper V(Callbacks, Record.Data, Source);
2590b57cec5SDimitry Andric return V.Visitor.visitMemberRecord(Record);
2600b57cec5SDimitry Andric }
2610b57cec5SDimitry Andric
visitMemberRecord(TypeLeafKind Kind,ArrayRef<uint8_t> Record,TypeVisitorCallbacks & Callbacks)2620b57cec5SDimitry Andric Error llvm::codeview::visitMemberRecord(TypeLeafKind Kind,
2630b57cec5SDimitry Andric ArrayRef<uint8_t> Record,
2640b57cec5SDimitry Andric TypeVisitorCallbacks &Callbacks) {
2650b57cec5SDimitry Andric CVMemberRecord R;
2660b57cec5SDimitry Andric R.Data = Record;
2670b57cec5SDimitry Andric R.Kind = Kind;
2680b57cec5SDimitry Andric return visitMemberRecord(R, Callbacks, VDS_BytesPresent);
2690b57cec5SDimitry Andric }
2700b57cec5SDimitry Andric
visitMemberRecordStream(ArrayRef<uint8_t> FieldList,TypeVisitorCallbacks & Callbacks)2710b57cec5SDimitry Andric Error llvm::codeview::visitMemberRecordStream(ArrayRef<uint8_t> FieldList,
2720b57cec5SDimitry Andric TypeVisitorCallbacks &Callbacks) {
2730b57cec5SDimitry Andric FieldListVisitHelper V(Callbacks, FieldList, VDS_BytesPresent);
2740b57cec5SDimitry Andric return V.Visitor.visitFieldListMemberStream(V.Reader);
2750b57cec5SDimitry Andric }
276