[CodeView] Write CodeView line information.

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

llvm-svn: 301882
diff --git a/llvm/lib/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.cpp b/llvm/lib/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.cpp
index 4bbfe28..79e5b9d 100644
--- a/llvm/lib/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.cpp
+++ b/llvm/lib/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.cpp
@@ -48,3 +48,50 @@
 
   return Error::success();
 }
+
+ModuleDebugFileChecksumFragment::ModuleDebugFileChecksumFragment()
+    : ModuleDebugFragment(ModuleDebugFragmentKind::FileChecksums) {}
+
+void ModuleDebugFileChecksumFragment::addChecksum(uint32_t StringTableOffset,
+                                                  FileChecksumKind Kind,
+                                                  ArrayRef<uint8_t> Bytes) {
+  FileChecksumEntry Entry;
+  if (!Bytes.empty()) {
+    uint8_t *Copy = Storage.Allocate<uint8_t>(Bytes.size());
+    ::memcpy(Copy, Bytes.data(), Bytes.size());
+    Entry.Checksum = makeArrayRef(Copy, Bytes.size());
+  }
+  Entry.FileNameOffset = StringTableOffset;
+  Entry.Kind = Kind;
+  Checksums.push_back(Entry);
+
+  // This maps the offset of this string in the string table to the offset
+  // of this checksum entry in the checksum buffer.
+  OffsetMap[StringTableOffset] = SerializedSize;
+  SerializedSize += sizeof(FileChecksumEntryHeader) + Bytes.size();
+}
+
+uint32_t ModuleDebugFileChecksumFragment::calculateSerializedLength() {
+  return SerializedSize;
+}
+
+Error ModuleDebugFileChecksumFragment::commit(BinaryStreamWriter &Writer) {
+  for (const auto &FC : Checksums) {
+    FileChecksumEntryHeader Header;
+    Header.ChecksumKind = uint8_t(FC.Kind);
+    Header.ChecksumSize = FC.Checksum.size();
+    Header.FileNameOffset = FC.FileNameOffset;
+    if (auto EC = Writer.writeObject(Header))
+      return EC;
+    if (auto EC = Writer.writeArray(makeArrayRef(FC.Checksum)))
+      return EC;
+  }
+  return Error::success();
+}
+
+uint32_t ModuleDebugFileChecksumFragment::mapChecksumOffset(
+    uint32_t StringTableOffset) const {
+  auto Iter = OffsetMap.find(StringTableOffset);
+  assert(Iter != OffsetMap.end());
+  return Iter->second;
+}
diff --git a/llvm/lib/DebugInfo/CodeView/ModuleDebugFragment.cpp b/llvm/lib/DebugInfo/CodeView/ModuleDebugFragment.cpp
index 36f86cb..2af1917 100644
--- a/llvm/lib/DebugInfo/CodeView/ModuleDebugFragment.cpp
+++ b/llvm/lib/DebugInfo/CodeView/ModuleDebugFragment.cpp
@@ -12,3 +12,5 @@
 using namespace llvm::codeview;
 
 ModuleDebugFragmentRef::~ModuleDebugFragmentRef() {}
+
+ModuleDebugFragment::~ModuleDebugFragment() {}
diff --git a/llvm/lib/DebugInfo/CodeView/ModuleDebugFragmentRecord.cpp b/llvm/lib/DebugInfo/CodeView/ModuleDebugFragmentRecord.cpp
index 20c06e9..263b632 100644
--- a/llvm/lib/DebugInfo/CodeView/ModuleDebugFragmentRecord.cpp
+++ b/llvm/lib/DebugInfo/CodeView/ModuleDebugFragmentRecord.cpp
@@ -8,6 +8,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/DebugInfo/CodeView/ModuleDebugFragmentRecord.h"
+#include "llvm/DebugInfo/CodeView/ModuleDebugFragment.h"
 
 #include "llvm/Support/BinaryStreamReader.h"
 
@@ -30,6 +31,13 @@
 
   ModuleDebugFragmentKind Kind =
       static_cast<ModuleDebugFragmentKind>(uint32_t(Header->Kind));
+  switch (Kind) {
+  case ModuleDebugFragmentKind::FileChecksums:
+  case ModuleDebugFragmentKind::Lines:
+    break;
+  default:
+    llvm_unreachable("Unexpected debug fragment kind!");
+  }
   if (auto EC = Reader.readStreamRef(Info.Data, Header->Length))
     return EC;
   Info.Kind = Kind;
