13ca95b02SDimitry Andric //===-- RecordSerialization.cpp -------------------------------------------===//
23ca95b02SDimitry Andric //
33ca95b02SDimitry Andric // The LLVM Compiler Infrastructure
43ca95b02SDimitry Andric //
53ca95b02SDimitry Andric // This file is distributed under the University of Illinois Open Source
63ca95b02SDimitry Andric // License. See LICENSE.TXT for details.
73ca95b02SDimitry Andric //
83ca95b02SDimitry Andric //===----------------------------------------------------------------------===//
93ca95b02SDimitry Andric //
103ca95b02SDimitry Andric // Utilities for serializing and deserializing CodeView records.
113ca95b02SDimitry Andric //
123ca95b02SDimitry Andric //===----------------------------------------------------------------------===//
133ca95b02SDimitry Andric
143ca95b02SDimitry Andric #include "llvm/DebugInfo/CodeView/RecordSerialization.h"
153ca95b02SDimitry Andric #include "llvm/ADT/APInt.h"
163ca95b02SDimitry Andric #include "llvm/ADT/APSInt.h"
17d88c1a5aSDimitry Andric #include "llvm/DebugInfo/CodeView/CodeViewError.h"
18*2cab237bSDimitry Andric #include "llvm/DebugInfo/CodeView/SymbolRecord.h"
193ca95b02SDimitry Andric #include "llvm/DebugInfo/CodeView/TypeRecord.h"
207a7e6055SDimitry Andric #include "llvm/Support/BinaryByteStream.h"
213ca95b02SDimitry Andric
223ca95b02SDimitry Andric using namespace llvm;
233ca95b02SDimitry Andric using namespace llvm::codeview;
243ca95b02SDimitry Andric using namespace llvm::support;
253ca95b02SDimitry Andric
263ca95b02SDimitry Andric /// Reinterpret a byte array as an array of characters. Does not interpret as
273ca95b02SDimitry Andric /// a C string, as StringRef has several helpers (split) that make that easy.
getBytesAsCharacters(ArrayRef<uint8_t> LeafData)283ca95b02SDimitry Andric StringRef llvm::codeview::getBytesAsCharacters(ArrayRef<uint8_t> LeafData) {
293ca95b02SDimitry Andric return StringRef(reinterpret_cast<const char *>(LeafData.data()),
303ca95b02SDimitry Andric LeafData.size());
313ca95b02SDimitry Andric }
323ca95b02SDimitry Andric
getBytesAsCString(ArrayRef<uint8_t> LeafData)333ca95b02SDimitry Andric StringRef llvm::codeview::getBytesAsCString(ArrayRef<uint8_t> LeafData) {
343ca95b02SDimitry Andric return getBytesAsCharacters(LeafData).split('\0').first;
353ca95b02SDimitry Andric }
363ca95b02SDimitry Andric
consume(BinaryStreamReader & Reader,APSInt & Num)377a7e6055SDimitry Andric Error llvm::codeview::consume(BinaryStreamReader &Reader, APSInt &Num) {
383ca95b02SDimitry Andric // Used to avoid overload ambiguity on APInt construtor.
393ca95b02SDimitry Andric bool FalseVal = false;
40d88c1a5aSDimitry Andric uint16_t Short;
41d88c1a5aSDimitry Andric if (auto EC = Reader.readInteger(Short))
42d88c1a5aSDimitry Andric return EC;
43d88c1a5aSDimitry Andric
443ca95b02SDimitry Andric if (Short < LF_NUMERIC) {
453ca95b02SDimitry Andric Num = APSInt(APInt(/*numBits=*/16, Short, /*isSigned=*/false),
463ca95b02SDimitry Andric /*isUnsigned=*/true);
47d88c1a5aSDimitry Andric return Error::success();
483ca95b02SDimitry Andric }
493ca95b02SDimitry Andric
50d88c1a5aSDimitry Andric switch (Short) {
51d88c1a5aSDimitry Andric case LF_CHAR: {
52d88c1a5aSDimitry Andric int8_t N;
53d88c1a5aSDimitry Andric if (auto EC = Reader.readInteger(N))
54d88c1a5aSDimitry Andric return EC;
55d88c1a5aSDimitry Andric Num = APSInt(APInt(8, N, true), false);
56d88c1a5aSDimitry Andric return Error::success();
57d88c1a5aSDimitry Andric }
58d88c1a5aSDimitry Andric case LF_SHORT: {
59d88c1a5aSDimitry Andric int16_t N;
60d88c1a5aSDimitry Andric if (auto EC = Reader.readInteger(N))
61d88c1a5aSDimitry Andric return EC;
62d88c1a5aSDimitry Andric Num = APSInt(APInt(16, N, true), false);
63d88c1a5aSDimitry Andric return Error::success();
64d88c1a5aSDimitry Andric }
65d88c1a5aSDimitry Andric case LF_USHORT: {
66d88c1a5aSDimitry Andric uint16_t N;
67d88c1a5aSDimitry Andric if (auto EC = Reader.readInteger(N))
68d88c1a5aSDimitry Andric return EC;
69d88c1a5aSDimitry Andric Num = APSInt(APInt(16, N, false), true);
70d88c1a5aSDimitry Andric return Error::success();
71d88c1a5aSDimitry Andric }
72d88c1a5aSDimitry Andric case LF_LONG: {
73d88c1a5aSDimitry Andric int32_t N;
74d88c1a5aSDimitry Andric if (auto EC = Reader.readInteger(N))
75d88c1a5aSDimitry Andric return EC;
76d88c1a5aSDimitry Andric Num = APSInt(APInt(32, N, true), false);
77d88c1a5aSDimitry Andric return Error::success();
78d88c1a5aSDimitry Andric }
79d88c1a5aSDimitry Andric case LF_ULONG: {
80d88c1a5aSDimitry Andric uint32_t N;
81d88c1a5aSDimitry Andric if (auto EC = Reader.readInteger(N))
82d88c1a5aSDimitry Andric return EC;
83d88c1a5aSDimitry Andric Num = APSInt(APInt(32, N, FalseVal), true);
84d88c1a5aSDimitry Andric return Error::success();
85d88c1a5aSDimitry Andric }
86d88c1a5aSDimitry Andric case LF_QUADWORD: {
87d88c1a5aSDimitry Andric int64_t N;
88d88c1a5aSDimitry Andric if (auto EC = Reader.readInteger(N))
89d88c1a5aSDimitry Andric return EC;
90d88c1a5aSDimitry Andric Num = APSInt(APInt(64, N, true), false);
91d88c1a5aSDimitry Andric return Error::success();
92d88c1a5aSDimitry Andric }
93d88c1a5aSDimitry Andric case LF_UQUADWORD: {
94d88c1a5aSDimitry Andric uint64_t N;
95d88c1a5aSDimitry Andric if (auto EC = Reader.readInteger(N))
96d88c1a5aSDimitry Andric return EC;
97d88c1a5aSDimitry Andric Num = APSInt(APInt(64, N, false), true);
98d88c1a5aSDimitry Andric return Error::success();
99d88c1a5aSDimitry Andric }
100d88c1a5aSDimitry Andric }
101d88c1a5aSDimitry Andric return make_error<CodeViewError>(cv_error_code::corrupt_record,
102d88c1a5aSDimitry Andric "Buffer contains invalid APSInt type");
103d88c1a5aSDimitry Andric }
104d88c1a5aSDimitry Andric
consume(StringRef & Data,APSInt & Num)105d88c1a5aSDimitry Andric Error llvm::codeview::consume(StringRef &Data, APSInt &Num) {
1063ca95b02SDimitry Andric ArrayRef<uint8_t> Bytes(Data.bytes_begin(), Data.bytes_end());
1077a7e6055SDimitry Andric BinaryByteStream S(Bytes, llvm::support::little);
1087a7e6055SDimitry Andric BinaryStreamReader SR(S);
109d88c1a5aSDimitry Andric auto EC = consume(SR, Num);
110d88c1a5aSDimitry Andric Data = Data.take_back(SR.bytesRemaining());
1113ca95b02SDimitry Andric return EC;
1123ca95b02SDimitry Andric }
1133ca95b02SDimitry Andric
1143ca95b02SDimitry Andric /// Decode a numeric leaf value that is known to be a uint64_t.
consume_numeric(BinaryStreamReader & Reader,uint64_t & Num)1157a7e6055SDimitry Andric Error llvm::codeview::consume_numeric(BinaryStreamReader &Reader,
1163ca95b02SDimitry Andric uint64_t &Num) {
1173ca95b02SDimitry Andric APSInt N;
118d88c1a5aSDimitry Andric if (auto EC = consume(Reader, N))
1193ca95b02SDimitry Andric return EC;
1203ca95b02SDimitry Andric if (N.isSigned() || !N.isIntN(64))
121d88c1a5aSDimitry Andric return make_error<CodeViewError>(cv_error_code::corrupt_record,
122d88c1a5aSDimitry Andric "Data is not a numeric value!");
1233ca95b02SDimitry Andric Num = N.getLimitedValue();
124d88c1a5aSDimitry Andric return Error::success();
1253ca95b02SDimitry Andric }
1263ca95b02SDimitry Andric
consume(BinaryStreamReader & Reader,uint32_t & Item)1277a7e6055SDimitry Andric Error llvm::codeview::consume(BinaryStreamReader &Reader, uint32_t &Item) {
128d88c1a5aSDimitry Andric return Reader.readInteger(Item);
1293ca95b02SDimitry Andric }
1303ca95b02SDimitry Andric
consume(StringRef & Data,uint32_t & Item)131d88c1a5aSDimitry Andric Error llvm::codeview::consume(StringRef &Data, uint32_t &Item) {
1323ca95b02SDimitry Andric ArrayRef<uint8_t> Bytes(Data.bytes_begin(), Data.bytes_end());
1337a7e6055SDimitry Andric BinaryByteStream S(Bytes, llvm::support::little);
1347a7e6055SDimitry Andric BinaryStreamReader SR(S);
135d88c1a5aSDimitry Andric auto EC = consume(SR, Item);
136d88c1a5aSDimitry Andric Data = Data.take_back(SR.bytesRemaining());
1373ca95b02SDimitry Andric return EC;
1383ca95b02SDimitry Andric }
1393ca95b02SDimitry Andric
consume(BinaryStreamReader & Reader,int32_t & Item)1407a7e6055SDimitry Andric Error llvm::codeview::consume(BinaryStreamReader &Reader, int32_t &Item) {
141d88c1a5aSDimitry Andric return Reader.readInteger(Item);
1423ca95b02SDimitry Andric }
1433ca95b02SDimitry Andric
consume(BinaryStreamReader & Reader,StringRef & Item)1447a7e6055SDimitry Andric Error llvm::codeview::consume(BinaryStreamReader &Reader, StringRef &Item) {
145d88c1a5aSDimitry Andric if (Reader.empty())
146d88c1a5aSDimitry Andric return make_error<CodeViewError>(cv_error_code::corrupt_record,
147d88c1a5aSDimitry Andric "Null terminated string buffer is empty!");
1483ca95b02SDimitry Andric
1497a7e6055SDimitry Andric return Reader.readCString(Item);
1503ca95b02SDimitry Andric }
151*2cab237bSDimitry Andric
readSymbolFromStream(BinaryStreamRef Stream,uint32_t Offset)152*2cab237bSDimitry Andric Expected<CVSymbol> llvm::codeview::readSymbolFromStream(BinaryStreamRef Stream,
153*2cab237bSDimitry Andric uint32_t Offset) {
154*2cab237bSDimitry Andric return readCVRecordFromStream<SymbolKind>(Stream, Offset);
155*2cab237bSDimitry Andric }
156