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(Record&: CVT)) |
46 | return EC; |
47 | if (auto EC = I.Mapping.visitKnownRecord(CVT, Record)) |
48 | return EC; |
49 | if (auto EC = I.Mapping.visitTypeEnd(Record&: 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>(args: 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(Err: Mapping.Mapping.visitTypeBegin(Record&: FieldList)); |
117 | } |
118 | |
119 | ~FieldListDeserializer() override { |
120 | RecordPrefix Pre(static_cast<uint16_t>(TypeLeafKind::LF_FIELDLIST)); |
121 | CVType FieldList(&Pre, sizeof(Pre)); |
122 | consumeError(Err: Mapping.Mapping.visitTypeEnd(Record&: 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(Buffer&: CVR.Data, Size: 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 | |