138cc8b3fSZachary Turner //===-- RecordSerialization.cpp -------------------------------------------===// 238cc8b3fSZachary Turner // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 638cc8b3fSZachary Turner // 738cc8b3fSZachary Turner //===----------------------------------------------------------------------===// 838cc8b3fSZachary Turner // 938cc8b3fSZachary Turner // Utilities for serializing and deserializing CodeView records. 1038cc8b3fSZachary Turner // 1138cc8b3fSZachary Turner //===----------------------------------------------------------------------===// 1238cc8b3fSZachary Turner 1338cc8b3fSZachary Turner #include "llvm/DebugInfo/CodeView/RecordSerialization.h" 1438cc8b3fSZachary Turner #include "llvm/ADT/APInt.h" 1538cc8b3fSZachary Turner #include "llvm/ADT/APSInt.h" 16660230ebSZachary Turner #include "llvm/DebugInfo/CodeView/CodeViewError.h" 1714d90fd0SReid Kleckner #include "llvm/DebugInfo/CodeView/SymbolRecord.h" 1838cc8b3fSZachary Turner #include "llvm/DebugInfo/CodeView/TypeRecord.h" 19d9dc2829SZachary Turner #include "llvm/Support/BinaryByteStream.h" 2038cc8b3fSZachary Turner 2138cc8b3fSZachary Turner using namespace llvm; 2238cc8b3fSZachary Turner using namespace llvm::codeview; 2338cc8b3fSZachary Turner using namespace llvm::support; 2438cc8b3fSZachary Turner 2538cc8b3fSZachary Turner /// Reinterpret a byte array as an array of characters. Does not interpret as 2638cc8b3fSZachary Turner /// a C string, as StringRef has several helpers (split) that make that easy. 2738cc8b3fSZachary Turner StringRef llvm::codeview::getBytesAsCharacters(ArrayRef<uint8_t> LeafData) { 2838cc8b3fSZachary Turner return StringRef(reinterpret_cast<const char *>(LeafData.data()), 2938cc8b3fSZachary Turner LeafData.size()); 3038cc8b3fSZachary Turner } 3138cc8b3fSZachary Turner 3238cc8b3fSZachary Turner StringRef llvm::codeview::getBytesAsCString(ArrayRef<uint8_t> LeafData) { 3338cc8b3fSZachary Turner return getBytesAsCharacters(LeafData).split('\0').first; 3438cc8b3fSZachary Turner } 3538cc8b3fSZachary Turner 36120faca4SZachary Turner Error llvm::codeview::consume(BinaryStreamReader &Reader, APSInt &Num) { 37*c8dedfe2SNico Weber // Used to avoid overload ambiguity on APInt constructor. 3838cc8b3fSZachary Turner bool FalseVal = false; 394d49eb9fSZachary Turner uint16_t Short; 40695ed56bSZachary Turner if (auto EC = Reader.readInteger(Short)) 414d49eb9fSZachary Turner return EC; 424d49eb9fSZachary Turner 4338cc8b3fSZachary Turner if (Short < LF_NUMERIC) { 4438cc8b3fSZachary Turner Num = APSInt(APInt(/*numBits=*/16, Short, /*isSigned=*/false), 4538cc8b3fSZachary Turner /*isUnsigned=*/true); 46660230ebSZachary Turner return Error::success(); 4738cc8b3fSZachary Turner } 484d49eb9fSZachary Turner 4938cc8b3fSZachary Turner switch (Short) { 504d49eb9fSZachary Turner case LF_CHAR: { 514d49eb9fSZachary Turner int8_t N; 52695ed56bSZachary Turner if (auto EC = Reader.readInteger(N)) 534d49eb9fSZachary Turner return EC; 544d49eb9fSZachary Turner Num = APSInt(APInt(8, N, true), false); 55660230ebSZachary Turner return Error::success(); 564d49eb9fSZachary Turner } 574d49eb9fSZachary Turner case LF_SHORT: { 584d49eb9fSZachary Turner int16_t N; 59695ed56bSZachary Turner if (auto EC = Reader.readInteger(N)) 604d49eb9fSZachary Turner return EC; 614d49eb9fSZachary Turner Num = APSInt(APInt(16, N, true), false); 62660230ebSZachary Turner return Error::success(); 634d49eb9fSZachary Turner } 644d49eb9fSZachary Turner case LF_USHORT: { 654d49eb9fSZachary Turner uint16_t N; 66695ed56bSZachary Turner if (auto EC = Reader.readInteger(N)) 674d49eb9fSZachary Turner return EC; 684d49eb9fSZachary Turner Num = APSInt(APInt(16, N, false), true); 69660230ebSZachary Turner return Error::success(); 704d49eb9fSZachary Turner } 714d49eb9fSZachary Turner case LF_LONG: { 724d49eb9fSZachary Turner int32_t N; 73695ed56bSZachary Turner if (auto EC = Reader.readInteger(N)) 744d49eb9fSZachary Turner return EC; 754d49eb9fSZachary Turner Num = APSInt(APInt(32, N, true), false); 76660230ebSZachary Turner return Error::success(); 774d49eb9fSZachary Turner } 784d49eb9fSZachary Turner case LF_ULONG: { 794d49eb9fSZachary Turner uint32_t N; 80695ed56bSZachary Turner if (auto EC = Reader.readInteger(N)) 814d49eb9fSZachary Turner return EC; 824d49eb9fSZachary Turner Num = APSInt(APInt(32, N, FalseVal), true); 83660230ebSZachary Turner return Error::success(); 844d49eb9fSZachary Turner } 854d49eb9fSZachary Turner case LF_QUADWORD: { 864d49eb9fSZachary Turner int64_t N; 87695ed56bSZachary Turner if (auto EC = Reader.readInteger(N)) 884d49eb9fSZachary Turner return EC; 894d49eb9fSZachary Turner Num = APSInt(APInt(64, N, true), false); 90660230ebSZachary Turner return Error::success(); 914d49eb9fSZachary Turner } 924d49eb9fSZachary Turner case LF_UQUADWORD: { 934d49eb9fSZachary Turner uint64_t N; 94695ed56bSZachary Turner if (auto EC = Reader.readInteger(N)) 954d49eb9fSZachary Turner return EC; 964d49eb9fSZachary Turner Num = APSInt(APInt(64, N, false), true); 97660230ebSZachary Turner return Error::success(); 9838cc8b3fSZachary Turner } 994d49eb9fSZachary Turner } 100660230ebSZachary Turner return make_error<CodeViewError>(cv_error_code::corrupt_record, 101660230ebSZachary Turner "Buffer contains invalid APSInt type"); 10238cc8b3fSZachary Turner } 10338cc8b3fSZachary Turner 104660230ebSZachary Turner Error llvm::codeview::consume(StringRef &Data, APSInt &Num) { 10538cc8b3fSZachary Turner ArrayRef<uint8_t> Bytes(Data.bytes_begin(), Data.bytes_end()); 106695ed56bSZachary Turner BinaryByteStream S(Bytes, llvm::support::little); 107120faca4SZachary Turner BinaryStreamReader SR(S); 1084d49eb9fSZachary Turner auto EC = consume(SR, Num); 1094d49eb9fSZachary Turner Data = Data.take_back(SR.bytesRemaining()); 11038cc8b3fSZachary Turner return EC; 11138cc8b3fSZachary Turner } 11238cc8b3fSZachary Turner 11338cc8b3fSZachary Turner /// Decode a numeric leaf value that is known to be a uint64_t. 114120faca4SZachary Turner Error llvm::codeview::consume_numeric(BinaryStreamReader &Reader, 1154d49eb9fSZachary Turner uint64_t &Num) { 11638cc8b3fSZachary Turner APSInt N; 1174d49eb9fSZachary Turner if (auto EC = consume(Reader, N)) 11838cc8b3fSZachary Turner return EC; 11938cc8b3fSZachary Turner if (N.isSigned() || !N.isIntN(64)) 120660230ebSZachary Turner return make_error<CodeViewError>(cv_error_code::corrupt_record, 121660230ebSZachary Turner "Data is not a numeric value!"); 12238cc8b3fSZachary Turner Num = N.getLimitedValue(); 123660230ebSZachary Turner return Error::success(); 12438cc8b3fSZachary Turner } 12538cc8b3fSZachary Turner 126120faca4SZachary Turner Error llvm::codeview::consume(BinaryStreamReader &Reader, uint32_t &Item) { 127695ed56bSZachary Turner return Reader.readInteger(Item); 12838cc8b3fSZachary Turner } 12938cc8b3fSZachary Turner 130660230ebSZachary Turner Error llvm::codeview::consume(StringRef &Data, uint32_t &Item) { 13138cc8b3fSZachary Turner ArrayRef<uint8_t> Bytes(Data.bytes_begin(), Data.bytes_end()); 132695ed56bSZachary Turner BinaryByteStream S(Bytes, llvm::support::little); 133120faca4SZachary Turner BinaryStreamReader SR(S); 1344d49eb9fSZachary Turner auto EC = consume(SR, Item); 1354d49eb9fSZachary Turner Data = Data.take_back(SR.bytesRemaining()); 13638cc8b3fSZachary Turner return EC; 13738cc8b3fSZachary Turner } 13838cc8b3fSZachary Turner 139120faca4SZachary Turner Error llvm::codeview::consume(BinaryStreamReader &Reader, int32_t &Item) { 140695ed56bSZachary Turner return Reader.readInteger(Item); 14138cc8b3fSZachary Turner } 14238cc8b3fSZachary Turner 143120faca4SZachary Turner Error llvm::codeview::consume(BinaryStreamReader &Reader, StringRef &Item) { 1444d49eb9fSZachary Turner if (Reader.empty()) 145660230ebSZachary Turner return make_error<CodeViewError>(cv_error_code::corrupt_record, 146660230ebSZachary Turner "Null terminated string buffer is empty!"); 14738cc8b3fSZachary Turner 148120faca4SZachary Turner return Reader.readCString(Item); 14938cc8b3fSZachary Turner } 15014d90fd0SReid Kleckner 15114d90fd0SReid Kleckner Expected<CVSymbol> llvm::codeview::readSymbolFromStream(BinaryStreamRef Stream, 15214d90fd0SReid Kleckner uint32_t Offset) { 15314d90fd0SReid Kleckner return readCVRecordFromStream<SymbolKind>(Stream, Offset); 15414d90fd0SReid Kleckner } 155