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/TypeIndex.h"
15 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
16 #include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
17 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
18 #include "llvm/Support/Error.h"
19 #include "llvm/Support/ScopedPrinter.h"
22 using namespace llvm::codeview;
26 /// Implementation of CodeView type stream merging.
28 /// A CodeView type stream is a series of records that reference each other
29 /// through type indices. A type index is either "simple", meaning it is less
30 /// than 0x1000 and refers to a builtin type, or it is complex, meaning it
31 /// refers to a prior type record in the current stream. The type index of a
32 /// record is equal to the number of records before it in the stream plus
35 /// Type records are only allowed to use type indices smaller than their own, so
36 /// a type stream is effectively a topologically sorted DAG. Cycles occuring in
37 /// the type graph of the source program are resolved with forward declarations
38 /// of composite types. This class implements the following type stream merging
39 /// algorithm, which relies on this DAG structure:
41 /// - Begin with a new empty stream, and a new empty hash table that maps from
42 /// type record contents to new type index.
43 /// - For each new type stream, maintain a map from source type index to
44 /// destination type index.
45 /// - For each record, copy it and rewrite its type indices to be valid in the
46 /// destination type stream.
47 /// - If the new type record is not already present in the destination stream
48 /// hash table, append it to the destination type stream, assign it the next
49 /// type index, and update the two hash tables.
50 /// - If the type record already exists in the destination stream, discard it
51 /// and update the type index map to forward the source type index to the
52 /// existing destination type index.
54 /// As an additional complication, type stream merging actually produces two
55 /// streams: an item (or IPI) stream and a type stream, as this is what is
56 /// actually stored in the final PDB. We choose which records go where by
57 /// looking at the record kind.
58 class TypeStreamMerger : public TypeVisitorCallbacks {
60 TypeStreamMerger(TypeTableBuilder &DestIdStream,
61 TypeTableBuilder &DestTypeStream,
62 SmallVectorImpl<TypeIndex> &SourceToDest,
63 TypeServerHandler *Handler)
64 : DestIdStream(DestIdStream), DestTypeStream(DestTypeStream),
65 FieldListBuilder(DestTypeStream), Handler(Handler),
66 IndexMap(SourceToDest) {}
68 static const TypeIndex Untranslated;
70 /// TypeVisitorCallbacks overrides.
71 #define TYPE_RECORD(EnumName, EnumVal, Name) \
72 Error visitKnownRecord(CVType &CVR, Name##Record &Record) override;
73 #define MEMBER_RECORD(EnumName, EnumVal, Name) \
74 Error visitKnownMember(CVMemberRecord &CVR, Name##Record &Record) override;
75 #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
76 #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
77 #include "llvm/DebugInfo/CodeView/TypeRecords.def"
79 Error visitUnknownType(CVType &Record) override;
81 Error visitTypeBegin(CVType &Record) override;
82 Error visitTypeEnd(CVType &Record) override;
83 Error visitMemberEnd(CVMemberRecord &Record) override;
85 Error mergeStream(const CVTypeArray &Types);
88 void addMapping(TypeIndex Idx);
90 bool remapIndex(TypeIndex &Idx);
92 size_t slotForIndex(TypeIndex Idx) const {
93 assert(!Idx.isSimple() && "simple type indices have no slots");
94 return Idx.getIndex() - TypeIndex::FirstNonSimpleIndex;
97 Error errorCorruptRecord() const {
98 return llvm::make_error<CodeViewError>(cv_error_code::corrupt_record);
101 template <typename RecordType>
102 Error writeRecord(RecordType &R, bool RemapSuccess) {
103 TypeIndex DestIdx = Untranslated;
105 DestIdx = DestTypeStream.writeKnownType(R);
107 return Error::success();
110 template <typename RecordType>
111 Error writeIdRecord(RecordType &R, bool RemapSuccess) {
112 TypeIndex DestIdx = Untranslated;
114 DestIdx = DestIdStream.writeKnownType(R);
116 return Error::success();
119 template <typename RecordType>
120 Error writeMember(RecordType &R, bool RemapSuccess) {
122 FieldListBuilder.writeMemberType(R);
124 HadUntranslatedMember = true;
125 return Error::success();
128 Optional<Error> LastError;
130 bool IsSecondPass = false;
132 bool HadUntranslatedMember = false;
134 unsigned NumBadIndices = 0;
136 BumpPtrAllocator Allocator;
138 TypeTableBuilder &DestIdStream;
139 TypeTableBuilder &DestTypeStream;
140 FieldListRecordBuilder FieldListBuilder;
141 TypeServerHandler *Handler;
143 TypeIndex CurIndex{TypeIndex::FirstNonSimpleIndex};
145 /// Map from source type index to destination type index. Indexed by source
146 /// type index minus 0x1000.
147 SmallVectorImpl<TypeIndex> &IndexMap;
150 } // end anonymous namespace
152 const TypeIndex TypeStreamMerger::Untranslated(SimpleTypeKind::NotTranslated);
154 Error TypeStreamMerger::visitTypeBegin(CVRecord<TypeLeafKind> &Rec) {
155 return Error::success();
158 Error TypeStreamMerger::visitTypeEnd(CVRecord<TypeLeafKind> &Rec) {
159 CurIndex = TypeIndex(CurIndex.getIndex() + 1);
161 assert(IndexMap.size() == slotForIndex(CurIndex) &&
162 "visitKnownRecord should add one index map entry");
163 return Error::success();
166 Error TypeStreamMerger::visitMemberEnd(CVMemberRecord &Rec) {
167 return Error::success();
170 void TypeStreamMerger::addMapping(TypeIndex Idx) {
172 assert(IndexMap.size() == slotForIndex(CurIndex) &&
173 "visitKnownRecord should add one index map entry");
174 IndexMap.push_back(Idx);
176 assert(slotForIndex(CurIndex) < IndexMap.size());
177 IndexMap[slotForIndex(CurIndex)] = Idx;
181 bool TypeStreamMerger::remapIndex(TypeIndex &Idx) {
182 // Simple types are unchanged.
186 // Check if this type index refers to a record we've already translated
187 // successfully. If it refers to a type later in the stream or a record we
188 // had to defer, defer it until later pass.
189 unsigned MapPos = slotForIndex(Idx);
190 if (MapPos < IndexMap.size() && IndexMap[MapPos] != Untranslated) {
191 Idx = IndexMap[MapPos];
195 // If this is the second pass and this index isn't in the map, then it points
196 // outside the current type stream, and this is a corrupt record.
197 if (IsSecondPass && MapPos >= IndexMap.size()) {
198 // FIXME: Print a more useful error. We can give the current record and the
199 // index that we think its pointing to.
200 LastError = joinErrors(std::move(*LastError), errorCorruptRecord());
205 // This type index is invalid. Remap this to "not translated by cvpack",
206 // and return failure.
211 //----------------------------------------------------------------------------//
213 //----------------------------------------------------------------------------//
215 Error TypeStreamMerger::visitKnownRecord(CVType &, FuncIdRecord &R) {
217 Success &= remapIndex(R.ParentScope);
218 Success &= remapIndex(R.FunctionType);
219 return writeIdRecord(R, Success);
222 Error TypeStreamMerger::visitKnownRecord(CVType &, MemberFuncIdRecord &R) {
224 Success &= remapIndex(R.ClassType);
225 Success &= remapIndex(R.FunctionType);
226 return writeIdRecord(R, Success);
229 Error TypeStreamMerger::visitKnownRecord(CVType &, StringIdRecord &R) {
230 return writeIdRecord(R, remapIndex(R.Id));
233 Error TypeStreamMerger::visitKnownRecord(CVType &, StringListRecord &R) {
235 for (TypeIndex &Str : R.StringIndices)
236 Success &= remapIndex(Str);
237 return writeIdRecord(R, Success);
240 Error TypeStreamMerger::visitKnownRecord(CVType &, BuildInfoRecord &R) {
242 for (TypeIndex &Arg : R.ArgIndices)
243 Success &= remapIndex(Arg);
244 return writeIdRecord(R, Success);
247 Error TypeStreamMerger::visitKnownRecord(CVType &, UdtSourceLineRecord &R) {
249 Success &= remapIndex(R.UDT);
250 Success &= remapIndex(R.SourceFile);
251 // FIXME: Translate UdtSourceLineRecord into UdtModSourceLineRecords in the
253 return writeIdRecord(R, Success);
256 Error TypeStreamMerger::visitKnownRecord(CVType &, UdtModSourceLineRecord &R) {
258 Success &= remapIndex(R.UDT);
259 Success &= remapIndex(R.SourceFile);
260 return writeIdRecord(R, Success);
263 //----------------------------------------------------------------------------//
265 //----------------------------------------------------------------------------//
267 Error TypeStreamMerger::visitKnownRecord(CVType &, ModifierRecord &R) {
268 return writeRecord(R, remapIndex(R.ModifiedType));
271 Error TypeStreamMerger::visitKnownRecord(CVType &, ProcedureRecord &R) {
273 Success &= remapIndex(R.ReturnType);
274 Success &= remapIndex(R.ArgumentList);
275 return writeRecord(R, Success);
278 Error TypeStreamMerger::visitKnownRecord(CVType &, MemberFunctionRecord &R) {
280 Success &= remapIndex(R.ReturnType);
281 Success &= remapIndex(R.ClassType);
282 Success &= remapIndex(R.ThisType);
283 Success &= remapIndex(R.ArgumentList);
284 return writeRecord(R, Success);
287 Error TypeStreamMerger::visitKnownRecord(CVType &Type, ArgListRecord &R) {
289 for (TypeIndex &Arg : R.ArgIndices)
290 Success &= remapIndex(Arg);
291 if (auto EC = writeRecord(R, Success))
293 return Error::success();
296 Error TypeStreamMerger::visitKnownRecord(CVType &, PointerRecord &R) {
298 Success &= remapIndex(R.ReferentType);
299 if (R.isPointerToMember())
300 Success &= remapIndex(R.MemberInfo->ContainingType);
301 return writeRecord(R, Success);
304 Error TypeStreamMerger::visitKnownRecord(CVType &, ArrayRecord &R) {
306 Success &= remapIndex(R.ElementType);
307 Success &= remapIndex(R.IndexType);
308 return writeRecord(R, Success);
311 Error TypeStreamMerger::visitKnownRecord(CVType &, ClassRecord &R) {
313 Success &= remapIndex(R.FieldList);
314 Success &= remapIndex(R.DerivationList);
315 Success &= remapIndex(R.VTableShape);
316 return writeRecord(R, Success);
319 Error TypeStreamMerger::visitKnownRecord(CVType &, UnionRecord &R) {
320 return writeRecord(R, remapIndex(R.FieldList));
323 Error TypeStreamMerger::visitKnownRecord(CVType &, EnumRecord &R) {
325 Success &= remapIndex(R.FieldList);
326 Success &= remapIndex(R.UnderlyingType);
327 return writeRecord(R, Success);
330 Error TypeStreamMerger::visitKnownRecord(CVType &, BitFieldRecord &R) {
331 return writeRecord(R, remapIndex(R.Type));
334 Error TypeStreamMerger::visitKnownRecord(CVType &, VFTableShapeRecord &R) {
335 return writeRecord(R, true);
338 Error TypeStreamMerger::visitKnownRecord(CVType &, TypeServer2Record &R) {
339 return writeRecord(R, true);
342 Error TypeStreamMerger::visitKnownRecord(CVType &, LabelRecord &R) {
343 return writeRecord(R, true);
346 Error TypeStreamMerger::visitKnownRecord(CVType &, VFTableRecord &R) {
348 Success &= remapIndex(R.CompleteClass);
349 Success &= remapIndex(R.OverriddenVFTable);
350 return writeRecord(R, Success);
353 Error TypeStreamMerger::visitKnownRecord(CVType &,
354 MethodOverloadListRecord &R) {
356 for (OneMethodRecord &Meth : R.Methods)
357 Success &= remapIndex(Meth.Type);
358 return writeRecord(R, Success);
361 Error TypeStreamMerger::visitKnownRecord(CVType &, FieldListRecord &R) {
362 // Visit the members inside the field list.
363 HadUntranslatedMember = false;
364 FieldListBuilder.begin();
365 if (auto EC = codeview::visitMemberRecordStream(R.Data, *this))
368 // Write the record if we translated all field list members.
369 TypeIndex DestIdx = Untranslated;
370 if (!HadUntranslatedMember)
371 DestIdx = FieldListBuilder.end();
373 FieldListBuilder.reset();
376 return Error::success();
379 //----------------------------------------------------------------------------//
381 //----------------------------------------------------------------------------//
383 Error TypeStreamMerger::visitKnownMember(CVMemberRecord &,
384 NestedTypeRecord &R) {
385 return writeMember(R, remapIndex(R.Type));
388 Error TypeStreamMerger::visitKnownMember(CVMemberRecord &, OneMethodRecord &R) {
390 Success &= remapIndex(R.Type);
391 return writeMember(R, Success);
394 Error TypeStreamMerger::visitKnownMember(CVMemberRecord &,
395 OverloadedMethodRecord &R) {
396 return writeMember(R, remapIndex(R.MethodList));
399 Error TypeStreamMerger::visitKnownMember(CVMemberRecord &,
400 DataMemberRecord &R) {
401 return writeMember(R, remapIndex(R.Type));
404 Error TypeStreamMerger::visitKnownMember(CVMemberRecord &,
405 StaticDataMemberRecord &R) {
406 return writeMember(R, remapIndex(R.Type));
409 Error TypeStreamMerger::visitKnownMember(CVMemberRecord &,
410 EnumeratorRecord &R) {
411 return writeMember(R, true);
414 Error TypeStreamMerger::visitKnownMember(CVMemberRecord &, VFPtrRecord &R) {
415 return writeMember(R, remapIndex(R.Type));
418 Error TypeStreamMerger::visitKnownMember(CVMemberRecord &, BaseClassRecord &R) {
419 return writeMember(R, remapIndex(R.Type));
422 Error TypeStreamMerger::visitKnownMember(CVMemberRecord &,
423 VirtualBaseClassRecord &R) {
425 Success &= remapIndex(R.BaseType);
426 Success &= remapIndex(R.VBPtrType);
427 return writeMember(R, Success);
430 Error TypeStreamMerger::visitKnownMember(CVMemberRecord &,
431 ListContinuationRecord &R) {
432 return writeMember(R, remapIndex(R.ContinuationIndex));
435 Error TypeStreamMerger::visitUnknownType(CVType &Rec) {
436 // We failed to translate a type. Translate this index as "not translated".
437 addMapping(TypeIndex(SimpleTypeKind::NotTranslated));
438 return errorCorruptRecord();
441 Error TypeStreamMerger::mergeStream(const CVTypeArray &Types) {
442 assert(IndexMap.empty());
443 LastError = Error::success();
445 if (auto EC = codeview::visitTypeStream(Types, *this, Handler))
448 // If we found bad indices but no other errors, try doing another pass and see
449 // if we can resolve the indices that weren't in the map on the first pass.
450 // This may require multiple passes, but we should always make progress. MASM
451 // is the only known CodeView producer that makes type streams that aren't
452 // topologically sorted. The standard library contains MASM-produced objects,
453 // so this is important to handle correctly, but we don't have to be too
454 // efficient. MASM type streams are usually very small.
455 while (!*LastError && NumBadIndices > 0) {
456 unsigned BadIndicesRemaining = NumBadIndices;
459 CurIndex = TypeIndex(TypeIndex::FirstNonSimpleIndex);
461 if (auto EC = codeview::visitTypeStream(Types, *this, Handler))
464 assert(NumBadIndices <= BadIndicesRemaining &&
465 "second pass found more bad indices");
466 if (!*LastError && NumBadIndices == BadIndicesRemaining) {
467 return llvm::make_error<CodeViewError>(
468 cv_error_code::corrupt_record, "input type graph contains cycles");
474 Error Ret = std::move(*LastError);
479 Error llvm::codeview::mergeTypeStreams(TypeTableBuilder &DestIdStream,
480 TypeTableBuilder &DestTypeStream,
481 SmallVectorImpl<TypeIndex> &SourceToDest,
482 TypeServerHandler *Handler,
483 const CVTypeArray &Types) {
484 return TypeStreamMerger(DestIdStream, DestTypeStream, SourceToDest, Handler)