1 | //===-- RecordSerialization.cpp -------------------------------------------===// |
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 | // Utilities for serializing and deserializing CodeView records. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "llvm/DebugInfo/CodeView/RecordSerialization.h" |
14 | #include "llvm/ADT/APInt.h" |
15 | #include "llvm/ADT/APSInt.h" |
16 | #include "llvm/DebugInfo/CodeView/CVRecord.h" |
17 | #include "llvm/DebugInfo/CodeView/CodeViewError.h" |
18 | #include "llvm/DebugInfo/CodeView/SymbolRecord.h" |
19 | #include "llvm/Support/BinaryByteStream.h" |
20 | |
21 | using namespace llvm; |
22 | using namespace llvm::codeview; |
23 | using namespace llvm::support; |
24 | |
25 | /// Reinterpret a byte array as an array of characters. Does not interpret as |
26 | /// a C string, as StringRef has several helpers (split) that make that easy. |
27 | StringRef llvm::codeview::getBytesAsCharacters(ArrayRef<uint8_t> LeafData) { |
28 | return StringRef(reinterpret_cast<const char *>(LeafData.data()), |
29 | LeafData.size()); |
30 | } |
31 | |
32 | StringRef llvm::codeview::getBytesAsCString(ArrayRef<uint8_t> LeafData) { |
33 | return getBytesAsCharacters(LeafData).split(Separator: '\0').first; |
34 | } |
35 | |
36 | Error llvm::codeview::consume(BinaryStreamReader &Reader, APSInt &Num) { |
37 | // Used to avoid overload ambiguity on APInt constructor. |
38 | bool FalseVal = false; |
39 | uint16_t Short; |
40 | if (auto EC = Reader.readInteger(Dest&: Short)) |
41 | return EC; |
42 | |
43 | if (Short < LF_NUMERIC) { |
44 | Num = APSInt(APInt(/*numBits=*/16, Short, /*isSigned=*/false), |
45 | /*isUnsigned=*/true); |
46 | return Error::success(); |
47 | } |
48 | |
49 | switch (Short) { |
50 | case LF_CHAR: { |
51 | int8_t N; |
52 | if (auto EC = Reader.readInteger(Dest&: N)) |
53 | return EC; |
54 | Num = APSInt(APInt(8, N, true), false); |
55 | return Error::success(); |
56 | } |
57 | case LF_SHORT: { |
58 | int16_t N; |
59 | if (auto EC = Reader.readInteger(Dest&: N)) |
60 | return EC; |
61 | Num = APSInt(APInt(16, N, true), false); |
62 | return Error::success(); |
63 | } |
64 | case LF_USHORT: { |
65 | uint16_t N; |
66 | if (auto EC = Reader.readInteger(Dest&: N)) |
67 | return EC; |
68 | Num = APSInt(APInt(16, N, false), true); |
69 | return Error::success(); |
70 | } |
71 | case LF_LONG: { |
72 | int32_t N; |
73 | if (auto EC = Reader.readInteger(Dest&: N)) |
74 | return EC; |
75 | Num = APSInt(APInt(32, N, true), false); |
76 | return Error::success(); |
77 | } |
78 | case LF_ULONG: { |
79 | uint32_t N; |
80 | if (auto EC = Reader.readInteger(Dest&: N)) |
81 | return EC; |
82 | Num = APSInt(APInt(32, N, FalseVal), true); |
83 | return Error::success(); |
84 | } |
85 | case LF_QUADWORD: { |
86 | int64_t N; |
87 | if (auto EC = Reader.readInteger(Dest&: N)) |
88 | return EC; |
89 | Num = APSInt(APInt(64, N, true), false); |
90 | return Error::success(); |
91 | } |
92 | case LF_UQUADWORD: { |
93 | uint64_t N; |
94 | if (auto EC = Reader.readInteger(Dest&: N)) |
95 | return EC; |
96 | Num = APSInt(APInt(64, N, false), true); |
97 | return Error::success(); |
98 | } |
99 | } |
100 | return make_error<CodeViewError>(Args: cv_error_code::corrupt_record, |
101 | Args: "Buffer contains invalid APSInt type" ); |
102 | } |
103 | |
104 | Error llvm::codeview::consume(StringRef &Data, APSInt &Num) { |
105 | ArrayRef<uint8_t> Bytes(Data.bytes_begin(), Data.bytes_end()); |
106 | BinaryByteStream S(Bytes, llvm::endianness::little); |
107 | BinaryStreamReader SR(S); |
108 | auto EC = consume(Reader&: SR, Num); |
109 | Data = Data.take_back(N: SR.bytesRemaining()); |
110 | return EC; |
111 | } |
112 | |
113 | /// Decode a numeric leaf value that is known to be a uint64_t. |
114 | Error llvm::codeview::consume_numeric(BinaryStreamReader &Reader, |
115 | uint64_t &Num) { |
116 | APSInt N; |
117 | if (auto EC = consume(Reader, Num&: N)) |
118 | return EC; |
119 | if (N.isSigned() || !N.isIntN(N: 64)) |
120 | return make_error<CodeViewError>(Args: cv_error_code::corrupt_record, |
121 | Args: "Data is not a numeric value!" ); |
122 | Num = N.getLimitedValue(); |
123 | return Error::success(); |
124 | } |
125 | |
126 | Error llvm::codeview::consume(BinaryStreamReader &Reader, uint32_t &Item) { |
127 | return Reader.readInteger(Dest&: Item); |
128 | } |
129 | |
130 | Error llvm::codeview::consume(StringRef &Data, uint32_t &Item) { |
131 | ArrayRef<uint8_t> Bytes(Data.bytes_begin(), Data.bytes_end()); |
132 | BinaryByteStream S(Bytes, llvm::endianness::little); |
133 | BinaryStreamReader SR(S); |
134 | auto EC = consume(Reader&: SR, Item); |
135 | Data = Data.take_back(N: SR.bytesRemaining()); |
136 | return EC; |
137 | } |
138 | |
139 | Error llvm::codeview::consume(BinaryStreamReader &Reader, int32_t &Item) { |
140 | return Reader.readInteger(Dest&: Item); |
141 | } |
142 | |
143 | Error llvm::codeview::consume(BinaryStreamReader &Reader, StringRef &Item) { |
144 | if (Reader.empty()) |
145 | return make_error<CodeViewError>(Args: cv_error_code::corrupt_record, |
146 | Args: "Null terminated string buffer is empty!" ); |
147 | |
148 | return Reader.readCString(Dest&: Item); |
149 | } |
150 | |
151 | Expected<CVSymbol> llvm::codeview::readSymbolFromStream(BinaryStreamRef Stream, |
152 | uint32_t Offset) { |
153 | return readCVRecordFromStream<SymbolKind>(Stream, Offset); |
154 | } |
155 | |