@@ -37,7 +45,9 @@
 }
 
 uint32_t ModuleDebugFragmentRecord::getRecordLength() const {
-  return sizeof(ModuleDebugFragmentHeader) + Data.getLength();
+  uint32_t Result = sizeof(ModuleDebugFragmentHeader) + Data.getLength();
+  assert(Result % 4 == 0);
+  return Result;
 }
 
 ModuleDebugFragmentKind ModuleDebugFragmentRecord::kind() const { return Kind; }
@@ -45,3 +55,29 @@
 BinaryStreamRef ModuleDebugFragmentRecord::getRecordData() const {
   return Data;
 }
+
+ModuleDebugFragmentRecordBuilder::ModuleDebugFragmentRecordBuilder(
+    ModuleDebugFragmentKind Kind, ModuleDebugFragment &Frag)
+    : Kind(Kind), Frag(Frag) {}
+
+uint32_t ModuleDebugFragmentRecordBuilder::calculateSerializedLength() {
+  uint32_t Size = sizeof(ModuleDebugFragmentHeader) +
+                  alignTo(Frag.calculateSerializedLength(), 4);
+  return Size;
+}
+
+Error ModuleDebugFragmentRecordBuilder::commit(BinaryStreamWriter &Writer) {
+  ModuleDebugFragmentHeader Header;
+  Header.Kind = uint32_t(Kind);
+  Header.Length =
+      calculateSerializedLength() - sizeof(ModuleDebugFragmentHeader);
+
+  if (auto EC = Writer.writeObject(Header))
+    return EC;
+  if (auto EC = Frag.commit(Writer))
+    return EC;
+  if (auto EC = Writer.padToAlignment(4))
+    return EC;
+
+  return Error::success();
+}
diff --git a/llvm/lib/DebugInfo/CodeView/ModuleDebugLineFragment.cpp b/llvm/lib/DebugInfo/CodeView/ModuleDebugLineFragment.cpp
index 6a9751c..103010c 100644
--- a/llvm/lib/DebugInfo/CodeView/ModuleDebugLineFragment.cpp
+++ b/llvm/lib/DebugInfo/CodeView/ModuleDebugLineFragment.cpp
@@ -64,3 +64,92 @@
 bool ModuleDebugLineFragmentRef::hasColumnInfo() const {
   return !!(Header->Flags & LF_HaveColumns);
 }
+
+ModuleDebugLineFragment::ModuleDebugLineFragment()
+    : ModuleDebugFragment(ModuleDebugFragmentKind::Lines) {}
+
+void ModuleDebugLineFragment::createBlock(uint32_t ChecksumBufferOffset) {
+  Blocks.emplace_back(ChecksumBufferOffset);
+}
+
+void ModuleDebugLineFragment::addLineInfo(uint32_t Offset,
+                                          const LineInfo &Line) {
+  Block &B = Blocks.back();
+  LineNumberEntry LNE;
+  LNE.Flags = Line.getRawData();
+  LNE.Offset = Offset;
+  B.Lines.push_back(LNE);
+}
+
+void ModuleDebugLineFragment::addLineAndColumnInfo(uint32_t Offset,
+                                                   const LineInfo &Line,
+                                                   uint32_t ColStart,
+                                                   uint32_t ColEnd) {
+  Block &B = Blocks.back();
+  assert(B.Lines.size() == B.Columns.size());
+
+  addLineInfo(Offset, Line);
+  ColumnNumberEntry CNE;
+  CNE.StartColumn = ColStart;
+  CNE.EndColumn = ColEnd;
+  B.Columns.push_back(CNE);
+}
+
+Error ModuleDebugLineFragment::commit(BinaryStreamWriter &Writer) {
+  LineFragmentHeader Header;
+  Header.CodeSize = CodeSize;
+  Header.Flags = hasColumnInfo() ? LF_HaveColumns : 0;
+  Header.RelocOffset = RelocOffset;
+  Header.RelocSegment = RelocSegment;
+
+  if (auto EC = Writer.writeObject(Header))
+    return EC;
+
+  for (const auto &B : Blocks) {
+    LineBlockFragmentHeader BlockHeader;
+    assert(B.Lines.size() == B.Columns.size() || B.Columns.empty());
+
+    BlockHeader.NumLines = B.Lines.size();
+    BlockHeader.BlockSize = sizeof(LineBlockFragmentHeader);
+    BlockHeader.BlockSize += BlockHeader.NumLines * sizeof(LineNumberEntry);
+    if (hasColumnInfo())
+      BlockHeader.BlockSize += BlockHeader.NumLines * sizeof(ColumnNumberEntry);
+    BlockHeader.NameIndex = B.ChecksumBufferOffset;
+    if (auto EC = Writer.writeObject(BlockHeader))
+      return EC;
+
+    if (auto EC = Writer.writeArray(makeArrayRef(B.Lines)))
+      return EC;
+
+    if (hasColumnInfo()) {
+      if (auto EC = Writer.writeArray(makeArrayRef(B.Columns)))
+        return EC;
+    }
+  }
+  return Error::success();
+}
+
+uint32_t ModuleDebugLineFragment::calculateSerializedLength() {
+  uint32_t Size = sizeof(LineFragmentHeader);
+  for (const auto &B : Blocks) {
+    Size += sizeof(LineBlockFragmentHeader);
+    Size += B.Lines.size() * sizeof(LineNumberEntry);
+    if (hasColumnInfo())
+      Size += B.Columns.size() * sizeof(ColumnNumberEntry);
+  }
+  return Size;
+}
+
+void ModuleDebugLineFragment::setRelocationAddress(uint16_t Segment,
+                                                   uint16_t Offset) {
+  RelocOffset = Offset;
+  RelocSegment = Segment;
+}
+
+void ModuleDebugLineFragment::setCodeSize(uint32_t Size) { CodeSize = Size; }
+
+void ModuleDebugLineFragment::setFlags(LineFlags Flags) { this->Flags = Flags; }
+
+bool ModuleDebugLineFragment::hasColumnInfo() const {
+  return Flags & LF_HaveColumns;
+}
diff --git a/llvm/lib/DebugInfo/CodeView/TypeDatabase.cpp b/llvm/lib/DebugInfo/CodeView/TypeDatabase.cpp
index f9ded6c..efaba46 100644
--- a/llvm/lib/DebugInfo/CodeView/TypeDatabase.cpp
+++ b/llvm/lib/DebugInfo/CodeView/TypeDatabase.cpp
@@ -110,6 +110,10 @@
   return TypeRecords[Index.getIndex() - TypeIndex::FirstNonSimpleIndex];
 }
 
