1 //===-- TypeStreamMerger.cpp ------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "llvm/DebugInfo/CodeView/TypeStreamMerger.h"
11 #include "llvm/ADT/SmallString.h"
12 #include "llvm/ADT/StringExtras.h"
13 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
14 #include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
15 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
16 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
17 #include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
18 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
19 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
20 #include "llvm/Support/Error.h"
21 #include "llvm/Support/ScopedPrinter.h"
24 using namespace llvm::codeview;
28 /// Implementation of CodeView type stream merging.
30 /// A CodeView type stream is a series of records that reference each other
31 /// through type indices. A type index is either "simple", meaning it is less
32 /// than 0x1000 and refers to a builtin type, or it is complex, meaning it
33 /// refers to a prior type record in the current stream. The type index of a
34 /// record is equal to the number of records before it in the stream plus
37 /// Type records are only allowed to use type indices smaller than their own, so
38 /// a type stream is effectively a topologically sorted DAG. Cycles occuring in
39 /// the type graph of the source program are resolved with forward declarations
40 /// of composite types. This class implements the following type stream merging
41 /// algorithm, which relies on this DAG structure:
43 /// - Begin with a new empty stream, and a new empty hash table that maps from
44 /// type record contents to new type index.
45 /// - For each new type stream, maintain a map from source type index to
46 /// destination type index.
47 /// - For each record, copy it and rewrite its type indices to be valid in the
48 /// destination type stream.
49 /// - If the new type record is not already present in the destination stream
50 /// hash table, append it to the destination type stream, assign it the next
51 /// type index, and update the two hash tables.
52 /// - If the type record already exists in the destination stream, discard it
53 /// and update the type index map to forward the source type index to the
54 /// existing destination type index.
55 class TypeStreamMerger : public TypeVisitorCallbacks {
57 TypeStreamMerger(TypeTableBuilder &DestStream)
58 : DestStream(DestStream), FieldListBuilder(DestStream) {
62 /// TypeVisitorCallbacks overrides.
63 #define TYPE_RECORD(EnumName, EnumVal, Name) \
64 Error visitKnownRecord(CVType &CVR, Name##Record &Record) override;
65 #define MEMBER_RECORD(EnumName, EnumVal, Name) \
66 Error visitKnownMember(CVMemberRecord &CVR, Name##Record &Record) override;
67 #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
68 #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
69 #include "llvm/DebugInfo/CodeView/TypeRecords.def"
71 Error visitUnknownType(CVType &Record) override;
73 Error visitTypeBegin(CVType &Record) override;
74 Error visitTypeEnd(CVType &Record) override;
75 Error visitMemberEnd(CVMemberRecord &Record) override;
77 bool mergeStream(const CVTypeArray &Types);
80 template <typename RecordType>
81 Error visitKnownRecordImpl(RecordType &Record) {
82 FoundBadTypeIndex |= !Record.remapTypeIndices(IndexMap);
83 IndexMap.push_back(DestStream.writeKnownType(Record));
84 return Error::success();
87 Error visitKnownRecordImpl(FieldListRecord &Record) {
88 CVTypeVisitor Visitor(*this);
90 if (auto EC = Visitor.visitFieldListMemberStream(Record.Data))
92 return Error::success();
95 template <typename RecordType>
96 Error visitKnownMemberRecordImpl(RecordType &Record) {
97 FoundBadTypeIndex |= !Record.remapTypeIndices(IndexMap);
98 FieldListBuilder.writeMemberType(Record);
99 return Error::success();
102 bool hadError() { return FoundBadTypeIndex; }
104 bool FoundBadTypeIndex = false;
106 BumpPtrAllocator Allocator;
108 TypeTableBuilder &DestStream;
109 FieldListRecordBuilder FieldListBuilder;
111 bool IsInFieldList{false};
112 size_t BeginIndexMapSize = 0;
114 /// Map from source type index to destination type index. Indexed by source
115 /// type index minus 0x1000.
116 SmallVector<TypeIndex, 0> IndexMap;
119 } // end anonymous namespace
121 Error TypeStreamMerger::visitTypeBegin(CVRecord<TypeLeafKind> &Rec) {
122 if (Rec.Type == TypeLeafKind::LF_FIELDLIST) {
123 assert(!IsInFieldList);
124 IsInFieldList = true;
125 FieldListBuilder.begin();
127 BeginIndexMapSize = IndexMap.size();
128 return Error::success();
131 Error TypeStreamMerger::visitTypeEnd(CVRecord<TypeLeafKind> &Rec) {
132 if (Rec.Type == TypeLeafKind::LF_FIELDLIST) {
133 TypeIndex Index = FieldListBuilder.end();
134 IndexMap.push_back(Index);
135 IsInFieldList = false;
137 return Error::success();
140 Error TypeStreamMerger::visitMemberEnd(CVMemberRecord &Rec) {
141 assert(IndexMap.size() == BeginIndexMapSize + 1);
142 return Error::success();
145 #define TYPE_RECORD(EnumName, EnumVal, Name) \
146 Error TypeStreamMerger::visitKnownRecord(CVType &CVR, \
147 Name##Record &Record) { \
148 return visitKnownRecordImpl(Record); \
150 #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
151 #define MEMBER_RECORD(EnumName, EnumVal, Name) \
152 Error TypeStreamMerger::visitKnownMember(CVMemberRecord &CVR, \
153 Name##Record &Record) { \
154 return visitKnownMemberRecordImpl(Record); \
156 #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
157 #include "llvm/DebugInfo/CodeView/TypeRecords.def"
159 Error TypeStreamMerger::visitUnknownType(CVType &Rec) {
160 // We failed to translate a type. Translate this index as "not translated".
162 TypeIndex(SimpleTypeKind::NotTranslated, SimpleTypeMode::Direct));
163 return llvm::make_error<CodeViewError>(cv_error_code::corrupt_record);
166 bool TypeStreamMerger::mergeStream(const CVTypeArray &Types) {
167 assert(IndexMap.empty());
168 TypeVisitorCallbackPipeline Pipeline;
170 TypeDeserializer Deserializer;
171 Pipeline.addCallbackToPipeline(Deserializer);
172 Pipeline.addCallbackToPipeline(*this);
174 CVTypeVisitor Visitor(Pipeline);
176 if (auto EC = Visitor.visitTypeStream(Types)) {
177 consumeError(std::move(EC));
184 bool llvm::codeview::mergeTypeStreams(TypeTableBuilder &DestStream,
185 const CVTypeArray &Types) {
186 return TypeStreamMerger(DestStream).mergeStream(Types);