[llvm] r250356 - [llvm-pdbdump] Provide a mechanism to dump the raw contents of a PDB

David Majnemer via llvm-commits llvm-commits at lists.llvm.org
Wed Oct 14 18:27:19 PDT 2015


Author: majnemer
Date: Wed Oct 14 20:27:19 2015
New Revision: 250356

URL: http://llvm.org/viewvc/llvm-project?rev=250356&view=rev
Log:
[llvm-pdbdump] Provide a mechanism to dump the raw contents of a PDB

A PDB can be thought of as a very simple file system.  It is
occasionally illuminating to see the contents of the underlying files.

Differential Revision: http://reviews.llvm.org/D13674

Added:
    llvm/trunk/test/DebugInfo/PDB/DIA/
    llvm/trunk/test/DebugInfo/PDB/DIA/lit.local.cfg
      - copied, changed from r250352, llvm/trunk/test/DebugInfo/PDB/lit.local.cfg
    llvm/trunk/test/DebugInfo/PDB/DIA/pdbdump-flags.test
      - copied, changed from r250352, llvm/trunk/test/DebugInfo/PDB/pdbdump-flags.test
    llvm/trunk/test/DebugInfo/PDB/DIA/pdbdump-symbol-format.test
      - copied, changed from r250352, llvm/trunk/test/DebugInfo/PDB/pdbdump-symbol-format.test
    llvm/trunk/test/DebugInfo/PDB/pdbdump-headers.test
Removed:
    llvm/trunk/test/DebugInfo/PDB/lit.local.cfg
    llvm/trunk/test/DebugInfo/PDB/pdbdump-flags.test
    llvm/trunk/test/DebugInfo/PDB/pdbdump-symbol-format.test
Modified:
    llvm/trunk/include/llvm/DebugInfo/PDB/PDBTypes.h
    llvm/trunk/include/llvm/Support/MemoryBuffer.h
    llvm/trunk/lib/Support/MemoryBuffer.cpp
    llvm/trunk/tools/llvm-pdbdump/llvm-pdbdump.cpp

Modified: llvm/trunk/include/llvm/DebugInfo/PDB/PDBTypes.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/PDB/PDBTypes.h?rev=250356&r1=250355&r2=250356&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/PDB/PDBTypes.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/PDB/PDBTypes.h Wed Oct 14 20:27:19 2015
@@ -11,6 +11,7 @@
 #define LLVM_DEBUGINFO_PDB_PDBTYPES_H
 
 #include "llvm/Config/llvm-config.h"
+#include "llvm/Support/Endian.h"
 #include <functional>
 #include <stdint.h>
 
@@ -500,6 +501,35 @@ struct Variant {
   bool operator!=(const Variant &Other) const { return !(*this == Other); }
 };
 
+namespace PDB {
+static const char Magic[] = {'M',  'i',  'c',    'r', 'o', 's',  'o',  'f',
+                             't',  ' ',  'C',    '/', 'C', '+',  '+',  ' ',
+                             'M',  'S',  'F',    ' ', '7', '.',  '0',  '0',
+                             '\r', '\n', '\x1a', 'D', 'S', '\0', '\0', '\0'};
+
+// The superblock is overlaid at the beginning of the file (offset 0).
+// It starts with a magic header and is followed by information which describes
+// the layout of the file system.
+struct SuperBlock {
+  char MagicBytes[sizeof(Magic)];
+  // The file system is split into a variable number of fixed size elements.
+  // These elements are referred to as blocks.  The size of a block may vary
+  // from system to system.
+  support::ulittle32_t BlockSize;
+  // This field's purpose is not yet known.
+  support::ulittle32_t Unknown0;
+  // This contains the number of blocks resident in the file system.  In
+  // practice, NumBlocks * BlockSize is equivalent to the size of the PDB file.
+  support::ulittle32_t NumBlocks;
+  // This contains the number of bytes which make up the directory.
+  support::ulittle32_t NumDirectoryBytes;
+  // This field's purpose is not yet known.
+  support::ulittle32_t Unknown1;
+  // This contains the block # of the block map.
+  support::ulittle32_t BlockMapAddr;
+};
+}
+
 } // namespace llvm
 
 namespace std {
@@ -513,4 +543,5 @@ template <> struct hash<llvm::PDB_SymTyp
 };
 }
 
+
 #endif

