Imported Upstream version 6.10.0.49

Former-commit-id: 1d6753294b2993e1fbf92de9366bb9544db4189b
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2020-01-16 16:38:04 +00:00
parent d94e79959b
commit 468663ddbb
48518 changed files with 2789335 additions and 61176 deletions

View File

@ -0,0 +1,90 @@
//===- 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;
}

View File

@ -0,0 +1,179 @@
//===- 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));
}

View File

@ -0,0 +1,280 @@
//===- 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;
}

View File

@ -0,0 +1,349 @@
//===- 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];
}

View File

@ -0,0 +1,396 @@
//===- 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();
}

View File

@ -0,0 +1,38 @@
//===- 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);
}
}
}

View File

@ -0,0 +1,322 @@
//===- 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();
}

View File

@ -0,0 +1,124 @@
//===- 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();
}

View File

@ -0,0 +1,86 @@
//===- 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();
}

View File

@ -0,0 +1,308 @@
//===- 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;
}

View File

@ -0,0 +1,137 @@
//===- 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;
}

View File

@ -0,0 +1,74 @@
//===- 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();
}

View File

@ -0,0 +1,123 @@
//===- 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;
}

View File

@ -0,0 +1,152 @@
//===- 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);
}

View File

@ -0,0 +1,47 @@
//===- 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

View File

@ -0,0 +1,50 @@
//===- 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

View File

@ -0,0 +1,51 @@
//==- 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);
}
}
}

View File

@ -0,0 +1,108 @@
//===- 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());
}

View File

@ -0,0 +1,59 @@
//==- 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

View File

@ -0,0 +1,86 @@
//===- 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