OSDN Git Service

[codeview] Dump line number and column information.
authorZachary Turner <zturner@google.com>
Fri, 3 Jun 2016 03:25:59 +0000 (03:25 +0000)
committerZachary Turner <zturner@google.com>
Fri, 3 Jun 2016 03:25:59 +0000 (03:25 +0000)
To facilitate this, a couple of changes had to be made:

1. `ModuleSubstream` got moved from `DebugInfo/PDB` to
`DebugInfo/CodeView`, and various codeview related types are defined
there.  It turns out `DebugInfo/CodeView/Line.h` already defines many of
these structures, but this is really old code that is not endian aware,
doesn't interact well with `StreamInterface` and not very helpful for
getting stuff out of a PDB.  Eventually we should migrate the old readobj
`COFFDumper` code to these new structures, or at least merge their
functionality somehow.

2. A `ModuleSubstream` visitor is introduced.  Depending on where your
module substream array comes from, different subsets of record types can
be expected.  We are already hand parsing these substream arrays in many
places especially in `COFFDumper.cpp`.  In the future we can migrate these
paths to the visitor as well, which should reduce a lot of code in
`COFFDumper.cpp`.

Differential Revision: http://reviews.llvm.org/D20936
Reviewed By: ruiu, majnemer

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

16 files changed:
include/llvm/DebugInfo/CodeView/ModuleSubstream.h [new file with mode: 0644]
include/llvm/DebugInfo/CodeView/ModuleSubstreamVisitor.h [new file with mode: 0644]
include/llvm/DebugInfo/CodeView/StreamArray.h
include/llvm/DebugInfo/CodeView/StreamReader.h
include/llvm/DebugInfo/PDB/Raw/DbiStream.h
include/llvm/DebugInfo/PDB/Raw/ModStream.h
include/llvm/DebugInfo/PDB/Raw/ModuleSubstreamRecord.h [deleted file]
include/llvm/DebugInfo/PDB/Raw/RawTypes.h
lib/DebugInfo/CodeView/CMakeLists.txt
lib/DebugInfo/CodeView/ModuleSubstream.cpp [moved from lib/DebugInfo/PDB/Raw/ModuleSubstreamRecord.cpp with 52% similarity]
lib/DebugInfo/CodeView/ModuleSubstreamVisitor.cpp [new file with mode: 0644]
lib/DebugInfo/PDB/CMakeLists.txt
lib/DebugInfo/PDB/Raw/ModStream.cpp
test/DebugInfo/PDB/pdbdump-headers.test
tools/llvm-pdbdump/llvm-pdbdump.cpp
tools/llvm-readobj/COFFDumper.cpp

