[LLD][COFF] Survive empty and invalid PCH signature

Solve two issues that showed up when using LLD with Unreal Engine & FASTBuild:
1. It seems the S_OBJNAME record doesn't always record the "precomp signature". We were relying on that to match the PCH.OBJ with their dependent-OBJ.
2. MSVC link.exe is able to link a PCH.OBJ when the "precomp signatureÈ doesn't match, but LLD was failing. This was occuring since the Unreal Engine Build Tool was compiling the PCH.OBJ, but the dependent-OBJ were compiled & cached through FASTBuild. Upon a clean rebuild, the PCH.OBJs were recompiled by the Unreal Build Tool, thus the "precomp signatures" were changing; however the OBJs were already cached by FASTBuild, thus having an old "precomp signatures".

We now ignore "precomp signatures" and properly fallback to cmd-line name lookup, like MSVC link.exe does, and only fail if the PCH.OBJ type stream doesn't match the count expected by the dependent-OBJ.

Differential Revision: https://reviews.llvm.org/D136762
This commit is contained in:
Alexandre Ganea 2022-11-20 10:24:02 -05:00
parent e2bff1e489
commit 242a9cf7e6
8 changed files with 128 additions and 72 deletions

View File

@ -125,18 +125,23 @@ public:
class PrecompSource : public TpiSource {
public:
PrecompSource(COFFLinkerContext &ctx, ObjFile *f) : TpiSource(ctx, PCH, f) {
if (!f->pchSignature || !*f->pchSignature)
fatal(toString(f) +
" claims to be a PCH object, but does not have a valid signature");
auto it = ctx.precompSourceMappings.emplace(*f->pchSignature, this);
if (!it.second)
fatal("a PCH object with the same signature has already been provided (" +
toString(it.first->second->file) + " and " + toString(file) + ")");
// If the S_OBJNAME record contains the PCH signature, we'll register this
// source file right away.
registerMapping();
}
Error mergeDebugT(TypeMerger *m) override;
void loadGHashes() override;
bool isDependency() const override { return true; }
private:
void registerMapping();
// Whether this precomp OBJ was recorded in the precompSourceMappings map.
// Only happens if the file->pchSignature is valid.
bool registered = false;
};
// This class represents the debug type stream of an OBJ file that depends on a
@ -310,10 +315,15 @@ Error TpiSource::mergeDebugT(TypeMerger *m) {
// When dealing with PCH.OBJ, some indices were already merged.
unsigned nbHeadIndices = indexMapStorage.size();
if (auto err = mergeTypeAndIdRecords(
m->idTable, m->typeTable, indexMapStorage, types, file->pchSignature))
Optional<PCHMergerInfo> pchInfo;
if (auto err = mergeTypeAndIdRecords(m->idTable, m->typeTable,
indexMapStorage, types, pchInfo))
fatal("codeview::mergeTypeAndIdRecords failed: " +
toString(std::move(err)));
if (pchInfo) {
file->pchSignature = pchInfo->PCHSignature;
endPrecompIdx = pchInfo->EndPrecompIndex;
}
// In an object, there is only one mapping for both types and items.
tpiMap = indexMapStorage;
@ -494,16 +504,15 @@ Expected<PrecompSource *> UsePrecompSource::findPrecompMap(ObjFile *file,
pr.getPrecompFilePath(),
make_error<pdb::PDBError>(pdb::pdb_error_code::no_matching_pch));
if (pr.getSignature() != file->pchSignature)
// Don't rely on the PCH signature to validate the concordance between the PCH
// and the OBJ that uses it. However we do validate here that the
// LF_ENDPRECOMP record index lines up with the number of type records
// LF_PRECOMP is expecting.
if (precomp->endPrecompIdx != pr.getTypesCount())
return createFileError(
toString(file),
make_error<pdb::PDBError>(pdb::pdb_error_code::no_matching_pch));
if (pr.getSignature() != *precomp->file->pchSignature)
return createFileError(
toString(precomp->file),
make_error<pdb::PDBError>(pdb::pdb_error_code::no_matching_pch));
return precomp;
}
@ -541,6 +550,30 @@ Error UsePrecompSource::mergeDebugT(TypeMerger *m) {
return TpiSource::mergeDebugT(m);
}
Error PrecompSource::mergeDebugT(TypeMerger *m) {
// In some cases, the S_OBJNAME record doesn't contain the PCH signature.
// The signature comes later with the LF_ENDPRECOMP record, so we first need
// to merge in all the .PCH.OBJ file type records, before registering below.
if (Error e = TpiSource::mergeDebugT(m))
return e;
registerMapping();
return Error::success();
}
void PrecompSource::registerMapping() {
if (registered)
return;
if (file->pchSignature && *file->pchSignature) {
auto it = ctx.precompSourceMappings.emplace(*file->pchSignature, this);
if (!it.second)
fatal("a PCH object with the same signature has already been provided (" +
toString(it.first->second->file) + " and " + toString(file) + ")");
registered = true;
}
}
//===----------------------------------------------------------------------===//
// Parellel GHash type merging implementation.
//===----------------------------------------------------------------------===//
@ -808,8 +841,14 @@ void PrecompSource::loadGHashes() {
// Remember the index of the LF_ENDPRECOMP record so it can be excluded from
// the PDB. There must be an entry in the list of ghashes so that the type
// indexes of the following records in the /Yc PCH object line up.
if (ty.kind() == LF_ENDPRECOMP)
endPrecompGHashIdx = ghashIdx;
if (ty.kind() == LF_ENDPRECOMP) {
EndPrecompRecord endPrecomp;
cantFail(TypeDeserializer::deserializeAs<EndPrecompRecord>(
const_cast<CVType &>(ty), endPrecomp));
file->pchSignature = endPrecomp.getSignature();
registerMapping();
endPrecompIdx = ghashIdx;
}
hashVec.push_back(GloballyHashedType::hashType(ty, hashVec, hashVec));
isItemIndex.push_back(isIdRecord(ty.kind()));
@ -819,9 +858,13 @@ void PrecompSource::loadGHashes() {
}
void UsePrecompSource::loadGHashes() {
PrecompSource *pchSrc = findPrecompSource(file, precompDependency);
if (!pchSrc)
auto e = findPrecompMap(file, precompDependency);
if (!e) {
warn(toString(e.takeError()));
return;
}
PrecompSource *pchSrc = *e;
// To compute ghashes of a /Yu object file, we need to build on the ghashes of
// the /Yc PCH object. After we are done hashing, discard the ghashes from the

View File

@ -106,18 +106,18 @@ public:
/// it is unique. This prevents a record from being added to the input ghash
/// table.
bool shouldOmitFromPdb(uint32_t ghashIdx) {
return ghashIdx == endPrecompGHashIdx;
return ghashIdx == endPrecompIdx;
}
const TpiKind kind;
bool ownedGHashes = true;
uint32_t tpiSrcIdx = 0;
protected:
/// The ghash index (zero based, not 0x1000-based) of the LF_ENDPRECOMP record
/// in this object, if one exists. This is the all ones value otherwise. It is
/// recorded here so that it can be omitted from the final ghash table.
uint32_t endPrecompGHashIdx = ~0U;
/// The index (zero based, not 0x1000-based) of the LF_ENDPRECOMP record in
/// this object, if one exists. This is the all ones value otherwise. It is
/// recorded here for validation, and so that it can be omitted from the final
/// ghash table.
uint32_t endPrecompIdx = ~0U;
public:
ObjFile *file;

View File

@ -734,7 +734,8 @@ void ObjFile::initializeFlags() {
if (sym->kind() == SymbolKind::S_OBJNAME) {
auto objName = cantFail(SymbolDeserializer::deserializeAs<ObjNameSym>(
sym.get()));
pchSignature = objName.Signature;
if (objName.Signature)
pchSignature = objName.Signature;
}
offset += sym->length();
}
@ -800,6 +801,10 @@ void ObjFile::initializeDependencies() {
if (firstType->kind() == LF_PRECOMP) {
PrecompRecord precomp = cantFail(
TypeDeserializer::deserializeAs<PrecompRecord>(firstType->data()));
// We're better off trusting the LF_PRECOMP signature. In some cases the
// S_OBJNAME record doesn't contain a valid PCH signature.
if (precomp.Signature)
pchSignature = precomp.Signature;
debugTypesObj = makeUsePrecompSource(ctx, this, precomp);
// Drop the LF_PRECOMP record from the input stream.
debugTypes = debugTypes.drop_front(firstType->RecordData.size());

View File

@ -45,6 +45,9 @@ COFF Improvements
(`D137723 <https://reviews.llvm.org/D137723>`_)
* Switched from SHA1 to BLAKE3 for PDB type hashing / ``-gcodeview-ghash``
(`D137101 <https://reviews.llvm.org/D137101>`_)
* Improvements to the PCH.OBJ files handling. Now LLD behaves the same as MSVC
link.exe when merging PCH.OBJ files that don't have the same signature.
(`D136762 <https://reviews.llvm.org/D136762>`_)
MinGW Improvements
------------------

View File

@ -1,11 +1,13 @@
RUN: lld-link %S/Inputs/precomp-a.obj %S/Inputs/precomp-b.obj %S/Inputs/precomp.obj /nodefaultlib /entry:main /debug /pdb:%t.pdb /out:%t.exe /opt:ref /opt:icf /summary | FileCheck %s -check-prefix SUMMARY
RUN: lld-link %S/Inputs/precomp-a.obj %S/Inputs/precomp-b.obj %S/Inputs/precomp.obj /nodefaultlib /entry:main /debug:noghash /pdb:%t.pdb /out:%t.exe /opt:ref /opt:icf /summary | FileCheck %s -check-prefix SUMMARY
RUN: llvm-pdbutil dump -types %t.pdb | FileCheck %s
RUN: lld-link %S/Inputs/precomp-a.obj %S/Inputs/precomp-b.obj %S/Inputs/precomp.obj /nodefaultlib /entry:main /debug:ghash /pdb:%t.pdb /out:%t.exe /opt:ref /opt:icf /summary | FileCheck %s -check-prefix SUMMARY
RUN: llvm-pdbutil dump -types %t.pdb | FileCheck %s
RUN: lld-link %S/Inputs/precomp.obj %S/Inputs/precomp-a.obj %S/Inputs/precomp-b.obj /nodefaultlib /entry:main /debug /pdb:%t.pdb /out:%t.exe /opt:ref /opt:icf
RUN: llvm-pdbutil dump -types %t.pdb | FileCheck %s
RUN: lld-link %S/Inputs/precomp-a.obj %S/Inputs/precomp-invalid.obj %S/Inputs/precomp.obj /nodefaultlib /entry:main /debug /pdb:%t.pdb /out:%t.exe /opt:ref /opt:icf 2>&1 | FileCheck %s -check-prefix FAILURE
RUN: lld-link %S/Inputs/precomp-a.obj %S/Inputs/precomp-invalid.obj %S/Inputs/precomp.obj /nodefaultlib /entry:main /debug:ghash /pdb:%t.pdb /out:%t.exe /opt:ref /opt:icf 2>&1 | FileCheck %s -check-prefix FAILURE
RUN: lld-link %S/Inputs/precomp-a.obj %S/Inputs/precomp-invalid.obj %S/Inputs/precomp.obj /nodefaultlib /entry:main /debug:noghash /pdb:%t.pdb /out:%t.exe /opt:ref /opt:icf 2>&1
RUN: lld-link %S/Inputs/precomp-a.obj %S/Inputs/precomp-invalid.obj %S/Inputs/precomp.obj /nodefaultlib /entry:main /debug:ghash /pdb:%t.pdb /out:%t.exe /opt:ref /opt:icf 2>&1
FIXME: The following RUN line should fail, regardless of whether debug info is
enabled or not. Normally this would result in an error due to missing _PchSym_
@ -14,14 +16,11 @@ special case for those symbols and it emits the LNK2011 error.
RUN: lld-link %S/Inputs/precomp-a.obj %S/Inputs/precomp-b.obj /nodefaultlib /entry:main /debug /pdb:%t.pdb /out:%t.exe /opt:ref /opt:icf 2>&1 | FileCheck %s -check-prefix FAILURE-MISSING-PRECOMPOBJ
FAILURE: warning: Cannot use debug info for '{{.*}}precomp-invalid.obj' [LNK4099]
FAILURE-NEXT: failed to load reference '{{.*}}precomp.obj': No matching precompiled header could be located.
FAILURE-MISSING-PRECOMPOBJ: warning: Cannot use debug info for '{{.*}}precomp-a.obj' [LNK4099]
FAILURE-MISSING-PRECOMPOBJ-NEXT: failed to load reference '{{.*}}precomp.obj': No matching precompiled header could be located.
Check that a PCH object file with a missing S_OBJNAME record results in an
error. Edit out this record from the yaml-ified object:
Check that a PCH object file with an empty S_OBJNAME record works fine.
Edit out this record from the yaml-ified object:
- Kind: S_OBJNAME
ObjNameSym:
Signature: 545589255
@ -29,22 +28,27 @@ error. Edit out this record from the yaml-ified object:
RUN: obj2yaml %S/Inputs/precomp.obj | grep -v 'SectionData: *04000000' > %t.precomp.yaml
RUN: sed '/S_OBJNAME/,/ObjectName:/d' < %t.precomp.yaml > precomp-no-objname.yaml
RUN: sed 's/Signature: *545589255/Signature: 0/' < %t.precomp.yaml > precomp-zero-sig.yaml
RUN: sed '16,19s/Signature: *545589255/Signature: 0/' < %t.precomp.yaml > precomp-zero-sig.yaml
RUN: yaml2obj precomp-no-objname.yaml -o %t.precomp-no-objname.obj
RUN: yaml2obj precomp-zero-sig.yaml -o %t.precomp-zero-sig.obj
RUN: env LLD_IN_TEST=1 lld-link %t.precomp-no-objname.obj %S/Inputs/precomp-a.obj %S/Inputs/precomp-b.obj /nodefaultlib /entry:main /debug:noghash /pdb:%t.pdb /out:%t.exe 2>&1 | FileCheck %s -check-prefix WARNING --allow-empty
RUN: env LLD_IN_TEST=1 lld-link %t.precomp-no-objname.obj %S/Inputs/precomp-a.obj %S/Inputs/precomp-b.obj /nodefaultlib /entry:main /debug:ghash /pdb:%t.pdb /out:%t.exe 2>&1 | FileCheck %s -check-prefix WARNING --allow-empty
RUN: env LLD_IN_TEST=1 lld-link %t.precomp-zero-sig.obj %S/Inputs/precomp-a.obj %S/Inputs/precomp-b.obj /nodefaultlib /entry:main /debug:noghash /pdb:%t.pdb /out:%t.exe 2>&1 | FileCheck %s -check-prefix WARNING --allow-empty
RUN: env LLD_IN_TEST=1 lld-link %t.precomp-zero-sig.obj %S/Inputs/precomp-a.obj %S/Inputs/precomp-b.obj /nodefaultlib /entry:main /debug:ghash /pdb:%t.pdb /out:%t.exe 2>&1 | FileCheck %s -check-prefix WARNING --allow-empty
RUN: env LLD_IN_TEST=1 not lld-link %t.precomp-no-objname.obj %S/Inputs/precomp-a.obj %S/Inputs/precomp-b.obj /nodefaultlib /entry:main /debug /pdb:%t.pdb /out:%t.exe 2>&1 | FileCheck %s -check-prefix FAILURE-NO-SIGNATURE
WARNING-NOT: warning
RUN: env LLD_IN_TEST=1 not lld-link %t.precomp-zero-sig.obj %S/Inputs/precomp-a.obj %S/Inputs/precomp-b.obj /nodefaultlib /entry:main /debug /pdb:%t.pdb /out:%t.exe 2>&1 | FileCheck %s -check-prefix FAILURE-NO-SIGNATURE
Check that a PCH with wrong signature, but with right LF_PRECOMP records count, works.
FAILURE-NO-SIGNATURE: error: {{.*}}.obj claims to be a PCH object, but does not have a valid signature
RUN: sed '16,19s/Signature: *545589255/Signature: 123456789/' < %t.precomp.yaml > precomp-wrong-sig.yaml
RUN: yaml2obj precomp-wrong-sig.yaml -o %T/precomp.obj
RUN: env LLD_IN_TEST=1 lld-link %T/precomp.obj %S/Inputs/precomp-a.obj %S/Inputs/precomp-b.obj /nodefaultlib /entry:main /debug:noghash /pdb:%t.pdb /out:%t.exe 2>&1 | FileCheck %s -check-prefix WARNING --allow-empty
RUN: env LLD_IN_TEST=1 lld-link %T/precomp.obj %S/Inputs/precomp-a.obj %S/Inputs/precomp-b.obj /nodefaultlib /entry:main /debug:ghash /pdb:%t.pdb /out:%t.exe 2>&1 | FileCheck %s -check-prefix WARNING --allow-empty
Check that two PCH objs with duplicate signatures are an error.
RUN: cp %S/Inputs/precomp.obj %t.precomp-dup.obj
RUN: env LLD_IN_TEST=1 not lld-link %S/Inputs/precomp.obj %t.precomp-dup.obj %S/Inputs/precomp-a.obj %S/Inputs/precomp-b.obj /nodefaultlib /entry:main /debug /pdb:%t.pdb /out:%t.exe 2>&1 | FileCheck %s -check-prefix FAILURE-DUP-SIGNATURE
FAILURE-DUP-SIGNATURE: error: a PCH object with the same signature has already been provided ({{.*precomp.obj and .*precomp-dup.obj.*}})
@ -52,13 +56,6 @@ CHECK: Types (TPI Stream)
CHECK-NOT: LF_PRECOMP
CHECK-NOT: LF_ENDPRECOMP
Re-run with ghash. Eventually, perhaps this will be the default.
RUN: lld-link %S/Inputs/precomp-a.obj %S/Inputs/precomp-b.obj %S/Inputs/precomp.obj /nodefaultlib /entry:main /debug /debug:ghash /pdb:%t.pdb /out:%t.exe /opt:ref /opt:icf /summary | FileCheck %s -check-prefix SUMMARY
RUN: llvm-pdbutil dump -types %t.pdb | FileCheck %s
SUMMARY: Summary
SUMMARY-NEXT: --------------------------------------------------------------------------------
SUMMARY-NEXT: 3 Input OBJ files (expanded from all cmd-line inputs)

View File

@ -23,6 +23,13 @@ struct GloballyHashedType;
class GlobalTypeTableBuilder;
class MergingTypeTableBuilder;
/// Used to forward information about PCH.OBJ (precompiled) files, when
/// applicable.
struct PCHMergerInfo {
uint32_t PCHSignature{};
uint32_t EndPrecompIndex = ~0U;
};
/// Merge one set of type records into another. This method assumes
/// that all records are type records, and there are no Id records present.
///
@ -84,20 +91,20 @@ Error mergeTypeAndIdRecords(MergingTypeTableBuilder &DestIds,
MergingTypeTableBuilder &DestTypes,
SmallVectorImpl<TypeIndex> &SourceToDest,
const CVTypeArray &IdsAndTypes,
Optional<uint32_t> &PCHSignature);
Optional<PCHMergerInfo> &PCHInfo);
Error mergeTypeAndIdRecords(GlobalTypeTableBuilder &DestIds,
GlobalTypeTableBuilder &DestTypes,
SmallVectorImpl<TypeIndex> &SourceToDest,
const CVTypeArray &IdsAndTypes,
ArrayRef<GloballyHashedType> Hashes,
Optional<uint32_t> &PCHSignature);
Optional<PCHMergerInfo> &PCHInfo);
Error mergeTypeRecords(GlobalTypeTableBuilder &Dest,
SmallVectorImpl<TypeIndex> &SourceToDest,
const CVTypeArray &Types,
ArrayRef<GloballyHashedType> Hashes,
Optional<uint32_t> &PCHSignature);
Optional<PCHMergerInfo> &PCHInfo);
Error mergeIdRecords(GlobalTypeTableBuilder &Dest, ArrayRef<TypeIndex> Types,
SmallVectorImpl<TypeIndex> &SourceToDest,

View File

@ -77,7 +77,8 @@ public:
// Local hashing entry points
Error mergeTypesAndIds(MergingTypeTableBuilder &DestIds,
MergingTypeTableBuilder &DestTypes,
const CVTypeArray &IdsAndTypes, Optional<uint32_t> &S);
const CVTypeArray &IdsAndTypes,
Optional<PCHMergerInfo> &PCHInfo);
Error mergeIdRecords(MergingTypeTableBuilder &Dest,
ArrayRef<TypeIndex> TypeSourceToDest,
const CVTypeArray &Ids);
@ -89,14 +90,14 @@ public:
GlobalTypeTableBuilder &DestTypes,
const CVTypeArray &IdsAndTypes,
ArrayRef<GloballyHashedType> Hashes,
Optional<uint32_t> &S);
Optional<PCHMergerInfo> &PCHInfo);
Error mergeIdRecords(GlobalTypeTableBuilder &Dest,
ArrayRef<TypeIndex> TypeSourceToDest,
const CVTypeArray &Ids,
ArrayRef<GloballyHashedType> Hashes);
Error mergeTypeRecords(GlobalTypeTableBuilder &Dest, const CVTypeArray &Types,
ArrayRef<GloballyHashedType> Hashes,
Optional<uint32_t> &S);
Optional<PCHMergerInfo> &PCHInfo);
private:
Error doit(const CVTypeArray &Types);
@ -196,7 +197,7 @@ private:
/// its type indices.
SmallVector<uint8_t, 256> RemapStorage;
Optional<uint32_t> PCHSignature;
Optional<PCHMergerInfo> PCHInfo;
};
} // end anonymous namespace
@ -259,12 +260,12 @@ Error TypeStreamMerger::mergeIdRecords(MergingTypeTableBuilder &Dest,
Error TypeStreamMerger::mergeTypesAndIds(MergingTypeTableBuilder &DestIds,
MergingTypeTableBuilder &DestTypes,
const CVTypeArray &IdsAndTypes,
Optional<uint32_t> &S) {
Optional<PCHMergerInfo> &PCHInfo) {
DestIdStream = &DestIds;
DestTypeStream = &DestTypes;
UseGlobalHashes = false;
auto Err = doit(IdsAndTypes);
S = PCHSignature;
PCHInfo = this->PCHInfo;
return Err;
}
@ -272,12 +273,12 @@ Error TypeStreamMerger::mergeTypesAndIds(MergingTypeTableBuilder &DestIds,
Error TypeStreamMerger::mergeTypeRecords(GlobalTypeTableBuilder &Dest,
const CVTypeArray &Types,
ArrayRef<GloballyHashedType> Hashes,
Optional<uint32_t> &S) {
Optional<PCHMergerInfo> &PCHInfo) {
DestGlobalTypeStream = &Dest;
UseGlobalHashes = true;
GlobalHashes = Hashes;
auto Err = doit(Types);
S = PCHSignature;
PCHInfo = this->PCHInfo;
return Err;
}
@ -297,13 +298,13 @@ Error TypeStreamMerger::mergeTypesAndIds(GlobalTypeTableBuilder &DestIds,
GlobalTypeTableBuilder &DestTypes,
const CVTypeArray &IdsAndTypes,
ArrayRef<GloballyHashedType> Hashes,
Optional<uint32_t> &S) {
Optional<PCHMergerInfo> &PCHInfo) {
DestGlobalIdStream = &DestIds;
DestGlobalTypeStream = &DestTypes;
UseGlobalHashes = true;
GlobalHashes = Hashes;
auto Err = doit(IdsAndTypes);
S = PCHSignature;
PCHInfo = this->PCHInfo;
return Err;
}
@ -446,27 +447,26 @@ Error llvm::codeview::mergeIdRecords(MergingTypeTableBuilder &Dest,
Error llvm::codeview::mergeTypeAndIdRecords(
MergingTypeTableBuilder &DestIds, MergingTypeTableBuilder &DestTypes,
SmallVectorImpl<TypeIndex> &SourceToDest, const CVTypeArray &IdsAndTypes,
Optional<uint32_t> &PCHSignature) {
Optional<PCHMergerInfo> &PCHInfo) {
TypeStreamMerger M(SourceToDest);
return M.mergeTypesAndIds(DestIds, DestTypes, IdsAndTypes, PCHSignature);
return M.mergeTypesAndIds(DestIds, DestTypes, IdsAndTypes, PCHInfo);
}
Error llvm::codeview::mergeTypeAndIdRecords(
GlobalTypeTableBuilder &DestIds, GlobalTypeTableBuilder &DestTypes,
SmallVectorImpl<TypeIndex> &SourceToDest, const CVTypeArray &IdsAndTypes,
ArrayRef<GloballyHashedType> Hashes, Optional<uint32_t> &PCHSignature) {
ArrayRef<GloballyHashedType> Hashes, Optional<PCHMergerInfo> &PCHInfo) {
TypeStreamMerger M(SourceToDest);
return M.mergeTypesAndIds(DestIds, DestTypes, IdsAndTypes, Hashes,
PCHSignature);
return M.mergeTypesAndIds(DestIds, DestTypes, IdsAndTypes, Hashes, PCHInfo);
}
Error llvm::codeview::mergeTypeRecords(GlobalTypeTableBuilder &Dest,
SmallVectorImpl<TypeIndex> &SourceToDest,
const CVTypeArray &Types,
ArrayRef<GloballyHashedType> Hashes,
Optional<uint32_t> &PCHSignature) {
Optional<PCHMergerInfo> &PCHInfo) {
TypeStreamMerger M(SourceToDest);
return M.mergeTypeRecords(Dest, Types, Hashes, PCHSignature);
return M.mergeTypeRecords(Dest, Types, Hashes, PCHInfo);
}
Error llvm::codeview::mergeIdRecords(GlobalTypeTableBuilder &Dest,
@ -487,9 +487,10 @@ Expected<bool> TypeStreamMerger::shouldRemapType(const CVType &Type) {
if (auto EC = TypeDeserializer::deserializeAs(const_cast<CVType &>(Type),
EP))
return joinErrors(std::move(EC), errorCorruptRecord());
if (PCHSignature)
// Only one record of this kind can appear in a OBJ.
if (PCHInfo)
return errorCorruptRecord();
PCHSignature.emplace(EP.getSignature());
PCHInfo.emplace(PCHMergerInfo{EP.getSignature(), CurIndex.toArrayIndex()});
return false;
}
return true;

View File

@ -1371,17 +1371,17 @@ void COFFDumper::mergeCodeViewTypes(MergingTypeTableBuilder &CVIDs,
Obj->getFileName());
}
SmallVector<TypeIndex, 128> SourceToDest;
Optional<uint32_t> PCHSignature;
Optional<PCHMergerInfo> PCHInfo;
if (GHash) {
std::vector<GloballyHashedType> Hashes =
GloballyHashedType::hashTypes(Types);
if (Error E =
mergeTypeAndIdRecords(GlobalCVIDs, GlobalCVTypes, SourceToDest,
Types, Hashes, PCHSignature))
Types, Hashes, PCHInfo))
return reportError(std::move(E), Obj->getFileName());
} else {
if (Error E = mergeTypeAndIdRecords(CVIDs, CVTypes, SourceToDest, Types,
PCHSignature))
PCHInfo))
return reportError(std::move(E), Obj->getFileName());
}
}