]> granicus.if.org Git - llvm/commitdiff
[llvm-pdbdump] Add support for diffing the PDB Stream.
authorZachary Turner <zturner@google.com>
Thu, 16 Mar 2017 20:18:41 +0000 (20:18 +0000)
committerZachary Turner <zturner@google.com>
Thu, 16 Mar 2017 20:18:41 +0000 (20:18 +0000)
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.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@297983 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/DebugInfo/CodeView/Formatters.h
include/llvm/DebugInfo/PDB/Native/Formatters.h [new file with mode: 0644]
include/llvm/DebugInfo/PDB/Native/InfoStream.h
include/llvm/DebugInfo/PDB/Native/NamedStreamMap.h
include/llvm/DebugInfo/PDB/Native/RawTypes.h
lib/DebugInfo/PDB/Native/InfoStream.cpp
lib/DebugInfo/PDB/Native/NamedStreamMap.cpp
tools/llvm-pdbdump/Diff.cpp

index d64024c56be5cc77c16a749b4eec9a23a1d8a04b..37a91098a8b65e3e625b88e21e26adce1a02a11e 100644 (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);
+}
 }
 }
 
diff --git a/include/llvm/DebugInfo/PDB/Native/Formatters.h b/include/llvm/DebugInfo/PDB/Native/Formatters.h
new file mode 100644 (file)
index 0000000..183f0ad
--- /dev/null
@@ -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
index 0b59d9e789dbbfeebe83541eae54cb5da7c988df..4a4222a680e611dccd52f57d49ef9ae6166852a9 100644 (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;
 };
 }
index 2327bfadb69e04574a0964e193154c3abcd71a69..d4206503e7dca5e706e10895b896f749227cb0dd 100644 (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);
index 5f0a824b4dd616e2f0b70f42e1a93205b0eb54da..1b2631efce70e7d9d43cc172cb9572c38f814bd3 100644 (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 {
index f3f64847fcfd1db9b44c630a2ea91f5ff43e16f9..1ce0fe842065a024c5fa526d09145ff607d0b03a 100644 (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;
 }
index ae453282b06270bc08de64775ab904d575272847..c7ba32b82bc6be11e9a6e62d17bcb428dfcb2add 100644 (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())
index d78c07f1019c3a3332ca9f79c521665fd1abc2be..529e57da5c1f149913e60ad6a262d7066dc46a36 100644 (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);
-
-    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);
+    printSymmetricDifferences(File1, File2, OnlyP, OnlyQ, "String");
+
+    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(); }