llvm-project/llvm/lib/DebugInfo/PDB/Native/NamedStreamMap.cpp

136 lines
4.1 KiB
C++

//===- NamedStreamMap.cpp - PDB Named Stream Map ----------------*- 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/NamedStreamMap.h"
#include "llvm/ADT/SparseBitVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/DebugInfo/PDB/Native/HashTable.h"
#include "llvm/DebugInfo/PDB/Native/RawError.h"
#include "llvm/Support/BinaryStreamReader.h"
#include "llvm/Support/Error.h"
#include <algorithm>
#include <cstdint>
using namespace llvm;
using namespace llvm::pdb;
NamedStreamMap::NamedStreamMap() = default;
Error NamedStreamMap::load(BinaryStreamReader &Stream) {
Mapping.clear();
FinalizedHashTable.clear();
FinalizedInfo.reset();
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"));
BinaryStreamRef StringsBuffer;
if (auto EC = Stream.readStreamRef(StringsBuffer, StringBufferSize))
return EC;
HashTable OffsetIndexMap;
if (auto EC = OffsetIndexMap.load(Stream))
return EC;
uint32_t NameOffset;
uint32_t NameIndex;
for (const auto &Entry : OffsetIndexMap) {
std::tie(NameOffset, NameIndex) = Entry;
// Compute the offset of the start of the string relative to the stream.
BinaryStreamReader NameReader(StringsBuffer);
NameReader.setOffset(NameOffset);
// Pump out our c-string from the stream.
StringRef Str;
if (auto EC = NameReader.readCString(Str))
return joinErrors(std::move(EC),
make_error<RawError>(raw_error_code::corrupt_file,
"Expected name map name"));
// Add this to a string-map from name to stream number.
Mapping.insert({Str, NameIndex});
}
return Error::success();
}
Error NamedStreamMap::commit(BinaryStreamWriter &Writer) const {
assert(FinalizedInfo.hasValue());
// The first field is the number of bytes of string data.
if (auto EC = Writer.writeInteger(FinalizedInfo->StringDataBytes))
return EC;
// Now all of the string data itself.
for (const auto &Item : Mapping) {
if (auto EC = Writer.writeCString(Item.getKey()))
return EC;
}
// And finally the Offset Index map.
if (auto EC = FinalizedHashTable.commit(Writer))
return EC;
return Error::success();
}
uint32_t NamedStreamMap::finalize() {
if (FinalizedInfo.hasValue())
return FinalizedInfo->SerializedLength;
// Build the finalized hash table.
FinalizedHashTable.clear();
FinalizedInfo.emplace();
for (const auto &Item : Mapping) {
FinalizedHashTable.set(FinalizedInfo->StringDataBytes, Item.getValue());
FinalizedInfo->StringDataBytes += Item.getKeyLength() + 1;
}
// Number of bytes of string data.
FinalizedInfo->SerializedLength += sizeof(support::ulittle32_t);
// Followed by that many actual bytes of string data.
FinalizedInfo->SerializedLength += FinalizedInfo->StringDataBytes;
// Followed by the mapping from Offset to Index.
FinalizedInfo->SerializedLength +=
FinalizedHashTable.calculateSerializedLength();
return FinalizedInfo->SerializedLength;
}
iterator_range<StringMapConstIterator<uint32_t>>
NamedStreamMap::entries() const {
return make_range<StringMapConstIterator<uint32_t>>(Mapping.begin(),
Mapping.end());
}
uint32_t NamedStreamMap::size() const { return Mapping.size(); }
bool NamedStreamMap::get(StringRef Stream, uint32_t &StreamNo) const {
auto Iter = Mapping.find(Stream);
if (Iter == Mapping.end())
return false;
StreamNo = Iter->second;
return true;
}
void NamedStreamMap::set(StringRef Stream, uint32_t StreamNo) {
FinalizedInfo.reset();
Mapping[Stream] = StreamNo;
}
void NamedStreamMap::remove(StringRef Stream) {
FinalizedInfo.reset();
Mapping.erase(Stream);
}