1 //===- llvm/unittest/DebugInfo/CodeView/TypeIndexDiscoveryTest.cpp --------===//
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/TypeIndexDiscovery.h"
12 #include "llvm/DebugInfo/CodeView/AppendingTypeTableBuilder.h"
13 #include "llvm/DebugInfo/CodeView/ContinuationRecordBuilder.h"
14 #include "llvm/DebugInfo/CodeView/SymbolSerializer.h"
15 #include "llvm/Support/Allocator.h"
17 #include "gmock/gmock.h"
18 #include "gtest/gtest.h"
21 using namespace llvm::codeview;
23 class TypeIndexIteratorTest : public testing::Test {
25 TypeIndexIteratorTest() {}
27 void SetUp() override {
29 TTB = make_unique<AppendingTypeTableBuilder>(Storage);
30 CRB = make_unique<ContinuationRecordBuilder>();
34 void TearDown() override {
40 template <typename... Indices>
41 bool checkTypeReferences(uint32_t RecordIndex, Indices &&... TIs) const {
42 EXPECT_EQ(sizeof...(Indices), countRefs(RecordIndex));
44 // Choose between type or symbol records. The checking code doesn't care
46 std::vector<ArrayRef<uint8_t>> CVRecords;
47 if (Symbols.empty()) {
48 CVRecords = TTB->records();
50 for (const CVSymbol &S : Symbols)
51 CVRecords.push_back(S.data());
54 return checkTypeReferencesImpl(RecordIndex, CVRecords,
55 std::forward<Indices>(TIs)...);
58 template <typename... T> void writeFieldList(T &&... MemberRecords) {
59 CRB->begin(ContinuationRecordKind::FieldList);
60 writeFieldListImpl(std::forward<T>(MemberRecords)...);
61 auto Records = CRB->end(TTB->nextTypeIndex());
62 ASSERT_EQ(1u, Records.size());
63 TTB->insertRecordBytes(Records.front().RecordData);
64 discoverAllTypeIndices();
67 template <typename... T> void writeTypeRecords(T &&... Records) {
68 writeTypeRecordsImpl(std::forward<T>(Records)...);
69 ASSERT_EQ(sizeof...(T), TTB->records().size());
70 discoverAllTypeIndices();
73 template <typename... T> void writeSymbolRecords(T &&... Records) {
74 writeSymbolRecordsImpl(std::forward<T>(Records)...);
75 ASSERT_EQ(sizeof...(T), Symbols.size());
76 discoverTypeIndicesInSymbols();
79 std::unique_ptr<AppendingTypeTableBuilder> TTB;
82 uint32_t countRefs(uint32_t RecordIndex) const {
83 auto &R = Refs[RecordIndex];
91 bool checkOneTypeReference(uint32_t RecordIndex, ArrayRef<uint8_t> RecordData,
93 RecordData = RecordData.drop_front(sizeof(RecordPrefix));
94 auto &RefList = Refs[RecordIndex];
95 for (auto &Ref : RefList) {
96 uint32_t Offset = Ref.Offset;
97 ArrayRef<uint8_t> Loc = RecordData.drop_front(Offset);
98 ArrayRef<TypeIndex> Indices(
99 reinterpret_cast<const TypeIndex *>(Loc.data()), Ref.Count);
100 if (llvm::any_of(Indices,
101 [TI](const TypeIndex &Other) { return Other == TI; }))
107 template <typename... Indices>
108 bool checkTypeReferencesImpl(uint32_t RecordIndex,
109 ArrayRef<ArrayRef<uint8_t>> CVRecords) const {
113 template <typename... Indices>
114 bool checkTypeReferencesImpl(uint32_t RecordIndex,
115 ArrayRef<ArrayRef<uint8_t>> CVRecords,
116 TypeIndex TI, Indices &&... Rest) const {
117 ArrayRef<uint8_t> Record = CVRecords[RecordIndex];
118 bool Success = checkOneTypeReference(RecordIndex, Record, TI);
119 EXPECT_TRUE(Success);
120 return Success & checkTypeReferencesImpl(RecordIndex, CVRecords,
121 std::forward<Indices>(Rest)...);
124 void discoverAllTypeIndices() {
125 Refs.resize(TTB->records().size());
126 for (uint32_t I = 0; I < TTB->records().size(); ++I) {
127 ArrayRef<uint8_t> Data = TTB->records()[I];
128 discoverTypeIndices(Data, Refs[I]);
132 void discoverTypeIndicesInSymbols() {
133 Refs.resize(Symbols.size());
134 for (uint32_t I = 0; I < Symbols.size(); ++I)
135 discoverTypeIndicesInSymbol(Symbols[I], Refs[I]);
138 // Helper function to write out a field list record with the given list
139 // of member records.
140 void writeFieldListImpl() {}
142 template <typename RecType, typename... Rest>
143 void writeFieldListImpl(RecType &&Record, Rest &&... Records) {
144 CRB->writeMemberType(Record);
145 writeFieldListImpl(std::forward<Rest>(Records)...);
148 // Helper function to write out a list of type records.
149 void writeTypeRecordsImpl() {}
151 template <typename RecType, typename... Rest>
152 void writeTypeRecordsImpl(RecType &&Record, Rest &&... Records) {
153 TTB->writeLeafType(Record);
154 writeTypeRecordsImpl(std::forward<Rest>(Records)...);
157 // Helper function to write out a list of symbol records.
158 void writeSymbolRecordsImpl() {}
160 template <typename RecType, typename... Rest>
161 void writeSymbolRecordsImpl(RecType &&Record, Rest &&... Records) {
162 Symbols.push_back(SymbolSerializer::writeOneSymbol(Record, Storage,
163 CodeViewContainer::Pdb));
164 writeSymbolRecordsImpl(std::forward<Rest>(Records)...);
167 std::vector<SmallVector<TiReference, 4>> Refs;
168 std::unique_ptr<ContinuationRecordBuilder> CRB;
169 std::vector<CVSymbol> Symbols;
170 BumpPtrAllocator Storage;
174 static FuncIdRecord FuncId(TypeIndex(1), TypeIndex(2), "FuncId");
175 static MemberFuncIdRecord MemFuncId(TypeIndex(3), TypeIndex(4), "FuncId");
176 static StringIdRecord StringId(TypeIndex(5), "TheString");
178 std::vector<TypeIndex> Ids = {TypeIndex(6), TypeIndex(7), TypeIndex(8)};
179 StringListRecord Record{TypeRecordKind::StringList, Ids};
182 std::vector<TypeIndex> Ids = {TypeIndex(9), TypeIndex(10), TypeIndex(11)};
183 BuildInfoRecord Record{Ids};
185 static UdtSourceLineRecord UdtSourceLine(TypeIndex(12), TypeIndex(13), 0);
186 static UdtModSourceLineRecord UdtModSourceLine(TypeIndex(14), TypeIndex(15), 0,
188 static ModifierRecord Modifier(TypeIndex(16), ModifierOptions::None);
189 static ProcedureRecord Procedure(TypeIndex(17), CallingConvention::PpcCall,
190 FunctionOptions::None, 0, TypeIndex(18));
191 static MemberFunctionRecord MemberFunction(TypeIndex(19), TypeIndex(20),
193 CallingConvention::ThisCall,
194 FunctionOptions::None, 2,
197 std::vector<TypeIndex> Ids = {TypeIndex(23), TypeIndex(24), TypeIndex(25)};
198 ArgListRecord Record{TypeRecordKind::ArgList, Ids};
200 static ArrayRecord Array(TypeIndex(26), TypeIndex(27), 10, "MyArray");
201 static ClassRecord Class(TypeRecordKind::Class, 3, ClassOptions::None,
202 TypeIndex(28), TypeIndex(29), TypeIndex(30), 10,
203 "MyClass", "MyClassUniqueName");
204 static ClassRecord Struct(TypeRecordKind::Struct, 3, ClassOptions::None,
205 TypeIndex(31), TypeIndex(32), TypeIndex(33), 10,
206 "MyClass", "MyClassUniqueName");
207 static UnionRecord Union(1, ClassOptions::None, TypeIndex(34), 10, "MyUnion",
208 "MyUnionUniqueName");
209 static EnumRecord Enum(1, ClassOptions::None, TypeIndex(35), "MyEnum",
210 "EnumUniqueName", TypeIndex(36));
211 static BitFieldRecord BitField(TypeIndex(37), 1, 0);
212 static VFTableRecord VFTable(TypeIndex(38), TypeIndex(39), 1, "VFT", {});
213 static VFTableShapeRecord VTableShape({});
215 const TypeIndex T1{40};
216 const TypeIndex T2{41};
217 const TypeIndex T3{42};
218 const TypeIndex T4{43};
220 std::vector<OneMethodRecord> Methods{
221 {T1, MemberAccess::Public, MethodKind::IntroducingVirtual,
222 MethodOptions::None, 0, "Method1"},
223 {T2, MemberAccess::Public, MethodKind::PureVirtual, MethodOptions::None,
225 {T3, MemberAccess::Public, MethodKind::PureIntroducingVirtual,
226 MethodOptions::None, 0, "Method1"},
227 {T4, MemberAccess::Public, MethodKind::Static, MethodOptions::None, 0,
230 MethodOverloadListRecord Record{Methods};
231 } MethodOverloadList;
232 static PointerRecord Pointer(TypeIndex(44), PointerKind::Near32,
233 PointerMode::Pointer, PointerOptions::Const, 3);
234 static PointerRecord MemberPointer(
235 TypeIndex(45), PointerKind::Near32, PointerMode::PointerToDataMember,
236 PointerOptions::Const, 3,
237 MemberPointerInfo(TypeIndex(46),
238 PointerToMemberRepresentation::GeneralData));
242 static BaseClassRecord BaseClass(MemberAccess::Public, TypeIndex(47), 0);
243 static EnumeratorRecord Enumerator(MemberAccess::Public,
244 APSInt(APInt(8, 3, false)), "Test");
245 DataMemberRecord DataMember(MemberAccess::Public, TypeIndex(48), 0, "Test");
246 OverloadedMethodRecord OverloadedMethod(3, TypeIndex(49), "MethodList");
248 const TypeIndex T1{50};
249 const TypeIndex T2{51};
250 const TypeIndex T3{52};
251 const TypeIndex T4{53};
252 OneMethodRecord R1{T1,
253 MemberAccess::Public,
254 MethodKind::IntroducingVirtual,
258 OneMethodRecord R2{T2,
259 MemberAccess::Public,
260 MethodKind::PureVirtual,
264 OneMethodRecord R3{T3,
265 MemberAccess::Public,
266 MethodKind::PureIntroducingVirtual,
270 OneMethodRecord R4{T4,
271 MemberAccess::Protected,
273 MethodOptions::CompilerGenerated,
277 static NestedTypeRecord NestedType(TypeIndex(54), "MyClass");
278 static StaticDataMemberRecord StaticDataMember(MemberAccess::Public,
279 TypeIndex(55), "Foo");
280 static VirtualBaseClassRecord VirtualBaseClass(TypeRecordKind::VirtualBaseClass,
281 MemberAccess::Public,
282 TypeIndex(56), TypeIndex(57), 0,
284 static VFPtrRecord VFPtr(TypeIndex(58));
285 static ListContinuationRecord Continuation(TypeIndex(59));
288 TEST_F(TypeIndexIteratorTest, FuncId) {
289 using namespace leafs;
290 writeTypeRecords(FuncId);
291 checkTypeReferences(0, FuncId.FunctionType, FuncId.ParentScope);
294 TEST_F(TypeIndexIteratorTest, MemFuncId) {
295 using namespace leafs;
296 writeTypeRecords(MemFuncId);
297 checkTypeReferences(0, MemFuncId.ClassType, MemFuncId.FunctionType);
300 TEST_F(TypeIndexIteratorTest, StringId) {
301 using namespace leafs;
302 writeTypeRecords(StringId);
303 checkTypeReferences(0, StringId.Id);
306 TEST_F(TypeIndexIteratorTest, SubstrList) {
307 using namespace leafs;
308 writeTypeRecords(StringList.Record);
309 checkTypeReferences(0, StringList.Ids[0], StringList.Ids[1],
313 TEST_F(TypeIndexIteratorTest, BuildInfo) {
314 using namespace leafs;
315 writeTypeRecords(BuildInfo.Record);
316 checkTypeReferences(0, BuildInfo.Ids[0], BuildInfo.Ids[1], BuildInfo.Ids[2]);
319 TEST_F(TypeIndexIteratorTest, UdtSrcLine) {
320 using namespace leafs;
321 writeTypeRecords(UdtSourceLine);
322 checkTypeReferences(0, UdtSourceLine.UDT, UdtSourceLine.SourceFile);
325 TEST_F(TypeIndexIteratorTest, UdtModSrcLine) {
326 using namespace leafs;
327 writeTypeRecords(UdtModSourceLine);
328 checkTypeReferences(0, UdtModSourceLine.UDT, UdtModSourceLine.SourceFile);
331 TEST_F(TypeIndexIteratorTest, Modifier) {
332 using namespace leafs;
333 writeTypeRecords(Modifier);
334 checkTypeReferences(0, Modifier.ModifiedType);
337 TEST_F(TypeIndexIteratorTest, Procedure) {
338 using namespace leafs;
339 writeTypeRecords(Procedure);
340 checkTypeReferences(0, Procedure.ReturnType, Procedure.ArgumentList);
343 TEST_F(TypeIndexIteratorTest, MemFunc) {
344 using namespace leafs;
345 writeTypeRecords(MemberFunction);
346 checkTypeReferences(0, MemberFunction.ReturnType, MemberFunction.ClassType,
347 MemberFunction.ThisType, MemberFunction.ArgumentList);
350 TEST_F(TypeIndexIteratorTest, ArgList) {
351 using namespace leafs;
352 writeTypeRecords(ArgList.Record);
353 checkTypeReferences(0, ArgList.Ids[0], ArgList.Ids[1], ArgList.Ids[2]);
356 TEST_F(TypeIndexIteratorTest, Array) {
357 using namespace leafs;
358 writeTypeRecords(Array);
359 checkTypeReferences(0, Array.ElementType, Array.IndexType);
362 TEST_F(TypeIndexIteratorTest, Class) {
363 using namespace leafs;
364 writeTypeRecords(Class);
365 checkTypeReferences(0, Class.FieldList, Class.DerivationList,
369 TEST_F(TypeIndexIteratorTest, Struct) {
370 using namespace leafs;
371 writeTypeRecords(Struct);
372 checkTypeReferences(0, Struct.FieldList, Struct.DerivationList,
376 TEST_F(TypeIndexIteratorTest, Union) {
377 using namespace leafs;
378 writeTypeRecords(Union);
379 checkTypeReferences(0, Union.FieldList);
382 TEST_F(TypeIndexIteratorTest, Enum) {
383 using namespace leafs;
384 writeTypeRecords(Enum);
385 checkTypeReferences(0, Enum.FieldList, Enum.UnderlyingType);
388 TEST_F(TypeIndexIteratorTest, Bitfield) {
389 using namespace leafs;
390 writeTypeRecords(BitField);
391 checkTypeReferences(0, BitField.Type);
394 TEST_F(TypeIndexIteratorTest, VTable) {
395 using namespace leafs;
396 writeTypeRecords(VFTable);
397 checkTypeReferences(0, VFTable.CompleteClass, VFTable.OverriddenVFTable);
400 TEST_F(TypeIndexIteratorTest, VTShape) {
401 using namespace leafs;
402 writeTypeRecords(VTableShape);
403 checkTypeReferences(0);
406 TEST_F(TypeIndexIteratorTest, OverloadList) {
407 using namespace leafs;
408 writeTypeRecords(MethodOverloadList.Record);
409 checkTypeReferences(0, MethodOverloadList.T1, MethodOverloadList.T2,
410 MethodOverloadList.T3, MethodOverloadList.T4);
413 TEST_F(TypeIndexIteratorTest, Pointer) {
414 using namespace leafs;
415 writeTypeRecords(Pointer);
416 checkTypeReferences(0, Pointer.ReferentType);
419 TEST_F(TypeIndexIteratorTest, MemberPointer) {
420 using namespace leafs;
421 writeTypeRecords(MemberPointer);
422 checkTypeReferences(0, MemberPointer.ReferentType,
423 MemberPointer.MemberInfo->ContainingType);
426 TEST_F(TypeIndexIteratorTest, ManyTypes) {
428 using namespace leafs;
429 writeTypeRecords(FuncId, MemFuncId, StringId, StringList.Record,
430 BuildInfo.Record, UdtSourceLine, UdtModSourceLine, Modifier,
431 Procedure, MemberFunction, ArgList.Record, Array, Class,
432 Union, Enum, BitField, VFTable, VTableShape,
433 MethodOverloadList.Record, Pointer, MemberPointer);
435 checkTypeReferences(0, FuncId.FunctionType, FuncId.ParentScope);
436 checkTypeReferences(1, MemFuncId.ClassType, MemFuncId.FunctionType);
437 checkTypeReferences(2, StringId.Id);
438 checkTypeReferences(3, StringList.Ids[0], StringList.Ids[1],
440 checkTypeReferences(4, BuildInfo.Ids[0], BuildInfo.Ids[1], BuildInfo.Ids[2]);
441 checkTypeReferences(5, UdtSourceLine.UDT, UdtSourceLine.SourceFile);
442 checkTypeReferences(6, UdtModSourceLine.UDT, UdtModSourceLine.SourceFile);
443 checkTypeReferences(7, Modifier.ModifiedType);
444 checkTypeReferences(8, Procedure.ReturnType, Procedure.ArgumentList);
445 checkTypeReferences(9, MemberFunction.ReturnType, MemberFunction.ClassType,
446 MemberFunction.ThisType, MemberFunction.ArgumentList);
447 checkTypeReferences(10, ArgList.Ids[0], ArgList.Ids[1], ArgList.Ids[2]);
448 checkTypeReferences(11, Array.ElementType, Array.IndexType);
449 checkTypeReferences(12, Class.FieldList, Class.DerivationList,
451 checkTypeReferences(13, Union.FieldList);
452 checkTypeReferences(14, Enum.FieldList, Enum.UnderlyingType);
453 checkTypeReferences(15, BitField.Type);
454 checkTypeReferences(16, VFTable.CompleteClass, VFTable.OverriddenVFTable);
455 checkTypeReferences(17);
456 checkTypeReferences(18, MethodOverloadList.T1, MethodOverloadList.T2,
457 MethodOverloadList.T3, MethodOverloadList.T4);
458 checkTypeReferences(19, Pointer.ReferentType);
459 checkTypeReferences(20, MemberPointer.ReferentType,
460 MemberPointer.MemberInfo->ContainingType);
463 TEST_F(TypeIndexIteratorTest, FieldListBaseClass) {
464 using namespace members;
465 writeFieldList(BaseClass);
466 checkTypeReferences(0, BaseClass.Type);
469 TEST_F(TypeIndexIteratorTest, FieldListEnumerator) {
470 using namespace members;
471 writeFieldList(Enumerator);
472 checkTypeReferences(0);
475 TEST_F(TypeIndexIteratorTest, FieldListMember) {
476 using namespace members;
477 writeFieldList(DataMember);
478 checkTypeReferences(0, DataMember.Type);
481 TEST_F(TypeIndexIteratorTest, FieldListMethod) {
482 using namespace members;
483 writeFieldList(OverloadedMethod);
484 checkTypeReferences(0, OverloadedMethod.MethodList);
487 TEST_F(TypeIndexIteratorTest, FieldListOneMethod) {
488 using namespace members;
489 writeFieldList(OneMethod.R1, OneMethod.R2, OneMethod.R3, OneMethod.R4);
490 checkTypeReferences(0, OneMethod.T1, OneMethod.T2, OneMethod.T3,
494 TEST_F(TypeIndexIteratorTest, FieldListNestedType) {
495 using namespace members;
496 writeFieldList(NestedType);
497 checkTypeReferences(0, NestedType.Type);
500 TEST_F(TypeIndexIteratorTest, FieldListStaticMember) {
501 using namespace members;
502 writeFieldList(StaticDataMember);
503 checkTypeReferences(0, StaticDataMember.Type);
506 TEST_F(TypeIndexIteratorTest, FieldListVirtualBase) {
507 using namespace members;
508 writeFieldList(VirtualBaseClass);
509 checkTypeReferences(0, VirtualBaseClass.BaseType, VirtualBaseClass.VBPtrType);
512 TEST_F(TypeIndexIteratorTest, FieldListVFTable) {
513 using namespace members;
514 writeFieldList(VFPtr);
515 checkTypeReferences(0, VFPtr.Type);
518 TEST_F(TypeIndexIteratorTest, FieldListContinuation) {
519 using namespace members;
520 writeFieldList(Continuation);
521 checkTypeReferences(0, Continuation.ContinuationIndex);
524 TEST_F(TypeIndexIteratorTest, ManyMembers) {
525 using namespace members;
526 writeFieldList(BaseClass, Enumerator, DataMember, OverloadedMethod,
527 OneMethod.R1, OneMethod.R2, OneMethod.R3, OneMethod.R4,
528 NestedType, StaticDataMember, VirtualBaseClass, VFPtr,
532 0, BaseClass.Type, DataMember.Type, OverloadedMethod.MethodList,
533 OneMethod.T1, OneMethod.T2, OneMethod.T3, OneMethod.T4, NestedType.Type,
534 StaticDataMember.Type, VirtualBaseClass.BaseType,
535 VirtualBaseClass.VBPtrType, VFPtr.Type, Continuation.ContinuationIndex);
538 TEST_F(TypeIndexIteratorTest, ProcSym) {
539 ProcSym GS(SymbolRecordKind::GlobalProcSym);
540 GS.FunctionType = TypeIndex::Float32();
541 ProcSym LS(SymbolRecordKind::ProcSym);
542 LS.FunctionType = TypeIndex::Float64();
543 writeSymbolRecords(GS, LS);
544 checkTypeReferences(0, GS.FunctionType);
545 checkTypeReferences(1, LS.FunctionType);
548 TEST_F(TypeIndexIteratorTest, DataSym) {
549 DataSym DS(SymbolRecordKind::GlobalData);
550 DS.Type = TypeIndex::Float32();
551 writeSymbolRecords(DS);
552 checkTypeReferences(0, DS.Type);
555 TEST_F(TypeIndexIteratorTest, RegisterSym) {
556 RegisterSym Reg(SymbolRecordKind::RegisterSym);
557 Reg.Index = TypeIndex::UInt32();
558 Reg.Register = RegisterId::EAX;
560 writeSymbolRecords(Reg);
561 checkTypeReferences(0, Reg.Index);
564 TEST_F(TypeIndexIteratorTest, CallerSym) {
565 CallerSym Callees(SymbolRecordKind::CalleeSym);
566 Callees.Indices.push_back(TypeIndex(1));
567 Callees.Indices.push_back(TypeIndex(2));
568 Callees.Indices.push_back(TypeIndex(3));
569 CallerSym Callers(SymbolRecordKind::CallerSym);
570 Callers.Indices.push_back(TypeIndex(4));
571 Callers.Indices.push_back(TypeIndex(5));
572 Callers.Indices.push_back(TypeIndex(6));
573 CallerSym Inlinees(SymbolRecordKind::InlineesSym);
574 Inlinees.Indices.push_back(TypeIndex(7));
575 Inlinees.Indices.push_back(TypeIndex(8));
576 Inlinees.Indices.push_back(TypeIndex(9));
577 writeSymbolRecords(Callees, Callers, Inlinees);
578 checkTypeReferences(0, TypeIndex(1), TypeIndex(2), TypeIndex(3));
579 checkTypeReferences(1, TypeIndex(4), TypeIndex(5), TypeIndex(6));
580 checkTypeReferences(2, TypeIndex(7), TypeIndex(8), TypeIndex(9));
583 TEST_F(TypeIndexIteratorTest, Precomp) {
584 PrecompRecord P(TypeRecordKind::Precomp);
585 P.StartTypeIndex = TypeIndex::FirstNonSimpleIndex;
587 P.Signature = 0x12345678;
588 P.PrecompFilePath = "C:/precomp.obj";
590 EndPrecompRecord EP(TypeRecordKind::EndPrecomp);
591 EP.Signature = P.Signature;
593 writeTypeRecords(P, EP);
594 checkTypeReferences(0);