[CodeView] Isolate Debug Info Fragments into standalone classes.

Previously parsing of these were all grouped together into a
single master class that could parse any type of debug info
fragment.

With writing forthcoming, the complexity of each individual
fragment is enough to warrant them having their own classes so
that reading and writing of each fragment type can be grouped
together, but isolated from the code for reading and writing
other fragment types.

In doing so, I found a place where parsing code was duplicated
for the FileChecksums fragment, across llvm-readobj and the
CodeView library, and one of the implementations had a bug.
Now that the codepaths are merged, the bug is resolved.

Differential Revision: https://reviews.llvm.org/D32547

llvm-svn: 301557
diff --git a/llvm/lib/DebugInfo/CodeView/CMakeLists.txt b/llvm/lib/DebugInfo/CodeView/CMakeLists.txt
index 5dae51e..7655f6c 100644
--- a/llvm/lib/DebugInfo/CodeView/CMakeLists.txt
+++ b/llvm/lib/DebugInfo/CodeView/CMakeLists.txt
@@ -7,8 +7,12 @@
   EnumTables.cpp
   Formatters.cpp
   Line.cpp
+  ModuleDebugFileChecksumFragment.cpp
   ModuleDebugFragment.cpp
+  ModuleDebugFragmentRecord.cpp
   ModuleDebugFragmentVisitor.cpp
+  ModuleDebugLineFragment.cpp
+  ModuleDebugUnknownFragment.cpp
   RecordSerialization.cpp
   SymbolRecordMapping.cpp
   SymbolDumper.cpp
diff --git a/llvm/lib/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.cpp b/llvm/lib/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.cpp
new file mode 100644
index 0000000..3f234ad
--- /dev/null
+++ b/llvm/lib/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.cpp
@@ -0,0 +1,49 @@
+//===- ModuleDebugFileChecksumFragment.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/ModuleDebugFileChecksumFragment.h"
+
+#include "llvm/DebugInfo/CodeView/CodeViewError.h"
+#include "llvm/Support/BinaryStreamReader.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+struct FileChecksumEntryHeader {
+  using ulittle32_t = support::ulittle32_t;
+
+  ulittle32_t FileNameOffset; // Byte offset of filename in global string table.
+  uint8_t ChecksumSize;       // Number of bytes of checksum.
+  uint8_t ChecksumKind;       // FileChecksumKind
+                              // Checksum bytes follow.
+};
+
+Error llvm::VarStreamArrayExtractor<FileChecksumEntry>::extract(
+    BinaryStreamRef Stream, uint32_t &Len, FileChecksumEntry &Item, void *Ctx) {
+  BinaryStreamReader Reader(Stream);
+
+  const FileChecksumEntryHeader *Header;
+  if (auto EC = Reader.readObject(Header))
+    return EC;
+
+  Item.FileNameOffset = Header->FileNameOffset;
+  Item.Kind = static_cast<FileChecksumKind>(Header->ChecksumKind);
+  if (auto EC = Reader.readBytes(Item.Checksum, Header->ChecksumSize))
+    return EC;
+
+  Len = alignTo(Header->ChecksumSize + sizeof(FileChecksumEntryHeader), 4);
+  return Error::success();
+}
+
+Error ModuleDebugFileChecksumFragment::initialize(BinaryStreamReader Reader) {
+  if (auto EC = Reader.readArray(Checksums, Reader.bytesRemaining()))
+    return EC;
+
+  return Error::success();
+}
diff --git a/llvm/lib/DebugInfo/CodeView/ModuleDebugFragment.cpp b/llvm/lib/DebugInfo/CodeView/ModuleDebugFragment.cpp
index 1329f8c..a3327b0 100644
--- a/llvm/lib/DebugInfo/CodeView/ModuleDebugFragment.cpp
+++ b/llvm/lib/DebugInfo/CodeView/ModuleDebugFragment.cpp
@@ -1,5 +1,4 @@
-//===- ModuleDebugFragment.cpp --------------------------------------*- C++
-//-*-===//
+//===- ModuleDebugFragment.cpp -----------------------------------*- C++-*-===//
 //
 //                     The LLVM Compiler Infrastructure
 //
@@ -10,37 +9,6 @@
 
 #include "llvm/DebugInfo/CodeView/ModuleDebugFragment.h"
 
-#include "llvm/Support/BinaryStreamReader.h"
-
-using namespace llvm;
 using namespace llvm::codeview;
 
