10b57cec5SDimitry Andric //===-- RecordSerialization.cpp -------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // Utilities for serializing and deserializing CodeView records.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/RecordSerialization.h"
140b57cec5SDimitry Andric #include "llvm/ADT/APInt.h"
150b57cec5SDimitry Andric #include "llvm/ADT/APSInt.h"
1681ad6265SDimitry Andric #include "llvm/DebugInfo/CodeView/CVRecord.h"
170b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/CodeViewError.h"
180b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/SymbolRecord.h"
190b57cec5SDimitry Andric #include "llvm/Support/BinaryByteStream.h"
200b57cec5SDimitry Andric 
210b57cec5SDimitry Andric using namespace llvm;
220b57cec5SDimitry Andric using namespace llvm::codeview;
230b57cec5SDimitry Andric using namespace llvm::support;
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric /// Reinterpret a byte array as an array of characters. Does not interpret as
260b57cec5SDimitry Andric /// a C string, as StringRef has several helpers (split) that make that easy.
getBytesAsCharacters(ArrayRef<uint8_t> LeafData)270b57cec5SDimitry Andric StringRef llvm::codeview::getBytesAsCharacters(ArrayRef<uint8_t> LeafData) {
280b57cec5SDimitry Andric   return StringRef(reinterpret_cast<const char *>(LeafData.data()),
290b57cec5SDimitry Andric                    LeafData.size());
300b57cec5SDimitry Andric }
310b57cec5SDimitry Andric 
getBytesAsCString(ArrayRef<uint8_t> LeafData)320b57cec5SDimitry Andric StringRef llvm::codeview::getBytesAsCString(ArrayRef<uint8_t> LeafData) {
330b57cec5SDimitry Andric   return getBytesAsCharacters(LeafData).split('\0').first;
340b57cec5SDimitry Andric }
350b57cec5SDimitry Andric 
consume(BinaryStreamReader & Reader,APSInt & Num)360b57cec5SDimitry Andric Error llvm::codeview::consume(BinaryStreamReader &Reader, APSInt &Num) {
37e8d8bef9SDimitry Andric   // Used to avoid overload ambiguity on APInt constructor.
380b57cec5SDimitry Andric   bool FalseVal = false;
390b57cec5SDimitry Andric   uint16_t Short;
400b57cec5SDimitry Andric   if (auto EC = Reader.readInteger(Short))
410b57cec5SDimitry Andric     return EC;
420b57cec5SDimitry Andric 
430b57cec5SDimitry Andric   if (Short < LF_NUMERIC) {
440b57cec5SDimitry Andric     Num = APSInt(APInt(/*numBits=*/16, Short, /*isSigned=*/false),
450b57cec5SDimitry Andric                  /*isUnsigned=*/true);
460b57cec5SDimitry Andric     return Error::success();
470b57cec5SDimitry Andric   }
480b57cec5SDimitry Andric 
490b57cec5SDimitry Andric   switch (Short) {
500b57cec5SDimitry Andric   case LF_CHAR: {
510b57cec5SDimitry Andric     int8_t N;
520b57cec5SDimitry Andric     if (auto EC = Reader.readInteger(N))
530b57cec5SDimitry Andric       return EC;
540b57cec5SDimitry Andric     Num = APSInt(APInt(8, N, true), false);
550b57cec5SDimitry Andric     return Error::success();
560b57cec5SDimitry Andric   }
570b57cec5SDimitry Andric   case LF_SHORT: {
580b57cec5SDimitry Andric     int16_t N;
590b57cec5SDimitry Andric     if (auto EC = Reader.readInteger(N))
600b57cec5SDimitry Andric       return EC;
610b57cec5SDimitry Andric     Num = APSInt(APInt(16, N, true), false);
620b57cec5SDimitry Andric     return Error::success();
630b57cec5SDimitry Andric   }
640b57cec5SDimitry Andric   case LF_USHORT: {
650b57cec5SDimitry Andric     uint16_t N;
660b57cec5SDimitry Andric     if (auto EC = Reader.readInteger(N))
670b57cec5SDimitry Andric       return EC;
680b57cec5SDimitry Andric     Num = APSInt(APInt(16, N, false), true);
690b57cec5SDimitry Andric     return Error::success();
700b57cec5SDimitry Andric   }
710b57cec5SDimitry Andric   case LF_LONG: {
720b57cec5SDimitry Andric     int32_t N;
730b57cec5SDimitry Andric     if (auto EC = Reader.readInteger(N))
740b57cec5SDimitry Andric       return EC;
750b57cec5SDimitry Andric     Num = APSInt(APInt(32, N, true), false);
760b57cec5SDimitry Andric     return Error::success();
770b57cec5SDimitry Andric   }
780b57cec5SDimitry Andric   case LF_ULONG: {
790b57cec5SDimitry Andric     uint32_t N;
800b57cec5SDimitry Andric     if (auto EC = Reader.readInteger(N))
810b57cec5SDimitry Andric       return EC;
820b57cec5SDimitry Andric     Num = APSInt(APInt(32, N, FalseVal), true);
830b57cec5SDimitry Andric     return Error::success();
840b57cec5SDimitry Andric   }
850b57cec5SDimitry Andric   case LF_QUADWORD: {
860b57cec5SDimitry Andric     int64_t N;
870b57cec5SDimitry Andric     if (auto EC = Reader.readInteger(N))
880b57cec5SDimitry Andric       return EC;
890b57cec5SDimitry Andric     Num = APSInt(APInt(64, N, true), false);
900b57cec5SDimitry Andric     return Error::success();
910b57cec5SDimitry Andric   }
920b57cec5SDimitry Andric   case LF_UQUADWORD: {
930b57cec5SDimitry Andric     uint64_t N;
940b57cec5SDimitry Andric     if (auto EC = Reader.readInteger(N))
950b57cec5SDimitry Andric       return EC;
960b57cec5SDimitry Andric     Num = APSInt(APInt(64, N, false), true);
970b57cec5SDimitry Andric     return Error::success();
980b57cec5SDimitry Andric   }
990b57cec5SDimitry Andric   }
1000b57cec5SDimitry Andric   return make_error<CodeViewError>(cv_error_code::corrupt_record,
1010b57cec5SDimitry Andric                                    "Buffer contains invalid APSInt type");
1020b57cec5SDimitry Andric }
1030b57cec5SDimitry Andric 
consume(StringRef & Data,APSInt & Num)1040b57cec5SDimitry Andric Error llvm::codeview::consume(StringRef &Data, APSInt &Num) {
1050b57cec5SDimitry Andric   ArrayRef<uint8_t> Bytes(Data.bytes_begin(), Data.bytes_end());
1065f757f3fSDimitry Andric   BinaryByteStream S(Bytes, llvm::endianness::little);
1070b57cec5SDimitry Andric   BinaryStreamReader SR(S);
1080b57cec5SDimitry Andric   auto EC = consume(SR, Num);
1090b57cec5SDimitry Andric   Data = Data.take_back(SR.bytesRemaining());
1100b57cec5SDimitry Andric   return EC;
1110b57cec5SDimitry Andric }
1120b57cec5SDimitry Andric 
1130b57cec5SDimitry Andric /// Decode a numeric leaf value that is known to be a uint64_t.
consume_numeric(BinaryStreamReader & Reader,uint64_t & Num)1140b57cec5SDimitry Andric Error llvm::codeview::consume_numeric(BinaryStreamReader &Reader,
1150b57cec5SDimitry Andric                                       uint64_t &Num) {
1160b57cec5SDimitry Andric   APSInt N;
1170b57cec5SDimitry Andric   if (auto EC = consume(Reader, N))
1180b57cec5SDimitry Andric     return EC;
1190b57cec5SDimitry Andric   if (N.isSigned() || !N.isIntN(64))
1200b57cec5SDimitry Andric     return make_error<CodeViewError>(cv_error_code::corrupt_record,
1210b57cec5SDimitry Andric                                      "Data is not a numeric value!");
1220b57cec5SDimitry Andric   Num = N.getLimitedValue();
1230b57cec5SDimitry Andric   return Error::success();
1240b57cec5SDimitry Andric }
1250b57cec5SDimitry Andric 
consume(BinaryStreamReader & Reader,uint32_t & Item)1260b57cec5SDimitry Andric Error llvm::codeview::consume(BinaryStreamReader &Reader, uint32_t &Item) {
1270b57cec5SDimitry Andric   return Reader.readInteger(Item);
1280b57cec5SDimitry Andric }
1290b57cec5SDimitry Andric 
consume(StringRef & Data,uint32_t & Item)1300b57cec5SDimitry Andric Error llvm::codeview::consume(StringRef &Data, uint32_t &Item) {
1310b57cec5SDimitry Andric   ArrayRef<uint8_t> Bytes(Data.bytes_begin(), Data.bytes_end());
1325f757f3fSDimitry Andric   BinaryByteStream S(Bytes, llvm::endianness::little);
1330b57cec5SDimitry Andric   BinaryStreamReader SR(S);
1340b57cec5SDimitry Andric   auto EC = consume(SR, Item);
1350b57cec5SDimitry Andric   Data = Data.take_back(SR.bytesRemaining());
1360b57cec5SDimitry Andric   return EC;
1370b57cec5SDimitry Andric }
1380b57cec5SDimitry Andric 
consume(BinaryStreamReader & Reader,int32_t & Item)1390b57cec5SDimitry Andric Error llvm::codeview::consume(BinaryStreamReader &Reader, int32_t &Item) {
1400b57cec5SDimitry Andric   return Reader.readInteger(Item);
1410b57cec5SDimitry Andric }
1420b57cec5SDimitry Andric 
consume(BinaryStreamReader & Reader,StringRef & Item)1430b57cec5SDimitry Andric Error llvm::codeview::consume(BinaryStreamReader &Reader, StringRef &Item) {
1440b57cec5SDimitry Andric   if (Reader.empty())
1450b57cec5SDimitry Andric     return make_error<CodeViewError>(cv_error_code::corrupt_record,
1460b57cec5SDimitry Andric                                      "Null terminated string buffer is empty!");
1470b57cec5SDimitry Andric 
1480b57cec5SDimitry Andric   return Reader.readCString(Item);
1490b57cec5SDimitry Andric }
1500b57cec5SDimitry Andric 
readSymbolFromStream(BinaryStreamRef Stream,uint32_t Offset)1510b57cec5SDimitry Andric Expected<CVSymbol> llvm::codeview::readSymbolFromStream(BinaryStreamRef Stream,
1520b57cec5SDimitry Andric                                                         uint32_t Offset) {
1530b57cec5SDimitry Andric   return readCVRecordFromStream<SymbolKind>(Stream, Offset);
1540b57cec5SDimitry Andric }
155