llvm.org GIT mirror llvm / 7306956
[CodeView] Hook up CodeViewRecordIO to type serialization path. Previously support had been added for using CodeViewRecordIO to read (deserialize) CodeView type records. This patch adds support for writing those same records. With this patch, reading and writing of CodeView type records finally uses a single codepath. Differential Revision: https://reviews.llvm.org/D26253 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@286304 91177308-0d34-0410-b5e6-96231b3b80d8 Zachary Turner 3 years ago
37 changed file(s) with 857 addition(s) and 1374 deletion(s). Raw diff Collapse all Expand all
1212 #include "llvm/ADT/APSInt.h"
1313 #include "llvm/ADT/Optional.h"
1414 #include "llvm/ADT/STLExtras.h"
15 #include "llvm/ADT/SmallVector.h"
1516 #include "llvm/ADT/StringRef.h"
16 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
17 #include "llvm/DebugInfo/CodeView/CodeView.h"
18 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
1719 #include "llvm/DebugInfo/MSF/StreamReader.h"
1820 #include "llvm/DebugInfo/MSF/StreamWriter.h"
1921 #include "llvm/Support/Error.h"
2022
21 #include
2223 #include
2324
25 #include
26
2427 namespace llvm {
25 namespace msf {
26 class StreamReader;
27 class StreamWriter;
28 }
2928 namespace codeview {
3029
3130 class CodeViewRecordIO {
32 struct ActiveRecord {
33 uint16_t Kind;
34 };
31 uint32_t getCurrentOffset() const {
32 return (isWriting()) ? Writer->getOffset() : Reader->getOffset();
33 }
3534
3635 public:
3736 explicit CodeViewRecordIO(msf::StreamReader &Reader) : Reader(&Reader) {}
3837 explicit CodeViewRecordIO(msf::StreamWriter &Writer) : Writer(&Writer) {}
3938
40 Error beginRecord(uint16_t Kind);
39 Error beginRecord(Optional MaxLength);
4140 Error endRecord();
41
4242 Error mapInteger(TypeIndex &TypeInd);
4343
4444 bool isReading() const { return Reader != nullptr; }
4545 bool isWriting() const { return !isReading(); }
46
47 uint32_t maxFieldLength() const;
4648
4749 template Error mapInteger(T &Value) {
4850 if (isWriting())
5254 }
5355
5456 template Error mapEnum(T &Value) {
57 if (sizeof(Value) > maxFieldLength())
58 return make_error(cv_error_code::insufficient_buffer);
59
5560 using U = typename std::underlying_type::type;
5661 U X;
5762 if (isWriting())
123128 Error writeEncodedSignedInteger(const int64_t &Value);
124129 Error writeEncodedUnsignedInteger(const uint64_t &Value);
125130
126 Optional CurrentRecord;
131 struct RecordLimit {
132 uint32_t BeginOffset;
133 Optional MaxLength;
134
135 Optional bytesRemaining(uint32_t CurrentOffset) const {
136 if (!MaxLength.hasValue())
137 return None;
138 assert(CurrentOffset >= BeginOffset);
139
140 uint32_t BytesUsed = CurrentOffset - BeginOffset;
141 if (BytesUsed >= *MaxLength)
142 return 0;
143 return *MaxLength - BytesUsed;
144 }
145 };
146
147 SmallVector Limits;
127148
128149 msf::StreamReader *Reader = nullptr;
129150 msf::StreamWriter *Writer = nullptr;
+0
-67
include/llvm/DebugInfo/CodeView/FieldListRecordBuilder.h less more
None //===- FieldListRecordBuilder.h ---------------------------------*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #ifndef LLVM_DEBUGINFO_CODEVIEW_FIELDLISTRECORDBUILDER_H
10 #define LLVM_DEBUGINFO_CODEVIEW_FIELDLISTRECORDBUILDER_H
11
12 #include "llvm/DebugInfo/CodeView/ListRecordBuilder.h"
13 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
14
15 namespace llvm {
16 namespace codeview {
17
18 class MethodInfo {
19 public:
20 MethodInfo() : Access(), Kind(), Options(), Type(), VTableSlotOffset(-1) {}
21
22 MethodInfo(MemberAccess Access, MethodKind Kind, MethodOptions Options,
23 TypeIndex Type, int32_t VTableSlotOffset)
24 : Access(Access), Kind(Kind), Options(Options), Type(Type),
25 VTableSlotOffset(VTableSlotOffset) {}
26
27 MemberAccess getAccess() const { return Access; }
28 MethodKind getKind() const { return Kind; }
29 MethodOptions getOptions() const { return Options; }
30 TypeIndex getType() const { return Type; }
31 int32_t getVTableSlotOffset() const { return VTableSlotOffset; }
32
33 private:
34 MemberAccess Access;
35 MethodKind Kind;
36 MethodOptions Options;
37 TypeIndex Type;
38 int32_t VTableSlotOffset;
39 };
40
41 class FieldListRecordBuilder : public ListRecordBuilder {
42 private:
43 FieldListRecordBuilder(const FieldListRecordBuilder &) = delete;
44 void operator=(const FieldListRecordBuilder &) = delete;
45
46 public:
47 FieldListRecordBuilder();
48
49 void reset() { ListRecordBuilder::reset(); }
50
51 void writeMemberType(const BaseClassRecord &Record);
52 void writeMemberType(const EnumeratorRecord &Record);
53 void writeMemberType(const DataMemberRecord &Record);
54 void writeMemberType(const OneMethodRecord &Record);
55 void writeMemberType(const OverloadedMethodRecord &Record);
56 void writeMemberType(const NestedTypeRecord &Record);
57 void writeMemberType(const StaticDataMemberRecord &Record);
58 void writeMemberType(const VirtualBaseClassRecord &Record);
59 void writeMemberType(const VFPtrRecord &Type);
60
61 using ListRecordBuilder::writeMemberType;
62 };
63 }
64 }
65
66 #endif
+0
-65
include/llvm/DebugInfo/CodeView/ListRecordBuilder.h less more
None //===- ListRecordBuilder.h --------------------------------------*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #ifndef LLVM_DEBUGINFO_CODEVIEW_LISTRECORDBUILDER_H
10 #define LLVM_DEBUGINFO_CODEVIEW_LISTRECORDBUILDER_H
11
12 #include "llvm/DebugInfo/CodeView/TypeRecordBuilder.h"
13
14 namespace llvm {
15 namespace codeview {
16 class TypeTableBuilder;
17
18 class ListRecordBuilder {
19 private:
20 ListRecordBuilder(const ListRecordBuilder &) = delete;
21 ListRecordBuilder &operator=(const ListRecordBuilder &) = delete;
22
23 protected:
24 const int MethodKindShift = 2;
25
26 explicit ListRecordBuilder(TypeRecordKind Kind);
27
28 public:
29 llvm::StringRef str() { return Builder.str(); }
30
31 void reset() {
32 Builder.reset(Kind);
33 ContinuationOffsets.clear();
34 SubrecordStart = 0;
35 }
36
37 void writeMemberType(const ListContinuationRecord &R);
38
39 /// Writes this list record as a possible sequence of records.
40 TypeIndex writeListRecord(TypeTableBuilder &Table);
41
42 protected:
43 void finishSubRecord();
44
45 TypeRecordBuilder &getBuilder() { return Builder; }
46
47 private:
48 size_t getLastContinuationStart() const {
49 return ContinuationOffsets.empty() ? 0 : ContinuationOffsets.back();
50 }
51 size_t getLastContinuationEnd() const { return Builder.size(); }
52 size_t getLastContinuationSize() const {
53 return getLastContinuationEnd() - getLastContinuationStart();
54 }
55
56 TypeRecordKind Kind;
57 TypeRecordBuilder Builder;
58 SmallVector ContinuationOffsets;
59 size_t SubrecordStart = 0;
60 };
61 }
62 }
63
64 #endif
+0
-50
include/llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h less more
None //===- MemoryTypeTableBuilder.h ---------------------------------*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #ifndef LLVM_DEBUGINFO_CODEVIEW_MEMORYTYPETABLEBUILDER_H
10 #define LLVM_DEBUGINFO_CODEVIEW_MEMORYTYPETABLEBUILDER_H
11
12 #include "llvm/ADT/DenseMap.h"
13 #include "llvm/ADT/StringRef.h"
14 #include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
15 #include
16
17 namespace llvm {
18 namespace codeview {
19
20 class MemoryTypeTableBuilder : public TypeTableBuilder {
21 public:
22 explicit MemoryTypeTableBuilder(BumpPtrAllocator &Allocator)
23 : RecordStorage(Allocator) {}
24
25 bool empty() const { return Records.empty(); }
26
27 template void ForEachRecord(TFunc Func) {
28 uint32_t Index = TypeIndex::FirstNonSimpleIndex;
29
30 for (StringRef R : Records) {
31 Func(TypeIndex(Index), R);
32 ++Index;
33 }
34 }
35
36 TypeIndex writeRecord(llvm::StringRef Data) override;
37
38 ArrayRef getRecords() const { return Records; }
39
40 private:
41 std::vector Records;
42 BumpPtrAllocator &RecordStorage;
43 DenseMap HashedRecords;
44 };
45
46 } // end namespace codeview
47 } // end namespace llvm
48
49 #endif // LLVM_DEBUGINFO_CODEVIEW_MEMORYTYPETABLEBUILDER_H
+0
-35
include/llvm/DebugInfo/CodeView/MethodListRecordBuilder.h less more
None //===- MethodListRecordBuilder.h --------------------------------*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #ifndef LLVM_DEBUGINFO_CODEVIEW_METHODLISTRECORDBUILDER_H
10 #define LLVM_DEBUGINFO_CODEVIEW_METHODLISTRECORDBUILDER_H
11
12 #include "llvm/DebugInfo/CodeView/ListRecordBuilder.h"
13
14 namespace llvm {
15 namespace codeview {
16
17 class MethodInfo;
18
19 class MethodListRecordBuilder : public ListRecordBuilder {
20 private:
21 MethodListRecordBuilder(const MethodListRecordBuilder &) = delete;
22 MethodListRecordBuilder &operator=(const MethodListRecordBuilder &) = delete;
23
24 public:
25 MethodListRecordBuilder();
26
27 void writeMethod(MemberAccess Access, MethodKind Kind, MethodOptions Options,
28 TypeIndex Type, int32_t VTableSlotOffset);
29 void writeMethod(const MethodInfo &Method);
30 };
31 }
32 }
33
34 #endif
3131 enum : unsigned { MaxRecordLength = 0xFF00 };
3232
3333 struct RecordPrefix {
34 ulittle16_t RecordLen; // Record length, starting from &Leaf.
34 ulittle16_t RecordLen; // Record length, starting from &RecordKind.
3535 ulittle16_t RecordKind; // Record kind enum (SymRecordKind or TypeRecordKind)
3636 };
3737
7575 };
7676
7777 public:
78 explicit FieldListDeserializer(msf::StreamReader &Reader) : Mapping(Reader) {}
78 explicit FieldListDeserializer(msf::StreamReader &Reader) : Mapping(Reader) {
79 CVType FieldList;
80 FieldList.Type = TypeLeafKind::LF_FIELDLIST;
81 consumeError(Mapping.Mapping.visitTypeBegin(FieldList));
82 }
83
84 ~FieldListDeserializer() {
85 CVType FieldList;
86 FieldList.Type = TypeLeafKind::LF_FIELDLIST;
87 consumeError(Mapping.Mapping.visitTypeEnd(FieldList));
88 }
7989
8090 Error visitMemberBegin(CVMemberRecord &Record) override {
8191 Mapping.StartOffset = Mapping.Reader.getOffset();
9292 static const uint32_t SimpleModeMask = 0x00000700;
9393
9494 public:
95 TypeIndex() : Index(0) {}
95 TypeIndex() : Index(static_cast(SimpleTypeKind::None)) {}
9696 explicit TypeIndex(uint32_t Index) : Index(Index) {}
9797 explicit TypeIndex(SimpleTypeKind Kind)
9898 : Index(static_cast(Kind)) {}
700700 StringRef Name)
701701 : TypeRecord(TypeRecordKind::OneMethod), Type(Type), Attrs(Attrs),
702702 VFTableOffset(VFTableOffset), Name(Name) {}
703 OneMethodRecord(TypeIndex Type, MemberAccess Access, MethodKind Kind,
703 OneMethodRecord(TypeIndex Type, MemberAccess Access, MethodKind MK,
704704 MethodOptions Options, int32_t VFTableOffset, StringRef Name)
705705 : TypeRecord(TypeRecordKind::OneMethod), Type(Type),
706 Attrs(Access, Kind, Options), VFTableOffset(VFTableOffset), Name(Name) {
707 }
706 Attrs(Access, MK, Options), VFTableOffset(VFTableOffset), Name(Name) {}
708707
709708 /// Rewrite member type indices with IndexMap. Returns false if a type index
710709 /// is not in the map.
711710 bool remapTypeIndices(ArrayRef IndexMap);
712711
713712 TypeIndex getType() const { return Type; }
714 MethodKind getKind() const { return Attrs.getMethodKind(); }
713 MethodKind getMethodKind() const { return Attrs.getMethodKind(); }
715714 MethodOptions getOptions() const { return Attrs.getFlags(); }
716715 MemberAccess getAccess() const { return Attrs.getAccess(); }
717716 int32_t getVFTableOffset() const { return VFTableOffset; }
718717 StringRef getName() const { return Name; }
719718
720719 bool isIntroducingVirtual() const {
721 return getKind() == MethodKind::IntroducingVirtual ||
722 getKind() == MethodKind::PureIntroducingVirtual;
720 return getMethodKind() == MethodKind::IntroducingVirtual ||
721 getMethodKind() == MethodKind::PureIntroducingVirtual;
723722 }
724723 TypeIndex Type;
725724 MemberAttributes Attrs;
1515 #include "llvm/Support/Error.h"
1616
1717 namespace llvm {
18 namespace msf {
19 class StreamReader;
20 class StreamWriter;
21 }
1822 namespace codeview {
1923 class TypeRecordMapping : public TypeVisitorCallbacks {
2024 public:
2125 explicit TypeRecordMapping(msf::StreamReader &Reader) : IO(Reader) {}
26 explicit TypeRecordMapping(msf::StreamWriter &Writer) : IO(Writer) {}
2227
2328 Error visitTypeBegin(CVType &Record) override;
2429 Error visitTypeEnd(CVType &Record) override;
3641
3742 private:
3843 Optional TypeKind;
44 Optional MemberKind;
3945
4046 CodeViewRecordIO IO;
4147 };
+0
-85
include/llvm/DebugInfo/CodeView/TypeSerializationVisitor.h less more
None //===- TypeSerializationVisitor.h -------------------------------*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #ifndef LLVM_DEBUGINFO_CODEVIEW_TYPESERIALIZATIONVISITOR_H
10 #define LLVM_DEBUGINFO_CODEVIEW_TYPESERIALIZATIONVISITOR_H
11
12 #include "llvm/DebugInfo/CodeView/FieldListRecordBuilder.h"
13 #include "llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h"
14 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
15
16 #include "llvm/ADT/StringRef.h"
17 #include "llvm/Support/Error.h"
18
19 namespace llvm {
20 namespace codeview {
21
22 class TypeSerializationVisitor : public TypeVisitorCallbacks {
23 public:
24 TypeSerializationVisitor(FieldListRecordBuilder &FieldListBuilder,
25 MemoryTypeTableBuilder &TypeTableBuilder)
26 : FieldListBuilder(FieldListBuilder), TypeTableBuilder(TypeTableBuilder) {
27 }
28
29 virtual Error visitTypeBegin(CVType &Record) override {
30 if (Record.Type == TypeLeafKind::LF_FIELDLIST)
31 FieldListBuilder.reset();
32 return Error::success();
33 }
34
35 virtual Error visitTypeEnd(CVType &Record) override {
36 // Since this visitor's purpose is to serialize the record, fill out the
37 // fields of `Record` with the bytes of the record.
38 if (Record.Type == TypeLeafKind::LF_FIELDLIST) {
39 TypeTableBuilder.writeFieldList(FieldListBuilder);
40 updateCVRecord(Record);
41 }
42
43 return Error::success();
44 }
45
46 #define TYPE_RECORD(EnumName, EnumVal, Name) \
47 virtual Error visitKnownRecord(CVType &CVR, Name##Record &Record) override { \
48 visitKnownRecordImpl(CVR, Record); \
49 return Error::success(); \
50 }
51 #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
52 #define MEMBER_RECORD(EnumName, EnumVal, Name) \
53 virtual Error visitKnownMember(CVMemberRecord &CVR, Name##Record &Record) \
54 override { \
55 visitMemberRecordImpl(Record); \
56 return Error::success(); \
57 }
58 #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
59 #include "llvm/DebugInfo/CodeView/TypeRecords.def"
60
61 private:
62 void updateCVRecord(CVType &Record) {
63 StringRef S = TypeTableBuilder.getRecords().back();
64 Record.RecordData = ArrayRef(S.bytes_begin(), S.bytes_end());
65 }
66 template
67 void visitKnownRecordImpl(CVType &CVR, RecordKind &Record) {
68 TypeTableBuilder.writeKnownType(Record);
69 updateCVRecord(CVR);
70 }
71 template
72 void visitMemberRecordImpl(RecordKind &Record) {
73 FieldListBuilder.writeMemberType(Record);
74 }
75
76 void visitKnownRecordImpl(CVType &CVR, FieldListRecord &FieldList) {}
77
78 FieldListRecordBuilder &FieldListBuilder;
79 MemoryTypeTableBuilder &TypeTableBuilder;
80 };
81 }
82 }
83
84 #endif
0 //===- TypeSerializer.h -----------------------------------------*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #ifndef LLVM_DEBUGINFO_CODEVIEW_TYPESERIALIZER_H
10 #define LLVM_DEBUGINFO_CODEVIEW_TYPESERIALIZER_H
11
12 #include "llvm/DebugInfo/CodeView/TypeRecordMapping.h"
13 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
14 #include "llvm/DebugInfo/MSF/ByteStream.h"
15 #include "llvm/DebugInfo/MSF/StreamWriter.h"
16
17 #include "llvm/ADT/Optional.h"
18 #include "llvm/ADT/SmallVector.h"
19 #include "llvm/ADT/StringMap.h"
20 #include "llvm/ADT/StringRef.h"
21 #include "llvm/Support/Allocator.h"
22 #include "llvm/Support/Error.h"
23
24 namespace llvm {
25
26 namespace codeview {
27
28 class TypeSerializer : public TypeVisitorCallbacks {
29 struct SubRecord {
30 SubRecord(TypeLeafKind K, uint32_t S) : Kind(K), Size(S) {}
31
32 TypeLeafKind Kind;
33 uint32_t Size = 0;
34 };
35 struct RecordSegment {
36 SmallVector SubRecords;
37
38 uint32_t length() const {
39 uint32_t L = sizeof(RecordPrefix);
40 for (const auto &R : SubRecords) {
41 L += R.Size;
42 }
43 return L;
44 }
45 };
46
47 typedef SmallVector, 2> RecordList;
48
49 static constexpr uint8_t ContinuationLength = 8;
50 BumpPtrAllocator &RecordStorage;
51 RecordSegment CurrentSegment;
52 RecordList FieldListSegments;
53
54 TypeIndex LastTypeIndex;
55 Optional TypeKind;
56 Optional MemberKind;
57 std::vector RecordBuffer;
58 msf::MutableByteStream Stream;
59 msf::StreamWriter Writer;
60 TypeRecordMapping Mapping;
61
62 RecordList SeenRecords;
63 StringMap HashedRecords;
64
65 bool isInFieldList() const;
66 TypeIndex calcNextTypeIndex() const;
67 TypeIndex incrementTypeIndex();
68 MutableArrayRef getCurrentSubRecordData();
69 MutableArrayRef getCurrentRecordData();
70 Error writeRecordPrefix(TypeLeafKind Kind);
71 TypeIndex insertRecordBytesPrivate(MutableArrayRef Record);
72
73 Expected>
74 addPadding(MutableArrayRef Record);
75
76 public:
77 explicit TypeSerializer(BumpPtrAllocator &Storage);
78
79 ArrayRef> records() const;
80 TypeIndex getLastTypeIndex() const;
81 TypeIndex insertRecordBytes(MutableArrayRef Record);
82 Expected visitTypeEndGetIndex(CVType &Record);
83
84 Error visitTypeBegin(CVType &Record) override;
85 Error visitTypeEnd(CVType &Record) override;
86 Error visitMemberBegin(CVMemberRecord &Record) override;
87 Error visitMemberEnd(CVMemberRecord &Record) override;
88
89 #define TYPE_RECORD(EnumName, EnumVal, Name) \
90 virtual Error visitKnownRecord(CVType &CVR, Name##Record &Record) override { \
91 return visitKnownRecordImpl(CVR, Record); \
92 }
93 #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
94 #define MEMBER_RECORD(EnumName, EnumVal, Name) \
95 Error visitKnownMember(CVMemberRecord &CVR, Name##Record &Record) override { \
96 return visitKnownMemberImpl(CVR, Record); \
97 }
98 #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
99 #include "llvm/DebugInfo/CodeView/TypeRecords.def"
100
101 private:
102 template
103 Error visitKnownRecordImpl(CVType &CVR, RecordKind &Record) {
104 return Mapping.visitKnownRecord(CVR, Record);
105 }
106
107 template
108 Error visitKnownMemberImpl(CVMemberRecord &CVR, RecordType &Record) {
109 assert(CVR.Kind == static_cast(Record.getKind()));
110
111 if (auto EC = Writer.writeEnum(CVR.Kind))
112 return EC;
113
114 if (auto EC = Mapping.visitKnownMember(CVR, Record))
115 return EC;
116
117 // Get all the data that was just written and is yet to be committed to
118 // the current segment. Then pad it to 4 bytes.
119 MutableArrayRef ThisRecord = getCurrentSubRecordData();
120 auto ExpectedRecord = addPadding(ThisRecord);
121 if (!ExpectedRecord)
122 return ExpectedRecord.takeError();
123 ThisRecord = *ExpectedRecord;
124
125 CurrentSegment.SubRecords.emplace_back(CVR.Kind, ThisRecord.size());
126 CVR.Data = ThisRecord;
127
128 // Both the last subrecord and the total length of this segment should be
129 // multiples of 4.
130 assert(ThisRecord.size() % 4 == 0);
131 assert(CurrentSegment.length() % 4 == 0);
132
133 return Error::success();
134 }
135 };
136 }
137 }
138
139 #endif
99 #ifndef LLVM_DEBUGINFO_CODEVIEW_TYPETABLEBUILDER_H
1010 #define LLVM_DEBUGINFO_CODEVIEW_TYPETABLEBUILDER_H
1111
12 #include "llvm/DebugInfo/CodeView/CodeView.h"
13 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
14 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
15 #include "llvm/Support/Compiler.h"
12 #include "llvm/DebugInfo/CodeView/TypeSerializer.h"
13 #include "llvm/Support/Allocator.h"
14 #include "llvm/Support/Error.h"
1615
1716 namespace llvm {
1817
19 class StringRef;
20
2118 namespace codeview {
22
23 class FieldListRecordBuilder;
24 class MethodListRecordBuilder;
25 class TypeRecordBuilder;
2619
2720 class TypeTableBuilder {
2821 private:
2922 TypeTableBuilder(const TypeTableBuilder &) = delete;
3023 TypeTableBuilder &operator=(const TypeTableBuilder &) = delete;
3124
32 protected:
33 TypeTableBuilder();
25 TypeIndex handleError(llvm::Error EC) const {
26 assert(false && "Couldn't write Type!");
27 llvm::consumeError(std::move(EC));
28 return TypeIndex();
29 }
30
31 BumpPtrAllocator &Allocator;
32 TypeSerializer Serializer;
3433
3534 public:
36 virtual ~TypeTableBuilder();
35 explicit TypeTableBuilder(BumpPtrAllocator &Allocator)
36 : Allocator(Allocator), Serializer(Allocator) {}
37
38 bool empty() const { return Serializer.records().empty(); }
39
40 BumpPtrAllocator &getAllocator() const { return Allocator; }
41
42 template TypeIndex writeKnownType(T &Record) {
43 static_assert(!std::is_same::value,
44 "Can't serialize FieldList!");
45
46 CVType Type;
47 Type.Type = static_cast(Record.getKind());
48 if (auto EC = Serializer.visitTypeBegin(Type))
49 return handleError(std::move(EC));
50 if (auto EC = Serializer.visitKnownRecord(Type, Record))
51 return handleError(std::move(EC));
52
53 auto ExpectedIndex = Serializer.visitTypeEndGetIndex(Type);
54 if (!ExpectedIndex)
55 return handleError(ExpectedIndex.takeError());
56
57 return *ExpectedIndex;
58 }
59
60 TypeIndex writeSerializedRecord(MutableArrayRef Record) {
61 return Serializer.insertRecordBytes(Record);
62 }
63
64 template void ForEachRecord(TFunc Func) {
65 uint32_t Index = TypeIndex::FirstNonSimpleIndex;
66
67 for (auto Record : Serializer.records()) {
68 Func(TypeIndex(Index), Record);
69 ++Index;
70 }
71 }
72
73 ArrayRef> records() const {
74 return Serializer.records();
75 }
76 };
77
78 class FieldListRecordBuilder {
79 TypeTableBuilder &TypeTable;
80 TypeSerializer TempSerializer;
81 CVType Type;
3782
3883 public:
39 TypeIndex writeKnownType(const ModifierRecord &Record);
40 TypeIndex writeKnownType(const ProcedureRecord &Record);
41 TypeIndex writeKnownType(const MemberFunctionRecord &Record);
42 TypeIndex writeKnownType(const ArgListRecord &Record);
43 TypeIndex writeKnownType(const PointerRecord &Record);
44 TypeIndex writeKnownType(const ArrayRecord &Record);
45 TypeIndex writeKnownType(const ClassRecord &Record);
46 TypeIndex writeKnownType(const UnionRecord &Record);
47 TypeIndex writeKnownType(const EnumRecord &Record);
48 TypeIndex writeKnownType(const BitFieldRecord &Record);
49 TypeIndex writeKnownType(const VFTableShapeRecord &Record);
50 TypeIndex writeKnownType(const StringIdRecord &Record);
51 TypeIndex writeKnownType(const VFTableRecord &Record);
52 TypeIndex writeKnownType(const UdtSourceLineRecord &Record);
53 TypeIndex writeKnownType(const UdtModSourceLineRecord &Record);
54 TypeIndex writeKnownType(const FuncIdRecord &Record);
55 TypeIndex writeKnownType(const MemberFuncIdRecord &Record);
56 TypeIndex writeKnownType(const BuildInfoRecord &Record);
57 TypeIndex writeKnownType(const MethodOverloadListRecord &Record);
58 TypeIndex writeKnownType(const TypeServer2Record &Record);
84 explicit FieldListRecordBuilder(TypeTableBuilder &TypeTable)
85 : TypeTable(TypeTable), TempSerializer(TypeTable.getAllocator()) {
86 Type.Type = TypeLeafKind::LF_FIELDLIST;
87 }
5988
60 TypeIndex writeFieldList(FieldListRecordBuilder &FieldList);
89 void begin() {
90 if (auto EC = TempSerializer.visitTypeBegin(Type))
91 consumeError(std::move(EC));
92 }
6193
62 TypeIndex writeRecord(TypeRecordBuilder &builder);
94 template void writeMemberType(T &Record) {
95 CVMemberRecord CVMR;
96 CVMR.Kind = static_cast(Record.getKind());
97 if (auto EC = TempSerializer.visitMemberBegin(CVMR))
98 consumeError(std::move(EC));
99 if (auto EC = TempSerializer.visitKnownMember(CVMR, Record))
100 consumeError(std::move(EC));
101 if (auto EC = TempSerializer.visitMemberEnd(CVMR))
102 consumeError(std::move(EC));
103 }
63104
64 virtual TypeIndex writeRecord(llvm::StringRef record) = 0;
105 TypeIndex end() {
106 if (auto EC = TempSerializer.visitTypeEnd(Type)) {
107 consumeError(std::move(EC));
108 return TypeIndex();
109 }
65110
66 ArrayRef getRecordKinds() const { return RecordKinds; }
67
68 private:
69 std::vector RecordKinds;
111 TypeIndex Index;
112 for (auto Record : TempSerializer.records()) {
113 Index = TypeTable.writeSerializedRecord(Record);
114 }
115 return Index;
116 }
70117 };
71118 }
72119 }
7373
7474 #define TYPE_RECORD(EnumName, EnumVal, Name) \
7575 Error visitKnownRecord(CVType &CVR, Name##Record &Record) override { \
76 for (auto Visitor : Pipeline) { \
77 if (auto EC = Visitor->visitKnownRecord(CVR, Record)) \
78 return EC; \
79 } \
80 return Error::success(); \
76 return visitKnownRecordImpl(CVR, Record); \
8177 }
8278 #define MEMBER_RECORD(EnumName, EnumVal, Name) \
8379 Error visitKnownMember(CVMemberRecord &CVMR, Name##Record &Record) \
8480 override { \
85 for (auto Visitor : Pipeline) { \
86 if (auto EC = Visitor->visitKnownMember(CVMR, Record)) \
87 return EC; \
88 } \
89 return Error::success(); \
81 return visitKnownMemberImpl(CVMR, Record); \
9082 }
9183 #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
9284 #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
9385 #include "llvm/DebugInfo/CodeView/TypeRecords.def"
9486
9587 private:
88 template Error visitKnownRecordImpl(CVType &CVR, T &Record) {
89 for (auto Visitor : Pipeline) {
90 if (auto EC = Visitor->visitKnownRecord(CVR, Record))
91 return EC;
92 }
93 return Error::success();
94 }
95
96 template
97 Error visitKnownMemberImpl(CVMemberRecord &CVMR, T &Record) {
98 for (auto Visitor : Pipeline) {
99 if (auto EC = Visitor->visitKnownMember(CVMR, Record))
100 return EC;
101 }
102 return Error::success();
103 }
96104 std::vector Pipeline;
97105 };
98106 }
2525 class StreamWriter {
2626 public:
2727 StreamWriter() {}
28 StreamWriter(WritableStreamRef Stream);
28 explicit StreamWriter(WritableStreamRef Stream);
2929
3030 Error writeBytes(ArrayRef Buffer);
3131 Error writeInteger(uint8_t Int);
1414 #include "llvm/ADT/TinyPtrVector.h"
1515 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
1616 #include "llvm/DebugInfo/CodeView/CodeView.h"
17 #include "llvm/DebugInfo/CodeView/FieldListRecordBuilder.h"
1817 #include "llvm/DebugInfo/CodeView/Line.h"
1918 #include "llvm/DebugInfo/CodeView/SymbolRecord.h"
2019 #include "llvm/DebugInfo/CodeView/TypeDumper.h"
221220
222221 // Build the fully qualified name of the scope.
223222 std::string ScopeName = getFullyQualifiedName(Scope);
224 TypeIndex TI =
225 TypeTable.writeKnownType(StringIdRecord(TypeIndex(), ScopeName));
223 StringIdRecord SID(TypeIndex(), ScopeName);
224 auto TI = TypeTable.writeKnownType(SID);
226225 return recordTypeIndexForDINode(Scope, TI);
227226 }
228227
468467 }
469468
470469 CVTypeDumper CVTD(nullptr, /*PrintRecordBytes=*/false);
471 TypeTable.ForEachRecord(
472 [&](TypeIndex Index, StringRef Record) {
473 if (OS.isVerboseAsm()) {
474 // Emit a block comment describing the type record for readability.
475 SmallString<512> CommentBlock;
476 raw_svector_ostream CommentOS(CommentBlock);
477 ScopedPrinter SP(CommentOS);
478 SP.setPrefix(CommentPrefix);
479 CVTD.setPrinter(&SP);
480 Error E = CVTD.dump({Record.bytes_begin(), Record.bytes_end()});
481 if (E) {
482 logAllUnhandledErrors(std::move(E), errs(), "error: ");
483 llvm_unreachable("produced malformed type record");
484 }
485 // emitRawComment will insert its own tab and comment string before
486 // the first line, so strip off our first one. It also prints its own
487 // newline.
488 OS.emitRawComment(
489 CommentOS.str().drop_front(CommentPrefix.size() - 1).rtrim());
490 } else {
470 TypeTable.ForEachRecord([&](TypeIndex Index, ArrayRef Record) {
471 if (OS.isVerboseAsm()) {
472 // Emit a block comment describing the type record for readability.
473 SmallString<512> CommentBlock;
474 raw_svector_ostream CommentOS(CommentBlock);
475 ScopedPrinter SP(CommentOS);
476 SP.setPrefix(CommentPrefix);
477 CVTD.setPrinter(&SP);
478 Error E = CVTD.dump(Record);
479 if (E) {
480 logAllUnhandledErrors(std::move(E), errs(), "error: ");
481 llvm_unreachable("produced malformed type record");
482 }
483 // emitRawComment will insert its own tab and comment string before
484 // the first line, so strip off our first one. It also prints its own
485 // newline.
486 OS.emitRawComment(
487 CommentOS.str().drop_front(CommentPrefix.size() - 1).rtrim());
488 } else {
491489 #ifndef NDEBUG
492 // Assert that the type data is valid even if we aren't dumping
493 // comments. The MSVC linker doesn't do much type record validation,
494 // so the first link of an invalid type record can succeed while
495 // subsequent links will fail with LNK1285.
496 ByteStream Stream({Record.bytes_begin(), Record.bytes_end()});
497 CVTypeArray Types;
498 StreamReader Reader(Stream);
499 Error E = Reader.readArray(Types, Reader.getLength());
500 if (!E) {
501 TypeVisitorCallbacks C;
502 E = CVTypeVisitor(C).visitTypeStream(Types);
503 }
504 if (E) {
505 logAllUnhandledErrors(std::move(E), errs(), "error: ");
506 llvm_unreachable("produced malformed type record");
507 }
490 // Assert that the type data is valid even if we aren't dumping
491 // comments. The MSVC linker doesn't do much type record validation,
492 // so the first link of an invalid type record can succeed while
493 // subsequent links will fail with LNK1285.
494 ByteStream Stream(Record);
495 CVTypeArray Types;
496 StreamReader Reader(Stream);
497 Error E = Reader.readArray(Types, Reader.getLength());
498 if (!E) {
499 TypeVisitorCallbacks C;
500 E = CVTypeVisitor(C).visitTypeStream(Types);
501 }
502 if (E) {
503 logAllUnhandledErrors(std::move(E), errs(), "error: ");
504 llvm_unreachable("produced malformed type record");
505 }
508506 #endif
509 }
510 OS.EmitBinaryData(Record);
511 });
507 }
508 StringRef S(reinterpret_cast(Record.data()), Record.size());
509 OS.EmitBinaryData(S);
510 });
512511 }
513512
514513 namespace {
11941193 (i == 0 && ElementSize == 0) ? Ty->getSizeInBits() / 8 : ElementSize;
11951194
11961195 StringRef Name = (i == 0) ? Ty->getName() : "";
1197 ElementTypeIndex = TypeTable.writeKnownType(
1198 ArrayRecord(ElementTypeIndex, IndexType, ArraySize, Name));
1196 ArrayRecord AR(ElementTypeIndex, IndexType, ArraySize, Name);
1197 ElementTypeIndex = TypeTable.writeKnownType(AR);
11991198 }
12001199
12011200 (void)PartiallyIncomplete;
14201419 BaseTy = cast(BaseTy)->getBaseType().resolve();
14211420 }
14221421 TypeIndex ModifiedTI = getTypeIndex(BaseTy);
1423 return TypeTable.writeKnownType(ModifierRecord(ModifiedTI, Mods));
1422 ModifierRecord MR(ModifiedTI, Mods);
1423 return TypeTable.writeKnownType(MR);
14241424 }
14251425
14261426 TypeIndex CodeViewDebug::lowerTypeFunction(const DISubroutineType *Ty) {
14771477 // TODO: Need to use the correct values for:
14781478 // FunctionOptions
14791479 // ThisPointerAdjustment.
1480 TypeIndex TI = TypeTable.writeKnownType(MemberFunctionRecord(
1481 ReturnTypeIndex, ClassType, ThisTypeIndex, CC, FunctionOptions::None,
1482 ArgTypeIndices.size(), ArgListIndex, ThisAdjustment));
1480 MemberFunctionRecord MFR(ReturnTypeIndex, ClassType, ThisTypeIndex, CC,
1481 FunctionOptions::None, ArgTypeIndices.size(),
1482 ArgListIndex, ThisAdjustment);
1483 TypeIndex TI = TypeTable.writeKnownType(MFR);
14831484
14841485 return TI;
14851486 }
14871488 TypeIndex CodeViewDebug::lowerTypeVFTableShape(const DIDerivedType *Ty) {
14881489 unsigned VSlotCount = Ty->getSizeInBits() / (8 * Asm->MAI->getPointerSize());
14891490 SmallVector Slots(VSlotCount, VFTableSlotKind::Near);
1490 return TypeTable.writeKnownType(VFTableShapeRecord(Slots));
1491
1492 VFTableShapeRecord VFTSR(Slots);
1493 return TypeTable.writeKnownType(VFTSR);
14911494 }
14921495
14931496 static MemberAccess translateAccessFlags(unsigned RecordTag, unsigned Flags) {
15771580 if (Ty->isForwardDecl()) {
15781581 CO |= ClassOptions::ForwardReference;
15791582 } else {
1580 FieldListRecordBuilder Fields;
1583 FieldListRecordBuilder FLRB(TypeTable);
1584
1585 FLRB.begin();
15811586 for (const DINode *Element : Ty->getElements()) {
15821587 // We assume that the frontend provides all members in source declaration
15831588 // order, which is what MSVC does.
15841589 if (auto *Enumerator = dyn_cast_or_null(Element)) {
1585 Fields.writeMemberType(EnumeratorRecord(
1586 MemberAccess::Public, APSInt::getUnsigned(Enumerator->getValue()),
1587 Enumerator->getName()));
1590 EnumeratorRecord ER(MemberAccess::Public,
1591 APSInt::getUnsigned(Enumerator->getValue()),
1592 Enumerator->getName());
1593 FLRB.writeMemberType(ER);
15881594 EnumeratorCount++;
15891595 }
15901596 }
1591 FTI = TypeTable.writeFieldList(Fields);
1597 FTI = FLRB.end();
15921598 }
15931599
15941600 std::string FullName = getFullyQualifiedName(Ty);
15951601
1596 return TypeTable.writeKnownType(EnumRecord(EnumeratorCount, CO, FTI, FullName,
1597 Ty->getIdentifier(),
1598 getTypeIndex(Ty->getBaseType())));
1602 EnumRecord ER(EnumeratorCount, CO, FTI, FullName, Ty->getIdentifier(),
1603 getTypeIndex(Ty->getBaseType()));
1604 return TypeTable.writeKnownType(ER);
15991605 }
16001606
16011607 //===----------------------------------------------------------------------===//
16941700 ClassOptions CO =
16951701 ClassOptions::ForwardReference | getCommonClassOptions(Ty);
16961702 std::string FullName = getFullyQualifiedName(Ty);
1697 TypeIndex FwdDeclTI = TypeTable.writeKnownType(
1698 ClassRecord(Kind, 0, CO, TypeIndex(), TypeIndex(), TypeIndex(), 0,
1699 FullName, Ty->getIdentifier()));
1703 ClassRecord CR(Kind, 0, CO, TypeIndex(), TypeIndex(), TypeIndex(), 0,
1704 FullName, Ty->getIdentifier());
1705 TypeIndex FwdDeclTI = TypeTable.writeKnownType(CR);
17001706 if (!Ty->isForwardDecl())
17011707 DeferredCompleteTypes.push_back(Ty);
17021708 return FwdDeclTI;
17201726
17211727 uint64_t SizeInBytes = Ty->getSizeInBits() / 8;
17221728
1723 TypeIndex ClassTI = TypeTable.writeKnownType(
1724 ClassRecord(Kind, FieldCount, CO, FieldTI, TypeIndex(), VShapeTI,
1725 SizeInBytes, FullName, Ty->getIdentifier()));
1726
1727 TypeTable.writeKnownType(UdtSourceLineRecord(
1728 ClassTI, TypeTable.writeKnownType(StringIdRecord(
1729 TypeIndex(0x0), getFullFilepath(Ty->getFile()))),
1730 Ty->getLine()));
1729 ClassRecord CR(Kind, FieldCount, CO, FieldTI, TypeIndex(), VShapeTI,
1730 SizeInBytes, FullName, Ty->getIdentifier());
1731 TypeIndex ClassTI = TypeTable.writeKnownType(CR);
1732
1733 StringIdRecord SIDR(TypeIndex(0x0), getFullFilepath(Ty->getFile()));
1734 TypeIndex SIDI = TypeTable.writeKnownType(SIDR);
1735 UdtSourceLineRecord USLR(ClassTI, SIDI, Ty->getLine());
1736 TypeTable.writeKnownType(USLR);
17311737
17321738 addToUDTs(Ty, ClassTI);
17331739
17381744 ClassOptions CO =
17391745 ClassOptions::ForwardReference | getCommonClassOptions(Ty);
17401746 std::string FullName = getFullyQualifiedName(Ty);
1741 TypeIndex FwdDeclTI = TypeTable.writeKnownType(
1742 UnionRecord(0, CO, TypeIndex(), 0, FullName, Ty->getIdentifier()));
1747 UnionRecord UR(0, CO, TypeIndex(), 0, FullName, Ty->getIdentifier());
1748 TypeIndex FwdDeclTI = TypeTable.writeKnownType(UR);
17431749 if (!Ty->isForwardDecl())
17441750 DeferredCompleteTypes.push_back(Ty);
17451751 return FwdDeclTI;
17591765 uint64_t SizeInBytes = Ty->getSizeInBits() / 8;
17601766 std::string FullName = getFullyQualifiedName(Ty);
17611767
1762 TypeIndex UnionTI = TypeTable.writeKnownType(UnionRecord(
1763 FieldCount, CO, FieldTI, SizeInBytes, FullName, Ty->getIdentifier()));
1764
1765 TypeTable.writeKnownType(UdtSourceLineRecord(
1766 UnionTI, TypeTable.writeKnownType(StringIdRecord(
1767 TypeIndex(0x0), getFullFilepath(Ty->getFile()))),
1768 Ty->getLine()));
1768 UnionRecord UR(FieldCount, CO, FieldTI, SizeInBytes, FullName,
1769 Ty->getIdentifier());
1770 TypeIndex UnionTI = TypeTable.writeKnownType(UR);
1771
1772 StringIdRecord SIR(TypeIndex(0x0), getFullFilepath(Ty->getFile()));
1773 TypeIndex SIRI = TypeTable.writeKnownType(SIR);
1774 UdtSourceLineRecord USLR(UnionTI, SIRI, Ty->getLine());
1775 TypeTable.writeKnownType(USLR);
17691776
17701777 addToUDTs(Ty, UnionTI);
17711778
17801787 // list record.
17811788 unsigned MemberCount = 0;
17821789 ClassInfo Info = collectClassInfo(Ty);
1783 FieldListRecordBuilder Fields;
1790 FieldListRecordBuilder FLBR(TypeTable);
1791 FLBR.begin();
17841792
17851793 // Create base classes.
17861794 for (const DIDerivedType *I : Info.Inheritance) {
17931801 auto RecordKind = (I->getFlags() & DINode::FlagIndirectVirtualBase) == DINode::FlagIndirectVirtualBase
17941802 ? TypeRecordKind::IndirectVirtualBaseClass
17951803 : TypeRecordKind::VirtualBaseClass;
1796 Fields.writeMemberType(VirtualBaseClassRecord(
1804 VirtualBaseClassRecord VBCR(
17971805 RecordKind, translateAccessFlags(Ty->getTag(), I->getFlags()),
17981806 getTypeIndex(I->getBaseType()), getVBPTypeIndex(), VBPtrOffset,
1799 VBTableIndex));
1807 VBTableIndex);
1808
1809 FLBR.writeMemberType(VBCR);
18001810 } else {
18011811 assert(I->getOffsetInBits() % 8 == 0 &&
18021812 "bases must be on byte boundaries");
1803 Fields.writeMemberType(BaseClassRecord(
1804 translateAccessFlags(Ty->getTag(), I->getFlags()),
1805 getTypeIndex(I->getBaseType()), I->getOffsetInBits() / 8));
1813 BaseClassRecord BCR(translateAccessFlags(Ty->getTag(), I->getFlags()),
1814 getTypeIndex(I->getBaseType()),
1815 I->getOffsetInBits() / 8);
1816 FLBR.writeMemberType(BCR);
18061817 }
18071818 }
18081819
18151826 translateAccessFlags(Ty->getTag(), Member->getFlags());
18161827
18171828 if (Member->isStaticMember()) {
1818 Fields.writeMemberType(
1819 StaticDataMemberRecord(Access, MemberBaseType, MemberName));
1829 StaticDataMemberRecord SDMR(Access, MemberBaseType, MemberName);
1830 FLBR.writeMemberType(SDMR);
18201831 MemberCount++;
18211832 continue;
18221833 }
18241835 // Virtual function pointer member.
18251836 if ((Member->getFlags() & DINode::FlagArtificial) &&
18261837 Member->getName().startswith("_vptr$")) {
1827 Fields.writeMemberType(VFPtrRecord(getTypeIndex(Member->getBaseType())));
1838 VFPtrRecord VFPR(getTypeIndex(Member->getBaseType()));
1839 FLBR.writeMemberType(VFPR);
18281840 MemberCount++;
18291841 continue;
18301842 }
18391851 MemberOffsetInBits = CI->getZExtValue() + MemberInfo.BaseOffset;
18401852 }
18411853 StartBitOffset -= MemberOffsetInBits;
1842 MemberBaseType = TypeTable.writeKnownType(BitFieldRecord(
1843 MemberBaseType, Member->getSizeInBits(), StartBitOffset));
1854 BitFieldRecord BFR(MemberBaseType, Member->getSizeInBits(),
1855 StartBitOffset);
1856 MemberBaseType = TypeTable.writeKnownType(BFR);
18441857 }
18451858 uint64_t MemberOffsetInBytes = MemberOffsetInBits / 8;
1846 Fields.writeMemberType(DataMemberRecord(Access, MemberBaseType,
1847 MemberOffsetInBytes, MemberName));
1859 DataMemberRecord DMR(Access, MemberBaseType, MemberOffsetInBytes,
1860 MemberName);
1861 FLBR.writeMemberType(DMR);
18481862 MemberCount++;
18491863 }
18501864
18691883 }
18701884 assert(Methods.size() > 0 && "Empty methods map entry");
18711885 if (Methods.size() == 1)
1872 Fields.writeMemberType(Methods[0]);
1886 FLBR.writeMemberType(Methods[0]);
18731887 else {
1874 TypeIndex MethodList =
1875 TypeTable.writeKnownType(MethodOverloadListRecord(Methods));
1876 Fields.writeMemberType(
1877 OverloadedMethodRecord(Methods.size(), MethodList, Name));
1888 MethodOverloadListRecord MOLR(Methods);
1889 TypeIndex MethodList = TypeTable.writeKnownType(MOLR);
1890 OverloadedMethodRecord OMR(Methods.size(), MethodList, Name);
1891 FLBR.writeMemberType(OMR);
18781892 }
18791893 }
18801894
18811895 // Create nested classes.
18821896 for (const DICompositeType *Nested : Info.NestedClasses) {
18831897 NestedTypeRecord R(getTypeIndex(DITypeRef(Nested)), Nested->getName());
1884 Fields.writeMemberType(R);
1898 FLBR.writeMemberType(R);
18851899 MemberCount++;
18861900 }
18871901
1888 TypeIndex FieldTI = TypeTable.writeFieldList(Fields);
1902 TypeIndex FieldTI = FLBR.end();
18891903 return std::make_tuple(FieldTI, Info.VShapeTI, MemberCount,
18901904 !Info.NestedClasses.empty());
18911905 }
1919 #include "llvm/CodeGen/AsmPrinter.h"
2020 #include "llvm/CodeGen/MachineFunction.h"
2121 #include "llvm/CodeGen/MachineModuleInfo.h"
22 #include "llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h"
2322 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
23 #include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
2424 #include "llvm/IR/DebugInfo.h"
2525 #include "llvm/IR/DebugLoc.h"
2626 #include "llvm/MC/MCStreamer.h"
3636 class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase {
3737 MCStreamer &OS;
3838 llvm::BumpPtrAllocator Allocator;
39 codeview::MemoryTypeTableBuilder TypeTable;
39 codeview::TypeTableBuilder TypeTable;
4040
4141 /// Represents the most general definition range.
4242 struct LocalVarDefRange {
33 CVSymbolVisitor.cpp
44 CVTypeVisitor.cpp
55 EnumTables.cpp
6 FieldListRecordBuilder.cpp
76 Line.cpp
8 ListRecordBuilder.cpp
9 MemoryTypeTableBuilder.cpp
10 MethodListRecordBuilder.cpp
117 ModuleSubstream.cpp
128 ModuleSubstreamVisitor.cpp
139 RecordSerialization.cpp
1410 SymbolDumper.cpp
1511 TypeDumper.cpp
1612 TypeRecord.cpp
17 TypeRecordBuilder.cpp
1813 TypeRecordMapping.cpp
14 TypeSerializer.cpp
1915 TypeStreamMerger.cpp
20 TypeTableBuilder.cpp
2116
2217 ADDITIONAL_HEADER_DIRS
2318 ${LLVM_MAIN_INCLUDE_DIR}/llvm/DebugInfo/CodeView
1515
1616 using namespace llvm;
1717 using namespace llvm::codeview;
18
19 template
20 static Expected
21 deserializeMemberRecord(FieldListDeserializer &Deserializer,
22 msf::StreamReader &Reader, TypeLeafKind Kind) {
23 T MR(static_cast(Kind));
24 CVMemberRecord CVR;
25 CVR.Kind = Kind;
26
27 if (auto EC = Deserializer.visitMemberBegin(CVR))
28 return std::move(EC);
29 if (auto EC = Deserializer.visitKnownMember(CVR, MR))
30 return std::move(EC);
31 if (auto EC = Deserializer.visitMemberEnd(CVR))
32 return std::move(EC);
33
34 return CVR;
35 }
3618
3719 CVTypeVisitor::CVTypeVisitor(TypeVisitorCallbacks &Callbacks)
3820 : Callbacks(Callbacks) {}
8466 return Error::success();
8567 }
8668
87 Error CVTypeVisitor::visitMemberRecord(CVMemberRecord &Record) {
69 static Error visitMemberRecord(CVMemberRecord &Record,
70 TypeVisitorCallbacks &Callbacks) {
8871 if (auto EC = Callbacks.visitMemberBegin(Record))
8972 return EC;
9073
11295 return Error::success();
11396 }
11497
98 Error CVTypeVisitor::visitMemberRecord(CVMemberRecord &Record) {
99 return ::visitMemberRecord(Record, Callbacks);
100 }
101
115102 /// Visits the type records in Data. Sets the error flag on parse failures.
116103 Error CVTypeVisitor::visitTypeStream(const CVTypeArray &Types) {
117104 for (auto I : Types) {
118105 if (auto EC = visitTypeRecord(I))
119106 return EC;
120107 }
121 return Error::success();
122 }
123
124 template
125 static Error visitKnownMember(FieldListDeserializer &Deserializer,
126 msf::StreamReader &Reader, TypeLeafKind Leaf,
127 TypeVisitorCallbacks &Callbacks) {
128 MR Record(static_cast(Leaf));
129 CVMemberRecord CVR;
130 CVR.Kind = Leaf;
131
132 if (auto EC = Callbacks.visitMemberBegin(CVR))
133 return EC;
134 if (auto EC = Callbacks.visitKnownMember(CVR, Record))
135 return EC;
136 if (auto EC = Callbacks.visitMemberEnd(CVR))
137 return EC;
138108 return Error::success();
139109 }
140110
149119 if (auto EC = Reader.readEnum(Leaf))
150120 return EC;
151121
152 CVType Record;
153 switch (Leaf) {
154 default:
155 // Field list records do not describe their own length, so we cannot
156 // continue parsing past a type that we don't know how to deserialize.
157 return llvm::make_error(
158 cv_error_code::unknown_member_record);
159 #define MEMBER_RECORD(EnumName, EnumVal, Name) \
160 case EnumName: { \
161 if (auto EC = visitKnownMember(Deserializer, Reader, Leaf, \
162 Pipeline)) \
163 return EC; \
164 break; \
122 CVMemberRecord Record;
123 Record.Kind = Leaf;
124 if (auto EC = ::visitMemberRecord(Record, Pipeline))
125 return EC;
165126 }
166 #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \
167 MEMBER_RECORD(EnumVal, EnumVal, AliasName)
168 #include "llvm/DebugInfo/CodeView/TypeRecords.def"
169 }
170 }
127
171128 return Error::success();
172129 }
173130
1515 using namespace llvm;
1616 using namespace llvm::codeview;
1717
18 Error CodeViewRecordIO::beginRecord(uint16_t Kind) {
19 assert(!CurrentRecord.hasValue() && "There is already a record active!");
20 CurrentRecord.emplace();
21
22 CurrentRecord->Kind = Kind;
18 Error CodeViewRecordIO::beginRecord(Optional MaxLength) {
19 RecordLimit Limit;
20 Limit.MaxLength = MaxLength;
21 Limit.BeginOffset = getCurrentOffset();
22 Limits.push_back(Limit);
2323 return Error::success();
2424 }
2525
2626 Error CodeViewRecordIO::endRecord() {
27 assert(CurrentRecord.hasValue() && "Not in a record!");
28 CurrentRecord.reset();
29 return Error::success();
27 assert(!Limits.empty() && "Not in a record!");
28 Limits.pop_back();
29 return Error::success();
30 }
31
32 uint32_t CodeViewRecordIO::maxFieldLength() const {
33 assert(!Limits.empty() && "Not in a record!");
34
35 // The max length of the next field is the minimum of all lengths that would
36 // be allowed by any of the sub-records we're in. In practice, we can only
37 // ever be at most 1 sub-record deep (in a FieldList), but this works for
38 // the general case.
39 uint32_t Offset = getCurrentOffset();
40 Optional Min = Limits.front().bytesRemaining(Offset);
41 for (auto X : makeArrayRef(Limits).drop_front()) {
42 Optional ThisMin = X.bytesRemaining(Offset);
43 if (ThisMin.hasValue())
44 Min = (Min.hasValue()) ? std::min(*Min, *ThisMin) : *ThisMin;
45 }
46 assert(Min.hasValue() && "Every field must have a maximum length!");
47
48 return *Min;
3049 }
3150
3251 Error CodeViewRecordIO::skipPadding() {
113132
114133 Error CodeViewRecordIO::mapStringZ(StringRef &Value) {
115134 if (isWriting()) {
116 if (auto EC = Writer->writeZeroString(Value))
135 // Truncate if we attempt to write too much.
136 StringRef S = Value.take_front(maxFieldLength() - 1);
137 if (auto EC = Writer->writeZeroString(S))
117138 return EC;
118139 } else {
119140 if (auto EC = Reader->readZeroString(Value))
123144 }
124145
125146 Error CodeViewRecordIO::mapGuid(StringRef &Guid) {
147 constexpr uint32_t GuidSize = 16;
148 if (maxFieldLength() < GuidSize)
149 return make_error(cv_error_code::insufficient_buffer);
150
126151 if (isWriting()) {
127152 assert(Guid.size() == 16 && "Invalid Guid Size!");
128153 if (auto EC = Writer->writeFixedString(Guid))
+0
-132
lib/DebugInfo/CodeView/FieldListRecordBuilder.cpp less more
None //===-- FieldListRecordBuilder.cpp ----------------------------------------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm/DebugInfo/CodeView/FieldListRecordBuilder.h"
10
11 using namespace llvm;
12 using namespace codeview;
13
14 FieldListRecordBuilder::FieldListRecordBuilder()
15 : ListRecordBuilder(TypeRecordKind::FieldList) {}
16
17 void FieldListRecordBuilder::writeMemberType(const BaseClassRecord &Record) {
18 TypeRecordBuilder &Builder = getBuilder();
19
20 Builder.writeTypeRecordKind(TypeRecordKind::BaseClass);
21 Builder.writeUInt16(static_cast(Record.getAccess()));
22 Builder.writeTypeIndex(Record.getBaseType());
23 Builder.writeEncodedUnsignedInteger(Record.getBaseOffset());
24
25 finishSubRecord();
26 }
27
28 void FieldListRecordBuilder::writeMemberType(const EnumeratorRecord &Record) {
29 TypeRecordBuilder &Builder = getBuilder();
30
31 Builder.writeTypeRecordKind(TypeRecordKind::Enumerator);
32 Builder.writeUInt16(static_cast(Record.getAccess()));
33 // FIXME: Handle full APInt such as __int128.
34 Builder.writeEncodedUnsignedInteger(Record.getValue().getZExtValue());
35 Builder.writeNullTerminatedString(Record.getName());
36
37 finishSubRecord();
38 }
39
40 void FieldListRecordBuilder::writeMemberType(const DataMemberRecord &Record) {
41 TypeRecordBuilder &Builder = getBuilder();
42
43 Builder.writeTypeRecordKind(Record.getKind());
44 Builder.writeUInt16(static_cast(Record.getAccess()));
45 Builder.writeTypeIndex(Record.getType());
46 Builder.writeEncodedUnsignedInteger(Record.getFieldOffset());
47 Builder.writeNullTerminatedString(Record.getName());
48
49 finishSubRecord();
50 }
51
52 void FieldListRecordBuilder::writeMemberType(
53 const OverloadedMethodRecord &Record) {
54 TypeRecordBuilder &Builder = getBuilder();
55
56 Builder.writeTypeRecordKind(TypeRecordKind::OverloadedMethod);
57 Builder.writeUInt16(Record.getNumOverloads());
58 Builder.writeTypeIndex(Record.getMethodList());
59 Builder.writeNullTerminatedString(Record.getName());
60
61 finishSubRecord();
62 }
63
64 void FieldListRecordBuilder::writeMemberType(const OneMethodRecord &Record) {
65 TypeRecordBuilder &Builder = getBuilder();
66
67 uint16_t Flags = static_cast(Record.getAccess());
68 Flags |= static_cast(Record.getKind()) << MethodKindShift;
69 Flags |= static_cast(Record.getOptions());
70
71 Builder.writeTypeRecordKind(TypeRecordKind::OneMethod);
72 Builder.writeUInt16(Flags);
73 Builder.writeTypeIndex(Record.getType());
74 if (Record.isIntroducingVirtual()) {
75 assert(Record.getVFTableOffset() >= 0);
76 Builder.writeInt32(Record.getVFTableOffset());
77 } else {
78 assert(Record.getVFTableOffset() == -1);
79 }
80
81 Builder.writeNullTerminatedString(Record.getName());
82
83 finishSubRecord();
84 }
85
86 void FieldListRecordBuilder::writeMemberType(const NestedTypeRecord &Record) {
87 TypeRecordBuilder &Builder = getBuilder();
88
89 Builder.writeTypeRecordKind(Record.getKind());
90 Builder.writeUInt16(0);
91 Builder.writeTypeIndex(Record.getNestedType());
92 Builder.writeNullTerminatedString(Record.getName());
93
94 finishSubRecord();
95 }
96
97 void FieldListRecordBuilder::writeMemberType(
98 const StaticDataMemberRecord &Record) {
99 TypeRecordBuilder &Builder = getBuilder();
100
101 Builder.writeTypeRecordKind(Record.getKind());
102 Builder.writeUInt16(static_cast(Record.getAccess()));
103 Builder.writeTypeIndex(Record.getType());
104 Builder.writeNullTerminatedString(Record.getName());
105
106 finishSubRecord();
107 }
108
109 void FieldListRecordBuilder::writeMemberType(
110 const VirtualBaseClassRecord &Record) {
111 TypeRecordBuilder &Builder = getBuilder();
112
113 Builder.writeTypeRecordKind(Record.getKind());
114 Builder.writeUInt16(static_cast(Record.getAccess()));
115 Builder.writeTypeIndex(Record.getBaseType());
116 Builder.writeTypeIndex(Record.getVBPtrType());
117 Builder.writeEncodedInteger(Record.getVBPtrOffset());
118 Builder.writeEncodedUnsignedInteger(Record.getVTableIndex());
119
120 finishSubRecord();
121 }
122
123 void FieldListRecordBuilder::writeMemberType(const VFPtrRecord &Record) {
124 TypeRecordBuilder &Builder = getBuilder();
125
126 Builder.writeTypeRecordKind(TypeRecordKind::VFPtr);
127 Builder.writeUInt16(0);
128 Builder.writeTypeIndex(Record.getType());
129
130 finishSubRecord();
131 }
+0
-103
lib/DebugInfo/CodeView/ListRecordBuilder.cpp less more
None //===-- ListRecordBuilder.cpp ---------------------------------------------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm/ADT/SmallString.h"
10 #include "llvm/DebugInfo/CodeView/ListRecordBuilder.h"
11 #include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
12
13 using namespace llvm;
14 using namespace codeview;
15
16 ListRecordBuilder::ListRecordBuilder(TypeRecordKind Kind)
17 : Kind(Kind), Builder(Kind) {}
18
19 void ListRecordBuilder::writeMemberType(const ListContinuationRecord &R) {
20 TypeRecordBuilder &Builder = getBuilder();
21
22 assert(getLastContinuationSize() < MaxRecordLength - 8 && "continuation won't fit");
23
24 Builder.writeTypeRecordKind(TypeRecordKind::ListContinuation);
25 Builder.writeUInt16(0);
26 Builder.writeTypeIndex(R.getContinuationIndex());
27
28 // End the current segment manually so that nothing comes after the
29 // continuation.
30 ContinuationOffsets.push_back(Builder.size());
31 SubrecordStart = Builder.size();
32 }
33
34 void ListRecordBuilder::finishSubRecord() {
35 // The type table inserts a 16 bit size field before each list, so factor that
36 // into our alignment padding.
37 uint32_t Remainder =
38 (Builder.size() + 2 * (ContinuationOffsets.size() + 1)) % 4;
39 if (Remainder != 0) {
40 for (int32_t PaddingBytesLeft = 4 - Remainder; PaddingBytesLeft > 0;
41 --PaddingBytesLeft) {
42 Builder.writeUInt8(LF_PAD0 + PaddingBytesLeft);
43 }
44 }
45
46 // Check if this subrecord makes the current segment not fit in 64K minus the
47 // space for a continuation record (8 bytes). If the segment does not fit,
48 // back up and insert a continuation record, sliding the current subrecord
49 // down.
50 if (getLastContinuationSize() > MaxRecordLength - 8) {
51 assert(SubrecordStart != 0 && "can't slide from the start!");
52 SmallString<128> SubrecordCopy(
53 Builder.str().slice(SubrecordStart, Builder.size()));
54 assert(SubrecordCopy.size() < MaxRecordLength - 8 &&
55 "subrecord is too large to slide!");
56 Builder.truncate(SubrecordStart);
57
58 // Write a placeholder continuation record.
59 Builder.writeTypeRecordKind(TypeRecordKind::ListContinuation);
60 Builder.writeUInt16(0);
61 Builder.writeUInt32(0);
62 ContinuationOffsets.push_back(Builder.size());
63 assert(Builder.size() == SubrecordStart + 8 && "wrong continuation size");
64 assert(getLastContinuationSize() < MaxRecordLength && "segment too big");
65
66 // Start a new list record of the appropriate kind, and copy the previous
67 // subrecord into place.
68 Builder.writeTypeRecordKind(Kind);
69 Builder.writeBytes(SubrecordCopy);
70 }
71
72 SubrecordStart = Builder.size();
73 }
74
75 TypeIndex ListRecordBuilder::writeListRecord(TypeTableBuilder &Table) {
76 // Get the continuation segments as a reversed vector of StringRefs for
77 // convenience.
78 SmallVector Segments;
79 StringRef Data = str();
80 size_t LastEnd = 0;
81 for (size_t SegEnd : ContinuationOffsets) {
82 Segments.push_back(Data.slice(LastEnd, SegEnd));
83 LastEnd = SegEnd;
84 }
85 Segments.push_back(Data.slice(LastEnd, Builder.size()));
86
87 // Pop the last record off and emit it directly.
88 StringRef LastRec = Segments.pop_back_val();
89 TypeIndex ContinuationIndex = Table.writeRecord(LastRec);
90
91 // Emit each record with a continuation in reverse order, so that each one
92 // references the previous record.
93 for (StringRef Rec : reverse(Segments)) {
94 assert(*reinterpret_cast(Rec.data()) ==
95 unsigned(Kind));
96 ulittle32_t *ContinuationPtr =
97 reinterpret_cast(const_cast(Rec.end())) - 1;
98 *ContinuationPtr = ContinuationIndex.getIndex();
99 ContinuationIndex = Table.writeRecord(Rec);
100 }
101 return ContinuationIndex;
102 }
+0
-46
lib/DebugInfo/CodeView/MemoryTypeTableBuilder.cpp less more
None //===-- MemoryTypeTableBuilder.cpp ----------------------------------------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h"
10 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
11
12 using namespace llvm;
13 using namespace codeview;
14
15 TypeIndex MemoryTypeTableBuilder::writeRecord(StringRef Data) {
16 assert(Data.size() <= UINT16_MAX);
17 auto I = HashedRecords.find(Data);
18 if (I != HashedRecords.end()) {
19 return I->second;
20 }
21
22 // The record provided by the user lacks the 2 byte size field prefix and is
23 // not padded to 4 bytes. Ultimately, that is what gets emitted in the object
24 // file, so pad it out now.
25 const int SizeOfRecLen = 2;
26 const int Align = 4;
27 int TotalSize = alignTo(Data.size() + SizeOfRecLen, Align);
28 assert(TotalSize - SizeOfRecLen <= UINT16_MAX);
29 char *Mem =
30 reinterpret_cast(RecordStorage.Allocate(TotalSize, Align));
31 *reinterpret_cast(Mem) = uint16_t(TotalSize - SizeOfRecLen);
32 memcpy(Mem + SizeOfRecLen, Data.data(), Data.size());
33 for (int I = Data.size() + SizeOfRecLen; I < TotalSize; ++I)
34 Mem[I] = LF_PAD0 + (TotalSize - I);
35
36 TypeIndex TI(static_cast(Records.size()) +
37 TypeIndex::FirstNonSimpleIndex);
38
39 // Use only the data supplied by the user as a key to the hash table, so that
40 // future lookups will succeed.
41 HashedRecords.insert(std::make_pair(StringRef(Mem + SizeOfRecLen, Data.size()), TI));
42 Records.push_back(StringRef(Mem, TotalSize));
43
44 return TI;
45 }
+0
-49
lib/DebugInfo/CodeView/MethodListRecordBuilder.cpp less more
None //===-- MethodListRecordBuilder.cpp ---------------------------------------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm/DebugInfo/CodeView/MethodListRecordBuilder.h"
10 #include "llvm/DebugInfo/CodeView/FieldListRecordBuilder.h"
11
12 using namespace llvm;
13 using namespace codeview;
14
15 MethodListRecordBuilder::MethodListRecordBuilder()
16 : ListRecordBuilder(TypeRecordKind::MethodOverloadList) {}
17
18 void MethodListRecordBuilder::writeMethod(MemberAccess Access, MethodKind Kind,
19 MethodOptions Options, TypeIndex Type,
20 int32_t VTableSlotOffset) {
21 TypeRecordBuilder &Builder = getBuilder();
22
23 uint16_t Flags = static_cast(Access);
24 Flags |= static_cast(Kind) << MethodKindShift;
25 Flags |= static_cast(Options);
26
27 Builder.writeUInt16(Flags);
28 Builder.writeUInt16(0);
29 Builder.writeTypeIndex(Type);
30 switch (Kind) {
31 case MethodKind::IntroducingVirtual:
32 case MethodKind::PureIntroducingVirtual:
33 assert(VTableSlotOffset >= 0);
34 Builder.writeInt32(VTableSlotOffset);
35 break;
36
37 default:
38 assert(VTableSlotOffset == -1);
39 break;
40 }
41
42 // TODO: Fail if too big?
43 }
44
45 void MethodListRecordBuilder::writeMethod(const MethodInfo &Method) {
46 writeMethod(Method.getAccess(), Method.getKind(), Method.getOptions(),
47 Method.getType(), Method.getVTableSlotOffset());
48 }
427427 MethodOverloadListRecord &MethodList) {
428428 for (auto &M : MethodList.getMethods()) {
429429 ListScope S(*W, "Method");
430 printMemberAttributes(M.getAccess(), M.getKind(), M.getOptions());
430 printMemberAttributes(M.getAccess(), M.getMethodKind(), M.getOptions());
431431 printTypeIndex("Type", M.getType());
432432 if (M.isIntroducingVirtual())
433433 W->printHex("VFTableOffset", M.getVFTableOffset());
606606
607607 Error CVTypeDumper::visitKnownMember(CVMemberRecord &CVR,
608608 OneMethodRecord &Method) {
609 MethodKind K = Method.getKind();
609 MethodKind K = Method.getMethodKind();
610610 printMemberAttributes(Method.getAccess(), K, Method.getOptions());
611611 printTypeIndex("Type", Method.getType());
612612 // If virtual, then read the vftable offset.
+0
-119
lib/DebugInfo/CodeView/TypeRecordBuilder.cpp less more
None //===-- TypeRecordBuilder.cpp ---------------------------------------------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm/DebugInfo/CodeView/TypeRecordBuilder.h"
10
11 using namespace llvm;
12 using namespace codeview;
13
14 TypeRecordBuilder::TypeRecordBuilder(TypeRecordKind Kind)
15 : Kind(Kind), Stream(Buffer), Writer(Stream) {
16 writeTypeRecordKind(Kind);
17 }
18
19 StringRef TypeRecordBuilder::str() {
20 return StringRef(Buffer.data(), Buffer.size());
21 }
22
23 void TypeRecordBuilder::writeUInt8(uint8_t Value) {
24 Writer.write(Value);
25 }
26
27 void TypeRecordBuilder::writeInt16(int16_t Value) {
28 Writer.write(Value);
29 }
30
31 void TypeRecordBuilder::writeUInt16(uint16_t Value) {
32 Writer.write(Value);
33 }
34
35 void TypeRecordBuilder::writeInt32(int32_t Value) {
36 Writer.write(Value);
37 }
38
39 void TypeRecordBuilder::writeUInt32(uint32_t Value) {
40 Writer.write(Value);
41 }
42
43 void TypeRecordBuilder::writeInt64(int64_t Value) {
44 Writer.write(Value);
45 }
46
47 void TypeRecordBuilder::writeUInt64(uint64_t Value) {
48 Writer.write(Value);
49 }
50
51 void TypeRecordBuilder::writeEncodedInteger(int64_t Value) {
52 if (Value >= 0) {
53 writeEncodedUnsignedInteger(static_cast(Value));
54 } else {
55 writeEncodedSignedInteger(Value);
56 }
57 }
58
59 void TypeRecordBuilder::writeEncodedSignedInteger(int64_t Value) {
60 if (Value >= std::numeric_limits::min() &&
61 Value <= std::numeric_limits::max()) {
62 writeUInt16(LF_CHAR);
63 writeInt16(static_cast(Value));
64 } else if (Value >= std::numeric_limits::min() &&
65 Value <= std::numeric_limits::max()) {
66 writeUInt16(LF_SHORT);
67 writeInt16(static_cast(Value));
68 } else if (Value >= std::numeric_limits::min() &&
69 Value <= std::numeric_limits::max()) {
70 writeUInt16(LF_LONG);
71 writeInt32(static_cast(Value));
72 } else {
73 writeUInt16(LF_QUADWORD);
74 writeInt64(Value);
75 }
76 }
77
78 void TypeRecordBuilder::writeEncodedUnsignedInteger(uint64_t Value) {
79 if (Value < LF_CHAR) {
80 writeUInt16(static_cast(Value));
81 } else if (Value <= std::numeric_limits::max()) {
82 writeUInt16(LF_USHORT);
83 writeUInt16(static_cast(Value));
84 } else if (Value <= std::numeric_limits::max()) {
85 writeUInt16(LF_ULONG);
86 writeUInt32(static_cast(Value));
87 } else {
88 writeUInt16(LF_UQUADWORD);
89 writeUInt64(Value);
90 }
91 }
92
93 void TypeRecordBuilder::writeNullTerminatedString(StringRef Value) {
94 // Usually the null terminated string comes last, so truncate it to avoid a
95 // record larger than MaxNameLength. Don't do this if this is a list record.
96 // Those have special handling to split the record.
97 unsigned MaxNameLength = MaxRecordLength;
98 if (Kind != TypeRecordKind::FieldList &&
99 Kind != TypeRecordKind::MethodOverloadList)
100 MaxNameLength = maxBytesRemaining();
101 assert(MaxNameLength > 0 && "need room for null terminator");
102 Value = Value.take_front(MaxNameLength - 1);
103 Stream.write(Value.data(), Value.size());
104 writeUInt8(0);
105 }
106
107 void TypeRecordBuilder::writeGuid(StringRef Guid) {
108 assert(Guid.size() == 16);
109 Stream.write(Guid.data(), 16);
110 }
111
112 void TypeRecordBuilder::writeTypeIndex(TypeIndex TypeInd) {
113 writeUInt32(TypeInd.getIndex());
114 }
115
116 void TypeRecordBuilder::writeTypeRecordKind(TypeRecordKind Kind) {
117 writeUInt16(static_cast(Kind));
118 }
1616 return EC;
1717
1818 namespace {
19 struct MapStringZ {
20 Error operator()(CodeViewRecordIO &IO, StringRef &S) const {
21 return IO.mapStringZ(S);
22 }
23 };
24
25 struct MapInteger {
26 template Error operator()(CodeViewRecordIO &IO, T &N) const {
27 return IO.mapInteger(N);
28 }
29 };
30
31 struct MapEnum {
32 template Error operator()(CodeViewRecordIO &IO, T &N) const {
33 return IO.mapEnum(N);
34 }
35 };
36
3719 struct MapOneMethodRecord {
3820 explicit MapOneMethodRecord(bool IsFromOverloadList)
3921 : IsFromOverloadList(IsFromOverloadList) {}
6345
6446 static Error mapNameAndUniqueName(CodeViewRecordIO &IO, StringRef &Name,
6547 StringRef &UniqueName, bool HasUniqueName) {
66 error(IO.mapStringZ(Name));
67 if (HasUniqueName)
68 error(IO.mapStringZ(UniqueName));
48 if (IO.isWriting()) {
49 // Try to be smart about what we write here. We can't write anything too
50 // large, so if we're going to go over the limit, truncate both the name
51 // and unique name by the same amount.
52 uint32_t BytesLeft = IO.maxFieldLength();
53 if (HasUniqueName) {
54 uint32_t BytesNeeded = Name.size() + UniqueName.size() + 2;
55 StringRef N = Name;
56 StringRef U = UniqueName;
57 if (BytesNeeded > BytesLeft) {
58 uint32_t BytesToDrop = (BytesNeeded - BytesLeft);
59 uint32_t DropN = std::min(N.size(), BytesToDrop / 2);
60 uint32_t DropU = std::min(U.size(), BytesToDrop - DropN);
61
62 N = N.drop_back(DropN);
63 U = U.drop_back(DropU);
64 }
65
66 error(IO.mapStringZ(N));
67 error(IO.mapStringZ(U));
68 } else {
69 uint32_t BytesNeeded = Name.size() + 1;
70 StringRef N = Name;
71 if (BytesNeeded > BytesLeft) {
72 uint32_t BytesToDrop = std::min(N.size(), BytesToDrop);
73 N = N.drop_back(BytesToDrop);
74 }
75 error(IO.mapStringZ(N));
76 }
77 } else {
78 error(IO.mapStringZ(Name));
79 if (HasUniqueName)
80 error(IO.mapStringZ(UniqueName));
81 }
6982
7083 return Error::success();
7184 }
7285
7386 Error TypeRecordMapping::visitTypeBegin(CVType &CVR) {
74 error(IO.beginRecord(CVR.Type));
87 assert(!TypeKind.hasValue() && "Already in a type mapping!");
88 assert(!MemberKind.hasValue() && "Already in a member mapping!");
89
90 // FieldList and MethodList records can be any length because they can be
91 // split with continuation records. All other record types cannot be
92 // longer than the maximum record length.
93 Optional MaxLen;
94 if (CVR.Type != TypeLeafKind::LF_FIELDLIST &&
95 CVR.Type != TypeLeafKind::LF_METHODLIST)
96 MaxLen = MaxRecordLength - sizeof(RecordPrefix);
97 error(IO.beginRecord(MaxLen));
7598 TypeKind = CVR.Type;
7699 return Error::success();
77100 }
78101
79102 Error TypeRecordMapping::visitTypeEnd(CVType &Record) {
103 assert(TypeKind.hasValue() && "Not in a type mapping!");
104 assert(!MemberKind.hasValue() && "Still in a member mapping!");
105
80106 error(IO.endRecord());
107
81108 TypeKind.reset();
82109 return Error::success();
83110 }
84111
85112 Error TypeRecordMapping::visitMemberBegin(CVMemberRecord &Record) {
113 assert(TypeKind.hasValue() && "Not in a type mapping!");
114 assert(!MemberKind.hasValue() && "Already in a member mapping!");
115
116 // The largest possible subrecord is one in which there is a record prefix,
117 // followed by the subrecord, followed by a continuation, and that entire
118 // sequence spaws `MaxRecordLength` bytes. So the record's length is
119 // calculated as follows.
120 constexpr uint32_t ContinuationLength = 8;
121 error(IO.beginRecord(MaxRecordLength - sizeof(RecordPrefix) -
122 ContinuationLength));
123
124 MemberKind = Record.Kind;
86125 return Error::success();
87126 }
88127
89128 Error TypeRecordMapping::visitMemberEnd(CVMemberRecord &Record) {
129 assert(TypeKind.hasValue() && "Not in a type mapping!");
130 assert(MemberKind.hasValue() && "Not in a member mapping!");
131
90132 if (!IO.isWriting()) {
91133 if (auto EC = IO.skipPadding())
92134 return EC;
93135 }
94136
137 MemberKind.reset();
138 error(IO.endRecord());
95139 return Error::success();
96140 }
97141
128172 }
129173
130174 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ArgListRecord &Record) {
131 error(IO.mapVectorN(Record.StringIndices, MapInteger()));
175 error(IO.mapVectorN(
176 Record.StringIndices,
177 [](CodeViewRecordIO &IO, TypeIndex &N) { return IO.mapInteger(N); }));
132178
133179 return Error::success();
134180 }
244290 NamesLen += Name.size() + 1;
245291 }
246292 error(IO.mapInteger(NamesLen));
247 error(IO.mapVectorTail(Record.MethodNames, MapStringZ()));
293 error(IO.mapVectorTail(
294 Record.MethodNames,
295 [](CodeViewRecordIO &IO, StringRef &S) { return IO.mapStringZ(S); }));
248296
249297 return Error::success();
250298 }
294342
295343 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
296344 BuildInfoRecord &Record) {
297 error(IO.mapVectorN(Record.ArgIndices, MapInteger()));
345 error(IO.mapVectorN(
346 Record.ArgIndices,
347 [](CodeViewRecordIO &IO, TypeIndex &N) { return IO.mapInteger(N); }));
298348
299349 return Error::success();
300350 }
0 //===- TypeSerialzier.cpp ---------------------------------------*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm/DebugInfo/CodeView/TypeSerializer.h"
10
11 #include "llvm/DebugInfo/MSF/StreamWriter.h"
12
13 #include
14
15 using namespace llvm;
16 using namespace llvm::codeview;
17
18 bool TypeSerializer::isInFieldList() const {
19 return TypeKind.hasValue() && *TypeKind == TypeLeafKind::LF_FIELDLIST;
20 }
21
22 TypeIndex TypeSerializer::calcNextTypeIndex() const {
23 if (LastTypeIndex.isNoneType())
24 return TypeIndex(TypeIndex::FirstNonSimpleIndex);
25 else
26 return TypeIndex(LastTypeIndex.getIndex() + 1);
27 }
28
29 TypeIndex TypeSerializer::incrementTypeIndex() {
30 TypeIndex Previous = LastTypeIndex;
31 LastTypeIndex = calcNextTypeIndex();
32 return Previous;
33 }
34
35 MutableArrayRef TypeSerializer::getCurrentSubRecordData() {
36 assert(isInFieldList());
37 return getCurrentRecordData().drop_front(CurrentSegment.length());
38 }
39
40 MutableArrayRef TypeSerializer::getCurrentRecordData() {
41 return MutableArrayRef(RecordBuffer).take_front(Writer.getOffset());
42 }
43
44 Error TypeSerializer::writeRecordPrefix(TypeLeafKind Kind) {
45 RecordPrefix Prefix;
46 Prefix.RecordKind = Kind;
47 Prefix.RecordLen = 0;
48 if (auto EC = Writer.writeObject(Prefix))
49 return EC;
50 return Error::success();
51 }
52
53 TypeIndex
54 TypeSerializer::insertRecordBytesPrivate(MutableArrayRef Record) {
55 assert(Record.size() % 4 == 0 && "Record is not aligned to 4 bytes!");
56
57 StringRef S(reinterpret_cast(Record.data()), Record.size());
58
59 TypeIndex NextTypeIndex = calcNextTypeIndex();
60 auto Result = HashedRecords.try_emplace(S, NextTypeIndex);
61 if (Result.second) {
62 LastTypeIndex = NextTypeIndex;
63 SeenRecords.push_back(Record);
64 }
65 return Result.first->getValue();
66 }
67
68 Expected>
69 TypeSerializer::addPadding(MutableArrayRef Record) {
70 uint32_t Align = Record.size() % 4;
71 if (Align == 0)
72 return Record;
73
74 int PaddingBytes = 4 - Align;
75 int N = PaddingBytes;
76 while (PaddingBytes > 0) {
77 uint8_t Pad = static_cast(LF_PAD0 + PaddingBytes);
78 if (auto EC = Writer.writeInteger(Pad))
79 return std::move(EC);
80 --PaddingBytes;
81 }
82 return MutableArrayRef(Record.data(), Record.size() + N);
83 }
84
85 TypeSerializer::TypeSerializer(BumpPtrAllocator &Storage)
86 : RecordStorage(Storage), LastTypeIndex(),
87 RecordBuffer(MaxRecordLength * 2), Stream(RecordBuffer), Writer(Stream),
88 Mapping(Writer) {
89 // RecordBuffer needs to be able to hold enough data so that if we are 1
90 // byte short of MaxRecordLen, and then we try to write MaxRecordLen bytes,
91 // we won't overflow.
92 }
93
94 ArrayRef> TypeSerializer::records() const {
95 return SeenRecords;
96 }
97
98 TypeIndex TypeSerializer::getLastTypeIndex() const { return LastTypeIndex; }
99
100 TypeIndex TypeSerializer::insertRecordBytes(MutableArrayRef Record) {
101 assert(!TypeKind.hasValue() && "Already in a type mapping!");
102 assert(Writer.getOffset() == 0 && "Stream has data already!");
103
104 return insertRecordBytesPrivate(Record);
105 }
106
107 Error TypeSerializer::visitTypeBegin(CVType &Record) {
108 assert(!TypeKind.hasValue() && "Already in a type mapping!");
109 assert(Writer.getOffset() == 0 && "Stream has data already!");
110
111 if (auto EC = writeRecordPrefix(Record.kind()))
112 return EC;
113
114 TypeKind = Record.kind();
115 if (auto EC = Mapping.visitTypeBegin(Record))
116 return EC;
117
118 return Error::success();
119 }
120
121 Expected TypeSerializer::visitTypeEndGetIndex(CVType &Record) {
122 assert(TypeKind.hasValue() && "Not in a type mapping!");
123 if (auto EC = Mapping.visitTypeEnd(Record))
124 return std::move(EC);
125
126 // Update the record's length and fill out the CVType members to point to
127 // the stable memory holding the record's data.
128 auto ThisRecordData = getCurrentRecordData();
129 auto ExpectedData = addPadding(ThisRecordData);
130 if (!ExpectedData)
131 return ExpectedData.takeError();
132 ThisRecordData = *ExpectedData;
133
134 RecordPrefix *Prefix =
135 reinterpret_cast(ThisRecordData.data());
136 Prefix->RecordLen = ThisRecordData.size() - sizeof(uint16_t);
137
138 uint8_t *Copy = RecordStorage.Allocate(ThisRecordData.size());
139 ::memcpy(Copy, ThisRecordData.data(), ThisRecordData.size());
140 ThisRecordData = MutableArrayRef(Copy, ThisRecordData.size());
141 Record = CVType(*TypeKind, ThisRecordData);
142 TypeIndex InsertedTypeIndex = insertRecordBytesPrivate(ThisRecordData);
143
144 // Write out each additional segment in reverse order, and update each
145 // record's continuation index to point to the previous one.
146 for (auto X : reverse(FieldListSegments)) {
147 auto CIBytes = X.take_back(sizeof(uint32_t));
148 support::ulittle32_t *CI =
149 reinterpret_cast(CIBytes.data());
150 assert(*CI == 0xB0C0B0C0 && "Invalid TypeIndex placeholder");
151 *CI = InsertedTypeIndex.getIndex();
152 InsertedTypeIndex = insertRecordBytesPrivate(X);
153 }
154
155 TypeKind.reset();
156 Writer.setOffset(0);
157 FieldListSegments.clear();
158 CurrentSegment.SubRecords.clear();
159
160 return InsertedTypeIndex;
161 }
162
163 Error TypeSerializer::visitTypeEnd(CVType &Record) {
164 auto ExpectedIndex = visitTypeEndGetIndex(Record);
165 if (!ExpectedIndex)
166 return ExpectedIndex.takeError();
167 return Error::success();
168 }
169
170 Error TypeSerializer::visitMemberBegin(CVMemberRecord &Record) {
171 assert(isInFieldList() && "Not in a field list!");
172 assert(!MemberKind.hasValue() && "Already in a member record!");
173 MemberKind = Record.Kind;
174
175 if (auto EC = Mapping.visitMemberBegin(Record))
176 return EC;
177
178 return Error::success();
179 }
180
181 Error TypeSerializer::visitMemberEnd(CVMemberRecord &Record) {
182 if (auto EC = Mapping.visitMemberEnd(Record))
183 return EC;
184
185 // Check if this subrecord makes the current segment not fit in 64K minus
186 // the space for a continuation record (8 bytes). If the segment does not
187 // fit, insert a continuation record.
188 if (Writer.getOffset() > MaxRecordLength - ContinuationLength) {
189 MutableArrayRef Data = getCurrentRecordData();
190 SubRecord LastSubRecord = CurrentSegment.SubRecords.back();
191 uint32_t CopySize = CurrentSegment.length() - LastSubRecord.Size;
192 auto CopyData = Data.take_front(CopySize);
193 auto LeftOverData = Data.drop_front(CopySize);
194 assert(LastSubRecord.Size == LeftOverData.size());
195
196 // Allocate stable storage for the record and copy the old record plus
197 // continuation over.
198 uint16_t LengthWithSize = CopySize + ContinuationLength;
199 assert(LengthWithSize <= MaxRecordLength);
200 RecordPrefix *Prefix = reinterpret_cast(CopyData.data());
201 Prefix->RecordLen = LengthWithSize - sizeof(uint16_t);
202
203 uint8_t *SegmentBytes = RecordStorage.Allocate(LengthWithSize);
204 auto SavedSegment = MutableArrayRef(SegmentBytes, LengthWithSize);
205 msf::MutableByteStream CS(SavedSegment);
206 msf::StreamWriter CW(CS);
207 if (auto EC = CW.writeBytes(CopyData))
208 return EC;
209 if (auto EC = CW.writeEnum(TypeLeafKind::LF_INDEX))
210 return EC;
211 if (auto EC = CW.writeInteger(uint16_t(0)))
212 return EC;
213 if (auto EC = CW.writeInteger(uint32_t(0xB0C0B0C0)))
214 return EC;
215 FieldListSegments.push_back(SavedSegment);
216
217 // Write a new placeholder record prefix to mark the start of this new
218 // top-level record.
219 Writer.setOffset(0);
220 if (auto EC = writeRecordPrefix(TypeLeafKind::LF_FIELDLIST))
221 return EC;
222
223 // Then move over the subrecord that overflowed the old segment to the
224 // beginning of this segment. Note that we have to use memmove here
225 // instead of Writer.writeBytes(), because the new and old locations
226 // could overlap.
227 ::memmove(Stream.data().data() + sizeof(RecordPrefix), LeftOverData.data(),
228 LeftOverData.size());
229 // And point the segment writer at the end of that subrecord.
230 Writer.setOffset(LeftOverData.size() + sizeof(RecordPrefix));
231
232 CurrentSegment.SubRecords.clear();
233 CurrentSegment.SubRecords.push_back(LastSubRecord);
234 }
235
236 // Update the CVMemberRecord since we may have shifted around or gotten
237 // padded.
238 Record.Data = getCurrentSubRecordData();
239
240 MemberKind.reset();
241 return Error::success();
242 }
1010 #include "llvm/ADT/SmallString.h"
1111 #include "llvm/ADT/StringExtras.h"
1212 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
13 #include "llvm/DebugInfo/CodeView/FieldListRecordBuilder.h"
1413 #include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
1514 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
1615 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
16 #include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
1717 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
1818 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
1919 #include "llvm/Support/Error.h"
5353 /// existing destination type index.
5454 class TypeStreamMerger : public TypeVisitorCallbacks {
5555 public:
56 TypeStreamMerger(TypeTableBuilder &DestStream) : DestStream(DestStream) {
56 TypeStreamMerger(TypeTableBuilder &DestStream)
57 : DestStream(DestStream), FieldListBuilder(DestStream) {
5758 assert(!hadError());
5859 }
5960
9394 template
9495 Error visitKnownMemberRecordImpl(RecordType &Record) {
9596 FoundBadTypeIndex |= !Record.remapTypeIndices(IndexMap);
96 FieldBuilder.writeMemberType(Record);
97 FieldListBuilder.writeMemberType(Record);
9798 return Error::success();
9899 }
99100
101102
102103 bool FoundBadTypeIndex = false;
103104
104 FieldListRecordBuilder FieldBuilder;
105 BumpPtrAllocator Allocator;
105106
106107 TypeTableBuilder &DestStream;
108 FieldListRecordBuilder FieldListBuilder;
107109
108110 bool IsInFieldList{false};
109111 size_t BeginIndexMapSize = 0;
119121 if (Rec.Type == TypeLeafKind::LF_FIELDLIST) {
120122 assert(!IsInFieldList);
121123 IsInFieldList = true;
124 FieldListBuilder.begin();
122125 } else
123126 BeginIndexMapSize = IndexMap.size();
124127 return Error::success();
126129
127130 Error TypeStreamMerger::visitTypeEnd(CVRecord &Rec) {
128131 if (Rec.Type == TypeLeafKind::LF_FIELDLIST) {
129 IndexMap.push_back(DestStream.writeFieldList(FieldBuilder));
130 FieldBuilder.reset();
132 TypeIndex Index = FieldListBuilder.end();
133 IndexMap.push_back(Index);
131134 IsInFieldList = false;
132135 }
133136 return Error::success();
+0
-300
lib/DebugInfo/CodeView/TypeTableBuilder.cpp less more
None //===-- TypeTableBuilder.cpp ----------------------------------------------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
10 #include "llvm/DebugInfo/CodeView/FieldListRecordBuilder.h"
11 #include "llvm/DebugInfo/CodeView/MethodListRecordBuilder.h"
12 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
13 #include "llvm/DebugInfo/CodeView/TypeRecordBuilder.h"
14 #include "llvm/Support/raw_ostream.h"
15
16 using namespace llvm;
17 using namespace codeview;
18
19 TypeTableBuilder::TypeTableBuilder() {}
20
21 TypeTableBuilder::~TypeTableBuilder() {}
22
23 TypeIndex TypeTableBuilder::writeKnownType(const ModifierRecord &Record) {
24 TypeRecordBuilder Builder(Record.getKind());
25
26 Builder.writeTypeIndex(Record.getModifiedType());
27 Builder.writeUInt16(static_cast(Record.getModifiers()));
28
29 return writeRecord(Builder);
30 }
31
32 TypeIndex TypeTableBuilder::writeKnownType(const ProcedureRecord &Record) {
33 TypeRecordBuilder Builder(Record.getKind());
34
35 Builder.writeTypeIndex(Record.getReturnType());
36 Builder.writeUInt8(static_cast(Record.getCallConv()));
37 Builder.writeUInt8(static_cast(Record.getOptions()));
38 Builder.writeUInt16(Record.getParameterCount());
39 Builder.writeTypeIndex(Record.getArgumentList());
40
41 return writeRecord(Builder);
42 }
43
44 TypeIndex TypeTableBuilder::writeKnownType(const MemberFunctionRecord &Record) {
45 TypeRecordBuilder Builder(Record.getKind());
46
47 Builder.writeTypeIndex(Record.getReturnType());
48 Builder.writeTypeIndex(Record.getClassType());
49 Builder.writeTypeIndex(Record.getThisType());
50 Builder.writeUInt8(static_cast(Record.getCallConv()));
51 Builder.writeUInt8(static_cast(Record.getOptions()));
52 Builder.writeUInt16(Record.getParameterCount());
53 Builder.writeTypeIndex(Record.getArgumentList());
54 Builder.writeInt32(Record.getThisPointerAdjustment());
55
56 return writeRecord(Builder);
57 }
58
59 TypeIndex TypeTableBuilder::writeKnownType(const ArgListRecord &Record) {
60 TypeRecordBuilder Builder(Record.getKind());
61
62 Builder.writeUInt32(Record.getIndices().size());
63 for (TypeIndex TI : Record.getIndices()) {
64 Builder.writeTypeIndex(TI);
65 }
66
67 return writeRecord(Builder);
68 }
69
70 TypeIndex TypeTableBuilder::writeKnownType(const PointerRecord &Record) {
71 TypeRecordBuilder Builder(Record.getKind());
72
73 Builder.writeTypeIndex(Record.getReferentType());
74 Builder.writeUInt32(Record.Attrs);
75
76 if (Record.isPointerToMember()) {
77 const MemberPointerInfo &M = Record.getMemberInfo();
78 Builder.writeTypeIndex(M.getContainingType());
79 Builder.writeUInt16(static_cast(M.getRepresentation()));
80 }
81
82 return writeRecord(Builder);
83 }
84
85 static void writeNameAndUniqueName(TypeRecordBuilder &Builder, ClassOptions CO,
86 StringRef Name, StringRef UniqueName) {
87 // Truncate the names to half the remaining record length.
88 unsigned MaxNameLength = Builder.maxBytesRemaining() / 2;
89 Name = Name.take_front(MaxNameLength - 1);
90 UniqueName = UniqueName.take_front(MaxNameLength - 1);
91
92 Builder.writeNullTerminatedString(Name);
93 if ((CO & ClassOptions::HasUniqueName) != ClassOptions::None) {
94 Builder.writeNullTerminatedString(UniqueName);
95 }
96 }
97
98 TypeIndex TypeTableBuilder::writeKnownType(const ArrayRecord &Record) {
99 TypeRecordBuilder Builder(Record.getKind());
100
101 Builder.writeTypeIndex(Record.getElementType());
102 Builder.writeTypeIndex(Record.getIndexType());
103 Builder.writeEncodedUnsignedInteger(Record.getSize());
104 Builder.writeNullTerminatedString(Record.getName());
105
106 return writeRecord(Builder);
107 }
108
109 TypeIndex TypeTableBuilder::writeKnownType(const ClassRecord &Record) {
110 assert((Record.getKind() == TypeRecordKind::Struct) ||
111 (Record.getKind() == TypeRecordKind::Class) ||
112 (Record.getKind() == TypeRecordKind::Interface));
113
114 TypeRecordBuilder Builder(Record.getKind());
115
116 Builder.writeUInt16(Record.getMemberCount());
117 uint16_t Flags =
118 static_cast(Record.getOptions()) |
119 (static_cast(Record.getHfa()) << ClassRecord::HfaKindShift) |
120 (static_cast(Record.getWinRTKind())
121 << ClassRecord::WinRTKindShift);
122 Builder.writeUInt16(Flags);
123 Builder.writeTypeIndex(Record.getFieldList());
124 Builder.writeTypeIndex(Record.getDerivationList());
125 Builder.writeTypeIndex(Record.getVTableShape());
126 Builder.writeEncodedUnsignedInteger(Record.getSize());
127 writeNameAndUniqueName(Builder, Record.getOptions(), Record.getName(),
128 Record.getUniqueName());
129
130 return writeRecord(Builder);
131 }
132
133 TypeIndex TypeTableBuilder::writeKnownType(const UnionRecord &Record) {
134 TypeRecordBuilder Builder(TypeRecordKind::Union);
135 Builder.writeUInt16(Record.getMemberCount());
136 uint16_t Flags =
137 static_cast(Record.getOptions()) |
138 (static_cast(Record.getHfa()) << ClassRecord::HfaKindShift);
139 Builder.writeUInt16(Flags);
140 Builder.writeTypeIndex(Record.getFieldList());
141 Builder.writeEncodedUnsignedInteger(Record.getSize());
142 writeNameAndUniqueName(Builder, Record.getOptions(), Record.getName(),
143 Record.getUniqueName());
144 return writeRecord(Builder);
145 }
146
147 TypeIndex TypeTableBuilder::writeKnownType(const EnumRecord &Record) {
148 TypeRecordBuilder Builder(Record.getKind());
149
150 Builder.writeUInt16(Record.getMemberCount());
151 Builder.writeUInt16(static_cast(Record.getOptions()));
152 Builder.writeTypeIndex(Record.getUnderlyingType());
153 Builder.writeTypeIndex(Record.getFieldList());
154 writeNameAndUniqueName(Builder, Record.getOptions(), Record.getName(),
155 Record.getUniqueName());
156
157 return writeRecord(Builder);
158 }
159
160 TypeIndex TypeTableBuilder::writeKnownType(const BitFieldRecord &Record) {
161 TypeRecordBuilder Builder(Record.getKind());
162
163 Builder.writeTypeIndex(Record.getType());
164 Builder.writeUInt8(Record.getBitSize());
165 Builder.writeUInt8(Record.getBitOffset());
166
167 return writeRecord(Builder);
168 }
169
170 TypeIndex TypeTableBuilder::writeKnownType(const VFTableShapeRecord &Record) {
171 TypeRecordBuilder Builder(Record.getKind());
172
173 ArrayRef Slots = Record.getSlots();
174
175 Builder.writeUInt16(Slots.size());
176 for (size_t SlotIndex = 0; SlotIndex < Slots.size(); SlotIndex += 2) {
177 uint8_t Byte = static_cast(Slots[SlotIndex]) << 4;
178 if ((SlotIndex + 1) < Slots.size()) {
179 Byte |= static_cast(Slots[SlotIndex + 1]);
180 }
181 Builder.writeUInt8(Byte);
182 }
183
184 return writeRecord(Builder);
185 }
186
187 TypeIndex TypeTableBuilder::writeKnownType(const VFTableRecord &Record) {
188 TypeRecordBuilder Builder(Record.getKind());
189 Builder.writeTypeIndex(Record.getCompleteClass());
190 Builder.writeTypeIndex(Record.getOverriddenVTable());
191 Builder.writeUInt32(Record.getVFPtrOffset());
192
193 // Sum up the lengths of the null-terminated names.
194 size_t NamesLen = Record.getName().size() + 1;
195 for (StringRef MethodName : Record.getMethodNames())
196 NamesLen += MethodName.size() + 1;
197
198 // FIXME: Avoid creating a record longer than MaxRecordLength.
199 Builder.writeUInt32(NamesLen);
200 Builder.writeNullTerminatedString(Record.getName());
201 for (StringRef MethodName : Record.getMethodNames())
202 Builder.writeNullTerminatedString(MethodName);
203
204 return writeRecord(Builder);
205 }
206
207 TypeIndex TypeTableBuilder::writeKnownType(const StringIdRecord &Record) {
208 TypeRecordBuilder Builder(TypeRecordKind::StringId);
209 Builder.writeTypeIndex(Record.getId());
210 Builder.writeNullTerminatedString(Record.getString());
211 return writeRecord(Builder);
212 }
213
214 TypeIndex TypeTableBuilder::writeKnownType(const UdtSourceLineRecord &Record) {
215 TypeRecordBuilder Builder(Record.getKind());
216 Builder.writeTypeIndex(Record.getUDT());
217 Builder.writeTypeIndex(Record.getSourceFile());
218 Builder.writeUInt32(Record.getLineNumber());
219 return writeRecord(Builder);
220 }
221
222 TypeIndex
223 TypeTableBuilder::writeKnownType(const UdtModSourceLineRecord &Record) {
224 TypeRecordBuilder Builder(Record.getKind());
225 Builder.writeTypeIndex(Record.getUDT());
226 Builder.writeTypeIndex(Record.getSourceFile());
227 Builder.writeUInt32(Record.getLineNumber());
228 Builder.writeUInt16(Record.getModule());
229 return writeRecord(Builder);
230 }
231
232 TypeIndex TypeTableBuilder::writeKnownType(const FuncIdRecord &Record) {
233 TypeRecordBuilder Builder(Record.getKind());
234 Builder.writeTypeIndex(Record.getParentScope());
235 Builder.writeTypeIndex(Record.getFunctionType());
236 Builder.writeNullTerminatedString(Record.getName());
237 return writeRecord(Builder);
238 }
239
240 TypeIndex TypeTableBuilder::writeKnownType(const MemberFuncIdRecord &Record) {
241 TypeRecordBuilder Builder(Record.getKind());
242 Builder.writeTypeIndex(Record.getClassType());
243 Builder.writeTypeIndex(Record.getFunctionType());
244 Builder.writeNullTerminatedString(Record.getName());
245 return writeRecord(Builder);
246 }
247
248 TypeIndex TypeTableBuilder::writeKnownType(const BuildInfoRecord &Record) {
249 TypeRecordBuilder Builder(Record.getKind());
250 assert(Record.getArgs().size() <= UINT16_MAX);
251 Builder.writeUInt16(Record.getArgs().size());
252 for (TypeIndex Arg : Record.getArgs())
253 Builder.writeTypeIndex(Arg);
254 return writeRecord(Builder);
255 }
256
257 TypeIndex TypeTableBuilder::writeRecord(TypeRecordBuilder &Builder) {
258 TypeIndex I = writeRecord(Builder.str());
259 RecordKinds.push_back(Builder.kind());
260 return I;
261 }
262
263 TypeIndex TypeTableBuilder::writeFieldList(FieldListRecordBuilder &FieldList) {
264 TypeIndex I = FieldList.writeListRecord(*this);
265 RecordKinds.push_back(TypeRecordKind::FieldList);
266 return I;
267 }
268
269 TypeIndex
270 TypeTableBuilder::writeKnownType(const MethodOverloadListRecord &Record) {
271 TypeRecordBuilder Builder(Record.getKind());
272 for (const OneMethodRecord &Method : Record.getMethods()) {
273 uint16_t Flags = static_cast(Method.getAccess());
274 Flags |= static_cast(Method.getKind())
275 << MemberAttributes::MethodKindShift;
276 Flags |= static_cast(Method.getOptions());
277 Builder.writeUInt16(Flags);
278 Builder.writeUInt16(0); // padding
279 Builder.writeTypeIndex(Method.getType());
280 if (Method.isIntroducingVirtual()) {
281 assert(Method.getVFTableOffset() >= 0);
282 Builder.writeInt32(Method.getVFTableOffset());
283 } else {
284 assert(Method.getVFTableOffset() == -1);
285 }
286 }
287
288 // TODO: Split the list into multiple records if it's longer than 64KB, using
289 // a subrecord of TypeRecordKind::Index to chain the records together.
290 return writeRecord(Builder);
291 }
292
293 TypeIndex TypeTableBuilder::writeKnownType(const TypeServer2Record &Record) {
294 TypeRecordBuilder Builder(Record.getKind());
295 Builder.writeGuid(Record.getGuid());
296 Builder.writeUInt32(Record.getAge());
297 Builder.writeNullTerminatedString(Record.getName());
298 return writeRecord(Builder);
299 }
1717 #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
1818 #include "llvm/DebugInfo/CodeView/SymbolVisitorCallbackPipeline.h"
1919 #include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
20 #include "llvm/DebugInfo/CodeView/TypeSerializationVisitor.h"
20 #include "llvm/DebugInfo/CodeView/TypeSerializer.h"
2121 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
2222 #include "llvm/DebugInfo/PDB/PDBExtras.h"
2323 #include "llvm/DebugInfo/PDB/PDBTypes.h"
243243 pdb::yaml::SerializationContext &Context) {
244244 codeview::TypeVisitorCallbackPipeline Pipeline;
245245 codeview::TypeDeserializer Deserializer;
246 codeview::TypeSerializationVisitor Serializer(Context.FieldListBuilder,
247 Context.TypeTableBuilder);
246 codeview::TypeSerializer Serializer(Context.Allocator);
248247 pdb::TpiHashUpdater Hasher;
249248
250249 if (IO.outputting()) {
254253 } else {
255254 // For Yaml to PDB, extract from the high level record type, then write it
256255 // to bytes.
256
257 // This might be interpreted as a hack, but serializing FieldList
258 // sub-records requires having access to the same serializer being used by
259 // the FieldList itself.
260 Context.ActiveSerializer = &Serializer;
257261 Pipeline.addCallbackToPipeline(Context.Dumper);
258262 Pipeline.addCallbackToPipeline(Serializer);
259263 Pipeline.addCallbackToPipeline(Hasher);
261265
262266 codeview::CVTypeVisitor Visitor(Pipeline);
263267 consumeError(Visitor.visitTypeRecord(Obj.Record));
264 }
268 Context.ActiveSerializer = nullptr;
269 }
1111
1212 #include "PdbYaml.h"
1313 #include "YamlTypeDumper.h"
14 #include "llvm/DebugInfo/CodeView/FieldListRecordBuilder.h"
15 #include "llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h"
14 #include "llvm/Support/Allocator.h"
1615
1716 namespace llvm {
17 namespace codeview {
18 class TypeSerializer;
19 }
1820 namespace yaml {
1921 class IO;
2022 }
2325 namespace yaml {
2426 struct SerializationContext {
2527 explicit SerializationContext(llvm::yaml::IO &IO, BumpPtrAllocator &Allocator)
26 : Dumper(IO, *this), TypeTableBuilder(Allocator) {}
28 : Dumper(IO, *this), Allocator(Allocator) {}
29
2730 codeview::yaml::YamlTypeDumperCallbacks Dumper;
28 codeview::MemoryTypeTableBuilder TypeTableBuilder;
29 codeview::FieldListRecordBuilder FieldListBuilder;
31 BumpPtrAllocator &Allocator;
32 codeview::TypeSerializer *ActiveSerializer = nullptr;
3033 };
3134 }
3235 }
1414 #include "llvm/DebugInfo/CodeView/EnumTables.h"
1515 #include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
1616 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
17 #include "llvm/DebugInfo/CodeView/TypeSerializationVisitor.h"
17 #include "llvm/DebugInfo/CodeView/TypeSerializer.h"
1818 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
1919 #include "llvm/DebugInfo/PDB/Raw/TpiHashing.h"
2020
539539 // which will recurse back to the standard handler for top-level fields
540540 // (top-level and member fields all have the exact same Yaml syntax so use
541541 // the same parser).
542 //
542 FieldListRecordSplitter Splitter(FieldListRecords);
543 CVTypeVisitor V(Splitter);
544 consumeError(V.visitFieldListMemberStream(FieldList.Data));
545 YamlIO.mapRequired("FieldList", FieldListRecords, Context);
546 } else {
543547 // If we are not outputting, then the array contains no data starting out,
544548 // and is instead populated from the sequence represented by the yaml --
545549 // again, using the same logic that we use for top-level records.
546 FieldListRecordSplitter Splitter(FieldListRecords);
547 CVTypeVisitor V(Splitter);
548 consumeError(V.visitFieldListMemberStream(FieldList.Data));
549 }
550 YamlIO.mapRequired("FieldList", FieldListRecords, Context);
550 assert(Context.ActiveSerializer && "There is no active serializer!");
551 codeview::TypeVisitorCallbackPipeline Pipeline;
552 pdb::TpiHashUpdater Hasher;
553
554 // For Yaml to PDB, dump it (to fill out the record fields from the Yaml)
555 // then serialize those fields to bytes, then update their hashes.
556 Pipeline.addCallbackToPipeline(Context.Dumper);
557 Pipeline.addCallbackToPipeline(*Context.ActiveSerializer);
558 Pipeline.addCallbackToPipeline(Hasher);
559
560 codeview::CVTypeVisitor Visitor(Pipeline);
561 YamlIO.mapRequired("FieldList", FieldListRecords, Visitor);
562 }
551563 }
552564
553565 namespace llvm {
557569 pdb::yaml::SerializationContext> {
558570 static void mapping(IO &IO, pdb::yaml::PdbTpiFieldListRecord &Obj,
559571 pdb::yaml::SerializationContext &Context) {
572 assert(IO.outputting());
560573 codeview::TypeVisitorCallbackPipeline Pipeline;
561574
562575 msf::ByteStream Data(Obj.Record.Data);
563576 msf::StreamReader FieldReader(Data);
564577 codeview::FieldListDeserializer Deserializer(FieldReader);
565 codeview::TypeSerializationVisitor Serializer(Context.FieldListBuilder,
566 Context.TypeTableBuilder);
567 pdb::TpiHashUpdater Hasher;
568
569 if (IO.outputting()) {
570 // For PDB to Yaml, deserialize into a high level record type, then dump
571 // it.
572 Pipeline.addCallbackToPipeline(Deserializer);
573 Pipeline.addCallbackToPipeline(Context.Dumper);
574 } else {
575 // For Yaml to PDB, extract from the high level record type, then write it
576 // to bytes.
577 Pipeline.addCallbackToPipeline(Context.Dumper);
578 Pipeline.addCallbackToPipeline(Serializer);
579 Pipeline.addCallbackToPipeline(Hasher);
580 }
578
579 // For PDB to Yaml, deserialize into a high level record type, then dump
580 // it.
581 Pipeline.addCallbackToPipeline(Deserializer);
582 Pipeline.addCallbackToPipeline(Context.Dumper);
581583
582584 codeview::CVTypeVisitor Visitor(Pipeline);
583585 consumeError(Visitor.visitMemberRecord(Obj.Record));
584586 }
585587 };
586 }
587 }
588
589 template <>
590 struct MappingContextTraits
591 codeview::CVTypeVisitor> {
592 static void mapping(IO &IO, pdb::yaml::PdbTpiFieldListRecord &Obj,
593 codeview::CVTypeVisitor &Visitor) {
594 consumeError(Visitor.visitMemberRecord(Obj.Record));
595 }
596 };
597 }
598 }
1010 #define LLVM_TOOLS_LLVMPDBDUMP_YAMLTYPEDUMPER_H
1111
1212 #include "llvm/DebugInfo/CodeView/CodeView.h"
13 #include "llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h"
1413 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
1514 #include "llvm/Support/YAMLTraits.h"
1615
2323 #include "llvm/ADT/StringExtras.h"
2424 #include "llvm/DebugInfo/CodeView/CodeView.h"
2525 #include "llvm/DebugInfo/CodeView/Line.h"
26 #include "llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h"
2726 #include "llvm/DebugInfo/CodeView/RecordSerialization.h"
2827 #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
2928 #include "llvm/DebugInfo/CodeView/SymbolDumpDelegate.h"
3332 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
3433 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
3534 #include "llvm/DebugInfo/CodeView/TypeStreamMerger.h"
35 #include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
3636 #include "llvm/DebugInfo/MSF/ByteStream.h"
3737 #include "llvm/Object/COFF.h"
3838 #include "llvm/Object/ObjectFile.h"
7878 void printCOFFBaseReloc() override;
7979 void printCOFFDebugDirectory() override;
8080 void printCodeViewDebugInfo() override;
81 void
82 mergeCodeViewTypes(llvm::codeview::MemoryTypeTableBuilder &CVTypes) override;
81 void mergeCodeViewTypes(llvm::codeview::TypeTableBuilder &CVTypes) override;
8382 void printStackMap() const override;
8483 private:
8584 void printSymbol(const SymbolRef &Sym);
10621061 W.printHex(Label, getFileNameForFileOffset(FileOffset), FileOffset);
10631062 }
10641063
1065 void COFFDumper::mergeCodeViewTypes(MemoryTypeTableBuilder &CVTypes) {
1064 void COFFDumper::mergeCodeViewTypes(TypeTableBuilder &CVTypes) {
10661065 for (const SectionRef &S : Obj->sections()) {
10671066 StringRef SectionName;
10681067 error(S.getName(SectionName));
15441543 StackMapV2Parser(StackMapContentsArray));
15451544 }
15461545
1547 void llvm::dumpCodeViewMergedTypes(
1548 ScopedPrinter &Writer, llvm::codeview::MemoryTypeTableBuilder &CVTypes) {
1546 void llvm::dumpCodeViewMergedTypes(ScopedPrinter &Writer,
1547 llvm::codeview::TypeTableBuilder &CVTypes) {
15491548 // Flatten it first, then run our dumper on it.
15501549 ListScope S(Writer, "MergedTypeStream");
15511550 SmallString<0> Buf;
1552 CVTypes.ForEachRecord([&](TypeIndex TI, StringRef Record) {
1551 CVTypes.ForEachRecord([&](TypeIndex TI, ArrayRef Record) {
15531552 Buf.append(Record.begin(), Record.end());
15541553 });
15551554 CVTypeDumper CVTD(&Writer, opts::CodeViewSubsectionBytes);
1818 class ObjectFile;
1919 }
2020 namespace codeview {
21 class MemoryTypeTableBuilder;
21 class TypeTableBuilder;
2222 }
2323
2424 class ScopedPrinter;
6464 virtual void printCOFFBaseReloc() { }
6565 virtual void printCOFFDebugDirectory() { }
6666 virtual void printCodeViewDebugInfo() { }
67 virtual void
68 mergeCodeViewTypes(llvm::codeview::MemoryTypeTableBuilder &CVTypes) {}
67 virtual void mergeCodeViewTypes(llvm::codeview::TypeTableBuilder &CVTypes) {}
6968
7069 // Only implemented for MachO.
7170 virtual void printMachODataInCode() { }
9695 void dumpCOFFImportFile(const object::COFFImportFile *File);
9796
9897 void dumpCodeViewMergedTypes(ScopedPrinter &Writer,
99 llvm::codeview::MemoryTypeTableBuilder &CVTypes);
98 llvm::codeview::TypeTableBuilder &CVTypes);
10099
101100 } // namespace llvm
102101
2121 #include "llvm-readobj.h"
2222 #include "Error.h"
2323 #include "ObjDumper.h"
24 #include "llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h"
24 #include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
2525 #include "llvm/Object/Archive.h"
2626 #include "llvm/Object/COFFImportFile.h"
2727 #include "llvm/Object/ELFObjectFile.h"
331331 }
332332 }
333333 namespace {
334 struct TypeTableBuilder {
335 TypeTableBuilder() : Allocator(), Builder(Allocator) {}
334 struct ReadObjTypeTableBuilder {
335 ReadObjTypeTableBuilder() : Allocator(), Builder(Allocator) {}
336336
337337 llvm::BumpPtrAllocator Allocator;
338 llvm::codeview::MemoryTypeTableBuilder Builder;
338 llvm::codeview::TypeTableBuilder Builder;
339339 };
340340 }
341 static TypeTableBuilder CVTypes;
341 static ReadObjTypeTableBuilder CVTypes;
342342
343343 /// @brief Creates an format-specific object file dumper.
344344 static std::error_code createDumper(const ObjectFile *Obj,