-ModuleDebugFragment::ModuleDebugFragment()
-    : Kind(ModuleDebugFragmentKind::None) {}
-
-ModuleDebugFragment::ModuleDebugFragment(ModuleDebugFragmentKind Kind,
-                                         BinaryStreamRef Data)
-    : Kind(Kind), Data(Data) {}
-
-Error ModuleDebugFragment::initialize(BinaryStreamRef Stream,
-                                      ModuleDebugFragment &Info) {
-  const ModuleDebugFragmentHeader *Header;
-  BinaryStreamReader Reader(Stream);
-  if (auto EC = Reader.readObject(Header))
-    return EC;
-
-  ModuleDebugFragmentKind Kind =
-      static_cast<ModuleDebugFragmentKind>(uint32_t(Header->Kind));
-  if (auto EC = Reader.readStreamRef(Info.Data, Header->Length))
-    return EC;
-  Info.Kind = Kind;
-  return Error::success();
-}
-
-uint32_t ModuleDebugFragment::getRecordLength() const {
-  return sizeof(ModuleDebugFragmentHeader) + Data.getLength();
-}
-
-ModuleDebugFragmentKind ModuleDebugFragment::kind() const { return Kind; }
-
-BinaryStreamRef ModuleDebugFragment::getRecordData() const { return Data; }
+ModuleDebugFragment::~ModuleDebugFragment() {}
diff --git a/llvm/lib/DebugInfo/CodeView/ModuleDebugFragmentRecord.cpp b/llvm/lib/DebugInfo/CodeView/ModuleDebugFragmentRecord.cpp
new file mode 100644
index 0000000..20c06e9
--- /dev/null
+++ b/llvm/lib/DebugInfo/CodeView/ModuleDebugFragmentRecord.cpp
@@ -0,0 +1,47 @@
+//===- ModuleDebugFragmentRecord.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/ModuleDebugFragmentRecord.h"
+
+#include "llvm/Support/BinaryStreamReader.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+ModuleDebugFragmentRecord::ModuleDebugFragmentRecord()
+    : Kind(ModuleDebugFragmentKind::None) {}
+
+ModuleDebugFragmentRecord::ModuleDebugFragmentRecord(
+    ModuleDebugFragmentKind Kind, BinaryStreamRef Data)
+    : Kind(Kind), Data(Data) {}
+
+Error ModuleDebugFragmentRecord::initialize(BinaryStreamRef Stream,
+                                            ModuleDebugFragmentRecord &Info) {
+  const ModuleDebugFragmentHeader *Header;
+  BinaryStreamReader Reader(Stream);
+  if (auto EC = Reader.readObject(Header))
+    return EC;
+
+  ModuleDebugFragmentKind Kind =
+      static_cast<ModuleDebugFragmentKind>(uint32_t(Header->Kind));
+  if (auto EC = Reader.readStreamRef(Info.Data, Header->Length))
+    return EC;
+  Info.Kind = Kind;
+  return Error::success();
+}
+
+uint32_t ModuleDebugFragmentRecord::getRecordLength() const {
+  return sizeof(ModuleDebugFragmentHeader) + Data.getLength();
+}
+
+ModuleDebugFragmentKind ModuleDebugFragmentRecord::kind() const { return Kind; }
+
+BinaryStreamRef ModuleDebugFragmentRecord::getRecordData() const {
+  return Data;
+}
diff --git a/llvm/lib/DebugInfo/CodeView/ModuleDebugFragmentVisitor.cpp b/llvm/lib/DebugInfo/CodeView/ModuleDebugFragmentVisitor.cpp
index 37cd887..53dc922 100644
--- a/llvm/lib/DebugInfo/CodeView/ModuleDebugFragmentVisitor.cpp
+++ b/llvm/lib/DebugInfo/CodeView/ModuleDebugFragmentVisitor.cpp
@@ -8,99 +8,36 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/DebugInfo/CodeView/ModuleDebugFragmentVisitor.h"
+
+#include "llvm/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.h"
+#include "llvm/DebugInfo/CodeView/ModuleDebugLineFragment.h"
 #include "llvm/Support/BinaryStreamReader.h"
 #include "llvm/Support/BinaryStreamRef.h"
 
 using namespace llvm;
 using namespace llvm::codeview;
 
