1
0
mirror of https://github.com/RPCS3/llvm.git synced 2025-04-07 15:52:21 +00:00

[PDB] Improve GSI hash table dumping for publics and globals

The PDB "symbol stream" actually contains symbol records for the publics
and the globals stream. The globals and publics streams are essentially
hash tables that point into a single stream of records. In order to
match cvdump's behavior, we need to only dump symbol records referenced
from the hash table. This patch implements that, and then implements
global stream dumping, since it's just a subset of public stream
dumping.

Now we shouldn't see S_PROCREF or S_GDATA32 records when dumping
publics, and instead we should see those record in the globals stream.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@309066 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Reid Kleckner 2017-07-26 00:40:36 +00:00
parent ec76cbbaaa
commit 4a753bdddf
18 changed files with 289 additions and 250 deletions

@ -61,30 +61,38 @@ template <typename Kind> struct RemappedRecord {
SmallVector<std::pair<uint32_t, TypeIndex>, 8> Mappings; SmallVector<std::pair<uint32_t, TypeIndex>, 8> Mappings;
}; };
} // end namespace codeview /// Read a complete record from a stream at a random offset.
template <typename Kind> template <typename Kind>
struct VarStreamArrayExtractor<codeview::CVRecord<Kind>> { inline Expected<CVRecord<Kind>> readCVRecordFromStream(BinaryStreamRef Stream,
Error operator()(BinaryStreamRef Stream, uint32_t &Len, uint32_t Offset) {
codeview::CVRecord<Kind> &Item) {
using namespace codeview;
const RecordPrefix *Prefix = nullptr; const RecordPrefix *Prefix = nullptr;
BinaryStreamReader Reader(Stream); BinaryStreamReader Reader(Stream);
uint32_t Offset = Reader.getOffset(); Reader.setOffset(Offset);
if (auto EC = Reader.readObject(Prefix)) if (auto EC = Reader.readObject(Prefix))
return EC; return std::move(EC);
if (Prefix->RecordLen < 2) if (Prefix->RecordLen < 2)
return make_error<CodeViewError>(cv_error_code::corrupt_record); return make_error<CodeViewError>(cv_error_code::corrupt_record);
Kind K = static_cast<Kind>(uint16_t(Prefix->RecordKind)); Kind K = static_cast<Kind>(uint16_t(Prefix->RecordKind));
Reader.setOffset(Offset); Reader.setOffset(Offset);
ArrayRef<uint8_t> RawData; ArrayRef<uint8_t> RawData;
if (auto EC = if (auto EC = Reader.readBytes(RawData, Prefix->RecordLen + sizeof(uint16_t)))
Reader.readBytes(RawData, Prefix->RecordLen + sizeof(uint16_t))) return std::move(EC);
return EC; return codeview::CVRecord<Kind>(K, RawData);
Item = codeview::CVRecord<Kind>(K, RawData); }
Len = Item.length();
} // end namespace codeview
template <typename Kind>
struct VarStreamArrayExtractor<codeview::CVRecord<Kind>> {
Error operator()(BinaryStreamRef Stream, uint32_t &Len,
codeview::CVRecord<Kind> &Item) {
auto ExpectedRec = codeview::readCVRecordFromStream<Kind>(Stream, 0);
if (!ExpectedRec)
return ExpectedRec.takeError();
Item = *ExpectedRec;
Len = ExpectedRec->length();
return Error::success(); return Error::success();
} }
}; };

@ -945,6 +945,9 @@ public:
using CVSymbol = CVRecord<SymbolKind>; using CVSymbol = CVRecord<SymbolKind>;
using CVSymbolArray = VarStreamArray<CVSymbol>; using CVSymbolArray = VarStreamArray<CVSymbol>;
Expected<CVSymbol> readSymbolFromStream(BinaryStreamRef Stream,
uint32_t Offset);
} // end namespace codeview } // end namespace codeview
} // end namespace llvm } // end namespace llvm

