[CodeView] Decouple record deserialization from visitor dispatch.

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

llvm-svn: 277871
This commit is contained in:
Zachary Turner 2016-08-05 21:45:34 +00:00
parent 9c3dac8efd
commit 5e3e4bb26b
28 changed files with 513 additions and 276 deletions

View File

@ -10,6 +10,7 @@
#ifndef LLVM_DEBUGINFO_CODEVIEW_CVTYPEVISITOR_H
#define LLVM_DEBUGINFO_CODEVIEW_CVTYPEVISITOR_H
#include "llvm/ADT/SmallVector.h"
#include "llvm/DebugInfo/CodeView/CVRecord.h"
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
@ -27,12 +28,6 @@ public:
/// Visits the type records in Data. Sets the error flag on parse failures.
Error visitTypeStream(const CVTypeArray &Types);
Error skipPadding(ArrayRef<uint8_t> &Data);
/// Visits individual member records of a field list record. Member records do
/// not describe their own length, and need special handling.
Error visitFieldList(const CVRecord<TypeLeafKind> &Record);
private:
/// The interface to the class that gets notified of each visitation.
TypeVisitorCallbacks &Callbacks;

View File

@ -21,8 +21,6 @@ namespace codeview {
enum class TypeRecordKind : uint16_t {
#define TYPE_RECORD(lf_ename, value, name) name = value,
#include "TypeRecords.def"
// FIXME: Add serialization support
FieldList = 0x1203,
};
/// Duplicate copy of the above enum, but using the official CV names. Useful

View File

@ -21,6 +21,7 @@ enum class cv_error_code {
insufficient_buffer,
operation_unsupported,
corrupt_record,
unknown_member_record,
};
/// Base class for errors originating when parsing raw PDB files

View File

@ -49,15 +49,17 @@ public:
void reset() { ListRecordBuilder::reset(); }
void writeBaseClass(const BaseClassRecord &Record);
void writeEnumerator(const EnumeratorRecord &Record);
void writeDataMember(const DataMemberRecord &Record);
void writeOneMethod(const OneMethodRecord &Record);
void writeOverloadedMethod(const OverloadedMethodRecord &Record);
void writeNestedType(const NestedTypeRecord &Record);
void writeStaticDataMember(const StaticDataMemberRecord &Record);
void writeVirtualBaseClass(const VirtualBaseClassRecord &Record);
void writeVFPtr(const VFPtrRecord &Type);
void writeMemberType(const BaseClassRecord &Record);
void writeMemberType(const EnumeratorRecord &Record);
void writeMemberType(const DataMemberRecord &Record);
void writeMemberType(const OneMethodRecord &Record);
void writeMemberType(const OverloadedMethodRecord &Record);
void writeMemberType(const NestedTypeRecord &Record);
void writeMemberType(const StaticDataMemberRecord &Record);
void writeMemberType(const VirtualBaseClassRecord &Record);
void writeMemberType(const VFPtrRecord &Type);
using ListRecordBuilder::writeMemberType;
};
}
}

View File

@ -35,7 +35,7 @@ public:
SubrecordStart = 0;
}
void writeListContinuation(const ListContinuationRecord &R);
void writeMemberType(const ListContinuationRecord &R);
/// Writes this list record as a possible sequence of records.
TypeIndex writeListRecord(TypeTableBuilder &Table);

View File

