1cda7ff9dSReid Kleckner //===- TypeReferenceTracker.cpp ------------------------------- *- C++ --*-===//
2cda7ff9dSReid Kleckner //
3cda7ff9dSReid Kleckner // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4cda7ff9dSReid Kleckner // See https://llvm.org/LICENSE.txt for license information.
5cda7ff9dSReid Kleckner // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6cda7ff9dSReid Kleckner //
7cda7ff9dSReid Kleckner //===----------------------------------------------------------------------===//
8cda7ff9dSReid Kleckner
9cda7ff9dSReid Kleckner #include "TypeReferenceTracker.h"
10cda7ff9dSReid Kleckner
11cda7ff9dSReid Kleckner #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
12cda7ff9dSReid Kleckner #include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
1375112133SCarlos Alberto Enciso #include "llvm/DebugInfo/PDB/Native/NativeSession.h"
1475112133SCarlos Alberto Enciso #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
15cda7ff9dSReid Kleckner #include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
1675112133SCarlos Alberto Enciso #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
1775112133SCarlos Alberto Enciso #include "llvm/Object/COFF.h"
18cda7ff9dSReid Kleckner
19cda7ff9dSReid Kleckner using namespace llvm;
20cda7ff9dSReid Kleckner using namespace llvm::pdb;
21cda7ff9dSReid Kleckner using namespace llvm::codeview;
22cda7ff9dSReid Kleckner
23cda7ff9dSReid Kleckner // LazyRandomTypeCollection doesn't appear to expose the number of records, so
24cda7ff9dSReid Kleckner // just iterate up front to find out.
getNumRecordsInCollection(LazyRandomTypeCollection & Types)25cda7ff9dSReid Kleckner static uint32_t getNumRecordsInCollection(LazyRandomTypeCollection &Types) {
26cda7ff9dSReid Kleckner uint32_t NumTypes = 0;
2789fab98eSFangrui Song for (std::optional<TypeIndex> TI = Types.getFirst(); TI;
2889fab98eSFangrui Song TI = Types.getNext(*TI))
29cda7ff9dSReid Kleckner ++NumTypes;
30cda7ff9dSReid Kleckner return NumTypes;
31cda7ff9dSReid Kleckner }
32cda7ff9dSReid Kleckner
TypeReferenceTracker(InputFile & File)33cda7ff9dSReid Kleckner TypeReferenceTracker::TypeReferenceTracker(InputFile &File)
34cda7ff9dSReid Kleckner : File(File), Types(File.types()),
35cda7ff9dSReid Kleckner Ids(File.isPdb() ? &File.ids() : nullptr) {
36cda7ff9dSReid Kleckner NumTypeRecords = getNumRecordsInCollection(Types);
37cda7ff9dSReid Kleckner TypeReferenced.resize(NumTypeRecords, false);
38cda7ff9dSReid Kleckner
39cda7ff9dSReid Kleckner // If this is a PDB, ids are stored separately, so make a separate bit vector.
40cda7ff9dSReid Kleckner if (Ids) {
41cda7ff9dSReid Kleckner NumIdRecords = getNumRecordsInCollection(*Ids);
42cda7ff9dSReid Kleckner IdReferenced.resize(NumIdRecords, false);
43cda7ff9dSReid Kleckner }
44cda7ff9dSReid Kleckner
45cda7ff9dSReid Kleckner // Get the TpiStream pointer for forward decl resolution if this is a pdb.
46cda7ff9dSReid Kleckner // Build the hash map to enable resolving forward decls.
47cda7ff9dSReid Kleckner if (File.isPdb()) {
48cda7ff9dSReid Kleckner Tpi = &cantFail(File.pdb().getPDBTpiStream());
49cda7ff9dSReid Kleckner Tpi->buildHashMap();
50cda7ff9dSReid Kleckner }
51cda7ff9dSReid Kleckner }
52cda7ff9dSReid Kleckner
mark()53cda7ff9dSReid Kleckner void TypeReferenceTracker::mark() {
54cda7ff9dSReid Kleckner // Walk type roots:
55cda7ff9dSReid Kleckner // - globals
56cda7ff9dSReid Kleckner // - modi symbols
57cda7ff9dSReid Kleckner // - LF_UDT_MOD_SRC_LINE? VC always links these in.
58*d87f9e28SFangrui Song for (const SymbolGroup &SG : File.symbol_groups()) {
59cda7ff9dSReid Kleckner if (File.isObj()) {
60cda7ff9dSReid Kleckner for (const auto &SS : SG.getDebugSubsections()) {
61cda7ff9dSReid Kleckner // FIXME: Are there other type-referencing subsections? Inlinees?
62cda7ff9dSReid Kleckner // Probably for IDs.
63cda7ff9dSReid Kleckner if (SS.kind() != DebugSubsectionKind::Symbols)
64cda7ff9dSReid Kleckner continue;
65cda7ff9dSReid Kleckner
66cda7ff9dSReid Kleckner CVSymbolArray Symbols;
67cda7ff9dSReid Kleckner BinaryStreamReader Reader(SS.getRecordData());
68cda7ff9dSReid Kleckner cantFail(Reader.readArray(Symbols, Reader.getLength()));
69cda7ff9dSReid Kleckner for (const CVSymbol &S : Symbols)
70cda7ff9dSReid Kleckner addTypeRefsFromSymbol(S);
71cda7ff9dSReid Kleckner }
72cda7ff9dSReid Kleckner } else if (SG.hasDebugStream()) {
73cda7ff9dSReid Kleckner for (const CVSymbol &S : SG.getPdbModuleStream().getSymbolArray())
74cda7ff9dSReid Kleckner addTypeRefsFromSymbol(S);
75cda7ff9dSReid Kleckner }
76cda7ff9dSReid Kleckner }
77cda7ff9dSReid Kleckner
78cda7ff9dSReid Kleckner // Walk globals and mark types referenced from globals.
79cda7ff9dSReid Kleckner if (File.isPdb() && File.pdb().hasPDBGlobalsStream()) {
80cda7ff9dSReid Kleckner SymbolStream &SymStream = cantFail(File.pdb().getPDBSymbolStream());
81cda7ff9dSReid Kleckner GlobalsStream &GS = cantFail(File.pdb().getPDBGlobalsStream());
82cda7ff9dSReid Kleckner for (uint32_t PubSymOff : GS.getGlobalsTable()) {
83cda7ff9dSReid Kleckner CVSymbol Sym = SymStream.readRecord(PubSymOff);
84cda7ff9dSReid Kleckner addTypeRefsFromSymbol(Sym);
85cda7ff9dSReid Kleckner }
86cda7ff9dSReid Kleckner }
87cda7ff9dSReid Kleckner
88cda7ff9dSReid Kleckner // FIXME: Should we walk Ids?
89cda7ff9dSReid Kleckner }
90cda7ff9dSReid Kleckner
addOneTypeRef(TiRefKind RefKind,TypeIndex RefTI)91cda7ff9dSReid Kleckner void TypeReferenceTracker::addOneTypeRef(TiRefKind RefKind, TypeIndex RefTI) {
92cda7ff9dSReid Kleckner // If it's simple or already seen, no need to add to work list.
93cda7ff9dSReid Kleckner BitVector &TypeOrIdReferenced =
94cda7ff9dSReid Kleckner (Ids && RefKind == TiRefKind::IndexRef) ? IdReferenced : TypeReferenced;
95cda7ff9dSReid Kleckner if (RefTI.isSimple() || TypeOrIdReferenced.test(RefTI.toArrayIndex()))
96cda7ff9dSReid Kleckner return;
97cda7ff9dSReid Kleckner
98cda7ff9dSReid Kleckner // Otherwise, mark it seen and add it to the work list.
99cda7ff9dSReid Kleckner TypeOrIdReferenced.set(RefTI.toArrayIndex());
100cda7ff9dSReid Kleckner RefWorklist.push_back({RefKind, RefTI});
101cda7ff9dSReid Kleckner }
102cda7ff9dSReid Kleckner
addTypeRefsFromSymbol(const CVSymbol & Sym)103cda7ff9dSReid Kleckner void TypeReferenceTracker::addTypeRefsFromSymbol(const CVSymbol &Sym) {
104cda7ff9dSReid Kleckner SmallVector<TiReference, 4> DepList;
105cda7ff9dSReid Kleckner // FIXME: Check for failure.
106cda7ff9dSReid Kleckner discoverTypeIndicesInSymbol(Sym, DepList);
107cda7ff9dSReid Kleckner addReferencedTypes(Sym.content(), DepList);
108cda7ff9dSReid Kleckner markReferencedTypes();
109cda7ff9dSReid Kleckner }
110cda7ff9dSReid Kleckner
addReferencedTypes(ArrayRef<uint8_t> RecData,ArrayRef<TiReference> DepList)111cda7ff9dSReid Kleckner void TypeReferenceTracker::addReferencedTypes(ArrayRef<uint8_t> RecData,
112cda7ff9dSReid Kleckner ArrayRef<TiReference> DepList) {
113cda7ff9dSReid Kleckner for (const auto &Ref : DepList) {
114cda7ff9dSReid Kleckner // FIXME: Report OOB slice instead of truncating.
115cda7ff9dSReid Kleckner ArrayRef<uint8_t> ByteSlice =
116cda7ff9dSReid Kleckner RecData.drop_front(Ref.Offset).take_front(4 * Ref.Count);
117cda7ff9dSReid Kleckner ArrayRef<TypeIndex> TIs(
118cda7ff9dSReid Kleckner reinterpret_cast<const TypeIndex *>(ByteSlice.data()),
119cda7ff9dSReid Kleckner ByteSlice.size() / 4);
120cda7ff9dSReid Kleckner
121cda7ff9dSReid Kleckner // If this is a PDB and this is an item reference, track it in the IPI
122cda7ff9dSReid Kleckner // bitvector. Otherwise, it's a type ref, or there is only one stream.
123cda7ff9dSReid Kleckner for (TypeIndex RefTI : TIs)
124cda7ff9dSReid Kleckner addOneTypeRef(Ref.Kind, RefTI);
125cda7ff9dSReid Kleckner }
126cda7ff9dSReid Kleckner }
127cda7ff9dSReid Kleckner
markReferencedTypes()128cda7ff9dSReid Kleckner void TypeReferenceTracker::markReferencedTypes() {
129cda7ff9dSReid Kleckner while (!RefWorklist.empty()) {
130cda7ff9dSReid Kleckner TiRefKind RefKind;
131cda7ff9dSReid Kleckner TypeIndex RefTI;
132cda7ff9dSReid Kleckner std::tie(RefKind, RefTI) = RefWorklist.pop_back_val();
13389fab98eSFangrui Song std::optional<CVType> Rec = (Ids && RefKind == TiRefKind::IndexRef)
134cda7ff9dSReid Kleckner ? Ids->tryGetType(RefTI)
135cda7ff9dSReid Kleckner : Types.tryGetType(RefTI);
136cda7ff9dSReid Kleckner if (!Rec)
137cda7ff9dSReid Kleckner continue; // FIXME: Report a reference to a non-existant type.
138cda7ff9dSReid Kleckner
139cda7ff9dSReid Kleckner SmallVector<TiReference, 4> DepList;
140cda7ff9dSReid Kleckner // FIXME: Check for failure.
141cda7ff9dSReid Kleckner discoverTypeIndices(*Rec, DepList);
142cda7ff9dSReid Kleckner addReferencedTypes(Rec->content(), DepList);
143cda7ff9dSReid Kleckner
144cda7ff9dSReid Kleckner // If this is a tag kind and this is a PDB input, mark the complete type as
145cda7ff9dSReid Kleckner // referenced.
146cda7ff9dSReid Kleckner // FIXME: This limitation makes this feature somewhat useless on object file
147cda7ff9dSReid Kleckner // inputs.
148cda7ff9dSReid Kleckner if (Tpi) {
149cda7ff9dSReid Kleckner switch (Rec->kind()) {
150cda7ff9dSReid Kleckner default:
151cda7ff9dSReid Kleckner break;
152cda7ff9dSReid Kleckner case LF_CLASS:
153cda7ff9dSReid Kleckner case LF_INTERFACE:
154cda7ff9dSReid Kleckner case LF_STRUCTURE:
155cda7ff9dSReid Kleckner case LF_UNION:
156cda7ff9dSReid Kleckner case LF_ENUM:
157cda7ff9dSReid Kleckner addOneTypeRef(TiRefKind::TypeRef,
158cda7ff9dSReid Kleckner cantFail(Tpi->findFullDeclForForwardRef(RefTI)));
159cda7ff9dSReid Kleckner break;
160cda7ff9dSReid Kleckner }
161cda7ff9dSReid Kleckner }
162cda7ff9dSReid Kleckner }
163cda7ff9dSReid Kleckner }
164