llvm.org GIT mirror llvm / 2a4f117
[CodeView] Provide a common interface for type collections. Right now we have multiple notions of things that represent collections of types. Most commonly used are TypeDatabase, which is supposed to keep mappings from TypeIndex to type name when reading a type stream, which happens when reading PDBs. And also TypeTableBuilder, which is used to build up a collection of types dynamically which we will later serialize (i.e. when writing PDBs). But often you just want to do some operation on a collection of types, and you may want to do the same operation on any kind of collection. For example, you might want to merge two TypeTableBuilders or you might want to merge two type streams that you loaded from various files. This dichotomy between reading and writing is responsible for a lot of the existing code duplication and overlapping responsibilities in the existing CodeView library classes. For example, after building up a TypeTableBuilder with a bunch of type records, if we want to dump it we have to re-invent a bunch of extra glue because our dumper takes a TypeDatabase or a CVTypeArray, which are both incompatible with TypeTableBuilder. This patch introduces an abstract base class called TypeCollection which is shared between the various type collection like things. Wherever we previously stored a TypeDatabase& in some common class, we now store a TypeCollection&. The advantage of this is that all the details of how the collection are implemented, such as lazy deserialization of partial type streams, is completely transparent and you can just treat any collection of types the same regardless of where it came from. Differential Revision: https://reviews.llvm.org/D33293 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@303388 91177308-0d34-0410-b5e6-96231b3b80d8 Zachary Turner 2 years ago
37 changed file(s) with 940 addition(s) and 669 deletion(s). Raw diff Collapse all Expand all
3131 uint32_t length() const { return RecordData.size(); }
3232 Kind kind() const { return Type; }
3333 ArrayRef data() const { return RecordData; }
34 StringRef str_data() const {
35 return StringRef(reinterpret_cast(RecordData.data()),
36 RecordData.size());
37 }
3438
3539 ArrayRef content() const {
3640 return RecordData.drop_front(sizeof(RecordPrefix));
+0
-61
include/llvm/DebugInfo/CodeView/CVTypeDumper.h less more
None //===-- CVTypeDumper.h - CodeView type info dumper --------------*- 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_CVTYPEDUMPER_H
10 #define LLVM_DEBUGINFO_CODEVIEW_CVTYPEDUMPER_H
11
12 #include "llvm/ADT/ArrayRef.h"
13 #include "llvm/ADT/StringSet.h"
14 #include "llvm/DebugInfo/CodeView/TypeDatabase.h"
15 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
16 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
17 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
18 #include "llvm/Support/ScopedPrinter.h"
19
20 namespace llvm {
21
22 namespace codeview {
23
24 class TypeServerHandler;
25
26 /// Dumper for CodeView type streams found in COFF object files and PDB files.
27 class CVTypeDumper {
28 public:
29 explicit CVTypeDumper(TypeDatabase &TypeDB,
30 TypeServerHandler *Handler = nullptr)
31 : TypeDB(TypeDB), Handler(Handler) {}
32
33 /// Dumps one type record. Returns false if there was a type parsing error,
34 /// and true otherwise. This should be called in order, since the dumper
35 /// maintains state about previous records which are necessary for cross
36 /// type references.
37 Error dump(const CVType &Record, TypeVisitorCallbacks &Dumper);
38
39 /// Dumps the type records in Types. Returns false if there was a type stream
40 /// parse error, and true otherwise.
41 Error dump(const CVTypeArray &Types, TypeVisitorCallbacks &Dumper);
42
43 /// Dumps the type records in Data. Returns false if there was a type stream
44 /// parse error, and true otherwise. Use this method instead of the
45 /// CVTypeArray overload when type records are laid out contiguously in
46 /// memory.
47 Error dump(ArrayRef Data, TypeVisitorCallbacks &Dumper);
48
49 static void printTypeIndex(ScopedPrinter &Printer, StringRef FieldName,
50 TypeIndex TI, TypeDatabase &DB);
51
52 private:
53 TypeDatabase &TypeDB;
54 TypeServerHandler *Handler;
55 };
56
57 } // end namespace codeview
58 } // end namespace llvm
59
60 #endif // LLVM_DEBUGINFO_CODEVIEW_TYPEDUMPER_H
99 #ifndef LLVM_DEBUGINFO_CODEVIEW_CVTYPEVISITOR_H
1010 #define LLVM_DEBUGINFO_CODEVIEW_CVTYPEVISITOR_H
1111
12 #include "llvm/ADT/TinyPtrVector.h"
1312 #include "llvm/DebugInfo/CodeView/CVRecord.h"
1413 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
15 #include "llvm/DebugInfo/CodeView/TypeServerHandler.h"
16 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
1714 #include "llvm/Support/Error.h"
1815
1916 namespace llvm {
2017 namespace codeview {
21
22 class CVTypeVisitor {
23 public:
24 explicit CVTypeVisitor(TypeVisitorCallbacks &Callbacks);
25
26 void addTypeServerHandler(TypeServerHandler &Handler);
27
28 Error visitTypeRecord(CVType &Record, TypeIndex Index);
29 Error visitTypeRecord(CVType &Record);
30 Error visitMemberRecord(CVMemberRecord Record);
31
32 /// Visits the type records in Data. Sets the error flag on parse failures.
33 Error visitTypeStream(const CVTypeArray &Types);
34 Error visitTypeStream(CVTypeRange Types);
35
36 Error visitFieldListMemberStream(ArrayRef FieldList);
37 Error visitFieldListMemberStream(BinaryStreamReader Reader);
38
39 private:
40 Expected handleTypeServer(CVType &Record);
41 Error finishVisitation(CVType &Record);
42
43 /// The interface to the class that gets notified of each visitation.
44 TypeVisitorCallbacks &Callbacks;
45
46 TinyPtrVector Handlers;
47 };
18 class TypeCollection;
19 class TypeServerHandler;
20 class TypeVisitorCallbacks;
4821
4922 enum VisitorDataSource {
5023 VDS_BytesPresent, // The record bytes are passed into the the visitation
7548 TypeServerHandler *TS = nullptr);
7649 Error visitTypeStream(CVTypeRange Types, TypeVisitorCallbacks &Callbacks,
7750 TypeServerHandler *TS = nullptr);
51 Error visitTypeStream(TypeCollection &Types, TypeVisitorCallbacks &Callbacks,
52 TypeServerHandler *TS = nullptr);
7853
7954 } // end namespace codeview
8055 } // end namespace llvm
0 //===- LazyRandomTypeCollection.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_LAZYRANDOMTYPECOLLECTION_H
10 #define LLVM_DEBUGINFO_CODEVIEW_LAZYRANDOMTYPECOLLECTION_H
11
12 #include "llvm/DebugInfo/CodeView/TypeCollection.h"
13 #include "llvm/DebugInfo/CodeView/TypeDatabase.h"
14 #include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h"
15 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
16 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
17 #include "llvm/Support/Error.h"
18
19 namespace llvm {
20 namespace codeview {
21
22 class TypeDatabase;
23 class TypeVisitorCallbacks;
24
25 /// \brief Provides amortized O(1) random access to a CodeView type stream.
26 /// Normally to access a type from a type stream, you must know its byte
27 /// offset into the type stream, because type records are variable-lengthed.
28 /// However, this is not the way we prefer to access them. For example, given
29 /// a symbol record one of the fields may be the TypeIndex of the symbol's
30 /// type record. Or given a type record such as an array type, there might
31 /// be a TypeIndex for the element type. Sequential access is perfect when
32 /// we're just dumping every entry, but it's very poor for real world usage.
33 ///
34 /// Type streams in PDBs contain an additional field which is a list of pairs
35 /// containing indices and their corresponding offsets, roughly every ~8KB of
36 /// record data. This general idea need not be confined to PDBs though. By
37 /// supplying such an array, the producer of a type stream can allow the
38 /// consumer much better access time, because the consumer can find the nearest
39 /// index in this array, and do a linear scan forward only from there.
40 ///
41 /// LazyRandomTypeCollection implements this algorithm, but additionally goes
42 /// one step further by caching offsets of every record that has been visited at
43 /// least once. This way, even repeated visits of the same record will never
44 /// require more than one linear scan. For a type stream of N elements divided
45 /// into M chunks of roughly equal size, this yields a worst case lookup time
46 /// of O(N/M) and an amortized time of O(1).
47 class LazyRandomTypeCollection : public TypeCollection {
48 typedef FixedStreamArray PartialOffsetArray;
49
50 public:
51 explicit LazyRandomTypeCollection(uint32_t RecordCountHint);
52 LazyRandomTypeCollection(StringRef Data, uint32_t RecordCountHint);
53 LazyRandomTypeCollection(ArrayRef Data, uint32_t RecordCountHint);
54 LazyRandomTypeCollection(const CVTypeArray &Types, uint32_t RecordCountHint,
55 PartialOffsetArray PartialOffsets);
56 LazyRandomTypeCollection(const CVTypeArray &Types, uint32_t RecordCountHint);
57
58 void reset(ArrayRef Data);
59 void reset(StringRef Data);
60
61 CVType getType(TypeIndex Index) override;
62 StringRef getTypeName(TypeIndex Index) override;
63 bool contains(TypeIndex Index) override;
64 uint32_t size() override;
65 uint32_t capacity() override;
66 TypeIndex getFirst() override;
67 Optional getNext(TypeIndex Prev) override;
68
69 private:
70 const TypeDatabase &database() const { return Database; }
71 Error ensureTypeExists(TypeIndex Index);
72
73 Error visitRangeForType(TypeIndex TI);
74 Error fullScanForType(TypeIndex TI);
75 Error visitRange(TypeIndex Begin, uint32_t BeginOffset, TypeIndex End);
76 Error visitOneRecord(TypeIndex TI, uint32_t Offset, CVType &Record);
77
78 /// Visited records get automatically added to the type database.
79 TypeDatabase Database;
80
81 /// The type array to allow random access visitation of.
82 CVTypeArray Types;
83
84 /// The database visitor which adds new records to the database.
85 TypeDatabaseVisitor DatabaseVisitor;
86
87 /// A vector mapping type indices to type offset. For every record that has
88 /// been visited, contains the absolute offset of that record in the record
89 /// array.
90 std::vector KnownOffsets;
91
92 /// An array of index offsets for the given type stream, allowing log(N)
93 /// lookups of a type record by index. Similar to KnownOffsets but only
94 /// contains offsets for some type indices, some of which may not have
95 /// ever been visited.
96 PartialOffsetArray PartialOffsets;
97 };
98
99 } // end namespace codeview
100 } // end namespace llvm
101
102 #endif // LLVM_DEBUGINFO_CODEVIEW_LAZYRANDOMTYPECOLLECTION_H
+0
-88
include/llvm/DebugInfo/CodeView/RandomAccessTypeVisitor.h less more
None //===- RandomAccessTypeVisitor.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_RANDOMACCESSTYPEVISITOR_H
10 #define LLVM_DEBUGINFO_CODEVIEW_RANDOMACCESSTYPEVISITOR_H
11
12 #include "llvm/ADT/TinyPtrVector.h"
13 #include "llvm/DebugInfo/CodeView/TypeDatabase.h"
14 #include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h"
15 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
16 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
17 #include "llvm/Support/Error.h"
18
19 namespace llvm {
20 namespace codeview {
21
22 class TypeDatabase;
23 class TypeServerHandler;
24 class TypeVisitorCallbacks;
25
26 /// \brief Provides amortized O(1) random access to a CodeView type stream.
27 /// Normally to access a type from a type stream, you must know its byte
28 /// offset into the type stream, because type records are variable-lengthed.
29 /// However, this is not the way we prefer to access them. For example, given
30 /// a symbol record one of the fields may be the TypeIndex of the symbol's
31 /// type record. Or given a type record such as an array type, there might
32 /// be a TypeIndex for the element type. Sequential access is perfect when
33 /// we're just dumping every entry, but it's very poor for real world usage.
34 ///
35 /// Type streams in PDBs contain an additional field which is a list of pairs
36 /// containing indices and their corresponding offsets, roughly every ~8KB of
37 /// record data. This general idea need not be confined to PDBs though. By
38 /// supplying such an array, the producer of a type stream can allow the
39 /// consumer much better access time, because the consumer can find the nearest
40 /// index in this array, and do a linear scan forward only from there.
41 ///
42 /// RandomAccessTypeVisitor implements this algorithm, but additionally goes one
43 /// step further by caching offsets of every record that has been visited at
44 /// least once. This way, even repeated visits of the same record will never
45 /// require more than one linear scan. For a type stream of N elements divided
46 /// into M chunks of roughly equal size, this yields a worst case lookup time
47 /// of O(N/M) and an amortized time of O(1).
48 class RandomAccessTypeVisitor {
49 typedef FixedStreamArray PartialOffsetArray;
50
51 public:
52 RandomAccessTypeVisitor(const CVTypeArray &Types, uint32_t NumRecords,
53 PartialOffsetArray PartialOffsets);
54
55 Error visitTypeIndex(TypeIndex Index, TypeVisitorCallbacks &Callbacks);
56
57 const TypeDatabase &database() const { return Database; }
58
59 private:
60 Error visitRangeForType(TypeIndex TI);
61 Error visitRange(TypeIndex Begin, uint32_t BeginOffset, TypeIndex End);
62
63 /// Visited records get automatically added to the type database.
64 TypeDatabase Database;
65
66 /// The type array to allow random access visitation of.
67 const CVTypeArray &Types;
68
69 /// The database visitor which adds new records to the database.
70 TypeDatabaseVisitor DatabaseVisitor;
71
72 /// A vector mapping type indices to type offset. For every record that has
73 /// been visited, contains the absolute offset of that record in the record
74 /// array.
75 std::vector KnownOffsets;
76
77 /// An array of index offsets for the given type stream, allowing log(N)
78 /// lookups of a type record by index. Similar to KnownOffsets but only
79 /// contains offsets for some type indices, some of which may not have
80 /// ever been visited.
81 PartialOffsetArray PartialOffsets;
82 };
83
84 } // end namespace codeview
85 } // end namespace llvm
86
87 #endif // LLVM_DEBUGINFO_CODEVIEW_RANDOMACCESSTYPEVISITOR_H
1919 class ScopedPrinter;
2020
2121 namespace codeview {
22 class TypeDatabase;
22 class TypeCollection;
2323
2424 /// Dumper for CodeView symbol streams found in COFF object files and PDB files.
2525 class CVSymbolDumper {
2626 public:
27 CVSymbolDumper(ScopedPrinter &W, TypeDatabase &TypeDB,
27 CVSymbolDumper(ScopedPrinter &W, TypeCollection &Types,
2828 std::unique_ptr ObjDelegate,
2929 bool PrintRecordBytes)
30 : W(W), TypeDB(TypeDB), ObjDelegate(std::move(ObjDelegate)),
30 : W(W), Types(Types), ObjDelegate(std::move(ObjDelegate)),
3131 PrintRecordBytes(PrintRecordBytes) {}
3232
3333 /// Dumps one type record. Returns false if there was a type parsing error,
4242
4343 private:
4444 ScopedPrinter &W;
45 TypeDatabase &TypeDB;
45 TypeCollection &Types;
4646 std::unique_ptr ObjDelegate;
4747
4848 bool PrintRecordBytes;
0 //===- TypeCollection.h - A collection of CodeView type records -*- 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_TYPECOLLECTION_H
10 #define LLVM_DEBUGINFO_CODEVIEW_TYPECOLLECTION_H
11
12 #include "llvm/ADT/StringRef.h"
13
14 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
15 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
16
17 namespace llvm {
18 namespace codeview {
19 class TypeCollection {
20 public:
21 virtual ~TypeCollection() = default;
22
23 bool empty() { return size() == 0; }
24
25 virtual TypeIndex getFirst() = 0;
26 virtual Optional getNext(TypeIndex Prev) = 0;
27
28 virtual CVType getType(TypeIndex Index) = 0;
29 virtual StringRef getTypeName(TypeIndex Index) = 0;
30 virtual bool contains(TypeIndex Index) = 0;
31 virtual uint32_t size() = 0;
32 virtual uint32_t capacity() = 0;
33 };
34 }
35 }
36
37 #endif
1212 #include "llvm/ADT/BitVector.h"
1313 #include "llvm/ADT/SmallVector.h"
1414 #include "llvm/ADT/StringRef.h"
15 #include "llvm/DebugInfo/CodeView/TypeCollection.h"
1516 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
1617 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
1718 #include "llvm/Support/Allocator.h"
1920
2021 namespace llvm {
2122 namespace codeview {
22 class TypeDatabase {
23 class TypeDatabase : public TypeCollection {
2324 friend class RandomAccessTypeVisitor;
2425
2526 public:
4041 CVType &getTypeRecord(TypeIndex Index);
4142
4243 bool contains(TypeIndex Index) const;
43
4444 uint32_t size() const;
4545 uint32_t capacity() const;
4646 bool empty() const;
4747
48 CVType getType(TypeIndex Index) override;
49 StringRef getTypeName(TypeIndex Index) override;
50 bool contains(TypeIndex Index) override;
51 uint32_t size() override;
52 uint32_t capacity() override;
53
54 TypeIndex getFirst() override;
55 Optional getNext(TypeIndex Prev) override;
56
57 Optional largestTypeIndexLessThan(TypeIndex TI) const;
58
59 private:
4860 TypeIndex getAppendIndex() const;
4961
50 private:
5162 void grow();
63 void grow(TypeIndex Index);
5264
5365 BumpPtrAllocator Allocator;
5466
5567 uint32_t Count = 0;
68 TypeIndex LargestTypeIndex;
5669
5770 /// All user defined type records in .debug$T live in here. Type indices
5871 /// greater than 0x1000 are user defined. Subtract 0x1000 from the index to
1111
1212 #include "llvm/ADT/ArrayRef.h"
1313 #include "llvm/ADT/StringSet.h"
14 #include "llvm/DebugInfo/CodeView/TypeDatabase.h"
1514 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
1615 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
1716 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
2120
2221 namespace codeview {
2322
23 class TypeCollection;
24
2425 /// Dumper for CodeView type streams found in COFF object files and PDB files.
2526 class TypeDumpVisitor : public TypeVisitorCallbacks {
2627 public:
27 TypeDumpVisitor(TypeDatabase &TypeDB, ScopedPrinter *W, bool PrintRecordBytes)
28 : W(W), PrintRecordBytes(PrintRecordBytes), TypeDB(TypeDB) {}
28 TypeDumpVisitor(TypeCollection &TpiTypes, ScopedPrinter *W,
29 bool PrintRecordBytes)
30 : W(W), PrintRecordBytes(PrintRecordBytes), TpiTypes(TpiTypes) {}
2931
3032 /// When dumping types from an IPI stream in a PDB, a type index may refer to
3133 /// a type or an item ID. The dumper will lookup the "name" of the index in
3234 /// the item database if appropriate. If ItemDB is null, it will use TypeDB,
3335 /// which is correct when dumping types from an object file (/Z7).
34 void setItemDB(TypeDatabase &DB) { ItemDB = &DB; }
36 void setIpiTypes(TypeCollection &Types) { IpiTypes = &Types; }
3537
3638 void printTypeIndex(StringRef FieldName, TypeIndex TI) const;
3739
6567 /// Get the database of indices for the stream that we are dumping. If ItemDB
6668 /// is set, then we must be dumping an item (IPI) stream. This will also
6769 /// always get the appropriate DB for printing item names.
68 TypeDatabase &getSourceDB() const { return ItemDB ? *ItemDB : TypeDB; }
70 TypeCollection &getSourceTypes() const {
71 return IpiTypes ? *IpiTypes : TpiTypes;
72 }
6973
7074 ScopedPrinter *W;
7175
7276 bool PrintRecordBytes = false;
7377
74 TypeDatabase &TypeDB;
75 TypeDatabase *ItemDB = nullptr;
78 TypeCollection &TpiTypes;
79 TypeCollection *IpiTypes = nullptr;
7680 };
7781
7882 } // end namespace codeview
1414 #include
1515
1616 namespace llvm {
17
18 class ScopedPrinter;
19
1720 namespace codeview {
21
22 class TypeCollection;
1823
1924 enum class SimpleTypeKind : uint32_t {
2025 None = 0x0000, // uncharacterized type (no type)
237242 return Result;
238243 }
239244
245 friend inline uint32_t operator-(const TypeIndex &A, const TypeIndex &B) {
246 assert(A >= B);
247 return A.toArrayIndex() - B.toArrayIndex();
248 }
249
240250 private:
241251 support::ulittle32_t Index;
242252 };
248258 TypeIndex Type;
249259 support::ulittle32_t Offset;
250260 };
261
262 void printTypeIndex(ScopedPrinter &Printer, StringRef FieldName, TypeIndex TI,
263 TypeCollection &Types);
251264 }
252265 }
253266
0 //===- TypeTableCollection.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_TYPETABLECOLLECTION_H
10 #define LLVM_DEBUGINFO_CODEVIEW_TYPETABLECOLLECTION_H
11
12 #include "llvm/DebugInfo/CodeView/TypeCollection.h"
13 #include "llvm/DebugInfo/CodeView/TypeDatabase.h"
14
15 namespace llvm {
16 namespace codeview {
17
18 class TypeTableCollection : public TypeCollection {
19 public:
20 explicit TypeTableCollection(ArrayRef> Records);
21
22 TypeIndex getFirst() override;
23 Optional getNext(TypeIndex Prev) override;
24
25 CVType getType(TypeIndex Index) override;
26 StringRef getTypeName(TypeIndex Index) override;
27 bool contains(TypeIndex Index) override;
28 uint32_t size() override;
29 uint32_t capacity() override;
30
31 private:
32 bool hasCapacityFor(TypeIndex Index) const;
33 void ensureTypeExists(TypeIndex Index);
34
35 ArrayRef> Records;
36 TypeDatabase Database;
37 };
38 }
39 }
40
41 #endif
1616 namespace codeview {
1717
1818 class TypeVisitorCallbacks {
19 friend class CVTypeVisitor;
20
2119 public:
2220 virtual ~TypeVisitorCallbacks() = default;
2321
1212 #include "llvm/ADT/SmallString.h"
1313 #include "llvm/ADT/SmallVector.h"
1414 #include "llvm/ADT/StringMap.h"
15 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
1615 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
1716 #include "llvm/DebugInfo/CodeView/TypeServerHandler.h"
1817 #include "llvm/DebugInfo/PDB/Native/NativeSession.h"
1212
1313 #include "CodeViewDebug.h"
1414 #include "llvm/ADT/TinyPtrVector.h"
15 #include "llvm/DebugInfo/CodeView/CVTypeDumper.h"
1615 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
1716 #include "llvm/DebugInfo/CodeView/CodeView.h"
1817 #include "llvm/DebugInfo/CodeView/Line.h"
2221 #include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
2322 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
2423 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
24 #include "llvm/DebugInfo/CodeView/TypeTableCollection.h"
2525 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
2626 #include "llvm/IR/Constants.h"
2727 #include "llvm/MC/MCAsmInfo.h"
468468 CommentPrefix += ' ';
469469 }
470470
471 TypeDatabase TypeDB(TypeTable.records().size());
472 CVTypeDumper CVTD(TypeDB);
473 TypeTable.ForEachRecord([&](TypeIndex Index, ArrayRef Record) {
471 TypeTableCollection Table(TypeTable.records());
472 Optional B = Table.getFirst();
473 do {
474 // This will fail if the record data is invalid.
475 CVType Record = Table.getType(*B);
476
474477 if (OS.isVerboseAsm()) {
475478 // Emit a block comment describing the type record for readability.
476479 SmallString<512> CommentBlock;
477480 raw_svector_ostream CommentOS(CommentBlock);
478481 ScopedPrinter SP(CommentOS);
479482 SP.setPrefix(CommentPrefix);
480 TypeDumpVisitor TDV(TypeDB, &SP, false);
481 Error E = CVTD.dump(Record, TDV);
483 TypeDumpVisitor TDV(Table, &SP, false);
484
485 Error E = codeview::visitTypeRecord(Record, *B, TDV);
482486 if (E) {
483487 logAllUnhandledErrors(std::move(E), errs(), "error: ");
484488 llvm_unreachable("produced malformed type record");
488492 // newline.
489493 OS.emitRawComment(
490494 CommentOS.str().drop_front(CommentPrefix.size() - 1).rtrim());
491 } else {
492 #ifndef NDEBUG
493 // Assert that the type data is valid even if we aren't dumping
494 // comments. The MSVC linker doesn't do much type record validation,
495 // so the first link of an invalid type record can succeed while
496 // subsequent links will fail with LNK1285.
497 BinaryByteStream Stream(Record, llvm::support::little);
498 CVTypeArray Types;
499 BinaryStreamReader Reader(Stream);
500 Error E = Reader.readArray(Types, Reader.getLength());
501 if (!E) {
502 TypeVisitorCallbacks C;
503 E = codeview::visitTypeStream(Types, C);
504 }
505 if (E) {
506 logAllUnhandledErrors(std::move(E), errs(), "error: ");
507 llvm_unreachable("produced malformed type record");
508 }
509 #endif
510 }
511 StringRef S(reinterpret_cast(Record.data()), Record.size());
512 OS.EmitBinaryData(S);
513 });
495 }
496 OS.EmitBinaryData(Record.str_data());
497 } while (B = Table.getNext(*B));
514498 }
515499
516500 namespace {
11 CodeViewError.cpp
22 CodeViewRecordIO.cpp
33 CVSymbolVisitor.cpp
4 CVTypeDumper.cpp
54 CVTypeVisitor.cpp
65 EnumTables.cpp
76 Formatters.cpp
7 LazyRandomTypeCollection.cpp
88 Line.cpp
99 ModuleDebugFileChecksumFragment.cpp
1010 ModuleDebugFragment.cpp
1212 ModuleDebugFragmentVisitor.cpp
1313 ModuleDebugInlineeLinesFragment.cpp
1414 ModuleDebugLineFragment.cpp
15 RandomAccessTypeVisitor.cpp
1615 RecordSerialization.cpp
1716 StringTable.cpp
1817 SymbolRecordMapping.cpp
2120 TypeDatabase.cpp
2221 TypeDatabaseVisitor.cpp
2322 TypeDumpVisitor.cpp
23 TypeIndex.cpp
2424 TypeRecordMapping.cpp
2525 TypeSerializer.cpp
2626 TypeStreamMerger.cpp
27
27 TypeTableCollection.cpp
28
2829 ADDITIONAL_HEADER_DIRS
2930 ${LLVM_MAIN_INCLUDE_DIR}/llvm/DebugInfo/CodeView
3031 )
+0
-61
lib/DebugInfo/CodeView/CVTypeDumper.cpp less more
None //===-- CVTypeDumper.cpp - CodeView type info dumper ------------*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm/DebugInfo/CodeView/CVTypeDumper.h"
10 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
11 #include "llvm/DebugInfo/CodeView/TypeDatabase.h"
12 #include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h"
13 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
14 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
15 #include "llvm/Support/BinaryByteStream.h"
16
17 using namespace llvm;
18 using namespace llvm::codeview;
19
20 Error CVTypeDumper::dump(const CVType &Record, TypeVisitorCallbacks &Dumper) {
21 TypeDatabaseVisitor DBV(TypeDB);
22 TypeVisitorCallbackPipeline Pipeline;
23 Pipeline.addCallbackToPipeline(DBV);
24 Pipeline.addCallbackToPipeline(Dumper);
25
26 CVType RecordCopy = Record;
27 return codeview::visitTypeRecord(RecordCopy, Pipeline, VDS_BytesPresent,
28 Handler);
29 }
30
31 Error CVTypeDumper::dump(const CVTypeArray &Types,
32 TypeVisitorCallbacks &Dumper) {
33 TypeDatabaseVisitor DBV(TypeDB);
34 TypeVisitorCallbackPipeline Pipeline;
35 Pipeline.addCallbackToPipeline(DBV);
36 Pipeline.addCallbackToPipeline(Dumper);
37
38 return codeview::visitTypeStream(Types, Pipeline, Handler);
39 }
40
41 Error CVTypeDumper::dump(ArrayRef Data, TypeVisitorCallbacks &Dumper) {
42 BinaryByteStream Stream(Data, llvm::support::little);
43 CVTypeArray Types;
44 BinaryStreamReader Reader(Stream);
45 if (auto EC = Reader.readArray(Types, Reader.getLength()))
46 return EC;
47
48 return dump(Types, Dumper);
49 }
50
51 void CVTypeDumper::printTypeIndex(ScopedPrinter &Printer, StringRef FieldName,
52 TypeIndex TI, TypeDatabase &DB) {
53 StringRef TypeName;
54 if (!TI.isNoneType())
55 TypeName = DB.getTypeName(TI);
56 if (!TypeName.empty())
57 Printer.printHex(FieldName, TypeName, TI.getIndex());
58 else
59 Printer.printHex(FieldName, TI.getIndex());
60 }
88
99 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
1010
11 #include "llvm/ADT/TinyPtrVector.h"
1112 #include "llvm/DebugInfo/CodeView/CodeViewError.h"
13 #include "llvm/DebugInfo/CodeView/TypeCollection.h"
1214 #include "llvm/DebugInfo/CodeView/TypeDatabase.h"
1315 #include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h"
1416 #include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
2123 using namespace llvm;
2224 using namespace llvm::codeview;
2325
24 CVTypeVisitor::CVTypeVisitor(TypeVisitorCallbacks &Callbacks)
25 : Callbacks(Callbacks) {}
2626
2727 template
2828 static Error visitKnownRecord(CVType &Record, TypeVisitorCallbacks &Callbacks) {
6565 return R;
6666 }
6767
68 static Error visitMemberRecord(CVMemberRecord &Record,
69 TypeVisitorCallbacks &Callbacks) {
70 if (auto EC = Callbacks.visitMemberBegin(Record))
71 return EC;
72
73 switch (Record.Kind) {
74 default:
75 if (auto EC = Callbacks.visitUnknownMember(Record))
76 return EC;
77 break;
78 #define MEMBER_RECORD(EnumName, EnumVal, Name) \
79 case EnumName: { \
80 if (auto EC = visitKnownMember(Record, Callbacks)) \
81 return EC; \
82 break; \
83 }
84 #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \
85 MEMBER_RECORD(EnumVal, EnumVal, AliasName)
86 #define TYPE_RECORD(EnumName, EnumVal, Name)
87 #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
88 #include "llvm/DebugInfo/CodeView/TypeRecords.def"
89 }
90
91 if (auto EC = Callbacks.visitMemberEnd(Record))
92 return EC;
93
94 return Error::success();
95 }
96
97 namespace {
98
99 class CVTypeVisitor {
100 public:
101 explicit CVTypeVisitor(TypeVisitorCallbacks &Callbacks);
102
103 void addTypeServerHandler(TypeServerHandler &Handler);
104
105 Error visitTypeRecord(CVType &Record, TypeIndex Index);
106 Error visitTypeRecord(CVType &Record);
107
108 /// Visits the type records in Data. Sets the error flag on parse failures.
109 Error visitTypeStream(const CVTypeArray &Types);
110 Error visitTypeStream(CVTypeRange Types);
111 Error visitTypeStream(TypeCollection &Types);
112
113 Error visitMemberRecord(CVMemberRecord Record);
114 Error visitFieldListMemberStream(BinaryStreamReader &Stream);
115
116 private:
117 Expected handleTypeServer(CVType &Record);
118 Error finishVisitation(CVType &Record);
119
120 /// The interface to the class that gets notified of each visitation.
121 TypeVisitorCallbacks &Callbacks;
122
123 TinyPtrVector Handlers;
124 };
125
126 CVTypeVisitor::CVTypeVisitor(TypeVisitorCallbacks &Callbacks)
127 : Callbacks(Callbacks) {}
128
68129 void CVTypeVisitor::addTypeServerHandler(TypeServerHandler &Handler) {
69130 Handlers.push_back(&Handler);
70131 }
143204 return finishVisitation(Record);
144205 }
145206
146 static Error visitMemberRecord(CVMemberRecord &Record,
147 TypeVisitorCallbacks &Callbacks) {
148 if (auto EC = Callbacks.visitMemberBegin(Record))
149 return EC;
150
151 switch (Record.Kind) {
152 default:
153 if (auto EC = Callbacks.visitUnknownMember(Record))
154 return EC;
155 break;
156 #define MEMBER_RECORD(EnumName, EnumVal, Name) \
157 case EnumName: { \
158 if (auto EC = visitKnownMember(Record, Callbacks)) \
159 return EC; \
160 break; \
161 }
162 #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \
163 MEMBER_RECORD(EnumVal, EnumVal, AliasName)
164 #define TYPE_RECORD(EnumName, EnumVal, Name)
165 #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
166 #include "llvm/DebugInfo/CodeView/TypeRecords.def"
167 }
168
169 if (auto EC = Callbacks.visitMemberEnd(Record))
170 return EC;
171
172 return Error::success();
173 }
174
175207 Error CVTypeVisitor::visitMemberRecord(CVMemberRecord Record) {
176208 return ::visitMemberRecord(Record, Callbacks);
177209 }
193225 return Error::success();
194226 }
195227
196 Error CVTypeVisitor::visitFieldListMemberStream(BinaryStreamReader Reader) {
197 FieldListDeserializer Deserializer(Reader);
198 TypeVisitorCallbackPipeline Pipeline;
199 Pipeline.addCallbackToPipeline(Deserializer);
200 Pipeline.addCallbackToPipeline(Callbacks);
201
228 Error CVTypeVisitor::visitTypeStream(TypeCollection &Types) {
229 Optional I = Types.getFirst();
230 do {
231 CVType Type = Types.getType(*I);
232 if (auto EC = visitTypeRecord(Type, *I))
233 return EC;
234 } while (I = Types.getNext(*I));
235 return Error::success();
236 }
237
238 Error CVTypeVisitor::visitFieldListMemberStream(BinaryStreamReader &Reader) {
202239 TypeLeafKind Leaf;
203240 while (!Reader.empty()) {
204241 if (auto EC = Reader.readEnum(Leaf))
206243
207244 CVMemberRecord Record;
208245 Record.Kind = Leaf;
209 if (auto EC = ::visitMemberRecord(Record, Pipeline))
210 return EC;
211 }
212
213 return Error::success();
214 }
215
216 Error CVTypeVisitor::visitFieldListMemberStream(ArrayRef Data) {
217 BinaryByteStream S(Data, llvm::support::little);
218 BinaryStreamReader SR(S);
219 return visitFieldListMemberStream(SR);
220 }
221
222 namespace {
246 if (auto EC = ::visitMemberRecord(Record, Callbacks))
247 return EC;
248 }
249
250 return Error::success();
251 }
252
223253 struct FieldListVisitHelper {
224254 FieldListVisitHelper(TypeVisitorCallbacks &Callbacks, ArrayRef Data,
225255 VisitorDataSource Source)
240270 };
241271
242272 struct VisitHelper {
243 VisitHelper(TypeVisitorCallbacks &Callbacks, VisitorDataSource Source,
244 TypeServerHandler *TS)
273 VisitHelper(TypeVisitorCallbacks &Callbacks, VisitorDataSource Source)
245274 : Visitor((Source == VDS_BytesPresent) ? Pipeline : Callbacks) {
246 if (TS)
247 Visitor.addTypeServerHandler(*TS);
248275 if (Source == VDS_BytesPresent) {
249276 Pipeline.addCallbackToPipeline(Deserializer);
250277 Pipeline.addCallbackToPipeline(Callbacks);
261288 TypeVisitorCallbacks &Callbacks,
262289 VisitorDataSource Source,
263290 TypeServerHandler *TS) {
264 VisitHelper Helper(Callbacks, Source, TS);
265 return Helper.Visitor.visitTypeRecord(Record, Index);
291 VisitHelper V(Callbacks, Source);
292 if (TS)
293 V.Visitor.addTypeServerHandler(*TS);
294 return V.Visitor.visitTypeRecord(Record, Index);
266295 }
267296
268297 Error llvm::codeview::visitTypeRecord(CVType &Record,
269298 TypeVisitorCallbacks &Callbacks,
270299 VisitorDataSource Source,
271300 TypeServerHandler *TS) {
272 VisitHelper Helper(Callbacks, Source, TS);
273 return Helper.Visitor.visitTypeRecord(Record);
274 }
275
276 Error llvm::codeview::visitMemberRecordStream(ArrayRef FieldList,
277 TypeVisitorCallbacks &Callbacks) {
278 CVTypeVisitor Visitor(Callbacks);
279 return Visitor.visitFieldListMemberStream(FieldList);
301 VisitHelper V(Callbacks, Source);
302 if (TS)
303 V.Visitor.addTypeServerHandler(*TS);
304 return V.Visitor.visitTypeRecord(Record);
305 }
306
307 Error llvm::codeview::visitTypeStream(const CVTypeArray &Types,
308 TypeVisitorCallbacks &Callbacks,
309 TypeServerHandler *TS) {
310 VisitHelper V(Callbacks, VDS_BytesPresent);
311 if (TS)
312 V.Visitor.addTypeServerHandler(*TS);
313 return V.Visitor.visitTypeStream(Types);
314 }
315
316 Error llvm::codeview::visitTypeStream(CVTypeRange Types,
317 TypeVisitorCallbacks &Callbacks,
318 TypeServerHandler *TS) {
319 VisitHelper V(Callbacks, VDS_BytesPresent);
320 if (TS)
321 V.Visitor.addTypeServerHandler(*TS);
322 return V.Visitor.visitTypeStream(Types);
323 }
324
325 Error llvm::codeview::visitTypeStream(TypeCollection &Types,
326 TypeVisitorCallbacks &Callbacks,
327 TypeServerHandler *TS) {
328 // When the internal visitor calls Types.getType(Index) the interface is
329 // required to return a CVType with the bytes filled out. So we can assume
330 // that the bytes will be present when individual records are visited.
331 VisitHelper V(Callbacks, VDS_BytesPresent);
332 if (TS)
333 V.Visitor.addTypeServerHandler(*TS);
334 return V.Visitor.visitTypeStream(Types);
280335 }
281336
282337 Error llvm::codeview::visitMemberRecord(CVMemberRecord Record,
283338 TypeVisitorCallbacks &Callbacks,
284339 VisitorDataSource Source) {
285 FieldListVisitHelper Helper(Callbacks, Record.Data, Source);
286 return Helper.Visitor.visitMemberRecord(Record);
340 FieldListVisitHelper V(Callbacks, Record.Data, Source);
341 return V.Visitor.visitMemberRecord(Record);
287342 }
288343
289344 Error llvm::codeview::visitMemberRecord(TypeLeafKind Kind,
295350 return visitMemberRecord(R, Callbacks, VDS_BytesPresent);
296351 }
297352
298 Error llvm::codeview::visitTypeStream(const CVTypeArray &Types,
299 TypeVisitorCallbacks &Callbacks,
300 TypeServerHandler *TS) {
301 VisitHelper Helper(Callbacks, VDS_BytesPresent, TS);
302 return Helper.Visitor.visitTypeStream(Types);
303 }
304
305 Error llvm::codeview::visitTypeStream(CVTypeRange Types,
306 TypeVisitorCallbacks &Callbacks,
307 TypeServerHandler *TS) {
308 VisitHelper Helper(Callbacks, VDS_BytesPresent, TS);
309 return Helper.Visitor.visitTypeStream(Types);
310 }
353 Error llvm::codeview::visitMemberRecordStream(ArrayRef FieldList,
354 TypeVisitorCallbacks &Callbacks) {
355 FieldListVisitHelper V(Callbacks, FieldList, VDS_BytesPresent);
356 return V.Visitor.visitFieldListMemberStream(V.Reader);
357 }
0 //===- LazyRandomTypeCollection.cpp ---------------------------- *- C++--*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
10
11 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
12 #include "llvm/DebugInfo/CodeView/CodeViewError.h"
13 #include "llvm/DebugInfo/CodeView/TypeDatabase.h"
14 #include "llvm/DebugInfo/CodeView/TypeServerHandler.h"
15 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
16
17 using namespace llvm;
18 using namespace llvm::codeview;
19
20 static void error(Error &&EC) {
21 assert(!static_cast(EC));
22 if (EC)
23 consumeError(std::move(EC));
24 }
25
26 LazyRandomTypeCollection::LazyRandomTypeCollection(uint32_t RecordCountHint)
27 : LazyRandomTypeCollection(CVTypeArray(), RecordCountHint,
28 PartialOffsetArray()) {}
29
30 LazyRandomTypeCollection::LazyRandomTypeCollection(
31 const CVTypeArray &Types, uint32_t RecordCountHint,
32 PartialOffsetArray PartialOffsets)
33 : Database(RecordCountHint), Types(Types), DatabaseVisitor(Database),
34 PartialOffsets(PartialOffsets) {
35 KnownOffsets.resize(Database.capacity());
36 }
37
38 LazyRandomTypeCollection::LazyRandomTypeCollection(ArrayRef Data,
39 uint32_t RecordCountHint)
40 : LazyRandomTypeCollection(RecordCountHint) {
41 reset(Data);
42 }
43
44 LazyRandomTypeCollection::LazyRandomTypeCollection(StringRef Data,
45 uint32_t RecordCountHint)
46 : LazyRandomTypeCollection(
47 makeArrayRef(Data.bytes_begin(), Data.bytes_end()), RecordCountHint) {
48 }
49
50 LazyRandomTypeCollection::LazyRandomTypeCollection(const CVTypeArray &Types,
51 uint32_t NumRecords)
52 : LazyRandomTypeCollection(Types, NumRecords, PartialOffsetArray()) {}
53
54 void LazyRandomTypeCollection::reset(StringRef Data) {
55 reset(makeArrayRef(Data.bytes_begin(), Data.bytes_end()));
56 }
57
58 void LazyRandomTypeCollection::reset(ArrayRef Data) {
59 PartialOffsets = PartialOffsetArray();
60
61 BinaryStreamReader Reader(Data, support::little);
62 error(Reader.readArray(Types, Reader.getLength()));
63
64 KnownOffsets.resize(Database.capacity());
65 }
66
67 CVType LazyRandomTypeCollection::getType(TypeIndex Index) {
68 error(ensureTypeExists(Index));
69 return Database.getTypeRecord(Index);
70 }
71
72 StringRef LazyRandomTypeCollection::getTypeName(TypeIndex Index) {
73 if (!Index.isSimple()) {
74 // Try to make sure the type exists. Even if it doesn't though, it may be
75 // because we're dumping a symbol stream with no corresponding type stream
76 // present, in which case we still want to be able to print
77 // for the type names.
78 consumeError(ensureTypeExists(Index));
79 }
80
81 return Database.getTypeName(Index);
82 }
83
84 bool LazyRandomTypeCollection::contains(TypeIndex Index) {
85 return Database.contains(Index);
86 }
87
88 uint32_t LazyRandomTypeCollection::size() { return Database.size(); }
89
90 uint32_t LazyRandomTypeCollection::capacity() { return Database.capacity(); }
91
92 Error LazyRandomTypeCollection::ensureTypeExists(TypeIndex TI) {
93 if (!Database.contains(TI)) {
94 if (auto EC = visitRangeForType(TI))
95 return EC;
96 }
97 return Error::success();
98 }
99
100 Error LazyRandomTypeCollection::visitRangeForType(TypeIndex TI) {
101 if (PartialOffsets.empty())
102 return fullScanForType(TI);
103
104 auto Next = std::upper_bound(PartialOffsets.begin(), PartialOffsets.end(), TI,
105 [](TypeIndex Value, const TypeIndexOffset &IO) {
106 return Value < IO.Type;
107 });
108
109 assert(Next != PartialOffsets.begin());
110 auto Prev = std::prev(Next);
111
112 TypeIndex TIB = Prev->Type;
113 if (Database.contains(TIB)) {
114 // They've asked us to fetch a type index, but the entry we found in the
115 // partial offsets array has already been visited. Since we visit an entire
116 // block every time, that means this record should have been previously
117 // discovered. Ultimately, this means this is a request for a non-existant
118 // type index.
119 return make_error("Invalid type index");
120 }
121
122 TypeIndex TIE;
123 if (Next == PartialOffsets.end()) {
124 TIE = TypeIndex::fromArrayIndex(Database.capacity());
125 } else {
126 TIE = Next->Type;
127 }
128
129 if (auto EC = visitRange(TIB, Prev->Offset, TIE))
130 return EC;
131 return Error::success();
132 }
133
134 TypeIndex LazyRandomTypeCollection::getFirst() {
135 TypeIndex TI = TypeIndex::fromArrayIndex(0);
136 error(ensureTypeExists(TI));
137 return TI;
138 }
139
140 Optional LazyRandomTypeCollection::getNext(TypeIndex Prev) {
141 // We can't be sure how long this type stream is, given that the initial count
142 // given to the constructor is just a hint. So just try to make sure the next
143 // record exists, and if anything goes wrong, we must be at the end.
144 if (auto EC = ensureTypeExists(Prev + 1)) {
145 consumeError(std::move(EC));
146 return None;
147 }
148
149 return Prev + 1;
150 }
151
152 Error LazyRandomTypeCollection::fullScanForType(TypeIndex TI) {
153 assert(PartialOffsets.empty());
154
155 TypeIndex CurrentTI = TypeIndex::fromArrayIndex(0);
156 uint32_t Offset = 0;
157 auto Begin = Types.begin();
158
159 if (!Database.empty()) {
160 // In the case of type streams which we don't know the number of records of,
161 // it's possible to search for a type index triggering a full scan, but then
162 // later additional records are added since we didn't know how many there
163 // would be until we did a full visitation, then you try to access the new
164 // type triggering another full scan. To avoid this, we assume that if the
165 // database has some records, this must be what's going on. So we ask the
166 // database for the largest type index less than the one we're searching for
167 // and only do the forward scan from there.
168 auto Prev = Database.largestTypeIndexLessThan(TI);
169 assert(Prev.hasValue() && "Empty database with valid types?");
170 Offset = KnownOffsets[Prev->toArrayIndex()];
171 CurrentTI = *Prev;
172 ++CurrentTI;
173 Begin = Types.at(Offset);
174 ++Begin;
175 Offset = Begin.offset();
176 }
177
178 auto End = Types.end();
179 while (Begin != End) {
180 if (auto EC = visitOneRecord(CurrentTI, Offset, *Begin))
181 return EC;
182
183 Offset += Begin.getRecordLength();
184 ++Begin;
185 ++CurrentTI;
186 }
187 if (CurrentTI <= TI) {
188 return make_error("Type Index does not exist!");
189 }
190 return Error::success();
191 }
192
193 Error LazyRandomTypeCollection::visitRange(TypeIndex Begin,
194 uint32_t BeginOffset,
195 TypeIndex End) {
196
197 auto RI = Types.at(BeginOffset);
198 assert(RI != Types.end());
199
200 while (Begin != End) {
201 if (auto EC = visitOneRecord(Begin, BeginOffset, *RI))
202 return EC;
203
204 BeginOffset += RI.getRecordLength();
205 ++Begin;
206 ++RI;
207 }
208
209 return Error::success();
210 }
211
212 Error LazyRandomTypeCollection::visitOneRecord(TypeIndex TI, uint32_t Offset,
213 CVType &Record) {
214 assert(!Database.contains(TI));
215 if (auto EC = codeview::visitTypeRecord(Record, TI, DatabaseVisitor))
216 return EC;
217 // Keep the KnownOffsets array the same size as the Database's capacity. Since
218 // we don't always know how many records are in the type stream, we need to be
219 // prepared for the database growing and receicing a type index that can't fit
220 // in our current buffer.
221 if (KnownOffsets.size() < Database.capacity())
222 KnownOffsets.resize(Database.capacity());
223 KnownOffsets[TI.toArrayIndex()] = Offset;
224 return Error::success();
225 }
+0
-89
lib/DebugInfo/CodeView/RandomAccessTypeVisitor.cpp less more
None //===- RandomAccessTypeVisitor.cpp ---------------------------- *- C++ --*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm/DebugInfo/CodeView/RandomAccessTypeVisitor.h"
10
11 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
12 #include "llvm/DebugInfo/CodeView/TypeDatabase.h"
13 #include "llvm/DebugInfo/CodeView/TypeServerHandler.h"
14 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
15
16 using namespace llvm;
17 using namespace llvm::codeview;
18
19 RandomAccessTypeVisitor::RandomAccessTypeVisitor(
20 const CVTypeArray &Types, uint32_t NumRecords,
21 PartialOffsetArray PartialOffsets)
22 : Database(NumRecords), Types(Types), DatabaseVisitor(Database),
23 PartialOffsets(PartialOffsets) {
24
25 KnownOffsets.resize(Database.capacity());
26 }
27
28 Error RandomAccessTypeVisitor::visitTypeIndex(TypeIndex TI,
29 TypeVisitorCallbacks &Callbacks) {
30 assert(TI.toArrayIndex() < Database.capacity());
31
32 if (!Database.contains(TI)) {
33 if (auto EC = visitRangeForType(TI))
34 return EC;
35 }
36
37 assert(Database.contains(TI));
38 auto &Record = Database.getTypeRecord(TI);
39 return codeview::visitTypeRecord(Record, TI, Callbacks);
40 }
41
42 Error RandomAccessTypeVisitor::visitRangeForType(TypeIndex TI) {
43 if (PartialOffsets.empty()) {
44 TypeIndex TIB(TypeIndex::FirstNonSimpleIndex);
45 TypeIndex TIE = TIB + Database.capacity();
46 return visitRange(TIB, 0, TIE);
47 }
48
49 auto Next = std::upper_bound(PartialOffsets.begin(), PartialOffsets.end(), TI,
50 [](TypeIndex Value, const TypeIndexOffset &IO) {
51 return Value < IO.Type;
52 });
53
54 assert(Next != PartialOffsets.begin());
55 auto Prev = std::prev(Next);
56
57 TypeIndex TIB = Prev->Type;
58 TypeIndex TIE;
59 if (Next == PartialOffsets.end()) {
60 TIE = TypeIndex::fromArrayIndex(Database.capacity());
61 } else {
62 TIE = Next->Type;
63 }
64
65 if (auto EC = visitRange(TIB, Prev->Offset, TIE))
66 return EC;
67 return Error::success();
68 }
69
70 Error RandomAccessTypeVisitor::visitRange(TypeIndex Begin, uint32_t BeginOffset,
71 TypeIndex End) {
72
73 auto RI = Types.at(BeginOffset);
74 assert(RI != Types.end());
75
76 while (Begin != End) {
77 assert(!Database.contains(Begin));
78 if (auto EC = codeview::visitTypeRecord(*RI, Begin, DatabaseVisitor))
79 return EC;
80 KnownOffsets[Begin.toArrayIndex()] = BeginOffset;
81
82 BeginOffset += RI.getRecordLength();
83 ++Begin;
84 ++RI;
85 }
86
87 return Error::success();
88 }
1010 #include "llvm/ADT/DenseMap.h"
1111 #include "llvm/ADT/SmallString.h"
1212 #include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h"
13 #include "llvm/DebugInfo/CodeView/CVTypeDumper.h"
1413 #include "llvm/DebugInfo/CodeView/EnumTables.h"
1514 #include "llvm/DebugInfo/CodeView/StringTable.h"
1615 #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
3231 /// the visitor out of SymbolDumper.h.
3332 class CVSymbolDumperImpl : public SymbolVisitorCallbacks {
3433 public:
35 CVSymbolDumperImpl(TypeDatabase &TypeDB, SymbolDumpDelegate *ObjDelegate,
34 CVSymbolDumperImpl(TypeCollection &Types, SymbolDumpDelegate *ObjDelegate,
3635 ScopedPrinter &W, bool PrintRecordBytes)
37 : TypeDB(TypeDB), ObjDelegate(ObjDelegate), W(W),
36 : Types(Types), ObjDelegate(ObjDelegate), W(W),
3837 PrintRecordBytes(PrintRecordBytes), InFunctionScope(false) {}
3938
4039 /// CVSymbolVisitor overrides.
5352 void printLocalVariableAddrGap(ArrayRef Gaps);
5453 void printTypeIndex(StringRef FieldName, TypeIndex TI);
5554
56 TypeDatabase &TypeDB;
55 TypeCollection &Types;
5756 SymbolDumpDelegate *ObjDelegate;
5857 ScopedPrinter &W;
5958
8281 }
8382
8483 void CVSymbolDumperImpl::printTypeIndex(StringRef FieldName, TypeIndex TI) {
85 CVTypeDumper::printTypeIndex(W, FieldName, TI, TypeDB);
84 codeview::printTypeIndex(W, FieldName, TI, Types);
8685 }
8786
8887 Error CVSymbolDumperImpl::visitSymbolBegin(CVSymbol &CVR) {
669668 Error CVSymbolDumper::dump(CVRecord &Record) {
670669 SymbolVisitorCallbackPipeline Pipeline;
671670 SymbolDeserializer Deserializer(ObjDelegate.get());
672 CVSymbolDumperImpl Dumper(TypeDB, ObjDelegate.get(), W, PrintRecordBytes);
671 CVSymbolDumperImpl Dumper(Types, ObjDelegate.get(), W, PrintRecordBytes);
673672
674673 Pipeline.addCallbackToPipeline(Deserializer);
675674 Pipeline.addCallbackToPipeline(Dumper);
680679 Error CVSymbolDumper::dump(const CVSymbolArray &Symbols) {
681680 SymbolVisitorCallbackPipeline Pipeline;
682681 SymbolDeserializer Deserializer(ObjDelegate.get());
683 CVSymbolDumperImpl Dumper(TypeDB, ObjDelegate.get(), W, PrintRecordBytes);
682 CVSymbolDumperImpl Dumper(Types, ObjDelegate.get(), W, PrintRecordBytes);
684683
685684 Pipeline.addCallbackToPipeline(Deserializer);
686685 Pipeline.addCallbackToPipeline(Dumper);
7171 }
7272
7373 TypeIndex TypeDatabase::appendType(StringRef Name, const CVType &Data) {
74 TypeIndex TI;
75 TI = getAppendIndex();
76 if (TI.toArrayIndex() >= capacity())
74 LargestTypeIndex = getAppendIndex();
75 if (LargestTypeIndex.toArrayIndex() >= capacity())
7776 grow();
78 recordType(Name, TI, Data);
79 return TI;
77 recordType(Name, LargestTypeIndex, Data);
78 return LargestTypeIndex;
8079 }
8180
8281 void TypeDatabase::recordType(StringRef Name, TypeIndex Index,
8382 const CVType &Data) {
83 LargestTypeIndex = empty() ? Index : std::max(Index, LargestTypeIndex);
84
85 if (LargestTypeIndex.toArrayIndex() >= capacity())
86 grow(Index);
87
8488 uint32_t AI = Index.toArrayIndex();
8589
8690 assert(!contains(Index));
143147
144148 uint32_t TypeDatabase::capacity() const { return TypeRecords.size(); }
145149
146 void TypeDatabase::grow() {
147 TypeRecords.emplace_back();
148 CVUDTNames.emplace_back();
149 ValidRecords.resize(ValidRecords.size() + 1);
150 CVType TypeDatabase::getType(TypeIndex Index) { return getTypeRecord(Index); }
151
152 StringRef TypeDatabase::getTypeName(TypeIndex Index) {
153 return static_cast(this)->getTypeName(Index);
154 }
155
156 bool TypeDatabase::contains(TypeIndex Index) {
157 return static_cast(this)->contains(Index);
158 }
159
160 uint32_t TypeDatabase::size() {
161 return static_cast(this)->size();
162 }
163
164 uint32_t TypeDatabase::capacity() {
165 return static_cast(this)->capacity();
166 }
167
168 void TypeDatabase::grow() { grow(LargestTypeIndex + 1); }
169
170 void TypeDatabase::grow(TypeIndex NewIndex) {
171 uint32_t NewSize = NewIndex.toArrayIndex() + 1;
172
173 if (NewSize <= capacity())
174 return;
175
176 uint32_t NewCapacity = NewSize * 3 / 2;
177
178 TypeRecords.resize(NewCapacity);
179 CVUDTNames.resize(NewCapacity);
180 ValidRecords.resize(NewCapacity);
150181 }
151182
152183 bool TypeDatabase::empty() const { return size() == 0; }
184
185 Optional TypeDatabase::largestTypeIndexLessThan(TypeIndex TI) const {
186 uint32_t AI = TI.toArrayIndex();
187 int N = ValidRecords.find_prev(AI);
188 if (N == -1)
189 return None;
190 return TypeIndex::fromArrayIndex(N);
191 }
153192
154193 TypeIndex TypeDatabase::getAppendIndex() const {
155194 if (empty())
156195 return TypeIndex::fromArrayIndex(0);
157196
158 int Index = ValidRecords.find_last();
159 assert(Index != -1);
160 return TypeIndex::fromArrayIndex(Index) + 1;
161 }
197 return LargestTypeIndex + 1;
198 }
199
200 TypeIndex TypeDatabase::getFirst() {
201 int N = ValidRecords.find_first();
202 assert(N != -1);
203 return TypeIndex::fromArrayIndex(N);
204 }
205
206 Optional TypeDatabase::getNext(TypeIndex Prev) {
207 int N = ValidRecords.find_next(Prev.toArrayIndex());
208 if (N == -1)
209 return None;
210 return TypeIndex::fromArrayIndex(N);
211 }
99 #include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
1010
1111 #include "llvm/ADT/SmallString.h"
12 #include "llvm/DebugInfo/CodeView/CVTypeDumper.h"
1312 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
1413 #include "llvm/DebugInfo/CodeView/Formatters.h"
14 #include "llvm/DebugInfo/CodeView/TypeCollection.h"
1515 #include "llvm/DebugInfo/CodeView/TypeDatabase.h"
1616 #include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h"
17 #include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
1817 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
1918 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
20 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
2119 #include "llvm/Support/BinaryByteStream.h"
2220 #include "llvm/Support/FormatVariadic.h"
2321 #include "llvm/Support/ScopedPrinter.h"
164162 }
165163
166164 void TypeDumpVisitor::printTypeIndex(StringRef FieldName, TypeIndex TI) const {
167 CVTypeDumper::printTypeIndex(*W, FieldName, TI, TypeDB);
165 codeview::printTypeIndex(*W, FieldName, TI, TpiTypes);
168166 }
169167
170168 void TypeDumpVisitor::printItemIndex(StringRef FieldName, TypeIndex TI) const {
171 CVTypeDumper::printTypeIndex(*W, FieldName, TI, getSourceDB());
169 codeview::printTypeIndex(*W, FieldName, TI, getSourceTypes());
172170 }
173171
174172 Error TypeDumpVisitor::visitTypeBegin(CVType &Record) {
175 TypeIndex TI = getSourceDB().getAppendIndex();
176 return visitTypeBegin(Record, TI);
173 return visitTypeBegin(Record, TypeIndex::fromArrayIndex(TpiTypes.size()));
177174 }
178175
179176 Error TypeDumpVisitor::visitTypeBegin(CVType &Record, TypeIndex Index) {
0 //===-- TypeIndex.cpp - CodeView type index ---------------------*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
10
11 #include "llvm/DebugInfo/CodeView/TypeCollection.h"
12 #include "llvm/Support/ScopedPrinter.h"
13
14 using namespace llvm;
15 using namespace llvm::codeview;
16
17 void llvm::codeview::printTypeIndex(ScopedPrinter &Printer, StringRef FieldName,
18 TypeIndex TI, TypeCollection &Types) {
19 StringRef TypeName;
20 if (!TI.isNoneType())
21 TypeName = Types.getTypeName(TI);
22 if (!TypeName.empty())
23 Printer.printHex(FieldName, TypeName, TI.getIndex());
24 else
25 Printer.printHex(FieldName, TI.getIndex());
26 }
1010 #include "llvm/ADT/SmallString.h"
1111 #include "llvm/ADT/StringExtras.h"
1212 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
13 #include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
1413 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
1514 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
1615 #include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
17 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
1816 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
1917 #include "llvm/Support/Error.h"
2018 #include "llvm/Support/ScopedPrinter.h"
0 //===- TypeTableCollection.cpp -------------------------------- *- C++ --*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm/DebugInfo/CodeView/TypeTableCollection.h"
10
11 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
12 #include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h"
13 #include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
14 #include "llvm/Support/BinaryByteStream.h"
15 #include "llvm/Support/BinaryStreamReader.h"
16
17 using namespace llvm;
18 using namespace llvm::codeview;
19
20 static void error(Error &&EC) {
21 assert(!static_cast(EC));
22 if (EC)
23 consumeError(std::move(EC));
24 }
25
26 TypeTableCollection::TypeTableCollection(
27 ArrayRef> Records)
28 : Records(Records), Database(Records.size()) {}
29
30 TypeIndex TypeTableCollection::getFirst() {
31 assert(!empty());
32 return TypeIndex::fromArrayIndex(0);
33 }
34
35 Optional TypeTableCollection::getNext(TypeIndex Prev) {
36 ++Prev;
37 assert(Prev.toArrayIndex() <= size());
38 if (Prev.toArrayIndex() == size())
39 return None;
40 return Prev;
41 }
42
43 void TypeTableCollection::ensureTypeExists(TypeIndex Index) {
44 assert(hasCapacityFor(Index));
45
46 if (Database.contains(Index))
47 return;
48
49 BinaryByteStream Bytes(Records[Index.toArrayIndex()], support::little);
50
51 CVType Type;
52 uint32_t Len;
53 error(VarStreamArrayExtractor::extract(Bytes, Len, Type));
54
55 TypeDatabaseVisitor DBV(Database);
56 error(codeview::visitTypeRecord(Type, Index, DBV));
57 assert(Database.contains(Index));
58 }
59
60 CVType TypeTableCollection::getType(TypeIndex Index) {
61 ensureTypeExists(Index);
62 return Database.getTypeRecord(Index);
63 }
64
65 StringRef TypeTableCollection::getTypeName(TypeIndex Index) {
66 if (!Index.isSimple())
67 ensureTypeExists(Index);
68 return Database.getTypeName(Index);
69 }
70
71 bool TypeTableCollection::contains(TypeIndex Index) {
72 return Database.contains(Index);
73 }
74
75 uint32_t TypeTableCollection::size() { return Records.size(); }
76
77 uint32_t TypeTableCollection::capacity() { return Records.size(); }
78
79 bool TypeTableCollection::hasCapacityFor(TypeIndex Index) const {
80 return Index.toArrayIndex() < Records.size();
81 }
2020
2121 #include "llvm/DebugInfo/PDB/Native/PDBTypeServerHandler.h"
2222
23 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
2324 #include "llvm/DebugInfo/CodeView/CodeViewError.h"
2425 #include "llvm/DebugInfo/PDB/GenericError.h"
2526 #include "llvm/DebugInfo/PDB/Native/InfoStream.h"
88
99 #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
1010 #include "llvm/ADT/iterator_range.h"
11 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
12 #include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
1311 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
14 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
1512 #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
1613 #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
1714 #include "llvm/DebugInfo/PDB/Native/PDBTypeServerHandler.h"
1313 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
1414 #include "llvm/DebugInfo/CodeView/TypeDatabase.h"
1515 #include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h"
16 #include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
1716 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
1817 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
1918 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
2828 return StringRef();
2929 }
3030
31 CompactTypeDumpVisitor::CompactTypeDumpVisitor(TypeDatabase &TypeDB,
31 CompactTypeDumpVisitor::CompactTypeDumpVisitor(TypeCollection &Types,
3232 ScopedPrinter *W)
33 : CompactTypeDumpVisitor(TypeDB, TypeIndex(TypeIndex::FirstNonSimpleIndex),
33 : CompactTypeDumpVisitor(Types, TypeIndex(TypeIndex::FirstNonSimpleIndex),
3434 W) {}
3535
36 CompactTypeDumpVisitor::CompactTypeDumpVisitor(TypeDatabase &TypeDB,
36 CompactTypeDumpVisitor::CompactTypeDumpVisitor(TypeCollection &Types,
3737 TypeIndex FirstTI,
3838 ScopedPrinter *W)
39 : W(W), TI(FirstTI), Offset(0), TypeDB(TypeDB) {}
39 : W(W), TI(FirstTI), Offset(0), Types(Types) {}
4040
4141 Error CompactTypeDumpVisitor::visitTypeBegin(CVType &Record) {
4242 return Error::success();
4545 Error CompactTypeDumpVisitor::visitTypeEnd(CVType &Record) {
4646 uint32_t I = TI.getIndex();
4747 StringRef Leaf = getLeafName(Record.Type);
48 StringRef Name = TypeDB.getTypeName(TI);
48 StringRef Name = Types.getTypeName(TI);
4949 W->printString(
5050 llvm::formatv("Index: {0:x} ({1:N} bytes, offset {2:N}) {3} \"{4}\"", I,
5151 Record.length(), Offset, Leaf, Name)
1616 namespace llvm {
1717 class ScopedPrinter;
1818 namespace codeview {
19 class TypeDatabase;
19 class TypeCollection;
2020 }
2121
2222 namespace pdb {
2525 /// Dumps records on a single line, and ignores member records.
2626 class CompactTypeDumpVisitor : public codeview::TypeVisitorCallbacks {
2727 public:
28 CompactTypeDumpVisitor(codeview::TypeDatabase &TypeDB, ScopedPrinter *W);
29 CompactTypeDumpVisitor(codeview::TypeDatabase &TypeDB,
28 CompactTypeDumpVisitor(codeview::TypeCollection &Types, ScopedPrinter *W);
29 CompactTypeDumpVisitor(codeview::TypeCollection &Types,
3030 codeview::TypeIndex FirstTI, ScopedPrinter *W);
3131
3232 /// Paired begin/end actions for all types. Receives all record data,
3939
4040 codeview::TypeIndex TI;
4141 uint32_t Offset;
42 codeview::TypeDatabase &TypeDB;
42 codeview::TypeCollection &Types;
4343 };
4444
4545 } // end namespace pdb
1313 #include "StreamUtil.h"
1414 #include "llvm-pdbdump.h"
1515
16 #include "llvm/DebugInfo/CodeView/CVTypeDumper.h"
1716 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
1817 #include "llvm/DebugInfo/CodeView/EnumTables.h"
18 #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
1919 #include "llvm/DebugInfo/CodeView/Line.h"
2020 #include "llvm/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.h"
2121 #include "llvm/DebugInfo/CodeView/ModuleDebugFragmentVisitor.h"
2424 #include "llvm/DebugInfo/CodeView/ModuleDebugUnknownFragment.h"
2525 #include "llvm/DebugInfo/CodeView/SymbolDumper.h"
2626 #include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h"
27 #include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
2827 #include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
2928 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
3029 #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
8382
8483 class C13RawVisitor : public C13DebugFragmentVisitor {
8584 public:
86 C13RawVisitor(ScopedPrinter &P, PDBFile &F, TypeDatabase &IPI)
85 C13RawVisitor(ScopedPrinter &P, PDBFile &F, LazyRandomTypeCollection &IPI)
8786 : C13DebugFragmentVisitor(F), P(P), IPI(IPI) {}
8887
8988 Error handleLines() override {
159158 if (auto EC = printFileName("FileName", L.Header->FileID))
160159 return EC;
161160
162 if (auto EC = dumpTypeRecord("Function", IPI, L.Header->Inlinee))
161 if (auto EC = dumpTypeRecord("Function", L.Header->Inlinee))
163162 return EC;
164163 P.printNumber("SourceLine", L.Header->SourceLineNum);
165164 if (IL.hasExtraFiles()) {
175174 }
176175
177176 private:
178 Error dumpTypeRecord(StringRef Label, TypeDatabase &DB, TypeIndex Index) {
179 CompactTypeDumpVisitor CTDV(DB, Index, &P);
177 Error dumpTypeRecord(StringRef Label, TypeIndex Index) {
178 CompactTypeDumpVisitor CTDV(IPI, Index, &P);
180179 DictScope D(P, Label);
181 if (DB.contains(Index)) {
182 CVType &Type = DB.getTypeRecord(Index);
180 if (IPI.contains(Index)) {
181 CVType Type = IPI.getType(Index);
183182 if (auto EC = codeview::visitTypeRecord(Type, CTDV))
184183 return EC;
185184 } else {
198197 }
199198
200199 ScopedPrinter &P;
201 TypeDatabase &IPI;
200 LazyRandomTypeCollection &IPI;
202201 };
203202 }
204203
608607 VerLabel = "IPI Version";
609608 }
610609
611 if (!DumpRecordBytes && !DumpRecords && !DumpTpiHash)
612 return Error::success();
613
614610 auto Tpi = (StreamIdx == StreamTPI) ? File.getPDBTpiStream()
615611 : File.getPDBIpiStream();
616612 if (!Tpi)
617613 return Tpi.takeError();
618614
615 auto ExpectedTypes = initializeTypeDatabase(StreamIdx);
616 if (!ExpectedTypes)
617 return ExpectedTypes.takeError();
618 auto &Types = *ExpectedTypes;
619
620 if (!DumpRecordBytes && !DumpRecords && !DumpTpiHash)
621 return Error::success();
622
619623 std::unique_ptr StreamScope;
620624 std::unique_ptr RecordScope;
621625
623627 P.printNumber(VerLabel, Tpi->getTpiVersion());
624628 P.printNumber("Record count", Tpi->getNumTypeRecords());
625629
626 Optional &StreamDB = (StreamIdx == StreamTPI) ? TypeDB : ItemDB;
627
628630 std::vector> Visitors;
629631
630 if (!StreamDB.hasValue()) {
631 StreamDB.emplace(Tpi->getNumTypeRecords());
632 Visitors.push_back(make_unique(*StreamDB));
633 }
634632 // If we're in dump mode, add a dumper with the appropriate detail level.
635633 if (DumpRecords) {
636634 std::unique_ptr Dumper;
637635 if (opts::raw::CompactRecords)
638 Dumper = make_unique(*StreamDB, &P);
636 Dumper = make_unique(Types, &P);
639637 else {
640 assert(TypeDB.hasValue());
641
642 auto X = make_unique(*TypeDB, &P, false);
638 assert(TpiTypes);
639
640 auto X = make_unique(*TpiTypes, &P, false);
643641 if (StreamIdx == StreamIPI)
644 X->setItemDB(*ItemDB);
642 X->setIpiTypes(*IpiTypes);
645643 Dumper = std::move(X);
646644 }
647645 Visitors.push_back(std::move(Dumper));
659657 if (DumpRecords || DumpRecordBytes)
660658 RecordScope = llvm::make_unique(P, "Records");
661659
662 bool HadError = false;
663
664 TypeIndex T(TypeIndex::FirstNonSimpleIndex);
665 for (auto Type : Tpi->types(&HadError)) {
660 Optional I = Types.getFirst();
661 do {
666662 std::unique_ptr OneRecordScope;
667663
668664 if ((DumpRecords || DumpRecordBytes) && !opts::raw::CompactRecords)
669665 OneRecordScope = llvm::make_unique(P, "");
670666
671 if (auto EC = codeview::visitTypeRecord(Type, Pipeline))
667 auto T = Types.getType(*I);
668 if (auto EC = codeview::visitTypeRecord(T, *I, Pipeline))
672669 return EC;
673
674 ++T;
675 }
676 if (HadError)
677 return make_error(raw_error_code::corrupt_file,
678 "TPI stream contained corrupt record");
670 } while (I = Types.getNext(*I));
679671
680672 if (DumpTpiHash) {
681673 DictScope DD(P, "Hash");
710702 return Error::success();
711703 }
712704
713 Error LLVMOutputStyle::buildTypeDatabase(uint32_t SN) {
714 assert(SN == StreamIPI || SN == StreamTPI);
715
716 auto &DB = (SN == StreamIPI) ? ItemDB : TypeDB;
717
718 if (DB.hasValue())
719 return Error::success();
720
705 Expected
706 LLVMOutputStyle::initializeTypeDatabase(uint32_t SN) {
707 auto &TypeCollection = (SN == StreamTPI) ? TpiTypes : IpiTypes;
721708 auto Tpi =
722709 (SN == StreamTPI) ? File.getPDBTpiStream() : File.getPDBIpiStream();
723
724710 if (!Tpi)
725711 return Tpi.takeError();
726712
727 DB.emplace(Tpi->getNumTypeRecords());
728
729 TypeDatabaseVisitor DBV(*DB);
730
731 auto HashValues = Tpi->getHashValues();
732 if (HashValues.empty())
733 return codeview::visitTypeStream(Tpi->typeArray(), DBV);
734
735 TypeVisitorCallbackPipeline Pipeline;
736 Pipeline.addCallbackToPipeline(DBV);
737
738 TpiHashVerifier HashVerifier(HashValues, Tpi->getNumHashBuckets());
739 Pipeline.addCallbackToPipeline(HashVerifier);
740
741 return codeview::visitTypeStream(Tpi->typeArray(), Pipeline);
713 if (!TypeCollection) {
714 // Initialize the type collection, even if we're not going to dump it. This
715 // way if some other part of the dumper decides it wants to use some or all
716 // of the records for whatever purposes, it can still access them lazily.
717 auto &Types = Tpi->typeArray();
718 uint32_t Count = Tpi->getNumTypeRecords();
719 auto Offsets = Tpi->getTypeIndexOffsets();
720 TypeCollection =
721 llvm::make_unique(Types, Count, Offsets);
722 }
723
724 return *TypeCollection;
742725 }
743726
744727 Error LLVMOutputStyle::dumpDbiStream() {
813796 return EC;
814797
815798 if (ShouldDumpSymbols) {
816 if (auto EC = buildTypeDatabase(StreamTPI))
817 return EC;
799 auto ExpectedTypes = initializeTypeDatabase(StreamTPI);
800 if (!ExpectedTypes)
801 return ExpectedTypes.takeError();
802 auto &Types = *ExpectedTypes;
818803
819804 ListScope SS(P, "Symbols");
820 codeview::CVSymbolDumper SD(P, *TypeDB, nullptr, false);
805 codeview::CVSymbolDumper SD(P, Types, nullptr, false);
821806 bool HadError = false;
822807 for (auto S : ModS.symbols(&HadError)) {
823808 DictScope LL(P, "");
838823 }
839824 if (opts::raw::DumpLineInfo) {
840825 ListScope SS(P, "LineInfo");
841 if (auto EC = buildTypeDatabase(StreamIPI))
842 return EC;
843
844 C13RawVisitor V(P, File, *ItemDB);
826 auto ExpectedTypes = initializeTypeDatabase(StreamIPI);
827 if (!ExpectedTypes)
828 return ExpectedTypes.takeError();
829 auto &IpiItems = *ExpectedTypes;
830 C13RawVisitor V(P, File, IpiItems);
845831 if (auto EC = codeview::visitModuleDebugFragments(
846832 ModS.linesAndChecksums(), V))
847833 return EC;
959945 P.printList("Section Offsets", Publics->getSectionOffsets(),
960946 printSectionOffset);
961947 ListScope L(P, "Symbols");
962 if (auto EC = buildTypeDatabase(StreamTPI))
963 return EC;
964
965 codeview::CVSymbolDumper SD(P, *TypeDB, nullptr, false);
948 auto ExpectedTypes = initializeTypeDatabase(StreamTPI);
949 if (!ExpectedTypes)
950 return ExpectedTypes.takeError();
951 auto &Tpi = *ExpectedTypes;
952
953 codeview::CVSymbolDumper SD(P, Tpi, nullptr, false);
966954 bool HadError = false;
967955 for (auto S : Publics->getSymbols(&HadError)) {
968956 DictScope DD(P, "");
2020
2121 namespace llvm {
2222 class BitVector;
23
24 namespace codeview {
25 class LazyRandomTypeCollection;
26 }
27
2328 namespace pdb {
2429 class LLVMOutputStyle : public OutputStyle {
2530 public:
2833 Error dump() override;
2934
3035 private:
31 Error buildTypeDatabase(uint32_t SN);
36 Expected
37 initializeTypeDatabase(uint32_t SN);
3238
3339 Error dumpFileHeaders();
3440 Error dumpStreamSummary();
5359
5460 PDBFile &File;
5561 ScopedPrinter P;
56 Optional TypeDB;
57 Optional ItemDB;
62 std::unique_ptr TpiTypes;
63 std::unique_ptr IpiTypes;
5864 SmallVector StreamPurposes;
5965 };
6066 }
1818 #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
1919 #include "llvm/DebugInfo/CodeView/SymbolSerializer.h"
2020 #include "llvm/DebugInfo/CodeView/SymbolVisitorCallbackPipeline.h"
21 #include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
2221 #include "llvm/DebugInfo/CodeView/TypeSerializer.h"
2322 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
2423 #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
370369 void MappingContextTraits::
371370 mapping(IO &IO, pdb::yaml::PdbTpiRecord &Obj,
372371 pdb::yaml::SerializationContext &Context) {
373
374372 if (IO.outputting()) {
375373 // For PDB to Yaml, deserialize into a high level record type, then dump it.
376374 consumeError(codeview::visitTypeRecord(Obj.Record, Context.Dumper));
1212 #include "OutputStyle.h"
1313 #include "PdbYaml.h"
1414
15 #include "llvm/DebugInfo/CodeView/CVTypeDumper.h"
1615 #include "llvm/Support/ScopedPrinter.h"
1716 #include "llvm/Support/YAMLTraits.h"
1817
1212
1313 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
1414 #include "llvm/DebugInfo/CodeView/EnumTables.h"
15 #include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
1615 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
1716 #include "llvm/DebugInfo/CodeView/TypeSerializer.h"
1817 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
2121 #include "llvm/ADT/DenseMap.h"
2222 #include "llvm/ADT/SmallString.h"
2323 #include "llvm/ADT/StringExtras.h"
24 #include "llvm/DebugInfo/CodeView/CVTypeDumper.h"
24 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
2525 #include "llvm/DebugInfo/CodeView/CodeView.h"
26 #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
2627 #include "llvm/DebugInfo/CodeView/Line.h"
2728 #include "llvm/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.h"
2829 #include "llvm/DebugInfo/CodeView/ModuleDebugInlineeLinesFragment.h"
3334 #include "llvm/DebugInfo/CodeView/SymbolDumpDelegate.h"
3435 #include "llvm/DebugInfo/CodeView/SymbolDumper.h"
3536 #include "llvm/DebugInfo/CodeView/SymbolRecord.h"
37 #include "llvm/DebugInfo/CodeView/TypeDatabase.h"
3638 #include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
3739 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
3840 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
3941 #include "llvm/DebugInfo/CodeView/TypeStreamMerger.h"
4042 #include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
43 #include "llvm/DebugInfo/CodeView/TypeTableCollection.h"
4144 #include "llvm/Object/COFF.h"
4245 #include "llvm/Object/ObjectFile.h"
4346 #include "llvm/Support/BinaryStreamReader.h"
4447 #include "llvm/Support/COFF.h"
45 #include "llvm/Support/ConvertUTF.h"
4648 #include "llvm/Support/Casting.h"
4749 #include "llvm/Support/Compiler.h"
50 #include "llvm/Support/ConvertUTF.h"
4851 #include "llvm/Support/DataExtractor.h"
4952 #include "llvm/Support/FormatVariadic.h"
5053 #include "llvm/Support/Path.h"
6972 public:
7073 friend class COFFObjectDumpDelegate;
7174 COFFDumper(const llvm::object::COFFObjectFile *Obj, ScopedPrinter &Writer)
72 : ObjDumper(Writer), Obj(Obj), Writer(Writer), TypeDB(100) {}
75 : ObjDumper(Writer), Obj(Obj), Writer(Writer), Types(100) {}
7376
7477 void printFileHeaders() override;
7578 void printSections() override;
105108 void printFileNameForOffset(StringRef Label, uint32_t FileOffset);
106109 void printTypeIndex(StringRef FieldName, TypeIndex TI) {
107110 // Forward to CVTypeDumper for simplicity.
108 CVTypeDumper::printTypeIndex(Writer, FieldName, TI, TypeDB);
111 codeview::printTypeIndex(Writer, FieldName, TI, Types);
109112 }
110113
111114 void printCodeViewSymbolsSubsection(StringRef Subsection,
158161 StringTableRef CVStringTable;
159162
160163 ScopedPrinter &Writer;
161 TypeDatabase TypeDB;
164 BinaryByteStream TypeContents;
165 LazyRandomTypeCollection Types;
162166 };
163167
164168 class COFFObjectDumpDelegate : public SymbolDumpDelegate {
974978 Subsection.bytes_end());
975979 auto CODD = llvm::make_unique(*this, Section, Obj,
976980 SectionContents);
977
978 CVSymbolDumper CVSD(W, TypeDB, std::move(CODD),
979 opts::CodeViewSubsectionBytes);
981 CVSymbolDumper CVSD(W, Types, std::move(CODD), opts::CodeViewSubsectionBytes);
980982 CVSymbolArray Symbols;
981983 BinaryStreamReader Reader(BinaryData, llvm::support::little);
982984 if (auto EC = Reader.readArray(Symbols, Reader.getLength())) {
10921094 if (Magic != COFF::DEBUG_SECTION_MAGIC)
10931095 return error(object_error::parse_failed);
10941096
1095 CVTypeDumper CVTD(TypeDB);
1096 TypeDumpVisitor TDV(TypeDB, &W, opts::CodeViewSubsectionBytes);
1097 if (auto EC = CVTD.dump({Data.bytes_begin(), Data.bytes_end()}, TDV)) {
1098 W.flush();
1099 error(llvm::errorToErrorCode(std::move(EC)));
1100 }
1097 Types.reset(Data);
1098
1099 TypeDumpVisitor TDV(Types, &W, opts::CodeViewSubsectionBytes);
1100 error(codeview::visitTypeStream(Types, TDV));
1101 W.flush();
11011102 }
11021103
11031104 void COFFDumper::printSections() {
16371638 TypeBuf.append(Record.begin(), Record.end());
16381639 });
16391640
1640 TypeDatabase TypeDB(CVTypes.records().size());
1641 TypeTableCollection TpiTypes(CVTypes.records());
16411642 {
16421643 ListScope S(Writer, "MergedTypeStream");
1643 CVTypeDumper CVTD(TypeDB);
1644 TypeDumpVisitor TDV(TypeDB, &Writer, opts::CodeViewSubsectionBytes);
1645 if (auto EC = CVTD.dump(
1646 {TypeBuf.str().bytes_begin(), TypeBuf.str().bytes_end()}, TDV)) {
1647 Writer.flush();
1648 error(std::move(EC));
1649 }
1644 TypeDumpVisitor TDV(TpiTypes, &Writer, opts::CodeViewSubsectionBytes);
1645 error(codeview::visitTypeStream(TpiTypes, TDV));
1646 Writer.flush();
16501647 }
16511648
16521649 // Flatten the id stream and print it next. The ID stream refers to names from
16531650 // the type stream.
1654 SmallString<0> IDBuf;
1655 IDTable.ForEachRecord([&](TypeIndex TI, ArrayRef Record) {
1656 IDBuf.append(Record.begin(), Record.end());
1657 });
1658
1651 TypeTableCollection IpiTypes(IDTable.records());
16591652 {
16601653 ListScope S(Writer, "MergedIDStream");
1661 TypeDatabase IDDB(IDTable.records().size());
1662 CVTypeDumper CVTD(IDDB);
1663 TypeDumpVisitor TDV(TypeDB, &Writer, opts::CodeViewSubsectionBytes);
1664 TDV.setItemDB(IDDB);
1665 if (auto EC = CVTD.dump(
1666 {IDBuf.str().bytes_begin(), IDBuf.str().bytes_end()}, TDV)) {
1667 Writer.flush();
1668 error(std::move(EC));
1669 }
1670 }
1671 }
1654 TypeDumpVisitor TDV(TpiTypes, &Writer, opts::CodeViewSubsectionBytes);
1655 TDV.setIpiTypes(IpiTypes);
1656 error(codeview::visitTypeStream(IpiTypes, TDV));
1657 Writer.flush();
1658 }
1659 }
1010
1111 #include "llvm/ADT/SmallBitVector.h"
1212 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
13 #include "llvm/DebugInfo/CodeView/RandomAccessTypeVisitor.h"
14 #include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
13 #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
1514 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
1615 #include "llvm/DebugInfo/CodeView/TypeRecordMapping.h"
1716 #include "llvm/DebugInfo/CodeView/TypeSerializer.h"
1817 #include "llvm/DebugInfo/CodeView/TypeServerHandler.h"
1918 #include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
20 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
2119 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
2220 #include "llvm/DebugInfo/PDB/Native/RawTypes.h"
2321 #include "llvm/Support/Allocator.h"
129127
130128 void SetUp() override {
131129 TestState = llvm::make_unique();
132
133 TestState->Pipeline.addCallbackToPipeline(TestState->Deserializer);
134 TestState->Pipeline.addCallbackToPipeline(TestState->Callbacks);
135130 }
136131
137132 void TearDown() override { TestState.reset(); }
138133
139134 protected:
140 bool ValidateDatabaseRecord(const RandomAccessTypeVisitor &Visitor,
141 uint32_t Index) {
135 bool ValidateDatabaseRecord(LazyRandomTypeCollection &Types, uint32_t Index) {
142136 TypeIndex TI = TypeIndex::fromArrayIndex(Index);
143 if (!Visitor.database().contains(TI))
144 return false;
145 if (GlobalState->TypeVector[Index] != Visitor.database().getTypeRecord(TI))
137 if (!Types.contains(TI))
138 return false;
139 if (GlobalState->TypeVector[Index] != Types.getType(TI))
146140 return false;
147141 return true;
148142 }
183177 struct PerTestState {
184178 FixedStreamArray Offsets;
185179
186 TypeVisitorCallbackPipeline Pipeline;
187 TypeDeserializer Deserializer;
188180 MockCallbacks Callbacks;
189181 };
190182
217209
218210 TEST_F(RandomAccessVisitorTest, MultipleVisits) {
219211 TestState->Offsets = createPartialOffsets(GlobalState->Stream, {0, 8});
220 RandomAccessTypeVisitor Visitor(GlobalState->TypeArray,
221 GlobalState->TypeVector.size(),
222 TestState->Offsets);
212 LazyRandomTypeCollection Types(GlobalState->TypeArray,
213 GlobalState->TypeVector.size(),
214 TestState->Offsets);
223215
224216 std::vector IndicesToVisit = {5, 5, 5};
225217
226218 for (uint32_t I : IndicesToVisit) {
227219 TypeIndex TI = TypeIndex::fromArrayIndex(I);
228 EXPECT_NO_ERROR(Visitor.visitTypeIndex(TI, TestState->Pipeline));
220 CVType T = Types.getType(TI);
221 EXPECT_NO_ERROR(codeview::visitTypeRecord(T, TI, TestState->Callbacks));
229222 }
230223
231224 // [0,8) should be present
232 EXPECT_EQ(8u, Visitor.database().size());
225 EXPECT_EQ(8u, Types.size());
233226 for (uint32_t I = 0; I < 8; ++I)
234 EXPECT_TRUE(ValidateDatabaseRecord(Visitor, I));
227 EXPECT_TRUE(ValidateDatabaseRecord(Types, I));
235228
236229 // 5, 5, 5
237230 EXPECT_EQ(3u, TestState->Callbacks.count());
247240
248241 std::vector IndicesToVisit = {7, 4, 2};
249242
250 RandomAccessTypeVisitor Visitor(GlobalState->TypeArray,
251 GlobalState->TypeVector.size(),
252 TestState->Offsets);
253
254 for (uint32_t I : IndicesToVisit) {
255 TypeIndex TI = TypeIndex::fromArrayIndex(I);
256 EXPECT_NO_ERROR(Visitor.visitTypeIndex(TI, TestState->Pipeline));
243 LazyRandomTypeCollection Types(GlobalState->TypeArray,
244 GlobalState->TypeVector.size(),
245 TestState->Offsets);
246 for (uint32_t I : IndicesToVisit) {
247 TypeIndex TI = TypeIndex::fromArrayIndex(I);
248 CVType T = Types.getType(TI);
249 EXPECT_NO_ERROR(codeview::visitTypeRecord(T, TI, TestState->Callbacks));
257250 }
258251
259252 // [0, 7]
260 EXPECT_EQ(8u, Visitor.database().size());
253 EXPECT_EQ(8u, Types.size());
261254 for (uint32_t I = 0; I < 8; ++I)
262 EXPECT_TRUE(ValidateDatabaseRecord(Visitor, I));
255 EXPECT_TRUE(ValidateDatabaseRecord(Types, I));
263256
264257 // 2, 4, 7
265258 EXPECT_EQ(3u, TestState->Callbacks.count());
275268
276269 std::vector IndicesToVisit = {2, 4, 7};
277270
278 RandomAccessTypeVisitor Visitor(GlobalState->TypeArray,
279 GlobalState->TypeVector.size(),
280 TestState->Offsets);
281
282 for (uint32_t I : IndicesToVisit) {
283 TypeIndex TI = TypeIndex::fromArrayIndex(I);
284 EXPECT_NO_ERROR(Visitor.visitTypeIndex(TI, TestState->Pipeline));
271 LazyRandomTypeCollection Types(GlobalState->TypeArray,
272 GlobalState->TypeVector.size(),
273 TestState->Offsets);
274 for (uint32_t I : IndicesToVisit) {
275 TypeIndex TI = TypeIndex::fromArrayIndex(I);
276 CVType T = Types.getType(TI);
277 EXPECT_NO_ERROR(codeview::visitTypeRecord(T, TI, TestState->Callbacks));
285278 }
286279
287280 // [0, 7]
288 EXPECT_EQ(8u, Visitor.database().size());
281 EXPECT_EQ(8u, Types.size());
289282 for (uint32_t I = 0; I < 8; ++I)
290 EXPECT_TRUE(ValidateDatabaseRecord(Visitor, I));
283 EXPECT_TRUE(ValidateDatabaseRecord(Types, I));
291284
292285 // 2, 4, 7
293286 EXPECT_EQ(3u, TestState->Callbacks.count());
304297
305298 std::vector IndicesToVisit = {0, 1, 2};
306299
307 RandomAccessTypeVisitor Visitor(GlobalState->TypeArray,
308 GlobalState->TypeVector.size(),
309 TestState->Offsets);
310
311 for (uint32_t I : IndicesToVisit) {
312 TypeIndex TI = TypeIndex::fromArrayIndex(I);
313 EXPECT_NO_ERROR(Visitor.visitTypeIndex(TI, TestState->Pipeline));
300 LazyRandomTypeCollection Types(GlobalState->TypeArray,
301 GlobalState->TypeVector.size(),
302 TestState->Offsets);
303
304 for (uint32_t I : IndicesToVisit) {
305 TypeIndex TI = TypeIndex::fromArrayIndex(I);
306 CVType T = Types.getType(TI);
307 EXPECT_NO_ERROR(codeview::visitTypeRecord(T, TI, TestState->Callbacks));
314308 }
315309
316310 // [0, 8) should be visited.
317 EXPECT_EQ(8u, Visitor.database().size());
311 EXPECT_EQ(8u, Types.size());
318312 for (uint32_t I = 0; I < 8; ++I)
319 EXPECT_TRUE(ValidateDatabaseRecord(Visitor, I));
313 EXPECT_TRUE(ValidateDatabaseRecord(Types, I));
320314
321315 // [0, 2]
322316 EXPECT_EQ(3u, TestState->Callbacks.count());
332326
333327 std::vector IndicesToVisit = {5, 7};
334328
335 RandomAccessTypeVisitor Visitor(GlobalState->TypeArray,
336 GlobalState->TypeVector.size(),
337 TestState->Offsets);
338
339 for (uint32_t I : IndicesToVisit) {
340 TypeIndex TI = TypeIndex::fromArrayIndex(I);
341 EXPECT_NO_ERROR(Visitor.visitTypeIndex(TI, TestState->Pipeline));
329 LazyRandomTypeCollection Types(GlobalState->TypeArray,
330 GlobalState->TypeVector.size(),
331 TestState->Offsets);
332
333 for (uint32_t I : IndicesToVisit) {
334 TypeIndex TI = TypeIndex::fromArrayIndex(I);
335 CVType T = Types.getType(TI);
336 EXPECT_NO_ERROR(codeview::visitTypeRecord(T, TI, TestState->Callbacks));
342337 }
343338
344339 // [4, 9)
345 EXPECT_EQ(5u, Visitor.database().size());
340 EXPECT_EQ(5u, Types.size());
346341 for (uint32_t I = 4; I < 9; ++I)
347 EXPECT_TRUE(ValidateDatabaseRecord(Visitor, I));
342 EXPECT_TRUE(ValidateDatabaseRecord(Types, I));
348343
349344 // 5, 7
350345 EXPECT_EQ(2u, TestState->Callbacks.count());