@ -16,28 +16,61 @@
#include "llvm/DebugInfo/PDB/PDBTypes.h" #include "llvm/DebugInfo/PDB/PDBTypes.h"
#include "llvm/Support/BinaryStreamArray.h" #include "llvm/Support/BinaryStreamArray.h"
#include "llvm/Support/Error.h" #include "llvm/Support/Error.h"
#include "llvm/ADT/iterator.h"
namespace llvm { namespace llvm {
namespace pdb { namespace pdb {
class DbiStream; class DbiStream;
class PDBFile; class PDBFile;
/// Iterator over hash records producing symbol record offsets. Abstracts away
/// the fact that symbol record offsets on disk are off-by-one.
class GSIHashIterator
: public iterator_adaptor_base<
GSIHashIterator, FixedStreamArrayIterator<PSHashRecord>,
std::random_access_iterator_tag, const uint32_t> {
public:
GSIHashIterator() = default;
template <typename T>
GSIHashIterator(T &&v)
: GSIHashIterator::iterator_adaptor_base(std::forward<T &&>(v)) {}
uint32_t operator*() const {
uint32_t Off = this->I->Off;
return --Off;
}
};
/// From https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/dbi/gsi.cpp
enum : unsigned { IPHR_HASH = 4096 };
/// A readonly view of a hash table used in the globals and publics streams.
/// Most clients will only want to iterate this to get symbol record offsets
/// into the PDB symbol stream.
class GSIHashTable {
public:
const GSIHashHeader *HashHdr;
FixedStreamArray<PSHashRecord> HashRecords;
ArrayRef<uint8_t> HashBitmap;
FixedStreamArray<support::ulittle32_t> HashBuckets;
Error read(BinaryStreamReader &Reader);
typedef GSIHashHeader iterator;
GSIHashIterator begin() const { return GSIHashIterator(HashRecords.begin()); }
GSIHashIterator end() const { return GSIHashIterator(HashRecords.end()); }
};
class GlobalsStream { class GlobalsStream {
public: public:
explicit GlobalsStream(std::unique_ptr<msf::MappedBlockStream> Stream); explicit GlobalsStream(std::unique_ptr<msf::MappedBlockStream> Stream);
~GlobalsStream(); ~GlobalsStream();
Error commit(); const GSIHashTable &getGlobalsTable() const { return GlobalsTable; }
FixedStreamArray<support::ulittle32_t> getHashBuckets() const {
return HashBuckets;
}
uint32_t getNumBuckets() const { return NumBuckets; }
Error reload(); Error reload();
private: private:
FixedStreamArray<PSHashRecord> HashRecords; GSIHashTable GlobalsTable;
ArrayRef<uint8_t> HashBitmap;
FixedStreamArray<support::ulittle32_t> HashBuckets;
uint32_t NumBuckets;
std::unique_ptr<msf::MappedBlockStream> Stream; std::unique_ptr<msf::MappedBlockStream> Stream;
}; };
} }

@ -12,6 +12,7 @@
#include "llvm/DebugInfo/CodeView/SymbolRecord.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h"
#include "llvm/DebugInfo/MSF/MappedBlockStream.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
#include "llvm/DebugInfo/PDB/Native/RawConstants.h" #include "llvm/DebugInfo/PDB/Native/RawConstants.h"
#include "llvm/DebugInfo/PDB/Native/RawTypes.h" #include "llvm/DebugInfo/PDB/Native/RawTypes.h"
#include "llvm/DebugInfo/PDB/PDBTypes.h" #include "llvm/DebugInfo/PDB/PDBTypes.h"
@ -26,21 +27,13 @@ class PDBFile;
class PublicsStream { class PublicsStream {
public: public:
PublicsStream(PDBFile &File, std::unique_ptr<msf::MappedBlockStream> Stream); PublicsStream(std::unique_ptr<msf::MappedBlockStream> Stream);
~PublicsStream(); ~PublicsStream();
Error reload(); Error reload();
uint32_t getSymHash() const; uint32_t getSymHash() const;
uint32_t getAddrMap() const; uint32_t getAddrMap() const;
uint32_t getNumBuckets() const { return NumBuckets; } const GSIHashTable &getPublicsTable() const { return PublicsTable; }
Expected<const codeview::CVSymbolArray &> getSymbolArray() const;
iterator_range<codeview::CVSymbolArray::Iterator>
getSymbols(bool *HadError) const;
FixedStreamArray<PSHashRecord> getHashRecords() const { return HashRecords; }
ArrayRef<uint8_t> getHashBitmap() const { return HashBitmap; }
FixedStreamArray<support::ulittle32_t> getHashBuckets() const {
return HashBuckets;
}
FixedStreamArray<support::ulittle32_t> getAddressMap() const { FixedStreamArray<support::ulittle32_t> getAddressMap() const {
return AddressMap; return AddressMap;
} }
@ -51,22 +44,14 @@ public:
return SectionOffsets; return SectionOffsets;
} }
Error commit();
private: private:
PDBFile &Pdb;
std::unique_ptr<msf::MappedBlockStream> Stream; std::unique_ptr<msf::MappedBlockStream> Stream;
uint32_t NumBuckets = 0; GSIHashTable PublicsTable;
FixedStreamArray<PSHashRecord> HashRecords;
ArrayRef<uint8_t> HashBitmap;
FixedStreamArray<support::ulittle32_t> HashBuckets;
FixedStreamArray<support::ulittle32_t> AddressMap; FixedStreamArray<support::ulittle32_t> AddressMap;
FixedStreamArray<support::ulittle32_t> ThunkMap; FixedStreamArray<support::ulittle32_t> ThunkMap;
FixedStreamArray<SectionOffset> SectionOffsets; FixedStreamArray<SectionOffset> SectionOffsets;
const PublicsStreamHeader *Header; const PublicsStreamHeader *Header;
const GSIHashHeader *HashHdr;
}; };
} }
} }