Modified: llvm/trunk/include/llvm/Support/MemoryBuffer.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/MemoryBuffer.h?rev=250356&r1=250355&r2=250356&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Support/MemoryBuffer.h (original)
+++ llvm/trunk/include/llvm/Support/MemoryBuffer.h Wed Oct 14 20:27:19 2015
@@ -122,7 +122,8 @@ public:
   /// Open the specified file as a MemoryBuffer, or open stdin if the Filename
   /// is "-".
   static ErrorOr<std::unique_ptr<MemoryBuffer>>
-  getFileOrSTDIN(const Twine &Filename, int64_t FileSize = -1);
+  getFileOrSTDIN(const Twine &Filename, int64_t FileSize = -1,
+                 bool RequiresNullTerminator = true);
 
   /// Map a subrange of the specified file as a MemoryBuffer.
   static ErrorOr<std::unique_ptr<MemoryBuffer>>

Modified: llvm/trunk/lib/Support/MemoryBuffer.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/MemoryBuffer.cpp?rev=250356&r1=250355&r2=250356&view=diff
==============================================================================
--- llvm/trunk/lib/Support/MemoryBuffer.cpp (original)
+++ llvm/trunk/lib/Support/MemoryBuffer.cpp Wed Oct 14 20:27:19 2015
@@ -162,13 +162,14 @@ MemoryBuffer::getNewMemBuffer(size_t Siz
 }
 
 ErrorOr<std::unique_ptr<MemoryBuffer>>
