CVTypeVisitor.cpp revision 360784
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 19using namespace llvm; 20using namespace llvm::codeview; 21 22 23template <typename T> 24static 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 32template <typename T> 33static 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 42static 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 71namespace { 72 73class CVTypeVisitor { 74public: 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 88private: 89 Error finishVisitation(CVType &Record); 90 91 /// The interface to the class that gets notified of each visitation. 92 TypeVisitorCallbacks &Callbacks; 93}; 94 95CVTypeVisitor::CVTypeVisitor(TypeVisitorCallbacks &Callbacks) 96 : Callbacks(Callbacks) {} 97 98Error 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 123Error CVTypeVisitor::visitTypeRecord(CVType &Record, TypeIndex Index) { 124 if (auto EC = Callbacks.visitTypeBegin(Record, Index)) 125 return EC; 126 127 return finishVisitation(Record); 128} 129 130Error CVTypeVisitor::visitTypeRecord(CVType &Record) { 131 if (auto EC = Callbacks.visitTypeBegin(Record)) 132 return EC; 133 134 return finishVisitation(Record); 135} 136 137Error 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. 142Error 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 150Error 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 158Error 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 169Error 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 184struct 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 203struct 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 218Error 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 225Error llvm::codeview::visitTypeRecord(CVType &Record, 226 TypeVisitorCallbacks &Callbacks, 227 VisitorDataSource Source) { 228 VisitHelper V(Callbacks, Source); 229 return V.Visitor.visitTypeRecord(Record); 230} 231 232Error 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 239Error llvm::codeview::visitTypeStream(CVTypeRange Types, 240 TypeVisitorCallbacks &Callbacks) { 241 VisitHelper V(Callbacks, VDS_BytesPresent); 242 return V.Visitor.visitTypeStream(Types); 243} 244 245Error 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 254Error 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 261Error 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 270Error 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