forked from OSchip/llvm-project
[llvm-pdbdump] Add support for diffing the String Table.
llvm-svn: 297901
This commit is contained in:
parent
ea4e60754e
commit
f1220084f6
|
@ -30,6 +30,8 @@ public:
|
|||
|
||||
Error load(BinaryStreamReader &Stream);
|
||||
|
||||
uint32_t getByteSize() const;
|
||||
|
||||
uint32_t getNameCount() const { return NameCount; }
|
||||
uint32_t getHashVersion() const { return HashVersion; }
|
||||
uint32_t getSignature() const { return Signature; }
|
||||
|
@ -42,9 +44,10 @@ public:
|
|||
private:
|
||||
BinaryStreamRef NamesBuffer;
|
||||
FixedStreamArray<support::ulittle32_t> IDs;
|
||||
uint32_t Signature;
|
||||
uint32_t HashVersion;
|
||||
uint32_t NameCount;
|
||||
uint32_t ByteSize = 0;
|
||||
uint32_t Signature = 0;
|
||||
uint32_t HashVersion = 0;
|
||||
uint32_t NameCount = 0;
|
||||
};
|
||||
|
||||
} // end namespace pdb
|
||||
|
|
|
@ -20,9 +20,11 @@ using namespace llvm;
|
|||
using namespace llvm::support;
|
||||
using namespace llvm::pdb;
|
||||
|
||||
StringTable::StringTable() : Signature(0), HashVersion(0), NameCount(0) {}
|
||||
StringTable::StringTable() {}
|
||||
|
||||
Error StringTable::load(BinaryStreamReader &Stream) {
|
||||
ByteSize = Stream.getLength();
|
||||
|
||||
const StringTableHeader *H;
|
||||
if (auto EC = Stream.readObject(H))
|
||||
return EC;
|
||||
|
@ -56,9 +58,18 @@ Error StringTable::load(BinaryStreamReader &Stream) {
|
|||
|
||||
if (auto EC = Stream.readInteger(NameCount))
|
||||
return EC;
|
||||
|
||||
if (Stream.bytesRemaining() > 0)
|
||||
return make_error<RawError>(raw_error_code::stream_too_long,
|
||||
"Unexpected bytes found in string table");
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
uint32_t StringTable::getByteSize() const {
|
||||
return ByteSize;
|
||||
}
|
||||
|
||||
StringRef StringTable::getStringForID(uint32_t ID) const {
|
||||
if (ID == IDs[0])
|
||||
return StringRef();
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/RawConstants.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/StringTable.h"
|
||||
|
||||
#include "llvm/Support/FormatAdapters.h"
|
||||
#include "llvm/Support/FormatVariadic.h"
|
||||
|
@ -21,6 +22,48 @@
|
|||
using namespace llvm;
|
||||
using namespace llvm::pdb;
|
||||
|
||||
template<typename R>
|
||||
using ValueOfRange = llvm::detail::ValueOfRange<R>;
|
||||
|
||||
template<typename Range, typename Comp>
|
||||
static void set_differences(Range &&R1, Range &&R2,
|
||||
SmallVectorImpl<ValueOfRange<Range>> *OnlyLeft,
|
||||
SmallVectorImpl<ValueOfRange<Range>> *OnlyRight,
|
||||
SmallVectorImpl<ValueOfRange<Range>> *Intersection, Comp Comparator) {
|
||||
|
||||
std::sort(R1.begin(), R1.end(), Comparator);
|
||||
std::sort(R2.begin(), R2.end(), Comparator);
|
||||
|
||||
if (OnlyLeft) {
|
||||
OnlyLeft->reserve(R1.size());
|
||||
auto End = std::set_difference(R1.begin(), R1.end(), R2.begin(), R2.end(),
|
||||
OnlyLeft->begin(), Comparator);
|
||||
OnlyLeft->set_size(std::distance(OnlyLeft->begin(), End));
|
||||
}
|
||||
if (OnlyRight) {
|
||||
OnlyLeft->reserve(R2.size());
|
||||
auto End = std::set_difference(R2.begin(), R2.end(), R1.begin(), R1.end(),
|
||||
OnlyRight->begin(), Comparator);
|
||||
OnlyRight->set_size(std::distance(OnlyRight->begin(), End));
|
||||
}
|
||||
if (Intersection) {
|
||||
Intersection->reserve(std::min(R1.size(), R2.size()));
|
||||
auto End = std::set_intersection(R1.begin(), R1.end(), R2.begin(),
|
||||
R2.end(), Intersection->begin(), Comparator);
|
||||
Intersection->set_size(std::distance(Intersection->begin(), End));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Range>
|
||||
static void set_differences(Range &&R1, Range &&R2,
|
||||
SmallVectorImpl<ValueOfRange<Range>> *OnlyLeft,
|
||||
SmallVectorImpl<ValueOfRange<Range>> *OnlyRight,
|
||||
SmallVectorImpl<ValueOfRange<Range>> *Intersection) {
|
||||
std::less<ValueOfRange<Range>> Comp;
|
||||
set_differences(std::forward<Range>(R1), std::forward<Range>(R2), OnlyLeft, OnlyRight, Intersection, Comp);
|
||||
}
|
||||
|
||||
|
||||
DiffStyle::DiffStyle(PDBFile &File1, PDBFile &File2)
|
||||
: File1(File1), File2(File2) {}
|
||||
|
||||
|
@ -162,26 +205,12 @@ Error DiffStyle::diffStreamDirectory() {
|
|||
auto Comparator = [](const value_type &I1, const value_type &I2) {
|
||||
return I1.value() < I2.value();
|
||||
};
|
||||
std::sort(PI.begin(), PI.end(), Comparator);
|
||||
std::sort(QI.begin(), QI.end(), Comparator);
|
||||
|
||||
decltype(PI) OnlyP;
|
||||
decltype(QI) OnlyQ;
|
||||
decltype(PI) Common;
|
||||
|
||||
OnlyP.reserve(P.size());
|
||||
OnlyQ.reserve(Q.size());
|
||||
Common.reserve(Q.size());
|
||||
|
||||
auto PEnd = std::set_difference(PI.begin(), PI.end(), QI.begin(), QI.end(),
|
||||
OnlyP.begin(), Comparator);
|
||||
auto QEnd = std::set_difference(QI.begin(), QI.end(), PI.begin(), PI.end(),
|
||||
OnlyQ.begin(), Comparator);
|
||||
auto ComEnd = std::set_intersection(PI.begin(), PI.end(), QI.begin(),
|
||||
QI.end(), Common.begin(), Comparator);
|
||||
OnlyP.set_size(std::distance(OnlyP.begin(), PEnd));
|
||||
OnlyQ.set_size(std::distance(OnlyQ.begin(), QEnd));
|
||||
Common.set_size(std::distance(Common.begin(), ComEnd));
|
||||
set_differences(PI, QI, &OnlyP, &OnlyQ, &Common, Comparator);
|
||||
|
||||
if (!OnlyP.empty()) {
|
||||
HasDifferences = true;
|
||||
|
@ -238,7 +267,98 @@ Error DiffStyle::diffStreamDirectory() {
|
|||
return Error::success();
|
||||
}
|
||||
|
||||
Error DiffStyle::diffStringTable() { return Error::success(); }
|
||||
Error DiffStyle::diffStringTable() {
|
||||
auto ExpectedST1 = File1.getStringTable();
|
||||
auto ExpectedST2 = File2.getStringTable();
|
||||
outs() << "String Table: Searching for differences...\n";
|
||||
bool Has1 = !!ExpectedST1;
|
||||
bool Has2 = !!ExpectedST2;
|
||||
if (!(Has1 && Has2)) {
|
||||
// If one has a string table and the other doesn't, we can print less output.
|
||||
if (Has1 != Has2) {
|
||||
if (Has1) {
|
||||
outs() << formatv(" {0}: ({1} strings)\n", File1.getFilePath(), ExpectedST1->getNameCount());
|
||||
outs() << formatv(" {0}: (string table not present)\n", File2.getFilePath());
|
||||
} else {
|
||||
outs() << formatv(" {0}: (string table not present)\n", File1.getFilePath());
|
||||
outs() << formatv(" {0}: ({1})\n", File2.getFilePath(), ExpectedST2->getNameCount());
|
||||
}
|
||||
}
|
||||
consumeError(ExpectedST1.takeError());
|
||||
consumeError(ExpectedST2.takeError());
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
bool HasDiff = false;
|
||||
auto &ST1 = *ExpectedST1;
|
||||
auto &ST2 = *ExpectedST2;
|
||||
|
||||
HasDiff |= diffAndPrint("Stream Size", File1, File2, ST1.getByteSize(), ST2.getByteSize());
|
||||
HasDiff |= diffAndPrint("Hash Version", File1, File2, ST1.getHashVersion(), ST1.getHashVersion());
|
||||
HasDiff |= diffAndPrint("Signature", File1, File2, ST1.getSignature(), ST1.getSignature());
|
||||
|
||||
// Both have a valid string table, dive in and compare individual strings.
|
||||
|
||||
auto IdList1 = ST1.name_ids();
|
||||
auto IdList2 = ST2.name_ids();
|
||||
if (opts::diff::Pedantic) {
|
||||
// In pedantic mode, we compare index by index (i.e. the strings are in the same order
|
||||
// in both tables.
|
||||
uint32_t Max = std::max(IdList1.size(), IdList2.size());
|
||||
for (uint32_t I = 0; I < Max; ++I) {
|
||||
Optional<uint32_t> Id1, Id2;
|
||||
StringRef S1, S2;
|
||||
if (I < IdList1.size()) {
|
||||
Id1 = IdList1[I];
|
||||
S1 = ST1.getStringForID(*Id1);
|
||||
}
|
||||
if (I < IdList2.size()) {
|
||||
Id2 = IdList2[I];
|
||||
S2 = ST2.getStringForID(*Id2);
|
||||
}
|
||||
if (Id1 == Id2 && S1 == S2)
|
||||
continue;
|
||||
|
||||
std::string OutId1 = Id1 ? formatv("{0}", *Id1).str() : "(index not present)";
|
||||
std::string OutId2 = Id2 ? formatv("{0}", *Id2).str() : "(index not present)";
|
||||
outs() << formatv(" String {0}\n", I);
|
||||
outs() << formatv(" {0}: Hash - {1}, Value - {2}\n", File1.getFilePath(), OutId1, S1);
|
||||
outs() << formatv(" {0}: Hash - {1}, Value - {2}\n", File2.getFilePath(), OutId2, S2);
|
||||
HasDiff = true;
|
||||
}
|
||||
} else {
|
||||
std::vector<StringRef> Strings1, Strings2;
|
||||
Strings1.reserve(IdList1.size());
|
||||
Strings2.reserve(IdList2.size());
|
||||
for (auto ID : IdList1)
|
||||
Strings1.push_back(ST1.getStringForID(ID));
|
||||
for (auto ID : IdList2)
|
||||
Strings2.push_back(ST2.getStringForID(ID));
|
||||
|
||||
SmallVector<StringRef, 64> OnlyP;
|
||||
SmallVector<StringRef, 64> OnlyQ;
|
||||
|
||||
set_differences(Strings1, Strings2, &OnlyP, &OnlyQ, nullptr);
|
||||
|
||||
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 (!HasDiff)
|
||||
outs() << "String Table: No differences detected!\n";
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error DiffStyle::diffFreePageMap() { return Error::success(); }
|
||||
|
||||
|
|
Loading…
Reference in New Issue