llvm.org GIT mirror llvm / 53034fb
[codeview] Remove TypeServerHandler and PDBTypeServerHandler Summary: Instead of wiring these through the CVTypeVisitor interface, clients should inspect the CVTypeArray before visiting it and potentially load up the type server's TPI stream if they need it. No tests relied on this functionality because LLD was the only client. Reviewers: ruiu Subscribers: mgorny, hiraditya, zturner, llvm-commits Differential Revision: https://reviews.llvm.org/D35394 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@308212 91177308-0d34-0410-b5e6-96231b3b80d8 Reid Kleckner 2 years ago
14 changed file(s) with 32 addition(s) and 508 deletion(s). Raw diff Collapse all Expand all
1616 namespace llvm {
1717 namespace codeview {
1818 class TypeCollection;
19 class TypeServerHandler;
2019 class TypeVisitorCallbacks;
2120
2221 enum VisitorDataSource {
3029
3130 Error visitTypeRecord(CVType &Record, TypeIndex Index,
3231 TypeVisitorCallbacks &Callbacks,
33 VisitorDataSource Source = VDS_BytesPresent,
34 TypeServerHandler *TS = nullptr);
32 VisitorDataSource Source = VDS_BytesPresent);
3533 Error visitTypeRecord(CVType &Record, TypeVisitorCallbacks &Callbacks,
36 VisitorDataSource Source = VDS_BytesPresent,
37 TypeServerHandler *TS = nullptr);
34 VisitorDataSource Source = VDS_BytesPresent);
3835
3936 Error visitMemberRecord(CVMemberRecord Record, TypeVisitorCallbacks &Callbacks,
4037 VisitorDataSource Source = VDS_BytesPresent);
4542 TypeVisitorCallbacks &Callbacks);
4643
4744 Error visitTypeStream(const CVTypeArray &Types, TypeVisitorCallbacks &Callbacks,
48 VisitorDataSource Source = VDS_BytesPresent,
49 TypeServerHandler *TS = nullptr);
50 Error visitTypeStream(CVTypeRange Types, TypeVisitorCallbacks &Callbacks,
51 TypeServerHandler *TS = nullptr);
52 Error visitTypeStream(TypeCollection &Types, TypeVisitorCallbacks &Callbacks,
53 TypeServerHandler *TS = nullptr);
45 VisitorDataSource Source = VDS_BytesPresent);
46 Error visitTypeStream(CVTypeRange Types, TypeVisitorCallbacks &Callbacks);
47 Error visitTypeStream(TypeCollection &Types, TypeVisitorCallbacks &Callbacks);
5448
5549 } // end namespace codeview
5650 } // end namespace llvm
+0
-38
include/llvm/DebugInfo/CodeView/TypeServerHandler.h less more
None //===- TypeServerHandler.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_TYPESERVERHANDLER_H
10 #define LLVM_DEBUGINFO_CODEVIEW_TYPESERVERHANDLER_H
11
12 #include "llvm/Support/Error.h"
13
14 namespace llvm {
15 namespace codeview {
16
17 class TypeServer2Record;
18 class TypeVisitorCallbacks;
19
20 class TypeServerHandler {
21 public:
22 virtual ~TypeServerHandler() = default;
23
24 /// Handle a TypeServer record. If the implementation returns true
25 /// the record will not be processed by the top-level visitor. If
26 /// it returns false, it will be processed. If it returns an Error,
27 /// then the top-level visitor will fail.
28 virtual Expected handle(TypeServer2Record &TS,
29 TypeVisitorCallbacks &Callbacks) {
30 return false;
31 }
32 };
33
34 } // end namespace codeview
35 } // end namespace llvm
36
37 #endif // LLVM_DEBUGINFO_CODEVIEW_TYPESERVERHANDLER_H
1818 namespace codeview {
1919
2020 class TypeIndex;
21 class TypeServerHandler;
2221 class TypeTableBuilder;
2322
2423 /// \brief Merge one set of type records into another. This method assumes
3938 /// appropriate error code.
4039 Error mergeTypeRecords(TypeTableBuilder &Dest,
4140 SmallVectorImpl &SourceToDest,
42 TypeServerHandler *Handler, const CVTypeArray &Types);
41 const CVTypeArray &Types);
4342
4443 /// \brief Merge one set of id records into another. This method assumes
4544 /// that all records are id records, and there are no Type records present.
6463 /// appropriate error code.
6564 Error mergeIdRecords(TypeTableBuilder &Dest, ArrayRef Types,
6665 SmallVectorImpl &SourceToDest,
67 const CVTypeArray &Ids);
66 const CVTypeArray &Ids);
6867
6968 /// \brief Merge a unified set of type and id records, splitting them into
7069 /// separate output streams.
8786 Error mergeTypeAndIdRecords(TypeTableBuilder &DestIds,
8887 TypeTableBuilder &DestTypes,
8988 SmallVectorImpl &SourceToDest,
90 TypeServerHandler *Handler,
91 const CVTypeArray &IdsAndTypes);
89 const CVTypeArray &IdsAndTypes);
9290
9391 } // end namespace codeview
9492 } // end namespace llvm
+0
-46
include/llvm/DebugInfo/PDB/Native/PDBTypeServerHandler.h less more
None //===- PDBTypeServerHandler.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_PDB_PDBTYPESERVERHANDLER_H
10 #define LLVM_DEBUGINFO_PDB_PDBTYPESERVERHANDLER_H
11
12 #include "llvm/ADT/SmallString.h"
13 #include "llvm/ADT/StringSet.h"
14 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
15 #include "llvm/DebugInfo/CodeView/TypeServerHandler.h"
16 #include "llvm/DebugInfo/PDB/Native/NativeSession.h"
17 #include "llvm/DebugInfo/PDB/PDBTypes.h"
18
19 #include
20 #include
21
22 namespace llvm {
23 namespace pdb {
24 class NativeSession;
25
26 class PDBTypeServerHandler : public codeview::TypeServerHandler {
27 public:
28 PDBTypeServerHandler(bool RevisitAlways = false);
29
30 void addSearchPath(StringRef Path);
31 Expected handle(codeview::TypeServer2Record &TS,
32 codeview::TypeVisitorCallbacks &Callbacks) override;
33
34 private:
35 Expected handleInternal(PDBFile &File,
36 codeview::TypeVisitorCallbacks &Callbacks);
37
38 bool RevisitAlways;
39 std::unique_ptr Session;
40 StringSet<> SearchPaths;
41 };
42 }
43 }
44
45 #endif
1313 #include "llvm/DebugInfo/CodeView/TypeCollection.h"
1414 #include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
1515 #include "llvm/DebugInfo/CodeView/TypeRecordMapping.h"
16 #include "llvm/DebugInfo/CodeView/TypeServerHandler.h"
1716 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
1817 #include "llvm/Support/BinaryByteStream.h"
1918 #include "llvm/Support/BinaryStreamReader.h"
4140 return Error::success();
4241 }
4342
44 static Expected deserializeTypeServerRecord(CVType &Record) {
45 TypeServer2Record R(TypeRecordKind::TypeServer2);
46 if (auto EC = TypeDeserializer::deserializeAs(Record, R))
47 return std::move(EC);
48 return R;
49 }
50
5143 static Error visitMemberRecord(CVMemberRecord &Record,
5244 TypeVisitorCallbacks &Callbacks) {
5345 if (auto EC = Callbacks.visitMemberBegin(Record))
8375 public:
8476 explicit CVTypeVisitor(TypeVisitorCallbacks &Callbacks);
8577
86 void addTypeServerHandler(TypeServerHandler &Handler);
87
8878 Error visitTypeRecord(CVType &Record, TypeIndex Index);
8979 Error visitTypeRecord(CVType &Record);
9080
9787 Error visitFieldListMemberStream(BinaryStreamReader &Stream);
9888
9989 private:
100 Expected handleTypeServer(CVType &Record);
10190 Error finishVisitation(CVType &Record);
10291
10392 /// The interface to the class that gets notified of each visitation.
10493 TypeVisitorCallbacks &Callbacks;
105
106 TinyPtrVector Handlers;
10794 };
10895
10996 CVTypeVisitor::CVTypeVisitor(TypeVisitorCallbacks &Callbacks)
11097 : Callbacks(Callbacks) {}
111
112 void CVTypeVisitor::addTypeServerHandler(TypeServerHandler &Handler) {
113 Handlers.push_back(&Handler);
114 }
115
116 Expected CVTypeVisitor::handleTypeServer(CVType &Record) {
117 if (Record.Type == TypeLeafKind::LF_TYPESERVER2 && !Handlers.empty()) {
118 auto TS = deserializeTypeServerRecord(Record);
119 if (!TS)
120 return TS.takeError();
121
122 for (auto Handler : Handlers) {
123 auto ExpectedResult = Handler->handle(*TS, Callbacks);
124 // If there was an error, return the error.
125 if (!ExpectedResult)
126 return ExpectedResult.takeError();
127
128 // If the handler processed the record, return success.
129 if (*ExpectedResult)
130 return true;
131
132 // Otherwise keep searching for a handler, eventually falling out and
133 // using the default record handler.
134 }
135 }
136 return false;
137 }
13898
13999 Error CVTypeVisitor::finishVisitation(CVType &Record) {
140100 switch (Record.Type) {
162122 }
163123
164124 Error CVTypeVisitor::visitTypeRecord(CVType &Record, TypeIndex Index) {
165 auto ExpectedResult = handleTypeServer(Record);
166 if (!ExpectedResult)
167 return ExpectedResult.takeError();
168 if (*ExpectedResult)
169 return Error::success();
170
171125 if (auto EC = Callbacks.visitTypeBegin(Record, Index))
172126 return EC;
173127
175129 }
176130
177131 Error CVTypeVisitor::visitTypeRecord(CVType &Record) {
178 auto ExpectedResult = handleTypeServer(Record);
179 if (!ExpectedResult)
180 return ExpectedResult.takeError();
181 if (*ExpectedResult)
182 return Error::success();
183
184132 if (auto EC = Callbacks.visitTypeBegin(Record))
185133 return EC;
186134
270218
271219 Error llvm::codeview::visitTypeRecord(CVType &Record, TypeIndex Index,
272220 TypeVisitorCallbacks &Callbacks,
273 VisitorDataSource Source,
274 TypeServerHandler *TS) {
221 VisitorDataSource Source) {
275222 VisitHelper V(Callbacks, Source);
276 if (TS)
277 V.Visitor.addTypeServerHandler(*TS);
278223 return V.Visitor.visitTypeRecord(Record, Index);
279224 }
280225
281226 Error llvm::codeview::visitTypeRecord(CVType &Record,
282227 TypeVisitorCallbacks &Callbacks,
283 VisitorDataSource Source,
284 TypeServerHandler *TS) {
228 VisitorDataSource Source) {
285229 VisitHelper V(Callbacks, Source);
286 if (TS)
287 V.Visitor.addTypeServerHandler(*TS);
288230 return V.Visitor.visitTypeRecord(Record);
289231 }
290232
291233 Error llvm::codeview::visitTypeStream(const CVTypeArray &Types,
292234 TypeVisitorCallbacks &Callbacks,
293 VisitorDataSource Source,
294 TypeServerHandler *TS) {
235 VisitorDataSource Source) {
295236 VisitHelper V(Callbacks, Source);
296 if (TS)
297 V.Visitor.addTypeServerHandler(*TS);
298237 return V.Visitor.visitTypeStream(Types);
299238 }
300239
301240 Error llvm::codeview::visitTypeStream(CVTypeRange Types,
302 TypeVisitorCallbacks &Callbacks,
303 TypeServerHandler *TS) {
241 TypeVisitorCallbacks &Callbacks) {
304242 VisitHelper V(Callbacks, VDS_BytesPresent);
305 if (TS)
306 V.Visitor.addTypeServerHandler(*TS);
307243 return V.Visitor.visitTypeStream(Types);
308244 }
309245
310246 Error llvm::codeview::visitTypeStream(TypeCollection &Types,
311 TypeVisitorCallbacks &Callbacks,
312 TypeServerHandler *TS) {
247 TypeVisitorCallbacks &Callbacks) {
313248 // When the internal visitor calls Types.getType(Index) the interface is
314249 // required to return a CVType with the bytes filled out. So we can assume
315250 // that the bytes will be present when individual records are visited.
316251 VisitHelper V(Callbacks, VDS_BytesPresent);
317 if (TS)
318 V.Visitor.addTypeServerHandler(*TS);
319252 return V.Visitor.visitTypeStream(Types);
320253 }
321254
5858 /// looking at the record kind.
5959 class TypeStreamMerger : public TypeVisitorCallbacks {
6060 public:
61 explicit TypeStreamMerger(SmallVectorImpl &SourceToDest,
62 TypeServerHandler *Handler)
63 : Handler(Handler), IndexMap(SourceToDest) {
61 explicit TypeStreamMerger(SmallVectorImpl &SourceToDest)
62 : IndexMap(SourceToDest) {
6463 SourceToDest.clear();
6564 }
6665
7069 Error visitTypeEnd(CVType &Record) override;
7170
7271 Error mergeTypesAndIds(TypeTableBuilder &DestIds, TypeTableBuilder &DestTypes,
73 const CVTypeArray &IdsAndTypes);
72 const CVTypeArray &IdsAndTypes);
7473 Error mergeIdRecords(TypeTableBuilder &Dest,
7574 ArrayRef TypeSourceToDest,
76 const CVTypeArray &Ids);
75 const CVTypeArray &Ids);
7776 Error mergeTypeRecords(TypeTableBuilder &Dest, const CVTypeArray &Types);
7877
7978 private:
152151
153152 TypeTableBuilder *DestIdStream = nullptr;
154153 TypeTableBuilder *DestTypeStream = nullptr;
155 TypeServerHandler *Handler = nullptr;
156154
157155 // If we're only mapping id records, this array contains the mapping for
158156 // type records.
255253 }
256254
257255 Error TypeStreamMerger::mergeTypeRecords(TypeTableBuilder &Dest,
258 const CVTypeArray &Types) {
256 const CVTypeArray &Types) {
259257 DestTypeStream = &Dest;
260258
261259 return doit(Types);
263261
264262 Error TypeStreamMerger::mergeIdRecords(TypeTableBuilder &Dest,
265263 ArrayRef TypeSourceToDest,
266 const CVTypeArray &Ids) {
264 const CVTypeArray &Ids) {
267265 DestIdStream = &Dest;
268266 TypeLookup = TypeSourceToDest;
269267
287285 // would buy us much since it's already pretty fast, but it's probably worth
288286 // a few cycles.
289287 if (auto EC =
290 codeview::visitTypeStream(Types, *this, VDS_BytesExternal, Handler))
288 codeview::visitTypeStream(Types, *this, VDS_BytesExternal))
291289 return EC;
292290
293291 // If we found bad indices but no other errors, try doing another pass and see
304302 CurIndex = TypeIndex(TypeIndex::FirstNonSimpleIndex);
305303
306304 if (auto EC =
307 codeview::visitTypeStream(Types, *this, VDS_BytesExternal, Handler))
305 codeview::visitTypeStream(Types, *this, VDS_BytesExternal))
308306 return EC;
309307
310308 assert(NumBadIndices <= BadIndicesRemaining &&
322320
323321 Error llvm::codeview::mergeTypeRecords(TypeTableBuilder &Dest,
324322 SmallVectorImpl &SourceToDest,
325 TypeServerHandler *Handler,
326 const CVTypeArray &Types) {
327 TypeStreamMerger M(SourceToDest, Handler);
323 const CVTypeArray &Types) {
324 TypeStreamMerger M(SourceToDest);
328325 return M.mergeTypeRecords(Dest, Types);
329326 }
330327
331328 Error llvm::codeview::mergeIdRecords(TypeTableBuilder &Dest,
332329 ArrayRef TypeSourceToDest,
333330 SmallVectorImpl &SourceToDest,
334 const CVTypeArray &Ids) {
335 TypeStreamMerger M(SourceToDest, nullptr);
331 const CVTypeArray &Ids) {
332 TypeStreamMerger M(SourceToDest);
336333 return M.mergeIdRecords(Dest, TypeSourceToDest, Ids);
337334 }
338335
339336 Error llvm::codeview::mergeTypeAndIdRecords(
340337 TypeTableBuilder &DestIds, TypeTableBuilder &DestTypes,
341 SmallVectorImpl &SourceToDest, TypeServerHandler *Handler,
342 const CVTypeArray &IdsAndTypes) {
343 TypeStreamMerger M(SourceToDest, Handler);
338 SmallVectorImpl &SourceToDest, const CVTypeArray &IdsAndTypes) {
339 TypeStreamMerger M(SourceToDest);
344340 return M.mergeTypesAndIds(DestIds, DestTypes, IdsAndTypes);
345341 }
5151 Native/PDBFileBuilder.cpp
5252 Native/PDBStringTable.cpp
5353 Native/PDBStringTableBuilder.cpp
54 Native/PDBTypeServerHandler.cpp
5554 Native/PublicsStream.cpp
5655 Native/PublicsStreamBuilder.cpp
5756 Native/RawError.cpp
+0
-125
lib/DebugInfo/PDB/Native/PDBTypeServerHandler.cpp less more
None //===- PDBTypeServerHandler.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 // Handles CodeView LF_TYPESERVER2 records by attempting to locate a matching
9 // PDB file, then loading the PDB file and visiting all types from the
10 // referenced PDB using the original supplied visitor.
11 //
12 // The net effect of this is that when visiting a PDB containing a TypeServer
13 // record, the TypeServer record is "replaced" with all of the records in
14 // the referenced PDB file. If a single instance of PDBTypeServerHandler
15 // encounters the same TypeServer multiple times (for example reusing one
16 // PDBTypeServerHandler across multiple visitations of distinct object files or
17 // PDB files), PDBTypeServerHandler will optionally revisit all the records
18 // again, or simply consume the record and do nothing.
19 //===----------------------------------------------------------------------===//
20
21 #include "llvm/DebugInfo/PDB/Native/PDBTypeServerHandler.h"
22
23 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
24 #include "llvm/DebugInfo/CodeView/CodeViewError.h"
25 #include "llvm/DebugInfo/PDB/GenericError.h"
26 #include "llvm/DebugInfo/PDB/Native/InfoStream.h"
27 #include "llvm/DebugInfo/PDB/Native/NativeSession.h"
28 #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
29 #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
30 #include "llvm/DebugInfo/PDB/PDB.h"
31 #include "llvm/Support/FileSystem.h"
32 #include "llvm/Support/Path.h"
33
34 using namespace llvm;
35 using namespace llvm::codeview;
36 using namespace llvm::pdb;
37
38 static void ignoreErrors(Error EC) {
39 llvm::handleAllErrors(std::move(EC), [&](ErrorInfoBase &EIB) {});
40 }
41
42 PDBTypeServerHandler::PDBTypeServerHandler(bool RevisitAlways)
43 : RevisitAlways(RevisitAlways) {}
44
45 void PDBTypeServerHandler::addSearchPath(StringRef Path) {
46 if (Path.empty() || !sys::fs::is_directory(Path))
47 return;
48
49 SearchPaths.insert(Path);
50 }
51
52 Expected
53 PDBTypeServerHandler::handleInternal(PDBFile &File,
54 TypeVisitorCallbacks &Callbacks) {
55 auto ExpectedTpi = File.getPDBTpiStream();
56 if (!ExpectedTpi)
57 return ExpectedTpi.takeError();
58
59 // For handling a type server, we should be using whatever the callback array
60 // was that is being used for the original file. We shouldn't allow the
61 // visitor to arbitrarily stick a deserializer in there.
62 if (auto EC = codeview::visitTypeStream(ExpectedTpi->typeArray(), Callbacks,
63 VDS_BytesExternal))
64 return std::move(EC);
65
66 return true;
67 }
68
69 Expected PDBTypeServerHandler::handle(TypeServer2Record &TS,
70 TypeVisitorCallbacks &Callbacks) {
71 if (Session) {
72 // If we've already handled this TypeServer and we only want to handle each
73 // TypeServer once, consume the record without doing anything.
74 if (!RevisitAlways)
75 return true;
76
77 return handleInternal(Session->getPDBFile(), Callbacks);
78 }
79
80 StringRef File = sys::path::filename(TS.Name);
81 if (File.empty())
82 return make_error(
83 cv_error_code::corrupt_record,
84 "TypeServer2Record does not contain filename!");
85
86 for (auto &Path : SearchPaths) {
87 SmallString<64> PathStr = Path.getKey();
88 sys::path::append(PathStr, File);
89 if (!sys::fs::exists(PathStr))
90 continue;
91
92 std::unique_ptr ThisSession;
93 if (auto EC = loadDataForPDB(PDB_ReaderType::Native, PathStr, ThisSession)) {
94 // It is not an error if this PDB fails to load, it just means that it
95 // doesn't match and we should continue searching.
96 ignoreErrors(std::move(EC));
97 continue;
98 }
99
100 std::unique_ptr NS(
101 static_cast(ThisSession.release()));
102 PDBFile &File = NS->getPDBFile();
103 auto ExpectedInfo = File.getPDBInfoStream();
104 // All PDB Files should have an Info stream.
105 if (!ExpectedInfo)
106 return ExpectedInfo.takeError();
107
108 // Just because a file with a matching name was found and it was an actual
109 // PDB file doesn't mean it matches. For it to match the InfoStream's GUID
110 // must match the GUID specified in the TypeServer2 record.
111 ArrayRef GuidBytes(ExpectedInfo->getGuid().Guid);
112 StringRef GuidStr(reinterpret_cast(GuidBytes.begin()),
113 GuidBytes.size());
114 if (GuidStr != TS.Guid)
115 continue;
116
117 Session = std::move(NS);
118 return handleInternal(File, Callbacks);
119 }
120
121 // We couldn't find a matching PDB, so let it be handled by someone else.
122 return make_error(generic_error_code::type_server_not_found,
123 File);
124 }
1313 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
1414 #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
1515 #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
16 #include "llvm/DebugInfo/PDB/Native/PDBTypeServerHandler.h"
1716 #include "llvm/DebugInfo/PDB/Native/RawConstants.h"
1817 #include "llvm/DebugInfo/PDB/Native/RawError.h"
1918 #include "llvm/DebugInfo/PDB/Native/RawTypes.h"
955955 SmallVector IdMap;
956956 if (File.hasPDBTpiStream()) {
957957 auto &Tpi = ExitOnErr(File.getPDBTpiStream());
958 ExitOnErr(codeview::mergeTypeRecords(MergedTpi, TypeMap, nullptr,
959 Tpi.typeArray()));
958 ExitOnErr(
959 codeview::mergeTypeRecords(MergedTpi, TypeMap, Tpi.typeArray()));
960960 }
961961 if (File.hasPDBIpiStream()) {
962962 auto &Ipi = ExitOnErr(File.getPDBIpiStream());
12141214 error(object_error::parse_failed);
12151215 }
12161216 SmallVector SourceToDest;
1217 if (auto EC = mergeTypeAndIdRecords(CVIDs, CVTypes, SourceToDest, nullptr,
1218 Types))
1217 if (auto EC = mergeTypeAndIdRecords(CVIDs, CVTypes, SourceToDest, Types))
12191218 return error(std::move(EC));
12201219 }
12211220 }
1212 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
1313 #include "llvm/DebugInfo/CodeView/TypeRecordMapping.h"
1414 #include "llvm/DebugInfo/CodeView/TypeSerializer.h"
15 #include "llvm/DebugInfo/CodeView/TypeServerHandler.h"
1615 #include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
1716 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
1817 #include "llvm/DebugInfo/PDB/Native/RawTypes.h"
401400
402401 StringRef Name = Types.getTypeName(IndexOne);
403402 EXPECT_EQ("const FooClass", Name);
404 }
403 }
99 StringTableBuilderTest.cpp
1010 MSFBuilderTest.cpp
1111 PDBApiTest.cpp
12 TypeServerHandlerTest.cpp
1312 )
1413
1514 add_llvm_unittest(DebugInfoPDBTests
1615 ${DebugInfoPDBSources}
1716 )
1817
19 target_link_libraries(DebugInfoPDBTests LLVMTestingSupport)
18 target_link_libraries(DebugInfoPDBTests LLVMTestingSupport)
+0
-183
unittests/DebugInfo/PDB/TypeServerHandlerTest.cpp less more
None //===- llvm/unittest/DebugInfo/PDB/TypeServerHandlerTest.cpp --------------===//
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/TypeServerHandler.h"
10 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
11 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
12 #include "llvm/DebugInfo/CodeView/TypeRecordMapping.h"
13 #include "llvm/DebugInfo/CodeView/TypeSerializer.h"
14 #include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
15 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
16 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
17 #include "llvm/DebugInfo/PDB/Native/RawTypes.h"
18 #include "llvm/Support/Allocator.h"
19 #include "llvm/Support/Error.h"
20 #include "llvm/Testing/Support/Error.h"
21
22 #include "gtest/gtest.h"
23
24 using namespace llvm;
25 using namespace llvm::codeview;
26 using namespace llvm::pdb;
27
28 namespace {
29
30 constexpr uint8_t Guid[] = {0x2a, 0x2c, 0x1c, 0x2a, 0xcb, 0x9e, 0x48, 0x18,
31 0x82, 0x82, 0x7a, 0x87, 0xc3, 0xfe, 0x16, 0xe8};
32 StringRef GuidStr(reinterpret_cast(Guid),
33 llvm::array_lengthof(Guid));
34
35 constexpr const char *Name = "Test Name";
36 constexpr int Age = 1;
37
38 class MockTypeServerHandler : public TypeServerHandler {
39 public:
40 explicit MockTypeServerHandler(bool HandleAlways)
41 : HandleAlways(HandleAlways) {}
42
43 Expected handle(TypeServer2Record &TS,
44 TypeVisitorCallbacks &Callbacks) override {
45 if (TS.Age != Age || TS.Guid != GuidStr || TS.Name != Name)
46 return make_error(cv_error_code::corrupt_record,
47 "Invalid TypeServer record!");
48
49 if (Handled && !HandleAlways)
50 return false;
51
52 Handled = true;
53 return true;
54 }
55
56 bool Handled = false;
57 bool HandleAlways;
58 };
59
60 class MockTypeVisitorCallbacks : public TypeVisitorCallbacks {
61 public:
62 enum class State {
63 Ready,
64 VisitTypeBegin,
65 VisitKnownRecord,
66 VisitTypeEnd,
67 };
68 Error visitTypeBegin(CVType &CVT) override {
69 if (S != State::Ready)
70 return make_error(cv_error_code::unspecified,
71 "Invalid visitor state!");
72
73 S = State::VisitTypeBegin;
74 return Error::success();
75 }
76
77 Error visitKnownRecord(CVType &CVT, TypeServer2Record &TS) override {
78 if (S != State::VisitTypeBegin)
79 return make_error(cv_error_code::unspecified,
80 "Invalid visitor state!");
81
82 S = State::VisitKnownRecord;
83 return Error::success();
84 }
85
86 Error visitTypeEnd(CVType &CVT) override {
87 if (S != State::VisitKnownRecord)
88 return make_error(cv_error_code::unspecified,
89 "Invalid visitor state!");
90
91 S = State::VisitTypeEnd;
92 return Error::success();
93 }
94
95 State S = State::Ready;
96 };
97
98 class TypeServerHandlerTest : public testing::Test {
99 public:
100 void SetUp() override {
101 TypeServer2Record R(TypeRecordKind::TypeServer2);
102 R.Age = Age;
103 R.Guid = GuidStr;
104 R.Name = Name;
105
106 TypeTableBuilder Builder(Allocator);
107 Builder.writeKnownType(R);
108 TypeServerRecord.RecordData = Builder.records().front();
109 TypeServerRecord.Type = TypeLeafKind::LF_TYPESERVER2;
110 }
111
112 protected:
113 BumpPtrAllocator Allocator;
114 CVType TypeServerRecord;
115 };
116
117 // Test that when no type server handler is registered, it gets handled by the
118 // normal
119 // visitor callbacks.
120 TEST_F(TypeServerHandlerTest, VisitRecordNoTypeServer) {
121 MockTypeVisitorCallbacks C2;
122 MockTypeVisitorCallbacks C1;
123 TypeVisitorCallbackPipeline Pipeline;
124
125 Pipeline.addCallbackToPipeline(C1);
126 Pipeline.addCallbackToPipeline(C2);
127
128 EXPECT_THAT_ERROR(codeview::visitTypeRecord(TypeServerRecord, Pipeline),
129 Succeeded());
130
131 EXPECT_EQ(MockTypeVisitorCallbacks::State::VisitTypeEnd, C1.S);
132 EXPECT_EQ(MockTypeVisitorCallbacks::State::VisitTypeEnd, C2.S);
133 }
134
135 // Test that when a TypeServerHandler is registered, it gets consumed by the
136 // handler if and only if the handler returns true.
137 TEST_F(TypeServerHandlerTest, VisitRecordWithTypeServerOnce) {
138 MockTypeServerHandler Handler(false);
139
140 MockTypeVisitorCallbacks C1;
141
142 // Our mock server returns true the first time.
143 EXPECT_THAT_ERROR(codeview::visitTypeRecord(TypeServerRecord, C1,
144 codeview::VDS_BytesExternal,
145 &Handler),
146 Succeeded());
147 EXPECT_TRUE(Handler.Handled);
148 EXPECT_EQ(MockTypeVisitorCallbacks::State::Ready, C1.S);
149
150 // And false the second time.
151 EXPECT_THAT_ERROR(codeview::visitTypeRecord(TypeServerRecord, C1,
152 codeview::VDS_BytesExternal,
153 &Handler),
154 Succeeded());
155 EXPECT_TRUE(Handler.Handled);
156 EXPECT_EQ(MockTypeVisitorCallbacks::State::VisitTypeEnd, C1.S);
157 }
158
159 // Test that when a type server handler is registered, if the handler keeps
160 // returning true, it will keep getting consumed by the handler and not go
161 // to the default processor.
162 TEST_F(TypeServerHandlerTest, VisitRecordWithTypeServerAlways) {
163 MockTypeServerHandler Handler(true);
164
165 MockTypeVisitorCallbacks C1;
166
167 EXPECT_THAT_ERROR(codeview::visitTypeRecord(TypeServerRecord, C1,
168 codeview::VDS_BytesExternal,
169 &Handler),
170 Succeeded());
171 EXPECT_TRUE(Handler.Handled);
172 EXPECT_EQ(MockTypeVisitorCallbacks::State::Ready, C1.S);
173
174 EXPECT_THAT_ERROR(codeview::visitTypeRecord(TypeServerRecord, C1,
175 codeview::VDS_BytesExternal,
176 &Handler),
177 Succeeded());
178 EXPECT_TRUE(Handler.Handled);
179 EXPECT_EQ(MockTypeVisitorCallbacks::State::Ready, C1.S);
180 }
181
182 } // end anonymous namespace