+CVType &TypeDatabase::getTypeRecord(TypeIndex Index) {
+  return TypeRecords[Index.getIndex() - TypeIndex::FirstNonSimpleIndex];
+}
+
 bool TypeDatabase::containsTypeIndex(TypeIndex Index) const {
   uint32_t I = Index.getIndex() - TypeIndex::FirstNonSimpleIndex;
   return I < CVUDTNames.size();
diff --git a/llvm/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp b/llvm/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp
index 8920dd9..41cb23a 100644
--- a/llvm/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp
@@ -10,6 +10,7 @@
 #include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h"
 
 #include "llvm/ADT/ArrayRef.h"
+#include "llvm/DebugInfo/CodeView/ModuleDebugFragmentRecord.h"
 #include "llvm/DebugInfo/MSF/MSFBuilder.h"
 #include "llvm/DebugInfo/MSF/MSFCommon.h"
 #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
@@ -35,11 +36,12 @@
 };
 }
 
-static uint32_t calculateDiSymbolStreamSize(uint32_t SymbolByteSize) {
+static uint32_t calculateDiSymbolStreamSize(uint32_t SymbolByteSize,
+                                            uint32_t C13Size) {
   uint32_t Size = sizeof(uint32_t); // Signature
   Size += SymbolByteSize;           // Symbol Data
-  Size += 0;                        // TODO: Layout.LineBytes
-  Size += 0;                        // TODO: Layout.C13Bytes
+  Size += 0;                        // TODO: Layout.C11Bytes
+  Size += C13Size;                  // C13 Debug Info Size
   Size += sizeof(uint32_t);         // GlobalRefs substream size (always 0)
   Size += 0;                        // GlobalRefs substream bytes
   return Size;
@@ -52,6 +54,8 @@
   Layout.Mod = ModIndex;
 }
 
+DbiModuleDescriptorBuilder::~DbiModuleDescriptorBuilder() {}
+
 uint16_t DbiModuleDescriptorBuilder::getStreamIndex() const {
   return Layout.ModDiStream;
 }
@@ -69,6 +73,15 @@
   SourceFiles.push_back(Path);
 }
 
