[pdb] Parse and dump section map and section contribs

Differential Revision: http://reviews.llvm.org/D20876
Reviewed By: rnk, ruiu

llvm-svn: 271488
diff --git a/llvm/lib/DebugInfo/PDB/CMakeLists.txt b/llvm/lib/DebugInfo/PDB/CMakeLists.txt
index 0938c07..46074f7 100644
--- a/llvm/lib/DebugInfo/PDB/CMakeLists.txt
+++ b/llvm/lib/DebugInfo/PDB/CMakeLists.txt
@@ -29,6 +29,7 @@
 
 add_pdb_impl_folder(Raw
   Raw/DbiStream.cpp
+  Raw/EnumTables.cpp
   Raw/InfoStream.cpp
   Raw/MappedBlockStream.cpp
   Raw/ModInfo.cpp
diff --git a/llvm/lib/DebugInfo/PDB/Raw/DbiStream.cpp b/llvm/lib/DebugInfo/PDB/Raw/DbiStream.cpp
index 1827ab0..96a68b6 100644
--- a/llvm/lib/DebugInfo/PDB/Raw/DbiStream.cpp
+++ b/llvm/lib/DebugInfo/PDB/Raw/DbiStream.cpp
@@ -10,14 +10,17 @@
 
 #include "llvm/DebugInfo/CodeView/StreamArray.h"
 #include "llvm/DebugInfo/CodeView/StreamReader.h"
+#include "llvm/DebugInfo/PDB/Raw/ISectionContribVisitor.h"
 #include "llvm/DebugInfo/PDB/Raw/InfoStream.h"
 #include "llvm/DebugInfo/PDB/Raw/ModInfo.h"
 #include "llvm/DebugInfo/PDB/Raw/NameHashTable.h"
 #include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
 #include "llvm/DebugInfo/PDB/Raw/RawConstants.h"
 #include "llvm/DebugInfo/PDB/Raw/RawError.h"
+#include "llvm/DebugInfo/PDB/Raw/RawTypes.h"
 
 using namespace llvm;
+using namespace llvm::codeview;
 using namespace llvm::pdb;
 using namespace llvm::support;
 
@@ -73,6 +76,20 @@
   ulittle32_t Reserved; // Pad to 64 bytes
 };
 
