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