summaryrefslogtreecommitdiffstats
path: root/gnu/llvm/lib/DebugInfo/CodeView/ContinuationRecordBuilder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/llvm/lib/DebugInfo/CodeView/ContinuationRecordBuilder.cpp')
-rw-r--r--gnu/llvm/lib/DebugInfo/CodeView/ContinuationRecordBuilder.cpp259
1 files changed, 0 insertions, 259 deletions
diff --git a/gnu/llvm/lib/DebugInfo/CodeView/ContinuationRecordBuilder.cpp b/gnu/llvm/lib/DebugInfo/CodeView/ContinuationRecordBuilder.cpp
deleted file mode 100644
index f180fc6990f..00000000000
--- a/gnu/llvm/lib/DebugInfo/CodeView/ContinuationRecordBuilder.cpp
+++ /dev/null
@@ -1,259 +0,0 @@
-#include "llvm/DebugInfo/CodeView/ContinuationRecordBuilder.h"
-
-using namespace llvm;
-using namespace llvm::codeview;
-
-namespace {
-struct ContinuationRecord {
- ulittle16_t Kind{uint16_t(TypeLeafKind::LF_INDEX)};
- ulittle16_t Size{0};
- ulittle32_t IndexRef{0xB0C0B0C0};
-};
-
-struct SegmentInjection {
- SegmentInjection(TypeLeafKind Kind) { Prefix.RecordKind = Kind; }
-
- ContinuationRecord Cont;
- RecordPrefix Prefix;
-};
-} // namespace
-
-static void addPadding(BinaryStreamWriter &Writer) {
- uint32_t Align = Writer.getOffset() % 4;
- if (Align == 0)
- return;
-
- int PaddingBytes = 4 - Align;
- while (PaddingBytes > 0) {
- uint8_t Pad = static_cast<uint8_t>(LF_PAD0 + PaddingBytes);
- cantFail(Writer.writeInteger(Pad));
- --PaddingBytes;
- }
-}
-
-static SegmentInjection InjectFieldList(TypeLeafKind::LF_FIELDLIST);
-static SegmentInjection InjectMethodOverloadList(TypeLeafKind::LF_METHODLIST);
-
-static constexpr uint32_t ContinuationLength = sizeof(ContinuationRecord);
-static constexpr uint32_t MaxSegmentLength =
- MaxRecordLength - ContinuationLength;
-
-static inline TypeLeafKind getTypeLeafKind(ContinuationRecordKind CK) {
- return (CK == ContinuationRecordKind::FieldList) ? LF_FIELDLIST
- : LF_METHODLIST;
-}
-
-ContinuationRecordBuilder::ContinuationRecordBuilder()
- : SegmentWriter(Buffer), Mapping(SegmentWriter) {}
-
-ContinuationRecordBuilder::~ContinuationRecordBuilder() {}
-
-void ContinuationRecordBuilder::begin(ContinuationRecordKind RecordKind) {
- assert(!Kind.hasValue());
- Kind = RecordKind;
- Buffer.clear();
- SegmentWriter.setOffset(0);
- SegmentOffsets.clear();
- SegmentOffsets.push_back(0);
- assert(SegmentWriter.getOffset() == 0);
- assert(SegmentWriter.getLength() == 0);
-
- const SegmentInjection *FLI =
- (RecordKind == ContinuationRecordKind::FieldList)
- ? &InjectFieldList
- : &InjectMethodOverloadList;
- const uint8_t *FLIB = reinterpret_cast<const uint8_t *>(FLI);
- InjectedSegmentBytes =
- ArrayRef<uint8_t>(FLIB, FLIB + sizeof(SegmentInjection));
-
- CVType Type;
- Type.Type = getTypeLeafKind(RecordKind);
- cantFail(Mapping.visitTypeBegin(Type));
-
- // Seed the first trecord with an appropriate record prefix.
- RecordPrefix Prefix;
- Prefix.RecordLen = 0;
- Prefix.RecordKind = Type.Type;
- cantFail(SegmentWriter.writeObject(Prefix));
-}
-
-template <typename RecordType>
-void ContinuationRecordBuilder::writeMemberType(RecordType &Record) {
- assert(Kind.hasValue());
-
- uint32_t OriginalOffset = SegmentWriter.getOffset();
- CVMemberRecord CVMR;
- CVMR.Kind = static_cast<TypeLeafKind>(Record.getKind());
-
- // Member Records aren't length-prefixed, they only have a 2-byte TypeLeafKind
- // at the beginning.
- cantFail(SegmentWriter.writeEnum(CVMR.Kind));
-
- // Let the Mapping handle the rest.
- cantFail(Mapping.visitMemberBegin(CVMR));
- cantFail(Mapping.visitKnownMember(CVMR, Record));
- cantFail(Mapping.visitMemberEnd(CVMR));
-
- // Make sure it's padded to 4 bytes.
- addPadding(SegmentWriter);
- assert(getCurrentSegmentLength() % 4 == 0);
-
- // The maximum length of a single segment is 64KB minus the size to insert a
- // continuation. So if we are over that, inject a continuation between the
- // previous member and the member that was just written, then end the previous
- // segment after the continuation and begin a new one with the just-written
- // member.
- if (getCurrentSegmentLength() > MaxSegmentLength) {
- // We need to inject some bytes before the member we just wrote but after
- // the previous member. Save off the length of the member we just wrote so
- // that we can do some sanity checking on it.
- uint32_t MemberLength = SegmentWriter.getOffset() - OriginalOffset;
- (void) MemberLength;
- insertSegmentEnd(OriginalOffset);
- // Since this member now becomes a new top-level record, it should have
- // gotten a RecordPrefix injected, and that RecordPrefix + the member we
- // just wrote should now constitute the entirety of the current "new"
- // segment.
- assert(getCurrentSegmentLength() == MemberLength + sizeof(RecordPrefix));
- }
-
- assert(getCurrentSegmentLength() % 4 == 0);
- assert(getCurrentSegmentLength() <= MaxSegmentLength);
-}
-
-uint32_t ContinuationRecordBuilder::getCurrentSegmentLength() const {
- return SegmentWriter.getOffset() - SegmentOffsets.back();
-}
-
-void ContinuationRecordBuilder::insertSegmentEnd(uint32_t Offset) {
- uint32_t SegmentBegin = SegmentOffsets.back();
- (void)SegmentBegin;
- assert(Offset > SegmentBegin);
- assert(Offset - SegmentBegin <= MaxSegmentLength);
-
- // We need to make space for the continuation record. For now we can't fill
- // out the length or the TypeIndex of the back-reference, but we need the
- // space to at least be there.
- Buffer.insert(Offset, InjectedSegmentBytes);
-
- uint32_t NewSegmentBegin = Offset + ContinuationLength;
- uint32_t SegmentLength = NewSegmentBegin - SegmentOffsets.back();
- (void) SegmentLength;
-
- assert(SegmentLength % 4 == 0);
- assert(SegmentLength <= MaxRecordLength);
- SegmentOffsets.push_back(NewSegmentBegin);
-
- // Seek to the end so that we can keep writing against the new segment.
- SegmentWriter.setOffset(SegmentWriter.getLength());
- assert(SegmentWriter.bytesRemaining() == 0);
-}
-
-CVType ContinuationRecordBuilder::createSegmentRecord(
- uint32_t OffBegin, uint32_t OffEnd, Optional<TypeIndex> RefersTo) {
- assert(OffEnd - OffBegin <= USHRT_MAX);
-
- MutableArrayRef<uint8_t> Data = Buffer.data();
- Data = Data.slice(OffBegin, OffEnd - OffBegin);
-
- CVType Type;
- Type.Type = getTypeLeafKind(*Kind);
- Type.RecordData = Data;
-
- // Write the length to the RecordPrefix, making sure it does not include
- // sizeof(RecordPrefix.Length)
- RecordPrefix *Prefix = reinterpret_cast<RecordPrefix *>(Data.data());
- assert(Prefix->RecordKind == Type.Type);
- Prefix->RecordLen = Data.size() - sizeof(RecordPrefix::RecordLen);
-
- if (RefersTo.hasValue()) {
- auto Continuation = Data.take_back(ContinuationLength);
- ContinuationRecord *CR =
- reinterpret_cast<ContinuationRecord *>(Continuation.data());
- assert(CR->Kind == TypeLeafKind::LF_INDEX);
- assert(CR->IndexRef == 0xB0C0B0C0);
- CR->IndexRef = RefersTo->getIndex();
- }
-
- return Type;
-}
-
-std::vector<CVType> ContinuationRecordBuilder::end(TypeIndex Index) {
- CVType Type;
- Type.Type = getTypeLeafKind(*Kind);
- cantFail(Mapping.visitTypeEnd(Type));
-
- // We're now done, and we have a series of segments each beginning at an
- // offset specified in the SegmentOffsets array. We now need to iterate
- // over each segment and post-process them in the following two ways:
- // 1) Each top-level record has a RecordPrefix whose type is either
- // LF_FIELDLIST or LF_METHODLIST, but the Length field is still 0.
- // Those should all be set to the correct length now.
- // 2) Each continuation record has an IndexRef field which we set to the
- // magic value 0xB0C0B0C0. Now that the caller has told us the TypeIndex
- // they want this sequence to start from, we can go through and update
- // each one.
- //
- // Logically, the sequence of records we've built up looks like this:
- //
- // SegmentOffsets[0]: <Length> (Initially: uninitialized)
- // SegmentOffsets[0]+2: LF_FIELDLIST
- // SegmentOffsets[0]+4: Member[0]
- // SegmentOffsets[0]+?: ...
- // SegmentOffsets[0]+?: Member[4]
- // SegmentOffsets[1]-8: LF_INDEX
- // SegmentOffsets[1]-6: 0
- // SegmentOffsets[1]-4: <Type Index of Next Record> (Initially: 0xB0C0B0C0)
- //
- // SegmentOffsets[1]: <Length> (Initially: uninitialized)
- // SegmentOffsets[1]+2: LF_FIELDLIST
- // SegmentOffsets[1]+4: Member[0]
- // SegmentOffsets[1]+?: ...
- // SegmentOffsets[1]+?: Member[s]
- // SegmentOffsets[2]-8: LF_INDEX
- // SegmentOffsets[2]-6: 0
- // SegmentOffsets[2]-4: <Type Index of Next Record> (Initially: 0xB0C0B0C0)
- //
- // ...
- //
- // SegmentOffsets[N]: <Length> (Initially: uninitialized)
- // SegmentOffsets[N]+2: LF_FIELDLIST
- // SegmentOffsets[N]+4: Member[0]
- // SegmentOffsets[N]+?: ...
- // SegmentOffsets[N]+?: Member[t]
- //
- // And this is the way we have laid them out in the serialization buffer. But
- // we cannot actually commit them to the underlying stream this way, due to
- // the topological sorting requirement of a type stream (specifically,
- // TypeIndex references can only point backwards, not forwards). So the
- // sequence that we return to the caller contains the records in reverse
- // order, which is the proper order for committing the serialized records.
-
- std::vector<CVType> Types;
- Types.reserve(SegmentOffsets.size());
-
- auto SO = makeArrayRef(SegmentOffsets);
-
- uint32_t End = SegmentWriter.getOffset();
-
- Optional<TypeIndex> RefersTo;
- for (uint32_t Offset : reverse(SO)) {
- Types.push_back(createSegmentRecord(Offset, End, RefersTo));
-
- End = Offset;
- RefersTo = Index++;
- }
-
- Kind.reset();
- return Types;
-}
-
-// Explicitly instantiate the member function for each known type so that we can
-// implement this in the cpp file.
-#define TYPE_RECORD(EnumName, EnumVal, Name)
-#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
-#define MEMBER_RECORD(EnumName, EnumVal, Name) \
- template void llvm::codeview::ContinuationRecordBuilder::writeMemberType( \
- Name##Record &Record);
-#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
-#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"