+template <typename ContribType>
+Error loadSectionContribs(FixedStreamArray<ContribType> &Output,
+                          StreamReader &Reader) {
+  if (Reader.bytesRemaining() % sizeof(ContribType) != 0)
+    return make_error<RawError>(
+        raw_error_code::corrupt_file,
+        "Invalid number of bytes of section contributions");
+
+  uint32_t Count = Reader.bytesRemaining() / sizeof(ContribType);
+  if (auto EC = Reader.readArray(Output, Count))
+    return EC;
+  return Error::success();
+}
+
 DbiStream::DbiStream(PDBFile &File)
     : Pdb(File), Stream(StreamDBI, File), Header(nullptr) {
   static_assert(sizeof(HeaderInfo) == 64, "Invalid HeaderInfo size!");
@@ -81,7 +98,7 @@
 DbiStream::~DbiStream() {}
 
 Error DbiStream::reload() {
-  codeview::StreamReader Reader(Stream);
+  StreamReader Reader(Stream);
 
   if (Stream.getLength() < sizeof(HeaderInfo))
     return make_error<RawError>(raw_error_code::corrupt_file,
@@ -98,7 +115,7 @@
   // produced in the last decade and allows us to avoid having to
   // special case all kinds of complicated arcane formats.
   if (Header->VersionHeader < PdbDbiV70)
-    return make_error<RawError>(raw_error_code::corrupt_file,
+    return make_error<RawError>(raw_error_code::feature_unsupported,
                                 "Unsupported DBI version.");
 
   auto InfoStream = Pdb.getPDBInfoStream();
@@ -138,7 +155,7 @@
 
   // Since each ModInfo in the stream is a variable length, we have to iterate
   // them to know how many there actually are.
-  codeview::VarStreamArray<ModInfo> ModInfoArray;
+  VarStreamArray<ModInfo> ModInfoArray;
   if (auto EC = Reader.readArray(ModInfoArray, Header->ModiSubstreamSize))
     return EC;
   for (auto &Info : ModInfoArray) {
@@ -161,6 +178,12 @@
                                                  sizeof(ulittle16_t)))
     return EC;
 
+  if (auto EC = initializeSectionContributionData())
+    return EC;
+
+  if (auto EC = initializeSectionMapData())
+    return EC;
+
   if (auto EC = initializeFileInfo())
     return EC;
 
@@ -168,7 +191,7 @@
     return make_error<RawError>(raw_error_code::corrupt_file,
                                 "Found unexpected bytes in DBI Stream.");
 
-  codeview::StreamReader ECReader(ECSubstream);
+  StreamReader ECReader(ECSubstream);
   if (auto EC = ECNames.load(ECReader))
     return EC;
 
@@ -222,6 +245,44 @@
 }
 
 ArrayRef<ModuleInfoEx> DbiStream::modules() const { return ModuleInfos; }
+codeview::FixedStreamArray<SecMapEntry> DbiStream::getSectionMap() const {
+  return SectionMap;
+}
+
+void llvm::pdb::DbiStream::visitSectionContributions(
+    ISectionContribVisitor &Visitor) const {
+  if (SectionContribVersion == DbiSecContribVer60) {
+    for (auto &SC : SectionContribs)
+      Visitor.visit(SC);
+  } else if (SectionContribVersion == DbiSecContribV2) {
+    for (auto &SC : SectionContribs2)
+      Visitor.visit(SC);
+  }
+}
+
+Error DbiStream::initializeSectionContributionData() {
+  StreamReader SCReader(SecContrSubstream);
+  if (auto EC = SCReader.readEnum(SectionContribVersion))
+    return EC;
+
+  if (SectionContribVersion == DbiSecContribVer60)
+    return loadSectionContribs<SectionContrib>(SectionContribs, SCReader);
+  if (SectionContribVersion == DbiSecContribV2)
+    return loadSectionContribs<SectionContrib2>(SectionContribs2, SCReader);
+
+  return make_error<RawError>(raw_error_code::feature_unsupported,
+                              "Unsupported DBI Section Contribution version");
+}
+
+Error DbiStream::initializeSectionMapData() {
+  StreamReader SMReader(SecMapSubstream);
+  const SecMapHeader *Header;
+  if (auto EC = SMReader.readObject(Header))
+    return EC;
+  if (auto EC = SMReader.readArray(SectionMap, Header->SecCount))
+    return EC;
+  return Error::success();
+}
 
 Error DbiStream::initializeFileInfo() {
   struct FileInfoSubstreamHeader {
@@ -246,7 +307,7 @@
   // it is computed by summing `ModFileCounts`.
   //
   const FileInfoSubstreamHeader *FH;
-  codeview::StreamReader FISR(FileInfoSubstream);
+  StreamReader FISR(FileInfoSubstream);
   if (auto EC = FISR.readObject(FH))
     return EC;
 
@@ -256,9 +317,9 @@
     return make_error<RawError>(raw_error_code::corrupt_file,
                                 "FileInfo substream count doesn't match DBI.");
 
-  codeview::FixedStreamArray<ulittle16_t> ModIndexArray;
-  codeview::FixedStreamArray<ulittle16_t> ModFileCountArray;
-  codeview::FixedStreamArray<little32_t> FileNameOffsets;
+  FixedStreamArray<ulittle16_t> ModIndexArray;
+  FixedStreamArray<ulittle16_t> ModFileCountArray;
+  FixedStreamArray<little32_t> FileNameOffsets;
 
   // First is an array of `NumModules` module indices.  This is not used for the
   // same reason that `NumSourceFiles` is not used.  It's an array of uint16's,
@@ -286,10 +347,10 @@
   if (auto EC = FISR.readArray(FileNameOffsets, NumSourceFiles))
     return EC;
 
-  codeview::StreamRef NamesBufferRef;
+  StreamRef NamesBufferRef;
   if (auto EC = FISR.readStreamRef(NamesBufferRef))
     return EC;
-  codeview::StreamReader Names(NamesBufferRef);
+  StreamReader Names(NamesBufferRef);
 
   // We go through each ModuleInfo, determine the number N of source files for
   // that module, and then get the next N offsets from the Offsets array, using
diff --git a/llvm/lib/DebugInfo/PDB/Raw/EnumTables.cpp b/llvm/lib/DebugInfo/PDB/Raw/EnumTables.cpp
new file mode 100644
index 0000000..fc9270c
--- /dev/null
+++ b/llvm/lib/DebugInfo/PDB/Raw/EnumTables.cpp
@@ -0,0 +1,38 @@
+//===- EnumTables.cpp - Enum to string conversion tables --------*- 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/EnumTables.h"
+#include "llvm/DebugInfo/PDB/Raw/RawConstants.h"
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+#define PDB_ENUM_CLASS_ENT(enum_class, enum)                                   \
+  { #enum, std::underlying_type < enum_class > ::type(enum_class::enum) }
+
+#define PDB_ENUM_ENT(ns, enum)                                                 \
+  { #enum, ns::enum }
+
+static const EnumEntry<uint16_t> OMFSegMapDescFlagNames[] = {
+    PDB_ENUM_CLASS_ENT(OMFSegDescFlags, Read),
+    PDB_ENUM_CLASS_ENT(OMFSegDescFlags, Write),
+    PDB_ENUM_CLASS_ENT(OMFSegDescFlags, Execute),
+    PDB_ENUM_CLASS_ENT(OMFSegDescFlags, AddressIs32Bit),
+    PDB_ENUM_CLASS_ENT(OMFSegDescFlags, IsSelector),
+    PDB_ENUM_CLASS_ENT(OMFSegDescFlags, IsAbsoluteAddress),
+    PDB_ENUM_CLASS_ENT(OMFSegDescFlags, IsGroup),
+};
+
+namespace llvm {
+namespace pdb {
+ArrayRef<EnumEntry<uint16_t>> getOMFSegMapDescFlagNames() {
+  return makeArrayRef(OMFSegMapDescFlagNames);
+}
+}
+}
\ No newline at end of file
diff --git a/llvm/lib/DebugInfo/PDB/Raw/ModStream.cpp b/llvm/lib/DebugInfo/PDB/Raw/ModStream.cpp
index 8b7a715..b7204cb 100644
--- a/llvm/lib/DebugInfo/PDB/Raw/ModStream.cpp
+++ b/llvm/lib/DebugInfo/PDB/Raw/ModStream.cpp
@@ -45,6 +45,10 @@
     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()))
+    return EC;
 
   uint32_t GlobalRefsSize;
   if (auto EC = Reader.readInteger(GlobalRefsSize))