1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-20 03:23:01 +02:00

[llvm-pdbdump] Add support for diffing the PDB Stream.

In doing so I discovered that we completely ignore some bytes
of the PDB Stream after we "finish" loading it.  These bytes
seem to specify some additional information about what kind
of data is present in the PDB.  A subsequent patch will add
code to read in those fields and store their values.

llvm-svn: 297983
This commit is contained in:
Zachary Turner 2017-03-16 20:18:41 +00:00
parent ac2a0e4e02
commit 2830b2b9fe
8 changed files with 189 additions and 23 deletions

View File

@ -30,6 +30,10 @@ public:
inline detail::GuidAdapter fmt_guid(StringRef Item) {
return detail::GuidAdapter(Item);
}
inline detail::GuidAdapter fmt_guid(ArrayRef<uint8_t> Item) {
return detail::GuidAdapter(Item);
}
}
}

View File

@ -0,0 +1,52 @@
//===- Formatters.h ---------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_DEBUGINFO_PDB_NATIVE_FORMATTERS_H
#define LLVM_DEBUGINFO_PDB_NATIVE_FORMATTERS_H
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/DebugInfo/CodeView/Formatters.h"
#include "llvm/DebugInfo/PDB/Native/RawConstants.h"
#include "llvm/DebugInfo/PDB/Native/RawTypes.h"
#include "llvm/Support/FormatProviders.h"
#define FORMAT_CASE(Value, Name) \
case Value: \
Stream << Name; \
break;
namespace llvm {
template <> struct format_provider<pdb::PDB_UniqueId> {
static void format(const pdb::PDB_UniqueId &V, llvm::raw_ostream &Stream,
StringRef Style) {
codeview::fmt_guid(V.Guid).format(Stream, Style);
}
};
template <> struct format_provider<pdb::PdbRaw_ImplVer> {
static void format(const pdb::PdbRaw_ImplVer &V, llvm::raw_ostream &Stream,
StringRef Style) {
switch (V) {
FORMAT_CASE(pdb::PdbRaw_ImplVer::PdbImplVC110, "VC110")
FORMAT_CASE(pdb::PdbRaw_ImplVer::PdbImplVC140, "VC140")
FORMAT_CASE(pdb::PdbRaw_ImplVer::PdbImplVC2, "VC2")
FORMAT_CASE(pdb::PdbRaw_ImplVer::PdbImplVC4, "VC4")
FORMAT_CASE(pdb::PdbRaw_ImplVer::PdbImplVC41, "VC41")
FORMAT_CASE(pdb::PdbRaw_ImplVer::PdbImplVC50, "VC50")
FORMAT_CASE(pdb::PdbRaw_ImplVer::PdbImplVC70, "VC70")
FORMAT_CASE(pdb::PdbRaw_ImplVer::PdbImplVC70Dep, "VC70Dep")
FORMAT_CASE(pdb::PdbRaw_ImplVer::PdbImplVC80, "VC80")
FORMAT_CASE(pdb::PdbRaw_ImplVer::PdbImplVC98, "VC98")
}
}
};
}
#endif

View File

@ -32,10 +32,13 @@ public:
Error reload();
uint32_t getStreamSize() const;
PdbRaw_ImplVer getVersion() const;
uint32_t getSignature() const;
uint32_t getAge() const;
PDB_UniqueId getGuid() const;
uint32_t getNamedStreamMapByteSize() const;
const NamedStreamMap &getNamedStreams() const;
@ -63,6 +66,8 @@ private:
// universally unique.
PDB_UniqueId Guid;
uint32_t NamedStreamMapByteSize = 0;
NamedStreamMap NamedStreams;
};
}

View File

@ -36,6 +36,7 @@ public:
Error commit(BinaryStreamWriter &Writer) const;
uint32_t finalize();
uint32_t size() const;
bool get(StringRef Stream, uint32_t &StreamNo) const;
void set(StringRef Stream, uint32_t StreamNo);
void remove(StringRef Stream);

View File