diff --git a/include/llvm/DebugInfo/CodeView/ModuleSubstream.h b/include/llvm/DebugInfo/CodeView/ModuleSubstream.h
new file mode 100644 (file)
index 0000000..0de564d
--- /dev/null
@@ -0,0 +1,87 @@
+//===- ModuleSubstream.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_CODEVIEW_MODULESUBSTREAM_H
+#define LLVM_DEBUGINFO_CODEVIEW_MODULESUBSTREAM_H
+
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/StreamArray.h"
+#include "llvm/DebugInfo/CodeView/StreamRef.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+
+namespace llvm {
+namespace codeview {
+
+// Corresponds to the `CV_DebugSSubsectionHeader_t` structure.
+struct ModuleSubsectionHeader {
+  support::ulittle32_t Kind;   // codeview::ModuleSubstreamKind enum
+  support::ulittle32_t Length; // number of bytes occupied by this record.
+};
+
+// Corresponds to the `CV_DebugSLinesHeader_t` structure.
+struct LineSubstreamHeader {
+  support::ulittle32_t RelocOffset;  // Code offset of line contribution.
+  support::ulittle16_t RelocSegment; // Code segment of line contribution.
+  support::ulittle16_t Flags;        // See LineFlags enumeration.
+  support::ulittle32_t CodeSize;     // Code size of this line contribution.
+};
+
+// Corresponds to the `CV_DebugSLinesFileBlockHeader_t` structure.
+struct LineFileBlockHeader {
+  support::ulittle32_t FileOffset;
+  support::ulittle32_t NumLines;  // Number of lines
+  support::ulittle32_t BlockSize; // Code size of block, in bytes.
+  // The following two variable length arrays appear immediately after the
+  // header.  The structure definitions follow.
+  // LineNumberEntry   Lines[NumLines];
+  // ColumnNumberEntry Columns[NumLines];
+};
+
+// Corresponds to `CV_Line_t` structure
+struct LineNumberEntry {
+  support::ulittle32_t Offset; // Offset to start of code bytes for line number
+  support::ulittle32_t Flags;  // Start:24, End:7, IsStatement:1
+};
+
+// Corresponds to `CV_Column_t` structure
+struct ColumnNumberEntry {
+  support::ulittle16_t StartColumn;
+  support::ulittle16_t EndColumn;
+};
+
+class ModuleSubstream {
+public:
+  ModuleSubstream();
+  ModuleSubstream(ModuleSubstreamKind Kind, StreamRef Data);
+  static Error initialize(StreamRef Stream, ModuleSubstream &Info);
+  uint32_t getRecordLength() const;
+  ModuleSubstreamKind getSubstreamKind() const;
+  StreamRef getRecordData() const;
+
+private:
+  ModuleSubstreamKind Kind;
+  StreamRef Data;
+};
+
+template <> struct VarStreamArrayExtractor<ModuleSubstream> {
+  Error operator()(StreamRef Stream, uint32_t &Length,
+                   ModuleSubstream &Info) const {
+    if (auto EC = ModuleSubstream::initialize(Stream, Info))
+      return EC;
+    Length = Info.getRecordLength();
+    return Error::success();
+  }
+};
+
+typedef VarStreamArray<ModuleSubstream> ModuleSubstreamArray;
+}
+}
+
+#endif // LLVM_DEBUGINFO_CODEVIEW_MODULESUBSTREAM_H
diff --git a/include/llvm/DebugInfo/CodeView/ModuleSubstreamVisitor.h b/include/llvm/DebugInfo/CodeView/ModuleSubstreamVisitor.h
new file mode 100644 (file)
index 0000000..7542de3
--- /dev/null
@@ -0,0 +1,96 @@
+//===- ModuleSubstreamVisitor.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_CODEVIEW_MODULESUBSTREAMVISITOR_H
+#define LLVM_DEBUGINFO_CODEVIEW_MODULESUBSTREAMVISITOR_H
+
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/CodeViewError.h"
+#include "llvm/DebugInfo/CodeView/Line.h"
+#include "llvm/DebugInfo/CodeView/ModuleSubstream.h"
+#include "llvm/DebugInfo/CodeView/StreamReader.h"
+#include "llvm/DebugInfo/CodeView/StreamRef.h"
+
+namespace llvm {
+namespace codeview {
+
+struct LineColumnEntry {
+  support::ulittle32_t Offset;
+  FixedStreamArray<LineNumberEntry> LineNumbers;
+  FixedStreamArray<ColumnNumberEntry> Columns;
+};
+
+class FileLineInfoExtractor {
+public:
+  FileLineInfoExtractor(const LineSubstreamHeader *Header) : Header(Header) {}
+
+  Error operator()(StreamRef Stream, uint32_t &Len,
+                   LineColumnEntry &Item) const {
+    const LineFileBlockHeader *BlockHeader;
+    StreamReader Reader(Stream);
+    if (auto EC = Reader.readObject(BlockHeader))
+      return EC;
+    bool HasColumn = Header->Flags & LineFlags::HaveColumns;
+    uint32_t LineInfoSize =
+        BlockHeader->NumLines *
+        (sizeof(LineNumberEntry) + (HasColumn ? sizeof(ColumnNumberEntry) : 0));
+    if (BlockHeader->BlockSize < sizeof(LineFileBlockHeader))
+      return make_error<CodeViewError>(cv_error_code::corrupt_record,
+                                       "Invalid line block record size");
+    uint32_t Size = BlockHeader->BlockSize - sizeof(LineFileBlockHeader);
+    if (LineInfoSize > Size)
+      return make_error<CodeViewError>(cv_error_code::corrupt_record,
+                                       "Invalid line block record size");
+    // The value recorded in BlockHeader->BlockSize includes the size of
+    // LineFileBlockHeader.
+    Len = BlockHeader->BlockSize;
+    Item.Offset = BlockHeader->FileOffset;
+    if (auto EC = Reader.readArray(Item.LineNumbers, BlockHeader->NumLines))
+      return EC;
+    if (HasColumn) {
+      if (auto EC = Reader.readArray(Item.Columns, BlockHeader->NumLines))
+        return EC;
+    }
+    return Error::success();
+  }
+
+private:
+  const LineSubstreamHeader *Header;
+};
+
+typedef VarStreamArray<LineColumnEntry, FileLineInfoExtractor> LineInfoArray;
+
+class IModuleSubstreamVisitor {
+public:
+  virtual ~IModuleSubstreamVisitor() {}
+
+  virtual Error visitUnknown(ModuleSubstreamKind Kind, StreamRef Data) = 0;
+  virtual Error visitSymbols(StreamRef Data);
+  virtual Error visitLines(StreamRef Data, const LineSubstreamHeader *Header,
+                           LineInfoArray Lines);
+  virtual Error visitStringTable(StreamRef Data);
+  virtual Error visitFileChecksums(StreamRef Data);
+  virtual Error visitFrameData(StreamRef Data);
+  virtual Error visitInlineeLines(StreamRef Data);
+  virtual Error visitCrossScopeImports(StreamRef Data);
+  virtual Error visitCrossScopeExports(StreamRef Data);
+  virtual Error visitILLines(StreamRef Data);
+  virtual Error visitFuncMDTokenMap(StreamRef Data);
+  virtual Error visitTypeMDTokenMap(StreamRef Data);
+  virtual Error visitMergedAssemblyInput(StreamRef Data);
+  virtual Error visitCoffSymbolRVA(StreamRef Data);
+};
+
+Error visitModuleSubstream(const ModuleSubstream &R,
+                           IModuleSubstreamVisitor &V);
+
+} // namespace codeview
+} // namespace llvm
+
+#endif // LLVM_DEBUGINFO_CODEVIEW_MODULESUBSTREAMVISITOR_H
index fcb9419..24f9037 100644 (file)
@@ -20,15 +20,20 @@ namespace llvm {
 namespace codeview {
 
 /// VarStreamArrayExtractor is intended to be specialized to provide customized
-/// extraction logic.  It should return the total number of bytes of the next
-/// record (so that the array knows how much data to skip to get to the next
-/// record, and it should initialize the second parameter with the desired
-/// value type.
+/// extraction logic.  On input it receives a StreamRef pointing to the
+/// beginning of the next record, but where the length of the record is not yet
+/// known.  Upon completion, it should return an appropriate Error instance if
+/// a record could not be extracted, or if one could be extracted it should
+/// return success and set Len to the number of bytes this record occupied in
+/// the underlying stream, and it should fill out the fields of the value type
+/// Item appropriately to represent the current record.
+///
+/// You can specialize this template for your own custom value types to avoid
+/// having to specify a second template argument to VarStreamArray (documented
+/// below).
 template <typename T> struct VarStreamArrayExtractor {
   // Method intentionally deleted.  You must provide an explicit specialization
-  // with the following method implemented.  On output return `Len` should
-  // contain the number of bytes to consume from the stream, and `Item` should
-  // be initialized with the proper value.
+  // with the following method implemented.
   Error operator()(StreamRef Stream, uint32_t &Len, T &Item) const = delete;
 };
 
@@ -40,7 +45,31 @@ template <typename T> struct VarStreamArrayExtractor {
 /// example, could mean allocating huge amounts of memory just to allow
 /// re-ordering of stream data to be contiguous before iterating over it.  By
 /// abstracting this out, we need not duplicate this memory, and we can
-/// iterate over arrays in arbitrarily formatted streams.
+/// iterate over arrays in arbitrarily formatted streams.  Elements are parsed
+/// lazily on iteration, so there is no upfront cost associated with building
+/// a VarStreamArray, no matter how large it may be.
+///
+/// You create a VarStreamArray by specifying a ValueType and an Extractor type.
+/// If you do not specify an Extractor type, it expects you to specialize
+/// VarStreamArrayExtractor<T> for your ValueType.
+///
+/// By default an Extractor is default constructed in the class, but in some
+/// cases you might find it useful for an Extractor to maintain state across
+/// extractions.  In this case you can provide your own Extractor through a
+/// secondary constructor.  The following examples show various ways of
+/// creating a VarStreamArray.
+///
+///       // Will use VarStreamArrayExtractor<MyType> as the extractor.
+///       VarStreamArray<MyType> MyTypeArray;
+///
+///       // Will use a default-constructed MyExtractor as the extractor.
+///       VarStreamArray<MyType, MyExtractor> MyTypeArray2;
+///
+///       // Will use the specific instance of MyExtractor provided.
+///       // MyExtractor need not be default-constructible in this case.
+///       MyExtractor E(SomeContext);
+///       VarStreamArray<MyType, MyExtractor> MyTypeArray3(E);
+///
 template <typename ValueType, typename Extractor> class VarStreamArrayIterator;
 
 template <typename ValueType,
@@ -52,17 +81,25 @@ public:
   typedef VarStreamArrayIterator<ValueType, Extractor> Iterator;
 
   VarStreamArray() {}
+  explicit VarStreamArray(const Extractor &E) : E(E) {}
 
-  VarStreamArray(StreamRef Stream) : Stream(Stream) {}
+  explicit VarStreamArray(StreamRef Stream) : Stream(Stream) {}
+  VarStreamArray(StreamRef Stream, const Extractor &E) : Stream(Stream), E(E) {}
+
+  VarStreamArray(const VarStreamArray<ValueType, Extractor> &Other)
+      : Stream(Other.Stream), E(Other.E) {}
 
   Iterator begin(bool *HadError = nullptr) const {
-    return Iterator(*this, HadError);
+    return Iterator(*this, E, HadError);
   }
 
-  Iterator end() const { return Iterator(); }
+  Iterator end() const { return Iterator(E); }
+
+  const Extractor &getExtractor() const { return E; }
 
 private:
   StreamRef Stream;
+  Extractor E;
 };
 
 template <typename ValueType, typename Extractor> class VarStreamArrayIterator {
@@ -70,18 +107,17 @@ template <typename ValueType, typename Extractor> class VarStreamArrayIterator {
   typedef VarStreamArray<ValueType, Extractor> ArrayType;
 
 public:
-  VarStreamArrayIterator(const ArrayType &Array, bool *HadError = nullptr)
-      : Array(&Array), IterRef(Array.Stream), HasError(false),
-        HadError(HadError) {
+  VarStreamArrayIterator(const ArrayType &Array, const Extractor &E,
+                         bool *HadError = nullptr)
+      : IterRef(Array.Stream), Array(&Array), HadError(HadError), Extract(E) {
     auto EC = Extract(IterRef, ThisLen, ThisValue);
     if (EC) {
       consumeError(std::move(EC));
       markError();
     }
   }
-  VarStreamArrayIterator()
-      : Array(nullptr), ThisLen(0), ThisValue(), IterRef(), HasError(false),
-        HadError(nullptr) {}
+  VarStreamArrayIterator() {}
+  explicit VarStreamArrayIterator(const Extractor &E) : Extract(E) {}
   ~VarStreamArrayIterator() {}
 
   bool operator==(const IterType &R) const {
@@ -146,12 +182,12 @@ private:
       *HadError = true;
   }
 
-  const ArrayType *Array;
-  uint32_t ThisLen;
   ValueType ThisValue;
   StreamRef IterRef;
-  bool HasError;
-  bool *HadError;
+  const ArrayType *Array{nullptr};
+  uint32_t ThisLen{0};
+  bool HasError{false};
+  bool *HadError{nullptr};
   Extractor Extract;
 };
 
@@ -196,8 +232,11 @@ template <typename T> class FixedStreamArrayIterator {
 public:
   FixedStreamArrayIterator(const FixedStreamArray<T> &Array)
       : Array(Array), Index(uint32_t(-1)) {}
-  FixedStreamArrayIterator(const FixedStreamArray<T> &Array, uint32_t Index)
-      : Array(Array), Index(Index) {}
+  FixedStreamArrayIterator(const FixedStreamArray<T> &Array, uint32_t ArrayIndex)
+      : Array(Array), Index(ArrayIndex) {
+    if (Array.size() <= Index)
+      Index = uint32_t(-1);
+  }
 
   bool operator==(const FixedStreamArrayIterator<T> &R) {
     assert(&Array == &R.Array);
index c8dd6e5..a0e6a07 100644 (file)
@@ -52,12 +52,12 @@ public:
     return Error::success();
   }
 
-  template <typename T>
-  Error readArray(VarStreamArray<T> &Array, uint32_t Size) {
+  template <typename T, typename U>
+  Error readArray(VarStreamArray<T, U> &Array, uint32_t Size) {
     StreamRef S;
     if (auto EC = readStreamRef(S, Size))
       return EC;
-    Array = VarStreamArray<T>(S);
+    Array = VarStreamArray<T, U>(S, Array.getExtractor());
     return Error::success();
   }
 
index 35a6564..c3b0027 100644 (file)
 #ifndef LLVM_DEBUGINFO_PDB_RAW_PDBDBISTREAM_H
 #define LLVM_DEBUGINFO_PDB_RAW_PDBDBISTREAM_H
 
+#include "llvm/DebugInfo/CodeView/ModuleSubstream.h"
 #include "llvm/DebugInfo/CodeView/StreamArray.h"
 #include "llvm/DebugInfo/CodeView/StreamRef.h"
 #include "llvm/DebugInfo/PDB/PDBTypes.h"
 #include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h"
 #include "llvm/DebugInfo/PDB/Raw/ModInfo.h"
-#include "llvm/DebugInfo/PDB/Raw/ModuleSubstreamRecord.h"
 #include "llvm/DebugInfo/PDB/Raw/NameHashTable.h"
 #include "llvm/DebugInfo/PDB/Raw/RawConstants.h"
 #include "llvm/DebugInfo/PDB/Raw/RawTypes.h"
index d7fb0cb..b76537f 100644 (file)
 
 #include "llvm/ADT/iterator_range.h"
 #include "llvm/DebugInfo/CodeView/CVRecord.h"
+#include "llvm/DebugInfo/CodeView/ModuleSubstream.h"
 #include "llvm/DebugInfo/CodeView/StreamArray.h"
 #include "llvm/DebugInfo/CodeView/StreamRef.h"
 #include "llvm/DebugInfo/CodeView/SymbolRecord.h"
 #include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h"
-#include "llvm/DebugInfo/PDB/Raw/ModuleSubstreamRecord.h"
 #include "llvm/Support/Error.h"
 
 namespace llvm {
@@ -26,8 +26,6 @@ class ModInfo;
 
 class ModStream {
 public:
-  typedef codeview::VarStreamArray<ModuleSubstreamRecord> LineInfoArray;
-
   ModStream(PDBFile &File, const ModInfo &Module);
   ~ModStream();
 
@@ -36,7 +34,8 @@ public:
   iterator_range<codeview::CVSymbolArray::Iterator>
   symbols(bool *HadError) const;
 
-  iterator_range<LineInfoArray::Iterator> lines(bool *HadError) const;
+  iterator_range<codeview::ModuleSubstreamArray::Iterator>
+  lines(bool *HadError) const;
 
 private:
   const ModInfo &Mod;
@@ -48,7 +47,7 @@ private:
   codeview::StreamRef C13LinesSubstream;
   codeview::StreamRef GlobalRefsSubstream;
 
-  LineInfoArray LineInfo;
+  codeview::ModuleSubstreamArray LineInfo;
 };
 }
 }
diff --git a/include/llvm/DebugInfo/PDB/Raw/ModuleSubstreamRecord.h b/include/llvm/DebugInfo/PDB/Raw/ModuleSubstreamRecord.h
deleted file mode 100644 (file)
index d2f837a..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-//===- ModuleSubstreamRecord.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_RAW_MODULESUBSTREAMRECORD_H
-#define LLVM_DEBUGINFO_PDB_RAW_MODULESUBSTREAMRECORD_H
-
-#include "llvm/DebugInfo/CodeView/CodeView.h"
-#include "llvm/DebugInfo/CodeView/StreamArray.h"
-#include "llvm/DebugInfo/CodeView/StreamRef.h"
-#include "llvm/Support/Error.h"
-
-namespace llvm {
-
-namespace pdb {
-class ModuleSubstreamRecord {
-public:
-  ModuleSubstreamRecord();
-  ModuleSubstreamRecord(codeview::ModuleSubstreamKind Kind,
-                        codeview::StreamRef Data);
-  static Error initialize(codeview::StreamRef Stream,
-                          ModuleSubstreamRecord &Info);
-  uint32_t getRecordLength() const;
-  codeview::ModuleSubstreamKind getSubstreamKind() const;
-  codeview::StreamRef getRecordData() const;
-
-private:
-  codeview::ModuleSubstreamKind Kind;
-  codeview::StreamRef Data;
-};
-}
-
-namespace codeview {
-template <> struct VarStreamArrayExtractor<pdb::ModuleSubstreamRecord> {
-  Error operator()(StreamRef Stream, uint32_t &Length,
-                   pdb::ModuleSubstreamRecord &Info) const {
-    if (auto EC = pdb::ModuleSubstreamRecord::initialize(Stream, Info))
-      return EC;
-    Length = Info.getRecordLength();
-    return Error::success();
-  }
-};
-}
-}
-
-#endif // LLVM_DEBUGINFO_PDB_RAW_MODULESUBSTREAMRECORD_H
index dad07b5..f804830 100644 (file)
@@ -72,45 +72,6 @@ struct SecMapEntry {
   support::ulittle32_t SecByteLength; // Byte count of the segment or group.
 };
 
-// Corresponds to the `CV_DebugSSubsectionHeader_t` structure.
-struct ModuleSubsectionHeader {
-  support::ulittle32_t Kind;   // codeview::ModuleSubstreamKind enum
-  support::ulittle32_t Length; // number of bytes occupied by this record.
-};
-
-// Corresponds to the `CV_DebugSLinesHeader_t` structure.
-struct LineTableSubsectionHeader {
-  support::ulittle32_t OffCon;
-  support::ulittle16_t SegCon;
-  support::ulittle16_t Flags;
-  support::ulittle32_t CbCon;
-};
-
-// Corresponds to the `CV_DebugSLinesFileBlockHeader_t` structure.
-struct SourceFileBlockHeader {
-  support::ulittle32_t offFile;
-  support::ulittle32_t nLines;
-  support::ulittle32_t cbBlock;
-  // LineInfo      lines[nLines];
-  // ColumnInfo    columns[nColumns];
-};
-
-// Corresponds to `CV_Line_t` structure
-struct LineInfo {
-  unsigned long Offset; // Offset to start of code bytes for line number
-  unsigned long LinenumStart : 24; // line where statement/expression starts
-  unsigned long
-      DeltaLineEnd : 7;         // delta to line where statement ends (optional)
-  unsigned long FStatement : 1; // true if a statement linenumber, else an
-                                // expression line num
-};
-
-// Corresponds to `CV_Column_t` structure
-struct ColumnInfo {
-  support::ulittle16_t OffColumnStart;
-  support::ulittle16_t OffColumnEnd;
-};
-
 } // namespace pdb
 } // namespace llvm
 
index d57c162..6c4e09f 100644 (file)
@@ -7,6 +7,8 @@ add_llvm_library(LLVMDebugInfoCodeView
   ListRecordBuilder.cpp
   MemoryTypeTableBuilder.cpp
   MethodListRecordBuilder.cpp
+  ModuleSubstream.cpp
+  ModuleSubstreamVisitor.cpp
   RecordSerialization.cpp
   StreamReader.cpp
   SymbolDumper.cpp
similarity index 52%
rename from lib/DebugInfo/PDB/Raw/ModuleSubstreamRecord.cpp
rename to lib/DebugInfo/CodeView/ModuleSubstream.cpp
index 3e0573b..2e31ed6 100644 (file)
@@ -1,4 +1,4 @@
-//===- ModuleSubstreamRecord.cpp --------------------------------*- C++ -*-===//
+//===- ModuleSubstream.cpp --------------------------------------*- C++ -*-===//
 //
 //                     The LLVM Compiler Infrastructure
 //
@@ -7,24 +7,19 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "llvm/DebugInfo/PDB/Raw/ModuleSubstreamRecord.h"
+#include "llvm/DebugInfo/CodeView/ModuleSubstream.h"
 
 #include "llvm/DebugInfo/CodeView/StreamReader.h"
-#include "llvm/DebugInfo/PDB/Raw/RawTypes.h"
 
 using namespace llvm;
 using namespace llvm::codeview;
-using namespace llvm::pdb;
 
-ModuleSubstreamRecord::ModuleSubstreamRecord()
-    : Kind(ModuleSubstreamKind::None) {}
+ModuleSubstream::ModuleSubstream() : Kind(ModuleSubstreamKind::None) {}
 
-ModuleSubstreamRecord::ModuleSubstreamRecord(ModuleSubstreamKind Kind,
-                                             StreamRef Data)
+ModuleSubstream::ModuleSubstream(ModuleSubstreamKind Kind, StreamRef Data)
     : Kind(Kind), Data(Data) {}
 
-Error ModuleSubstreamRecord::initialize(StreamRef Stream,
-                                        ModuleSubstreamRecord &Info) {
+Error ModuleSubstream::initialize(StreamRef Stream, ModuleSubstream &Info) {
   const ModuleSubsectionHeader *Header;
   StreamReader Reader(Stream);
   if (auto EC = Reader.readObject(Header))
@@ -38,12 +33,10 @@ Error ModuleSubstreamRecord::initialize(StreamRef Stream,
   return Error::success();
 }
 
-uint32_t ModuleSubstreamRecord::getRecordLength() const {
+uint32_t ModuleSubstream::getRecordLength() const {
   return sizeof(ModuleSubsectionHeader) + Data.getLength();
 }
 
-ModuleSubstreamKind ModuleSubstreamRecord::getSubstreamKind() const {
-  return Kind;
-}
+ModuleSubstreamKind ModuleSubstream::getSubstreamKind() const { return Kind; }
 
-StreamRef ModuleSubstreamRecord::getRecordData() const { return Data; }
+StreamRef ModuleSubstream::getRecordData() const { return Data; }
diff --git a/lib/DebugInfo/CodeView/ModuleSubstreamVisitor.cpp b/lib/DebugInfo/CodeView/ModuleSubstreamVisitor.cpp
new file mode 100644 (file)
index 0000000..7b5c350
--- /dev/null
@@ -0,0 +1,98 @@
+//===- ModuleSubstreamVisitor.cpp -------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/ModuleSubstreamVisitor.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+Error IModuleSubstreamVisitor::visitSymbols(StreamRef Data) {
+  return visitUnknown(ModuleSubstreamKind::Symbols, Data);
+}
+Error IModuleSubstreamVisitor::visitLines(StreamRef Data,
+                                          const LineSubstreamHeader *Header,
+                                          LineInfoArray Lines) {
+  return visitUnknown(ModuleSubstreamKind::Lines, Data);
+}
+Error IModuleSubstreamVisitor::visitStringTable(StreamRef Data) {
+  return visitUnknown(ModuleSubstreamKind::StringTable, Data);
+}
+Error IModuleSubstreamVisitor::visitFileChecksums(StreamRef Data) {
+  return visitUnknown(ModuleSubstreamKind::FileChecksums, Data);
+}
+Error IModuleSubstreamVisitor::visitFrameData(StreamRef Data) {
+  return visitUnknown(ModuleSubstreamKind::FrameData, Data);
+}
+Error IModuleSubstreamVisitor::visitInlineeLines(StreamRef Data) {
+  return visitUnknown(ModuleSubstreamKind::InlineeLines, Data);
+}
+Error IModuleSubstreamVisitor::visitCrossScopeImports(StreamRef Data) {
+  return visitUnknown(ModuleSubstreamKind::CrossScopeExports, Data);
+}
+Error IModuleSubstreamVisitor::visitCrossScopeExports(StreamRef Data) {
+  return visitUnknown(ModuleSubstreamKind::CrossScopeImports, Data);
+}
+Error IModuleSubstreamVisitor::visitILLines(StreamRef Data) {
+  return visitUnknown(ModuleSubstreamKind::ILLines, Data);
+}
+Error IModuleSubstreamVisitor::visitFuncMDTokenMap(StreamRef Data) {
+  return visitUnknown(ModuleSubstreamKind::FuncMDTokenMap, Data);
+}
+Error IModuleSubstreamVisitor::visitTypeMDTokenMap(StreamRef Data) {
+  return visitUnknown(ModuleSubstreamKind::TypeMDTokenMap, Data);
+}
+Error IModuleSubstreamVisitor::visitMergedAssemblyInput(StreamRef Data) {
+  return visitUnknown(ModuleSubstreamKind::MergedAssemblyInput, Data);
+}
+Error IModuleSubstreamVisitor::visitCoffSymbolRVA(StreamRef Data) {
+  return visitUnknown(ModuleSubstreamKind::CoffSymbolRVA, Data);
+}
+
+Error llvm::codeview::visitModuleSubstream(const ModuleSubstream &R,
+                                           IModuleSubstreamVisitor &V) {
+  switch (R.getSubstreamKind()) {
+  case ModuleSubstreamKind::Symbols:
+    return V.visitSymbols(R.getRecordData());
+  case ModuleSubstreamKind::Lines: {
+    StreamReader Reader(R.getRecordData());
+    const LineSubstreamHeader *Header;
+    if (auto EC = Reader.readObject(Header))
+      return EC;
+    FileLineInfoExtractor E(Header);
+    LineInfoArray LineInfos(E);
+    if (auto EC = Reader.readArray(LineInfos, Reader.bytesRemaining()))
+      return EC;
+    return V.visitLines(R.getRecordData(), Header, LineInfos);
+  }
+  case ModuleSubstreamKind::StringTable:
+    return V.visitStringTable(R.getRecordData());
+  case ModuleSubstreamKind::FileChecksums:
+    return V.visitFileChecksums(R.getRecordData());
+  case ModuleSubstreamKind::FrameData:
+    return V.visitFrameData(R.getRecordData());
+  case ModuleSubstreamKind::InlineeLines:
+    return V.visitInlineeLines(R.getRecordData());
+  case ModuleSubstreamKind::CrossScopeImports:
+    return V.visitCrossScopeImports(R.getRecordData());
+  case ModuleSubstreamKind::CrossScopeExports:
+    return V.visitCrossScopeExports(R.getRecordData());
+  case ModuleSubstreamKind::ILLines:
+    return V.visitILLines(R.getRecordData());
+  case ModuleSubstreamKind::FuncMDTokenMap:
+    return V.visitFuncMDTokenMap(R.getRecordData());
+  case ModuleSubstreamKind::TypeMDTokenMap:
+    return V.visitTypeMDTokenMap(R.getRecordData());
+  case ModuleSubstreamKind::MergedAssemblyInput:
+    return V.visitMergedAssemblyInput(R.getRecordData());
+  case ModuleSubstreamKind::CoffSymbolRVA:
+    return V.visitCoffSymbolRVA(R.getRecordData());
+  default:
+    return V.visitUnknown(R.getSubstreamKind(), R.getRecordData());
+  }
+}
index 4dc0b4f..46074f7 100644 (file)
@@ -33,7 +33,6 @@ add_pdb_impl_folder(Raw
   Raw/InfoStream.cpp
   Raw/MappedBlockStream.cpp
   Raw/ModInfo.cpp
-  Raw/ModuleSubstreamRecord.cpp
   Raw/ModStream.cpp
   Raw/NameHashTable.cpp
   Raw/NameMap.cpp
index a6d1977..14c5590 100644 (file)
@@ -69,7 +69,7 @@ ModStream::symbols(bool *HadError) const {
                           SymbolsSubstream.end());
 }
 
-iterator_range<ModStream::LineInfoArray::Iterator>
+iterator_range<codeview::ModuleSubstreamArray::Iterator>
 ModStream::lines(bool *HadError) const {
   return llvm::make_range(LineInfo.begin(HadError), LineInfo.end());
 }
index 85885fb..c7613af 100644 (file)
 ; EMPTY-NEXT:         }
 ; EMPTY-NEXT:       ]
 ; EMPTY-NEXT:       LineInfo [
-; EMPTY-NEXT:         {
-; EMPTY-NEXT:           Kind: Lines (0xF2)
+; EMPTY-NEXT:         Lines {
+; EMPTY-NEXT:           FileOffset: 0
+; EMPTY-NEXT:           Line {
+; EMPTY-NEXT:             Offset: 0
+; EMPTY-NEXT:             LineNumberStart: 5
+; EMPTY-NEXT:             EndDelta: 0
+; EMPTY-NEXT:             IsStatement: Yes
+; EMPTY-NEXT:           }
+; EMPTY-NEXT:           Line {
+; EMPTY-NEXT:             Offset: 3
+; EMPTY-NEXT:             LineNumberStart: 6
+; EMPTY-NEXT:             EndDelta: 0
+; EMPTY-NEXT:             IsStatement: Yes
+; EMPTY-NEXT:           }
+; EMPTY-NEXT:           Line {
+; EMPTY-NEXT:             Offset: 8
+; EMPTY-NEXT:             LineNumberStart: 7
+; EMPTY-NEXT:             EndDelta: 0
+; EMPTY-NEXT:             IsStatement: Yes
+; EMPTY-NEXT:           }
 ; EMPTY-NEXT:           Data (
 ; EMPTY-NEXT:             0000: 10000000 01000000 0A000000 00000000  |................|
 ; EMPTY-NEXT:             0010: 03000000 24000000 00000000 05000080  |....$...........|
 ; EMPTY-NEXT:             0020: 03000000 06000080 08000000 07000080  |................|
 ; EMPTY-NEXT:           )
 ; EMPTY-NEXT:         }
-; EMPTY-NEXT:         {
-; EMPTY-NEXT:           Kind: FileChecksums (0xF4)
+; EMPTY-NEXT:         FileChecksums {
 ; EMPTY-NEXT:           Data (
 ; EMPTY-NEXT:             0000: 56000000 1001A0A5 BD0D3ECD 93FC29D1  |V.........>...).|
 ; EMPTY-NEXT:             0010: 9DE826FB F4BC0000                    |..&.....|
index b5e53ed..30fe599 100644 (file)
@@ -27,6 +27,8 @@
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/Config/config.h"
 #include "llvm/DebugInfo/CodeView/EnumTables.h"
+#include "llvm/DebugInfo/CodeView/Line.h"
+#include "llvm/DebugInfo/CodeView/ModuleSubstreamVisitor.h"
 #include "llvm/DebugInfo/CodeView/StreamReader.h"
 #include "llvm/DebugInfo/CodeView/SymbolDumper.h"
 #include "llvm/DebugInfo/CodeView/TypeDumper.h"
@@ -68,6 +70,7 @@
 #include "llvm/Support/raw_ostream.h"
 
 using namespace llvm;
+using namespace llvm::codeview;
 using namespace llvm::pdb;
 
 namespace opts {
@@ -499,7 +502,7 @@ static Error dumpDbiStream(ScopedPrinter &P, PDBFile &File,
           ListScope SS(P, "Symbols");
           codeview::CVSymbolDumper SD(P, TD, nullptr, false);
           bool HadError = false;
-          for (auto &S : ModS.symbols(&HadError)) {
+          for (const auto &S : ModS.symbols(&HadError)) {
             DictScope DD(P, "");
 
             if (opts::DumpModuleSyms)
@@ -515,18 +518,67 @@ static Error dumpDbiStream(ScopedPrinter &P, PDBFile &File,
         if (opts::DumpLineInfo) {
           ListScope SS(P, "LineInfo");
           bool HadError = false;
-          for (auto &L : ModS.lines(&HadError)) {
-            DictScope DD(P, "");
-            P.printEnum("Kind", uint32_t(L.getSubstreamKind()),
-                        codeview::getModuleSubstreamKindNames());
-            ArrayRef<uint8_t> Data;
-            codeview::StreamReader R(L.getRecordData());
-            if (auto EC = R.readBytes(Data, R.bytesRemaining())) {
-              return make_error<RawError>(
-                  raw_error_code::corrupt_file,
-                  "DBI stream contained corrupt line info record");
+          // Define a locally scoped visitor to print the different
+          // substream types types.
+          class RecordVisitor : public codeview::IModuleSubstreamVisitor {
+          public:
+            RecordVisitor(ScopedPrinter &P) : P(P) {}
+            Error visitUnknown(ModuleSubstreamKind Kind,
+                               StreamRef Data) override {
+              DictScope DD(P, "Unknown");
+              return printBinaryData(Data);
+            }
+            Error visitFileChecksums(StreamRef Data) override {
+              DictScope DD(P, "FileChecksums");
+              return printBinaryData(Data);
+            }
+
+            Error visitLines(StreamRef Data, const LineSubstreamHeader *Header,
+                             LineInfoArray Lines) override {
+              DictScope DD(P, "Lines");
+              for (const auto &L : Lines) {
+                P.printNumber("FileOffset", L.Offset);
+                for (const auto &N : L.LineNumbers) {
+                  DictScope DDD(P, "Line");
+                  LineInfo LI(N.Flags);
+                  P.printNumber("Offset", N.Offset);
+                  if (LI.isAlwaysStepInto())
+                    P.printString("StepInto", StringRef("Always"));
+                  else if (LI.isNeverStepInto())
+                    P.printString("StepInto", StringRef("Never"));
+                  else
+                    P.printNumber("LineNumberStart", LI.getStartLine());
+                  P.printNumber("EndDelta", LI.getLineDelta());
+                  P.printBoolean("IsStatement", LI.isStatement());
+                }
+                for (const auto &C : L.Columns) {
+                  DictScope DDD(P, "Column");
+                  P.printNumber("Start", C.StartColumn);
+                  P.printNumber("End", C.EndColumn);
+                }
+              }
+              return printBinaryData(Data);
+            }
+
+          private:
+            Error printBinaryData(StreamRef Stream) {
+              ArrayRef<uint8_t> Data;
+              StreamReader R(Stream);
+              if (auto EC = R.readBytes(Data, R.bytesRemaining())) {
+                return make_error<RawError>(
+                    raw_error_code::corrupt_file,
+                    "DBI stream contained corrupt line info record");
+              }
+              P.printBinaryBlock("Data", Data);
+              P.flush();
+              return Error::success();
             }
-            P.printBinaryBlock("Data", Data);
+            ScopedPrinter &P;
+          };
+          RecordVisitor V(P);
+          for (const auto &L : ModS.lines(&HadError)) {
+            if (auto EC = codeview::visitModuleSubstream(L, V))
+              return EC;
           }
         }
       }
index f4df403..79559b7 100644 (file)
@@ -774,6 +774,7 @@ void COFFDumper::printCodeViewSymbolSection(StringRef SectionName,
 
   initializeFileAndStringTables(Data);
 
+  // TODO: Convert this over to using ModuleSubstreamVisitor.
   while (!Data.empty()) {
     // The section consists of a number of subsection in the following format:
     // |SubSectionType|SubSectionSize|Contents...|