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
= std::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