[CodeView] Support remaining debug subsection types

This adds support for Symbols, StringTable, and FrameData subsection
types.  Even though these subsections rarely if ever appear in a PDB
file (they are usually in object files), there's no theoretical reason
why they *couldn't* appear in a PDB.  The real issue though is that in
order to add support for dumping and writing them (which will be useful
for object files), we need a way to test them.  And since there is no
support for reading and writing them to / from object files yet, making
PDB support them is the best way to both add support for the underlying
format and add support for tests at the same time.  Later, when we go
to add support for reading / writing them from object files, we'll need
only minimal changes in the underlying read/write code.

llvm-svn: 305037
diff --git a/llvm/lib/DebugInfo/CodeView/DebugStringTableSubsection.cpp b/llvm/lib/DebugInfo/CodeView/DebugStringTableSubsection.cpp
index 7b972a1..6e647c4 100644
--- a/llvm/lib/DebugInfo/CodeView/DebugStringTableSubsection.cpp
+++ b/llvm/lib/DebugInfo/CodeView/DebugStringTableSubsection.cpp
@@ -24,7 +24,7 @@
   return Error::success();
 }
 Error DebugStringTableSubsectionRef::initialize(BinaryStreamReader &Reader) {
-  return Reader.readStreamRef(Stream, Reader.bytesRemaining());
+  return Reader.readStreamRef(Stream);
 }
 
 Expected<StringRef>
@@ -55,20 +55,19 @@
 }
 
 Error DebugStringTableSubsection::commit(BinaryStreamWriter &Writer) const {
-  assert(Writer.bytesRemaining() == StringSize);
-  uint32_t MaxOffset = 1;
+  uint32_t Begin = Writer.getOffset();
+  uint32_t End = Begin + StringSize;
 
   for (auto &Pair : Strings) {
     StringRef S = Pair.getKey();
-    uint32_t Offset = Pair.getValue();
+    uint32_t Offset = Begin + Pair.getValue();
     Writer.setOffset(Offset);
     if (auto EC = Writer.writeCString(S))
       return EC;
-    MaxOffset = std::max<uint32_t>(MaxOffset, Offset + S.size() + 1);
+    assert(Writer.getOffset() <= End);
   }
 
-  Writer.setOffset(MaxOffset);
-  assert(Writer.bytesRemaining() == 0);
+  Writer.setOffset(End);
   return Error::success();
 }
 
diff --git a/llvm/lib/DebugInfo/CodeView/DebugSubsectionRecord.cpp b/llvm/lib/DebugInfo/CodeView/DebugSubsectionRecord.cpp
index 0cf3184..eed8eda 100644
--- a/llvm/lib/DebugInfo/CodeView/DebugSubsectionRecord.cpp
+++ b/llvm/lib/DebugInfo/CodeView/DebugSubsectionRecord.cpp
@@ -40,6 +40,9 @@
   case DebugSubsectionKind::InlineeLines:
   case DebugSubsectionKind::CrossScopeExports:
   case DebugSubsectionKind::CrossScopeImports:
+  case DebugSubsectionKind::Symbols:
+  case DebugSubsectionKind::StringTable:
+  case DebugSubsectionKind::FrameData:
     break;
   default:
     llvm_unreachable("Unexpected debug fragment kind!");
@@ -52,9 +55,7 @@
 }
 
 uint32_t DebugSubsectionRecord::getRecordLength() const {
-  uint32_t Result = sizeof(DebugSubsectionHeader) + Data.getLength();
-  assert(Result % alignOf(Container) == 0);
-  return Result;
+  return sizeof(DebugSubsectionHeader) + Data.getLength();
 }
 
 DebugSubsectionKind DebugSubsectionRecord::kind() const { return Kind; }
@@ -66,25 +67,29 @@
     : Subsection(std::move(Subsection)), Container(Container) {}
 
 uint32_t DebugSubsectionRecordBuilder::calculateSerializedLength() {
-  uint32_t Size =
-      sizeof(DebugSubsectionHeader) +
-      alignTo(Subsection->calculateSerializedSize(), alignOf(Container));
+  // The length of the entire subsection is always padded to 4 bytes, regardless
+  // of the container kind.
+  uint32_t Size = sizeof(DebugSubsectionHeader) +
+                  alignTo(Subsection->calculateSerializedSize(), 4);
   return Size;
 }
 
-Error DebugSubsectionRecordBuilder::commit(BinaryStreamWriter &Writer) {
+Error DebugSubsectionRecordBuilder::commit(BinaryStreamWriter &Writer) const {
   assert(Writer.getOffset() % alignOf(Container) == 0 &&
          "Debug Subsection not properly aligned");
 
   DebugSubsectionHeader Header;
   Header.Kind = uint32_t(Subsection->kind());
-  Header.Length = calculateSerializedLength() - sizeof(DebugSubsectionHeader);
+  // The value written into the Header's Length field is only padded to the
+  // container's alignment
+  Header.Length =
+      alignTo(Subsection->calculateSerializedSize(), alignOf(Container));
 
   if (auto EC = Writer.writeObject(Header))
     return EC;
   if (auto EC = Subsection->commit(Writer))
     return EC;
-  if (auto EC = Writer.padToAlignment(alignOf(Container)))
+  if (auto EC = Writer.padToAlignment(4))
     return EC;
 
   return Error::success();
diff --git a/llvm/lib/DebugInfo/CodeView/DebugSubsectionVisitor.cpp b/llvm/lib/DebugInfo/CodeView/DebugSubsectionVisitor.cpp
index ee769d3..be56ea1 100644
--- a/llvm/lib/DebugInfo/CodeView/DebugSubsectionVisitor.cpp
+++ b/llvm/lib/DebugInfo/CodeView/DebugSubsectionVisitor.cpp
@@ -1,4 +1,4 @@
-//===- DebugSubsectionVisitor.cpp ---------------------------*- C++ -*-===//
+//===- DebugSubsectionVisitor.cpp -------------------------------*- C++ -*-===//
 //
 //                     The LLVM Compiler Infrastructure
 //
@@ -12,10 +12,12 @@
 #include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
 #include "llvm/DebugInfo/CodeView/DebugCrossExSubsection.h"
 #include "llvm/DebugInfo/CodeView/DebugCrossImpSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h"
 #include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h"
 #include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h"
 #include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"
 #include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h"
+#include "llvm/DebugInfo/CodeView/DebugSymbolsSubsection.h"
 #include "llvm/DebugInfo/CodeView/DebugUnknownSubsection.h"
 #include "llvm/Support/BinaryStreamReader.h"
 #include "llvm/Support/BinaryStreamRef.h"
@@ -91,6 +93,24 @@
       return EC;
     return V.visitCrossModuleImports(Section, State);
   }
+  case DebugSubsectionKind::Symbols: {
+    DebugSymbolsSubsectionRef Section;
+    if (auto EC = Section.initialize(Reader))
+      return EC;
+    return V.visitSymbols(Section, State);
+  }
+  case DebugSubsectionKind::StringTable: {
+    DebugStringTableSubsectionRef Section;
+    if (auto EC = Section.initialize(Reader))
+      return EC;
+    return V.visitStringTable(Section, State);
+  }
+  case DebugSubsectionKind::FrameData: {
+    DebugFrameDataSubsectionRef Section;
+    if (auto EC = Section.initialize(Reader))
+      return EC;
+    return V.visitFrameData(Section, State);
+  }
   default: {
     DebugUnknownSubsectionRef Fragment(R.kind(), R.getRecordData());
     return V.visitUnknown(Fragment);