1 //===- TypeDeserializer.h ---------------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #ifndef LLVM_DEBUGINFO_CODEVIEW_TYPEDESERIALIZER_H
10 #define LLVM_DEBUGINFO_CODEVIEW_TYPEDESERIALIZER_H
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"
28 class TypeDeserializer : public TypeVisitorCallbacks {
30 explicit MappingInfo(ArrayRef<uint8_t> RecordData)
31 : Stream(RecordData, llvm::support::little), Reader(Stream),
34 BinaryByteStream Stream;
35 BinaryStreamReader Reader;
36 TypeRecordMapping Mapping;
40 TypeDeserializer() = default;
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))
47 if (auto EC = I.Mapping.visitKnownRecord(CVT, Record))
49 if (auto EC = I.Mapping.visitTypeEnd(CVT))
51 return Error::success();
55 static Expected<T> deserializeAs(ArrayRef<uint8_t> Data) {
56 const RecordPrefix *Prefix =
57 reinterpret_cast<const RecordPrefix *>(Data.data());
59 static_cast<TypeRecordKind>(uint16_t(Prefix->RecordKind));
62 if (auto EC = deserializeAs<T>(CVT, Record))
67 Error visitTypeBegin(CVType &Record) override {
68 assert(!Mapping && "Already in a type mapping!");
69 Mapping = llvm::make_unique<MappingInfo>(Record.content());
70 return Mapping->Mapping.visitTypeBegin(Record);
73 Error visitTypeBegin(CVType &Record, TypeIndex Index) override {
74 return visitTypeBegin(Record);
77 Error visitTypeEnd(CVType &Record) override {
78 assert(Mapping && "Not in a type mapping!");
79 auto EC = Mapping->Mapping.visitTypeEnd(Record);
84 #define TYPE_RECORD(EnumName, EnumVal, Name) \
85 Error visitKnownRecord(CVType &CVR, Name##Record &Record) override { \
86 return visitKnownRecordImpl<Name##Record>(CVR, Record); \
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"
94 template <typename RecordType>
95 Error visitKnownRecordImpl(CVType &CVR, RecordType &Record) {
96 return Mapping->Mapping.visitKnownRecord(CVR, Record);
99 std::unique_ptr<MappingInfo> Mapping;
102 class FieldListDeserializer : public TypeVisitorCallbacks {
104 explicit MappingInfo(BinaryStreamReader &R)
105 : Reader(R), Mapping(Reader), StartOffset(0) {}
107 BinaryStreamReader &Reader;
108 TypeRecordMapping Mapping;
109 uint32_t StartOffset;
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));
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));
125 Error visitMemberBegin(CVMemberRecord &Record) override {
126 Mapping.StartOffset = Mapping.Reader.getOffset();
127 return Mapping.Mapping.visitMemberBegin(Record);
130 Error visitMemberEnd(CVMemberRecord &Record) override {
131 if (auto EC = Mapping.Mapping.visitMemberEnd(Record))
133 return Error::success();
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); \
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"
146 template <typename RecordType>
147 Error visitKnownMemberImpl(CVMemberRecord &CVR, RecordType &Record) {
148 if (auto EC = Mapping.Mapping.visitKnownMember(CVR, Record))
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))
156 assert(Mapping.Reader.getOffset() == EndOffset);
157 return Error::success();
162 } // end namespace codeview
163 } // end namespace llvm
165 #endif // LLVM_DEBUGINFO_CODEVIEW_TYPEDESERIALIZER_H