mirror of
https://github.com/RPCS3/llvm.git
synced 2025-05-23 22:06:19 +00:00

When investigating bugs in PDB generation, the first step is often to do the same link with link.exe and then compare PDBs. But comparing PDBs is hard because two completely different byte sequences can both be correct, so it hampers the investigation when you also have to spend time figuring out not just which bytes are different, but also if the difference is meaningful. This patch fixes a couple of cases related to string table emission, hash table emission, and the order in which we emit strings that makes more of our bytes the same as the bytes generated by MS PDBs. Differential Revision: https://reviews.llvm.org/D44810 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@328348 91177308-0d34-0410-b5e6-96231b3b80d8
128 lines
4.1 KiB
C++
128 lines
4.1 KiB
C++
//===- NamedStreamMap.cpp - PDB Named Stream Map --------------------------===//
|
|
//
|
|
// 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/NamedStreamMap.h"
|
|
#include "llvm/ADT/StringMap.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "llvm/ADT/iterator_range.h"
|
|
#include "llvm/DebugInfo/PDB/Native/Hash.h"
|
|
#include "llvm/DebugInfo/PDB/Native/HashTable.h"
|
|
#include "llvm/DebugInfo/PDB/Native/RawError.h"
|
|
#include "llvm/Support/BinaryStreamReader.h"
|
|
#include "llvm/Support/BinaryStreamRef.h"
|
|
#include "llvm/Support/BinaryStreamWriter.h"
|
|
#include "llvm/Support/Endian.h"
|
|
#include "llvm/Support/Error.h"
|
|
#include <algorithm>
|
|
#include <cassert>
|
|
#include <cstdint>
|
|
#include <tuple>
|
|
|
|
using namespace llvm;
|
|
using namespace llvm::pdb;
|
|
|
|
NamedStreamMapTraits::NamedStreamMapTraits(NamedStreamMap &NS) : NS(&NS) {}
|
|
|
|
uint16_t NamedStreamMapTraits::hashLookupKey(StringRef S) const {
|
|
// In the reference implementation, this uses
|
|
// HASH Hasher<ULONG*, USHORT*>::hashPbCb(PB pb, size_t cb, ULONG ulMod).
|
|
// Here, the type HASH is a typedef of unsigned short.
|
|
// ** It is not a bug that we truncate the result of hashStringV1, in fact
|
|
// it is a bug if we do not! **
|
|
return static_cast<uint16_t>(hashStringV1(S));
|
|
}
|
|
|
|
StringRef NamedStreamMapTraits::storageKeyToLookupKey(uint32_t Offset) const {
|
|
return NS->getString(Offset);
|
|
}
|
|
|
|
uint32_t NamedStreamMapTraits::lookupKeyToStorageKey(StringRef S) {
|
|
return NS->appendStringData(S);
|
|
}
|
|
|
|
NamedStreamMap::NamedStreamMap()
|
|
: HashTraits(*this), OffsetIndexMap(1, HashTraits) {}
|
|
|
|
Error NamedStreamMap::load(BinaryStreamReader &Stream) {
|
|
uint32_t StringBufferSize;
|
|
if (auto EC = Stream.readInteger(StringBufferSize))
|
|
return joinErrors(std::move(EC),
|
|
make_error<RawError>(raw_error_code::corrupt_file,
|
|
"Expected string buffer size"));
|
|
|
|
StringRef Buffer;
|
|
if (auto EC = Stream.readFixedString(Buffer, StringBufferSize))
|
|
return EC;
|
|
NamesBuffer.assign(Buffer.begin(), Buffer.end());
|
|
|
|
return OffsetIndexMap.load(Stream);
|
|
}
|
|
|
|
Error NamedStreamMap::commit(BinaryStreamWriter &Writer) const {
|
|
// The first field is the number of bytes of string data.
|
|
if (auto EC = Writer.writeInteger<uint32_t>(NamesBuffer.size()))
|
|
return EC;
|
|
|
|
// Then the actual string data.
|
|
StringRef Data(NamesBuffer.data(), NamesBuffer.size());
|
|
if (auto EC = Writer.writeFixedString(Data))
|
|
return EC;
|
|
|
|
// And finally the Offset Index map.
|
|
if (auto EC = OffsetIndexMap.commit(Writer))
|
|
return EC;
|
|
|
|
return Error::success();
|
|
}
|
|
|
|
uint32_t NamedStreamMap::calculateSerializedLength() const {
|
|
return sizeof(uint32_t) // String data size
|
|
+ NamesBuffer.size() // String data
|
|
+ OffsetIndexMap.calculateSerializedLength(); // Offset Index Map
|
|
}
|
|
|
|
uint32_t NamedStreamMap::size() const { return OffsetIndexMap.size(); }
|
|
|
|
StringRef NamedStreamMap::getString(uint32_t Offset) const {
|
|
assert(NamesBuffer.size() > Offset);
|
|
return StringRef(NamesBuffer.data() + Offset);
|
|
}
|
|
|
|
uint32_t NamedStreamMap::hashString(uint32_t Offset) const {
|
|
return hashStringV1(getString(Offset));
|
|
}
|
|
|
|
bool NamedStreamMap::get(StringRef Stream, uint32_t &StreamNo) const {
|
|
auto Iter = OffsetIndexMap.find_as(Stream);
|
|
if (Iter == OffsetIndexMap.end())
|
|
return false;
|
|
StreamNo = (*Iter).second;
|
|
return true;
|
|
}
|
|
|
|
StringMap<uint32_t> NamedStreamMap::entries() const {
|
|
StringMap<uint32_t> Result;
|
|
for (const auto &Entry : OffsetIndexMap) {
|
|
StringRef Stream(NamesBuffer.data() + Entry.first);
|
|
Result.try_emplace(Stream, Entry.second);
|
|
}
|
|
return Result;
|
|
}
|
|
|
|
uint32_t NamedStreamMap::appendStringData(StringRef S) {
|
|
uint32_t Offset = NamesBuffer.size();
|
|
NamesBuffer.insert(NamesBuffer.end(), S.begin(), S.end());
|
|
NamesBuffer.push_back('\0');
|
|
return Offset;
|
|
}
|
|
|
|
void NamedStreamMap::set(StringRef Stream, uint32_t StreamNo) {
|
|
OffsetIndexMap.set_as(Stream, support::ulittle32_t(StreamNo));
|
|
}
|