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