1 //===- TypeReferenceTracker.cpp ------------------------------- *- C++ --*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "TypeReferenceTracker.h"
11 #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
12 #include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
13 #include "llvm/DebugInfo/PDB/Native/NativeSession.h"
14 #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
15 #include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
16 #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
17 #include "llvm/Object/COFF.h"
20 using namespace llvm::pdb
;
21 using namespace llvm::codeview
;
23 // LazyRandomTypeCollection doesn't appear to expose the number of records, so
24 // just iterate up front to find out.
25 static uint32_t getNumRecordsInCollection(LazyRandomTypeCollection
&Types
) {
26 uint32_t NumTypes
= 0;
27 for (std::optional
<TypeIndex
> TI
= Types
.getFirst(); TI
;
28 TI
= Types
.getNext(*TI
))
33 TypeReferenceTracker::TypeReferenceTracker(InputFile
&File
)
34 : File(File
), Types(File
.types()),
35 Ids(File
.isPdb() ? &File
.ids() : nullptr) {
36 NumTypeRecords
= getNumRecordsInCollection(Types
);
37 TypeReferenced
.resize(NumTypeRecords
, false);
39 // If this is a PDB, ids are stored separately, so make a separate bit vector.
41 NumIdRecords
= getNumRecordsInCollection(*Ids
);
42 IdReferenced
.resize(NumIdRecords
, false);
45 // Get the TpiStream pointer for forward decl resolution if this is a pdb.
46 // Build the hash map to enable resolving forward decls.
48 Tpi
= &cantFail(File
.pdb().getPDBTpiStream());
53 void TypeReferenceTracker::mark() {
57 // - LF_UDT_MOD_SRC_LINE? VC always links these in.
58 for (const SymbolGroup
&SG
: File
.symbol_groups()) {
60 for (const auto &SS
: SG
.getDebugSubsections()) {
61 // FIXME: Are there other type-referencing subsections? Inlinees?
63 if (SS
.kind() != DebugSubsectionKind::Symbols
)
66 CVSymbolArray Symbols
;
67 BinaryStreamReader
Reader(SS
.getRecordData());
68 cantFail(Reader
.readArray(Symbols
, Reader
.getLength()));
69 for (const CVSymbol
&S
: Symbols
)
70 addTypeRefsFromSymbol(S
);
72 } else if (SG
.hasDebugStream()) {
73 for (const CVSymbol
&S
: SG
.getPdbModuleStream().getSymbolArray())
74 addTypeRefsFromSymbol(S
);
78 // Walk globals and mark types referenced from globals.
79 if (File
.isPdb() && File
.pdb().hasPDBGlobalsStream()) {
80 SymbolStream
&SymStream
= cantFail(File
.pdb().getPDBSymbolStream());
81 GlobalsStream
&GS
= cantFail(File
.pdb().getPDBGlobalsStream());
82 for (uint32_t PubSymOff
: GS
.getGlobalsTable()) {
83 CVSymbol Sym
= SymStream
.readRecord(PubSymOff
);
84 addTypeRefsFromSymbol(Sym
);
88 // FIXME: Should we walk Ids?
91 void TypeReferenceTracker::addOneTypeRef(TiRefKind RefKind
, TypeIndex RefTI
) {
92 // If it's simple or already seen, no need to add to work list.
93 BitVector
&TypeOrIdReferenced
=
94 (Ids
&& RefKind
== TiRefKind::IndexRef
) ? IdReferenced
: TypeReferenced
;
95 if (RefTI
.isSimple() || TypeOrIdReferenced
.test(RefTI
.toArrayIndex()))
98 // Otherwise, mark it seen and add it to the work list.
99 TypeOrIdReferenced
.set(RefTI
.toArrayIndex());
100 RefWorklist
.push_back({RefKind
, RefTI
});
103 void TypeReferenceTracker::addTypeRefsFromSymbol(const CVSymbol
&Sym
) {
104 SmallVector
<TiReference
, 4> DepList
;
105 // FIXME: Check for failure.
106 discoverTypeIndicesInSymbol(Sym
, DepList
);
107 addReferencedTypes(Sym
.content(), DepList
);
108 markReferencedTypes();
111 void TypeReferenceTracker::addReferencedTypes(ArrayRef
<uint8_t> RecData
,
112 ArrayRef
<TiReference
> DepList
) {
113 for (const auto &Ref
: DepList
) {
114 // FIXME: Report OOB slice instead of truncating.
115 ArrayRef
<uint8_t> ByteSlice
=
116 RecData
.drop_front(Ref
.Offset
).take_front(4 * Ref
.Count
);
117 ArrayRef
<TypeIndex
> TIs(
118 reinterpret_cast<const TypeIndex
*>(ByteSlice
.data()),
119 ByteSlice
.size() / 4);
121 // If this is a PDB and this is an item reference, track it in the IPI
122 // bitvector. Otherwise, it's a type ref, or there is only one stream.
123 for (TypeIndex RefTI
: TIs
)
124 addOneTypeRef(Ref
.Kind
, RefTI
);
128 void TypeReferenceTracker::markReferencedTypes() {
129 while (!RefWorklist
.empty()) {
132 std::tie(RefKind
, RefTI
) = RefWorklist
.pop_back_val();
133 std::optional
<CVType
> Rec
= (Ids
&& RefKind
== TiRefKind::IndexRef
)
134 ? Ids
->tryGetType(RefTI
)
135 : Types
.tryGetType(RefTI
);
137 continue; // FIXME: Report a reference to a non-existant type.
139 SmallVector
<TiReference
, 4> DepList
;
140 // FIXME: Check for failure.
141 discoverTypeIndices(*Rec
, DepList
);
142 addReferencedTypes(Rec
->content(), DepList
);
144 // If this is a tag kind and this is a PDB input, mark the complete type as
146 // FIXME: This limitation makes this feature somewhat useless on object file
149 switch (Rec
->kind()) {
157 addOneTypeRef(TiRefKind::TypeRef
,
158 cantFail(Tpi
->findFullDeclForForwardRef(RefTI
)));