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. llvm-svn: 309066
124 lines
4.4 KiB
C++
124 lines
4.4 KiB
C++
//===- GlobalsStream.cpp - PDB Index of Symbols by Name ---- ----*- C++ -*-===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// 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/RawError.h"
|
|
#include "llvm/Support/BinaryStreamReader.h"
|
|
#include "llvm/Support/Error.h"
|
|
#include <algorithm>
|
|
|
|
using namespace llvm;
|
|
using namespace llvm::msf;
|
|
using namespace llvm::pdb;
|
|
|
|
GlobalsStream::GlobalsStream(std::unique_ptr<MappedBlockStream> Stream)
|
|
: Stream(std::move(Stream)) {}
|
|
|
|
GlobalsStream::~GlobalsStream() = default;
|
|
|
|
Error GlobalsStream::reload() {
|
|
BinaryStreamReader Reader(*Stream);
|
|
if (auto E = GlobalsTable.read(Reader))
|
|
return E;
|
|
return Error::success();
|
|
}
|
|
|
|
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();
|
|
}
|
|
|
|
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();
|
|
}
|