OSDN Git Service

[llvm-pdbdump] Dump CodeView line information.
authorZachary Turner <zturner@google.com>
Thu, 2 Jun 2016 20:11:22 +0000 (20:11 +0000)
committerZachary Turner <zturner@google.com>
Thu, 2 Jun 2016 20:11:22 +0000 (20:11 +0000)
This first pass only splits apart the records and dumps the line
info kinds and binary data.  Subsequent patches will parse out
the binary data into more useful information and dump it in
detail.

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

14 files changed:
include/llvm/DebugInfo/CodeView/CodeView.h
include/llvm/DebugInfo/CodeView/EnumTables.h
include/llvm/DebugInfo/CodeView/StreamRef.h
include/llvm/DebugInfo/PDB/Raw/DbiStream.h
include/llvm/DebugInfo/PDB/Raw/ModStream.h
include/llvm/DebugInfo/PDB/Raw/ModuleSubstreamRecord.h [new file with mode: 0644]
include/llvm/DebugInfo/PDB/Raw/RawTypes.h
lib/DebugInfo/CodeView/EnumTables.cpp
lib/DebugInfo/CodeView/StreamReader.cpp
lib/DebugInfo/PDB/CMakeLists.txt
lib/DebugInfo/PDB/Raw/ModStream.cpp
lib/DebugInfo/PDB/Raw/ModuleSubstreamRecord.cpp [new file with mode: 0644]
test/DebugInfo/PDB/pdbdump-headers.test
tools/llvm-pdbdump/llvm-pdbdump.cpp

index 67c974a..a597d54 100644 (file)
@@ -287,6 +287,7 @@ enum class ModifierOptions : uint16_t {
 CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(ModifierOptions)
 
 enum class ModuleSubstreamKind : uint32_t {
+  None = 0,
   Symbols = 0xf1,
   Lines = 0xf2,
   StringTable = 0xf3,
index 7d14863..d1b103d 100644 (file)
@@ -30,6 +30,7 @@ ArrayRef<EnumEntry<uint32_t>> getCompileSym3FlagNames();
 ArrayRef<EnumEntry<unsigned>> getCPUTypeNames();
 ArrayRef<EnumEntry<uint32_t>> getFrameProcSymFlagNames();
 ArrayRef<EnumEntry<uint16_t>> getExportSymFlagNames();
+ArrayRef<EnumEntry<uint32_t>> getModuleSubstreamKindNames();
 ArrayRef<EnumEntry<uint8_t>> getThunkOrdinalNames();
 ArrayRef<EnumEntry<uint16_t>> getTrampolineNames();
 ArrayRef<EnumEntry<COFF::SectionCharacteristics>>
index b164381..107ab75 100644 (file)
@@ -23,6 +23,8 @@ public:
       : Stream(&Stream), ViewOffset(0), Length(Stream.getLength()) {}
   StreamRef(const StreamInterface &Stream, uint32_t Offset, uint32_t Length)
       : Stream(&Stream), ViewOffset(Offset), Length(Length) {}
+
+  StreamRef(const StreamRef &Stream, uint32_t Offset, uint32_t Length) = delete;
   StreamRef(const StreamRef &Other)
       : Stream(Other.Stream), ViewOffset(Other.ViewOffset),
         Length(Other.Length) {}
index 5319884..35a6564 100644 (file)
@@ -15,6 +15,7 @@
 #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 1460e82..d7fb0cb 100644 (file)
 
 #include "llvm/ADT/iterator_range.h"
 #include "llvm/DebugInfo/CodeView/CVRecord.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 {
@@ -24,6 +26,8 @@ class ModInfo;
 
 class ModStream {
 public:
+  typedef codeview::VarStreamArray<ModuleSubstreamRecord> LineInfoArray;
+
   ModStream(PDBFile &File, const ModInfo &Module);
   ~ModStream();
 
@@ -32,6 +36,8 @@ public:
   iterator_range<codeview::CVSymbolArray::Iterator>
   symbols(bool *HadError) const;
 
+  iterator_range<LineInfoArray::Iterator> lines(bool *HadError) const;
+
 private:
   const ModInfo &Mod;
 
@@ -41,6 +47,8 @@ private:
   codeview::StreamRef LinesSubstream;
   codeview::StreamRef C13LinesSubstream;
   codeview::StreamRef GlobalRefsSubstream;
+
+  LineInfoArray LineInfo;
 };
 }
 }
