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 20 using namespace llvm; 21 using namespace llvm::codeview; 22 23 24 template <typename T> 25 static 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 33 template <typename T> 34 static 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 43 static 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 72 namespace { 73 74 class CVTypeVisitor { 75 public: 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 89 private: 90 Error finishVisitation(CVType &Record); 91 92 /// The interface to the class that gets notified of each visitation. 93 TypeVisitorCallbacks &Callbacks; 94 }; 95 96 CVTypeVisitor::CVTypeVisitor(TypeVisitorCallbacks &Callbacks) 97 : Callbacks(Callbacks) {} 98 99 Error 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 124 Error CVTypeVisitor::visitTypeRecord(CVType &Record, TypeIndex Index) { 125 if (auto EC = Callbacks.visitTypeBegin(Record, Index)) 126 return EC; 127 128 return finishVisitation(Record); 129 } 130 131 Error CVTypeVisitor::visitTypeRecord(CVType &Record) { 132 if (auto EC = Callbacks.visitTypeBegin(Record)) 133 return EC; 134 135 return finishVisitation(Record); 136 } 137 138 Error 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. 143 Error 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 151 Error 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 159 Error CVTypeVisitor::visitTypeStream(TypeCollection &Types) { 160 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 170 Error 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 185 struct FieldListVisitHelper { 186 FieldListVisitHelper(TypeVisitorCallbacks &Callbacks, ArrayRef<uint8_t> Data, 187 VisitorDataSource Source) 188 : Stream(Data, llvm::support::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 204 struct 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 219 Error 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 226 Error llvm::codeview::visitTypeRecord(CVType &Record, 227 TypeVisitorCallbacks &Callbacks, 228 VisitorDataSource Source) { 229 VisitHelper V(Callbacks, Source); 230 return V.Visitor.visitTypeRecord(Record); 231 } 232 233 Error 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 240 Error llvm::codeview::visitTypeStream(CVTypeRange Types, 241 TypeVisitorCallbacks &Callbacks) { 242 VisitHelper V(Callbacks, VDS_BytesPresent); 243 return V.Visitor.visitTypeStream(Types); 244 } 245 246 Error 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 255 Error 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 262 Error 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 271 Error 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