]> granicus.if.org Git - llvm/commitdiff
[PDB] Fix an issue writing the publics stream.
authorZachary Turner <zturner@google.com>
Wed, 9 Aug 2017 04:23:59 +0000 (04:23 +0000)
committerZachary Turner <zturner@google.com>
Wed, 9 Aug 2017 04:23:59 +0000 (04:23 +0000)
In the refactor to merge the publics and globals stream, a bug
was introduced that wrote the wrong value for one of the fields
of the PublicsStreamHeader.  This caused debugging in WinDbg
to break.

We had no way of dumping any of these fields, so in addition to
fixing the bug I've added dumping support for them along with a
test that verifies the correct value is written.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@310439 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/DebugInfo/PDB/Native/GlobalsStream.h
include/llvm/DebugInfo/PDB/Native/PublicsStream.h
lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp
lib/DebugInfo/PDB/Native/PublicsStream.cpp
tools/llvm-pdbutil/DumpOutputStyle.cpp

index 615ca74bd44d096e78abfef43b19cba3679ee211..6351b35379227bef738938f1164e676f0d00dfc9 100644 (file)
@@ -57,6 +57,11 @@ public:
 
   Error read(BinaryStreamReader &Reader);
 
+  uint32_t getVerSignature() const { return HashHdr->VerSignature; }
+  uint32_t getVerHeader() const { return HashHdr->VerHdr; }
+  uint32_t getHashRecordSize() const { return HashHdr->HrSize; }
+  uint32_t getNumBuckets() const { return HashHdr->NumBuckets; }
+
   typedef GSIHashHeader iterator;
   GSIHashIterator begin() const { return GSIHashIterator(HashRecords.begin()); }
   GSIHashIterator end() const { return GSIHashIterator(HashRecords.end()); }
index f28628d2a6e7c8a754337d71c360b2b1e7c79fb6..2d0222a9071a0d871d5a07e4d1651ecd261b8198 100644 (file)
@@ -32,7 +32,8 @@ public:
   Error reload();
 
   uint32_t getSymHash() const;
