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 RecordPrefix() = default;
35 explicit RecordPrefix(uint16_t Kind
) : RecordLen(2), RecordKind(Kind
) {}
37 ulittle16_t RecordLen
; // Record length, starting from &RecordKind.
38 ulittle16_t RecordKind
; // Record kind enum (SymRecordKind or TypeRecordKind)
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.
43 StringRef
getBytesAsCharacters(ArrayRef
<uint8_t> LeafData
);
44 StringRef
getBytesAsCString(ArrayRef
<uint8_t> LeafData
);
46 inline Error
consume(BinaryStreamReader
&Reader
) { return Error::success(); }
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.
52 Error
consume(BinaryStreamReader
&Reader
, APSInt
&Num
);
54 /// Decodes a numeric leaf value that is known to be a particular type.
55 Error
consume_numeric(BinaryStreamReader
&Reader
, uint64_t &Value
);
57 /// Decodes signed and unsigned fixed-length integers.
58 Error
consume(BinaryStreamReader
&Reader
, uint32_t &Item
);
59 Error
consume(BinaryStreamReader
&Reader
, int32_t &Item
);
61 /// Decodes a null terminated string.
62 Error
consume(BinaryStreamReader
&Reader
, StringRef
&Item
);
64 Error
consume(StringRef
&Data
, APSInt
&Num
);
65 Error
consume(StringRef
&Data
, uint32_t &Item
);
67 /// Decodes an arbitrary object whose layout matches that of the underlying
68 /// byte sequence, and returns a pointer to the object.
69 template <typename T
> Error
consume(BinaryStreamReader
&Reader
, T
*&Item
) {
70 return Reader
.readObject(Item
);
73 template <typename T
, typename U
> struct serialize_conditional_impl
{
74 serialize_conditional_impl(T
&Item
, U Func
) : Item(Item
), Func(Func
) {}
76 Error
deserialize(BinaryStreamReader
&Reader
) const {
78 return Error::success();
79 return consume(Reader
, Item
);
86 template <typename T
, typename U
>
87 serialize_conditional_impl
<T
, U
> serialize_conditional(T
&Item
, U Func
) {
88 return serialize_conditional_impl
<T
, U
>(Item
, Func
);
91 template <typename T
, typename U
> struct serialize_array_impl
{
92 serialize_array_impl(ArrayRef
<T
> &Item
, U Func
) : Item(Item
), Func(Func
) {}
94 Error
deserialize(BinaryStreamReader
&Reader
) const {
95 return Reader
.readArray(Item
, Func());
102 template <typename T
> struct serialize_vector_tail_impl
{
103 serialize_vector_tail_impl(std::vector
<T
> &Item
) : Item(Item
) {}
105 Error
deserialize(BinaryStreamReader
&Reader
) const {
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
))
111 Item
.push_back(Field
);
113 return Error::success();
116 std::vector
<T
> &Item
;
119 struct serialize_null_term_string_array_impl
{
120 serialize_null_term_string_array_impl(std::vector
<StringRef
> &Item
)
123 Error
deserialize(BinaryStreamReader
&Reader
) const {
125 return make_error
<CodeViewError
>(cv_error_code::insufficient_buffer
,
126 "Null terminated string is empty!");
128 while (Reader
.peek() != 0) {
130 if (auto EC
= Reader
.readCString(Field
))
132 Item
.push_back(Field
);
134 return Reader
.skip(1);
137 std::vector
<StringRef
> &Item
;
140 template <typename T
> struct serialize_arrayref_tail_impl
{
141 serialize_arrayref_tail_impl(ArrayRef
<T
> &Item
) : Item(Item
) {}
143 Error
deserialize(BinaryStreamReader
&Reader
) const {
144 uint32_t Count
= Reader
.bytesRemaining() / sizeof(T
);
145 return Reader
.readArray(Item
, Count
);
151 template <typename T
> struct serialize_numeric_impl
{
152 serialize_numeric_impl(T
&Item
) : Item(Item
) {}
154 Error
deserialize(BinaryStreamReader
&Reader
) const {
155 return consume_numeric(Reader
, Item
);
161 template <typename T
, typename U
>
162 serialize_array_impl
<T
, U
> serialize_array(ArrayRef
<T
> &Item
, U Func
) {
163 return serialize_array_impl
<T
, U
>(Item
, Func
);
166 inline serialize_null_term_string_array_impl
167 serialize_null_term_string_array(std::vector
<StringRef
> &Item
) {
168 return serialize_null_term_string_array_impl(Item
);
171 template <typename T
>
172 serialize_vector_tail_impl
<T
> serialize_array_tail(std::vector
<T
> &Item
) {
173 return serialize_vector_tail_impl
<T
>(Item
);
176 template <typename T
>
177 serialize_arrayref_tail_impl
<T
> serialize_array_tail(ArrayRef
<T
> &Item
) {
178 return serialize_arrayref_tail_impl
<T
>(Item
);
181 template <typename T
> serialize_numeric_impl
<T
> serialize_numeric(T
&Item
) {
182 return serialize_numeric_impl
<T
>(Item
);
185 template <typename T
, typename U
>
186 Error
consume(BinaryStreamReader
&Reader
,
187 const serialize_conditional_impl
<T
, U
> &Item
) {
188 return Item
.deserialize(Reader
);
191 template <typename T
, typename U
>
192 Error
consume(BinaryStreamReader
&Reader
,
193 const serialize_array_impl
<T
, U
> &Item
) {
194 return Item
.deserialize(Reader
);
197 inline Error
consume(BinaryStreamReader
&Reader
,
198 const serialize_null_term_string_array_impl
&Item
) {
199 return Item
.deserialize(Reader
);
202 template <typename T
>
203 Error
consume(BinaryStreamReader
&Reader
,
204 const serialize_vector_tail_impl
<T
> &Item
) {
205 return Item
.deserialize(Reader
);
208 template <typename T
>
209 Error
consume(BinaryStreamReader
&Reader
,
210 const serialize_arrayref_tail_impl
<T
> &Item
) {
211 return Item
.deserialize(Reader
);
214 template <typename T
>
215 Error
consume(BinaryStreamReader
&Reader
,
216 const serialize_numeric_impl
<T
> &Item
) {
217 return Item
.deserialize(Reader
);
220 template <typename T
, typename U
, typename
... Args
>
221 Error
consume(BinaryStreamReader
&Reader
, T
&&X
, U
&&Y
, Args
&&... Rest
) {
222 if (auto EC
= consume(Reader
, X
))
224 return consume(Reader
, Y
, std::forward
<Args
>(Rest
)...);