@ -23,6 +23,20 @@ struct SectionOffset {
char Padding[2]; char Padding[2];
}; };
/// Header of the hash tables found in the globals and publics sections.
/// Based on GSIHashHdr 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;
};
// This is HRFile. // This is HRFile.
struct PSHashRecord { struct PSHashRecord {
support::ulittle32_t Off; // Offset in the symbol record stream support::ulittle32_t Off; // Offset in the symbol record stream

@ -15,6 +15,7 @@
#include "llvm/ADT/APInt.h" #include "llvm/ADT/APInt.h"
#include "llvm/ADT/APSInt.h" #include "llvm/ADT/APSInt.h"
#include "llvm/DebugInfo/CodeView/CodeViewError.h" #include "llvm/DebugInfo/CodeView/CodeViewError.h"
#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
#include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h"
#include "llvm/Support/BinaryByteStream.h" #include "llvm/Support/BinaryByteStream.h"
@ -147,3 +148,8 @@ Error llvm::codeview::consume(BinaryStreamReader &Reader, StringRef &Item) {
return Reader.readCString(Item); return Reader.readCString(Item);
} }
Expected<CVSymbol> llvm::codeview::readSymbolFromStream(BinaryStreamRef Stream,
uint32_t Offset) {
return readCVRecordFromStream<SymbolKind>(Stream, Offset);
}

@ -35,7 +35,6 @@ add_pdb_impl_folder(Native
Native/DbiStreamBuilder.cpp Native/DbiStreamBuilder.cpp
Native/EnumTables.cpp Native/EnumTables.cpp
Native/GlobalsStream.cpp Native/GlobalsStream.cpp
Native/GSI.cpp
Native/Hash.cpp Native/Hash.cpp
Native/HashTable.cpp Native/HashTable.cpp
Native/InfoStream.cpp Native/InfoStream.cpp

@ -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,
ArrayRef<uint8_t> &HashBitmap,
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.
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 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();
}
}
}

