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