OSDN Git Service

[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 d64024c..37a9109 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 0b59d9e..4a4222a 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 2327bfa..d420650 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 5f0a824..1b2631e 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 f3f6484..1ce0fe8 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 ae45328..c7ba32b 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 d78c07f..529e57d 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(); }