Home | History | Annotate | Line # | Download | only in CodeView
      1 //===- CVTypeVisitor.cpp ----------------------------------------*- C++ -*-===//
      2 //
      3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
      4 // See https://llvm.org/LICENSE.txt for license information.
      5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
      6 //
      7 //===----------------------------------------------------------------------===//
      8 
      9 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
     10 
     11 #include "llvm/DebugInfo/CodeView/CodeViewError.h"
     12 #include "llvm/DebugInfo/CodeView/TypeCollection.h"
     13 #include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
     14 #include "llvm/DebugInfo/CodeView/TypeRecordMapping.h"
     15 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
     16 #include "llvm/Support/BinaryByteStream.h"
     17 #include "llvm/Support/BinaryStreamReader.h"
     18 
     19 using namespace llvm;
     20 using namespace llvm::codeview;
     21 
     22 
     23 template <typename T>
     24 static Error visitKnownRecord(CVType &Record, TypeVisitorCallbacks &Callbacks) {
     25   TypeRecordKind RK = static_cast<TypeRecordKind>(Record.kind());
     26   T KnownRecord(RK);
     27   if (auto EC = Callbacks.visitKnownRecord(Record, KnownRecord))
     28     return EC;
     29   return Error::success();
     30 }
     31 
     32 template <typename T>
     33 static Error visitKnownMember(CVMemberRecord &Record,
     34                               TypeVisitorCallbacks &Callbacks) {
     35   TypeRecordKind RK = static_cast<TypeRecordKind>(Record.Kind);
     36   T KnownRecord(RK);
     37   if (auto EC = Callbacks.visitKnownMember(Record, KnownRecord))
     38     return EC;
     39   return Error::success();
     40 }
     41 
     42 static Error visitMemberRecord(CVMemberRecord &Record,
     43                                TypeVisitorCallbacks &Callbacks) {
     44   if (auto EC = Callbacks.visitMemberBegin(Record))
     45     return EC;
     46 
     47   switch (Record.Kind) {
     48   default:
     49     if (auto EC = Callbacks.visitUnknownMember(Record))
     50       return EC;
     51     break;
     52 #define MEMBER_RECORD(EnumName, EnumVal, Name)                                 \
     53   case EnumName: {                                                             \
     54     if (auto EC = visitKnownMember<Name##Record>(Record, Callbacks))           \
     55       return EC;                                                               \
     56     break;                                                                     \
     57   }
     58 #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)                \
     59   MEMBER_RECORD(EnumVal, EnumVal, AliasName)
     60 #define TYPE_RECORD(EnumName, EnumVal, Name)
     61 #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
     62 #include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
     63   }
     64 
     65   if (auto EC = Callbacks.visitMemberEnd(Record))
     66     return EC;
     67 
     68   return Error::success();
     69 }
     70 
     71 namespace {
     72 
     73 class CVTypeVisitor {
     74 public:
     75   explicit CVTypeVisitor(TypeVisitorCallbacks &Callbacks);
     76 
     77   Error visitTypeRecord(CVType &Record, TypeIndex Index);
     78   Error visitTypeRecord(CVType &Record);
     79 
     80   /// Visits the type records in Data. Sets the error flag on parse failures.
     81   Error visitTypeStream(const CVTypeArray &Types);
     82   Error visitTypeStream(CVTypeRange Types);
     83   Error visitTypeStream(TypeCollection &Types);
     84 
     85   Error visitMemberRecord(CVMemberRecord Record);
     86   Error visitFieldListMemberStream(BinaryStreamReader &Stream);
     87 
     88 private:
     89   Error finishVisitation(CVType &Record);
     90 
     91   /// The interface to the class that gets notified of each visitation.
     92   TypeVisitorCallbacks &Callbacks;
     93 };
     94 
     95 CVTypeVisitor::CVTypeVisitor(TypeVisitorCallbacks &Callbacks)
     96     : Callbacks(Callbacks) {}
     97 
     98 Error CVTypeVisitor::finishVisitation(CVType &Record) {
     99   switch (Record.kind()) {
    100   default:
    101     if (auto EC = Callbacks.visitUnknownType(Record))
    102       return EC;
    103     break;
    104 #define TYPE_RECORD(EnumName, EnumVal, Name)                                   \
    105   case EnumName: {                                                             \
    106     if (auto EC = visitKnownRecord<Name##Record>(Record, Callbacks))           \
    107       return EC;                                                               \
    108     break;                                                                     \
    109   }
    110 #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)                  \
    111   TYPE_RECORD(EnumVal, EnumVal, AliasName)
    112 #define MEMBER_RECORD(EnumName, EnumVal, Name)
    113 #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
    114 #include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
    115   }
    116 
    117   if (auto EC = Callbacks.visitTypeEnd(Record))
    118     return EC;
    119 
    120   return Error::success();
    121 }
    122 
    123 Error CVTypeVisitor::visitTypeRecord(CVType &Record, TypeIndex Index) {
    124   if (auto EC = Callbacks.visitTypeBegin(Record, Index))
    125     return EC;
    126 
    127   return finishVisitation(Record);
    128 }
    129 
    130 Error CVTypeVisitor::visitTypeRecord(CVType &Record) {
    131   if (auto EC = Callbacks.visitTypeBegin(Record))
    132     return EC;
    133 
    134   return finishVisitation(Record);
    135 }
    136 
    137 Error CVTypeVisitor::visitMemberRecord(CVMemberRecord Record) {
    138   return ::visitMemberRecord(Record, Callbacks);
    139 }
    140 
    141 /// Visits the type records in Data. Sets the error flag on parse failures.
    142 Error CVTypeVisitor::visitTypeStream(const CVTypeArray &Types) {
    143   for (auto I : Types) {
    144     if (auto EC = visitTypeRecord(I))
    145       return EC;
    146   }
    147   return Error::success();
    148 }
    149 
    150 Error CVTypeVisitor::visitTypeStream(CVTypeRange Types) {
    151   for (auto I : Types) {
    152     if (auto EC = visitTypeRecord(I))
    153       return EC;
    154   }
    155   return Error::success();
    156 }
    157 
    158 Error CVTypeVisitor::visitTypeStream(TypeCollection &Types) {
    159   Optional<TypeIndex> I = Types.getFirst();
    160   while (I) {
    161     CVType Type = Types.getType(*I);
    162     if (auto EC = visitTypeRecord(Type, *I))
    163       return EC;
    164     I = Types.getNext(*I);
    165   }
    166   return Error::success();
    167 }
    168 
    169 Error CVTypeVisitor::visitFieldListMemberStream(BinaryStreamReader &Reader) {
    170   TypeLeafKind Leaf;
    171   while (!Reader.empty()) {
    172     if (auto EC = Reader.readEnum(Leaf))
    173       return EC;
    174 
    175     CVMemberRecord Record;
    176     Record.Kind = Leaf;
    177     if (auto EC = ::visitMemberRecord(Record, Callbacks))
    178       return EC;
    179   }
    180 
    181   return Error::success();
    182 }
    183 
    184 struct FieldListVisitHelper {
    185   FieldListVisitHelper(TypeVisitorCallbacks &Callbacks, ArrayRef<uint8_t> Data,
    186                        VisitorDataSource Source)
    187       : Stream(Data, llvm::support::little), Reader(Stream),
    188         Deserializer(Reader),
    189         Visitor((Source == VDS_BytesPresent) ? Pipeline : Callbacks) {
    190     if (Source == VDS_BytesPresent) {
    191       Pipeline.addCallbackToPipeline(Deserializer);
    192       Pipeline.addCallbackToPipeline(Callbacks);
    193     }
    194   }
    195 
    196   BinaryByteStream Stream;
    197   BinaryStreamReader Reader;
    198   FieldListDeserializer Deserializer;
    199   TypeVisitorCallbackPipeline Pipeline;
    200   CVTypeVisitor Visitor;
    201 };
    202 
    203 struct VisitHelper {
    204   VisitHelper(TypeVisitorCallbacks &Callbacks, VisitorDataSource Source)
    205       : Visitor((Source == VDS_BytesPresent) ? Pipeline : Callbacks) {
    206     if (Source == VDS_BytesPresent) {
    207       Pipeline.addCallbackToPipeline(Deserializer);
    208       Pipeline.addCallbackToPipeline(Callbacks);
    209     }
    210   }
    211 
    212   TypeDeserializer Deserializer;
    213   TypeVisitorCallbackPipeline Pipeline;
    214   CVTypeVisitor Visitor;
    215 };
    216 }
    217 
    218 Error llvm::codeview::visitTypeRecord(CVType &Record, TypeIndex Index,
    219                                       TypeVisitorCallbacks &Callbacks,
    220                                       VisitorDataSource Source) {
    221   VisitHelper V(Callbacks, Source);
    222   return V.Visitor.visitTypeRecord(Record, Index);
    223 }
    224 
    225 Error llvm::codeview::visitTypeRecord(CVType &Record,
    226                                       TypeVisitorCallbacks &Callbacks,
    227                                       VisitorDataSource Source) {
    228   VisitHelper V(Callbacks, Source);
    229   return V.Visitor.visitTypeRecord(Record);
    230 }
    231 
    232 Error llvm::codeview::visitTypeStream(const CVTypeArray &Types,
    233                                       TypeVisitorCallbacks &Callbacks,
    234                                       VisitorDataSource Source) {
    235   VisitHelper V(Callbacks, Source);
    236   return V.Visitor.visitTypeStream(Types);
    237 }
    238 
    239 Error llvm::codeview::visitTypeStream(CVTypeRange Types,
    240                                       TypeVisitorCallbacks &Callbacks) {
    241   VisitHelper V(Callbacks, VDS_BytesPresent);
    242   return V.Visitor.visitTypeStream(Types);
    243 }
    244 
    245 Error llvm::codeview::visitTypeStream(TypeCollection &Types,
    246                                       TypeVisitorCallbacks &Callbacks) {
    247   // When the internal visitor calls Types.getType(Index) the interface is
    248   // required to return a CVType with the bytes filled out.  So we can assume
    249   // that the bytes will be present when individual records are visited.
    250   VisitHelper V(Callbacks, VDS_BytesPresent);
    251   return V.Visitor.visitTypeStream(Types);
    252 }
    253 
    254 Error llvm::codeview::visitMemberRecord(CVMemberRecord Record,
    255                                         TypeVisitorCallbacks &Callbacks,
    256                                         VisitorDataSource Source) {
    257   FieldListVisitHelper V(Callbacks, Record.Data, Source);
    258   return V.Visitor.visitMemberRecord(Record);
    259 }
    260 
    261 Error llvm::codeview::visitMemberRecord(TypeLeafKind Kind,
    262                                         ArrayRef<uint8_t> Record,
    263                                         TypeVisitorCallbacks &Callbacks) {
    264   CVMemberRecord R;
    265   R.Data = Record;
    266   R.Kind = Kind;
    267   return visitMemberRecord(R, Callbacks, VDS_BytesPresent);
    268 }
    269 
    270 Error llvm::codeview::visitMemberRecordStream(ArrayRef<uint8_t> FieldList,
    271                                               TypeVisitorCallbacks &Callbacks) {
    272   FieldListVisitHelper V(Callbacks, FieldList, VDS_BytesPresent);
    273   return V.Visitor.visitFieldListMemberStream(V.Reader);
    274 }
    275