1 | //===- CodeViewRecordIO.cpp -------------------------------------*- 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 | #include "llvm/DebugInfo/CodeView/CodeViewRecordIO.h" |
10 | #include "llvm/ADT/StringExtras.h" |
11 | #include "llvm/DebugInfo/CodeView/CodeView.h" |
12 | #include "llvm/DebugInfo/CodeView/GUID.h" |
13 | #include "llvm/DebugInfo/CodeView/RecordSerialization.h" |
14 | #include "llvm/DebugInfo/CodeView/TypeIndex.h" |
15 | #include "llvm/Support/BinaryStreamReader.h" |
16 | #include "llvm/Support/BinaryStreamWriter.h" |
17 | |
18 | using namespace llvm; |
19 | using namespace llvm::codeview; |
20 | |
21 | Error CodeViewRecordIO::beginRecord(std::optional<uint32_t> MaxLength) { |
22 | RecordLimit Limit; |
23 | Limit.MaxLength = MaxLength; |
24 | Limit.BeginOffset = getCurrentOffset(); |
25 | Limits.push_back(Elt: Limit); |
26 | return Error::success(); |
27 | } |
28 | |
29 | Error CodeViewRecordIO::endRecord() { |
30 | assert(!Limits.empty() && "Not in a record!" ); |
31 | Limits.pop_back(); |
32 | // We would like to assert that we actually read / wrote all the bytes that we |
33 | // expected to for this record, but unfortunately we can't do this. Some |
34 | // producers such as MASM over-allocate for certain types of records and |
35 | // commit the extraneous data, so when reading we can't be sure every byte |
36 | // will have been read. And when writing we over-allocate temporarily since |
37 | // we don't know how big the record is until we're finished writing it, so |
38 | // even though we don't commit the extraneous data, we still can't guarantee |
39 | // we're at the end of the allocated data. |
40 | |
41 | if (isStreaming()) { |
42 | // For streaming mode, add padding to align with 4 byte boundaries for each |
43 | // record |
44 | uint32_t Align = getStreamedLen() % 4; |
45 | if (Align == 0) |
46 | return Error::success(); |
47 | |
48 | int PaddingBytes = 4 - Align; |
49 | while (PaddingBytes > 0) { |
50 | char Pad = static_cast<uint8_t>(LF_PAD0 + PaddingBytes); |
51 | StringRef BytesSR = StringRef(&Pad, sizeof(Pad)); |
52 | Streamer->emitBytes(Data: BytesSR); |
53 | --PaddingBytes; |
54 | } |
55 | resetStreamedLen(); |
56 | } |
57 | return Error::success(); |
58 | } |
59 | |
60 | uint32_t CodeViewRecordIO::maxFieldLength() const { |
61 | if (isStreaming()) |
62 | return 0; |
63 | |
64 | assert(!Limits.empty() && "Not in a record!" ); |
65 | |
66 | // The max length of the next field is the minimum of all lengths that would |
67 | // be allowed by any of the sub-records we're in. In practice, we can only |
68 | // ever be at most 1 sub-record deep (in a FieldList), but this works for |
69 | // the general case. |
70 | uint32_t Offset = getCurrentOffset(); |
71 | std::optional<uint32_t> Min = Limits.front().bytesRemaining(CurrentOffset: Offset); |
72 | for (auto X : ArrayRef(Limits).drop_front()) { |
73 | std::optional<uint32_t> ThisMin = X.bytesRemaining(CurrentOffset: Offset); |
74 | if (ThisMin) |
75 | Min = Min ? std::min(a: *Min, b: *ThisMin) : *ThisMin; |
76 | } |
77 | assert(Min && "Every field must have a maximum length!" ); |
78 | |
79 | return *Min; |
80 | } |
81 | |
82 | Error CodeViewRecordIO::padToAlignment(uint32_t Align) { |
83 | if (isReading()) |
84 | return Reader->padToAlignment(Align); |
85 | return Writer->padToAlignment(Align); |
86 | } |
87 | |
88 | Error CodeViewRecordIO::skipPadding() { |
89 | assert(!isWriting() && "Cannot skip padding while writing!" ); |
90 | |
91 | if (Reader->bytesRemaining() == 0) |
92 | return Error::success(); |
93 | |
94 | uint8_t Leaf = Reader->peek(); |
95 | if (Leaf < LF_PAD0) |
96 | return Error::success(); |
97 | // Leaf is greater than 0xf0. We should advance by the number of bytes in |
98 | // the low 4 bits. |
99 | unsigned BytesToAdvance = Leaf & 0x0F; |
100 | return Reader->skip(Amount: BytesToAdvance); |
101 | } |
102 | |
103 | Error CodeViewRecordIO::mapByteVectorTail(ArrayRef<uint8_t> &Bytes, |
104 | const Twine &) { |
105 | if (isStreaming()) { |
106 | emitComment(Comment); |
107 | Streamer->emitBinaryData(Data: toStringRef(Input: Bytes)); |
108 | incrStreamedLen(Len: Bytes.size()); |
109 | } else if (isWriting()) { |
110 | if (auto EC = Writer->writeBytes(Buffer: Bytes)) |
111 | return EC; |
112 | } else { |
113 | if (auto EC = Reader->readBytes(Buffer&: Bytes, Size: Reader->bytesRemaining())) |
114 | return EC; |
115 | } |
116 | return Error::success(); |
117 | } |
118 | |
119 | Error CodeViewRecordIO::mapByteVectorTail(std::vector<uint8_t> &Bytes, |
120 | const Twine &) { |
121 | ArrayRef<uint8_t> BytesRef(Bytes); |
122 | if (auto EC = mapByteVectorTail(Bytes&: BytesRef, Comment)) |
123 | return EC; |
124 | if (!isWriting()) |
125 | Bytes.assign(first: BytesRef.begin(), last: BytesRef.end()); |
126 | |
127 | return Error::success(); |
128 | } |
129 | |
130 | Error CodeViewRecordIO::mapInteger(TypeIndex &TypeInd, const Twine &) { |
131 | if (isStreaming()) { |
132 | std::string TypeNameStr = Streamer->getTypeName(TI: TypeInd); |
133 | if (!TypeNameStr.empty()) |
134 | emitComment(Comment: Comment + ": " + TypeNameStr); |
135 | else |
136 | emitComment(Comment); |
137 | Streamer->emitIntValue(Value: TypeInd.getIndex(), Size: sizeof(TypeInd.getIndex())); |
138 | incrStreamedLen(Len: sizeof(TypeInd.getIndex())); |
139 | } else if (isWriting()) { |
140 | if (auto EC = Writer->writeInteger(Value: TypeInd.getIndex())) |
141 | return EC; |
142 | } else { |
143 | uint32_t I; |
144 | if (auto EC = Reader->readInteger(Dest&: I)) |
145 | return EC; |
146 | TypeInd.setIndex(I); |
147 | } |
148 | return Error::success(); |
149 | } |
150 | |
151 | Error CodeViewRecordIO::mapEncodedInteger(int64_t &Value, |
152 | const Twine &) { |
153 | if (isStreaming()) { |
154 | if (Value >= 0) |
155 | emitEncodedUnsignedInteger(Value: static_cast<uint64_t>(Value), Comment); |
156 | else |
157 | emitEncodedSignedInteger(Value, Comment); |
158 | } else if (isWriting()) { |
159 | if (Value >= 0) { |
160 | if (auto EC = writeEncodedUnsignedInteger(Value: static_cast<uint64_t>(Value))) |
161 | return EC; |
162 | } else { |
163 | if (auto EC = writeEncodedSignedInteger(Value)) |
164 | return EC; |
165 | } |
166 | } else { |
167 | APSInt N; |
168 | if (auto EC = consume(Reader&: *Reader, Num&: N)) |
169 | return EC; |
170 | Value = N.getExtValue(); |
171 | } |
172 | |
173 | return Error::success(); |
174 | } |
175 | |
176 | Error CodeViewRecordIO::mapEncodedInteger(uint64_t &Value, |
177 | const Twine &) { |
178 | if (isStreaming()) |
179 | emitEncodedUnsignedInteger(Value, Comment); |
180 | else if (isWriting()) { |
181 | if (auto EC = writeEncodedUnsignedInteger(Value)) |
182 | return EC; |
183 | } else { |
184 | APSInt N; |
185 | if (auto EC = consume(Reader&: *Reader, Num&: N)) |
186 | return EC; |
187 | Value = N.getZExtValue(); |
188 | } |
189 | return Error::success(); |
190 | } |
191 | |
192 | Error CodeViewRecordIO::mapEncodedInteger(APSInt &Value, const Twine &) { |
193 | if (isStreaming()) { |
194 | // FIXME: We also need to handle big values here, but it's |
195 | // not clear how we can excercise this code path yet. |
196 | if (Value.isSigned()) |
197 | emitEncodedSignedInteger(Value: Value.getSExtValue(), Comment); |
198 | else |
199 | emitEncodedUnsignedInteger(Value: Value.getZExtValue(), Comment); |
200 | } else if (isWriting()) { |
201 | if (Value.isSigned()) |
202 | return writeEncodedSignedInteger( |
203 | Value: Value.isSingleWord() ? Value.getSExtValue() : INT64_MIN); |
204 | return writeEncodedUnsignedInteger(Value: Value.getLimitedValue()); |
205 | } else |
206 | return consume(Reader&: *Reader, Num&: Value); |
207 | return Error::success(); |
208 | } |
209 | |
210 | Error CodeViewRecordIO::mapStringZ(StringRef &Value, const Twine &) { |
211 | if (isStreaming()) { |
212 | auto NullTerminatedString = StringRef(Value.data(), Value.size() + 1); |
213 | emitComment(Comment); |
214 | Streamer->emitBytes(Data: NullTerminatedString); |
215 | incrStreamedLen(Len: NullTerminatedString.size()); |
216 | } else if (isWriting()) { |
217 | // Truncate if we attempt to write too much. |
218 | StringRef S = Value.take_front(N: maxFieldLength() - 1); |
219 | if (auto EC = Writer->writeCString(Str: S)) |
220 | return EC; |
221 | } else { |
222 | if (auto EC = Reader->readCString(Dest&: Value)) |
223 | return EC; |
224 | } |
225 | return Error::success(); |
226 | } |
227 | |
228 | Error CodeViewRecordIO::mapGuid(GUID &Guid, const Twine &) { |
229 | constexpr uint32_t GuidSize = 16; |
230 | |
231 | if (isStreaming()) { |
232 | StringRef GuidSR = |
233 | StringRef((reinterpret_cast<const char *>(&Guid)), GuidSize); |
234 | emitComment(Comment); |
235 | Streamer->emitBytes(Data: GuidSR); |
236 | incrStreamedLen(Len: GuidSize); |
237 | return Error::success(); |
238 | } |
239 | |
240 | if (maxFieldLength() < GuidSize) |
241 | return make_error<CodeViewError>(Args: cv_error_code::insufficient_buffer); |
242 | |
243 | if (isWriting()) { |
244 | if (auto EC = Writer->writeBytes(Buffer: Guid.Guid)) |
245 | return EC; |
246 | } else { |
247 | ArrayRef<uint8_t> GuidBytes; |
248 | if (auto EC = Reader->readBytes(Buffer&: GuidBytes, Size: GuidSize)) |
249 | return EC; |
250 | memcpy(dest: Guid.Guid, src: GuidBytes.data(), n: GuidSize); |
251 | } |
252 | return Error::success(); |
253 | } |
254 | |
255 | Error CodeViewRecordIO::mapStringZVectorZ(std::vector<StringRef> &Value, |
256 | const Twine &) { |
257 | |
258 | if (!isReading()) { |
259 | emitComment(Comment); |
260 | for (auto V : Value) { |
261 | if (auto EC = mapStringZ(Value&: V)) |
262 | return EC; |
263 | } |
264 | uint8_t FinalZero = 0; |
265 | if (auto EC = mapInteger(Value&: FinalZero)) |
266 | return EC; |
267 | } else { |
268 | StringRef S; |
269 | if (auto EC = mapStringZ(Value&: S)) |
270 | return EC; |
271 | while (!S.empty()) { |
272 | Value.push_back(x: S); |
273 | if (auto EC = mapStringZ(Value&: S)) |
274 | return EC; |
275 | }; |
276 | } |
277 | return Error::success(); |
278 | } |
279 | |
280 | void CodeViewRecordIO::emitEncodedSignedInteger(const int64_t &Value, |
281 | const Twine &) { |
282 | // FIXME: There are no test cases covering this function. |
283 | // This may be because we always consider enumerators to be unsigned. |
284 | // See FIXME at CodeViewDebug.cpp : CodeViewDebug::lowerTypeEnum. |
285 | if (Value < LF_NUMERIC && Value >= 0) { |
286 | emitComment(Comment); |
287 | Streamer->emitIntValue(Value, Size: 2); |
288 | incrStreamedLen(Len: 2); |
289 | } else if (Value >= std::numeric_limits<int8_t>::min() && |
290 | Value <= std::numeric_limits<int8_t>::max()) { |
291 | Streamer->emitIntValue(Value: LF_CHAR, Size: 2); |
292 | emitComment(Comment); |
293 | Streamer->emitIntValue(Value, Size: 1); |
294 | incrStreamedLen(Len: 3); |
295 | } else if (Value >= std::numeric_limits<int16_t>::min() && |
296 | Value <= std::numeric_limits<int16_t>::max()) { |
297 | Streamer->emitIntValue(Value: LF_SHORT, Size: 2); |
298 | emitComment(Comment); |
299 | Streamer->emitIntValue(Value, Size: 2); |
300 | incrStreamedLen(Len: 4); |
301 | } else if (Value >= std::numeric_limits<int32_t>::min() && |
302 | Value <= std::numeric_limits<int32_t>::max()) { |
303 | Streamer->emitIntValue(Value: LF_LONG, Size: 2); |
304 | emitComment(Comment); |
305 | Streamer->emitIntValue(Value, Size: 4); |
306 | incrStreamedLen(Len: 6); |
307 | } else { |
308 | Streamer->emitIntValue(Value: LF_QUADWORD, Size: 2); |
309 | emitComment(Comment); |
310 | Streamer->emitIntValue(Value, Size: 4); // FIXME: Why not 8 (size of quadword)? |
311 | incrStreamedLen(Len: 6); // FIXME: Why not 10 (8 + 2)? |
312 | } |
313 | } |
314 | |
315 | void CodeViewRecordIO::emitEncodedUnsignedInteger(const uint64_t &Value, |
316 | const Twine &) { |
317 | if (Value < LF_NUMERIC) { |
318 | emitComment(Comment); |
319 | Streamer->emitIntValue(Value, Size: 2); |
320 | incrStreamedLen(Len: 2); |
321 | } else if (Value <= std::numeric_limits<uint16_t>::max()) { |
322 | Streamer->emitIntValue(Value: LF_USHORT, Size: 2); |
323 | emitComment(Comment); |
324 | Streamer->emitIntValue(Value, Size: 2); |
325 | incrStreamedLen(Len: 4); |
326 | } else if (Value <= std::numeric_limits<uint32_t>::max()) { |
327 | Streamer->emitIntValue(Value: LF_ULONG, Size: 2); |
328 | emitComment(Comment); |
329 | Streamer->emitIntValue(Value, Size: 4); |
330 | incrStreamedLen(Len: 6); |
331 | } else { |
332 | // FIXME: There are no test cases covering this block. |
333 | Streamer->emitIntValue(Value: LF_UQUADWORD, Size: 2); |
334 | emitComment(Comment); |
335 | Streamer->emitIntValue(Value, Size: 8); |
336 | incrStreamedLen(Len: 6); // FIXME: Why not 10 (8 + 2)? |
337 | } |
338 | } |
339 | |
340 | Error CodeViewRecordIO::writeEncodedSignedInteger(const int64_t &Value) { |
341 | if (Value < LF_NUMERIC && Value >= 0) { |
342 | if (auto EC = Writer->writeInteger<int16_t>(Value)) |
343 | return EC; |
344 | } else if (Value >= std::numeric_limits<int8_t>::min() && |
345 | Value <= std::numeric_limits<int8_t>::max()) { |
346 | if (auto EC = Writer->writeInteger<uint16_t>(Value: LF_CHAR)) |
347 | return EC; |
348 | if (auto EC = Writer->writeInteger<int8_t>(Value)) |
349 | return EC; |
350 | } else if (Value >= std::numeric_limits<int16_t>::min() && |
351 | Value <= std::numeric_limits<int16_t>::max()) { |
352 | if (auto EC = Writer->writeInteger<uint16_t>(Value: LF_SHORT)) |
353 | return EC; |
354 | if (auto EC = Writer->writeInteger<int16_t>(Value)) |
355 | return EC; |
356 | } else if (Value >= std::numeric_limits<int32_t>::min() && |
357 | Value <= std::numeric_limits<int32_t>::max()) { |
358 | if (auto EC = Writer->writeInteger<uint16_t>(Value: LF_LONG)) |
359 | return EC; |
360 | if (auto EC = Writer->writeInteger<int32_t>(Value)) |
361 | return EC; |
362 | } else { |
363 | if (auto EC = Writer->writeInteger<uint16_t>(Value: LF_QUADWORD)) |
364 | return EC; |
365 | if (auto EC = Writer->writeInteger(Value)) |
366 | return EC; |
367 | } |
368 | return Error::success(); |
369 | } |
370 | |
371 | Error CodeViewRecordIO::writeEncodedUnsignedInteger(const uint64_t &Value) { |
372 | if (Value < LF_NUMERIC) { |
373 | if (auto EC = Writer->writeInteger<uint16_t>(Value)) |
374 | return EC; |
375 | } else if (Value <= std::numeric_limits<uint16_t>::max()) { |
376 | if (auto EC = Writer->writeInteger<uint16_t>(Value: LF_USHORT)) |
377 | return EC; |
378 | if (auto EC = Writer->writeInteger<uint16_t>(Value)) |
379 | return EC; |
380 | } else if (Value <= std::numeric_limits<uint32_t>::max()) { |
381 | if (auto EC = Writer->writeInteger<uint16_t>(Value: LF_ULONG)) |
382 | return EC; |
383 | if (auto EC = Writer->writeInteger<uint32_t>(Value)) |
384 | return EC; |
385 | } else { |
386 | if (auto EC = Writer->writeInteger<uint16_t>(Value: LF_UQUADWORD)) |
387 | return EC; |
388 | if (auto EC = Writer->writeInteger(Value)) |
389 | return EC; |
390 | } |
391 | |
392 | return Error::success(); |
393 | } |
394 | |