PdbRaw_DbiVer getDbiVersion() const;
uint32_t getAge() const;
+ uint16_t getPublicSymbolStreamIndex() const;
bool isIncrementallyLinked() const;
bool hasCTypes() const;
struct PDBFileContext;
class DbiStream;
class InfoStream;
+class PublicsStream;
class TpiStream;
class PDBFile {
Expected<InfoStream &> getPDBInfoStream();
Expected<DbiStream &> getPDBDbiStream();
Expected<TpiStream &> getPDBTpiStream();
+ Expected<PublicsStream &> getPDBPublicsStream();
private:
std::unique_ptr<PDBFileContext> Context;
std::unique_ptr<InfoStream> Info;
std::unique_ptr<DbiStream> Dbi;
std::unique_ptr<TpiStream> Tpi;
+ std::unique_ptr<PublicsStream> Publics;
};
}
}
--- /dev/null
+//===- PublicsStream.h - PDB Public Symbol Stream -------- ------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_PDB_RAW_PUBLICSSTREAM_H
+#define LLVM_DEBUGINFO_PDB_RAW_PUBLICSSTREAM_H
+
+#include "llvm/DebugInfo/CodeView/TypeStream.h"
+#include "llvm/DebugInfo/PDB/PDBTypes.h"
+#include "llvm/DebugInfo/PDB/Raw/ByteStream.h"
+#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h"
+#include "llvm/DebugInfo/PDB/Raw/RawConstants.h"
+
+#include "llvm/Support/Error.h"
+
+namespace llvm {
+namespace pdb {
+class PDBFile;
+
+class PublicsStream {
+ struct HeaderInfo;
+ struct GSIHashHeader;
+ struct HRFile;
+
+public:
+ PublicsStream(PDBFile &File, uint32_t StreamNum);
+ ~PublicsStream();
+ Error reload();
+
+ uint32_t getStreamNum() const { return StreamNum; }
+ uint32_t getSymHash() const;
+ uint32_t getAddrMap() const;
+ uint32_t getNumBuckets() const { return NumBuckets; }
+
+private:
+ uint32_t StreamNum;
+ MappedBlockStream Stream;
+ uint32_t NumBuckets = 0;
+
+ std::unique_ptr<HeaderInfo> Header;
+ std::unique_ptr<GSIHashHeader> HashHdr;
+};
+}
+}
+
+#endif
Raw/NameHashTable.cpp
Raw/NameMap.cpp
Raw/PDBFile.cpp
+ Raw/PublicsStream.cpp
Raw/RawError.cpp
Raw/RawSession.cpp
Raw/StreamReader.cpp
struct DbiStream::HeaderInfo {
little32_t VersionSignature;
ulittle32_t VersionHeader;
- ulittle32_t Age; // Should match InfoStream.
- ulittle16_t GSSyms; // Number of global symbols
- ulittle16_t BuildNumber; // See DbiBuildNo structure.
- ulittle16_t PSSyms; // Number of public symbols
- ulittle16_t PdbDllVersion; // version of mspdbNNN.dll
- ulittle16_t SymRecords; // Number of symbols
- ulittle16_t PdbDllRbld; // rbld number of mspdbNNN.dll
- little32_t ModiSubstreamSize; // Size of module info stream
- little32_t SecContrSubstreamSize; // Size of sec. contribution stream
- little32_t SectionMapSize; // Size of sec. map substream
- little32_t FileInfoSize; // Size of file info substream
+ ulittle32_t Age; // Should match InfoStream.
+ ulittle16_t GSSyms; // Number of global symbols
+ ulittle16_t BuildNumber; // See DbiBuildNo structure.
+ ulittle16_t PublicSymbolStreamIndex; // Number of public symbols
+ ulittle16_t PdbDllVersion; // version of mspdbNNN.dll
+ ulittle16_t SymRecords; // Number of symbols
+ ulittle16_t PdbDllRbld; // rbld number of mspdbNNN.dll
+ little32_t ModiSubstreamSize; // Size of module info stream
+ little32_t SecContrSubstreamSize; // Size of sec. contribution stream
+ little32_t SectionMapSize; // Size of sec. map substream
+ little32_t FileInfoSize; // Size of file info substream
little32_t TypeServerSize; // Size of type server map
ulittle32_t MFCTypeServerIndex; // Index of MFC Type Server
little32_t OptionalDbgHdrSize; // Size of DbgHeader info
uint32_t DbiStream::getAge() const { return Header->Age; }
+uint16_t DbiStream::getPublicSymbolStreamIndex() const {
+ return Header->PublicSymbolStreamIndex;
+}
+
bool DbiStream::isIncrementallyLinked() const {
return (Header->Flags & FlagIncrementalMask) != 0;
}
#include "llvm/ADT/ArrayRef.h"
#include "llvm/DebugInfo/PDB/Raw/DbiStream.h"
#include "llvm/DebugInfo/PDB/Raw/InfoStream.h"
+#include "llvm/DebugInfo/PDB/Raw/PublicsStream.h"
#include "llvm/DebugInfo/PDB/Raw/RawError.h"
#include "llvm/DebugInfo/PDB/Raw/TpiStream.h"
#include "llvm/Support/Endian.h"
}
return *Tpi;
}
+
+Expected<PublicsStream &> PDBFile::getPDBPublicsStream() {
+ if (!Publics) {
+ auto DbiS = getPDBDbiStream();
+ if (auto EC = DbiS.takeError())
+ return std::move(EC);
+ uint32_t PublicsStreamNum = DbiS->getPublicSymbolStreamIndex();
+
+ Publics.reset(new PublicsStream(*this, PublicsStreamNum));
+ if (auto EC = Publics->reload())
+ return std::move(EC);
+ }
+ return *Publics;
+}
--- /dev/null
+//===- PublicsStream.cpp - PDB Public Symbol Stream -----------------------===//
+//
+// 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.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/PDB/Raw/PublicsStream.h"
+
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h"
+#include "llvm/DebugInfo/PDB/Raw/RawConstants.h"
+#include "llvm/DebugInfo/PDB/Raw/RawError.h"
+#include "llvm/DebugInfo/PDB/Raw/StreamReader.h"
+
+#include "llvm/ADT/BitVector.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/MathExtras.h"
+
+using namespace llvm;
+using namespace llvm::support;
+using namespace llvm::pdb;
+
+
+static const unsigned IPHR_HASH = 4096;
+
+// This is PSGSIHDR struct defined in
+// https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/dbi/gsi.h
+struct PublicsStream::HeaderInfo {
+ ulittle32_t SymHash;
+ ulittle32_t AddrMap;
+ ulittle32_t NumThunks;
+ ulittle32_t SizeOfThunk;
+ ulittle16_t ISectThunkTable;
+ char Padding[2];
+ ulittle32_t OffThunkTable;
+ ulittle32_t NumSects;
+};
+
+
+// This is GSIHashHdr struct defined in
+struct PublicsStream::GSIHashHeader {
+ enum {
+ HdrSignature = -1,
+ HdrVersion = 0xeffe0000 + 19990810,
+ };
+ ulittle32_t VerSignature;
+ ulittle32_t VerHdr;
+ ulittle32_t HrSize;
+ ulittle32_t NumBuckets;
+};
+
+struct PublicsStream::HRFile {
+ ulittle32_t Off;
+ ulittle32_t CRef;
+};
+
+PublicsStream::PublicsStream(PDBFile &File, uint32_t StreamNum)
+ : StreamNum(StreamNum), Stream(StreamNum, File) {}
+
+PublicsStream::~PublicsStream() {}
+
+uint32_t PublicsStream::getSymHash() const { return Header->SymHash; }
+uint32_t PublicsStream::getAddrMap() const { return Header->AddrMap; }
+
+// Publics stream contains fixed-size headers and a serialized hash table.
+// This implementation is not complete yet. It reads till the end of the
+// stream so that we verify the stream is at least not corrupted. However,
+// we skip over the hash table which we believe contains information about
+// public symbols.
+Error PublicsStream::reload() {
+ StreamReader Reader(Stream);
+
+ // Check stream size.
+ if (Reader.bytesRemaining() < sizeof(HeaderInfo) + sizeof(GSIHashHeader))
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Publics Stream does not contain a header.");
+
+ // Read PSGSIHDR and GSIHashHdr structs.
+ Header.reset(new HeaderInfo());
+ if (Reader.readObject(Header.get()))
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Publics Stream does not contain a header.");
+ HashHdr.reset(new GSIHashHeader());
+ if (Reader.readObject(HashHdr.get()))
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Publics Stream does not contain a header.");
+
+ // An array of HRFile follows. Read them.
+ if (HashHdr->HrSize % sizeof(HRFile))
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Invalid HR array size.");
+ std::vector<HRFile> HRs(HashHdr->HrSize / sizeof(HRFile));
+ if (auto EC = Reader.readArray<HRFile>(HRs))
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Could not read an HR array");
+
+ // A bitmap of a fixed length follows.
+ size_t BitmapSizeInBits = alignTo(IPHR_HASH + 1, 32);
+ std::vector<uint8_t> Bitmap(BitmapSizeInBits / 8);
+ if (auto EC = Reader.readArray<uint8_t>(Bitmap))
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Could not read a bitmap.");
+ for (uint8_t B : Bitmap)
+ NumBuckets += countPopulation(B);
+
+ // Buckets follow.
+ if (Reader.bytesRemaining() < NumBuckets * sizeof(uint32_t))
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Hash buckets corrupted.");
+
+ return Error::success();
+}
; RUN: llvm-pdbdump --dump-headers -dump-tpi-records -dump-tpi-record-bytes -dump-module-syms \
-; RUN: %p/Inputs/empty.pdb | FileCheck -check-prefix=EMPTY %s
+; RUN: --dump-publics %p/Inputs/empty.pdb | FileCheck -check-prefix=EMPTY %s
; RUN: llvm-pdbdump --dump-headers %p/Inputs/big-read.pdb | FileCheck -check-prefix=BIG %s
; RUN: llvm-pdbdump --dump-headers %p/Inputs/bad-block-size.pdb | FileCheck -check-prefix=BAD-BLOCK-SIZE %s
; EMPTY-NEXT: )
; EMPTY-NEXT: }
+; EMPTY: Publics Stream {
+; EMPTY-NEXT: Stream number: 7
+; EMPTY-NEXT: SymHash: 556
+; EMPTY-NEXT: AddrMap: 8
+; EMPTY-NEXT: Number of buckets: 2
+; EMPTY-NEXT: }
+
; BIG: FileHeaders {
; BIG-NEXT: BlockSize: 4096
; BIG-NEXT: Unknown0: 2
#include "llvm/DebugInfo/PDB/Raw/ModStream.h"
#include "llvm/DebugInfo/PDB/Raw/NameHashTable.h"
#include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Raw/PublicsStream.h"
#include "llvm/DebugInfo/PDB/Raw/RawError.h"
#include "llvm/DebugInfo/PDB/Raw/RawSession.h"
#include "llvm/DebugInfo/PDB/Raw/StreamReader.h"
cl::opt<bool> DumpModuleSyms("dump-module-syms",
cl::desc("dump module symbols"),
cl::cat(NativeOtions));
+cl::opt<bool> DumpPublics("dump-publics",
+ cl::desc("dump Publics stream data"),
+ cl::cat(NativeOtions));
cl::list<std::string>
ExcludeTypes("exclude-types",
return Error::success();
}
+static Error dumpPublicsStream(ScopedPrinter &P, PDBFile &File) {
+ if (!opts::DumpPublics)
+ return Error::success();
+
+ DictScope D(P, "Publics Stream");
+ auto PublicsS = File.getPDBPublicsStream();
+ if (auto EC = PublicsS.takeError())
+ return EC;
+ PublicsStream &Publics = PublicsS.get();
+ P.printNumber("Stream number", Publics.getStreamNum());
+ P.printNumber("SymHash", Publics.getSymHash());
+ P.printNumber("AddrMap", Publics.getAddrMap());
+ P.printNumber("Number of buckets", Publics.getNumBuckets());
+ return Error::success();
+}
+
static Error dumpStructure(RawSession &RS) {
PDBFile &File = RS.getPDBFile();
ScopedPrinter P(outs());
if (auto EC = dumpTpiStream(P, File))
return EC;
- return Error::success();
+
+ if (auto EC = dumpPublicsStream(P, File))
+ return EC;
+return Error::success();
}
static void dumpInput(StringRef Path) {
extern llvm::cl::list<std::string> IncludeCompilands;
}
-#endif
\ No newline at end of file
+#endif