1311116Sdim//===- TypeDeserializer.h ---------------------------------------*- C++ -*-===//
2311116Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6311116Sdim//
7311116Sdim//===----------------------------------------------------------------------===//
8311116Sdim
9311116Sdim#ifndef LLVM_DEBUGINFO_CODEVIEW_TYPEDESERIALIZER_H
10311116Sdim#define LLVM_DEBUGINFO_CODEVIEW_TYPEDESERIALIZER_H
11311116Sdim
12311116Sdim#include "llvm/ADT/ArrayRef.h"
13311116Sdim#include "llvm/ADT/STLExtras.h"
14311116Sdim#include "llvm/DebugInfo/CodeView/CodeView.h"
15311116Sdim#include "llvm/DebugInfo/CodeView/TypeRecord.h"
16311116Sdim#include "llvm/DebugInfo/CodeView/TypeRecordMapping.h"
17311116Sdim#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
18321369Sdim#include "llvm/Support/BinaryByteStream.h"
19321369Sdim#include "llvm/Support/BinaryStreamReader.h"
20311116Sdim#include "llvm/Support/Error.h"
21311116Sdim#include <cassert>
22311116Sdim#include <cstdint>
23311116Sdim#include <memory>
24311116Sdim
25311116Sdimnamespace llvm {
26311116Sdimnamespace codeview {
27311116Sdim
28311116Sdimclass TypeDeserializer : public TypeVisitorCallbacks {
29311116Sdim  struct MappingInfo {
30311116Sdim    explicit MappingInfo(ArrayRef<uint8_t> RecordData)
31321369Sdim        : Stream(RecordData, llvm::support::little), Reader(Stream),
32321369Sdim          Mapping(Reader) {}
33311116Sdim
34321369Sdim    BinaryByteStream Stream;
35321369Sdim    BinaryStreamReader Reader;
36311116Sdim    TypeRecordMapping Mapping;
37311116Sdim  };
38311116Sdim
39311116Sdimpublic:
40311116Sdim  TypeDeserializer() = default;
41311116Sdim
42321369Sdim  template <typename T> static Error deserializeAs(CVType &CVT, T &Record) {
43321369Sdim    Record.Kind = static_cast<TypeRecordKind>(CVT.kind());
44321369Sdim    MappingInfo I(CVT.content());
45321369Sdim    if (auto EC = I.Mapping.visitTypeBegin(CVT))
46321369Sdim      return EC;
47321369Sdim    if (auto EC = I.Mapping.visitKnownRecord(CVT, Record))
48321369Sdim      return EC;
49321369Sdim    if (auto EC = I.Mapping.visitTypeEnd(CVT))
50321369Sdim      return EC;
51321369Sdim    return Error::success();
52321369Sdim  }
53321369Sdim
54327952Sdim  template <typename T>
55327952Sdim  static Expected<T> deserializeAs(ArrayRef<uint8_t> Data) {
56327952Sdim    const RecordPrefix *Prefix =
57327952Sdim        reinterpret_cast<const RecordPrefix *>(Data.data());
58327952Sdim    TypeRecordKind K =
59327952Sdim        static_cast<TypeRecordKind>(uint16_t(Prefix->RecordKind));
60327952Sdim    T Record(K);
61353358Sdim    CVType CVT(Data);
62327952Sdim    if (auto EC = deserializeAs<T>(CVT, Record))
63327952Sdim      return std::move(EC);
64327952Sdim    return Record;
65327952Sdim  }
66327952Sdim
67311116Sdim  Error visitTypeBegin(CVType &Record) override {
68311116Sdim    assert(!Mapping && "Already in a type mapping!");
69360784Sdim    Mapping = std::make_unique<MappingInfo>(Record.content());
70311116Sdim    return Mapping->Mapping.visitTypeBegin(Record);
71311116Sdim  }
72311116Sdim
73321369Sdim  Error visitTypeBegin(CVType &Record, TypeIndex Index) override {
74321369Sdim    return visitTypeBegin(Record);
75321369Sdim  }
76321369Sdim
77311116Sdim  Error visitTypeEnd(CVType &Record) override {
78311116Sdim    assert(Mapping && "Not in a type mapping!");
79311116Sdim    auto EC = Mapping->Mapping.visitTypeEnd(Record);
80311116Sdim    Mapping.reset();
81311116Sdim    return EC;
82311116Sdim  }
83311116Sdim
84311116Sdim#define TYPE_RECORD(EnumName, EnumVal, Name)                                   \
85311116Sdim  Error visitKnownRecord(CVType &CVR, Name##Record &Record) override {         \
86311116Sdim    return visitKnownRecordImpl<Name##Record>(CVR, Record);                    \
87311116Sdim  }
88311116Sdim#define MEMBER_RECORD(EnumName, EnumVal, Name)
89311116Sdim#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
90311116Sdim#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
91321369Sdim#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
92311116Sdim
93311116Sdimprivate:
94311116Sdim  template <typename RecordType>
95311116Sdim  Error visitKnownRecordImpl(CVType &CVR, RecordType &Record) {
96311116Sdim    return Mapping->Mapping.visitKnownRecord(CVR, Record);
97311116Sdim  }
98311116Sdim
99311116Sdim  std::unique_ptr<MappingInfo> Mapping;
100311116Sdim};
101311116Sdim
102311116Sdimclass FieldListDeserializer : public TypeVisitorCallbacks {
103311116Sdim  struct MappingInfo {
104321369Sdim    explicit MappingInfo(BinaryStreamReader &R)
105311116Sdim        : Reader(R), Mapping(Reader), StartOffset(0) {}
106311116Sdim
107321369Sdim    BinaryStreamReader &Reader;
108311116Sdim    TypeRecordMapping Mapping;
109311116Sdim    uint32_t StartOffset;
110311116Sdim  };
111311116Sdim
112311116Sdimpublic:
113321369Sdim  explicit FieldListDeserializer(BinaryStreamReader &Reader) : Mapping(Reader) {
114353358Sdim    RecordPrefix Pre(static_cast<uint16_t>(TypeLeafKind::LF_FIELDLIST));
115353358Sdim    CVType FieldList(&Pre, sizeof(Pre));
116311116Sdim    consumeError(Mapping.Mapping.visitTypeBegin(FieldList));
117311116Sdim  }
118311116Sdim
119311116Sdim  ~FieldListDeserializer() override {
120353358Sdim    RecordPrefix Pre(static_cast<uint16_t>(TypeLeafKind::LF_FIELDLIST));
121353358Sdim    CVType FieldList(&Pre, sizeof(Pre));
122311116Sdim    consumeError(Mapping.Mapping.visitTypeEnd(FieldList));
123311116Sdim  }
124311116Sdim
125311116Sdim  Error visitMemberBegin(CVMemberRecord &Record) override {
126311116Sdim    Mapping.StartOffset = Mapping.Reader.getOffset();
127311116Sdim    return Mapping.Mapping.visitMemberBegin(Record);
128311116Sdim  }
129311116Sdim
130311116Sdim  Error visitMemberEnd(CVMemberRecord &Record) override {
131311116Sdim    if (auto EC = Mapping.Mapping.visitMemberEnd(Record))
132311116Sdim      return EC;
133311116Sdim    return Error::success();
134311116Sdim  }
135311116Sdim
136311116Sdim#define TYPE_RECORD(EnumName, EnumVal, Name)
137311116Sdim#define MEMBER_RECORD(EnumName, EnumVal, Name)                                 \
138311116Sdim  Error visitKnownMember(CVMemberRecord &CVR, Name##Record &Record) override { \
139311116Sdim    return visitKnownMemberImpl<Name##Record>(CVR, Record);                    \
140311116Sdim  }
141311116Sdim#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
142311116Sdim#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
143321369Sdim#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
144311116Sdim
145311116Sdimprivate:
146311116Sdim  template <typename RecordType>
147311116Sdim  Error visitKnownMemberImpl(CVMemberRecord &CVR, RecordType &Record) {
148311116Sdim    if (auto EC = Mapping.Mapping.visitKnownMember(CVR, Record))
149311116Sdim      return EC;
150311116Sdim
151311116Sdim    uint32_t EndOffset = Mapping.Reader.getOffset();
152311116Sdim    uint32_t RecordLength = EndOffset - Mapping.StartOffset;
153311116Sdim    Mapping.Reader.setOffset(Mapping.StartOffset);
154311116Sdim    if (auto EC = Mapping.Reader.readBytes(CVR.Data, RecordLength))
155311116Sdim      return EC;
156311116Sdim    assert(Mapping.Reader.getOffset() == EndOffset);
157311116Sdim    return Error::success();
158311116Sdim  }
159311116Sdim  MappingInfo Mapping;
160311116Sdim};
161311116Sdim
162311116Sdim} // end namespace codeview
163311116Sdim} // end namespace llvm
164311116Sdim
165311116Sdim#endif // LLVM_DEBUGINFO_CODEVIEW_TYPEDESERIALIZER_H
166