155 lines · cpp
1//===-- RecordSerialization.cpp -------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// Utilities for serializing and deserializing CodeView records.10//11//===----------------------------------------------------------------------===//12 13#include "llvm/DebugInfo/CodeView/RecordSerialization.h"14#include "llvm/ADT/APInt.h"15#include "llvm/ADT/APSInt.h"16#include "llvm/DebugInfo/CodeView/CVRecord.h"17#include "llvm/DebugInfo/CodeView/CodeViewError.h"18#include "llvm/DebugInfo/CodeView/SymbolRecord.h"19#include "llvm/Support/BinaryByteStream.h"20 21using namespace llvm;22using namespace llvm::codeview;23using namespace llvm::support;24 25/// Reinterpret a byte array as an array of characters. Does not interpret as26/// a C string, as StringRef has several helpers (split) that make that easy.27StringRef llvm::codeview::getBytesAsCharacters(ArrayRef<uint8_t> LeafData) {28 return StringRef(reinterpret_cast<const char *>(LeafData.data()),29 LeafData.size());30}31 32StringRef llvm::codeview::getBytesAsCString(ArrayRef<uint8_t> LeafData) {33 return getBytesAsCharacters(LeafData).split('\0').first;34}35 36Error llvm::codeview::consume(BinaryStreamReader &Reader, APSInt &Num) {37 // Used to avoid overload ambiguity on APInt constructor.38 bool FalseVal = false;39 uint16_t Short;40 if (auto EC = Reader.readInteger(Short))41 return EC;42 43 if (Short < LF_NUMERIC) {44 Num = APSInt(APInt(/*numBits=*/16, Short, /*isSigned=*/false),45 /*isUnsigned=*/true);46 return Error::success();47 }48 49 switch (Short) {50 case LF_CHAR: {51 int8_t N;52 if (auto EC = Reader.readInteger(N))53 return EC;54 Num = APSInt(APInt(8, N, true), false);55 return Error::success();56 }57 case LF_SHORT: {58 int16_t N;59 if (auto EC = Reader.readInteger(N))60 return EC;61 Num = APSInt(APInt(16, N, true), false);62 return Error::success();63 }64 case LF_USHORT: {65 uint16_t N;66 if (auto EC = Reader.readInteger(N))67 return EC;68 Num = APSInt(APInt(16, N, false), true);69 return Error::success();70 }71 case LF_LONG: {72 int32_t N;73 if (auto EC = Reader.readInteger(N))74 return EC;75 Num = APSInt(APInt(32, N, true), false);76 return Error::success();77 }78 case LF_ULONG: {79 uint32_t N;80 if (auto EC = Reader.readInteger(N))81 return EC;82 Num = APSInt(APInt(32, N, FalseVal), true);83 return Error::success();84 }85 case LF_QUADWORD: {86 int64_t N;87 if (auto EC = Reader.readInteger(N))88 return EC;89 Num = APSInt(APInt(64, N, true), false);90 return Error::success();91 }92 case LF_UQUADWORD: {93 uint64_t N;94 if (auto EC = Reader.readInteger(N))95 return EC;96 Num = APSInt(APInt(64, N, false), true);97 return Error::success();98 }99 }100 return make_error<CodeViewError>(cv_error_code::corrupt_record,101 "Buffer contains invalid APSInt type");102}103 104Error llvm::codeview::consume(StringRef &Data, APSInt &Num) {105 ArrayRef<uint8_t> Bytes(Data.bytes_begin(), Data.bytes_end());106 BinaryByteStream S(Bytes, llvm::endianness::little);107 BinaryStreamReader SR(S);108 auto EC = consume(SR, Num);109 Data = Data.take_back(SR.bytesRemaining());110 return EC;111}112 113/// Decode a numeric leaf value that is known to be a uint64_t.114Error llvm::codeview::consume_numeric(BinaryStreamReader &Reader,115 uint64_t &Num) {116 APSInt N;117 if (auto EC = consume(Reader, N))118 return EC;119 if (N.isSigned() || !N.isIntN(64))120 return make_error<CodeViewError>(cv_error_code::corrupt_record,121 "Data is not a numeric value!");122 Num = N.getLimitedValue();123 return Error::success();124}125 126Error llvm::codeview::consume(BinaryStreamReader &Reader, uint32_t &Item) {127 return Reader.readInteger(Item);128}129 130Error llvm::codeview::consume(StringRef &Data, uint32_t &Item) {131 ArrayRef<uint8_t> Bytes(Data.bytes_begin(), Data.bytes_end());132 BinaryByteStream S(Bytes, llvm::endianness::little);133 BinaryStreamReader SR(S);134 auto EC = consume(SR, Item);135 Data = Data.take_back(SR.bytesRemaining());136 return EC;137}138 139Error llvm::codeview::consume(BinaryStreamReader &Reader, int32_t &Item) {140 return Reader.readInteger(Item);141}142 143Error llvm::codeview::consume(BinaryStreamReader &Reader, StringRef &Item) {144 if (Reader.empty())145 return make_error<CodeViewError>(cv_error_code::corrupt_record,146 "Null terminated string buffer is empty!");147 148 return Reader.readCString(Item);149}150 151Expected<CVSymbol> llvm::codeview::readSymbolFromStream(BinaryStreamRef Stream,152 uint32_t Offset) {153 return readCVRecordFromStream<SymbolKind>(Stream, Offset);154}155