mirror of
https://github.com/RPCS3/llvm.git
synced 2025-04-15 04:20:27 +00:00

Until now, our use case for the visitor has been to take a stream of bytes representing a type stream, deserialize the records in sequence, and do something with them, where "something" is determined by how the user implements a particular set of callbacks on an abstract class. For actually writing PDBs, however, we want to do the reverse. We have some kind of description of the list of records in their in-memory format, and we want to process each one. Perhaps by serializing them to a byte stream, or perhaps by converting them from one description format (Yaml) to another (in-memory representation). This was difficult in the current model because deserialization and invoking the callbacks were tightly coupled. With this patch we change this so that TypeDeserializer is itself an implementation of the particular set of callbacks. This decouples deserialization from the iteration over a list of records and invocation of the callbacks. TypeDeserializer is initialized with another implementation of the callback interface, so that upon deserialization it can pass the deserialized record through to the next set of callbacks. In a sense this is like an implementation of the Decorator design pattern, where the Deserializer is a decorator. This will be useful for writing Pdbs from yaml, where we have a description of the type records in Yaml format. In this case, the visitor implementation would have each visitation callback method implemented in such a way as to extract the proper set of fields from the Yaml, and it could maintain state that builds up a list of these records. Finally at the end we can pass this information through to another set of callbacks which serializes them into a byte stream. Reviewed By: majnemer, ruiu, rnk Differential Revision: https://reviews.llvm.org/D23177 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@277871 91177308-0d34-0410-b5e6-96231b3b80d8
103 lines
3.8 KiB
C++
103 lines
3.8 KiB
C++
//===-- ListRecordBuilder.cpp ---------------------------------------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/ADT/SmallString.h"
|
|
#include "llvm/DebugInfo/CodeView/ListRecordBuilder.h"
|
|
#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
|
|
|
|
using namespace llvm;
|
|
using namespace codeview;
|
|
|
|
ListRecordBuilder::ListRecordBuilder(TypeRecordKind Kind)
|
|
: Kind(Kind), Builder(Kind) {}
|
|
|
|
void ListRecordBuilder::writeMemberType(const ListContinuationRecord &R) {
|
|
TypeRecordBuilder &Builder = getBuilder();
|
|
|
|
assert(getLastContinuationSize() < 65535 - 8 && "continuation won't fit");
|
|
|
|
Builder.writeTypeRecordKind(TypeRecordKind::ListContinuation);
|
|
Builder.writeUInt16(0);
|
|
Builder.writeTypeIndex(R.getContinuationIndex());
|
|
|
|
// End the current segment manually so that nothing comes after the
|
|
// continuation.
|
|
ContinuationOffsets.push_back(Builder.size());
|
|
SubrecordStart = Builder.size();
|
|
}
|
|
|
|
void ListRecordBuilder::finishSubRecord() {
|
|
// The type table inserts a 16 bit size field before each list, so factor that
|
|
// into our alignment padding.
|
|
uint32_t Remainder =
|
|
(Builder.size() + 2 * (ContinuationOffsets.size() + 1)) % 4;
|
|
if (Remainder != 0) {
|
|
for (int32_t PaddingBytesLeft = 4 - Remainder; PaddingBytesLeft > 0;
|
|
--PaddingBytesLeft) {
|
|
Builder.writeUInt8(LF_PAD0 + PaddingBytesLeft);
|
|
}
|
|
}
|
|
|
|
// Check if this subrecord makes the current segment not fit in 64K minus the
|
|
// space for a continuation record (8 bytes). If the segment does not fit,
|
|
// back up and insert a continuation record, sliding the current subrecord
|
|
// down.
|
|
if (getLastContinuationSize() > 65535 - 8) {
|
|
assert(SubrecordStart != 0 && "can't slide from the start!");
|
|
SmallString<128> SubrecordCopy(
|
|
Builder.str().slice(SubrecordStart, Builder.size()));
|
|
assert(SubrecordCopy.size() < 65530 && "subrecord is too large to slide!");
|
|
Builder.truncate(SubrecordStart);
|
|
|
|
// Write a placeholder continuation record.
|
|
Builder.writeTypeRecordKind(TypeRecordKind::ListContinuation);
|
|
Builder.writeUInt16(0);
|
|
Builder.writeUInt32(0);
|
|
ContinuationOffsets.push_back(Builder.size());
|
|
assert(Builder.size() == SubrecordStart + 8 && "wrong continuation size");
|
|
assert(getLastContinuationSize() < 65535 && "segment too big");
|
|
|
|
// Start a new list record of the appropriate kind, and copy the previous
|
|
// subrecord into place.
|
|
Builder.writeTypeRecordKind(Kind);
|
|
Builder.writeBytes(SubrecordCopy);
|
|
}
|
|
|
|
SubrecordStart = Builder.size();
|
|
}
|
|
|
|
TypeIndex ListRecordBuilder::writeListRecord(TypeTableBuilder &Table) {
|
|
// Get the continuation segments as a reversed vector of StringRefs for
|
|
// convenience.
|
|
SmallVector<StringRef, 1> Segments;
|
|
StringRef Data = str();
|
|
size_t LastEnd = 0;
|
|
for (size_t SegEnd : ContinuationOffsets) {
|
|
Segments.push_back(Data.slice(LastEnd, SegEnd));
|
|
LastEnd = SegEnd;
|
|
}
|
|
Segments.push_back(Data.slice(LastEnd, Builder.size()));
|
|
|
|
// Pop the last record off and emit it directly.
|
|
StringRef LastRec = Segments.pop_back_val();
|
|
TypeIndex ContinuationIndex = Table.writeRecord(LastRec);
|
|
|
|
// Emit each record with a continuation in reverse order, so that each one
|
|
// references the previous record.
|
|
for (StringRef Rec : reverse(Segments)) {
|
|
assert(*reinterpret_cast<const ulittle16_t *>(Rec.data()) ==
|
|
unsigned(Kind));
|
|
ulittle32_t *ContinuationPtr =
|
|
reinterpret_cast<ulittle32_t *>(const_cast<char *>(Rec.end())) - 1;
|
|
*ContinuationPtr = ContinuationIndex.getIndex();
|
|
ContinuationIndex = Table.writeRecord(Rec);
|
|
}
|
|
return ContinuationIndex;
|
|
}
|