diff options
Diffstat (limited to 'lib/DebugInfo/PDB')
30 files changed, 1290 insertions, 518 deletions
diff --git a/lib/DebugInfo/PDB/CMakeLists.txt b/lib/DebugInfo/PDB/CMakeLists.txt index 0be05e9bda5e..f6a529a69a8b 100644 --- a/lib/DebugInfo/PDB/CMakeLists.txt +++ b/lib/DebugInfo/PDB/CMakeLists.txt @@ -14,13 +14,17 @@ if(LLVM_ENABLE_DIA_SDK) add_pdb_impl_folder(DIA DIA/DIADataStream.cpp DIA/DIAEnumDebugStreams.cpp + DIA/DIAEnumInjectedSources.cpp DIA/DIAEnumLineNumbers.cpp + DIA/DIAEnumSectionContribs.cpp DIA/DIAEnumSourceFiles.cpp DIA/DIAEnumSymbols.cpp DIA/DIAEnumTables.cpp DIA/DIAError.cpp + DIA/DIAInjectedSource.cpp DIA/DIALineNumber.cpp DIA/DIARawSymbol.cpp + DIA/DIASectionContrib.cpp DIA/DIASession.cpp DIA/DIASourceFile.cpp DIA/DIATable.cpp @@ -61,7 +65,8 @@ add_pdb_impl_folder(Native Native/SymbolStream.cpp Native/TpiHashing.cpp Native/TpiStream.cpp - Native/TpiStreamBuilder.cpp) + Native/TpiStreamBuilder.cpp + ) list(APPEND LIBPDB_ADDITIONAL_HEADER_DIRS "${LLVM_MAIN_INCLUDE_DIR}/llvm/DebugInfo/PDB/Native") list(APPEND LIBPDB_ADDITIONAL_HEADER_DIRS "${LLVM_MAIN_INCLUDE_DIR}/llvm/DebugInfo/PDB") diff --git a/lib/DebugInfo/PDB/DIA/DIAEnumInjectedSources.cpp b/lib/DebugInfo/PDB/DIA/DIAEnumInjectedSources.cpp new file mode 100644 index 000000000000..d7c908e04593 --- /dev/null +++ b/lib/DebugInfo/PDB/DIA/DIAEnumInjectedSources.cpp @@ -0,0 +1,52 @@ +//==- DIAEnumSourceFiles.cpp - DIA Source File 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/DIA/DIAEnumInjectedSources.h" +#include "llvm/DebugInfo/PDB/DIA/DIAInjectedSource.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" + +using namespace llvm; +using namespace llvm::pdb; + +DIAEnumInjectedSources::DIAEnumInjectedSources( + const DIASession &PDBSession, + CComPtr<IDiaEnumInjectedSources> DiaEnumerator) + : Session(PDBSession), Enumerator(DiaEnumerator) {} + +uint32_t DIAEnumInjectedSources::getChildCount() const { + LONG Count = 0; + return (S_OK == Enumerator->get_Count(&Count)) ? Count : 0; +} + +std::unique_ptr<IPDBInjectedSource> +DIAEnumInjectedSources::getChildAtIndex(uint32_t Index) const { + CComPtr<IDiaInjectedSource> Item; + if (S_OK != Enumerator->Item(Index, &Item)) + return nullptr; + + return std::unique_ptr<IPDBInjectedSource>(new DIAInjectedSource(Item)); +} + +std::unique_ptr<IPDBInjectedSource> DIAEnumInjectedSources::getNext() { + CComPtr<IDiaInjectedSource> Item; + ULONG NumFetched = 0; + if (S_OK != Enumerator->Next(1, &Item, &NumFetched)) + return nullptr; + + return std::unique_ptr<IPDBInjectedSource>(new DIAInjectedSource(Item)); +} + +void DIAEnumInjectedSources::reset() { Enumerator->Reset(); } + +DIAEnumInjectedSources *DIAEnumInjectedSources::clone() const { + CComPtr<IDiaEnumInjectedSources> EnumeratorClone; + if (S_OK != Enumerator->Clone(&EnumeratorClone)) + return nullptr; + return new DIAEnumInjectedSources(Session, EnumeratorClone); +} diff --git a/lib/DebugInfo/PDB/DIA/DIAEnumSectionContribs.cpp b/lib/DebugInfo/PDB/DIA/DIAEnumSectionContribs.cpp new file mode 100644 index 000000000000..1f405f049198 --- /dev/null +++ b/lib/DebugInfo/PDB/DIA/DIAEnumSectionContribs.cpp @@ -0,0 +1,54 @@ +//==- DIAEnumSectionContribs.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/DIA/DIAEnumSectionContribs.h" +#include "llvm/DebugInfo/PDB/DIA/DIASectionContrib.h" +#include "llvm/DebugInfo/PDB/DIA/DIASession.h" + +using namespace llvm; +using namespace llvm::pdb; + +DIAEnumSectionContribs::DIAEnumSectionContribs( + const DIASession &PDBSession, + CComPtr<IDiaEnumSectionContribs> DiaEnumerator) + : Session(PDBSession), Enumerator(DiaEnumerator) {} + +uint32_t DIAEnumSectionContribs::getChildCount() const { + LONG Count = 0; + return (S_OK == Enumerator->get_Count(&Count)) ? Count : 0; +} + +std::unique_ptr<IPDBSectionContrib> +DIAEnumSectionContribs::getChildAtIndex(uint32_t Index) const { + CComPtr<IDiaSectionContrib> Item; + if (S_OK != Enumerator->Item(Index, &Item)) + return nullptr; + + return std::unique_ptr<IPDBSectionContrib>( + new DIASectionContrib(Session, Item)); +} + +std::unique_ptr<IPDBSectionContrib> DIAEnumSectionContribs::getNext() { + CComPtr<IDiaSectionContrib> Item; + ULONG NumFetched = 0; + if (S_OK != Enumerator->Next(1, &Item, &NumFetched)) + return nullptr; + + return std::unique_ptr<IPDBSectionContrib>( + new DIASectionContrib(Session, Item)); +} + +void DIAEnumSectionContribs::reset() { Enumerator->Reset(); } + +DIAEnumSectionContribs *DIAEnumSectionContribs::clone() const { + CComPtr<IDiaEnumSectionContribs> EnumeratorClone; + if (S_OK != Enumerator->Clone(&EnumeratorClone)) + return nullptr; + return new DIAEnumSectionContribs(Session, EnumeratorClone); +} diff --git a/lib/DebugInfo/PDB/DIA/DIAInjectedSource.cpp b/lib/DebugInfo/PDB/DIA/DIAInjectedSource.cpp new file mode 100644 index 000000000000..1d642f221d79 --- /dev/null +++ b/lib/DebugInfo/PDB/DIA/DIAInjectedSource.cpp @@ -0,0 +1,63 @@ +//===- DIAInjectedSource.cpp - DIA impl for IPDBInjectedSource --*- 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/DIA/DIAInjectedSource.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/DebugInfo/PDB/ConcreteSymbolEnumerator.h" +#include "llvm/DebugInfo/PDB/DIA/DIASession.h" +#include "llvm/DebugInfo/PDB/DIA/DIAUtils.h" + +using namespace llvm; +using namespace llvm::pdb; + +DIAInjectedSource::DIAInjectedSource(CComPtr<IDiaInjectedSource> DiaSourceFile) + : SourceFile(DiaSourceFile) {} + +uint32_t DIAInjectedSource::getCrc32() const { + DWORD Crc; + return (S_OK == SourceFile->get_crc(&Crc)) ? Crc : 0; +} + +uint64_t DIAInjectedSource::getCodeByteSize() const { + ULONGLONG Size; + return (S_OK == SourceFile->get_length(&Size)) ? Size : 0; +} + +std::string DIAInjectedSource::getFileName() const { + return invokeBstrMethod(*SourceFile, &IDiaInjectedSource::get_filename); +} + +std::string DIAInjectedSource::getObjectFileName() const { + return invokeBstrMethod(*SourceFile, &IDiaInjectedSource::get_objectFilename); +} + +std::string DIAInjectedSource::getVirtualFileName() const { + return invokeBstrMethod(*SourceFile, + &IDiaInjectedSource::get_virtualFilename); +} + +PDB_SourceCompression DIAInjectedSource::getCompression() const { + DWORD Compression = 0; + if (S_OK != SourceFile->get_sourceCompression(&Compression)) + return PDB_SourceCompression::None; + return static_cast<PDB_SourceCompression>(Compression); +} + +std::string DIAInjectedSource::getCode() const { + DWORD DataSize; + if (S_OK != SourceFile->get_source(0, &DataSize, nullptr)) + return ""; + + std::vector<uint8_t> Buffer(DataSize); + if (S_OK != SourceFile->get_source(DataSize, &DataSize, Buffer.data())) + return ""; + assert(Buffer.size() == DataSize); + return std::string(reinterpret_cast<const char *>(Buffer.data()), + Buffer.size()); +} diff --git a/lib/DebugInfo/PDB/DIA/DIARawSymbol.cpp b/lib/DebugInfo/PDB/DIA/DIARawSymbol.cpp index 8e4b1f8aa8c9..7d6cb254e1d1 100644 --- a/lib/DebugInfo/PDB/DIA/DIARawSymbol.cpp +++ b/lib/DebugInfo/PDB/DIA/DIARawSymbol.cpp @@ -11,7 +11,9 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" #include "llvm/DebugInfo/CodeView/Formatters.h" +#include "llvm/DebugInfo/PDB/DIA/DIAEnumLineNumbers.h" #include "llvm/DebugInfo/PDB/DIA/DIAEnumSymbols.h" +#include "llvm/DebugInfo/PDB/DIA/DIALineNumber.h" #include "llvm/DebugInfo/PDB/DIA/DIASession.h" #include "llvm/DebugInfo/PDB/PDBExtras.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" @@ -178,7 +180,7 @@ void DumpDIAValue(llvm::raw_ostream &OS, int Indent, StringRef Name, OS << "\n"; OS.indent(Indent); Variant V = VariantFromVARIANT(Value); - OS << V; + OS << Name << ": " << V; } } @@ -400,6 +402,47 @@ DIARawSymbol::findChildren(PDB_SymType Type, StringRef Name, } std::unique_ptr<IPDBEnumSymbols> +DIARawSymbol::findChildrenByAddr(PDB_SymType Type, StringRef Name, + PDB_NameSearchFlags Flags, uint32_t Section, + uint32_t Offset) const { + llvm::SmallVector<UTF16, 32> Name16; + llvm::convertUTF8ToUTF16String(Name, Name16); + + enum SymTagEnum EnumVal = static_cast<enum SymTagEnum>(Type); + + DWORD CompareFlags = static_cast<DWORD>(Flags); + wchar_t *Name16Str = reinterpret_cast<wchar_t *>(Name16.data()); + + CComPtr<IDiaEnumSymbols> DiaEnumerator; + if (S_OK != + Symbol->findChildrenExByAddr(EnumVal, Name16Str, CompareFlags, Section, + Offset, &DiaEnumerator)) + return nullptr; + + return llvm::make_unique<DIAEnumSymbols>(Session, DiaEnumerator); +} + +std::unique_ptr<IPDBEnumSymbols> +DIARawSymbol::findChildrenByVA(PDB_SymType Type, StringRef Name, + PDB_NameSearchFlags Flags, uint64_t VA) const { + llvm::SmallVector<UTF16, 32> Name16; + llvm::convertUTF8ToUTF16String(Name, Name16); + + enum SymTagEnum EnumVal = static_cast<enum SymTagEnum>(Type); + + DWORD CompareFlags = static_cast<DWORD>(Flags); + wchar_t *Name16Str = reinterpret_cast<wchar_t *>(Name16.data()); + + CComPtr<IDiaEnumSymbols> DiaEnumerator; + if (S_OK != + Symbol->findChildrenExByVA(EnumVal, Name16Str, CompareFlags, VA, + &DiaEnumerator)) + return nullptr; + + return llvm::make_unique<DIAEnumSymbols>(Session, DiaEnumerator); +} + +std::unique_ptr<IPDBEnumSymbols> DIARawSymbol::findChildrenByRVA(PDB_SymType Type, StringRef Name, PDB_NameSearchFlags Flags, uint32_t RVA) const { llvm::SmallVector<UTF16, 32> Name16; @@ -419,6 +462,15 @@ DIARawSymbol::findChildrenByRVA(PDB_SymType Type, StringRef Name, } std::unique_ptr<IPDBEnumSymbols> +DIARawSymbol::findInlineFramesByAddr(uint32_t Section, uint32_t Offset) const { + CComPtr<IDiaEnumSymbols> DiaEnumerator; + if (S_OK != Symbol->findInlineFramesByAddr(Section, Offset, &DiaEnumerator)) + return nullptr; + + return llvm::make_unique<DIAEnumSymbols>(Session, DiaEnumerator); +} + +std::unique_ptr<IPDBEnumSymbols> DIARawSymbol::findInlineFramesByRVA(uint32_t RVA) const { CComPtr<IDiaEnumSymbols> DiaEnumerator; if (S_OK != Symbol->findInlineFramesByRVA(RVA, &DiaEnumerator)) @@ -427,6 +479,51 @@ DIARawSymbol::findInlineFramesByRVA(uint32_t RVA) const { return llvm::make_unique<DIAEnumSymbols>(Session, DiaEnumerator); } +std::unique_ptr<IPDBEnumSymbols> +DIARawSymbol::findInlineFramesByVA(uint64_t VA) const { + CComPtr<IDiaEnumSymbols> DiaEnumerator; + if (S_OK != Symbol->findInlineFramesByVA(VA, &DiaEnumerator)) + return nullptr; + + return llvm::make_unique<DIAEnumSymbols>(Session, DiaEnumerator); +} + +std::unique_ptr<IPDBEnumLineNumbers> DIARawSymbol::findInlineeLines() const { + CComPtr<IDiaEnumLineNumbers> DiaEnumerator; + if (S_OK != Symbol->findInlineeLines(&DiaEnumerator)) + return nullptr; + + return llvm::make_unique<DIAEnumLineNumbers>(DiaEnumerator); +} + +std::unique_ptr<IPDBEnumLineNumbers> +DIARawSymbol::findInlineeLinesByAddr(uint32_t Section, uint32_t Offset, + uint32_t Length) const { + CComPtr<IDiaEnumLineNumbers> DiaEnumerator; + if (S_OK != Symbol->findInlineeLinesByAddr(Section, Offset, Length, &DiaEnumerator)) + return nullptr; + + return llvm::make_unique<DIAEnumLineNumbers>(DiaEnumerator); +} + +std::unique_ptr<IPDBEnumLineNumbers> +DIARawSymbol::findInlineeLinesByRVA(uint32_t RVA, uint32_t Length) const { + CComPtr<IDiaEnumLineNumbers> DiaEnumerator; + if (S_OK != Symbol->findInlineeLinesByRVA(RVA, Length, &DiaEnumerator)) + return nullptr; + + return llvm::make_unique<DIAEnumLineNumbers>(DiaEnumerator); +} + +std::unique_ptr<IPDBEnumLineNumbers> +DIARawSymbol::findInlineeLinesByVA(uint64_t VA, uint32_t Length) const { + CComPtr<IDiaEnumLineNumbers> DiaEnumerator; + if (S_OK != Symbol->findInlineeLinesByVA(VA, Length, &DiaEnumerator)) + return nullptr; + + return llvm::make_unique<DIAEnumLineNumbers>(DiaEnumerator); +} + void DIARawSymbol::getDataBytes(llvm::SmallVector<uint8_t, 32> &bytes) const { bytes.clear(); @@ -652,6 +749,15 @@ std::string DIARawSymbol::getSourceFileName() const { return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_sourceFileName); } +std::unique_ptr<IPDBLineNumber> +DIARawSymbol::getSrcLineOnTypeDefn() const { + CComPtr<IDiaLineNumber> LineNumber; + if (FAILED(Symbol->getSrcLineOnTypeDefn(&LineNumber)) || !LineNumber) + return nullptr; + + return llvm::make_unique<DIALineNumber>(LineNumber); +} + uint32_t DIARawSymbol::getStride() const { return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_stride); } diff --git a/lib/DebugInfo/PDB/DIA/DIASectionContrib.cpp b/lib/DebugInfo/PDB/DIA/DIASectionContrib.cpp new file mode 100644 index 000000000000..b7dc49f53e23 --- /dev/null +++ b/lib/DebugInfo/PDB/DIA/DIASectionContrib.cpp @@ -0,0 +1,126 @@ +//===- DIASectionContrib.cpp - DIA impl. of IPDBSectionContrib ---- 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/DIA/DIASectionContrib.h" +#include "llvm/DebugInfo/PDB/DIA/DIARawSymbol.h" +#include "llvm/DebugInfo/PDB/DIA/DIASession.h" +#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" + +using namespace llvm; +using namespace llvm::pdb; + +DIASectionContrib::DIASectionContrib(const DIASession &PDBSession, + CComPtr<IDiaSectionContrib> DiaSection) + : Session(PDBSession), Section(DiaSection) {} + +std::unique_ptr<PDBSymbolCompiland> DIASectionContrib::getCompiland() const { + CComPtr<IDiaSymbol> Symbol; + if (FAILED(Section->get_compiland(&Symbol))) + return nullptr; + + auto RawSymbol = llvm::make_unique<DIARawSymbol>(Session, Symbol); + return llvm::make_unique<PDBSymbolCompiland>(Session, std::move(RawSymbol)); +} + +template <typename ArgType> +ArgType +PrivateGetDIAValue(IDiaSectionContrib *Section, + HRESULT (__stdcall IDiaSectionContrib::*Method)(ArgType *)) { + ArgType Value; + if (S_OK == (Section->*Method)(&Value)) + return static_cast<ArgType>(Value); + + return ArgType(); +} + +uint32_t DIASectionContrib::getAddressSection() const { + return PrivateGetDIAValue(Section, &IDiaSectionContrib::get_addressSection); +} + +uint32_t DIASectionContrib::getAddressOffset() const { + return PrivateGetDIAValue(Section, &IDiaSectionContrib::get_addressOffset); +} + +uint64_t DIASectionContrib::getVirtualAddress() const { + return PrivateGetDIAValue(Section, &IDiaSectionContrib::get_virtualAddress); +} + +uint32_t DIASectionContrib::getRelativeVirtualAddress() const { + return PrivateGetDIAValue(Section, + &IDiaSectionContrib::get_relativeVirtualAddress); +} + +uint32_t DIASectionContrib::getLength() const { + return PrivateGetDIAValue(Section, &IDiaSectionContrib::get_length); +} + +bool DIASectionContrib::isNotPaged() const { + return PrivateGetDIAValue(Section, &IDiaSectionContrib::get_notPaged); +} + +bool DIASectionContrib::hasCode() const { + return PrivateGetDIAValue(Section, &IDiaSectionContrib::get_code); +} + +bool DIASectionContrib::hasCode16Bit() const { + return PrivateGetDIAValue(Section, &IDiaSectionContrib::get_code16bit); +} + +bool DIASectionContrib::hasInitializedData() const { + return PrivateGetDIAValue(Section, &IDiaSectionContrib::get_initializedData); +} + +bool DIASectionContrib::hasUninitializedData() const { + return PrivateGetDIAValue(Section, + &IDiaSectionContrib::get_uninitializedData); +} + +bool DIASectionContrib::isRemoved() const { + return PrivateGetDIAValue(Section, &IDiaSectionContrib::get_remove); +} + +bool DIASectionContrib::hasComdat() const { + return PrivateGetDIAValue(Section, &IDiaSectionContrib::get_comdat); +} + +bool DIASectionContrib::isDiscardable() const { + return PrivateGetDIAValue(Section, &IDiaSectionContrib::get_discardable); +} + +bool DIASectionContrib::isNotCached() const { + return PrivateGetDIAValue(Section, &IDiaSectionContrib::get_notCached); +} + +bool DIASectionContrib::isShared() const { + return PrivateGetDIAValue(Section, &IDiaSectionContrib::get_share); +} + +bool DIASectionContrib::isExecutable() const { + return PrivateGetDIAValue(Section, &IDiaSectionContrib::get_execute); +} + +bool DIASectionContrib::isReadable() const { + return PrivateGetDIAValue(Section, &IDiaSectionContrib::get_read); +} + +bool DIASectionContrib::isWritable() const { + return PrivateGetDIAValue(Section, &IDiaSectionContrib::get_write); +} + +uint32_t DIASectionContrib::getDataCrc32() const { + return PrivateGetDIAValue(Section, &IDiaSectionContrib::get_dataCrc); +} + +uint32_t DIASectionContrib::getRelocationsCrc32() const { + return PrivateGetDIAValue(Section, &IDiaSectionContrib::get_relocationsCrc); +} + +uint32_t DIASectionContrib::getCompilandId() const { + return PrivateGetDIAValue(Section, &IDiaSectionContrib::get_compilandId); +} diff --git a/lib/DebugInfo/PDB/DIA/DIASession.cpp b/lib/DebugInfo/PDB/DIA/DIASession.cpp index b8aaebbf7380..d81f59400eb3 100644 --- a/lib/DebugInfo/PDB/DIA/DIASession.cpp +++ b/lib/DebugInfo/PDB/DIA/DIASession.cpp @@ -9,7 +9,9 @@ #include "llvm/DebugInfo/PDB/DIA/DIASession.h" #include "llvm/ADT/STLExtras.h" #include "llvm/DebugInfo/PDB/DIA/DIAEnumDebugStreams.h" +#include "llvm/DebugInfo/PDB/DIA/DIAEnumInjectedSources.h" #include "llvm/DebugInfo/PDB/DIA/DIAEnumLineNumbers.h" +#include "llvm/DebugInfo/PDB/DIA/DIAEnumSectionContribs.h" #include "llvm/DebugInfo/PDB/DIA/DIAEnumSourceFiles.h" #include "llvm/DebugInfo/PDB/DIA/DIAEnumTables.h" #include "llvm/DebugInfo/PDB/DIA/DIAError.h" @@ -104,7 +106,7 @@ Error DIASession::createFromPdb(StringRef Path, if (!llvm::convertUTF8ToUTF16String(Path, Path16)) return make_error<GenericError>(generic_error_code::invalid_path); - const wchar_t *Path16Str = reinterpret_cast<const wchar_t*>(Path16.data()); + const wchar_t *Path16Str = reinterpret_cast<const wchar_t *>(Path16.data()); HRESULT HR; if (FAILED(HR = DiaDataSource->loadDataFromPdb(Path16Str))) { return ErrorFromHResult(HR, "Calling loadDataFromPdb {0}", Path); @@ -148,8 +150,8 @@ uint64_t DIASession::getLoadAddress() const { return (success) ? LoadAddress : 0; } -void DIASession::setLoadAddress(uint64_t Address) { - Session->put_loadAddress(Address); +bool DIASession::setLoadAddress(uint64_t Address) { + return (S_OK == Session->put_loadAddress(Address)); } std::unique_ptr<PDBSymbolExe> DIASession::getGlobalScope() { @@ -164,6 +166,28 @@ std::unique_ptr<PDBSymbolExe> DIASession::getGlobalScope() { return ExeSymbol; } +bool DIASession::addressForVA(uint64_t VA, uint32_t &Section, + uint32_t &Offset) const { + DWORD ArgSection, ArgOffset = 0; + if (S_OK == Session->addressForVA(VA, &ArgSection, &ArgOffset)) { + Section = static_cast<uint32_t>(ArgSection); + Offset = static_cast<uint32_t>(ArgOffset); + return true; + } + return false; +} + +bool DIASession::addressForRVA(uint32_t RVA, uint32_t &Section, + uint32_t &Offset) const { + DWORD ArgSection, ArgOffset = 0; + if (S_OK == Session->addressForRVA(RVA, &ArgSection, &ArgOffset)) { + Section = static_cast<uint32_t>(ArgSection); + Offset = static_cast<uint32_t>(ArgOffset); + return true; + } + return false; +} + std::unique_ptr<PDBSymbol> DIASession::getSymbolById(uint32_t SymbolId) const { CComPtr<IDiaSymbol> LocatedSymbol; if (S_OK != Session->symbolById(SymbolId, &LocatedSymbol)) @@ -190,6 +214,31 @@ DIASession::findSymbolByAddress(uint64_t Address, PDB_SymType Type) const { return PDBSymbol::create(*this, std::move(RawSymbol)); } +std::unique_ptr<PDBSymbol> DIASession::findSymbolByRVA(uint32_t RVA, + PDB_SymType Type) const { + enum SymTagEnum EnumVal = static_cast<enum SymTagEnum>(Type); + + CComPtr<IDiaSymbol> Symbol; + if (S_OK != Session->findSymbolByRVA(RVA, EnumVal, &Symbol)) + return nullptr; + + auto RawSymbol = llvm::make_unique<DIARawSymbol>(*this, Symbol); + return PDBSymbol::create(*this, std::move(RawSymbol)); +} + +std::unique_ptr<PDBSymbol> +DIASession::findSymbolBySectOffset(uint32_t Sect, uint32_t Offset, + PDB_SymType Type) const { + enum SymTagEnum EnumVal = static_cast<enum SymTagEnum>(Type); + + CComPtr<IDiaSymbol> Symbol; + if (S_OK != Session->findSymbolByAddr(Sect, Offset, EnumVal, &Symbol)) + return nullptr; + + auto RawSymbol = llvm::make_unique<DIARawSymbol>(*this, Symbol); + return PDBSymbol::create(*this, std::move(RawSymbol)); +} + std::unique_ptr<IPDBEnumLineNumbers> DIASession::findLineNumbers(const PDBSymbolCompiland &Compiland, const IPDBSourceFile &File) const { @@ -198,9 +247,8 @@ DIASession::findLineNumbers(const PDBSymbolCompiland &Compiland, const DIASourceFile &RawFile = static_cast<const DIASourceFile &>(File); CComPtr<IDiaEnumLineNumbers> LineNumbers; - if (S_OK != - Session->findLines(RawCompiland.getDiaSymbol(), RawFile.getDiaFile(), - &LineNumbers)) + if (S_OK != Session->findLines(RawCompiland.getDiaSymbol(), + RawFile.getDiaFile(), &LineNumbers)) return nullptr; return llvm::make_unique<DIAEnumLineNumbers>(LineNumbers); @@ -209,7 +257,31 @@ DIASession::findLineNumbers(const PDBSymbolCompiland &Compiland, std::unique_ptr<IPDBEnumLineNumbers> DIASession::findLineNumbersByAddress(uint64_t Address, uint32_t Length) const { CComPtr<IDiaEnumLineNumbers> LineNumbers; - if (S_OK != Session->findLinesByVA(Address, Length, &LineNumbers)) + if (S_OK != Session->findLinesByVA(Address, Length, &LineNumbers)) { + ULONGLONG LoadAddr = 0; + if (S_OK != Session->get_loadAddress(&LoadAddr)) + return nullptr; + DWORD RVA = static_cast<DWORD>(Address - LoadAddr); + if (S_OK != Session->findLinesByRVA(RVA, Length, &LineNumbers)) + return nullptr; + } + return llvm::make_unique<DIAEnumLineNumbers>(LineNumbers); +} + +std::unique_ptr<IPDBEnumLineNumbers> +DIASession::findLineNumbersByRVA(uint32_t RVA, uint32_t Length) const { + CComPtr<IDiaEnumLineNumbers> LineNumbers; + if (S_OK != Session->findLinesByRVA(RVA, Length, &LineNumbers)) + return nullptr; + + return llvm::make_unique<DIAEnumLineNumbers>(LineNumbers); +} + +std::unique_ptr<IPDBEnumLineNumbers> +DIASession::findLineNumbersBySectOffset(uint32_t Section, uint32_t Offset, + uint32_t Length) const { + CComPtr<IDiaEnumLineNumbers> LineNumbers; + if (S_OK != Session->findLinesByAddr(Section, Offset, Length, &LineNumbers)) return nullptr; return llvm::make_unique<DIAEnumLineNumbers>(LineNumbers); @@ -310,3 +382,40 @@ std::unique_ptr<IPDBEnumTables> DIASession::getEnumTables() const { return llvm::make_unique<DIAEnumTables>(DiaEnumerator); } + +template <class T> static CComPtr<T> getTableEnumerator(IDiaSession &Session) { + CComPtr<T> Enumerator; + CComPtr<IDiaEnumTables> ET; + CComPtr<IDiaTable> Table; + ULONG Count = 0; + + if (Session.getEnumTables(&ET) != S_OK) + return nullptr; + + while (ET->Next(1, &Table, &Count) == S_OK && Count == 1) { + // There is only one table that matches the given iid + if (S_OK == Table->QueryInterface(__uuidof(T), (void **)&Enumerator)) + break; + Table.Release(); + } + return Enumerator; +} +std::unique_ptr<IPDBEnumInjectedSources> +DIASession::getInjectedSources() const { + CComPtr<IDiaEnumInjectedSources> Files = + getTableEnumerator<IDiaEnumInjectedSources>(*Session); + if (!Files) + return nullptr; + + return llvm::make_unique<DIAEnumInjectedSources>(*this, Files); +} + +std::unique_ptr<IPDBEnumSectionContribs> +DIASession::getSectionContribs() const { + CComPtr<IDiaEnumSectionContribs> Sections = + getTableEnumerator<IDiaEnumSectionContribs>(*Session); + if (!Sections) + return nullptr; + + return llvm::make_unique<DIAEnumSectionContribs>(*this, Sections); +} diff --git a/lib/DebugInfo/PDB/GenericError.cpp b/lib/DebugInfo/PDB/GenericError.cpp index 4fcecb92fd15..2a677b9abe2d 100644 --- a/lib/DebugInfo/PDB/GenericError.cpp +++ b/lib/DebugInfo/PDB/GenericError.cpp @@ -30,7 +30,7 @@ public: return "Type server PDB was not found."; case generic_error_code::dia_sdk_not_present: return "LLVM was not compiled with support for DIA. This usually means " - "that you are are not using MSVC, or your Visual Studio " + "that you are not using MSVC, or your Visual Studio " "installation " "is corrupt."; case generic_error_code::invalid_path: diff --git a/lib/DebugInfo/PDB/Native/DbiModuleDescriptor.cpp b/lib/DebugInfo/PDB/Native/DbiModuleDescriptor.cpp index dabcc3447ee5..931ac7bb81db 100644 --- a/lib/DebugInfo/PDB/Native/DbiModuleDescriptor.cpp +++ b/lib/DebugInfo/PDB/Native/DbiModuleDescriptor.cpp @@ -49,6 +49,10 @@ uint16_t DbiModuleDescriptor::getTypeServerIndex() const { ModInfoFlags::TypeServerIndexShift; } +const SectionContrib &DbiModuleDescriptor::getSectionContrib() const { + return Layout->SC; +} + uint16_t DbiModuleDescriptor::getModuleStreamIndex() const { return Layout->ModDiStream; } diff --git a/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp b/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp index d765485bdb6d..b97f1e90bcf8 100644 --- a/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp +++ b/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp @@ -60,6 +60,11 @@ void DbiModuleDescriptorBuilder::setPdbFilePathNI(uint32_t NI) { PdbFilePathNI = NI; } +void DbiModuleDescriptorBuilder::setFirstSectionContrib( + const SectionContrib &SC) { + Layout.SC = SC; +} + void DbiModuleDescriptorBuilder::addSymbol(CVSymbol Symbol) { Symbols.push_back(Symbol); // Symbols written to a PDB file are required to be 4 byte aligned. The same @@ -90,7 +95,7 @@ uint32_t DbiModuleDescriptorBuilder::calculateSerializedLength() const { } void DbiModuleDescriptorBuilder::finalize() { - Layout.SC.ModuleIndex = Layout.Mod; + Layout.SC.Imod = Layout.Mod; Layout.FileNameOffs = 0; // TODO: Fix this Layout.Flags = 0; // TODO: Fix this Layout.C11Bytes = 0; diff --git a/lib/DebugInfo/PDB/Native/DbiStream.cpp b/lib/DebugInfo/PDB/Native/DbiStream.cpp index 04e6664c68db..edaa783398ca 100644 --- a/lib/DebugInfo/PDB/Native/DbiStream.cpp +++ b/lib/DebugInfo/PDB/Native/DbiStream.cpp @@ -45,12 +45,12 @@ static Error loadSectionContribs(FixedStreamArray<ContribType> &Output, return Error::success(); } -DbiStream::DbiStream(PDBFile &File, std::unique_ptr<MappedBlockStream> Stream) - : Pdb(File), Stream(std::move(Stream)), Header(nullptr) {} +DbiStream::DbiStream(std::unique_ptr<BinaryStream> Stream) + : Stream(std::move(Stream)), Header(nullptr) {} DbiStream::~DbiStream() = default; -Error DbiStream::reload() { +Error DbiStream::reload(PDBFile *Pdb) { BinaryStreamReader Reader(*Stream); if (Stream->getLength() < sizeof(DbiStreamHeader)) @@ -123,11 +123,11 @@ Error DbiStream::reload() { if (auto EC = initializeSectionContributionData()) return EC; - if (auto EC = initializeSectionHeadersData()) + if (auto EC = initializeSectionHeadersData(Pdb)) return EC; if (auto EC = initializeSectionMapData()) return EC; - if (auto EC = initializeFpoRecords()) + if (auto EC = initializeFpoRecords(Pdb)) return EC; if (Reader.bytesRemaining() > 0) @@ -246,7 +246,10 @@ Error DbiStream::initializeSectionContributionData() { } // Initializes this->SectionHeaders. -Error DbiStream::initializeSectionHeadersData() { +Error DbiStream::initializeSectionHeadersData(PDBFile *Pdb) { + if (!Pdb) + return Error::success(); + if (DbgStreams.size() == 0) return Error::success(); @@ -254,11 +257,11 @@ Error DbiStream::initializeSectionHeadersData() { if (StreamNum == kInvalidStreamIndex) return Error::success(); - if (StreamNum >= Pdb.getNumStreams()) + if (StreamNum >= Pdb->getNumStreams()) return make_error<RawError>(raw_error_code::no_stream); auto SHS = MappedBlockStream::createIndexedStream( - Pdb.getMsfLayout(), Pdb.getMsfBuffer(), StreamNum, Pdb.getAllocator()); + Pdb->getMsfLayout(), Pdb->getMsfBuffer(), StreamNum, Pdb->getAllocator()); size_t StreamLen = SHS->getLength(); if (StreamLen % sizeof(object::coff_section)) @@ -276,7 +279,10 @@ Error DbiStream::initializeSectionHeadersData() { } // Initializes this->Fpos. -Error DbiStream::initializeFpoRecords() { +Error DbiStream::initializeFpoRecords(PDBFile *Pdb) { + if (!Pdb) + return Error::success(); + if (DbgStreams.size() == 0) return Error::success(); @@ -286,11 +292,11 @@ Error DbiStream::initializeFpoRecords() { if (StreamNum == kInvalidStreamIndex) return Error::success(); - if (StreamNum >= Pdb.getNumStreams()) + if (StreamNum >= Pdb->getNumStreams()) return make_error<RawError>(raw_error_code::no_stream); auto FS = MappedBlockStream::createIndexedStream( - Pdb.getMsfLayout(), Pdb.getMsfBuffer(), StreamNum, Pdb.getAllocator()); + Pdb->getMsfLayout(), Pdb->getMsfBuffer(), StreamNum, Pdb->getAllocator()); size_t StreamLen = FS->getLength(); if (StreamLen % sizeof(object::FpoData)) diff --git a/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp b/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp index c96553ff9b16..f6043bfd7cf9 100644 --- a/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp +++ b/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp @@ -27,7 +27,7 @@ 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) {} + Header(nullptr) {} DbiStreamBuilder::~DbiStreamBuilder() {} @@ -37,6 +37,14 @@ void DbiStreamBuilder::setAge(uint32_t A) { Age = A; } void DbiStreamBuilder::setBuildNumber(uint16_t B) { BuildNumber = B; } +void DbiStreamBuilder::setBuildNumber(uint8_t Major, uint8_t Minor) { + BuildNumber = (uint16_t(Major) << DbiBuildNo::BuildMajorShift) & + DbiBuildNo::BuildMajorMask; + BuildNumber |= (uint16_t(Minor) << DbiBuildNo::BuildMinorShift) & + DbiBuildNo::BuildMinorMask; + BuildNumber |= DbiBuildNo::NewVersionFormatMask; +} + void DbiStreamBuilder::setPdbDllVersion(uint16_t V) { PdbDllVersion = V; } void DbiStreamBuilder::setPdbDllRbld(uint16_t R) { PdbDllRbld = R; } @@ -45,6 +53,11 @@ void DbiStreamBuilder::setFlags(uint16_t F) { Flags = F; } void DbiStreamBuilder::setMachineType(PDB_Machine M) { MachineType = M; } +void DbiStreamBuilder::setMachineType(COFF::MachineTypes M) { + // These enums are mirrors of each other, so we can just cast the value. + MachineType = static_cast<pdb::PDB_Machine>(static_cast<unsigned>(M)); +} + void DbiStreamBuilder::setSectionMap(ArrayRef<SecMapEntry> SecMap) { SectionMap = SecMap; } @@ -63,15 +76,8 @@ void DbiStreamBuilder::setPublicsStreamIndex(uint32_t 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; + DbgStreams[(int)Type].emplace(); + DbgStreams[(int)Type]->Data = Data; return Error::success(); } @@ -258,7 +264,7 @@ Error DbiStreamBuilder::finalize() { H->TypeServerSize = 0; H->SymRecordStreamIndex = SymRecordStreamIndex; H->PublicSymbolStreamIndex = PublicsStreamIndex; - H->MFCTypeServerIndex = kInvalidStreamIndex; + H->MFCTypeServerIndex = 0; // Not sure what this is, but link.exe writes 0. H->GlobalSymbolStreamIndex = GlobalsStreamIndex; Header = H; @@ -266,6 +272,15 @@ Error DbiStreamBuilder::finalize() { } Error DbiStreamBuilder::finalizeMsfLayout() { + for (auto &S : DbgStreams) { + if (!S.hasValue()) + continue; + auto ExpectedIndex = Msf.addStream(S->Data.size()); + if (!ExpectedIndex) + return ExpectedIndex.takeError(); + S->StreamNumber = *ExpectedIndex; + } + for (auto &MI : ModiList) { if (auto EC = MI->finalizeMsfLayout()) return EC; @@ -375,17 +390,23 @@ Error DbiStreamBuilder::commit(const msf::MSFLayout &Layout, if (auto EC = ECNamesBuilder.commit(Writer)) return EC; - for (auto &Stream : DbgStreams) - if (auto EC = Writer.writeInteger(Stream.StreamNumber)) + for (auto &Stream : DbgStreams) { + uint16_t StreamNumber = kInvalidStreamIndex; + if (Stream.hasValue()) + StreamNumber = Stream->StreamNumber; + if (auto EC = Writer.writeInteger(StreamNumber)) return EC; + } for (auto &Stream : DbgStreams) { - if (Stream.StreamNumber == kInvalidStreamIndex) + if (!Stream.hasValue()) continue; + assert(Stream->StreamNumber != kInvalidStreamIndex); + auto WritableStream = WritableMappedBlockStream::createIndexedStream( - Layout, MsfBuffer, Stream.StreamNumber, Allocator); + Layout, MsfBuffer, Stream->StreamNumber, Allocator); BinaryStreamWriter DbgStreamWriter(*WritableStream); - if (auto EC = DbgStreamWriter.writeArray(Stream.Data)) + if (auto EC = DbgStreamWriter.writeArray(Stream->Data)) return EC; } diff --git a/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp b/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp index e84f25dfeefa..58efc2256ae1 100644 --- a/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp +++ b/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp @@ -82,8 +82,29 @@ Error GSIHashStreamBuilder::commit(BinaryStreamWriter &Writer) { return Error::success(); } +static bool isAsciiString(StringRef S) { + return llvm::all_of(S, [](char C) { return unsigned(C) < 0x80; }); +} + +// See `caseInsensitiveComparePchPchCchCch` in gsi.cpp +static bool gsiRecordLess(StringRef S1, StringRef S2) { + size_t LS = S1.size(); + size_t RS = S2.size(); + // Shorter strings always compare less than longer strings. + if (LS != RS) + return LS < RS; + + // If either string contains non ascii characters, memcmp them. + if (LLVM_UNLIKELY(!isAsciiString(S1) || !isAsciiString(S2))) + return memcmp(S1.data(), S2.data(), LS) < 0; + + // Both strings are ascii, perform a case-insenstive comparison. + return S1.compare_lower(S2.data()) < 0; +} + void GSIHashStreamBuilder::finalizeBuckets(uint32_t RecordZeroOffset) { - std::array<std::vector<PSHashRecord>, IPHR_HASH + 1> TmpBuckets; + std::array<std::vector<std::pair<StringRef, PSHashRecord>>, IPHR_HASH + 1> + TmpBuckets; uint32_t SymOffset = RecordZeroOffset; for (const CVSymbol &Sym : Records) { PSHashRecord HR; @@ -94,8 +115,7 @@ void GSIHashStreamBuilder::finalizeBuckets(uint32_t RecordZeroOffset) { // 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? - + TmpBuckets[BucketIdx].push_back(std::make_pair(Name, HR)); SymOffset += Sym.length(); } @@ -117,8 +137,21 @@ void GSIHashStreamBuilder::finalizeBuckets(uint32_t RecordZeroOffset) { ulittle32_t ChainStartOff = ulittle32_t(HashRecords.size() * SizeOfHROffsetCalc); HashBuckets.push_back(ChainStartOff); - for (const auto &HR : Bucket) - HashRecords.push_back(HR); + + // Sort each bucket by memcmp of the symbol's name. It's important that + // we use the same sorting algorithm as is used by the reference + // implementation to ensure that the search for a record within a bucket + // can properly early-out when it detects the record won't be found. The + // algorithm used here corredsponds to the function + // caseInsensitiveComparePchPchCchCch in the reference implementation. + llvm::sort(Bucket.begin(), Bucket.end(), + [](const std::pair<StringRef, PSHashRecord> &Left, + const std::pair<StringRef, PSHashRecord> &Right) { + return gsiRecordLess(Left.first, Right.first); + }); + + for (const auto &Entry : Bucket) + HashRecords.push_back(Entry.second); } } @@ -150,14 +183,14 @@ Error GSIStreamBuilder::finalizeMsfLayout() { PSH->finalizeBuckets(PSHZero); GSH->finalizeBuckets(GSHZero); - Expected<uint32_t> Idx = Msf.addStream(calculatePublicsHashStreamSize()); + Expected<uint32_t> Idx = Msf.addStream(calculateGlobalsHashStreamSize()); if (!Idx) return Idx.takeError(); - PSH->StreamIndex = *Idx; - Idx = Msf.addStream(calculateGlobalsHashStreamSize()); + GSH->StreamIndex = *Idx; + Idx = Msf.addStream(calculatePublicsHashStreamSize()); if (!Idx) return Idx.takeError(); - GSH->StreamIndex = *Idx; + PSH->StreamIndex = *Idx; uint32_t RecordBytes = GSH->calculateRecordByteSize() + PSH->calculateRecordByteSize(); diff --git a/lib/DebugInfo/PDB/Native/HashTable.cpp b/lib/DebugInfo/PDB/Native/HashTable.cpp index 439217f91d04..cfabc9cd1ad8 100644 --- a/lib/DebugInfo/PDB/Native/HashTable.cpp +++ b/lib/DebugInfo/PDB/Native/HashTable.cpp @@ -22,200 +22,7 @@ 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, +Error llvm::pdb::readSparseBitVector(BinaryStreamReader &Stream, SparseBitVector<> &V) { uint32_t NumWords; if (auto EC = Stream.readInteger(NumWords)) @@ -237,18 +44,20 @@ Error HashTable::readSparseBitVector(BinaryStreamReader &Stream, return Error::success(); } -Error HashTable::writeSparseBitVector(BinaryStreamWriter &Writer, +Error llvm::pdb::writeSparseBitVector(BinaryStreamWriter &Writer, SparseBitVector<> &Vec) { + constexpr int BitsPerWord = 8 * sizeof(uint32_t); + int ReqBits = Vec.find_last() + 1; - uint32_t NumWords = alignTo(ReqBits, sizeof(uint32_t)) / sizeof(uint32_t); - if (auto EC = Writer.writeInteger(NumWords)) + uint32_t ReqWords = alignTo(ReqBits, BitsPerWord) / BitsPerWord; + if (auto EC = Writer.writeInteger(ReqWords)) 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) { + for (uint32_t I = 0; I != ReqWords; ++I) { uint32_t Word = 0; for (uint32_t WordIdx = 0; WordIdx < 32; ++WordIdx, ++Idx) { if (Vec.test(Idx)) @@ -261,48 +70,3 @@ Error HashTable::writeSparseBitVector(BinaryStreamWriter &Writer, } 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; -} diff --git a/lib/DebugInfo/PDB/Native/InfoStream.cpp b/lib/DebugInfo/PDB/Native/InfoStream.cpp index 17c9392a9dd5..973a520ffca9 100644 --- a/lib/DebugInfo/PDB/Native/InfoStream.cpp +++ b/lib/DebugInfo/PDB/Native/InfoStream.cpp @@ -20,20 +20,19 @@ using namespace llvm::codeview; using namespace llvm::msf; using namespace llvm::pdb; -InfoStream::InfoStream(std::unique_ptr<MappedBlockStream> Stream) - : Stream(std::move(Stream)) {} +InfoStream::InfoStream(std::unique_ptr<BinaryStream> Stream) + : Stream(std::move(Stream)), Header(nullptr) {} Error InfoStream::reload() { BinaryStreamReader Reader(*Stream); - const InfoStreamHeader *H; - if (auto EC = Reader.readObject(H)) + if (auto EC = Reader.readObject(Header)) return joinErrors( std::move(EC), make_error<RawError>(raw_error_code::corrupt_file, "PDB Stream does not contain a header.")); - switch (H->Version) { + switch (Header->Version) { case PdbImplVC70: case PdbImplVC80: case PdbImplVC110: @@ -44,11 +43,6 @@ Error InfoStream::reload() { "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; @@ -92,15 +86,14 @@ Error InfoStream::reload() { uint32_t InfoStream::getStreamSize() const { return Stream->getLength(); } -uint32_t InfoStream::getNamedStreamIndex(llvm::StringRef Name) const { +Expected<uint32_t> InfoStream::getNamedStreamIndex(llvm::StringRef Name) const { uint32_t Result; if (!NamedStreams.get(Name, Result)) - return 0; + return make_error<RawError>(raw_error_code::no_stream); return Result; } -iterator_range<StringMapConstIterator<uint32_t>> -InfoStream::named_streams() const { +StringMap<uint32_t> InfoStream::named_streams() const { return NamedStreams.entries(); } @@ -109,14 +102,16 @@ bool InfoStream::containsIdStream() const { } PdbRaw_ImplVer InfoStream::getVersion() const { - return static_cast<PdbRaw_ImplVer>(Version); + return static_cast<PdbRaw_ImplVer>(uint32_t(Header->Version)); } -uint32_t InfoStream::getSignature() const { return Signature; } +uint32_t InfoStream::getSignature() const { + return uint32_t(Header->Signature); +} -uint32_t InfoStream::getAge() const { return Age; } +uint32_t InfoStream::getAge() const { return uint32_t(Header->Age); } -GUID InfoStream::getGuid() const { return Guid; } +GUID InfoStream::getGuid() const { return Header->Guid; } uint32_t InfoStream::getNamedStreamMapByteSize() const { return NamedStreamMapByteSize; diff --git a/lib/DebugInfo/PDB/Native/InfoStreamBuilder.cpp b/lib/DebugInfo/PDB/Native/InfoStreamBuilder.cpp index 6450ae752f96..54d6835f1121 100644 --- a/lib/DebugInfo/PDB/Native/InfoStreamBuilder.cpp +++ b/lib/DebugInfo/PDB/Native/InfoStreamBuilder.cpp @@ -25,15 +25,17 @@ using namespace llvm::pdb; InfoStreamBuilder::InfoStreamBuilder(msf::MSFBuilder &Msf, NamedStreamMap &NamedStreams) - : Msf(Msf), Ver(PdbRaw_ImplVer::PdbImplVC70), Sig(-1), Age(0), - NamedStreams(NamedStreams) {} + : Msf(Msf), Ver(PdbRaw_ImplVer::PdbImplVC70), Age(0), + NamedStreams(NamedStreams) { + ::memset(&Guid, 0, sizeof(Guid)); +} 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::setSignature(uint32_t S) { Signature = S; } + void InfoStreamBuilder::setGuid(GUID G) { Guid = G; } void InfoStreamBuilder::addFeature(PdbRaw_FeatureSig Sig) { @@ -41,7 +43,8 @@ void InfoStreamBuilder::addFeature(PdbRaw_FeatureSig Sig) { } Error InfoStreamBuilder::finalizeMsfLayout() { - uint32_t Length = sizeof(InfoStreamHeader) + NamedStreams.finalize() + + uint32_t Length = sizeof(InfoStreamHeader) + + NamedStreams.calculateSerializedLength() + (Features.size() + 1) * sizeof(uint32_t); if (auto EC = Msf.setStreamSize(StreamPDB, Length)) return EC; @@ -55,10 +58,10 @@ Error InfoStreamBuilder::commit(const msf::MSFLayout &Layout, BinaryStreamWriter Writer(*InfoS); InfoStreamHeader H; - H.Age = Age; - H.Signature = Sig; + // Leave the build id fields 0 so they can be set as the last step before + // committing the file to disk. + ::memset(&H, 0, sizeof(H)); H.Version = Ver; - H.Guid = Guid; if (auto EC = Writer.writeObject(H)) return EC; @@ -70,5 +73,6 @@ Error InfoStreamBuilder::commit(const msf::MSFLayout &Layout, if (auto EC = Writer.writeEnum(E)) return EC; } + assert(Writer.bytesRemaining() == 0); return Error::success(); } diff --git a/lib/DebugInfo/PDB/Native/NamedStreamMap.cpp b/lib/DebugInfo/PDB/Native/NamedStreamMap.cpp index 6cdf6dde04d9..a4eaed90837d 100644 --- a/lib/DebugInfo/PDB/Native/NamedStreamMap.cpp +++ b/lib/DebugInfo/PDB/Native/NamedStreamMap.cpp @@ -11,6 +11,7 @@ #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/iterator_range.h" +#include "llvm/DebugInfo/PDB/Native/Hash.h" #include "llvm/DebugInfo/PDB/Native/HashTable.h" #include "llvm/DebugInfo/PDB/Native/RawError.h" #include "llvm/Support/BinaryStreamReader.h" @@ -26,127 +27,101 @@ 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"}; +NamedStreamMapTraits::NamedStreamMapTraits(NamedStreamMap &NS) : NS(&NS) {} -NamedStreamMap::NamedStreamMap() = default; +uint16_t NamedStreamMapTraits::hashLookupKey(StringRef S) const { + // In the reference implementation, this uses + // HASH Hasher<ULONG*, USHORT*>::hashPbCb(PB pb, size_t cb, ULONG ulMod). + // Here, the type HASH is a typedef of unsigned short. + // ** It is not a bug that we truncate the result of hashStringV1, in fact + // it is a bug if we do not! ** + return static_cast<uint16_t>(hashStringV1(S)); +} -Error NamedStreamMap::load(BinaryStreamReader &Stream) { - Mapping.clear(); - FinalizedHashTable.clear(); - FinalizedInfo.reset(); +StringRef NamedStreamMapTraits::storageKeyToLookupKey(uint32_t Offset) const { + return NS->getString(Offset); +} +uint32_t NamedStreamMapTraits::lookupKeyToStorageKey(StringRef S) { + return NS->appendStringData(S); +} + +NamedStreamMap::NamedStreamMap() + : HashTraits(*this), OffsetIndexMap(1, HashTraits) {} + +Error NamedStreamMap::load(BinaryStreamReader &Stream) { uint32_t StringBufferSize; if (auto EC = Stream.readInteger(StringBufferSize)) return joinErrors(std::move(EC), make_error<RawError>(raw_error_code::corrupt_file, "Expected string buffer size")); - BinaryStreamRef StringsBuffer; - if (auto EC = Stream.readStreamRef(StringsBuffer, StringBufferSize)) + StringRef Buffer; + if (auto EC = Stream.readFixedString(Buffer, StringBufferSize)) return EC; + NamesBuffer.assign(Buffer.begin(), Buffer.end()); - 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(); + return OffsetIndexMap.load(Stream); } 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)) + if (auto EC = Writer.writeInteger<uint32_t>(NamesBuffer.size())) 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; - } + // Then the actual string data. + StringRef Data(NamesBuffer.data(), NamesBuffer.size()); + if (auto EC = Writer.writeFixedString(Data)) + return EC; // And finally the Offset Index map. - if (auto EC = FinalizedHashTable.commit(Writer)) + if (auto EC = OffsetIndexMap.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(); +uint32_t NamedStreamMap::calculateSerializedLength() const { + return sizeof(uint32_t) // String data size + + NamesBuffer.size() // String data + + OffsetIndexMap.calculateSerializedLength(); // Offset Index Map +} - 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; - } +uint32_t NamedStreamMap::size() const { return OffsetIndexMap.size(); } - // 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; +StringRef NamedStreamMap::getString(uint32_t Offset) const { + assert(NamesBuffer.size() > Offset); + return StringRef(NamesBuffer.data() + Offset); } -iterator_range<StringMapConstIterator<uint32_t>> -NamedStreamMap::entries() const { - return make_range<StringMapConstIterator<uint32_t>>(Mapping.begin(), - Mapping.end()); +uint32_t NamedStreamMap::hashString(uint32_t Offset) const { + return hashStringV1(getString(Offset)); } -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()) + auto Iter = OffsetIndexMap.find_as(Stream); + if (Iter == OffsetIndexMap.end()) return false; - StreamNo = Iter->second; + StreamNo = (*Iter).second; return true; } -void NamedStreamMap::set(StringRef Stream, uint32_t StreamNo) { - FinalizedInfo.reset(); - Mapping[Stream] = StreamNo; +StringMap<uint32_t> NamedStreamMap::entries() const { + StringMap<uint32_t> Result; + for (const auto &Entry : OffsetIndexMap) { + StringRef Stream(NamesBuffer.data() + Entry.first); + Result.try_emplace(Stream, Entry.second); + } + return Result; } -void NamedStreamMap::remove(StringRef Stream) { - FinalizedInfo.reset(); - Mapping.erase(Stream); +uint32_t NamedStreamMap::appendStringData(StringRef S) { + uint32_t Offset = NamesBuffer.size(); + NamesBuffer.insert(NamesBuffer.end(), S.begin(), S.end()); + NamesBuffer.push_back('\0'); + return Offset; +} + +void NamedStreamMap::set(StringRef Stream, uint32_t StreamNo) { + OffsetIndexMap.set_as(Stream, support::ulittle32_t(StreamNo)); } diff --git a/lib/DebugInfo/PDB/Native/NativeRawSymbol.cpp b/lib/DebugInfo/PDB/Native/NativeRawSymbol.cpp index d23ee0a09196..a4b029596314 100644 --- a/lib/DebugInfo/PDB/Native/NativeRawSymbol.cpp +++ b/lib/DebugInfo/PDB/Native/NativeRawSymbol.cpp @@ -7,6 +7,7 @@ // //===----------------------------------------------------------------------===// +#include "llvm/DebugInfo/PDB/IPDBLineNumber.h" #include "llvm/DebugInfo/PDB/Native/NativeRawSymbol.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" @@ -30,16 +31,60 @@ NativeRawSymbol::findChildren(PDB_SymType Type, StringRef Name, } std::unique_ptr<IPDBEnumSymbols> +NativeRawSymbol::findChildrenByAddr(PDB_SymType Type, StringRef Name, + PDB_NameSearchFlags Flags, uint32_t Section, uint32_t Offset) const { + return nullptr; +} + +std::unique_ptr<IPDBEnumSymbols> +NativeRawSymbol::findChildrenByVA(PDB_SymType Type, StringRef Name, + PDB_NameSearchFlags Flags, uint64_t VA) const { + return nullptr; +} + +std::unique_ptr<IPDBEnumSymbols> NativeRawSymbol::findChildrenByRVA(PDB_SymType Type, StringRef Name, PDB_NameSearchFlags Flags, uint32_t RVA) const { return nullptr; } std::unique_ptr<IPDBEnumSymbols> +NativeRawSymbol::findInlineFramesByAddr(uint32_t Section, + uint32_t Offset) const { + return nullptr; +} + +std::unique_ptr<IPDBEnumSymbols> NativeRawSymbol::findInlineFramesByRVA(uint32_t RVA) const { return nullptr; } +std::unique_ptr<IPDBEnumSymbols> +NativeRawSymbol::findInlineFramesByVA(uint64_t VA) const { + return nullptr; +} + +std::unique_ptr<IPDBEnumLineNumbers> +NativeRawSymbol::findInlineeLines() const { + return nullptr; +} + +std::unique_ptr<IPDBEnumLineNumbers> +NativeRawSymbol::findInlineeLinesByAddr(uint32_t Section, uint32_t Offset, + uint32_t Length) const { + return nullptr; +} + +std::unique_ptr<IPDBEnumLineNumbers> +NativeRawSymbol::findInlineeLinesByRVA(uint32_t RVA, uint32_t Length) const { + return nullptr; +} + +std::unique_ptr<IPDBEnumLineNumbers> +NativeRawSymbol::findInlineeLinesByVA(uint64_t VA, uint32_t Length) const { + return nullptr; +} + void NativeRawSymbol::getDataBytes(SmallVector<uint8_t, 32> &bytes) const { bytes.clear(); } @@ -143,7 +188,7 @@ uint32_t NativeRawSymbol::getLiveRangeStartRelativeVirtualAddress() const { } codeview::RegisterId NativeRawSymbol::getLocalBasePointerRegisterId() const { - return codeview::RegisterId::EAX; + return codeview::RegisterId::CVRegEAX; } uint32_t NativeRawSymbol::getLowerBoundId() const { @@ -203,7 +248,7 @@ uint32_t NativeRawSymbol::getRank() const { } codeview::RegisterId NativeRawSymbol::getRegisterId() const { - return codeview::RegisterId::EAX; + return codeview::RegisterId::CVRegEAX; } uint32_t NativeRawSymbol::getRegisterType() const { @@ -234,6 +279,11 @@ std::string NativeRawSymbol::getSourceFileName() const { return {}; } +std::unique_ptr<IPDBLineNumber> +NativeRawSymbol::getSrcLineOnTypeDefn() const { + return nullptr; +} + uint32_t NativeRawSymbol::getStride() const { return 0; } diff --git a/lib/DebugInfo/PDB/Native/NativeSession.cpp b/lib/DebugInfo/PDB/Native/NativeSession.cpp index b01c2b54796c..086da13135c5 100644 --- a/lib/DebugInfo/PDB/Native/NativeSession.cpp +++ b/lib/DebugInfo/PDB/Native/NativeSession.cpp @@ -165,7 +165,7 @@ SymIndexId NativeSession::findSymbolByTypeIndex(codeview::TypeIndex Index) { uint64_t NativeSession::getLoadAddress() const { return 0; } -void NativeSession::setLoadAddress(uint64_t Address) {} +bool NativeSession::setLoadAddress(uint64_t Address) { return false; } std::unique_ptr<PDBSymbolExe> NativeSession::getGlobalScope() { const auto Id = static_cast<SymIndexId>(SymbolCache.size()); @@ -185,11 +185,32 @@ NativeSession::getSymbolById(uint32_t SymbolId) const { : nullptr; } +bool NativeSession::addressForVA(uint64_t VA, uint32_t &Section, + uint32_t &Offset) const { + return false; +} + +bool NativeSession::addressForRVA(uint32_t VA, uint32_t &Section, + uint32_t &Offset) const { + return false; +} + std::unique_ptr<PDBSymbol> NativeSession::findSymbolByAddress(uint64_t Address, PDB_SymType Type) const { return nullptr; } +std::unique_ptr<PDBSymbol> +NativeSession::findSymbolByRVA(uint32_t RVA, PDB_SymType Type) const { + return nullptr; +} + +std::unique_ptr<PDBSymbol> +NativeSession::findSymbolBySectOffset(uint32_t Sect, uint32_t Offset, + PDB_SymType Type) const { + return nullptr; +} + std::unique_ptr<IPDBEnumLineNumbers> NativeSession::findLineNumbers(const PDBSymbolCompiland &Compiland, const IPDBSourceFile &File) const { @@ -202,6 +223,17 @@ NativeSession::findLineNumbersByAddress(uint64_t Address, return nullptr; } +std::unique_ptr<IPDBEnumLineNumbers> +NativeSession::findLineNumbersByRVA(uint32_t RVA, uint32_t Length) const { + return nullptr; +} + +std::unique_ptr<IPDBEnumLineNumbers> +NativeSession::findLineNumbersBySectOffset(uint32_t Section, uint32_t Offset, + uint32_t Length) const { + return nullptr; +} + std::unique_ptr<IPDBEnumSourceFiles> NativeSession::findSourceFiles(const PDBSymbolCompiland *Compiland, StringRef Pattern, @@ -249,3 +281,13 @@ std::unique_ptr<IPDBEnumDataStreams> NativeSession::getDebugStreams() const { std::unique_ptr<IPDBEnumTables> NativeSession::getEnumTables() const { return nullptr; } + +std::unique_ptr<IPDBEnumInjectedSources> +NativeSession::getInjectedSources() const { + return nullptr; +} + +std::unique_ptr<IPDBEnumSectionContribs> +NativeSession::getSectionContribs() const { + return nullptr; +} diff --git a/lib/DebugInfo/PDB/Native/PDBFile.cpp b/lib/DebugInfo/PDB/Native/PDBFile.cpp index 15b31d821b1c..78b11937f051 100644 --- a/lib/DebugInfo/PDB/Native/PDBFile.cpp +++ b/lib/DebugInfo/PDB/Native/PDBFile.cpp @@ -289,8 +289,8 @@ Expected<DbiStream &> PDBFile::getPDBDbiStream() { auto DbiS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamDBI); if (!DbiS) return DbiS.takeError(); - auto TempDbi = llvm::make_unique<DbiStream>(*this, std::move(*DbiS)); - if (auto EC = TempDbi->reload()) + auto TempDbi = llvm::make_unique<DbiStream>(std::move(*DbiS)); + if (auto EC = TempDbi->reload(this)) return std::move(EC); Dbi = std::move(TempDbi); } @@ -370,7 +370,10 @@ Expected<PDBStringTable &> PDBFile::getStringTable() { if (!IS) return IS.takeError(); - uint32_t NameStreamIndex = IS->getNamedStreamIndex("/names"); + Expected<uint32_t> ExpectedNSI = IS->getNamedStreamIndex("/names"); + if (!ExpectedNSI) + return ExpectedNSI.takeError(); + uint32_t NameStreamIndex = *ExpectedNSI; auto NS = safelyCreateIndexedStream(ContainerLayout, *Buffer, NameStreamIndex); @@ -445,7 +448,13 @@ bool PDBFile::hasPDBStringTable() { auto IS = getPDBInfoStream(); if (!IS) return false; - return IS->getNamedStreamIndex("/names") < getNumStreams(); + Expected<uint32_t> ExpectedNSI = IS->getNamedStreamIndex("/names"); + if (!ExpectedNSI) { + consumeError(ExpectedNSI.takeError()); + return false; + } + assert(*ExpectedNSI < getNumStreams()); + return true; } /// Wrapper around MappedBlockStream::createIndexedStream() that checks if a diff --git a/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp b/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp index dee27c621fac..e164e7cf1c52 100644 --- a/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp +++ b/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp @@ -24,6 +24,8 @@ #include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h" #include "llvm/Support/BinaryStream.h" #include "llvm/Support/BinaryStreamWriter.h" +#include "llvm/Support/JamCRC.h" +#include "llvm/Support/Path.h" using namespace llvm; using namespace llvm::codeview; @@ -32,7 +34,8 @@ using namespace llvm::pdb; using namespace llvm::support; PDBFileBuilder::PDBFileBuilder(BumpPtrAllocator &Allocator) - : Allocator(Allocator) {} + : Allocator(Allocator), InjectedSourceHashTraits(Strings), + InjectedSourceTable(2, InjectedSourceHashTraits) {} PDBFileBuilder::~PDBFileBuilder() {} @@ -80,15 +83,46 @@ GSIStreamBuilder &PDBFileBuilder::getGsiBuilder() { return *Gsi; } -Error PDBFileBuilder::addNamedStream(StringRef Name, uint32_t Size) { +Expected<uint32_t> PDBFileBuilder::allocateNamedStream(StringRef Name, + uint32_t Size) { auto ExpectedStream = Msf->addStream(Size); - if (!ExpectedStream) - return ExpectedStream.takeError(); - NamedStreams.set(Name, *ExpectedStream); + if (ExpectedStream) + NamedStreams.set(Name, *ExpectedStream); + return ExpectedStream; +} + +Error PDBFileBuilder::addNamedStream(StringRef Name, StringRef Data) { + Expected<uint32_t> ExpectedIndex = allocateNamedStream(Name, Data.size()); + if (!ExpectedIndex) + return ExpectedIndex.takeError(); + assert(NamedStreamData.count(*ExpectedIndex) == 0); + NamedStreamData[*ExpectedIndex] = Data; return Error::success(); } -Expected<msf::MSFLayout> PDBFileBuilder::finalizeMsfLayout() { +void PDBFileBuilder::addInjectedSource(StringRef Name, + std::unique_ptr<MemoryBuffer> Buffer) { + // Stream names must be exact matches, since they get looked up in a hash + // table and the hash value is dependent on the exact contents of the string. + // link.exe lowercases a path and converts / to \, so we must do the same. + SmallString<64> VName; + sys::path::native(Name.lower(), VName); + + uint32_t NI = getStringTableBuilder().insert(Name); + uint32_t VNI = getStringTableBuilder().insert(VName); + + InjectedSourceDescriptor Desc; + Desc.Content = std::move(Buffer); + Desc.NameIndex = NI; + Desc.VNameIndex = VNI; + Desc.StreamName = "/src/files/"; + + Desc.StreamName += VName; + + InjectedSources.push_back(std::move(Desc)); +} + +Error PDBFileBuilder::finalizeMsfLayout() { if (Ipi && Ipi->getRecordCount() > 0) { // In theory newer PDBs always have an ID stream, but by saying that we're @@ -101,38 +135,85 @@ Expected<msf::MSFLayout> PDBFileBuilder::finalizeMsfLayout() { uint32_t StringsLen = Strings.calculateSerializedSize(); - if (auto EC = addNamedStream("/names", StringsLen)) - return std::move(EC); - if (auto EC = addNamedStream("/LinkInfo", 0)) - return std::move(EC); + Expected<uint32_t> SN = allocateNamedStream("/LinkInfo", 0); + if (!SN) + return SN.takeError(); - if (Info) { - if (auto EC = Info->finalizeMsfLayout()) - return std::move(EC); - } - if (Dbi) { - if (auto EC = Dbi->finalizeMsfLayout()) - return std::move(EC); + if (Gsi) { + if (auto EC = Gsi->finalizeMsfLayout()) + return EC; + if (Dbi) { + Dbi->setPublicsStreamIndex(Gsi->getPublicsStreamIndex()); + Dbi->setGlobalsStreamIndex(Gsi->getGlobalsStreamIndex()); + Dbi->setSymbolRecordStreamIndex(Gsi->getRecordStreamIdx()); + } } if (Tpi) { if (auto EC = Tpi->finalizeMsfLayout()) - return std::move(EC); + return EC; } + if (Dbi) { + if (auto EC = Dbi->finalizeMsfLayout()) + return EC; + } + SN = allocateNamedStream("/names", StringsLen); + if (!SN) + return SN.takeError(); + if (Ipi) { if (auto EC = Ipi->finalizeMsfLayout()) - return std::move(EC); + return EC; } - if (Gsi) { - if (auto EC = Gsi->finalizeMsfLayout()) - return std::move(EC); - if (Dbi) { - Dbi->setPublicsStreamIndex(Gsi->getPublicsStreamIndex()); - Dbi->setGlobalsStreamIndex(Gsi->getGlobalsStreamIndex()); - Dbi->setSymbolRecordStreamIndex(Gsi->getRecordStreamIdx()); + + // Do this last, since it relies on the named stream map being complete, and + // that can be updated by previous steps in the finalization. + if (Info) { + if (auto EC = Info->finalizeMsfLayout()) + return EC; + } + + if (!InjectedSources.empty()) { + for (const auto &IS : InjectedSources) { + JamCRC CRC(0); + CRC.update(makeArrayRef(IS.Content->getBufferStart(), + IS.Content->getBufferSize())); + + SrcHeaderBlockEntry Entry; + ::memset(&Entry, 0, sizeof(SrcHeaderBlockEntry)); + Entry.Size = sizeof(SrcHeaderBlockEntry); + Entry.FileSize = IS.Content->getBufferSize(); + Entry.FileNI = IS.NameIndex; + Entry.VFileNI = IS.VNameIndex; + Entry.ObjNI = 1; + Entry.IsVirtual = 0; + Entry.Version = + static_cast<uint32_t>(PdbRaw_SrcHeaderBlockVer::SrcVerOne); + Entry.CRC = CRC.getCRC(); + StringRef VName = getStringTableBuilder().getStringForId(IS.VNameIndex); + InjectedSourceTable.set_as(VName, std::move(Entry)); } + + uint32_t SrcHeaderBlockSize = + sizeof(SrcHeaderBlockHeader) + + InjectedSourceTable.calculateSerializedLength(); + SN = allocateNamedStream("/src/headerblock", SrcHeaderBlockSize); + if (!SN) + return SN.takeError(); + for (const auto &IS : InjectedSources) { + SN = allocateNamedStream(IS.StreamName, IS.Content->getBufferSize()); + if (!SN) + return SN.takeError(); + } + } + + // Do this last, since it relies on the named stream map being complete, and + // that can be updated by previous steps in the finalization. + if (Info) { + if (auto EC = Info->finalizeMsfLayout()) + return EC; } - return Msf->build(); + return Error::success(); } Expected<uint32_t> PDBFileBuilder::getNamedStreamIndex(StringRef Name) const { @@ -142,70 +223,55 @@ Expected<uint32_t> PDBFileBuilder::getNamedStreamIndex(StringRef Name) const { return SN; } -void PDBFileBuilder::commitFpm(WritableBinaryStream &MsfBuffer, - const MSFLayout &Layout) { - auto FpmStream = - WritableMappedBlockStream::createFpmStream(Layout, MsfBuffer, Allocator); - - // We only need to create the alt fpm stream so that it gets initialized. - WritableMappedBlockStream::createFpmStream(Layout, MsfBuffer, Allocator, - true); - - uint32_t BI = 0; - BinaryStreamWriter FpmWriter(*FpmStream); - while (BI < Layout.SB->NumBlocks) { - uint8_t ThisByte = 0; - for (uint32_t I = 0; I < 8; ++I) { - bool IsFree = - (BI < Layout.SB->NumBlocks) ? Layout.FreePageMap.test(BI) : true; - uint8_t Mask = uint8_t(IsFree) << I; - ThisByte |= Mask; - ++BI; - } - cantFail(FpmWriter.writeObject(ThisByte)); - } - assert(FpmWriter.bytesRemaining() == 0); +void PDBFileBuilder::commitSrcHeaderBlock(WritableBinaryStream &MsfBuffer, + const msf::MSFLayout &Layout) { + assert(!InjectedSourceTable.empty()); + + uint32_t SN = cantFail(getNamedStreamIndex("/src/headerblock")); + auto Stream = WritableMappedBlockStream::createIndexedStream( + Layout, MsfBuffer, SN, Allocator); + BinaryStreamWriter Writer(*Stream); + + SrcHeaderBlockHeader Header; + ::memset(&Header, 0, sizeof(Header)); + Header.Version = static_cast<uint32_t>(PdbRaw_SrcHeaderBlockVer::SrcVerOne); + Header.Size = Writer.bytesRemaining(); + + cantFail(Writer.writeObject(Header)); + cantFail(InjectedSourceTable.commit(Writer)); + + assert(Writer.bytesRemaining() == 0); } -Error PDBFileBuilder::commit(StringRef Filename) { - assert(!Filename.empty()); - auto ExpectedLayout = finalizeMsfLayout(); - if (!ExpectedLayout) - return ExpectedLayout.takeError(); - auto &Layout = *ExpectedLayout; - - uint64_t Filesize = Layout.SB->BlockSize * Layout.SB->NumBlocks; - auto OutFileOrError = FileOutputBuffer::create(Filename, Filesize); - if (auto E = OutFileOrError.takeError()) - return E; - FileBufferByteStream Buffer(std::move(*OutFileOrError), - llvm::support::little); - BinaryStreamWriter Writer(Buffer); - - if (auto EC = Writer.writeObject(*Layout.SB)) - return EC; +void PDBFileBuilder::commitInjectedSources(WritableBinaryStream &MsfBuffer, + const msf::MSFLayout &Layout) { + if (InjectedSourceTable.empty()) + return; - commitFpm(Buffer, Layout); + commitSrcHeaderBlock(MsfBuffer, Layout); - uint32_t BlockMapOffset = - msf::blockToOffset(Layout.SB->BlockMapAddr, Layout.SB->BlockSize); - Writer.setOffset(BlockMapOffset); - if (auto EC = Writer.writeArray(Layout.DirectoryBlocks)) - return EC; + for (const auto &IS : InjectedSources) { + uint32_t SN = cantFail(getNamedStreamIndex(IS.StreamName)); - auto DirStream = WritableMappedBlockStream::createDirectoryStream( - Layout, Buffer, Allocator); - BinaryStreamWriter DW(*DirStream); - if (auto EC = DW.writeInteger<uint32_t>(Layout.StreamSizes.size())) - return EC; + auto SourceStream = WritableMappedBlockStream::createIndexedStream( + Layout, MsfBuffer, SN, Allocator); + BinaryStreamWriter SourceWriter(*SourceStream); + assert(SourceWriter.bytesRemaining() == IS.Content->getBufferSize()); + cantFail(SourceWriter.writeBytes( + arrayRefFromStringRef(IS.Content->getBuffer()))); + } +} - if (auto EC = DW.writeArray(Layout.StreamSizes)) +Error PDBFileBuilder::commit(StringRef Filename) { + assert(!Filename.empty()); + if (auto EC = finalizeMsfLayout()) return EC; - for (const auto &Blocks : Layout.StreamMap) { - if (auto EC = DW.writeArray(Blocks)) - return EC; - } + MSFLayout Layout; + auto ExpectedMsfBuffer = Msf->commit(Filename, Layout); + if (!ExpectedMsfBuffer) + return ExpectedMsfBuffer.takeError(); + FileBufferByteStream Buffer = std::move(*ExpectedMsfBuffer); auto ExpectedSN = getNamedStreamIndex("/names"); if (!ExpectedSN) @@ -217,6 +283,17 @@ Error PDBFileBuilder::commit(StringRef Filename) { if (auto EC = Strings.commit(NSWriter)) return EC; + for (const auto &NSE : NamedStreamData) { + if (NSE.second.empty()) + continue; + + auto NS = WritableMappedBlockStream::createIndexedStream( + Layout, Buffer, NSE.first, Allocator); + BinaryStreamWriter NSW(*NS); + if (auto EC = NSW.writeBytes(arrayRefFromStringRef(NSE.second))) + return EC; + } + if (Info) { if (auto EC = Info->commit(Layout, Buffer)) return EC; @@ -242,5 +319,22 @@ Error PDBFileBuilder::commit(StringRef Filename) { return EC; } + auto InfoStreamBlocks = Layout.StreamMap[StreamPDB]; + assert(!InfoStreamBlocks.empty()); + uint64_t InfoStreamFileOffset = + blockToOffset(InfoStreamBlocks.front(), Layout.SB->BlockSize); + InfoStreamHeader *H = reinterpret_cast<InfoStreamHeader *>( + Buffer.getBufferStart() + InfoStreamFileOffset); + + commitInjectedSources(Buffer, Layout); + + // Set the build id at the very end, after every other byte of the PDB + // has been written. + // FIXME: Use a hash of the PDB rather than time(nullptr) for the signature. + H->Age = Info->getAge(); + H->Guid = Info->getGuid(); + Optional<uint32_t> Sig = Info->getSignature(); + H->Signature = Sig.hasValue() ? *Sig : time(nullptr); + return Buffer.commit(); } diff --git a/lib/DebugInfo/PDB/Native/PDBStringTable.cpp b/lib/DebugInfo/PDB/Native/PDBStringTable.cpp index f1c10357132b..afeea32043dd 100644 --- a/lib/DebugInfo/PDB/Native/PDBStringTable.cpp +++ b/lib/DebugInfo/PDB/Native/PDBStringTable.cpp @@ -122,7 +122,10 @@ Expected<uint32_t> PDBStringTable::getIDForString(StringRef Str) const { // we iterate the entire array. uint32_t Index = (Start + I) % Count; + // If we find 0, it means the item isn't in the hash table. uint32_t ID = IDs[Index]; + if (ID == 0) + return make_error<RawError>(raw_error_code::no_entry); auto ExpectedStr = getStringForID(ID); if (!ExpectedStr) return ExpectedStr.takeError(); diff --git a/lib/DebugInfo/PDB/Native/PDBStringTableBuilder.cpp b/lib/DebugInfo/PDB/Native/PDBStringTableBuilder.cpp index ece3e00b1a87..d9dcabf3d958 100644 --- a/lib/DebugInfo/PDB/Native/PDBStringTableBuilder.cpp +++ b/lib/DebugInfo/PDB/Native/PDBStringTableBuilder.cpp @@ -15,23 +15,101 @@ #include "llvm/Support/BinaryStreamWriter.h" #include "llvm/Support/Endian.h" +#include <map> + using namespace llvm; using namespace llvm::msf; using namespace llvm::support; using namespace llvm::support::endian; using namespace llvm::pdb; +StringTableHashTraits::StringTableHashTraits(PDBStringTableBuilder &Table) + : Table(&Table) {} + +uint32_t StringTableHashTraits::hashLookupKey(StringRef S) const { + return Table->getIdForString(S); +} + +StringRef StringTableHashTraits::storageKeyToLookupKey(uint32_t Offset) const { + return Table->getStringForId(Offset); +} + +uint32_t StringTableHashTraits::lookupKeyToStorageKey(StringRef S) { + return Table->insert(S); +} + uint32_t PDBStringTableBuilder::insert(StringRef S) { return Strings.insert(S); } +uint32_t PDBStringTableBuilder::getIdForString(StringRef S) const { + return Strings.getIdForString(S); +} + +StringRef PDBStringTableBuilder::getStringForId(uint32_t Id) const { + return Strings.getStringForId(Id); +} + +// This is a precomputed list of Buckets given the specified number of +// strings. Matching the reference algorithm exactly is not strictly +// necessary for correctness, but it helps when comparing LLD's PDBs with +// Microsoft's PDBs so as to eliminate superfluous differences. +static std::map<uint32_t, uint32_t> StringsToBuckets = { + {1, 2}, + {2, 4}, + {4, 7}, + {6, 11}, + {9, 17}, + {13, 26}, + {20, 40}, + {31, 61}, + {46, 92}, + {70, 139}, + {105, 209}, + {157, 314}, + {236, 472}, + {355, 709}, + {532, 1064}, + {799, 1597}, + {1198, 2396}, + {1798, 3595}, + {2697, 5393}, + {4045, 8090}, + {6068, 12136}, + {9103, 18205}, + {13654, 27308}, + {20482, 40963}, + {30723, 61445}, + {46084, 92168}, + {69127, 138253}, + {103690, 207380}, + {155536, 311071}, + {233304, 466607}, + {349956, 699911}, + {524934, 1049867}, + {787401, 1574801}, + {1181101, 2362202}, + {1771652, 3543304}, + {2657479, 5314957}, + {3986218, 7972436}, + {5979328, 11958655}, + {8968992, 17937983}, + {13453488, 26906975}, + {20180232, 40360463}, + {30270348, 60540695}, + {45405522, 90811043}, + {68108283, 136216565}, + {102162424, 204324848}, + {153243637, 306487273}, + {229865455, 459730910}, + {344798183, 689596366}, + {517197275, 1034394550}, + {775795913, 1551591826}}; + static uint32_t computeBucketCount(uint32_t NumStrings) { - // The /names stream is basically an on-disk open-addressing hash table. - // Hash collisions are resolved by linear probing. We cannot make - // utilization 100% because it will make the linear probing extremely - // slow. But lower utilization wastes disk space. As a reasonable - // load factor, we choose 80%. We need +1 because slot 0 is reserved. - return (NumStrings + 1) * 1.25; + auto Entry = StringsToBuckets.lower_bound(NumStrings); + assert(Entry != StringsToBuckets.end()); + return Entry->second; } uint32_t PDBStringTableBuilder::calculateHashTableSize() const { @@ -89,8 +167,6 @@ Error PDBStringTableBuilder::writeHashTable(BinaryStreamWriter &Writer) const { for (uint32_t I = 0; I != BucketCount; ++I) { uint32_t Slot = (Hash + I) % BucketCount; - if (Slot == 0) - continue; // Skip reserved slot if (Buckets[Slot] != 0) continue; Buckets[Slot] = Offset; diff --git a/lib/DebugInfo/PDB/Native/TpiStream.cpp b/lib/DebugInfo/PDB/Native/TpiStream.cpp index d3ef87d9009d..0680b673380a 100644 --- a/lib/DebugInfo/PDB/Native/TpiStream.cpp +++ b/lib/DebugInfo/PDB/Native/TpiStream.cpp @@ -152,7 +152,9 @@ FixedStreamArray<TypeIndexOffset> TpiStream::getTypeIndexOffsets() const { return TypeIndexOffsets; } -HashTable &TpiStream::getHashAdjusters() { return HashAdjusters; } +HashTable<support::ulittle32_t> &TpiStream::getHashAdjusters() { + return HashAdjusters; +} CVTypeRange TpiStream::types(bool *HadError) const { return make_range(TypeRecords.begin(HadError), TypeRecords.end()); diff --git a/lib/DebugInfo/PDB/PDBExtras.cpp b/lib/DebugInfo/PDB/PDBExtras.cpp index ee752cda346e..a4e316417f96 100644 --- a/lib/DebugInfo/PDB/PDBExtras.cpp +++ b/lib/DebugInfo/PDB/PDBExtras.cpp @@ -113,6 +113,8 @@ raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, const PDB_LocType &Loc) { CASE_OUTPUT_ENUM_CLASS_STR(PDB_LocType, IlRel, "IL rel", OS) CASE_OUTPUT_ENUM_CLASS_STR(PDB_LocType, MetaData, "metadata", OS) CASE_OUTPUT_ENUM_CLASS_STR(PDB_LocType, Constant, "constant", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_LocType, RegRelAliasIndir, + "regrelaliasindir", OS) default: OS << "Unknown"; } @@ -139,6 +141,7 @@ raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Checksum, None, OS) CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Checksum, MD5, OS) CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Checksum, SHA1, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Checksum, SHA256, OS) } return OS; } @@ -254,6 +257,18 @@ raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, return OS; } +raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, + const PDB_SourceCompression &Compression) { + switch (Compression) { + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SourceCompression, None, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SourceCompression, Huffman, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SourceCompression, LZ, OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_SourceCompression, RunLengthEncoded, "RLE", + OS) + } + return OS; +} + raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, const Variant &Value) { switch (Value.Type) { case PDB_VariantType::Bool: diff --git a/lib/DebugInfo/PDB/PDBInterfaceAnchors.cpp b/lib/DebugInfo/PDB/PDBInterfaceAnchors.cpp index b2b03fbe167b..c62796507a01 100644 --- a/lib/DebugInfo/PDB/PDBInterfaceAnchors.cpp +++ b/lib/DebugInfo/PDB/PDBInterfaceAnchors.cpp @@ -12,8 +12,10 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/PDB/IPDBDataStream.h" +#include "llvm/DebugInfo/PDB/IPDBInjectedSource.h" #include "llvm/DebugInfo/PDB/IPDBLineNumber.h" #include "llvm/DebugInfo/PDB/IPDBRawSymbol.h" +#include "llvm/DebugInfo/PDB/IPDBSectionContrib.h" #include "llvm/DebugInfo/PDB/IPDBSession.h" #include "llvm/DebugInfo/PDB/IPDBTable.h" @@ -29,3 +31,7 @@ IPDBRawSymbol::~IPDBRawSymbol() = default; IPDBLineNumber::~IPDBLineNumber() = default; IPDBTable::~IPDBTable() = default; + +IPDBInjectedSource::~IPDBInjectedSource() = default; + +IPDBSectionContrib::~IPDBSectionContrib() = default; diff --git a/lib/DebugInfo/PDB/PDBSymbolCompiland.cpp b/lib/DebugInfo/PDB/PDBSymbolCompiland.cpp index 854cf42d1bae..8798c7b9db88 100644 --- a/lib/DebugInfo/PDB/PDBSymbolCompiland.cpp +++ b/lib/DebugInfo/PDB/PDBSymbolCompiland.cpp @@ -1,4 +1,4 @@ -//===- PDBSymbolCompiland.cpp - compiland details --------*- C++ -*-===// +//===- PDBSymbolCompiland.cpp - compiland details ---------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,11 +7,16 @@ // //===----------------------------------------------------------------------===// +#include "llvm/DebugInfo/PDB/IPDBSession.h" +#include "llvm/DebugInfo/PDB/IPDBSourceFile.h" + #include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" +#include "llvm/DebugInfo/PDB/PDBSymbolCompilandDetails.h" #include "llvm/DebugInfo/PDB/PDBSymbolCompilandEnv.h" - #include "llvm/DebugInfo/PDB/PDBSymDumper.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/Path.h" #include <utility> using namespace llvm; @@ -27,20 +32,85 @@ void PDBSymbolCompiland::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); } -std::string PDBSymbolCompiland::getSourceFileName() const -{ - std::string Result = RawSymbol->getSourceFileName(); - if (!Result.empty()) - return Result; - auto Envs = findAllChildren<PDBSymbolCompilandEnv>(); - if (!Envs) - return std::string(); - while (auto Env = Envs->getNext()) { +std::string PDBSymbolCompiland::getSourceFileName() const { + return sys::path::filename(getSourceFileFullPath()).str(); +} + +std::string PDBSymbolCompiland::getSourceFileFullPath() const { + std::string SourceFileFullPath; + + // RecordedResult could be the basename, relative path or full path of the + // source file. Usually it is retrieved and recorded from the command that + // compiles this compiland. + // + // cmd FileName -> RecordedResult = .\\FileName + // cmd (Path)\\FileName -> RecordedResult = (Path)\\FileName + // + std::string RecordedResult = RawSymbol->getSourceFileName(); + + if (RecordedResult.empty()) { + if (auto Envs = findAllChildren<PDBSymbolCompilandEnv>()) { + std::string EnvWorkingDir, EnvSrc; + + while (auto Env = Envs->getNext()) { std::string Var = Env->getName(); - if (Var != "src") - continue; - std::string Value = Env->getValue(); - return Value; + if (Var == "cwd") { + EnvWorkingDir = Env->getValue(); + continue; + } + if (Var == "src") { + EnvSrc = Env->getValue(); + if (sys::path::is_absolute(EnvSrc)) + return EnvSrc; + RecordedResult = EnvSrc; + continue; + } + } + if (!EnvWorkingDir.empty() && !EnvSrc.empty()) { + auto Len = EnvWorkingDir.length(); + if (EnvWorkingDir[Len - 1] != '/' && EnvWorkingDir[Len - 1] != '\\') { + std::string Path = EnvWorkingDir + "\\" + EnvSrc; + std::replace(Path.begin(), Path.end(), '/', '\\'); + // We will return it as full path if we can't find a better one. + if (sys::path::is_absolute(Path)) + SourceFileFullPath = Path; + } + } + } + } + + if (!RecordedResult.empty()) { + if (sys::path::is_absolute(RecordedResult)) + return RecordedResult; + + // This searches name that has same basename as the one in RecordedResult. + auto OneSrcFile = Session.findOneSourceFile( + this, RecordedResult, PDB_NameSearchFlags::NS_CaseInsensitive); + if (OneSrcFile) + return OneSrcFile->getFileName(); + } + + // At this point, we have to walk through all source files of this compiland, + // and determine the right source file if any that is used to generate this + // compiland based on language indicated in compilanddetails language field. + auto Details = findOneChild<PDBSymbolCompilandDetails>(); + PDB_Lang Lang = Details ? Details->getLanguage() : PDB_Lang::Cpp; + auto SrcFiles = Session.getSourceFilesForCompiland(*this); + if (SrcFiles) { + bool LangC = (Lang == PDB_Lang::Cpp || Lang == PDB_Lang::C); + while (auto File = SrcFiles->getNext()) { + std::string FileName = File->getFileName(); + auto file_extension = sys::path::extension(FileName); + if (StringSwitch<bool>(file_extension.lower()) + .Case(".cpp", LangC) + .Case(".c", LangC) + .Case(".cc", LangC) + .Case(".cxx", LangC) + .Case(".asm", Lang == PDB_Lang::Masm) + .Default(false)) + return File->getFileName(); } - return std::string(); + } + + return SourceFileFullPath; } diff --git a/lib/DebugInfo/PDB/PDBSymbolData.cpp b/lib/DebugInfo/PDB/PDBSymbolData.cpp index 60026689c6f1..ae4a8038ccd7 100644 --- a/lib/DebugInfo/PDB/PDBSymbolData.cpp +++ b/lib/DebugInfo/PDB/PDBSymbolData.cpp @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/PDB/PDBSymbolData.h" - +#include "llvm/DebugInfo/PDB/IPDBSectionContrib.h" #include "llvm/DebugInfo/PDB/IPDBSession.h" #include "llvm/DebugInfo/PDB/PDBSymDumper.h" @@ -24,3 +24,52 @@ PDBSymbolData::PDBSymbolData(const IPDBSession &PDBSession, } void PDBSymbolData::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); } + +std::unique_ptr<IPDBEnumLineNumbers> PDBSymbolData::getLineNumbers() const { + auto Len = RawSymbol->getLength(); + Len = Len ? Len : 1; + if (auto RVA = RawSymbol->getRelativeVirtualAddress()) + return Session.findLineNumbersByRVA(RVA, Len); + + if (auto Section = RawSymbol->getAddressSection()) + return Session.findLineNumbersBySectOffset( + Section, RawSymbol->getAddressOffset(), Len); + + return nullptr; +} + +uint32_t PDBSymbolData::getCompilandId() const { + if (auto Lines = getLineNumbers()) { + if (auto FirstLine = Lines->getNext()) + return FirstLine->getCompilandId(); + } + + uint32_t DataSection = RawSymbol->getAddressSection(); + uint32_t DataOffset = RawSymbol->getAddressOffset(); + if (DataSection == 0) { + if (auto RVA = RawSymbol->getRelativeVirtualAddress()) + Session.addressForRVA(RVA, DataSection, DataOffset); + } + + if (DataSection) { + if (auto SecContribs = Session.getSectionContribs()) { + while (auto Section = SecContribs->getNext()) { + if (Section->getAddressSection() == DataSection && + Section->getAddressOffset() <= DataOffset && + (Section->getAddressOffset() + Section->getLength()) > DataOffset) + return Section->getCompilandId(); + } + } + } else { + auto LexParentId = RawSymbol->getLexicalParentId(); + while (auto LexParent = Session.getSymbolById(LexParentId)) { + if (LexParent->getSymTag() == PDB_SymType::Exe) + break; + if (LexParent->getSymTag() == PDB_SymType::Compiland) + return LexParentId; + LexParentId = LexParent->getRawSymbol().getLexicalParentId(); + } + } + + return 0; +} diff --git a/lib/DebugInfo/PDB/PDBSymbolFunc.cpp b/lib/DebugInfo/PDB/PDBSymbolFunc.cpp index c8c44d97e2f7..37ca1abe86e9 100644 --- a/lib/DebugInfo/PDB/PDBSymbolFunc.cpp +++ b/lib/DebugInfo/PDB/PDBSymbolFunc.cpp @@ -105,3 +105,18 @@ bool PDBSymbolFunc::isDestructor() const { return true; return false; } + +std::unique_ptr<IPDBEnumLineNumbers> PDBSymbolFunc::getLineNumbers() const { + auto Len = RawSymbol->getLength(); + return Session.findLineNumbersByAddress(RawSymbol->getVirtualAddress(), + Len ? Len : 1); +} + +uint32_t PDBSymbolFunc::getCompilandId() const { + if (auto Lines = getLineNumbers()) { + if (auto FirstLine = Lines->getNext()) { + return FirstLine->getCompilandId(); + } + } + return 0; +} diff --git a/lib/DebugInfo/PDB/PDBSymbolTypeFunctionSig.cpp b/lib/DebugInfo/PDB/PDBSymbolTypeFunctionSig.cpp index 0304c6286c8f..8fd3b49155c9 100644 --- a/lib/DebugInfo/PDB/PDBSymbolTypeFunctionSig.cpp +++ b/lib/DebugInfo/PDB/PDBSymbolTypeFunctionSig.cpp @@ -14,6 +14,7 @@ #include "llvm/DebugInfo/PDB/IPDBSession.h" #include "llvm/DebugInfo/PDB/PDBSymDumper.h" #include "llvm/DebugInfo/PDB/PDBSymbol.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionArg.h" #include <utility> @@ -84,3 +85,21 @@ void PDBSymbolTypeFunctionSig::dump(PDBSymDumper &Dumper) const { void PDBSymbolTypeFunctionSig::dumpRight(PDBSymDumper &Dumper) const { Dumper.dumpRight(*this); } + +bool PDBSymbolTypeFunctionSig::isCVarArgs() const { + auto SigArguments = getArguments(); + if (!SigArguments) + return false; + uint32_t NumArgs = SigArguments->getChildCount(); + if (NumArgs == 0) + return false; + auto Last = SigArguments->getChildAtIndex(NumArgs - 1); + if (auto Builtin = llvm::dyn_cast_or_null<PDBSymbolTypeBuiltin>(Last.get())) { + if (Builtin->getBuiltinType() == PDB_BuiltinType::None) + return true; + } + + // Note that for a variadic template signature, this method always returns + // false since the parameters of the template are specialized. + return false; +} |