1//===- RecordSerialization.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_RECORDSERIALIZATION_H
10#define LLVM_DEBUGINFO_CODEVIEW_RECORDSERIALIZATION_H
11
12#include "llvm/ADT/APSInt.h"
13#include "llvm/ADT/ArrayRef.h"
14#include "llvm/ADT/StringRef.h"
15#include "llvm/DebugInfo/CodeView/CodeView.h"
16#include "llvm/DebugInfo/CodeView/CodeViewError.h"
17#include "llvm/Support/BinaryStreamReader.h"
18#include "llvm/Support/Endian.h"
19#include "llvm/Support/Error.h"
20#include <cinttypes>
21#include <tuple>
22
23namespace llvm {
24namespace codeview {
25using llvm::support::little32_t;
26using llvm::support::ulittle16_t;
27using llvm::support::ulittle32_t;
28
29/// Limit on the size of all codeview symbol and type records, including the
30/// RecordPrefix. MSVC does not emit any records larger than this.
31enum : unsigned { MaxRecordLength = 0xFF00 };
32
33struct RecordPrefix {
34  RecordPrefix() = default;
35  explicit RecordPrefix(uint16_t Kind) : RecordLen(2), RecordKind(Kind) {}
36
37  ulittle16_t RecordLen;  // Record length, starting from &RecordKind.
38  ulittle16_t RecordKind; // Record kind enum (SymRecordKind or TypeRecordKind)
39};
40
41/// Reinterpret a byte array as an array of characters. Does not interpret as
42/// a C string, as StringRef has several helpers (split) that make that easy.
43StringRef getBytesAsCharacters(ArrayRef<uint8_t> LeafData);
44StringRef getBytesAsCString(ArrayRef<uint8_t> LeafData);
45
46inline Error consume(BinaryStreamReader &Reader) { return Error::success(); }
47
48/// Decodes a numeric "leaf" value. These are integer literals encountered in
49/// the type stream. If the value is positive and less than LF_NUMERIC (1 <<
50/// 15), it is emitted directly in Data. Otherwise, it has a tag like LF_CHAR
51/// that indicates the bitwidth and sign of the numeric data.
52Error consume(BinaryStreamReader &Reader, APSInt &Num);
53
54/// Decodes a numeric leaf value that is known to be a particular type.
55Error consume_numeric(BinaryStreamReader &Reader, uint64_t &Value);
56
57/// Decodes signed and unsigned fixed-length integers.
58Error consume(BinaryStreamReader &Reader, uint32_t &Item);
59Error consume(BinaryStreamReader &Reader, int32_t &Item);
60
61/// Decodes a null terminated string.
62Error consume(BinaryStreamReader &Reader, StringRef &Item);
63
64Error consume(StringRef &Data, APSInt &Num);
65Error consume(StringRef &Data, uint32_t &Item);
66
67/// Decodes an arbitrary object whose layout matches that of the underlying
68/// byte sequence, and returns a pointer to the object.
69template <typename T> Error consume(BinaryStreamReader &Reader, T *&Item) {
70  return Reader.readObject(Item);
71}
72
73template <typename T, typename U> struct serialize_conditional_impl {
74  serialize_conditional_impl(T &Item, U Func) : Item(Item), Func(Func) {}
75
76  Error deserialize(BinaryStreamReader &Reader) const {
77    if (!Func())
78      return Error::success();
79    return consume(Reader, Item);
80  }
81
82  T &Item;
83  U Func;
84};
85
86template <typename T, typename U>
87serialize_conditional_impl<T, U> serialize_conditional(T &Item, U Func) {
88  return serialize_conditional_impl<T, U>(Item, Func);
89}
90
91template <typename T, typename U> struct serialize_array_impl {
92  serialize_array_impl(ArrayRef<T> &Item, U Func) : Item(Item), Func(Func) {}
93
94  Error deserialize(BinaryStreamReader &Reader) const {
95    return Reader.readArray(Item, Func());
96  }
97
98  ArrayRef<T> &Item;
99  U Func;
100};
101
102template <typename T> struct serialize_vector_tail_impl {
103  serialize_vector_tail_impl(std::vector<T> &Item) : Item(Item) {}
104
105  Error deserialize(BinaryStreamReader &Reader) const {
106    T Field;
107    // Stop when we run out of bytes or we hit record padding bytes.
108    while (!Reader.empty() && Reader.peek() < LF_PAD0) {
109      if (auto EC = consume(Reader, Field))
110        return EC;
111      Item.push_back(Field);
112    }
113    return Error::success();
114  }
115
116  std::vector<T> &Item;
117};
118
119struct serialize_null_term_string_array_impl {
120  serialize_null_term_string_array_impl(std::vector<StringRef> &Item)
121      : Item(Item) {}
122
123  Error deserialize(BinaryStreamReader &Reader) const {
124    if (Reader.empty())
125      return make_error<CodeViewError>(cv_error_code::insufficient_buffer,
126                                       "Null terminated string is empty!");
127
128    while (Reader.peek() != 0) {
129      StringRef Field;
130      if (auto EC = Reader.readCString(Field))
131        return EC;
132      Item.push_back(Field);
133    }
134    return Reader.skip(1);
135  }
136
137  std::vector<StringRef> &Item;
138};
139
140template <typename T> struct serialize_arrayref_tail_impl {
141  serialize_arrayref_tail_impl(ArrayRef<T> &Item) : Item(Item) {}
142
143  Error deserialize(BinaryStreamReader &Reader) const {
144    uint32_t Count = Reader.bytesRemaining() / sizeof(T);
145    return Reader.readArray(Item, Count);
146  }
147
148  ArrayRef<T> &Item;
149};
150
151template <typename T> struct serialize_numeric_impl {
152  serialize_numeric_impl(T &Item) : Item(Item) {}
153
154  Error deserialize(BinaryStreamReader &Reader) const {
155    return consume_numeric(Reader, Item);
156  }
157
158  T &Item;
159};
160
161template <typename T, typename U>
162serialize_array_impl<T, U> serialize_array(ArrayRef<T> &Item, U Func) {
163  return serialize_array_impl<T, U>(Item, Func);
164}
165
166inline serialize_null_term_string_array_impl
167serialize_null_term_string_array(std::vector<StringRef> &Item) {
168  return serialize_null_term_string_array_impl(Item);
169}
170
171template <typename T>
172serialize_vector_tail_impl<T> serialize_array_tail(std::vector<T> &Item) {
173  return serialize_vector_tail_impl<T>(Item);
174}
175
176template <typename T>
177serialize_arrayref_tail_impl<T> serialize_array_tail(ArrayRef<T> &Item) {
178  return serialize_arrayref_tail_impl<T>(Item);
179}
180
181template <typename T> serialize_numeric_impl<T> serialize_numeric(T &Item) {
182  return serialize_numeric_impl<T>(Item);
183}
184
185template <typename T, typename U>
186Error consume(BinaryStreamReader &Reader,
187              const serialize_conditional_impl<T, U> &Item) {
188  return Item.deserialize(Reader);
189}
190
191template <typename T, typename U>
192Error consume(BinaryStreamReader &Reader,
193              const serialize_array_impl<T, U> &Item) {
194  return Item.deserialize(Reader);
195}
196
197inline Error consume(BinaryStreamReader &Reader,
198                     const serialize_null_term_string_array_impl &Item) {
199  return Item.deserialize(Reader);
200}
201
202template <typename T>
203Error consume(BinaryStreamReader &Reader,
204              const serialize_vector_tail_impl<T> &Item) {
205  return Item.deserialize(Reader);
206}
207
208template <typename T>
209Error consume(BinaryStreamReader &Reader,
210              const serialize_arrayref_tail_impl<T> &Item) {
211  return Item.deserialize(Reader);
212}
213
214template <typename T>
215Error consume(BinaryStreamReader &Reader,
216              const serialize_numeric_impl<T> &Item) {
217  return Item.deserialize(Reader);
218}
219
220template <typename T, typename U, typename... Args>
221Error consume(BinaryStreamReader &Reader, T &&X, U &&Y, Args &&... Rest) {
222  if (auto EC = consume(Reader, X))
223    return EC;
224  return consume(Reader, Y, std::forward<Args>(Rest)...);
225}
226
227}
228}
229
230#endif
231