#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
-#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
#include "llvm/DebugInfo/MSF/StreamReader.h"
#include "llvm/DebugInfo/MSF/StreamWriter.h"
#include "llvm/Support/Error.h"
-#include <stdint.h>
#include <type_traits>
+#include <stdint.h>
+
namespace llvm {
-namespace msf {
-class StreamReader;
-class StreamWriter;
-}
namespace codeview {
class CodeViewRecordIO {
- struct ActiveRecord {
- uint16_t Kind;
- };
+ uint32_t getCurrentOffset() const {
+ return (isWriting()) ? Writer->getOffset() : Reader->getOffset();
+ }
public:
explicit CodeViewRecordIO(msf::StreamReader &Reader) : Reader(&Reader) {}
explicit CodeViewRecordIO(msf::StreamWriter &Writer) : Writer(&Writer) {}
- Error beginRecord(uint16_t Kind);
+ Error beginRecord(Optional<uint32_t> MaxLength);
Error endRecord();
+
Error mapInteger(TypeIndex &TypeInd);
bool isReading() const { return Reader != nullptr; }
bool isWriting() const { return !isReading(); }
+ uint32_t maxFieldLength() const;
+
template <typename T> Error mapInteger(T &Value) {
if (isWriting())
return Writer->writeInteger(Value);
}
template <typename T> Error mapEnum(T &Value) {
+ if (sizeof(Value) > maxFieldLength())
+ return make_error<CodeViewError>(cv_error_code::insufficient_buffer);
+
using U = typename std::underlying_type<T>::type;
U X;
if (isWriting())
Error writeEncodedSignedInteger(const int64_t &Value);
Error writeEncodedUnsignedInteger(const uint64_t &Value);
- Optional<ActiveRecord> CurrentRecord;
+ struct RecordLimit {
+ uint32_t BeginOffset;
+ Optional<uint32_t> MaxLength;
+
+ Optional<uint32_t> bytesRemaining(uint32_t CurrentOffset) const {
+ if (!MaxLength.hasValue())
+ return None;
+ assert(CurrentOffset >= BeginOffset);
+
+ uint32_t BytesUsed = CurrentOffset - BeginOffset;
+ if (BytesUsed >= *MaxLength)
+ return 0;
+ return *MaxLength - BytesUsed;
+ }
+ };
+
+ SmallVector<RecordLimit, 2> Limits;
msf::StreamReader *Reader = nullptr;
msf::StreamWriter *Writer = nullptr;
+++ /dev/null
-//===- FieldListRecordBuilder.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_FIELDLISTRECORDBUILDER_H
-#define LLVM_DEBUGINFO_CODEVIEW_FIELDLISTRECORDBUILDER_H
-
-#include "llvm/DebugInfo/CodeView/ListRecordBuilder.h"
-#include "llvm/DebugInfo/CodeView/TypeRecord.h"
-
-namespace llvm {
-namespace codeview {
-
-class MethodInfo {
-public:
- MethodInfo() : Access(), Kind(), Options(), Type(), VTableSlotOffset(-1) {}
-
- MethodInfo(MemberAccess Access, MethodKind Kind, MethodOptions Options,
- TypeIndex Type, int32_t VTableSlotOffset)
- : Access(Access), Kind(Kind), Options(Options), Type(Type),
- VTableSlotOffset(VTableSlotOffset) {}
-
- MemberAccess getAccess() const { return Access; }
- MethodKind getKind() const { return Kind; }
- MethodOptions getOptions() const { return Options; }
- TypeIndex getType() const { return Type; }
- int32_t getVTableSlotOffset() const { return VTableSlotOffset; }
-
-private:
- MemberAccess Access;
- MethodKind Kind;
- MethodOptions Options;
- TypeIndex Type;
- int32_t VTableSlotOffset;
-};
-
-class FieldListRecordBuilder : public ListRecordBuilder {
-private:
- FieldListRecordBuilder(const FieldListRecordBuilder &) = delete;
- void operator=(const FieldListRecordBuilder &) = delete;
-
-public:
- FieldListRecordBuilder();
-
- void reset() { ListRecordBuilder::reset(); }
-
- 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;
-};
-}
-}
-
-#endif
+++ /dev/null
-//===- ListRecordBuilder.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_LISTRECORDBUILDER_H
-#define LLVM_DEBUGINFO_CODEVIEW_LISTRECORDBUILDER_H
-
-#include "llvm/DebugInfo/CodeView/TypeRecordBuilder.h"
-
-namespace llvm {
-namespace codeview {
-class TypeTableBuilder;
-
-class ListRecordBuilder {
-private:
- ListRecordBuilder(const ListRecordBuilder &) = delete;
- ListRecordBuilder &operator=(const ListRecordBuilder &) = delete;
-
-protected:
- const int MethodKindShift = 2;
-
- explicit ListRecordBuilder(TypeRecordKind Kind);
-
-public:
- llvm::StringRef str() { return Builder.str(); }
-
- void reset() {
- Builder.reset(Kind);
- ContinuationOffsets.clear();
- SubrecordStart = 0;
- }
-
- void writeMemberType(const ListContinuationRecord &R);
-
- /// Writes this list record as a possible sequence of records.
- TypeIndex writeListRecord(TypeTableBuilder &Table);
-
-protected:
- void finishSubRecord();
-
- TypeRecordBuilder &getBuilder() { return Builder; }
-
-private:
- size_t getLastContinuationStart() const {
- return ContinuationOffsets.empty() ? 0 : ContinuationOffsets.back();
- }
- size_t getLastContinuationEnd() const { return Builder.size(); }
- size_t getLastContinuationSize() const {
- return getLastContinuationEnd() - getLastContinuationStart();
- }
-
- TypeRecordKind Kind;
- TypeRecordBuilder Builder;
- SmallVector<size_t, 4> ContinuationOffsets;
- size_t SubrecordStart = 0;
-};
-}
-}
-
-#endif
+++ /dev/null
-//===- MemoryTypeTableBuilder.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_MEMORYTYPETABLEBUILDER_H
-#define LLVM_DEBUGINFO_CODEVIEW_MEMORYTYPETABLEBUILDER_H
-
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
-#include <vector>
-
-namespace llvm {
-namespace codeview {
-
-class MemoryTypeTableBuilder : public TypeTableBuilder {
-public:
- explicit MemoryTypeTableBuilder(BumpPtrAllocator &Allocator)
- : RecordStorage(Allocator) {}
-
- bool empty() const { return Records.empty(); }
-
- template <typename TFunc> void ForEachRecord(TFunc Func) {
- uint32_t Index = TypeIndex::FirstNonSimpleIndex;
-
- for (StringRef R : Records) {
- Func(TypeIndex(Index), R);
- ++Index;
- }
- }
-
- TypeIndex writeRecord(llvm::StringRef Data) override;
-
- ArrayRef<StringRef> getRecords() const { return Records; }
-
-private:
- std::vector<StringRef> Records;
- BumpPtrAllocator &RecordStorage;
- DenseMap<StringRef, TypeIndex> HashedRecords;
-};
-
-} // end namespace codeview
-} // end namespace llvm
-
-#endif // LLVM_DEBUGINFO_CODEVIEW_MEMORYTYPETABLEBUILDER_H
+++ /dev/null
-//===- MethodListRecordBuilder.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_METHODLISTRECORDBUILDER_H
-#define LLVM_DEBUGINFO_CODEVIEW_METHODLISTRECORDBUILDER_H
-
-#include "llvm/DebugInfo/CodeView/ListRecordBuilder.h"
-
-namespace llvm {
-namespace codeview {
-
-class MethodInfo;
-
-class MethodListRecordBuilder : public ListRecordBuilder {
-private:
- MethodListRecordBuilder(const MethodListRecordBuilder &) = delete;
- MethodListRecordBuilder &operator=(const MethodListRecordBuilder &) = delete;
-
-public:
- MethodListRecordBuilder();
-
- void writeMethod(MemberAccess Access, MethodKind Kind, MethodOptions Options,
- TypeIndex Type, int32_t VTableSlotOffset);
- void writeMethod(const MethodInfo &Method);
-};
-}
-}
-
-#endif
enum : unsigned { MaxRecordLength = 0xFF00 };
struct RecordPrefix {
- ulittle16_t RecordLen; // Record length, starting from &Leaf.
+ ulittle16_t RecordLen; // Record length, starting from &RecordKind.
ulittle16_t RecordKind; // Record kind enum (SymRecordKind or TypeRecordKind)
};
};
public:
- explicit FieldListDeserializer(msf::StreamReader &Reader) : Mapping(Reader) {}
+ explicit FieldListDeserializer(msf::StreamReader &Reader) : Mapping(Reader) {
+ CVType FieldList;
+ FieldList.Type = TypeLeafKind::LF_FIELDLIST;
+ consumeError(Mapping.Mapping.visitTypeBegin(FieldList));
+ }
+
+ ~FieldListDeserializer() {
+ CVType FieldList;
+ FieldList.Type = TypeLeafKind::LF_FIELDLIST;
+ consumeError(Mapping.Mapping.visitTypeEnd(FieldList));
+ }
Error visitMemberBegin(CVMemberRecord &Record) override {
Mapping.StartOffset = Mapping.Reader.getOffset();
static const uint32_t SimpleModeMask = 0x00000700;
public:
- TypeIndex() : Index(0) {}
+ TypeIndex() : Index(static_cast<uint32_t>(SimpleTypeKind::None)) {}
explicit TypeIndex(uint32_t Index) : Index(Index) {}
explicit TypeIndex(SimpleTypeKind Kind)
: Index(static_cast<uint32_t>(Kind)) {}
StringRef Name)
: TypeRecord(TypeRecordKind::OneMethod), Type(Type), Attrs(Attrs),
VFTableOffset(VFTableOffset), Name(Name) {}
- OneMethodRecord(TypeIndex Type, MemberAccess Access, MethodKind Kind,
+ OneMethodRecord(TypeIndex Type, MemberAccess Access, MethodKind MK,
MethodOptions Options, int32_t VFTableOffset, StringRef Name)
: TypeRecord(TypeRecordKind::OneMethod), Type(Type),
- Attrs(Access, Kind, Options), VFTableOffset(VFTableOffset), Name(Name) {
- }
+ Attrs(Access, MK, Options), VFTableOffset(VFTableOffset), Name(Name) {}
/// Rewrite member type indices with IndexMap. Returns false if a type index
/// is not in the map.
bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap);
TypeIndex getType() const { return Type; }
- MethodKind getKind() const { return Attrs.getMethodKind(); }
+ MethodKind getMethodKind() const { return Attrs.getMethodKind(); }
MethodOptions getOptions() const { return Attrs.getFlags(); }
MemberAccess getAccess() const { return Attrs.getAccess(); }
int32_t getVFTableOffset() const { return VFTableOffset; }
StringRef getName() const { return Name; }
bool isIntroducingVirtual() const {
- return getKind() == MethodKind::IntroducingVirtual ||
- getKind() == MethodKind::PureIntroducingVirtual;
+ return getMethodKind() == MethodKind::IntroducingVirtual ||
+ getMethodKind() == MethodKind::PureIntroducingVirtual;
}
TypeIndex Type;
MemberAttributes Attrs;
#include "llvm/Support/Error.h"
namespace llvm {
+namespace msf {
+class StreamReader;
+class StreamWriter;
+}
namespace codeview {
class TypeRecordMapping : public TypeVisitorCallbacks {
public:
explicit TypeRecordMapping(msf::StreamReader &Reader) : IO(Reader) {}
+ explicit TypeRecordMapping(msf::StreamWriter &Writer) : IO(Writer) {}
Error visitTypeBegin(CVType &Record) override;
Error visitTypeEnd(CVType &Record) override;
private:
Optional<TypeLeafKind> TypeKind;
+ Optional<TypeLeafKind> MemberKind;
CodeViewRecordIO IO;
};
+++ /dev/null
-//===- TypeSerializationVisitor.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_TYPESERIALIZATIONVISITOR_H
-#define LLVM_DEBUGINFO_CODEVIEW_TYPESERIALIZATIONVISITOR_H
-
-#include "llvm/DebugInfo/CodeView/FieldListRecordBuilder.h"
-#include "llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h"
-#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
-
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/Error.h"
-
-namespace llvm {
-namespace codeview {
-
-class TypeSerializationVisitor : public TypeVisitorCallbacks {
-public:
- TypeSerializationVisitor(FieldListRecordBuilder &FieldListBuilder,
- MemoryTypeTableBuilder &TypeTableBuilder)
- : FieldListBuilder(FieldListBuilder), TypeTableBuilder(TypeTableBuilder) {
- }
-
- virtual Error visitTypeBegin(CVType &Record) override {
- if (Record.Type == TypeLeafKind::LF_FIELDLIST)
- FieldListBuilder.reset();
- return Error::success();
- }
-
- 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);
- updateCVRecord(Record);
- }
-
- return Error::success();
- }
-
-#define TYPE_RECORD(EnumName, EnumVal, Name) \
- virtual Error visitKnownRecord(CVType &CVR, Name##Record &Record) override { \
- visitKnownRecordImpl(CVR, Record); \
- return Error::success(); \
- }
-#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
-#define MEMBER_RECORD(EnumName, EnumVal, Name) \
- virtual Error visitKnownMember(CVMemberRecord &CVR, Name##Record &Record) \
- override { \
- visitMemberRecordImpl(Record); \
- return Error::success(); \
- }
-#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
-#include "llvm/DebugInfo/CodeView/TypeRecords.def"
-
-private:
- void updateCVRecord(CVType &Record) {
- StringRef S = TypeTableBuilder.getRecords().back();
- Record.RecordData = ArrayRef<uint8_t>(S.bytes_begin(), S.bytes_end());
- }
- template <typename RecordKind>
- void visitKnownRecordImpl(CVType &CVR, RecordKind &Record) {
- TypeTableBuilder.writeKnownType(Record);
- updateCVRecord(CVR);
- }
- template <typename RecordKind>
- void visitMemberRecordImpl(RecordKind &Record) {
- FieldListBuilder.writeMemberType(Record);
- }
-
- void visitKnownRecordImpl(CVType &CVR, FieldListRecord &FieldList) {}
-
- FieldListRecordBuilder &FieldListBuilder;
- MemoryTypeTableBuilder &TypeTableBuilder;
-};
-}
-}
-
-#endif
--- /dev/null
+//===- TypeSerializer.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_TYPESERIALIZER_H
+#define LLVM_DEBUGINFO_CODEVIEW_TYPESERIALIZER_H
+
+#include "llvm/DebugInfo/CodeView/TypeRecordMapping.h"
+#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
+#include "llvm/DebugInfo/MSF/ByteStream.h"
+#include "llvm/DebugInfo/MSF/StreamWriter.h"
+
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Error.h"
+
+namespace llvm {
+
+namespace codeview {
+
+class TypeSerializer : public TypeVisitorCallbacks {
+ struct SubRecord {
+ SubRecord(TypeLeafKind K, uint32_t S) : Kind(K), Size(S) {}
+
+ TypeLeafKind Kind;
+ uint32_t Size = 0;
+ };
+ struct RecordSegment {
+ SmallVector<SubRecord, 16> SubRecords;
+
+ uint32_t length() const {
+ uint32_t L = sizeof(RecordPrefix);
+ for (const auto &R : SubRecords) {
+ L += R.Size;
+ }
+ return L;
+ }
+ };
+
+ typedef SmallVector<MutableArrayRef<uint8_t>, 2> RecordList;
+
+ static constexpr uint8_t ContinuationLength = 8;
+ BumpPtrAllocator &RecordStorage;
+ RecordSegment CurrentSegment;
+ RecordList FieldListSegments;
+
+ TypeIndex LastTypeIndex;
+ Optional<TypeLeafKind> TypeKind;
+ Optional<TypeLeafKind> MemberKind;
+ std::vector<uint8_t> RecordBuffer;
+ msf::MutableByteStream Stream;
+ msf::StreamWriter Writer;
+ TypeRecordMapping Mapping;
+
+ RecordList SeenRecords;
+ StringMap<TypeIndex> HashedRecords;
+
+ bool isInFieldList() const;
+ TypeIndex calcNextTypeIndex() const;
+ TypeIndex incrementTypeIndex();
+ MutableArrayRef<uint8_t> getCurrentSubRecordData();
+ MutableArrayRef<uint8_t> getCurrentRecordData();
+ Error writeRecordPrefix(TypeLeafKind Kind);
+ TypeIndex insertRecordBytesPrivate(MutableArrayRef<uint8_t> Record);
+
+ Expected<MutableArrayRef<uint8_t>>
+ addPadding(MutableArrayRef<uint8_t> Record);
+
+public:
+ explicit TypeSerializer(BumpPtrAllocator &Storage);
+
+ ArrayRef<MutableArrayRef<uint8_t>> records() const;
+ TypeIndex getLastTypeIndex() const;
+ TypeIndex insertRecordBytes(MutableArrayRef<uint8_t> Record);
+ Expected<TypeIndex> visitTypeEndGetIndex(CVType &Record);
+
+ Error visitTypeBegin(CVType &Record) override;
+ Error visitTypeEnd(CVType &Record) override;
+ Error visitMemberBegin(CVMemberRecord &Record) override;
+ Error visitMemberEnd(CVMemberRecord &Record) override;
+
+#define TYPE_RECORD(EnumName, EnumVal, Name) \
+ virtual Error visitKnownRecord(CVType &CVR, Name##Record &Record) override { \
+ return visitKnownRecordImpl(CVR, Record); \
+ }
+#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
+#define MEMBER_RECORD(EnumName, EnumVal, Name) \
+ Error visitKnownMember(CVMemberRecord &CVR, Name##Record &Record) override { \
+ return visitKnownMemberImpl<Name##Record>(CVR, Record); \
+ }
+#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
+#include "llvm/DebugInfo/CodeView/TypeRecords.def"
+
+private:
+ template <typename RecordKind>
+ Error visitKnownRecordImpl(CVType &CVR, RecordKind &Record) {
+ return Mapping.visitKnownRecord(CVR, Record);
+ }
+
+ template <typename RecordType>
+ Error visitKnownMemberImpl(CVMemberRecord &CVR, RecordType &Record) {
+ assert(CVR.Kind == static_cast<TypeLeafKind>(Record.getKind()));
+
+ if (auto EC = Writer.writeEnum(CVR.Kind))
+ return EC;
+
+ if (auto EC = Mapping.visitKnownMember(CVR, Record))
+ return EC;
+
+ // Get all the data that was just written and is yet to be committed to
+ // the current segment. Then pad it to 4 bytes.
+ MutableArrayRef<uint8_t> ThisRecord = getCurrentSubRecordData();
+ auto ExpectedRecord = addPadding(ThisRecord);
+ if (!ExpectedRecord)
+ return ExpectedRecord.takeError();
+ ThisRecord = *ExpectedRecord;
+
+ CurrentSegment.SubRecords.emplace_back(CVR.Kind, ThisRecord.size());
+ CVR.Data = ThisRecord;
+
+ // Both the last subrecord and the total length of this segment should be
+ // multiples of 4.
+ assert(ThisRecord.size() % 4 == 0);
+ assert(CurrentSegment.length() % 4 == 0);
+
+ return Error::success();
+ }
+};
+}
+}
+
+#endif
#ifndef LLVM_DEBUGINFO_CODEVIEW_TYPETABLEBUILDER_H
#define LLVM_DEBUGINFO_CODEVIEW_TYPETABLEBUILDER_H
-#include "llvm/DebugInfo/CodeView/CodeView.h"
-#include "llvm/DebugInfo/CodeView/TypeIndex.h"
-#include "llvm/DebugInfo/CodeView/TypeRecord.h"
-#include "llvm/Support/Compiler.h"
+#include "llvm/DebugInfo/CodeView/TypeSerializer.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Error.h"
namespace llvm {
-class StringRef;
-
namespace codeview {
-class FieldListRecordBuilder;
-class MethodListRecordBuilder;
-class TypeRecordBuilder;
-
class TypeTableBuilder {
private:
TypeTableBuilder(const TypeTableBuilder &) = delete;
TypeTableBuilder &operator=(const TypeTableBuilder &) = delete;
-protected:
- TypeTableBuilder();
+ TypeIndex handleError(llvm::Error EC) const {
+ assert(false && "Couldn't write Type!");
+ llvm::consumeError(std::move(EC));
+ return TypeIndex();
+ }
-public:
- virtual ~TypeTableBuilder();
+ BumpPtrAllocator &Allocator;
+ TypeSerializer Serializer;
public:
- 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);
-
- TypeIndex writeRecord(TypeRecordBuilder &builder);
-
- virtual TypeIndex writeRecord(llvm::StringRef record) = 0;
-
- ArrayRef<TypeRecordKind> getRecordKinds() const { return RecordKinds; }
+ explicit TypeTableBuilder(BumpPtrAllocator &Allocator)
+ : Allocator(Allocator), Serializer(Allocator) {}
-private:
- std::vector<TypeRecordKind> RecordKinds;
+ bool empty() const { return Serializer.records().empty(); }
+
+ BumpPtrAllocator &getAllocator() const { return Allocator; }
+
+ template <typename T> TypeIndex writeKnownType(T &Record) {
+ static_assert(!std::is_same<T, FieldListRecord>::value,
+ "Can't serialize FieldList!");
+
+ CVType Type;
+ Type.Type = static_cast<TypeLeafKind>(Record.getKind());
+ if (auto EC = Serializer.visitTypeBegin(Type))
+ return handleError(std::move(EC));
+ if (auto EC = Serializer.visitKnownRecord(Type, Record))
+ return handleError(std::move(EC));
+
+ auto ExpectedIndex = Serializer.visitTypeEndGetIndex(Type);
+ if (!ExpectedIndex)
+ return handleError(ExpectedIndex.takeError());
+
+ return *ExpectedIndex;
+ }
+
+ TypeIndex writeSerializedRecord(MutableArrayRef<uint8_t> Record) {
+ return Serializer.insertRecordBytes(Record);
+ }
+
+ template <typename TFunc> void ForEachRecord(TFunc Func) {
+ uint32_t Index = TypeIndex::FirstNonSimpleIndex;
+
+ for (auto Record : Serializer.records()) {
+ Func(TypeIndex(Index), Record);
+ ++Index;
+ }
+ }
+
+ ArrayRef<MutableArrayRef<uint8_t>> records() const {
+ return Serializer.records();
+ }
+};
+
+class FieldListRecordBuilder {
+ TypeTableBuilder &TypeTable;
+ TypeSerializer TempSerializer;
+ CVType Type;
+
+public:
+ explicit FieldListRecordBuilder(TypeTableBuilder &TypeTable)
+ : TypeTable(TypeTable), TempSerializer(TypeTable.getAllocator()) {
+ Type.Type = TypeLeafKind::LF_FIELDLIST;
+ }
+
+ void begin() {
+ if (auto EC = TempSerializer.visitTypeBegin(Type))
+ consumeError(std::move(EC));
+ }
+
+ template <typename T> void writeMemberType(T &Record) {
+ CVMemberRecord CVMR;
+ CVMR.Kind = static_cast<TypeLeafKind>(Record.getKind());
+ if (auto EC = TempSerializer.visitMemberBegin(CVMR))
+ consumeError(std::move(EC));
+ if (auto EC = TempSerializer.visitKnownMember(CVMR, Record))
+ consumeError(std::move(EC));
+ if (auto EC = TempSerializer.visitMemberEnd(CVMR))
+ consumeError(std::move(EC));
+ }
+
+ TypeIndex end() {
+ if (auto EC = TempSerializer.visitTypeEnd(Type)) {
+ consumeError(std::move(EC));
+ return TypeIndex();
+ }
+
+ TypeIndex Index;
+ for (auto Record : TempSerializer.records()) {
+ Index = TypeTable.writeSerializedRecord(Record);
+ }
+ return Index;
+ }
};
}
}
#define TYPE_RECORD(EnumName, EnumVal, Name) \
Error visitKnownRecord(CVType &CVR, Name##Record &Record) override { \
- for (auto Visitor : Pipeline) { \
- if (auto EC = Visitor->visitKnownRecord(CVR, Record)) \
- return EC; \
- } \
- return Error::success(); \
+ return visitKnownRecordImpl(CVR, Record); \
}
#define MEMBER_RECORD(EnumName, EnumVal, Name) \
Error visitKnownMember(CVMemberRecord &CVMR, Name##Record &Record) \
override { \
- for (auto Visitor : Pipeline) { \
- if (auto EC = Visitor->visitKnownMember(CVMR, Record)) \
- return EC; \
- } \
- return Error::success(); \
+ return visitKnownMemberImpl(CVMR, Record); \
}
#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
#include "llvm/DebugInfo/CodeView/TypeRecords.def"
private:
+ template <typename T> Error visitKnownRecordImpl(CVType &CVR, T &Record) {
+ for (auto Visitor : Pipeline) {
+ if (auto EC = Visitor->visitKnownRecord(CVR, Record))
+ return EC;
+ }
+ return Error::success();
+ }
+
+ template <typename T>
+ Error visitKnownMemberImpl(CVMemberRecord &CVMR, T &Record) {
+ for (auto Visitor : Pipeline) {
+ if (auto EC = Visitor->visitKnownMember(CVMR, Record))
+ return EC;
+ }
+ return Error::success();
+ }
std::vector<TypeVisitorCallbacks *> Pipeline;
};
}
class StreamWriter {
public:
StreamWriter() {}
- StreamWriter(WritableStreamRef Stream);
+ explicit StreamWriter(WritableStreamRef Stream);
Error writeBytes(ArrayRef<uint8_t> Buffer);
Error writeInteger(uint8_t Int);
#include "llvm/ADT/TinyPtrVector.h"
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
#include "llvm/DebugInfo/CodeView/CodeView.h"
-#include "llvm/DebugInfo/CodeView/FieldListRecordBuilder.h"
#include "llvm/DebugInfo/CodeView/Line.h"
#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
#include "llvm/DebugInfo/CodeView/TypeDumper.h"
// Build the fully qualified name of the scope.
std::string ScopeName = getFullyQualifiedName(Scope);
- TypeIndex TI =
- TypeTable.writeKnownType(StringIdRecord(TypeIndex(), ScopeName));
+ StringIdRecord SID(TypeIndex(), ScopeName);
+ auto TI = TypeTable.writeKnownType(SID);
return recordTypeIndexForDINode(Scope, TI);
}
}
CVTypeDumper CVTD(nullptr, /*PrintRecordBytes=*/false);
- TypeTable.ForEachRecord(
- [&](TypeIndex Index, StringRef Record) {
- if (OS.isVerboseAsm()) {
- // Emit a block comment describing the type record for readability.
- SmallString<512> CommentBlock;
- raw_svector_ostream CommentOS(CommentBlock);
- ScopedPrinter SP(CommentOS);
- SP.setPrefix(CommentPrefix);
- CVTD.setPrinter(&SP);
- Error E = CVTD.dump({Record.bytes_begin(), Record.bytes_end()});
- if (E) {
- logAllUnhandledErrors(std::move(E), errs(), "error: ");
- llvm_unreachable("produced malformed type record");
- }
- // emitRawComment will insert its own tab and comment string before
- // the first line, so strip off our first one. It also prints its own
- // newline.
- OS.emitRawComment(
- CommentOS.str().drop_front(CommentPrefix.size() - 1).rtrim());
- } else {
+ TypeTable.ForEachRecord([&](TypeIndex Index, ArrayRef<uint8_t> Record) {
+ if (OS.isVerboseAsm()) {
+ // Emit a block comment describing the type record for readability.
+ SmallString<512> CommentBlock;
+ raw_svector_ostream CommentOS(CommentBlock);
+ ScopedPrinter SP(CommentOS);
+ SP.setPrefix(CommentPrefix);
+ CVTD.setPrinter(&SP);
+ Error E = CVTD.dump(Record);
+ if (E) {
+ logAllUnhandledErrors(std::move(E), errs(), "error: ");
+ llvm_unreachable("produced malformed type record");
+ }
+ // emitRawComment will insert its own tab and comment string before
+ // the first line, so strip off our first one. It also prints its own
+ // newline.
+ OS.emitRawComment(
+ CommentOS.str().drop_front(CommentPrefix.size() - 1).rtrim());
+ } else {
#ifndef NDEBUG
- // Assert that the type data is valid even if we aren't dumping
- // comments. The MSVC linker doesn't do much type record validation,
- // so the first link of an invalid type record can succeed while
- // subsequent links will fail with LNK1285.
- ByteStream Stream({Record.bytes_begin(), Record.bytes_end()});
- CVTypeArray Types;
- StreamReader Reader(Stream);
- Error E = Reader.readArray(Types, Reader.getLength());
- if (!E) {
- TypeVisitorCallbacks C;
- E = CVTypeVisitor(C).visitTypeStream(Types);
- }
- if (E) {
- logAllUnhandledErrors(std::move(E), errs(), "error: ");
- llvm_unreachable("produced malformed type record");
- }
+ // Assert that the type data is valid even if we aren't dumping
+ // comments. The MSVC linker doesn't do much type record validation,
+ // so the first link of an invalid type record can succeed while
+ // subsequent links will fail with LNK1285.
+ ByteStream Stream(Record);
+ CVTypeArray Types;
+ StreamReader Reader(Stream);
+ Error E = Reader.readArray(Types, Reader.getLength());
+ if (!E) {
+ TypeVisitorCallbacks C;
+ E = CVTypeVisitor(C).visitTypeStream(Types);
+ }
+ if (E) {
+ logAllUnhandledErrors(std::move(E), errs(), "error: ");
+ llvm_unreachable("produced malformed type record");
+ }
#endif
- }
- OS.EmitBinaryData(Record);
- });
+ }
+ StringRef S(reinterpret_cast<const char *>(Record.data()), Record.size());
+ OS.EmitBinaryData(S);
+ });
}
namespace {
(i == 0 && ElementSize == 0) ? Ty->getSizeInBits() / 8 : ElementSize;
StringRef Name = (i == 0) ? Ty->getName() : "";
- ElementTypeIndex = TypeTable.writeKnownType(
- ArrayRecord(ElementTypeIndex, IndexType, ArraySize, Name));
+ ArrayRecord AR(ElementTypeIndex, IndexType, ArraySize, Name);
+ ElementTypeIndex = TypeTable.writeKnownType(AR);
}
(void)PartiallyIncomplete;
BaseTy = cast<DIDerivedType>(BaseTy)->getBaseType().resolve();
}
TypeIndex ModifiedTI = getTypeIndex(BaseTy);
- return TypeTable.writeKnownType(ModifierRecord(ModifiedTI, Mods));
+ ModifierRecord MR(ModifiedTI, Mods);
+ return TypeTable.writeKnownType(MR);
}
TypeIndex CodeViewDebug::lowerTypeFunction(const DISubroutineType *Ty) {
// TODO: Need to use the correct values for:
// FunctionOptions
// ThisPointerAdjustment.
- TypeIndex TI = TypeTable.writeKnownType(MemberFunctionRecord(
- ReturnTypeIndex, ClassType, ThisTypeIndex, CC, FunctionOptions::None,
- ArgTypeIndices.size(), ArgListIndex, ThisAdjustment));
+ MemberFunctionRecord MFR(ReturnTypeIndex, ClassType, ThisTypeIndex, CC,
+ FunctionOptions::None, ArgTypeIndices.size(),
+ ArgListIndex, ThisAdjustment);
+ TypeIndex TI = TypeTable.writeKnownType(MFR);
return TI;
}
TypeIndex CodeViewDebug::lowerTypeVFTableShape(const DIDerivedType *Ty) {
unsigned VSlotCount = Ty->getSizeInBits() / (8 * Asm->MAI->getPointerSize());
SmallVector<VFTableSlotKind, 4> Slots(VSlotCount, VFTableSlotKind::Near);
- return TypeTable.writeKnownType(VFTableShapeRecord(Slots));
+
+ VFTableShapeRecord VFTSR(Slots);
+ return TypeTable.writeKnownType(VFTSR);
}
static MemberAccess translateAccessFlags(unsigned RecordTag, unsigned Flags) {
if (Ty->isForwardDecl()) {
CO |= ClassOptions::ForwardReference;
} else {
- FieldListRecordBuilder Fields;
+ FieldListRecordBuilder FLRB(TypeTable);
+
+ FLRB.begin();
for (const DINode *Element : Ty->getElements()) {
// 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.writeMemberType(EnumeratorRecord(
- MemberAccess::Public, APSInt::getUnsigned(Enumerator->getValue()),
- Enumerator->getName()));
+ EnumeratorRecord ER(MemberAccess::Public,
+ APSInt::getUnsigned(Enumerator->getValue()),
+ Enumerator->getName());
+ FLRB.writeMemberType(ER);
EnumeratorCount++;
}
}
- FTI = TypeTable.writeFieldList(Fields);
+ FTI = FLRB.end();
}
std::string FullName = getFullyQualifiedName(Ty);
- return TypeTable.writeKnownType(EnumRecord(EnumeratorCount, CO, FTI, FullName,
- Ty->getIdentifier(),
- getTypeIndex(Ty->getBaseType())));
+ EnumRecord ER(EnumeratorCount, CO, FTI, FullName, Ty->getIdentifier(),
+ getTypeIndex(Ty->getBaseType()));
+ return TypeTable.writeKnownType(ER);
}
//===----------------------------------------------------------------------===//
ClassOptions CO =
ClassOptions::ForwardReference | getCommonClassOptions(Ty);
std::string FullName = getFullyQualifiedName(Ty);
- TypeIndex FwdDeclTI = TypeTable.writeKnownType(
- ClassRecord(Kind, 0, CO, TypeIndex(), TypeIndex(), TypeIndex(), 0,
- FullName, Ty->getIdentifier()));
+ ClassRecord CR(Kind, 0, CO, TypeIndex(), TypeIndex(), TypeIndex(), 0,
+ FullName, Ty->getIdentifier());
+ TypeIndex FwdDeclTI = TypeTable.writeKnownType(CR);
if (!Ty->isForwardDecl())
DeferredCompleteTypes.push_back(Ty);
return FwdDeclTI;
uint64_t SizeInBytes = Ty->getSizeInBits() / 8;
- TypeIndex ClassTI = TypeTable.writeKnownType(
- ClassRecord(Kind, FieldCount, CO, FieldTI, TypeIndex(), VShapeTI,
- SizeInBytes, FullName, Ty->getIdentifier()));
+ ClassRecord CR(Kind, FieldCount, CO, FieldTI, TypeIndex(), VShapeTI,
+ SizeInBytes, FullName, Ty->getIdentifier());
+ TypeIndex ClassTI = TypeTable.writeKnownType(CR);
- TypeTable.writeKnownType(UdtSourceLineRecord(
- ClassTI, TypeTable.writeKnownType(StringIdRecord(
- TypeIndex(0x0), getFullFilepath(Ty->getFile()))),
- Ty->getLine()));
+ StringIdRecord SIDR(TypeIndex(0x0), getFullFilepath(Ty->getFile()));
+ TypeIndex SIDI = TypeTable.writeKnownType(SIDR);
+ UdtSourceLineRecord USLR(ClassTI, SIDI, Ty->getLine());
+ TypeTable.writeKnownType(USLR);
addToUDTs(Ty, ClassTI);
ClassOptions CO =
ClassOptions::ForwardReference | getCommonClassOptions(Ty);
std::string FullName = getFullyQualifiedName(Ty);
- TypeIndex FwdDeclTI = TypeTable.writeKnownType(
- UnionRecord(0, CO, TypeIndex(), 0, FullName, Ty->getIdentifier()));
+ UnionRecord UR(0, CO, TypeIndex(), 0, FullName, Ty->getIdentifier());
+ TypeIndex FwdDeclTI = TypeTable.writeKnownType(UR);
if (!Ty->isForwardDecl())
DeferredCompleteTypes.push_back(Ty);
return FwdDeclTI;
uint64_t SizeInBytes = Ty->getSizeInBits() / 8;
std::string FullName = getFullyQualifiedName(Ty);
- TypeIndex UnionTI = TypeTable.writeKnownType(UnionRecord(
- FieldCount, CO, FieldTI, SizeInBytes, FullName, Ty->getIdentifier()));
+ UnionRecord UR(FieldCount, CO, FieldTI, SizeInBytes, FullName,
+ Ty->getIdentifier());
+ TypeIndex UnionTI = TypeTable.writeKnownType(UR);
- TypeTable.writeKnownType(UdtSourceLineRecord(
- UnionTI, TypeTable.writeKnownType(StringIdRecord(
- TypeIndex(0x0), getFullFilepath(Ty->getFile()))),
- Ty->getLine()));
+ StringIdRecord SIR(TypeIndex(0x0), getFullFilepath(Ty->getFile()));
+ TypeIndex SIRI = TypeTable.writeKnownType(SIR);
+ UdtSourceLineRecord USLR(UnionTI, SIRI, Ty->getLine());
+ TypeTable.writeKnownType(USLR);
addToUDTs(Ty, UnionTI);
// list record.
unsigned MemberCount = 0;
ClassInfo Info = collectClassInfo(Ty);
- FieldListRecordBuilder Fields;
+ FieldListRecordBuilder FLBR(TypeTable);
+ FLBR.begin();
// Create base classes.
for (const DIDerivedType *I : Info.Inheritance) {
auto RecordKind = (I->getFlags() & DINode::FlagIndirectVirtualBase) == DINode::FlagIndirectVirtualBase
? TypeRecordKind::IndirectVirtualBaseClass
: TypeRecordKind::VirtualBaseClass;
- Fields.writeMemberType(VirtualBaseClassRecord(
+ VirtualBaseClassRecord VBCR(
RecordKind, translateAccessFlags(Ty->getTag(), I->getFlags()),
getTypeIndex(I->getBaseType()), getVBPTypeIndex(), VBPtrOffset,
- VBTableIndex));
+ VBTableIndex);
+
+ FLBR.writeMemberType(VBCR);
} else {
assert(I->getOffsetInBits() % 8 == 0 &&
"bases must be on byte boundaries");
- Fields.writeMemberType(BaseClassRecord(
- translateAccessFlags(Ty->getTag(), I->getFlags()),
- getTypeIndex(I->getBaseType()), I->getOffsetInBits() / 8));
+ BaseClassRecord BCR(translateAccessFlags(Ty->getTag(), I->getFlags()),
+ getTypeIndex(I->getBaseType()),
+ I->getOffsetInBits() / 8);
+ FLBR.writeMemberType(BCR);
}
}
translateAccessFlags(Ty->getTag(), Member->getFlags());
if (Member->isStaticMember()) {
- Fields.writeMemberType(
- StaticDataMemberRecord(Access, MemberBaseType, MemberName));
+ StaticDataMemberRecord SDMR(Access, MemberBaseType, MemberName);
+ FLBR.writeMemberType(SDMR);
MemberCount++;
continue;
}
// Virtual function pointer member.
if ((Member->getFlags() & DINode::FlagArtificial) &&
Member->getName().startswith("_vptr$")) {
- Fields.writeMemberType(VFPtrRecord(getTypeIndex(Member->getBaseType())));
+ VFPtrRecord VFPR(getTypeIndex(Member->getBaseType()));
+ FLBR.writeMemberType(VFPR);
MemberCount++;
continue;
}
MemberOffsetInBits = CI->getZExtValue() + MemberInfo.BaseOffset;
}
StartBitOffset -= MemberOffsetInBits;
- MemberBaseType = TypeTable.writeKnownType(BitFieldRecord(
- MemberBaseType, Member->getSizeInBits(), StartBitOffset));
+ BitFieldRecord BFR(MemberBaseType, Member->getSizeInBits(),
+ StartBitOffset);
+ MemberBaseType = TypeTable.writeKnownType(BFR);
}
uint64_t MemberOffsetInBytes = MemberOffsetInBits / 8;
- Fields.writeMemberType(DataMemberRecord(Access, MemberBaseType,
- MemberOffsetInBytes, MemberName));
+ DataMemberRecord DMR(Access, MemberBaseType, MemberOffsetInBytes,
+ MemberName);
+ FLBR.writeMemberType(DMR);
MemberCount++;
}
}
assert(Methods.size() > 0 && "Empty methods map entry");
if (Methods.size() == 1)
- Fields.writeMemberType(Methods[0]);
+ FLBR.writeMemberType(Methods[0]);
else {
- TypeIndex MethodList =
- TypeTable.writeKnownType(MethodOverloadListRecord(Methods));
- Fields.writeMemberType(
- OverloadedMethodRecord(Methods.size(), MethodList, Name));
+ MethodOverloadListRecord MOLR(Methods);
+ TypeIndex MethodList = TypeTable.writeKnownType(MOLR);
+ OverloadedMethodRecord OMR(Methods.size(), MethodList, Name);
+ FLBR.writeMemberType(OMR);
}
}
// Create nested classes.
for (const DICompositeType *Nested : Info.NestedClasses) {
NestedTypeRecord R(getTypeIndex(DITypeRef(Nested)), Nested->getName());
- Fields.writeMemberType(R);
+ FLBR.writeMemberType(R);
MemberCount++;
}
- TypeIndex FieldTI = TypeTable.writeFieldList(Fields);
+ TypeIndex FieldTI = FLBR.end();
return std::make_tuple(FieldTI, Info.VShapeTI, MemberCount,
!Info.NestedClasses.empty());
}
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
-#include "llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h"
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/DebugLoc.h"
#include "llvm/MC/MCStreamer.h"
class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase {
MCStreamer &OS;
llvm::BumpPtrAllocator Allocator;
- codeview::MemoryTypeTableBuilder TypeTable;
+ codeview::TypeTableBuilder TypeTable;
/// Represents the most general definition range.
struct LocalVarDefRange {
CVSymbolVisitor.cpp
CVTypeVisitor.cpp
EnumTables.cpp
- FieldListRecordBuilder.cpp
Line.cpp
- ListRecordBuilder.cpp
- MemoryTypeTableBuilder.cpp
- MethodListRecordBuilder.cpp
ModuleSubstream.cpp
ModuleSubstreamVisitor.cpp
RecordSerialization.cpp
SymbolDumper.cpp
TypeDumper.cpp
TypeRecord.cpp
- TypeRecordBuilder.cpp
TypeRecordMapping.cpp
+ TypeSerializer.cpp
TypeStreamMerger.cpp
- TypeTableBuilder.cpp
ADDITIONAL_HEADER_DIRS
${LLVM_MAIN_INCLUDE_DIR}/llvm/DebugInfo/CodeView
using namespace llvm;
using namespace llvm::codeview;
-template <typename T>
-static Expected<CVMemberRecord>
-deserializeMemberRecord(FieldListDeserializer &Deserializer,
- msf::StreamReader &Reader, TypeLeafKind Kind) {
- T MR(static_cast<TypeRecordKind>(Kind));
- CVMemberRecord CVR;
- CVR.Kind = Kind;
-
- if (auto EC = Deserializer.visitMemberBegin(CVR))
- return std::move(EC);
- if (auto EC = Deserializer.visitKnownMember(CVR, MR))
- return std::move(EC);
- if (auto EC = Deserializer.visitMemberEnd(CVR))
- return std::move(EC);
-
- return CVR;
-}
-
CVTypeVisitor::CVTypeVisitor(TypeVisitorCallbacks &Callbacks)
: Callbacks(Callbacks) {}
return Error::success();
}
-Error CVTypeVisitor::visitMemberRecord(CVMemberRecord &Record) {
+static Error visitMemberRecord(CVMemberRecord &Record,
+ TypeVisitorCallbacks &Callbacks) {
if (auto EC = Callbacks.visitMemberBegin(Record))
return EC;
return Error::success();
}
+Error CVTypeVisitor::visitMemberRecord(CVMemberRecord &Record) {
+ return ::visitMemberRecord(Record, Callbacks);
+}
+
/// Visits the type records in Data. Sets the error flag on parse failures.
Error CVTypeVisitor::visitTypeStream(const CVTypeArray &Types) {
for (auto I : Types) {
return Error::success();
}
-template <typename MR>
-static Error visitKnownMember(FieldListDeserializer &Deserializer,
- msf::StreamReader &Reader, TypeLeafKind Leaf,
- TypeVisitorCallbacks &Callbacks) {
- MR Record(static_cast<TypeRecordKind>(Leaf));
- CVMemberRecord CVR;
- CVR.Kind = Leaf;
-
- if (auto EC = Callbacks.visitMemberBegin(CVR))
- return EC;
- if (auto EC = Callbacks.visitKnownMember(CVR, Record))
- return EC;
- if (auto EC = Callbacks.visitMemberEnd(CVR))
- return EC;
- return Error::success();
-}
-
Error CVTypeVisitor::visitFieldListMemberStream(msf::StreamReader Reader) {
FieldListDeserializer Deserializer(Reader);
TypeVisitorCallbackPipeline Pipeline;
if (auto EC = Reader.readEnum(Leaf))
return EC;
- CVType Record;
- 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.
- return llvm::make_error<CodeViewError>(
- cv_error_code::unknown_member_record);
-#define MEMBER_RECORD(EnumName, EnumVal, Name) \
- case EnumName: { \
- if (auto EC = visitKnownMember<Name##Record>(Deserializer, Reader, Leaf, \
- Pipeline)) \
- return EC; \
- break; \
- }
-#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \
- MEMBER_RECORD(EnumVal, EnumVal, AliasName)
-#include "llvm/DebugInfo/CodeView/TypeRecords.def"
- }
+ CVMemberRecord Record;
+ Record.Kind = Leaf;
+ if (auto EC = ::visitMemberRecord(Record, Pipeline))
+ return EC;
}
+
return Error::success();
}
using namespace llvm;
using namespace llvm::codeview;
-Error CodeViewRecordIO::beginRecord(uint16_t Kind) {
- assert(!CurrentRecord.hasValue() && "There is already a record active!");
- CurrentRecord.emplace();
-
- CurrentRecord->Kind = Kind;
+Error CodeViewRecordIO::beginRecord(Optional<uint32_t> MaxLength) {
+ RecordLimit Limit;
+ Limit.MaxLength = MaxLength;
+ Limit.BeginOffset = getCurrentOffset();
+ Limits.push_back(Limit);
return Error::success();
}
Error CodeViewRecordIO::endRecord() {
- assert(CurrentRecord.hasValue() && "Not in a record!");
- CurrentRecord.reset();
+ assert(!Limits.empty() && "Not in a record!");
+ Limits.pop_back();
return Error::success();
}
+uint32_t CodeViewRecordIO::maxFieldLength() const {
+ assert(!Limits.empty() && "Not in a record!");
+
+ // The max length of the next field is the minimum of all lengths that would
+ // be allowed by any of the sub-records we're in. In practice, we can only
+ // ever be at most 1 sub-record deep (in a FieldList), but this works for
+ // the general case.
+ uint32_t Offset = getCurrentOffset();
+ Optional<uint32_t> Min = Limits.front().bytesRemaining(Offset);
+ for (auto X : makeArrayRef(Limits).drop_front()) {
+ Optional<uint32_t> ThisMin = X.bytesRemaining(Offset);
+ if (ThisMin.hasValue())
+ Min = (Min.hasValue()) ? std::min(*Min, *ThisMin) : *ThisMin;
+ }
+ assert(Min.hasValue() && "Every field must have a maximum length!");
+
+ return *Min;
+}
+
Error CodeViewRecordIO::skipPadding() {
assert(!isWriting() && "Cannot skip padding while writing!");
Error CodeViewRecordIO::mapStringZ(StringRef &Value) {
if (isWriting()) {
- if (auto EC = Writer->writeZeroString(Value))
+ // Truncate if we attempt to write too much.
+ StringRef S = Value.take_front(maxFieldLength() - 1);
+ if (auto EC = Writer->writeZeroString(S))
return EC;
} else {
if (auto EC = Reader->readZeroString(Value))
}
Error CodeViewRecordIO::mapGuid(StringRef &Guid) {
+ constexpr uint32_t GuidSize = 16;
+ if (maxFieldLength() < GuidSize)
+ return make_error<CodeViewError>(cv_error_code::insufficient_buffer);
+
if (isWriting()) {
assert(Guid.size() == 16 && "Invalid Guid Size!");
if (auto EC = Writer->writeFixedString(Guid))
+++ /dev/null
-//===-- FieldListRecordBuilder.cpp ----------------------------------------===//
-//
-// 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/FieldListRecordBuilder.h"
-
-using namespace llvm;
-using namespace codeview;
-
-FieldListRecordBuilder::FieldListRecordBuilder()
- : ListRecordBuilder(TypeRecordKind::FieldList) {}
-
-void FieldListRecordBuilder::writeMemberType(const BaseClassRecord &Record) {
- TypeRecordBuilder &Builder = getBuilder();
-
- Builder.writeTypeRecordKind(TypeRecordKind::BaseClass);
- Builder.writeUInt16(static_cast<uint16_t>(Record.getAccess()));
- Builder.writeTypeIndex(Record.getBaseType());
- Builder.writeEncodedUnsignedInteger(Record.getBaseOffset());
-
- finishSubRecord();
-}
-
-void FieldListRecordBuilder::writeMemberType(const EnumeratorRecord &Record) {
- TypeRecordBuilder &Builder = getBuilder();
-
- Builder.writeTypeRecordKind(TypeRecordKind::Enumerator);
- Builder.writeUInt16(static_cast<uint16_t>(Record.getAccess()));
- // FIXME: Handle full APInt such as __int128.
- Builder.writeEncodedUnsignedInteger(Record.getValue().getZExtValue());
- Builder.writeNullTerminatedString(Record.getName());
-
- finishSubRecord();
-}
-
-void FieldListRecordBuilder::writeMemberType(const DataMemberRecord &Record) {
- TypeRecordBuilder &Builder = getBuilder();
-
- Builder.writeTypeRecordKind(Record.getKind());
- Builder.writeUInt16(static_cast<uint16_t>(Record.getAccess()));
- Builder.writeTypeIndex(Record.getType());
- Builder.writeEncodedUnsignedInteger(Record.getFieldOffset());
- Builder.writeNullTerminatedString(Record.getName());
-
- finishSubRecord();
-}
-
-void FieldListRecordBuilder::writeMemberType(
- const OverloadedMethodRecord &Record) {
- TypeRecordBuilder &Builder = getBuilder();
-
- Builder.writeTypeRecordKind(TypeRecordKind::OverloadedMethod);
- Builder.writeUInt16(Record.getNumOverloads());
- Builder.writeTypeIndex(Record.getMethodList());
- Builder.writeNullTerminatedString(Record.getName());
-
- finishSubRecord();
-}
-
-void FieldListRecordBuilder::writeMemberType(const OneMethodRecord &Record) {
- TypeRecordBuilder &Builder = getBuilder();
-
- uint16_t Flags = static_cast<uint16_t>(Record.getAccess());
- Flags |= static_cast<uint16_t>(Record.getKind()) << MethodKindShift;
- Flags |= static_cast<uint16_t>(Record.getOptions());
-
- Builder.writeTypeRecordKind(TypeRecordKind::OneMethod);
- Builder.writeUInt16(Flags);
- Builder.writeTypeIndex(Record.getType());
- if (Record.isIntroducingVirtual()) {
- assert(Record.getVFTableOffset() >= 0);
- Builder.writeInt32(Record.getVFTableOffset());
- } else {
- assert(Record.getVFTableOffset() == -1);
- }
-
- Builder.writeNullTerminatedString(Record.getName());
-
- finishSubRecord();
-}
-
-void FieldListRecordBuilder::writeMemberType(const NestedTypeRecord &Record) {
- TypeRecordBuilder &Builder = getBuilder();
-
- Builder.writeTypeRecordKind(Record.getKind());
- Builder.writeUInt16(0);
- Builder.writeTypeIndex(Record.getNestedType());
- Builder.writeNullTerminatedString(Record.getName());
-
- finishSubRecord();
-}
-
-void FieldListRecordBuilder::writeMemberType(
- const StaticDataMemberRecord &Record) {
- TypeRecordBuilder &Builder = getBuilder();
-
- Builder.writeTypeRecordKind(Record.getKind());
- Builder.writeUInt16(static_cast<uint16_t>(Record.getAccess()));
- Builder.writeTypeIndex(Record.getType());
- Builder.writeNullTerminatedString(Record.getName());
-
- finishSubRecord();
-}
-
-void FieldListRecordBuilder::writeMemberType(
- const VirtualBaseClassRecord &Record) {
- TypeRecordBuilder &Builder = getBuilder();
-
- Builder.writeTypeRecordKind(Record.getKind());
- Builder.writeUInt16(static_cast<uint16_t>(Record.getAccess()));
- Builder.writeTypeIndex(Record.getBaseType());
- Builder.writeTypeIndex(Record.getVBPtrType());
- Builder.writeEncodedInteger(Record.getVBPtrOffset());
- Builder.writeEncodedUnsignedInteger(Record.getVTableIndex());
-
- finishSubRecord();
-}
-
-void FieldListRecordBuilder::writeMemberType(const VFPtrRecord &Record) {
- TypeRecordBuilder &Builder = getBuilder();
-
- Builder.writeTypeRecordKind(TypeRecordKind::VFPtr);
- Builder.writeUInt16(0);
- Builder.writeTypeIndex(Record.getType());
-
- finishSubRecord();
-}
+++ /dev/null
-//===-- ListRecordBuilder.cpp ---------------------------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/ADT/SmallString.h"
-#include "llvm/DebugInfo/CodeView/ListRecordBuilder.h"
-#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
-
-using namespace llvm;
-using namespace codeview;
-
-ListRecordBuilder::ListRecordBuilder(TypeRecordKind Kind)
- : Kind(Kind), Builder(Kind) {}
-
-void ListRecordBuilder::writeMemberType(const ListContinuationRecord &R) {
- TypeRecordBuilder &Builder = getBuilder();
-
- assert(getLastContinuationSize() < MaxRecordLength - 8 && "continuation won't fit");
-
- Builder.writeTypeRecordKind(TypeRecordKind::ListContinuation);
- Builder.writeUInt16(0);
- Builder.writeTypeIndex(R.getContinuationIndex());
-
- // End the current segment manually so that nothing comes after the
- // continuation.
- ContinuationOffsets.push_back(Builder.size());
- SubrecordStart = Builder.size();
-}
-
-void ListRecordBuilder::finishSubRecord() {
- // The type table inserts a 16 bit size field before each list, so factor that
- // into our alignment padding.
- uint32_t Remainder =
- (Builder.size() + 2 * (ContinuationOffsets.size() + 1)) % 4;
- if (Remainder != 0) {
- for (int32_t PaddingBytesLeft = 4 - Remainder; PaddingBytesLeft > 0;
- --PaddingBytesLeft) {
- Builder.writeUInt8(LF_PAD0 + PaddingBytesLeft);
- }
- }
-
- // Check if this subrecord makes the current segment not fit in 64K minus the
- // space for a continuation record (8 bytes). If the segment does not fit,
- // back up and insert a continuation record, sliding the current subrecord
- // down.
- if (getLastContinuationSize() > MaxRecordLength - 8) {
- assert(SubrecordStart != 0 && "can't slide from the start!");
- SmallString<128> SubrecordCopy(
- Builder.str().slice(SubrecordStart, Builder.size()));
- assert(SubrecordCopy.size() < MaxRecordLength - 8 &&
- "subrecord is too large to slide!");
- Builder.truncate(SubrecordStart);
-
- // Write a placeholder continuation record.
- Builder.writeTypeRecordKind(TypeRecordKind::ListContinuation);
- Builder.writeUInt16(0);
- Builder.writeUInt32(0);
- ContinuationOffsets.push_back(Builder.size());
- assert(Builder.size() == SubrecordStart + 8 && "wrong continuation size");
- assert(getLastContinuationSize() < MaxRecordLength && "segment too big");
-
- // Start a new list record of the appropriate kind, and copy the previous
- // subrecord into place.
- Builder.writeTypeRecordKind(Kind);
- Builder.writeBytes(SubrecordCopy);
- }
-
- SubrecordStart = Builder.size();
-}
-
-TypeIndex ListRecordBuilder::writeListRecord(TypeTableBuilder &Table) {
- // Get the continuation segments as a reversed vector of StringRefs for
- // convenience.
- SmallVector<StringRef, 1> Segments;
- StringRef Data = str();
- size_t LastEnd = 0;
- for (size_t SegEnd : ContinuationOffsets) {
- Segments.push_back(Data.slice(LastEnd, SegEnd));
- LastEnd = SegEnd;
- }
- Segments.push_back(Data.slice(LastEnd, Builder.size()));
-
- // Pop the last record off and emit it directly.
- StringRef LastRec = Segments.pop_back_val();
- TypeIndex ContinuationIndex = Table.writeRecord(LastRec);
-
- // Emit each record with a continuation in reverse order, so that each one
- // references the previous record.
- for (StringRef Rec : reverse(Segments)) {
- assert(*reinterpret_cast<const ulittle16_t *>(Rec.data()) ==
- unsigned(Kind));
- ulittle32_t *ContinuationPtr =
- reinterpret_cast<ulittle32_t *>(const_cast<char *>(Rec.end())) - 1;
- *ContinuationPtr = ContinuationIndex.getIndex();
- ContinuationIndex = Table.writeRecord(Rec);
- }
- return ContinuationIndex;
-}
+++ /dev/null
-//===-- MemoryTypeTableBuilder.cpp ----------------------------------------===//
-//
-// 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/MemoryTypeTableBuilder.h"
-#include "llvm/DebugInfo/CodeView/TypeIndex.h"
-
-using namespace llvm;
-using namespace codeview;
-
-TypeIndex MemoryTypeTableBuilder::writeRecord(StringRef Data) {
- assert(Data.size() <= UINT16_MAX);
- auto I = HashedRecords.find(Data);
- if (I != HashedRecords.end()) {
- return I->second;
- }
-
- // The record provided by the user lacks the 2 byte size field prefix and is
- // not padded to 4 bytes. Ultimately, that is what gets emitted in the object
- // file, so pad it out now.
- const int SizeOfRecLen = 2;
- const int Align = 4;
- int TotalSize = alignTo(Data.size() + SizeOfRecLen, Align);
- assert(TotalSize - SizeOfRecLen <= UINT16_MAX);
- char *Mem =
- reinterpret_cast<char *>(RecordStorage.Allocate(TotalSize, Align));
- *reinterpret_cast<ulittle16_t *>(Mem) = uint16_t(TotalSize - SizeOfRecLen);
- memcpy(Mem + SizeOfRecLen, Data.data(), Data.size());
- for (int I = Data.size() + SizeOfRecLen; I < TotalSize; ++I)
- Mem[I] = LF_PAD0 + (TotalSize - I);
-
- TypeIndex TI(static_cast<uint32_t>(Records.size()) +
- TypeIndex::FirstNonSimpleIndex);
-
- // Use only the data supplied by the user as a key to the hash table, so that
- // future lookups will succeed.
- HashedRecords.insert(std::make_pair(StringRef(Mem + SizeOfRecLen, Data.size()), TI));
- Records.push_back(StringRef(Mem, TotalSize));
-
- return TI;
-}
+++ /dev/null
-//===-- MethodListRecordBuilder.cpp ---------------------------------------===//
-//
-// 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/MethodListRecordBuilder.h"
-#include "llvm/DebugInfo/CodeView/FieldListRecordBuilder.h"
-
-using namespace llvm;
-using namespace codeview;
-
-MethodListRecordBuilder::MethodListRecordBuilder()
- : ListRecordBuilder(TypeRecordKind::MethodOverloadList) {}
-
-void MethodListRecordBuilder::writeMethod(MemberAccess Access, MethodKind Kind,
- MethodOptions Options, TypeIndex Type,
- int32_t VTableSlotOffset) {
- TypeRecordBuilder &Builder = getBuilder();
-
- uint16_t Flags = static_cast<uint16_t>(Access);
- Flags |= static_cast<uint16_t>(Kind) << MethodKindShift;
- Flags |= static_cast<uint16_t>(Options);
-
- Builder.writeUInt16(Flags);
- Builder.writeUInt16(0);
- Builder.writeTypeIndex(Type);
- switch (Kind) {
- case MethodKind::IntroducingVirtual:
- case MethodKind::PureIntroducingVirtual:
- assert(VTableSlotOffset >= 0);
- Builder.writeInt32(VTableSlotOffset);
- break;
-
- default:
- assert(VTableSlotOffset == -1);
- break;
- }
-
- // TODO: Fail if too big?
-}
-
-void MethodListRecordBuilder::writeMethod(const MethodInfo &Method) {
- writeMethod(Method.getAccess(), Method.getKind(), Method.getOptions(),
- Method.getType(), Method.getVTableSlotOffset());
-}
MethodOverloadListRecord &MethodList) {
for (auto &M : MethodList.getMethods()) {
ListScope S(*W, "Method");
- printMemberAttributes(M.getAccess(), M.getKind(), M.getOptions());
+ printMemberAttributes(M.getAccess(), M.getMethodKind(), M.getOptions());
printTypeIndex("Type", M.getType());
if (M.isIntroducingVirtual())
W->printHex("VFTableOffset", M.getVFTableOffset());
Error CVTypeDumper::visitKnownMember(CVMemberRecord &CVR,
OneMethodRecord &Method) {
- MethodKind K = Method.getKind();
+ MethodKind K = Method.getMethodKind();
printMemberAttributes(Method.getAccess(), K, Method.getOptions());
printTypeIndex("Type", Method.getType());
// If virtual, then read the vftable offset.
+++ /dev/null
-//===-- TypeRecordBuilder.cpp ---------------------------------------------===//
-//
-// 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/TypeRecordBuilder.h"
-
-using namespace llvm;
-using namespace codeview;
-
-TypeRecordBuilder::TypeRecordBuilder(TypeRecordKind Kind)
- : Kind(Kind), Stream(Buffer), Writer(Stream) {
- writeTypeRecordKind(Kind);
-}
-
-StringRef TypeRecordBuilder::str() {
- return StringRef(Buffer.data(), Buffer.size());
-}
-
-void TypeRecordBuilder::writeUInt8(uint8_t Value) {
- Writer.write(Value);
-}
-
-void TypeRecordBuilder::writeInt16(int16_t Value) {
- Writer.write(Value);
-}
-
-void TypeRecordBuilder::writeUInt16(uint16_t Value) {
- Writer.write(Value);
-}
-
-void TypeRecordBuilder::writeInt32(int32_t Value) {
- Writer.write(Value);
-}
-
-void TypeRecordBuilder::writeUInt32(uint32_t Value) {
- Writer.write(Value);
-}
-
-void TypeRecordBuilder::writeInt64(int64_t Value) {
- Writer.write(Value);
-}
-
-void TypeRecordBuilder::writeUInt64(uint64_t Value) {
- Writer.write(Value);
-}
-
-void TypeRecordBuilder::writeEncodedInteger(int64_t Value) {
- if (Value >= 0) {
- writeEncodedUnsignedInteger(static_cast<uint64_t>(Value));
- } else {
- writeEncodedSignedInteger(Value);
- }
-}
-
-void TypeRecordBuilder::writeEncodedSignedInteger(int64_t Value) {
- if (Value >= std::numeric_limits<int8_t>::min() &&
- Value <= std::numeric_limits<int8_t>::max()) {
- writeUInt16(LF_CHAR);
- writeInt16(static_cast<int8_t>(Value));
- } else if (Value >= std::numeric_limits<int16_t>::min() &&
- Value <= std::numeric_limits<int16_t>::max()) {
- writeUInt16(LF_SHORT);
- writeInt16(static_cast<int16_t>(Value));
- } else if (Value >= std::numeric_limits<int32_t>::min() &&
- Value <= std::numeric_limits<int32_t>::max()) {
- writeUInt16(LF_LONG);
- writeInt32(static_cast<int32_t>(Value));
- } else {
- writeUInt16(LF_QUADWORD);
- writeInt64(Value);
- }
-}
-
-void TypeRecordBuilder::writeEncodedUnsignedInteger(uint64_t Value) {
- if (Value < LF_CHAR) {
- writeUInt16(static_cast<uint16_t>(Value));
- } else if (Value <= std::numeric_limits<uint16_t>::max()) {
- writeUInt16(LF_USHORT);
- writeUInt16(static_cast<uint16_t>(Value));
- } else if (Value <= std::numeric_limits<uint32_t>::max()) {
- writeUInt16(LF_ULONG);
- writeUInt32(static_cast<uint32_t>(Value));
- } else {
- writeUInt16(LF_UQUADWORD);
- writeUInt64(Value);
- }
-}
-
-void TypeRecordBuilder::writeNullTerminatedString(StringRef Value) {
- // Usually the null terminated string comes last, so truncate it to avoid a
- // record larger than MaxNameLength. Don't do this if this is a list record.
- // Those have special handling to split the record.
- unsigned MaxNameLength = MaxRecordLength;
- if (Kind != TypeRecordKind::FieldList &&
- Kind != TypeRecordKind::MethodOverloadList)
- MaxNameLength = maxBytesRemaining();
- assert(MaxNameLength > 0 && "need room for null terminator");
- Value = Value.take_front(MaxNameLength - 1);
- Stream.write(Value.data(), Value.size());
- writeUInt8(0);
-}
-
-void TypeRecordBuilder::writeGuid(StringRef Guid) {
- assert(Guid.size() == 16);
- Stream.write(Guid.data(), 16);
-}
-
-void TypeRecordBuilder::writeTypeIndex(TypeIndex TypeInd) {
- writeUInt32(TypeInd.getIndex());
-}
-
-void TypeRecordBuilder::writeTypeRecordKind(TypeRecordKind Kind) {
- writeUInt16(static_cast<uint16_t>(Kind));
-}
return EC;
namespace {
-struct MapStringZ {
- Error operator()(CodeViewRecordIO &IO, StringRef &S) const {
- return IO.mapStringZ(S);
- }
-};
-
-struct MapInteger {
- template <typename T> Error operator()(CodeViewRecordIO &IO, T &N) const {
- return IO.mapInteger(N);
- }
-};
-
-struct MapEnum {
- template <typename T> Error operator()(CodeViewRecordIO &IO, T &N) const {
- return IO.mapEnum(N);
- }
-};
-
struct MapOneMethodRecord {
explicit MapOneMethodRecord(bool IsFromOverloadList)
: IsFromOverloadList(IsFromOverloadList) {}
static Error mapNameAndUniqueName(CodeViewRecordIO &IO, StringRef &Name,
StringRef &UniqueName, bool HasUniqueName) {
- error(IO.mapStringZ(Name));
- if (HasUniqueName)
- error(IO.mapStringZ(UniqueName));
+ if (IO.isWriting()) {
+ // Try to be smart about what we write here. We can't write anything too
+ // large, so if we're going to go over the limit, truncate both the name
+ // and unique name by the same amount.
+ uint32_t BytesLeft = IO.maxFieldLength();
+ if (HasUniqueName) {
+ uint32_t BytesNeeded = Name.size() + UniqueName.size() + 2;
+ StringRef N = Name;
+ StringRef U = UniqueName;
+ if (BytesNeeded > BytesLeft) {
+ uint32_t BytesToDrop = (BytesNeeded - BytesLeft);
+ uint32_t DropN = std::min(N.size(), BytesToDrop / 2);
+ uint32_t DropU = std::min(U.size(), BytesToDrop - DropN);
+
+ N = N.drop_back(DropN);
+ U = U.drop_back(DropU);
+ }
+
+ error(IO.mapStringZ(N));
+ error(IO.mapStringZ(U));
+ } else {
+ uint32_t BytesNeeded = Name.size() + 1;
+ StringRef N = Name;
+ if (BytesNeeded > BytesLeft) {
+ uint32_t BytesToDrop = std::min(N.size(), BytesToDrop);
+ N = N.drop_back(BytesToDrop);
+ }
+ error(IO.mapStringZ(N));
+ }
+ } else {
+ error(IO.mapStringZ(Name));
+ if (HasUniqueName)
+ error(IO.mapStringZ(UniqueName));
+ }
return Error::success();
}
Error TypeRecordMapping::visitTypeBegin(CVType &CVR) {
- error(IO.beginRecord(CVR.Type));
+ assert(!TypeKind.hasValue() && "Already in a type mapping!");
+ assert(!MemberKind.hasValue() && "Already in a member mapping!");
+
+ // FieldList and MethodList records can be any length because they can be
+ // split with continuation records. All other record types cannot be
+ // longer than the maximum record length.
+ Optional<uint32_t> MaxLen;
+ if (CVR.Type != TypeLeafKind::LF_FIELDLIST &&
+ CVR.Type != TypeLeafKind::LF_METHODLIST)
+ MaxLen = MaxRecordLength - sizeof(RecordPrefix);
+ error(IO.beginRecord(MaxLen));
TypeKind = CVR.Type;
return Error::success();
}
Error TypeRecordMapping::visitTypeEnd(CVType &Record) {
+ assert(TypeKind.hasValue() && "Not in a type mapping!");
+ assert(!MemberKind.hasValue() && "Still in a member mapping!");
+
error(IO.endRecord());
+
TypeKind.reset();
return Error::success();
}
Error TypeRecordMapping::visitMemberBegin(CVMemberRecord &Record) {
+ assert(TypeKind.hasValue() && "Not in a type mapping!");
+ assert(!MemberKind.hasValue() && "Already in a member mapping!");
+
+ // The largest possible subrecord is one in which there is a record prefix,
+ // followed by the subrecord, followed by a continuation, and that entire
+ // sequence spaws `MaxRecordLength` bytes. So the record's length is
+ // calculated as follows.
+ constexpr uint32_t ContinuationLength = 8;
+ error(IO.beginRecord(MaxRecordLength - sizeof(RecordPrefix) -
+ ContinuationLength));
+
+ MemberKind = Record.Kind;
return Error::success();
}
Error TypeRecordMapping::visitMemberEnd(CVMemberRecord &Record) {
+ assert(TypeKind.hasValue() && "Not in a type mapping!");
+ assert(MemberKind.hasValue() && "Not in a member mapping!");
+
if (!IO.isWriting()) {
if (auto EC = IO.skipPadding())
return EC;
}
+ MemberKind.reset();
+ error(IO.endRecord());
return Error::success();
}
}
Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ArgListRecord &Record) {
- error(IO.mapVectorN<uint32_t>(Record.StringIndices, MapInteger()));
+ error(IO.mapVectorN<uint32_t>(
+ Record.StringIndices,
+ [](CodeViewRecordIO &IO, TypeIndex &N) { return IO.mapInteger(N); }));
return Error::success();
}
NamesLen += Name.size() + 1;
}
error(IO.mapInteger(NamesLen));
- error(IO.mapVectorTail(Record.MethodNames, MapStringZ()));
+ error(IO.mapVectorTail(
+ Record.MethodNames,
+ [](CodeViewRecordIO &IO, StringRef &S) { return IO.mapStringZ(S); }));
return Error::success();
}
Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
BuildInfoRecord &Record) {
- error(IO.mapVectorN<uint16_t>(Record.ArgIndices, MapInteger()));
+ error(IO.mapVectorN<uint16_t>(
+ Record.ArgIndices,
+ [](CodeViewRecordIO &IO, TypeIndex &N) { return IO.mapInteger(N); }));
return Error::success();
}
--- /dev/null
+//===- TypeSerialzier.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/TypeSerializer.h"
+
+#include "llvm/DebugInfo/MSF/StreamWriter.h"
+
+#include <string.h>
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+bool TypeSerializer::isInFieldList() const {
+ return TypeKind.hasValue() && *TypeKind == TypeLeafKind::LF_FIELDLIST;
+}
+
+TypeIndex TypeSerializer::calcNextTypeIndex() const {
+ if (LastTypeIndex.isNoneType())
+ return TypeIndex(TypeIndex::FirstNonSimpleIndex);
+ else
+ return TypeIndex(LastTypeIndex.getIndex() + 1);
+}
+
+TypeIndex TypeSerializer::incrementTypeIndex() {
+ TypeIndex Previous = LastTypeIndex;
+ LastTypeIndex = calcNextTypeIndex();
+ return Previous;
+}
+
+MutableArrayRef<uint8_t> TypeSerializer::getCurrentSubRecordData() {
+ assert(isInFieldList());
+ return getCurrentRecordData().drop_front(CurrentSegment.length());
+}
+
+MutableArrayRef<uint8_t> TypeSerializer::getCurrentRecordData() {
+ return MutableArrayRef<uint8_t>(RecordBuffer).take_front(Writer.getOffset());
+}
+
+Error TypeSerializer::writeRecordPrefix(TypeLeafKind Kind) {
+ RecordPrefix Prefix;
+ Prefix.RecordKind = Kind;
+ Prefix.RecordLen = 0;
+ if (auto EC = Writer.writeObject(Prefix))
+ return EC;
+ return Error::success();
+}
+
+TypeIndex
+TypeSerializer::insertRecordBytesPrivate(MutableArrayRef<uint8_t> Record) {
+ assert(Record.size() % 4 == 0 && "Record is not aligned to 4 bytes!");
+
+ StringRef S(reinterpret_cast<const char *>(Record.data()), Record.size());
+
+ TypeIndex NextTypeIndex = calcNextTypeIndex();
+ auto Result = HashedRecords.try_emplace(S, NextTypeIndex);
+ if (Result.second) {
+ LastTypeIndex = NextTypeIndex;
+ SeenRecords.push_back(Record);
+ }
+ return Result.first->getValue();
+}
+
+Expected<MutableArrayRef<uint8_t>>
+TypeSerializer::addPadding(MutableArrayRef<uint8_t> Record) {
+ uint32_t Align = Record.size() % 4;
+ if (Align == 0)
+ return Record;
+
+ int PaddingBytes = 4 - Align;
+ int N = PaddingBytes;
+ while (PaddingBytes > 0) {
+ uint8_t Pad = static_cast<uint8_t>(LF_PAD0 + PaddingBytes);
+ if (auto EC = Writer.writeInteger(Pad))
+ return std::move(EC);
+ --PaddingBytes;
+ }
+ return MutableArrayRef<uint8_t>(Record.data(), Record.size() + N);
+}
+
+TypeSerializer::TypeSerializer(BumpPtrAllocator &Storage)
+ : RecordStorage(Storage), LastTypeIndex(),
+ RecordBuffer(MaxRecordLength * 2), Stream(RecordBuffer), Writer(Stream),
+ Mapping(Writer) {
+ // RecordBuffer needs to be able to hold enough data so that if we are 1
+ // byte short of MaxRecordLen, and then we try to write MaxRecordLen bytes,
+ // we won't overflow.
+}
+
+ArrayRef<MutableArrayRef<uint8_t>> TypeSerializer::records() const {
+ return SeenRecords;
+}
+
+TypeIndex TypeSerializer::getLastTypeIndex() const { return LastTypeIndex; }
+
+TypeIndex TypeSerializer::insertRecordBytes(MutableArrayRef<uint8_t> Record) {
+ assert(!TypeKind.hasValue() && "Already in a type mapping!");
+ assert(Writer.getOffset() == 0 && "Stream has data already!");
+
+ return insertRecordBytesPrivate(Record);
+}
+
+Error TypeSerializer::visitTypeBegin(CVType &Record) {
+ assert(!TypeKind.hasValue() && "Already in a type mapping!");
+ assert(Writer.getOffset() == 0 && "Stream has data already!");
+
+ if (auto EC = writeRecordPrefix(Record.kind()))
+ return EC;
+
+ TypeKind = Record.kind();
+ if (auto EC = Mapping.visitTypeBegin(Record))
+ return EC;
+
+ return Error::success();
+}
+
+Expected<TypeIndex> TypeSerializer::visitTypeEndGetIndex(CVType &Record) {
+ assert(TypeKind.hasValue() && "Not in a type mapping!");
+ if (auto EC = Mapping.visitTypeEnd(Record))
+ return std::move(EC);
+
+ // Update the record's length and fill out the CVType members to point to
+ // the stable memory holding the record's data.
+ auto ThisRecordData = getCurrentRecordData();
+ auto ExpectedData = addPadding(ThisRecordData);
+ if (!ExpectedData)
+ return ExpectedData.takeError();
+ ThisRecordData = *ExpectedData;
+
+ RecordPrefix *Prefix =
+ reinterpret_cast<RecordPrefix *>(ThisRecordData.data());
+ Prefix->RecordLen = ThisRecordData.size() - sizeof(uint16_t);
+
+ uint8_t *Copy = RecordStorage.Allocate<uint8_t>(ThisRecordData.size());
+ ::memcpy(Copy, ThisRecordData.data(), ThisRecordData.size());
+ ThisRecordData = MutableArrayRef<uint8_t>(Copy, ThisRecordData.size());
+ Record = CVType(*TypeKind, ThisRecordData);
+ TypeIndex InsertedTypeIndex = insertRecordBytesPrivate(ThisRecordData);
+
+ // Write out each additional segment in reverse order, and update each
+ // record's continuation index to point to the previous one.
+ for (auto X : reverse(FieldListSegments)) {
+ auto CIBytes = X.take_back(sizeof(uint32_t));
+ support::ulittle32_t *CI =
+ reinterpret_cast<support::ulittle32_t *>(CIBytes.data());
+ assert(*CI == 0xB0C0B0C0 && "Invalid TypeIndex placeholder");
+ *CI = InsertedTypeIndex.getIndex();
+ InsertedTypeIndex = insertRecordBytesPrivate(X);
+ }
+
+ TypeKind.reset();
+ Writer.setOffset(0);
+ FieldListSegments.clear();
+ CurrentSegment.SubRecords.clear();
+
+ return InsertedTypeIndex;
+}
+
+Error TypeSerializer::visitTypeEnd(CVType &Record) {
+ auto ExpectedIndex = visitTypeEndGetIndex(Record);
+ if (!ExpectedIndex)
+ return ExpectedIndex.takeError();
+ return Error::success();
+}
+
+Error TypeSerializer::visitMemberBegin(CVMemberRecord &Record) {
+ assert(isInFieldList() && "Not in a field list!");
+ assert(!MemberKind.hasValue() && "Already in a member record!");
+ MemberKind = Record.Kind;
+
+ if (auto EC = Mapping.visitMemberBegin(Record))
+ return EC;
+
+ return Error::success();
+}
+
+Error TypeSerializer::visitMemberEnd(CVMemberRecord &Record) {
+ if (auto EC = Mapping.visitMemberEnd(Record))
+ return EC;
+
+ // Check if this subrecord makes the current segment not fit in 64K minus
+ // the space for a continuation record (8 bytes). If the segment does not
+ // fit, insert a continuation record.
+ if (Writer.getOffset() > MaxRecordLength - ContinuationLength) {
+ MutableArrayRef<uint8_t> Data = getCurrentRecordData();
+ SubRecord LastSubRecord = CurrentSegment.SubRecords.back();
+ uint32_t CopySize = CurrentSegment.length() - LastSubRecord.Size;
+ auto CopyData = Data.take_front(CopySize);
+ auto LeftOverData = Data.drop_front(CopySize);
+ assert(LastSubRecord.Size == LeftOverData.size());
+
+ // Allocate stable storage for the record and copy the old record plus
+ // continuation over.
+ uint16_t LengthWithSize = CopySize + ContinuationLength;
+ assert(LengthWithSize <= MaxRecordLength);
+ RecordPrefix *Prefix = reinterpret_cast<RecordPrefix *>(CopyData.data());
+ Prefix->RecordLen = LengthWithSize - sizeof(uint16_t);
+
+ uint8_t *SegmentBytes = RecordStorage.Allocate<uint8_t>(LengthWithSize);
+ auto SavedSegment = MutableArrayRef<uint8_t>(SegmentBytes, LengthWithSize);
+ msf::MutableByteStream CS(SavedSegment);
+ msf::StreamWriter CW(CS);
+ if (auto EC = CW.writeBytes(CopyData))
+ return EC;
+ if (auto EC = CW.writeEnum(TypeLeafKind::LF_INDEX))
+ return EC;
+ if (auto EC = CW.writeInteger(uint16_t(0)))
+ return EC;
+ if (auto EC = CW.writeInteger(uint32_t(0xB0C0B0C0)))
+ return EC;
+ FieldListSegments.push_back(SavedSegment);
+
+ // Write a new placeholder record prefix to mark the start of this new
+ // top-level record.
+ Writer.setOffset(0);
+ if (auto EC = writeRecordPrefix(TypeLeafKind::LF_FIELDLIST))
+ return EC;
+
+ // Then move over the subrecord that overflowed the old segment to the
+ // beginning of this segment. Note that we have to use memmove here
+ // instead of Writer.writeBytes(), because the new and old locations
+ // could overlap.
+ ::memmove(Stream.data().data() + sizeof(RecordPrefix), LeftOverData.data(),
+ LeftOverData.size());
+ // And point the segment writer at the end of that subrecord.
+ Writer.setOffset(LeftOverData.size() + sizeof(RecordPrefix));
+
+ CurrentSegment.SubRecords.clear();
+ CurrentSegment.SubRecords.push_back(LastSubRecord);
+ }
+
+ // Update the CVMemberRecord since we may have shifted around or gotten
+ // padded.
+ Record.Data = getCurrentSubRecordData();
+
+ MemberKind.reset();
+ return Error::success();
+}
#include "llvm/ADT/SmallString.h"
#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/TypeTableBuilder.h"
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
#include "llvm/Support/Error.h"
/// existing destination type index.
class TypeStreamMerger : public TypeVisitorCallbacks {
public:
- TypeStreamMerger(TypeTableBuilder &DestStream) : DestStream(DestStream) {
+ TypeStreamMerger(TypeTableBuilder &DestStream)
+ : DestStream(DestStream), FieldListBuilder(DestStream) {
assert(!hadError());
}
template <typename RecordType>
Error visitKnownMemberRecordImpl(RecordType &Record) {
FoundBadTypeIndex |= !Record.remapTypeIndices(IndexMap);
- FieldBuilder.writeMemberType(Record);
+ FieldListBuilder.writeMemberType(Record);
return Error::success();
}
bool FoundBadTypeIndex = false;
- FieldListRecordBuilder FieldBuilder;
+ BumpPtrAllocator Allocator;
TypeTableBuilder &DestStream;
+ FieldListRecordBuilder FieldListBuilder;
bool IsInFieldList{false};
size_t BeginIndexMapSize = 0;
if (Rec.Type == TypeLeafKind::LF_FIELDLIST) {
assert(!IsInFieldList);
IsInFieldList = true;
+ FieldListBuilder.begin();
} else
BeginIndexMapSize = IndexMap.size();
return Error::success();
Error TypeStreamMerger::visitTypeEnd(CVRecord<TypeLeafKind> &Rec) {
if (Rec.Type == TypeLeafKind::LF_FIELDLIST) {
- IndexMap.push_back(DestStream.writeFieldList(FieldBuilder));
- FieldBuilder.reset();
+ TypeIndex Index = FieldListBuilder.end();
+ IndexMap.push_back(Index);
IsInFieldList = false;
}
return Error::success();
+++ /dev/null
-//===-- TypeTableBuilder.cpp ----------------------------------------------===//
-//
-// 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/TypeTableBuilder.h"
-#include "llvm/DebugInfo/CodeView/FieldListRecordBuilder.h"
-#include "llvm/DebugInfo/CodeView/MethodListRecordBuilder.h"
-#include "llvm/DebugInfo/CodeView/TypeIndex.h"
-#include "llvm/DebugInfo/CodeView/TypeRecordBuilder.h"
-#include "llvm/Support/raw_ostream.h"
-
-using namespace llvm;
-using namespace codeview;
-
-TypeTableBuilder::TypeTableBuilder() {}
-
-TypeTableBuilder::~TypeTableBuilder() {}
-
-TypeIndex TypeTableBuilder::writeKnownType(const ModifierRecord &Record) {
- TypeRecordBuilder Builder(Record.getKind());
-
- Builder.writeTypeIndex(Record.getModifiedType());
- Builder.writeUInt16(static_cast<uint16_t>(Record.getModifiers()));
-
- return writeRecord(Builder);
-}
-
-TypeIndex TypeTableBuilder::writeKnownType(const ProcedureRecord &Record) {
- TypeRecordBuilder Builder(Record.getKind());
-
- Builder.writeTypeIndex(Record.getReturnType());
- Builder.writeUInt8(static_cast<uint8_t>(Record.getCallConv()));
- Builder.writeUInt8(static_cast<uint8_t>(Record.getOptions()));
- Builder.writeUInt16(Record.getParameterCount());
- Builder.writeTypeIndex(Record.getArgumentList());
-
- return writeRecord(Builder);
-}
-
-TypeIndex TypeTableBuilder::writeKnownType(const MemberFunctionRecord &Record) {
- TypeRecordBuilder Builder(Record.getKind());
-
- Builder.writeTypeIndex(Record.getReturnType());
- Builder.writeTypeIndex(Record.getClassType());
- Builder.writeTypeIndex(Record.getThisType());
- Builder.writeUInt8(static_cast<uint8_t>(Record.getCallConv()));
- Builder.writeUInt8(static_cast<uint8_t>(Record.getOptions()));
- Builder.writeUInt16(Record.getParameterCount());
- Builder.writeTypeIndex(Record.getArgumentList());
- Builder.writeInt32(Record.getThisPointerAdjustment());
-
- return writeRecord(Builder);
-}
-
-TypeIndex TypeTableBuilder::writeKnownType(const ArgListRecord &Record) {
- TypeRecordBuilder Builder(Record.getKind());
-
- Builder.writeUInt32(Record.getIndices().size());
- for (TypeIndex TI : Record.getIndices()) {
- Builder.writeTypeIndex(TI);
- }
-
- return writeRecord(Builder);
-}
-
-TypeIndex TypeTableBuilder::writeKnownType(const PointerRecord &Record) {
- TypeRecordBuilder Builder(Record.getKind());
-
- Builder.writeTypeIndex(Record.getReferentType());
- Builder.writeUInt32(Record.Attrs);
-
- if (Record.isPointerToMember()) {
- const MemberPointerInfo &M = Record.getMemberInfo();
- Builder.writeTypeIndex(M.getContainingType());
- Builder.writeUInt16(static_cast<uint16_t>(M.getRepresentation()));
- }
-
- return writeRecord(Builder);
-}
-
-static void writeNameAndUniqueName(TypeRecordBuilder &Builder, ClassOptions CO,
- StringRef Name, StringRef UniqueName) {
- // Truncate the names to half the remaining record length.
- unsigned MaxNameLength = Builder.maxBytesRemaining() / 2;
- Name = Name.take_front(MaxNameLength - 1);
- UniqueName = UniqueName.take_front(MaxNameLength - 1);
-
- Builder.writeNullTerminatedString(Name);
- if ((CO & ClassOptions::HasUniqueName) != ClassOptions::None) {
- Builder.writeNullTerminatedString(UniqueName);
- }
-}
-
-TypeIndex TypeTableBuilder::writeKnownType(const ArrayRecord &Record) {
- TypeRecordBuilder Builder(Record.getKind());
-
- Builder.writeTypeIndex(Record.getElementType());
- Builder.writeTypeIndex(Record.getIndexType());
- Builder.writeEncodedUnsignedInteger(Record.getSize());
- Builder.writeNullTerminatedString(Record.getName());
-
- return writeRecord(Builder);
-}
-
-TypeIndex TypeTableBuilder::writeKnownType(const ClassRecord &Record) {
- assert((Record.getKind() == TypeRecordKind::Struct) ||
- (Record.getKind() == TypeRecordKind::Class) ||
- (Record.getKind() == TypeRecordKind::Interface));
-
- TypeRecordBuilder Builder(Record.getKind());
-
- Builder.writeUInt16(Record.getMemberCount());
- uint16_t Flags =
- static_cast<uint16_t>(Record.getOptions()) |
- (static_cast<uint16_t>(Record.getHfa()) << ClassRecord::HfaKindShift) |
- (static_cast<uint16_t>(Record.getWinRTKind())
- << ClassRecord::WinRTKindShift);
- Builder.writeUInt16(Flags);
- Builder.writeTypeIndex(Record.getFieldList());
- Builder.writeTypeIndex(Record.getDerivationList());
- Builder.writeTypeIndex(Record.getVTableShape());
- Builder.writeEncodedUnsignedInteger(Record.getSize());
- writeNameAndUniqueName(Builder, Record.getOptions(), Record.getName(),
- Record.getUniqueName());
-
- return writeRecord(Builder);
-}
-
-TypeIndex TypeTableBuilder::writeKnownType(const UnionRecord &Record) {
- TypeRecordBuilder Builder(TypeRecordKind::Union);
- Builder.writeUInt16(Record.getMemberCount());
- uint16_t Flags =
- static_cast<uint16_t>(Record.getOptions()) |
- (static_cast<uint16_t>(Record.getHfa()) << ClassRecord::HfaKindShift);
- Builder.writeUInt16(Flags);
- Builder.writeTypeIndex(Record.getFieldList());
- Builder.writeEncodedUnsignedInteger(Record.getSize());
- writeNameAndUniqueName(Builder, Record.getOptions(), Record.getName(),
- Record.getUniqueName());
- return writeRecord(Builder);
-}
-
-TypeIndex TypeTableBuilder::writeKnownType(const EnumRecord &Record) {
- TypeRecordBuilder Builder(Record.getKind());
-
- Builder.writeUInt16(Record.getMemberCount());
- Builder.writeUInt16(static_cast<uint16_t>(Record.getOptions()));
- Builder.writeTypeIndex(Record.getUnderlyingType());
- Builder.writeTypeIndex(Record.getFieldList());
- writeNameAndUniqueName(Builder, Record.getOptions(), Record.getName(),
- Record.getUniqueName());
-
- return writeRecord(Builder);
-}
-
-TypeIndex TypeTableBuilder::writeKnownType(const BitFieldRecord &Record) {
- TypeRecordBuilder Builder(Record.getKind());
-
- Builder.writeTypeIndex(Record.getType());
- Builder.writeUInt8(Record.getBitSize());
- Builder.writeUInt8(Record.getBitOffset());
-
- return writeRecord(Builder);
-}
-
-TypeIndex TypeTableBuilder::writeKnownType(const VFTableShapeRecord &Record) {
- TypeRecordBuilder Builder(Record.getKind());
-
- ArrayRef<VFTableSlotKind> Slots = Record.getSlots();
-
- Builder.writeUInt16(Slots.size());
- for (size_t SlotIndex = 0; SlotIndex < Slots.size(); SlotIndex += 2) {
- uint8_t Byte = static_cast<uint8_t>(Slots[SlotIndex]) << 4;
- if ((SlotIndex + 1) < Slots.size()) {
- Byte |= static_cast<uint8_t>(Slots[SlotIndex + 1]);
- }
- Builder.writeUInt8(Byte);
- }
-
- return writeRecord(Builder);
-}
-
-TypeIndex TypeTableBuilder::writeKnownType(const VFTableRecord &Record) {
- TypeRecordBuilder Builder(Record.getKind());
- Builder.writeTypeIndex(Record.getCompleteClass());
- Builder.writeTypeIndex(Record.getOverriddenVTable());
- Builder.writeUInt32(Record.getVFPtrOffset());
-
- // Sum up the lengths of the null-terminated names.
- size_t NamesLen = Record.getName().size() + 1;
- for (StringRef MethodName : Record.getMethodNames())
- NamesLen += MethodName.size() + 1;
-
- // FIXME: Avoid creating a record longer than MaxRecordLength.
- Builder.writeUInt32(NamesLen);
- Builder.writeNullTerminatedString(Record.getName());
- for (StringRef MethodName : Record.getMethodNames())
- Builder.writeNullTerminatedString(MethodName);
-
- return writeRecord(Builder);
-}
-
-TypeIndex TypeTableBuilder::writeKnownType(const StringIdRecord &Record) {
- TypeRecordBuilder Builder(TypeRecordKind::StringId);
- Builder.writeTypeIndex(Record.getId());
- Builder.writeNullTerminatedString(Record.getString());
- return writeRecord(Builder);
-}
-
-TypeIndex TypeTableBuilder::writeKnownType(const UdtSourceLineRecord &Record) {
- TypeRecordBuilder Builder(Record.getKind());
- Builder.writeTypeIndex(Record.getUDT());
- Builder.writeTypeIndex(Record.getSourceFile());
- Builder.writeUInt32(Record.getLineNumber());
- return writeRecord(Builder);
-}
-
-TypeIndex
-TypeTableBuilder::writeKnownType(const UdtModSourceLineRecord &Record) {
- TypeRecordBuilder Builder(Record.getKind());
- Builder.writeTypeIndex(Record.getUDT());
- Builder.writeTypeIndex(Record.getSourceFile());
- Builder.writeUInt32(Record.getLineNumber());
- Builder.writeUInt16(Record.getModule());
- return writeRecord(Builder);
-}
-
-TypeIndex TypeTableBuilder::writeKnownType(const FuncIdRecord &Record) {
- TypeRecordBuilder Builder(Record.getKind());
- Builder.writeTypeIndex(Record.getParentScope());
- Builder.writeTypeIndex(Record.getFunctionType());
- Builder.writeNullTerminatedString(Record.getName());
- return writeRecord(Builder);
-}
-
-TypeIndex TypeTableBuilder::writeKnownType(const MemberFuncIdRecord &Record) {
- TypeRecordBuilder Builder(Record.getKind());
- Builder.writeTypeIndex(Record.getClassType());
- Builder.writeTypeIndex(Record.getFunctionType());
- Builder.writeNullTerminatedString(Record.getName());
- return writeRecord(Builder);
-}
-
-TypeIndex TypeTableBuilder::writeKnownType(const BuildInfoRecord &Record) {
- TypeRecordBuilder Builder(Record.getKind());
- assert(Record.getArgs().size() <= UINT16_MAX);
- Builder.writeUInt16(Record.getArgs().size());
- for (TypeIndex Arg : Record.getArgs())
- Builder.writeTypeIndex(Arg);
- return writeRecord(Builder);
-}
-
-TypeIndex TypeTableBuilder::writeRecord(TypeRecordBuilder &Builder) {
- TypeIndex I = writeRecord(Builder.str());
- RecordKinds.push_back(Builder.kind());
- return I;
-}
-
-TypeIndex TypeTableBuilder::writeFieldList(FieldListRecordBuilder &FieldList) {
- TypeIndex I = FieldList.writeListRecord(*this);
- RecordKinds.push_back(TypeRecordKind::FieldList);
- return I;
-}
-
-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());
- Flags |= static_cast<uint16_t>(Method.getKind())
- << MemberAttributes::MethodKindShift;
- Flags |= static_cast<uint16_t>(Method.getOptions());
- Builder.writeUInt16(Flags);
- Builder.writeUInt16(0); // padding
- Builder.writeTypeIndex(Method.getType());
- if (Method.isIntroducingVirtual()) {
- assert(Method.getVFTableOffset() >= 0);
- Builder.writeInt32(Method.getVFTableOffset());
- } else {
- assert(Method.getVFTableOffset() == -1);
- }
- }
-
- // TODO: Split the list into multiple records if it's longer than 64KB, using
- // a subrecord of TypeRecordKind::Index to chain the records together.
- return writeRecord(Builder);
-}
-
-TypeIndex TypeTableBuilder::writeKnownType(const TypeServer2Record &Record) {
- TypeRecordBuilder Builder(Record.getKind());
- Builder.writeGuid(Record.getGuid());
- Builder.writeUInt32(Record.getAge());
- Builder.writeNullTerminatedString(Record.getName());
- return writeRecord(Builder);
-}
#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
#include "llvm/DebugInfo/CodeView/SymbolVisitorCallbackPipeline.h"
#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
-#include "llvm/DebugInfo/CodeView/TypeSerializationVisitor.h"
+#include "llvm/DebugInfo/CodeView/TypeSerializer.h"
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
#include "llvm/DebugInfo/PDB/PDBExtras.h"
#include "llvm/DebugInfo/PDB/PDBTypes.h"
pdb::yaml::SerializationContext &Context) {
codeview::TypeVisitorCallbackPipeline Pipeline;
codeview::TypeDeserializer Deserializer;
- codeview::TypeSerializationVisitor Serializer(Context.FieldListBuilder,
- Context.TypeTableBuilder);
+ codeview::TypeSerializer Serializer(Context.Allocator);
pdb::TpiHashUpdater Hasher;
if (IO.outputting()) {
} else {
// For Yaml to PDB, extract from the high level record type, then write it
// to bytes.
+
+ // This might be interpreted as a hack, but serializing FieldList
+ // sub-records requires having access to the same serializer being used by
+ // the FieldList itself.
+ Context.ActiveSerializer = &Serializer;
Pipeline.addCallbackToPipeline(Context.Dumper);
Pipeline.addCallbackToPipeline(Serializer);
Pipeline.addCallbackToPipeline(Hasher);
codeview::CVTypeVisitor Visitor(Pipeline);
consumeError(Visitor.visitTypeRecord(Obj.Record));
+ Context.ActiveSerializer = nullptr;
}
#include "PdbYaml.h"
#include "YamlTypeDumper.h"
-#include "llvm/DebugInfo/CodeView/FieldListRecordBuilder.h"
-#include "llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h"
+#include "llvm/Support/Allocator.h"
namespace llvm {
+namespace codeview {
+class TypeSerializer;
+}
namespace yaml {
class IO;
}
namespace yaml {
struct SerializationContext {
explicit SerializationContext(llvm::yaml::IO &IO, BumpPtrAllocator &Allocator)
- : Dumper(IO, *this), TypeTableBuilder(Allocator) {}
+ : Dumper(IO, *this), Allocator(Allocator) {}
+
codeview::yaml::YamlTypeDumperCallbacks Dumper;
- codeview::MemoryTypeTableBuilder TypeTableBuilder;
- codeview::FieldListRecordBuilder FieldListBuilder;
+ BumpPtrAllocator &Allocator;
+ codeview::TypeSerializer *ActiveSerializer = nullptr;
};
}
}
#include "llvm/DebugInfo/CodeView/EnumTables.h"
#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
-#include "llvm/DebugInfo/CodeView/TypeSerializationVisitor.h"
+#include "llvm/DebugInfo/CodeView/TypeSerializer.h"
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
#include "llvm/DebugInfo/PDB/Raw/TpiHashing.h"
// which will recurse back to the standard handler for top-level fields
// (top-level and member fields all have the exact same Yaml syntax so use
// the same parser).
- //
- // If we are not outputting, then the array contains no data starting out,
- // and is instead populated from the sequence represented by the yaml --
- // again, using the same logic that we use for top-level records.
FieldListRecordSplitter Splitter(FieldListRecords);
CVTypeVisitor V(Splitter);
consumeError(V.visitFieldListMemberStream(FieldList.Data));
+ YamlIO.mapRequired("FieldList", FieldListRecords, Context);
+ } else {
+ // If we are not outputting, then the array contains no data starting out,
+ // and is instead populated from the sequence represented by the yaml --
+ // again, using the same logic that we use for top-level records.
+ assert(Context.ActiveSerializer && "There is no active serializer!");
+ codeview::TypeVisitorCallbackPipeline Pipeline;
+ pdb::TpiHashUpdater Hasher;
+
+ // For Yaml to PDB, dump it (to fill out the record fields from the Yaml)
+ // then serialize those fields to bytes, then update their hashes.
+ Pipeline.addCallbackToPipeline(Context.Dumper);
+ Pipeline.addCallbackToPipeline(*Context.ActiveSerializer);
+ Pipeline.addCallbackToPipeline(Hasher);
+
+ codeview::CVTypeVisitor Visitor(Pipeline);
+ YamlIO.mapRequired("FieldList", FieldListRecords, Visitor);
}
- YamlIO.mapRequired("FieldList", FieldListRecords, Context);
}
namespace llvm {
pdb::yaml::SerializationContext> {
static void mapping(IO &IO, pdb::yaml::PdbTpiFieldListRecord &Obj,
pdb::yaml::SerializationContext &Context) {
+ assert(IO.outputting());
codeview::TypeVisitorCallbackPipeline Pipeline;
msf::ByteStream Data(Obj.Record.Data);
msf::StreamReader FieldReader(Data);
codeview::FieldListDeserializer Deserializer(FieldReader);
- codeview::TypeSerializationVisitor Serializer(Context.FieldListBuilder,
- Context.TypeTableBuilder);
- pdb::TpiHashUpdater Hasher;
- if (IO.outputting()) {
- // For PDB to Yaml, deserialize into a high level record type, then dump
- // it.
- Pipeline.addCallbackToPipeline(Deserializer);
- Pipeline.addCallbackToPipeline(Context.Dumper);
- } else {
- // For Yaml to PDB, extract from the high level record type, then write it
- // to bytes.
- Pipeline.addCallbackToPipeline(Context.Dumper);
- Pipeline.addCallbackToPipeline(Serializer);
- Pipeline.addCallbackToPipeline(Hasher);
- }
+ // For PDB to Yaml, deserialize into a high level record type, then dump
+ // it.
+ Pipeline.addCallbackToPipeline(Deserializer);
+ Pipeline.addCallbackToPipeline(Context.Dumper);
codeview::CVTypeVisitor Visitor(Pipeline);
consumeError(Visitor.visitMemberRecord(Obj.Record));
}
};
+
+template <>
+struct MappingContextTraits<pdb::yaml::PdbTpiFieldListRecord,
+ codeview::CVTypeVisitor> {
+ static void mapping(IO &IO, pdb::yaml::PdbTpiFieldListRecord &Obj,
+ codeview::CVTypeVisitor &Visitor) {
+ consumeError(Visitor.visitMemberRecord(Obj.Record));
+ }
+};
}
}
#define LLVM_TOOLS_LLVMPDBDUMP_YAMLTYPEDUMPER_H
#include "llvm/DebugInfo/CodeView/CodeView.h"
-#include "llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h"
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
#include "llvm/Support/YAMLTraits.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/DebugInfo/CodeView/CodeView.h"
#include "llvm/DebugInfo/CodeView/Line.h"
-#include "llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h"
#include "llvm/DebugInfo/CodeView/RecordSerialization.h"
#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
#include "llvm/DebugInfo/CodeView/SymbolDumpDelegate.h"
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
#include "llvm/DebugInfo/CodeView/TypeStreamMerger.h"
+#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
#include "llvm/DebugInfo/MSF/ByteStream.h"
#include "llvm/Object/COFF.h"
#include "llvm/Object/ObjectFile.h"
void printCOFFBaseReloc() override;
void printCOFFDebugDirectory() override;
void printCodeViewDebugInfo() override;
- void
- mergeCodeViewTypes(llvm::codeview::MemoryTypeTableBuilder &CVTypes) override;
+ void mergeCodeViewTypes(llvm::codeview::TypeTableBuilder &CVTypes) override;
void printStackMap() const override;
private:
void printSymbol(const SymbolRef &Sym);
W.printHex(Label, getFileNameForFileOffset(FileOffset), FileOffset);
}
-void COFFDumper::mergeCodeViewTypes(MemoryTypeTableBuilder &CVTypes) {
+void COFFDumper::mergeCodeViewTypes(TypeTableBuilder &CVTypes) {
for (const SectionRef &S : Obj->sections()) {
StringRef SectionName;
error(S.getName(SectionName));
StackMapV2Parser<support::big>(StackMapContentsArray));
}
-void llvm::dumpCodeViewMergedTypes(
- ScopedPrinter &Writer, llvm::codeview::MemoryTypeTableBuilder &CVTypes) {
+void llvm::dumpCodeViewMergedTypes(ScopedPrinter &Writer,
+ llvm::codeview::TypeTableBuilder &CVTypes) {
// Flatten it first, then run our dumper on it.
ListScope S(Writer, "MergedTypeStream");
SmallString<0> Buf;
- CVTypes.ForEachRecord([&](TypeIndex TI, StringRef Record) {
+ CVTypes.ForEachRecord([&](TypeIndex TI, ArrayRef<uint8_t> Record) {
Buf.append(Record.begin(), Record.end());
});
CVTypeDumper CVTD(&Writer, opts::CodeViewSubsectionBytes);
class ObjectFile;
}
namespace codeview {
-class MemoryTypeTableBuilder;
+class TypeTableBuilder;
}
class ScopedPrinter;
virtual void printCOFFBaseReloc() { }
virtual void printCOFFDebugDirectory() { }
virtual void printCodeViewDebugInfo() { }
- virtual void
- mergeCodeViewTypes(llvm::codeview::MemoryTypeTableBuilder &CVTypes) {}
+ virtual void mergeCodeViewTypes(llvm::codeview::TypeTableBuilder &CVTypes) {}
// Only implemented for MachO.
virtual void printMachODataInCode() { }
void dumpCOFFImportFile(const object::COFFImportFile *File);
void dumpCodeViewMergedTypes(ScopedPrinter &Writer,
- llvm::codeview::MemoryTypeTableBuilder &CVTypes);
+ llvm::codeview::TypeTableBuilder &CVTypes);
} // namespace llvm
#include "llvm-readobj.h"
#include "Error.h"
#include "ObjDumper.h"
-#include "llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h"
+#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/COFFImportFile.h"
#include "llvm/Object/ELFObjectFile.h"
}
}
namespace {
-struct TypeTableBuilder {
- TypeTableBuilder() : Allocator(), Builder(Allocator) {}
+struct ReadObjTypeTableBuilder {
+ ReadObjTypeTableBuilder() : Allocator(), Builder(Allocator) {}
llvm::BumpPtrAllocator Allocator;
- llvm::codeview::MemoryTypeTableBuilder Builder;
+ llvm::codeview::TypeTableBuilder Builder;
};
}
-static TypeTableBuilder CVTypes;
+static ReadObjTypeTableBuilder CVTypes;
/// @brief Creates an format-specific object file dumper.
static std::error_code createDumper(const ObjectFile *Obj,