static Expected<TypeServer2Record> deserializeTypeServerRecord(CVType &Record) { class StealTypeServerVisitor : public TypeVisitorCallbacks { public: explicit StealTypeServerVisitor(TypeServer2Record &TR) : TR(TR) {} Error visitKnownRecord(CVType &CVR, TypeServer2Record &Record) override { TR = Record; return Error::success(); } private: TypeServer2Record &TR; }; TypeServer2Record R(TypeRecordKind::TypeServer2); TypeDeserializer Deserializer; StealTypeServerVisitor Thief(R); TypeVisitorCallbackPipeline Pipeline; Pipeline.addCallbackToPipeline(Deserializer); Pipeline.addCallbackToPipeline(Thief); CVTypeVisitor Visitor(Pipeline); if (auto EC = Visitor.visitTypeRecord(Record)) return std::move(EC); return R; }
Error CVTypeDumper::dump(const CVTypeArray &Types, TypeVisitorCallbacks &Dumper) { TypeDatabaseVisitor DBV(TypeDB); TypeDeserializer Deserializer; TypeVisitorCallbackPipeline Pipeline; Pipeline.addCallbackToPipeline(Deserializer); Pipeline.addCallbackToPipeline(DBV); Pipeline.addCallbackToPipeline(Dumper); CVTypeVisitor Visitor(Pipeline); if (Handler) Visitor.addTypeServerHandler(*Handler); if (auto EC = Visitor.visitTypeStream(Types)) return EC; return Error::success(); }
Error CVTypeVisitor::visitFieldListMemberStream(BinaryStreamReader Reader) { FieldListDeserializer Deserializer(Reader); TypeVisitorCallbackPipeline Pipeline; Pipeline.addCallbackToPipeline(Deserializer); Pipeline.addCallbackToPipeline(Callbacks); TypeLeafKind Leaf; while (!Reader.empty()) { if (auto EC = Reader.readEnum(Leaf)) return EC; CVMemberRecord Record; Record.Kind = Leaf; if (auto EC = ::visitMemberRecord(Record, Pipeline)) return EC; } return Error::success(); }
Error AnalysisStyle::dump() { auto Tpi = File.getPDBTpiStream(); if (!Tpi) return Tpi.takeError(); TypeDatabase TypeDB(Tpi->getNumTypeRecords()); TypeDatabaseVisitor DBV(TypeDB); TypeVisitorCallbackPipeline Pipeline; HashLookupVisitor Hasher(*Tpi); // Add them to the database Pipeline.addCallbackToPipeline(DBV); // Store their hash values Pipeline.addCallbackToPipeline(Hasher); if (auto EC = codeview::visitTypeStream(Tpi->typeArray(), Pipeline)) return EC; auto &Adjusters = Tpi->getHashAdjusters(); DenseSet<uint32_t> AdjusterSet; for (const auto &Adj : Adjusters) { assert(AdjusterSet.find(Adj.second) == AdjusterSet.end()); AdjusterSet.insert(Adj.second); } uint32_t Count = 0; outs() << "Searching for hash collisions\n"; for (const auto &H : Hasher.Lookup) { if (H.second.size() <= 1) continue; ++Count; outs() << formatv("Hash: {0}, Count: {1} records\n", H.first, H.second.size()); for (const auto &R : H.second) { auto Iter = AdjusterSet.find(R.TI.getIndex()); StringRef Prefix; if (Iter != AdjusterSet.end()) { Prefix = "[HEAD]"; AdjusterSet.erase(Iter); } StringRef LeafName = getLeafTypeName(R.Record.Type); uint32_t TI = R.TI.getIndex(); StringRef TypeName = TypeDB.getTypeName(R.TI); outs() << formatv("{0,-6} {1} ({2:x}) {3}\n", Prefix, LeafName, TI, TypeName); } } outs() << "\n"; outs() << "Dumping hash adjustment chains\n"; for (const auto &A : Tpi->getHashAdjusters()) { TypeIndex TI(A.second); StringRef TypeName = TypeDB.getTypeName(TI); const CVType &HeadRecord = TypeDB.getTypeRecord(TI); assert(HeadRecord.Hash.hasValue()); auto CollisionsIter = Hasher.Lookup.find(*HeadRecord.Hash); if (CollisionsIter == Hasher.Lookup.end()) continue; const auto &Collisions = CollisionsIter->second; outs() << TypeName << "\n"; outs() << formatv(" [HEAD] {0:x} {1} {2}\n", A.second, getLeafTypeName(HeadRecord.Type), TypeName); for (const auto &Chain : Collisions) { if (Chain.TI == TI) continue; const CVType &TailRecord = TypeDB.getTypeRecord(Chain.TI); outs() << formatv(" {0:x} {1} {2}\n", Chain.TI.getIndex(), getLeafTypeName(TailRecord.Type), TypeDB.getTypeName(Chain.TI)); } } outs() << formatv("There are {0} orphaned hash adjusters\n", AdjusterSet.size()); for (const auto &Adj : AdjusterSet) { outs() << formatv(" {0}\n", Adj); } uint32_t DistinctHashValues = Hasher.Lookup.size(); outs() << formatv("{0}/{1} hash collisions", Count, DistinctHashValues); return Error::success(); }