forked from OSchip/llvm-project
Implement various flavors of type merging.
Previous algotirhm assumed that types and ids are in a single unified stream. For inputs that come from object files, this is the case. But if the input is already a PDB, or is the result of a previous merge, then the types and ids will already have been split up, in which case we need an algorithm that can accept operate on independent streams of types and ids that refer across stream boundaries to each other. Differential Revision: https://reviews.llvm.org/D33417 llvm-svn: 303577
This commit is contained in:
parent
12f8c31c04
commit
d4136e945e
|
@ -117,8 +117,9 @@ static void mergeDebugT(SymbolTable *Symtab, pdb::PDBFileBuilder &Builder,
|
|||
Handler.addSearchPath(llvm::sys::path::parent_path(File->getName()));
|
||||
if (auto EC = Reader.readArray(Types, Reader.getLength()))
|
||||
fatal(EC, "Reader::readArray failed");
|
||||
if (auto Err = codeview::mergeTypeStreams(IDTable, TypeTable, SourceToDest,
|
||||
&Handler, Types))
|
||||
codeview::LazyRandomTypeCollection TypesAndIds(Types, 100);
|
||||
if (auto Err = codeview::mergeTypeAndIdRecords(
|
||||
IDTable, TypeTable, SourceToDest, &Handler, TypesAndIds))
|
||||
fatal(Err, "codeview::mergeTypeStreams failed");
|
||||
}
|
||||
|
||||
|
|
|
@ -22,11 +22,74 @@ class TypeIndex;
|
|||
class TypeServerHandler;
|
||||
class TypeTableBuilder;
|
||||
|
||||
/// Merges one type stream into another. Returns true on success.
|
||||
Error mergeTypeStreams(TypeTableBuilder &DestIdStream,
|
||||
TypeTableBuilder &DestTypeStream,
|
||||
/// \brief Merge one set of type records into another. This method assumes
|
||||
/// that all records are type records, and there are no Id records present.
|
||||
///
|
||||
/// \param Dest The table to store the re-written type records into.
|
||||
///
|
||||
/// \param SourceToDest A vector, indexed by the TypeIndex in the source
|
||||
/// type stream, that contains the index of the corresponding type record
|
||||
/// in the destination stream.
|
||||
///
|
||||
/// \param Handler (optional) If non-null, an interface that gets invoked
|
||||
/// to handle type server records.
|
||||
///
|
||||
/// \param Types The collection of types to merge in.
|
||||
///
|
||||
/// \returns Error::success() if the operation succeeded, otherwise an
|
||||
/// appropriate error code.
|
||||
Error mergeTypeRecords(TypeTableBuilder &Dest,
|
||||
SmallVectorImpl<TypeIndex> &SourceToDest,
|
||||
TypeServerHandler *Handler, const CVTypeArray &Types);
|
||||
TypeServerHandler *Handler, TypeCollection &Types);
|
||||
|
||||
/// \brief Merge one set of id records into another. This method assumes
|
||||
/// that all records are id records, and there are no Type records present.
|
||||
/// However, since Id records can refer back to Type records, this method
|
||||
/// assumes that the referenced type records have also been merged into
|
||||
/// another type stream (for example using the above method), and accepts
|
||||
/// the mapping from source to dest for that stream so that it can re-write
|
||||
/// the type record mappings accordingly.
|
||||
///
|
||||
/// \param Dest The table to store the re-written id records into.
|
||||
///
|
||||
/// \param Types The mapping to use for the type records that these id
|
||||
/// records refer to.
|
||||
///
|
||||
/// \param SourceToDest A vector, indexed by the TypeIndex in the source
|
||||
/// id stream, that contains the index of the corresponding id record
|
||||
/// in the destination stream.
|
||||
///
|
||||
/// \param Types The collection of id records to merge in.
|
||||
///
|
||||
/// \returns Error::success() if the operation succeeded, otherwise an
|
||||
/// appropriate error code.
|
||||
Error mergeIdRecords(TypeTableBuilder &Dest, ArrayRef<TypeIndex> Types,
|
||||
SmallVectorImpl<TypeIndex> &SourceToDest,
|
||||
TypeCollection &Ids);
|
||||
|
||||
/// \brief Merge a unified set of type and id records, splitting them into
|
||||
/// separate output streams.
|
||||
///
|
||||
/// \param DestIds The table to store the re-written id records into.
|
||||
///
|
||||
/// \param DestTypes the table to store the re-written type records into.
|
||||
///
|
||||
/// \param SourceToDest A vector, indexed by the TypeIndex in the source
|
||||
/// id stream, that contains the index of the corresponding id record
|
||||
/// in the destination stream.
|
||||
///
|
||||
/// \param Handler (optional) If non-null, an interface that gets invoked
|
||||
/// to handle type server records.
|
||||
///
|
||||
/// \param IdsAndTypes The collection of id records to merge in.
|
||||
///
|
||||
/// \returns Error::success() if the operation succeeded, otherwise an
|
||||
/// appropriate error code.
|
||||
Error mergeTypeAndIdRecords(TypeTableBuilder &DestIds,
|
||||
TypeTableBuilder &DestTypes,
|
||||
SmallVectorImpl<TypeIndex> &SourceToDest,
|
||||
TypeServerHandler *Handler,
|
||||
TypeCollection &IdsAndTypes);
|
||||
|
||||
} // end namespace codeview
|
||||
} // end namespace llvm
|
||||
|
|
|
@ -21,6 +21,9 @@
|
|||
#include "llvm/Support/Error.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace codeview {
|
||||
class LazyRandomTypeCollection;
|
||||
}
|
||||
namespace msf {
|
||||
class MappedBlockStream;
|
||||
}
|
||||
|
@ -53,12 +56,16 @@ public:
|
|||
codeview::CVTypeRange types(bool *HadError) const;
|
||||
const codeview::CVTypeArray &typeArray() const { return TypeRecords; }
|
||||
|
||||
codeview::LazyRandomTypeCollection &typeCollection() { return *Types; }
|
||||
|
||||
Error commit();
|
||||
|
||||
private:
|
||||
const PDBFile &Pdb;
|
||||
std::unique_ptr<msf::MappedBlockStream> Stream;
|
||||
|
||||
std::unique_ptr<codeview::LazyRandomTypeCollection> Types;
|
||||
|
||||
codeview::CVTypeArray TypeRecords;
|
||||
|
||||
std::unique_ptr<BinaryStream> HashStream;
|
||||
|
|
|
@ -57,13 +57,11 @@ namespace {
|
|||
/// looking at the record kind.
|
||||
class TypeStreamMerger : public TypeVisitorCallbacks {
|
||||
public:
|
||||
TypeStreamMerger(TypeTableBuilder &DestIdStream,
|
||||
TypeTableBuilder &DestTypeStream,
|
||||
SmallVectorImpl<TypeIndex> &SourceToDest,
|
||||
TypeServerHandler *Handler)
|
||||
: DestIdStream(DestIdStream), DestTypeStream(DestTypeStream),
|
||||
FieldListBuilder(DestTypeStream), Handler(Handler),
|
||||
IndexMap(SourceToDest) {}
|
||||
explicit TypeStreamMerger(SmallVectorImpl<TypeIndex> &SourceToDest,
|
||||
TypeServerHandler *Handler)
|
||||
: Handler(Handler), IndexMap(SourceToDest) {
|
||||
SourceToDest.clear();
|
||||
}
|
||||
|
||||
static const TypeIndex Untranslated;
|
||||
|
||||
|
@ -82,12 +80,22 @@ public:
|
|||
Error visitTypeEnd(CVType &Record) override;
|
||||
Error visitMemberEnd(CVMemberRecord &Record) override;
|
||||
|
||||
Error mergeStream(const CVTypeArray &Types);
|
||||
Error mergeTypesAndIds(TypeTableBuilder &DestIds, TypeTableBuilder &DestTypes,
|
||||
TypeCollection &IdsAndTypes);
|
||||
Error mergeIdRecords(TypeTableBuilder &Dest,
|
||||
ArrayRef<TypeIndex> TypeSourceToDest,
|
||||
TypeCollection &Ids);
|
||||
Error mergeTypeRecords(TypeTableBuilder &Dest, TypeCollection &Types);
|
||||
|
||||
private:
|
||||
Error doit(TypeCollection &Types);
|
||||
|
||||
void addMapping(TypeIndex Idx);
|
||||
|
||||
bool remapIndex(TypeIndex &Idx);
|
||||
bool remapTypeIndex(TypeIndex &Idx);
|
||||
bool remapItemIndex(TypeIndex &Idx);
|
||||
|
||||
bool remapIndex(TypeIndex &Idx, ArrayRef<TypeIndex> Map);
|
||||
|
||||
size_t slotForIndex(TypeIndex Idx) const {
|
||||
assert(!Idx.isSimple() && "simple type indices have no slots");
|
||||
|
@ -102,7 +110,7 @@ private:
|
|||
Error writeRecord(RecordType &R, bool RemapSuccess) {
|
||||
TypeIndex DestIdx = Untranslated;
|
||||
if (RemapSuccess)
|
||||
DestIdx = DestTypeStream.writeKnownType(R);
|
||||
DestIdx = DestTypeStream->writeKnownType(R);
|
||||
addMapping(DestIdx);
|
||||
return Error::success();
|
||||
}
|
||||
|
@ -111,7 +119,7 @@ private:
|
|||
Error writeIdRecord(RecordType &R, bool RemapSuccess) {
|
||||
TypeIndex DestIdx = Untranslated;
|
||||
if (RemapSuccess)
|
||||
DestIdx = DestIdStream.writeKnownType(R);
|
||||
DestIdx = DestIdStream->writeKnownType(R);
|
||||
addMapping(DestIdx);
|
||||
return Error::success();
|
||||
}
|
||||
|
@ -119,7 +127,7 @@ private:
|
|||
template <typename RecordType>
|
||||
Error writeMember(RecordType &R, bool RemapSuccess) {
|
||||
if (RemapSuccess)
|
||||
FieldListBuilder.writeMemberType(R);
|
||||
FieldListBuilder->writeMemberType(R);
|
||||
else
|
||||
HadUntranslatedMember = true;
|
||||
return Error::success();
|
||||
|
@ -135,13 +143,17 @@ private:
|
|||
|
||||
BumpPtrAllocator Allocator;
|
||||
|
||||
TypeTableBuilder &DestIdStream;
|
||||
TypeTableBuilder &DestTypeStream;
|
||||
FieldListRecordBuilder FieldListBuilder;
|
||||
TypeServerHandler *Handler;
|
||||
|
||||
TypeIndex CurIndex{TypeIndex::FirstNonSimpleIndex};
|
||||
|
||||
TypeTableBuilder *DestIdStream = nullptr;
|
||||
TypeTableBuilder *DestTypeStream = nullptr;
|
||||
std::unique_ptr<FieldListRecordBuilder> FieldListBuilder;
|
||||
TypeServerHandler *Handler = nullptr;
|
||||
|
||||
// If we're only mapping id records, this array contains the mapping for
|
||||
// type records.
|
||||
ArrayRef<TypeIndex> TypeLookup;
|
||||
|
||||
/// Map from source type index to destination type index. Indexed by source
|
||||
/// type index minus 0x1000.
|
||||
SmallVectorImpl<TypeIndex> &IndexMap;
|
||||
|
@ -178,7 +190,7 @@ void TypeStreamMerger::addMapping(TypeIndex Idx) {
|
|||
}
|
||||
}
|
||||
|
||||
bool TypeStreamMerger::remapIndex(TypeIndex &Idx) {
|
||||
bool TypeStreamMerger::remapIndex(TypeIndex &Idx, ArrayRef<TypeIndex> Map) {
|
||||
// Simple types are unchanged.
|
||||
if (Idx.isSimple())
|
||||
return true;
|
||||
|
@ -187,14 +199,14 @@ bool TypeStreamMerger::remapIndex(TypeIndex &Idx) {
|
|||
// successfully. If it refers to a type later in the stream or a record we
|
||||
// had to defer, defer it until later pass.
|
||||
unsigned MapPos = slotForIndex(Idx);
|
||||
if (MapPos < IndexMap.size() && IndexMap[MapPos] != Untranslated) {
|
||||
Idx = IndexMap[MapPos];
|
||||
if (MapPos < Map.size() && Map[MapPos] != Untranslated) {
|
||||
Idx = Map[MapPos];
|
||||
return true;
|
||||
}
|
||||
|
||||
// If this is the second pass and this index isn't in the map, then it points
|
||||
// outside the current type stream, and this is a corrupt record.
|
||||
if (IsSecondPass && MapPos >= IndexMap.size()) {
|
||||
if (IsSecondPass && MapPos >= Map.size()) {
|
||||
// FIXME: Print a more useful error. We can give the current record and the
|
||||
// index that we think its pointing to.
|
||||
LastError = joinErrors(std::move(*LastError), errorCorruptRecord());
|
||||
|
@ -208,55 +220,82 @@ bool TypeStreamMerger::remapIndex(TypeIndex &Idx) {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool TypeStreamMerger::remapTypeIndex(TypeIndex &Idx) {
|
||||
// If we're mapping a pure index stream, then IndexMap only contains mappings
|
||||
// from OldIdStream -> NewIdStream, in which case we will need to use the
|
||||
// special mapping from OldTypeStream -> NewTypeStream which was computed
|
||||
// externally. Regardless, we use this special map if and only if we are
|
||||
// doing an id-only mapping.
|
||||
if (DestTypeStream == nullptr)
|
||||
return remapIndex(Idx, TypeLookup);
|
||||
|
||||
assert(TypeLookup.empty());
|
||||
return remapIndex(Idx, IndexMap);
|
||||
}
|
||||
|
||||
bool TypeStreamMerger::remapItemIndex(TypeIndex &Idx) {
|
||||
assert(DestIdStream);
|
||||
return remapIndex(Idx, IndexMap);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
// Item records
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
Error TypeStreamMerger::visitKnownRecord(CVType &, FuncIdRecord &R) {
|
||||
assert(DestIdStream);
|
||||
bool Success = true;
|
||||
Success &= remapIndex(R.ParentScope);
|
||||
Success &= remapIndex(R.FunctionType);
|
||||
Success &= remapItemIndex(R.ParentScope);
|
||||
Success &= remapTypeIndex(R.FunctionType);
|
||||
return writeIdRecord(R, Success);
|
||||
}
|
||||
|
||||
Error TypeStreamMerger::visitKnownRecord(CVType &, MemberFuncIdRecord &R) {
|
||||
assert(DestIdStream);
|
||||
bool Success = true;
|
||||
Success &= remapIndex(R.ClassType);
|
||||
Success &= remapIndex(R.FunctionType);
|
||||
Success &= remapTypeIndex(R.ClassType);
|
||||
Success &= remapTypeIndex(R.FunctionType);
|
||||
return writeIdRecord(R, Success);
|
||||
}
|
||||
|
||||
Error TypeStreamMerger::visitKnownRecord(CVType &, StringIdRecord &R) {
|
||||
return writeIdRecord(R, remapIndex(R.Id));
|
||||
assert(DestIdStream);
|
||||
return writeIdRecord(R, remapItemIndex(R.Id));
|
||||
}
|
||||
|
||||
Error TypeStreamMerger::visitKnownRecord(CVType &, StringListRecord &R) {
|
||||
assert(DestIdStream);
|
||||
bool Success = true;
|
||||
for (TypeIndex &Str : R.StringIndices)
|
||||
Success &= remapIndex(Str);
|
||||
Success &= remapItemIndex(Str);
|
||||
return writeIdRecord(R, Success);
|
||||
}
|
||||
|
||||
Error TypeStreamMerger::visitKnownRecord(CVType &, BuildInfoRecord &R) {
|
||||
assert(DestIdStream);
|
||||
bool Success = true;
|
||||
for (TypeIndex &Arg : R.ArgIndices)
|
||||
Success &= remapIndex(Arg);
|
||||
Success &= remapItemIndex(Arg);
|
||||
return writeIdRecord(R, Success);
|
||||
}
|
||||
|
||||
Error TypeStreamMerger::visitKnownRecord(CVType &, UdtSourceLineRecord &R) {
|
||||
assert(DestIdStream);
|
||||
bool Success = true;
|
||||
Success &= remapIndex(R.UDT);
|
||||
Success &= remapIndex(R.SourceFile);
|
||||
Success &= remapTypeIndex(R.UDT);
|
||||
Success &= remapItemIndex(R.SourceFile);
|
||||
// FIXME: Translate UdtSourceLineRecord into UdtModSourceLineRecords in the
|
||||
// IPI stream.
|
||||
return writeIdRecord(R, Success);
|
||||
}
|
||||
|
||||
Error TypeStreamMerger::visitKnownRecord(CVType &, UdtModSourceLineRecord &R) {
|
||||
assert(DestIdStream);
|
||||
bool Success = true;
|
||||
Success &= remapIndex(R.UDT);
|
||||
Success &= remapIndex(R.SourceFile);
|
||||
Success &= remapTypeIndex(R.UDT);
|
||||
// UdtModSourceLine Source File Ids are offsets into the global string table.
|
||||
// FIXME: We need to merge string table records for this to be valid.
|
||||
// Success &= remapItemIndex(R.SourceFile);
|
||||
return writeIdRecord(R, Success);
|
||||
}
|
||||
|
||||
|
@ -265,112 +304,128 @@ Error TypeStreamMerger::visitKnownRecord(CVType &, UdtModSourceLineRecord &R) {
|
|||
//----------------------------------------------------------------------------//
|
||||
|
||||
Error TypeStreamMerger::visitKnownRecord(CVType &, ModifierRecord &R) {
|
||||
return writeRecord(R, remapIndex(R.ModifiedType));
|
||||
assert(DestTypeStream);
|
||||
return writeRecord(R, remapTypeIndex(R.ModifiedType));
|
||||
}
|
||||
|
||||
Error TypeStreamMerger::visitKnownRecord(CVType &, ProcedureRecord &R) {
|
||||
assert(DestTypeStream);
|
||||
bool Success = true;
|
||||
Success &= remapIndex(R.ReturnType);
|
||||
Success &= remapIndex(R.ArgumentList);
|
||||
Success &= remapTypeIndex(R.ReturnType);
|
||||
Success &= remapTypeIndex(R.ArgumentList);
|
||||
return writeRecord(R, Success);
|
||||
}
|
||||
|
||||
Error TypeStreamMerger::visitKnownRecord(CVType &, MemberFunctionRecord &R) {
|
||||
assert(DestTypeStream);
|
||||
bool Success = true;
|
||||
Success &= remapIndex(R.ReturnType);
|
||||
Success &= remapIndex(R.ClassType);
|
||||
Success &= remapIndex(R.ThisType);
|
||||
Success &= remapIndex(R.ArgumentList);
|
||||
Success &= remapTypeIndex(R.ReturnType);
|
||||
Success &= remapTypeIndex(R.ClassType);
|
||||
Success &= remapTypeIndex(R.ThisType);
|
||||
Success &= remapTypeIndex(R.ArgumentList);
|
||||
return writeRecord(R, Success);
|
||||
}
|
||||
|
||||
Error TypeStreamMerger::visitKnownRecord(CVType &Type, ArgListRecord &R) {
|
||||
assert(DestTypeStream);
|
||||
bool Success = true;
|
||||
for (TypeIndex &Arg : R.ArgIndices)
|
||||
Success &= remapIndex(Arg);
|
||||
Success &= remapTypeIndex(Arg);
|
||||
if (auto EC = writeRecord(R, Success))
|
||||
return EC;
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error TypeStreamMerger::visitKnownRecord(CVType &, PointerRecord &R) {
|
||||
assert(DestTypeStream);
|
||||
bool Success = true;
|
||||
Success &= remapIndex(R.ReferentType);
|
||||
Success &= remapTypeIndex(R.ReferentType);
|
||||
if (R.isPointerToMember())
|
||||
Success &= remapIndex(R.MemberInfo->ContainingType);
|
||||
Success &= remapTypeIndex(R.MemberInfo->ContainingType);
|
||||
return writeRecord(R, Success);
|
||||
}
|
||||
|
||||
Error TypeStreamMerger::visitKnownRecord(CVType &, ArrayRecord &R) {
|
||||
assert(DestTypeStream);
|
||||
bool Success = true;
|
||||
Success &= remapIndex(R.ElementType);
|
||||
Success &= remapIndex(R.IndexType);
|
||||
Success &= remapTypeIndex(R.ElementType);
|
||||
Success &= remapTypeIndex(R.IndexType);
|
||||
return writeRecord(R, Success);
|
||||
}
|
||||
|
||||
Error TypeStreamMerger::visitKnownRecord(CVType &, ClassRecord &R) {
|
||||
assert(DestTypeStream);
|
||||
bool Success = true;
|
||||
Success &= remapIndex(R.FieldList);
|
||||
Success &= remapIndex(R.DerivationList);
|
||||
Success &= remapIndex(R.VTableShape);
|
||||
Success &= remapTypeIndex(R.FieldList);
|
||||
Success &= remapTypeIndex(R.DerivationList);
|
||||
Success &= remapTypeIndex(R.VTableShape);
|
||||
return writeRecord(R, Success);
|
||||
}
|
||||
|
||||
Error TypeStreamMerger::visitKnownRecord(CVType &, UnionRecord &R) {
|
||||
return writeRecord(R, remapIndex(R.FieldList));
|
||||
assert(DestTypeStream);
|
||||
return writeRecord(R, remapTypeIndex(R.FieldList));
|
||||
}
|
||||
|
||||
Error TypeStreamMerger::visitKnownRecord(CVType &, EnumRecord &R) {
|
||||
assert(DestTypeStream);
|
||||
bool Success = true;
|
||||
Success &= remapIndex(R.FieldList);
|
||||
Success &= remapIndex(R.UnderlyingType);
|
||||
Success &= remapTypeIndex(R.FieldList);
|
||||
Success &= remapTypeIndex(R.UnderlyingType);
|
||||
return writeRecord(R, Success);
|
||||
}
|
||||
|
||||
Error TypeStreamMerger::visitKnownRecord(CVType &, BitFieldRecord &R) {
|
||||
return writeRecord(R, remapIndex(R.Type));
|
||||
assert(DestTypeStream);
|
||||
return writeRecord(R, remapTypeIndex(R.Type));
|
||||
}
|
||||
|
||||
Error TypeStreamMerger::visitKnownRecord(CVType &, VFTableShapeRecord &R) {
|
||||
assert(DestTypeStream);
|
||||
return writeRecord(R, true);
|
||||
}
|
||||
|
||||
Error TypeStreamMerger::visitKnownRecord(CVType &, TypeServer2Record &R) {
|
||||
assert(DestTypeStream);
|
||||
return writeRecord(R, true);
|
||||
}
|
||||
|
||||
Error TypeStreamMerger::visitKnownRecord(CVType &, LabelRecord &R) {
|
||||
assert(DestTypeStream);
|
||||
return writeRecord(R, true);
|
||||
}
|
||||
|
||||
Error TypeStreamMerger::visitKnownRecord(CVType &, VFTableRecord &R) {
|
||||
assert(DestTypeStream);
|
||||
bool Success = true;
|
||||
Success &= remapIndex(R.CompleteClass);
|
||||
Success &= remapIndex(R.OverriddenVFTable);
|
||||
Success &= remapTypeIndex(R.CompleteClass);
|
||||
Success &= remapTypeIndex(R.OverriddenVFTable);
|
||||
return writeRecord(R, Success);
|
||||
}
|
||||
|
||||
Error TypeStreamMerger::visitKnownRecord(CVType &,
|
||||
MethodOverloadListRecord &R) {
|
||||
assert(DestTypeStream);
|
||||
bool Success = true;
|
||||
for (OneMethodRecord &Meth : R.Methods)
|
||||
Success &= remapIndex(Meth.Type);
|
||||
Success &= remapTypeIndex(Meth.Type);
|
||||
return writeRecord(R, Success);
|
||||
}
|
||||
|
||||
Error TypeStreamMerger::visitKnownRecord(CVType &, FieldListRecord &R) {
|
||||
assert(DestTypeStream);
|
||||
// Visit the members inside the field list.
|
||||
HadUntranslatedMember = false;
|
||||
FieldListBuilder.begin();
|
||||
FieldListBuilder->begin();
|
||||
if (auto EC = codeview::visitMemberRecordStream(R.Data, *this))
|
||||
return EC;
|
||||
|
||||
// Write the record if we translated all field list members.
|
||||
TypeIndex DestIdx = Untranslated;
|
||||
if (!HadUntranslatedMember)
|
||||
DestIdx = FieldListBuilder.end();
|
||||
DestIdx = FieldListBuilder->end();
|
||||
else
|
||||
FieldListBuilder.reset();
|
||||
FieldListBuilder->reset();
|
||||
addMapping(DestIdx);
|
||||
|
||||
return Error::success();
|
||||
|
@ -382,28 +437,28 @@ Error TypeStreamMerger::visitKnownRecord(CVType &, FieldListRecord &R) {
|
|||
|
||||
Error TypeStreamMerger::visitKnownMember(CVMemberRecord &,
|
||||
NestedTypeRecord &R) {
|
||||
return writeMember(R, remapIndex(R.Type));
|
||||
return writeMember(R, remapTypeIndex(R.Type));
|
||||
}
|
||||
|
||||
Error TypeStreamMerger::visitKnownMember(CVMemberRecord &, OneMethodRecord &R) {
|
||||
bool Success = true;
|
||||
Success &= remapIndex(R.Type);
|
||||
Success &= remapTypeIndex(R.Type);
|
||||
return writeMember(R, Success);
|
||||
}
|
||||
|
||||
Error TypeStreamMerger::visitKnownMember(CVMemberRecord &,
|
||||
OverloadedMethodRecord &R) {
|
||||
return writeMember(R, remapIndex(R.MethodList));
|
||||
return writeMember(R, remapTypeIndex(R.MethodList));
|
||||
}
|
||||
|
||||
Error TypeStreamMerger::visitKnownMember(CVMemberRecord &,
|
||||
DataMemberRecord &R) {
|
||||
return writeMember(R, remapIndex(R.Type));
|
||||
return writeMember(R, remapTypeIndex(R.Type));
|
||||
}
|
||||
|
||||
Error TypeStreamMerger::visitKnownMember(CVMemberRecord &,
|
||||
StaticDataMemberRecord &R) {
|
||||
return writeMember(R, remapIndex(R.Type));
|
||||
return writeMember(R, remapTypeIndex(R.Type));
|
||||
}
|
||||
|
||||
Error TypeStreamMerger::visitKnownMember(CVMemberRecord &,
|
||||
|
@ -412,24 +467,24 @@ Error TypeStreamMerger::visitKnownMember(CVMemberRecord &,
|
|||
}
|
||||
|
||||
Error TypeStreamMerger::visitKnownMember(CVMemberRecord &, VFPtrRecord &R) {
|
||||
return writeMember(R, remapIndex(R.Type));
|
||||
return writeMember(R, remapTypeIndex(R.Type));
|
||||
}
|
||||
|
||||
Error TypeStreamMerger::visitKnownMember(CVMemberRecord &, BaseClassRecord &R) {
|
||||
return writeMember(R, remapIndex(R.Type));
|
||||
return writeMember(R, remapTypeIndex(R.Type));
|
||||
}
|
||||
|
||||
Error TypeStreamMerger::visitKnownMember(CVMemberRecord &,
|
||||
VirtualBaseClassRecord &R) {
|
||||
bool Success = true;
|
||||
Success &= remapIndex(R.BaseType);
|
||||
Success &= remapIndex(R.VBPtrType);
|
||||
Success &= remapTypeIndex(R.BaseType);
|
||||
Success &= remapTypeIndex(R.VBPtrType);
|
||||
return writeMember(R, Success);
|
||||
}
|
||||
|
||||
Error TypeStreamMerger::visitKnownMember(CVMemberRecord &,
|
||||
ListContinuationRecord &R) {
|
||||
return writeMember(R, remapIndex(R.ContinuationIndex));
|
||||
return writeMember(R, remapTypeIndex(R.ContinuationIndex));
|
||||
}
|
||||
|
||||
Error TypeStreamMerger::visitUnknownType(CVType &Rec) {
|
||||
|
@ -438,8 +493,34 @@ Error TypeStreamMerger::visitUnknownType(CVType &Rec) {
|
|||
return errorCorruptRecord();
|
||||
}
|
||||
|
||||
Error TypeStreamMerger::mergeStream(const CVTypeArray &Types) {
|
||||
assert(IndexMap.empty());
|
||||
Error TypeStreamMerger::mergeTypeRecords(TypeTableBuilder &Dest,
|
||||
TypeCollection &Types) {
|
||||
DestTypeStream = &Dest;
|
||||
FieldListBuilder = llvm::make_unique<FieldListRecordBuilder>(Dest);
|
||||
|
||||
return doit(Types);
|
||||
}
|
||||
|
||||
Error TypeStreamMerger::mergeIdRecords(TypeTableBuilder &Dest,
|
||||
ArrayRef<TypeIndex> TypeSourceToDest,
|
||||
TypeCollection &Ids) {
|
||||
DestIdStream = &Dest;
|
||||
TypeLookup = TypeSourceToDest;
|
||||
|
||||
return doit(Ids);
|
||||
}
|
||||
|
||||
Error TypeStreamMerger::mergeTypesAndIds(TypeTableBuilder &DestIds,
|
||||
TypeTableBuilder &DestTypes,
|
||||
TypeCollection &IdsAndTypes) {
|
||||
DestIdStream = &DestIds;
|
||||
DestTypeStream = &DestTypes;
|
||||
FieldListBuilder = llvm::make_unique<FieldListRecordBuilder>(DestTypes);
|
||||
|
||||
return doit(IdsAndTypes);
|
||||
}
|
||||
|
||||
Error TypeStreamMerger::doit(TypeCollection &Types) {
|
||||
LastError = Error::success();
|
||||
|
||||
if (auto EC = codeview::visitTypeStream(Types, *this, Handler))
|
||||
|
@ -469,18 +550,32 @@ Error TypeStreamMerger::mergeStream(const CVTypeArray &Types) {
|
|||
}
|
||||
}
|
||||
|
||||
IndexMap.clear();
|
||||
|
||||
Error Ret = std::move(*LastError);
|
||||
LastError.reset();
|
||||
return Ret;
|
||||
}
|
||||
|
||||
Error llvm::codeview::mergeTypeStreams(TypeTableBuilder &DestIdStream,
|
||||
TypeTableBuilder &DestTypeStream,
|
||||
Error llvm::codeview::mergeTypeRecords(TypeTableBuilder &Dest,
|
||||
SmallVectorImpl<TypeIndex> &SourceToDest,
|
||||
TypeServerHandler *Handler,
|
||||
const CVTypeArray &Types) {
|
||||
return TypeStreamMerger(DestIdStream, DestTypeStream, SourceToDest, Handler)
|
||||
.mergeStream(Types);
|
||||
TypeCollection &Types) {
|
||||
TypeStreamMerger M(SourceToDest, Handler);
|
||||
return M.mergeTypeRecords(Dest, Types);
|
||||
}
|
||||
|
||||
Error llvm::codeview::mergeIdRecords(TypeTableBuilder &Dest,
|
||||
ArrayRef<TypeIndex> TypeSourceToDest,
|
||||
SmallVectorImpl<TypeIndex> &SourceToDest,
|
||||
TypeCollection &Ids) {
|
||||
TypeStreamMerger M(SourceToDest, nullptr);
|
||||
return M.mergeIdRecords(Dest, TypeSourceToDest, Ids);
|
||||
}
|
||||
|
||||
Error llvm::codeview::mergeTypeAndIdRecords(
|
||||
TypeTableBuilder &DestIds, TypeTableBuilder &DestTypes,
|
||||
SmallVectorImpl<TypeIndex> &SourceToDest, TypeServerHandler *Handler,
|
||||
TypeCollection &IdsAndTypes) {
|
||||
|
||||
TypeStreamMerger M(SourceToDest, Handler);
|
||||
return M.mergeTypesAndIds(DestIds, DestTypes, IdsAndTypes);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,9 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
|
||||
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
|
||||
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
|
||||
#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
|
||||
|
@ -104,6 +106,8 @@ Error TpiStream::reload() {
|
|||
HashStream = std::move(HS);
|
||||
}
|
||||
|
||||
Types = llvm::make_unique<LazyRandomTypeCollection>(
|
||||
TypeRecords, getNumTypeRecords(), getTypeIndexOffsets());
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
IpiStream:
|
||||
Records:
|
||||
# 'One' [TypeIndex: 0x1000 (4096)]
|
||||
- Kind: LF_STRING_ID
|
||||
StringId:
|
||||
Id: 0
|
||||
String: 'One'
|
||||
# 'Two' [TypeIndex: 0x1001 (4097)]
|
||||
- Kind: LF_STRING_ID
|
||||
StringId:
|
||||
Id: 0
|
||||
String: 'Two'
|
||||
# 'OnlyInFirst' [TypeIndex: 0x1002 (4098)]
|
||||
- Kind: LF_STRING_ID
|
||||
StringId:
|
||||
Id: 0
|
||||
String: 'OnlyInFirst'
|
||||
# 'SubOne' [TypeIndex: 0x1003 (4099)]
|
||||
- Kind: LF_STRING_ID
|
||||
StringId:
|
||||
Id: 0
|
||||
String: 'SubOne'
|
||||
# 'SubTwo' [TypeIndex: 0x1004 (4100)]
|
||||
- Kind: LF_STRING_ID
|
||||
StringId:
|
||||
Id: 0
|
||||
String: 'SubTwo'
|
||||
# 'SubOne', 'SubTwo' [TypeIndex: 0x1005 (4101)]
|
||||
- Kind: LF_SUBSTR_LIST
|
||||
StringList:
|
||||
StringIndices: [ 4099, 4100 ]
|
||||
# 'Main' {'SubOne', 'SubTwo'} [TypeIndex: 0x1006 (4102)]
|
||||
- Kind: LF_STRING_ID
|
||||
StringId:
|
||||
Id: 4101
|
||||
String: 'Main'
|
|
@ -0,0 +1,31 @@
|
|||
IpiStream:
|
||||
Records:
|
||||
# 'SubTwo' [TypeIndex: 0x1000 (4096)]
|
||||
- Kind: LF_STRING_ID
|
||||
StringId:
|
||||
Id: 0
|
||||
String: 'SubTwo'
|
||||
# 'OnlyInSecond' [TypeIndex: 0x1001 (4097)]
|
||||
- Kind: LF_STRING_ID
|
||||
StringId:
|
||||
Id: 0
|
||||
String: 'OnlyInSecond'
|
||||
# 'SubOne' [TypeIndex: 0x1002 (4098)]
|
||||
- Kind: LF_STRING_ID
|
||||
StringId:
|
||||
Id: 0
|
||||
String: 'SubOne'
|
||||
# 'SubOne', 'SubTwo' [TypeIndex: 0x1003 (4099)]
|
||||
- Kind: LF_SUBSTR_LIST
|
||||
StringList:
|
||||
StringIndices: [ 4098, 4096 ]
|
||||
# 'One' [TypeIndex: 0x1004 (4100)]
|
||||
- Kind: LF_STRING_ID
|
||||
StringId:
|
||||
Id: 0
|
||||
String: 'One'
|
||||
# 'Main' {'SubOne', 'SubTwo'} [TypeIndex: 0x1005 (4101)]
|
||||
- Kind: LF_STRING_ID
|
||||
StringId:
|
||||
Id: 4099
|
||||
String: 'Main'
|
|
@ -0,0 +1,113 @@
|
|||
# The idea is to set up some types in the TPI stream, and then have records in
|
||||
# the IPI stream that refer to them. There are three types of IPI records that
|
||||
# can refer to TPI records. They are:
|
||||
# 1) LF_PROCEDURE - Referred to by LF_FUNC_ID
|
||||
# 2) LF_STRUCTURE - Referred to by LF_UDT_MOD_SRC_LINE
|
||||
# Referred to by LF_UDT_SRC_LINE
|
||||
# 3) LF_MFUNCTION - Referred to by LF_MFUNC_ID
|
||||
# We will set up one of each of these, and then create IPI records that refer to
|
||||
# them. We intentionally choose an unintuitive ordering of the records in both
|
||||
# streams (while still maintaining the topological sorting required by CodeView
|
||||
# type streams), to make sure the merging algorithm is sufficiently exercised.
|
||||
# For easy understanding, a semantic representation of the types we will set up
|
||||
# is as follows:
|
||||
# - int main(int, char**)
|
||||
#
|
||||
# - struct FooBar {
|
||||
# public:
|
||||
# void *FooMember;
|
||||
# void FooMethod(int);
|
||||
# };
|
||||
TpiStream:
|
||||
Records:
|
||||
# TypeIndex: 4096 (0x1000)
|
||||
# char**
|
||||
- Kind: LF_POINTER
|
||||
Pointer:
|
||||
ReferentType: 1136
|
||||
Attrs: 32778
|
||||
# TypeIndex: 4097 (0x1001)
|
||||
# public void *FooMember
|
||||
- Kind: LF_FIELDLIST
|
||||
FieldList:
|
||||
- Kind: LF_MEMBER
|
||||
DataMember:
|
||||
Attrs: 3 # public
|
||||
Type: 1027 # void*
|
||||
FieldOffset: 0
|
||||
Name: FooMember # FooMember
|
||||
# TypeIndex: 4098 (0x1002)
|
||||
# (int, char**)
|
||||
- Kind: LF_ARGLIST
|
||||
ArgList:
|
||||
ArgIndices: [ 116, 4096 ]
|
||||
# TypeIndex: 4099 (0x1003)
|
||||
# struct FooBar {
|
||||
# public:
|
||||
# void *FooMember;
|
||||
# };
|
||||
- Kind: LF_STRUCTURE
|
||||
Class:
|
||||
MemberCount: 1
|
||||
Options: [ None, HasUniqueName ]
|
||||
FieldList: 4097
|
||||
Name: FooBar
|
||||
UniqueName: 'FooBar'
|
||||
DerivationList: 0
|
||||
VTableShape: 0
|
||||
Size: 4
|
||||
# TypeIndex: 4100 (0x1004)
|
||||
# FooBar *
|
||||
- Kind: LF_POINTER
|
||||
Pointer:
|
||||
ReferentType: 4099 # FooBar
|
||||
Attrs: 32778
|
||||
# TypeIndex: 4101 (0x1005)
|
||||
# (int)
|
||||
- Kind: LF_ARGLIST
|
||||
ArgList:
|
||||
ArgIndices: [ 116 ]
|
||||
# TypeIndex: 4102 (0x1006)
|
||||
- Kind: LF_MFUNCTION
|
||||
MemberFunction:
|
||||
ReturnType: 3 # void
|
||||
ClassType: 4099 # struct FooBar
|
||||
ThisType: 4100 # FooBar *
|
||||
CallConv: ThisCall
|
||||
Options: [ None, Constructor ]
|
||||
ParameterCount: 1
|
||||
ArgumentList: 4101 # (int)
|
||||
ThisPointerAdjustment: 0
|
||||
# TypeIndex: 4103 (0x1007)
|
||||
# int (int, char**)
|
||||
- Kind: LF_PROCEDURE
|
||||
Procedure:
|
||||
ReturnType: 116 # int
|
||||
CallConv: NearC
|
||||
Options: [ None ]
|
||||
ParameterCount: 2
|
||||
ArgumentList: 4098 # (int, char**)
|
||||
IpiStream:
|
||||
Records:
|
||||
# TypeIndex: 4096 (0x1000)
|
||||
# int main(int, char **)
|
||||
- Kind: LF_FUNC_ID
|
||||
FuncId:
|
||||
ParentScope: 0
|
||||
FunctionType: 4103 # int main(int, char**)
|
||||
Name: main
|
||||
# TypeIndex: 4097 (0x1001)
|
||||
# void FooBar::FooMethod(int)
|
||||
- Kind: LF_MFUNC_ID
|
||||
MemberFuncId:
|
||||
ClassType: 4099 # struct FooBar
|
||||
FunctionType: 4102 # void FooMethod(int)
|
||||
Name: FooMethod
|
||||
# TypeIndex: 4098 (0x1002)
|
||||
# struct FooBar
|
||||
- Kind: LF_UDT_MOD_SRC_LINE
|
||||
UdtModSourceLine:
|
||||
UDT: 4099 # struct FooBar
|
||||
SourceFile: 0 # We don't support this yet
|
||||
LineNumber: 0
|
||||
Module: 0 # We don't support this yet
|
|
@ -0,0 +1,143 @@
|
|||
# In file 1 we set up some basic types and IDs to refer to them. In this file
|
||||
# we will set up the same types. For some of them we will make them identical
|
||||
# but re-order the records in the file to make sure they have different type
|
||||
# indices and appear in different orders. In other cases we will make slight
|
||||
# adjustments to the types, to ensure that they do not get merged in.
|
||||
#
|
||||
# For easy understanding, a semantic representation of the types we will set up
|
||||
# is as follows:
|
||||
# - int main(int, char**) // This record should share an LF_PROCEDURE and id
|
||||
# // record with corresponding function from the
|
||||
# // first file.
|
||||
# - int main2(int, char**) // This record should share the LF_PROCEDURE
|
||||
# // record but have a unique id record.
|
||||
# - void foo(int, char**) // This record should have a unique LF_PROCEDURE
|
||||
# // record, but the LF_ARGLIST record internally
|
||||
# // should be shared.
|
||||
#
|
||||
# - struct FooBar { // Because the type of this record exactly matches
|
||||
# // the corresponding file, its entire type record
|
||||
# // hierarchy should be shared.
|
||||
# public:
|
||||
# void *FooMember;
|
||||
# void FooMethod2(int); // Note that the *type* of this member should be
|
||||
# // the same as the type of the record from the
|
||||
# // first stream. But since it has a different
|
||||
# // name, it will not share an id record.
|
||||
# };
|
||||
TpiStream:
|
||||
Records:
|
||||
# TypeIndex: 4096 (0x1000)
|
||||
# (int)
|
||||
- Kind: LF_ARGLIST
|
||||
ArgList:
|
||||
ArgIndices: [ 116 ]
|
||||
# TypeIndex: 4097 (0x1001)
|
||||
# public void *FooMember
|
||||
- Kind: LF_FIELDLIST
|
||||
FieldList:
|
||||
- Kind: LF_MEMBER
|
||||
DataMember:
|
||||
Attrs: 3 # public
|
||||
Type: 1027 # void*
|
||||
FieldOffset: 0
|
||||
Name: FooMember # FooMember
|
||||
# TypeIndex: 4098 (0x1002)
|
||||
# char**
|
||||
- Kind: LF_POINTER
|
||||
Pointer:
|
||||
ReferentType: 1136
|
||||
Attrs: 32778
|
||||
# TypeIndex: 4099 (0x1003)
|
||||
# (int, char**)
|
||||
- Kind: LF_ARGLIST
|
||||
ArgList:
|
||||
ArgIndices: [ 116, 4098 ]
|
||||
# TypeIndex: 4100 (0x1004)
|
||||
# struct FooBar {
|
||||
# public:
|
||||
# void *FooMember;
|
||||
# };
|
||||
- Kind: LF_STRUCTURE
|
||||
Class:
|
||||
MemberCount: 1
|
||||
Options: [ None, HasUniqueName ]
|
||||
FieldList: 4097
|
||||
Name: FooBar
|
||||
UniqueName: 'FooBar'
|
||||
DerivationList: 0
|
||||
VTableShape: 0
|
||||
Size: 4
|
||||
# TypeIndex: 4101 (0x1005)
|
||||
# void (int, char**)
|
||||
- Kind: LF_PROCEDURE
|
||||
Procedure:
|
||||
ReturnType: 3 # void
|
||||
CallConv: NearC
|
||||
Options: [ None ]
|
||||
ParameterCount: 2
|
||||
ArgumentList: 4099 # (int, char**)
|
||||
# TypeIndex: 4102 (0x1006)
|
||||
# FooBar *
|
||||
- Kind: LF_POINTER
|
||||
Pointer:
|
||||
ReferentType: 4100 # FooBar
|
||||
Attrs: 32778
|
||||
# TypeIndex: 4103 (0x1007)
|
||||
# int (int, char**)
|
||||
- Kind: LF_PROCEDURE
|
||||
Procedure:
|
||||
ReturnType: 116 # int
|
||||
CallConv: NearC
|
||||
Options: [ None ]
|
||||
ParameterCount: 2
|
||||
ArgumentList: 4099 # (int, char**)
|
||||
# TypeIndex: 4104 (0x1008)
|
||||
- Kind: LF_MFUNCTION
|
||||
MemberFunction:
|
||||
ReturnType: 3 # void
|
||||
ClassType: 4100 # struct FooBar
|
||||
ThisType: 4102 # FooBar *
|
||||
CallConv: ThisCall
|
||||
Options: [ None, Constructor ]
|
||||
ParameterCount: 1
|
||||
ArgumentList: 4096 # (int)
|
||||
ThisPointerAdjustment: 0
|
||||
IpiStream:
|
||||
Records:
|
||||
# TypeIndex: 4096 (0x1000)
|
||||
# struct FooBar
|
||||
- Kind: LF_UDT_MOD_SRC_LINE
|
||||
UdtModSourceLine:
|
||||
UDT: 4100 # struct FooBar
|
||||
SourceFile: 0 # We don't support this yet
|
||||
LineNumber: 0
|
||||
Module: 0 # We don't support this yet
|
||||
# TypeIndex: 4097 (0x1001)
|
||||
# int main2(int, char **)
|
||||
- Kind: LF_FUNC_ID
|
||||
FuncId:
|
||||
ParentScope: 0
|
||||
FunctionType: 4103 # int main2(int, char**)
|
||||
Name: main2
|
||||
# TypeIndex: 4098 (0x1002)
|
||||
# void foo(int, char **)
|
||||
- Kind: LF_FUNC_ID
|
||||
FuncId:
|
||||
ParentScope: 0
|
||||
FunctionType: 4101 # void main2(int, char**)
|
||||
Name: foo
|
||||
# TypeIndex: 4099 (0x1003)
|
||||
# void FooBar::FooMethod2(int)
|
||||
- Kind: LF_MFUNC_ID
|
||||
MemberFuncId:
|
||||
ClassType: 4100 # struct FooBar
|
||||
FunctionType: 4104 # void FooBar::FooMethod2(int)
|
||||
Name: FooMethod2
|
||||
# TypeIndex: 4100 (0x1004)
|
||||
# int main(int, char **)
|
||||
- Kind: LF_FUNC_ID
|
||||
FuncId:
|
||||
ParentScope: 0
|
||||
FunctionType: 4103 # int main(int, char**)
|
||||
Name: main
|
|
@ -0,0 +1,65 @@
|
|||
; RUN: llvm-pdbdump yaml2pdb -pdb=%t.1.pdb %p/Inputs/merge-ids-and-types-1.yaml
|
||||
; RUN: llvm-pdbdump yaml2pdb -pdb=%t.2.pdb %p/Inputs/merge-ids-and-types-2.yaml
|
||||
; RUN: llvm-pdbdump merge -pdb=%t.3.pdb %t.1.pdb %t.2.pdb
|
||||
; RUN: llvm-pdbdump raw -tpi-records %t.3.pdb | FileCheck -check-prefix=TPI-TYPES %s
|
||||
; RUN: llvm-pdbdump raw -tpi-records %t.3.pdb | FileCheck -check-prefix=INTMAIN %s
|
||||
; RUN: llvm-pdbdump raw -tpi-records %t.3.pdb | FileCheck -check-prefix=VOIDMAIN %s
|
||||
; RUN: llvm-pdbdump raw -ipi-records %t.3.pdb | FileCheck -check-prefix=IPI-TYPES %s
|
||||
; RUN: llvm-pdbdump raw -ipi-records %t.3.pdb | FileCheck -check-prefix=IPI-NAMES %s
|
||||
; RUN: llvm-pdbdump raw -ipi-records %t.3.pdb | FileCheck -check-prefix=IPI-UDT %s
|
||||
|
||||
TPI-TYPES: Type Info Stream (TPI)
|
||||
TPI-TYPES: Record count: 9
|
||||
TPI-TYPES-DAG: TypeLeafKind: LF_POINTER
|
||||
TPI-TYPES-DAG: TypeLeafKind: LF_FIELDLIST
|
||||
TPI-TYPES-DAG: TypeLeafKind: LF_ARGLIST
|
||||
TPI-TYPES-DAG: TypeLeafKind: LF_STRUCTURE
|
||||
TPI-TYPES-DAG: TypeLeafKind: LF_MEMBER
|
||||
TPI-TYPES-DAG: TypeLeafKind: LF_POINTER
|
||||
TPI-TYPES-DAG: TypeLeafKind: LF_ARGLIST
|
||||
TPI-TYPES-DAG: TypeLeafKind: LF_MFUNCTION
|
||||
TPI-TYPES-DAG: TypeLeafKind: LF_PROCEDURE
|
||||
TPI-TYPES-DAG: TypeLeafKind: LF_PROCEDURE
|
||||
TPI-TYPES-DAG: TypeLeafKind: LF_ARGLIST
|
||||
|
||||
; Both procedures should use the same arglist even though they have a different
|
||||
; return type.
|
||||
INTMAIN: ArgList ([[ID:.*]])
|
||||
INTMAIN-NEXT: TypeLeafKind: LF_ARGLIST
|
||||
INTMAIN-NEXT: NumArgs: 2
|
||||
INTMAIN-NEXT: Arguments [
|
||||
INTMAIN-NEXT: ArgType: int
|
||||
INTMAIN-NEXT: ArgType: char**
|
||||
INTMAIN: TypeLeafKind: LF_PROCEDURE
|
||||
INTMAIN: ReturnType: int
|
||||
INTMAIN: NumParameters: 2
|
||||
INTMAIN-NEXT: ArgListType: (int, char**) ([[ID]])
|
||||
|
||||
VOIDMAIN: ArgList ([[ID:.*]])
|
||||
VOIDMAIN-NEXT: TypeLeafKind: LF_ARGLIST
|
||||
VOIDMAIN-NEXT: NumArgs: 2
|
||||
VOIDMAIN-NEXT: Arguments [
|
||||
VOIDMAIN-NEXT: ArgType: int
|
||||
VOIDMAIN-NEXT: ArgType: char**
|
||||
VOIDMAIN: TypeLeafKind: LF_PROCEDURE
|
||||
VOIDMAIN: ReturnType: void
|
||||
VOIDMAIN: NumParameters: 2
|
||||
VOIDMAIN-NEXT: ArgListType: (int, char**) ([[ID]])
|
||||
|
||||
IPI-TYPES: Type Info Stream (IPI)
|
||||
IPI-TYPES: Record count: 6
|
||||
IPI-TYPES-DAG: TypeLeafKind: LF_FUNC_ID
|
||||
IPI-TYPES-DAG: TypeLeafKind: LF_MFUNC_ID
|
||||
IPI-TYPES-DAG: TypeLeafKind: LF_UDT_MOD_SRC_LINE
|
||||
IPI-TYPES-DAG: TypeLeafKind: LF_FUNC_ID
|
||||
IPI-TYPES-DAG: TypeLeafKind: LF_FUNC_ID
|
||||
IPI-TYPES-DAG: TypeLeafKind: LF_MFUNC_ID
|
||||
|
||||
IPI-NAMES-DAG: Name: main
|
||||
IPI-NAMES-DAG: Name: FooMethod
|
||||
IPI-NAMES-DAG: Name: main2
|
||||
IPI-NAMES-DAG: Name: foo
|
||||
IPI-NAMES-DAG: Name: FooMethod2
|
||||
|
||||
IPI-UDT: TypeLeafKind: LF_UDT_MOD_SRC_LINE
|
||||
IPI-UDT-NEXT: UDT: FooBar
|
|
@ -0,0 +1,31 @@
|
|||
; RUN: llvm-pdbdump yaml2pdb -pdb=%t.1.pdb %p/Inputs/merge-ids-1.yaml
|
||||
; RUN: llvm-pdbdump yaml2pdb -pdb=%t.2.pdb %p/Inputs/merge-ids-2.yaml
|
||||
; RUN: llvm-pdbdump merge -pdb=%t.3.pdb %t.1.pdb %t.2.pdb
|
||||
; RUN: llvm-pdbdump raw -ipi-records %t.3.pdb | FileCheck -check-prefix=MERGED %s
|
||||
; RUN: llvm-pdbdump raw -ipi-records %t.3.pdb | FileCheck -check-prefix=SUBSTRS %s
|
||||
; RUN: llvm-pdbdump raw -tpi-records %t.3.pdb | FileCheck -check-prefix=TPI-EMPTY %s
|
||||
|
||||
|
||||
MERGED: Type Info Stream (IPI)
|
||||
MERGED: Record count: 8
|
||||
MERGED-DAG: StringData: One
|
||||
MERGED-DAG: StringData: Two
|
||||
MERGED-DAG: StringData: SubOne
|
||||
MERGED-DAG: StringData: SubTwo
|
||||
MERGED-DAG: StringData: Main
|
||||
MERGED-DAG: TypeLeafKind: LF_SUBSTR_LIST
|
||||
MERGED-DAG: StringData: OnlyInFirst
|
||||
MERGED-DAG: StringData: OnlyInSecond
|
||||
|
||||
SUBSTRS: StringList
|
||||
SUBSTRS: TypeLeafKind: LF_SUBSTR_LIST
|
||||
SUBSTRS-NEXT: NumStrings: 2
|
||||
SUBSTRS-NEXT: Strings [
|
||||
SUBSTRS-NEXT: SubOne
|
||||
SUBSTRS-NEXT: SubTwo
|
||||
SUBSTRS: StringId
|
||||
SUBSTRS-NEXT: TypeLeafKind: LF_STRING_ID
|
||||
SUBSTRS-NEXT: Id: "SubOne" "SubTwo"
|
||||
SUBSTRS-NEXT: StringData: Main
|
||||
|
||||
TPI-EMPTY: Record count: 0
|
|
@ -1,5 +1,5 @@
|
|||
; RUN: llvm-pdbdump yaml2pdb -pdb=%t.1.pdb %p/Inputs/merge1.yaml
|
||||
; RUN: llvm-pdbdump yaml2pdb -pdb=%t.2.pdb %p/Inputs/merge2.yaml
|
||||
; RUN: llvm-pdbdump yaml2pdb -pdb=%t.1.pdb %p/Inputs/merge-types-1.yaml
|
||||
; RUN: llvm-pdbdump yaml2pdb -pdb=%t.2.pdb %p/Inputs/merge-types-2.yaml
|
||||
; RUN: llvm-pdbdump merge -pdb=%t.3.pdb %t.1.pdb %t.2.pdb
|
||||
; RUN: llvm-pdbdump raw -tpi-records %t.3.pdb | FileCheck -check-prefix=MERGED %s
|
||||
; RUN: llvm-pdbdump raw -tpi-records %t.3.pdb | FileCheck -check-prefix=ARGLIST %s
|
||||
|
|
|
@ -500,6 +500,7 @@ static void yamlToPdb(StringRef Path) {
|
|||
pdb::yaml::PdbInfoStream DefaultInfoStream;
|
||||
pdb::yaml::PdbDbiStream DefaultDbiStream;
|
||||
pdb::yaml::PdbTpiStream DefaultTpiStream;
|
||||
pdb::yaml::PdbTpiStream DefaultIpiStream;
|
||||
|
||||
const auto &Info = YamlObj.PdbStream.getValueOr(DefaultInfoStream);
|
||||
|
||||
|
@ -601,11 +602,11 @@ static void yamlToPdb(StringRef Path) {
|
|||
for (const auto &R : Tpi.Records)
|
||||
TpiBuilder.addTypeRecord(R.Record.data(), R.Record.Hash);
|
||||
|
||||
const auto &Ipi = YamlObj.IpiStream.getValueOr(DefaultTpiStream);
|
||||
const auto &Ipi = YamlObj.IpiStream.getValueOr(DefaultIpiStream);
|
||||
auto &IpiBuilder = Builder.getIpiBuilder();
|
||||
IpiBuilder.setVersionHeader(Ipi.Version);
|
||||
for (const auto &R : Ipi.Records)
|
||||
TpiBuilder.addTypeRecord(R.Record.data(), R.Record.Hash);
|
||||
IpiBuilder.addTypeRecord(R.Record.data(), R.Record.Hash);
|
||||
|
||||
ExitOnErr(Builder.commit(opts::yaml2pdb::YamlPdbOutputFile));
|
||||
}
|
||||
|
@ -852,18 +853,17 @@ static void mergePdbs() {
|
|||
for (const auto &Path : opts::merge::InputFilenames) {
|
||||
std::unique_ptr<IPDBSession> Session;
|
||||
auto &File = loadPDB(Path, Session);
|
||||
SmallVector<TypeIndex, 128> SourceToDest;
|
||||
SmallVector<TypeIndex, 128> TypeMap;
|
||||
SmallVector<TypeIndex, 128> IdMap;
|
||||
if (File.hasPDBTpiStream()) {
|
||||
SourceToDest.clear();
|
||||
auto &Tpi = ExitOnErr(File.getPDBTpiStream());
|
||||
ExitOnErr(codeview::mergeTypeStreams(MergedIpi, MergedTpi, SourceToDest,
|
||||
nullptr, Tpi.typeArray()));
|
||||
ExitOnErr(codeview::mergeTypeRecords(MergedTpi, TypeMap, nullptr,
|
||||
Tpi.typeCollection()));
|
||||
}
|
||||
if (File.hasPDBIpiStream()) {
|
||||
SourceToDest.clear();
|
||||
auto &Ipi = ExitOnErr(File.getPDBIpiStream());
|
||||
ExitOnErr(codeview::mergeTypeStreams(MergedIpi, MergedTpi, SourceToDest,
|
||||
nullptr, Ipi.typeArray()));
|
||||
ExitOnErr(codeview::mergeIdRecords(MergedIpi, TypeMap, IdMap,
|
||||
Ipi.typeCollection()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1072,9 +1072,10 @@ void COFFDumper::mergeCodeViewTypes(TypeTableBuilder &CVIDs,
|
|||
W.flush();
|
||||
error(object_error::parse_failed);
|
||||
}
|
||||
LazyRandomTypeCollection TypesAndIds(Types, 100);
|
||||
SmallVector<TypeIndex, 128> SourceToDest;
|
||||
if (auto EC =
|
||||
mergeTypeStreams(CVIDs, CVTypes, SourceToDest, nullptr, Types))
|
||||
if (auto EC = mergeTypeAndIdRecords(CVIDs, CVTypes, SourceToDest, nullptr,
|
||||
TypesAndIds))
|
||||
return error(std::move(EC));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue