Index: lld/COFF/PDB.h =================================================================== --- lld/COFF/PDB.h +++ lld/COFF/PDB.h @@ -28,7 +28,7 @@ void createPDB(SymbolTable *Symtab, llvm::ArrayRef OutputSections, llvm::ArrayRef SectionTable, - const llvm::codeview::DebugInfo &BuildId); + llvm::codeview::DebugInfo *BuildId); std::pair getFileLine(const SectionChunk *C, uint32_t Addr); Index: lld/COFF/PDB.cpp =================================================================== --- lld/COFF/PDB.cpp +++ lld/COFF/PDB.cpp @@ -93,7 +93,7 @@ } /// Emit the basic PDB structure: initial streams, headers, etc. - void initialize(const llvm::codeview::DebugInfo &BuildId); + void initialize(llvm::codeview::DebugInfo *BuildId); /// Add natvis files specified on the command line. void addNatvisFiles(); @@ -125,8 +125,8 @@ void addSections(ArrayRef OutputSections, ArrayRef SectionTable); - /// Write the PDB to disk. - void commit(); + /// Write the PDB to disk and return the Guid generated for it. + void commit(codeview::GUID *Guid); private: BumpPtrAllocator Alloc; @@ -331,8 +331,8 @@ return std::move(NS); } -Expected PDBLinker::maybeMergeTypeServerPDB(ObjFile *File, - TypeServer2Record &TS) { +Expected +PDBLinker::maybeMergeTypeServerPDB(ObjFile *File, TypeServer2Record &TS) { const GUID &TSId = TS.getGuid(); StringRef TSPath = TS.getName(); @@ -952,7 +952,8 @@ // subsections. auto NewChecksums = make_unique(PDBStrTab); for (FileChecksumEntry &FC : Checksums) { - SmallString<128> FileName = ExitOnErr(CVStrTab.getString(FC.FileNameOffset)); + SmallString<128> FileName = + ExitOnErr(CVStrTab.getString(FC.FileNameOffset)); if (!sys::path::is_absolute(FileName) && !Config->PDBSourcePath.empty()) { SmallString<128> AbsoluteFileName = Config->PDBSourcePath; @@ -1131,7 +1132,7 @@ void coff::createPDB(SymbolTable *Symtab, ArrayRef OutputSections, ArrayRef SectionTable, - const llvm::codeview::DebugInfo &BuildId) { + llvm::codeview::DebugInfo *BuildId) { ScopedTimer T1(TotalPdbLinkTimer); PDBLinker PDB(Symtab); @@ -1141,12 +1142,19 @@ PDB.addNatvisFiles(); ScopedTimer T2(DiskCommitTimer); - PDB.commit(); + codeview::GUID Guid; + PDB.commit(&Guid); + memcpy(&BuildId->PDB70.Signature, &Guid, 16); } -void PDBLinker::initialize(const llvm::codeview::DebugInfo &BuildId) { +void PDBLinker::initialize(llvm::codeview::DebugInfo *BuildId) { ExitOnErr(Builder.initialize(4096)); // 4096 is blocksize + BuildId->Signature.CVSignature = OMF::Signature::PDB70; + // Signature is set to a hash of the PDB contents when the PDB is done. + memset(BuildId->PDB70.Signature, 0, 16); + BuildId->PDB70.Age = 1; + // Create streams in MSF for predefined streams, namely // PDB, TPI, DBI and IPI. for (int I = 0; I < (int)pdb::kSpecialStreamCount; ++I) @@ -1154,15 +1162,12 @@ // Add an Info stream. auto &InfoBuilder = Builder.getInfoBuilder(); - GUID uuid; - memcpy(&uuid, &BuildId.PDB70.Signature, sizeof(uuid)); - InfoBuilder.setAge(BuildId.PDB70.Age); - InfoBuilder.setGuid(uuid); InfoBuilder.setVersion(pdb::PdbRaw_ImplVer::PdbImplVC70); + InfoBuilder.setHashPDBContentsToGUID(true); // Add an empty DBI stream. pdb::DbiStreamBuilder &DbiBuilder = Builder.getDbiBuilder(); - DbiBuilder.setAge(BuildId.PDB70.Age); + DbiBuilder.setAge(BuildId->PDB70.Age); DbiBuilder.setVersionHeader(pdb::PdbDbiV70); DbiBuilder.setMachineType(Config->Machine); // Technically we are not link.exe 14.11, but there are known cases where @@ -1206,9 +1211,9 @@ DbiBuilder.addDbgStream(pdb::DbgHeaderType::SectionHdr, SectionTable)); } -void PDBLinker::commit() { +void PDBLinker::commit(codeview::GUID *Guid) { // Write to a file. - ExitOnErr(Builder.commit(Config->PDBPath)); + ExitOnErr(Builder.commit(Config->PDBPath, Guid)); } static Expected Index: lld/COFF/Writer.cpp =================================================================== --- lld/COFF/Writer.cpp +++ lld/COFF/Writer.cpp @@ -209,7 +209,6 @@ DebugDirectoryChunk *DebugDirectory = nullptr; std::vector DebugRecords; CVDebugRecordChunk *BuildId = nullptr; - Optional PreviousBuildId; ArrayRef SectionTable; uint64_t FileSize; @@ -285,67 +284,6 @@ } // namespace coff } // namespace lld -// PDBs are matched against executables using a build id which consists of three -// components: -// 1. A 16-bit GUID -// 2. An age -// 3. A time stamp. -// -// Debuggers and symbol servers match executables against debug info by checking -// each of these components of the EXE/DLL against the corresponding value in -// the PDB and failing a match if any of the components differ. In the case of -// symbol servers, symbols are cached in a folder that is a function of the -// GUID. As a result, in order to avoid symbol cache pollution where every -// incremental build copies a new PDB to the symbol cache, we must try to re-use -// the existing GUID if one exists, but bump the age. This way the match will -// fail, so the symbol cache knows to use the new PDB, but the GUID matches, so -// it overwrites the existing item in the symbol cache rather than making a new -// one. -static Optional loadExistingBuildId(StringRef Path) { - // We don't need to incrementally update a previous build id if we're not - // writing codeview debug info. - if (!Config->Debug) - return None; - - auto ExpectedBinary = llvm::object::createBinary(Path); - if (!ExpectedBinary) { - consumeError(ExpectedBinary.takeError()); - return None; - } - - auto Binary = std::move(*ExpectedBinary); - if (!Binary.getBinary()->isCOFF()) - return None; - - std::error_code EC; - COFFObjectFile File(Binary.getBinary()->getMemoryBufferRef(), EC); - if (EC) - return None; - - // If the machine of the binary we're outputting doesn't match the machine - // of the existing binary, don't try to re-use the build id. - if (File.is64() != Config->is64() || File.getMachine() != Config->Machine) - return None; - - for (const auto &DebugDir : File.debug_directories()) { - if (DebugDir.Type != IMAGE_DEBUG_TYPE_CODEVIEW) - continue; - - const codeview::DebugInfo *ExistingDI = nullptr; - StringRef PDBFileName; - if (auto EC = File.getDebugPDBInfo(ExistingDI, PDBFileName)) { - (void)EC; - return None; - } - // We only support writing PDBs in v70 format. So if this is not a build - // id that we recognize / support, ignore it. - if (ExistingDI->Signature.CVSignature != OMF::Signature::PDB70) - return None; - return *ExistingDI; - } - return None; -} - // The main function of the writer. void Writer::run() { ScopedTimer T1(CodeLayoutTimer); @@ -364,9 +302,6 @@ fatal("image size (" + Twine(FileSize) + ") " + "exceeds maximum allowable size (" + Twine(UINT32_MAX) + ")"); - // We must do this before opening the output file, as it depends on being able - // to read the contents of the existing output file. - PreviousBuildId = loadExistingBuildId(Config->OutputFile); openFile(Config->OutputFile); if (Config->is64()) { writeHeader(); @@ -375,14 +310,14 @@ } writeSections(); sortExceptionTable(); - writeBuildId(); T1.stop(); if (!Config->PDBPath.empty() && Config->Debug) { assert(BuildId); - createPDB(Symtab, OutputSections, SectionTable, *BuildId->BuildId); + createPDB(Symtab, OutputSections, SectionTable, BuildId->BuildId); } + writeBuildId(); writeMapFile(OutputSections); @@ -1225,25 +1160,10 @@ // timestamp as well as a Guid and Age of the PDB. // 2) In all cases, the PE COFF file header also contains a timestamp. // For reproducibility, instead of a timestamp we want to use a hash of the - // binary, however when building with debug info the hash needs to take into - // account the debug info, since it's possible to add blank lines to a file - // which causes the debug info to change but not the generated code. - // - // To handle this, we first set the Guid and Age in the debug directory (but - // only if we're doing a debug build). Then, we hash the binary (thus causing - // the hash to change if only the debug info changes, since the Age will be - // different). Finally, we write that hash into the debug directory (if - // present) as well as the COFF file header (always). + // PE contents. if (Config->Debug) { assert(BuildId && "BuildId is not set!"); - if (PreviousBuildId.hasValue()) { - *BuildId->BuildId = *PreviousBuildId; - BuildId->BuildId->PDB70.Age = BuildId->BuildId->PDB70.Age + 1; - } else { - BuildId->BuildId->Signature.CVSignature = OMF::Signature::PDB70; - BuildId->BuildId->PDB70.Age = 1; - llvm::getRandomBytes(BuildId->BuildId->PDB70.Signature, 16); - } + // BuildId->BuildId was filled in when the PDB was written. } // At this point the only fields in the COFF file which remain unset are the Index: lld/test/COFF/rsds.test =================================================================== --- lld/test/COFF/rsds.test +++ lld/test/COFF/rsds.test @@ -1,9 +1,9 @@ # RUN: yaml2obj %s > %t.obj # RUN: rm -f %t.dll %t.pdb -# RUN: lld-link /debug /pdbaltpath:test1.pdb /dll /out:%t.dll /entry:DllMain %t.obj +# RUN: lld-link /debug /pdbaltpath:test.pdb /dll /out:%t.dll /entry:DllMain %t.obj # RUN: llvm-readobj -coff-debug-directory %t.dll > %t.1.txt -# RUN: lld-link /debug /pdbaltpath:test2.pdb /dll /out:%t.dll /entry:DllMain %t.obj +# RUN: lld-link /debug /pdbaltpath:test.pdb /dll /out:%t.dll /entry:DllMain %t.obj # RUN: llvm-readobj -coff-debug-directory %t.dll > %t.2.txt # RUN: cat %t.1.txt %t.2.txt | FileCheck %s @@ -12,7 +12,7 @@ # RUN: llvm-readobj -coff-debug-directory %t.dll > %t.3.txt # RUN: lld-link /debug /pdb:%t2.pdb /dll /out:%t.dll /entry:DllMain %t.obj # RUN: llvm-readobj -coff-debug-directory %t.dll > %t.4.txt -# RUN: cat %t.3.txt %t.4.txt | FileCheck %s +# RUN: cat %t.3.txt %t.4.txt | FileCheck --check-prefix TWOPDBS %s # RUN: rm -f %t.dll %t.pdb # RUN: lld-link /Brepro /dll /out:%t.dll /entry:DllMain %t.obj @@ -37,7 +37,7 @@ # CHECK: PDBSignature: 0x53445352 # CHECK: PDBGUID: [[GUID:\(([A-Za-z0-9]{2} ?){16}\)]] # CHECK: PDBAge: 1 -# CHECK: PDBFileName: {{.*}}1.pdb +# CHECK: PDBFileName: {{.*}}.pdb # CHECK: } # CHECK: } # CHECK: ] @@ -55,12 +55,51 @@ # CHECK: PDBInfo { # CHECK: PDBSignature: 0x53445352 # CHECK: PDBGUID: [[GUID]] -# CHECK: PDBAge: 2 -# CHECK: PDBFileName: {{.*}}2.pdb +# CHECK: PDBAge: 1 +# CHECK: PDBFileName: {{.*}}.pdb # CHECK: } # CHECK: } # CHECK: ] +# TWOPDBS: File: [[FILE:.*]].dll +# TWOPDBS: DebugDirectory [ +# TWOPDBS: DebugEntry { +# TWOPDBS: Characteristics: 0x0 +# TWOPDBS: TimeDateStamp: +# TWOPDBS: MajorVersion: 0x0 +# TWOPDBS: MinorVersion: 0x0 +# TWOPDBS: Type: CodeView (0x2) +# TWOPDBS: SizeOfData: 0x{{[^0]}} +# TWOPDBS: AddressOfRawData: 0x{{[^0]}} +# TWOPDBS: PointerToRawData: 0x{{[^0]}} +# TWOPDBS: PDBInfo { +# TWOPDBS: PDBSignature: 0x53445352 +# TWOPDBS: PDBGUID: [[GUID:\(([A-Za-z0-9]{2} ?){16}\)]] +# TWOPDBS: PDBAge: 1 +# TWOPDBS: PDBFileName: {{.*}}.pdb +# TWOPDBS: } +# TWOPDBS: } +# TWOPDBS: ] +# TWOPDBS: File: [[FILE]].dll +# TWOPDBS: DebugDirectory [ +# TWOPDBS: DebugEntry { +# TWOPDBS: Characteristics: 0x0 +# TWOPDBS: TimeDateStamp: +# TWOPDBS: MajorVersion: 0x0 +# TWOPDBS: MinorVersion: 0x0 +# TWOPDBS: Type: CodeView (0x2) +# TWOPDBS: SizeOfData: 0x{{[^0]}} +# TWOPDBS: AddressOfRawData: 0x{{[^0]}} +# TWOPDBS: PointerToRawData: 0x{{[^0]}} +# TWOPDBS: PDBInfo { +# TWOPDBS: PDBSignature: 0x53445352 +# TWOPDBS-NOT: PDBGUID: [[GUID]] +# TWOPDBS: PDBAge: 1 +# TWOPDBS: PDBFileName: {{.*}}.pdb +# TWOPDBS: } +# TWOPDBS: } +# TWOPDBS: ] + # REPRO: File: {{.*}}.dll # REPRO: DebugDirectory [ # REPRO: DebugEntry { Index: llvm/include/llvm/DebugInfo/MSF/MSFBuilder.h =================================================================== --- llvm/include/llvm/DebugInfo/MSF/MSFBuilder.h +++ llvm/include/llvm/DebugInfo/MSF/MSFBuilder.h @@ -14,13 +14,42 @@ #include "llvm/ADT/BitVector.h" #include "llvm/DebugInfo/MSF/MSFCommon.h" #include "llvm/Support/Allocator.h" +#include "llvm/Support/BinaryByteStream.h" #include "llvm/Support/Error.h" +#include "llvm/Support/xxhash.h" #include #include #include namespace llvm { -class FileBufferByteStream; + +class HashingFileBufferByteStream final : public FileBufferByteStream { +public: + HashingFileBufferByteStream(std::unique_ptr Buffer, + llvm::support::endianness Endian) + : FileBufferByteStream(std::move(Buffer), Endian), + HashState(XXH64_createState()) { + XXH64_reset(HashState, 0); + } + + HashingFileBufferByteStream(HashingFileBufferByteStream &&RHS) + : FileBufferByteStream(std::move(RHS)) { + HashState = RHS.HashState; + RHS.HashState = nullptr; + } + + ~HashingFileBufferByteStream() { + XXH64_freeState(HashState); + } + + Error writeBytes(uint32_t Offset, ArrayRef Data) override { + XXH64_update(HashState, Data.data(), Data.size()); + return FileBufferByteStream::writeBytes(Offset, Data); + } + + XXH64_state_t *HashState; +}; + class WritableBinaryStream; namespace msf { @@ -114,7 +143,8 @@ Expected generateLayout(); /// Write the MSF layout to the underlying file. - Expected commit(StringRef Path, MSFLayout &Layout); + Expected commit(StringRef Path, + MSFLayout &Layout); BumpPtrAllocator &getAllocator() { return Allocator; } Index: llvm/include/llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h =================================================================== --- llvm/include/llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h +++ llvm/include/llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h @@ -35,11 +35,18 @@ InfoStreamBuilder &operator=(const InfoStreamBuilder &) = delete; void setVersion(PdbRaw_ImplVer V); + void addFeature(PdbRaw_FeatureSig Sig); + + // If this is true, the PDB contents are hashed and this hash is used as + // PDB GUID and as Signature. The age is always 1. + void setHashPDBContentsToGUID(bool B); + + // These only have an effect if hashPDBContentsToGUID() is false. void setSignature(uint32_t S); void setAge(uint32_t A); void setGuid(codeview::GUID G); - void addFeature(PdbRaw_FeatureSig Sig); + bool hashPDBContentsToGUID() const { return HashPDBContentsToGUID; } uint32_t getAge() const { return Age; } codeview::GUID getGuid() const { return Guid; } Optional getSignature() const { return Signature; } @@ -60,6 +67,8 @@ Optional Signature; codeview::GUID Guid; + bool HashPDBContentsToGUID = false; + NamedStreamMap &NamedStreams; }; } Index: llvm/include/llvm/DebugInfo/PDB/Native/PDBFileBuilder.h =================================================================== --- llvm/include/llvm/DebugInfo/PDB/Native/PDBFileBuilder.h +++ llvm/include/llvm/DebugInfo/PDB/Native/PDBFileBuilder.h @@ -53,7 +53,9 @@ PDBStringTableBuilder &getStringTableBuilder(); GSIStreamBuilder &getGsiBuilder(); - Error commit(StringRef Filename); + // If HashPDBContentsToGUID is true on the InfoStreamBuilder, Guid is filled + // with the computed PDB GUID on return. + Error commit(StringRef Filename, codeview::GUID *Guid); Expected getNamedStreamIndex(StringRef Name) const; Error addNamedStream(StringRef Name, StringRef Data); Index: llvm/include/llvm/Support/xxhash.h =================================================================== --- llvm/include/llvm/Support/xxhash.h +++ llvm/include/llvm/Support/xxhash.h @@ -44,6 +44,18 @@ namespace llvm { uint64_t xxHash64(llvm::StringRef Data); uint64_t xxHash64(llvm::ArrayRef Data); + +// Streaming support. +typedef enum { XXH_OK=0, XXH_ERROR } XXH_errorcode; +typedef struct XXH64_state_s XXH64_state_t; /* incomplete type */ + +XXH64_state_t *XXH64_createState(); +XXH_errorcode XXH64_freeState(XXH64_state_t *statePtr); +XXH_errorcode XXH64_reset(XXH64_state_t *statePtr, unsigned long long seed); +XXH_errorcode XXH64_update(XXH64_state_t *statePtr, const void *input, + size_t length); +// FIXME: do i want this? do i want a 128 version? +uint64_t XXH64_digest(const XXH64_state_t *statePtr); } #endif Index: llvm/lib/DebugInfo/MSF/MSFBuilder.cpp =================================================================== --- llvm/lib/DebugInfo/MSF/MSFBuilder.cpp +++ llvm/lib/DebugInfo/MSF/MSFBuilder.cpp @@ -11,7 +11,6 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/DebugInfo/MSF/MSFError.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/Support/BinaryByteStream.h" #include "llvm/Support/BinaryStreamWriter.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" @@ -336,8 +335,8 @@ assert(FpmWriter.bytesRemaining() == 0); } -Expected MSFBuilder::commit(StringRef Path, - MSFLayout &Layout) { +Expected MSFBuilder::commit(StringRef Path, + MSFLayout &Layout) { Expected L = generateLayout(); if (!L) return L.takeError(); @@ -349,7 +348,7 @@ if (auto EC = OutFileOrError.takeError()) return std::move(EC); - FileBufferByteStream Buffer(std::move(*OutFileOrError), + HashingFileBufferByteStream Buffer(std::move(*OutFileOrError), llvm::support::little); BinaryStreamWriter Writer(Buffer); Index: llvm/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp =================================================================== --- llvm/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp +++ llvm/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp @@ -310,13 +310,14 @@ PublicsStreamHeader Header; // FIXME: Fill these in. They are for incremental linking. + Header.SymHash = PSH->calculateSerializedLength(); + Header.AddrMap = PSH->Records.size() * 4; Header.NumThunks = 0; Header.SizeOfThunk = 0; Header.ISectThunkTable = 0; + memset(Header.Padding, 0, sizeof(Header.Padding)); Header.OffThunkTable = 0; Header.NumSections = 0; - Header.SymHash = PSH->calculateSerializedLength(); - Header.AddrMap = PSH->Records.size() * 4; if (auto EC = Writer.writeObject(Header)) return EC; Index: llvm/lib/DebugInfo/PDB/Native/InfoStreamBuilder.cpp =================================================================== --- llvm/lib/DebugInfo/PDB/Native/InfoStreamBuilder.cpp +++ llvm/lib/DebugInfo/PDB/Native/InfoStreamBuilder.cpp @@ -32,15 +32,20 @@ void InfoStreamBuilder::setVersion(PdbRaw_ImplVer V) { Ver = V; } +void InfoStreamBuilder::addFeature(PdbRaw_FeatureSig Sig) { + Features.push_back(Sig); +} + +void InfoStreamBuilder::setHashPDBContentsToGUID(bool B) { + HashPDBContentsToGUID = B; +} + void InfoStreamBuilder::setAge(uint32_t A) { Age = A; } void InfoStreamBuilder::setSignature(uint32_t S) { Signature = S; } void InfoStreamBuilder::setGuid(GUID G) { Guid = G; } -void InfoStreamBuilder::addFeature(PdbRaw_FeatureSig Sig) { - Features.push_back(Sig); -} Error InfoStreamBuilder::finalizeMsfLayout() { uint32_t Length = sizeof(InfoStreamHeader) + Index: llvm/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp =================================================================== --- llvm/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp +++ llvm/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp @@ -261,16 +261,17 @@ } } -Error PDBFileBuilder::commit(StringRef Filename) { +Error PDBFileBuilder::commit(StringRef Filename, codeview::GUID *Guid) { assert(!Filename.empty()); if (auto EC = finalizeMsfLayout()) return EC; MSFLayout Layout; - auto ExpectedMsfBuffer = Msf->commit(Filename, Layout); + Expected ExpectedMsfBuffer = + Msf->commit(Filename, Layout); if (!ExpectedMsfBuffer) return ExpectedMsfBuffer.takeError(); - FileBufferByteStream Buffer = std::move(*ExpectedMsfBuffer); + HashingFileBufferByteStream Buffer = std::move(*ExpectedMsfBuffer); auto ExpectedSN = getNamedStreamIndex("/names"); if (!ExpectedSN) @@ -329,9 +330,22 @@ // Set the build id at the very end, after every other byte of the PDB // has been written. + if (Info->hashPDBContentsToGUID()) { + H->Age = 1; + uint64_t Digest = XXH64_digest(Buffer.HashState); + memcpy(H->Guid.Guid, &Digest, 8); + // xxhash only gives us 8 bytes, so put some fixed data in the other half. + memcpy(H->Guid.Guid + 8, "LLD PDB.", 8); + + // Return GUID to caller. + memcpy(Guid, H->Guid.Guid, 16); + } else { + H->Age = Info->getAge(); + H->Guid = Info->getGuid(); + } + // FIXME: Use a hash of the PDB rather than time(nullptr) for the signature. - H->Age = Info->getAge(); - H->Guid = Info->getGuid(); + // XXX: change this too Optional Sig = Info->getSignature(); H->Signature = Sig.hasValue() ? *Sig : time(nullptr); Index: llvm/lib/Support/xxhash.cpp =================================================================== --- llvm/lib/Support/xxhash.cpp +++ llvm/lib/Support/xxhash.cpp @@ -136,3 +136,144 @@ uint64_t llvm::xxHash64(ArrayRef Data) { return xxHash64({(const char *)Data.data(), Data.size()}); } + +struct llvm::XXH64_state_s { + uint64_t total_len; + uint64_t V1; + uint64_t V2; + uint64_t V3; + uint64_t V4; + uint64_t mem64[4]; + uint32_t memsize; +}; /* typedef'd to XXH64_state_t */ + +XXH64_state_t *llvm::XXH64_createState(void) { + return (XXH64_state_t *)malloc(sizeof(XXH64_state_t)); +} + +XXH_errorcode llvm::XXH64_freeState(XXH64_state_t *statePtr) { + free(statePtr); + return XXH_OK; +} + +XXH_errorcode llvm::XXH64_reset(XXH64_state_t *statePtr, unsigned long long seed) { + XXH64_state_t state; /* using a local state to memcpy() in order to avoid + strict-aliasing warnings */ + memset(&state, 0, sizeof(state)); + state.V1 = seed + PRIME64_1 + PRIME64_2; + state.V2 = seed + PRIME64_2; + state.V3 = seed + 0; + state.V4 = seed - PRIME64_1; + memcpy(statePtr, &state, sizeof(state)); + return XXH_OK; +} + +XXH_errorcode llvm::XXH64_update(XXH64_state_t *state, const void *input, + size_t len) { + const unsigned char *P = (const unsigned char *)input; + const unsigned char *const BEnd = P + len; + + if (input == NULL) + return XXH_ERROR; + + state->total_len += len; + + if (state->memsize + len < 32) { /* fill in tmp buffer */ + memcpy(((unsigned char *)state->mem64) + state->memsize, input, len); + state->memsize += (uint32_t)len; + return XXH_OK; + } + + if (state->memsize) { /* tmp buffer is full */ + memcpy(((unsigned char *)state->mem64) + state->memsize, input, + 32 - state->memsize); + state->V1 = round(state->V1, endian::read64le(state->mem64 + 0)); + state->V2 = round(state->V2, endian::read64le(state->mem64 + 1)); + state->V3 = round(state->V3, endian::read64le(state->mem64 + 2)); + state->V4 = round(state->V4, endian::read64le(state->mem64 + 3)); + P += 32 - state->memsize; + state->memsize = 0; + } + + if (P + 32 <= BEnd) { + const unsigned char *const Limit = BEnd - 32; + uint64_t V1 = state->V1; + uint64_t V2 = state->V2; + uint64_t V3 = state->V3; + uint64_t V4 = state->V4; + + do { + V1 = round(V1, endian::read64le(P)); + P += 8; + V2 = round(V2, endian::read64le(P)); + P += 8; + V3 = round(V3, endian::read64le(P)); + P += 8; + V4 = round(V4, endian::read64le(P)); + P += 8; + } while (P <= Limit); + + state->V1 = V1; + state->V2 = V2; + state->V3 = V3; + state->V4 = V4; + } + + if (P < BEnd) { + memcpy(state->mem64, P, (size_t)(BEnd - P)); + state->memsize = (unsigned)(BEnd - P); + } + + return XXH_OK; +} + +uint64_t llvm::XXH64_digest(const XXH64_state_t *state) { + const unsigned char *P = (const unsigned char *)state->mem64; + const unsigned char *const BEnd = + (const unsigned char *)state->mem64 + state->memsize; + uint64_t h64; + + if (state->total_len >= 32) { + uint64_t const V1 = state->V1; + uint64_t const V2 = state->V2; + uint64_t const V3 = state->V3; + uint64_t const V4 = state->V4; + + h64 = rotl64(V1, 1) + rotl64(V2, 7) + rotl64(V3, 12) + rotl64(V4, 18); + h64 = mergeRound(h64, V1); + h64 = mergeRound(h64, V2); + h64 = mergeRound(h64, V3); + h64 = mergeRound(h64, V4); + } else { + h64 = state->V3 + PRIME64_5; + } + + h64 += (uint64_t)state->total_len; + + while (P + 8 <= BEnd) { + uint64_t const k1 = round(0, endian::read64le(P)); + h64 ^= k1; + h64 = rotl64(h64, 27) * PRIME64_1 + PRIME64_4; + P += 8; + } + + if (P + 4 <= BEnd) { + h64 ^= (uint64_t)(endian::read32le(P)) * PRIME64_1; + h64 = rotl64(h64, 23) * PRIME64_2 + PRIME64_3; + P += 4; + } + + while (P < BEnd) { + h64 ^= (*P) * PRIME64_5; + h64 = rotl64(h64, 11) * PRIME64_1; + P++; + } + + h64 ^= h64 >> 33; + h64 *= PRIME64_2; + h64 ^= h64 >> 29; + h64 *= PRIME64_3; + h64 ^= h64 >> 32; + + return h64; +} Index: llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp =================================================================== --- llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp +++ llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp @@ -800,7 +800,8 @@ Builder.getStringTableBuilder().setStrings(*Strings.strings()); - ExitOnErr(Builder.commit(opts::yaml2pdb::YamlPdbOutputFile)); + codeview::GUID IgnoredOutGuid; + ExitOnErr(Builder.commit(opts::yaml2pdb::YamlPdbOutputFile, &IgnoredOutGuid)); } static PDBFile &loadPDB(StringRef Path, std::unique_ptr &Session) { @@ -1260,7 +1261,9 @@ OutFile = opts::merge::InputFilenames[0]; llvm::sys::path::replace_extension(OutFile, "merged.pdb"); } - ExitOnErr(Builder.commit(OutFile)); + + codeview::GUID IgnoredOutGuid; + ExitOnErr(Builder.commit(OutFile, &IgnoredOutGuid)); } static void explain() {