llvm.org GIT mirror llvm / c254cb7
[CodeView] Simplify the use of visiting type records & streams. There is often a lot of boilerplate code required to visit a type record or type stream. The #1 use case is that you have a sequence of bytes that represent one or more records, and you want to deserialize each one, switch on it, and call a callback with the deserialized record that the user can examine. Currently this requires at least 6 lines of code: codeview::TypeVisitorCallbackPipeline Pipeline; Pipeline.addCallbackToPipeline(Deserializer); Pipeline.addCallbackToPipeline(MyCallbacks); codeview::CVTypeVisitor Visitor(Pipeline); consumeError(Visitor.visitTypeRecord(Record)); With this patch, it becomes one line of code: consumeError(codeview::visitTypeRecord(Record, MyCallbacks)); This is done by having the deserialization happen internally inside of the visitTypeRecord function. Since this is occasionally not desirable, the function provides a 3rd parameter that can be used to change this behavior. Hopefully this can significantly reduce the barrier to entry to using the visitation infrastructure. Differential Revision: https://reviews.llvm.org/D33245 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@303271 91177308-0d34-0410-b5e6-96231b3b80d8 Zachary Turner 2 years ago
16 changed file(s) with 206 addition(s) and 176 deletion(s). Raw diff Collapse all Expand all
2727
2828 Error visitTypeRecord(CVType &Record, TypeIndex Index);
2929 Error visitTypeRecord(CVType &Record);
30 Error visitMemberRecord(CVMemberRecord &Record);
30 Error visitMemberRecord(CVMemberRecord Record);
3131
3232 /// Visits the type records in Data. Sets the error flag on parse failures.
3333 Error visitTypeStream(const CVTypeArray &Types);
4646 TinyPtrVector Handlers;
4747 };
4848
49 enum VisitorDataSource {
50 VDS_BytesPresent, // The record bytes are passed into the the visitation
51 // function. The algorithm should first deserialize them
52 // before passing them on through the pipeline.
53 VDS_BytesExternal // The record bytes are not present, and it is the
54 // responsibility of the visitor callback interface to
55 // supply the bytes.
56 };
57
58 Error visitTypeRecord(CVType &Record, TypeIndex Index,
59 TypeVisitorCallbacks &Callbacks,
60 VisitorDataSource Source = VDS_BytesPresent,
61 TypeServerHandler *TS = nullptr);
62 Error visitTypeRecord(CVType &Record, TypeVisitorCallbacks &Callbacks,
63 VisitorDataSource Source = VDS_BytesPresent,
64 TypeServerHandler *TS = nullptr);
65
66 Error visitMemberRecord(CVMemberRecord Record, TypeVisitorCallbacks &Callbacks,
67 VisitorDataSource Source = VDS_BytesPresent);
68 Error visitMemberRecord(TypeLeafKind Kind, ArrayRef Record,
69 TypeVisitorCallbacks &Callbacks);
70
71 Error visitMemberRecordStream(ArrayRef FieldList,
72 TypeVisitorCallbacks &Callbacks);
73
74 Error visitTypeStream(const CVTypeArray &Types, TypeVisitorCallbacks &Callbacks,
75 TypeServerHandler *TS = nullptr);
76 Error visitTypeStream(CVTypeRange Types, TypeVisitorCallbacks &Callbacks,
77 TypeServerHandler *TS = nullptr);
78
4979 } // end namespace codeview
5080 } // end namespace llvm
5181
1010 #define LLVM_DEBUGINFO_CODEVIEW_RANDOMACCESSTYPEVISITOR_H
1111
1212 #include "llvm/ADT/TinyPtrVector.h"
13 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
1413 #include "llvm/DebugInfo/CodeView/TypeDatabase.h"
1514 #include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h"
16 #include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
1715 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
1816 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
19 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
2017 #include "llvm/Support/Error.h"
2118
2219 namespace llvm {
7269 /// The database visitor which adds new records to the database.
7370 TypeDatabaseVisitor DatabaseVisitor;
7471
75 /// The deserializer which deserializes new records.
76 TypeDeserializer Deserializer;
77
78 /// The visitation callback pipeline to use. By default this contains a
79 /// deserializer and a type database visitor. But the callback specified
80 /// in the constructor is also added.
81 TypeVisitorCallbackPipeline Pipeline;
82
83 /// The visitor used to visit the internal pipeline for deserialization and
84 /// database maintenance.
85 CVTypeVisitor InternalVisitor;
86
8772 /// A vector mapping type indices to type offset. For every record that has
8873 /// been visited, contains the absolute offset of that record in the record
8974 /// array.
5050 HashTable &getHashAdjusters();
5151
5252 codeview::CVTypeRange types(bool *HadError) const;
53 const codeview::CVTypeArray &typeArray() const { return TypeRecords; }
5354
5455 Error commit();
5556
500500 Error E = Reader.readArray(Types, Reader.getLength());
501501 if (!E) {
502502 TypeVisitorCallbacks C;
503 E = CVTypeVisitor(C).visitTypeStream(Types);
503 E = codeview::visitTypeStream(Types, C);
504504 }
505505 if (E) {
506506 logAllUnhandledErrors(std::move(E), errs(), "error: ");
1010 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
1111 #include "llvm/DebugInfo/CodeView/TypeDatabase.h"
1212 #include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h"
13 #include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
1413 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
1514 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
1615 #include "llvm/Support/BinaryByteStream.h"
2019
2120 Error CVTypeDumper::dump(const CVType &Record, TypeVisitorCallbacks &Dumper) {
2221 TypeDatabaseVisitor DBV(TypeDB);
23 TypeDeserializer Deserializer;
2422 TypeVisitorCallbackPipeline Pipeline;
25 Pipeline.addCallbackToPipeline(Deserializer);
2623 Pipeline.addCallbackToPipeline(DBV);
2724 Pipeline.addCallbackToPipeline(Dumper);
2825
29 CVTypeVisitor Visitor(Pipeline);
30 if (Handler)
31 Visitor.addTypeServerHandler(*Handler);
32
3326 CVType RecordCopy = Record;
34 if (auto EC = Visitor.visitTypeRecord(RecordCopy))
35 return EC;
36 return Error::success();
27 return codeview::visitTypeRecord(RecordCopy, Pipeline, VDS_BytesPresent,
28 Handler);
3729 }
3830
3931 Error CVTypeDumper::dump(const CVTypeArray &Types,
4032 TypeVisitorCallbacks &Dumper) {
4133 TypeDatabaseVisitor DBV(TypeDB);
42 TypeDeserializer Deserializer;
4334 TypeVisitorCallbackPipeline Pipeline;
44 Pipeline.addCallbackToPipeline(Deserializer);
4535 Pipeline.addCallbackToPipeline(DBV);
4636 Pipeline.addCallbackToPipeline(Dumper);
4737
48 CVTypeVisitor Visitor(Pipeline);
49 if (Handler)
50 Visitor.addTypeServerHandler(*Handler);
51
52 if (auto EC = Visitor.visitTypeStream(Types))
53 return EC;
54 return Error::success();
38 return codeview::visitTypeStream(Types, Pipeline, Handler);
5539 }
5640
5741 Error CVTypeDumper::dump(ArrayRef Data, TypeVisitorCallbacks &Dumper) {
5858 };
5959
6060 TypeServer2Record R(TypeRecordKind::TypeServer2);
61 TypeDeserializer Deserializer;
6261 StealTypeServerVisitor Thief(R);
63 TypeVisitorCallbackPipeline Pipeline;
64 Pipeline.addCallbackToPipeline(Deserializer);
65 Pipeline.addCallbackToPipeline(Thief);
66 CVTypeVisitor Visitor(Pipeline);
67 if (auto EC = Visitor.visitTypeRecord(Record))
62 if (auto EC = visitTypeRecord(Record, Thief))
6863 return std::move(EC);
6964
7065 return R;
177172 return Error::success();
178173 }
179174
180 Error CVTypeVisitor::visitMemberRecord(CVMemberRecord &Record) {
175 Error CVTypeVisitor::visitMemberRecord(CVMemberRecord Record) {
181176 return ::visitMemberRecord(Record, Callbacks);
182177 }
183178
223218 BinaryStreamReader SR(S);
224219 return visitFieldListMemberStream(SR);
225220 }
221
222 namespace {
223 struct FieldListVisitHelper {
224 FieldListVisitHelper(TypeVisitorCallbacks &Callbacks, ArrayRef Data,
225 VisitorDataSource Source)
226 : Stream(Data, llvm::support::little), Reader(Stream),
227 Deserializer(Reader),
228 Visitor((Source == VDS_BytesPresent) ? Pipeline : Callbacks) {
229 if (Source == VDS_BytesPresent) {
230 Pipeline.addCallbackToPipeline(Deserializer);
231 Pipeline.addCallbackToPipeline(Callbacks);
232 }
233 }
234
235 BinaryByteStream Stream;
236 BinaryStreamReader Reader;
237 FieldListDeserializer Deserializer;
238 TypeVisitorCallbackPipeline Pipeline;
239 CVTypeVisitor Visitor;
240 };
241
242 struct VisitHelper {
243 VisitHelper(TypeVisitorCallbacks &Callbacks, VisitorDataSource Source,
244 TypeServerHandler *TS)
245 : Visitor((Source == VDS_BytesPresent) ? Pipeline : Callbacks) {
246 if (TS)
247 Visitor.addTypeServerHandler(*TS);
248 if (Source == VDS_BytesPresent) {
249 Pipeline.addCallbackToPipeline(Deserializer);
250 Pipeline.addCallbackToPipeline(Callbacks);
251 }
252 }
253
254 TypeDeserializer Deserializer;
255 TypeVisitorCallbackPipeline Pipeline;
256 CVTypeVisitor Visitor;
257 };
258 }
259
260 Error llvm::codeview::visitTypeRecord(CVType &Record, TypeIndex Index,
261 TypeVisitorCallbacks &Callbacks,
262 VisitorDataSource Source,
263 TypeServerHandler *TS) {
264 VisitHelper Helper(Callbacks, Source, TS);
265 return Helper.Visitor.visitTypeRecord(Record, Index);
266 }
267
268 Error llvm::codeview::visitTypeRecord(CVType &Record,
269 TypeVisitorCallbacks &Callbacks,
270 VisitorDataSource Source,
271 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);
280 }
281
282 Error llvm::codeview::visitMemberRecord(CVMemberRecord Record,
283 TypeVisitorCallbacks &Callbacks,
284 VisitorDataSource Source) {
285 FieldListVisitHelper Helper(Callbacks, Record.Data, Source);
286 return Helper.Visitor.visitMemberRecord(Record);
287 }
288
289 Error llvm::codeview::visitMemberRecord(TypeLeafKind Kind,
290 ArrayRef Record,
291 TypeVisitorCallbacks &Callbacks) {
292 CVMemberRecord R;
293 R.Data = Record;
294 R.Kind = Kind;
295 return visitMemberRecord(R, Callbacks, VDS_BytesPresent);
296 }
297
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 }
88
99 #include "llvm/DebugInfo/CodeView/RandomAccessTypeVisitor.h"
1010
11 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
1112 #include "llvm/DebugInfo/CodeView/TypeDatabase.h"
1213 #include "llvm/DebugInfo/CodeView/TypeServerHandler.h"
1314 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
1920 const CVTypeArray &Types, uint32_t NumRecords,
2021 PartialOffsetArray PartialOffsets)
2122 : Database(NumRecords), Types(Types), DatabaseVisitor(Database),
22 InternalVisitor(Pipeline), PartialOffsets(PartialOffsets) {
23 Pipeline.addCallbackToPipeline(Deserializer);
24 Pipeline.addCallbackToPipeline(DatabaseVisitor);
23 PartialOffsets(PartialOffsets) {
2524
2625 KnownOffsets.resize(Database.capacity());
2726 }
3736
3837 assert(Database.contains(TI));
3938 auto &Record = Database.getTypeRecord(TI);
40 CVTypeVisitor V(Callbacks);
41 return V.visitTypeRecord(Record, TI);
39 return codeview::visitTypeRecord(Record, TI, Callbacks);
4240 }
4341
4442 Error RandomAccessTypeVisitor::visitRangeForType(TypeIndex TI) {
7775
7876 while (Begin != End) {
7977 assert(!Database.contains(Begin));
80 if (auto EC = InternalVisitor.visitTypeRecord(*RI, Begin))
78 if (auto EC = codeview::visitTypeRecord(*RI, Begin, DatabaseVisitor))
8179 return EC;
8280 KnownOffsets[Begin.toArrayIndex()] = BeginOffset;
8381
215215
216216 Error TypeDumpVisitor::visitKnownRecord(CVType &CVR,
217217 FieldListRecord &FieldList) {
218 CVTypeVisitor Visitor(*this);
219 if (auto EC = Visitor.visitFieldListMemberStream(FieldList.Data))
218 if (auto EC = codeview::visitMemberRecordStream(FieldList.Data, *this))
220219 return EC;
221220
222221 return Error::success();
360360 // Visit the members inside the field list.
361361 HadUntranslatedMember = false;
362362 FieldListBuilder.begin();
363 CVTypeVisitor Visitor(*this);
364 if (auto EC = Visitor.visitFieldListMemberStream(R.Data))
363 if (auto EC = codeview::visitMemberRecordStream(R.Data, *this))
365364 return EC;
366365
367366 // Write the record if we translated all field list members.
439438
440439 Error TypeStreamMerger::mergeStream(const CVTypeArray &Types) {
441440 assert(IndexMap.empty());
442 TypeVisitorCallbackPipeline Pipeline;
443441 LastError = Error::success();
444442
445 TypeDeserializer Deserializer;
446 Pipeline.addCallbackToPipeline(Deserializer);
447 Pipeline.addCallbackToPipeline(*this);
448
449 CVTypeVisitor Visitor(Pipeline);
450 if (Handler)
451 Visitor.addTypeServerHandler(*Handler);
452
453 if (auto EC = Visitor.visitTypeStream(Types))
443 if (auto EC = codeview::visitTypeStream(Types, *this, Handler))
454444 return EC;
455445
456446 // If we found bad indices but no other errors, try doing another pass and see
465455 IsSecondPass = true;
466456 NumBadIndices = 0;
467457 CurIndex = TypeIndex(TypeIndex::FirstNonSimpleIndex);
468 if (auto EC = Visitor.visitTypeStream(Types))
458
459 if (auto EC = codeview::visitTypeStream(Types, *this, Handler))
469460 return EC;
470461
471462 assert(NumBadIndices <= BadIndicesRemaining &&
5454 auto ExpectedTpi = File.getPDBTpiStream();
5555 if (!ExpectedTpi)
5656 return ExpectedTpi.takeError();
57 CVTypeVisitor Visitor(Callbacks);
5857
59 if (auto EC = Visitor.visitTypeStream(ExpectedTpi->types(nullptr)))
58 if (auto EC = codeview::visitTypeStream(ExpectedTpi->typeArray(), Callbacks))
6059 return std::move(EC);
6160
6261 return true;
7575
7676 TypeDatabase TypeDB(Tpi->getNumTypeRecords());
7777 TypeDatabaseVisitor DBV(TypeDB);
78 TypeDeserializer Deserializer;
7978 TypeVisitorCallbackPipeline Pipeline;
8079 HashLookupVisitor Hasher(*Tpi);
81 // Deserialize the types
82 Pipeline.addCallbackToPipeline(Deserializer);
8380 // Add them to the database
8481 Pipeline.addCallbackToPipeline(DBV);
8582 // Store their hash values
8683 Pipeline.addCallbackToPipeline(Hasher);
8784
88 CVTypeVisitor Visitor(Pipeline);
89
90 bool Error = false;
91 for (auto Item : Tpi->types(&Error)) {
92 if (auto EC = Visitor.visitTypeRecord(Item))
93 return EC;
94 }
95 if (Error)
96 return make_error(raw_error_code::corrupt_file,
97 "TPI stream contained corrupt record");
85 if (auto EC = codeview::visitTypeStream(Tpi->typeArray(), Pipeline))
86 return EC;
9887
9988 auto &Adjusters = Tpi->getHashAdjusters();
10089 DenseSet AdjusterSet;
177177 private:
178178 Error dumpTypeRecord(StringRef Label, TypeDatabase &DB, TypeIndex Index) {
179179 CompactTypeDumpVisitor CTDV(DB, Index, &P);
180 CVTypeVisitor Visitor(CTDV);
181180 DictScope D(P, Label);
182181 if (DB.contains(Index)) {
183182 CVType &Type = DB.getTypeRecord(Index);
184 if (auto EC = Visitor.visitTypeRecord(Type))
183 if (auto EC = codeview::visitTypeRecord(Type, CTDV))
185184 return EC;
186185 } else {
187186 P.printString(
628627
629628 std::vector> Visitors;
630629
631 Visitors.push_back(make_unique());
632630 if (!StreamDB.hasValue()) {
633631 StreamDB.emplace(Tpi->getNumTypeRecords());
634632 Visitors.push_back(make_unique(*StreamDB));
658656 for (const auto &V : Visitors)
659657 Pipeline.addCallbackToPipeline(*V);
660658
661 CVTypeVisitor Visitor(Pipeline);
662
663659 if (DumpRecords || DumpRecordBytes)
664660 RecordScope = llvm::make_unique(P, "Records");
665661
672668 if ((DumpRecords || DumpRecordBytes) && !opts::raw::CompactRecords)
673669 OneRecordScope = llvm::make_unique(P, "");
674670
675 if (auto EC = Visitor.visitTypeRecord(Type))
671 if (auto EC = codeview::visitTypeRecord(Type, Pipeline))
676672 return EC;
677 T.setIndex(T.getIndex() + 1);
673
674 ++T;
678675 }
679676 if (HadError)
680677 return make_error(raw_error_code::corrupt_file,
729726
730727 DB.emplace(Tpi->getNumTypeRecords());
731728
729 TypeDatabaseVisitor DBV(*DB);
730
731 auto HashValues = Tpi->getHashValues();
732 if (HashValues.empty())
733 return codeview::visitTypeStream(Tpi->typeArray(), DBV);
734
732735 TypeVisitorCallbackPipeline Pipeline;
733 TypeDeserializer Deserializer;
734 TypeDatabaseVisitor DBV(*DB);
735 Pipeline.addCallbackToPipeline(Deserializer);
736736 Pipeline.addCallbackToPipeline(DBV);
737737
738 auto HashValues = Tpi->getHashValues();
739 std::unique_ptr HashVerifier;
740 if (!HashValues.empty()) {
741 HashVerifier =
742 make_unique(HashValues, Tpi->getNumHashBuckets());
743 Pipeline.addCallbackToPipeline(*HashVerifier);
744 }
745
746 CVTypeVisitor Visitor(Pipeline);
747 return Visitor.visitTypeStream(Tpi->types(nullptr));
738 TpiHashVerifier HashVerifier(HashValues, Tpi->getNumHashBuckets());
739 Pipeline.addCallbackToPipeline(HashVerifier);
740
741 return codeview::visitTypeStream(Tpi->typeArray(), Pipeline);
748742 }
749743
750744 Error LLVMOutputStyle::dumpDbiStream() {
370370 void MappingContextTraits::
371371 mapping(IO &IO, pdb::yaml::PdbTpiRecord &Obj,
372372 pdb::yaml::SerializationContext &Context) {
373 codeview::TypeVisitorCallbackPipeline Pipeline;
374 codeview::TypeDeserializer Deserializer;
375 codeview::TypeSerializer Serializer(Context.Allocator);
376 pdb::TpiHashUpdater Hasher;
377373
378374 if (IO.outputting()) {
379375 // For PDB to Yaml, deserialize into a high level record type, then dump it.
380 Pipeline.addCallbackToPipeline(Deserializer);
381 Pipeline.addCallbackToPipeline(Context.Dumper);
376 consumeError(codeview::visitTypeRecord(Obj.Record, Context.Dumper));
382377 } else {
378 codeview::TypeVisitorCallbackPipeline Pipeline;
379 codeview::TypeSerializer Serializer(Context.Allocator);
380 pdb::TpiHashUpdater Hasher;
383381 // For Yaml to PDB, extract from the high level record type, then write it
384382 // to bytes.
385383
390388 Pipeline.addCallbackToPipeline(Context.Dumper);
391389 Pipeline.addCallbackToPipeline(Serializer);
392390 Pipeline.addCallbackToPipeline(Hasher);
393 }
394
395 codeview::CVTypeVisitor Visitor(Pipeline);
396 consumeError(Visitor.visitTypeRecord(Obj.Record));
391 consumeError(codeview::visitTypeRecord(Obj.Record, Pipeline,
392 codeview::VDS_BytesExternal));
393 }
394
397395 Context.ActiveSerializer = nullptr;
398396 }
279279
280280 void MappingContextTraits::mapping(
281281 IO &IO, CVType &Record, pdb::yaml::SerializationContext &Context) {
282 if (IO.outputting()) {
283 codeview::TypeDeserializer Deserializer;
284
285 codeview::TypeVisitorCallbackPipeline Pipeline;
286 Pipeline.addCallbackToPipeline(Deserializer);
287 Pipeline.addCallbackToPipeline(Context.Dumper);
288
289 codeview::CVTypeVisitor Visitor(Pipeline);
290 consumeError(Visitor.visitTypeRecord(Record));
291 }
282 if (IO.outputting())
283 consumeError(codeview::visitTypeRecord(Record, Context.Dumper));
292284 }
293285
294286 void MappingTraits::mapping(IO &IO, StringIdRecord &String) {
555547 // (top-level and member fields all have the exact same Yaml syntax so use
556548 // the same parser).
557549 FieldListRecordSplitter Splitter(FieldListRecords);
558 CVTypeVisitor V(Splitter);
559 consumeError(V.visitFieldListMemberStream(FieldList.Data));
560 YamlIO.mapRequired("FieldList", FieldListRecords, Context);
561 } else {
562 // If we are not outputting, then the array contains no data starting out,
563 // and is instead populated from the sequence represented by the yaml --
564 // again, using the same logic that we use for top-level records.
565 assert(Context.ActiveSerializer && "There is no active serializer!");
566 codeview::TypeVisitorCallbackPipeline Pipeline;
567 pdb::TpiHashUpdater Hasher;
568
569 // For Yaml to PDB, dump it (to fill out the record fields from the Yaml)
570 // then serialize those fields to bytes, then update their hashes.
571 Pipeline.addCallbackToPipeline(Context.Dumper);
572 Pipeline.addCallbackToPipeline(*Context.ActiveSerializer);
573 Pipeline.addCallbackToPipeline(Hasher);
574
575 codeview::CVTypeVisitor Visitor(Pipeline);
576 YamlIO.mapRequired("FieldList", FieldListRecords, Visitor);
577 }
550 consumeError(codeview::visitMemberRecordStream(FieldList.Data, Splitter));
551 }
552 // Note that if we're not outputting (i.e. Yaml -> PDB) the result of this
553 // mapping gets lost, as the records are simply stored in this locally scoped
554 // vector. What's important though is they are all sharing a single
555 // Serializer
556 // instance (in `Context.ActiveSerializer`), and that is building up a list of
557 // all the types. The fact that we need a throwaway vector here is just to
558 // appease the YAML API to treat this as a sequence and do this mapping once
559 // for each YAML Sequence element in the input Yaml stream.
560 YamlIO.mapRequired("FieldList", FieldListRecords, Context);
578561 }
579562
580563 namespace llvm {
584567 pdb::yaml::SerializationContext> {
585568 static void mapping(IO &IO, pdb::yaml::PdbTpiFieldListRecord &Obj,
586569 pdb::yaml::SerializationContext &Context) {
587 assert(IO.outputting());
588 codeview::TypeVisitorCallbackPipeline Pipeline;
589
590 BinaryByteStream Data(Obj.Record.Data, llvm::support::little);
591 BinaryStreamReader FieldReader(Data);
592 codeview::FieldListDeserializer Deserializer(FieldReader);
593
594 // For PDB to Yaml, deserialize into a high level record type, then dump
595 // it.
596 Pipeline.addCallbackToPipeline(Deserializer);
597 Pipeline.addCallbackToPipeline(Context.Dumper);
598
599 codeview::CVTypeVisitor Visitor(Pipeline);
600 consumeError(Visitor.visitMemberRecord(Obj.Record));
601 }
602 };
603
604 template <>
605 struct MappingContextTraits
606 codeview::CVTypeVisitor> {
607 static void mapping(IO &IO, pdb::yaml::PdbTpiFieldListRecord &Obj,
608 codeview::CVTypeVisitor &Visitor) {
609 consumeError(Visitor.visitMemberRecord(Obj.Record));
610 }
611 };
612 }
613 }
570 if (IO.outputting())
571 consumeError(codeview::visitMemberRecord(Obj.Record, Context.Dumper));
572 else {
573 // If we are not outputting, then the array contains no data starting out,
574 // and is instead populated from the sequence represented by the yaml --
575 // again, using the same logic that we use for top-level records.
576 assert(Context.ActiveSerializer && "There is no active serializer!");
577 codeview::TypeVisitorCallbackPipeline Pipeline;
578 pdb::TpiHashUpdater Hasher;
579
580 Pipeline.addCallbackToPipeline(Context.Dumper);
581 Pipeline.addCallbackToPipeline(*Context.ActiveSerializer);
582 Pipeline.addCallbackToPipeline(Hasher);
583 consumeError(
584 codeview::visitMemberRecord(Obj.Record, Pipeline, VDS_BytesExternal));
585 }
586 }
587 };
588 }
589 }
1111 #include "llvm/ADT/SmallBitVector.h"
1212 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
1313 #include "llvm/DebugInfo/CodeView/RandomAccessTypeVisitor.h"
14 #include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
1415 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
1516 #include "llvm/DebugInfo/CodeView/TypeRecordMapping.h"
1617 #include "llvm/DebugInfo/CodeView/TypeSerializer.h"
125125
126126 Pipeline.addCallbackToPipeline(C1);
127127 Pipeline.addCallbackToPipeline(C2);
128 CVTypeVisitor Visitor(Pipeline);
129 EXPECT_NO_ERROR(Visitor.visitTypeRecord(TypeServerRecord));
128
129 EXPECT_NO_ERROR(codeview::visitTypeRecord(TypeServerRecord, Pipeline));
130130
131131 EXPECT_EQ(MockTypeVisitorCallbacks::State::VisitTypeEnd, C1.S);
132132 EXPECT_EQ(MockTypeVisitorCallbacks::State::VisitTypeEnd, C2.S);
138138 MockTypeServerHandler Handler(false);
139139
140140 MockTypeVisitorCallbacks C1;
141 CVTypeVisitor Visitor(C1);
142 Visitor.addTypeServerHandler(Handler);
143141
144142 // Our mock server returns true the first time.
145 EXPECT_NO_ERROR(Visitor.visitTypeRecord(TypeServerRecord));
143 EXPECT_NO_ERROR(codeview::visitTypeRecord(
144 TypeServerRecord, C1, codeview::VDS_BytesExternal, &Handler));
146145 EXPECT_TRUE(Handler.Handled);
147146 EXPECT_EQ(MockTypeVisitorCallbacks::State::Ready, C1.S);
148147
149148 // And false the second time.
150 EXPECT_NO_ERROR(Visitor.visitTypeRecord(TypeServerRecord));
149 EXPECT_NO_ERROR(codeview::visitTypeRecord(
150 TypeServerRecord, C1, codeview::VDS_BytesExternal, &Handler));
151151 EXPECT_TRUE(Handler.Handled);
152152 EXPECT_EQ(MockTypeVisitorCallbacks::State::VisitTypeEnd, C1.S);
153153 }
159159 MockTypeServerHandler Handler(true);
160160
161161 MockTypeVisitorCallbacks C1;
162 CVTypeVisitor Visitor(C1);
163 Visitor.addTypeServerHandler(Handler);
164162
165 EXPECT_NO_ERROR(Visitor.visitTypeRecord(TypeServerRecord));
163 EXPECT_NO_ERROR(codeview::visitTypeRecord(
164 TypeServerRecord, C1, codeview::VDS_BytesExternal, &Handler));
166165 EXPECT_TRUE(Handler.Handled);
167166 EXPECT_EQ(MockTypeVisitorCallbacks::State::Ready, C1.S);
168167
169 EXPECT_NO_ERROR(Visitor.visitTypeRecord(TypeServerRecord));
168 EXPECT_NO_ERROR(codeview::visitTypeRecord(
169 TypeServerRecord, C1, codeview::VDS_BytesExternal, &Handler));
170170 EXPECT_TRUE(Handler.Handled);
171171 EXPECT_EQ(MockTypeVisitorCallbacks::State::Ready, C1.S);
172172 }