diff --git a/include/llvm/DebugInfo/PDB/Raw/ModuleSubstreamRecord.h b/include/llvm/DebugInfo/PDB/Raw/ModuleSubstreamRecord.h
new file mode 100644 (file)
index 0000000..d2f837a
--- /dev/null
@@ -0,0 +1,51 @@
+//===- 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 f804830..dad07b5 100644 (file)
@@ -72,6 +72,45 @@ 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 b209aa9..edb4897 100644 (file)
@@ -231,6 +231,23 @@ static const EnumEntry<uint32_t> FrameProcSymFlagNames[] = {
     CV_ENUM_CLASS_ENT(FrameProcedureOptions, GuardCfw),
 };
 
+static const EnumEntry<uint32_t> ModuleSubstreamKindNames[] = {
+    CV_ENUM_CLASS_ENT(ModuleSubstreamKind, None),
+    CV_ENUM_CLASS_ENT(ModuleSubstreamKind, Symbols),
+    CV_ENUM_CLASS_ENT(ModuleSubstreamKind, Lines),
+    CV_ENUM_CLASS_ENT(ModuleSubstreamKind, StringTable),
+    CV_ENUM_CLASS_ENT(ModuleSubstreamKind, FileChecksums),
+    CV_ENUM_CLASS_ENT(ModuleSubstreamKind, FrameData),
+    CV_ENUM_CLASS_ENT(ModuleSubstreamKind, InlineeLines),
+    CV_ENUM_CLASS_ENT(ModuleSubstreamKind, CrossScopeImports),
+    CV_ENUM_CLASS_ENT(ModuleSubstreamKind, CrossScopeExports),
+    CV_ENUM_CLASS_ENT(ModuleSubstreamKind, ILLines),
+    CV_ENUM_CLASS_ENT(ModuleSubstreamKind, FuncMDTokenMap),
+    CV_ENUM_CLASS_ENT(ModuleSubstreamKind, TypeMDTokenMap),
+    CV_ENUM_CLASS_ENT(ModuleSubstreamKind, MergedAssemblyInput),
+    CV_ENUM_CLASS_ENT(ModuleSubstreamKind, CoffSymbolRVA),
+};
+
 static const EnumEntry<uint16_t> ExportSymFlagNames[] = {
     CV_ENUM_CLASS_ENT(ExportFlags, IsConstant),
     CV_ENUM_CLASS_ENT(ExportFlags, IsData),
@@ -331,6 +348,9 @@ ArrayRef<EnumEntry<uint32_t>> getFrameProcSymFlagNames() {
 ArrayRef<EnumEntry<uint16_t>> getExportSymFlagNames() {
   return makeArrayRef(ExportSymFlagNames);
 }
+ArrayRef<EnumEntry<uint32_t>> getModuleSubstreamKindNames() {
+  return makeArrayRef(ModuleSubstreamKindNames);
+}
 ArrayRef<EnumEntry<uint8_t>> getThunkOrdinalNames() {
   return makeArrayRef(ThunkOrdinalNames);
 }
index 2adf948..cc5cebc 100644 (file)
@@ -15,7 +15,7 @@
 using namespace llvm;
 using namespace llvm::codeview;
 
-StreamReader::StreamReader(StreamRef Stream) : Stream(Stream), Offset(0) {}
+StreamReader::StreamReader(StreamRef S) : Stream(S), Offset(0) {}
 
 Error StreamReader::readBytes(ArrayRef<uint8_t> &Buffer, uint32_t Size) {
   if (auto EC = Stream.readBytes(Offset, Size, Buffer))
index 46074f7..4dc0b4f 100644 (file)
@@ -33,6 +33,7 @@ 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 b7204cb..a6d1977 100644 (file)
@@ -13,6 +13,7 @@
 #include "llvm/DebugInfo/PDB/Raw/ModInfo.h"
 #include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
 #include "llvm/DebugInfo/PDB/Raw/RawError.h"
+#include "llvm/DebugInfo/PDB/Raw/RawTypes.h"
 
 using namespace llvm;
 using namespace llvm::pdb;
@@ -45,9 +46,9 @@ Error ModStream::reload() {
     return EC;
   if (auto EC = Reader.readStreamRef(C13LinesSubstream, C13Size))
     return EC;
-  ArrayRef<uint8_t> LineBytes;
-  codeview::StreamReader LinesReader(C13LinesSubstream);
-  if (auto EC = LinesReader.readBytes(LineBytes, C13LinesSubstream.getLength()))
+
+  codeview::StreamReader LineReader(C13LinesSubstream);
+  if (auto EC = LineReader.readArray(LineInfo, LineReader.bytesRemaining()))
     return EC;
 
   uint32_t GlobalRefsSize;
@@ -67,3 +68,8 @@ ModStream::symbols(bool *HadError) const {
   return llvm::make_range(SymbolsSubstream.begin(HadError),
                           SymbolsSubstream.end());
 }
+
+iterator_range<ModStream::LineInfoArray::Iterator>
+ModStream::lines(bool *HadError) const {
+  return llvm::make_range(LineInfo.begin(HadError), LineInfo.end());
+}
diff --git a/lib/DebugInfo/PDB/Raw/ModuleSubstreamRecord.cpp b/lib/DebugInfo/PDB/Raw/ModuleSubstreamRecord.cpp
new file mode 100644 (file)
index 0000000..3e0573b
--- /dev/null
@@ -0,0 +1,49 @@
+//===- ModuleSubstreamRecord.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/PDB/Raw/ModuleSubstreamRecord.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) {}
+
+ModuleSubstreamRecord::ModuleSubstreamRecord(ModuleSubstreamKind Kind,
+                                             StreamRef Data)
+    : Kind(Kind), Data(Data) {}
+
+Error ModuleSubstreamRecord::initialize(StreamRef Stream,
+                                        ModuleSubstreamRecord &Info) {
+  const ModuleSubsectionHeader *Header;
+  StreamReader Reader(Stream);
+  if (auto EC = Reader.readObject(Header))
+    return EC;
+
+  ModuleSubstreamKind Kind =
+      static_cast<ModuleSubstreamKind>(uint32_t(Header->Kind));
+  if (auto EC = Reader.readStreamRef(Info.Data, Header->Length))
+    return EC;
+  Info.Kind = Kind;
+  return Error::success();
+}
+
+uint32_t ModuleSubstreamRecord::getRecordLength() const {
+  return sizeof(ModuleSubsectionHeader) + Data.getLength();
+}
+
+ModuleSubstreamKind ModuleSubstreamRecord::getSubstreamKind() const {
+  return Kind;
+}
+
+StreamRef ModuleSubstreamRecord::getRecordData() const { return Data; }
index b8f2b56..85885fb 100644 (file)
@@ -1,8 +1,8 @@
 ; RUN: llvm-pdbdump -raw-headers -raw-tpi-records -raw-tpi-record-bytes -raw-module-syms \
 ; RUN:              -raw-sym-record-bytes -raw-publics -raw-module-files -raw-stream-name=/names \
 ; RUN:              -raw-stream-summary -raw-stream-blocks -raw-ipi-records -raw-ipi-record-bytes \
-; RUN:              -raw-section-contribs -raw-section-map -raw-section-headers %p/Inputs/empty.pdb \
-; RUN:              | FileCheck -check-prefix=EMPTY %s
+; RUN:              -raw-section-contribs -raw-section-map -raw-section-headers -raw-line-info \
+; RUN:              %p/Inputs/empty.pdb | FileCheck -check-prefix=EMPTY %s
 ; RUN: llvm-pdbdump -raw-all %p/Inputs/empty.pdb | FileCheck -check-prefix=ALL %s
 ; RUN: llvm-pdbdump -raw-headers -raw-stream-name=/names -raw-modules -raw-module-files \
 ; RUN:              %p/Inputs/big-read.pdb | FileCheck -check-prefix=BIG %s
 ; EMPTY-NEXT:           )
 ; EMPTY-NEXT:         }
 ; EMPTY-NEXT:       ]
+; EMPTY-NEXT:       LineInfo [
+; EMPTY-NEXT:         {
+; EMPTY-NEXT:           Kind: Lines (0xF2)
+; 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:           Data (
+; EMPTY-NEXT:             0000: 56000000 1001A0A5 BD0D3ECD 93FC29D1  |V.........>...).|
+; EMPTY-NEXT:             0010: 9DE826FB F4BC0000                    |..&.....|
+; EMPTY-NEXT:           )
+; EMPTY-NEXT:         }
+; EMPTY-NEXT:       ]
 ; EMPTY-NEXT:     }
 ; EMPTY-NEXT:     {
 ; EMPTY-NEXT:       Name: * Linker *
 ; EMPTY-NEXT:           )
 ; EMPTY-NEXT:         }
 ; EMPTY-NEXT:       ]