-MemoryBuffer::getFileOrSTDIN(const Twine &Filename, int64_t FileSize) {
+MemoryBuffer::getFileOrSTDIN(const Twine &Filename, int64_t FileSize,
+                             bool RequiresNullTerminator) {
   SmallString<256> NameBuf;
   StringRef NameRef = Filename.toStringRef(NameBuf);
 
   if (NameRef == "-")
     return getSTDIN();
-  return getFile(Filename, FileSize);
+  return getFile(Filename, FileSize, RequiresNullTerminator);
 }
 
 ErrorOr<std::unique_ptr<MemoryBuffer>>

Copied: llvm/trunk/test/DebugInfo/PDB/DIA/lit.local.cfg (from r250352, llvm/trunk/test/DebugInfo/PDB/lit.local.cfg)
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/PDB/DIA/lit.local.cfg?p2=llvm/trunk/test/DebugInfo/PDB/DIA/lit.local.cfg&p1=llvm/trunk/test/DebugInfo/PDB/lit.local.cfg&r1=250352&r2=250356&rev=250356&view=diff
==============================================================================
    (empty)

Copied: llvm/trunk/test/DebugInfo/PDB/DIA/pdbdump-flags.test (from r250352, llvm/trunk/test/DebugInfo/PDB/pdbdump-flags.test)
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/PDB/DIA/pdbdump-flags.test?p2=llvm/trunk/test/DebugInfo/PDB/DIA/pdbdump-flags.test&p1=llvm/trunk/test/DebugInfo/PDB/pdbdump-flags.test&r1=250352&r2=250356&rev=250356&view=diff
==============================================================================
--- llvm/trunk/test/DebugInfo/PDB/pdbdump-flags.test (original)
+++ llvm/trunk/test/DebugInfo/PDB/DIA/pdbdump-flags.test Wed Oct 14 20:27:19 2015
@@ -1,7 +1,7 @@
-; RUN: llvm-pdbdump %p/Inputs/empty.pdb | FileCheck %s -check-prefix=NO_ARGS
-; RUN: llvm-pdbdump -types %p/Inputs/empty.pdb | FileCheck %s -check-prefix=TYPES
-; RUN: llvm-pdbdump -compilands %p/Inputs/empty.pdb | FileCheck %s -check-prefix=COMPILANDS
-; RUN: llvm-pdbdump -types -compilands %p/Inputs/empty.pdb | FileCheck %s -check-prefix=MULTIPLE
+; RUN: llvm-pdbdump %p/../Inputs/empty.pdb | FileCheck %s -check-prefix=NO_ARGS
+; RUN: llvm-pdbdump -types %p/../Inputs/empty.pdb | FileCheck %s -check-prefix=TYPES
+; RUN: llvm-pdbdump -compilands %p/../Inputs/empty.pdb | FileCheck %s -check-prefix=COMPILANDS
+; RUN: llvm-pdbdump -types -compilands %p/../Inputs/empty.pdb | FileCheck %s -check-prefix=MULTIPLE
 
 ; Check that neither symbols nor compilands are dumped when neither argument specified.
 ; NO_ARGS: empty.pdb

Copied: llvm/trunk/test/DebugInfo/PDB/DIA/pdbdump-symbol-format.test (from r250352, llvm/trunk/test/DebugInfo/PDB/pdbdump-symbol-format.test)
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/PDB/DIA/pdbdump-symbol-format.test?p2=llvm/trunk/test/DebugInfo/PDB/DIA/pdbdump-symbol-format.test&p1=llvm/trunk/test/DebugInfo/PDB/pdbdump-symbol-format.test&r1=250352&r2=250356&rev=250356&view=diff
==============================================================================
--- llvm/trunk/test/DebugInfo/PDB/pdbdump-symbol-format.test (original)
+++ llvm/trunk/test/DebugInfo/PDB/DIA/pdbdump-symbol-format.test Wed Oct 14 20:27:19 2015
@@ -1,6 +1,6 @@
-; RUN: llvm-pdbdump -symbols %p/Inputs/symbolformat.pdb | FileCheck --check-prefix=SYM_FORMAT %s
-; RUN: llvm-pdbdump -types %p/Inputs/symbolformat.pdb | FileCheck --check-prefix=TYPES_FORMAT %s
-; RUN: llvm-pdbdump -globals %p/Inputs/symbolformat.pdb | FileCheck --check-prefix=GLOBALS %s
+; RUN: llvm-pdbdump -symbols %p/../Inputs/symbolformat.pdb | FileCheck --check-prefix=SYM_FORMAT %s
+; RUN: llvm-pdbdump -types %p/../Inputs/symbolformat.pdb | FileCheck --check-prefix=TYPES_FORMAT %s
+; RUN: llvm-pdbdump -globals %p/../Inputs/symbolformat.pdb | FileCheck --check-prefix=GLOBALS %s
 
 ; The format is func [0x<rva_start>+<prologue_length> - 0x<rva_end>-<epilogue_length>]
 ; SYM_FORMAT: ---SYMBOLS---

Removed: llvm/trunk/test/DebugInfo/PDB/lit.local.cfg
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/PDB/lit.local.cfg?rev=250355&view=auto
==============================================================================
--- llvm/trunk/test/DebugInfo/PDB/lit.local.cfg (original)
+++ llvm/trunk/test/DebugInfo/PDB/lit.local.cfg (removed)
@@ -1 +0,0 @@
-config.unsupported = not config.have_dia_sdk

Removed: llvm/trunk/test/DebugInfo/PDB/pdbdump-flags.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/PDB/pdbdump-flags.test?rev=250355&view=auto
==============================================================================
--- llvm/trunk/test/DebugInfo/PDB/pdbdump-flags.test (original)
+++ llvm/trunk/test/DebugInfo/PDB/pdbdump-flags.test (removed)
@@ -1,40 +0,0 @@
-; RUN: llvm-pdbdump %p/Inputs/empty.pdb | FileCheck %s -check-prefix=NO_ARGS
-; RUN: llvm-pdbdump -types %p/Inputs/empty.pdb | FileCheck %s -check-prefix=TYPES
-; RUN: llvm-pdbdump -compilands %p/Inputs/empty.pdb | FileCheck %s -check-prefix=COMPILANDS
-; RUN: llvm-pdbdump -types -compilands %p/Inputs/empty.pdb | FileCheck %s -check-prefix=MULTIPLE
-
-; Check that neither symbols nor compilands are dumped when neither argument specified.
-; NO_ARGS: empty.pdb
-; NO_ARGS: Guid: {0B355641-86A0-A249-896F-9988FAE52FF0}
-; NO_ARGS: Attributes: HasPrivateSymbols
-; NO_ARGS-NOT: ---TYPES---
-; NO_ARGS-NOT: ---COMPILANDS---
-; NO_ARGS-NOT: ---GLOBALS---
-; NO_ARGS-NOT: ---SYMBOLS---
-
-; Check that only types are dumped when only -types is specified.
-; TYPES: empty.pdb
-; TYPES: Guid: {0B355641-86A0-A249-896F-9988FAE52FF0}
-; TYPES: Attributes: HasPrivateSymbols
-; TYPES: ---TYPES---
-; TYPES-NOT: ---COMPILANDS---
-; TYPES-NOT: ---GLOBALS---
-; TYPES-NOT: ---SYMBOLS---
-
-; Check that only compilands are dumped when only -compilands is specified.
-; COMPILANDS: empty.pdb
-; COMPILANDS: Guid: {0B355641-86A0-A249-896F-9988FAE52FF0}
-; COMPILANDS: Attributes: HasPrivateSymbols
-; COMPILANDS: ---COMPILANDS---
-; COMPILANDS-NOT: ---TYPES---
-; COMPILANDS-NOT: ---GLOBALS---
-; COMPILANDS-NOT: ---SYMBOLS---
-
-; Check that types and compilands are dumped when both arguments are specified.
-; MULTIPLE: empty.pdb
-; MULTIPLE: Guid: {0B355641-86A0-A249-896F-9988FAE52FF0}
-; MULTIPLE: Attributes: HasPrivateSymbols
-; MULTIPLE: ---COMPILANDS---
-; MULTIPLE: ---TYPES---
-; MULTIPLE-NOT: ---GLOBALS---
-; MULTIPLE-NOT: ---SYMBOLS---

Added: llvm/trunk/test/DebugInfo/PDB/pdbdump-headers.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/PDB/pdbdump-headers.test?rev=250356&view=auto
==============================================================================
--- llvm/trunk/test/DebugInfo/PDB/pdbdump-headers.test (added)
+++ llvm/trunk/test/DebugInfo/PDB/pdbdump-headers.test Wed Oct 14 20:27:19 2015
@@ -0,0 +1,12 @@
+; RUN: llvm-pdbdump --dump-headers %p/Inputs/empty.pdb | FileCheck %s
+
+; CHECK:      BlockSize: 4096
+; CHECK-NEXT: Unknown0: 2
+; CHECK-NEXT: NumBlocks: 25
+; CHECK-NEXT: NumDirectoryBytes: 136
+; CHECK-NEXT: Unknown1: 0
+; CHECK-NEXT: BlockMapAddr: 24
+; CHECK-NEXT: NumDirectoryBlocks: 1
+; CHECK-NEXT: BlockMapOffset: 98304
+; CHECK-NEXT: DirectoryBlocks: [23]
+; CHECK-NEXT: NumFiles: 17

Removed: llvm/trunk/test/DebugInfo/PDB/pdbdump-symbol-format.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/PDB/pdbdump-symbol-format.test?rev=250355&view=auto
==============================================================================
--- llvm/trunk/test/DebugInfo/PDB/pdbdump-symbol-format.test (original)
+++ llvm/trunk/test/DebugInfo/PDB/pdbdump-symbol-format.test (removed)
@@ -1,53 +0,0 @@
-; RUN: llvm-pdbdump -symbols %p/Inputs/symbolformat.pdb | FileCheck --check-prefix=SYM_FORMAT %s
-; RUN: llvm-pdbdump -types %p/Inputs/symbolformat.pdb | FileCheck --check-prefix=TYPES_FORMAT %s
-; RUN: llvm-pdbdump -globals %p/Inputs/symbolformat.pdb | FileCheck --check-prefix=GLOBALS %s
-
-; The format is func [0x<rva_start>+<prologue_length> - 0x<rva_end>-<epilogue_length>]
-; SYM_FORMAT: ---SYMBOLS---
-; SYM_FORMAT: symbolformat-fpo.obj
-; SYM_FORMAT-DAG: func [{{.*}}] (FPO) unsigned __cdecl fpo_func(unsigned n)
-; SYM_FORMAT: symbolformat.obj
-; SYM_FORMAT-DAG: func [{{.*}}] (EBP) int __cdecl _purecall()
-; SYM_FORMAT-DAG: func [{{.*}}] (EBP) int __cdecl main(int argc, char** argv)
-; SYM_FORMAT-DAG: func [{{.*}}] (EBP) void A::A()
-; SYM_FORMAT-DAG: func [{{.*}}] (EBP) void B::B()
-; SYM_FORMAT-DAG: thunk [{{.*}}] (Pcode) B::`vcall'{0}'
-; SYM_FORMAT-DAG: func [{{.*}}] (EBP) virtual void B::PureFunc()
-; SYM_FORMAT-DAG: func [{{.*}}] (EBP) void A::RegularFunc()
-; SYM_FORMAT-DAG: func [{{.*}}] (EBP) virtual void A::VirtualFunc()
-
-; TYPES_FORMAT: ---TYPES---
-; TYPES_FORMAT: Enums
-; TYPES_FORMAT-DAG: enum TestEnum
-; TYPES_FORMAT-DAG: enum TestEnumClass
-; TYPES_FORMAT: Typedefs
-; TYPES_FORMAT-DAG: typedef int IntType
-; TYPES_FORMAT-DAG: typedef class A ClassAType
-; TYPES_FORMAT: Classes
-; TYPES_FORMAT: struct A {
-; TYPES_FORMAT: public:
-; TYPES_FORMAT: virtual void PureFunc() = 0
-; TYPES_FORMAT: virtual void VirtualFunc()
-; TYPES_FORMAT: void RegularFunc()
-; TYPES_FORMAT: }
-; TYPES_FORMAT-DAG: struct MemberTest {
-; TYPES_FORMAT: data +0x00 MemberTest::NestedEnum m_nested_enum
-; TYPES_FORMAT: data +0x04 int m_typedef
-; TYPES_FORMAT: data +0x08 bool m_bool
-; TYPES_FORMAT: data +0x09 char m_char
-; TYPES_FORMAT: data +0x0a wchar_t m_wchar_t
-; TYPES_FORMAT: data +0x0c int m_int
-; TYPES_FORMAT: data +0x10 unsigned m_unsigned
-; TYPES_FORMAT: data +0x14 long m_long
-; TYPES_FORMAT: data +0x18 unsigned long m_unsigned_long
-; TYPES_FORMAT: data +0x20 __int64 m_int64
-; TYPES_FORMAT: data +0x28 unsigned __int64 m_unsigned_int64
-; TYPES_FORMAT: data +0x30 float m_float
-; TYPES_FORMAT: data +0x38 double m_double
-; TYPES_FORMAT: data +0x40 void (__cdecl *m_pfn_2_args)(int, double)
-; TYPES_FORMAT: }
-
-; GLOBALS: ---GLOBALS---
-; GLOBALS-DAG: func [{{.*}}] (FPO) unsigned __cdecl fpo_func(unsigned n)
-; GLOBALS-DAG: data [{{.*}}] static void* g_global_pointer
-; GLOBALS-DAG: data [{{.*}}] static int g_global_int

Modified: llvm/trunk/tools/llvm-pdbdump/llvm-pdbdump.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-pdbdump/llvm-pdbdump.cpp?rev=250356&r1=250355&r2=250356&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-pdbdump/llvm-pdbdump.cpp (original)
+++ llvm/trunk/tools/llvm-pdbdump/llvm-pdbdump.cpp Wed Oct 14 20:27:19 2015
@@ -22,6 +22,8 @@
 #include "VariableDumper.h"
 
 #include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/BitVector.h"
+#include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/Config/config.h"
 #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"
@@ -38,6 +40,7 @@
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/Format.h"
 #include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/PrettyStackTrace.h"
 #include "llvm/Support/Process.h"
 #include "llvm/Support/raw_ostream.h"
@@ -79,6 +82,17 @@ cl::opt<uint64_t> LoadAddress(
     cl::desc("Assume the module is loaded at the specified address"),
     cl::cat(OtherOptions));
 
+cl::opt<bool> DumpHeaders("dump-headers", cl::desc("dump PDB headers"),
+                          cl::cat(OtherOptions));
+cl::opt<bool> DumpStreamSizes("dump-stream-sizes",
+                              cl::desc("dump PDB stream sizes"),
+                              cl::cat(OtherOptions));
+cl::opt<bool> DumpStreamBlocks("dump-stream-blocks",
+                               cl::desc("dump PDB stream blocks"),
+                               cl::cat(OtherOptions));
+cl::opt<std::string> DumpStreamData("dump-stream", cl::desc("dump stream data"),
+                                    cl::cat(OtherOptions));
+
 cl::list<std::string>
     ExcludeTypes("exclude-types",
                  cl::desc("Exclude types by regular expression"),
@@ -121,10 +135,264 @@ cl::opt<bool> NoEnumDefs("no-enum-defini
                          cl::cat(FilterCategory));
 }
 
+
+static void reportError(StringRef Input, StringRef Message) {
+  if (Input == "-")
+    Input = "<stdin>";
+  errs() << Input << ": " << Message << "\n";
+  errs().flush();
+  exit(1);
+}
+
+static void reportError(StringRef Input, std::error_code EC) {
+  reportError(Input, EC.message());
+}
+
+static std::error_code checkOffset(MemoryBufferRef M, uintptr_t Addr,
+                                   const uint64_t Size) {
+  if (Addr + Size < Addr || Addr + Size < Size ||
+      Addr + Size > uintptr_t(M.getBufferEnd()) ||
+      Addr < uintptr_t(M.getBufferStart())) {
+    return std::make_error_code(std::errc::bad_address);
+  }
+  return std::error_code();
+}
+
+template <typename T>
+static std::error_code checkOffset(MemoryBufferRef M, ArrayRef<T> AR) {
+  return checkOffset(M, uintptr_t(AR.data()), (uint64_t)AR.size() * sizeof(T));
+}
+
+static std::error_code checkOffset(MemoryBufferRef M, StringRef SR) {
+  return checkOffset(M, uintptr_t(SR.data()), SR.size());
+}
+
+// Sets Obj unless any bytes in [addr, addr + size) fall outsize of m.
+// Returns unexpected_eof if error.
+template <typename T>
+static std::error_code getObject(const T *&Obj, MemoryBufferRef M,
+                                 const void *Ptr,
+                                 const uint64_t Size = sizeof(T)) {
+  uintptr_t Addr = uintptr_t(Ptr);
+  if (std::error_code EC = checkOffset(M, Addr, Size))
+    return EC;
+  Obj = reinterpret_cast<const T *>(Addr);
+  return std::error_code();
+}
+
+static uint64_t bytesToBlocks(uint64_t NumBytes, uint64_t BlockSize) {
+  return RoundUpToAlignment(NumBytes, BlockSize) / BlockSize;
+}
+
+static uint64_t blockToOffset(uint64_t BlockNumber, uint64_t BlockSize) {
+  return BlockNumber * BlockSize;
+}
+
+static void dumpStructure(MemoryBufferRef M) {
+  const PDB::SuperBlock *SB;
+  if (auto EC = getObject(SB, M, M.getBufferStart()))
+    reportError(M.getBufferIdentifier(), EC);
+
+  if (opts::DumpHeaders) {
+    outs() << "BlockSize: " << SB->BlockSize << '\n';
+    outs() << "Unknown0: " << SB->Unknown0 << '\n';
+    outs() << "NumBlocks: " << SB->NumBlocks << '\n';
+    outs() << "NumDirectoryBytes: " << SB->NumDirectoryBytes << '\n';
+    outs() << "Unknown1: " << SB->Unknown1 << '\n';
+    outs() << "BlockMapAddr: " << SB->BlockMapAddr << '\n';
+  }
+
+  // We don't support blocksizes which aren't a multiple of four bytes.
+  if (SB->BlockSize % sizeof(support::ulittle32_t) != 0)
+    reportError(M.getBufferIdentifier(),
+                std::make_error_code(std::errc::illegal_byte_sequence));
+
+  // We don't support directories whose sizes aren't a multiple of four bytes.
+  if (SB->NumDirectoryBytes % sizeof(support::ulittle32_t) != 0)
+    reportError(M.getBufferIdentifier(),
+                std::make_error_code(std::errc::illegal_byte_sequence));
+
+  // The number of blocks which comprise the directory is a simple function of
+  // the number of bytes it contains.
+  uint64_t NumDirectoryBlocks =
+      bytesToBlocks(SB->NumDirectoryBytes, SB->BlockSize);
+  if (opts::DumpHeaders)
+    outs() << "NumDirectoryBlocks: " << NumDirectoryBlocks << '\n';
+
+  // The block map, as we understand it, is a block which consists of a list of
+  // block numbers.
+  // It is unclear what would happen if the number of blocks couldn't fit on a
+  // single block.
+  if (NumDirectoryBlocks > SB->BlockSize / sizeof(support::ulittle32_t))
+    reportError(M.getBufferIdentifier(),
+                std::make_error_code(std::errc::illegal_byte_sequence));
+
+
+  uint64_t BlockMapOffset = (uint64_t)SB->BlockMapAddr * SB->BlockSize;
+  if (opts::DumpHeaders)
+    outs() << "BlockMapOffset: " << BlockMapOffset << '\n';
+
+  // The directory is not contiguous.  Instead, the block map contains a
+  // contiguous list of block numbers whose contents, when concatenated in
+  // order, make up the directory.
+  auto DirectoryBlocks =
+      makeArrayRef(reinterpret_cast<const support::ulittle32_t *>(
+                       M.getBufferStart() + BlockMapOffset),
+                   NumDirectoryBlocks);
+  if (auto EC = checkOffset(M, DirectoryBlocks))
+    reportError(M.getBufferIdentifier(), EC);
+
+  if (opts::DumpHeaders) {
+    outs() << "DirectoryBlocks: [";
+    for (const support::ulittle32_t &DirectoryBlockAddr : DirectoryBlocks) {
+      if (&DirectoryBlockAddr != &DirectoryBlocks.front())
+        outs() << ", ";
+      outs() << DirectoryBlockAddr;
+    }
+    outs() << "]\n";
+  }
+
+  bool SeenNumStreams = false;
+  uint32_t NumStreams = 0;
+  std::vector<uint32_t> StreamSizes;
+  DenseMap<uint32_t, std::vector<uint32_t>> StreamMap;
+  uint32_t StreamIdx = 0;
+  uint64_t DirectoryBytesRead = 0;
+  // The structure of the directory is as follows:
+  //    struct PDBDirectory {
+  //      uint32_t NumStreams;
+  //      uint32_t StreamSizes[NumStreams];
+  //      uint32_t StreamMap[NumStreams][];
+  //    };
+  //
+  //  Empty streams don't consume entries in the StreamMap.
+  for (uint32_t DirectoryBlockAddr : DirectoryBlocks) {
+    uint64_t DirectoryBlockOffset =
+        blockToOffset(DirectoryBlockAddr, SB->BlockSize);
+    auto DirectoryBlock =
+        makeArrayRef(reinterpret_cast<const support::ulittle32_t *>(
+                         M.getBufferStart() + DirectoryBlockOffset),
+                     SB->BlockSize / sizeof(support::ulittle32_t));
+    if (auto EC = checkOffset(M, DirectoryBlock))
+      reportError(M.getBufferIdentifier(), EC);
+
+    // We read data out of the directory four bytes at a time.  Depending on
+    // where we are in the directory, the contents may be: the number of streams
+    // in the directory, a stream's size, or a block in the stream map.
+    for (uint32_t Data : DirectoryBlock) {
+      // Don't read beyond the end of the directory.
+      if (DirectoryBytesRead == SB->NumDirectoryBytes)
+        break;
+
+      DirectoryBytesRead += sizeof(Data);
+
+      // This data must be the number of streams if we haven't seen it yet.
+      if (!SeenNumStreams) {
+        NumStreams = Data;
+        SeenNumStreams = true;
+        continue;
+      }
+      // This data must be a stream size if we have not seen them all yet.
+      if (StreamSizes.size() < NumStreams) {
+        // It seems like some streams have their set to -1 when their contents
+        // are not present.  Treat them like empty streams for now.
+        if (Data == UINT32_MAX)
+          StreamSizes.push_back(0);
+        else
+          StreamSizes.push_back(Data);
+        continue;
+      }
+
+      // This data must be a stream block number if we have seen all of the
+      // stream sizes.
+      std::vector<uint32_t> *StreamBlocks = nullptr;
+      // Figure out which stream this block number belongs to.
+      while (StreamIdx < NumStreams) {
+        uint64_t NumExpectedStreamBlocks =
+            bytesToBlocks(StreamSizes[StreamIdx], SB->BlockSize);
+        StreamBlocks = &StreamMap[StreamIdx];
+        if (NumExpectedStreamBlocks > StreamBlocks->size())
+          break;
+        ++StreamIdx;
+      }
+      // It seems this block doesn't belong to any stream?  The stream is either
+      // corrupt or something more mysterious is going on.
+      if (StreamIdx == NumStreams)
+        reportError(M.getBufferIdentifier(),
+                    std::make_error_code(std::errc::illegal_byte_sequence));
+
+      StreamBlocks->push_back(Data);
+    }
+  }
+
+  // We should have read exactly SB->NumDirectoryBytes bytes.
+  assert(DirectoryBytesRead == SB->NumDirectoryBytes);
+
+  if (opts::DumpHeaders)
+    outs() << "NumStreams: " << NumStreams << '\n';
+  if (opts::DumpStreamSizes)
+    for (uint32_t StreamIdx = 0; StreamIdx < NumStreams; ++StreamIdx)
+      outs() << "StreamSizes[" << StreamIdx << "]: " << StreamSizes[StreamIdx]
+             << '\n';
+
+  if (opts::DumpStreamBlocks) {
+    for (uint32_t StreamIdx = 0; StreamIdx < NumStreams; ++StreamIdx) {
+      outs() << "StreamBlocks[" << StreamIdx << "]: [";
+      std::vector<uint32_t> &StreamBlocks = StreamMap[StreamIdx];
+      for (uint32_t &StreamBlock : StreamBlocks) {
+        if (&StreamBlock != &StreamBlocks.front())
+          outs() << ", ";
+        outs() << StreamBlock;
+      }
+      outs() << "]\n";
+    }
+  }
+
+  StringRef DumpStreamStr = opts::DumpStreamData;
+  uint32_t DumpStreamNum;
+  if (!DumpStreamStr.getAsInteger(/*Radix=*/0U, DumpStreamNum) &&
+      DumpStreamNum < NumStreams) {
+    uint32_t StreamBytesRead = 0;
+    uint32_t StreamSize = StreamSizes[DumpStreamNum];
+    std::vector<uint32_t> &StreamBlocks = StreamMap[DumpStreamNum];
+    for (uint32_t &StreamBlockAddr : StreamBlocks) {
+      uint64_t StreamBlockOffset = blockToOffset(StreamBlockAddr, SB->BlockSize);
+      uint32_t BytesLeftToReadInStream = StreamSize - StreamBytesRead;
+      if (BytesLeftToReadInStream == 0)
+        break;
+
+      uint32_t BytesToReadInBlock =
+          std::min(BytesLeftToReadInStream, static_cast<uint32_t>(SB->BlockSize));
+      auto StreamBlockData =
+          StringRef(M.getBufferStart() + StreamBlockOffset, BytesToReadInBlock);
+      if (auto EC = checkOffset(M, StreamBlockData))
+        reportError(M.getBufferIdentifier(), EC);
+
+      outs() << StreamBlockData;
+      StreamBytesRead += StreamBlockData.size();
+    }
+  }
+}
+
 static void dumpInput(StringRef Path) {
+  if (opts::DumpHeaders || !opts::DumpStreamData.empty()) {
+    ErrorOr<std::unique_ptr<MemoryBuffer>> ErrorOrBuffer =
+        MemoryBuffer::getFileOrSTDIN(Path, /*FileSize=*/-1,
+                                     /*RequiresNullTerminator=*/false);
+
+    if (std::error_code EC = ErrorOrBuffer.getError())
+      reportError(Path, EC);
+
+    std::unique_ptr<MemoryBuffer> &Buffer = ErrorOrBuffer.get();
+
+    dumpStructure(Buffer->getMemBufferRef());
+
+    outs().flush();
+    return;
+  }
+
   std::unique_ptr<IPDBSession> Session;
-  PDB_ErrorCode Error =
-      llvm::loadDataForPDB(PDB_ReaderType::DIA, Path, Session);
+  PDB_ErrorCode Error = loadDataForPDB(PDB_ReaderType::DIA, Path, Session);
   switch (Error) {
   case PDB_ErrorCode::Success:
     break;
@@ -159,7 +427,7 @@ static void dumpInput(StringRef Path) {
 
   Printer.NewLine();
   WithColor(Printer, PDB_ColorItem::Identifier).get() << "Size";
-  if (!llvm::sys::fs::file_size(FileName, FileSize)) {
+  if (!sys::fs::file_size(FileName, FileSize)) {
     Printer << ": " << FileSize << " bytes";
   } else {
     Printer << ": (Unable to obtain file size)";
@@ -256,11 +524,11 @@ int main(int argc_, const char *argv_[])
   PrettyStackTraceProgram X(argc_, argv_);
 
   SmallVector<const char *, 256> argv;
-  llvm::SpecificBumpPtrAllocator<char> ArgAllocator;
-  std::error_code EC = llvm::sys::Process::GetArgumentVector(
-      argv, llvm::makeArrayRef(argv_, argc_), ArgAllocator);
+  SpecificBumpPtrAllocator<char> ArgAllocator;
+  std::error_code EC = sys::Process::GetArgumentVector(
+      argv, makeArrayRef(argv_, argc_), ArgAllocator);
   if (EC) {
-    llvm::errs() << "error: couldn't get arguments: " << EC.message() << '\n';
+    errs() << "error: couldn't get arguments: " << EC.message() << '\n';
     return 1;
   }
 




More information about the llvm-commits mailing list