-Error ModuleDebugFragmentVisitor::visitSymbols(BinaryStreamRef Data) {
-  return visitUnknown(ModuleDebugFragmentKind::Symbols, Data);
-}
-Error ModuleDebugFragmentVisitor::visitLines(BinaryStreamRef Data,
-                                             const LineFragmentHeader *Header,
-                                             const LineInfoArray &Lines) {
-  return visitUnknown(ModuleDebugFragmentKind::Lines, Data);
-}
-Error ModuleDebugFragmentVisitor::visitStringTable(BinaryStreamRef Data) {
-  return visitUnknown(ModuleDebugFragmentKind::StringTable, Data);
-}
-Error ModuleDebugFragmentVisitor::visitFileChecksums(
-    BinaryStreamRef Data, const FileChecksumArray &Checksums) {
-  return visitUnknown(ModuleDebugFragmentKind::FileChecksums, Data);
-}
-Error ModuleDebugFragmentVisitor::visitFrameData(BinaryStreamRef Data) {
-  return visitUnknown(ModuleDebugFragmentKind::FrameData, Data);
-}
-Error ModuleDebugFragmentVisitor::visitInlineeLines(BinaryStreamRef Data) {
-  return visitUnknown(ModuleDebugFragmentKind::InlineeLines, Data);
-}
-Error ModuleDebugFragmentVisitor::visitCrossScopeImports(BinaryStreamRef Data) {
-  return visitUnknown(ModuleDebugFragmentKind::CrossScopeExports, Data);
-}
-Error ModuleDebugFragmentVisitor::visitCrossScopeExports(BinaryStreamRef Data) {
-  return visitUnknown(ModuleDebugFragmentKind::CrossScopeImports, Data);
-}
-Error ModuleDebugFragmentVisitor::visitILLines(BinaryStreamRef Data) {
-  return visitUnknown(ModuleDebugFragmentKind::ILLines, Data);
-}
-Error ModuleDebugFragmentVisitor::visitFuncMDTokenMap(BinaryStreamRef Data) {
-  return visitUnknown(ModuleDebugFragmentKind::FuncMDTokenMap, Data);
-}
-Error ModuleDebugFragmentVisitor::visitTypeMDTokenMap(BinaryStreamRef Data) {
-  return visitUnknown(ModuleDebugFragmentKind::TypeMDTokenMap, Data);
-}
-Error ModuleDebugFragmentVisitor::visitMergedAssemblyInput(
-    BinaryStreamRef Data) {
-  return visitUnknown(ModuleDebugFragmentKind::MergedAssemblyInput, Data);
-}
-Error ModuleDebugFragmentVisitor::visitCoffSymbolRVA(BinaryStreamRef Data) {
-  return visitUnknown(ModuleDebugFragmentKind::CoffSymbolRVA, Data);
-}
-
-Error llvm::codeview::visitModuleDebugFragment(const ModuleDebugFragment &R,
-                                               ModuleDebugFragmentVisitor &V) {
+Error llvm::codeview::visitModuleDebugFragment(
+    const ModuleDebugFragmentRecord &R, ModuleDebugFragmentVisitor &V) {
+  BinaryStreamReader Reader(R.getRecordData());
   switch (R.kind()) {
-  case ModuleDebugFragmentKind::Symbols:
-    return V.visitSymbols(R.getRecordData());
   case ModuleDebugFragmentKind::Lines: {
-    BinaryStreamReader Reader(R.getRecordData());
-    const LineFragmentHeader *Header;
-    if (auto EC = Reader.readObject(Header))
+    ModuleDebugLineFragment Fragment;
+    if (auto EC = Fragment.initialize(Reader))
       return EC;
-    LineInfoArray LineInfos;
-    if (auto EC = Reader.readArray(LineInfos, Reader.bytesRemaining(), Header))
-      return EC;
-    return V.visitLines(R.getRecordData(), Header, LineInfos);
+
+    return V.visitLines(Fragment);
   }
-  case ModuleDebugFragmentKind::StringTable:
-    return V.visitStringTable(R.getRecordData());
   case ModuleDebugFragmentKind::FileChecksums: {
-    BinaryStreamReader Reader(R.getRecordData());
-    FileChecksumArray Checksums;
-    if (auto EC = Reader.readArray(Checksums, Reader.bytesRemaining()))
+    ModuleDebugFileChecksumFragment Fragment;
+    if (auto EC = Fragment.initialize(Reader))
       return EC;
-    return V.visitFileChecksums(R.getRecordData(), Checksums);
+
+    return V.visitFileChecksums(Fragment);
   }
-  case ModuleDebugFragmentKind::FrameData:
-    return V.visitFrameData(R.getRecordData());
-  case ModuleDebugFragmentKind::InlineeLines:
-    return V.visitInlineeLines(R.getRecordData());
-  case ModuleDebugFragmentKind::CrossScopeImports:
-    return V.visitCrossScopeImports(R.getRecordData());
-  case ModuleDebugFragmentKind::CrossScopeExports:
-    return V.visitCrossScopeExports(R.getRecordData());
-  case ModuleDebugFragmentKind::ILLines:
-    return V.visitILLines(R.getRecordData());
-  case ModuleDebugFragmentKind::FuncMDTokenMap:
-    return V.visitFuncMDTokenMap(R.getRecordData());
-  case ModuleDebugFragmentKind::TypeMDTokenMap:
-    return V.visitTypeMDTokenMap(R.getRecordData());
-  case ModuleDebugFragmentKind::MergedAssemblyInput:
-    return V.visitMergedAssemblyInput(R.getRecordData());
-  case ModuleDebugFragmentKind::CoffSymbolRVA:
-    return V.visitCoffSymbolRVA(R.getRecordData());
-  default:
-    return V.visitUnknown(R.kind(), R.getRecordData());
+  default: {
+    ModuleDebugUnknownFragment Fragment(R.kind(), R.getRecordData());
+    return V.visitUnknown(Fragment);
+  }
   }
 }
diff --git a/llvm/lib/DebugInfo/CodeView/ModuleDebugLineFragment.cpp b/llvm/lib/DebugInfo/CodeView/ModuleDebugLineFragment.cpp
new file mode 100644
index 0000000..1b84089
--- /dev/null
+++ b/llvm/lib/DebugInfo/CodeView/ModuleDebugLineFragment.cpp
@@ -0,0 +1,63 @@
+//===- ModuleDebugLineFragment.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/ModuleDebugLineFragment.h"
+
+#include "llvm/DebugInfo/CodeView/CodeViewError.h"
+#include "llvm/DebugInfo/CodeView/ModuleDebugFragmentRecord.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+Error LineColumnExtractor::extract(BinaryStreamRef Stream, uint32_t &Len,
+                                   LineColumnEntry &Item,
+                                   const LineFragmentHeader *Header) {
+  using namespace codeview;
+  const LineBlockFragmentHeader *BlockHeader;
+  BinaryStreamReader Reader(Stream);
+  if (auto EC = Reader.readObject(BlockHeader))
+    return EC;
+  bool HasColumn = Header->Flags & uint32_t(LineFlags::HaveColumns);
+  uint32_t LineInfoSize =
+      BlockHeader->NumLines *
+      (sizeof(LineNumberEntry) + (HasColumn ? sizeof(ColumnNumberEntry) : 0));
+  if (BlockHeader->BlockSize < sizeof(LineBlockFragmentHeader))
+    return make_error<CodeViewError>(cv_error_code::corrupt_record,
+                                     "Invalid line block record size");
+  uint32_t Size = BlockHeader->BlockSize - sizeof(LineBlockFragmentHeader);
+  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
+  // LineBlockFragmentHeader.
+  Len = BlockHeader->BlockSize;
+  Item.NameIndex = BlockHeader->NameIndex;
+  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();
+}
+
+ModuleDebugLineFragment::ModuleDebugLineFragment()
+    : ModuleDebugFragment(ModuleDebugFragmentKind::Lines) {}
+
+Error ModuleDebugLineFragment::initialize(BinaryStreamReader Reader) {
+  if (auto EC = Reader.readObject(Header))
+    return EC;
+
+  if (auto EC =
+          Reader.readArray(LinesAndColumns, Reader.bytesRemaining(), Header))
+    return EC;
+
+  return Error::success();
+}
diff --git a/llvm/lib/DebugInfo/CodeView/ModuleDebugUnknownFragment.cpp b/llvm/lib/DebugInfo/CodeView/ModuleDebugUnknownFragment.cpp
new file mode 100644
index 0000000..9fd2cb8
--- /dev/null
+++ b/llvm/lib/DebugInfo/CodeView/ModuleDebugUnknownFragment.cpp
@@ -0,0 +1,10 @@
+//===- ModuleDebugUnknownFragment.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/ModuleDebugUnknownFragment.h"
\ No newline at end of file