+uint32_t DbiModuleDescriptorBuilder::calculateC13DebugInfoSize() const {
+  uint32_t Result = 0;
+  for (const auto &Builder : C13Builders) {
+    assert(Builder && "Empty C13 Fragment Builder!");
+    Result += Builder->calculateSerializedLength();
+  }
+  return Result;
+}
+
 uint32_t DbiModuleDescriptorBuilder::calculateSerializedLength() const {
   uint32_t L = sizeof(Layout);
   uint32_t M = ModuleName.size() + 1;
@@ -80,7 +93,7 @@
   Layout.FileNameOffs = 0; // TODO: Fix this
   Layout.Flags = 0;        // TODO: Fix this
   Layout.C11Bytes = 0;
-  Layout.C13Bytes = 0;
+  Layout.C13Bytes = calculateC13DebugInfoSize();
   (void)Layout.Mod;         // Set in constructor
   (void)Layout.ModDiStream; // Set in finalizeMsfLayout
   Layout.NumFiles = SourceFiles.size();
@@ -94,7 +107,9 @@
 
 Error DbiModuleDescriptorBuilder::finalizeMsfLayout() {
   this->Layout.ModDiStream = kInvalidStreamIndex;
-  auto ExpectedSN = MSF.addStream(calculateDiSymbolStreamSize(SymbolByteSize));
+  uint32_t C13Size = calculateC13DebugInfoSize();
+  auto ExpectedSN =
+      MSF.addStream(calculateDiSymbolStreamSize(SymbolByteSize, C13Size));
   if (!ExpectedSN)
     return ExpectedSN.takeError();
   Layout.ModDiStream = *ExpectedSN;
@@ -130,7 +145,13 @@
     if (auto EC = SymbolWriter.writeStreamRef(RecordsRef))
       return EC;
     // TODO: Write C11 Line data
-    // TODO: Write C13 Line data
+
+    for (const auto &Builder : C13Builders) {
+      assert(Builder && "Empty C13 Fragment Builder!");
+      if (auto EC = Builder->commit(SymbolWriter))
+        return EC;
+    }
+
     // TODO: Figure out what GlobalRefs substream actually is and populate it.
     if (auto EC = SymbolWriter.writeInteger<uint32_t>(0))
       return EC;
@@ -139,3 +160,29 @@
   }
   return Error::success();
 }
+
+void DbiModuleDescriptorBuilder::addC13LineFragment(
+    std::unique_ptr<ModuleDebugLineFragment> Lines) {
+  ModuleDebugLineFragment &Frag = *Lines;
+
+  // File Checksums have to come first, so push an empty entry on if this
+  // is the first.
+  if (C13Builders.empty())
+    C13Builders.push_back(nullptr);
+
+  this->LineInfo.push_back(std::move(Lines));
+  C13Builders.push_back(
+      llvm::make_unique<ModuleDebugFragmentRecordBuilder>(Frag.kind(), Frag));
+}
+
+void DbiModuleDescriptorBuilder::setC13FileChecksums(
+    std::unique_ptr<ModuleDebugFileChecksumFragment> Checksums) {
+  assert(!ChecksumInfo && "Can't have more than one checksum info!");
+
+  if (C13Builders.empty())
+    C13Builders.push_back(nullptr);
+
+  ChecksumInfo = std::move(Checksums);
+  C13Builders[0] = llvm::make_unique<ModuleDebugFragmentRecordBuilder>(
+      ChecksumInfo->kind(), *ChecksumInfo);
+}
diff --git a/llvm/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp b/llvm/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp
index 62bda65..c19a2f0 100644
--- a/llvm/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp
@@ -101,6 +101,14 @@
   return Error::success();
 }
 
+Expected<uint32_t> DbiStreamBuilder::getSourceFileNameIndex(StringRef File) {
+  auto NameIter = SourceFileNames.find(File);
+  if (NameIter == SourceFileNames.end())
+    return make_error<RawError>(raw_error_code::no_entry,
+                                "The specified source file was not found");
+  return NameIter->getValue();
+}
+
 uint32_t DbiStreamBuilder::calculateModiSubstreamSize() const {
   uint32_t Size = 0;
   for (const auto &M : ModiList)
diff --git a/llvm/lib/DebugInfo/PDB/Native/ModuleDebugStreamBuilder.cpp b/llvm/lib/DebugInfo/PDB/Native/ModuleDebugStreamBuilder.cpp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/llvm/lib/DebugInfo/PDB/Native/ModuleDebugStreamBuilder.cpp
diff --git a/llvm/lib/DebugInfo/PDB/Native/StringTableBuilder.cpp b/llvm/lib/DebugInfo/PDB/Native/StringTableBuilder.cpp
index e0f8370..40dc8e1 100644
--- a/llvm/lib/DebugInfo/PDB/Native/StringTableBuilder.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/StringTableBuilder.cpp
@@ -29,6 +29,12 @@
   return P.first->second;
 }
 
+uint32_t StringTableBuilder::getStringIndex(StringRef S) {
+  auto Iter = Strings.find(S);
+  assert(Iter != Strings.end());
+  return Iter->second;
+}
+
 static uint32_t computeBucketCount(uint32_t NumStrings) {
   // The /names stream is basically an on-disk open-addressing hash table.
   // Hash collisions are resolved by linear probing. We cannot make