101095a5dSDimitry Andric //===-- RecordSerialization.cpp -------------------------------------------===//
201095a5dSDimitry Andric //
3e6d15924SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e6d15924SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5e6d15924SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
601095a5dSDimitry Andric //
701095a5dSDimitry Andric //===----------------------------------------------------------------------===//
801095a5dSDimitry Andric //
901095a5dSDimitry Andric // Utilities for serializing and deserializing CodeView records.
1001095a5dSDimitry Andric //
1101095a5dSDimitry Andric //===----------------------------------------------------------------------===//
1201095a5dSDimitry Andric
1301095a5dSDimitry Andric #include "llvm/DebugInfo/CodeView/RecordSerialization.h"
1401095a5dSDimitry Andric #include "llvm/ADT/APInt.h"
1501095a5dSDimitry Andric #include "llvm/ADT/APSInt.h"
16145449b1SDimitry Andric #include "llvm/DebugInfo/CodeView/CVRecord.h"
17b915e9e0SDimitry Andric #include "llvm/DebugInfo/CodeView/CodeViewError.h"
18044eb2f6SDimitry Andric #include "llvm/DebugInfo/CodeView/SymbolRecord.h"
1971d5a254SDimitry Andric #include "llvm/Support/BinaryByteStream.h"
2001095a5dSDimitry Andric
2101095a5dSDimitry Andric using namespace llvm;
2201095a5dSDimitry Andric using namespace llvm::codeview;
2301095a5dSDimitry Andric using namespace llvm::support;
2401095a5dSDimitry Andric
2501095a5dSDimitry Andric /// Reinterpret a byte array as an array of characters. Does not interpret as
2601095a5dSDimitry Andric /// a C string, as StringRef has several helpers (split) that make that easy.
getBytesAsCharacters(ArrayRef<uint8_t> LeafData)2701095a5dSDimitry Andric StringRef llvm::codeview::getBytesAsCharacters(ArrayRef<uint8_t> LeafData) {
2801095a5dSDimitry Andric return StringRef(reinterpret_cast<const char *>(LeafData.data()),
2901095a5dSDimitry Andric LeafData.size());
3001095a5dSDimitry Andric }
3101095a5dSDimitry Andric
getBytesAsCString(ArrayRef<uint8_t> LeafData)3201095a5dSDimitry Andric StringRef llvm::codeview::getBytesAsCString(ArrayRef<uint8_t> LeafData) {
3301095a5dSDimitry Andric return getBytesAsCharacters(LeafData).split('\0').first;
3401095a5dSDimitry Andric }
3501095a5dSDimitry Andric
consume(BinaryStreamReader & Reader,APSInt & Num)3671d5a254SDimitry Andric Error llvm::codeview::consume(BinaryStreamReader &Reader, APSInt &Num) {
37b60736ecSDimitry Andric // Used to avoid overload ambiguity on APInt constructor.
3801095a5dSDimitry Andric bool FalseVal = false;
39b915e9e0SDimitry Andric uint16_t Short;
40b915e9e0SDimitry Andric if (auto EC = Reader.readInteger(Short))
41b915e9e0SDimitry Andric return EC;
42b915e9e0SDimitry Andric
4301095a5dSDimitry Andric if (Short < LF_NUMERIC) {
4401095a5dSDimitry Andric Num = APSInt(APInt(/*numBits=*/16, Short, /*isSigned=*/false),
4501095a5dSDimitry Andric /*isUnsigned=*/true);
46b915e9e0SDimitry Andric return Error::success();
4701095a5dSDimitry Andric }
4801095a5dSDimitry Andric
49b915e9e0SDimitry Andric switch (Short) {
50b915e9e0SDimitry Andric case LF_CHAR: {
51b915e9e0SDimitry Andric int8_t N;
52b915e9e0SDimitry Andric if (auto EC = Reader.readInteger(N))
53b915e9e0SDimitry Andric return EC;
54b915e9e0SDimitry Andric Num = APSInt(APInt(8, N, true), false);
55b915e9e0SDimitry Andric return Error::success();
56b915e9e0SDimitry Andric }
57b915e9e0SDimitry Andric case LF_SHORT: {
58b915e9e0SDimitry Andric int16_t N;
59b915e9e0SDimitry Andric if (auto EC = Reader.readInteger(N))
60b915e9e0SDimitry Andric return EC;
61b915e9e0SDimitry Andric Num = APSInt(APInt(16, N, true), false);
62b915e9e0SDimitry Andric return Error::success();
63b915e9e0SDimitry Andric }
64b915e9e0SDimitry Andric case LF_USHORT: {
65b915e9e0SDimitry Andric uint16_t N;
66b915e9e0SDimitry Andric if (auto EC = Reader.readInteger(N))
67b915e9e0SDimitry Andric return EC;
68b915e9e0SDimitry Andric Num = APSInt(APInt(16, N, false), true);
69b915e9e0SDimitry Andric return Error::success();
70b915e9e0SDimitry Andric }
71b915e9e0SDimitry Andric case LF_LONG: {
72b915e9e0SDimitry Andric int32_t N;
73b915e9e0SDimitry Andric if (auto EC = Reader.readInteger(N))
74b915e9e0SDimitry Andric return EC;
75b915e9e0SDimitry Andric Num = APSInt(APInt(32, N, true), false);
76b915e9e0SDimitry Andric return Error::success();
77b915e9e0SDimitry Andric }
78b915e9e0SDimitry Andric case LF_ULONG: {
79b915e9e0SDimitry Andric uint32_t N;
80b915e9e0SDimitry Andric if (auto EC = Reader.readInteger(N))
81b915e9e0SDimitry Andric return EC;
82b915e9e0SDimitry Andric Num = APSInt(APInt(32, N, FalseVal), true);
83b915e9e0SDimitry Andric return Error::success();
84b915e9e0SDimitry Andric }
85b915e9e0SDimitry Andric case LF_QUADWORD: {
86b915e9e0SDimitry Andric int64_t N;
87b915e9e0SDimitry Andric if (auto EC = Reader.readInteger(N))
88b915e9e0SDimitry Andric return EC;
89b915e9e0SDimitry Andric Num = APSInt(APInt(64, N, true), false);
90b915e9e0SDimitry Andric return Error::success();
91b915e9e0SDimitry Andric }
92b915e9e0SDimitry Andric case LF_UQUADWORD: {
93b915e9e0SDimitry Andric uint64_t N;
94b915e9e0SDimitry Andric if (auto EC = Reader.readInteger(N))
95b915e9e0SDimitry Andric return EC;
96b915e9e0SDimitry Andric Num = APSInt(APInt(64, N, false), true);
97b915e9e0SDimitry Andric return Error::success();
98b915e9e0SDimitry Andric }
99b915e9e0SDimitry Andric }
100b915e9e0SDimitry Andric return make_error<CodeViewError>(cv_error_code::corrupt_record,
101b915e9e0SDimitry Andric "Buffer contains invalid APSInt type");
102b915e9e0SDimitry Andric }
103b915e9e0SDimitry Andric
consume(StringRef & Data,APSInt & Num)104b915e9e0SDimitry Andric Error llvm::codeview::consume(StringRef &Data, APSInt &Num) {
10501095a5dSDimitry Andric ArrayRef<uint8_t> Bytes(Data.bytes_begin(), Data.bytes_end());
106b1c73532SDimitry Andric BinaryByteStream S(Bytes, llvm::endianness::little);
10771d5a254SDimitry Andric BinaryStreamReader SR(S);
108b915e9e0SDimitry Andric auto EC = consume(SR, Num);
109b915e9e0SDimitry Andric Data = Data.take_back(SR.bytesRemaining());
11001095a5dSDimitry Andric return EC;
11101095a5dSDimitry Andric }
11201095a5dSDimitry Andric
11301095a5dSDimitry Andric /// Decode a numeric leaf value that is known to be a uint64_t.
consume_numeric(BinaryStreamReader & Reader,uint64_t & Num)11471d5a254SDimitry Andric Error llvm::codeview::consume_numeric(BinaryStreamReader &Reader,
11501095a5dSDimitry Andric uint64_t &Num) {
11601095a5dSDimitry Andric APSInt N;
117b915e9e0SDimitry Andric if (auto EC = consume(Reader, N))
11801095a5dSDimitry Andric return EC;
11901095a5dSDimitry Andric if (N.isSigned() || !N.isIntN(64))
120b915e9e0SDimitry Andric return make_error<CodeViewError>(cv_error_code::corrupt_record,
121b915e9e0SDimitry Andric "Data is not a numeric value!");
12201095a5dSDimitry Andric Num = N.getLimitedValue();
123b915e9e0SDimitry Andric return Error::success();
12401095a5dSDimitry Andric }
12501095a5dSDimitry Andric
consume(BinaryStreamReader & Reader,uint32_t & Item)12671d5a254SDimitry Andric Error llvm::codeview::consume(BinaryStreamReader &Reader, uint32_t &Item) {
127b915e9e0SDimitry Andric return Reader.readInteger(Item);
12801095a5dSDimitry Andric }
12901095a5dSDimitry Andric
consume(StringRef & Data,uint32_t & Item)130b915e9e0SDimitry Andric Error llvm::codeview::consume(StringRef &Data, uint32_t &Item) {
13101095a5dSDimitry Andric ArrayRef<uint8_t> Bytes(Data.bytes_begin(), Data.bytes_end());
132b1c73532SDimitry Andric BinaryByteStream S(Bytes, llvm::endianness::little);
13371d5a254SDimitry Andric BinaryStreamReader SR(S);
134b915e9e0SDimitry Andric auto EC = consume(SR, Item);
135b915e9e0SDimitry Andric Data = Data.take_back(SR.bytesRemaining());
13601095a5dSDimitry Andric return EC;
13701095a5dSDimitry Andric }
13801095a5dSDimitry Andric
consume(BinaryStreamReader & Reader,int32_t & Item)13971d5a254SDimitry Andric Error llvm::codeview::consume(BinaryStreamReader &Reader, int32_t &Item) {
140b915e9e0SDimitry Andric return Reader.readInteger(Item);
14101095a5dSDimitry Andric }
14201095a5dSDimitry Andric
consume(BinaryStreamReader & Reader,StringRef & Item)14371d5a254SDimitry Andric Error llvm::codeview::consume(BinaryStreamReader &Reader, StringRef &Item) {
144b915e9e0SDimitry Andric if (Reader.empty())
145b915e9e0SDimitry Andric return make_error<CodeViewError>(cv_error_code::corrupt_record,
146b915e9e0SDimitry Andric "Null terminated string buffer is empty!");
14701095a5dSDimitry Andric
14871d5a254SDimitry Andric return Reader.readCString(Item);
14901095a5dSDimitry Andric }
150044eb2f6SDimitry Andric
readSymbolFromStream(BinaryStreamRef Stream,uint32_t Offset)151044eb2f6SDimitry Andric Expected<CVSymbol> llvm::codeview::readSymbolFromStream(BinaryStreamRef Stream,
152044eb2f6SDimitry Andric uint32_t Offset) {
153044eb2f6SDimitry Andric return readCVRecordFromStream<SymbolKind>(Stream, Offset);
154044eb2f6SDimitry Andric }
155