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.
getBytesAsCharacters(ArrayRef<uint8_t> LeafData)27 StringRef llvm::codeview::getBytesAsCharacters(ArrayRef<uint8_t> LeafData) {
28 return StringRef(reinterpret_cast<const char *>(LeafData.data()),
29 LeafData.size());
30 }
31
getBytesAsCString(ArrayRef<uint8_t> LeafData)32 StringRef llvm::codeview::getBytesAsCString(ArrayRef<uint8_t> LeafData) {
33 return getBytesAsCharacters(LeafData).split('\0').first;
34 }
35
consume(BinaryStreamReader & Reader,APSInt & Num)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(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(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(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(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(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(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(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(N))
95 return EC;
96 Num = APSInt(APInt(64, N, false), true);
97 return Error::success();
98 }
99 }
100 return make_error<CodeViewError>(cv_error_code::corrupt_record,
101 "Buffer contains invalid APSInt type");
102 }
103
consume(StringRef & Data,APSInt & Num)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(SR, Num);
109 Data = Data.take_back(SR.bytesRemaining());
110 return EC;
111 }
112
113 /// Decode a numeric leaf value that is known to be a uint64_t.
consume_numeric(BinaryStreamReader & Reader,uint64_t & Num)114 Error llvm::codeview::consume_numeric(BinaryStreamReader &Reader,
115 uint64_t &Num) {
116 APSInt N;
117 if (auto EC = consume(Reader, N))
118 return EC;
119 if (N.isSigned() || !N.isIntN(64))
120 return make_error<CodeViewError>(cv_error_code::corrupt_record,
121 "Data is not a numeric value!");
122 Num = N.getLimitedValue();
123 return Error::success();
124 }
125
consume(BinaryStreamReader & Reader,uint32_t & Item)126 Error llvm::codeview::consume(BinaryStreamReader &Reader, uint32_t &Item) {
127 return Reader.readInteger(Item);
128 }
129
consume(StringRef & Data,uint32_t & Item)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(SR, Item);
135 Data = Data.take_back(SR.bytesRemaining());
136 return EC;
137 }
138
consume(BinaryStreamReader & Reader,int32_t & Item)139 Error llvm::codeview::consume(BinaryStreamReader &Reader, int32_t &Item) {
140 return Reader.readInteger(Item);
141 }
142
consume(BinaryStreamReader & Reader,StringRef & Item)143 Error llvm::codeview::consume(BinaryStreamReader &Reader, StringRef &Item) {
144 if (Reader.empty())
145 return make_error<CodeViewError>(cv_error_code::corrupt_record,
146 "Null terminated string buffer is empty!");
147
148 return Reader.readCString(Item);
149 }
150
readSymbolFromStream(BinaryStreamRef Stream,uint32_t Offset)151 Expected<CVSymbol> llvm::codeview::readSymbolFromStream(BinaryStreamRef Stream,
152 uint32_t Offset) {
153 return readCVRecordFromStream<SymbolKind>(Stream, Offset);
154 }
155