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