diff options
Diffstat (limited to 'contrib/llvm-project/llvm/lib/DebugInfo/CodeView/CodeViewRecordIO.cpp')
-rw-r--r-- | contrib/llvm-project/llvm/lib/DebugInfo/CodeView/CodeViewRecordIO.cpp | 368 |
1 files changed, 368 insertions, 0 deletions
diff --git a/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/CodeViewRecordIO.cpp b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/CodeViewRecordIO.cpp new file mode 100644 index 000000000000..2f49474115a1 --- /dev/null +++ b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/CodeViewRecordIO.cpp @@ -0,0 +1,368 @@ +//===- CodeViewRecordIO.cpp -------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/CodeViewRecordIO.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/RecordSerialization.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/BinaryStreamWriter.h" + +using namespace llvm; +using namespace llvm::codeview; + +Error CodeViewRecordIO::beginRecord(Optional<uint32_t> MaxLength) { + RecordLimit Limit; + Limit.MaxLength = MaxLength; + Limit.BeginOffset = getCurrentOffset(); + Limits.push_back(Limit); + resetStreamedLen(); + return Error::success(); +} + +Error CodeViewRecordIO::endRecord() { + assert(!Limits.empty() && "Not in a record!"); + Limits.pop_back(); + // We would like to assert that we actually read / wrote all the bytes that we + // expected to for this record, but unfortunately we can't do this. Some + // producers such as MASM over-allocate for certain types of records and + // commit the extraneous data, so when reading we can't be sure every byte + // will have been read. And when writing we over-allocate temporarily since + // we don't know how big the record is until we're finished writing it, so + // even though we don't commit the extraneous data, we still can't guarantee + // we're at the end of the allocated data. + + if (isStreaming()) { + // For streaming mode, add padding to align with 4 byte boundaries for each + // record + uint32_t Align = getStreamedLen() % 4; + if (Align == 0) + return Error::success(); + + int PaddingBytes = 4 - Align; + while (PaddingBytes > 0) { + char Pad = static_cast<uint8_t>(LF_PAD0 + PaddingBytes); + StringRef BytesSR = StringRef(&Pad, sizeof(Pad)); + Streamer->EmitBytes(BytesSR); + --PaddingBytes; + } + } + return Error::success(); +} + +uint32_t CodeViewRecordIO::maxFieldLength() const { + if (isStreaming()) + return 0; + + assert(!Limits.empty() && "Not in a record!"); + + // The max length of the next field is the minimum of all lengths that would + // be allowed by any of the sub-records we're in. In practice, we can only + // ever be at most 1 sub-record deep (in a FieldList), but this works for + // the general case. + uint32_t Offset = getCurrentOffset(); + Optional<uint32_t> Min = Limits.front().bytesRemaining(Offset); + for (auto X : makeArrayRef(Limits).drop_front()) { + Optional<uint32_t> ThisMin = X.bytesRemaining(Offset); + if (ThisMin.hasValue()) + Min = (Min.hasValue()) ? std::min(*Min, *ThisMin) : *ThisMin; + } + assert(Min.hasValue() && "Every field must have a maximum length!"); + + return *Min; +} + +Error CodeViewRecordIO::padToAlignment(uint32_t Align) { + if (isReading()) + return Reader->padToAlignment(Align); + return Writer->padToAlignment(Align); +} + +Error CodeViewRecordIO::skipPadding() { + assert(!isWriting() && "Cannot skip padding while writing!"); + + if (Reader->bytesRemaining() == 0) + return Error::success(); + + uint8_t Leaf = Reader->peek(); + if (Leaf < LF_PAD0) + return Error::success(); + // Leaf is greater than 0xf0. We should advance by the number of bytes in + // the low 4 bits. + unsigned BytesToAdvance = Leaf & 0x0F; + return Reader->skip(BytesToAdvance); +} + +Error CodeViewRecordIO::mapByteVectorTail(ArrayRef<uint8_t> &Bytes, + const Twine &Comment) { + if (isStreaming()) { + emitComment(Comment); + Streamer->EmitBinaryData(toStringRef(Bytes)); + incrStreamedLen(Bytes.size()); + } else if (isWriting()) { + if (auto EC = Writer->writeBytes(Bytes)) + return EC; + } else { + if (auto EC = Reader->readBytes(Bytes, Reader->bytesRemaining())) + return EC; + } + return Error::success(); +} + +Error CodeViewRecordIO::mapByteVectorTail(std::vector<uint8_t> &Bytes, + const Twine &Comment) { + ArrayRef<uint8_t> BytesRef(Bytes); + if (auto EC = mapByteVectorTail(BytesRef, Comment)) + return EC; + if (!isWriting()) + Bytes.assign(BytesRef.begin(), BytesRef.end()); + + return Error::success(); +} + +Error CodeViewRecordIO::mapInteger(TypeIndex &TypeInd, const Twine &Comment) { + if (isStreaming()) { + emitComment(Comment); + Streamer->EmitIntValue(TypeInd.getIndex(), sizeof(TypeInd.getIndex())); + incrStreamedLen(sizeof(TypeInd.getIndex())); + } else if (isWriting()) { + if (auto EC = Writer->writeInteger(TypeInd.getIndex())) + return EC; + } else { + uint32_t I; + if (auto EC = Reader->readInteger(I)) + return EC; + TypeInd.setIndex(I); + } + return Error::success(); +} + +Error CodeViewRecordIO::mapEncodedInteger(int64_t &Value, + const Twine &Comment) { + if (isStreaming()) { + if (Value >= 0) + emitEncodedUnsignedInteger(static_cast<uint64_t>(Value), Comment); + else + emitEncodedSignedInteger(Value, Comment); + } else if (isWriting()) { + if (Value >= 0) { + if (auto EC = writeEncodedUnsignedInteger(static_cast<uint64_t>(Value))) + return EC; + } else { + if (auto EC = writeEncodedSignedInteger(Value)) + return EC; + } + } else { + APSInt N; + if (auto EC = consume(*Reader, N)) + return EC; + Value = N.getExtValue(); + } + + return Error::success(); +} + +Error CodeViewRecordIO::mapEncodedInteger(uint64_t &Value, + const Twine &Comment) { + if (isStreaming()) + emitEncodedUnsignedInteger(Value, Comment); + else if (isWriting()) { + if (auto EC = writeEncodedUnsignedInteger(Value)) + return EC; + } else { + APSInt N; + if (auto EC = consume(*Reader, N)) + return EC; + Value = N.getZExtValue(); + } + return Error::success(); +} + +Error CodeViewRecordIO::mapEncodedInteger(APSInt &Value, const Twine &Comment) { + if (isStreaming()) { + if (Value.isSigned()) + emitEncodedSignedInteger(Value.getSExtValue(), Comment); + else + emitEncodedUnsignedInteger(Value.getZExtValue(), Comment); + } else if (isWriting()) { + if (Value.isSigned()) + return writeEncodedSignedInteger(Value.getSExtValue()); + return writeEncodedUnsignedInteger(Value.getZExtValue()); + } else + return consume(*Reader, Value); + return Error::success(); +} + +Error CodeViewRecordIO::mapStringZ(StringRef &Value, const Twine &Comment) { + if (isStreaming()) { + auto NullTerminatedString = StringRef(Value.data(), Value.size() + 1); + emitComment(Comment); + Streamer->EmitBytes(NullTerminatedString); + incrStreamedLen(NullTerminatedString.size()); + } else if (isWriting()) { + // Truncate if we attempt to write too much. + StringRef S = Value.take_front(maxFieldLength() - 1); + if (auto EC = Writer->writeCString(S)) + return EC; + } else { + if (auto EC = Reader->readCString(Value)) + return EC; + } + return Error::success(); +} + +Error CodeViewRecordIO::mapGuid(GUID &Guid, const Twine &Comment) { + constexpr uint32_t GuidSize = 16; + + if (isStreaming()) { + StringRef GuidSR = + StringRef((reinterpret_cast<const char *>(&Guid)), GuidSize); + emitComment(Comment); + Streamer->EmitBytes(GuidSR); + incrStreamedLen(GuidSize); + return Error::success(); + } + + if (maxFieldLength() < GuidSize) + return make_error<CodeViewError>(cv_error_code::insufficient_buffer); + + if (isWriting()) { + if (auto EC = Writer->writeBytes(Guid.Guid)) + return EC; + } else { + ArrayRef<uint8_t> GuidBytes; + if (auto EC = Reader->readBytes(GuidBytes, GuidSize)) + return EC; + memcpy(Guid.Guid, GuidBytes.data(), GuidSize); + } + return Error::success(); +} + +Error CodeViewRecordIO::mapStringZVectorZ(std::vector<StringRef> &Value, + const Twine &Comment) { + + if (!isReading()) { + emitComment(Comment); + for (auto V : Value) { + if (auto EC = mapStringZ(V)) + return EC; + } + uint8_t FinalZero = 0; + if (auto EC = mapInteger(FinalZero)) + return EC; + } else { + StringRef S; + if (auto EC = mapStringZ(S)) + return EC; + while (!S.empty()) { + Value.push_back(S); + if (auto EC = mapStringZ(S)) + return EC; + }; + } + return Error::success(); +} + +void CodeViewRecordIO::emitEncodedSignedInteger(const int64_t &Value, + const Twine &Comment) { + assert(Value < 0 && "Encoded integer is not signed!"); + if (Value >= std::numeric_limits<int8_t>::min()) { + Streamer->EmitIntValue(LF_CHAR, 2); + emitComment(Comment); + Streamer->EmitIntValue(Value, 1); + incrStreamedLen(3); + } else if (Value >= std::numeric_limits<int16_t>::min()) { + Streamer->EmitIntValue(LF_SHORT, 2); + emitComment(Comment); + Streamer->EmitIntValue(Value, 2); + incrStreamedLen(4); + } else if (Value >= std::numeric_limits<int32_t>::min()) { + Streamer->EmitIntValue(LF_LONG, 2); + emitComment(Comment); + Streamer->EmitIntValue(Value, 4); + incrStreamedLen(6); + } else { + Streamer->EmitIntValue(LF_QUADWORD, 2); + emitComment(Comment); + Streamer->EmitIntValue(Value, 4); + incrStreamedLen(6); + } +} + +void CodeViewRecordIO::emitEncodedUnsignedInteger(const uint64_t &Value, + const Twine &Comment) { + if (Value < LF_NUMERIC) { + emitComment(Comment); + Streamer->EmitIntValue(Value, 2); + incrStreamedLen(2); + } else if (Value <= std::numeric_limits<uint16_t>::max()) { + Streamer->EmitIntValue(LF_USHORT, 2); + emitComment(Comment); + Streamer->EmitIntValue(Value, 2); + incrStreamedLen(4); + } else if (Value <= std::numeric_limits<uint32_t>::max()) { + Streamer->EmitIntValue(LF_ULONG, 2); + emitComment(Comment); + Streamer->EmitIntValue(Value, 4); + incrStreamedLen(6); + } else { + Streamer->EmitIntValue(LF_UQUADWORD, 2); + emitComment(Comment); + Streamer->EmitIntValue(Value, 8); + incrStreamedLen(6); + } +} + +Error CodeViewRecordIO::writeEncodedSignedInteger(const int64_t &Value) { + assert(Value < 0 && "Encoded integer is not signed!"); + if (Value >= std::numeric_limits<int8_t>::min()) { + if (auto EC = Writer->writeInteger<uint16_t>(LF_CHAR)) + return EC; + if (auto EC = Writer->writeInteger<int8_t>(Value)) + return EC; + } else if (Value >= std::numeric_limits<int16_t>::min()) { + if (auto EC = Writer->writeInteger<uint16_t>(LF_SHORT)) + return EC; + if (auto EC = Writer->writeInteger<int16_t>(Value)) + return EC; + } else if (Value >= std::numeric_limits<int32_t>::min()) { + if (auto EC = Writer->writeInteger<uint16_t>(LF_LONG)) + return EC; + if (auto EC = Writer->writeInteger<int32_t>(Value)) + return EC; + } else { + if (auto EC = Writer->writeInteger<uint16_t>(LF_QUADWORD)) + return EC; + if (auto EC = Writer->writeInteger(Value)) + return EC; + } + return Error::success(); +} + +Error CodeViewRecordIO::writeEncodedUnsignedInteger(const uint64_t &Value) { + if (Value < LF_NUMERIC) { + if (auto EC = Writer->writeInteger<uint16_t>(Value)) + return EC; + } else if (Value <= std::numeric_limits<uint16_t>::max()) { + if (auto EC = Writer->writeInteger<uint16_t>(LF_USHORT)) + return EC; + if (auto EC = Writer->writeInteger<uint16_t>(Value)) + return EC; + } else if (Value <= std::numeric_limits<uint32_t>::max()) { + if (auto EC = Writer->writeInteger<uint16_t>(LF_ULONG)) + return EC; + if (auto EC = Writer->writeInteger<uint32_t>(Value)) + return EC; + } else { + if (auto EC = Writer->writeInteger<uint16_t>(LF_UQUADWORD)) + return EC; + if (auto EC = Writer->writeInteger(Value)) + return EC; + } + + return Error::success(); +} |