llvm.org GIT mirror llvm / b17277e
[PDB] Add the ability to map forward references to full decls. Some records point to an LF_CLASS, LF_UNION, LF_STRUCTURE, or LF_ENUM which is a forward reference and doesn't contain complete debug information. In these cases, we'd like to be able to quickly locate the full record. The TPI stream stores an array of pre-computed record hash values, one for each type record. If we pre-process this on startup, we can build a mapping from hash value -> {list of possible matching type indices}. Since hashes of full records are only based on the name and or unique name and not the full record contents, we can then use forward ref record to compute the hash of what *would* be the full record by just hashing the name, use this to get the list of possible matches, and iterate those looking for a match on name or unique name. llvm-pdbutil is updated to resolve forward references for the purposes of testing (plus it's just useful). Differential Revision: https://reviews.llvm.org/D52283 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@342656 91177308-0d34-0410-b5e6-96231b3b80d8 Zachary Turner 1 year, 2 days ago
15 changed file(s) with 416 addition(s) and 17 deletion(s). Raw diff Collapse all Expand all
342342 char Reserved[8];
343343 };
344344
345 constexpr int I = sizeof(SrcHeaderBlockEntry);
346345 static_assert(sizeof(SrcHeaderBlockEntry) == 40, "Incorrect struct size!");
347346
348347 } // namespace pdb
1717
1818 Expected hashTypeRecord(const llvm::codeview::CVType &Type);
1919
20 struct TagRecordHash {
21 explicit TagRecordHash(codeview::ClassRecord CR, uint32_t Full,
22 uint32_t Forward)
23 : Class(std::move(CR)), FullRecordHash(Full), ForwardDeclHash(Forward) {
24 State = 0;
25 }
26
27 explicit TagRecordHash(codeview::EnumRecord ER, uint32_t Full,
28 uint32_t Forward)
29 : Enum(std::move(ER)), FullRecordHash(Full), ForwardDeclHash(Forward) {
30 State = 1;
31 }
32
33 explicit TagRecordHash(codeview::UnionRecord UR, uint32_t Full,
34 uint32_t Forward)
35 : Union(std::move(UR)), FullRecordHash(Full), ForwardDeclHash(Forward) {
36 State = 2;
37 }
38
39 uint32_t FullRecordHash;
40 uint32_t ForwardDeclHash;
41
42 codeview::TagRecord &getRecord() {
43 switch (State) {
44 case 0:
45 return Class;
46 case 1:
47 return Enum;
48 case 2:
49 return Union;
50 }
51 llvm_unreachable("unreachable!");
52 }
53
54 private:
55 union {
56 codeview::ClassRecord Class;
57 codeview::EnumRecord Enum;
58 codeview::UnionRecord Union;
59 };
60
61 uint8_t State = 0;
62 };
63
64 /// Given a CVType referring to a class, structure, union, or enum, compute
65 /// the hash of its forward decl and full decl.
66 Expected hashTagRecord(const codeview::CVType &Type);
67
2068 } // end namespace pdb
2169 } // end namespace llvm
2270
5757
5858 codeview::LazyRandomTypeCollection &typeCollection() { return *Types; }
5959
60 Expected
61 findFullDeclForForwardRef(codeview::TypeIndex ForwardRefTI) const;
62
6063 BinarySubstreamRef getTypeRecordsSubstream() const;
6164
6265 Error commit();
66
67 void buildHashMap();
68
69 bool supportsTypeLookup() const;
6370
6471 private:
6572 PDBFile &Pdb;
7683 FixedStreamArray TypeIndexOffsets;
7784 HashTable HashAdjusters;
7885
86 std::vector> HashMap;
87
7988 const TpiStreamHeader *Header;
8089 };
8190 }
4949 }
5050
5151 template
52 static Expected getTagRecordHashForUdt(const CVType &Rec) {
53 T Deserialized;
54 if (auto E = TypeDeserializer::deserializeAs(const_cast(Rec),
55 Deserialized))
56 return std::move(E);
57
58 ClassOptions Opts = Deserialized.getOptions();
59
60 bool ForwardRef = bool(Opts & ClassOptions::ForwardReference);
61
62 uint32_t ThisRecordHash = getHashForUdt(Deserialized, Rec.data());
63
64 // If we don't have a forward ref we can't compute the hash of it from the
65 // full record because it requires hashing the entire buffer.
66 if (!ForwardRef)
67 return TagRecordHash{std::move(Deserialized), ThisRecordHash, 0};
68
69 bool Scoped = bool(Opts & ClassOptions::Scoped);
70
71 StringRef NameToHash =
72 Scoped ? Deserialized.getUniqueName() : Deserialized.getName();
73 uint32_t FullHash = hashStringV1(NameToHash);
74 return TagRecordHash{std::move(Deserialized), FullHash, ThisRecordHash};
75 }
76
77 template
5278 static Expected getSourceLineHash(const CVType &Rec) {
5379 T Deserialized;
5480 if (auto E = TypeDeserializer::deserializeAs(const_cast(Rec),
5783 char Buf[4];
5884 support::endian::write32le(Buf, Deserialized.getUDT().getIndex());
5985 return hashStringV1(StringRef(Buf, 4));
86 }
87
88 Expected llvm::pdb::hashTagRecord(const codeview::CVType &Type) {
89 switch (Type.kind()) {
90 case LF_CLASS:
91 case LF_STRUCTURE:
92 case LF_INTERFACE:
93 return getTagRecordHashForUdt(Type);
94 case LF_UNION:
95 return getTagRecordHashForUdt(Type);
96 case LF_ENUM:
97 return getTagRecordHashForUdt(Type);
98 default:
99 assert(false && "Type is not a tag record!");
100 }
101 return make_error("Invalid record type",
102 inconvertibleErrorCode());
60103 }
61104
62105 Expected llvm::pdb::hashTypeRecord(const CVType &Rec) {
1010
1111 #include "llvm/ADT/iterator_range.h"
1212 #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
13 #include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
14 #include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"
1315 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
1416 #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
17 #include "llvm/DebugInfo/PDB/Native/Hash.h"
1518 #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
1619 #include "llvm/DebugInfo/PDB/Native/RawConstants.h"
1720 #include "llvm/DebugInfo/PDB/Native/RawError.h"
139142 uint32_t TpiStream::getNumHashBuckets() const { return Header->NumHashBuckets; }
140143 uint32_t TpiStream::getHashKeySize() const { return Header->HashKeySize; }
141144
145 void TpiStream::buildHashMap() {
146 if (!HashMap.empty())
147 return;
148 if (HashValues.empty())
149 return;
150
151 HashMap.resize(Header->NumHashBuckets);
152
153 TypeIndex TIB{Header->TypeIndexBegin};
154 TypeIndex TIE{Header->TypeIndexEnd};
155 while (TIB < TIE) {
156 uint32_t HV = HashValues[TIB.toArrayIndex()];
157 HashMap[HV].push_back(TIB++);
158 }
159 }
160
161 bool TpiStream::supportsTypeLookup() const { return !HashMap.empty(); }
162
163 template static ClassOptions getUdtOptions(CVType CVT) {
164 RecordT Record;
165 if (auto EC = TypeDeserializer::deserializeAs(CVT, Record)) {
166 consumeError(std::move(EC));
167 return ClassOptions::None;
168 }
169 return Record.getOptions();
170 }
171
172 static bool isUdtForwardRef(CVType CVT) {
173 ClassOptions UdtOptions = ClassOptions::None;
174 switch (CVT.kind()) {
175 case LF_STRUCTURE:
176 case LF_CLASS:
177 case LF_INTERFACE:
178 UdtOptions = getUdtOptions(std::move(CVT));
179 break;
180 case LF_ENUM:
181 UdtOptions = getUdtOptions(std::move(CVT));
182 break;
183 case LF_UNION:
184 UdtOptions = getUdtOptions(std::move(CVT));
185 break;
186 default:
187 return false;
188 }
189 return (UdtOptions & ClassOptions::ForwardReference) != ClassOptions::None;
190 }
191
192 Expected
193 TpiStream::findFullDeclForForwardRef(TypeIndex ForwardRefTI) const {
194 CVType F = Types->getType(ForwardRefTI);
195 if (!isUdtForwardRef(F))
196 return ForwardRefTI;
197
198 Expected ForwardTRH = hashTagRecord(F);
199 if (!ForwardTRH)
200 return ForwardTRH.takeError();
201
202 TagRecordHash Copy = std::move(*ForwardTRH);
203 uint32_t BucketIdx = ForwardTRH->FullRecordHash % Header->NumHashBuckets;
204
205 for (TypeIndex TI : HashMap[BucketIdx]) {
206 CVType CVT = Types->getType(TI);
207 if (CVT.kind() != F.kind())
208 continue;
209
210 Expected FullTRH = hashTagRecord(CVT);
211 if (!FullTRH)
212 return FullTRH.takeError();
213 if (ForwardTRH->FullRecordHash != FullTRH->FullRecordHash)
214 continue;
215 TagRecord &ForwardTR = ForwardTRH->getRecord();
216 TagRecord &FullTR = FullTRH->getRecord();
217
218 if (!ForwardTR.hasUniqueName()) {
219 if (ForwardTR.getName() == FullTR.getName())
220 return TI;
221 continue;
222 }
223
224 if (!FullTR.hasUniqueName())
225 continue;
226 if (ForwardTR.getUniqueName() == FullTR.getUniqueName())
227 return TI;
228 }
229 return ForwardRefTI;
230 }
231
142232 BinarySubstreamRef TpiStream::getTypeRecordsSubstream() const {
143233 return TypeRecordsSubstream;
144234 }
0 // Build with "cl.exe /Z7 /GR- /GS- /GX- every-class.cpp /link /debug:full /nodefaultlib /incremental:no /entry:main"
1
2 #include
3
4 // clang-format off
5 void *__purecall = 0;
6
7 void __cdecl operator delete(void *, unsigned int) {}
8 void __cdecl operator delete(void *, unsigned __int64) {}
9
10 struct Nothing {};
11 struct Constructor { Constructor() {} };
12 struct Assignment {
13 Assignment &operator=(Assignment Other) { return *this; }
14 };
15 struct Cast {
16 operator int() { return 42; }
17 };
18
19 struct Nested {
20 struct F {};
21 };
22 struct Operator {
23 int operator+(int X) { return 42; }
24 };
25
26 class Class {};
27
28 union Union {};
29
30 enum class Enum {A};
31
32
33 template void f(T t) {}
34
35 int main(int argc, char **argv) {
36 struct Scoped {};
37
38 struct { } Anonymous;
39
40 f(Nothing{});
41 f(Constructor{});
42 f(Assignment{});
43 f(Cast{});
44 f(Nested{});
45 f(Operator{});
46 f(Nested::F{});
47 f(Scoped{});
48 f(Class{});
49 f(Union{});
50 f(Anonymous);
51 f(Enum::A);
52
53
54 f(Nothing{});
55 f(Nothing{});
56 f(Nothing{});
57 f<__unaligned Nothing>(Nothing{});
58
59 return 0;
60 }
88
99
1010 RUN: llvm-pdbutil dump -type-index=0x101A,0x102C,0x103D,0x104D,0x1098,0x10AA,0x10AC \
11 RUN: -dependents %p/Inputs/every-type.pdb | FileCheck --check-prefix=TYPES %s
11 RUN: -dont-resolve-forward-refs -dependents %p/Inputs/every-type.pdb \
12 RUN: | FileCheck --check-prefix=TYPES %s
1213
1314 RUN: llvm-pdbutil pdb2yaml -tpi-stream -ipi-stream %p/Inputs/every-type.pdb > %t.pdb.yaml
1415 RUN: llvm-pdbutil yaml2pdb -pdb=%t.yaml.pdb %t.pdb.yaml
1516 RUN: llvm-pdbutil dump -type-index=0x101A,0x102C,0x103D,0x104D,0x1098,0x10AA,0x10AC \
16 RUN: -dependents %t.yaml.pdb | FileCheck --check-prefix=TYPES %s
17 RUN: -dependents -dont-resolve-forward-refs %t.yaml.pdb \
18 RUN: | FileCheck --check-prefix=TYPES %s
1719
1820 TYPES: Types (TPI Stream)
1921 TYPES-NEXT: ============================================================
0 ; RUN: llvm-pdbutil dump -types %p/Inputs/every-class.pdb \
1 ; RUN: | FileCheck %s
2
3 ; CHECK: Types (TPI Stream)
4 ; CHECK: ============================================================
5 ; CHECK: Showing 157 records
6 ; CHECK: 0x1008 | LF_STRUCTURE [size = 124] `main::__l2::`
7 ; CHECK: unique name: `.?AU@?1??main@@YAHHPEAPEAD@Z@`aa6523bc`
8 ; CHECK: vtable: , base list: , field list: 0x1007
9 ; CHECK: options: has unique name | scoped, sizeof 1
10 ; CHECK: 0x1009 | LF_STRUCTURE [size = 88] `main::__l2::Scoped`
11 ; CHECK: unique name: `.?AUScoped@?1??main@@YAHHPEAPEAD@Z@`aa6523bc`
12 ; CHECK: vtable: , base list: , field list: 0x1007
13 ; CHECK: options: has unique name | scoped, sizeof 1
14 ; CHECK: 0x1054 | LF_STRUCTURE [size = 48] `Nested::F`
15 ; CHECK: unique name: `.?AUF@Nested@@`
16 ; CHECK: vtable: , base list: , field list:
17 ; CHECK: options: forward ref (-> 0x1057) | has unique name | is nested, sizeof 0
18 ; CHECK: 0x1056 | LF_STRUCTURE [size = 44] `Nested`
19 ; CHECK: unique name: `.?AUNested@@`
20 ; CHECK: vtable: , base list: , field list: 0x1055
21 ; CHECK: options: contains nested class | has unique name, sizeof 1
22 ; CHECK: 0x1057 | LF_STRUCTURE [size = 48] `Nested::F`
23 ; CHECK: unique name: `.?AUF@Nested@@`
24 ; CHECK: vtable: , base list: , field list: 0x1007
25 ; CHECK: options: has unique name | is nested, sizeof 1
26 ; CHECK: 0x1058 | LF_STRUCTURE [size = 52] `Constructor`
27 ; CHECK: unique name: `.?AUConstructor@@`
28 ; CHECK: vtable: , base list: , field list:
29 ; CHECK: options: forward ref (-> 0x105C) | has unique name, sizeof 0
30 ; CHECK: 0x105C | LF_STRUCTURE [size = 52] `Constructor`
31 ; CHECK: unique name: `.?AUConstructor@@`
32 ; CHECK: vtable: , base list: , field list: 0x105B
33 ; CHECK: options: has ctor / dtor | has unique name, sizeof 1
34 ; CHECK: 0x105D | LF_CLASS [size = 40] `Class`
35 ; CHECK: unique name: `.?AVClass@@`
36 ; CHECK: vtable: , base list: , field list: 0x1007
37 ; CHECK: options: has unique name, sizeof 1
38 ; CHECK: 0x105E | LF_UNION [size = 32] `Union`
39 ; CHECK: unique name: `.?ATUnion@@`
40 ; CHECK: field list: 0x1007
41 ; CHECK: options: has unique name | sealed, sizeof 1
42 ; CHECK: 0x105F | LF_STRUCTURE [size = 48] `Operator`
43 ; CHECK: unique name: `.?AUOperator@@`
44 ; CHECK: vtable: , base list: , field list:
45 ; CHECK: options: forward ref (-> 0x1064) | has unique name, sizeof 0
46 ; CHECK: 0x1064 | LF_STRUCTURE [size = 48] `Operator`
47 ; CHECK: unique name: `.?AUOperator@@`
48 ; CHECK: vtable: , base list: , field list: 0x1063
49 ; CHECK: options: has unique name | overloaded operator, sizeof 1
50 ; CHECK: 0x1066 | LF_ENUM [size = 36] `Enum`
51 ; CHECK: unique name: `.?AW4Enum@@`
52 ; CHECK: field list: 0x1065, underlying type: 0x0074 (int)
53 ; CHECK: options: has unique name
54 ; CHECK: 0x1067 | LF_STRUCTURE [size = 40] `Cast`
55 ; CHECK: unique name: `.?AUCast@@`
56 ; CHECK: vtable: , base list: , field list:
57 ; CHECK: options: forward ref (-> 0x106B) | has unique name, sizeof 0
58 ; CHECK: 0x106B | LF_STRUCTURE [size = 40] `Cast`
59 ; CHECK: unique name: `.?AUCast@@`
60 ; CHECK: vtable: , base list: , field list: 0x106A
61 ; CHECK: options: conversion operator | has unique name | overloaded operator, sizeof 1
62 ; CHECK: 0x106C | LF_STRUCTURE [size = 44] `Nothing`
63 ; CHECK: unique name: `.?AUNothing@@`
64 ; CHECK: vtable: , base list: , field list: 0x1007
65 ; CHECK: options: has unique name, sizeof 1
66 ; CHECK: 0x106D | LF_STRUCTURE [size = 52] `Assignment`
67 ; CHECK: unique name: `.?AUAssignment@@`
68 ; CHECK: vtable: , base list: , field list:
69 ; CHECK: options: forward ref (-> 0x1073) | has unique name, sizeof 0
70 ; CHECK: 0x1073 | LF_STRUCTURE [size = 52] `Assignment`
71 ; CHECK: unique name: `.?AUAssignment@@`
72 ; CHECK: vtable: , base list: , field list: 0x1072
73 ; CHECK: options: has unique name | overloaded operator | overloaded operator=, sizeof 1
74 ; CHECK: 0x1074 | LF_STRUCTURE [size = 44] `Nothing`
75 ; CHECK: unique name: `.?AUNothing@@`
76 ; CHECK: vtable: , base list: , field list:
77 ; CHECK: options: forward ref (<- 0x106C) | has unique name, sizeof 0
78 ; CHECK: 0x1081 | LF_UNION [size = 32] `Union`
79 ; CHECK: unique name: `.?ATUnion@@`
80 ; CHECK: field list:
81 ; CHECK: options: forward ref (<- 0x105E) | has unique name, sizeof 0
82 ; CHECK: 0x1084 | LF_STRUCTURE [size = 124] `main::__l2::`
83 ; CHECK: unique name: `.?AU@?1??main@@YAHHPEAPEAD@Z@`aa6523bc`
84 ; CHECK: vtable: , base list: , field list:
85 ; CHECK: options: forward ref (<- 0x1008) | has unique name | scoped, sizeof 0
86 ; CHECK: 0x108E | LF_STRUCTURE [size = 44] `Nested`
87 ; CHECK: unique name: `.?AUNested@@`
88 ; CHECK: vtable: , base list: , field list:
89 ; CHECK: options: forward ref (<- 0x1056) | has unique name, sizeof 0
90 ; CHECK: 0x1095 | LF_STRUCTURE [size = 88] `main::__l2::Scoped`
91 ; CHECK: unique name: `.?AUScoped@?1??main@@YAHHPEAPEAD@Z@`aa6523bc`
92 ; CHECK: vtable: , base list: , field list:
93 ; CHECK: options: forward ref (<- 0x1009) | has unique name | scoped, sizeof 0
94 ; CHECK: 0x1098 | LF_CLASS [size = 40] `Class`
95 ; CHECK: unique name: `.?AVClass@@`
96 ; CHECK: vtable: , base list: , field list:
97 ; CHECK: options: forward ref (<- 0x105D) | has unique name, sizeof 0
None ; RUN: llvm-pdbutil dump -all %p/Inputs/empty.pdb | FileCheck -check-prefix=ALL %s
0 ; RUN: llvm-pdbutil dump -all -dont-resolve-forward-refs %p/Inputs/empty.pdb \
1 ; RUN: | FileCheck -check-prefix=ALL %s
12 ; RUN: llvm-pdbutil dump -summary -modules -files \
23 ; RUN: %p/Inputs/big-read.pdb | FileCheck -check-prefix=BIG %s
3 ; RUN: not llvm-pdbutil dump -summary %p/Inputs/bad-block-size.pdb 2>&1 | FileCheck -check-prefix=BAD-BLOCK-SIZE %s
4 ; RUN: not llvm-pdbutil dump -summary %p/Inputs/bad-block-size.pdb 2>&1 \
5 ; RUN: | FileCheck -check-prefix=BAD-BLOCK-SIZE %s
46
57 ALL: Summary
68 ALL-NEXT: ============================================================
12401240 dumpFullTypeStream(LinePrinter &Printer, LazyRandomTypeCollection &Types,
12411241 uint32_t NumTypeRecords, uint32_t NumHashBuckets,
12421242 FixedStreamArray HashValues,
1243 bool Bytes, bool Extras) {
1243 TpiStream *Stream, bool Bytes, bool Extras) {
12441244
12451245 Printer.formatLine("Showing {0:N} records", NumTypeRecords);
12461246 uint32_t Width = NumDigits(TypeIndex::FirstNonSimpleIndex + NumTypeRecords);
12471247
12481248 MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types,
1249 NumHashBuckets, HashValues);
1249 NumHashBuckets, HashValues, Stream);
12501250
12511251 if (auto EC = codeview::visitTypeStream(Types, V)) {
12521252 Printer.formatLine("An error occurred dumping type records: {0}",
12621262 NumDigits(TypeIndex::FirstNonSimpleIndex + Stream.getNumTypeRecords());
12631263
12641264 MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types,
1265 Stream.getNumHashBuckets(), Stream.getHashValues());
1265 Stream.getNumHashBuckets(), Stream.getHashValues(),
1266 &Stream);
12661267
12671268 if (opts::dump::DumpTypeDependents) {
12681269 // If we need to dump all dependents, then iterate each index and find
13241325 Types.reset(Reader, 100);
13251326
13261327 if (opts::dump::DumpTypes) {
1327 dumpFullTypeStream(P, Types, 0, 0, {}, opts::dump::DumpTypeData, false);
1328 dumpFullTypeStream(P, Types, 0, 0, {}, nullptr, opts::dump::DumpTypeData,
1329 false);
13281330 } else if (opts::dump::DumpTypeExtras) {
13291331 auto LocalHashes = LocallyHashedType::hashTypeCollection(Types);
13301332 auto GlobalHashes = GloballyHashedType::hashTypeCollection(Types);
13931395
13941396 auto &Types = (StreamIdx == StreamTPI) ? File.types() : File.ids();
13951397
1398 // Enable resolving forward decls.
1399 Stream.buildHashMap();
1400
13961401 if (DumpTypes || !Indices.empty()) {
13971402 if (Indices.empty())
13981403 dumpFullTypeStream(P, Types, Stream.getNumTypeRecords(),
13991404 Stream.getNumHashBuckets(), Stream.getHashValues(),
1400 DumpBytes, DumpExtras);
1405 &Stream, DumpBytes, DumpExtras);
14011406 else {
14021407 std::vector TiList(Indices.begin(), Indices.end());
14031408 dumpPartialTypeStream(P, Types, Stream, TiList, DumpBytes, DumpExtras,
1111 #include "FormatUtil.h"
1212 #include "LinePrinter.h"
1313
14 #include "llvm-pdbutil.h"
1415 #include "llvm/DebugInfo/CodeView/CVRecord.h"
1516 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
1617 #include "llvm/DebugInfo/CodeView/CodeView.h"
1819 #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
1920 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
2021 #include "llvm/DebugInfo/PDB/Native/TpiHashing.h"
22 #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
2123 #include "llvm/Support/FormatVariadic.h"
2224 #include "llvm/Support/MathExtras.h"
2325
2628 using namespace llvm::pdb;
2729
2830 static std::string formatClassOptions(uint32_t IndentLevel,
29 ClassOptions Options) {
31 ClassOptions Options, TpiStream *Stream,
32 TypeIndex CurrentTypeIndex) {
3033 std::vector Opts;
34
35 if (Stream && Stream->supportsTypeLookup() &&
36 !opts::dump::DontResolveForwardRefs &&
37 ((Options & ClassOptions::ForwardReference) != ClassOptions::None)) {
38 // If we're able to resolve forward references, do that.
39 Expected ETI =
40 Stream->findFullDeclForForwardRef(CurrentTypeIndex);
41 if (!ETI) {
42 consumeError(ETI.takeError());
43 PUSH_FLAG(ClassOptions, ForwardReference, Options, "forward ref (???)");
44 } else {
45 const char *Direction = (*ETI == CurrentTypeIndex)
46 ? "="
47 : ((*ETI < CurrentTypeIndex) ? "<-" : "->");
48 std::string Formatted =
49 formatv("forward ref ({0} {1})", Direction, *ETI).str();
50 PUSH_FLAG(ClassOptions, ForwardReference, Options, std::move(Formatted));
51 }
52 } else {
53 PUSH_FLAG(ClassOptions, ForwardReference, Options, "forward ref");
54 }
55
3156 PUSH_FLAG(ClassOptions, HasConstructorOrDestructor, Options,
3257 "has ctor / dtor");
3358 PUSH_FLAG(ClassOptions, ContainsNestedClass, Options,
3459 "contains nested class");
3560 PUSH_FLAG(ClassOptions, HasConversionOperator, Options,
3661 "conversion operator");
37 PUSH_FLAG(ClassOptions, ForwardReference, Options, "forward ref");
3862 PUSH_FLAG(ClassOptions, HasUniqueName, Options, "has unique name");
3963 PUSH_FLAG(ClassOptions, Intrinsic, Options, "intrin");
4064 PUSH_FLAG(ClassOptions, Nested, Options, "is nested");
193217 }
194218
195219 Error MinimalTypeDumpVisitor::visitTypeBegin(CVType &Record, TypeIndex Index) {
220 CurrentTypeIndex = Index;
196221 // formatLine puts the newline at the beginning, so we use formatLine here
197222 // to start a new line, and then individual visit methods use format to
198223 // append to the existing line.
303328 P.formatLine("vtable: {0}, base list: {1}, field list: {2}",
304329 Class.VTableShape, Class.DerivationList, Class.FieldList);
305330 P.formatLine("options: {0}, sizeof {1}",
306 formatClassOptions(P.getIndentLevel(), Class.Options),
331 formatClassOptions(P.getIndentLevel(), Class.Options, Stream,
332 CurrentTypeIndex),
307333 Class.Size);
308334 return Error::success();
309335 }
315341 P.formatLine("unique name: `{0}`", Union.UniqueName);
316342 P.formatLine("field list: {0}", Union.FieldList);
317343 P.formatLine("options: {0}, sizeof {1}",
318 formatClassOptions(P.getIndentLevel(), Union.Options),
344 formatClassOptions(P.getIndentLevel(), Union.Options, Stream,
345 CurrentTypeIndex),
319346 Union.Size);
320347 return Error::success();
321348 }
327354 P.formatLine("field list: {0}, underlying type: {1}", Enum.FieldList,
328355 Enum.UnderlyingType);
329356 P.formatLine("options: {0}",
330 formatClassOptions(P.getIndentLevel(), Enum.Options));
357 formatClassOptions(P.getIndentLevel(), Enum.Options, Stream,
358 CurrentTypeIndex));
331359 return Error::success();
332360 }
333361
1919
2020 namespace pdb {
2121 class LinePrinter;
22 class TpiStream;
2223
2324 class MinimalTypeDumpVisitor : public codeview::TypeVisitorCallbacks {
2425 public:
2526 MinimalTypeDumpVisitor(LinePrinter &P, uint32_t Width, bool RecordBytes,
2627 bool Hashes, codeview::LazyRandomTypeCollection &Types,
2728 uint32_t NumHashBuckets,
28 FixedStreamArray HashValues)
29 FixedStreamArray HashValues,
30 pdb::TpiStream *Stream)
2931 : P(P), Width(Width), RecordBytes(RecordBytes), Hashes(Hashes),
30 Types(Types), NumHashBuckets(NumHashBuckets), HashValues(HashValues) {}
32 Types(Types), NumHashBuckets(NumHashBuckets), HashValues(HashValues),
33 Stream(Stream) {}
3134
3235 Error visitTypeBegin(codeview::CVType &Record,
3336 codeview::TypeIndex Index) override;
5457 bool Hashes = false;
5558 codeview::LazyRandomTypeCollection &Types;
5659 uint32_t NumHashBuckets;
60 codeview::TypeIndex CurrentTypeIndex;
5761 FixedStreamArray HashValues;
62 pdb::TpiStream *Stream = nullptr;
5863 };
5964 } // namespace pdb
6065 } // namespace llvm
182182 cl::sub(DiaDumpSubcommand));
183183 static cl::opt Pointers("pointers", cl::desc("Dump enum types"),
184184 cl::sub(DiaDumpSubcommand));
185 static cl::opt UDTs("udts", cl::desc("Dump udt types"),
186 cl::sub(DiaDumpSubcommand));
185187 static cl::opt Compilands("compilands",
186188 cl::desc("Dump compiland information"),
187189 cl::sub(DiaDumpSubcommand));
463465 cl::opt DumpTypeExtras("type-extras",
464466 cl::desc("dump type hashes and index offsets"),
465467 cl::cat(TypeOptions), cl::sub(DumpSubcommand));
468
469 cl::opt DontResolveForwardRefs(
470 "dont-resolve-forward-refs",
471 cl::desc("When dumping type records for classes, unions, enums, and "
472 "structs, don't try to resolve forward references"),
473 cl::cat(TypeOptions), cl::sub(DumpSubcommand));
466474
467475 cl::list DumpTypeIndex(
468476 "type-index", cl::ZeroOrMore, cl::CommaSeparated,
159159 extern llvm::cl::list DumpIdIndex;
160160 extern llvm::cl::opt DumpModi;
161161 extern llvm::cl::opt JustMyCode;
162 extern llvm::cl::opt DontResolveForwardRefs;
162163 extern llvm::cl::opt DumpSymbols;
163164 extern llvm::cl::opt DumpSymRecordBytes;
164165 extern llvm::cl::opt DumpGSIRecords;