1 //===- RecordSerialization.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_RECORDSERIALIZATION_H
10 #define LLVM_DEBUGINFO_CODEVIEW_RECORDSERIALIZATION_H
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"
25 using llvm::support::little32_t
;
26 using llvm::support::ulittle16_t
;
27 using llvm::support::ulittle32_t
;
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.
31 enum : unsigned { MaxRecordLength
= 0xFF00 };
34 ulittle16_t RecordLen
; // Record length, starting from &RecordKind.
35 ulittle16_t RecordKind
; // Record kind enum (SymRecordKind or TypeRecordKind)
38 /// Reinterpret a byte array as an array of characters. Does not interpret as
39 /// a C string, as StringRef has several helpers (split) that make that easy.
40 StringRef
getBytesAsCharacters(ArrayRef
<uint8_t> LeafData
);
41 StringRef
getBytesAsCString(ArrayRef
<uint8_t> LeafData
);
43 inline Error
consume(BinaryStreamReader
&Reader
) { return Error::success(); }
45 /// Decodes a numeric "leaf" value. These are integer literals encountered in
46 /// the type stream. If the value is positive and less than LF_NUMERIC (1 <<
47 /// 15), it is emitted directly in Data. Otherwise, it has a tag like LF_CHAR
48 /// that indicates the bitwidth and sign of the numeric data.
49 Error
consume(BinaryStreamReader
&Reader
, APSInt
&Num
);
51 /// Decodes a numeric leaf value that is known to be a particular type.
52 Error
consume_numeric(BinaryStreamReader
&Reader
, uint64_t &Value
);
54 /// Decodes signed and unsigned fixed-length integers.
55 Error
consume(BinaryStreamReader
&Reader
, uint32_t &Item
);
56 Error
consume(BinaryStreamReader
&Reader
, int32_t &Item
);
58 /// Decodes a null terminated string.
59 Error
consume(BinaryStreamReader
&Reader
, StringRef
&Item
);
61 Error
consume(StringRef
&Data
, APSInt
&Num
);
62 Error
consume(StringRef
&Data
, uint32_t &Item
);
64 /// Decodes an arbitrary object whose layout matches that of the underlying
65 /// byte sequence, and returns a pointer to the object.
66 template <typename T
> Error
consume(BinaryStreamReader
&Reader
, T
*&Item
) {
67 return Reader
.readObject(Item
);
70 template <typename T
, typename U
> struct serialize_conditional_impl
{
71 serialize_conditional_impl(T
&Item
, U Func
) : Item(Item
), Func(Func
) {}
73 Error
deserialize(BinaryStreamReader
&Reader
) const {
75 return Error::success();
76 return consume(Reader
, Item
);
83 template <typename T
, typename U
>
84 serialize_conditional_impl
<T
, U
> serialize_conditional(T
&Item
, U Func
) {
85 return serialize_conditional_impl
<T
, U
>(Item
, Func
);
88 template <typename T
, typename U
> struct serialize_array_impl
{
89 serialize_array_impl(ArrayRef
<T
> &Item
, U Func
) : Item(Item
), Func(Func
) {}
91 Error
deserialize(BinaryStreamReader
&Reader
) const {
92 return Reader
.readArray(Item
, Func());
99 template <typename T
> struct serialize_vector_tail_impl
{
100 serialize_vector_tail_impl(std::vector
<T
> &Item
) : Item(Item
) {}
102 Error
deserialize(BinaryStreamReader
&Reader
) const {
104 // Stop when we run out of bytes or we hit record padding bytes.
105 while (!Reader
.empty() && Reader
.peek() < LF_PAD0
) {
106 if (auto EC
= consume(Reader
, Field
))
108 Item
.push_back(Field
);
110 return Error::success();
113 std::vector
<T
> &Item
;
116 struct serialize_null_term_string_array_impl
{
117 serialize_null_term_string_array_impl(std::vector
<StringRef
> &Item
)
120 Error
deserialize(BinaryStreamReader
&Reader
) const {
122 return make_error
<CodeViewError
>(cv_error_code::insufficient_buffer
,
123 "Null terminated string is empty!");
125 while (Reader
.peek() != 0) {
127 if (auto EC
= Reader
.readCString(Field
))
129 Item
.push_back(Field
);
131 return Reader
.skip(1);
134 std::vector
<StringRef
> &Item
;
137 template <typename T
> struct serialize_arrayref_tail_impl
{
138 serialize_arrayref_tail_impl(ArrayRef
<T
> &Item
) : Item(Item
) {}
140 Error
deserialize(BinaryStreamReader
&Reader
) const {
141 uint32_t Count
= Reader
.bytesRemaining() / sizeof(T
);
142 return Reader
.readArray(Item
, Count
);
148 template <typename T
> struct serialize_numeric_impl
{
149 serialize_numeric_impl(T
&Item
) : Item(Item
) {}
151 Error
deserialize(BinaryStreamReader
&Reader
) const {
152 return consume_numeric(Reader
, Item
);
158 template <typename T
, typename U
>
159 serialize_array_impl
<T
, U
> serialize_array(ArrayRef
<T
> &Item
, U Func
) {
160 return serialize_array_impl
<T
, U
>(Item
, Func
);
163 inline serialize_null_term_string_array_impl
164 serialize_null_term_string_array(std::vector
<StringRef
> &Item
) {
165 return serialize_null_term_string_array_impl(Item
);
168 template <typename T
>
169 serialize_vector_tail_impl
<T
> serialize_array_tail(std::vector
<T
> &Item
) {
170 return serialize_vector_tail_impl
<T
>(Item
);
173 template <typename T
>
174 serialize_arrayref_tail_impl
<T
> serialize_array_tail(ArrayRef
<T
> &Item
) {
175 return serialize_arrayref_tail_impl
<T
>(Item
);
178 template <typename T
> serialize_numeric_impl
<T
> serialize_numeric(T
&Item
) {
179 return serialize_numeric_impl
<T
>(Item
);
182 template <typename T
, typename U
>
183 Error
consume(BinaryStreamReader
&Reader
,
184 const serialize_conditional_impl
<T
, U
> &Item
) {
185 return Item
.deserialize(Reader
);
188 template <typename T
, typename U
>
189 Error
consume(BinaryStreamReader
&Reader
,
190 const serialize_array_impl
<T
, U
> &Item
) {
191 return Item
.deserialize(Reader
);
194 inline Error
consume(BinaryStreamReader
&Reader
,
195 const serialize_null_term_string_array_impl
&Item
) {
196 return Item
.deserialize(Reader
);
199 template <typename T
>
200 Error
consume(BinaryStreamReader
&Reader
,
201 const serialize_vector_tail_impl
<T
> &Item
) {
202 return Item
.deserialize(Reader
);
205 template <typename T
>
206 Error
consume(BinaryStreamReader
&Reader
,
207 const serialize_arrayref_tail_impl
<T
> &Item
) {
208 return Item
.deserialize(Reader
);
211 template <typename T
>
212 Error
consume(BinaryStreamReader
&Reader
,
213 const serialize_numeric_impl
<T
> &Item
) {
214 return Item
.deserialize(Reader
);
217 template <typename T
, typename U
, typename
... Args
>
218 Error
consume(BinaryStreamReader
&Reader
, T
&&X
, U
&&Y
, Args
&&... Rest
) {
219 if (auto EC
= consume(Reader
, X
))
221 return consume(Reader
, Y
, std::forward
<Args
>(Rest
)...);