@ -266,6 +266,10 @@ struct PDB_UniqueId {
uint8_t Guid[16];
};
inline bool operator==(const PDB_UniqueId &LHS, const PDB_UniqueId &RHS) {
return 0 == ::memcmp(LHS.Guid, RHS.Guid, sizeof(LHS.Guid));
}
// The header preceeding the global TPI stream.
// This corresponds to `HDR` in PDB/dbi/tpi.h.
struct TpiStreamHeader {

View File

@ -51,9 +51,16 @@ Error InfoStream::reload() {
Age = H->Age;
Guid = H->Guid;
return NamedStreams.load(Reader);
uint32_t Offset = Reader.getOffset();
if (auto EC = NamedStreams.load(Reader))
return EC;
uint32_t NewOffset = Reader.getOffset();
NamedStreamMapByteSize = NewOffset - Offset;
return Error::success();
}
uint32_t InfoStream::getStreamSize() const { return Stream->getLength(); }
uint32_t InfoStream::getNamedStreamIndex(llvm::StringRef Name) const {
uint32_t Result;
if (!NamedStreams.get(Name, Result))
@ -76,6 +83,10 @@ uint32_t InfoStream::getAge() const { return Age; }
PDB_UniqueId InfoStream::getGuid() const { return Guid; }
uint32_t InfoStream::getNamedStreamMapByteSize() const {
return NamedStreamMapByteSize;
}
const NamedStreamMap &InfoStream::getNamedStreams() const {
return NamedStreams;
}

View File

@ -114,6 +114,8 @@ NamedStreamMap::entries() const {
Mapping.end());
}
uint32_t NamedStreamMap::size() const { return Mapping.size(); }
bool NamedStreamMap::get(StringRef Stream, uint32_t &StreamNo) const {
auto Iter = Mapping.find(Stream);
if (Iter == Mapping.end())

View File

@ -12,6 +12,8 @@
#include "StreamUtil.h"
#include "llvm-pdbdump.h"
#include "llvm/DebugInfo/PDB/Native/Formatters.h"
#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
#include "llvm/DebugInfo/PDB/Native/RawConstants.h"
#include "llvm/DebugInfo/PDB/Native/StringTable.h"
@ -114,12 +116,37 @@ Error DiffStyle::dump() {
template <typename T>
static bool diffAndPrint(StringRef Label, PDBFile &File1, PDBFile &File2, T V1,
T V2) {
if (V1 != V2) {
outs().indent(2) << Label << "\n";
outs().indent(4) << formatv("{0}: {1}\n", File1.getFilePath(), V1);
outs().indent(4) << formatv("{0}: {1}\n", File2.getFilePath(), V2);
if (V1 == V2) {
outs() << formatv(" {0}: No differences detected!\n", Label);
return false;
}
return (V1 != V2);
outs().indent(2) << Label << "\n";
outs().indent(4) << formatv("{0}: {1}\n", File1.getFilePath(), V1);
outs().indent(4) << formatv("{0}: {1}\n", File2.getFilePath(), V2);
return true;
}
template <typename T>
static bool printSymmetricDifferences(PDBFile &File1, PDBFile &File2,
T &&OnlyRange1, T &&OnlyRange2,
StringRef Label) {
bool HasDiff = false;
if (!OnlyRange1.empty()) {
HasDiff = true;
outs() << formatv(" {0} {1}(s) only in ({2})\n", OnlyRange1.size(), Label,
File1.getFilePath());
for (const auto &Item : OnlyRange1)
outs() << formatv(" {0}\n", Label, Item);
}
if (!OnlyRange2.empty()) {
HasDiff = true;
outs() << formatv(" {0} {1}(s) only in ({2})\n", OnlyRange2.size(),
File2.getFilePath());
for (const auto &Item : OnlyRange2)
outs() << formatv(" {0}\n", Item);
}
return HasDiff;
}
Error DiffStyle::diffSuperBlock() {
@ -299,8 +326,16 @@ Error DiffStyle::diffStringTable() {
auto &ST1 = *ExpectedST1;
auto &ST2 = *ExpectedST2;
HasDiff |= diffAndPrint("Stream Size", File1, File2, ST1.getByteSize(),
ST2.getByteSize());
if (ST1.getByteSize() != ST2.getByteSize()) {
outs() << " Stream Size\n";
outs() << formatv(" {0} - {1} byte(s)\n", File1.getFilePath(),
ST1.getByteSize());
outs() << formatv(" {0} - {1} byte(s)\n", File2.getFilePath(),
ST2.getByteSize());
outs() << formatv(" Difference: {0} bytes\n",
AbsoluteDifference(ST1.getByteSize(), ST2.getByteSize()));
HasDiff = true;
}
HasDiff |= diffAndPrint("Hash Version", File1, File2, ST1.getHashVersion(),
ST1.getHashVersion());
HasDiff |= diffAndPrint("Signature", File1, File2, ST1.getSignature(),
@ -351,22 +386,21 @@ Error DiffStyle::diffStringTable() {
SmallVector<StringRef, 64> OnlyP;
SmallVector<StringRef, 64> OnlyQ;
auto End1 = std::remove(Strings1.begin(), Strings1.end(), "");
auto End2 = std::remove(Strings2.begin(), Strings2.end(), "");
uint32_t Empty1 = std::distance(End1, Strings1.end());
uint32_t Empty2 = std::distance(End2, Strings2.end());
Strings1.erase(End1, Strings1.end());
Strings2.erase(End2, Strings2.end());
set_differences(Strings1, Strings2, &OnlyP, &OnlyQ);
printSymmetricDifferences(File1, File2, OnlyP, OnlyQ, "String");
if (!OnlyP.empty()) {
HasDiff = true;
outs() << formatv(" {0} String(s) only in ({1})\n", OnlyP.size(),
File1.getFilePath());
for (auto Item : OnlyP)
outs() << formatv(" {2}\n", Item);
}
if (!OnlyQ.empty()) {
HasDiff = true;
outs() << formatv(" {0} String(s) only in ({1})\n", OnlyQ.size(),
File2.getFilePath());
for (auto Item : OnlyQ)
outs() << formatv(" {2}\n", Item);
if (Empty1 != Empty2) {
PDBFile &MoreF = (Empty1 > Empty2) ? File1 : File2;
PDBFile &LessF = (Empty1 < Empty2) ? File1 : File2;
uint32_t Difference = AbsoluteDifference(Empty1, Empty2);
outs() << formatv(" {0} had {1} more empty strings than {2}\n",
MoreF.getFilePath(), Difference, LessF.getFilePath());
}
}
if (!HasDiff)
@ -376,7 +410,60 @@ Error DiffStyle::diffStringTable() {
Error DiffStyle::diffFreePageMap() { return Error::success(); }
Error DiffStyle::diffInfoStream() { return Error::success(); }
Error DiffStyle::diffInfoStream() {
auto ExpectedInfo1 = File1.getPDBInfoStream();
auto ExpectedInfo2 = File2.getPDBInfoStream();
outs() << "PDB Stream: Searching for differences...\n";
bool Has1 = !!ExpectedInfo1;
bool Has2 = !!ExpectedInfo2;
if (!(Has1 && Has2)) {
if (Has1 != Has2)
outs() << formatv("{0} does not have a PDB Stream!\n",
Has1 ? File1.getFilePath() : File2.getFilePath());
consumeError(ExpectedInfo2.takeError());
consumeError(ExpectedInfo2.takeError());
return Error::success();
}
bool HasDiff = false;
auto &IS1 = *ExpectedInfo1;
auto &IS2 = *ExpectedInfo2;
if (IS1.getStreamSize() != IS2.getStreamSize()) {
outs() << " Stream Size\n";
outs() << formatv(" {0} - {1} byte(s)\n", File1.getFilePath(),
IS1.getStreamSize());
outs() << formatv(" {0} - {1} byte(s)\n", File2.getFilePath(),
IS2.getStreamSize());
outs() << formatv(
" Difference: {0} bytes\n",
AbsoluteDifference(IS1.getStreamSize(), IS2.getStreamSize()));
HasDiff = true;
}
HasDiff |= diffAndPrint("Age", File1, File2, IS1.getAge(), IS2.getAge());
HasDiff |= diffAndPrint("Guid", File1, File2, IS1.getGuid(), IS2.getGuid());
HasDiff |= diffAndPrint("Signature", File1, File2, IS1.getSignature(),
IS2.getSignature());
HasDiff |=
diffAndPrint("Version", File1, File2, IS1.getVersion(), IS2.getVersion());
HasDiff |= diffAndPrint("Named Stream Byte Size", File1, File2,
IS1.getNamedStreamMapByteSize(),
IS2.getNamedStreamMapByteSize());
SmallVector<StringRef, 4> NS1;
SmallVector<StringRef, 4> NS2;
for (const auto &X : IS1.getNamedStreams().entries())
NS1.push_back(X.getKey());
for (const auto &X : IS2.getNamedStreams().entries())
NS2.push_back(X.getKey());
SmallVector<StringRef, 4> OnlyP;
SmallVector<StringRef, 4> OnlyQ;
set_differences(NS1, NS2, &OnlyP, &OnlyQ);
printSymmetricDifferences(File1, File2, OnlyP, OnlyQ, "Named Streams");
if (!HasDiff)
outs() << "PDB Stream: No differences detected!\n";
return Error::success();
}
Error DiffStyle::diffDbiStream() { return Error::success(); }