-  uint32_t getAddrMap() const;
+  uint16_t getThunkTableSection() const;
+  uint32_t getThunkTableOffset() const;
   const GSIHashTable &getPublicsTable() const { return PublicsTable; }
   FixedStreamArray<support::ulittle32_t> getAddressMap() const {
     return AddressMap;
index eb7a0bbcc3d516cf8e8c9cab5d5c6440f764c50d..46951a0b88e9541840bf698361ece825e3f68dcf 100644 (file)
@@ -153,7 +153,6 @@ Error GSIStreamBuilder::finalizeMsfLayout() {
   if (!Idx)
     return Idx.takeError();
   PSH->StreamIndex = *Idx;
-
   Idx = Msf.addStream(calculateGlobalsHashStreamSize());
   if (!Idx)
     return Idx.takeError();
@@ -253,32 +252,22 @@ Error GSIStreamBuilder::commitSymbolRecordStream(
 
 Error GSIStreamBuilder::commitPublicsHashStream(
     WritableBinaryStreamRef Stream) {
-  // Skip the publics stream header so that we can write the GSH header first.
-  // Then seek back to the beginning and update the publics stream header with
-  // the byte offset after the GSH header.
   BinaryStreamWriter Writer(Stream);
-  Writer.setOffset(sizeof(PublicsStreamHeader));
-
-  if (auto EC = PSH->commit(Writer))
-    return EC;
-  uint32_t OffsetAfterGSIHashes = Writer.getOffset();
-
-  Writer.setOffset(0);
-
-  // FIXME: Fill these in. They are for incremental linking.
   PublicsStreamHeader Header;
-  Header.AddrMap = PSH->Records.size() * 4;
 
+  // FIXME: Fill these in. They are for incremental linking.
   Header.NumThunks = 0;
   Header.SizeOfThunk = 0;
   Header.ISectThunkTable = 0;
   Header.OffThunkTable = 0;
   Header.NumSections = 0;
-  Header.SymHash = OffsetAfterGSIHashes;
+  Header.SymHash = PSH->calculateSerializedLength();
+  Header.AddrMap = PSH->Records.size() * 4;
   if (auto EC = Writer.writeObject(Header))
     return EC;
 
-  Writer.setOffset(OffsetAfterGSIHashes);
+  if (auto EC = PSH->commit(Writer))
+    return EC;
 
   std::vector<ulittle32_t> AddrMap = computeAddrMap(PSH->Records);
   if (auto EC = Writer.writeArray(makeArrayRef(AddrMap)))
index c716720b5a7f95c8ed2c3cf00551dffa973e33b5..a3a44ceddca9fba29ab4cfd7fe1729cd6b32a362 100644 (file)
@@ -46,7 +46,12 @@ PublicsStream::PublicsStream(std::unique_ptr<MappedBlockStream> Stream)
 PublicsStream::~PublicsStream() = default;
 
 uint32_t PublicsStream::getSymHash() const { return Header->SymHash; }
-uint32_t PublicsStream::getAddrMap() const { return Header->AddrMap; }
+uint16_t PublicsStream::getThunkTableSection() const {
+  return Header->ISectThunkTable;
+}
+uint32_t PublicsStream::getThunkTableOffset() const {
+  return Header->OffThunkTable;
+}
 
 // Publics stream contains fixed-size headers and a serialized hash table.
 // This implementation is not complete yet. It reads till the end of the
index 73e4a14a8546d10348e0640c21f84d7f41b80bf2..bc0bb0830d951a4540c04116277538eee8489b61 100644 (file)
@@ -896,6 +896,13 @@ Error DumpOutputStyle::dumpPublics() {
   auto &Publics = Err(File.getPDBPublicsStream());
 
   const GSIHashTable &PublicsTable = Publics.getPublicsTable();
+  if (opts::dump::DumpPublicExtras) {
+    P.printLine("Publics Header");
+    AutoIndent Indent(P);
+    P.formatLine("sym hash = {0}, thunk table addr = {1}", Publics.getSymHash(),
+                 formatSegmentOffset(Publics.getThunkTableSection(),
+                                     Publics.getThunkTableOffset()));
+  }
   Err(dumpSymbolsFromGSI(PublicsTable, opts::dump::DumpPublicExtras));
 
   // Skip the rest if we aren't dumping extras.
@@ -941,30 +948,42 @@ Error DumpOutputStyle::dumpSymbolsFromGSI(const GSIHashTable &Table,
   auto ExpectedIds = initializeTypes(StreamIPI);
   if (!ExpectedIds)
     return ExpectedIds.takeError();
-  SymbolVisitorCallbackPipeline Pipeline;
-  SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb);
-  MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, *ExpectedIds,
-                             *ExpectedTypes);
-
-  Pipeline.addCallbackToPipeline(Deserializer);
-  Pipeline.addCallbackToPipeline(Dumper);
-  CVSymbolVisitor Visitor(Pipeline);
-
-  BinaryStreamRef SymStream =
-      ExpectedSyms->getSymbolArray().getUnderlyingStream();
-  for (uint32_t PubSymOff : Table) {
-    Expected<CVSymbol> Sym = readSymbolFromStream(SymStream, PubSymOff);
-    if (!Sym)
-      return Sym.takeError();
-    if (auto E = Visitor.visitSymbolRecord(*Sym, PubSymOff))
-      return E;
+
+  if (HashExtras) {
+    P.printLine("GSI Header");
+    AutoIndent Indent(P);
+    P.formatLine("sig = {0:X}, hdr = {1:X}, hr size = {2}, num buckets = {3}",
+                 Table.getVerSignature(), Table.getVerHeader(),
+                 Table.getHashRecordSize(), Table.getNumBuckets());
+  }
+
+  {
+    P.printLine("Records");
+    SymbolVisitorCallbackPipeline Pipeline;
+    SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb);
+    MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, *ExpectedIds,
+                               *ExpectedTypes);
+
+    Pipeline.addCallbackToPipeline(Deserializer);
+    Pipeline.addCallbackToPipeline(Dumper);
+    CVSymbolVisitor Visitor(Pipeline);
+
+    BinaryStreamRef SymStream =
+        ExpectedSyms->getSymbolArray().getUnderlyingStream();
+    for (uint32_t PubSymOff : Table) {
+      Expected<CVSymbol> Sym = readSymbolFromStream(SymStream, PubSymOff);
+      if (!Sym)
+        return Sym.takeError();
+      if (auto E = Visitor.visitSymbolRecord(*Sym, PubSymOff))
+        return E;
+    }
   }
 
   // Return early if we aren't dumping public hash table and address map info.
   if (!HashExtras)
     return Error::success();
 
-  P.formatLine("Hash Records");
+  P.formatLine("Hash Entries");
   {
     AutoIndent Indent2(P);
     for (const PSHashRecord &HR : Table.HashRecords)