llvm.org GIT mirror llvm / ab45c06
[CodeView] Refactor / Rewrite TypeSerializer and TypeTableBuilder. The motivation behind this patch is that future directions require us to be able to compute the hash value of records independently of actually using them for de-duplication. The current structure of TypeSerializer / TypeTableBuilder being a single entry point that takes an unserialized type record, and then hashes and de-duplicates it is not flexible enough to allow this. At the same time, the existing TypeSerializer is already extremely complex for this very reason -- it tries to be too many things. In addition to serializing, hashing, and de-duplicating, ti also supports splitting up field list records and adding continuations. All of this functionality crammed into this one class makes it very complicated to work with and hard to maintain. To solve all of these problems, I've re-written everything from scratch and split the functionality into separate pieces that can easily be reused. The end result is that one class TypeSerializer is turned into 3 new classes SimpleTypeSerializer, ContinuationRecordBuilder, and TypeTableBuilder, each of which in isolation is simple and straightforward. A quick summary of these new classes and their responsibilities are: - SimpleTypeSerializer : Turns a non-FieldList leaf type into a series of bytes. Does not do any hashing. Every time you call it, it will re-serialize and return bytes again. The same instance can be re-used over and over to avoid re-allocations, and in exchange for this optimization the bytes returned by the serializer only live until the caller attempts to serialize a new record. - ContinuationRecordBuilder : Turns a FieldList-like record into a series of fragments. Does not do any hashing. Like SimpleTypeSerializer, returns references to privately owned bytes, so the storage is invalidated as soon as the caller tries to re-use the instance. Works equally well for LF_FIELDLIST as it does for LF_METHODLIST, solving a long-standing theoretical limitation of the previous implementation. - TypeTableBuilder : Accepts sequences of bytes that the user has already serialized, and inserts them by de-duplicating with a hash table. For the sake of convenience and efficiency, this class internally stores a SimpleTypeSerializer so that it can accept unserialized records. The same is not true of ContinuationRecordBuilder. The user is required to create their own instance of ContinuationRecordBuilder. Differential Revision: https://reviews.llvm.org/D40518 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@319198 91177308-0d34-0410-b5e6-96231b3b80d8 Zachary Turner 1 year, 11 months ago
21 changed file(s) with 797 addition(s) and 734 deletion(s). Raw diff Collapse all Expand all
0 //===- ContinuationRecordBuilder.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_CONTINUATIONRECORDBUILDER_H
10 #define LLVM_DEBUGINFO_CODEVIEW_CONTINUATIONRECORDBUILDER_H
11
12 #include "llvm/ADT/ArrayRef.h"
13 #include "llvm/ADT/Optional.h"
14 #include "llvm/ADT/SmallVector.h"
15 #include "llvm/DebugInfo/CodeView/CodeView.h"
16 #include "llvm/DebugInfo/CodeView/RecordSerialization.h"
17 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
18 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
19 #include "llvm/DebugInfo/CodeView/TypeRecordMapping.h"
20 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
21 #include "llvm/Support/Allocator.h"
22 #include "llvm/Support/BinaryByteStream.h"
23 #include "llvm/Support/BinaryStreamWriter.h"
24 #include "llvm/Support/Error.h"
25 #include
26 #include
27 #include
28 #include
29
30 namespace llvm {
31 namespace codeview {
32 enum class ContinuationRecordKind { FieldList, MethodOverloadList };
33
34 class ContinuationRecordBuilder {
35 SmallVector SegmentOffsets;
36 Optional Kind;
37 AppendingBinaryByteStream Buffer;
38 BinaryStreamWriter SegmentWriter;
39 TypeRecordMapping Mapping;
40 ArrayRef InjectedSegmentBytes;
41
42 uint32_t getCurrentSegmentLength() const;
43
44 void insertSegmentEnd(uint32_t Offset);
45 CVType createSegmentRecord(uint32_t OffBegin, uint32_t OffEnd,
46 Optional RefersTo);
47
48 public:
49 ContinuationRecordBuilder();
50 ~ContinuationRecordBuilder();
51
52 void begin(ContinuationRecordKind RecordKind);
53
54 // This template is explicitly instantiated in the implementation file for all
55 // supported types. The method itself is ugly, so inlining it into the header
56 // file clutters an otherwise straightforward interface.
57 template void writeMemberType(RecordType &Record);
58
59 std::vector end(TypeIndex Index);
60 };
61 } // namespace codeview
62 } // namespace llvm
63
64 #endif
0 //===- SimpleTypeSerializer.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_SIMPLETYPESERIALIZER_H
10 #define LLVM_DEBUGINFO_CODEVIEW_SIMPLETYPESERIALIZER_H
11
12 #include "llvm/ADT/ArrayRef.h"
13 #include "llvm/ADT/Optional.h"
14 #include "llvm/ADT/SmallVector.h"
15 #include "llvm/DebugInfo/CodeView/CodeView.h"
16 #include "llvm/DebugInfo/CodeView/RecordSerialization.h"
17 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
18 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
19 #include "llvm/DebugInfo/CodeView/TypeRecordMapping.h"
20 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
21 #include "llvm/Support/Allocator.h"
22 #include "llvm/Support/BinaryByteStream.h"
23 #include "llvm/Support/BinaryStreamWriter.h"
24 #include "llvm/Support/Error.h"
25 #include
26 #include
27 #include
28 #include
29
30 namespace llvm {
31 namespace codeview {
32
33 class SimpleTypeSerializer {
34 std::vector ScratchBuffer;
35
36 public:
37 SimpleTypeSerializer();
38 ~SimpleTypeSerializer();
39
40 // This template is explicitly instantiated in the implementation file for all
41 // supported types. The method itself is ugly, so inlining it into the header
42 // file clutters an otherwise straightforward interface.
43 template ArrayRef serialize(T &Record);
44
45 // Don't allow serialization of field list records using this interface.
46 ArrayRef serialize(const FieldListRecord &Record) = delete;
47 };
48
49 } // end namespace codeview
50 } // end namespace llvm
51
52 #endif // LLVM_DEBUGINFO_CODEVIEW_SIMPLETYPESERIALIZER_H
+0
-159
include/llvm/DebugInfo/CodeView/TypeSerializer.h less more
None //===- 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/ADT/ArrayRef.h"
13 #include "llvm/ADT/Optional.h"
14 #include "llvm/ADT/SmallVector.h"
15 #include "llvm/DebugInfo/CodeView/CodeView.h"
16 #include "llvm/DebugInfo/CodeView/RecordSerialization.h"
17 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
18 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
19 #include "llvm/DebugInfo/CodeView/TypeRecordMapping.h"
20 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
21 #include "llvm/Support/Allocator.h"
22 #include "llvm/Support/BinaryByteStream.h"
23 #include "llvm/Support/BinaryStreamWriter.h"
24 #include "llvm/Support/Error.h"
25 #include
26 #include
27 #include
28 #include
29
30 namespace llvm {
31 namespace codeview {
32
33 class TypeHasher;
34
35 class TypeSerializer : public TypeVisitorCallbacks {
36 struct SubRecord {
37 SubRecord(TypeLeafKind K, uint32_t S) : Kind(K), Size(S) {}
38
39 TypeLeafKind Kind;
40 uint32_t Size = 0;
41 };
42 struct RecordSegment {
43 SmallVector SubRecords;
44
45 uint32_t length() const {
46 uint32_t L = sizeof(RecordPrefix);
47 for (const auto &R : SubRecords) {
48 L += R.Size;
49 }
50 return L;
51 }
52 };
53
54 using MutableRecordList = SmallVector, 2>;
55
56 static constexpr uint8_t ContinuationLength = 8;
57 BumpPtrAllocator &RecordStorage;
58 RecordSegment CurrentSegment;
59 MutableRecordList FieldListSegments;
60
61 Optional TypeKind;
62 Optional MemberKind;
63 std::vector RecordBuffer;
64 MutableBinaryByteStream Stream;
65 BinaryStreamWriter Writer;
66 TypeRecordMapping Mapping;
67
68 /// Private type record hashing implementation details are handled here.
69 std::unique_ptr Hasher;
70
71 /// Contains a list of all records indexed by TypeIndex.toArrayIndex().
72 SmallVector, 2> SeenRecords;
73
74 /// Temporary storage that we use to copy a record's data while re-writing
75 /// its type indices.
76 SmallVector RemapStorage;
77
78 TypeIndex nextTypeIndex() const;
79
80 bool isInFieldList() const;
81 MutableArrayRef getCurrentSubRecordData();
82 MutableArrayRef getCurrentRecordData();
83 Error writeRecordPrefix(TypeLeafKind Kind);
84
85 Expected>
86 addPadding(MutableArrayRef Record);
87
88 public:
89 explicit TypeSerializer(BumpPtrAllocator &Storage, bool Hash = true);
90 ~TypeSerializer() override;
91
92 void reset();
93
94 BumpPtrAllocator &getAllocator() { return RecordStorage; }
95
96 ArrayRef> records() const;
97 TypeIndex insertRecordBytes(ArrayRef &Record);
98 TypeIndex insertRecord(const RemappedType &Record);
99 Expected visitTypeEndGetIndex(CVType &Record);
100
101 using TypeVisitorCallbacks::visitTypeBegin;
102 Error visitTypeBegin(CVType &Record) override;
103 Error visitTypeEnd(CVType &Record) override;
104 Error visitMemberBegin(CVMemberRecord &Record) override;
105 Error visitMemberEnd(CVMemberRecord &Record) override;
106
107 #define TYPE_RECORD(EnumName, EnumVal, Name) \
108 virtual Error visitKnownRecord(CVType &CVR, Name##Record &Record) override { \
109 return visitKnownRecordImpl(CVR, Record); \
110 }
111 #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
112 #define MEMBER_RECORD(EnumName, EnumVal, Name) \
113 Error visitKnownMember(CVMemberRecord &CVR, Name##Record &Record) override { \
114 return visitKnownMemberImpl(CVR, Record); \
115 }
116 #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
117 #include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
118
119 private:
120 template
121 Error visitKnownRecordImpl(CVType &CVR, RecordKind &Record) {
122 return Mapping.visitKnownRecord(CVR, Record);
123 }
124
125 template
126 Error visitKnownMemberImpl(CVMemberRecord &CVR, RecordType &Record) {
127 assert(CVR.Kind == static_cast(Record.getKind()));
128
129 if (auto EC = Writer.writeEnum(CVR.Kind))
130 return EC;
131
132 if (auto EC = Mapping.visitKnownMember(CVR, Record))
133 return EC;
134
135 // Get all the data that was just written and is yet to be committed to
136 // the current segment. Then pad it to 4 bytes.
137 MutableArrayRef ThisRecord = getCurrentSubRecordData();
138 auto ExpectedRecord = addPadding(ThisRecord);
139 if (!ExpectedRecord)
140 return ExpectedRecord.takeError();
141 ThisRecord = *ExpectedRecord;
142
143 CurrentSegment.SubRecords.emplace_back(CVR.Kind, ThisRecord.size());
144 CVR.Data = ThisRecord;
145
146 // Both the last subrecord and the total length of this segment should be
147 // multiples of 4.
148 assert(ThisRecord.size() % 4 == 0);
149 assert(CurrentSegment.length() % 4 == 0);
150
151 return Error::success();
152 }
153 };
154
155 } // end namespace codeview
156 } // end namespace llvm
157
158 #endif // LLVM_DEBUGINFO_CODEVIEW_TYPESERIALIZER_H
None //===- TypeTableBuilder.h ---------------------------------------*- C++ -*-===//
0 //===- TypeTableBuilder.h ----------------------------------------*- C++-*-===//
11 //
22 // The LLVM Compiler Infrastructure
33 //
1010 #define LLVM_DEBUGINFO_CODEVIEW_TYPETABLEBUILDER_H
1111
1212 #include "llvm/ADT/ArrayRef.h"
13 #include "llvm/ADT/Optional.h"
14 #include "llvm/ADT/SmallVector.h"
1315 #include "llvm/DebugInfo/CodeView/CodeView.h"
16 #include "llvm/DebugInfo/CodeView/RecordSerialization.h"
17 #include "llvm/DebugInfo/CodeView/SimpleTypeSerializer.h"
1418 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
1519 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
16 #include "llvm/DebugInfo/CodeView/TypeSerializer.h"
20 #include "llvm/DebugInfo/CodeView/TypeRecordMapping.h"
21 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
1722 #include "llvm/Support/Allocator.h"
23 #include "llvm/Support/BinaryByteStream.h"
24 #include "llvm/Support/BinaryStreamWriter.h"
1825 #include "llvm/Support/Error.h"
19 #include
2026 #include
2127 #include
22 #include <type_traits>
28 #include <memory>
29 #include
2330
2431 namespace llvm {
2532 namespace codeview {
2633
27 class TypeTableBuilder {
28 private:
29 TypeIndex handleError(Error EC) const {
30 assert(false && "Couldn't write Type!");
31 consumeError(std::move(EC));
32 return TypeIndex();
33 }
34 class ContinuationRecordBuilder;
35 class TypeHasher;
3436
35 BumpPtrAllocator &Allocator;
36 TypeSerializer Serializer;
37 class TypeTableBuilder : public TypeVisitorCallbacks {
38
39 BumpPtrAllocator &RecordStorage;
40 SimpleTypeSerializer SimpleSerializer;
41
42 /// Private type record hashing implementation details are handled here.
43 std::unique_ptr Hasher;
44
45 /// Contains a list of all records indexed by TypeIndex.toArrayIndex().
46 SmallVector, 2> SeenRecords;
47
48 /// Temporary storage that we use to copy a record's data while re-writing
49 /// its type indices.
50 SmallVector RemapStorage;
3751
3852 public:
39 explicit TypeTableBuilder(BumpPtrAllocator &Allocator,
40 bool WriteUnique = true)
41 : Allocator(Allocator), Serializer(Allocator, WriteUnique) {}
42 TypeTableBuilder(const TypeTableBuilder &) = delete;
43 TypeTableBuilder &operator=(const TypeTableBuilder &) = delete;
53 explicit TypeTableBuilder(BumpPtrAllocator &Storage, bool Hash = true);
54 ~TypeTableBuilder() override;
4455
45 bool empty() const { return Serializer.records().empty(); }
56 void reset();
4657
47 BumpPtrAllocator &getAllocator() const { return Allocator; }
58 bool empty() const { return SeenRecords.empty(); }
4859
49 template TypeIndex writeKnownType(T &Record) {
50 static_assert(!std::is_same::value,
51 "Can't serialize FieldList!");
60 TypeIndex nextTypeIndex() const;
5261
53 CVType Type;
54 Type.Type = static_cast(Record.getKind());
55 if (auto EC = Serializer.visitTypeBegin(Type))
56 return handleError(std::move(EC));
57 if (auto EC = Serializer.visitKnownRecord(Type, Record))
58 return handleError(std::move(EC));
62 BumpPtrAllocator &getAllocator() { return RecordStorage; }
5963
60 auto ExpectedIndex = Serializer.visitTypeEndGetIndex(Type);
61 if (!ExpectedIndex)
62 return handleError(ExpectedIndex.takeError());
64 ArrayRef> records() const;
65 TypeIndex insertRecordBytes(ArrayRef &Record);
66 TypeIndex insertRecord(const RemappedType &Record);
67 TypeIndex insertRecord(ContinuationRecordBuilder &Builder);
6368
64 return *ExpectedIndex;
65 }
66
67 TypeIndex writeSerializedRecord(ArrayRef Record) {
68 return Serializer.insertRecordBytes(Record);
69 }
70
71 TypeIndex writeSerializedRecord(const RemappedType &Record) {
72 return Serializer.insertRecord(Record);
69 template TypeIndex writeLeafType(T &Record) {
70 ArrayRef Data = SimpleSerializer.serialize(Record);
71 return insertRecordBytes(Data);
7372 }
7473
7574 template void ForEachRecord(TFunc Func) {
7675 uint32_t Index = TypeIndex::FirstNonSimpleIndex;
7776
78 for (auto Record : Serializer.records()) {
77 for (auto Record : SeenRecords) {
7978 Func(TypeIndex(Index), Record);
8079 ++Index;
8180 }
82 }
83
84 ArrayRef> records() const { return Serializer.records(); }
85 };
86
87 class FieldListRecordBuilder {
88 TypeTableBuilder &TypeTable;
89 BumpPtrAllocator Allocator;
90 TypeSerializer TempSerializer;
91 CVType Type;
92
93 public:
94 explicit FieldListRecordBuilder(TypeTableBuilder &TypeTable)
95 : TypeTable(TypeTable), TempSerializer(Allocator, false) {
96 Type.Type = TypeLeafKind::LF_FIELDLIST;
97 }
98
99 void begin() {
100 TempSerializer.reset();
101
102 if (auto EC = TempSerializer.visitTypeBegin(Type))
103 consumeError(std::move(EC));
104 }
105
106 template void writeMemberType(T &Record) {
107 CVMemberRecord CVMR;
108 CVMR.Kind = static_cast(Record.getKind());
109 if (auto EC = TempSerializer.visitMemberBegin(CVMR))
110 consumeError(std::move(EC));
111 if (auto EC = TempSerializer.visitKnownMember(CVMR, Record))
112 consumeError(std::move(EC));
113 if (auto EC = TempSerializer.visitMemberEnd(CVMR))
114 consumeError(std::move(EC));
115 }
116
117 TypeIndex end(bool Write) {
118 TypeIndex Index;
119 if (auto EC = TempSerializer.visitTypeEnd(Type)) {
120 consumeError(std::move(EC));
121 return TypeIndex();
122 }
123
124 if (Write) {
125 for (auto Record : TempSerializer.records())
126 Index = TypeTable.writeSerializedRecord(Record);
127 }
128
129 return Index;
13081 }
13182 };
13283
2626 namespace llvm {
2727
2828 namespace codeview {
29
3029 class TypeTableBuilder;
31
32 } // end namespace codeview
30 }
3331
3432 namespace CodeViewYAML {
3533
4745 struct LeafRecord {
4846 std::shared_ptr Leaf;
4947
50 codeview::CVType toCodeViewRecord(BumpPtrAllocator &Allocator) const;
51 codeview::CVType toCodeViewRecord(codeview::TypeTableBuilder &TS) const;
48 codeview::CVType
49 toCodeViewRecord(codeview::TypeTableBuilder &Serializer) const;
5250 static Expected fromCodeViewRecord(codeview::CVType Type);
5351 };
5452
134134 /// causing the underlying data to grow. This class owns the underlying data.
135135 class AppendingBinaryByteStream : public WritableBinaryStream {
136136 std::vector Data;
137 llvm::support::endianness Endian;
137 llvm::support::endianness Endian = llvm::support::little;
138138
139139 public:
140140 AppendingBinaryByteStream() = default;
152152
153153 Buffer = makeArrayRef(Data).slice(Offset, Size);
154154 return Error::success();
155 }
156
157 void insert(uint32_t Offset, ArrayRef Bytes) {
158 Data.insert(Data.begin() + Offset, Bytes.begin(), Bytes.end());
155159 }
156160
157161 Error readLongestContiguousChunk(uint32_t Offset,
4141 #include "llvm/Config/llvm-config.h"
4242 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
4343 #include "llvm/DebugInfo/CodeView/CodeView.h"
44 #include "llvm/DebugInfo/CodeView/ContinuationRecordBuilder.h"
4445 #include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h"
4546 #include "llvm/DebugInfo/CodeView/Line.h"
4647 #include "llvm/DebugInfo/CodeView/SymbolRecord.h"
277278 // Build the fully qualified name of the scope.
278279 std::string ScopeName = getFullyQualifiedName(Scope);
279280 StringIdRecord SID(TypeIndex(), ScopeName);
280 auto TI = TypeTable.writeKnownType(SID);
281 auto TI = TypeTable.writeLeafType(SID);
281282 return recordTypeIndexForDINode(Scope, TI);
282283 }
283284
302303 TypeIndex ClassType = getTypeIndex(Class);
303304 MemberFuncIdRecord MFuncId(ClassType, getMemberFunctionType(SP, Class),
304305 DisplayName);
305 TI = TypeTable.writeKnownType(MFuncId);
306 TI = TypeTable.writeLeafType(MFuncId);
306307 } else {
307308 // Otherwise, this must be a free function.
308309 TypeIndex ParentScope = getScopeIndex(Scope);
309310 FuncIdRecord FuncId(ParentScope, getTypeIndex(SP->getType()), DisplayName);
310 TI = TypeTable.writeKnownType(FuncId);
311 TI = TypeTable.writeLeafType(FuncId);
311312 }
312313
313314 return recordTypeIndexForDINode(SP, TI);
13031304
13041305 StringRef Name = (i == 0) ? Ty->getName() : "";
13051306 ArrayRecord AR(ElementTypeIndex, IndexType, ArraySize, Name);
1306 ElementTypeIndex = TypeTable.writeKnownType(AR);
1307 ElementTypeIndex = TypeTable.writeLeafType(AR);
13071308 }
13081309
13091310 return ElementTypeIndex;
14361437 // do.
14371438 PointerOptions PO = PointerOptions::None;
14381439 PointerRecord PR(PointeeTI, PK, PM, PO, Ty->getSizeInBits() / 8);
1439 return TypeTable.writeKnownType(PR);
1440 return TypeTable.writeLeafType(PR);
14401441 }
14411442
14421443 static PointerToMemberRepresentation
14871488 MemberPointerInfo MPI(
14881489 ClassTI, translatePtrToMemberRep(SizeInBytes, IsPMF, Ty->getFlags()));
14891490 PointerRecord PR(PointeeTI, PK, PM, PO, SizeInBytes, MPI);
1490 return TypeTable.writeKnownType(PR);
1491 return TypeTable.writeLeafType(PR);
14911492 }
14921493
14931494 /// Given a DWARF calling convention, get the CodeView equivalent. If we don't
15261527 }
15271528 TypeIndex ModifiedTI = getTypeIndex(BaseTy);
15281529 ModifierRecord MR(ModifiedTI, Mods);
1529 return TypeTable.writeKnownType(MR);
1530 return TypeTable.writeLeafType(MR);
15301531 }
15311532
15321533 TypeIndex CodeViewDebug::lowerTypeFunction(const DISubroutineType *Ty) {
15431544 }
15441545
15451546 ArgListRecord ArgListRec(TypeRecordKind::ArgList, ArgTypeIndices);
1546 TypeIndex ArgListIndex = TypeTable.writeKnownType(ArgListRec);
1547 TypeIndex ArgListIndex = TypeTable.writeLeafType(ArgListRec);
15471548
15481549 CallingConvention CC = dwarfCCToCodeView(Ty->getCC());
15491550
15501551 ProcedureRecord Procedure(ReturnTypeIndex, CC, FunctionOptions::None,
15511552 ArgTypeIndices.size(), ArgListIndex);
1552 return TypeTable.writeKnownType(Procedure);
1553 return TypeTable.writeLeafType(Procedure);
15531554 }
15541555
15551556 TypeIndex CodeViewDebug::lowerTypeMemberFunction(const DISubroutineType *Ty,
15771578 }
15781579
15791580 ArgListRecord ArgListRec(TypeRecordKind::ArgList, ArgTypeIndices);
1580 TypeIndex ArgListIndex = TypeTable.writeKnownType(ArgListRec);
1581 TypeIndex ArgListIndex = TypeTable.writeLeafType(ArgListRec);
15811582
15821583 CallingConvention CC = dwarfCCToCodeView(Ty->getCC());
15831584
15851586 MemberFunctionRecord MFR(ReturnTypeIndex, ClassType, ThisTypeIndex, CC,
15861587 FunctionOptions::None, ArgTypeIndices.size(),
15871588 ArgListIndex, ThisAdjustment);
1588 TypeIndex TI = TypeTable.writeKnownType(MFR);
1589
1590 return TI;
1589 return TypeTable.writeLeafType(MFR);
15911590 }
15921591
15931592 TypeIndex CodeViewDebug::lowerTypeVFTableShape(const DIDerivedType *Ty) {
15961595 SmallVector Slots(VSlotCount, VFTableSlotKind::Near);
15971596
15981597 VFTableShapeRecord VFTSR(Slots);
1599 return TypeTable.writeKnownType(VFTSR);
1598 return TypeTable.writeLeafType(VFTSR);
16001599 }
16011600
16021601 static MemberAccess translateAccessFlags(unsigned RecordTag, unsigned Flags) {
16871686 if (Ty->isForwardDecl()) {
16881687 CO |= ClassOptions::ForwardReference;
16891688 } else {
1690 FieldListRecordBuilder FLRB(TypeTable);
1691
1692 FLRB.begin();
1689 ContinuationRecordBuilder ContinuationBuilder;
1690 ContinuationBuilder.begin(ContinuationRecordKind::FieldList);
16931691 for (const DINode *Element : Ty->getElements()) {
16941692 // We assume that the frontend provides all members in source declaration
16951693 // order, which is what MSVC does.
16971695 EnumeratorRecord ER(MemberAccess::Public,
16981696 APSInt::getUnsigned(Enumerator->getValue()),
16991697 Enumerator->getName());
1700 FLRB.writeMemberType(ER);
1698 ContinuationBuilder.writeMemberType(ER);
17011699 EnumeratorCount++;
17021700 }
17031701 }
1704 FTI = FLRB.end(true);
1702 FTI = TypeTable.insertRecord(ContinuationBuilder);
17051703 }
17061704
17071705 std::string FullName = getFullyQualifiedName(Ty);
17081706
17091707 EnumRecord ER(EnumeratorCount, CO, FTI, FullName, Ty->getIdentifier(),
17101708 getTypeIndex(Ty->getBaseType()));
1711 return TypeTable.writeKnownType(ER);
1709 return TypeTable.writeLeafType(ER);
17121710 }
17131711
17141712 //===----------------------------------------------------------------------===//
18111809 std::string FullName = getFullyQualifiedName(Ty);
18121810 ClassRecord CR(Kind, 0, CO, TypeIndex(), TypeIndex(), TypeIndex(), 0,
18131811 FullName, Ty->getIdentifier());
1814 TypeIndex FwdDeclTI = TypeTable.writeKnownType(CR);
1812 TypeIndex FwdDeclTI = TypeTable.writeLeafType(CR);
18151813 if (!Ty->isForwardDecl())
18161814 DeferredCompleteTypes.push_back(Ty);
18171815 return FwdDeclTI;
18371835
18381836 ClassRecord CR(Kind, FieldCount, CO, FieldTI, TypeIndex(), VShapeTI,
18391837 SizeInBytes, FullName, Ty->getIdentifier());
1840 TypeIndex ClassTI = TypeTable.writeKnownType(CR);
1838 TypeIndex ClassTI = TypeTable.writeLeafType(CR);
18411839
18421840 if (const auto *File = Ty->getFile()) {
18431841 StringIdRecord SIDR(TypeIndex(0x0), getFullFilepath(File));
1844 TypeIndex SIDI = TypeTable.writeKnownType(SIDR);
1842 TypeIndex SIDI = TypeTable.writeLeafType(SIDR);
1843
18451844 UdtSourceLineRecord USLR(ClassTI, SIDI, Ty->getLine());
1846 TypeTable.writeKnownType(USLR);
1845 TypeTable.writeLeafType(USLR);
18471846 }
18481847
18491848 addToUDTs(Ty);
18561855 ClassOptions::ForwardReference | getCommonClassOptions(Ty);
18571856 std::string FullName = getFullyQualifiedName(Ty);
18581857 UnionRecord UR(0, CO, TypeIndex(), 0, FullName, Ty->getIdentifier());
1859 TypeIndex FwdDeclTI = TypeTable.writeKnownType(UR);
1858 TypeIndex FwdDeclTI = TypeTable.writeLeafType(UR);
18601859 if (!Ty->isForwardDecl())
18611860 DeferredCompleteTypes.push_back(Ty);
18621861 return FwdDeclTI;
18781877
18791878 UnionRecord UR(FieldCount, CO, FieldTI, SizeInBytes, FullName,
18801879 Ty->getIdentifier());
1881 TypeIndex UnionTI = TypeTable.writeKnownType(UR);
1880 TypeIndex UnionTI = TypeTable.writeLeafType(UR);
18821881
18831882 StringIdRecord SIR(TypeIndex(0x0), getFullFilepath(Ty->getFile()));
1884 TypeIndex SIRI = TypeTable.writeKnownType(SIR);
1883 TypeIndex SIRI = TypeTable.writeLeafType(SIR);
1884
18851885 UdtSourceLineRecord USLR(UnionTI, SIRI, Ty->getLine());
1886 TypeTable.writeKnownType(USLR);
1886 TypeTable.writeLeafType(USLR);
18871887
18881888 addToUDTs(Ty);
18891889
18981898 // list record.
18991899 unsigned MemberCount = 0;
19001900 ClassInfo Info = collectClassInfo(Ty);
1901 FieldListRecordBuilder FLBR(TypeTable);
1902 FLBR.begin();
1901 ContinuationRecordBuilder ContinuationBuilder;
1902 ContinuationBuilder.begin(ContinuationRecordKind::FieldList);
19031903
19041904 // Create base classes.
19051905 for (const DIDerivedType *I : Info.Inheritance) {
19171917 getTypeIndex(I->getBaseType()), getVBPTypeIndex(), VBPtrOffset,
19181918 VBTableIndex);
19191919
1920 FLBR.writeMemberType(VBCR);
1920 ContinuationBuilder.writeMemberType(VBCR);
19211921 } else {
19221922 assert(I->getOffsetInBits() % 8 == 0 &&
19231923 "bases must be on byte boundaries");
19241924 BaseClassRecord BCR(translateAccessFlags(Ty->getTag(), I->getFlags()),
19251925 getTypeIndex(I->getBaseType()),
19261926 I->getOffsetInBits() / 8);
1927 FLBR.writeMemberType(BCR);
1927 ContinuationBuilder.writeMemberType(BCR);
19281928 }
19291929 }
19301930
19381938
19391939 if (Member->isStaticMember()) {
19401940 StaticDataMemberRecord SDMR(Access, MemberBaseType, MemberName);
1941 FLBR.writeMemberType(SDMR);
1941 ContinuationBuilder.writeMemberType(SDMR);
19421942 MemberCount++;
19431943 continue;
19441944 }
19471947 if ((Member->getFlags() & DINode::FlagArtificial) &&
19481948 Member->getName().startswith("_vptr$")) {
19491949 VFPtrRecord VFPR(getTypeIndex(Member->getBaseType()));
1950 FLBR.writeMemberType(VFPR);
1950 ContinuationBuilder.writeMemberType(VFPR);
19511951 MemberCount++;
19521952 continue;
19531953 }
19641964 StartBitOffset -= MemberOffsetInBits;
19651965 BitFieldRecord BFR(MemberBaseType, Member->getSizeInBits(),
19661966 StartBitOffset);
1967 MemberBaseType = TypeTable.writeKnownType(BFR);
1967 MemberBaseType = TypeTable.writeLeafType(BFR);
19681968 }
19691969 uint64_t MemberOffsetInBytes = MemberOffsetInBits / 8;
19701970 DataMemberRecord DMR(Access, MemberBaseType, MemberOffsetInBytes,
19711971 MemberName);
1972 FLBR.writeMemberType(DMR);
1972 ContinuationBuilder.writeMemberType(DMR);
19731973 MemberCount++;
19741974 }
19751975
19941994 }
19951995 assert(!Methods.empty() && "Empty methods map entry");
19961996 if (Methods.size() == 1)
1997 FLBR.writeMemberType(Methods[0]);
1997 ContinuationBuilder.writeMemberType(Methods[0]);
19981998 else {
1999 // FIXME: Make this use its own ContinuationBuilder so that
2000 // MethodOverloadList can be split correctly.
19992001 MethodOverloadListRecord MOLR(Methods);
2000 TypeIndex MethodList = TypeTable.writeKnownType(MOLR);
2002 TypeIndex MethodList = TypeTable.writeLeafType(MOLR);
2003
20012004 OverloadedMethodRecord OMR(Methods.size(), MethodList, Name);
2002 FLBR.writeMemberType(OMR);
2005 ContinuationBuilder.writeMemberType(OMR);
20032006 }
20042007 }
20052008
20062009 // Create nested classes.
20072010 for (const DIType *Nested : Info.NestedTypes) {
20082011 NestedTypeRecord R(getTypeIndex(DITypeRef(Nested)), Nested->getName());
2009 FLBR.writeMemberType(R);
2012 ContinuationBuilder.writeMemberType(R);
20102013 MemberCount++;
20112014 }
20122015
2013 TypeIndex FieldTI = FLBR.end(true);
2016 TypeIndex FieldTI = TypeTable.insertRecord(ContinuationBuilder);
20142017 return std::make_tuple(FieldTI, Info.VShapeTI, MemberCount,
20152018 !Info.NestedTypes.empty());
20162019 }
20192022 if (!VBPType.getIndex()) {
20202023 // Make a 'const int *' type.
20212024 ModifierRecord MR(TypeIndex::Int32(), ModifierOptions::Const);
2022 TypeIndex ModifiedTI = TypeTable.writeKnownType(MR);
2025 TypeIndex ModifiedTI = TypeTable.writeLeafType(MR);
20232026
20242027 PointerKind PK = getPointerSizeInBytes() == 8 ? PointerKind::Near64
20252028 : PointerKind::Near32;
20262029 PointerMode PM = PointerMode::Pointer;
20272030 PointerOptions PO = PointerOptions::None;
20282031 PointerRecord PR(ModifiedTI, PK, PM, PO, getPointerSizeInBytes());
2029
2030 VBPType = TypeTable.writeKnownType(PR);
2032 VBPType = TypeTable.writeLeafType(PR);
20312033 }
20322034
20332035 return VBPType;
20602062 : PointerKind::Near32,
20612063 PointerMode::LValueReference, PointerOptions::None,
20622064 Ty->getSizeInBits() / 8);
2063 return TypeTable.writeKnownType(PR);
2065 return TypeTable.writeLeafType(PR);
20642066 }
20652067
20662068 TypeIndex CodeViewDebug::getCompleteTypeIndex(DITypeRef TypeRef) {
0 add_llvm_library(LLVMDebugInfoCodeView
11 CodeViewError.cpp
22 CodeViewRecordIO.cpp
3 ContinuationRecordBuilder.cpp
34 CVSymbolVisitor.cpp
45 CVTypeVisitor.cpp
56 DebugChecksumsSubsection.cpp
2021 Line.cpp
2122 RecordName.cpp
2223 RecordSerialization.cpp
24 SimpleTypeSerializer.cpp
2325 StringsAndChecksums.cpp
2426 SymbolRecordMapping.cpp
2527 SymbolDumper.cpp
2830 TypeIndex.cpp
2931 TypeIndexDiscovery.cpp
3032 TypeRecordMapping.cpp
31 TypeSerializer.cpp
33 TypeTableBuilder.cpp
3234 TypeStreamMerger.cpp
3335 TypeTableCollection.cpp
3436
0 #include "llvm/DebugInfo/CodeView/ContinuationRecordBuilder.h"
1
2 using namespace llvm;
3 using namespace llvm::codeview;
4
5 namespace {
6 struct ContinuationRecord {
7 ulittle16_t Kind{uint16_t(TypeLeafKind::LF_INDEX)};
8 ulittle16_t Size{0};
9 ulittle32_t IndexRef{0xB0C0B0C0};
10 };
11
12 struct SegmentInjection {
13 SegmentInjection(TypeLeafKind Kind) { Prefix.RecordKind = Kind; }
14
15 ContinuationRecord Cont;
16 RecordPrefix Prefix;
17 };
18 } // namespace
19
20 static void addPadding(BinaryStreamWriter &Writer) {
21 uint32_t Align = Writer.getOffset() % 4;
22 if (Align == 0)
23 return;
24
25 int PaddingBytes = 4 - Align;
26 while (PaddingBytes > 0) {
27 uint8_t Pad = static_cast(LF_PAD0 + PaddingBytes);
28 cantFail(Writer.writeInteger(Pad));
29 --PaddingBytes;
30 }
31 }
32
33 static SegmentInjection InjectFieldList(TypeLeafKind::LF_FIELDLIST);
34 static SegmentInjection InjectMethodOverloadList(TypeLeafKind::LF_METHODLIST);
35
36 static constexpr uint32_t ContinuationLength = sizeof(ContinuationRecord);
37 static constexpr uint32_t MaxSegmentLength =
38 MaxRecordLength - ContinuationLength;
39
40 static inline TypeLeafKind getTypeLeafKind(ContinuationRecordKind CK) {
41 return (CK == ContinuationRecordKind::FieldList) ? LF_FIELDLIST
42 : LF_METHODLIST;
43 }
44
45 ContinuationRecordBuilder::ContinuationRecordBuilder()
46 : SegmentWriter(Buffer), Mapping(SegmentWriter) {}
47
48 ContinuationRecordBuilder::~ContinuationRecordBuilder() {}
49
50 void ContinuationRecordBuilder::begin(ContinuationRecordKind RecordKind) {
51 assert(!Kind.hasValue());
52 Kind = RecordKind;
53 Buffer.clear();
54 SegmentWriter.setOffset(0);
55 SegmentOffsets.clear();
56 SegmentOffsets.push_back(0);
57 assert(SegmentWriter.getOffset() == 0);
58 assert(SegmentWriter.getLength() == 0);
59
60 const SegmentInjection *FLI =
61 (RecordKind == ContinuationRecordKind::FieldList)
62 ? &InjectFieldList
63 : &InjectMethodOverloadList;
64 const uint8_t *FLIB = reinterpret_cast(FLI);
65 InjectedSegmentBytes =
66 ArrayRef(FLIB, FLIB + sizeof(SegmentInjection));
67
68 CVType Type;
69 Type.Type = getTypeLeafKind(RecordKind);
70 cantFail(Mapping.visitTypeBegin(Type));
71
72 // Seed the first trecord with an appropriate record prefix.
73 RecordPrefix Prefix;
74 Prefix.RecordLen = 0;
75 Prefix.RecordKind = Type.Type;
76 cantFail(SegmentWriter.writeObject(Prefix));
77 }
78
79 template
80 void ContinuationRecordBuilder::writeMemberType(RecordType &Record) {
81 assert(Kind.hasValue());
82
83 uint32_t OriginalOffset = SegmentWriter.getOffset();
84 CVMemberRecord CVMR;
85 CVMR.Kind = static_cast(Record.getKind());
86
87 // Member Records aren't length-prefixed, they only have a 2-byte TypeLeafKind
88 // at the beginning.
89 cantFail(SegmentWriter.writeEnum(CVMR.Kind));
90
91 // Let the Mapping handle the rest.
92 cantFail(Mapping.visitMemberBegin(CVMR));
93 cantFail(Mapping.visitKnownMember(CVMR, Record));
94 cantFail(Mapping.visitMemberEnd(CVMR));
95
96 // Make sure it's padded to 4 bytes.
97 addPadding(SegmentWriter);
98 assert(getCurrentSegmentLength() % 4 == 0);
99
100 // The maximum length of a single segment is 64KB minus the size to insert a
101 // continuation. So if we are over that, inject a continuation between the
102 // previous member and the member that was just written, then end the previous
103 // segment after the continuation and begin a new one with the just-written
104 // member.
105 if (getCurrentSegmentLength() > MaxSegmentLength) {
106 // We need to inject some bytes before the member we just wrote but after
107 // the previous member. Save off the length of the member we just wrote so
108 // that we can do some sanity checking on it.
109 uint32_t MemberLength = SegmentWriter.getOffset() - OriginalOffset;
110 insertSegmentEnd(OriginalOffset);
111 // Since this member now becomes a new top-level record, it should have
112 // gotten a RecordPrefix injected, and that RecordPrefix + the member we
113 // just wrote should now constitute the entirety of the current "new"
114 // segment.
115 assert(getCurrentSegmentLength() == MemberLength + sizeof(RecordPrefix));
116 }
117
118 assert(getCurrentSegmentLength() % 4 == 0);
119 assert(getCurrentSegmentLength() <= MaxSegmentLength);
120 }
121
122 uint32_t ContinuationRecordBuilder::getCurrentSegmentLength() const {
123 return SegmentWriter.getOffset() - SegmentOffsets.back();
124 }
125
126 void ContinuationRecordBuilder::insertSegmentEnd(uint32_t Offset) {
127 uint32_t SegmentBegin = SegmentOffsets.back();
128 assert(Offset > SegmentBegin);
129 assert(Offset - SegmentBegin <= MaxSegmentLength);
130
131 // We need to make space for the continuation record. For now we can't fill
132 // out the length or the TypeIndex of the back-reference, but we need the
133 // space to at least be there.
134 Buffer.insert(Offset, InjectedSegmentBytes);
135
136 uint32_t NewSegmentBegin = Offset + ContinuationLength;
137 uint32_t SegmentLength = NewSegmentBegin - SegmentOffsets.back();
138
139 assert(SegmentLength % 4 == 0);
140 assert(SegmentLength <= MaxRecordLength);
141 SegmentOffsets.push_back(NewSegmentBegin);
142
143 // Seek to the end so that we can keep writing against the new segment.
144 SegmentWriter.setOffset(SegmentWriter.getLength());
145 assert(SegmentWriter.bytesRemaining() == 0);
146 }
147
148 CVType ContinuationRecordBuilder::createSegmentRecord(
149 uint32_t OffBegin, uint32_t OffEnd, Optional RefersTo) {
150 assert(OffEnd - OffBegin <= USHRT_MAX);
151
152 MutableArrayRef Data = Buffer.data();
153 Data = Data.slice(OffBegin, OffEnd - OffBegin);
154
155 CVType Type;
156 Type.Type = getTypeLeafKind(*Kind);
157 Type.RecordData = Data;
158
159 // Write the length to the RecordPrefix, making sure it does not include
160 // sizeof(RecordPrefix.Length)
161 RecordPrefix *Prefix = reinterpret_cast(Data.data());
162 assert(Prefix->RecordKind == Type.Type);
163 Prefix->RecordLen = Data.size() - sizeof(RecordPrefix::RecordLen);
164
165 if (RefersTo.hasValue()) {
166 auto Continuation = Data.take_back(ContinuationLength);
167 ContinuationRecord *CR =
168 reinterpret_cast(Continuation.data());
169 assert(CR->Kind == TypeLeafKind::LF_INDEX);
170 assert(CR->IndexRef == 0xB0C0B0C0);
171 CR->IndexRef = RefersTo->getIndex();
172 }
173
174 return Type;
175 }
176
177 std::vector ContinuationRecordBuilder::end(TypeIndex Index) {
178 CVType Type;
179 Type.Type = getTypeLeafKind(*Kind);
180 cantFail(Mapping.visitTypeEnd(Type));
181
182 // We're now done, and we have a series of segments each beginning at an
183 // offset specified in the SegmentOffsets array. We now need to iterate
184 // over each segment and post-process them in the following two ways:
185 // 1) Each top-level record has a RecordPrefix whose type is either
186 // LF_FIELDLIST or LF_METHODLIST, but the Length field is still 0.
187 // Those should all be set to the correct length now.
188 // 2) Each continuation record has an IndexRef field which we set to the
189 // magic value 0xB0C0B0C0. Now that the caller has told us the TypeIndex
190 // they want this sequence to start from, we can go through and update
191 // each one.
192 //
193 // Logically, the sequence of records we've built up looks like this:
194 //
195 // SegmentOffsets[0]: (Initially: uninitialized)
196 // SegmentOffsets[0]+2: LF_FIELDLIST
197 // SegmentOffsets[0]+4: Member[0]
198 // SegmentOffsets[0]+?: ...
199 // SegmentOffsets[0]+?: Member[4]
200 // SegmentOffsets[1]-8: LF_INDEX
201 // SegmentOffsets[1]-6: 0
202 // SegmentOffsets[1]-4: (Initially: 0xB0C0B0C0)
203 //
204 // SegmentOffsets[1]: (Initially: uninitialized)
205 // SegmentOffsets[1]+2: LF_FIELDLIST
206 // SegmentOffsets[1]+4: Member[0]
207 // SegmentOffsets[1]+?: ...
208 // SegmentOffsets[1]+?: Member[s]
209 // SegmentOffsets[2]-8: LF_INDEX
210 // SegmentOffsets[2]-6: 0
211 // SegmentOffsets[2]-4: (Initially: 0xB0C0B0C0)
212 //
213 // ...
214 //
215 // SegmentOffsets[N]: (Initially: uninitialized)
216 // SegmentOffsets[N]+2: LF_FIELDLIST
217 // SegmentOffsets[N]+4: Member[0]
218 // SegmentOffsets[N]+?: ...
219 // SegmentOffsets[N]+?: Member[t]
220 //
221 // And this is the way we have laid them out in the serialization buffer. But
222 // we cannot actually commit them to the underlying stream this way, due to
223 // the topological sorting requirement of a type stream (specifically,
224 // TypeIndex references can only point backwards, not forwards). So the
225 // sequence that we return to the caller contains the records in reverse
226 // order, which is the proper order for committing the serialized records.
227
228 std::vector Types;
229 Types.reserve(SegmentOffsets.size());
230
231 auto SO = makeArrayRef(SegmentOffsets);
232
233 uint32_t End = SegmentWriter.getOffset();
234
235 Optional RefersTo;
236 for (uint32_t Offset : reverse(SO)) {
237 Types.push_back(createSegmentRecord(Offset, End, RefersTo));
238
239 End = Offset;
240 RefersTo = Index++;
241 }
242
243 Kind.reset();
244 return Types;
245 }
246
247 // Explicitly instantiate the member function for each known type so that we can
248 // implement this in the cpp file.
249 #define TYPE_RECORD(EnumName, EnumVal, Name)
250 #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
251 #define MEMBER_RECORD(EnumName, EnumVal, Name) \
252 template void llvm::codeview::ContinuationRecordBuilder::writeMemberType( \
253 Name##Record &Record);
254 #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
255 #include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
0 #include "llvm/DebugInfo/CodeView/SimpleTypeSerializer.h"
1
2 using namespace llvm;
3 using namespace llvm::codeview;
4
5 static void writeRecordPrefix(BinaryStreamWriter &Writer, TypeLeafKind Kind) {
6 RecordPrefix Prefix;
7 Prefix.RecordKind = Kind;
8 Prefix.RecordLen = 0;
9 cantFail(Writer.writeObject(Prefix));
10 }
11
12 static void addPadding(BinaryStreamWriter &Writer) {
13 uint32_t Align = Writer.getOffset() % 4;
14 if (Align == 0)
15 return;
16
17 int PaddingBytes = 4 - Align;
18 while (PaddingBytes > 0) {
19 uint8_t Pad = static_cast(LF_PAD0 + PaddingBytes);
20 cantFail(Writer.writeInteger(Pad));
21 --PaddingBytes;
22 }
23 }
24
25 SimpleTypeSerializer::SimpleTypeSerializer() : ScratchBuffer(MaxRecordLength) {}
26
27 SimpleTypeSerializer::~SimpleTypeSerializer() {}
28
29 template
30 ArrayRef SimpleTypeSerializer::serialize(T &Record) {
31 BinaryStreamWriter Writer(ScratchBuffer, support::little);
32 TypeRecordMapping Mapping(Writer);
33
34 CVType CVT;
35 CVT.Type = static_cast(Record.getKind());
36
37 writeRecordPrefix(Writer, CVT.Type);
38
39 cantFail(Mapping.visitTypeBegin(CVT));
40 cantFail(Mapping.visitKnownRecord(CVT, Record));
41 cantFail(Mapping.visitTypeEnd(CVT));
42
43 addPadding(Writer);
44
45 RecordPrefix *Prefix = reinterpret_cast(ScratchBuffer.data());
46
47 Prefix->RecordKind = CVT.kind();
48 Prefix->RecordLen = Writer.getOffset() - sizeof(uint16_t);
49
50 return {ScratchBuffer.data(), Writer.getOffset()};
51 }
52
53 // Explicitly instantiate the member function for each known type so that we can
54 // implement this in the cpp file.
55 #define TYPE_RECORD(EnumName, EnumVal, Name) \
56 template ArrayRef llvm::codeview::SimpleTypeSerializer::serialize( \
57 Name##Record &Record);
58 #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
59 #define MEMBER_RECORD(EnumName, EnumVal, Name)
60 #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
61 #include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
425425
426426 Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
427427 OneMethodRecord &Record) {
428 MapOneMethodRecord Mapper(false);
428 const bool IsFromOverloadList = (TypeKind == LF_METHODLIST);
429 MapOneMethodRecord Mapper(IsFromOverloadList);
429430 return Mapper(IO, Record);
430431 }
431432
+0
-389
lib/DebugInfo/CodeView/TypeSerializer.cpp less more
None //===- TypeSerialzier.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/TypeSerializer.h"
10 #include "llvm/ADT/ArrayRef.h"
11 #include "llvm/ADT/DenseSet.h"
12 #include "llvm/ADT/STLExtras.h"
13 #include "llvm/DebugInfo/CodeView/CodeView.h"
14 #include "llvm/DebugInfo/CodeView/RecordSerialization.h"
15 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
16 #include "llvm/Support/Allocator.h"
17 #include "llvm/Support/BinaryByteStream.h"
18 #include "llvm/Support/BinaryStreamWriter.h"
19 #include "llvm/Support/Endian.h"
20 #include "llvm/Support/Error.h"
21 #include
22 #include
23 #include
24 #include
25
26 using namespace llvm;
27 using namespace llvm::codeview;
28
29 namespace {
30
31 struct HashedType {
32 uint64_t Hash;
33 const uint8_t *Data;
34 unsigned Size; // FIXME: Go to uint16_t?
35 TypeIndex Index;
36 };
37
38 /// Wrapper around a poitner to a HashedType. Hash and equality operations are
39 /// based on data in the pointee.
40 struct HashedTypePtr {
41 HashedTypePtr() = default;
42 HashedTypePtr(HashedType *Ptr) : Ptr(Ptr) {}
43
44 HashedType *Ptr = nullptr;
45 };
46
47 } // end anonymous namespace
48
49 namespace llvm {
50
51 template <> struct DenseMapInfo {
52 static inline HashedTypePtr getEmptyKey() { return HashedTypePtr(nullptr); }
53
54 static inline HashedTypePtr getTombstoneKey() {
55 return HashedTypePtr(reinterpret_cast(1));
56 }
57
58 static unsigned getHashValue(HashedTypePtr Val) {
59 assert(Val.Ptr != getEmptyKey().Ptr && Val.Ptr != getTombstoneKey().Ptr);
60 return Val.Ptr->Hash;
61 }
62
63 static bool isEqual(HashedTypePtr LHSP, HashedTypePtr RHSP) {
64 HashedType *LHS = LHSP.Ptr;
65 HashedType *RHS = RHSP.Ptr;
66 if (RHS == getEmptyKey().Ptr || RHS == getTombstoneKey().Ptr)
67 return LHS == RHS;
68 if (LHS->Hash != RHS->Hash || LHS->Size != RHS->Size)
69 return false;
70 return ::memcmp(LHS->Data, RHS->Data, LHS->Size) == 0;
71 }
72 };
73
74 } // end namespace llvm
75
76 /// Private implementation so that we don't leak our DenseMap instantiations to
77 /// users.
78 class llvm::codeview::TypeHasher {
79 private:
80 /// Storage for type record provided by the caller. Records will outlive the
81 /// hasher object, so they should be allocated here.
82 BumpPtrAllocator &RecordStorage;
83
84 /// Storage for hash keys. These only need to live as long as the hashing
85 /// operation.
86 BumpPtrAllocator KeyStorage;
87
88 /// Hash table. We really want a DenseMap, TypeIndex> here,
89 /// but DenseMap is inefficient when the keys are long (like type records)
90 /// because it recomputes the hash value of every key when it grows. This
91 /// value type stores the hash out of line in KeyStorage, so that table
92 /// entries are small and easy to rehash.
93 DenseSet HashedRecords;
94
95 public:
96 TypeHasher(BumpPtrAllocator &RecordStorage) : RecordStorage(RecordStorage) {}
97
98 void reset() { HashedRecords.clear(); }
99
100 /// Takes the bytes of type record, inserts them into the hash table, saves
101 /// them, and returns a pointer to an identical stable type record along with
102 /// its type index in the destination stream.
103 TypeIndex getOrCreateRecord(ArrayRef &Record, TypeIndex TI);
104 };
105
106 TypeIndex TypeHasher::getOrCreateRecord(ArrayRef &Record,
107 TypeIndex TI) {
108 assert(Record.size() < UINT32_MAX && "Record too big");
109 assert(Record.size() % 4 == 0 && "Record is not aligned to 4 bytes!");
110
111 // Compute the hash up front so we can store it in the key.
112 HashedType TempHashedType = {hash_value(Record), Record.data(),
113 unsigned(Record.size()), TI};
114 auto Result = HashedRecords.insert(HashedTypePtr(&TempHashedType));
115 HashedType *&Hashed = Result.first->Ptr;
116
117 if (Result.second) {
118 // This was a new type record. We need stable storage for both the key and
119 // the record. The record should outlive the hashing operation.
120 Hashed = KeyStorage.Allocate();
121 *Hashed = TempHashedType;
122
123 uint8_t *Stable = RecordStorage.Allocate(Record.size());
124 memcpy(Stable, Record.data(), Record.size());
125 Hashed->Data = Stable;
126 assert(Hashed->Size == Record.size());
127 }
128
129 // Update the caller's copy of Record to point a stable copy.
130 Record = ArrayRef(Hashed->Data, Hashed->Size);
131 return Hashed->Index;
132 }
133
134 TypeIndex TypeSerializer::nextTypeIndex() const {
135 return TypeIndex::fromArrayIndex(SeenRecords.size());
136 }
137
138 bool TypeSerializer::isInFieldList() const {
139 return TypeKind.hasValue() && *TypeKind == TypeLeafKind::LF_FIELDLIST;
140 }
141
142 MutableArrayRef TypeSerializer::getCurrentSubRecordData() {
143 assert(isInFieldList());
144 return getCurrentRecordData().drop_front(CurrentSegment.length());
145 }
146
147 MutableArrayRef TypeSerializer::getCurrentRecordData() {
148 return MutableArrayRef(RecordBuffer).take_front(Writer.getOffset());
149 }
150
151 Error TypeSerializer::writeRecordPrefix(TypeLeafKind Kind) {
152 RecordPrefix Prefix;
153 Prefix.RecordKind = Kind;
154 Prefix.RecordLen = 0;
155 if (auto EC = Writer.writeObject(Prefix))
156 return EC;
157 return Error::success();
158 }
159
160 Expected>
161 TypeSerializer::addPadding(MutableArrayRef Record) {
162 uint32_t Align = Record.size() % 4;
163 if (Align == 0)
164 return Record;
165
166 int PaddingBytes = 4 - Align;
167 int N = PaddingBytes;
168 while (PaddingBytes > 0) {
169 uint8_t Pad = static_cast(LF_PAD0 + PaddingBytes);
170 if (auto EC = Writer.writeInteger(Pad))
171 return std::move(EC);
172 --PaddingBytes;
173 }
174 return MutableArrayRef(Record.data(), Record.size() + N);
175 }
176
177 TypeSerializer::TypeSerializer(BumpPtrAllocator &Storage, bool Hash)
178 : RecordStorage(Storage), RecordBuffer(MaxRecordLength * 2),
179 Stream(RecordBuffer, support::little), Writer(Stream),
180 Mapping(Writer) {
181 // RecordBuffer needs to be able to hold enough data so that if we are 1
182 // byte short of MaxRecordLen, and then we try to write MaxRecordLen bytes,
183 // we won't overflow.
184 if (Hash)
185 Hasher = llvm::make_unique(Storage);
186 }
187
188 TypeSerializer::~TypeSerializer() = default;
189
190 ArrayRef> TypeSerializer::records() const {
191 return SeenRecords;
192 }
193
194 void TypeSerializer::reset() {
195 if (Hasher)
196 Hasher->reset();
197 Writer.setOffset(0);
198 CurrentSegment = RecordSegment();
199 FieldListSegments.clear();
200 TypeKind.reset();
201 MemberKind.reset();
202 SeenRecords.clear();
203 }
204
205 TypeIndex TypeSerializer::insertRecordBytes(ArrayRef &Record) {
206 assert(!TypeKind.hasValue() && "Already in a type mapping!");
207 assert(Writer.getOffset() == 0 && "Stream has data already!");
208
209 if (Hasher) {
210 TypeIndex ActualTI = Hasher->getOrCreateRecord(Record, nextTypeIndex());
211 if (nextTypeIndex() == ActualTI)
212 SeenRecords.push_back(Record);
213 return ActualTI;
214 }
215
216 TypeIndex NewTI = nextTypeIndex();
217 uint8_t *Stable = RecordStorage.Allocate(Record.size());
218 memcpy(Stable, Record.data(), Record.size());
219 Record = ArrayRef(Stable, Record.size());
220 SeenRecords.push_back(Record);
221 return NewTI;
222 }
223
224 TypeIndex TypeSerializer::insertRecord(const RemappedType &Record) {
225 assert(!TypeKind.hasValue() && "Already in a type mapping!");
226 assert(Writer.getOffset() == 0 && "Stream has data already!");
227
228 TypeIndex TI;
229 ArrayRef OriginalData = Record.OriginalRecord.RecordData;
230 if (Record.Mappings.empty()) {
231 // This record did not remap any type indices. Just write it.
232 return insertRecordBytes(OriginalData);
233 }
234
235 // At least one type index was remapped. Before we can hash it we have to
236 // copy the full record bytes, re-write each type index, then hash the copy.
237 // We do this in temporary storage since only the DenseMap can decide whether
238 // this record already exists, and if it does we don't want the memory to
239 // stick around.
240 RemapStorage.resize(OriginalData.size());
241 ::memcpy(&RemapStorage[0], OriginalData.data(), OriginalData.size());
242 uint8_t *ContentBegin = RemapStorage.data() + sizeof(RecordPrefix);
243 for (const auto &M : Record.Mappings) {
244 // First 4 bytes of every record are the record prefix, but the mapping
245 // offset is relative to the content which starts after.
246 *(TypeIndex *)(ContentBegin + M.first) = M.second;
247 }
248 auto RemapRef = makeArrayRef(RemapStorage);
249 return insertRecordBytes(RemapRef);
250 }
251
252 Error TypeSerializer::visitTypeBegin(CVType &Record) {
253 assert(!TypeKind.hasValue() && "Already in a type mapping!");
254 assert(Writer.getOffset() == 0 && "Stream has data already!");
255
256 if (auto EC = writeRecordPrefix(Record.kind()))
257 return EC;
258
259 TypeKind = Record.kind();
260 if (auto EC = Mapping.visitTypeBegin(Record))
261 return EC;
262
263 return Error::success();
264 }
265
266 Expected TypeSerializer::visitTypeEndGetIndex(CVType &Record) {
267 assert(TypeKind.hasValue() && "Not in a type mapping!");
268 if (auto EC = Mapping.visitTypeEnd(Record))
269 return std::move(EC);
270
271 // Update the record's length and fill out the CVType members to point to
272 // the stable memory holding the record's data.
273 auto ThisRecordData = getCurrentRecordData();
274 auto ExpectedData = addPadding(ThisRecordData);
275 if (!ExpectedData)
276 return ExpectedData.takeError();
277 ThisRecordData = *ExpectedData;
278
279 RecordPrefix *Prefix =
280 reinterpret_cast(ThisRecordData.data());
281 Prefix->RecordLen = ThisRecordData.size() - sizeof(uint16_t);
282
283 Record.Type = *TypeKind;
284 Record.RecordData = ThisRecordData;
285
286 // insertRecordBytes assumes we're not in a mapping, so do this first.
287 TypeKind.reset();
288 Writer.setOffset(0);
289
290 TypeIndex InsertedTypeIndex = insertRecordBytes(Record.RecordData);
291
292 // Write out each additional segment in reverse order, and update each
293 // record's continuation index to point to the previous one.
294 for (auto X : reverse(FieldListSegments)) {
295 auto CIBytes = X.take_back(sizeof(uint32_t));
296 support::ulittle32_t *CI =
297 reinterpret_cast(CIBytes.data());
298 assert(*CI == 0xB0C0B0C0 && "Invalid TypeIndex placeholder");
299 *CI = InsertedTypeIndex.getIndex();
300 InsertedTypeIndex = insertRecordBytes(X);
301 }
302
303 FieldListSegments.clear();
304 CurrentSegment.SubRecords.clear();
305
306 return InsertedTypeIndex;
307 }
308
309 Error TypeSerializer::visitTypeEnd(CVType &Record) {
310 auto ExpectedIndex = visitTypeEndGetIndex(Record);
311 if (!ExpectedIndex)
312 return ExpectedIndex.takeError();
313 return Error::success();
314 }
315
316 Error TypeSerializer::visitMemberBegin(CVMemberRecord &Record) {
317 assert(isInFieldList() && "Not in a field list!");
318 assert(!MemberKind.hasValue() && "Already in a member record!");
319 MemberKind = Record.Kind;
320
321 if (auto EC = Mapping.visitMemberBegin(Record))
322 return EC;
323
324 return Error::success();
325 }
326
327 Error TypeSerializer::visitMemberEnd(CVMemberRecord &Record) {
328 if (auto EC = Mapping.visitMemberEnd(Record))
329 return EC;
330
331 // Check if this subrecord makes the current segment not fit in 64K minus
332 // the space for a continuation record (8 bytes). If the segment does not
333 // fit, insert a continuation record.
334 if (Writer.getOffset() > MaxRecordLength - ContinuationLength) {
335 MutableArrayRef Data = getCurrentRecordData();
336 SubRecord LastSubRecord = CurrentSegment.SubRecords.back();
337 uint32_t CopySize = CurrentSegment.length() - LastSubRecord.Size;
338 auto CopyData = Data.take_front(CopySize);
339 auto LeftOverData = Data.drop_front(CopySize);
340 assert(LastSubRecord.Size == LeftOverData.size());
341
342 // Allocate stable storage for the record and copy the old record plus
343 // continuation over.
344 uint16_t LengthWithSize = CopySize + ContinuationLength;
345 assert(LengthWithSize <= MaxRecordLength);
346 RecordPrefix *Prefix = reinterpret_cast(CopyData.data());
347 Prefix->RecordLen = LengthWithSize - sizeof(uint16_t);
348
349 uint8_t *SegmentBytes = RecordStorage.Allocate(LengthWithSize);
350 auto SavedSegment = MutableArrayRef(SegmentBytes, LengthWithSize);
351 MutableBinaryByteStream CS(SavedSegment, support::little);
352 BinaryStreamWriter CW(CS);
353 if (auto EC = CW.writeBytes(CopyData))
354 return EC;
355 if (auto EC = CW.writeEnum(TypeLeafKind::LF_INDEX))
356 return EC;
357 if (auto EC = CW.writeInteger(0))
358 return EC;
359 if (auto EC = CW.writeInteger(0xB0C0B0C0))
360 return EC;
361 FieldListSegments.push_back(SavedSegment);
362
363 // Write a new placeholder record prefix to mark the start of this new
364 // top-level record.
365 Writer.setOffset(0);
366 if (auto EC = writeRecordPrefix(TypeLeafKind::LF_FIELDLIST))
367 return EC;
368
369 // Then move over the subrecord that overflowed the old segment to the
370 // beginning of this segment. Note that we have to use memmove here
371 // instead of Writer.writeBytes(), because the new and old locations
372 // could overlap.
373 ::memmove(Stream.data().data() + sizeof(RecordPrefix), LeftOverData.data(),
374 LeftOverData.size());
375 // And point the segment writer at the end of that subrecord.
376 Writer.setOffset(LeftOverData.size() + sizeof(RecordPrefix));
377
378 CurrentSegment.SubRecords.clear();
379 CurrentSegment.SubRecords.push_back(LastSubRecord);
380 }
381
382 // Update the CVMemberRecord since we may have shifted around or gotten
383 // padded.
384 Record.Data = getCurrentSubRecordData();
385
386 MemberKind.reset();
387 return Error::success();
388 }
9999 bool RemapSuccess) {
100100 TypeIndex DestIdx = Untranslated;
101101 if (RemapSuccess)
102 DestIdx = Dest.writeSerializedRecord(Record);
102 DestIdx = Dest.insertRecord(Record);
103103 addMapping(DestIdx);
104104 return Error::success();
105105 }
0 //===- TypeSerialzier.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/ADT/ArrayRef.h"
11 #include "llvm/ADT/DenseSet.h"
12 #include "llvm/ADT/STLExtras.h"
13 #include "llvm/DebugInfo/CodeView/CodeView.h"
14 #include "llvm/DebugInfo/CodeView/ContinuationRecordBuilder.h"
15 #include "llvm/DebugInfo/CodeView/RecordSerialization.h"
16 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
17 #include "llvm/Support/Allocator.h"
18 #include "llvm/Support/BinaryByteStream.h"
19 #include "llvm/Support/BinaryStreamWriter.h"
20 #include "llvm/Support/Endian.h"
21 #include "llvm/Support/Error.h"
22 #include
23 #include
24 #include
25 #include
26
27 using namespace llvm;
28 using namespace llvm::codeview;
29
30 namespace {
31
32 struct HashedType {
33 uint64_t Hash;
34 const uint8_t *Data;
35 unsigned Size; // FIXME: Go to uint16_t?
36 TypeIndex Index;
37 };
38
39 /// Wrapper around a poitner to a HashedType. Hash and equality operations are
40 /// based on data in the pointee.
41 struct HashedTypePtr {
42 HashedTypePtr() = default;
43 HashedTypePtr(HashedType *Ptr) : Ptr(Ptr) {}
44
45 HashedType *Ptr = nullptr;
46 };
47
48 } // end anonymous namespace
49
50 namespace llvm {
51
52 template <> struct DenseMapInfo {
53 static inline HashedTypePtr getEmptyKey() { return HashedTypePtr(nullptr); }
54
55 static inline HashedTypePtr getTombstoneKey() {
56 return HashedTypePtr(reinterpret_cast(1));
57 }
58
59 static unsigned getHashValue(HashedTypePtr Val) {
60 assert(Val.Ptr != getEmptyKey().Ptr && Val.Ptr != getTombstoneKey().Ptr);
61 return Val.Ptr->Hash;
62 }
63
64 static bool isEqual(HashedTypePtr LHSP, HashedTypePtr RHSP) {
65 HashedType *LHS = LHSP.Ptr;
66 HashedType *RHS = RHSP.Ptr;
67 if (RHS == getEmptyKey().Ptr || RHS == getTombstoneKey().Ptr)
68 return LHS == RHS;
69 if (LHS->Hash != RHS->Hash || LHS->Size != RHS->Size)
70 return false;
71 return ::memcmp(LHS->Data, RHS->Data, LHS->Size) == 0;
72 }
73 };
74
75 } // end namespace llvm
76
77 /// Private implementation so that we don't leak our DenseMap instantiations to
78 /// users.
79 class llvm::codeview::TypeHasher {
80 private:
81 /// Storage for type record provided by the caller. Records will outlive the
82 /// hasher object, so they should be allocated here.
83 BumpPtrAllocator &RecordStorage;
84
85 /// Storage for hash keys. These only need to live as long as the hashing
86 /// operation.
87 BumpPtrAllocator KeyStorage;
88
89 /// Hash table. We really want a DenseMap, TypeIndex> here,
90 /// but DenseMap is inefficient when the keys are long (like type records)
91 /// because it recomputes the hash value of every key when it grows. This
92 /// value type stores the hash out of line in KeyStorage, so that table
93 /// entries are small and easy to rehash.
94 DenseSet HashedRecords;
95
96 public:
97 TypeHasher(BumpPtrAllocator &RecordStorage) : RecordStorage(RecordStorage) {}
98
99 void reset() { HashedRecords.clear(); }
100
101 /// Takes the bytes of type record, inserts them into the hash table, saves
102 /// them, and returns a pointer to an identical stable type record along with
103 /// its type index in the destination stream.
104 TypeIndex getOrCreateRecord(ArrayRef &Record, TypeIndex TI);
105 };
106
107 TypeIndex TypeHasher::getOrCreateRecord(ArrayRef &Record,
108 TypeIndex TI) {
109 assert(Record.size() < UINT32_MAX && "Record too big");
110 assert(Record.size() % 4 == 0 && "Record is not aligned to 4 bytes!");
111
112 // Compute the hash up front so we can store it in the key.
113 HashedType TempHashedType = {hash_value(Record), Record.data(),
114 unsigned(Record.size()), TI};
115 auto Result = HashedRecords.insert(HashedTypePtr(&TempHashedType));
116 HashedType *&Hashed = Result.first->Ptr;
117
118 if (Result.second) {
119 // This was a new type record. We need stable storage for both the key and
120 // the record. The record should outlive the hashing operation.
121 Hashed = KeyStorage.Allocate();
122 *Hashed = TempHashedType;
123
124 uint8_t *Stable = RecordStorage.Allocate(Record.size());
125 memcpy(Stable, Record.data(), Record.size());
126 Hashed->Data = Stable;
127 assert(Hashed->Size == Record.size());
128 }
129
130 // Update the caller's copy of Record to point a stable copy.
131 Record = ArrayRef(Hashed->Data, Hashed->Size);
132 return Hashed->Index;
133 }
134
135 TypeIndex TypeTableBuilder::nextTypeIndex() const {
136 return TypeIndex::fromArrayIndex(SeenRecords.size());
137 }
138
139 TypeTableBuilder::TypeTableBuilder(BumpPtrAllocator &Storage, bool Hash)
140 : RecordStorage(Storage) {
141 if (Hash)
142 Hasher = llvm::make_unique(Storage);
143 }
144
145 TypeTableBuilder::~TypeTableBuilder() = default;
146
147 ArrayRef> TypeTableBuilder::records() const {
148 return SeenRecords;
149 }
150
151 void TypeTableBuilder::reset() {
152 if (Hasher)
153 Hasher->reset();
154 SeenRecords.clear();
155 }
156
157 TypeIndex TypeTableBuilder::insertRecordBytes(ArrayRef &Record) {
158 if (Hasher) {
159 TypeIndex ActualTI = Hasher->getOrCreateRecord(Record, nextTypeIndex());
160 if (nextTypeIndex() == ActualTI)
161 SeenRecords.push_back(Record);
162 return ActualTI;
163 }
164
165 TypeIndex NewTI = nextTypeIndex();
166 uint8_t *Stable = RecordStorage.Allocate(Record.size());
167 memcpy(Stable, Record.data(), Record.size());
168 Record = ArrayRef(Stable, Record.size());
169 SeenRecords.push_back(Record);
170 return NewTI;
171 }
172
173 TypeIndex TypeTableBuilder::insertRecord(const RemappedType &Record) {
174 TypeIndex TI;
175 ArrayRef OriginalData = Record.OriginalRecord.RecordData;
176 if (Record.Mappings.empty()) {
177 // This record did not remap any type indices. Just write it.
178 return insertRecordBytes(OriginalData);
179 }
180
181 // At least one type index was remapped. Before we can hash it we have to
182 // copy the full record bytes, re-write each type index, then hash the copy.
183 // We do this in temporary storage since only the DenseMap can decide whether
184 // this record already exists, and if it does we don't want the memory to
185 // stick around.
186 RemapStorage.resize(OriginalData.size());
187 ::memcpy(&RemapStorage[0], OriginalData.data(), OriginalData.size());
188 uint8_t *ContentBegin = RemapStorage.data() + sizeof(RecordPrefix);
189 for (const auto &M : Record.Mappings) {
190 // First 4 bytes of every record are the record prefix, but the mapping
191 // offset is relative to the content which starts after.
192 *(TypeIndex *)(ContentBegin + M.first) = M.second;
193 }
194 auto RemapRef = makeArrayRef(RemapStorage);
195 return insertRecordBytes(RemapRef);
196 }
197
198 TypeIndex TypeTableBuilder::insertRecord(ContinuationRecordBuilder &Builder) {
199 TypeIndex TI;
200 auto Fragments = Builder.end(nextTypeIndex());
201 assert(!Fragments.empty());
202 for (auto C : Fragments)
203 TI = insertRecordBytes(C.RecordData);
204 return TI;
205 }
1010
1111 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
1212 #include "llvm/DebugInfo/CodeView/RecordName.h"
13 #include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
1413 #include "llvm/Support/BinaryByteStream.h"
1514 #include "llvm/Support/BinaryStreamReader.h"
1615
1919 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
2020 #include "llvm/DebugInfo/CodeView/CodeView.h"
2121 #include "llvm/DebugInfo/CodeView/CodeViewError.h"
22 #include "llvm/DebugInfo/CodeView/ContinuationRecordBuilder.h"
2223 #include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
2324 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
2425 #include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
8182 virtual ~LeafRecordBase() = default;
8283
8384 virtual void map(yaml::IO &io) = 0;
84 virtual CVType toCodeViewRecord(TypeTableBuilder &TTB) const = 0;
85 virtual CVType toCodeViewRecord(TypeTableBuilder &TS) const = 0;
8586 virtual Error fromCodeViewRecord(CVType Type) = 0;
8687 };
8788
9596 return TypeDeserializer::deserializeAs(Type, Record);
9697 }
9798
98 CVType toCodeViewRecord(TypeTableBuilder &TTB) const override {
99 TTB.writeKnownType(Record);
100 return CVType(Kind, TTB.records().back());
99 CVType toCodeViewRecord(TypeTableBuilder &TS) const override {
100 TS.writeLeafType(Record);
101 return CVType(Kind, TS.records().back());
101102 }
102103
103104 mutable T Record;
107108 explicit LeafRecordImpl(TypeLeafKind K) : LeafRecordBase(K) {}
108109
109110 void map(yaml::IO &io) override;
110 CVType toCodeViewRecord(TypeTableBuilder &TTB) const override;
111 CVType toCodeViewRecord(TypeTableBuilder &TS) const override;
111112 Error fromCodeViewRecord(CVType Type) override;
112113
113114 std::vector Members;
120121 virtual ~MemberRecordBase() = default;
121122
122123 virtual void map(yaml::IO &io) = 0;
123 virtual void writeTo(FieldListRecordBuilder &FLRB) = 0;
124 virtual void writeTo(ContinuationRecordBuilder &CRB) = 0;
124125 };
125126
126127 template struct MemberRecordImpl : public MemberRecordBase {
129130
130131 void map(yaml::IO &io) override;
131132
132 void writeTo(FieldListRecordBuilder &FLRB) override {
133 FLRB.writeMemberType(Record);
133 void writeTo(ContinuationRecordBuilder &CRB) override {
134 CRB.writeMemberType(Record);
134135 }
135136
136137 mutable T Record;
488489 }
489490
490491 CVType
491 LeafRecordImpl::toCodeViewRecord(TypeTableBuilder &TTB) const {
492 FieldListRecordBuilder FLRB(TTB);
493 FLRB.begin();
492 LeafRecordImpl::toCodeViewRecord(TypeTableBuilder &TS) const {
493 ContinuationRecordBuilder CRB;
494 CRB.begin(ContinuationRecordKind::FieldList);
494495 for (const auto &Member : Members) {
495 Member.Member->writeTo(FLRB);
496 }
497 FLRB.end(true);
498 return CVType(Kind, TTB.records().back());
496 Member.Member->writeTo(CRB);
497 }
498 TS.insertRecord(CRB);
499 return CVType(Kind, TS.records().back());
499500 }
500501
501502 void MappingTraits::mapping(IO &io, OneMethodRecord &Record) {
680681 return make_error(cv_error_code::corrupt_record);
681682 }
682683
683 CVType LeafRecord::toCodeViewRecord(BumpPtrAllocator &Alloc) const {
684 TypeTableBuilder TTB(Alloc);
685 return Leaf->toCodeViewRecord(TTB);
686 }
687
688 CVType LeafRecord::toCodeViewRecord(TypeTableBuilder &TTB) const {
689 return Leaf->toCodeViewRecord(TTB);
684 CVType LeafRecord::toCodeViewRecord(TypeTableBuilder &Serializer) const {
685 return Leaf->toCodeViewRecord(Serializer);
690686 }
691687
692688 namespace llvm {
785781
786782 ArrayRef llvm::CodeViewYAML::toDebugT(ArrayRef Leafs,
787783 BumpPtrAllocator &Alloc) {
788 TypeTableBuilder TTB(Alloc, false);
784 TypeTableBuilder TS(Alloc, false);
789785 uint32_t Size = sizeof(uint32_t);
790786 for (const auto &Leaf : Leafs) {
791 CVType T = Leaf.toCodeViewRecord(TTB);
787 CVType T = Leaf.Leaf->toCodeViewRecord(TS);
792788 Size += T.length();
793789 assert(T.length() % 4 == 0 && "Improper type record alignment!");
794790 }
797793 BinaryStreamWriter Writer(Output, support::little);
798794 ExitOnError Err("Error writing type record to .debug$T section");
799795 Err(Writer.writeInteger(COFF::DEBUG_SECTION_MAGIC));
800 for (const auto &R : TTB.records()) {
796 for (const auto &R : TS.records()) {
801797 Err(Writer.writeBytes(R));
802798 }
803799 assert(Writer.bytesRemaining() == 0 && "Didn't write all type record bytes!");
88 ; CHECK-NEXT: AccessSpecifier: Public (0x3)
99 ; CHECK-NEXT: EnumValue: 5436
1010 ; CHECK-NEXT: Name: EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE5437
11 ; CHECK-NEXT: }
12 ; CHECK: EnumValue: 5695
13 ; CHECK-NEXT: Name: EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE5696
1114 ; CHECK-NEXT: }
1215 ; CHECK-NOT: ContinuationIndex
1316
5053 ; CHECK-NEXT: Name: EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE1
5154 ; CHECK-NEXT: }
5255 ; CHECK: ContinuationIndex: (0x1003)
56
57 ; CHECK-LABEL: Enum (0x1005) {
58 ; CHECK-NEXT: TypeLeafKind: LF_ENUM (0x1507)
59 ; CHECK-NEXT: NumEnumerators: 5696
60 ; CHECK-NEXT: Properties [ (0x200)
61 ; CHECK-NEXT: HasUniqueName (0x200)
62 ; CHECK-NEXT: ]
63 ; CHECK-NEXT: UnderlyingType: int (0x74)
64 ; CHECK-NEXT: FieldListType: (0x1004)
65 ; CHECK-NEXT: Name: BigThing
66 ; CHECK-NEXT: LinkageName: .?AW4BigThing@@
67 ; CHECK-NEXT: }
5368
5469 ; ModuleID = 't.cpp'
5570 source_filename = "t.cpp"
1414 #include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"
1515 #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
1616 #include "llvm/DebugInfo/CodeView/SymbolVisitorCallbackPipeline.h"
17 #include "llvm/DebugInfo/CodeView/TypeSerializer.h"
1817 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
1918 #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
2019 #include "llvm/DebugInfo/PDB/Native/RawTypes.h"
726726 auto &TpiBuilder = Builder.getTpiBuilder();
727727 const auto &Tpi = YamlObj.TpiStream.getValueOr(DefaultTpiStream);
728728 TpiBuilder.setVersionHeader(Tpi.Version);
729 TypeTableBuilder TS(Allocator);
729730 for (const auto &R : Tpi.Records) {
730 CVType Type = R.toCodeViewRecord(Allocator);
731 CVType Type = R.toCodeViewRecord(TS);
731732 TpiBuilder.addTypeRecord(Type.RecordData, None);
732733 }
733734
735736 auto &IpiBuilder = Builder.getIpiBuilder();
736737 IpiBuilder.setVersionHeader(Ipi.Version);
737738 for (const auto &R : Ipi.Records) {
738 CVType Type = R.toCodeViewRecord(Allocator);
739 CVType Type = R.toCodeViewRecord(TS);
739740 IpiBuilder.addTypeRecord(Type.RecordData, None);
740741 }
741742
1111 #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
1212 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
1313 #include "llvm/DebugInfo/CodeView/TypeRecordMapping.h"
14 #include "llvm/DebugInfo/CodeView/TypeSerializer.h"
1514 #include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
1615 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
1716 #include "llvm/DebugInfo/PDB/Native/RawTypes.h"
107106 Stream << "Array [" << I << "]";
108107 AR.Name = GlobalState->Strings.save(Stream.str());
109108 GlobalState->Records.push_back(AR);
110 GlobalState->Indices.push_back(Builder.writeKnownType(AR));
109 GlobalState->Indices.push_back(Builder.writeLeafType(AR));
111110
112111 CVType Type(TypeLeafKind::LF_ARRAY, Builder.records().back());
113112 GlobalState->TypeVector.push_back(Type);
362361 Class.DerivationList = TypeIndex::fromArrayIndex(0);
363362 Class.FieldList = TypeIndex::fromArrayIndex(0);
364363 Class.VTableShape = TypeIndex::fromArrayIndex(0);
365 TypeIndex IndexZero = Builder.writeKnownType(Class);
364 TypeIndex IndexZero = Builder.writeLeafType(Class);
366365
367366 // TypeIndex 1 refers to type index 0.
368367 ModifierRecord Modifier(TypeRecordKind::Modifier);
369368 Modifier.ModifiedType = TypeIndex::fromArrayIndex(0);
370369 Modifier.Modifiers = ModifierOptions::Const;
371 TypeIndex IndexOne = Builder.writeKnownType(Modifier);
370 TypeIndex IndexOne = Builder.writeLeafType(Modifier);
372371
373372 // set up a type stream that refers to the above two serialized records.
374373 std::vector TypeArray;
88
99 #include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"
1010
11 #include "llvm/DebugInfo/CodeView/ContinuationRecordBuilder.h"
12 #include "llvm/DebugInfo/CodeView/SymbolSerializer.h"
1113 #include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
12 #include "llvm/DebugInfo/CodeView/SymbolSerializer.h"
1314 #include "llvm/Support/Allocator.h"
1415
1516 #include "gmock/gmock.h"
2526 void SetUp() override {
2627 Refs.clear();
2728 TTB = make_unique(Storage);
28 FLRB = make_unique(*TTB);
29 CRB = make_unique();
2930 Symbols.clear();
3031 }
3132
3233 void TearDown() override {
33 FLRB.reset();
34 CRB.reset();
3435 TTB.reset();
3536 }
3637
5455 }
5556
5657 template void writeFieldList(T &&... MemberRecords) {
57 FLRB->begin();
58 CRB->begin(ContinuationRecordKind::FieldList);
5859 writeFieldListImpl(std::forward(MemberRecords)...);
59 FLRB->end(true);
60 ASSERT_EQ(1u, TTB->records().size());
60 auto Records = CRB->end(TTB->nextTypeIndex());
61 ASSERT_EQ(1u, Records.size());
62 TTB->insertRecordBytes(Records.front().RecordData);
6163 discoverAllTypeIndices();
6264 }
6365
139141
140142 template
141143 void writeFieldListImpl(RecType &&Record, Rest &&... Records) {
142 FLRB->writeMemberType(Record);
144 CRB->writeMemberType(Record);
143145 writeFieldListImpl(std::forward(Records)...);
144146 }
145147
148150
149151 template
150152 void writeTypeRecordsImpl(RecType &&Record, Rest &&... Records) {
151 TTB->writeKnownType(Record);
153 TTB->writeLeafType(Record);
152154 writeTypeRecordsImpl(std::forward(Records)...);
153155 }
154156
163165 }
164166
165167 std::vector> Refs;
166 std::unique_ptr<FieldListRecordBuilder> FLRB;
168 std::unique_ptr<ContinuationRecordBuilder> CRB;
167169 std::vector Symbols;
168170 BumpPtrAllocator Storage;
169171 };