Skip to content

Commit

Permalink
Give InfoStreamBuilder an opt-in method to write a hash of the PDB as…
Browse files Browse the repository at this point in the history
… GUID.

Naively computing the hash after the PDB data has been generated is in practice
as fast as other approaches I tried. I also tried online-computing the hash as
parts of the PDB were written out (https://reviews.llvm.org/D51887; that's also
where all the measuring data is) and computing the hash in parallel
(https://reviews.llvm.org/D51957). This approach here is simplest, without
being slower.

Differential Revision: https://reviews.llvm.org/D51956

llvm-svn: 342333
  • Loading branch information
nico committed Sep 15, 2018
1 parent da15acb commit 205ca68
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 14 deletions.
11 changes: 10 additions & 1 deletion llvm/include/llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h
Expand Up @@ -35,11 +35,18 @@ class InfoStreamBuilder {
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<uint32_t> getSignature() const { return Signature; }
Expand All @@ -60,6 +67,8 @@ class InfoStreamBuilder {
Optional<uint32_t> Signature;
codeview::GUID Guid;

bool HashPDBContentsToGUID = false;

NamedStreamMap &NamedStreams;
};
}
Expand Down
4 changes: 3 additions & 1 deletion llvm/include/llvm/DebugInfo/PDB/Native/PDBFileBuilder.h
Expand Up @@ -53,7 +53,9 @@ class PDBFileBuilder {
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<uint32_t> getNamedStreamIndex(StringRef Name) const;
Error addNamedStream(StringRef Name, StringRef Data);
Expand Down
11 changes: 8 additions & 3 deletions llvm/lib/DebugInfo/PDB/Native/InfoStreamBuilder.cpp
Expand Up @@ -32,15 +32,20 @@ InfoStreamBuilder::InfoStreamBuilder(msf::MSFBuilder &Msf,

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) +
Expand Down
33 changes: 26 additions & 7 deletions llvm/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp
Expand Up @@ -25,6 +25,7 @@
#include "llvm/Support/BinaryStreamWriter.h"
#include "llvm/Support/JamCRC.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/xxhash.h"

using namespace llvm;
using namespace llvm::codeview;
Expand Down Expand Up @@ -261,13 +262,14 @@ void PDBFileBuilder::commitInjectedSources(WritableBinaryStream &MsfBuffer,
}
}

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<FileBufferByteStream> ExpectedMsfBuffer =
Msf->commit(Filename, Layout);
if (!ExpectedMsfBuffer)
return ExpectedMsfBuffer.takeError();
FileBufferByteStream Buffer = std::move(*ExpectedMsfBuffer);
Expand Down Expand Up @@ -329,11 +331,28 @@ Error PDBFileBuilder::commit(StringRef Filename) {

// Set the build id at the very end, after every other byte of the PDB
// has been written.
// FIXME: Use a hash of the PDB rather than time(nullptr) for the signature.
H->Age = Info->getAge();
H->Guid = Info->getGuid();
Optional<uint32_t> Sig = Info->getSignature();
H->Signature = Sig.hasValue() ? *Sig : time(nullptr);
if (Info->hashPDBContentsToGUID()) {
// Compute a hash of all sections of the output file.
uint64_t Digest =
xxHash64({Buffer.getBufferStart(), Buffer.getBufferEnd()});

H->Age = 1;

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);

// Put the hash in the Signature field too.
H->Signature = static_cast<uint32_t>(Digest);

// Return GUID to caller.
memcpy(Guid, H->Guid.Guid, 16);
} else {
H->Age = Info->getAge();
H->Guid = Info->getGuid();
Optional<uint32_t> Sig = Info->getSignature();
H->Signature = Sig.hasValue() ? *Sig : time(nullptr);
}

return Buffer.commit();
}
7 changes: 5 additions & 2 deletions llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp
Expand Up @@ -803,7 +803,8 @@ static void yamlToPdb(StringRef Path) {

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<IPDBSession> &Session) {
Expand Down Expand Up @@ -1263,7 +1264,9 @@ static void mergePdbs() {
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() {
Expand Down

0 comments on commit 205ca68

Please sign in to comment.