@ -37,23 +37,6 @@ class BinaryStreamReader;
namespace pdb { 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 GSIHashHdr 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, Error readGSIHashBuckets(FixedStreamArray<support::ulittle32_t> &HashBuckets,
ArrayRef<uint8_t> &HashBitmap, ArrayRef<uint8_t> &HashBitmap,
const GSIHashHeader *HashHdr, const GSIHashHeader *HashHdr,

@ -6,9 +6,21 @@
// License. See LICENSE.TXT for details. // 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 "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
#include "GSI.h" #include "llvm/DebugInfo/PDB/Native/RawError.h"
#include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/BinaryStreamReader.h"
#include "llvm/Support/Error.h" #include "llvm/Support/Error.h"
#include <algorithm> #include <algorithm>
@ -24,19 +36,88 @@ GlobalsStream::~GlobalsStream() = default;
Error GlobalsStream::reload() { Error GlobalsStream::reload() {
BinaryStreamReader Reader(*Stream); BinaryStreamReader Reader(*Stream);
if (auto E = GlobalsTable.read(Reader))
return E;
return Error::success();
}
const GSIHashHeader *HashHdr; static Error checkHashHdrVersion(const GSIHashHeader *HashHdr) {
if (auto EC = readGSIHashHeader(HashHdr, Reader)) if (HashHdr->VerHdr != GSIHashHeader::HdrVersion)
return EC; return make_error<RawError>(
raw_error_code::feature_unsupported,
if (auto EC = readGSIHashRecords(HashRecords, HashHdr, Reader)) "Encountered unsupported globals stream version.");
return EC;
if (auto EC = readGSIHashBuckets(HashBuckets, HashBitmap, HashHdr, Reader))
return EC;
NumBuckets = HashBuckets.size();
return Error::success(); return Error::success();
} }
Error GlobalsStream::commit() { 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;
// 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;
// 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 GSIHashTable::read(BinaryStreamReader &Reader) {
if (auto EC = readGSIHashHeader(HashHdr, Reader))
return EC;
if (auto EC = readGSIHashRecords(HashRecords, HashHdr, Reader))
return EC;
if (auto EC = readGSIHashBuckets(HashBuckets, HashBitmap, HashHdr, Reader))
return EC;
return Error::success();
}

@ -318,8 +318,7 @@ Expected<PublicsStream &> PDBFile::getPDBPublicsStream() {
ContainerLayout, *Buffer, DbiS->getPublicSymbolStreamIndex()); ContainerLayout, *Buffer, DbiS->getPublicSymbolStreamIndex());
if (!PublicS) if (!PublicS)
return PublicS.takeError(); return PublicS.takeError();
auto TempPublics = auto TempPublics = llvm::make_unique<PublicsStream>(std::move(*PublicS));
llvm::make_unique<PublicsStream>(*this, std::move(*PublicS));
if (auto EC = TempPublics->reload()) if (auto EC = TempPublics->reload())
return std::move(EC); return std::move(EC);
Publics = std::move(TempPublics); Publics = std::move(TempPublics);

@ -41,9 +41,8 @@ using namespace llvm::msf;
using namespace llvm::support; using namespace llvm::support;
using namespace llvm::pdb; using namespace llvm::pdb;
PublicsStream::PublicsStream(PDBFile &File, PublicsStream::PublicsStream(std::unique_ptr<MappedBlockStream> Stream)
std::unique_ptr<MappedBlockStream> Stream) : Stream(std::move(Stream)) {}
: Pdb(File), Stream(std::move(Stream)) {}
PublicsStream::~PublicsStream() = default; PublicsStream::~PublicsStream() = default;
@ -64,20 +63,14 @@ Error PublicsStream::reload() {
return make_error<RawError>(raw_error_code::corrupt_file, return make_error<RawError>(raw_error_code::corrupt_file,
"Publics Stream does not contain a header."); "Publics Stream does not contain a header.");
// Read PSGSIHDR and GSIHashHdr structs. // Read PSGSIHDR struct.
if (Reader.readObject(Header)) if (Reader.readObject(Header))
return make_error<RawError>(raw_error_code::corrupt_file, return make_error<RawError>(raw_error_code::corrupt_file,
"Publics Stream does not contain a header."); "Publics Stream does not contain a header.");
if (auto EC = readGSIHashHeader(HashHdr, Reader)) // Read the hash table.
return EC; if (auto E = PublicsTable.read(Reader))
return E;
if (auto EC = readGSIHashRecords(HashRecords, HashHdr, Reader))
return EC;
if (auto EC = readGSIHashBuckets(HashBuckets, HashBitmap, HashHdr, Reader))
return EC;
NumBuckets = HashBuckets.size();
// Something called "address map" follows. // Something called "address map" follows.
uint32_t NumAddressMapEntries = Header->AddrMap / sizeof(uint32_t); uint32_t NumAddressMapEntries = Header->AddrMap / sizeof(uint32_t);
@ -105,26 +98,3 @@ Error PublicsStream::reload() {
"Corrupted publics stream."); "Corrupted publics stream.");
return Error::success(); 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(); }

