Skip to content

Commit

Permalink
Add CodeViewRecordIO for reading and writing.
Browse files Browse the repository at this point in the history
Using a pattern similar to that of YamlIO, this allows
us to have a single codepath for translating codeview
records to and from serialized byte streams.  The
current patch only hooks this up to the reading of
CodeView type records.  A subsequent patch will hook
it up for writing of CodeView type records, and then a
third patch will hook up the reading and writing of
CodeView symbols.

Differential Revision: https://reviews.llvm.org/D26040

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@285836 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
Zachary Turner committed Nov 2, 2016
1 parent 08f7b24 commit d773047
Show file tree
Hide file tree
Showing 18 changed files with 1,190 additions and 1,152 deletions.
135 changes: 135 additions & 0 deletions include/llvm/DebugInfo/CodeView/CodeViewRecordIO.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
//===- CodeViewRecordIO.h ---------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_DEBUGINFO_CODEVIEW_CODEVIEWRECORDIO_H
#define LLVM_DEBUGINFO_CODEVIEW_CODEVIEWRECORDIO_H

#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
#include "llvm/DebugInfo/MSF/StreamReader.h"
#include "llvm/DebugInfo/MSF/StreamWriter.h"
#include "llvm/Support/Error.h"

#include <stdint.h>
#include <type_traits>

namespace llvm {
namespace msf {
class StreamReader;
class StreamWriter;
}
namespace codeview {

class CodeViewRecordIO {
struct ActiveRecord {
uint16_t Kind;
};

public:
explicit CodeViewRecordIO(msf::StreamReader &Reader) : Reader(&Reader) {}
explicit CodeViewRecordIO(msf::StreamWriter &Writer) : Writer(&Writer) {}

Error beginRecord(uint16_t Kind);
Error endRecord();
Error mapInteger(TypeIndex &TypeInd);

bool isReading() const { return Reader != nullptr; }
bool isWriting() const { return !isReading(); }

template <typename T> Error mapInteger(T &Value) {
if (isWriting())
return Writer->writeInteger(Value);

return Reader->readInteger(Value);
}

template <typename T> Error mapEnum(T &Value) {
using U = typename std::underlying_type<T>::type;
U X;
if (isWriting())
X = static_cast<U>(Value);

if (auto EC = mapInteger(X))
return EC;
if (isReading())
Value = static_cast<T>(X);
return Error::success();
}

Error mapEncodedInteger(int64_t &Value);
Error mapEncodedInteger(uint64_t &Value);
Error mapEncodedInteger(APSInt &Value);
Error mapStringZ(StringRef &Value);
Error mapGuid(StringRef &Guid);

template <typename SizeType, typename T, typename ElementMapper>
Error mapVectorN(T &Items, const ElementMapper &Mapper) {
SizeType Size;
if (isWriting()) {
Size = static_cast<SizeType>(Items.size());
if (auto EC = Writer->writeInteger(Size))
return EC;

for (auto &X : Items) {
if (auto EC = Mapper(*this, X))
return EC;
}
} else {
if (auto EC = Reader->readInteger(Size))
return EC;
for (SizeType I = 0; I < Size; ++I) {
typename T::value_type Item;
if (auto EC = Mapper(*this, Item))
return EC;
Items.push_back(Item);
}
}

return Error::success();
}

template <typename T, typename ElementMapper>
Error mapVectorTail(T &Items, const ElementMapper &Mapper) {
if (isWriting()) {
for (auto &Item : Items) {
if (auto EC = Mapper(*this, Item))
return EC;
}
} else {
typename T::value_type Field;
// Stop when we run out of bytes or we hit record padding bytes.
while (!Reader->empty() && Reader->peek() < LF_PAD0) {
if (auto EC = Mapper(*this, Field))
return EC;
Items.push_back(Field);
}
}
return Error::success();
}

Error mapByteVectorTail(ArrayRef<uint8_t> &Bytes);

Error skipPadding();

private:
Error writeEncodedSignedInteger(const int64_t &Value);
Error writeEncodedUnsignedInteger(const uint64_t &Value);

Optional<ActiveRecord> CurrentRecord;

msf::StreamReader *Reader = nullptr;
msf::StreamWriter *Writer = nullptr;
};
}
}

#endif
101 changes: 76 additions & 25 deletions include/llvm/DebugInfo/CodeView/TypeDeserializer.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,57 +10,108 @@
#ifndef LLVM_DEBUGINFO_CODEVIEW_TYPEDESERIALIZER_H
#define LLVM_DEBUGINFO_CODEVIEW_TYPEDESERIALIZER_H

#include "llvm/ADT/Optional.h"
#include "llvm/DebugInfo/CodeView/CodeViewRecordIO.h"
#include "llvm/DebugInfo/CodeView/TypeRecordMapping.h"
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
#include "llvm/DebugInfo/MSF/ByteStream.h"
#include "llvm/DebugInfo/MSF/StreamReader.h"
#include "llvm/DebugInfo/MSF/StreamWriter.h"
#include "llvm/Support/Error.h"

