Skip to content

Commit

Permalink
[pdb] Pass CVRecord's through the visitor as non-const references.
Browse files Browse the repository at this point in the history
This simplifies a lot of code, and will actually be necessary for
an upcoming patch to serialize TPI record hash values.

The idea before was that visitors should be examining records, not
modifying them.  But this is no longer true with a visitor that
constructs a CVRecord from Yaml.  To handle this until now, we
were doing some fixups on CVRecord objects at a higher level, but
the code is really awkward, and it makes sense to just have the
visitor write the bytes into the CVRecord.  In doing so I uncovered
a few bugs related to `Data` and `RawData` and fixed those.

Reviewed By: rnk
Differential Revision: https://reviews.llvm.org/D24362

llvm-svn: 281067
  • Loading branch information
Zachary Turner committed Sep 9, 2016
1 parent 00ef271 commit 9ba31a5
Show file tree
Hide file tree
Showing 15 changed files with 139 additions and 162 deletions.
2 changes: 1 addition & 1 deletion llvm/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h
Expand Up @@ -23,7 +23,7 @@ class CVTypeVisitor {
public:
explicit CVTypeVisitor(TypeVisitorCallbacks &Callbacks);

Error visitTypeRecord(const CVRecord<TypeLeafKind> &Record);
Error visitTypeRecord(CVRecord<TypeLeafKind> &Record);

/// Visits the type records in Data. Sets the error flag on parse failures.
Error visitTypeStream(const CVTypeArray &Types);
Expand Down
6 changes: 3 additions & 3 deletions llvm/include/llvm/DebugInfo/CodeView/TypeDeserializer.h
Expand Up @@ -20,8 +20,8 @@ class TypeDeserializer : public TypeVisitorCallbacks {
TypeDeserializer() {}

#define TYPE_RECORD(EnumName, EnumVal, Name) \
Error visitKnownRecord(const CVRecord<TypeLeafKind> &CVR, \
Name##Record &Record) override { \
Error visitKnownRecord(CVRecord<TypeLeafKind> &CVR, Name##Record &Record) \
override { \
return defaultVisitKnownRecord(CVR, Record); \
}
#define MEMBER_RECORD(EnumName, EnumVal, Name) \
Expand All @@ -45,7 +45,7 @@ class TypeDeserializer : public TypeVisitorCallbacks {

private:
template <typename T>
Error defaultVisitKnownRecord(const CVRecord<TypeLeafKind> &CVR, T &Record) {
Error defaultVisitKnownRecord(CVRecord<TypeLeafKind> &CVR, T &Record) {
ArrayRef<uint8_t> RD = CVR.Data;
if (auto EC = deserializeRecord(RD, CVR.Type, Record))
return EC;
Expand Down
13 changes: 6 additions & 7 deletions llvm/include/llvm/DebugInfo/CodeView/TypeDumper.h
Expand Up @@ -63,18 +63,17 @@ class CVTypeDumper : public TypeVisitorCallbacks {
ScopedPrinter *getPrinter() { return W; }

/// Action to take on unknown types. By default, they are ignored.
Error visitUnknownType(const CVRecord<TypeLeafKind> &Record) override;
Error visitUnknownMember(const CVRecord<TypeLeafKind> &Record) override;
Error visitUnknownType(CVRecord<TypeLeafKind> &Record) override;
Error visitUnknownMember(CVRecord<TypeLeafKind> &Record) override;

/// Paired begin/end actions for all types. Receives all record data,
/// including the fixed-length record prefix.
Expected<TypeLeafKind>
visitTypeBegin(const CVRecord<TypeLeafKind> &Record) override;
Error visitTypeEnd(const CVRecord<TypeLeafKind> &Record) override;
Error visitTypeBegin(CVRecord<TypeLeafKind> &Record) override;
Error visitTypeEnd(CVRecord<TypeLeafKind> &Record) override;

#define TYPE_RECORD(EnumName, EnumVal, Name) \
Error visitKnownRecord(const CVRecord<TypeLeafKind> &CVR, \
Name##Record &Record) override;
Error visitKnownRecord(CVRecord<TypeLeafKind> &CVR, Name##Record &Record) \
override;
#define MEMBER_RECORD(EnumName, EnumVal, Name) \
TYPE_RECORD(EnumName, EnumVal, Name)
#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
Expand Down
19 changes: 14 additions & 5 deletions llvm/include/llvm/DebugInfo/CodeView/TypeSerializationVisitor.h
Expand Up @@ -15,6 +15,7 @@
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"

#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Error.h"

namespace llvm {
namespace codeview {
Expand All @@ -26,27 +27,35 @@ class TypeSerializationVisitor : public TypeVisitorCallbacks {
: FieldListBuilder(FieldListBuilder), TypeTableBuilder(TypeTableBuilder) {
}

virtual Expected<TypeLeafKind> visitTypeBegin(const CVType &Record) override {
virtual Error visitTypeBegin(CVType &Record) override {
if (Record.Type == TypeLeafKind::LF_FIELDLIST)
FieldListBuilder.reset();
return Record.Type;
return Error::success();
}

virtual Error visitTypeEnd(const CVRecord<TypeLeafKind> &Record) override {
virtual Error visitTypeEnd(CVType &Record) override {
// Since this visitor's purpose is to serialize the record, fill out the
// fields of `Record` with the bytes of the record.
if (Record.Type == TypeLeafKind::LF_FIELDLIST)
TypeTableBuilder.writeFieldList(FieldListBuilder);

StringRef S = TypeTableBuilder.getRecords().back();
ArrayRef<uint8_t> Data(S.bytes_begin(), S.bytes_end());
Record.RawData = Data;
Record.Data = Record.RawData.drop_front(sizeof(RecordPrefix));
Record.Length = Data.size() - sizeof(ulittle16_t);
return Error::success();
}

#define TYPE_RECORD(EnumName, EnumVal, Name) \
virtual Error visitKnownRecord(const CVRecord<TypeLeafKind> &CVR, \
virtual Error visitKnownRecord(CVRecord<TypeLeafKind> &CVR, \
Name##Record &Record) override { \
visitKnownRecordImpl(Record); \
return Error::success(); \
}
#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
#define MEMBER_RECORD(EnumName, EnumVal, Name) \
virtual Error visitKnownRecord(const CVRecord<TypeLeafKind> &CVR, \
virtual Error visitKnownRecord(CVRecord<TypeLeafKind> &CVR, \
Name##Record &Record) override { \
visitMemberRecordImpl(Record); \
return Error::success(); \
Expand Down
29 changes: 9 additions & 20 deletions llvm/include/llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h
Expand Up @@ -22,41 +22,30 @@ class TypeVisitorCallbackPipeline : public TypeVisitorCallbacks {
public:
TypeVisitorCallbackPipeline() {}

virtual Error
visitUnknownType(const CVRecord<TypeLeafKind> &Record) override {
virtual Error visitUnknownType(CVRecord<TypeLeafKind> &Record) override {
for (auto Visitor : Pipeline) {
if (auto EC = Visitor->visitUnknownType(Record))
return EC;
}
return Error::success();
}

virtual Error
visitUnknownMember(const CVRecord<TypeLeafKind> &Record) override {
virtual Error visitUnknownMember(CVRecord<TypeLeafKind> &Record) override {
for (auto Visitor : Pipeline) {
if (auto EC = Visitor->visitUnknownMember(Record))
return EC;
}
return Error::success();
}

virtual Expected<TypeLeafKind>
visitTypeBegin(const CVRecord<TypeLeafKind> &Record) override {
// An implementation can calculate of visitTypeBegin() can calculate the
// kind based on an arbitrary factor, including the Type that is already
// specified in the Record. So, as we go through the pipeline invoking
// each visitor, update the state in a copy of the record so that each
// visitor in the pipeline sees the most recently value of the type.
CVRecord<TypeLeafKind> RecordCopy = Record;
virtual Error visitTypeBegin(CVRecord<TypeLeafKind> &Record) override {
for (auto Visitor : Pipeline) {
if (auto ExpectedKind = Visitor->visitTypeBegin(RecordCopy)) {
RecordCopy.Type = *ExpectedKind;
} else
return ExpectedKind.takeError();
if (auto EC = Visitor->visitTypeBegin(Record))
return EC;
}
return RecordCopy.Type;
return Error::success();
}
virtual Error visitTypeEnd(const CVRecord<TypeLeafKind> &Record) override {
virtual Error visitTypeEnd(CVRecord<TypeLeafKind> &Record) override {
for (auto Visitor : Pipeline) {
if (auto EC = Visitor->visitTypeEnd(Record))
return EC;
Expand All @@ -69,8 +58,8 @@ class TypeVisitorCallbackPipeline : public TypeVisitorCallbacks {
}

#define TYPE_RECORD(EnumName, EnumVal, Name) \
Error visitKnownRecord(const CVRecord<TypeLeafKind> &CVR, \
Name##Record &Record) override { \
Error visitKnownRecord(CVRecord<TypeLeafKind> &CVR, Name##Record &Record) \
override { \
for (auto Visitor : Pipeline) { \
if (auto EC = Visitor->visitKnownRecord(CVR, Record)) \
return EC; \
Expand Down
13 changes: 6 additions & 7 deletions llvm/include/llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h
Expand Up @@ -25,26 +25,25 @@ class TypeVisitorCallbacks {
virtual ~TypeVisitorCallbacks() {}

/// Action to take on unknown types. By default, they are ignored.
virtual Error visitUnknownType(const CVRecord<TypeLeafKind> &Record) {
virtual Error visitUnknownType(CVRecord<TypeLeafKind> &Record) {
return Error::success();
}
virtual Error visitUnknownMember(const CVRecord<TypeLeafKind> &Record) {
virtual Error visitUnknownMember(CVRecord<TypeLeafKind> &Record) {
return Error::success();
}

/// Paired begin/end actions for all types. Receives all record data,
/// including the fixed-length record prefix. visitTypeBegin() should return
/// the type of the Record, or an error if it cannot be determined.
virtual Expected<TypeLeafKind>
visitTypeBegin(const CVRecord<TypeLeafKind> &Record) {
return Record.Type;
virtual Error visitTypeBegin(CVRecord<TypeLeafKind> &Record) {
return Error::success();
}
virtual Error visitTypeEnd(const CVRecord<TypeLeafKind> &Record) {
virtual Error visitTypeEnd(CVRecord<TypeLeafKind> &Record) {
return Error::success();
}

#define TYPE_RECORD(EnumName, EnumVal, Name) \
virtual Error visitKnownRecord(const CVRecord<TypeLeafKind> &CVR, \
virtual Error visitKnownRecord(CVRecord<TypeLeafKind> &CVR, \
Name##Record &Record) { \
return Error::success(); \
}
Expand Down
4 changes: 3 additions & 1 deletion llvm/include/llvm/DebugInfo/PDB/Raw/TpiStreamBuilder.h
Expand Up @@ -30,7 +30,9 @@ class ReadableStreamRef;
class WritableStream;

template <> struct SequencedItemTraits<llvm::codeview::CVType> {
static size_t length(const codeview::CVType &Item) { return Item.Length; }
static size_t length(const codeview::CVType &Item) {
return Item.RawData.size();
}
static ArrayRef<uint8_t> bytes(const codeview::CVType &Item) {
return Item.RawData;
}
Expand Down
51 changes: 26 additions & 25 deletions llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp
Expand Up @@ -65,7 +65,7 @@ CVTypeVisitor::CVTypeVisitor(TypeVisitorCallbacks &Callbacks)
: Callbacks(Callbacks) {}

template <typename T>
static Error visitKnownRecord(const CVRecord<TypeLeafKind> &Record,
static Error visitKnownRecord(CVRecord<TypeLeafKind> &Record,
TypeVisitorCallbacks &Callbacks) {
TypeRecordKind RK = static_cast<TypeRecordKind>(Record.Type);
T KnownRecord(RK);
Expand All @@ -74,24 +74,18 @@ static Error visitKnownRecord(const CVRecord<TypeLeafKind> &Record,
return Error::success();
}

Error CVTypeVisitor::visitTypeRecord(const CVRecord<TypeLeafKind> &Record) {
TypeLeafKind Kind;
if (auto ExpectedKind = Callbacks.visitTypeBegin(Record))
Kind = *ExpectedKind;
else
return ExpectedKind.takeError();

CVType RecordCopy = Record;
RecordCopy.Type = Kind;
Error CVTypeVisitor::visitTypeRecord(CVRecord<TypeLeafKind> &Record) {
if (auto EC = Callbacks.visitTypeBegin(Record))
return EC;

switch (Kind) {
switch (Record.Type) {
default:
if (auto EC = Callbacks.visitUnknownType(RecordCopy))
if (auto EC = Callbacks.visitUnknownType(Record))
return EC;
break;
#define TYPE_RECORD(EnumName, EnumVal, Name) \
case EnumName: { \
if (auto EC = visitKnownRecord<Name##Record>(RecordCopy, Callbacks)) \
if (auto EC = visitKnownRecord<Name##Record>(Record, Callbacks)) \
return EC; \
break; \
}
Expand All @@ -104,21 +98,37 @@ Error CVTypeVisitor::visitTypeRecord(const CVRecord<TypeLeafKind> &Record) {
#include "llvm/DebugInfo/CodeView/TypeRecords.def"
}

if (auto EC = Callbacks.visitTypeEnd(RecordCopy))
if (auto EC = Callbacks.visitTypeEnd(Record))
return EC;

return Error::success();
}

/// Visits the type records in Data. Sets the error flag on parse failures.
Error CVTypeVisitor::visitTypeStream(const CVTypeArray &Types) {
for (const auto &I : Types) {
for (auto I : Types) {
if (auto EC = visitTypeRecord(I))
return EC;
}
return Error::success();
}

template <typename MR>
static Error visitKnownMember(ArrayRef<uint8_t> &Data, TypeLeafKind Leaf,
TypeVisitorCallbacks &Callbacks) {
auto ExpectedRecord = deserializeMemberRecord<MR>(Data, Leaf);
if (!ExpectedRecord)
return ExpectedRecord.takeError();
CVType &Record = *ExpectedRecord;
if (auto EC = Callbacks.visitTypeBegin(Record))
return EC;
if (auto EC = visitKnownRecord<MR>(Record, Callbacks))
return EC;
if (auto EC = Callbacks.visitTypeEnd(Record))
return EC;
return Error::success();
}

Error CVTypeVisitor::visitFieldListMemberStream(ArrayRef<uint8_t> Data) {
while (!Data.empty()) {
const support::ulittle16_t *LeafValue;
Expand All @@ -135,16 +145,7 @@ Error CVTypeVisitor::visitFieldListMemberStream(ArrayRef<uint8_t> Data) {
cv_error_code::unknown_member_record);
#define MEMBER_RECORD(EnumName, EnumVal, Name) \
case EnumName: { \
auto ExpectedRecord = deserializeMemberRecord<Name##Record>(Data, Leaf); \
if (!ExpectedRecord) \
return ExpectedRecord.takeError(); \
auto &Record = *ExpectedRecord; \
auto ExpectedKind = Callbacks.visitTypeBegin(Record); \
if (!ExpectedKind || *ExpectedKind != Leaf) \
return ExpectedKind.takeError(); \
if (auto EC = visitKnownRecord<Name##Record>(Record, Callbacks)) \
return EC; \
if (auto EC = Callbacks.visitTypeEnd(Record)) \
if (auto EC = visitKnownMember<Name##Record>(Data, Leaf, Callbacks)) \
return EC; \
break; \
}
Expand Down

0 comments on commit 9ba31a5

Please sign in to comment.