@ -8,10 +8,10 @@
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/PDB/Native/PublicsStreamBuilder.h" #include "llvm/DebugInfo/PDB/Native/PublicsStreamBuilder.h"
#include "llvm/DebugInfo/MSF/MSFBuilder.h" #include "llvm/DebugInfo/MSF/MSFBuilder.h"
#include "llvm/DebugInfo/MSF/MSFCommon.h" #include "llvm/DebugInfo/MSF/MSFCommon.h"
#include "llvm/DebugInfo/MSF/MappedBlockStream.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
#include "GSI.h" #include "GSI.h"

@ -452,16 +452,20 @@ ALL-NEXT: 0x100D: ` Kits\8.1\include\um" -I"C:\Program Files (x86)\Wi
ALL: Type Index Offsets: ALL: Type Index Offsets:
ALL-NEXT: TI: 0x1000, Offset: 0 ALL-NEXT: TI: 0x1000, Offset: 0
ALL: Hash Adjusters: ALL: Hash Adjusters:
ALL: Global Symbols
ALL-NEXT: ============================================================
ALL-NEXT: 56 | S_PROCREF [size = 20] `main`
ALL-NEXT: module = 1, sum name = 0, offset = 120
ALL-NEXT: 76 | S_GDATA32 [size = 28] `__purecall`
ALL-NEXT: type = 0x0403 (void*), addr = 0003:0000
ALL-NOT: S_PUB32
ALL: Public Symbols ALL: Public Symbols
ALL-NEXT: ============================================================ ALL-NEXT: ============================================================
ALL-NEXT: 0 | S_PUB32 [size = 36] `?__purecall@@3PAXA` ALL-NEXT: 0 | S_PUB32 [size = 36] `?__purecall@@3PAXA`
ALL-NEXT: flags = none, addr = 0003:0000 ALL-NEXT: flags = none, addr = 0003:0000
ALL-NEXT: 36 | S_PUB32 [size = 20] `_main` ALL-NEXT: 36 | S_PUB32 [size = 20] `_main`
ALL-NEXT: flags = function, addr = 0001:0016 ALL-NEXT: flags = function, addr = 0001:0016
ALL-NEXT: 56 | S_PROCREF [size = 20] `main` ALL-NOT: S_PROCREF
ALL-NEXT: module = 1, sum name = 0, offset = 120
ALL-NEXT: 76 | S_GDATA32 [size = 28] `__purecall`
ALL-NEXT: type = 0x0403 (void*), addr = 0003:0000
ALL: Symbols ALL: Symbols
ALL-NEXT: ============================================================ ALL-NEXT: ============================================================
ALL-NEXT: Mod 0000 | `d:\src\llvm\test\DebugInfo\PDB\Inputs\empty.obj`: ALL-NEXT: Mod 0000 | `d:\src\llvm\test\DebugInfo\PDB\Inputs\empty.obj`:

@ -49,6 +49,7 @@
#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h" #include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"
#include "llvm/DebugInfo/PDB/Native/PDBFile.h" #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
#include "llvm/DebugInfo/PDB/Native/PublicsStream.h" #include "llvm/DebugInfo/PDB/Native/PublicsStream.h"
#include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
#include "llvm/DebugInfo/PDB/Native/RawError.h" #include "llvm/DebugInfo/PDB/Native/RawError.h"
#include "llvm/DebugInfo/PDB/Native/TpiHashing.h" #include "llvm/DebugInfo/PDB/Native/TpiHashing.h"
#include "llvm/DebugInfo/PDB/Native/TpiStream.h" #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
@ -129,6 +130,11 @@ Error DumpOutputStyle::dump() {
return EC; return EC;
} }
if (opts::dump::DumpGlobals) {
if (auto EC = dumpGlobals())
return EC;
}
if (opts::dump::DumpPublics) { if (opts::dump::DumpPublics) {
if (auto EC = dumpPublics()) if (auto EC = dumpPublics())
return EC; return EC;
@ -851,58 +857,38 @@ Error DumpOutputStyle::dumpModuleSyms() {
return Error::success(); return Error::success();
} }
Error DumpOutputStyle::dumpGlobals() {
printHeader(P, "Global Symbols");
AutoIndent Indent(P);
if (!File.hasPDBGlobalsStream()) {
P.formatLine("Globals stream not present");
return Error::success();
}
ExitOnError Err("Error dumping globals stream");
auto &Globals = Err(File.getPDBGlobalsStream());
const GSIHashTable &Table = Globals.getGlobalsTable();
Err(dumpSymbolsFromGSI(Table, opts::dump::DumpGlobalExtras));
return Error::success();
}
Error DumpOutputStyle::dumpPublics() { Error DumpOutputStyle::dumpPublics() {
printHeader(P, "Public Symbols"); printHeader(P, "Public Symbols");
AutoIndent Indent(P); AutoIndent Indent(P);
if (!File.hasPDBPublicsStream()) { if (!File.hasPDBPublicsStream()) {
P.formatLine("Publics stream not present"); P.formatLine("Publics stream not present");
return Error::success(); return Error::success();
} }
ExitOnError Err("Error dumping publics stream"); ExitOnError Err("Error dumping publics stream");
auto &Types = Err(initializeTypes(StreamTPI));
auto &Publics = Err(File.getPDBPublicsStream()); auto &Publics = Err(File.getPDBPublicsStream());
SymbolVisitorCallbackPipeline Pipeline;
SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb);
MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Types);
Pipeline.addCallbackToPipeline(Deserializer); const GSIHashTable &PublicsTable = Publics.getPublicsTable();
Pipeline.addCallbackToPipeline(Dumper); Err(dumpSymbolsFromGSI(PublicsTable, opts::dump::DumpPublicExtras));
CVSymbolVisitor Visitor(Pipeline);
auto ExpectedSymbols = Publics.getSymbolArray(); // Skip the rest if we aren't dumping extras.
if (!ExpectedSymbols) {
P.formatLine("Could not read public symbol record stream");
return Error::success();
}
if (auto EC = Visitor.visitSymbolStream(*ExpectedSymbols, 0))
P.formatLine("Error while processing public symbol records. {0}",
toString(std::move(EC)));
// Return early if we aren't dumping public hash table and address map info.
if (!opts::dump::DumpPublicExtras) if (!opts::dump::DumpPublicExtras)
return Error::success(); return Error::success();
P.formatLine("Hash Records");
{
AutoIndent Indent2(P);
for (const PSHashRecord &HR : Publics.getHashRecords())
P.formatLine("off = {0}, refcnt = {1}", uint32_t(HR.Off),
uint32_t(HR.CRef));
}
// FIXME: Dump the bitmap.
P.formatLine("Hash Buckets");
{
AutoIndent Indent2(P);
for (uint32_t Hash : Publics.getHashBuckets())
P.formatLine("{0:x8}", Hash);
}
P.formatLine("Address Map"); P.formatLine("Address Map");
{ {
// These are offsets into the publics stream sorted by secidx:secrel. // These are offsets into the publics stream sorted by secidx:secrel.
@ -931,6 +917,56 @@ Error DumpOutputStyle::dumpPublics() {
return Error::success(); return Error::success();
} }
Error DumpOutputStyle::dumpSymbolsFromGSI(const GSIHashTable &Table,
bool HashExtras) {
auto ExpectedSyms = File.getPDBSymbolStream();
if (!ExpectedSyms)
return ExpectedSyms.takeError();
auto ExpectedTypes = initializeTypes(StreamTPI);
if (!ExpectedTypes)
return ExpectedTypes.takeError();
SymbolVisitorCallbackPipeline Pipeline;
SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb);
MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, *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");
{
AutoIndent Indent2(P);
for (const PSHashRecord &HR : Table.HashRecords)
P.formatLine("off = {0}, refcnt = {1}", uint32_t(HR.Off),
uint32_t(HR.CRef));
}
// FIXME: Dump the bitmap.
P.formatLine("Hash Buckets");
{
AutoIndent Indent2(P);
for (uint32_t Hash : Table.HashBuckets)
P.formatLine("{0:x8}", Hash);
}
return Error::success();
}
static std::string formatSectionCharacteristics(uint32_t IndentLevel, static std::string formatSectionCharacteristics(uint32_t IndentLevel,
uint32_t C) { uint32_t C) {
using SC = COFF::SectionCharacteristics; using SC = COFF::SectionCharacteristics;

@ -26,6 +26,8 @@ class LazyRandomTypeCollection;
} }
namespace pdb { namespace pdb {
class GSIHashTable;
class DumpOutputStyle : public OutputStyle { class DumpOutputStyle : public OutputStyle {
public: public:
DumpOutputStyle(PDBFile &File); DumpOutputStyle(PDBFile &File);
@ -46,7 +48,9 @@ private:
Error dumpModules(); Error dumpModules();
Error dumpModuleFiles(); Error dumpModuleFiles();
Error dumpModuleSyms(); Error dumpModuleSyms();
Error dumpGlobals();
Error dumpPublics(); Error dumpPublics();
Error dumpSymbolsFromGSI(const GSIHashTable &Table, bool HashExtras);
Error dumpSectionContribs(); Error dumpSectionContribs();
Error dumpSectionMap(); Error dumpSectionMap();

@ -450,6 +450,10 @@ cl::opt<bool> DumpTypeDependents(
cl::cat(TypeOptions), cl::sub(DumpSubcommand)); cl::cat(TypeOptions), cl::sub(DumpSubcommand));
// SYMBOL OPTIONS // SYMBOL OPTIONS
cl::opt<bool> DumpGlobals("globals", cl::desc("dump Globals symbol records"),
cl::cat(SymbolOptions), cl::sub(DumpSubcommand));
cl::opt<bool> DumpGlobalExtras("global-extras", cl::desc("dump Globals hashes"),
cl::cat(SymbolOptions), cl::sub(DumpSubcommand));
cl::opt<bool> DumpPublics("publics", cl::desc("dump Publics stream data"), cl::opt<bool> DumpPublics("publics", cl::desc("dump Publics stream data"),
cl::cat(SymbolOptions), cl::sub(DumpSubcommand)); cl::cat(SymbolOptions), cl::sub(DumpSubcommand));
cl::opt<bool> DumpPublicExtras("public-extras", cl::opt<bool> DumpPublicExtras("public-extras",
@ -1066,6 +1070,7 @@ int main(int argc_, const char *argv_[]) {
opts::dump::DumpXme = true; opts::dump::DumpXme = true;
opts::dump::DumpXmi = true; opts::dump::DumpXmi = true;
opts::dump::DumpIds = true; opts::dump::DumpIds = true;
opts::dump::DumpGlobals = true;
opts::dump::DumpPublics = true; opts::dump::DumpPublics = true;
opts::dump::DumpSectionContribs = true; opts::dump::DumpSectionContribs = true;
opts::dump::DumpSectionMap = true; opts::dump::DumpSectionMap = true;

@ -143,6 +143,8 @@ extern llvm::cl::opt<bool> DumpIdExtras;
extern llvm::cl::list<uint32_t> DumpIdIndex; extern llvm::cl::list<uint32_t> DumpIdIndex;
extern llvm::cl::opt<bool> DumpSymbols; extern llvm::cl::opt<bool> DumpSymbols;
extern llvm::cl::opt<bool> DumpSymRecordBytes; extern llvm::cl::opt<bool> DumpSymRecordBytes;
extern llvm::cl::opt<bool> DumpGlobals;
extern llvm::cl::opt<bool> DumpGlobalExtras;
extern llvm::cl::opt<bool> DumpPublics; extern llvm::cl::opt<bool> DumpPublics;
extern llvm::cl::opt<bool> DumpPublicExtras; extern llvm::cl::opt<bool> DumpPublicExtras;
extern llvm::cl::opt<bool> DumpSectionContribs; extern llvm::cl::opt<bool> DumpSectionContribs;