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