llvm.org GIT mirror llvm / d32a382
Resubmit "[CodeView] Provide a common interface for type collections." This was originally reverted because it was a breaking a bunch of bots and the breakage was not surfacing on Windows. After much head-scratching this was ultimately traced back to a bug in the lit test runner related to its pipe handling. Now that the bug in lit is fixed, Windows correctly reports these test failures, and as such I have finally (hopefully) fixed all of them in this patch. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@303446 91177308-0d34-0410-b5e6-96231b3b80d8 Zachary Turner 2 years ago
39 changed file(s) with 951 addition(s) and 671 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 Optional 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 Optional 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 Optional 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 Optional 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 while (B) {
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 B = Table.getNext(*B);
498 }
514499 }
515500
516501 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 while (I) {
231 CVType Type = Types.getType(*I);
232 if (auto EC = visitTypeRecord(Type, *I))
233 return EC;
234 I = Types.getNext(*I);
235 }
236 return Error::success();
237 }
238
239 Error CVTypeVisitor::visitFieldListMemberStream(BinaryStreamReader &Reader) {
202240 TypeLeafKind Leaf;
203241 while (!Reader.empty()) {
204242 if (auto EC = Reader.readEnum(Leaf))
206244
207245 CVMemberRecord Record;
208246 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 {
247 if (auto EC = ::visitMemberRecord(Record, Callbacks))
248 return EC;
249 }
250
251 return Error::success();
252 }
253
223254 struct FieldListVisitHelper {
224255 FieldListVisitHelper(TypeVisitorCallbacks &Callbacks, ArrayRef Data,
225256 VisitorDataSource Source)
240271 };
241272
242273 struct VisitHelper {
243 VisitHelper(TypeVisitorCallbacks &Callbacks, VisitorDataSource Source,
244 TypeServerHandler *TS)
274 VisitHelper(TypeVisitorCallbacks &Callbacks, VisitorDataSource Source)
245275 : Visitor((Source == VDS_BytesPresent) ? Pipeline : Callbacks) {
246 if (TS)
247 Visitor.addTypeServerHandler(*TS);
248276 if (Source == VDS_BytesPresent) {
249277 Pipeline.addCallbackToPipeline(Deserializer);
250278 Pipeline.addCallbackToPipeline(Callbacks);
261289 TypeVisitorCallbacks &Callbacks,
262290 VisitorDataSource Source,
263291 TypeServerHandler *TS) {
264 VisitHelper Helper(Callbacks, Source, TS);
265 return Helper.Visitor.visitTypeRecord(Record, Index);
292 VisitHelper V(Callbacks, Source);
293 if (TS)
294 V.Visitor.addTypeServerHandler(*TS);
295 return V.Visitor.visitTypeRecord(Record, Index);
266296 }
267297
268298 Error llvm::codeview::visitTypeRecord(CVType &Record,
269299 TypeVisitorCallbacks &Callbacks,
270300 VisitorDataSource Source,
271301 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);
302 VisitHelper V(Callbacks, Source);
303 if (TS)
304 V.Visitor.addTypeServerHandler(*TS);
305 return V.Visitor.visitTypeRecord(Record);
306 }
307
308 Error llvm::codeview::visitTypeStream(const CVTypeArray &Types,
309 TypeVisitorCallbacks &Callbacks,
310 TypeServerHandler *TS) {
311 VisitHelper V(Callbacks, VDS_BytesPresent);
312 if (TS)
313 V.Visitor.addTypeServerHandler(*TS);
314 return V.Visitor.visitTypeStream(Types);
315 }
316
317 Error llvm::codeview::visitTypeStream(CVTypeRange Types,
318 TypeVisitorCallbacks &Callbacks,
319 TypeServerHandler *TS) {
320 VisitHelper V(Callbacks, VDS_BytesPresent);
321 if (TS)
322 V.Visitor.addTypeServerHandler(*TS);
323 return V.Visitor.visitTypeStream(Types);
324 }
325
326 Error llvm::codeview::visitTypeStream(TypeCollection &Types,
327 TypeVisitorCallbacks &Callbacks,
328 TypeServerHandler *TS) {
329 // When the internal visitor calls Types.getType(Index) the interface is
330 // required to return a CVType with the bytes filled out. So we can assume
331 // that the bytes will be present when individual records are visited.
332 VisitHelper V(Callbacks, VDS_BytesPresent);
333 if (TS)
334 V.Visitor.addTypeServerHandler(*TS);
335 return V.Visitor.visitTypeStream(Types);
280336 }
281337
282338 Error llvm::codeview::visitMemberRecord(CVMemberRecord Record,
283339 TypeVisitorCallbacks &Callbacks,
284340 VisitorDataSource Source) {
285 FieldListVisitHelper Helper(Callbacks, Record.Data, Source);
286 return Helper.Visitor.visitMemberRecord(Record);
341 FieldListVisitHelper V(Callbacks, Record.Data, Source);
342 return V.Visitor.visitMemberRecord(Record);
287343 }
288344
289345 Error llvm::codeview::visitMemberRecord(TypeLeafKind Kind,
295351 return visitMemberRecord(R, Callbacks, VDS_BytesPresent);
296352 }
297353
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 }
354 Error llvm::codeview::visitMemberRecordStream(ArrayRef FieldList,
355 TypeVisitorCallbacks &Callbacks) {
356 FieldListVisitHelper V(Callbacks, FieldList, VDS_BytesPresent);
357 return V.Visitor.visitFieldListMemberStream(V.Reader);
358 }
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 Optional LazyRandomTypeCollection::getFirst() {
135 TypeIndex TI = TypeIndex::fromArrayIndex(0);
136 if (auto EC = ensureTypeExists(TI)) {
137 consumeError(std::move(EC));
138 return None;
139 }
140 return TI;
141 }
142
143 Optional LazyRandomTypeCollection::getNext(TypeIndex Prev) {
144 // We can't be sure how long this type stream is, given that the initial count
145 // given to the constructor is just a hint. So just try to make sure the next
146 // record exists, and if anything goes wrong, we must be at the end.
147 if (auto EC = ensureTypeExists(Prev + 1)) {
148 consumeError(std::move(EC));
149 return None;
150 }
151
152 return Prev + 1;
153 }
154
155 Error LazyRandomTypeCollection::fullScanForType(TypeIndex TI) {
156 assert(PartialOffsets.empty());
157
158 TypeIndex CurrentTI = TypeIndex::fromArrayIndex(0);
159 uint32_t Offset = 0;
160 auto Begin = Types.begin();
161
162 if (!Database.empty()) {
163 // In the case of type streams which we don't know the number of records of,
164 // it's possible to search for a type index triggering a full scan, but then
165 // later additional records are added since we didn't know how many there
166 // would be until we did a full visitation, then you try to access the new
167 // type triggering another full scan. To avoid this, we assume that if the
168 // database has some records, this must be what's going on. So we ask the
169 // database for the largest type index less than the one we're searching for
170 // and only do the forward scan from there.
171 auto Prev = Database.largestTypeIndexLessThan(TI);
172 assert(Prev.hasValue() && "Empty database with valid types?");
173 Offset = KnownOffsets[Prev->toArrayIndex()];
174 CurrentTI = *Prev;
175 ++CurrentTI;
176 Begin = Types.at(Offset);
177 ++Begin;
178 Offset = Begin.offset();
179 }
180
181 auto End = Types.end();
182 while (Begin != End) {
183 if (auto EC = visitOneRecord(CurrentTI, Offset, *Begin))
184 return EC;
185
186 Offset += Begin.getRecordLength();
187 ++Begin;
188 ++CurrentTI;
189 }
190 if (CurrentTI <= TI) {
191 return make_error("Type Index does not exist!");
192 }
193 return Error::success();
194 }
195
196 Error LazyRandomTypeCollection::visitRange(TypeIndex Begin,
197 uint32_t BeginOffset,
198 TypeIndex End) {
199
200 auto RI = Types.at(BeginOffset);
201 assert(RI != Types.end());
202
203 while (Begin != End) {
204 if (auto EC = visitOneRecord(Begin, BeginOffset, *RI))
205 return EC;
206
207 BeginOffset += RI.getRecordLength();
208 ++Begin;
209 ++RI;
210 }
211
212 return Error::success();
213 }
214
215 Error LazyRandomTypeCollection::visitOneRecord(TypeIndex TI, uint32_t Offset,
216 CVType &Record) {
217 assert(!Database.contains(TI));
218 if (auto EC = codeview::visitTypeRecord(Record, TI, DatabaseVisitor))
219 return EC;
220 // Keep the KnownOffsets array the same size as the Database's capacity. Since
221 // we don't always know how many records are in the type stream, we need to be
222 // prepared for the database growing and receicing a type index that can't fit
223 // in our current buffer.
224 if (KnownOffsets.size() < Database.capacity())
225 KnownOffsets.resize(Database.capacity());
226 KnownOffsets[TI.toArrayIndex()] = Offset;
227 return Error::success();
228 }
+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 Optional TypeDatabase::getFirst() {
201 int N = ValidRecords.find_first();
202 if (N == -1)
203 return None;
204 return TypeIndex::fromArrayIndex(N);
205 }
206
207 Optional TypeDatabase::getNext(TypeIndex Prev) {
208 int N = ValidRecords.find_next(Prev.toArrayIndex());
209 if (N == -1)
210 return None;
211 return TypeIndex::fromArrayIndex(N);
212 }
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) {
244241 W->printNumber("NumStrings", Size);
245242 ListScope Arguments(*W, "Strings");
246243 for (uint32_t I = 0; I < Size; ++I) {
247 printTypeIndex("String", Indices[I]);
244 printItemIndex("String", Indices[I]);
248245 }
249246 return Error::success();
250247 }
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 Optional TypeTableCollection::getFirst() {
31 if (empty())
32 return None;
33 return TypeIndex::fromArrayIndex(0);
34 }
35
36 Optional TypeTableCollection::getNext(TypeIndex Prev) {
37 ++Prev;
38 assert(Prev.toArrayIndex() <= size());
39 if (Prev.toArrayIndex() == size())
40 return None;
41 return Prev;
42 }
43
44 void TypeTableCollection::ensureTypeExists(TypeIndex Index) {
45 assert(hasCapacityFor(Index));
46
47 if (Database.contains(Index))
48 return;
49
50 BinaryByteStream Bytes(Records[Index.toArrayIndex()], support::little);
51
52 CVType Type;
53 uint32_t Len;
54 error(VarStreamArrayExtractor::extract(Bytes, Len, Type));
55
56 TypeDatabaseVisitor DBV(Database);
57 error(codeview::visitTypeRecord(Type, Index, DBV));
58 assert(Database.contains(Index));
59 }
60
61 CVType TypeTableCollection::getType(TypeIndex Index) {
62 ensureTypeExists(Index);
63 return Database.getTypeRecord(Index);
64 }
65
66 StringRef TypeTableCollection::getTypeName(TypeIndex Index) {
67 if (!Index.isSimple())
68 ensureTypeExists(Index);
69 return Database.getTypeName(Index);
70 }
71
72 bool TypeTableCollection::contains(TypeIndex Index) {
73 return Database.contains(Index);
74 }
75
76 uint32_t TypeTableCollection::size() { return Records.size(); }
77
78 uint32_t TypeTableCollection::capacity() { return Records.size(); }
79
80 bool TypeTableCollection::hasCapacityFor(TypeIndex Index) const {
81 return Index.toArrayIndex() < Records.size();
82 }
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"
325325 ; EMPTY-NEXT: TypeLeafKind: LF_SUBSTR_LIST (0x1604)
326326 ; EMPTY-NEXT: NumStrings: 1
327327 ; EMPTY-NEXT: Strings [
328 ; EMPTY-NEXT: String: __vc_attributes::threadingAttribute (0x100B)
328 ; EMPTY-NEXT: String: -Zi -MT -I"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\INCLUDE" -I"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\ATLMFC\INCLUDE" -I"C:\Program Files (x86)\Windows Kits\8.1\include\shared" -I"C:\Program Files (x86)\Windows
329329 ; EMPTY-NEXT: ]
330330 ; EMPTY-NEXT: }
331331 ; EMPTY-NEXT: Bytes (
12521252 ; ALL: TypeLeafKind: LF_SUBSTR_LIST (0x1604)
12531253 ; ALL: NumStrings: 1
12541254 ; ALL: Strings [
1255 ; ALL: String: __vc_attributes::threadingAttribute (0x100B)
1255 ; ALL: String: -Zi -MT -I"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\INCLUDE" -I"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\ATLMFC\INCLUDE" -I"C:\Program Files (x86)\Windows Kits\8.1\include\shared" -I"C:\Program Files (x86)\Windows (0x100B)
12561256 ; ALL: ]
12571257 ; ALL: }
12581258 ; ALL: }
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 while (I) {
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 I = Types.getNext(*I);
671 }
679672
680673 if (DumpTpiHash) {
681674 DictScope DD(P, "Hash");
710703 return Error::success();
711704 }
712705
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
706 Expected
707 LLVMOutputStyle::initializeTypeDatabase(uint32_t SN) {
708 auto &TypeCollection = (SN == StreamTPI) ? TpiTypes : IpiTypes;
721709 auto Tpi =
722710 (SN == StreamTPI) ? File.getPDBTpiStream() : File.getPDBIpiStream();
723
724711 if (!Tpi)
725712 return Tpi.takeError();
726713
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);
714 if (!TypeCollection) {
715 // Initialize the type collection, even if we're not going to dump it. This
716 // way if some other part of the dumper decides it wants to use some or all
717 // of the records for whatever purposes, it can still access them lazily.
718 auto &Types = Tpi->typeArray();
719 uint32_t Count = Tpi->getNumTypeRecords();
720 auto Offsets = Tpi->getTypeIndexOffsets();
721 TypeCollection =
722 llvm::make_unique(Types, Count, Offsets);
723 }
724
725 return *TypeCollection;
742726 }
743727
744728 Error LLVMOutputStyle::dumpDbiStream() {
813797 return EC;
814798
815799 if (ShouldDumpSymbols) {
816 if (auto EC = buildTypeDatabase(StreamTPI))
817 return EC;
800 auto ExpectedTypes = initializeTypeDatabase(StreamTPI);
801 if (!ExpectedTypes)
802 return ExpectedTypes.takeError();
803 auto &Types = *ExpectedTypes;
818804
819805 ListScope SS(P, "Symbols");
820 codeview::CVSymbolDumper SD(P, *TypeDB, nullptr, false);
806 codeview::CVSymbolDumper SD(P, Types, nullptr, false);
821807 bool HadError = false;
822808 for (auto S : ModS.symbols(&HadError)) {
823809 DictScope LL(P, "");
838824 }
839825 if (opts::raw::DumpLineInfo) {
840826 ListScope SS(P, "LineInfo");
841 if (auto EC = buildTypeDatabase(StreamIPI))
842 return EC;
843
844 C13RawVisitor V(P, File, *ItemDB);
827 auto ExpectedTypes = initializeTypeDatabase(StreamIPI);
828 if (!ExpectedTypes)
829 return ExpectedTypes.takeError();
830 auto &IpiItems = *ExpectedTypes;
831 C13RawVisitor V(P, File, IpiItems);
845832 if (auto EC = codeview::visitModuleDebugFragments(
846833 ModS.linesAndChecksums(), V))
847834 return EC;
959946 P.printList("Section Offsets", Publics->getSectionOffsets(),
960947 printSectionOffset);
961948 ListScope L(P, "Symbols");
962 if (auto EC = buildTypeDatabase(StreamTPI))
963 return EC;
964
965 codeview::CVSymbolDumper SD(P, *TypeDB, nullptr, false);
949 auto ExpectedTypes = initializeTypeDatabase(StreamTPI);
950 if (!ExpectedTypes)
951 return ExpectedTypes.takeError();
952 auto &Tpi = *ExpectedTypes;
953
954 codeview::CVSymbolDumper SD(P, Tpi, nullptr, false);
966955 bool HadError = false;
967956 for (auto S : Publics->getSymbols(&HadError)) {
968957 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"
3030 #include "llvm/ADT/STLExtras.h"
3131 #include "llvm/ADT/StringExtras.h"
3232 #include "llvm/Config/config.h"
33 #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
3334 #include "llvm/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.h"
3435 #include "llvm/DebugInfo/CodeView/ModuleDebugInlineeLinesFragment.h"
3536 #include "llvm/DebugInfo/CodeView/ModuleDebugLineFragment.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"
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())) {
10931095 if (Magic != COFF::DEBUG_SECTION_MAGIC)
10941096 return error(object_error::parse_failed);
10951097
1096 CVTypeDumper CVTD(TypeDB);
1097 TypeDumpVisitor TDV(TypeDB, &W, opts::CodeViewSubsectionBytes);
1098 if (auto EC = CVTD.dump({Data.bytes_begin(), Data.bytes_end()}, TDV)) {
1099 W.flush();
1100 error(llvm::errorToErrorCode(std::move(EC)));
1101 }
1098 Types.reset(Data);
1099
1100 TypeDumpVisitor TDV(Types, &W, opts::CodeViewSubsectionBytes);
1101 error(codeview::visitTypeStream(Types, TDV));
1102 W.flush();
11021103 }
11031104
11041105 void COFFDumper::printSections() {
16381639 TypeBuf.append(Record.begin(), Record.end());
16391640 });
16401641
1641 TypeDatabase TypeDB(CVTypes.records().size());
1642 TypeTableCollection TpiTypes(CVTypes.records());
16421643 {
16431644 ListScope S(Writer, "MergedTypeStream");
1644 CVTypeDumper CVTD(TypeDB);
1645 TypeDumpVisitor TDV(TypeDB, &Writer, opts::CodeViewSubsectionBytes);
1646 if (auto EC = CVTD.dump(
1647 {TypeBuf.str().bytes_begin(), TypeBuf.str().bytes_end()}, TDV)) {
1648 Writer.flush();
1649 error(std::move(EC));
1650 }
1645 TypeDumpVisitor TDV(TpiTypes, &Writer, opts::CodeViewSubsectionBytes);
1646 error(codeview::visitTypeStream(TpiTypes, TDV));
1647 Writer.flush();
16511648 }
16521649
16531650 // Flatten the id stream and print it next. The ID stream refers to names from
16541651 // the type stream.
1655 SmallString<0> IDBuf;
1656 IDTable.ForEachRecord([&](TypeIndex TI, ArrayRef Record) {
1657 IDBuf.append(Record.begin(), Record.end());
1658 });
1659
1652 TypeTableCollection IpiTypes(IDTable.records());
16601653 {
16611654 ListScope S(Writer, "MergedIDStream");
1662 TypeDatabase IDDB(IDTable.records().size());
1663 CVTypeDumper CVTD(IDDB);
1664 TypeDumpVisitor TDV(TypeDB, &Writer, opts::CodeViewSubsectionBytes);
1665 TDV.setItemDB(IDDB);
1666 if (auto EC = CVTD.dump(
1667 {IDBuf.str().bytes_begin(), IDBuf.str().bytes_end()}, TDV)) {
1668 Writer.flush();
1669 error(std::move(EC));
1670 }
1671 }
1672 }
1655 TypeDumpVisitor TDV(TpiTypes, &Writer, opts::CodeViewSubsectionBytes);
1656 TDV.setIpiTypes(IpiTypes);
1657 error(codeview::visitTypeStream(IpiTypes, TDV));
1658 Writer.flush();
1659 }
1660 }
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());