+; EMPTY-NEXT:       LineInfo [
+; EMPTY-NEXT:       ]
 ; EMPTY-NEXT:     }
 ; EMPTY-NEXT:   ]
 ; EMPTY-NEXT: }
index b295876..0e7003d 100644 (file)
@@ -144,6 +144,9 @@ cl::opt<bool> DumpPublics("raw-publics", cl::desc("dump Publics stream data"),
 cl::opt<bool> DumpSectionContribs("raw-section-contribs",
                                   cl::desc("dump section contributions"),
                                   cl::cat(NativeOptions));
+cl::opt<bool> DumpLineInfo("raw-line-info",
+                           cl::desc("dump file and line information"),
+                           cl::cat(NativeOptions));
 cl::opt<bool> DumpSectionMap("raw-section-map", cl::desc("dump section map"),
                              cl::cat(NativeOptions));
 cl::opt<bool>
@@ -429,8 +432,8 @@ static Error dumpNamedStream(ScopedPrinter &P, PDBFile &File) {
 
 static Error dumpDbiStream(ScopedPrinter &P, PDBFile &File,
                            codeview::CVTypeDumper &TD) {
-  bool DumpModules =
-      opts::DumpModules || opts::DumpModuleSyms || opts::DumpModuleFiles;
+  bool DumpModules = opts::DumpModules || opts::DumpModuleSyms ||
+                     opts::DumpModuleFiles || opts::DumpLineInfo;
   if (!opts::DumpHeaders && !DumpModules)
     return Error::success();
 
@@ -487,25 +490,45 @@ static Error dumpDbiStream(ScopedPrinter &P, PDBFile &File,
           (Modi.Info.getModuleStreamIndex() < File.getNumStreams());
       bool ShouldDumpSymbols =
           (opts::DumpModuleSyms || opts::DumpSymRecordBytes);
-      if (HasModuleDI && ShouldDumpSymbols) {
-        ListScope SS(P, "Symbols");
+      if (HasModuleDI && (ShouldDumpSymbols || opts::DumpLineInfo)) {
         ModStream ModS(File, Modi.Info);
         if (auto EC = ModS.reload())
           return EC;
 
-        codeview::CVSymbolDumper SD(P, TD, nullptr, false);
-        bool HadError = false;
-        for (auto &S : ModS.symbols(&HadError)) {
-          DictScope DD(P, "");
-
-          if (opts::DumpModuleSyms)
-            SD.dump(S);
-          if (opts::DumpSymRecordBytes)
-            P.printBinaryBlock("Bytes", S.Data);
+        if (ShouldDumpSymbols) {
+          ListScope SS(P, "Symbols");
+          codeview::CVSymbolDumper SD(P, TD, nullptr, false);
+          bool HadError = false;
+          for (auto &S : ModS.symbols(&HadError)) {
+            DictScope DD(P, "");
+
+            if (opts::DumpModuleSyms)
+              SD.dump(S);
+            if (opts::DumpSymRecordBytes)
+              P.printBinaryBlock("Bytes", S.Data);
+          }
+          if (HadError)
+            return make_error<RawError>(
+                raw_error_code::corrupt_file,
+                "DBI stream contained corrupt symbol record");
+        }
+        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");
+            }
+            P.printBinaryBlock("Data", Data);
+          }
         }
-        if (HadError)
-          return make_error<RawError>(raw_error_code::corrupt_file,
-                                      "DBI stream contained corrupt record");
       }
     }
   }
@@ -805,6 +828,8 @@ bool isRawDumpEnabled() {
     return true;
   if (opts::DumpSectionMap)
     return true;
+  if (opts::DumpLineInfo)
+    return true;
   return false;
 }
 
@@ -972,6 +997,7 @@ int main(int argc_, const char *argv_[]) {
     opts::DumpIpiRecords = true;
     opts::DumpSectionMap = true;
     opts::DumpSectionContribs = true;
+    opts::DumpLineInfo = true;
   }
 
   // When adding filters for excluded compilands and types, we need to remember