@ -44,7 +44,7 @@ inline Error consumeObject(U &Data, const T *&Res) {
if (Data.size() < sizeof(*Res))
return make_error<CodeViewError>(
cv_error_code::insufficient_buffer,
"Error consuming object. Not enough data for requested object size.");
"Insufficient bytes for expected object type");
Res = reinterpret_cast<const T *>(Data.data());
Data = Data.drop_front(sizeof(*Res));
return Error::success();
@ -146,9 +146,8 @@ struct serialize_null_term_string_array_impl {
Error deserialize(ArrayRef<uint8_t> &Data) const {
if (Data.empty())
return make_error<CodeViewError>(
cv_error_code::insufficient_buffer,
"Null terminated string buffer is empty!");
return make_error<CodeViewError>(cv_error_code::insufficient_buffer,
"Null terminated string is empty!");
StringRef Field;
// Stop when we run out of bytes or we hit record padding bytes.
@ -159,7 +158,7 @@ struct serialize_null_term_string_array_impl {
if (Data.empty())
return make_error<CodeViewError>(
cv_error_code::insufficient_buffer,
"Null terminated string buffer is empty!");
"Null terminated string has no null terminator!");
}
Data = Data.drop_front(1);
return Error::success();

View File

@ -0,0 +1,101 @@
//===- TypeDeserializer.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_TYPEDESERIALIZER_H
#define LLVM_DEBUGINFO_CODEVIEW_TYPEDESERIALIZER_H
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
#include "llvm/Support/Error.h"
namespace llvm {
namespace codeview {
class TypeDeserializerBase : public TypeVisitorCallbacks {
public:
explicit TypeDeserializerBase(TypeVisitorCallbacks &Recipient)
: Recipient(Recipient) {}
Error visitTypeBegin(const CVRecord<TypeLeafKind> &Record) override {
return Recipient.visitTypeBegin(Record);
}
Error visitTypeEnd(const CVRecord<TypeLeafKind> &Record) override {
return Recipient.visitTypeEnd(Record);
}
#define TYPE_RECORD(EnumName, EnumVal, Name) \
Error visitKnownRecord(const CVRecord<TypeLeafKind> &CVR, \
Name##Record &Record) override { \
return defaultVisitKnownRecord(CVR, Record); \
}
#define MEMBER_RECORD(EnumName, EnumVal, Name) \
TYPE_RECORD(EnumName, EnumVal, Name)
#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
#include "TypeRecords.def"
protected:
TypeVisitorCallbacks &Recipient;
template <typename T>
Error deserializeRecord(ArrayRef<uint8_t> &Data, TypeLeafKind Kind,
T &Record) const {
TypeRecordKind RK = static_cast<TypeRecordKind>(Kind);
auto ExpectedRecord = T::deserialize(RK, Data);
if (!ExpectedRecord)
return ExpectedRecord.takeError();
Record = std::move(*ExpectedRecord);
return Error::success();
}
private:
template <typename T>
Error defaultVisitKnownRecord(const CVRecord<TypeLeafKind> &CVR, T &Record) {
ArrayRef<uint8_t> RD = CVR.Data;
if (auto EC = deserializeRecord(RD, CVR.Type, Record))
return EC;
return Recipient.visitKnownRecord(CVR, Record);
}
};
class TypeDeserializer : public TypeDeserializerBase {
public:
explicit TypeDeserializer(TypeVisitorCallbacks &Recipient)
: TypeDeserializerBase(Recipient) {}
/// FieldList records need special handling. For starters, they do not
/// describe their own length, so a different extraction algorithm is
/// necessary. Secondly, a single FieldList record will result in the
/// deserialization of many records. So even though the top level visitor
/// calls visitFieldBegin() on a single record, multiple records get visited
/// through the callback interface.
Error visitKnownRecord(const CVRecord<TypeLeafKind> &CVR,
FieldListRecord &Record) override;
private:
template <typename T>
Error visitKnownMember(ArrayRef<uint8_t> &Data, TypeLeafKind Kind,
T &Record) {
ArrayRef<uint8_t> OldData = Data;
if (auto EC = deserializeRecord(Data, Kind, Record))
return EC;
assert(Data.size() < OldData.size());
CVRecord<TypeLeafKind> CVR;
CVR.Length = OldData.size() - Data.size();
CVR.Data = OldData.slice(0, CVR.Length);
CVR.RawData = CVR.Data;
return Recipient.visitKnownRecord(CVR, Record);
}
Error skipPadding(ArrayRef<uint8_t> &Data);
};
}
}
#endif

View File

@ -72,7 +72,8 @@ public:
Error visitTypeEnd(const CVRecord<TypeLeafKind> &Record) override;
#define TYPE_RECORD(EnumName, EnumVal, Name) \
Error visit##Name(Name##Record &Record) override;
Error visitKnownRecord(const 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)

View File

@ -114,6 +114,7 @@ private:
// LF_MODIFIER
class ModifierRecord : public TypeRecord {
public:
explicit ModifierRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
ModifierRecord(TypeIndex ModifiedType, ModifierOptions Modifiers)
: TypeRecord(TypeRecordKind::Modifier), ModifiedType(ModifiedType),
Modifiers(Modifiers) {}
@ -141,6 +142,7 @@ private:
// LF_PROCEDURE
class ProcedureRecord : public TypeRecord {
public:
explicit ProcedureRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
ProcedureRecord(TypeIndex ReturnType, CallingConvention CallConv,
FunctionOptions Options, uint16_t ParameterCount,
TypeIndex ArgumentList)
@ -182,6 +184,8 @@ private:
// LF_MFUNCTION
class MemberFunctionRecord : public TypeRecord {
public:
explicit MemberFunctionRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
MemberFunctionRecord(TypeIndex ReturnType, TypeIndex ClassType,
TypeIndex ThisType, CallingConvention CallConv,
FunctionOptions Options, uint16_t ParameterCount,
@ -233,6 +237,7 @@ private:
// LF_MFUNC_ID
class MemberFuncIdRecord : public TypeRecord {
public:
explicit MemberFuncIdRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
MemberFuncIdRecord(TypeIndex ClassType, TypeIndex FunctionType,
StringRef Name)
: TypeRecord(TypeRecordKind::MemberFuncId), ClassType(ClassType),
@ -262,6 +267,8 @@ private:
// LF_ARGLIST, LF_SUBSTR_LIST
class ArgListRecord : public TypeRecord {
public:
explicit ArgListRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
ArgListRecord(TypeRecordKind Kind, ArrayRef<TypeIndex> Indices)
: TypeRecord(Kind), StringIndices(Indices) {}
@ -297,6 +304,8 @@ public:
static const uint32_t PointerSizeShift = 13;
static const uint32_t PointerSizeMask = 0xFF;
explicit PointerRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
PointerRecord(TypeIndex ReferentType, PointerKind Kind, PointerMode Mode,
PointerOptions Options, uint8_t Size)
: PointerRecord(ReferentType, Kind, Mode, Options, Size,
@ -382,6 +391,7 @@ private:
// LF_NESTTYPE
class NestedTypeRecord : public TypeRecord {
public:
explicit NestedTypeRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
NestedTypeRecord(TypeIndex Type, StringRef Name)
: TypeRecord(TypeRecordKind::NestedType), Type(Type), Name(Name) {}
@ -406,9 +416,30 @@ private:
StringRef Name;
};
// LF_FIELDLIST
class FieldListRecord : public TypeRecord {
public:
explicit FieldListRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
FieldListRecord(ArrayRef<uint8_t> ListData)
: TypeRecord(TypeRecordKind::FieldList), ListData(ListData) {}
/// Rewrite member type indices with IndexMap. Returns false if a type index
/// is not in the map.
bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap) { return false; }
static Expected<FieldListRecord> deserialize(TypeRecordKind Kind,
ArrayRef<uint8_t> &Data);
ArrayRef<uint8_t> getFieldListData() const { return ListData; }
private:
ArrayRef<uint8_t> ListData;
};
// LF_ARRAY
class ArrayRecord : public TypeRecord {
public:
explicit ArrayRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
ArrayRecord(TypeIndex ElementType, TypeIndex IndexType, uint64_t Size,
StringRef Name)
: TypeRecord(TypeRecordKind::Array), ElementType(ElementType),
@ -442,6 +473,7 @@ private:
class TagRecord : public TypeRecord {
protected:
explicit TagRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
TagRecord(TypeRecordKind Kind, uint16_t MemberCount, ClassOptions Options,
TypeIndex FieldList, StringRef Name, StringRef UniqueName)
: TypeRecord(Kind), MemberCount(MemberCount), Options(Options),
@ -474,6 +506,7 @@ private:
// LF_CLASS, LF_STRUCTURE, LF_INTERFACE
class ClassRecord : public TagRecord {
public:
explicit ClassRecord(TypeRecordKind Kind) : TagRecord(Kind) {}
ClassRecord(TypeRecordKind Kind, uint16_t MemberCount, ClassOptions Options,
HfaKind Hfa, WindowsRTClassKind WinRTKind, TypeIndex FieldList,
TypeIndex DerivationList, TypeIndex VTableShape, uint64_t Size,
@ -520,6 +553,7 @@ private:
// LF_UNION
struct UnionRecord : public TagRecord {
explicit UnionRecord(TypeRecordKind Kind) : TagRecord(Kind) {}
UnionRecord(uint16_t MemberCount, ClassOptions Options, HfaKind Hfa,
TypeIndex FieldList, uint64_t Size, StringRef Name,
StringRef UniqueName)
@ -554,6 +588,7 @@ private:
// LF_ENUM
class EnumRecord : public TagRecord {
public:
explicit EnumRecord(TypeRecordKind Kind) : TagRecord(Kind) {}
EnumRecord(uint16_t MemberCount, ClassOptions Options, TypeIndex FieldList,
StringRef Name, StringRef UniqueName, TypeIndex UnderlyingType)
: TagRecord(TypeRecordKind::Enum, MemberCount, Options, FieldList, Name,
@ -587,6 +622,7 @@ private:
// LF_BITFIELD
class BitFieldRecord : public TypeRecord {
public:
explicit BitFieldRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
BitFieldRecord(TypeIndex Type, uint8_t BitSize, uint8_t BitOffset)
: TypeRecord(TypeRecordKind::BitField), Type(Type), BitSize(BitSize),
BitOffset(BitOffset) {}
@ -617,6 +653,7 @@ private:
// LF_VTSHAPE
class VFTableShapeRecord : public TypeRecord {
public:
explicit VFTableShapeRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
explicit VFTableShapeRecord(ArrayRef<VFTableSlotKind> Slots)
: TypeRecord(TypeRecordKind::VFTableShape), SlotsRef(Slots) {}
explicit VFTableShapeRecord(std::vector<VFTableSlotKind> Slots)
@ -653,6 +690,7 @@ private:
// LF_TYPESERVER2
class TypeServer2Record : public TypeRecord {
public:
explicit TypeServer2Record(TypeRecordKind Kind) : TypeRecord(Kind) {}
TypeServer2Record(StringRef Guid, uint32_t Age, StringRef Name)
: TypeRecord(TypeRecordKind::TypeServer2), Guid(Guid), Age(Age),
Name(Name) {}
@ -685,6 +723,7 @@ private:
// LF_STRING_ID
class StringIdRecord : public TypeRecord {
public:
explicit StringIdRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
StringIdRecord(TypeIndex Id, StringRef String)
: TypeRecord(TypeRecordKind::StringId), Id(Id), String(String) {}
@ -712,6 +751,7 @@ private:
// LF_FUNC_ID
class FuncIdRecord : public TypeRecord {
public:
explicit FuncIdRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
FuncIdRecord(TypeIndex ParentScope, TypeIndex FunctionType, StringRef Name)
: TypeRecord(TypeRecordKind::FuncId), ParentScope(ParentScope),
FunctionType(FunctionType), Name(Name) {}
@ -744,6 +784,7 @@ private:
// LF_UDT_SRC_LINE
class UdtSourceLineRecord : public TypeRecord {
public:
explicit UdtSourceLineRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
UdtSourceLineRecord(TypeIndex UDT, TypeIndex SourceFile, uint32_t LineNumber)
: TypeRecord(TypeRecordKind::UdtSourceLine), UDT(UDT),
SourceFile(SourceFile), LineNumber(LineNumber) {}
@ -774,6 +815,7 @@ private:
// LF_UDT_MOD_SRC_LINE
class UdtModSourceLineRecord : public TypeRecord {
public:
explicit UdtModSourceLineRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
UdtModSourceLineRecord(TypeIndex UDT, TypeIndex SourceFile,
uint32_t LineNumber, uint16_t Module)
: TypeRecord(TypeRecordKind::UdtSourceLine), UDT(UDT),
@ -812,6 +854,7 @@ private:
// LF_BUILDINFO
class BuildInfoRecord : public TypeRecord {
public:
explicit BuildInfoRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
BuildInfoRecord(ArrayRef<TypeIndex> ArgIndices)
: TypeRecord(TypeRecordKind::BuildInfo),
ArgIndices(ArgIndices.begin(), ArgIndices.end()) {}
@ -836,6 +879,7 @@ private:
// LF_VFTABLE
class VFTableRecord : public TypeRecord {
public:
explicit VFTableRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
VFTableRecord(TypeIndex CompleteClass, TypeIndex OverriddenVFTable,
uint32_t VFPtrOffset, StringRef Name,
ArrayRef<StringRef> Methods)
@ -887,6 +931,7 @@ private:
// LF_ONEMETHOD
class OneMethodRecord : public TypeRecord {
public:
explicit OneMethodRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
OneMethodRecord(TypeIndex Type, MethodKind Kind, MethodOptions Options,
MemberAccess Access, int32_t VFTableOffset, StringRef Name)
: TypeRecord(TypeRecordKind::OneMethod), Type(Type), Kind(Kind),
@ -932,6 +977,7 @@ private:
// LF_METHODLIST
class MethodOverloadListRecord : public TypeRecord {
public:
explicit MethodOverloadListRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
MethodOverloadListRecord(ArrayRef<OneMethodRecord> Methods)
: TypeRecord(TypeRecordKind::MethodOverloadList), Methods(Methods) {}
@ -960,6 +1006,7 @@ private:
/// For method overload sets. LF_METHOD
class OverloadedMethodRecord : public TypeRecord {
public:
explicit OverloadedMethodRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
OverloadedMethodRecord(uint16_t NumOverloads, TypeIndex MethodList,
StringRef Name)
: TypeRecord(TypeRecordKind::OverloadedMethod),
@ -991,6 +1038,7 @@ private:
// LF_MEMBER
class DataMemberRecord : public TypeRecord {
public:
explicit DataMemberRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
DataMemberRecord(MemberAccess Access, TypeIndex Type, uint64_t Offset,
StringRef Name)
: TypeRecord(TypeRecordKind::DataMember), Access(Access), Type(Type),
@ -1025,6 +1073,7 @@ private:
// LF_STMEMBER
class StaticDataMemberRecord : public TypeRecord {
public:
explicit StaticDataMemberRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
StaticDataMemberRecord(MemberAccess Access, TypeIndex Type, StringRef Name)
: TypeRecord(TypeRecordKind::StaticDataMember), Access(Access),
Type(Type), Name(Name) {}
@ -1055,6 +1104,7 @@ private:
// LF_ENUMERATE
class EnumeratorRecord : public TypeRecord {
public:
explicit EnumeratorRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
EnumeratorRecord(MemberAccess Access, APSInt Value, StringRef Name)
: TypeRecord(TypeRecordKind::Enumerator), Access(Access),
Value(std::move(Value)), Name(Name) {}
@ -1085,6 +1135,7 @@ private:
// LF_VFUNCTAB
class VFPtrRecord : public TypeRecord {
public:
explicit VFPtrRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
VFPtrRecord(TypeIndex Type)
: TypeRecord(TypeRecordKind::VFPtr), Type(Type) {}
@ -1108,6 +1159,7 @@ private:
// LF_BCLASS, LF_BINTERFACE
class BaseClassRecord : public TypeRecord {
public:
explicit BaseClassRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
BaseClassRecord(MemberAccess Access, TypeIndex Type, uint64_t Offset)
: TypeRecord(TypeRecordKind::BaseClass), Access(Access), Type(Type),
Offset(Offset) {}
@ -1137,6 +1189,7 @@ private:
// LF_VBCLASS, LF_IVBCLASS
class VirtualBaseClassRecord : public TypeRecord {
public:
explicit VirtualBaseClassRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
VirtualBaseClassRecord(MemberAccess Access, TypeIndex BaseType,
TypeIndex VBPtrType, uint64_t Offset, uint64_t Index)
: TypeRecord(TypeRecordKind::VirtualBaseClass), Access(Access),
@ -1175,6 +1228,7 @@ private:
/// together. The first will end in an LF_INDEX record that points to the next.
class ListContinuationRecord : public TypeRecord {
public:
explicit ListContinuationRecord(TypeRecordKind Kind) : TypeRecord(Kind) {}
ListContinuationRecord(TypeIndex ContinuationIndex)
: TypeRecord(TypeRecordKind::ListContinuation),
ContinuationIndex(ContinuationIndex) {}

View File

@ -43,6 +43,8 @@ TYPE_RECORD(LF_PROCEDURE, 0x1008, Procedure)
TYPE_RECORD(LF_MFUNCTION, 0x1009, MemberFunction)
TYPE_RECORD(LF_ARGLIST, 0x1201, ArgList)
TYPE_RECORD(LF_FIELDLIST, 0x1203, FieldList)
TYPE_RECORD(LF_ARRAY, 0x1503, Array)
TYPE_RECORD(LF_CLASS, 0x1504, Class)
TYPE_RECORD_ALIAS(LF_STRUCTURE, 0x1505, Struct, Class)
@ -159,7 +161,6 @@ CV_TYPE(LF_OEM2, 0x1011)
CV_TYPE(LF_SKIP, 0x1200)
CV_TYPE(LF_DEFARG_ST, 0x1202)
CV_TYPE(LF_FIELDLIST, 0x1203)
CV_TYPE(LF_DERIVED, 0x1204)
CV_TYPE(LF_DIMCONU, 0x1207)
CV_TYPE(LF_DIMCONLU, 0x1208)

View File

@ -37,26 +37,26 @@ public:
virtual ~TypeTableBuilder();
public:
TypeIndex writeModifier(const ModifierRecord &Record);
TypeIndex writeProcedure(const ProcedureRecord &Record);
TypeIndex writeMemberFunction(const MemberFunctionRecord &Record);
TypeIndex writeArgList(const ArgListRecord &Record);
TypeIndex writePointer(const PointerRecord &Record);
TypeIndex writeArray(const ArrayRecord &Record);
TypeIndex writeClass(const ClassRecord &Record);
TypeIndex writeUnion(const UnionRecord &Record);
TypeIndex writeEnum(const EnumRecord &Record);
TypeIndex writeBitField(const BitFieldRecord &Record);
TypeIndex writeVFTableShape(const VFTableShapeRecord &Record);
TypeIndex writeStringId(const StringIdRecord &Record);
TypeIndex writeVFTable(const VFTableRecord &Record);
TypeIndex writeUdtSourceLine(const UdtSourceLineRecord &Record);
TypeIndex writeUdtModSourceLine(const UdtModSourceLineRecord &Record);
TypeIndex writeFuncId(const FuncIdRecord &Record);
TypeIndex writeMemberFuncId(const MemberFuncIdRecord &Record);
TypeIndex writeBuildInfo(const BuildInfoRecord &Record);
TypeIndex writeMethodOverloadList(const MethodOverloadListRecord &Record);
TypeIndex writeTypeServer2(const TypeServer2Record &Record);
TypeIndex writeKnownType(const ModifierRecord &Record);
TypeIndex writeKnownType(const ProcedureRecord &Record);
TypeIndex writeKnownType(const MemberFunctionRecord &Record);
TypeIndex writeKnownType(const ArgListRecord &Record);
TypeIndex writeKnownType(const PointerRecord &Record);
TypeIndex writeKnownType(const ArrayRecord &Record);
TypeIndex writeKnownType(const ClassRecord &Record);
TypeIndex writeKnownType(const UnionRecord &Record);
TypeIndex writeKnownType(const EnumRecord &Record);
TypeIndex writeKnownType(const BitFieldRecord &Record);
TypeIndex writeKnownType(const VFTableShapeRecord &Record);
TypeIndex writeKnownType(const StringIdRecord &Record);
TypeIndex writeKnownType(const VFTableRecord &Record);
TypeIndex writeKnownType(const UdtSourceLineRecord &Record);
TypeIndex writeKnownType(const UdtModSourceLineRecord &Record);
TypeIndex writeKnownType(const FuncIdRecord &Record);
TypeIndex writeKnownType(const MemberFuncIdRecord &Record);
TypeIndex writeKnownType(const BuildInfoRecord &Record);
TypeIndex writeKnownType(const MethodOverloadListRecord &Record);
TypeIndex writeKnownType(const TypeServer2Record &Record);
TypeIndex writeFieldList(FieldListRecordBuilder &FieldList);

View File

@ -41,16 +41,11 @@ public:
return Error::success();
}
virtual Error visitFieldListBegin(const CVRecord<TypeLeafKind> &Record) {
return Error::success();
}
virtual Error visitFieldListEnd(const CVRecord<TypeLeafKind> &Record) {
return Error::success();
}
#define TYPE_RECORD(EnumName, EnumVal, Name) \
virtual Error visit##Name(Name##Record &Record) { return Error::success(); }
virtual Error visitKnownRecord(const CVRecord<TypeLeafKind> &CVR, \
Name##Record &Record) { \
return Error::success(); \
}
#define MEMBER_RECORD(EnumName, EnumVal, Name) \
TYPE_RECORD(EnumName, EnumVal, Name)
#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)

View File

@ -212,7 +212,7 @@ TypeIndex CodeViewDebug::getScopeIndex(const DIScope *Scope) {
// Build the fully qualified name of the scope.
std::string ScopeName = getFullyQualifiedName(Scope);
TypeIndex TI =
TypeTable.writeStringId(StringIdRecord(TypeIndex(), ScopeName));
TypeTable.writeKnownType(StringIdRecord(TypeIndex(), ScopeName));
return recordTypeIndexForDINode(Scope, TI);
}
@ -237,12 +237,12 @@ TypeIndex CodeViewDebug::getFuncIdForSubprogram(const DISubprogram *SP) {
TypeIndex ClassType = getTypeIndex(Class);
MemberFuncIdRecord MFuncId(ClassType, getMemberFunctionType(SP, Class),
DisplayName);
TI = TypeTable.writeMemberFuncId(MFuncId);
TI = TypeTable.writeKnownType(MFuncId);
} else {
// Otherwise, this must be a free function.
TypeIndex ParentScope = getScopeIndex(Scope);
FuncIdRecord FuncId(ParentScope, getTypeIndex(SP->getType()), DisplayName);
TI = TypeTable.writeFuncId(FuncId);
TI = TypeTable.writeKnownType(FuncId);
}
return recordTypeIndexForDINode(SP, TI);
@ -1030,7 +1030,7 @@ TypeIndex CodeViewDebug::lowerTypeArray(const DICompositeType *Ty) {
StringRef Name = (i == 0) ? Ty->getName() : "";
// Update the element size and element type index for subsequent subranges.
ElementSize *= Count;
ElementTypeIndex = TypeTable.writeArray(
ElementTypeIndex = TypeTable.writeKnownType(
ArrayRecord(ElementTypeIndex, IndexType, ElementSize, Name));
}
@ -1174,7 +1174,7 @@ TypeIndex CodeViewDebug::lowerTypePointer(const DIDerivedType *Ty) {
// do.
PointerOptions PO = PointerOptions::None;
PointerRecord PR(PointeeTI, PK, PM, PO, Ty->getSizeInBits() / 8);
return TypeTable.writePointer(PR);
return TypeTable.writeKnownType(PR);
}
static PointerToMemberRepresentation
@ -1225,7 +1225,7 @@ TypeIndex CodeViewDebug::lowerTypeMemberPointer(const DIDerivedType *Ty) {
MemberPointerInfo MPI(
ClassTI, translatePtrToMemberRep(SizeInBytes, IsPMF, Ty->getFlags()));
PointerRecord PR(PointeeTI, PK, PM, PO, SizeInBytes, MPI);
return TypeTable.writePointer(PR);
return TypeTable.writeKnownType(PR);
}
/// Given a DWARF calling convention, get the CodeView equivalent. If we don't
@ -1272,7 +1272,7 @@ TypeIndex CodeViewDebug::lowerTypeModifier(const DIDerivedType *Ty) {
return I->second;
ModifierRecord MR(ModifiedTI, Mods);
return TypeTable.writeModifier(MR);
return TypeTable.writeKnownType(MR);
}
TypeIndex CodeViewDebug::lowerTypeFunction(const DISubroutineType *Ty) {
@ -1289,13 +1289,13 @@ TypeIndex CodeViewDebug::lowerTypeFunction(const DISubroutineType *Ty) {
}
ArgListRecord ArgListRec(TypeRecordKind::ArgList, ArgTypeIndices);
TypeIndex ArgListIndex = TypeTable.writeArgList(ArgListRec);
TypeIndex ArgListIndex = TypeTable.writeKnownType(ArgListRec);
CallingConvention CC = dwarfCCToCodeView(Ty->getCC());
ProcedureRecord Procedure(ReturnTypeIndex, CC, FunctionOptions::None,
ArgTypeIndices.size(), ArgListIndex);
return TypeTable.writeProcedure(Procedure);
return TypeTable.writeKnownType(Procedure);
}
TypeIndex CodeViewDebug::lowerTypeMemberFunction(const DISubroutineType *Ty,
@ -1322,14 +1322,14 @@ TypeIndex CodeViewDebug::lowerTypeMemberFunction(const DISubroutineType *Ty,
}
ArgListRecord ArgListRec(TypeRecordKind::ArgList, ArgTypeIndices);
TypeIndex ArgListIndex = TypeTable.writeArgList(ArgListRec);
TypeIndex ArgListIndex = TypeTable.writeKnownType(ArgListRec);
CallingConvention CC = dwarfCCToCodeView(Ty->getCC());
// TODO: Need to use the correct values for:
// FunctionOptions
// ThisPointerAdjustment.
TypeIndex TI = TypeTable.writeMemberFunction(MemberFunctionRecord(
TypeIndex TI = TypeTable.writeKnownType(MemberFunctionRecord(
ReturnTypeIndex, ClassType, ThisTypeIndex, CC, FunctionOptions::None,
ArgTypeIndices.size(), ArgListIndex, ThisAdjustment));
@ -1428,7 +1428,7 @@ TypeIndex CodeViewDebug::lowerTypeEnum(const DICompositeType *Ty) {
// We assume that the frontend provides all members in source declaration
// order, which is what MSVC does.
if (auto *Enumerator = dyn_cast_or_null<DIEnumerator>(Element)) {
Fields.writeEnumerator(EnumeratorRecord(
Fields.writeMemberType(EnumeratorRecord(
MemberAccess::Public, APSInt::getUnsigned(Enumerator->getValue()),
Enumerator->getName()));
EnumeratorCount++;
@ -1439,9 +1439,9 @@ TypeIndex CodeViewDebug::lowerTypeEnum(const DICompositeType *Ty) {
std::string FullName = getFullyQualifiedName(Ty);
return TypeTable.writeEnum(EnumRecord(EnumeratorCount, CO, FTI, FullName,
Ty->getIdentifier(),
getTypeIndex(Ty->getBaseType())));
return TypeTable.writeKnownType(EnumRecord(EnumeratorCount, CO, FTI, FullName,
Ty->getIdentifier(),
getTypeIndex(Ty->getBaseType())));
}
//===----------------------------------------------------------------------===//
@ -1536,7 +1536,7 @@ TypeIndex CodeViewDebug::lowerTypeClass(const DICompositeType *Ty) {
ClassOptions CO =
ClassOptions::ForwardReference | getCommonClassOptions(Ty);
std::string FullName = getFullyQualifiedName(Ty);
TypeIndex FwdDeclTI = TypeTable.writeClass(ClassRecord(
TypeIndex FwdDeclTI = TypeTable.writeKnownType(ClassRecord(
Kind, 0, CO, HfaKind::None, WindowsRTClassKind::None, TypeIndex(),
TypeIndex(), TypeIndex(), 0, FullName, Ty->getIdentifier()));
if (!Ty->isForwardDecl())
@ -1562,12 +1562,12 @@ TypeIndex CodeViewDebug::lowerCompleteTypeClass(const DICompositeType *Ty) {
uint64_t SizeInBytes = Ty->getSizeInBits() / 8;
TypeIndex ClassTI = TypeTable.writeClass(ClassRecord(
TypeIndex ClassTI = TypeTable.writeKnownType(ClassRecord(
Kind, FieldCount, CO, HfaKind::None, WindowsRTClassKind::None, FieldTI,
TypeIndex(), VShapeTI, SizeInBytes, FullName, Ty->getIdentifier()));
TypeTable.writeUdtSourceLine(UdtSourceLineRecord(
ClassTI, TypeTable.writeStringId(StringIdRecord(
TypeTable.writeKnownType(UdtSourceLineRecord(
ClassTI, TypeTable.writeKnownType(StringIdRecord(
TypeIndex(0x0), getFullFilepath(Ty->getFile()))),
Ty->getLine()));
@ -1580,9 +1580,8 @@ TypeIndex CodeViewDebug::lowerTypeUnion(const DICompositeType *Ty) {
ClassOptions CO =
ClassOptions::ForwardReference | getCommonClassOptions(Ty);
std::string FullName = getFullyQualifiedName(Ty);
TypeIndex FwdDeclTI =
TypeTable.writeUnion(UnionRecord(0, CO, HfaKind::None, TypeIndex(), 0,
FullName, Ty->getIdentifier()));
TypeIndex FwdDeclTI = TypeTable.writeKnownType(UnionRecord(
0, CO, HfaKind::None, TypeIndex(), 0, FullName, Ty->getIdentifier()));
if (!Ty->isForwardDecl())
DeferredCompleteTypes.push_back(Ty);
return FwdDeclTI;
@ -1602,12 +1601,12 @@ TypeIndex CodeViewDebug::lowerCompleteTypeUnion(const DICompositeType *Ty) {
uint64_t SizeInBytes = Ty->getSizeInBits() / 8;
std::string FullName = getFullyQualifiedName(Ty);
TypeIndex UnionTI = TypeTable.writeUnion(
TypeIndex UnionTI = TypeTable.writeKnownType(
UnionRecord(FieldCount, CO, HfaKind::None, FieldTI, SizeInBytes, FullName,
Ty->getIdentifier()));
TypeTable.writeUdtSourceLine(UdtSourceLineRecord(
UnionTI, TypeTable.writeStringId(StringIdRecord(
TypeTable.writeKnownType(UdtSourceLineRecord(
UnionTI, TypeTable.writeKnownType(StringIdRecord(
TypeIndex(0x0), getFullFilepath(Ty->getFile()))),
Ty->getLine()));
@ -1634,14 +1633,14 @@ CodeViewDebug::lowerRecordFieldList(const DICompositeType *Ty) {
unsigned VBPtrOffset = 0;
// FIXME: Despite the accessor name, the offset is really in bytes.
unsigned VBTableIndex = I->getOffsetInBits() / 4;
Fields.writeVirtualBaseClass(VirtualBaseClassRecord(
Fields.writeMemberType(VirtualBaseClassRecord(
translateAccessFlags(Ty->getTag(), I->getFlags()),
getTypeIndex(I->getBaseType()), getVBPTypeIndex(), VBPtrOffset,
VBTableIndex));
} else {
assert(I->getOffsetInBits() % 8 == 0 &&
"bases must be on byte boundaries");
Fields.writeBaseClass(BaseClassRecord(
Fields.writeMemberType(BaseClassRecord(
translateAccessFlags(Ty->getTag(), I->getFlags()),
getTypeIndex(I->getBaseType()), I->getOffsetInBits() / 8));
}
@ -1656,7 +1655,7 @@ CodeViewDebug::lowerRecordFieldList(const DICompositeType *Ty) {
translateAccessFlags(Ty->getTag(), Member->getFlags());
if (Member->isStaticMember()) {
Fields.writeStaticDataMember(
Fields.writeMemberType(
StaticDataMemberRecord(Access, MemberBaseType, MemberName));
MemberCount++;
continue;
@ -1672,11 +1671,11 @@ CodeViewDebug::lowerRecordFieldList(const DICompositeType *Ty) {
MemberOffsetInBits = CI->getZExtValue() + MemberInfo.BaseOffset;
}
StartBitOffset -= MemberOffsetInBits;
MemberBaseType = TypeTable.writeBitField(BitFieldRecord(
MemberBaseType = TypeTable.writeKnownType(BitFieldRecord(
MemberBaseType, Member->getSizeInBits(), StartBitOffset));
}
uint64_t MemberOffsetInBytes = MemberOffsetInBits / 8;
Fields.writeDataMember(DataMemberRecord(Access, MemberBaseType,
Fields.writeMemberType(DataMemberRecord(Access, MemberBaseType,
MemberOffsetInBytes, MemberName));
MemberCount++;
}
@ -1703,11 +1702,11 @@ CodeViewDebug::lowerRecordFieldList(const DICompositeType *Ty) {
}
assert(Methods.size() > 0 && "Empty methods map entry");
if (Methods.size() == 1)
Fields.writeOneMethod(Methods[0]);
Fields.writeMemberType(Methods[0]);
else {
TypeIndex MethodList =
TypeTable.writeMethodOverloadList(MethodOverloadListRecord(Methods));
Fields.writeOverloadedMethod(
TypeTable.writeKnownType(MethodOverloadListRecord(Methods));
Fields.writeMemberType(
OverloadedMethodRecord(Methods.size(), MethodList, Name));
}
}
@ -1715,7 +1714,7 @@ CodeViewDebug::lowerRecordFieldList(const DICompositeType *Ty) {
// Create nested classes.
for (const DICompositeType *Nested : Info.NestedClasses) {
NestedTypeRecord R(getTypeIndex(DITypeRef(Nested)), Nested->getName());
Fields.writeNestedType(R);
Fields.writeMemberType(R);
MemberCount++;
}
@ -1728,7 +1727,7 @@ TypeIndex CodeViewDebug::getVBPTypeIndex() {
if (!VBPType.getIndex()) {
// Make a 'const int *' type.
ModifierRecord MR(TypeIndex::Int32(), ModifierOptions::Const);
TypeIndex ModifiedTI = TypeTable.writeModifier(MR);
TypeIndex ModifiedTI = TypeTable.writeKnownType(MR);
PointerKind PK = getPointerSizeInBytes() == 8 ? PointerKind::Near64
: PointerKind::Near32;
@ -1736,7 +1735,7 @@ TypeIndex CodeViewDebug::getVBPTypeIndex() {
PointerOptions PO = PointerOptions::None;
PointerRecord PR(ModifiedTI, PK, PM, PO, getPointerSizeInBytes());
VBPType = TypeTable.writePointer(PR);
VBPType = TypeTable.writeKnownType(PR);
}
return VBPType;

View File

@ -11,6 +11,7 @@ add_llvm_library(LLVMDebugInfoCodeView
ModuleSubstreamVisitor.cpp
RecordSerialization.cpp
SymbolDumper.cpp
TypeDeserializer.cpp
TypeDumper.cpp
TypeRecord.cpp
TypeRecordBuilder.cpp

View File

@ -8,47 +8,39 @@
//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
#include "llvm/DebugInfo/CodeView/CodeViewError.h"
#include "llvm/DebugInfo/Msf/ByteStream.h"
using namespace llvm;
using namespace llvm::codeview;
template <typename T>
static Error takeObject(ArrayRef<uint8_t> &Data, const T *&Res) {
if (Data.size() < sizeof(*Res))
return llvm::make_error<CodeViewError>(cv_error_code::insufficient_buffer);
Res = reinterpret_cast<const T *>(Data.data());
Data = Data.drop_front(sizeof(*Res));
return Error::success();
}
CVTypeVisitor::CVTypeVisitor(TypeVisitorCallbacks &Callbacks)
: Callbacks(Callbacks) {}
template <typename T>
static Error visitKnownRecord(const CVRecord<TypeLeafKind> &Record,
TypeVisitorCallbacks &Callbacks) {
TypeRecordKind RK = static_cast<TypeRecordKind>(Record.Type);
T KnownRecord(RK);
if (auto EC = Callbacks.visitKnownRecord(Record, KnownRecord))
return EC;
return Error::success();
}
Error CVTypeVisitor::visitTypeRecord(const CVRecord<TypeLeafKind> &Record) {
ArrayRef<uint8_t> LeafData = Record.Data;
if (auto EC = Callbacks.visitTypeBegin(Record))
return EC;
switch (Record.Type) {
default:
if (auto EC = Callbacks.visitUnknownType(Record))
return EC;
break;
case LF_FIELDLIST:
if (auto EC = Callbacks.visitFieldListBegin(Record))
return EC;
if (auto EC = visitFieldList(Record))
return EC;
if (auto EC = Callbacks.visitFieldListEnd(Record))
return EC;
break;
#define TYPE_RECORD(EnumName, EnumVal, Name) \
case EnumName: { \
TypeRecordKind RK = static_cast<TypeRecordKind>(EnumName); \
auto ExpectedRecord = Name##Record::deserialize(RK, LeafData); \
if (!ExpectedRecord) \
return ExpectedRecord.takeError(); \
if (auto EC = Callbacks.visit##Name(*ExpectedRecord)) \
if (auto EC = visitKnownRecord<Name##Record>(Record, Callbacks)) \
return EC; \
break; \
}
@ -57,8 +49,10 @@ Error CVTypeVisitor::visitTypeRecord(const CVRecord<TypeLeafKind> &Record) {
#define MEMBER_RECORD(EnumName, EnumVal, Name)
#include "llvm/DebugInfo/CodeView/TypeRecords.def"
}
if (auto EC = Callbacks.visitTypeEnd(Record))
return EC;
return Error::success();
}
@ -70,55 +64,3 @@ Error CVTypeVisitor::visitTypeStream(const CVTypeArray &Types) {
}
return Error::success();
}
Error CVTypeVisitor::skipPadding(ArrayRef<uint8_t> &Data) {
if (Data.empty())
return Error::success();
uint8_t Leaf = Data.front();
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;
if (Data.size() < BytesToAdvance) {
return llvm::make_error<CodeViewError>(cv_error_code::corrupt_record,
"Invalid padding bytes!");
}
Data = Data.drop_front(BytesToAdvance);
return Error::success();
}
/// Visits individual member records of a field list record. Member records do
/// not describe their own length, and need special handling.
Error CVTypeVisitor::visitFieldList(const CVRecord<TypeLeafKind> &Record) {
ArrayRef<uint8_t> RecordData = Record.Data;
while (!RecordData.empty()) {
const ulittle16_t *LeafPtr;
if (auto EC = takeObject(RecordData, LeafPtr))
return EC;
TypeLeafKind Leaf = TypeLeafKind(unsigned(*LeafPtr));
switch (Leaf) {
default:
// Field list records do not describe their own length, so we cannot
// continue parsing past an unknown member type.
if (auto EC = Callbacks.visitUnknownMember(Record))
return llvm::make_error<CodeViewError>(cv_error_code::corrupt_record);
#define MEMBER_RECORD(EnumName, EnumVal, Name) \
case EnumName: { \
TypeRecordKind RK = static_cast<TypeRecordKind>(EnumName); \
auto ExpectedRecord = Name##Record::deserialize(RK, RecordData); \
if (!ExpectedRecord) \
return ExpectedRecord.takeError(); \
if (auto EC = Callbacks.visit##Name(*ExpectedRecord)) \
return EC; \
break; \
}
#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \
MEMBER_RECORD(EnumVal, EnumVal, AliasName)
#include "llvm/DebugInfo/CodeView/TypeRecords.def"
}
if (auto EC = skipPadding(RecordData))
return EC;
}
return Error::success();
}

View File

@ -33,6 +33,8 @@ public:
return "The CodeView record is corrupted.";
case cv_error_code::operation_unsupported:
return "The requested operation is not supported.";
case cv_error_code::unknown_member_record:
return "The member record is of an unknown type.";
}
llvm_unreachable("Unrecognized cv_error_code");
}

View File

@ -15,7 +15,7 @@ using namespace codeview;
FieldListRecordBuilder::FieldListRecordBuilder()
: ListRecordBuilder(TypeRecordKind::FieldList) {}
void FieldListRecordBuilder::writeBaseClass(const BaseClassRecord &Record) {
void FieldListRecordBuilder::writeMemberType(const BaseClassRecord &Record) {
TypeRecordBuilder &Builder = getBuilder();
Builder.writeTypeRecordKind(TypeRecordKind::BaseClass);
@ -26,7 +26,7 @@ void FieldListRecordBuilder::writeBaseClass(const BaseClassRecord &Record) {
finishSubRecord();
}
void FieldListRecordBuilder::writeEnumerator(const EnumeratorRecord &Record) {
void FieldListRecordBuilder::writeMemberType(const EnumeratorRecord &Record) {
TypeRecordBuilder &Builder = getBuilder();
Builder.writeTypeRecordKind(TypeRecordKind::Enumerator);
@ -38,7 +38,7 @@ void FieldListRecordBuilder::writeEnumerator(const EnumeratorRecord &Record) {
finishSubRecord();
}
void FieldListRecordBuilder::writeDataMember(const DataMemberRecord &Record) {
void FieldListRecordBuilder::writeMemberType(const DataMemberRecord &Record) {
TypeRecordBuilder &Builder = getBuilder();
Builder.writeTypeRecordKind(Record.getKind());
@ -50,7 +50,7 @@ void FieldListRecordBuilder::writeDataMember(const DataMemberRecord &Record) {
finishSubRecord();
}
void FieldListRecordBuilder::writeOverloadedMethod(
void FieldListRecordBuilder::writeMemberType(
const OverloadedMethodRecord &Record) {
TypeRecordBuilder &Builder = getBuilder();
@ -62,7 +62,7 @@ void FieldListRecordBuilder::writeOverloadedMethod(
finishSubRecord();
}
void FieldListRecordBuilder::writeOneMethod(const OneMethodRecord &Record) {
void FieldListRecordBuilder::writeMemberType(const OneMethodRecord &Record) {
TypeRecordBuilder &Builder = getBuilder();
uint16_t Flags = static_cast<uint16_t>(Record.getAccess());
@ -84,7 +84,7 @@ void FieldListRecordBuilder::writeOneMethod(const OneMethodRecord &Record) {
finishSubRecord();
}
void FieldListRecordBuilder::writeNestedType(const NestedTypeRecord &Record) {
void FieldListRecordBuilder::writeMemberType(const NestedTypeRecord &Record) {
TypeRecordBuilder &Builder = getBuilder();
Builder.writeTypeRecordKind(Record.getKind());
@ -95,7 +95,7 @@ void FieldListRecordBuilder::writeNestedType(const NestedTypeRecord &Record) {
finishSubRecord();
}
void FieldListRecordBuilder::writeStaticDataMember(
void FieldListRecordBuilder::writeMemberType(
const StaticDataMemberRecord &Record) {
TypeRecordBuilder &Builder = getBuilder();
@ -107,7 +107,7 @@ void FieldListRecordBuilder::writeStaticDataMember(
finishSubRecord();
}
void FieldListRecordBuilder::writeVirtualBaseClass(
void FieldListRecordBuilder::writeMemberType(
const VirtualBaseClassRecord &Record) {
TypeRecordBuilder &Builder = getBuilder();
@ -121,7 +121,7 @@ void FieldListRecordBuilder::writeVirtualBaseClass(
finishSubRecord();
}
void FieldListRecordBuilder::writeVFPtr(const VFPtrRecord &Record) {
void FieldListRecordBuilder::writeMemberType(const VFPtrRecord &Record) {
TypeRecordBuilder &Builder = getBuilder();
Builder.writeTypeRecordKind(TypeRecordKind::VFPtr);

View File

@ -17,7 +17,7 @@ using namespace codeview;
ListRecordBuilder::ListRecordBuilder(TypeRecordKind Kind)
: Kind(Kind), Builder(Kind) {}
void ListRecordBuilder::writeListContinuation(const ListContinuationRecord &R) {
void ListRecordBuilder::writeMemberType(const ListContinuationRecord &R) {
TypeRecordBuilder &Builder = getBuilder();
assert(getLastContinuationSize() < 65535 - 8 && "continuation won't fit");

View File

@ -0,0 +1,81 @@
//===- TypeDeserializer.cpp -------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
using namespace llvm;
using namespace llvm::codeview;
template <typename T>
static Error takeObject(ArrayRef<uint8_t> &Data, const T *&Res) {
if (Data.size() < sizeof(*Res))
return llvm::make_error<CodeViewError>(cv_error_code::insufficient_buffer);
Res = reinterpret_cast<const T *>(Data.data());
Data = Data.drop_front(sizeof(*Res));
return Error::success();
}
Error TypeDeserializer::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR,
FieldListRecord &Record) {
ArrayRef<uint8_t> FieldListRecordData = CVR.Data;
auto ExpectedRecord = FieldListRecord::deserialize(TypeRecordKind::FieldList,
FieldListRecordData);
if (!ExpectedRecord)
return ExpectedRecord.takeError();
Record = *ExpectedRecord;
ArrayRef<uint8_t> MemberData = Record.getFieldListData();
while (!MemberData.empty()) {
const ulittle16_t *LeafPtr;
if (auto EC = takeObject(MemberData, LeafPtr))
return EC;
TypeLeafKind Leaf = TypeLeafKind(unsigned(*LeafPtr));
switch (Leaf) {
default:
// Field list records do not describe their own length, so we cannot
// continue parsing past a type that we don't know how to deserialize.
if (auto EC = Recipient.visitUnknownMember(CVR))
return EC;
return llvm::make_error<CodeViewError>(
cv_error_code::unknown_member_record);
#define MEMBER_RECORD(EnumName, EnumVal, Name) \
case EnumName: { \
TypeRecordKind RK = static_cast<TypeRecordKind>(Leaf); \
Name##Record Member(RK); \
if (auto EC = visitKnownMember(MemberData, Leaf, Member)) \
return EC; \
break; \
}
#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \
MEMBER_RECORD(EnumVal, EnumVal, AliasName)
#include "llvm/DebugInfo/CodeView/TypeRecords.def"
}
if (auto EC = skipPadding(MemberData))
return EC;
}
return Error::success();
}
Error TypeDeserializer::skipPadding(ArrayRef<uint8_t> &Data) {
if (Data.empty())
return Error::success();
uint8_t Leaf = Data.front();
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;
if (Data.size() < BytesToAdvance) {
return llvm::make_error<CodeViewError>(cv_error_code::corrupt_record,
"Invalid padding bytes!");
}
Data = Data.drop_front(BytesToAdvance);
return Error::success();
}

View File

@ -10,6 +10,7 @@
#include "llvm/DebugInfo/CodeView/TypeDumper.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
#include "llvm/DebugInfo/MSF/ByteStream.h"
@ -195,8 +196,6 @@ static StringRef getLeafTypeName(TypeLeafKind LT) {
case ename: \
return #name;
#include "llvm/DebugInfo/CodeView/TypeRecords.def"
case LF_FIELDLIST:
return "FieldList";
default:
break;
}
@ -231,7 +230,13 @@ Error CVTypeDumper::visitTypeEnd(const CVRecord<TypeLeafKind> &Record) {
return Error::success();
}
Error CVTypeDumper::visitStringId(StringIdRecord &String) {
Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR,
FieldListRecord &FieldList) {
return Error::success();
}
Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR,
StringIdRecord &String) {
printTypeIndex("Id", String.getId());
W->printString("StringData", String.getString());
// Put this in CVUDTNames so it gets printed with LF_UDT_SRC_LINE.
@ -239,7 +244,8 @@ Error CVTypeDumper::visitStringId(StringIdRecord &String) {
return Error::success();
}
Error CVTypeDumper::visitArgList(ArgListRecord &Args) {
Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR,
ArgListRecord &Args) {
auto Indices = Args.getIndices();
uint32_t Size = Indices.size();
W->printNumber("NumArgs", Size);
@ -257,7 +263,8 @@ Error CVTypeDumper::visitArgList(ArgListRecord &Args) {
return Error::success();
}
Error CVTypeDumper::visitClass(ClassRecord &Class) {
Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR,
ClassRecord &Class) {
uint16_t Props = static_cast<uint16_t>(Class.getOptions());
W->printNumber("MemberCount", Class.getMemberCount());
W->printFlags("Properties", Props, makeArrayRef(ClassOptionNames));
@ -272,7 +279,8 @@ Error CVTypeDumper::visitClass(ClassRecord &Class) {
return Error::success();
}
Error CVTypeDumper::visitUnion(UnionRecord &Union) {
Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR,
UnionRecord &Union) {
uint16_t Props = static_cast<uint16_t>(Union.getOptions());
W->printNumber("MemberCount", Union.getMemberCount());
W->printFlags("Properties", Props, makeArrayRef(ClassOptionNames));
@ -285,7 +293,8 @@ Error CVTypeDumper::visitUnion(UnionRecord &Union) {
return Error::success();
}
Error CVTypeDumper::visitEnum(EnumRecord &Enum) {
Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR,
EnumRecord &Enum) {
uint16_t Props = static_cast<uint16_t>(Enum.getOptions());
W->printNumber("NumEnumerators", Enum.getMemberCount());
W->printFlags("Properties", uint16_t(Enum.getOptions()),
@ -299,7 +308,8 @@ Error CVTypeDumper::visitEnum(EnumRecord &Enum) {
return Error::success();
}
Error CVTypeDumper::visitArray(ArrayRecord &AT) {
Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR,
ArrayRecord &AT) {
printTypeIndex("ElementType", AT.getElementType());
printTypeIndex("IndexType", AT.getIndexType());
W->printNumber("SizeOf", AT.getSize());
@ -308,7 +318,8 @@ Error CVTypeDumper::visitArray(ArrayRecord &AT) {
return Error::success();
}
Error CVTypeDumper::visitVFTable(VFTableRecord &VFT) {
Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR,
VFTableRecord &VFT) {
printTypeIndex("CompleteClass", VFT.getCompleteClass());
printTypeIndex("OverriddenVFTable", VFT.getOverriddenVTable());
W->printHex("VFPtrOffset", VFT.getVFPtrOffset());
@ -319,7 +330,8 @@ Error CVTypeDumper::visitVFTable(VFTableRecord &VFT) {
return Error::success();
}
Error CVTypeDumper::visitMemberFuncId(MemberFuncIdRecord &Id) {
Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR,
MemberFuncIdRecord &Id) {
printTypeIndex("ClassType", Id.getClassType());
printTypeIndex("FunctionType", Id.getFunctionType());
W->printString("Name", Id.getName());
@ -327,7 +339,8 @@ Error CVTypeDumper::visitMemberFuncId(MemberFuncIdRecord &Id) {
return Error::success();
}
Error CVTypeDumper::visitProcedure(ProcedureRecord &Proc) {
Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR,
ProcedureRecord &Proc) {
printTypeIndex("ReturnType", Proc.getReturnType());
W->printEnum("CallingConvention", uint8_t(Proc.getCallConv()),
makeArrayRef(CallingConventions));
@ -345,7 +358,8 @@ Error CVTypeDumper::visitProcedure(ProcedureRecord &Proc) {
return Error::success();
}
Error CVTypeDumper::visitMemberFunction(MemberFunctionRecord &MF) {
Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR,
MemberFunctionRecord &MF) {
printTypeIndex("ReturnType", MF.getReturnType());
printTypeIndex("ClassType", MF.getClassType());
printTypeIndex("ThisType", MF.getThisType());
@ -369,8 +383,8 @@ Error CVTypeDumper::visitMemberFunction(MemberFunctionRecord &MF) {
return Error::success();
}
Error CVTypeDumper::visitMethodOverloadList(
MethodOverloadListRecord &MethodList) {
Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR,
MethodOverloadListRecord &MethodList) {
for (auto &M : MethodList.getMethods()) {
ListScope S(*W, "Method");
printMemberAttributes(M.getAccess(), M.getKind(), M.getOptions());
@ -381,7 +395,8 @@ Error CVTypeDumper::visitMethodOverloadList(
return Error::success();
}
Error CVTypeDumper::visitFuncId(FuncIdRecord &Func) {
Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR,
FuncIdRecord &Func) {
printTypeIndex("ParentScope", Func.getParentScope());
printTypeIndex("FunctionType", Func.getFunctionType());
W->printString("Name", Func.getName());
@ -389,7 +404,8 @@ Error CVTypeDumper::visitFuncId(FuncIdRecord &Func) {
return Error::success();
}
Error CVTypeDumper::visitTypeServer2(TypeServer2Record &TS) {
Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR,
TypeServer2Record &TS) {
W->printBinary("Signature", TS.getGuid());
W->printNumber("Age", TS.getAge());
W->printString("Name", TS.getName());
@ -397,7 +413,8 @@ Error CVTypeDumper::visitTypeServer2(TypeServer2Record &TS) {
return Error::success();
}
Error CVTypeDumper::visitPointer(PointerRecord &Ptr) {
Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR,
PointerRecord &Ptr) {
printTypeIndex("PointeeType", Ptr.getReferentType());
W->printHex("PointerAttributes", uint32_t(Ptr.getOptions()));
W->printEnum("PtrType", unsigned(Ptr.getPointerKind()),
@ -448,7 +465,8 @@ Error CVTypeDumper::visitPointer(PointerRecord &Ptr) {
return Error::success();
}
Error CVTypeDumper::visitModifier(ModifierRecord &Mod) {
Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR,
ModifierRecord &Mod) {
uint16_t Mods = static_cast<uint16_t>(Mod.getModifiers());
printTypeIndex("ModifiedType", Mod.getModifiedType());
W->printFlags("Modifiers", Mods, makeArrayRef(TypeModifierNames));
@ -466,26 +484,30 @@ Error CVTypeDumper::visitModifier(ModifierRecord &Mod) {
return Error::success();
}
Error CVTypeDumper::visitBitField(BitFieldRecord &BitField) {
Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR,
BitFieldRecord &BitField) {
printTypeIndex("Type", BitField.getType());
W->printNumber("BitSize", BitField.getBitSize());
W->printNumber("BitOffset", BitField.getBitOffset());
return Error::success();
}
Error CVTypeDumper::visitVFTableShape(VFTableShapeRecord &Shape) {
Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR,
VFTableShapeRecord &Shape) {
W->printNumber("VFEntryCount", Shape.getEntryCount());
return Error::success();
}
Error CVTypeDumper::visitUdtSourceLine(UdtSourceLineRecord &Line) {
Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR,
UdtSourceLineRecord &Line) {
printTypeIndex("UDT", Line.getUDT());
printTypeIndex("SourceFile", Line.getSourceFile());
W->printNumber("LineNumber", Line.getLineNumber());
return Error::success();
}
Error CVTypeDumper::visitUdtModSourceLine(UdtModSourceLineRecord &Line) {
Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR,
UdtModSourceLineRecord &Line) {
printTypeIndex("UDT", Line.getUDT());
printTypeIndex("SourceFile", Line.getSourceFile());
W->printNumber("LineNumber", Line.getLineNumber());
@ -493,7 +515,8 @@ Error CVTypeDumper::visitUdtModSourceLine(UdtModSourceLineRecord &Line) {
return Error::success();
}
Error CVTypeDumper::visitBuildInfo(BuildInfoRecord &Args) {
Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR,
BuildInfoRecord &Args) {
W->printNumber("NumArgs", static_cast<uint32_t>(Args.getArgs().size()));
ListScope Arguments(*W, "Arguments");
@ -533,7 +556,8 @@ Error CVTypeDumper::visitUnknownType(const CVRecord<TypeLeafKind> &Record) {
return Error::success();
}
Error CVTypeDumper::visitNestedType(NestedTypeRecord &Nested) {
Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR,
NestedTypeRecord &Nested) {
DictScope S(*W, "NestedType");
printTypeIndex("Type", Nested.getNestedType());
W->printString("Name", Nested.getName());
@ -541,7 +565,8 @@ Error CVTypeDumper::visitNestedType(NestedTypeRecord &Nested) {
return Error::success();
}
Error CVTypeDumper::visitOneMethod(OneMethodRecord &Method) {
Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR,
OneMethodRecord &Method) {
DictScope S(*W, "OneMethod");
MethodKind K = Method.getKind();
printMemberAttributes(Method.getAccess(), K, Method.getOptions());
@ -554,7 +579,8 @@ Error CVTypeDumper::visitOneMethod(OneMethodRecord &Method) {
return Error::success();
}
Error CVTypeDumper::visitOverloadedMethod(OverloadedMethodRecord &Method) {
Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR,
OverloadedMethodRecord &Method) {
DictScope S(*W, "OverloadedMethod");
W->printHex("MethodCount", Method.getNumOverloads());
printTypeIndex("MethodListIndex", Method.getMethodList());
@ -563,7 +589,8 @@ Error CVTypeDumper::visitOverloadedMethod(OverloadedMethodRecord &Method) {
return Error::success();
}
Error CVTypeDumper::visitDataMember(DataMemberRecord &Field) {
Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR,
DataMemberRecord &Field) {
DictScope S(*W, "DataMember");
printMemberAttributes(Field.getAccess(), MethodKind::Vanilla,
MethodOptions::None);
@ -574,7 +601,8 @@ Error CVTypeDumper::visitDataMember(DataMemberRecord &Field) {
return Error::success();
}
Error CVTypeDumper::visitStaticDataMember(StaticDataMemberRecord &Field) {
Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR,
StaticDataMemberRecord &Field) {
DictScope S(*W, "StaticDataMember");
printMemberAttributes(Field.getAccess(), MethodKind::Vanilla,
MethodOptions::None);
@ -584,13 +612,15 @@ Error CVTypeDumper::visitStaticDataMember(StaticDataMemberRecord &Field) {
return Error::success();
}
Error CVTypeDumper::visitVFPtr(VFPtrRecord &VFTable) {
Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR,
VFPtrRecord &VFTable) {
DictScope S(*W, "VFPtr");
printTypeIndex("Type", VFTable.getType());
return Error::success();
}
Error CVTypeDumper::visitEnumerator(EnumeratorRecord &Enum) {
Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR,
EnumeratorRecord &Enum) {
DictScope S(*W, "Enumerator");
printMemberAttributes(Enum.getAccess(), MethodKind::Vanilla,
MethodOptions::None);
@ -600,7 +630,8 @@ Error CVTypeDumper::visitEnumerator(EnumeratorRecord &Enum) {
return Error::success();
}
Error CVTypeDumper::visitBaseClass(BaseClassRecord &Base) {
Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR,
BaseClassRecord &Base) {
DictScope S(*W, "BaseClass");
printMemberAttributes(Base.getAccess(), MethodKind::Vanilla,
MethodOptions::None);
@ -609,7 +640,8 @@ Error CVTypeDumper::visitBaseClass(BaseClassRecord &Base) {
return Error::success();
}
Error CVTypeDumper::visitVirtualBaseClass(VirtualBaseClassRecord &Base) {
Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR,
VirtualBaseClassRecord &Base) {
DictScope S(*W, "VirtualBaseClass");
printMemberAttributes(Base.getAccess(), MethodKind::Vanilla,
MethodOptions::None);
@ -620,7 +652,8 @@ Error CVTypeDumper::visitVirtualBaseClass(VirtualBaseClassRecord &Base) {
return Error::success();
}
Error CVTypeDumper::visitListContinuation(ListContinuationRecord &Cont) {
Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR,
ListContinuationRecord &Cont) {
DictScope S(*W, "ListContinuation");
printTypeIndex("ContinuationIndex", Cont.getContinuationIndex());
return Error::success();
@ -665,7 +698,8 @@ void CVTypeDumper::printTypeIndex(StringRef FieldName, TypeIndex TI) {
Error CVTypeDumper::dump(const CVRecord<TypeLeafKind> &Record) {
assert(W && "printer should not be null");
CVTypeVisitor Visitor(*this);
TypeDeserializer Deserializer(*this);
CVTypeVisitor Visitor(Deserializer);
if (auto EC = Visitor.visitTypeRecord(Record))
return EC;
@ -674,7 +708,9 @@ Error CVTypeDumper::dump(const CVRecord<TypeLeafKind> &Record) {
Error CVTypeDumper::dump(const CVTypeArray &Types) {
assert(W && "printer should not be null");
CVTypeVisitor Visitor(*this);
TypeDeserializer Deserializer(*this);
CVTypeVisitor Visitor(Deserializer);
if (auto EC = Visitor.visitTypeStream(Types))
return EC;
return Error::success();

View File

@ -114,6 +114,11 @@ NestedTypeRecord::deserialize(TypeRecordKind Kind, ArrayRef<uint8_t> &Data) {
return NestedTypeRecord(L->Type, Name);
}
Expected<FieldListRecord>
FieldListRecord::deserialize(TypeRecordKind Kind, ArrayRef<uint8_t> &Data) {
return FieldListRecord(Data);
}
Expected<ArrayRecord> ArrayRecord::deserialize(TypeRecordKind Kind,
ArrayRef<uint8_t> &Data) {
const Layout *L = nullptr;

View File

@ -12,6 +12,7 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
#include "llvm/DebugInfo/CodeView/FieldListRecordBuilder.h"
#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
@ -58,7 +59,8 @@ public:
/// TypeVisitorCallbacks overrides.
#define TYPE_RECORD(EnumName, EnumVal, Name) \
Error visit##Name(Name##Record &Record) override;
Error visitKnownRecord(const 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)
@ -70,11 +72,28 @@ public:
Error visitTypeBegin(const CVRecord<TypeLeafKind> &Record) override;
Error visitTypeEnd(const CVRecord<TypeLeafKind> &Record) override;
Error visitFieldListEnd(const CVRecord<TypeLeafKind> &Record) override;
bool mergeStream(const CVTypeArray &Types);
private:
template <typename RecordType>
Error visitKnownRecordImpl(RecordType &Record) {
FoundBadTypeIndex |= !Record.remapTypeIndices(IndexMap);
IndexMap.push_back(DestStream.writeKnownType(Record));
return Error::success();
}
Error visitKnownRecordImpl(FieldListRecord &Record) {
// Don't do anything, this will get written in the call to visitTypeEnd().
return Error::success();
}
template <typename RecordType>
Error visitKnownMemberRecordImpl(RecordType &Record) {
FoundBadTypeIndex |= !Record.remapTypeIndices(IndexMap);
FieldBuilder.writeMemberType(Record);
return Error::success();
}
bool hadError() { return FoundBadTypeIndex; }
bool FoundBadTypeIndex = false;
@ -93,33 +112,31 @@ private:
} // end anonymous namespace
Error TypeStreamMerger::visitTypeBegin(const CVRecord<TypeLeafKind> &Rec) {
BeginIndexMapSize = IndexMap.size();
if (Rec.Type != TypeLeafKind::LF_FIELDLIST)
BeginIndexMapSize = IndexMap.size();
return Error::success();
}
Error TypeStreamMerger::visitTypeEnd(const CVRecord<TypeLeafKind> &Rec) {
assert(IndexMap.size() == BeginIndexMapSize + 1);
return Error::success();
}
Error TypeStreamMerger::visitFieldListEnd(const CVRecord<TypeLeafKind> &Rec) {
IndexMap.push_back(DestStream.writeFieldList(FieldBuilder));
FieldBuilder.reset();
if (Rec.Type == TypeLeafKind::LF_FIELDLIST) {
IndexMap.push_back(DestStream.writeFieldList(FieldBuilder));
FieldBuilder.reset();
} else {
assert(IndexMap.size() == BeginIndexMapSize + 1);
}
return Error::success();
}
#define TYPE_RECORD(EnumName, EnumVal, Name) \
Error TypeStreamMerger::visit##Name(Name##Record &Record) { \
FoundBadTypeIndex |= !Record.remapTypeIndices(IndexMap); \
IndexMap.push_back(DestStream.write##Name(Record)); \
return Error::success(); \
Error TypeStreamMerger::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR, \
Name##Record &Record) { \
return visitKnownRecordImpl(Record); \
}
#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
#define MEMBER_RECORD(EnumName, EnumVal, Name) \
Error TypeStreamMerger::visit##Name(Name##Record &Record) { \
FoundBadTypeIndex |= !Record.remapTypeIndices(IndexMap); \
FieldBuilder.write##Name(Record); \
return Error::success(); \
Error TypeStreamMerger::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR, \
Name##Record &Record) { \
return visitKnownMemberRecordImpl(Record); \
}
#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
#include "llvm/DebugInfo/CodeView/TypeRecords.def"
@ -133,7 +150,9 @@ Error TypeStreamMerger::visitUnknownType(const CVRecord<TypeLeafKind> &Rec) {
bool TypeStreamMerger::mergeStream(const CVTypeArray &Types) {
assert(IndexMap.empty());
CVTypeVisitor Visitor(*this);
TypeDeserializer Deserializer(*this);
CVTypeVisitor Visitor(Deserializer);
if (auto EC = Visitor.visitTypeStream(Types)) {
consumeError(std::move(EC));
return false;

View File

@ -21,7 +21,7 @@ TypeTableBuilder::TypeTableBuilder() {}
TypeTableBuilder::~TypeTableBuilder() {}
TypeIndex TypeTableBuilder::writeModifier(const ModifierRecord &Record) {
TypeIndex TypeTableBuilder::writeKnownType(const ModifierRecord &Record) {
TypeRecordBuilder Builder(Record.getKind());
Builder.writeTypeIndex(Record.getModifiedType());
@ -30,7 +30,7 @@ TypeIndex TypeTableBuilder::writeModifier(const ModifierRecord &Record) {
return writeRecord(Builder);
}
TypeIndex TypeTableBuilder::writeProcedure(const ProcedureRecord &Record) {
TypeIndex TypeTableBuilder::writeKnownType(const ProcedureRecord &Record) {
TypeRecordBuilder Builder(Record.getKind());
Builder.writeTypeIndex(Record.getReturnType());
@ -42,8 +42,7 @@ TypeIndex TypeTableBuilder::writeProcedure(const ProcedureRecord &Record) {
return writeRecord(Builder);
}
TypeIndex
TypeTableBuilder::writeMemberFunction(const MemberFunctionRecord &Record) {
TypeIndex TypeTableBuilder::writeKnownType(const MemberFunctionRecord &Record) {
TypeRecordBuilder Builder(Record.getKind());
Builder.writeTypeIndex(Record.getReturnType());
@ -58,7 +57,7 @@ TypeTableBuilder::writeMemberFunction(const MemberFunctionRecord &Record) {
return writeRecord(Builder);
}
TypeIndex TypeTableBuilder::writeArgList(const ArgListRecord &Record) {
TypeIndex TypeTableBuilder::writeKnownType(const ArgListRecord &Record) {
TypeRecordBuilder Builder(Record.getKind());
Builder.writeUInt32(Record.getIndices().size());
@ -69,7 +68,7 @@ TypeIndex TypeTableBuilder::writeArgList(const ArgListRecord &Record) {
return writeRecord(Builder);
}
TypeIndex TypeTableBuilder::writePointer(const PointerRecord &Record) {
TypeIndex TypeTableBuilder::writeKnownType(const PointerRecord &Record) {
TypeRecordBuilder Builder(Record.getKind());
Builder.writeTypeIndex(Record.getReferentType());
@ -90,7 +89,7 @@ TypeIndex TypeTableBuilder::writePointer(const PointerRecord &Record) {
return writeRecord(Builder);
}
TypeIndex TypeTableBuilder::writeArray(const ArrayRecord &Record) {
TypeIndex TypeTableBuilder::writeKnownType(const ArrayRecord &Record) {
TypeRecordBuilder Builder(Record.getKind());
Builder.writeTypeIndex(Record.getElementType());
@ -101,7 +100,7 @@ TypeIndex TypeTableBuilder::writeArray(const ArrayRecord &Record) {
return writeRecord(Builder);
}
TypeIndex TypeTableBuilder::writeClass(const ClassRecord &Record) {
TypeIndex TypeTableBuilder::writeKnownType(const ClassRecord &Record) {
assert((Record.getKind() == TypeRecordKind::Struct) ||
(Record.getKind() == TypeRecordKind::Class) ||
(Record.getKind() == TypeRecordKind::Interface));
@ -128,7 +127,7 @@ TypeIndex TypeTableBuilder::writeClass(const ClassRecord &Record) {
return writeRecord(Builder);
}
TypeIndex TypeTableBuilder::writeUnion(const UnionRecord &Record) {
TypeIndex TypeTableBuilder::writeKnownType(const UnionRecord &Record) {
TypeRecordBuilder Builder(TypeRecordKind::Union);
Builder.writeUInt16(Record.getMemberCount());
uint16_t Flags =
@ -145,7 +144,7 @@ TypeIndex TypeTableBuilder::writeUnion(const UnionRecord &Record) {
return writeRecord(Builder);
}
TypeIndex TypeTableBuilder::writeEnum(const EnumRecord &Record) {
TypeIndex TypeTableBuilder::writeKnownType(const EnumRecord &Record) {
TypeRecordBuilder Builder(Record.getKind());
Builder.writeUInt16(Record.getMemberCount());
@ -161,7 +160,7 @@ TypeIndex TypeTableBuilder::writeEnum(const EnumRecord &Record) {
return writeRecord(Builder);
}
TypeIndex TypeTableBuilder::writeBitField(const BitFieldRecord &Record) {
TypeIndex TypeTableBuilder::writeKnownType(const BitFieldRecord &Record) {
TypeRecordBuilder Builder(Record.getKind());
Builder.writeTypeIndex(Record.getType());
@ -171,8 +170,7 @@ TypeIndex TypeTableBuilder::writeBitField(const BitFieldRecord &Record) {
return writeRecord(Builder);
}
TypeIndex
TypeTableBuilder::writeVFTableShape(const VFTableShapeRecord &Record) {
TypeIndex TypeTableBuilder::writeKnownType(const VFTableShapeRecord &Record) {
TypeRecordBuilder Builder(Record.getKind());
ArrayRef<VFTableSlotKind> Slots = Record.getSlots();
@ -189,8 +187,7 @@ TypeTableBuilder::writeVFTableShape(const VFTableShapeRecord &Record) {
return writeRecord(Builder);
}
TypeIndex
TypeTableBuilder::writeVFTable(const VFTableRecord &Record) {
TypeIndex TypeTableBuilder::writeKnownType(const VFTableRecord &Record) {
TypeRecordBuilder Builder(Record.getKind());
Builder.writeTypeIndex(Record.getCompleteClass());
Builder.writeTypeIndex(Record.getOverriddenVTable());
@ -209,15 +206,14 @@ TypeTableBuilder::writeVFTable(const VFTableRecord &Record) {
return writeRecord(Builder);
}
TypeIndex TypeTableBuilder::writeStringId(const StringIdRecord &Record) {
TypeIndex TypeTableBuilder::writeKnownType(const StringIdRecord &Record) {
TypeRecordBuilder Builder(TypeRecordKind::StringId);
Builder.writeTypeIndex(Record.getId());
Builder.writeNullTerminatedString(Record.getString());
return writeRecord(Builder);
}
TypeIndex
TypeTableBuilder::writeUdtSourceLine(const UdtSourceLineRecord &Record) {
TypeIndex TypeTableBuilder::writeKnownType(const UdtSourceLineRecord &Record) {
TypeRecordBuilder Builder(Record.getKind());
Builder.writeTypeIndex(Record.getUDT());
Builder.writeTypeIndex(Record.getSourceFile());
@ -226,7 +222,7 @@ TypeTableBuilder::writeUdtSourceLine(const UdtSourceLineRecord &Record) {
}
TypeIndex
TypeTableBuilder::writeUdtModSourceLine(const UdtModSourceLineRecord &Record) {
TypeTableBuilder::writeKnownType(const UdtModSourceLineRecord &Record) {
TypeRecordBuilder Builder(Record.getKind());
Builder.writeTypeIndex(Record.getUDT());
Builder.writeTypeIndex(Record.getSourceFile());
@ -235,7 +231,7 @@ TypeTableBuilder::writeUdtModSourceLine(const UdtModSourceLineRecord &Record) {
return writeRecord(Builder);
}
TypeIndex TypeTableBuilder::writeFuncId(const FuncIdRecord &Record) {
TypeIndex TypeTableBuilder::writeKnownType(const FuncIdRecord &Record) {
TypeRecordBuilder Builder(Record.getKind());
Builder.writeTypeIndex(Record.getParentScope());
Builder.writeTypeIndex(Record.getFunctionType());
@ -243,8 +239,7 @@ TypeIndex TypeTableBuilder::writeFuncId(const FuncIdRecord &Record) {
return writeRecord(Builder);
}
TypeIndex
TypeTableBuilder::writeMemberFuncId(const MemberFuncIdRecord &Record) {
TypeIndex TypeTableBuilder::writeKnownType(const MemberFuncIdRecord &Record) {
TypeRecordBuilder Builder(Record.getKind());
Builder.writeTypeIndex(Record.getClassType());
Builder.writeTypeIndex(Record.getFunctionType());
@ -252,8 +247,7 @@ TypeTableBuilder::writeMemberFuncId(const MemberFuncIdRecord &Record) {
return writeRecord(Builder);
}
TypeIndex
TypeTableBuilder::writeBuildInfo(const BuildInfoRecord &Record) {
TypeIndex TypeTableBuilder::writeKnownType(const BuildInfoRecord &Record) {
TypeRecordBuilder Builder(Record.getKind());
assert(Record.getArgs().size() <= UINT16_MAX);
Builder.writeUInt16(Record.getArgs().size());
@ -270,8 +264,8 @@ TypeIndex TypeTableBuilder::writeFieldList(FieldListRecordBuilder &FieldList) {
return FieldList.writeListRecord(*this);
}
TypeIndex TypeTableBuilder::writeMethodOverloadList(
const MethodOverloadListRecord &Record) {
TypeIndex
TypeTableBuilder::writeKnownType(const MethodOverloadListRecord &Record) {
TypeRecordBuilder Builder(Record.getKind());
for (const OneMethodRecord &Method : Record.getMethods()) {
uint16_t Flags = static_cast<uint16_t>(Method.getAccess());
@ -294,7 +288,7 @@ TypeIndex TypeTableBuilder::writeMethodOverloadList(
return writeRecord(Builder);
}
TypeIndex TypeTableBuilder::writeTypeServer2(const TypeServer2Record &Record) {
TypeIndex TypeTableBuilder::writeKnownType(const TypeServer2Record &Record) {
TypeRecordBuilder Builder(Record.getKind());
Builder.writeGuid(Record.getGuid());
Builder.writeUInt32(Record.getAge());

View File

@ -11,6 +11,7 @@
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
#include "llvm/DebugInfo/CodeView/CodeView.h"
#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
@ -96,17 +97,28 @@ public:
uint32_t NumHashBuckets)
: HashValues(HashValues), NumHashBuckets(NumHashBuckets) {}
Error visitUdtSourceLine(UdtSourceLineRecord &Rec) override {
Error visitKnownRecord(const CVRecord<TypeLeafKind> &CVR,
UdtSourceLineRecord &Rec) override {
return verifySourceLine(Rec);
}
Error visitUdtModSourceLine(UdtModSourceLineRecord &Rec) override {
Error visitKnownRecord(const CVRecord<TypeLeafKind> &CVR,
UdtModSourceLineRecord &Rec) override {
return verifySourceLine(Rec);
}
Error visitClass(ClassRecord &Rec) override { return verify(Rec); }
Error visitEnum(EnumRecord &Rec) override { return verify(Rec); }
Error visitUnion(UnionRecord &Rec) override { return verify(Rec); }
Error visitKnownRecord(const CVRecord<TypeLeafKind> &CVR,
ClassRecord &Rec) override {
return verify(Rec);
}
Error visitKnownRecord(const CVRecord<TypeLeafKind> &CVR,
EnumRecord &Rec) override {
return verify(Rec);
}
Error visitKnownRecord(const CVRecord<TypeLeafKind> &CVR,
UnionRecord &Rec) override {
return verify(Rec);
}
Error visitTypeBegin(const CVRecord<TypeLeafKind> &Rec) override {
++Index;
@ -148,7 +160,8 @@ private:
// Currently we only verify SRC_LINE records.
Error TpiStream::verifyHashValues() {
TpiHashVerifier Verifier(HashValues, Header->NumHashBuckets);
CVTypeVisitor Visitor(Verifier);
TypeDeserializer Deserializer(Verifier);
CVTypeVisitor Visitor(Deserializer);
return Visitor.visitTypeStream(TypeRecords);
}

View File

@ -83,7 +83,7 @@ static void printSectionOffset(llvm::raw_ostream &OS,
}
LLVMOutputStyle::LLVMOutputStyle(PDBFile &File)
: File(File), P(outs()), TD(&P, false) {}
: File(File), P(outs()), Dumper(&P, false) {}
Error LLVMOutputStyle::dump() {
if (auto EC = dumpFileHeaders())
@ -482,7 +482,7 @@ Error LLVMOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
DictScope DD(P, "");
if (DumpRecords) {
if (auto EC = TD.dump(Type))
if (auto EC = Dumper.dump(Type))
return EC;
}
@ -498,16 +498,16 @@ Error LLVMOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
// iterate them in order to build the list of types so that we can print
// them when dumping module symbols. So when they want to dump symbols
// but not types, use a null output stream.
ScopedPrinter *OldP = TD.getPrinter();
TD.setPrinter(nullptr);
ScopedPrinter *OldP = Dumper.getPrinter();
Dumper.setPrinter(nullptr);
bool HadError = false;
for (auto &Type : Tpi->types(&HadError)) {
if (auto EC = TD.dump(Type))
if (auto EC = Dumper.dump(Type))
return EC;
}
TD.setPrinter(OldP);
Dumper.setPrinter(OldP);
dumpTpiHash(P, *Tpi);
if (HadError)
return make_error<RawError>(raw_error_code::corrupt_file,
@ -586,7 +586,7 @@ Error LLVMOutputStyle::dumpDbiStream() {
if (ShouldDumpSymbols) {
ListScope SS(P, "Symbols");
codeview::CVSymbolDumper SD(P, TD, nullptr, false);
codeview::CVSymbolDumper SD(P, Dumper, nullptr, false);
bool HadError = false;
for (const auto &S : ModS.symbols(&HadError)) {
DictScope DD(P, "");
@ -796,7 +796,7 @@ Error LLVMOutputStyle::dumpPublicsStream() {
P.printList("Section Offsets", Publics->getSectionOffsets(),
printSectionOffset);
ListScope L(P, "Symbols");
codeview::CVSymbolDumper SD(P, TD, nullptr, false);
codeview::CVSymbolDumper SD(P, Dumper, nullptr, false);
bool HadError = false;
for (auto S : Publics->getSymbols(&HadError)) {
DictScope DD(P, "");

View File

@ -46,7 +46,7 @@ private:
PDBFile &File;
ScopedPrinter P;
codeview::CVTypeDumper TD;
codeview::CVTypeDumper Dumper;
};
}
}

View File

@ -272,18 +272,16 @@ LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg) {
exit(1);
}
void error(llvm::Error EC) {
void error(Error EC) {
if (!EC)
return;
handleAllErrors(std::move(EC),
[&](ErrorInfoBase &EI) { reportError(EI.message()); });
[&](const ErrorInfoBase &EI) { reportError(EI.message()); });
}
void error(std::error_code EC) {
if (!EC)
return;
reportError(EC.message());
}

View File

@ -23,7 +23,7 @@ namespace llvm {
// Various helper functions.
LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg);
void error(std::error_code ec);
void error(std::error_code EC);
void error(llvm::Error EC);
template <class T> T unwrapOrError(ErrorOr<T> EO) {
if (EO)