summaryrefslogtreecommitdiff
path: root/lib/DebugInfo/PDB/Native
diff options
context:
space:
mode:
Diffstat (limited to 'lib/DebugInfo/PDB/Native')
-rw-r--r--lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp19
-rw-r--r--lib/DebugInfo/PDB/Native/DbiStream.cpp1
-rw-r--r--lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp40
-rw-r--r--lib/DebugInfo/PDB/Native/GSI.cpp93
-rw-r--r--lib/DebugInfo/PDB/Native/GSI.h68
-rw-r--r--lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp322
-rw-r--r--lib/DebugInfo/PDB/Native/GlobalsStream.cpp100
-rw-r--r--lib/DebugInfo/PDB/Native/InfoStream.cpp2
-rw-r--r--lib/DebugInfo/PDB/Native/NativeBuiltinSymbol.cpp1
-rw-r--r--lib/DebugInfo/PDB/Native/NativeEnumSymbol.cpp108
-rw-r--r--lib/DebugInfo/PDB/Native/NativeEnumTypes.cpp59
-rw-r--r--lib/DebugInfo/PDB/Native/NativeExeSymbol.cpp2
-rw-r--r--lib/DebugInfo/PDB/Native/NativeRawSymbol.cpp5
-rw-r--r--lib/DebugInfo/PDB/Native/NativeSession.cpp55
-rw-r--r--lib/DebugInfo/PDB/Native/PDBFile.cpp38
-rw-r--r--lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp59
-rw-r--r--lib/DebugInfo/PDB/Native/PDBStringTable.cpp1
-rw-r--r--lib/DebugInfo/PDB/Native/PDBStringTableBuilder.cpp2
-rw-r--r--lib/DebugInfo/PDB/Native/PublicsStream.cpp52
-rw-r--r--lib/DebugInfo/PDB/Native/PublicsStreamBuilder.cpp89
-rw-r--r--lib/DebugInfo/PDB/Native/SymbolStream.cpp9
-rw-r--r--lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp1
22 files changed, 731 insertions, 395 deletions
diff --git a/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp b/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp
index 897f78c51032..d765485bdb6d 100644
--- a/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp
+++ b/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp
@@ -16,6 +16,7 @@
#include "llvm/DebugInfo/MSF/MSFCommon.h"
#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h"
+#include "llvm/DebugInfo/PDB/Native/GSIStreamBuilder.h"
#include "llvm/DebugInfo/PDB/Native/RawConstants.h"
#include "llvm/DebugInfo/PDB/Native/RawError.h"
#include "llvm/Support/BinaryItemStream.h"
@@ -26,16 +27,6 @@ using namespace llvm::codeview;
using namespace llvm::msf;
using namespace llvm::pdb;
-namespace llvm {
-template <> struct BinaryItemTraits<CVSymbol> {
- static size_t length(const CVSymbol &Item) { return Item.RecordData.size(); }
-
- static ArrayRef<uint8_t> bytes(const CVSymbol &Item) {
- return Item.RecordData;
- }
-};
-}
-
static uint32_t calculateDiSymbolStreamSize(uint32_t SymbolByteSize,
uint32_t C13Size) {
uint32_t Size = sizeof(uint32_t); // Signature
@@ -98,14 +89,6 @@ uint32_t DbiModuleDescriptorBuilder::calculateSerializedLength() const {
return alignTo(L + M + O, sizeof(uint32_t));
}
-template <typename T> struct Foo {
- explicit Foo(T &&Answer) : Answer(Answer) {}
-
- T Answer;
-};
-
-template <typename T> Foo<T> makeFoo(T &&t) { return Foo<T>(std::move(t)); }
-
void DbiModuleDescriptorBuilder::finalize() {
Layout.SC.ModuleIndex = Layout.Mod;
Layout.FileNameOffs = 0; // TODO: Fix this
diff --git a/lib/DebugInfo/PDB/Native/DbiStream.cpp b/lib/DebugInfo/PDB/Native/DbiStream.cpp
index 0eeac7e4c084..04e6664c68db 100644
--- a/lib/DebugInfo/PDB/Native/DbiStream.cpp
+++ b/lib/DebugInfo/PDB/Native/DbiStream.cpp
@@ -12,7 +12,6 @@
#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h"
#include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h"
-#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
#include "llvm/DebugInfo/PDB/Native/RawConstants.h"
#include "llvm/DebugInfo/PDB/Native/RawError.h"
diff --git a/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp b/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp
index 25076e40fc98..c96553ff9b16 100644
--- a/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp
+++ b/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp
@@ -49,6 +49,10 @@ void DbiStreamBuilder::setSectionMap(ArrayRef<SecMapEntry> SecMap) {
SectionMap = SecMap;
}
+void DbiStreamBuilder::setGlobalsStreamIndex(uint32_t Index) {
+ GlobalsStreamIndex = Index;
+}
+
void DbiStreamBuilder::setSymbolRecordStreamIndex(uint32_t Index) {
SymRecordStreamIndex = Index;
}
@@ -86,24 +90,9 @@ uint32_t DbiStreamBuilder::calculateSerializedLength() const {
Expected<DbiModuleDescriptorBuilder &>
DbiStreamBuilder::addModuleInfo(StringRef ModuleName) {
uint32_t Index = ModiList.size();
- auto MIB =
- llvm::make_unique<DbiModuleDescriptorBuilder>(ModuleName, Index, Msf);
- auto M = MIB.get();
- auto Result = ModiMap.insert(std::make_pair(ModuleName, std::move(MIB)));
-
- if (!Result.second)
- return make_error<RawError>(raw_error_code::duplicate_entry,
- "The specified module already exists");
- ModiList.push_back(M);
- return *M;
-}
-
-Error DbiStreamBuilder::addModuleSourceFile(StringRef Module, StringRef File) {
- auto ModIter = ModiMap.find(Module);
- if (ModIter == ModiMap.end())
- return make_error<RawError>(raw_error_code::no_entry,
- "The specified module was not found");
- return addModuleSourceFile(*ModIter->second, File);
+ ModiList.push_back(
+ llvm::make_unique<DbiModuleDescriptorBuilder>(ModuleName, Index, Msf));
+ return *ModiList.back();
}
Error DbiStreamBuilder::addModuleSourceFile(DbiModuleDescriptorBuilder &Module,
@@ -270,7 +259,7 @@ Error DbiStreamBuilder::finalize() {
H->SymRecordStreamIndex = SymRecordStreamIndex;
H->PublicSymbolStreamIndex = PublicsStreamIndex;
H->MFCTypeServerIndex = kInvalidStreamIndex;
- H->GlobalSymbolStreamIndex = kInvalidStreamIndex;
+ H->GlobalSymbolStreamIndex = GlobalsStreamIndex;
Header = H;
return Error::success();
@@ -307,19 +296,6 @@ static uint16_t toSecMapFlags(uint32_t Flags) {
return Ret;
}
-void DbiStreamBuilder::addSectionContrib(DbiModuleDescriptorBuilder *ModuleDbi,
- const object::coff_section *SecHdr) {
- SectionContrib SC;
- memset(&SC, 0, sizeof(SC));
- SC.ISect = (uint16_t)~0U; // This represents nil.
- SC.Off = SecHdr->PointerToRawData;
- SC.Size = SecHdr->SizeOfRawData;
- SC.Characteristics = SecHdr->Characteristics;
- // Use the module index in the module dbi stream or nil (-1).
- SC.Imod = ModuleDbi ? ModuleDbi->getModuleIndex() : (uint16_t)~0U;
- SectionContribs.emplace_back(SC);
-}
-
// A utility function to create a Section Map for a given list of COFF sections.
//
// A Section Map seem to be a copy of a COFF section list in other format.
diff --git a/lib/DebugInfo/PDB/Native/GSI.cpp b/lib/DebugInfo/PDB/Native/GSI.cpp
deleted file mode 100644
index b219fe275f73..000000000000
--- a/lib/DebugInfo/PDB/Native/GSI.cpp
+++ /dev/null
@@ -1,93 +0,0 @@
-//===- GSI.cpp - Common Functions for GlobalsStream and PublicsStream ----===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "GSI.h"
-
-#include "llvm/DebugInfo/PDB/Native/RawError.h"
-#include "llvm/DebugInfo/PDB/Native/RawTypes.h"
-#include "llvm/Support/BinaryStreamArray.h"
-#include "llvm/Support/BinaryStreamReader.h"
-
-#include "llvm/Support/Error.h"
-
-namespace llvm {
-namespace pdb {
-
-static Error checkHashHdrVersion(const GSIHashHeader *HashHdr) {
- if (HashHdr->VerHdr != GSIHashHeader::HdrVersion)
- return make_error<RawError>(
- raw_error_code::feature_unsupported,
- "Encountered unsupported globals stream version.");
-
- return Error::success();
-}
-
-Error readGSIHashBuckets(FixedStreamArray<support::ulittle32_t> &HashBuckets,
- const GSIHashHeader *HashHdr,
- BinaryStreamReader &Reader) {
- if (auto EC = checkHashHdrVersion(HashHdr))
- return EC;
-
- // Before the actual hash buckets, there is a bitmap of length determined by
- // IPHR_HASH.
- ArrayRef<uint8_t> Bitmap;
- size_t BitmapSizeInBits = alignTo(IPHR_HASH + 1, 32);
- uint32_t NumBitmapEntries = BitmapSizeInBits / 8;
- if (auto EC = Reader.readBytes(Bitmap, NumBitmapEntries))
- return joinErrors(std::move(EC),
- make_error<RawError>(raw_error_code::corrupt_file,
- "Could not read a bitmap."));
- uint32_t NumBuckets = 0;
- for (uint8_t B : Bitmap)
- NumBuckets += countPopulation(B);
-
- // Hash buckets follow.
- if (auto EC = Reader.readArray(HashBuckets, NumBuckets))
- return joinErrors(std::move(EC),
- make_error<RawError>(raw_error_code::corrupt_file,
- "Hash buckets corrupted."));
-
- return Error::success();
-}
-
-Error readGSIHashHeader(const GSIHashHeader *&HashHdr,
- BinaryStreamReader &Reader) {
- if (Reader.readObject(HashHdr))
- return make_error<RawError>(raw_error_code::corrupt_file,
- "Stream does not contain a GSIHashHeader.");
-
- if (HashHdr->VerSignature != GSIHashHeader::HdrSignature)
- return make_error<RawError>(
- raw_error_code::feature_unsupported,
- "GSIHashHeader signature (0xffffffff) not found.");
-
- return Error::success();
-}
-
-Error readGSIHashRecords(FixedStreamArray<PSHashRecord> &HashRecords,
- const GSIHashHeader *HashHdr,
- BinaryStreamReader &Reader) {
- if (auto EC = checkHashHdrVersion(HashHdr))
- return EC;
-
- // HashHdr->HrSize specifies the number of bytes of PSHashRecords we have.
- // Verify that we can read them all.
- if (HashHdr->HrSize % sizeof(PSHashRecord))
- return make_error<RawError>(raw_error_code::corrupt_file,
- "Invalid HR array size.");
- uint32_t NumHashRecords = HashHdr->HrSize / sizeof(PSHashRecord);
- if (auto EC = Reader.readArray(HashRecords, NumHashRecords))
- return joinErrors(std::move(EC),
- make_error<RawError>(raw_error_code::corrupt_file,
- "Error reading hash records."));
-
- return Error::success();
-}
-}
-}
diff --git a/lib/DebugInfo/PDB/Native/GSI.h b/lib/DebugInfo/PDB/Native/GSI.h
deleted file mode 100644
index 9e63bc83548f..000000000000
--- a/lib/DebugInfo/PDB/Native/GSI.h
+++ /dev/null
@@ -1,68 +0,0 @@
-//===- GSI.h - Common Declarations for GlobalsStream and PublicsStream ----===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// The data structures defined in this file are based on the reference
-// implementation which is available at
-// https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/dbi/gsi.h
-//
-// When you are reading the reference source code, you'd find the
-// information below useful.
-//
-// - ppdb1->m_fMinimalDbgInfo seems to be always true.
-// - SMALLBUCKETS macro is defined.
-//
-// The reference doesn't compile, so I learned just by reading code.
-// It's not guaranteed to be correct.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_LIB_DEBUGINFO_PDB_RAW_GSI_H
-#define LLVM_LIB_DEBUGINFO_PDB_RAW_GSI_H
-
-#include "llvm/DebugInfo/PDB/Native/RawTypes.h"
-#include "llvm/Support/BinaryStreamArray.h"
-
-#include "llvm/Support/Endian.h"
-#include "llvm/Support/Error.h"
-
-namespace llvm {
-
-class BinaryStreamReader;
-
-namespace pdb {
-
-/// From https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/dbi/gsi.cpp
-static const unsigned IPHR_HASH = 4096;
-
-/// Header of the hash tables found in the globals and publics sections.
-/// Based on GSIHashHeader in
-/// https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/dbi/gsi.h
-struct GSIHashHeader {
- enum : unsigned {
- HdrSignature = ~0U,
- HdrVersion = 0xeffe0000 + 19990810,
- };
- support::ulittle32_t VerSignature;
- support::ulittle32_t VerHdr;
- support::ulittle32_t HrSize;
- support::ulittle32_t NumBuckets;
-};
-
-Error readGSIHashBuckets(FixedStreamArray<support::ulittle32_t> &HashBuckets,
- const GSIHashHeader *HashHdr,
- BinaryStreamReader &Reader);
-Error readGSIHashHeader(const GSIHashHeader *&HashHdr,
- BinaryStreamReader &Reader);
-Error readGSIHashRecords(FixedStreamArray<PSHashRecord> &HashRecords,
- const GSIHashHeader *HashHdr,
- BinaryStreamReader &Reader);
-}
-}
-
-#endif
diff --git a/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp b/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp
new file mode 100644
index 000000000000..e84f25dfeefa
--- /dev/null
+++ b/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp
@@ -0,0 +1,322 @@
+//===- DbiStreamBuilder.cpp - PDB Dbi 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/GSIStreamBuilder.h"
+
+#include "llvm/DebugInfo/CodeView/RecordName.h"
+#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
+#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
+#include "llvm/DebugInfo/CodeView/SymbolSerializer.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"
+#include "llvm/DebugInfo/PDB/Native/Hash.h"
+#include "llvm/Support/BinaryItemStream.h"
+#include "llvm/Support/BinaryStreamWriter.h"
+#include <algorithm>
+#include <vector>
+
+using namespace llvm;
+using namespace llvm::msf;
+using namespace llvm::pdb;
+using namespace llvm::codeview;
+
+struct llvm::pdb::GSIHashStreamBuilder {
+ std::vector<CVSymbol> Records;
+ uint32_t StreamIndex;
+ std::vector<PSHashRecord> HashRecords;
+ std::array<support::ulittle32_t, (IPHR_HASH + 32) / 32> HashBitmap;
+ std::vector<support::ulittle32_t> HashBuckets;
+
+ uint32_t calculateSerializedLength() const;
+ uint32_t calculateRecordByteSize() const;
+ Error commit(BinaryStreamWriter &Writer);
+ void finalizeBuckets(uint32_t RecordZeroOffset);
+
+ template <typename T> void addSymbol(const T &Symbol, MSFBuilder &Msf) {
+ T Copy(Symbol);
+ Records.push_back(SymbolSerializer::writeOneSymbol(Copy, Msf.getAllocator(),
+ CodeViewContainer::Pdb));
+ }
+ void addSymbol(const CVSymbol &Symbol) { Records.push_back(Symbol); }
+};
+
+uint32_t GSIHashStreamBuilder::calculateSerializedLength() const {
+ uint32_t Size = sizeof(GSIHashHeader);
+ Size += HashRecords.size() * sizeof(PSHashRecord);
+ Size += HashBitmap.size() * sizeof(uint32_t);
+ Size += HashBuckets.size() * sizeof(uint32_t);
+ return Size;
+}
+
+uint32_t GSIHashStreamBuilder::calculateRecordByteSize() const {
+ uint32_t Size = 0;
+ for (const auto &Sym : Records)
+ Size += Sym.length();
+ return Size;
+}
+
+Error GSIHashStreamBuilder::commit(BinaryStreamWriter &Writer) {
+ GSIHashHeader Header;
+ Header.VerSignature = GSIHashHeader::HdrSignature;
+ Header.VerHdr = GSIHashHeader::HdrVersion;
+ Header.HrSize = HashRecords.size() * sizeof(PSHashRecord);
+ Header.NumBuckets = HashBitmap.size() * 4 + HashBuckets.size() * 4;
+
+ if (auto EC = Writer.writeObject(Header))
+ return EC;
+
+ if (auto EC = Writer.writeArray(makeArrayRef(HashRecords)))
+ return EC;
+ if (auto EC = Writer.writeArray(makeArrayRef(HashBitmap)))
+ return EC;
+ if (auto EC = Writer.writeArray(makeArrayRef(HashBuckets)))
+ return EC;
+ return Error::success();
+}
+
+void GSIHashStreamBuilder::finalizeBuckets(uint32_t RecordZeroOffset) {
+ std::array<std::vector<PSHashRecord>, IPHR_HASH + 1> TmpBuckets;
+ uint32_t SymOffset = RecordZeroOffset;
+ for (const CVSymbol &Sym : Records) {
+ PSHashRecord HR;
+ // Add one when writing symbol offsets to disk. See GSI1::fixSymRecs.
+ HR.Off = SymOffset + 1;
+ HR.CRef = 1; // Always use a refcount of 1.
+
+ // Hash the name to figure out which bucket this goes into.
+ StringRef Name = getSymbolName(Sym);
+ size_t BucketIdx = hashStringV1(Name) % IPHR_HASH;
+ TmpBuckets[BucketIdx].push_back(HR); // FIXME: Does order matter?
+
+ SymOffset += Sym.length();
+ }
+
+ // Compute the three tables: the hash records in bucket and chain order, the
+ // bucket presence bitmap, and the bucket chain start offsets.
+ HashRecords.reserve(Records.size());
+ for (ulittle32_t &Word : HashBitmap)
+ Word = 0;
+ for (size_t BucketIdx = 0; BucketIdx < IPHR_HASH + 1; ++BucketIdx) {
+ auto &Bucket = TmpBuckets[BucketIdx];
+ if (Bucket.empty())
+ continue;
+ HashBitmap[BucketIdx / 32] |= 1U << (BucketIdx % 32);
+
+ // Calculate what the offset of the first hash record in the chain would
+ // be if it were inflated to contain 32-bit pointers. On a 32-bit system,
+ // each record would be 12 bytes. See HROffsetCalc in gsi.h.
+ const int SizeOfHROffsetCalc = 12;
+ ulittle32_t ChainStartOff =
+ ulittle32_t(HashRecords.size() * SizeOfHROffsetCalc);
+ HashBuckets.push_back(ChainStartOff);
+ for (const auto &HR : Bucket)
+ HashRecords.push_back(HR);
+ }
+}
+
+GSIStreamBuilder::GSIStreamBuilder(msf::MSFBuilder &Msf)
+ : Msf(Msf), PSH(llvm::make_unique<GSIHashStreamBuilder>()),
+ GSH(llvm::make_unique<GSIHashStreamBuilder>()) {}
+
+GSIStreamBuilder::~GSIStreamBuilder() {}
+
+uint32_t GSIStreamBuilder::calculatePublicsHashStreamSize() const {
+ uint32_t Size = 0;
+ Size += sizeof(PublicsStreamHeader);
+ Size += PSH->calculateSerializedLength();
+ Size += PSH->Records.size() * sizeof(uint32_t); // AddrMap
+ // FIXME: Add thunk map and section offsets for incremental linking.
+
+ return Size;
+}
+
+uint32_t GSIStreamBuilder::calculateGlobalsHashStreamSize() const {
+ return GSH->calculateSerializedLength();
+}
+
+Error GSIStreamBuilder::finalizeMsfLayout() {
+ // First we write public symbol records, then we write global symbol records.
+ uint32_t PSHZero = 0;
+ uint32_t GSHZero = PSH->calculateRecordByteSize();
+
+ PSH->finalizeBuckets(PSHZero);
+ GSH->finalizeBuckets(GSHZero);
+
+ Expected<uint32_t> Idx = Msf.addStream(calculatePublicsHashStreamSize());
+ if (!Idx)
+ return Idx.takeError();
+ PSH->StreamIndex = *Idx;
+ Idx = Msf.addStream(calculateGlobalsHashStreamSize());
+ if (!Idx)
+ return Idx.takeError();
+ GSH->StreamIndex = *Idx;
+
+ uint32_t RecordBytes =
+ GSH->calculateRecordByteSize() + PSH->calculateRecordByteSize();
+
+ Idx = Msf.addStream(RecordBytes);
+ if (!Idx)
+ return Idx.takeError();
+ RecordStreamIdx = *Idx;
+ return Error::success();
+}
+
+static bool comparePubSymByAddrAndName(
+ const std::pair<const CVSymbol *, const PublicSym32 *> &LS,
+ const std::pair<const CVSymbol *, const PublicSym32 *> &RS) {
+ if (LS.second->Segment != RS.second->Segment)
+ return LS.second->Segment < RS.second->Segment;
+ if (LS.second->Offset != RS.second->Offset)
+ return LS.second->Offset < RS.second->Offset;
+
+ return LS.second->Name < RS.second->Name;
+}
+
+/// Compute the address map. The address map is an array of symbol offsets
+/// sorted so that it can be binary searched by address.
+static std::vector<ulittle32_t> computeAddrMap(ArrayRef<CVSymbol> Records) {
+ // Make a vector of pointers to the symbols so we can sort it by address.
+ // Also gather the symbol offsets while we're at it.
+
+ std::vector<PublicSym32> DeserializedPublics;
+ std::vector<std::pair<const CVSymbol *, const PublicSym32 *>> PublicsByAddr;
+ std::vector<uint32_t> SymOffsets;
+ DeserializedPublics.reserve(Records.size());
+ PublicsByAddr.reserve(Records.size());
+ SymOffsets.reserve(Records.size());
+
+ uint32_t SymOffset = 0;
+ for (const CVSymbol &Sym : Records) {
+ assert(Sym.kind() == SymbolKind::S_PUB32);
+ DeserializedPublics.push_back(
+ cantFail(SymbolDeserializer::deserializeAs<PublicSym32>(Sym)));
+ PublicsByAddr.emplace_back(&Sym, &DeserializedPublics.back());
+ SymOffsets.push_back(SymOffset);
+ SymOffset += Sym.length();
+ }
+ std::stable_sort(PublicsByAddr.begin(), PublicsByAddr.end(),
+ comparePubSymByAddrAndName);
+
+ // Fill in the symbol offsets in the appropriate order.
+ std::vector<ulittle32_t> AddrMap;
+ AddrMap.reserve(Records.size());
+ for (auto &Sym : PublicsByAddr) {
+ ptrdiff_t Idx = std::distance(Records.data(), Sym.first);
+ assert(Idx >= 0 && size_t(Idx) < Records.size());
+ AddrMap.push_back(ulittle32_t(SymOffsets[Idx]));
+ }
+ return AddrMap;
+}
+
+uint32_t GSIStreamBuilder::getPublicsStreamIndex() const {
+ return PSH->StreamIndex;
+}
+
+uint32_t GSIStreamBuilder::getGlobalsStreamIndex() const {
+ return GSH->StreamIndex;
+}
+
+void GSIStreamBuilder::addPublicSymbol(const PublicSym32 &Pub) {
+ PSH->addSymbol(Pub, Msf);
+}
+
+void GSIStreamBuilder::addGlobalSymbol(const ProcRefSym &Sym) {
+ GSH->addSymbol(Sym, Msf);
+}
+
+void GSIStreamBuilder::addGlobalSymbol(const DataSym &Sym) {
+ GSH->addSymbol(Sym, Msf);
+}
+
+void GSIStreamBuilder::addGlobalSymbol(const ConstantSym &Sym) {
+ GSH->addSymbol(Sym, Msf);
+}
+
+void GSIStreamBuilder::addGlobalSymbol(const UDTSym &Sym) {
+ GSH->addSymbol(Sym, Msf);
+}
+
+void GSIStreamBuilder::addGlobalSymbol(const codeview::CVSymbol &Sym) {
+ GSH->addSymbol(Sym);
+}
+
+static Error writeRecords(BinaryStreamWriter &Writer,
+ ArrayRef<CVSymbol> Records) {
+ BinaryItemStream<CVSymbol> ItemStream(support::endianness::little);
+ ItemStream.setItems(Records);
+ BinaryStreamRef RecordsRef(ItemStream);
+ return Writer.writeStreamRef(RecordsRef);
+}
+
+Error GSIStreamBuilder::commitSymbolRecordStream(
+ WritableBinaryStreamRef Stream) {
+ BinaryStreamWriter Writer(Stream);
+
+ // Write public symbol records first, followed by global symbol records. This
+ // must match the order that we assume in finalizeMsfLayout when computing
+ // PSHZero and GSHZero.
+ if (auto EC = writeRecords(Writer, PSH->Records))
+ return EC;
+ if (auto EC = writeRecords(Writer, GSH->Records))
+ return EC;
+
+ return Error::success();
+}
+
+Error GSIStreamBuilder::commitPublicsHashStream(
+ WritableBinaryStreamRef Stream) {
+ BinaryStreamWriter Writer(Stream);
+ PublicsStreamHeader Header;
+
+ // 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 = PSH->calculateSerializedLength();
+ Header.AddrMap = PSH->Records.size() * 4;
+ if (auto EC = Writer.writeObject(Header))
+ return EC;
+
+ if (auto EC = PSH->commit(Writer))
+ return EC;
+
+ std::vector<ulittle32_t> AddrMap = computeAddrMap(PSH->Records);
+ if (auto EC = Writer.writeArray(makeArrayRef(AddrMap)))
+ return EC;
+
+ return Error::success();
+}
+
+Error GSIStreamBuilder::commitGlobalsHashStream(
+ WritableBinaryStreamRef Stream) {
+ BinaryStreamWriter Writer(Stream);
+ return GSH->commit(Writer);
+}
+
+Error GSIStreamBuilder::commit(const msf::MSFLayout &Layout,
+ WritableBinaryStreamRef Buffer) {
+ auto GS = WritableMappedBlockStream::createIndexedStream(
+ Layout, Buffer, getGlobalsStreamIndex(), Msf.getAllocator());
+ auto PS = WritableMappedBlockStream::createIndexedStream(
+ Layout, Buffer, getPublicsStreamIndex(), Msf.getAllocator());
+ auto PRS = WritableMappedBlockStream::createIndexedStream(
+ Layout, Buffer, getRecordStreamIdx(), Msf.getAllocator());
+
+ if (auto EC = commitSymbolRecordStream(*PRS))
+ return EC;
+ if (auto EC = commitGlobalsHashStream(*GS))
+ return EC;
+ if (auto EC = commitPublicsHashStream(*PS))
+ return EC;
+ return Error::success();
+}
diff --git a/lib/DebugInfo/PDB/Native/GlobalsStream.cpp b/lib/DebugInfo/PDB/Native/GlobalsStream.cpp
index a2ee0f047c58..36076f436ad0 100644
--- a/lib/DebugInfo/PDB/Native/GlobalsStream.cpp
+++ b/lib/DebugInfo/PDB/Native/GlobalsStream.cpp
@@ -1,4 +1,4 @@
-//===- GlobalsStream.cpp - PDB Index of Symbols by Name ---- ----*- C++ -*-===//
+//===- GlobalsStream.cpp - PDB Index of Symbols by Name ---------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -6,9 +6,21 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
+//
+// The on-disk structores used in this file are based on the reference
+// implementation which is available at
+// https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/dbi/gsi.h
+//
+// When you are reading the reference source code, you'd find the
+// information below useful.
+//
+// - ppdb1->m_fMinimalDbgInfo seems to be always true.
+// - SMALLBUCKETS macro is defined.
+//
+//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
-#include "GSI.h"
+#include "llvm/DebugInfo/PDB/Native/RawError.h"
#include "llvm/Support/BinaryStreamReader.h"
#include "llvm/Support/Error.h"
#include <algorithm>
@@ -24,19 +36,89 @@ GlobalsStream::~GlobalsStream() = default;
Error GlobalsStream::reload() {
BinaryStreamReader Reader(*Stream);
+ if (auto E = GlobalsTable.read(Reader))
+ return E;
+ return Error::success();
+}
- const GSIHashHeader *HashHdr;
- if (auto EC = readGSIHashHeader(HashHdr, Reader))
- return EC;
+static Error checkHashHdrVersion(const GSIHashHeader *HashHdr) {
+ if (HashHdr->VerHdr != GSIHashHeader::HdrVersion)
+ return make_error<RawError>(
+ raw_error_code::feature_unsupported,
+ "Encountered unsupported globals stream version.");
- if (auto EC = readGSIHashRecords(HashRecords, HashHdr, Reader))
+ return Error::success();
+}
+
+static Error readGSIHashHeader(const GSIHashHeader *&HashHdr,
+ BinaryStreamReader &Reader) {
+ if (Reader.readObject(HashHdr))
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Stream does not contain a GSIHashHeader.");
+
+ if (HashHdr->VerSignature != GSIHashHeader::HdrSignature)
+ return make_error<RawError>(
+ raw_error_code::feature_unsupported,
+ "GSIHashHeader signature (0xffffffff) not found.");
+
+ return Error::success();
+}
+
+static Error readGSIHashRecords(FixedStreamArray<PSHashRecord> &HashRecords,
+ const GSIHashHeader *HashHdr,
+ BinaryStreamReader &Reader) {
+ if (auto EC = checkHashHdrVersion(HashHdr))
return EC;
- if (auto EC = readGSIHashBuckets(HashBuckets, HashHdr, Reader))
+ // HashHdr->HrSize specifies the number of bytes of PSHashRecords we have.
+ // Verify that we can read them all.
+ if (HashHdr->HrSize % sizeof(PSHashRecord))
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Invalid HR array size.");
+ uint32_t NumHashRecords = HashHdr->HrSize / sizeof(PSHashRecord);
+ if (auto EC = Reader.readArray(HashRecords, NumHashRecords))
+ return joinErrors(std::move(EC),
+ make_error<RawError>(raw_error_code::corrupt_file,
+ "Error reading hash records."));
+
+ return Error::success();
+}
+
+static Error
+readGSIHashBuckets(FixedStreamArray<support::ulittle32_t> &HashBuckets,
+ ArrayRef<uint8_t> &HashBitmap, const GSIHashHeader *HashHdr,
+ BinaryStreamReader &Reader) {
+ if (auto EC = checkHashHdrVersion(HashHdr))
return EC;
- NumBuckets = HashBuckets.size();
+
+ // Before the actual hash buckets, there is a bitmap of length determined by
+ // IPHR_HASH.
+ size_t BitmapSizeInBits = alignTo(IPHR_HASH + 1, 32);
+ uint32_t NumBitmapEntries = BitmapSizeInBits / 8;
+ if (auto EC = Reader.readBytes(HashBitmap, NumBitmapEntries))
+ return joinErrors(std::move(EC),
+ make_error<RawError>(raw_error_code::corrupt_file,
+ "Could not read a bitmap."));
+ uint32_t NumBuckets = 0;
+ for (uint8_t B : HashBitmap)
+ NumBuckets += countPopulation(B);
+
+ // Hash buckets follow.
+ if (auto EC = Reader.readArray(HashBuckets, NumBuckets))
+ return joinErrors(std::move(EC),
+ make_error<RawError>(raw_error_code::corrupt_file,
+ "Hash buckets corrupted."));
return Error::success();
}
-Error GlobalsStream::commit() { return Error::success(); }
+Error GSIHashTable::read(BinaryStreamReader &Reader) {
+ if (auto EC = readGSIHashHeader(HashHdr, Reader))
+ return EC;
+ if (auto EC = readGSIHashRecords(HashRecords, HashHdr, Reader))
+ return EC;
+ if (HashHdr->HrSize > 0)
+ if (auto EC = readGSIHashBuckets(HashBuckets, HashBitmap, HashHdr, Reader))
+ return EC;
+ return Error::success();
+}
diff --git a/lib/DebugInfo/PDB/Native/InfoStream.cpp b/lib/DebugInfo/PDB/Native/InfoStream.cpp
index 829879060c33..17c9392a9dd5 100644
--- a/lib/DebugInfo/PDB/Native/InfoStream.cpp
+++ b/lib/DebugInfo/PDB/Native/InfoStream.cpp
@@ -10,12 +10,10 @@
#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/SmallVector.h"
-#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
#include "llvm/DebugInfo/PDB/Native/RawConstants.h"
#include "llvm/DebugInfo/PDB/Native/RawError.h"
#include "llvm/DebugInfo/PDB/Native/RawTypes.h"
#include "llvm/Support/BinaryStreamReader.h"
-#include "llvm/Support/BinaryStreamWriter.h"
using namespace llvm;
using namespace llvm::codeview;
diff --git a/lib/DebugInfo/PDB/Native/NativeBuiltinSymbol.cpp b/lib/DebugInfo/PDB/Native/NativeBuiltinSymbol.cpp
index 60416f69e137..4644ddcf24e3 100644
--- a/lib/DebugInfo/PDB/Native/NativeBuiltinSymbol.cpp
+++ b/lib/DebugInfo/PDB/Native/NativeBuiltinSymbol.cpp
@@ -9,7 +9,6 @@
#include "llvm/DebugInfo/PDB/Native/NativeBuiltinSymbol.h"
-#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
namespace llvm {
namespace pdb {
diff --git a/lib/DebugInfo/PDB/Native/NativeEnumSymbol.cpp b/lib/DebugInfo/PDB/Native/NativeEnumSymbol.cpp
new file mode 100644
index 000000000000..38d65917306a
--- /dev/null
+++ b/lib/DebugInfo/PDB/Native/NativeEnumSymbol.cpp
@@ -0,0 +1,108 @@
+//===- NativeEnumSymbol.cpp - info about enum type --------------*- 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/NativeEnumSymbol.h"
+
+#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h"
+
+#include <cassert>
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+NativeEnumSymbol::NativeEnumSymbol(NativeSession &Session, SymIndexId Id,
+ const codeview::CVType &CVT)
+ : NativeRawSymbol(Session, Id), CV(CVT),
+ Record(codeview::TypeRecordKind::Enum) {
+ assert(CV.kind() == codeview::TypeLeafKind::LF_ENUM);
+ cantFail(visitTypeRecord(CV, *this));
+}
+
+NativeEnumSymbol::~NativeEnumSymbol() {}
+
+std::unique_ptr<NativeRawSymbol> NativeEnumSymbol::clone() const {
+ return llvm::make_unique<NativeEnumSymbol>(Session, SymbolId, CV);
+}
+
+std::unique_ptr<IPDBEnumSymbols>
+NativeEnumSymbol::findChildren(PDB_SymType Type) const {
+ switch (Type) {
+ case PDB_SymType::Data: {
+ // TODO(amccarth): Provide an actual implementation.
+ return nullptr;
+ }
+ default:
+ return nullptr;
+ }
+}
+
+Error NativeEnumSymbol::visitKnownRecord(codeview::CVType &CVR,
+ codeview::EnumRecord &ER) {
+ Record = ER;
+ return Error::success();
+}
+
+Error NativeEnumSymbol::visitKnownMember(codeview::CVMemberRecord &CVM,
+ codeview::EnumeratorRecord &R) {
+ return Error::success();
+}
+
+PDB_SymType NativeEnumSymbol::getSymTag() const { return PDB_SymType::Enum; }
+
+uint32_t NativeEnumSymbol::getClassParentId() const { return 0xFFFFFFFF; }
+
+uint32_t NativeEnumSymbol::getUnmodifiedTypeId() const { return 0; }
+
+bool NativeEnumSymbol::hasConstructor() const {
+ return bool(Record.getOptions() &
+ codeview::ClassOptions::HasConstructorOrDestructor);
+}
+
+bool NativeEnumSymbol::hasAssignmentOperator() const {
+ return bool(Record.getOptions() &
+ codeview::ClassOptions::HasOverloadedAssignmentOperator);
+}
+
+bool NativeEnumSymbol::hasCastOperator() const {
+ return bool(Record.getOptions() &
+ codeview::ClassOptions::HasConversionOperator);
+}
+
+uint64_t NativeEnumSymbol::getLength() const {
+ const auto Id = Session.findSymbolByTypeIndex(Record.getUnderlyingType());
+ const auto UnderlyingType =
+ Session.getConcreteSymbolById<PDBSymbolTypeBuiltin>(Id);
+ return UnderlyingType ? UnderlyingType->getLength() : 0;
+}
+
+std::string NativeEnumSymbol::getName() const { return Record.getName(); }
+
+bool NativeEnumSymbol::isNested() const {
+ return bool(Record.getOptions() & codeview::ClassOptions::Nested);
+}
+
+bool NativeEnumSymbol::hasOverloadedOperator() const {
+ return bool(Record.getOptions() &
+ codeview::ClassOptions::HasOverloadedOperator);
+}
+
+bool NativeEnumSymbol::isPacked() const {
+ return bool(Record.getOptions() & codeview::ClassOptions::Packed);
+}
+
+bool NativeEnumSymbol::isScoped() const {
+ return bool(Record.getOptions() & codeview::ClassOptions::Scoped);
+}
+
+uint32_t NativeEnumSymbol::getTypeId() const {
+ return Session.findSymbolByTypeIndex(Record.getUnderlyingType());
+}
diff --git a/lib/DebugInfo/PDB/Native/NativeEnumTypes.cpp b/lib/DebugInfo/PDB/Native/NativeEnumTypes.cpp
new file mode 100644
index 000000000000..36a68a1c62de
--- /dev/null
+++ b/lib/DebugInfo/PDB/Native/NativeEnumTypes.cpp
@@ -0,0 +1,59 @@
+//==- NativeEnumTypes.cpp - Native Type Enumerator impl ----------*- 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/NativeEnumTypes.h"
+
+#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"
+#include "llvm/DebugInfo/PDB/Native/NativeEnumSymbol.h"
+#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
+#include "llvm/DebugInfo/PDB/PDBSymbol.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
+
+namespace llvm {
+namespace pdb {
+
+NativeEnumTypes::NativeEnumTypes(NativeSession &PDBSession,
+ codeview::LazyRandomTypeCollection &Types,
+ codeview::TypeLeafKind Kind)
+ : Matches(), Index(0), Session(PDBSession), Kind(Kind) {
+ for (auto Index = Types.getFirst(); Index;
+ Index = Types.getNext(Index.getValue())) {
+ if (Types.getType(Index.getValue()).kind() == Kind)
+ Matches.push_back(Index.getValue());
+ }
+}
+
+NativeEnumTypes::NativeEnumTypes(
+ NativeSession &PDBSession, const std::vector<codeview::TypeIndex> &Matches,
+ codeview::TypeLeafKind Kind)
+ : Matches(Matches), Index(0), Session(PDBSession), Kind(Kind) {}
+
+uint32_t NativeEnumTypes::getChildCount() const {
+ return static_cast<uint32_t>(Matches.size());
+}
+
+std::unique_ptr<PDBSymbol>
+NativeEnumTypes::getChildAtIndex(uint32_t Index) const {
+ if (Index < Matches.size())
+ return Session.createEnumSymbol(Matches[Index]);
+ return nullptr;
+}
+
+std::unique_ptr<PDBSymbol> NativeEnumTypes::getNext() {
+ return getChildAtIndex(Index++);
+}
+
+void NativeEnumTypes::reset() { Index = 0; }
+
+NativeEnumTypes *NativeEnumTypes::clone() const {
+ return new NativeEnumTypes(Session, Matches, Kind);
+}
+
+} // namespace pdb
+} // namespace llvm
diff --git a/lib/DebugInfo/PDB/Native/NativeExeSymbol.cpp b/lib/DebugInfo/PDB/Native/NativeExeSymbol.cpp
index 3241000b06db..e8b06065fc60 100644
--- a/lib/DebugInfo/PDB/Native/NativeExeSymbol.cpp
+++ b/lib/DebugInfo/PDB/Native/NativeExeSymbol.cpp
@@ -38,6 +38,8 @@ NativeExeSymbol::findChildren(PDB_SymType Type) const {
consumeError(Dbi.takeError());
break;
}
+ case PDB_SymType::Enum:
+ return Session.createTypeEnumerator(codeview::LF_ENUM);
default:
break;
}
diff --git a/lib/DebugInfo/PDB/Native/NativeRawSymbol.cpp b/lib/DebugInfo/PDB/Native/NativeRawSymbol.cpp
index df3f418052a9..d23ee0a09196 100644
--- a/lib/DebugInfo/PDB/Native/NativeRawSymbol.cpp
+++ b/lib/DebugInfo/PDB/Native/NativeRawSymbol.cpp
@@ -286,6 +286,11 @@ std::string NativeRawSymbol::getUndecoratedName() const {
return {};
}
+std::string NativeRawSymbol::getUndecoratedNameEx(
+ PDB_UndnameFlags Flags) const {
+ return {};
+}
+
uint32_t NativeRawSymbol::getUnmodifiedTypeId() const {
return 0;
}
diff --git a/lib/DebugInfo/PDB/Native/NativeSession.cpp b/lib/DebugInfo/PDB/Native/NativeSession.cpp
index 76de0d8f9e7e..b01c2b54796c 100644
--- a/lib/DebugInfo/PDB/Native/NativeSession.cpp
+++ b/lib/DebugInfo/PDB/Native/NativeSession.cpp
@@ -16,11 +16,15 @@
#include "llvm/DebugInfo/PDB/IPDBSourceFile.h"
#include "llvm/DebugInfo/PDB/Native/NativeBuiltinSymbol.h"
#include "llvm/DebugInfo/PDB/Native/NativeCompilandSymbol.h"
+#include "llvm/DebugInfo/PDB/Native/NativeEnumSymbol.h"
+#include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h"
#include "llvm/DebugInfo/PDB/Native/NativeExeSymbol.h"
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
#include "llvm/DebugInfo/PDB/Native/RawError.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h"
#include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/BinaryByteStream.h"
#include "llvm/Support/Error.h"
@@ -28,6 +32,7 @@
#include "llvm/Support/MemoryBuffer.h"
#include <algorithm>
+#include <cassert>
#include <memory>
#include <utility>
@@ -63,15 +68,9 @@ NativeSession::NativeSession(std::unique_ptr<PDBFile> PdbFile,
NativeSession::~NativeSession() = default;
-Error NativeSession::createFromPdb(StringRef Path,
+Error NativeSession::createFromPdb(std::unique_ptr<MemoryBuffer> Buffer,
std::unique_ptr<IPDBSession> &Session) {
- ErrorOr<std::unique_ptr<MemoryBuffer>> ErrorOrBuffer =
- MemoryBuffer::getFileOrSTDIN(Path, /*FileSize=*/-1,
- /*RequiresNullTerminator=*/false);
- if (!ErrorOrBuffer)
- return make_error<GenericError>(generic_error_code::invalid_path);
-
- std::unique_ptr<MemoryBuffer> Buffer = std::move(*ErrorOrBuffer);
+ StringRef Path = Buffer->getBufferIdentifier();
auto Stream = llvm::make_unique<MemoryBufferByteStream>(
std::move(Buffer), llvm::support::little);
@@ -102,6 +101,25 @@ NativeSession::createCompilandSymbol(DbiModuleDescriptor MI) {
*this, std::unique_ptr<IPDBRawSymbol>(SymbolCache[Id]->clone()));
}
+std::unique_ptr<PDBSymbolTypeEnum>
+NativeSession::createEnumSymbol(codeview::TypeIndex Index) {
+ const auto Id = findSymbolByTypeIndex(Index);
+ return llvm::make_unique<PDBSymbolTypeEnum>(
+ *this, std::unique_ptr<IPDBRawSymbol>(SymbolCache[Id]->clone()));
+}
+
+std::unique_ptr<IPDBEnumSymbols>
+NativeSession::createTypeEnumerator(codeview::TypeLeafKind Kind) {
+ auto Tpi = Pdb->getPDBTpiStream();
+ if (!Tpi) {
+ consumeError(Tpi.takeError());
+ return nullptr;
+ }
+ auto &Types = Tpi->typeCollection();
+ return std::unique_ptr<IPDBEnumSymbols>(
+ new NativeEnumTypes(*this, Types, codeview::LF_ENUM));
+}
+
SymIndexId NativeSession::findSymbolByTypeIndex(codeview::TypeIndex Index) {
// First see if it's already in our cache.
const auto Entry = TypeIndexToSymbolId.find(Index);
@@ -129,9 +147,20 @@ SymIndexId NativeSession::findSymbolByTypeIndex(codeview::TypeIndex Index) {
return Id;
}
- // TODO: Look up PDB type by type index
-
- return 0;
+ // We need to instantiate and cache the desired type symbol.
+ auto Tpi = Pdb->getPDBTpiStream();
+ if (!Tpi) {
+ consumeError(Tpi.takeError());
+ return 0;
+ }
+ auto &Types = Tpi->typeCollection();
+ const auto &I = Types.getType(Index);
+ const auto Id = static_cast<SymIndexId>(SymbolCache.size());
+ // TODO(amccarth): Make this handle all types, not just LF_ENUMs.
+ assert(I.kind() == codeview::LF_ENUM);
+ SymbolCache.emplace_back(llvm::make_unique<NativeEnumSymbol>(*this, Id, I));
+ TypeIndexToSymbolId[Index] = Id;
+ return Id;
}
uint64_t NativeSession::getLoadAddress() const { return 0; }
@@ -216,3 +245,7 @@ NativeSession::getSourceFileById(uint32_t FileId) const {
std::unique_ptr<IPDBEnumDataStreams> NativeSession::getDebugStreams() const {
return nullptr;
}
+
+std::unique_ptr<IPDBEnumTables> NativeSession::getEnumTables() const {
+ return nullptr;
+}
diff --git a/lib/DebugInfo/PDB/Native/PDBFile.cpp b/lib/DebugInfo/PDB/Native/PDBFile.cpp
index 0b6492efc70f..15b31d821b1c 100644
--- a/lib/DebugInfo/PDB/Native/PDBFile.cpp
+++ b/lib/DebugInfo/PDB/Native/PDBFile.cpp
@@ -85,6 +85,11 @@ uint32_t PDBFile::getNumStreams() const {
return ContainerLayout.StreamSizes.size();
}
+uint32_t PDBFile::getMaxStreamSize() const {
+ return *std::max_element(ContainerLayout.StreamSizes.begin(),
+ ContainerLayout.StreamSizes.end());
+}
+
uint32_t PDBFile::getStreamByteSize(uint32_t StreamIndex) const {
return ContainerLayout.StreamSizes[StreamIndex];
}
@@ -150,8 +155,7 @@ Error PDBFile::parseFileHeaders() {
MappedBlockStream::createFpmStream(ContainerLayout, *Buffer, Allocator);
BinaryStreamReader FpmReader(*FpmStream);
ArrayRef<uint8_t> FpmBytes;
- if (auto EC = FpmReader.readBytes(FpmBytes,
- msf::getFullFpmByteSize(ContainerLayout)))
+ if (auto EC = FpmReader.readBytes(FpmBytes, FpmReader.bytesRemaining()))
return EC;
uint32_t BlocksRemaining = getBlockCount();
uint32_t BI = 0;
@@ -230,6 +234,13 @@ ArrayRef<support::ulittle32_t> PDBFile::getDirectoryBlockArray() const {
return ContainerLayout.DirectoryBlocks;
}
+std::unique_ptr<MappedBlockStream> PDBFile::createIndexedStream(uint16_t SN) {
+ if (SN == kInvalidStreamIndex)
+ return nullptr;
+ return MappedBlockStream::createIndexedStream(ContainerLayout, *Buffer, SN,
+ Allocator);
+}
+
MSFStreamLayout PDBFile::getStreamLayout(uint32_t StreamIdx) const {
MSFStreamLayout Result;
auto Blocks = getStreamBlockList(StreamIdx);
@@ -238,6 +249,10 @@ MSFStreamLayout PDBFile::getStreamLayout(uint32_t StreamIdx) const {
return Result;
}
+msf::MSFStreamLayout PDBFile::getFpmStreamLayout() const {
+ return msf::getFpmStreamLayout(ContainerLayout);
+}
+
Expected<GlobalsStream &> PDBFile::getPDBGlobalsStream() {
if (!Globals) {
auto DbiS = getPDBDbiStream();
@@ -297,6 +312,9 @@ Expected<TpiStream &> PDBFile::getPDBTpiStream() {
Expected<TpiStream &> PDBFile::getPDBIpiStream() {
if (!Ipi) {
+ if (!hasPDBIpiStream())
+ return make_error<RawError>(raw_error_code::no_stream);
+
auto IpiS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamIPI);
if (!IpiS)
return IpiS.takeError();
@@ -318,8 +336,7 @@ Expected<PublicsStream &> PDBFile::getPDBPublicsStream() {
ContainerLayout, *Buffer, DbiS->getPublicSymbolStreamIndex());
if (!PublicS)
return PublicS.takeError();
- auto TempPublics =
- llvm::make_unique<PublicsStream>(*this, std::move(*PublicS));
+ auto TempPublics = llvm::make_unique<PublicsStream>(std::move(*PublicS));
if (auto EC = TempPublics->reload())
return std::move(EC);
Publics = std::move(TempPublics);
@@ -393,9 +410,18 @@ bool PDBFile::hasPDBGlobalsStream() {
return DbiS->getGlobalSymbolStreamIndex() < getNumStreams();
}
-bool PDBFile::hasPDBInfoStream() { return StreamPDB < getNumStreams(); }
+bool PDBFile::hasPDBInfoStream() const { return StreamPDB < getNumStreams(); }
+
+bool PDBFile::hasPDBIpiStream() const {
+ if (!hasPDBInfoStream())
+ return false;
+
+ if (StreamIPI >= getNumStreams())
+ return false;
-bool PDBFile::hasPDBIpiStream() const { return StreamIPI < getNumStreams(); }
+ auto &InfoStream = cantFail(const_cast<PDBFile *>(this)->getPDBInfoStream());
+ return InfoStream.containsIdStream();
+}
bool PDBFile::hasPDBPublicsStream() {
auto DbiS = getPDBDbiStream();
diff --git a/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp b/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp
index 9f35fd73629c..dee27c621fac 100644
--- a/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp
+++ b/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp
@@ -15,10 +15,10 @@
#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/GSIStreamBuilder.h"
#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
#include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h"
#include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h"
-#include "llvm/DebugInfo/PDB/Native/PublicsStreamBuilder.h"
#include "llvm/DebugInfo/PDB/Native/RawError.h"
#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
#include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h"
@@ -74,10 +74,10 @@ PDBStringTableBuilder &PDBFileBuilder::getStringTableBuilder() {
return Strings;
}
-PublicsStreamBuilder &PDBFileBuilder::getPublicsBuilder() {
- if (!Publics)
- Publics = llvm::make_unique<PublicsStreamBuilder>(*Msf);
- return *Publics;
+GSIStreamBuilder &PDBFileBuilder::getGsiBuilder() {
+ if (!Gsi)
+ Gsi = llvm::make_unique<GSIStreamBuilder>(*Msf);
+ return *Gsi;
}
Error PDBFileBuilder::addNamedStream(StringRef Name, uint32_t Size) {
@@ -122,12 +122,13 @@ Expected<msf::MSFLayout> PDBFileBuilder::finalizeMsfLayout() {
if (auto EC = Ipi->finalizeMsfLayout())
return std::move(EC);
}
- if (Publics) {
- if (auto EC = Publics->finalizeMsfLayout())
+ if (Gsi) {
+ if (auto EC = Gsi->finalizeMsfLayout())
return std::move(EC);
if (Dbi) {
- Dbi->setPublicsStreamIndex(Publics->getStreamIndex());
- Dbi->setSymbolRecordStreamIndex(Publics->getRecordStreamIdx());
+ Dbi->setPublicsStreamIndex(Gsi->getPublicsStreamIndex());
+ Dbi->setGlobalsStreamIndex(Gsi->getGlobalsStreamIndex());
+ Dbi->setSymbolRecordStreamIndex(Gsi->getRecordStreamIdx());
}
}
@@ -141,6 +142,31 @@ Expected<uint32_t> PDBFileBuilder::getNamedStreamIndex(StringRef Name) const {
return SN;
}
+void PDBFileBuilder::commitFpm(WritableBinaryStream &MsfBuffer,
+ const MSFLayout &Layout) {
+ auto FpmStream =
+ WritableMappedBlockStream::createFpmStream(Layout, MsfBuffer, Allocator);
+
+ // We only need to create the alt fpm stream so that it gets initialized.
+ WritableMappedBlockStream::createFpmStream(Layout, MsfBuffer, Allocator,
+ true);
+
+ uint32_t BI = 0;
+ BinaryStreamWriter FpmWriter(*FpmStream);
+ while (BI < Layout.SB->NumBlocks) {
+ uint8_t ThisByte = 0;
+ for (uint32_t I = 0; I < 8; ++I) {
+ bool IsFree =
+ (BI < Layout.SB->NumBlocks) ? Layout.FreePageMap.test(BI) : true;
+ uint8_t Mask = uint8_t(IsFree) << I;
+ ThisByte |= Mask;
+ ++BI;
+ }
+ cantFail(FpmWriter.writeObject(ThisByte));
+ }
+ assert(FpmWriter.bytesRemaining() == 0);
+}
+
Error PDBFileBuilder::commit(StringRef Filename) {
assert(!Filename.empty());
auto ExpectedLayout = finalizeMsfLayout();
@@ -150,15 +176,17 @@ Error PDBFileBuilder::commit(StringRef Filename) {
uint64_t Filesize = Layout.SB->BlockSize * Layout.SB->NumBlocks;
auto OutFileOrError = FileOutputBuffer::create(Filename, Filesize);
- if (OutFileOrError.getError())
- return llvm::make_error<pdb::GenericError>(generic_error_code::invalid_path,
- Filename);
+ if (auto E = OutFileOrError.takeError())
+ return E;
FileBufferByteStream Buffer(std::move(*OutFileOrError),
llvm::support::little);
BinaryStreamWriter Writer(Buffer);
if (auto EC = Writer.writeObject(*Layout.SB))
return EC;
+
+ commitFpm(Buffer, Layout);
+
uint32_t BlockMapOffset =
msf::blockToOffset(Layout.SB->BlockMapAddr, Layout.SB->BlockSize);
Writer.setOffset(BlockMapOffset);
@@ -209,11 +237,8 @@ Error PDBFileBuilder::commit(StringRef Filename) {
return EC;
}
- if (Publics) {
- auto PS = WritableMappedBlockStream::createIndexedStream(
- Layout, Buffer, Publics->getStreamIndex(), Allocator);
- BinaryStreamWriter PSWriter(*PS);
- if (auto EC = Publics->commit(PSWriter))
+ if (Gsi) {
+ if (auto EC = Gsi->commit(Layout, Buffer))
return EC;
}
diff --git a/lib/DebugInfo/PDB/Native/PDBStringTable.cpp b/lib/DebugInfo/PDB/Native/PDBStringTable.cpp
index acd45f7a6219..f1c10357132b 100644
--- a/lib/DebugInfo/PDB/Native/PDBStringTable.cpp
+++ b/lib/DebugInfo/PDB/Native/PDBStringTable.cpp
@@ -10,7 +10,6 @@
#include "llvm/DebugInfo/PDB/Native/PDBStringTable.h"
#include "llvm/ADT/ArrayRef.h"
-#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
#include "llvm/DebugInfo/PDB/Native/Hash.h"
#include "llvm/DebugInfo/PDB/Native/RawError.h"
#include "llvm/DebugInfo/PDB/Native/RawTypes.h"
diff --git a/lib/DebugInfo/PDB/Native/PDBStringTableBuilder.cpp b/lib/DebugInfo/PDB/Native/PDBStringTableBuilder.cpp
index 90acfadd311f..ece3e00b1a87 100644
--- a/lib/DebugInfo/PDB/Native/PDBStringTableBuilder.cpp
+++ b/lib/DebugInfo/PDB/Native/PDBStringTableBuilder.cpp
@@ -10,9 +10,7 @@
#include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h"
#include "llvm/ADT/ArrayRef.h"
-#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
#include "llvm/DebugInfo/PDB/Native/Hash.h"
-#include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h"
#include "llvm/DebugInfo/PDB/Native/RawTypes.h"
#include "llvm/Support/BinaryStreamWriter.h"
#include "llvm/Support/Endian.h"
diff --git a/lib/DebugInfo/PDB/Native/PublicsStream.cpp b/lib/DebugInfo/PDB/Native/PublicsStream.cpp
index 9c3e654f808b..f6466eb80464 100644
--- a/lib/DebugInfo/PDB/Native/PublicsStream.cpp
+++ b/lib/DebugInfo/PDB/Native/PublicsStream.cpp
@@ -23,13 +23,10 @@
//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/PDB/Native/PublicsStream.h"
-#include "GSI.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
-#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
#include "llvm/DebugInfo/PDB/Native/RawError.h"
-#include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
#include "llvm/Support/BinaryStreamReader.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/Error.h"
@@ -41,14 +38,18 @@ using namespace llvm::msf;
using namespace llvm::support;
using namespace llvm::pdb;
-PublicsStream::PublicsStream(PDBFile &File,
- std::unique_ptr<MappedBlockStream> Stream)
- : Pdb(File), Stream(std::move(Stream)) {}
+PublicsStream::PublicsStream(std::unique_ptr<MappedBlockStream> Stream)
+ : Stream(std::move(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
@@ -64,20 +65,14 @@ Error PublicsStream::reload() {
return make_error<RawError>(raw_error_code::corrupt_file,
"Publics Stream does not contain a header.");
- // Read PSGSIHDR and GSIHashHdr structs.
+ // Read PSGSIHDR struct.
if (Reader.readObject(Header))
return make_error<RawError>(raw_error_code::corrupt_file,
"Publics Stream does not contain a header.");
- if (auto EC = readGSIHashHeader(HashHdr, Reader))
- return EC;
-
- if (auto EC = readGSIHashRecords(HashRecords, HashHdr, Reader))
- return EC;
-
- if (auto EC = readGSIHashBuckets(HashBuckets, HashHdr, Reader))
- return EC;
- NumBuckets = HashBuckets.size();
+ // Read the hash table.
+ if (auto E = PublicsTable.read(Reader))
+ return E;
// Something called "address map" follows.
uint32_t NumAddressMapEntries = Header->AddrMap / sizeof(uint32_t);
@@ -105,26 +100,3 @@ Error PublicsStream::reload() {
"Corrupted publics stream.");
return Error::success();
}
-
-iterator_range<codeview::CVSymbolArray::Iterator>
-PublicsStream::getSymbols(bool *HadError) const {
- auto SymbolS = Pdb.getPDBSymbolStream();
- if (SymbolS.takeError()) {
- codeview::CVSymbolArray::Iterator Iter;
- return make_range(Iter, Iter);
- }
- SymbolStream &SS = SymbolS.get();
-
- return SS.getSymbols(HadError);
-}
-
-Expected<const codeview::CVSymbolArray &>
-PublicsStream::getSymbolArray() const {
- auto SymbolS = Pdb.getPDBSymbolStream();
- if (!SymbolS)
- return SymbolS.takeError();
-
- return SymbolS->getSymbolArray();
-}
-
-Error PublicsStream::commit() { return Error::success(); }
diff --git a/lib/DebugInfo/PDB/Native/PublicsStreamBuilder.cpp b/lib/DebugInfo/PDB/Native/PublicsStreamBuilder.cpp
deleted file mode 100644
index 28c4a8fc35d9..000000000000
--- a/lib/DebugInfo/PDB/Native/PublicsStreamBuilder.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-//===- DbiStreamBuilder.cpp - PDB Dbi 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/PublicsStreamBuilder.h"
-
-#include "llvm/DebugInfo/MSF/MSFBuilder.h"
-#include "llvm/DebugInfo/MSF/MSFCommon.h"
-#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
-
-#include "GSI.h"
-
-using namespace llvm;
-using namespace llvm::msf;
-using namespace llvm::pdb;
-
-PublicsStreamBuilder::PublicsStreamBuilder(msf::MSFBuilder &Msf) : Msf(Msf) {}
-
-PublicsStreamBuilder::~PublicsStreamBuilder() {}
-
-uint32_t PublicsStreamBuilder::calculateSerializedLength() const {
- uint32_t Size = 0;
- Size += sizeof(PublicsStreamHeader);
- Size += sizeof(GSIHashHeader);
- Size += HashRecords.size() * sizeof(PSHashRecord);
- 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 PublicsStreamBuilder::finalizeMsfLayout() {
- Expected<uint32_t> Idx = Msf.addStream(calculateSerializedLength());
- if (!Idx)
- return Idx.takeError();
- StreamIdx = *Idx;
-
- Expected<uint32_t> RecordIdx = Msf.addStream(0);
- if (!RecordIdx)
- return RecordIdx.takeError();
- RecordStreamIdx = *RecordIdx;
- return Error::success();
-}
-
-Error PublicsStreamBuilder::commit(BinaryStreamWriter &PublicsWriter) {
- PublicsStreamHeader PSH;
- GSIHashHeader GSH;
-
- // FIXME: Figure out what to put for these values.
- PSH.AddrMap = 0;
- PSH.ISectThunkTable = 0;
- PSH.NumSections = 0;
- PSH.NumThunks = 0;
- PSH.OffThunkTable = 0;
- PSH.SizeOfThunk = 0;
- PSH.SymHash = 0;
-
- GSH.VerSignature = GSIHashHeader::HdrSignature;
- GSH.VerHdr = GSIHashHeader::HdrVersion;
- GSH.HrSize = 0;
- GSH.NumBuckets = 0;
-
- if (auto EC = PublicsWriter.writeObject(PSH))
- return EC;
- if (auto EC = PublicsWriter.writeObject(GSH))
- return EC;
- if (auto EC = PublicsWriter.writeArray(makeArrayRef(HashRecords)))
- return EC;
-
- 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/lib/DebugInfo/PDB/Native/SymbolStream.cpp b/lib/DebugInfo/PDB/Native/SymbolStream.cpp
index 9e9ebd11495b..2d8d04ceca4d 100644
--- a/lib/DebugInfo/PDB/Native/SymbolStream.cpp
+++ b/lib/DebugInfo/PDB/Native/SymbolStream.cpp
@@ -10,11 +10,8 @@
#include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
#include "llvm/DebugInfo/CodeView/CodeView.h"
-#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
-#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
-#include "llvm/DebugInfo/PDB/Native/RawConstants.h"
-#include "llvm/DebugInfo/PDB/Native/RawError.h"
#include "llvm/Support/BinaryStreamReader.h"
#include "llvm/Support/Endian.h"
@@ -43,3 +40,7 @@ SymbolStream::getSymbols(bool *HadError) const {
}
Error SymbolStream::commit() { return Error::success(); }
+
+codeview::CVSymbol SymbolStream::readRecord(uint32_t Offset) const {
+ return *SymbolRecords.at(Offset);
+}
diff --git a/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp b/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp
index 9e943c7f114d..8dd30018028e 100644
--- a/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp
+++ b/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp
@@ -17,7 +17,6 @@
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
#include "llvm/DebugInfo/PDB/Native/RawError.h"
#include "llvm/DebugInfo/PDB/Native/RawTypes.h"
-#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/BinaryByteStream.h"
#include "llvm/Support/BinaryStreamArray.h"