Line data Source code
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.
28 14 : StringRef llvm::codeview::getBytesAsCharacters(ArrayRef<uint8_t> LeafData) {
29 14 : return StringRef(reinterpret_cast<const char *>(LeafData.data()),
30 14 : LeafData.size());
31 : }
32 :
33 0 : StringRef llvm::codeview::getBytesAsCString(ArrayRef<uint8_t> LeafData) {
34 0 : return getBytesAsCharacters(LeafData).split('\0').first;
35 : }
36 :
37 10918 : 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 21836 : if (auto EC = Reader.readInteger(Short))
42 : return EC;
43 :
44 10918 : if (Short < LF_NUMERIC) {
45 21212 : Num = APSInt(APInt(/*numBits=*/16, Short, /*isSigned=*/false),
46 10606 : /*isUnsigned=*/true);
47 : return Error::success();
48 : }
49 :
50 312 : switch (Short) {
51 4 : case LF_CHAR: {
52 : int8_t N;
53 8 : if (auto EC = Reader.readInteger(N))
54 : return EC;
55 8 : Num = APSInt(APInt(8, N, true), false);
56 : return Error::success();
57 : }
58 2 : case LF_SHORT: {
59 : int16_t N;
60 4 : if (auto EC = Reader.readInteger(N))
61 : return EC;
62 4 : Num = APSInt(APInt(16, N, true), false);
63 : return Error::success();
64 : }
65 23 : case LF_USHORT: {
66 : uint16_t N;
67 46 : if (auto EC = Reader.readInteger(N))
68 : return EC;
69 46 : Num = APSInt(APInt(16, N, false), true);
70 : return Error::success();
71 : }
72 2 : case LF_LONG: {
73 : int32_t N;
74 4 : if (auto EC = Reader.readInteger(N))
75 : return EC;
76 4 : Num = APSInt(APInt(32, N, true), false);
77 : return Error::success();
78 : }
79 277 : case LF_ULONG: {
80 : uint32_t N;
81 554 : if (auto EC = Reader.readInteger(N))
82 : return EC;
83 554 : Num = APSInt(APInt(32, N, FalseVal), true);
84 : return Error::success();
85 : }
86 2 : case LF_QUADWORD: {
87 : int64_t N;
88 4 : if (auto EC = Reader.readInteger(N))
89 : return EC;
90 4 : Num = APSInt(APInt(64, N, true), false);
91 : return Error::success();
92 : }
93 2 : case LF_UQUADWORD: {
94 : uint64_t N;
95 4 : if (auto EC = Reader.readInteger(N))
96 : return EC;
97 4 : 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 :
105 0 : 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 0 : BinaryStreamReader SR(S);
109 0 : auto EC = consume(SR, Num);
110 0 : Data = Data.take_back(SR.bytesRemaining());
111 0 : return EC;
112 : }
113 :
114 : /// Decode a numeric leaf value that is known to be a uint64_t.
115 0 : Error llvm::codeview::consume_numeric(BinaryStreamReader &Reader,
116 : uint64_t &Num) {
117 : APSInt N;
118 0 : if (auto EC = consume(Reader, N))
119 : return EC;
120 0 : if (N.isSigned() || !N.isIntN(64))
121 : return make_error<CodeViewError>(cv_error_code::corrupt_record,
122 : "Data is not a numeric value!");
123 0 : Num = N.getLimitedValue();
124 : return Error::success();
125 : }
126 :
127 2098 : Error llvm::codeview::consume(BinaryStreamReader &Reader, uint32_t &Item) {
128 2098 : return Reader.readInteger(Item);
129 : }
130 :
131 2098 : 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 2098 : BinaryStreamReader SR(S);
135 2098 : auto EC = consume(SR, Item);
136 4196 : Data = Data.take_back(SR.bytesRemaining());
137 2098 : return EC;
138 : }
139 :
140 0 : Error llvm::codeview::consume(BinaryStreamReader &Reader, int32_t &Item) {
141 0 : return Reader.readInteger(Item);
142 : }
143 :
144 0 : Error llvm::codeview::consume(BinaryStreamReader &Reader, StringRef &Item) {
145 0 : if (Reader.empty())
146 : return make_error<CodeViewError>(cv_error_code::corrupt_record,
147 : "Null terminated string buffer is empty!");
148 :
149 0 : return Reader.readCString(Item);
150 : }
151 :
152 31 : Expected<CVSymbol> llvm::codeview::readSymbolFromStream(BinaryStreamRef Stream,
153 : uint32_t Offset) {
154 31 : return readCVRecordFromStream<SymbolKind>(Stream, Offset);
155 : }
|