You've already forked linux-packaging-mono
Imported Upstream version 5.18.0.207
Former-commit-id: 3b152f462918d427ce18620a2cbe4f8b79650449
This commit is contained in:
parent
8e12397d70
commit
eb85e2fc17
@ -1,90 +0,0 @@
|
||||
//===- DbiModuleDescriptor.cpp - PDB module information -------------------===//
|
||||
//
|
||||
// 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/DbiModuleDescriptor.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/RawTypes.h"
|
||||
#include "llvm/Support/BinaryStreamReader.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#include <cstdint>
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::pdb;
|
||||
using namespace llvm::support;
|
||||
|
||||
DbiModuleDescriptor::DbiModuleDescriptor() = default;
|
||||
|
||||
DbiModuleDescriptor::DbiModuleDescriptor(const DbiModuleDescriptor &Info) =
|
||||
default;
|
||||
|
||||
DbiModuleDescriptor::~DbiModuleDescriptor() = default;
|
||||
|
||||
Error DbiModuleDescriptor::initialize(BinaryStreamRef Stream,
|
||||
DbiModuleDescriptor &Info) {
|
||||
BinaryStreamReader Reader(Stream);
|
||||
if (auto EC = Reader.readObject(Info.Layout))
|
||||
return EC;
|
||||
|
||||
if (auto EC = Reader.readCString(Info.ModuleName))
|
||||
return EC;
|
||||
|
||||
if (auto EC = Reader.readCString(Info.ObjFileName))
|
||||
return EC;
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
bool DbiModuleDescriptor::hasECInfo() const {
|
||||
return (Layout->Flags & ModInfoFlags::HasECFlagMask) != 0;
|
||||
}
|
||||
|
||||
uint16_t DbiModuleDescriptor::getTypeServerIndex() const {
|
||||
return (Layout->Flags & ModInfoFlags::TypeServerIndexMask) >>
|
||||
ModInfoFlags::TypeServerIndexShift;
|
||||
}
|
||||
|
||||
uint16_t DbiModuleDescriptor::getModuleStreamIndex() const {
|
||||
return Layout->ModDiStream;
|
||||
}
|
||||
|
||||
uint32_t DbiModuleDescriptor::getSymbolDebugInfoByteSize() const {
|
||||
return Layout->SymBytes;
|
||||
}
|
||||
|
||||
uint32_t DbiModuleDescriptor::getC11LineInfoByteSize() const {
|
||||
return Layout->C11Bytes;
|
||||
}
|
||||
|
||||
uint32_t DbiModuleDescriptor::getC13LineInfoByteSize() const {
|
||||
return Layout->C13Bytes;
|
||||
}
|
||||
|
||||
uint32_t DbiModuleDescriptor::getNumberOfFiles() const {
|
||||
return Layout->NumFiles;
|
||||
}
|
||||
|
||||
uint32_t DbiModuleDescriptor::getSourceFileNameIndex() const {
|
||||
return Layout->SrcFileNameNI;
|
||||
}
|
||||
|
||||
uint32_t DbiModuleDescriptor::getPdbFilePathNameIndex() const {
|
||||
return Layout->PdbFilePathNI;
|
||||
}
|
||||
|
||||
StringRef DbiModuleDescriptor::getModuleName() const { return ModuleName; }
|
||||
|
||||
StringRef DbiModuleDescriptor::getObjFileName() const { return ObjFileName; }
|
||||
|
||||
uint32_t DbiModuleDescriptor::getRecordLength() const {
|
||||
uint32_t M = ModuleName.str().size() + 1;
|
||||
uint32_t O = ObjFileName.str().size() + 1;
|
||||
uint32_t Size = sizeof(ModuleInfoHeader) + M + O;
|
||||
Size = alignTo(Size, 4);
|
||||
return Size;
|
||||
}
|
@ -1,179 +0,0 @@
|
||||
//===- DbiModuleDescriptorBuilder.cpp - PDB Mod Info Creation ---*- 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/DbiModuleDescriptorBuilder.h"
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/BinaryFormat/COFF.h"
|
||||
#include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h"
|
||||
#include "llvm/DebugInfo/MSF/MSFBuilder.h"
|
||||
#include "llvm/DebugInfo/MSF/MSFCommon.h"
|
||||
#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/GSIStreamBuilder.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/RawConstants.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/RawError.h"
|
||||
#include "llvm/Support/BinaryItemStream.h"
|
||||
#include "llvm/Support/BinaryStreamWriter.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::codeview;
|
||||
using namespace llvm::msf;
|
||||
using namespace llvm::pdb;
|
||||
|
||||
static uint32_t calculateDiSymbolStreamSize(uint32_t SymbolByteSize,
|
||||
uint32_t C13Size) {
|
||||
uint32_t Size = sizeof(uint32_t); // Signature
|
||||
Size += alignTo(SymbolByteSize, 4); // Symbol Data
|
||||
Size += 0; // TODO: Layout.C11Bytes
|
||||
Size += C13Size; // C13 Debug Info Size
|
||||
Size += sizeof(uint32_t); // GlobalRefs substream size (always 0)
|
||||
Size += 0; // GlobalRefs substream bytes
|
||||
return Size;
|
||||
}
|
||||
|
||||
DbiModuleDescriptorBuilder::DbiModuleDescriptorBuilder(StringRef ModuleName,
|
||||
uint32_t ModIndex,
|
||||
msf::MSFBuilder &Msf)
|
||||
: MSF(Msf), ModuleName(ModuleName) {
|
||||
::memset(&Layout, 0, sizeof(Layout));
|
||||
Layout.Mod = ModIndex;
|
||||
}
|
||||
|
||||
DbiModuleDescriptorBuilder::~DbiModuleDescriptorBuilder() {}
|
||||
|
||||
uint16_t DbiModuleDescriptorBuilder::getStreamIndex() const {
|
||||
return Layout.ModDiStream;
|
||||
}
|
||||
|
||||
void DbiModuleDescriptorBuilder::setObjFileName(StringRef Name) {
|
||||
ObjFileName = Name;
|
||||
}
|
||||
|
||||
void DbiModuleDescriptorBuilder::setPdbFilePathNI(uint32_t NI) {
|
||||
PdbFilePathNI = NI;
|
||||
}
|
||||
|
||||
void DbiModuleDescriptorBuilder::addSymbol(CVSymbol Symbol) {
|
||||
Symbols.push_back(Symbol);
|
||||
// Symbols written to a PDB file are required to be 4 byte aligned. The same
|
||||
// is not true of object files.
|
||||
assert(Symbol.length() % alignOf(CodeViewContainer::Pdb) == 0 &&
|
||||
"Invalid Symbol alignment!");
|
||||
SymbolByteSize += Symbol.length();
|
||||
}
|
||||
|
||||
void DbiModuleDescriptorBuilder::addSourceFile(StringRef Path) {
|
||||
SourceFiles.push_back(Path);
|
||||
}
|
||||
|
||||
uint32_t DbiModuleDescriptorBuilder::calculateC13DebugInfoSize() const {
|
||||
uint32_t Result = 0;
|
||||
for (const auto &Builder : C13Builders) {
|
||||
assert(Builder && "Empty C13 Fragment Builder!");
|
||||
Result += Builder->calculateSerializedLength();
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
uint32_t DbiModuleDescriptorBuilder::calculateSerializedLength() const {
|
||||
uint32_t L = sizeof(Layout);
|
||||
uint32_t M = ModuleName.size() + 1;
|
||||
uint32_t O = ObjFileName.size() + 1;
|
||||
return alignTo(L + M + O, sizeof(uint32_t));
|
||||
}
|
||||
|
||||
void DbiModuleDescriptorBuilder::finalize() {
|
||||
Layout.SC.ModuleIndex = Layout.Mod;
|
||||
Layout.FileNameOffs = 0; // TODO: Fix this
|
||||
Layout.Flags = 0; // TODO: Fix this
|
||||
Layout.C11Bytes = 0;
|
||||
Layout.C13Bytes = calculateC13DebugInfoSize();
|
||||
(void)Layout.Mod; // Set in constructor
|
||||
(void)Layout.ModDiStream; // Set in finalizeMsfLayout
|
||||
Layout.NumFiles = SourceFiles.size();
|
||||
Layout.PdbFilePathNI = PdbFilePathNI;
|
||||
Layout.SrcFileNameNI = 0;
|
||||
|
||||
// This value includes both the signature field as well as the record bytes
|
||||
// from the symbol stream.
|
||||
Layout.SymBytes = SymbolByteSize + sizeof(uint32_t);
|
||||
}
|
||||
|
||||
Error DbiModuleDescriptorBuilder::finalizeMsfLayout() {
|
||||
this->Layout.ModDiStream = kInvalidStreamIndex;
|
||||
uint32_t C13Size = calculateC13DebugInfoSize();
|
||||
auto ExpectedSN =
|
||||
MSF.addStream(calculateDiSymbolStreamSize(SymbolByteSize, C13Size));
|
||||
if (!ExpectedSN)
|
||||
return ExpectedSN.takeError();
|
||||
Layout.ModDiStream = *ExpectedSN;
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error DbiModuleDescriptorBuilder::commit(BinaryStreamWriter &ModiWriter,
|
||||
const msf::MSFLayout &MsfLayout,
|
||||
WritableBinaryStreamRef MsfBuffer) {
|
||||
// We write the Modi record to the `ModiWriter`, but we additionally write its
|
||||
// symbol stream to a brand new stream.
|
||||
if (auto EC = ModiWriter.writeObject(Layout))
|
||||
return EC;
|
||||
if (auto EC = ModiWriter.writeCString(ModuleName))
|
||||
return EC;
|
||||
if (auto EC = ModiWriter.writeCString(ObjFileName))
|
||||
return EC;
|
||||
if (auto EC = ModiWriter.padToAlignment(sizeof(uint32_t)))
|
||||
return EC;
|
||||
|
||||
if (Layout.ModDiStream != kInvalidStreamIndex) {
|
||||
auto NS = WritableMappedBlockStream::createIndexedStream(
|
||||
MsfLayout, MsfBuffer, Layout.ModDiStream, MSF.getAllocator());
|
||||
WritableBinaryStreamRef Ref(*NS);
|
||||
BinaryStreamWriter SymbolWriter(Ref);
|
||||
// Write the symbols.
|
||||
if (auto EC =
|
||||
SymbolWriter.writeInteger<uint32_t>(COFF::DEBUG_SECTION_MAGIC))
|
||||
return EC;
|
||||
BinaryItemStream<CVSymbol> Records(llvm::support::endianness::little);
|
||||
Records.setItems(Symbols);
|
||||
BinaryStreamRef RecordsRef(Records);
|
||||
if (auto EC = SymbolWriter.writeStreamRef(RecordsRef))
|
||||
return EC;
|
||||
if (auto EC = SymbolWriter.padToAlignment(4))
|
||||
return EC;
|
||||
// TODO: Write C11 Line data
|
||||
assert(SymbolWriter.getOffset() % alignOf(CodeViewContainer::Pdb) == 0 &&
|
||||
"Invalid debug section alignment!");
|
||||
for (const auto &Builder : C13Builders) {
|
||||
assert(Builder && "Empty C13 Fragment Builder!");
|
||||
if (auto EC = Builder->commit(SymbolWriter))
|
||||
return EC;
|
||||
}
|
||||
|
||||
// TODO: Figure out what GlobalRefs substream actually is and populate it.
|
||||
if (auto EC = SymbolWriter.writeInteger<uint32_t>(0))
|
||||
return EC;
|
||||
if (SymbolWriter.bytesRemaining() > 0)
|
||||
return make_error<RawError>(raw_error_code::stream_too_long);
|
||||
}
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
void DbiModuleDescriptorBuilder::addDebugSubsection(
|
||||
std::shared_ptr<DebugSubsection> Subsection) {
|
||||
assert(Subsection);
|
||||
C13Builders.push_back(llvm::make_unique<DebugSubsectionRecordBuilder>(
|
||||
std::move(Subsection), CodeViewContainer::Pdb));
|
||||
}
|
||||
|
||||
void DbiModuleDescriptorBuilder::addDebugSubsection(
|
||||
const DebugSubsectionRecord &SubsectionContents) {
|
||||
C13Builders.push_back(llvm::make_unique<DebugSubsectionRecordBuilder>(
|
||||
SubsectionContents, CodeViewContainer::Pdb));
|
||||
}
|
@ -1,280 +0,0 @@
|
||||
//===- DbiModuleList.cpp - PDB module information list --------------------===//
|
||||
//
|
||||
// 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/DbiModuleList.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/RawError.h"
|
||||
#include "llvm/Support/BinaryStreamReader.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::pdb;
|
||||
|
||||
DbiModuleSourceFilesIterator::DbiModuleSourceFilesIterator(
|
||||
const DbiModuleList &Modules, uint32_t Modi, uint16_t Filei)
|
||||
: Modules(&Modules), Modi(Modi), Filei(Filei) {
|
||||
setValue();
|
||||
}
|
||||
|
||||
bool DbiModuleSourceFilesIterator::
|
||||
operator==(const DbiModuleSourceFilesIterator &R) const {
|
||||
// incompatible iterators are never equal
|
||||
if (!isCompatible(R))
|
||||
return false;
|
||||
|
||||
// If they're compatible, and they're both ends, then they're equal.
|
||||
if (isEnd() && R.isEnd())
|
||||
return true;
|
||||
|
||||
// If one is an end and the other is not, they're not equal.
|
||||
if (isEnd() != R.isEnd())
|
||||
return false;
|
||||
|
||||
// Now we know:
|
||||
// - They're compatible
|
||||
// - They're not *both* end iterators
|
||||
// - Their endness is the same.
|
||||
// Thus, they're compatible iterators pointing to a valid file on the same
|
||||
// module. All we need to check are the file indices.
|
||||
assert(Modules == R.Modules);
|
||||
assert(Modi == R.Modi);
|
||||
assert(!isEnd());
|
||||
assert(!R.isEnd());
|
||||
|
||||
return (Filei == R.Filei);
|
||||
}
|
||||
|
||||
bool DbiModuleSourceFilesIterator::
|
||||
operator<(const DbiModuleSourceFilesIterator &R) const {
|
||||
assert(isCompatible(R));
|
||||
|
||||
// It's not sufficient to compare the file indices, because default
|
||||
// constructed iterators could be equal to iterators with valid indices. To
|
||||
// account for this, early-out if they're equal.
|
||||
if (*this == R)
|
||||
return false;
|
||||
|
||||
return Filei < R.Filei;
|
||||
}
|
||||
|
||||
std::ptrdiff_t DbiModuleSourceFilesIterator::
|
||||
operator-(const DbiModuleSourceFilesIterator &R) const {
|
||||
assert(isCompatible(R));
|
||||
assert(!(*this < R));
|
||||
|
||||
// If they're both end iterators, the distance is 0.
|
||||
if (isEnd() && R.isEnd())
|
||||
return 0;
|
||||
|
||||
assert(!R.isEnd());
|
||||
|
||||
// At this point, R cannot be end, but *this can, which means that *this
|
||||
// might be a universal end iterator with none of its fields set. So in that
|
||||
// case have to rely on R as the authority to figure out how many files there
|
||||
// are to compute the distance.
|
||||
uint32_t Thisi = Filei;
|
||||
if (isEnd()) {
|
||||
uint32_t RealModi = R.Modi;
|
||||
Thisi = R.Modules->getSourceFileCount(RealModi);
|
||||
}
|
||||
|
||||
assert(Thisi >= R.Filei);
|
||||
return Thisi - R.Filei;
|
||||
}
|
||||
|
||||
DbiModuleSourceFilesIterator &DbiModuleSourceFilesIterator::
|
||||
operator+=(std::ptrdiff_t N) {
|
||||
assert(!isEnd());
|
||||
|
||||
Filei += N;
|
||||
assert(Filei <= Modules->getSourceFileCount(Modi));
|
||||
setValue();
|
||||
return *this;
|
||||
}
|
||||
|
||||
DbiModuleSourceFilesIterator &DbiModuleSourceFilesIterator::
|
||||
operator-=(std::ptrdiff_t N) {
|
||||
// Note that we can subtract from an end iterator, but not a universal end
|
||||
// iterator.
|
||||
assert(!isUniversalEnd());
|
||||
|
||||
assert(N <= Filei);
|
||||
|
||||
Filei -= N;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void DbiModuleSourceFilesIterator::setValue() {
|
||||
if (isEnd()) {
|
||||
ThisValue = "";
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t Off = Modules->ModuleInitialFileIndex[Modi] + Filei;
|
||||
auto ExpectedValue = Modules->getFileName(Off);
|
||||
if (!ExpectedValue) {
|
||||
consumeError(ExpectedValue.takeError());
|
||||
Filei = Modules->getSourceFileCount(Modi);
|
||||
} else
|
||||
ThisValue = *ExpectedValue;
|
||||
}
|
||||
|
||||
bool DbiModuleSourceFilesIterator::isEnd() const {
|
||||
if (isUniversalEnd())
|
||||
return true;
|
||||
|
||||
assert(Modules);
|
||||
assert(Modi <= Modules->getModuleCount());
|
||||
assert(Filei <= Modules->getSourceFileCount(Modi));
|
||||
|
||||
if (Modi == Modules->getModuleCount())
|
||||
return true;
|
||||
if (Filei == Modules->getSourceFileCount(Modi))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DbiModuleSourceFilesIterator::isUniversalEnd() const { return !Modules; }
|
||||
|
||||
bool DbiModuleSourceFilesIterator::isCompatible(
|
||||
const DbiModuleSourceFilesIterator &R) const {
|
||||
// Universal iterators are compatible with any other iterator.
|
||||
if (isUniversalEnd() || R.isUniversalEnd())
|
||||
return true;
|
||||
|
||||
// At this point, neither iterator is a universal end iterator, although one
|
||||
// or both might be non-universal end iterators. Regardless, the module index
|
||||
// is valid, so they are compatible if and only if they refer to the same
|
||||
// module.
|
||||
return Modi == R.Modi;
|
||||
}
|
||||
|
||||
Error DbiModuleList::initialize(BinaryStreamRef ModInfo,
|
||||
BinaryStreamRef FileInfo) {
|
||||
if (auto EC = initializeModInfo(ModInfo))
|
||||
return EC;
|
||||
if (auto EC = initializeFileInfo(FileInfo))
|
||||
return EC;
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error DbiModuleList::initializeModInfo(BinaryStreamRef ModInfo) {
|
||||
ModInfoSubstream = ModInfo;
|
||||
|
||||
if (ModInfo.getLength() == 0)
|
||||
return Error::success();
|
||||
|
||||
BinaryStreamReader Reader(ModInfo);
|
||||
|
||||
if (auto EC = Reader.readArray(Descriptors, ModInfo.getLength()))
|
||||
return EC;
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error DbiModuleList::initializeFileInfo(BinaryStreamRef FileInfo) {
|
||||
FileInfoSubstream = FileInfo;
|
||||
|
||||
if (FileInfo.getLength() == 0)
|
||||
return Error::success();
|
||||
|
||||
BinaryStreamReader FISR(FileInfo);
|
||||
if (auto EC = FISR.readObject(FileInfoHeader))
|
||||
return EC;
|
||||
|
||||
// First is an array of `NumModules` module indices. This does not seem to be
|
||||
// used for anything meaningful, so we ignore it.
|
||||
FixedStreamArray<support::ulittle16_t> ModuleIndices;
|
||||
if (auto EC = FISR.readArray(ModuleIndices, FileInfoHeader->NumModules))
|
||||
return EC;
|
||||
if (auto EC = FISR.readArray(ModFileCountArray, FileInfoHeader->NumModules))
|
||||
return EC;
|
||||
|
||||
// Compute the real number of source files. We can't trust the value in
|
||||
// `FileInfoHeader->NumSourceFiles` because it is a unit16, and the sum of all
|
||||
// source file counts might be larger than a unit16. So we compute the real
|
||||
// count by summing up the individual counts.
|
||||
uint32_t NumSourceFiles = 0;
|
||||
for (auto Count : ModFileCountArray)
|
||||
NumSourceFiles += Count;
|
||||
|
||||
// In the reference implementation, this array is where the pointer documented
|
||||
// at the definition of ModuleInfoHeader::FileNameOffs points to. Note that
|
||||
// although the field in ModuleInfoHeader is ignored this array is not, as it
|
||||
// is the authority on where each filename begins in the names buffer.
|
||||
if (auto EC = FISR.readArray(FileNameOffsets, NumSourceFiles))
|
||||
return EC;
|
||||
|
||||
if (auto EC = FISR.readStreamRef(NamesBuffer))
|
||||
return EC;
|
||||
|
||||
auto DescriptorIter = Descriptors.begin();
|
||||
uint32_t NextFileIndex = 0;
|
||||
ModuleInitialFileIndex.resize(FileInfoHeader->NumModules);
|
||||
ModuleDescriptorOffsets.resize(FileInfoHeader->NumModules);
|
||||
for (size_t I = 0; I < FileInfoHeader->NumModules; ++I) {
|
||||
assert(DescriptorIter != Descriptors.end());
|
||||
ModuleInitialFileIndex[I] = NextFileIndex;
|
||||
ModuleDescriptorOffsets[I] = DescriptorIter.offset();
|
||||
|
||||
NextFileIndex += ModFileCountArray[I];
|
||||
++DescriptorIter;
|
||||
}
|
||||
|
||||
assert(DescriptorIter == Descriptors.end());
|
||||
assert(NextFileIndex == NumSourceFiles);
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
uint32_t DbiModuleList::getModuleCount() const {
|
||||
return FileInfoHeader->NumModules;
|
||||
}
|
||||
|
||||
uint32_t DbiModuleList::getSourceFileCount() const {
|
||||
return FileNameOffsets.size();
|
||||
}
|
||||
|
||||
uint16_t DbiModuleList::getSourceFileCount(uint32_t Modi) const {
|
||||
return ModFileCountArray[Modi];
|
||||
}
|
||||
|
||||
DbiModuleDescriptor DbiModuleList::getModuleDescriptor(uint32_t Modi) const {
|
||||
assert(Modi < getModuleCount());
|
||||
uint32_t Offset = ModuleDescriptorOffsets[Modi];
|
||||
auto Iter = Descriptors.at(Offset);
|
||||
assert(Iter != Descriptors.end());
|
||||
return *Iter;
|
||||
}
|
||||
|
||||
iterator_range<DbiModuleSourceFilesIterator>
|
||||
DbiModuleList::source_files(uint32_t Modi) const {
|
||||
return make_range<DbiModuleSourceFilesIterator>(
|
||||
DbiModuleSourceFilesIterator(*this, Modi, 0),
|
||||
DbiModuleSourceFilesIterator());
|
||||
}
|
||||
|
||||
Expected<StringRef> DbiModuleList::getFileName(uint32_t Index) const {
|
||||
BinaryStreamReader Names(NamesBuffer);
|
||||
if (Index >= getSourceFileCount())
|
||||
return make_error<RawError>(raw_error_code::index_out_of_bounds);
|
||||
|
||||
uint32_t FileOffset = FileNameOffsets[Index];
|
||||
Names.setOffset(FileOffset);
|
||||
StringRef Name;
|
||||
if (auto EC = Names.readCString(Name))
|
||||
return std::move(EC);
|
||||
return Name;
|
||||
}
|
349
external/llvm/lib/DebugInfo/PDB/Native/DbiStream.cpp
vendored
349
external/llvm/lib/DebugInfo/PDB/Native/DbiStream.cpp
vendored
@ -1,349 +0,0 @@
|
||||
//===- DbiStream.cpp - PDB Dbi Stream (Stream 3) Access -------------------===//
|
||||
//
|
||||
// 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/DbiStream.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/RawConstants.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/RawError.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/RawTypes.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBTypes.h"
|
||||
#include "llvm/Object/COFF.h"
|
||||
#include "llvm/Support/BinaryStreamArray.h"
|
||||
#include "llvm/Support/BinaryStreamReader.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::codeview;
|
||||
using namespace llvm::msf;
|
||||
using namespace llvm::pdb;
|
||||
using namespace llvm::support;
|
||||
|
||||
template <typename ContribType>
|
||||
static Error loadSectionContribs(FixedStreamArray<ContribType> &Output,
|
||||
BinaryStreamReader &Reader) {
|
||||
if (Reader.bytesRemaining() % sizeof(ContribType) != 0)
|
||||
return make_error<RawError>(
|
||||
raw_error_code::corrupt_file,
|
||||
"Invalid number of bytes of section contributions");
|
||||
|
||||
uint32_t Count = Reader.bytesRemaining() / sizeof(ContribType);
|
||||
if (auto EC = Reader.readArray(Output, Count))
|
||||
return EC;
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
DbiStream::DbiStream(PDBFile &File, std::unique_ptr<MappedBlockStream> Stream)
|
||||
: Pdb(File), Stream(std::move(Stream)), Header(nullptr) {}
|
||||
|
||||
DbiStream::~DbiStream() = default;
|
||||
|
||||
Error DbiStream::reload() {
|
||||
BinaryStreamReader Reader(*Stream);
|
||||
|
||||
if (Stream->getLength() < sizeof(DbiStreamHeader))
|
||||
return make_error<RawError>(raw_error_code::corrupt_file,
|
||||
"DBI Stream does not contain a header.");
|
||||
if (auto EC = Reader.readObject(Header))
|
||||
return make_error<RawError>(raw_error_code::corrupt_file,
|
||||
"DBI Stream does not contain a header.");
|
||||
|
||||
if (Header->VersionSignature != -1)
|
||||
return make_error<RawError>(raw_error_code::corrupt_file,
|
||||
"Invalid DBI version signature.");
|
||||
|
||||
// Require at least version 7, which should be present in all PDBs
|
||||
// produced in the last decade and allows us to avoid having to
|
||||
// special case all kinds of complicated arcane formats.
|
||||
if (Header->VersionHeader < PdbDbiV70)
|
||||
return make_error<RawError>(raw_error_code::feature_unsupported,
|
||||
"Unsupported DBI version.");
|
||||
|
||||
if (Stream->getLength() !=
|
||||
sizeof(DbiStreamHeader) + Header->ModiSubstreamSize +
|
||||
Header->SecContrSubstreamSize + Header->SectionMapSize +
|
||||
Header->FileInfoSize + Header->TypeServerSize +
|
||||
Header->OptionalDbgHdrSize + Header->ECSubstreamSize)
|
||||
return make_error<RawError>(raw_error_code::corrupt_file,
|
||||
"DBI Length does not equal sum of substreams.");
|
||||
|
||||
// Only certain substreams are guaranteed to be aligned. Validate
|
||||
// them here.
|
||||
if (Header->ModiSubstreamSize % sizeof(uint32_t) != 0)
|
||||
return make_error<RawError>(raw_error_code::corrupt_file,
|
||||
"DBI MODI substream not aligned.");
|
||||
if (Header->SecContrSubstreamSize % sizeof(uint32_t) != 0)
|
||||
return make_error<RawError>(
|
||||
raw_error_code::corrupt_file,
|
||||
"DBI section contribution substream not aligned.");
|
||||
if (Header->SectionMapSize % sizeof(uint32_t) != 0)
|
||||
return make_error<RawError>(raw_error_code::corrupt_file,
|
||||
"DBI section map substream not aligned.");
|
||||
if (Header->FileInfoSize % sizeof(uint32_t) != 0)
|
||||
return make_error<RawError>(raw_error_code::corrupt_file,
|
||||
"DBI file info substream not aligned.");
|
||||
if (Header->TypeServerSize % sizeof(uint32_t) != 0)
|
||||
return make_error<RawError>(raw_error_code::corrupt_file,
|
||||
"DBI type server substream not aligned.");
|
||||
|
||||
if (auto EC = Reader.readSubstream(ModiSubstream, Header->ModiSubstreamSize))
|
||||
return EC;
|
||||
|
||||
if (auto EC = Reader.readSubstream(SecContrSubstream,
|
||||
Header->SecContrSubstreamSize))
|
||||
return EC;
|
||||
if (auto EC = Reader.readSubstream(SecMapSubstream, Header->SectionMapSize))
|
||||
return EC;
|
||||
if (auto EC = Reader.readSubstream(FileInfoSubstream, Header->FileInfoSize))
|
||||
return EC;
|
||||
if (auto EC =
|
||||
Reader.readSubstream(TypeServerMapSubstream, Header->TypeServerSize))
|
||||
return EC;
|
||||
if (auto EC = Reader.readSubstream(ECSubstream, Header->ECSubstreamSize))
|
||||
return EC;
|
||||
if (auto EC = Reader.readArray(
|
||||
DbgStreams, Header->OptionalDbgHdrSize / sizeof(ulittle16_t)))
|
||||
return EC;
|
||||
|
||||
if (auto EC = Modules.initialize(ModiSubstream.StreamData,
|
||||
FileInfoSubstream.StreamData))
|
||||
return EC;
|
||||
|
||||
if (auto EC = initializeSectionContributionData())
|
||||
return EC;
|
||||
if (auto EC = initializeSectionHeadersData())
|
||||
return EC;
|
||||
if (auto EC = initializeSectionMapData())
|
||||
return EC;
|
||||
if (auto EC = initializeFpoRecords())
|
||||
return EC;
|
||||
|
||||
if (Reader.bytesRemaining() > 0)
|
||||
return make_error<RawError>(raw_error_code::corrupt_file,
|
||||
"Found unexpected bytes in DBI Stream.");
|
||||
|
||||
if (!ECSubstream.empty()) {
|
||||
BinaryStreamReader ECReader(ECSubstream.StreamData);
|
||||
if (auto EC = ECNames.reload(ECReader))
|
||||
return EC;
|
||||
}
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
PdbRaw_DbiVer DbiStream::getDbiVersion() const {
|
||||
uint32_t Value = Header->VersionHeader;
|
||||
return static_cast<PdbRaw_DbiVer>(Value);
|
||||
}
|
||||
|
||||
uint32_t DbiStream::getAge() const { return Header->Age; }
|
||||
|
||||
uint16_t DbiStream::getPublicSymbolStreamIndex() const {
|
||||
return Header->PublicSymbolStreamIndex;
|
||||
}
|
||||
|
||||
uint16_t DbiStream::getGlobalSymbolStreamIndex() const {
|
||||
return Header->GlobalSymbolStreamIndex;
|
||||
}
|
||||
|
||||
uint16_t DbiStream::getFlags() const { return Header->Flags; }
|
||||
|
||||
bool DbiStream::isIncrementallyLinked() const {
|
||||
return (Header->Flags & DbiFlags::FlagIncrementalMask) != 0;
|
||||
}
|
||||
|
||||
bool DbiStream::hasCTypes() const {
|
||||
return (Header->Flags & DbiFlags::FlagHasCTypesMask) != 0;
|
||||
}
|
||||
|
||||
bool DbiStream::isStripped() const {
|
||||
return (Header->Flags & DbiFlags::FlagStrippedMask) != 0;
|
||||
}
|
||||
|
||||
uint16_t DbiStream::getBuildNumber() const { return Header->BuildNumber; }
|
||||
|
||||
uint16_t DbiStream::getBuildMajorVersion() const {
|
||||
return (Header->BuildNumber & DbiBuildNo::BuildMajorMask) >>
|
||||
DbiBuildNo::BuildMajorShift;
|
||||
}
|
||||
|
||||
uint16_t DbiStream::getBuildMinorVersion() const {
|
||||
return (Header->BuildNumber & DbiBuildNo::BuildMinorMask) >>
|
||||
DbiBuildNo::BuildMinorShift;
|
||||
}
|
||||
|
||||
uint16_t DbiStream::getPdbDllRbld() const { return Header->PdbDllRbld; }
|
||||
|
||||
uint32_t DbiStream::getPdbDllVersion() const { return Header->PdbDllVersion; }
|
||||
|
||||
uint32_t DbiStream::getSymRecordStreamIndex() const {
|
||||
return Header->SymRecordStreamIndex;
|
||||
}
|
||||
|
||||
PDB_Machine DbiStream::getMachineType() const {
|
||||
uint16_t Machine = Header->MachineType;
|
||||
return static_cast<PDB_Machine>(Machine);
|
||||
}
|
||||
|
||||
FixedStreamArray<object::coff_section> DbiStream::getSectionHeaders() {
|
||||
return SectionHeaders;
|
||||
}
|
||||
|
||||
FixedStreamArray<object::FpoData> DbiStream::getFpoRecords() {
|
||||
return FpoRecords;
|
||||
}
|
||||
|
||||
const DbiModuleList &DbiStream::modules() const { return Modules; }
|
||||
|
||||
FixedStreamArray<SecMapEntry> DbiStream::getSectionMap() const {
|
||||
return SectionMap;
|
||||
}
|
||||
|
||||
void DbiStream::visitSectionContributions(
|
||||
ISectionContribVisitor &Visitor) const {
|
||||
if (!SectionContribs.empty()) {
|
||||
assert(SectionContribVersion == DbiSecContribVer60);
|
||||
for (auto &SC : SectionContribs)
|
||||
Visitor.visit(SC);
|
||||
} else if (!SectionContribs2.empty()) {
|
||||
assert(SectionContribVersion == DbiSecContribV2);
|
||||
for (auto &SC : SectionContribs2)
|
||||
Visitor.visit(SC);
|
||||
}
|
||||
}
|
||||
|
||||
Expected<StringRef> DbiStream::getECName(uint32_t NI) const {
|
||||
return ECNames.getStringForID(NI);
|
||||
}
|
||||
|
||||
Error DbiStream::initializeSectionContributionData() {
|
||||
if (SecContrSubstream.empty())
|
||||
return Error::success();
|
||||
|
||||
BinaryStreamReader SCReader(SecContrSubstream.StreamData);
|
||||
if (auto EC = SCReader.readEnum(SectionContribVersion))
|
||||
return EC;
|
||||
|
||||
if (SectionContribVersion == DbiSecContribVer60)
|
||||
return loadSectionContribs<SectionContrib>(SectionContribs, SCReader);
|
||||
if (SectionContribVersion == DbiSecContribV2)
|
||||
return loadSectionContribs<SectionContrib2>(SectionContribs2, SCReader);
|
||||
|
||||
return make_error<RawError>(raw_error_code::feature_unsupported,
|
||||
"Unsupported DBI Section Contribution version");
|
||||
}
|
||||
|
||||
// Initializes this->SectionHeaders.
|
||||
Error DbiStream::initializeSectionHeadersData() {
|
||||
if (DbgStreams.size() == 0)
|
||||
return Error::success();
|
||||
|
||||
uint32_t StreamNum = getDebugStreamIndex(DbgHeaderType::SectionHdr);
|
||||
if (StreamNum == kInvalidStreamIndex)
|
||||
return Error::success();
|
||||
|
||||
if (StreamNum >= Pdb.getNumStreams())
|
||||
return make_error<RawError>(raw_error_code::no_stream);
|
||||
|
||||
auto SHS = MappedBlockStream::createIndexedStream(
|
||||
Pdb.getMsfLayout(), Pdb.getMsfBuffer(), StreamNum, Pdb.getAllocator());
|
||||
|
||||
size_t StreamLen = SHS->getLength();
|
||||
if (StreamLen % sizeof(object::coff_section))
|
||||
return make_error<RawError>(raw_error_code::corrupt_file,
|
||||
"Corrupted section header stream.");
|
||||
|
||||
size_t NumSections = StreamLen / sizeof(object::coff_section);
|
||||
BinaryStreamReader Reader(*SHS);
|
||||
if (auto EC = Reader.readArray(SectionHeaders, NumSections))
|
||||
return make_error<RawError>(raw_error_code::corrupt_file,
|
||||
"Could not read a bitmap.");
|
||||
|
||||
SectionHeaderStream = std::move(SHS);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
// Initializes this->Fpos.
|
||||
Error DbiStream::initializeFpoRecords() {
|
||||
if (DbgStreams.size() == 0)
|
||||
return Error::success();
|
||||
|
||||
uint32_t StreamNum = getDebugStreamIndex(DbgHeaderType::NewFPO);
|
||||
|
||||
// This means there is no FPO data.
|
||||
if (StreamNum == kInvalidStreamIndex)
|
||||
return Error::success();
|
||||
|
||||
if (StreamNum >= Pdb.getNumStreams())
|
||||
return make_error<RawError>(raw_error_code::no_stream);
|
||||
|
||||
auto FS = MappedBlockStream::createIndexedStream(
|
||||
Pdb.getMsfLayout(), Pdb.getMsfBuffer(), StreamNum, Pdb.getAllocator());
|
||||
|
||||
size_t StreamLen = FS->getLength();
|
||||
if (StreamLen % sizeof(object::FpoData))
|
||||
return make_error<RawError>(raw_error_code::corrupt_file,
|
||||
"Corrupted New FPO stream.");
|
||||
|
||||
size_t NumRecords = StreamLen / sizeof(object::FpoData);
|
||||
BinaryStreamReader Reader(*FS);
|
||||
if (auto EC = Reader.readArray(FpoRecords, NumRecords))
|
||||
return make_error<RawError>(raw_error_code::corrupt_file,
|
||||
"Corrupted New FPO stream.");
|
||||
FpoStream = std::move(FS);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
BinarySubstreamRef DbiStream::getSectionContributionData() const {
|
||||
return SecContrSubstream;
|
||||
}
|
||||
|
||||
BinarySubstreamRef DbiStream::getSecMapSubstreamData() const {
|
||||
return SecMapSubstream;
|
||||
}
|
||||
|
||||
BinarySubstreamRef DbiStream::getModiSubstreamData() const {
|
||||
return ModiSubstream;
|
||||
}
|
||||
|
||||
BinarySubstreamRef DbiStream::getFileInfoSubstreamData() const {
|
||||
return FileInfoSubstream;
|
||||
}
|
||||
|
||||
BinarySubstreamRef DbiStream::getTypeServerMapSubstreamData() const {
|
||||
return TypeServerMapSubstream;
|
||||
}
|
||||
|
||||
BinarySubstreamRef DbiStream::getECSubstreamData() const { return ECSubstream; }
|
||||
|
||||
Error DbiStream::initializeSectionMapData() {
|
||||
if (SecMapSubstream.empty())
|
||||
return Error::success();
|
||||
|
||||
BinaryStreamReader SMReader(SecMapSubstream.StreamData);
|
||||
const SecMapHeader *Header;
|
||||
if (auto EC = SMReader.readObject(Header))
|
||||
return EC;
|
||||
if (auto EC = SMReader.readArray(SectionMap, Header->SecCount))
|
||||
return EC;
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
uint32_t DbiStream::getDebugStreamIndex(DbgHeaderType Type) const {
|
||||
uint16_t T = static_cast<uint16_t>(Type);
|
||||
if (T >= DbgStreams.size())
|
||||
return kInvalidStreamIndex;
|
||||
return DbgStreams[T];
|
||||
}
|
@ -1,396 +0,0 @@
|
||||
//===- DbiStreamBuilder.cpp - PDB Dbi Stream Creation -----------*- 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/DbiStreamBuilder.h"
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/BinaryFormat/COFF.h"
|
||||
#include "llvm/DebugInfo/MSF/MSFBuilder.h"
|
||||
#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/RawError.h"
|
||||
#include "llvm/Object/COFF.h"
|
||||
#include "llvm/Support/BinaryStreamWriter.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::codeview;
|
||||
using namespace llvm::msf;
|
||||
using namespace llvm::pdb;
|
||||
|
||||
DbiStreamBuilder::DbiStreamBuilder(msf::MSFBuilder &Msf)
|
||||
: Msf(Msf), Allocator(Msf.getAllocator()), Age(1), BuildNumber(0),
|
||||
PdbDllVersion(0), PdbDllRbld(0), Flags(0), MachineType(PDB_Machine::x86),
|
||||
Header(nullptr), DbgStreams((int)DbgHeaderType::Max) {}
|
||||
|
||||
DbiStreamBuilder::~DbiStreamBuilder() {}
|
||||
|
||||
void DbiStreamBuilder::setVersionHeader(PdbRaw_DbiVer V) { VerHeader = V; }
|
||||
|
||||
void DbiStreamBuilder::setAge(uint32_t A) { Age = A; }
|
||||
|
||||
void DbiStreamBuilder::setBuildNumber(uint16_t B) { BuildNumber = B; }
|
||||
|
||||
void DbiStreamBuilder::setPdbDllVersion(uint16_t V) { PdbDllVersion = V; }
|
||||
|
||||
void DbiStreamBuilder::setPdbDllRbld(uint16_t R) { PdbDllRbld = R; }
|
||||
|
||||
void DbiStreamBuilder::setFlags(uint16_t F) { Flags = F; }
|
||||
|
||||
void DbiStreamBuilder::setMachineType(PDB_Machine M) { MachineType = M; }
|
||||
|
||||
void DbiStreamBuilder::setSectionMap(ArrayRef<SecMapEntry> SecMap) {
|
||||
SectionMap = SecMap;
|
||||
}
|
||||
|
||||
void DbiStreamBuilder::setGlobalsStreamIndex(uint32_t Index) {
|
||||
GlobalsStreamIndex = Index;
|
||||
}
|
||||
|
||||
void DbiStreamBuilder::setSymbolRecordStreamIndex(uint32_t Index) {
|
||||
SymRecordStreamIndex = Index;
|
||||
}
|
||||
|
||||
void DbiStreamBuilder::setPublicsStreamIndex(uint32_t Index) {
|
||||
PublicsStreamIndex = Index;
|
||||
}
|
||||
|
||||
Error DbiStreamBuilder::addDbgStream(pdb::DbgHeaderType Type,
|
||||
ArrayRef<uint8_t> Data) {
|
||||
if (DbgStreams[(int)Type].StreamNumber != kInvalidStreamIndex)
|
||||
return make_error<RawError>(raw_error_code::duplicate_entry,
|
||||
"The specified stream type already exists");
|
||||
auto ExpectedIndex = Msf.addStream(Data.size());
|
||||
if (!ExpectedIndex)
|
||||
return ExpectedIndex.takeError();
|
||||
uint32_t Index = std::move(*ExpectedIndex);
|
||||
DbgStreams[(int)Type].Data = Data;
|
||||
DbgStreams[(int)Type].StreamNumber = Index;
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
uint32_t DbiStreamBuilder::addECName(StringRef Name) {
|
||||
return ECNamesBuilder.insert(Name);
|
||||
}
|
||||
|
||||
uint32_t DbiStreamBuilder::calculateSerializedLength() const {
|
||||
// For now we only support serializing the header.
|
||||
return sizeof(DbiStreamHeader) + calculateFileInfoSubstreamSize() +
|
||||
calculateModiSubstreamSize() + calculateSectionContribsStreamSize() +
|
||||
calculateSectionMapStreamSize() + calculateDbgStreamsSize() +
|
||||
ECNamesBuilder.calculateSerializedSize();
|
||||
}
|
||||
|
||||
Expected<DbiModuleDescriptorBuilder &>
|
||||
DbiStreamBuilder::addModuleInfo(StringRef ModuleName) {
|
||||
uint32_t Index = ModiList.size();
|
||||
ModiList.push_back(
|
||||
llvm::make_unique<DbiModuleDescriptorBuilder>(ModuleName, Index, Msf));
|
||||
return *ModiList.back();
|
||||
}
|
||||
|
||||
Error DbiStreamBuilder::addModuleSourceFile(DbiModuleDescriptorBuilder &Module,
|
||||
StringRef File) {
|
||||
uint32_t Index = SourceFileNames.size();
|
||||
SourceFileNames.insert(std::make_pair(File, Index));
|
||||
Module.addSourceFile(File);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Expected<uint32_t> DbiStreamBuilder::getSourceFileNameIndex(StringRef File) {
|
||||
auto NameIter = SourceFileNames.find(File);
|
||||
if (NameIter == SourceFileNames.end())
|
||||
return make_error<RawError>(raw_error_code::no_entry,
|
||||
"The specified source file was not found");
|
||||
return NameIter->getValue();
|
||||
}
|
||||
|
||||
uint32_t DbiStreamBuilder::calculateModiSubstreamSize() const {
|
||||
uint32_t Size = 0;
|
||||
for (const auto &M : ModiList)
|
||||
Size += M->calculateSerializedLength();
|
||||
return Size;
|
||||
}
|
||||
|
||||
uint32_t DbiStreamBuilder::calculateSectionContribsStreamSize() const {
|
||||
if (SectionContribs.empty())
|
||||
return 0;
|
||||
return sizeof(enum PdbRaw_DbiSecContribVer) +
|
||||
sizeof(SectionContribs[0]) * SectionContribs.size();
|
||||
}
|
||||
|
||||
uint32_t DbiStreamBuilder::calculateSectionMapStreamSize() const {
|
||||
if (SectionMap.empty())
|
||||
return 0;
|
||||
return sizeof(SecMapHeader) + sizeof(SecMapEntry) * SectionMap.size();
|
||||
}
|
||||
|
||||
uint32_t DbiStreamBuilder::calculateNamesOffset() const {
|
||||
uint32_t Offset = 0;
|
||||
Offset += sizeof(ulittle16_t); // NumModules
|
||||
Offset += sizeof(ulittle16_t); // NumSourceFiles
|
||||
Offset += ModiList.size() * sizeof(ulittle16_t); // ModIndices
|
||||
Offset += ModiList.size() * sizeof(ulittle16_t); // ModFileCounts
|
||||
uint32_t NumFileInfos = 0;
|
||||
for (const auto &M : ModiList)
|
||||
NumFileInfos += M->source_files().size();
|
||||
Offset += NumFileInfos * sizeof(ulittle32_t); // FileNameOffsets
|
||||
return Offset;
|
||||
}
|
||||
|
||||
uint32_t DbiStreamBuilder::calculateFileInfoSubstreamSize() const {
|
||||
uint32_t Size = calculateNamesOffset();
|
||||
Size += calculateNamesBufferSize();
|
||||
return alignTo(Size, sizeof(uint32_t));
|
||||
}
|
||||
|
||||
uint32_t DbiStreamBuilder::calculateNamesBufferSize() const {
|
||||
uint32_t Size = 0;
|
||||
for (const auto &F : SourceFileNames) {
|
||||
Size += F.getKeyLength() + 1; // Names[I];
|
||||
}
|
||||
return Size;
|
||||
}
|
||||
|
||||
uint32_t DbiStreamBuilder::calculateDbgStreamsSize() const {
|
||||
return DbgStreams.size() * sizeof(uint16_t);
|
||||
}
|
||||
|
||||
Error DbiStreamBuilder::generateFileInfoSubstream() {
|
||||
uint32_t Size = calculateFileInfoSubstreamSize();
|
||||
auto Data = Allocator.Allocate<uint8_t>(Size);
|
||||
uint32_t NamesOffset = calculateNamesOffset();
|
||||
|
||||
FileInfoBuffer = MutableBinaryByteStream(MutableArrayRef<uint8_t>(Data, Size),
|
||||
llvm::support::little);
|
||||
|
||||
WritableBinaryStreamRef MetadataBuffer =
|
||||
WritableBinaryStreamRef(FileInfoBuffer).keep_front(NamesOffset);
|
||||
BinaryStreamWriter MetadataWriter(MetadataBuffer);
|
||||
|
||||
uint16_t ModiCount = std::min<uint32_t>(UINT16_MAX, ModiList.size());
|
||||
uint16_t FileCount = std::min<uint32_t>(UINT16_MAX, SourceFileNames.size());
|
||||
if (auto EC = MetadataWriter.writeInteger(ModiCount)) // NumModules
|
||||
return EC;
|
||||
if (auto EC = MetadataWriter.writeInteger(FileCount)) // NumSourceFiles
|
||||
return EC;
|
||||
for (uint16_t I = 0; I < ModiCount; ++I) {
|
||||
if (auto EC = MetadataWriter.writeInteger(I)) // Mod Indices
|
||||
return EC;
|
||||
}
|
||||
for (const auto &MI : ModiList) {
|
||||
FileCount = static_cast<uint16_t>(MI->source_files().size());
|
||||
if (auto EC = MetadataWriter.writeInteger(FileCount)) // Mod File Counts
|
||||
return EC;
|
||||
}
|
||||
|
||||
// Before writing the FileNameOffsets array, write the NamesBuffer array.
|
||||
// A side effect of this is that this will actually compute the various
|
||||
// file name offsets, so we can then go back and write the FileNameOffsets
|
||||
// array to the other substream.
|
||||
NamesBuffer = WritableBinaryStreamRef(FileInfoBuffer).drop_front(NamesOffset);
|
||||
BinaryStreamWriter NameBufferWriter(NamesBuffer);
|
||||
for (auto &Name : SourceFileNames) {
|
||||
Name.second = NameBufferWriter.getOffset();
|
||||
if (auto EC = NameBufferWriter.writeCString(Name.getKey()))
|
||||
return EC;
|
||||
}
|
||||
|
||||
for (const auto &MI : ModiList) {
|
||||
for (StringRef Name : MI->source_files()) {
|
||||
auto Result = SourceFileNames.find(Name);
|
||||
if (Result == SourceFileNames.end())
|
||||
return make_error<RawError>(raw_error_code::no_entry,
|
||||
"The source file was not found.");
|
||||
if (auto EC = MetadataWriter.writeInteger(Result->second))
|
||||
return EC;
|
||||
}
|
||||
}
|
||||
|
||||
if (auto EC = NameBufferWriter.padToAlignment(sizeof(uint32_t)))
|
||||
return EC;
|
||||
|
||||
if (NameBufferWriter.bytesRemaining() > 0)
|
||||
return make_error<RawError>(raw_error_code::invalid_format,
|
||||
"The names buffer contained unexpected data.");
|
||||
|
||||
if (MetadataWriter.bytesRemaining() > sizeof(uint32_t))
|
||||
return make_error<RawError>(
|
||||
raw_error_code::invalid_format,
|
||||
"The metadata buffer contained unexpected data.");
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error DbiStreamBuilder::finalize() {
|
||||
if (Header)
|
||||
return Error::success();
|
||||
|
||||
for (auto &MI : ModiList)
|
||||
MI->finalize();
|
||||
|
||||
if (auto EC = generateFileInfoSubstream())
|
||||
return EC;
|
||||
|
||||
DbiStreamHeader *H = Allocator.Allocate<DbiStreamHeader>();
|
||||
::memset(H, 0, sizeof(DbiStreamHeader));
|
||||
H->VersionHeader = *VerHeader;
|
||||
H->VersionSignature = -1;
|
||||
H->Age = Age;
|
||||
H->BuildNumber = BuildNumber;
|
||||
H->Flags = Flags;
|
||||
H->PdbDllRbld = PdbDllRbld;
|
||||
H->PdbDllVersion = PdbDllVersion;
|
||||
H->MachineType = static_cast<uint16_t>(MachineType);
|
||||
|
||||
H->ECSubstreamSize = ECNamesBuilder.calculateSerializedSize();
|
||||
H->FileInfoSize = FileInfoBuffer.getLength();
|
||||
H->ModiSubstreamSize = calculateModiSubstreamSize();
|
||||
H->OptionalDbgHdrSize = DbgStreams.size() * sizeof(uint16_t);
|
||||
H->SecContrSubstreamSize = calculateSectionContribsStreamSize();
|
||||
H->SectionMapSize = calculateSectionMapStreamSize();
|
||||
H->TypeServerSize = 0;
|
||||
H->SymRecordStreamIndex = SymRecordStreamIndex;
|
||||
H->PublicSymbolStreamIndex = PublicsStreamIndex;
|
||||
H->MFCTypeServerIndex = kInvalidStreamIndex;
|
||||
H->GlobalSymbolStreamIndex = GlobalsStreamIndex;
|
||||
|
||||
Header = H;
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error DbiStreamBuilder::finalizeMsfLayout() {
|
||||
for (auto &MI : ModiList) {
|
||||
if (auto EC = MI->finalizeMsfLayout())
|
||||
return EC;
|
||||
}
|
||||
|
||||
uint32_t Length = calculateSerializedLength();
|
||||
if (auto EC = Msf.setStreamSize(StreamDBI, Length))
|
||||
return EC;
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
static uint16_t toSecMapFlags(uint32_t Flags) {
|
||||
uint16_t Ret = 0;
|
||||
if (Flags & COFF::IMAGE_SCN_MEM_READ)
|
||||
Ret |= static_cast<uint16_t>(OMFSegDescFlags::Read);
|
||||
if (Flags & COFF::IMAGE_SCN_MEM_WRITE)
|
||||
Ret |= static_cast<uint16_t>(OMFSegDescFlags::Write);
|
||||
if (Flags & COFF::IMAGE_SCN_MEM_EXECUTE)
|
||||
Ret |= static_cast<uint16_t>(OMFSegDescFlags::Execute);
|
||||
if (Flags & COFF::IMAGE_SCN_MEM_EXECUTE)
|
||||
Ret |= static_cast<uint16_t>(OMFSegDescFlags::Execute);
|
||||
if (!(Flags & COFF::IMAGE_SCN_MEM_16BIT))
|
||||
Ret |= static_cast<uint16_t>(OMFSegDescFlags::AddressIs32Bit);
|
||||
|
||||
// This seems always 1.
|
||||
Ret |= static_cast<uint16_t>(OMFSegDescFlags::IsSelector);
|
||||
|
||||
return Ret;
|
||||
}
|
||||
|
||||
// A utility function to create a Section Map for a given list of COFF sections.
|
||||
//
|
||||
// A Section Map seem to be a copy of a COFF section list in other format.
|
||||
// I don't know why a PDB file contains both a COFF section header and
|
||||
// a Section Map, but it seems it must be present in a PDB.
|
||||
std::vector<SecMapEntry> DbiStreamBuilder::createSectionMap(
|
||||
ArrayRef<llvm::object::coff_section> SecHdrs) {
|
||||
std::vector<SecMapEntry> Ret;
|
||||
int Idx = 0;
|
||||
|
||||
auto Add = [&]() -> SecMapEntry & {
|
||||
Ret.emplace_back();
|
||||
auto &Entry = Ret.back();
|
||||
memset(&Entry, 0, sizeof(Entry));
|
||||
|
||||
Entry.Frame = Idx + 1;
|
||||
|
||||
// We don't know the meaning of these fields yet.
|
||||
Entry.SecName = UINT16_MAX;
|
||||
Entry.ClassName = UINT16_MAX;
|
||||
|
||||
return Entry;
|
||||
};
|
||||
|
||||
for (auto &Hdr : SecHdrs) {
|
||||
auto &Entry = Add();
|
||||
Entry.Flags = toSecMapFlags(Hdr.Characteristics);
|
||||
Entry.SecByteLength = Hdr.VirtualSize;
|
||||
++Idx;
|
||||
}
|
||||
|
||||
// The last entry is for absolute symbols.
|
||||
auto &Entry = Add();
|
||||
Entry.Flags = static_cast<uint16_t>(OMFSegDescFlags::AddressIs32Bit) |
|
||||
static_cast<uint16_t>(OMFSegDescFlags::IsAbsoluteAddress);
|
||||
Entry.SecByteLength = UINT32_MAX;
|
||||
|
||||
return Ret;
|
||||
}
|
||||
|
||||
Error DbiStreamBuilder::commit(const msf::MSFLayout &Layout,
|
||||
WritableBinaryStreamRef MsfBuffer) {
|
||||
if (auto EC = finalize())
|
||||
return EC;
|
||||
|
||||
auto DbiS = WritableMappedBlockStream::createIndexedStream(
|
||||
Layout, MsfBuffer, StreamDBI, Allocator);
|
||||
|
||||
BinaryStreamWriter Writer(*DbiS);
|
||||
if (auto EC = Writer.writeObject(*Header))
|
||||
return EC;
|
||||
|
||||
for (auto &M : ModiList) {
|
||||
if (auto EC = M->commit(Writer, Layout, MsfBuffer))
|
||||
return EC;
|
||||
}
|
||||
|
||||
if (!SectionContribs.empty()) {
|
||||
if (auto EC = Writer.writeEnum(DbiSecContribVer60))
|
||||
return EC;
|
||||
if (auto EC = Writer.writeArray(makeArrayRef(SectionContribs)))
|
||||
return EC;
|
||||
}
|
||||
|
||||
if (!SectionMap.empty()) {
|
||||
ulittle16_t Size = static_cast<ulittle16_t>(SectionMap.size());
|
||||
SecMapHeader SMHeader = {Size, Size};
|
||||
if (auto EC = Writer.writeObject(SMHeader))
|
||||
return EC;
|
||||
if (auto EC = Writer.writeArray(SectionMap))
|
||||
return EC;
|
||||
}
|
||||
|
||||
if (auto EC = Writer.writeStreamRef(FileInfoBuffer))
|
||||
return EC;
|
||||
|
||||
if (auto EC = ECNamesBuilder.commit(Writer))
|
||||
return EC;
|
||||
|
||||
for (auto &Stream : DbgStreams)
|
||||
if (auto EC = Writer.writeInteger(Stream.StreamNumber))
|
||||
return EC;
|
||||
|
||||
for (auto &Stream : DbgStreams) {
|
||||
if (Stream.StreamNumber == kInvalidStreamIndex)
|
||||
continue;
|
||||
auto WritableStream = WritableMappedBlockStream::createIndexedStream(
|
||||
Layout, MsfBuffer, Stream.StreamNumber, Allocator);
|
||||
BinaryStreamWriter DbgStreamWriter(*WritableStream);
|
||||
if (auto EC = DbgStreamWriter.writeArray(Stream.Data))
|
||||
return EC;
|
||||
}
|
||||
|
||||
if (Writer.bytesRemaining() > 0)
|
||||
return make_error<RawError>(raw_error_code::invalid_format,
|
||||
"Unexpected bytes found in DBI Stream");
|
||||
return Error::success();
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
//===- EnumTables.cpp - Enum to string conversion tables --------*- 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/EnumTables.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/RawConstants.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::pdb;
|
||||
|
||||
#define PDB_ENUM_CLASS_ENT(enum_class, enum) \
|
||||
{ #enum, std::underlying_type < enum_class > ::type(enum_class::enum) }
|
||||
|
||||
#define PDB_ENUM_ENT(ns, enum) \
|
||||
{ #enum, ns::enum }
|
||||
|
||||
static const EnumEntry<uint16_t> OMFSegMapDescFlagNames[] = {
|
||||
PDB_ENUM_CLASS_ENT(OMFSegDescFlags, Read),
|
||||
PDB_ENUM_CLASS_ENT(OMFSegDescFlags, Write),
|
||||
PDB_ENUM_CLASS_ENT(OMFSegDescFlags, Execute),
|
||||
PDB_ENUM_CLASS_ENT(OMFSegDescFlags, AddressIs32Bit),
|
||||
PDB_ENUM_CLASS_ENT(OMFSegDescFlags, IsSelector),
|
||||
PDB_ENUM_CLASS_ENT(OMFSegDescFlags, IsAbsoluteAddress),
|
||||
PDB_ENUM_CLASS_ENT(OMFSegDescFlags, IsGroup),
|
||||
};
|
||||
|
||||
namespace llvm {
|
||||
namespace pdb {
|
||||
ArrayRef<EnumEntry<uint16_t>> getOMFSegMapDescFlagNames() {
|
||||
return makeArrayRef(OMFSegMapDescFlagNames);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,322 +0,0 @@
|
||||
//===- DbiStreamBuilder.cpp - PDB Dbi Stream Creation -----------*- 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/GSIStreamBuilder.h"
|
||||
|
||||
#include "llvm/DebugInfo/CodeView/RecordName.h"
|
||||
#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
|
||||
#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
|
||||
#include "llvm/DebugInfo/CodeView/SymbolSerializer.h"
|
||||
#include "llvm/DebugInfo/MSF/MSFBuilder.h"
|
||||
#include "llvm/DebugInfo/MSF/MSFCommon.h"
|
||||
#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/Hash.h"
|
||||
#include "llvm/Support/BinaryItemStream.h"
|
||||
#include "llvm/Support/BinaryStreamWriter.h"
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::msf;
|
||||
using namespace llvm::pdb;
|
||||
using namespace llvm::codeview;
|
||||
|
||||
struct llvm::pdb::GSIHashStreamBuilder {
|
||||
std::vector<CVSymbol> Records;
|
||||
uint32_t StreamIndex;
|
||||
std::vector<PSHashRecord> HashRecords;
|
||||
std::array<support::ulittle32_t, (IPHR_HASH + 32) / 32> HashBitmap;
|
||||
std::vector<support::ulittle32_t> HashBuckets;
|
||||
|
||||
uint32_t calculateSerializedLength() const;
|
||||
uint32_t calculateRecordByteSize() const;
|
||||
Error commit(BinaryStreamWriter &Writer);
|
||||
void finalizeBuckets(uint32_t RecordZeroOffset);
|
||||
|
||||
template <typename T> void addSymbol(const T &Symbol, MSFBuilder &Msf) {
|
||||
T Copy(Symbol);
|
||||
Records.push_back(SymbolSerializer::writeOneSymbol(Copy, Msf.getAllocator(),
|
||||
CodeViewContainer::Pdb));
|
||||
}
|
||||
void addSymbol(const CVSymbol &Symbol) { Records.push_back(Symbol); }
|
||||
};
|
||||
|
||||
uint32_t GSIHashStreamBuilder::calculateSerializedLength() const {
|
||||
uint32_t Size = sizeof(GSIHashHeader);
|
||||
Size += HashRecords.size() * sizeof(PSHashRecord);
|
||||
Size += HashBitmap.size() * sizeof(uint32_t);
|
||||
Size += HashBuckets.size() * sizeof(uint32_t);
|
||||
return Size;
|
||||
}
|
||||
|
||||
uint32_t GSIHashStreamBuilder::calculateRecordByteSize() const {
|
||||
uint32_t Size = 0;
|
||||
for (const auto &Sym : Records)
|
||||
Size += Sym.length();
|
||||
return Size;
|
||||
}
|
||||
|
||||
Error GSIHashStreamBuilder::commit(BinaryStreamWriter &Writer) {
|
||||
GSIHashHeader Header;
|
||||
Header.VerSignature = GSIHashHeader::HdrSignature;
|
||||
Header.VerHdr = GSIHashHeader::HdrVersion;
|
||||
Header.HrSize = HashRecords.size() * sizeof(PSHashRecord);
|
||||
Header.NumBuckets = HashBitmap.size() * 4 + HashBuckets.size() * 4;
|
||||
|
||||
if (auto EC = Writer.writeObject(Header))
|
||||
return EC;
|
||||
|
||||
if (auto EC = Writer.writeArray(makeArrayRef(HashRecords)))
|
||||
return EC;
|
||||
if (auto EC = Writer.writeArray(makeArrayRef(HashBitmap)))
|
||||
return EC;
|
||||
if (auto EC = Writer.writeArray(makeArrayRef(HashBuckets)))
|
||||
return EC;
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
void GSIHashStreamBuilder::finalizeBuckets(uint32_t RecordZeroOffset) {
|
||||
std::array<std::vector<PSHashRecord>, IPHR_HASH + 1> TmpBuckets;
|
||||
uint32_t SymOffset = RecordZeroOffset;
|
||||
for (const CVSymbol &Sym : Records) {
|
||||
PSHashRecord HR;
|
||||
// Add one when writing symbol offsets to disk. See GSI1::fixSymRecs.
|
||||
HR.Off = SymOffset + 1;
|
||||
HR.CRef = 1; // Always use a refcount of 1.
|
||||
|
||||
// Hash the name to figure out which bucket this goes into.
|
||||
StringRef Name = getSymbolName(Sym);
|
||||
size_t BucketIdx = hashStringV1(Name) % IPHR_HASH;
|
||||
TmpBuckets[BucketIdx].push_back(HR); // FIXME: Does order matter?
|
||||
|
||||
SymOffset += Sym.length();
|
||||
}
|
||||
|
||||
// Compute the three tables: the hash records in bucket and chain order, the
|
||||
// bucket presence bitmap, and the bucket chain start offsets.
|
||||
HashRecords.reserve(Records.size());
|
||||
for (ulittle32_t &Word : HashBitmap)
|
||||
Word = 0;
|
||||
for (size_t BucketIdx = 0; BucketIdx < IPHR_HASH + 1; ++BucketIdx) {
|
||||
auto &Bucket = TmpBuckets[BucketIdx];
|
||||
if (Bucket.empty())
|
||||
continue;
|
||||
HashBitmap[BucketIdx / 32] |= 1U << (BucketIdx % 32);
|
||||
|
||||
// Calculate what the offset of the first hash record in the chain would
|
||||
// be if it were inflated to contain 32-bit pointers. On a 32-bit system,
|
||||
// each record would be 12 bytes. See HROffsetCalc in gsi.h.
|
||||
const int SizeOfHROffsetCalc = 12;
|
||||
ulittle32_t ChainStartOff =
|
||||
ulittle32_t(HashRecords.size() * SizeOfHROffsetCalc);
|
||||
HashBuckets.push_back(ChainStartOff);
|
||||
for (const auto &HR : Bucket)
|
||||
HashRecords.push_back(HR);
|
||||
}
|
||||
}
|
||||
|
||||
GSIStreamBuilder::GSIStreamBuilder(msf::MSFBuilder &Msf)
|
||||
: Msf(Msf), PSH(llvm::make_unique<GSIHashStreamBuilder>()),
|
||||
GSH(llvm::make_unique<GSIHashStreamBuilder>()) {}
|
||||
|
||||
GSIStreamBuilder::~GSIStreamBuilder() {}
|
||||
|
||||
uint32_t GSIStreamBuilder::calculatePublicsHashStreamSize() const {
|
||||
uint32_t Size = 0;
|
||||
Size += sizeof(PublicsStreamHeader);
|
||||
Size += PSH->calculateSerializedLength();
|
||||
Size += PSH->Records.size() * sizeof(uint32_t); // AddrMap
|
||||
// FIXME: Add thunk map and section offsets for incremental linking.
|
||||
|
||||
return Size;
|
||||
}
|
||||
|
||||
uint32_t GSIStreamBuilder::calculateGlobalsHashStreamSize() const {
|
||||
return GSH->calculateSerializedLength();
|
||||
}
|
||||
|
||||
Error GSIStreamBuilder::finalizeMsfLayout() {
|
||||
// First we write public symbol records, then we write global symbol records.
|
||||
uint32_t PSHZero = 0;
|
||||
uint32_t GSHZero = PSH->calculateRecordByteSize();
|
||||
|
||||
PSH->finalizeBuckets(PSHZero);
|
||||
GSH->finalizeBuckets(GSHZero);
|
||||
|
||||
Expected<uint32_t> Idx = Msf.addStream(calculatePublicsHashStreamSize());
|
||||
if (!Idx)
|
||||
return Idx.takeError();
|
||||
PSH->StreamIndex = *Idx;
|
||||
Idx = Msf.addStream(calculateGlobalsHashStreamSize());
|
||||
if (!Idx)
|
||||
return Idx.takeError();
|
||||
GSH->StreamIndex = *Idx;
|
||||
|
||||
uint32_t RecordBytes =
|
||||
GSH->calculateRecordByteSize() + PSH->calculateRecordByteSize();
|
||||
|
||||
Idx = Msf.addStream(RecordBytes);
|
||||
if (!Idx)
|
||||
return Idx.takeError();
|
||||
RecordStreamIdx = *Idx;
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
static bool comparePubSymByAddrAndName(
|
||||
const std::pair<const CVSymbol *, const PublicSym32 *> &LS,
|
||||
const std::pair<const CVSymbol *, const PublicSym32 *> &RS) {
|
||||
if (LS.second->Segment != RS.second->Segment)
|
||||
return LS.second->Segment < RS.second->Segment;
|
||||
if (LS.second->Offset != RS.second->Offset)
|
||||
return LS.second->Offset < RS.second->Offset;
|
||||
|
||||
return LS.second->Name < RS.second->Name;
|
||||
}
|
||||
|
||||
/// Compute the address map. The address map is an array of symbol offsets
|
||||
/// sorted so that it can be binary searched by address.
|
||||
static std::vector<ulittle32_t> computeAddrMap(ArrayRef<CVSymbol> Records) {
|
||||
// Make a vector of pointers to the symbols so we can sort it by address.
|
||||
// Also gather the symbol offsets while we're at it.
|
||||
|
||||
std::vector<PublicSym32> DeserializedPublics;
|
||||
std::vector<std::pair<const CVSymbol *, const PublicSym32 *>> PublicsByAddr;
|
||||
std::vector<uint32_t> SymOffsets;
|
||||
DeserializedPublics.reserve(Records.size());
|
||||
PublicsByAddr.reserve(Records.size());
|
||||
SymOffsets.reserve(Records.size());
|
||||
|
||||
uint32_t SymOffset = 0;
|
||||
for (const CVSymbol &Sym : Records) {
|
||||
assert(Sym.kind() == SymbolKind::S_PUB32);
|
||||
DeserializedPublics.push_back(
|
||||
cantFail(SymbolDeserializer::deserializeAs<PublicSym32>(Sym)));
|
||||
PublicsByAddr.emplace_back(&Sym, &DeserializedPublics.back());
|
||||
SymOffsets.push_back(SymOffset);
|
||||
SymOffset += Sym.length();
|
||||
}
|
||||
std::stable_sort(PublicsByAddr.begin(), PublicsByAddr.end(),
|
||||
comparePubSymByAddrAndName);
|
||||
|
||||
// Fill in the symbol offsets in the appropriate order.
|
||||
std::vector<ulittle32_t> AddrMap;
|
||||
AddrMap.reserve(Records.size());
|
||||
for (auto &Sym : PublicsByAddr) {
|
||||
ptrdiff_t Idx = std::distance(Records.data(), Sym.first);
|
||||
assert(Idx >= 0 && size_t(Idx) < Records.size());
|
||||
AddrMap.push_back(ulittle32_t(SymOffsets[Idx]));
|
||||
}
|
||||
return AddrMap;
|
||||
}
|
||||
|
||||
uint32_t GSIStreamBuilder::getPublicsStreamIndex() const {
|
||||
return PSH->StreamIndex;
|
||||
}
|
||||
|
||||
uint32_t GSIStreamBuilder::getGlobalsStreamIndex() const {
|
||||
return GSH->StreamIndex;
|
||||
}
|
||||
|
||||
void GSIStreamBuilder::addPublicSymbol(const PublicSym32 &Pub) {
|
||||
PSH->addSymbol(Pub, Msf);
|
||||
}
|
||||
|
||||
void GSIStreamBuilder::addGlobalSymbol(const ProcRefSym &Sym) {
|
||||
GSH->addSymbol(Sym, Msf);
|
||||
}
|
||||
|
||||
void GSIStreamBuilder::addGlobalSymbol(const DataSym &Sym) {
|
||||
GSH->addSymbol(Sym, Msf);
|
||||
}
|
||||
|
||||
void GSIStreamBuilder::addGlobalSymbol(const ConstantSym &Sym) {
|
||||
GSH->addSymbol(Sym, Msf);
|
||||
}
|
||||
|
||||
void GSIStreamBuilder::addGlobalSymbol(const UDTSym &Sym) {
|
||||
GSH->addSymbol(Sym, Msf);
|
||||
}
|
||||
|
||||
void GSIStreamBuilder::addGlobalSymbol(const codeview::CVSymbol &Sym) {
|
||||
GSH->addSymbol(Sym);
|
||||
}
|
||||
|
||||
static Error writeRecords(BinaryStreamWriter &Writer,
|
||||
ArrayRef<CVSymbol> Records) {
|
||||
BinaryItemStream<CVSymbol> ItemStream(support::endianness::little);
|
||||
ItemStream.setItems(Records);
|
||||
BinaryStreamRef RecordsRef(ItemStream);
|
||||
return Writer.writeStreamRef(RecordsRef);
|
||||
}
|
||||
|
||||
Error GSIStreamBuilder::commitSymbolRecordStream(
|
||||
WritableBinaryStreamRef Stream) {
|
||||
BinaryStreamWriter Writer(Stream);
|
||||
|
||||
// Write public symbol records first, followed by global symbol records. This
|
||||
// must match the order that we assume in finalizeMsfLayout when computing
|
||||
// PSHZero and GSHZero.
|
||||
if (auto EC = writeRecords(Writer, PSH->Records))
|
||||
return EC;
|
||||
if (auto EC = writeRecords(Writer, GSH->Records))
|
||||
return EC;
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error GSIStreamBuilder::commitPublicsHashStream(
|
||||
WritableBinaryStreamRef Stream) {
|
||||
BinaryStreamWriter Writer(Stream);
|
||||
PublicsStreamHeader Header;
|
||||
|
||||
// FIXME: Fill these in. They are for incremental linking.
|
||||
Header.NumThunks = 0;
|
||||
Header.SizeOfThunk = 0;
|
||||
Header.ISectThunkTable = 0;
|
||||
Header.OffThunkTable = 0;
|
||||
Header.NumSections = 0;
|
||||
Header.SymHash = PSH->calculateSerializedLength();
|
||||
Header.AddrMap = PSH->Records.size() * 4;
|
||||
if (auto EC = Writer.writeObject(Header))
|
||||
return EC;
|
||||
|
||||
if (auto EC = PSH->commit(Writer))
|
||||
return EC;
|
||||
|
||||
std::vector<ulittle32_t> AddrMap = computeAddrMap(PSH->Records);
|
||||
if (auto EC = Writer.writeArray(makeArrayRef(AddrMap)))
|
||||
return EC;
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error GSIStreamBuilder::commitGlobalsHashStream(
|
||||
WritableBinaryStreamRef Stream) {
|
||||
BinaryStreamWriter Writer(Stream);
|
||||
return GSH->commit(Writer);
|
||||
}
|
||||
|
||||
Error GSIStreamBuilder::commit(const msf::MSFLayout &Layout,
|
||||
WritableBinaryStreamRef Buffer) {
|
||||
auto GS = WritableMappedBlockStream::createIndexedStream(
|
||||
Layout, Buffer, getGlobalsStreamIndex(), Msf.getAllocator());
|
||||
auto PS = WritableMappedBlockStream::createIndexedStream(
|
||||
Layout, Buffer, getPublicsStreamIndex(), Msf.getAllocator());
|
||||
auto PRS = WritableMappedBlockStream::createIndexedStream(
|
||||
Layout, Buffer, getRecordStreamIdx(), Msf.getAllocator());
|
||||
|
||||
if (auto EC = commitSymbolRecordStream(*PRS))
|
||||
return EC;
|
||||
if (auto EC = commitGlobalsHashStream(*GS))
|
||||
return EC;
|
||||
if (auto EC = commitPublicsHashStream(*PS))
|
||||
return EC;
|
||||
return Error::success();
|
||||
}
|
@ -1,124 +0,0 @@
|
||||
//===- 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 (HashHdr->HrSize > 0)
|
||||
if (auto EC = readGSIHashBuckets(HashBuckets, HashBitmap, HashHdr, Reader))
|
||||
return EC;
|
||||
return Error::success();
|
||||
}
|
86
external/llvm/lib/DebugInfo/PDB/Native/Hash.cpp
vendored
86
external/llvm/lib/DebugInfo/PDB/Native/Hash.cpp
vendored
@ -1,86 +0,0 @@
|
||||
//===- Hash.cpp - PDB Hash Functions --------------------------------------===//
|
||||
//
|
||||
// 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/Hash.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
#include "llvm/Support/JamCRC.h"
|
||||
#include <cstdint>
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::support;
|
||||
|
||||
// Corresponds to `Hasher::lhashPbCb` in PDB/include/misc.h.
|
||||
// Used for name hash table and TPI/IPI hashes.
|
||||
uint32_t pdb::hashStringV1(StringRef Str) {
|
||||
uint32_t Result = 0;
|
||||
uint32_t Size = Str.size();
|
||||
|
||||
ArrayRef<ulittle32_t> Longs(reinterpret_cast<const ulittle32_t *>(Str.data()),
|
||||
Size / 4);
|
||||
|
||||
for (auto Value : Longs)
|
||||
Result ^= Value;
|
||||
|
||||
const uint8_t *Remainder = reinterpret_cast<const uint8_t *>(Longs.end());
|
||||
uint32_t RemainderSize = Size % 4;
|
||||
|
||||
// Maximum of 3 bytes left. Hash a 2 byte word if possible, then hash the
|
||||
// possibly remaining 1 byte.
|
||||
if (RemainderSize >= 2) {
|
||||
uint16_t Value = *reinterpret_cast<const ulittle16_t *>(Remainder);
|
||||
Result ^= static_cast<uint32_t>(Value);
|
||||
Remainder += 2;
|
||||
RemainderSize -= 2;
|
||||
}
|
||||
|
||||
// hash possible odd byte
|
||||
if (RemainderSize == 1) {
|
||||
Result ^= *(Remainder++);
|
||||
}
|
||||
|
||||
const uint32_t toLowerMask = 0x20202020;
|
||||
Result |= toLowerMask;
|
||||
Result ^= (Result >> 11);
|
||||
|
||||
return Result ^ (Result >> 16);
|
||||
}
|
||||
|
||||
// Corresponds to `HasherV2::HashULONG` in PDB/include/misc.h.
|
||||
// Used for name hash table.
|
||||
uint32_t pdb::hashStringV2(StringRef Str) {
|
||||
uint32_t Hash = 0xb170a1bf;
|
||||
|
||||
ArrayRef<char> Buffer(Str.begin(), Str.end());
|
||||
|
||||
ArrayRef<ulittle32_t> Items(
|
||||
reinterpret_cast<const ulittle32_t *>(Buffer.data()),
|
||||
Buffer.size() / sizeof(ulittle32_t));
|
||||
for (ulittle32_t Item : Items) {
|
||||
Hash += Item;
|
||||
Hash += (Hash << 10);
|
||||
Hash ^= (Hash >> 6);
|
||||
}
|
||||
Buffer = Buffer.slice(Items.size() * sizeof(ulittle32_t));
|
||||
for (uint8_t Item : Buffer) {
|
||||
Hash += Item;
|
||||
Hash += (Hash << 10);
|
||||
Hash ^= (Hash >> 6);
|
||||
}
|
||||
|
||||
return Hash * 1664525U + 1013904223U;
|
||||
}
|
||||
|
||||
// Corresponds to `SigForPbCb` in langapi/shared/crc32.h.
|
||||
uint32_t pdb::hashBufferV8(ArrayRef<uint8_t> Buf) {
|
||||
JamCRC JC(/*Init=*/0U);
|
||||
JC.update(makeArrayRef<char>(reinterpret_cast<const char *>(Buf.data()),
|
||||
Buf.size()));
|
||||
return JC.getCRC();
|
||||
}
|
308
external/llvm/lib/DebugInfo/PDB/Native/HashTable.cpp
vendored
308
external/llvm/lib/DebugInfo/PDB/Native/HashTable.cpp
vendored
@ -1,308 +0,0 @@
|
||||
//===- HashTable.cpp - PDB Hash Table -------------------------------------===//
|
||||
//
|
||||
// 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/HashTable.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/RawError.h"
|
||||
#include "llvm/Support/BinaryStreamReader.h"
|
||||
#include "llvm/Support/BinaryStreamWriter.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::pdb;
|
||||
|
||||
HashTable::HashTable() : HashTable(8) {}
|
||||
|
||||
HashTable::HashTable(uint32_t Capacity) { Buckets.resize(Capacity); }
|
||||
|
||||
Error HashTable::load(BinaryStreamReader &Stream) {
|
||||
const Header *H;
|
||||
if (auto EC = Stream.readObject(H))
|
||||
return EC;
|
||||
if (H->Capacity == 0)
|
||||
return make_error<RawError>(raw_error_code::corrupt_file,
|
||||
"Invalid Hash Table Capacity");
|
||||
if (H->Size > maxLoad(H->Capacity))
|
||||
return make_error<RawError>(raw_error_code::corrupt_file,
|
||||
"Invalid Hash Table Size");
|
||||
|
||||
Buckets.resize(H->Capacity);
|
||||
|
||||
if (auto EC = readSparseBitVector(Stream, Present))
|
||||
return EC;
|
||||
if (Present.count() != H->Size)
|
||||
return make_error<RawError>(raw_error_code::corrupt_file,
|
||||
"Present bit vector does not match size!");
|
||||
|
||||
if (auto EC = readSparseBitVector(Stream, Deleted))
|
||||
return EC;
|
||||
if (Present.intersects(Deleted))
|
||||
return make_error<RawError>(raw_error_code::corrupt_file,
|
||||
"Present bit vector interesects deleted!");
|
||||
|
||||
for (uint32_t P : Present) {
|
||||
if (auto EC = Stream.readInteger(Buckets[P].first))
|
||||
return EC;
|
||||
if (auto EC = Stream.readInteger(Buckets[P].second))
|
||||
return EC;
|
||||
}
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
uint32_t HashTable::calculateSerializedLength() const {
|
||||
uint32_t Size = sizeof(Header);
|
||||
|
||||
int NumBitsP = Present.find_last() + 1;
|
||||
int NumBitsD = Deleted.find_last() + 1;
|
||||
|
||||
// Present bit set number of words, followed by that many actual words.
|
||||
Size += sizeof(uint32_t);
|
||||
Size += alignTo(NumBitsP, sizeof(uint32_t));
|
||||
|
||||
// Deleted bit set number of words, followed by that many actual words.
|
||||
Size += sizeof(uint32_t);
|
||||
Size += alignTo(NumBitsD, sizeof(uint32_t));
|
||||
|
||||
// One (Key, Value) pair for each entry Present.
|
||||
Size += 2 * sizeof(uint32_t) * size();
|
||||
|
||||
return Size;
|
||||
}
|
||||
|
||||
Error HashTable::commit(BinaryStreamWriter &Writer) const {
|
||||
Header H;
|
||||
H.Size = size();
|
||||
H.Capacity = capacity();
|
||||
if (auto EC = Writer.writeObject(H))
|
||||
return EC;
|
||||
|
||||
if (auto EC = writeSparseBitVector(Writer, Present))
|
||||
return EC;
|
||||
|
||||
if (auto EC = writeSparseBitVector(Writer, Deleted))
|
||||
return EC;
|
||||
|
||||
for (const auto &Entry : *this) {
|
||||
if (auto EC = Writer.writeInteger(Entry.first))
|
||||
return EC;
|
||||
if (auto EC = Writer.writeInteger(Entry.second))
|
||||
return EC;
|
||||
}
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
void HashTable::clear() {
|
||||
Buckets.resize(8);
|
||||
Present.clear();
|
||||
Deleted.clear();
|
||||
}
|
||||
|
||||
uint32_t HashTable::capacity() const { return Buckets.size(); }
|
||||
|
||||
uint32_t HashTable::size() const { return Present.count(); }
|
||||
|
||||
HashTableIterator HashTable::begin() const { return HashTableIterator(*this); }
|
||||
|
||||
HashTableIterator HashTable::end() const {
|
||||
return HashTableIterator(*this, 0, true);
|
||||
}
|
||||
|
||||
HashTableIterator HashTable::find(uint32_t K) {
|
||||
uint32_t H = K % capacity();
|
||||
uint32_t I = H;
|
||||
Optional<uint32_t> FirstUnused;
|
||||
do {
|
||||
if (isPresent(I)) {
|
||||
if (Buckets[I].first == K)
|
||||
return HashTableIterator(*this, I, false);
|
||||
} else {
|
||||
if (!FirstUnused)
|
||||
FirstUnused = I;
|
||||
// Insertion occurs via linear probing from the slot hint, and will be
|
||||
// inserted at the first empty / deleted location. Therefore, if we are
|
||||
// probing and find a location that is neither present nor deleted, then
|
||||
// nothing must have EVER been inserted at this location, and thus it is
|
||||
// not possible for a matching value to occur later.
|
||||
if (!isDeleted(I))
|
||||
break;
|
||||
}
|
||||
I = (I + 1) % capacity();
|
||||
} while (I != H);
|
||||
|
||||
// The only way FirstUnused would not be set is if every single entry in the
|
||||
// table were Present. But this would violate the load factor constraints
|
||||
// that we impose, so it should never happen.
|
||||
assert(FirstUnused);
|
||||
return HashTableIterator(*this, *FirstUnused, true);
|
||||
}
|
||||
|
||||
void HashTable::set(uint32_t K, uint32_t V) {
|
||||
auto Entry = find(K);
|
||||
if (Entry != end()) {
|
||||
assert(isPresent(Entry.index()));
|
||||
assert(Buckets[Entry.index()].first == K);
|
||||
// We're updating, no need to do anything special.
|
||||
Buckets[Entry.index()].second = V;
|
||||
return;
|
||||
}
|
||||
|
||||
auto &B = Buckets[Entry.index()];
|
||||
assert(!isPresent(Entry.index()));
|
||||
assert(Entry.isEnd());
|
||||
B.first = K;
|
||||
B.second = V;
|
||||
Present.set(Entry.index());
|
||||
Deleted.reset(Entry.index());
|
||||
|
||||
grow();
|
||||
|
||||
assert(find(K) != end());
|
||||
}
|
||||
|
||||
void HashTable::remove(uint32_t K) {
|
||||
auto Iter = find(K);
|
||||
// It wasn't here to begin with, just exit.
|
||||
if (Iter == end())
|
||||
return;
|
||||
|
||||
assert(Present.test(Iter.index()));
|
||||
assert(!Deleted.test(Iter.index()));
|
||||
Deleted.set(Iter.index());
|
||||
Present.reset(Iter.index());
|
||||
}
|
||||
|
||||
uint32_t HashTable::get(uint32_t K) {
|
||||
auto I = find(K);
|
||||
assert(I != end());
|
||||
return (*I).second;
|
||||
}
|
||||
|
||||
uint32_t HashTable::maxLoad(uint32_t capacity) { return capacity * 2 / 3 + 1; }
|
||||
|
||||
void HashTable::grow() {
|
||||
uint32_t S = size();
|
||||
if (S < maxLoad(capacity()))
|
||||
return;
|
||||
assert(capacity() != UINT32_MAX && "Can't grow Hash table!");
|
||||
|
||||
uint32_t NewCapacity =
|
||||
(capacity() <= INT32_MAX) ? capacity() * 2 : UINT32_MAX;
|
||||
|
||||
// Growing requires rebuilding the table and re-hashing every item. Make a
|
||||
// copy with a larger capacity, insert everything into the copy, then swap
|
||||
// it in.
|
||||
HashTable NewMap(NewCapacity);
|
||||
for (auto I : Present) {
|
||||
NewMap.set(Buckets[I].first, Buckets[I].second);
|
||||
}
|
||||
|
||||
Buckets.swap(NewMap.Buckets);
|
||||
std::swap(Present, NewMap.Present);
|
||||
std::swap(Deleted, NewMap.Deleted);
|
||||
assert(capacity() == NewCapacity);
|
||||
assert(size() == S);
|
||||
}
|
||||
|
||||
Error HashTable::readSparseBitVector(BinaryStreamReader &Stream,
|
||||
SparseBitVector<> &V) {
|
||||
uint32_t NumWords;
|
||||
if (auto EC = Stream.readInteger(NumWords))
|
||||
return joinErrors(
|
||||
std::move(EC),
|
||||
make_error<RawError>(raw_error_code::corrupt_file,
|
||||
"Expected hash table number of words"));
|
||||
|
||||
for (uint32_t I = 0; I != NumWords; ++I) {
|
||||
uint32_t Word;
|
||||
if (auto EC = Stream.readInteger(Word))
|
||||
return joinErrors(std::move(EC),
|
||||
make_error<RawError>(raw_error_code::corrupt_file,
|
||||
"Expected hash table word"));
|
||||
for (unsigned Idx = 0; Idx < 32; ++Idx)
|
||||
if (Word & (1U << Idx))
|
||||
V.set((I * 32) + Idx);
|
||||
}
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error HashTable::writeSparseBitVector(BinaryStreamWriter &Writer,
|
||||
SparseBitVector<> &Vec) {
|
||||
int ReqBits = Vec.find_last() + 1;
|
||||
uint32_t NumWords = alignTo(ReqBits, sizeof(uint32_t)) / sizeof(uint32_t);
|
||||
if (auto EC = Writer.writeInteger(NumWords))
|
||||
return joinErrors(
|
||||
std::move(EC),
|
||||
make_error<RawError>(raw_error_code::corrupt_file,
|
||||
"Could not write linear map number of words"));
|
||||
|
||||
uint32_t Idx = 0;
|
||||
for (uint32_t I = 0; I != NumWords; ++I) {
|
||||
uint32_t Word = 0;
|
||||
for (uint32_t WordIdx = 0; WordIdx < 32; ++WordIdx, ++Idx) {
|
||||
if (Vec.test(Idx))
|
||||
Word |= (1 << WordIdx);
|
||||
}
|
||||
if (auto EC = Writer.writeInteger(Word))
|
||||
return joinErrors(std::move(EC), make_error<RawError>(
|
||||
raw_error_code::corrupt_file,
|
||||
"Could not write linear map word"));
|
||||
}
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
HashTableIterator::HashTableIterator(const HashTable &Map, uint32_t Index,
|
||||
bool IsEnd)
|
||||
: Map(&Map), Index(Index), IsEnd(IsEnd) {}
|
||||
|
||||
HashTableIterator::HashTableIterator(const HashTable &Map) : Map(&Map) {
|
||||
int I = Map.Present.find_first();
|
||||
if (I == -1) {
|
||||
Index = 0;
|
||||
IsEnd = true;
|
||||
} else {
|
||||
Index = static_cast<uint32_t>(I);
|
||||
IsEnd = false;
|
||||
}
|
||||
}
|
||||
|
||||
HashTableIterator &HashTableIterator::operator=(const HashTableIterator &R) {
|
||||
Map = R.Map;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool HashTableIterator::operator==(const HashTableIterator &R) const {
|
||||
if (IsEnd && R.IsEnd)
|
||||
return true;
|
||||
if (IsEnd != R.IsEnd)
|
||||
return false;
|
||||
|
||||
return (Map == R.Map) && (Index == R.Index);
|
||||
}
|
||||
|
||||
const std::pair<uint32_t, uint32_t> &HashTableIterator::operator*() const {
|
||||
assert(Map->Present.test(Index));
|
||||
return Map->Buckets[Index];
|
||||
}
|
||||
|
||||
HashTableIterator &HashTableIterator::operator++() {
|
||||
while (Index < Map->Buckets.size()) {
|
||||
++Index;
|
||||
if (Map->Present.test(Index))
|
||||
return *this;
|
||||
}
|
||||
|
||||
IsEnd = true;
|
||||
return *this;
|
||||
}
|
@ -1,137 +0,0 @@
|
||||
//===- InfoStream.cpp - PDB Info Stream (Stream 1) Access -------*- 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/InfoStream.h"
|
||||
#include "llvm/ADT/BitVector.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/RawConstants.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/RawError.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/RawTypes.h"
|
||||
#include "llvm/Support/BinaryStreamReader.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::codeview;
|
||||
using namespace llvm::msf;
|
||||
using namespace llvm::pdb;
|
||||
|
||||
InfoStream::InfoStream(std::unique_ptr<MappedBlockStream> Stream)
|
||||
: Stream(std::move(Stream)) {}
|
||||
|
||||
Error InfoStream::reload() {
|
||||
BinaryStreamReader Reader(*Stream);
|
||||
|
||||
const InfoStreamHeader *H;
|
||||
if (auto EC = Reader.readObject(H))
|
||||
return joinErrors(
|
||||
std::move(EC),
|
||||
make_error<RawError>(raw_error_code::corrupt_file,
|
||||
"PDB Stream does not contain a header."));
|
||||
|
||||
switch (H->Version) {
|
||||
case PdbImplVC70:
|
||||
case PdbImplVC80:
|
||||
case PdbImplVC110:
|
||||
case PdbImplVC140:
|
||||
break;
|
||||
default:
|
||||
return make_error<RawError>(raw_error_code::corrupt_file,
|
||||
"Unsupported PDB stream version.");
|
||||
}
|
||||
|
||||
Version = H->Version;
|
||||
Signature = H->Signature;
|
||||
Age = H->Age;
|
||||
Guid = H->Guid;
|
||||
|
||||
uint32_t Offset = Reader.getOffset();
|
||||
if (auto EC = NamedStreams.load(Reader))
|
||||
return EC;
|
||||
uint32_t NewOffset = Reader.getOffset();
|
||||
NamedStreamMapByteSize = NewOffset - Offset;
|
||||
|
||||
Reader.setOffset(Offset);
|
||||
if (auto EC = Reader.readSubstream(SubNamedStreams, NamedStreamMapByteSize))
|
||||
return EC;
|
||||
|
||||
bool Stop = false;
|
||||
while (!Stop && !Reader.empty()) {
|
||||
PdbRaw_FeatureSig Sig;
|
||||
if (auto EC = Reader.readEnum(Sig))
|
||||
return EC;
|
||||
// Since this value comes from a file, it's possible we have some strange
|
||||
// value which doesn't correspond to any value. We don't want to warn on
|
||||
// -Wcovered-switch-default in this case, so switch on the integral value
|
||||
// instead of the enumeration value.
|
||||
switch (uint32_t(Sig)) {
|
||||
case uint32_t(PdbRaw_FeatureSig::VC110):
|
||||
// No other flags for VC110 PDB.
|
||||
Stop = true;
|
||||
LLVM_FALLTHROUGH;
|
||||
case uint32_t(PdbRaw_FeatureSig::VC140):
|
||||
Features |= PdbFeatureContainsIdStream;
|
||||
break;
|
||||
case uint32_t(PdbRaw_FeatureSig::NoTypeMerge):
|
||||
Features |= PdbFeatureNoTypeMerging;
|
||||
break;
|
||||
case uint32_t(PdbRaw_FeatureSig::MinimalDebugInfo):
|
||||
Features |= PdbFeatureMinimalDebugInfo;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
FeatureSignatures.push_back(Sig);
|
||||
}
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
uint32_t InfoStream::getStreamSize() const { return Stream->getLength(); }
|
||||
|
||||
uint32_t InfoStream::getNamedStreamIndex(llvm::StringRef Name) const {
|
||||
uint32_t Result;
|
||||
if (!NamedStreams.get(Name, Result))
|
||||
return 0;
|
||||
return Result;
|
||||
}
|
||||
|
||||
iterator_range<StringMapConstIterator<uint32_t>>
|
||||
InfoStream::named_streams() const {
|
||||
return NamedStreams.entries();
|
||||
}
|
||||
|
||||
bool InfoStream::containsIdStream() const {
|
||||
return !!(Features & PdbFeatureContainsIdStream);
|
||||
}
|
||||
|
||||
PdbRaw_ImplVer InfoStream::getVersion() const {
|
||||
return static_cast<PdbRaw_ImplVer>(Version);
|
||||
}
|
||||
|
||||
uint32_t InfoStream::getSignature() const { return Signature; }
|
||||
|
||||
uint32_t InfoStream::getAge() const { return Age; }
|
||||
|
||||
GUID InfoStream::getGuid() const { return Guid; }
|
||||
|
||||
uint32_t InfoStream::getNamedStreamMapByteSize() const {
|
||||
return NamedStreamMapByteSize;
|
||||
}
|
||||
|
||||
PdbRaw_Features InfoStream::getFeatures() const { return Features; }
|
||||
|
||||
ArrayRef<PdbRaw_FeatureSig> InfoStream::getFeatureSignatures() const {
|
||||
return FeatureSignatures;
|
||||
}
|
||||
|
||||
const NamedStreamMap &InfoStream::getNamedStreams() const {
|
||||
return NamedStreams;
|
||||
}
|
||||
|
||||
BinarySubstreamRef InfoStream::getNamedStreamsBuffer() const {
|
||||
return SubNamedStreams;
|
||||
}
|
@ -1,74 +0,0 @@
|
||||
//===- InfoStreamBuilder.cpp - PDB Info Stream Creation ---------*- 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/InfoStreamBuilder.h"
|
||||
|
||||
#include "llvm/DebugInfo/MSF/MSFBuilder.h"
|
||||
#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/NamedStreamMap.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/RawError.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/RawTypes.h"
|
||||
#include "llvm/Support/BinaryStreamWriter.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::codeview;
|
||||
using namespace llvm::msf;
|
||||
using namespace llvm::pdb;
|
||||
|
||||
InfoStreamBuilder::InfoStreamBuilder(msf::MSFBuilder &Msf,
|
||||
NamedStreamMap &NamedStreams)
|
||||
: Msf(Msf), Ver(PdbRaw_ImplVer::PdbImplVC70), Sig(-1), Age(0),
|
||||
NamedStreams(NamedStreams) {}
|
||||
|
||||
void InfoStreamBuilder::setVersion(PdbRaw_ImplVer V) { Ver = V; }
|
||||
|
||||
void InfoStreamBuilder::setSignature(uint32_t S) { Sig = S; }
|
||||
|
||||
void InfoStreamBuilder::setAge(uint32_t A) { Age = A; }
|
||||
|
||||
void InfoStreamBuilder::setGuid(GUID G) { Guid = G; }
|
||||
|
||||
void InfoStreamBuilder::addFeature(PdbRaw_FeatureSig Sig) {
|
||||
Features.push_back(Sig);
|
||||
}
|
||||
|
||||
Error InfoStreamBuilder::finalizeMsfLayout() {
|
||||
uint32_t Length = sizeof(InfoStreamHeader) + NamedStreams.finalize() +
|
||||
(Features.size() + 1) * sizeof(uint32_t);
|
||||
if (auto EC = Msf.setStreamSize(StreamPDB, Length))
|
||||
return EC;
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error InfoStreamBuilder::commit(const msf::MSFLayout &Layout,
|
||||
WritableBinaryStreamRef Buffer) const {
|
||||
auto InfoS = WritableMappedBlockStream::createIndexedStream(
|
||||
Layout, Buffer, StreamPDB, Msf.getAllocator());
|
||||
BinaryStreamWriter Writer(*InfoS);
|
||||
|
||||
InfoStreamHeader H;
|
||||
H.Age = Age;
|
||||
H.Signature = Sig;
|
||||
H.Version = Ver;
|
||||
H.Guid = Guid;
|
||||
if (auto EC = Writer.writeObject(H))
|
||||
return EC;
|
||||
|
||||
if (auto EC = NamedStreams.commit(Writer))
|
||||
return EC;
|
||||
if (auto EC = Writer.writeInteger(0))
|
||||
return EC;
|
||||
for (auto E : Features) {
|
||||
if (auto EC = Writer.writeEnum(E))
|
||||
return EC;
|
||||
}
|
||||
return Error::success();
|
||||
}
|
@ -1,123 +0,0 @@
|
||||
//===- ModuleDebugStream.cpp - PDB Module Info Stream Access --------------===//
|
||||
//
|
||||
// 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/ModuleDebugStream.h"
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/DebugInfo/CodeView/CodeView.h"
|
||||
#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
|
||||
#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/RawError.h"
|
||||
#include "llvm/Support/BinaryStreamReader.h"
|
||||
#include "llvm/Support/BinaryStreamRef.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::codeview;
|
||||
using namespace llvm::msf;
|
||||
using namespace llvm::pdb;
|
||||
|
||||
ModuleDebugStreamRef::ModuleDebugStreamRef(
|
||||
const DbiModuleDescriptor &Module,
|
||||
std::unique_ptr<MappedBlockStream> Stream)
|
||||
: Mod(Module), Stream(std::move(Stream)) {}
|
||||
|
||||
ModuleDebugStreamRef::~ModuleDebugStreamRef() = default;
|
||||
|
||||
Error ModuleDebugStreamRef::reload() {
|
||||
BinaryStreamReader Reader(*Stream);
|
||||
|
||||
uint32_t SymbolSize = Mod.getSymbolDebugInfoByteSize();
|
||||
uint32_t C11Size = Mod.getC11LineInfoByteSize();
|
||||
uint32_t C13Size = Mod.getC13LineInfoByteSize();
|
||||
|
||||
if (C11Size > 0 && C13Size > 0)
|
||||
return make_error<RawError>(raw_error_code::corrupt_file,
|
||||
"Module has both C11 and C13 line info");
|
||||
|
||||
BinaryStreamRef S;
|
||||
|
||||
if (auto EC = Reader.readInteger(Signature))
|
||||
return EC;
|
||||
if (auto EC = Reader.readSubstream(SymbolsSubstream, SymbolSize - 4))
|
||||
return EC;
|
||||
if (auto EC = Reader.readSubstream(C11LinesSubstream, C11Size))
|
||||
return EC;
|
||||
if (auto EC = Reader.readSubstream(C13LinesSubstream, C13Size))
|
||||
return EC;
|
||||
|
||||
BinaryStreamReader SymbolReader(SymbolsSubstream.StreamData);
|
||||
if (auto EC =
|
||||
SymbolReader.readArray(SymbolArray, SymbolReader.bytesRemaining()))
|
||||
return EC;
|
||||
|
||||
BinaryStreamReader SubsectionsReader(C13LinesSubstream.StreamData);
|
||||
if (auto EC = SubsectionsReader.readArray(Subsections,
|
||||
SubsectionsReader.bytesRemaining()))
|
||||
return EC;
|
||||
|
||||
uint32_t GlobalRefsSize;
|
||||
if (auto EC = Reader.readInteger(GlobalRefsSize))
|
||||
return EC;
|
||||
if (auto EC = Reader.readSubstream(GlobalRefsSubstream, GlobalRefsSize))
|
||||
return EC;
|
||||
if (Reader.bytesRemaining() > 0)
|
||||
return make_error<RawError>(raw_error_code::corrupt_file,
|
||||
"Unexpected bytes in module stream.");
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
BinarySubstreamRef ModuleDebugStreamRef::getSymbolsSubstream() const {
|
||||
return SymbolsSubstream;
|
||||
}
|
||||
|
||||
BinarySubstreamRef ModuleDebugStreamRef::getC11LinesSubstream() const {
|
||||
return C11LinesSubstream;
|
||||
}
|
||||
|
||||
BinarySubstreamRef ModuleDebugStreamRef::getC13LinesSubstream() const {
|
||||
return C13LinesSubstream;
|
||||
}
|
||||
|
||||
BinarySubstreamRef ModuleDebugStreamRef::getGlobalRefsSubstream() const {
|
||||
return GlobalRefsSubstream;
|
||||
}
|
||||
|
||||
iterator_range<codeview::CVSymbolArray::Iterator>
|
||||
ModuleDebugStreamRef::symbols(bool *HadError) const {
|
||||
return make_range(SymbolArray.begin(HadError), SymbolArray.end());
|
||||
}
|
||||
|
||||
iterator_range<ModuleDebugStreamRef::DebugSubsectionIterator>
|
||||
ModuleDebugStreamRef::subsections() const {
|
||||
return make_range(Subsections.begin(), Subsections.end());
|
||||
}
|
||||
|
||||
bool ModuleDebugStreamRef::hasDebugSubsections() const {
|
||||
return !C13LinesSubstream.empty();
|
||||
}
|
||||
|
||||
Error ModuleDebugStreamRef::commit() { return Error::success(); }
|
||||
|
||||
Expected<codeview::DebugChecksumsSubsectionRef>
|
||||
ModuleDebugStreamRef::findChecksumsSubsection() const {
|
||||
codeview::DebugChecksumsSubsectionRef Result;
|
||||
for (const auto &SS : subsections()) {
|
||||
if (SS.kind() != DebugSubsectionKind::FileChecksums)
|
||||
continue;
|
||||
|
||||
if (auto EC = Result.initialize(SS.getRecordData()))
|
||||
return std::move(EC);
|
||||
return Result;
|
||||
}
|
||||
return Result;
|
||||
}
|
@ -1,152 +0,0 @@
|
||||
//===- 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/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;
|
||||
|
||||
// FIXME: This shouldn't be necessary, but if we insert the strings in any
|
||||
// other order, cvdump cannot read the generated name map. This suggests that
|
||||
// we may be using the wrong hash function. A closer inspection of the cvdump
|
||||
// source code may reveal something, but for now this at least makes us work,
|
||||
// even if only by accident.
|
||||
static constexpr const char *OrderedStreamNames[] = {"/LinkInfo", "/names",
|
||||
"/src/headerblock"};
|
||||
|
||||
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;
|
||||
|
||||
for (const auto &Name : OrderedStreamNames) {
|
||||
auto Item = Mapping.find(Name);
|
||||
if (Item == Mapping.end())
|
||||
continue;
|
||||
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 &Name : OrderedStreamNames) {
|
||||
auto Item = Mapping.find(Name);
|
||||
if (Item == Mapping.end())
|
||||
continue;
|
||||
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);
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
//===- NativeBuiltinSymbol.cpp ------------------------------------ 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/NativeBuiltinSymbol.h"
|
||||
|
||||
|
||||
namespace llvm {
|
||||
namespace pdb {
|
||||
|
||||
NativeBuiltinSymbol::NativeBuiltinSymbol(NativeSession &PDBSession,
|
||||
SymIndexId Id, PDB_BuiltinType T,
|
||||
uint64_t L)
|
||||
: NativeRawSymbol(PDBSession, Id), Session(PDBSession), Type(T), Length(L) {
|
||||
}
|
||||
|
||||
NativeBuiltinSymbol::~NativeBuiltinSymbol() {}
|
||||
|
||||
std::unique_ptr<NativeRawSymbol> NativeBuiltinSymbol::clone() const {
|
||||
return llvm::make_unique<NativeBuiltinSymbol>(Session, SymbolId, Type, Length);
|
||||
}
|
||||
|
||||
void NativeBuiltinSymbol::dump(raw_ostream &OS, int Indent) const {
|
||||
// TODO: Apparently nothing needs this yet.
|
||||
}
|
||||
|
||||
PDB_SymType NativeBuiltinSymbol::getSymTag() const {
|
||||
return PDB_SymType::BuiltinType;
|
||||
}
|
||||
|
||||
PDB_BuiltinType NativeBuiltinSymbol::getBuiltinType() const { return Type; }
|
||||
|
||||
bool NativeBuiltinSymbol::isConstType() const { return false; }
|
||||
|
||||
uint64_t NativeBuiltinSymbol::getLength() const { return Length; }
|
||||
|
||||
bool NativeBuiltinSymbol::isUnalignedType() const { return false; }
|
||||
|
||||
bool NativeBuiltinSymbol::isVolatileType() const { return false; }
|
||||
|
||||
} // namespace pdb
|
||||
} // namespace llvm
|
@ -1,50 +0,0 @@
|
||||
//===- NativeCompilandSymbol.cpp - Native impl for compilands ---*- 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/NativeCompilandSymbol.h"
|
||||
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace pdb {
|
||||
|
||||
NativeCompilandSymbol::NativeCompilandSymbol(NativeSession &Session,
|
||||
SymIndexId SymbolId,
|
||||
DbiModuleDescriptor MI)
|
||||
: NativeRawSymbol(Session, SymbolId), Module(MI) {}
|
||||
|
||||
PDB_SymType NativeCompilandSymbol::getSymTag() const {
|
||||
return PDB_SymType::Compiland;
|
||||
}
|
||||
|
||||
std::unique_ptr<NativeRawSymbol> NativeCompilandSymbol::clone() const {
|
||||
return llvm::make_unique<NativeCompilandSymbol>(Session, SymbolId, Module);
|
||||
}
|
||||
|
||||
bool NativeCompilandSymbol::isEditAndContinueEnabled() const {
|
||||
return Module.hasECInfo();
|
||||
}
|
||||
|
||||
uint32_t NativeCompilandSymbol::getLexicalParentId() const { return 0; }
|
||||
|
||||
// The usage of getObjFileName for getLibraryName and getModuleName for getName
|
||||
// may seem backwards, but it is consistent with DIA, which is what this API
|
||||
// was modeled after. We may rename these methods later to try to eliminate
|
||||
// this potential confusion.
|
||||
|
||||
std::string NativeCompilandSymbol::getLibraryName() const {
|
||||
return Module.getObjFileName();
|
||||
}
|
||||
|
||||
std::string NativeCompilandSymbol::getName() const {
|
||||
return Module.getModuleName();
|
||||
}
|
||||
|
||||
} // namespace pdb
|
||||
} // namespace llvm
|
@ -1,51 +0,0 @@
|
||||
//==- NativeEnumModules.cpp - Native Symbol Enumerator impl ------*- 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/NativeEnumModules.h"
|
||||
|
||||
#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/DbiModuleList.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/NativeCompilandSymbol.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbol.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace pdb {
|
||||
|
||||
NativeEnumModules::NativeEnumModules(NativeSession &PDBSession,
|
||||
const DbiModuleList &Modules,
|
||||
uint32_t Index)
|
||||
: Session(PDBSession), Modules(Modules), Index(Index) {}
|
||||
|
||||
uint32_t NativeEnumModules::getChildCount() const {
|
||||
return static_cast<uint32_t>(Modules.getModuleCount());
|
||||
}
|
||||
|
||||
std::unique_ptr<PDBSymbol>
|
||||
NativeEnumModules::getChildAtIndex(uint32_t Index) const {
|
||||
if (Index >= Modules.getModuleCount())
|
||||
return nullptr;
|
||||
return Session.createCompilandSymbol(Modules.getModuleDescriptor(Index));
|
||||
}
|
||||
|
||||
std::unique_ptr<PDBSymbol> NativeEnumModules::getNext() {
|
||||
if (Index >= Modules.getModuleCount())
|
||||
return nullptr;
|
||||
return getChildAtIndex(Index++);
|
||||
}
|
||||
|
||||
void NativeEnumModules::reset() { Index = 0; }
|
||||
|
||||
NativeEnumModules *NativeEnumModules::clone() const {
|
||||
return new NativeEnumModules(Session, Modules, Index);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,108 +0,0 @@
|
||||
//===- NativeEnumSymbol.cpp - info about enum type --------------*- 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/NativeEnumSymbol.h"
|
||||
|
||||
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
|
||||
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::pdb;
|
||||
|
||||
NativeEnumSymbol::NativeEnumSymbol(NativeSession &Session, SymIndexId Id,
|
||||
const codeview::CVType &CVT)
|
||||
: NativeRawSymbol(Session, Id), CV(CVT),
|
||||
Record(codeview::TypeRecordKind::Enum) {
|
||||
assert(CV.kind() == codeview::TypeLeafKind::LF_ENUM);
|
||||
cantFail(visitTypeRecord(CV, *this));
|
||||
}
|
||||
|
||||
NativeEnumSymbol::~NativeEnumSymbol() {}
|
||||
|
||||
std::unique_ptr<NativeRawSymbol> NativeEnumSymbol::clone() const {
|
||||
return llvm::make_unique<NativeEnumSymbol>(Session, SymbolId, CV);
|
||||
}
|
||||
|
||||
std::unique_ptr<IPDBEnumSymbols>
|
||||
NativeEnumSymbol::findChildren(PDB_SymType Type) const {
|
||||
switch (Type) {
|
||||
case PDB_SymType::Data: {
|
||||
// TODO(amccarth): Provide an actual implementation.
|
||||
return nullptr;
|
||||
}
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
Error NativeEnumSymbol::visitKnownRecord(codeview::CVType &CVR,
|
||||
codeview::EnumRecord &ER) {
|
||||
Record = ER;
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error NativeEnumSymbol::visitKnownMember(codeview::CVMemberRecord &CVM,
|
||||
codeview::EnumeratorRecord &R) {
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
PDB_SymType NativeEnumSymbol::getSymTag() const { return PDB_SymType::Enum; }
|
||||
|
||||
uint32_t NativeEnumSymbol::getClassParentId() const { return 0xFFFFFFFF; }
|
||||
|
||||
uint32_t NativeEnumSymbol::getUnmodifiedTypeId() const { return 0; }
|
||||
|
||||
bool NativeEnumSymbol::hasConstructor() const {
|
||||
return bool(Record.getOptions() &
|
||||
codeview::ClassOptions::HasConstructorOrDestructor);
|
||||
}
|
||||
|
||||
bool NativeEnumSymbol::hasAssignmentOperator() const {
|
||||
return bool(Record.getOptions() &
|
||||
codeview::ClassOptions::HasOverloadedAssignmentOperator);
|
||||
}
|
||||
|
||||
bool NativeEnumSymbol::hasCastOperator() const {
|
||||
return bool(Record.getOptions() &
|
||||
codeview::ClassOptions::HasConversionOperator);
|
||||
}
|
||||
|
||||
uint64_t NativeEnumSymbol::getLength() const {
|
||||
const auto Id = Session.findSymbolByTypeIndex(Record.getUnderlyingType());
|
||||
const auto UnderlyingType =
|
||||
Session.getConcreteSymbolById<PDBSymbolTypeBuiltin>(Id);
|
||||
return UnderlyingType ? UnderlyingType->getLength() : 0;
|
||||
}
|
||||
|
||||
std::string NativeEnumSymbol::getName() const { return Record.getName(); }
|
||||
|
||||
bool NativeEnumSymbol::isNested() const {
|
||||
return bool(Record.getOptions() & codeview::ClassOptions::Nested);
|
||||
}
|
||||
|
||||
bool NativeEnumSymbol::hasOverloadedOperator() const {
|
||||
return bool(Record.getOptions() &
|
||||
codeview::ClassOptions::HasOverloadedOperator);
|
||||
}
|
||||
|
||||
bool NativeEnumSymbol::isPacked() const {
|
||||
return bool(Record.getOptions() & codeview::ClassOptions::Packed);
|
||||
}
|
||||
|
||||
bool NativeEnumSymbol::isScoped() const {
|
||||
return bool(Record.getOptions() & codeview::ClassOptions::Scoped);
|
||||
}
|
||||
|
||||
uint32_t NativeEnumSymbol::getTypeId() const {
|
||||
return Session.findSymbolByTypeIndex(Record.getUnderlyingType());
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
//==- NativeEnumTypes.cpp - Native Type Enumerator impl ----------*- 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/NativeEnumTypes.h"
|
||||
|
||||
#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/NativeEnumSymbol.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbol.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace pdb {
|
||||
|
||||
NativeEnumTypes::NativeEnumTypes(NativeSession &PDBSession,
|
||||
codeview::LazyRandomTypeCollection &Types,
|
||||
codeview::TypeLeafKind Kind)
|
||||
: Matches(), Index(0), Session(PDBSession), Kind(Kind) {
|
||||
for (auto Index = Types.getFirst(); Index;
|
||||
Index = Types.getNext(Index.getValue())) {
|
||||
if (Types.getType(Index.getValue()).kind() == Kind)
|
||||
Matches.push_back(Index.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
NativeEnumTypes::NativeEnumTypes(
|
||||
NativeSession &PDBSession, const std::vector<codeview::TypeIndex> &Matches,
|
||||
codeview::TypeLeafKind Kind)
|
||||
: Matches(Matches), Index(0), Session(PDBSession), Kind(Kind) {}
|
||||
|
||||
uint32_t NativeEnumTypes::getChildCount() const {
|
||||
return static_cast<uint32_t>(Matches.size());
|
||||
}
|
||||
|
||||
std::unique_ptr<PDBSymbol>
|
||||
NativeEnumTypes::getChildAtIndex(uint32_t Index) const {
|
||||
if (Index < Matches.size())
|
||||
return Session.createEnumSymbol(Matches[Index]);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<PDBSymbol> NativeEnumTypes::getNext() {
|
||||
return getChildAtIndex(Index++);
|
||||
}
|
||||
|
||||
void NativeEnumTypes::reset() { Index = 0; }
|
||||
|
||||
NativeEnumTypes *NativeEnumTypes::clone() const {
|
||||
return new NativeEnumTypes(Session, Matches, Kind);
|
||||
}
|
||||
|
||||
} // namespace pdb
|
||||
} // namespace llvm
|
@ -1,86 +0,0 @@
|
||||
//===- NativeExeSymbol.cpp - native impl for PDBSymbolExe -------*- 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/NativeExeSymbol.h"
|
||||
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/NativeEnumModules.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace pdb {
|
||||
|
||||
NativeExeSymbol::NativeExeSymbol(NativeSession &Session, SymIndexId SymbolId)
|
||||
: NativeRawSymbol(Session, SymbolId), File(Session.getPDBFile()) {}
|
||||
|
||||
std::unique_ptr<NativeRawSymbol> NativeExeSymbol::clone() const {
|
||||
return llvm::make_unique<NativeExeSymbol>(Session, SymbolId);
|
||||
}
|
||||
|
||||
std::unique_ptr<IPDBEnumSymbols>
|
||||
NativeExeSymbol::findChildren(PDB_SymType Type) const {
|
||||
switch (Type) {
|
||||
case PDB_SymType::Compiland: {
|
||||
auto Dbi = File.getPDBDbiStream();
|
||||
if (Dbi) {
|
||||
const DbiModuleList &Modules = Dbi->modules();
|
||||
return std::unique_ptr<IPDBEnumSymbols>(
|
||||
new NativeEnumModules(Session, Modules));
|
||||
}
|
||||
consumeError(Dbi.takeError());
|
||||
break;
|
||||
}
|
||||
case PDB_SymType::Enum:
|
||||
return Session.createTypeEnumerator(codeview::LF_ENUM);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint32_t NativeExeSymbol::getAge() const {
|
||||
auto IS = File.getPDBInfoStream();
|
||||
if (IS)
|
||||
return IS->getAge();
|
||||
consumeError(IS.takeError());
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string NativeExeSymbol::getSymbolsFileName() const {
|
||||
return File.getFilePath();
|
||||
}
|
||||
|
||||
codeview::GUID NativeExeSymbol::getGuid() const {
|
||||
auto IS = File.getPDBInfoStream();
|
||||
if (IS)
|
||||
return IS->getGuid();
|
||||
consumeError(IS.takeError());
|
||||
return codeview::GUID{{0}};
|
||||
}
|
||||
|
||||
bool NativeExeSymbol::hasCTypes() const {
|
||||
auto Dbi = File.getPDBDbiStream();
|
||||
if (Dbi)
|
||||
return Dbi->hasCTypes();
|
||||
consumeError(Dbi.takeError());
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NativeExeSymbol::hasPrivateSymbols() const {
|
||||
auto Dbi = File.getPDBDbiStream();
|
||||
if (Dbi)
|
||||
return !Dbi->isStripped();
|
||||
consumeError(Dbi.takeError());
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace pdb
|
||||
} // namespace llvm
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user