TypeDeserializer.h revision 360784
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
25namespace llvm {
26namespace codeview {
27
28class TypeDeserializer : public TypeVisitorCallbacks {
29  struct MappingInfo {
30    explicit MappingInfo(ArrayRef<uint8_t> RecordData)
31        : Stream(RecordData, llvm::support::little), Reader(Stream),
32          Mapping(Reader) {}
33
34    BinaryByteStream Stream;
35    BinaryStreamReader Reader;
36    TypeRecordMapping Mapping;
37  };
38
39public:
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
93private:
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
102class 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
112public:
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
145private:
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