namespace llvm {
namespace codeview {

class TypeDeserializer : public TypeVisitorCallbacks {
struct MappingInfo {
explicit MappingInfo(ArrayRef<uint8_t> RecordData)
: Stream(RecordData), Reader(Stream), Mapping(Reader) {}

msf::ByteStream Stream;
msf::StreamReader Reader;
TypeRecordMapping Mapping;
};

public:
TypeDeserializer() {}

Error visitTypeBegin(CVType &Record) override {
assert(!Mapping && "Already in a type mapping!");
Mapping = llvm::make_unique<MappingInfo>(Record.content());
return Mapping->Mapping.visitTypeBegin(Record);
}
Error visitTypeEnd(CVType &Record) override {
assert(Mapping && "Not in a type mapping!");
auto EC = Mapping->Mapping.visitTypeEnd(Record);
Mapping.reset();
return EC;
}

#define TYPE_RECORD(EnumName, EnumVal, Name) \
Error visitKnownRecord(CVType &CVR, Name##Record &Record) override { \
return defaultVisitKnownRecord(CVR, Record); \
}
#define MEMBER_RECORD(EnumName, EnumVal, Name) \
Error visitKnownMember(CVMemberRecord &CVR, Name##Record &Record) override { \
return defaultVisitKnownMember(CVR, Record); \
return visitKnownRecordImpl<Name##Record>(CVR, Record); \
}
#define MEMBER_RECORD(EnumName, EnumVal, Name)
#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
#include "TypeRecords.def"

protected:
template <typename T>
Error deserializeRecord(msf::StreamReader &Reader, TypeLeafKind Kind,
T &Record) const {
TypeRecordKind RK = static_cast<TypeRecordKind>(Kind);
auto ExpectedRecord = T::deserialize(RK, Reader);
if (!ExpectedRecord)
return ExpectedRecord.takeError();
Record = std::move(*ExpectedRecord);
return Error::success();
private:
template <typename RecordType>
Error visitKnownRecordImpl(CVType &CVR, RecordType &Record) {
return Mapping->Mapping.visitKnownRecord(CVR, Record);
}

private:
template <typename T> Error defaultVisitKnownRecord(CVType &CVR, T &Record) {
msf::ByteStream S(CVR.content());
msf::StreamReader SR(S);
if (auto EC = deserializeRecord(SR, CVR.Type, Record))
std::unique_ptr<MappingInfo> Mapping;
};

class FieldListDeserializer : public TypeVisitorCallbacks {
struct MappingInfo {
explicit MappingInfo(msf::StreamReader &R)
: Reader(R), Mapping(Reader), StartOffset(0) {}

msf::StreamReader &Reader;
TypeRecordMapping Mapping;
uint32_t StartOffset;
};

public:
explicit FieldListDeserializer(msf::StreamReader &Reader) : Mapping(Reader) {}

Error visitMemberBegin(CVMemberRecord &Record) override {
Mapping.StartOffset = Mapping.Reader.getOffset();
return Mapping.Mapping.visitMemberBegin(Record);
}
Error visitMemberEnd(CVMemberRecord &Record) override {
if (auto EC = Mapping.Mapping.visitMemberEnd(Record))
return EC;
return Error::success();
}
template <typename T>
Error defaultVisitKnownMember(CVMemberRecord &CVMR, T &Record) {
msf::ByteStream S(CVMR.Data);
msf::StreamReader SR(S);
if (auto EC = deserializeRecord(SR, CVMR.Kind, Record))

#define TYPE_RECORD(EnumName, EnumVal, Name)
#define MEMBER_RECORD(EnumName, EnumVal, Name) \
Error visitKnownMember(CVMemberRecord &CVR, Name##Record &Record) override { \
return visitKnownMemberImpl<Name##Record>(CVR, Record); \
}
#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
#include "TypeRecords.def"

private:
template <typename RecordType>
Error visitKnownMemberImpl(CVMemberRecord &CVR, RecordType &Record) {
if (auto EC = Mapping.Mapping.visitKnownMember(CVR, Record))
return EC;

uint32_t EndOffset = Mapping.Reader.getOffset();
uint32_t RecordLength = EndOffset - Mapping.StartOffset;
Mapping.Reader.setOffset(Mapping.StartOffset);
if (auto EC = Mapping.Reader.readBytes(CVR.Data, RecordLength))
return EC;
assert(Mapping.Reader.getOffset() == EndOffset);
return Error::success();
}
MappingInfo Mapping;
};
}
}
Expand Down
1 change: 1 addition & 0 deletions include/llvm/DebugInfo/CodeView/TypeIndex.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ class TypeIndex {
: Index(static_cast<uint32_t>(Kind) | static_cast<uint32_t>(Mode)) {}

uint32_t getIndex() const { return Index; }
void setIndex(uint32_t I) { Index = I; }
bool isSimple() const { return Index < FirstNonSimpleIndex; }

bool isNoneType() const { return *this == None(); }
Expand Down
Loading

0 comments on commit d773047

Please sign in to comment.