[lld/pdb] Add an empty globals stream.

We don't write any actual symbols to this stream yet, but for
now we just create the stream and hook it up to the appropriate
places and give it a valid header.

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

llvm-svn: 309608
diff --git a/llvm/lib/DebugInfo/PDB/CMakeLists.txt b/llvm/lib/DebugInfo/PDB/CMakeLists.txt
index 5840ab1..2658584 100644
--- a/llvm/lib/DebugInfo/PDB/CMakeLists.txt
+++ b/llvm/lib/DebugInfo/PDB/CMakeLists.txt
@@ -35,6 +35,7 @@
   Native/DbiStreamBuilder.cpp
   Native/EnumTables.cpp
   Native/GlobalsStream.cpp
+  Native/GlobalsStreamBuilder.cpp
   Native/Hash.cpp
   Native/HashTable.cpp
   Native/InfoStream.cpp
diff --git a/llvm/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp b/llvm/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp
index 25076e4..0fe583b 100644
--- a/llvm/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp
@@ -49,6 +49,10 @@
   SectionMap = SecMap;
 }
 
+void DbiStreamBuilder::setGlobalsStreamIndex(uint32_t Index) {
+  GlobalsStreamIndex = Index;
+}
+
 void DbiStreamBuilder::setSymbolRecordStreamIndex(uint32_t Index) {
   SymRecordStreamIndex = Index;
 }
@@ -270,7 +274,7 @@
   H->SymRecordStreamIndex = SymRecordStreamIndex;
   H->PublicSymbolStreamIndex = PublicsStreamIndex;
   H->MFCTypeServerIndex = kInvalidStreamIndex;
-  H->GlobalSymbolStreamIndex = kInvalidStreamIndex;
+  H->GlobalSymbolStreamIndex = GlobalsStreamIndex;
 
   Header = H;
   return Error::success();
diff --git a/llvm/lib/DebugInfo/PDB/Native/GlobalsStreamBuilder.cpp b/llvm/lib/DebugInfo/PDB/Native/GlobalsStreamBuilder.cpp
new file mode 100644
index 0000000..004691e
--- /dev/null
+++ b/llvm/lib/DebugInfo/PDB/Native/GlobalsStreamBuilder.cpp
@@ -0,0 +1,79 @@
+//===- GlobalsStreamBuilder.cpp - PDB Globals Stream Creation ---*- 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/Native/GlobalsStreamBuilder.h"
+
+#include "llvm/DebugInfo/MSF/MSFBuilder.h"
+#include "llvm/DebugInfo/MSF/MSFCommon.h"
+#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
+#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
+
+using namespace llvm;
+using namespace llvm::msf;
+using namespace llvm::pdb;
+
+GlobalsStreamBuilder::GlobalsStreamBuilder(msf::MSFBuilder &Msf) : Msf(Msf) {}
+
+GlobalsStreamBuilder::~GlobalsStreamBuilder() {}
+
+uint32_t GlobalsStreamBuilder::calculateSerializedLength() const {
+  uint32_t Size = 0;
+  // First is the header
+  Size += sizeof(GSIHashHeader);
+
+  // Next is the records.  For now we don't write any records, just an empty
+  // stream.
+  // FIXME: Write records and account for their size here.
+  Size += 0;
+
+  // Next is a bitmap indicating which hash buckets are valid.  The bitmap
+  // is alway present, but we only write buckets for bitmap entries which are
+  // non-zero, which now is noting.
+  size_t BitmapSizeInBits = alignTo(IPHR_HASH + 1, 32);
+  uint32_t NumBitmapEntries = BitmapSizeInBits / 8;
+  Size += NumBitmapEntries;
+
+  // FIXME: Account for hash buckets.  For now since we we write a zero-bitmap
+  // indicating that no hash buckets are valid, we also write zero byets of hash
+  // bucket data.
+  Size += 0;
+  return Size;
+}
+
+Error GlobalsStreamBuilder::finalizeMsfLayout() {
+  Expected<uint32_t> Idx = Msf.addStream(calculateSerializedLength());
+  if (!Idx)
+    return Idx.takeError();
+  StreamIdx = *Idx;
+  return Error::success();
+}
+
+Error GlobalsStreamBuilder::commit(BinaryStreamWriter &PublicsWriter) {
+  GSIHashHeader GSH;
+
+  GSH.VerSignature = GSIHashHeader::HdrSignature;
+  GSH.VerHdr = GSIHashHeader::HdrVersion;
+  GSH.HrSize = 0;
+  GSH.NumBuckets = 0;
+
+  if (auto EC = PublicsWriter.writeObject(GSH))
+    return EC;
+
+  // FIXME: Once we start writing a value other than 0 for GSH.HrSize, we need
+  // to write the hash records here.
+  size_t BitmapSizeInBits = alignTo(IPHR_HASH + 1, 32);
+  uint32_t NumBitmapEntries = BitmapSizeInBits / 8;
+  std::vector<uint8_t> BitmapData(NumBitmapEntries);
+  // FIXME: Build an actual bitmap
+  if (auto EC = PublicsWriter.writeBytes(makeArrayRef(BitmapData)))
+    return EC;
+
+  // FIXME: Write actual hash buckets.
+  return Error::success();
+}
diff --git a/llvm/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp b/llvm/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp
index 21e5e4b..a8b80ac 100644
--- a/llvm/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp
@@ -15,6 +15,7 @@
 #include "llvm/DebugInfo/PDB/GenericError.h"
 #include "llvm/DebugInfo/PDB/Native/DbiStream.h"
 #include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h"
+#include "llvm/DebugInfo/PDB/Native/GlobalsStreamBuilder.h"
 #include "llvm/DebugInfo/PDB/Native/InfoStream.h"
 #include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h"
 #include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h"
@@ -80,6 +81,12 @@
   return *Publics;
 }
 
+GlobalsStreamBuilder &PDBFileBuilder::getGlobalsBuilder() {
+  if (!Globals)
+    Globals = llvm::make_unique<GlobalsStreamBuilder>(*Msf);
+  return *Globals;
+}
+
 Error PDBFileBuilder::addNamedStream(StringRef Name, uint32_t Size) {
   auto ExpectedStream = Msf->addStream(Size);
   if (!ExpectedStream)
@@ -131,6 +138,13 @@
     }
   }
 
+  if (Globals) {
+    if (auto EC = Globals->finalizeMsfLayout())
+      return std::move(EC);
+    if (Dbi)
+      Dbi->setGlobalsStreamIndex(Globals->getStreamIndex());
+  }
+
   return Msf->build();
 }
 
@@ -220,5 +234,13 @@
       return EC;
   }
 
+  if (Globals) {
+    auto GS = WritableMappedBlockStream::createIndexedStream(
+        Layout, Buffer, Globals->getStreamIndex(), Allocator);
+    BinaryStreamWriter GSWriter(*GS);
+    if (auto EC = Globals->commit(GSWriter))
+      return EC;
+  }
+
   return Buffer.commit();
 }