1 //===- TypeDeserializer.h ---------------------------------------*- 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 #ifndef LLVM_DEBUGINFO_CODEVIEW_TYPEDESERIALIZER_H 10 #define LLVM_DEBUGINFO_CODEVIEW_TYPEDESERIALIZER_H 11 12 #include "llvm/ADT/ArrayRef.h" 13 #include "llvm/ADT/STLExtras.h" 14 #include "llvm/DebugInfo/CodeView/CodeView.h" 15 #include "llvm/DebugInfo/CodeView/TypeRecord.h" 16 #include "llvm/DebugInfo/CodeView/TypeRecordMapping.h" 17 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" 18 #include "llvm/Support/BinaryByteStream.h" 19 #include "llvm/Support/BinaryStreamReader.h" 20 #include "llvm/Support/Error.h" 21 #include <cassert> 22 #include <cstdint> 23 #include <memory> 24 25 namespace llvm { 26 namespace codeview { 27 28 class TypeDeserializer : public TypeVisitorCallbacks { 29 struct MappingInfo { 30 explicit MappingInfo(ArrayRef<uint8_t> RecordData) 31 : Stream(RecordData, llvm::endianness::little), Reader(Stream), 32 Mapping(Reader) {} 33 34 BinaryByteStream Stream; 35 BinaryStreamReader Reader; 36 TypeRecordMapping Mapping; 37 }; 38 39 public: 40 TypeDeserializer() = default; 41 42 template <typename T> static Error deserializeAs(CVType &CVT, T &Record) { 43 Record.Kind = static_cast<TypeRecordKind>(CVT.kind()); 44 MappingInfo I(CVT.content()); 45 if (auto EC = I.Mapping.visitTypeBegin(CVT)) 46 return EC; 47 if (auto EC = I.Mapping.visitKnownRecord(CVT, Record)) 48 return EC; 49 if (auto EC = I.Mapping.visitTypeEnd(CVT)) 50 return EC; 51 return Error::success(); 52 } 53 54 template <typename T> 55 static Expected<T> deserializeAs(ArrayRef<uint8_t> Data) { 56 const RecordPrefix *Prefix = 57 reinterpret_cast<const RecordPrefix *>(Data.data()); 58 TypeRecordKind K = 59 static_cast<TypeRecordKind>(uint16_t(Prefix->RecordKind)); 60 T Record(K); 61 CVType CVT(Data); 62 if (auto EC = deserializeAs<T>(CVT, Record)) 63 return std::move(EC); 64 return Record; 65 } 66 67 Error visitTypeBegin(CVType &Record) override { 68 assert(!Mapping && "Already in a type mapping!"); 69 Mapping = std::make_unique<MappingInfo>(Record.content()); 70 return Mapping->Mapping.visitTypeBegin(Record); 71 } 72 73 Error visitTypeBegin(CVType &Record, TypeIndex Index) override { 74 return visitTypeBegin(Record); 75 } 76 77 Error visitTypeEnd(CVType &Record) override { 78 assert(Mapping && "Not in a type mapping!"); 79 auto EC = Mapping->Mapping.visitTypeEnd(Record); 80 Mapping.reset(); 81 return EC; 82 } 83 84 #define TYPE_RECORD(EnumName, EnumVal, Name) \ 85 Error visitKnownRecord(CVType &CVR, Name##Record &Record) override { \ 86 return visitKnownRecordImpl<Name##Record>(CVR, Record); \ 87 } 88 #define MEMBER_RECORD(EnumName, EnumVal, Name) 89 #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) 90 #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) 91 #include "llvm/DebugInfo/CodeView/CodeViewTypes.def" 92 93 private: 94 template <typename RecordType> 95 Error visitKnownRecordImpl(CVType &CVR, RecordType &Record) { 96 return Mapping->Mapping.visitKnownRecord(CVR, Record); 97 } 98 99 std::unique_ptr<MappingInfo> Mapping; 100 }; 101 102 class FieldListDeserializer : public TypeVisitorCallbacks { 103 struct MappingInfo { 104 explicit MappingInfo(BinaryStreamReader &R) 105 : Reader(R), Mapping(Reader), StartOffset(0) {} 106 107 BinaryStreamReader &Reader; 108 TypeRecordMapping Mapping; 109 uint32_t StartOffset; 110 }; 111 112 public: 113 explicit FieldListDeserializer(BinaryStreamReader &Reader) : Mapping(Reader) { 114 RecordPrefix Pre(static_cast<uint16_t>(TypeLeafKind::LF_FIELDLIST)); 115 CVType FieldList(&Pre, sizeof(Pre)); 116 consumeError(Mapping.Mapping.visitTypeBegin(FieldList)); 117 } 118 119 ~FieldListDeserializer() override { 120 RecordPrefix Pre(static_cast<uint16_t>(TypeLeafKind::LF_FIELDLIST)); 121 CVType FieldList(&Pre, sizeof(Pre)); 122 consumeError(Mapping.Mapping.visitTypeEnd(FieldList)); 123 } 124 125 Error visitMemberBegin(CVMemberRecord &Record) override { 126 Mapping.StartOffset = Mapping.Reader.getOffset(); 127 return Mapping.Mapping.visitMemberBegin(Record); 128 } 129 130 Error visitMemberEnd(CVMemberRecord &Record) override { 131 if (auto EC = Mapping.Mapping.visitMemberEnd(Record)) 132 return EC; 133 return Error::success(); 134 } 135 136 #define TYPE_RECORD(EnumName, EnumVal, Name) 137 #define MEMBER_RECORD(EnumName, EnumVal, Name) \ 138 Error visitKnownMember(CVMemberRecord &CVR, Name##Record &Record) override { \ 139 return visitKnownMemberImpl<Name##Record>(CVR, Record); \ 140 } 141 #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) 142 #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) 143 #include "llvm/DebugInfo/CodeView/CodeViewTypes.def" 144 145 private: 146 template <typename RecordType> 147 Error visitKnownMemberImpl(CVMemberRecord &CVR, RecordType &Record) { 148 if (auto EC = Mapping.Mapping.visitKnownMember(CVR, Record)) 149 return EC; 150 151 uint32_t EndOffset = Mapping.Reader.getOffset(); 152 uint32_t RecordLength = EndOffset - Mapping.StartOffset; 153 Mapping.Reader.setOffset(Mapping.StartOffset); 154 if (auto EC = Mapping.Reader.readBytes(CVR.Data, RecordLength)) 155 return EC; 156 assert(Mapping.Reader.getOffset() == EndOffset); 157 return Error::success(); 158 } 159 MappingInfo Mapping; 160 }; 161 162 } // end namespace codeview 163 } // end namespace llvm 164 165 #endif // LLVM_DEBUGINFO_CODEVIEW_TYPEDESERIALIZER_H 166