diff options
Diffstat (limited to 'llvm/lib/DebugInfo/PDB')
101 files changed, 12564 insertions, 0 deletions
diff --git a/llvm/lib/DebugInfo/PDB/DIA/DIADataStream.cpp b/llvm/lib/DebugInfo/PDB/DIA/DIADataStream.cpp new file mode 100644 index 0000000000000..8a806f298d0fb --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/DIA/DIADataStream.cpp @@ -0,0 +1,56 @@ +//===- DIADataStream.cpp - DIA implementation of IPDBDataStream -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/DIA/DIADataStream.h" +#include "llvm/DebugInfo/PDB/DIA/DIAUtils.h" + +using namespace llvm; +using namespace llvm::pdb; + +DIADataStream::DIADataStream(CComPtr<IDiaEnumDebugStreamData> DiaStreamData) + : StreamData(DiaStreamData) {} + +uint32_t DIADataStream::getRecordCount() const { + LONG Count = 0; + return (S_OK == StreamData->get_Count(&Count)) ? Count : 0; +} + +std::string DIADataStream::getName() const { + return invokeBstrMethod(*StreamData, &IDiaEnumDebugStreamData::get_name); +} + +llvm::Optional<DIADataStream::RecordType> +DIADataStream::getItemAtIndex(uint32_t Index) const { + RecordType Record; + DWORD RecordSize = 0; + StreamData->Item(Index, 0, &RecordSize, nullptr); + if (RecordSize == 0) + return llvm::Optional<RecordType>(); + + Record.resize(RecordSize); + if (S_OK != StreamData->Item(Index, RecordSize, &RecordSize, &Record[0])) + return llvm::Optional<RecordType>(); + return Record; +} + +bool DIADataStream::getNext(RecordType &Record) { + Record.clear(); + DWORD RecordSize = 0; + ULONG CountFetched = 0; + StreamData->Next(1, 0, &RecordSize, nullptr, &CountFetched); + if (RecordSize == 0) + return false; + + Record.resize(RecordSize); + if (S_OK == + StreamData->Next(1, RecordSize, &RecordSize, &Record[0], &CountFetched)) + return false; + return true; +} + +void DIADataStream::reset() { StreamData->Reset(); } diff --git a/llvm/lib/DebugInfo/PDB/DIA/DIAEnumDebugStreams.cpp b/llvm/lib/DebugInfo/PDB/DIA/DIAEnumDebugStreams.cpp new file mode 100644 index 0000000000000..e4cb4daf94b14 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/DIA/DIAEnumDebugStreams.cpp @@ -0,0 +1,46 @@ +//==- DIAEnumDebugStreams.cpp - DIA Debug Stream Enumerator impl -*- C++ -*-==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/DIA/DIAEnumDebugStreams.h" +#include "llvm/DebugInfo/PDB/DIA/DIADataStream.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" + +using namespace llvm; +using namespace llvm::pdb; + +DIAEnumDebugStreams::DIAEnumDebugStreams( + CComPtr<IDiaEnumDebugStreams> DiaEnumerator) + : Enumerator(DiaEnumerator) {} + +uint32_t DIAEnumDebugStreams::getChildCount() const { + LONG Count = 0; + return (S_OK == Enumerator->get_Count(&Count)) ? Count : 0; +} + +std::unique_ptr<IPDBDataStream> +DIAEnumDebugStreams::getChildAtIndex(uint32_t Index) const { + CComPtr<IDiaEnumDebugStreamData> Item; + VARIANT VarIndex; + VarIndex.vt = VT_I4; + VarIndex.lVal = Index; + if (S_OK != Enumerator->Item(VarIndex, &Item)) + return nullptr; + + return std::unique_ptr<IPDBDataStream>(new DIADataStream(Item)); +} + +std::unique_ptr<IPDBDataStream> DIAEnumDebugStreams::getNext() { + CComPtr<IDiaEnumDebugStreamData> Item; + ULONG NumFetched = 0; + if (S_OK != Enumerator->Next(1, &Item, &NumFetched)) + return nullptr; + + return std::unique_ptr<IPDBDataStream>(new DIADataStream(Item)); +} + +void DIAEnumDebugStreams::reset() { Enumerator->Reset(); } diff --git a/llvm/lib/DebugInfo/PDB/DIA/DIAEnumFrameData.cpp b/llvm/lib/DebugInfo/PDB/DIA/DIAEnumFrameData.cpp new file mode 100644 index 0000000000000..8a181b448a270 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/DIA/DIAEnumFrameData.cpp @@ -0,0 +1,41 @@ +//==- DIAEnumFrameData.cpp ---------------------------------------*- C++ -*-==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/DIA/DIAEnumFrameData.h" +#include "llvm/DebugInfo/PDB/DIA/DIAFrameData.h" +#include "llvm/DebugInfo/PDB/DIA/DIASession.h" + +using namespace llvm::pdb; + +DIAEnumFrameData::DIAEnumFrameData(CComPtr<IDiaEnumFrameData> DiaEnumerator) + : Enumerator(DiaEnumerator) {} + +uint32_t DIAEnumFrameData::getChildCount() const { + LONG Count = 0; + return (S_OK == Enumerator->get_Count(&Count)) ? Count : 0; +} + +std::unique_ptr<IPDBFrameData> +DIAEnumFrameData::getChildAtIndex(uint32_t Index) const { + CComPtr<IDiaFrameData> Item; + if (S_OK != Enumerator->Item(Index, &Item)) + return nullptr; + + return std::unique_ptr<IPDBFrameData>(new DIAFrameData(Item)); +} + +std::unique_ptr<IPDBFrameData> DIAEnumFrameData::getNext() { + CComPtr<IDiaFrameData> Item; + ULONG NumFetched = 0; + if (S_OK != Enumerator->Next(1, &Item, &NumFetched)) + return nullptr; + + return std::unique_ptr<IPDBFrameData>(new DIAFrameData(Item)); +} + +void DIAEnumFrameData::reset() { Enumerator->Reset(); } diff --git a/llvm/lib/DebugInfo/PDB/DIA/DIAEnumInjectedSources.cpp b/llvm/lib/DebugInfo/PDB/DIA/DIAEnumInjectedSources.cpp new file mode 100644 index 0000000000000..7226ab2ba0a04 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/DIA/DIAEnumInjectedSources.cpp @@ -0,0 +1,43 @@ +//==- DIAEnumSourceFiles.cpp - DIA Source File Enumerator impl ---*- C++ -*-==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#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( + CComPtr<IDiaEnumInjectedSources> DiaEnumerator) + : 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(); } diff --git a/llvm/lib/DebugInfo/PDB/DIA/DIAEnumLineNumbers.cpp b/llvm/lib/DebugInfo/PDB/DIA/DIAEnumLineNumbers.cpp new file mode 100644 index 0000000000000..6f1d7733fb2de --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/DIA/DIAEnumLineNumbers.cpp @@ -0,0 +1,43 @@ +//==- DIAEnumLineNumbers.cpp - DIA Line Number Enumerator impl ---*- C++ -*-==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/DIA/DIAEnumLineNumbers.h" +#include "llvm/DebugInfo/PDB/DIA/DIALineNumber.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" + +using namespace llvm; +using namespace llvm::pdb; + +DIAEnumLineNumbers::DIAEnumLineNumbers( + CComPtr<IDiaEnumLineNumbers> DiaEnumerator) + : Enumerator(DiaEnumerator) {} + +uint32_t DIAEnumLineNumbers::getChildCount() const { + LONG Count = 0; + return (S_OK == Enumerator->get_Count(&Count)) ? Count : 0; +} + +std::unique_ptr<IPDBLineNumber> +DIAEnumLineNumbers::getChildAtIndex(uint32_t Index) const { + CComPtr<IDiaLineNumber> Item; + if (S_OK != Enumerator->Item(Index, &Item)) + return nullptr; + + return std::unique_ptr<IPDBLineNumber>(new DIALineNumber(Item)); +} + +std::unique_ptr<IPDBLineNumber> DIAEnumLineNumbers::getNext() { + CComPtr<IDiaLineNumber> Item; + ULONG NumFetched = 0; + if (S_OK != Enumerator->Next(1, &Item, &NumFetched)) + return nullptr; + + return std::unique_ptr<IPDBLineNumber>(new DIALineNumber(Item)); +} + +void DIAEnumLineNumbers::reset() { Enumerator->Reset(); } diff --git a/llvm/lib/DebugInfo/PDB/DIA/DIAEnumSectionContribs.cpp b/llvm/lib/DebugInfo/PDB/DIA/DIAEnumSectionContribs.cpp new file mode 100644 index 0000000000000..4f9b232a024aa --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/DIA/DIAEnumSectionContribs.cpp @@ -0,0 +1,46 @@ +//==- DIAEnumSectionContribs.cpp ---------------------------------*- C++ -*-==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#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(); } diff --git a/llvm/lib/DebugInfo/PDB/DIA/DIAEnumSourceFiles.cpp b/llvm/lib/DebugInfo/PDB/DIA/DIAEnumSourceFiles.cpp new file mode 100644 index 0000000000000..943e9e1b4d580 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/DIA/DIAEnumSourceFiles.cpp @@ -0,0 +1,43 @@ +//==- DIAEnumSourceFiles.cpp - DIA Source File Enumerator impl ---*- C++ -*-==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/DIA/DIAEnumSourceFiles.h" +#include "llvm/DebugInfo/PDB/DIA/DIASourceFile.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" + +using namespace llvm; +using namespace llvm::pdb; + +DIAEnumSourceFiles::DIAEnumSourceFiles( + const DIASession &PDBSession, CComPtr<IDiaEnumSourceFiles> DiaEnumerator) + : Session(PDBSession), Enumerator(DiaEnumerator) {} + +uint32_t DIAEnumSourceFiles::getChildCount() const { + LONG Count = 0; + return (S_OK == Enumerator->get_Count(&Count)) ? Count : 0; +} + +std::unique_ptr<IPDBSourceFile> +DIAEnumSourceFiles::getChildAtIndex(uint32_t Index) const { + CComPtr<IDiaSourceFile> Item; + if (S_OK != Enumerator->Item(Index, &Item)) + return nullptr; + + return std::unique_ptr<IPDBSourceFile>(new DIASourceFile(Session, Item)); +} + +std::unique_ptr<IPDBSourceFile> DIAEnumSourceFiles::getNext() { + CComPtr<IDiaSourceFile> Item; + ULONG NumFetched = 0; + if (S_OK != Enumerator->Next(1, &Item, &NumFetched)) + return nullptr; + + return std::unique_ptr<IPDBSourceFile>(new DIASourceFile(Session, Item)); +} + +void DIAEnumSourceFiles::reset() { Enumerator->Reset(); } diff --git a/llvm/lib/DebugInfo/PDB/DIA/DIAEnumSymbols.cpp b/llvm/lib/DebugInfo/PDB/DIA/DIAEnumSymbols.cpp new file mode 100644 index 0000000000000..5153596d52ae0 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/DIA/DIAEnumSymbols.cpp @@ -0,0 +1,47 @@ +//==- DIAEnumSymbols.cpp - DIA Symbol Enumerator impl ------------*- C++ -*-==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/DIA/DIAEnumSymbols.h" +#include "llvm/DebugInfo/PDB/DIA/DIARawSymbol.h" +#include "llvm/DebugInfo/PDB/DIA/DIASession.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" + +using namespace llvm; +using namespace llvm::pdb; + +DIAEnumSymbols::DIAEnumSymbols(const DIASession &PDBSession, + CComPtr<IDiaEnumSymbols> DiaEnumerator) + : Session(PDBSession), Enumerator(DiaEnumerator) {} + +uint32_t DIAEnumSymbols::getChildCount() const { + LONG Count = 0; + return (S_OK == Enumerator->get_Count(&Count)) ? Count : 0; +} + +std::unique_ptr<PDBSymbol> +DIAEnumSymbols::getChildAtIndex(uint32_t Index) const { + CComPtr<IDiaSymbol> Item; + if (S_OK != Enumerator->Item(Index, &Item)) + return nullptr; + + std::unique_ptr<DIARawSymbol> RawSymbol(new DIARawSymbol(Session, Item)); + return std::unique_ptr<PDBSymbol>(PDBSymbol::create(Session, std::move(RawSymbol))); +} + +std::unique_ptr<PDBSymbol> DIAEnumSymbols::getNext() { + CComPtr<IDiaSymbol> Item; + ULONG NumFetched = 0; + if (S_OK != Enumerator->Next(1, &Item, &NumFetched)) + return nullptr; + + std::unique_ptr<DIARawSymbol> RawSymbol(new DIARawSymbol(Session, Item)); + return std::unique_ptr<PDBSymbol>( + PDBSymbol::create(Session, std::move(RawSymbol))); +} + +void DIAEnumSymbols::reset() { Enumerator->Reset(); } diff --git a/llvm/lib/DebugInfo/PDB/DIA/DIAEnumTables.cpp b/llvm/lib/DebugInfo/PDB/DIA/DIAEnumTables.cpp new file mode 100644 index 0000000000000..335b575d65423 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/DIA/DIAEnumTables.cpp @@ -0,0 +1,44 @@ +//===- DIAEnumTables.cpp - DIA Table Enumerator Impl ------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/DIA/DIAEnumTables.h" +#include "llvm/DebugInfo/PDB/DIA/DIATable.h" + +using namespace llvm; +using namespace llvm::pdb; + +DIAEnumTables::DIAEnumTables(CComPtr<IDiaEnumTables> DiaEnumerator) + : Enumerator(DiaEnumerator) {} + +uint32_t DIAEnumTables::getChildCount() const { + LONG Count = 0; + return (S_OK == Enumerator->get_Count(&Count)) ? Count : 0; +} + +std::unique_ptr<IPDBTable> +DIAEnumTables::getChildAtIndex(uint32_t Index) const { + CComPtr<IDiaTable> Item; + VARIANT Var; + Var.vt = VT_UINT; + Var.uintVal = Index; + if (S_OK != Enumerator->Item(Var, &Item)) + return nullptr; + + return std::unique_ptr<IPDBTable>(new DIATable(Item)); +} + +std::unique_ptr<IPDBTable> DIAEnumTables::getNext() { + CComPtr<IDiaTable> Item; + ULONG CeltFetched = 0; + if (S_OK != Enumerator->Next(1, &Item, &CeltFetched)) + return nullptr; + + return std::unique_ptr<IPDBTable>(new DIATable(Item)); +} + +void DIAEnumTables::reset() { Enumerator->Reset(); } diff --git a/llvm/lib/DebugInfo/PDB/DIA/DIAError.cpp b/llvm/lib/DebugInfo/PDB/DIA/DIAError.cpp new file mode 100644 index 0000000000000..819651f777878 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/DIA/DIAError.cpp @@ -0,0 +1,37 @@ +#include "llvm/DebugInfo/PDB/DIA/DIAError.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/ManagedStatic.h" + +using namespace llvm; +using namespace llvm::pdb; + +// FIXME: This class is only here to support the transition to llvm::Error. It +// will be removed once this transition is complete. Clients should prefer to +// deal with the Error value directly, rather than converting to error_code. +class DIAErrorCategory : public std::error_category { +public: + const char *name() const noexcept override { return "llvm.pdb.dia"; } + std::string message(int Condition) const override { + switch (static_cast<dia_error_code>(Condition)) { + case dia_error_code::could_not_create_impl: + return "Failed to connect to DIA at runtime. Verify that Visual Studio " + "is properly installed, or that msdiaXX.dll is in your PATH."; + case dia_error_code::invalid_file_format: + return "Unable to load PDB. The file has an unrecognized format."; + case dia_error_code::invalid_parameter: + return "The parameter is incorrect."; + case dia_error_code::already_loaded: + return "Unable to load the PDB or EXE, because it is already loaded."; + case dia_error_code::debug_info_mismatch: + return "The PDB file and the EXE file do not match."; + case dia_error_code::unspecified: + return "An unknown error has occurred."; + } + llvm_unreachable("Unrecognized DIAErrorCode"); + } +}; + +static llvm::ManagedStatic<DIAErrorCategory> DIACategory; +const std::error_category &llvm::pdb::DIAErrCategory() { return *DIACategory; } + +char DIAError::ID; diff --git a/llvm/lib/DebugInfo/PDB/DIA/DIAFrameData.cpp b/llvm/lib/DebugInfo/PDB/DIA/DIAFrameData.cpp new file mode 100644 index 0000000000000..7975156b1abde --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/DIA/DIAFrameData.cpp @@ -0,0 +1,52 @@ +//===- DIAFrameData.cpp - DIA impl. of IPDBFrameData -------------- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/DIA/DIAFrameData.h" +#include "llvm/DebugInfo/PDB/DIA/DIASession.h" +#include "llvm/DebugInfo/PDB/DIA/DIAUtils.h" + +using namespace llvm::pdb; + +DIAFrameData::DIAFrameData(CComPtr<IDiaFrameData> DiaFrameData) + : FrameData(DiaFrameData) {} + +template <typename ArgType> +ArgType +PrivateGetDIAValue(IDiaFrameData *FrameData, + HRESULT (__stdcall IDiaFrameData::*Method)(ArgType *)) { + ArgType Value; + if (S_OK == (FrameData->*Method)(&Value)) + return static_cast<ArgType>(Value); + + return ArgType(); +} + +uint32_t DIAFrameData::getAddressOffset() const { + return PrivateGetDIAValue(FrameData, &IDiaFrameData::get_addressOffset); +} + +uint32_t DIAFrameData::getAddressSection() const { + return PrivateGetDIAValue(FrameData, &IDiaFrameData::get_addressSection); +} + +uint32_t DIAFrameData::getLengthBlock() const { + return PrivateGetDIAValue(FrameData, &IDiaFrameData::get_lengthBlock); +} + +std::string DIAFrameData::getProgram() const { + return invokeBstrMethod(*FrameData, &IDiaFrameData::get_program); +} + +uint32_t DIAFrameData::getRelativeVirtualAddress() const { + return PrivateGetDIAValue(FrameData, + &IDiaFrameData::get_relativeVirtualAddress); +} + +uint64_t DIAFrameData::getVirtualAddress() const { + return PrivateGetDIAValue(FrameData, &IDiaFrameData::get_virtualAddress); +} diff --git a/llvm/lib/DebugInfo/PDB/DIA/DIAInjectedSource.cpp b/llvm/lib/DebugInfo/PDB/DIA/DIAInjectedSource.cpp new file mode 100644 index 0000000000000..032b230b5faa0 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/DIA/DIAInjectedSource.cpp @@ -0,0 +1,62 @@ +//===- DIAInjectedSource.cpp - DIA impl for IPDBInjectedSource --*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#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); +} + +uint32_t DIAInjectedSource::getCompression() const { + DWORD Compression = 0; + if (S_OK != SourceFile->get_sourceCompression(&Compression)) + return PDB_SourceCompression::None; + return static_cast<uint32_t>(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/llvm/lib/DebugInfo/PDB/DIA/DIALineNumber.cpp b/llvm/lib/DebugInfo/PDB/DIA/DIALineNumber.cpp new file mode 100644 index 0000000000000..3af02ea36c7ba --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/DIA/DIALineNumber.cpp @@ -0,0 +1,75 @@ +//===- DIALineNumber.cpp - DIA implementation of IPDBLineNumber -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/DIA/DIALineNumber.h" + +using namespace llvm; +using namespace llvm::pdb; + +DIALineNumber::DIALineNumber(CComPtr<IDiaLineNumber> DiaLineNumber) + : LineNumber(DiaLineNumber) {} + +uint32_t DIALineNumber::getLineNumber() const { + DWORD Line = 0; + return (S_OK == LineNumber->get_lineNumber(&Line)) ? Line : 0; +} + +uint32_t DIALineNumber::getLineNumberEnd() const { + DWORD LineEnd = 0; + return (S_OK == LineNumber->get_lineNumberEnd(&LineEnd)) ? LineEnd : 0; +} + +uint32_t DIALineNumber::getColumnNumber() const { + DWORD Column = 0; + return (S_OK == LineNumber->get_columnNumber(&Column)) ? Column : 0; +} + +uint32_t DIALineNumber::getColumnNumberEnd() const { + DWORD ColumnEnd = 0; + return (S_OK == LineNumber->get_columnNumberEnd(&ColumnEnd)) ? ColumnEnd : 0; +} + +uint32_t DIALineNumber::getAddressSection() const { + DWORD Section = 0; + return (S_OK == LineNumber->get_addressSection(&Section)) ? Section : 0; +} + +uint32_t DIALineNumber::getAddressOffset() const { + DWORD Offset = 0; + return (S_OK == LineNumber->get_addressOffset(&Offset)) ? Offset : 0; +} + +uint32_t DIALineNumber::getRelativeVirtualAddress() const { + DWORD RVA = 0; + return (S_OK == LineNumber->get_relativeVirtualAddress(&RVA)) ? RVA : 0; +} + +uint64_t DIALineNumber::getVirtualAddress() const { + ULONGLONG Addr = 0; + return (S_OK == LineNumber->get_virtualAddress(&Addr)) ? Addr : 0; +} + +uint32_t DIALineNumber::getLength() const { + DWORD Length = 0; + return (S_OK == LineNumber->get_length(&Length)) ? Length : 0; +} + +uint32_t DIALineNumber::getSourceFileId() const { + DWORD Id = 0; + return (S_OK == LineNumber->get_sourceFileId(&Id)) ? Id : 0; +} + +uint32_t DIALineNumber::getCompilandId() const { + DWORD Id = 0; + return (S_OK == LineNumber->get_compilandId(&Id)) ? Id : 0; +} + +bool DIALineNumber::isStatement() const { + BOOL Statement = 0; + return (S_OK == LineNumber->get_statement(&Statement)) ? Statement : false; +} diff --git a/llvm/lib/DebugInfo/PDB/DIA/DIARawSymbol.cpp b/llvm/lib/DebugInfo/PDB/DIA/DIARawSymbol.cpp new file mode 100644 index 0000000000000..c2552f55703ce --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/DIA/DIARawSymbol.cpp @@ -0,0 +1,1270 @@ +//===- DIARawSymbol.cpp - DIA implementation of IPDBRawSymbol ---*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/DIA/DIARawSymbol.h" +#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/DIA/DIAUtils.h" +#include "llvm/DebugInfo/PDB/PDBExtras.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTableShape.h" +#include "llvm/Support/ConvertUTF.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; +using namespace llvm::pdb; + +namespace { +Variant VariantFromVARIANT(const VARIANT &V) { + Variant Result; + switch (V.vt) { + case VT_I1: + Result.Value.Int8 = V.cVal; + Result.Type = PDB_VariantType::Int8; + break; + case VT_I2: + Result.Value.Int16 = V.iVal; + Result.Type = PDB_VariantType::Int16; + break; + case VT_I4: + Result.Value.Int32 = V.intVal; + Result.Type = PDB_VariantType::Int32; + break; + case VT_I8: + Result.Value.Int64 = V.llVal; + Result.Type = PDB_VariantType::Int64; + break; + case VT_UI1: + Result.Value.UInt8 = V.bVal; + Result.Type = PDB_VariantType::UInt8; + break; + case VT_UI2: + Result.Value.UInt16 = V.uiVal; + Result.Type = PDB_VariantType::UInt16; + break; + case VT_UI4: + Result.Value.UInt32 = V.uintVal; + Result.Type = PDB_VariantType::UInt32; + break; + case VT_UI8: + Result.Value.UInt64 = V.ullVal; + Result.Type = PDB_VariantType::UInt64; + break; + case VT_BOOL: + Result.Value.Bool = (V.boolVal == VARIANT_TRUE) ? true : false; + Result.Type = PDB_VariantType::Bool; + break; + case VT_R4: + Result.Value.Single = V.fltVal; + Result.Type = PDB_VariantType::Single; + break; + case VT_R8: + Result.Value.Double = V.dblVal; + Result.Type = PDB_VariantType::Double; + break; + case VT_BSTR: { + const char *SrcBytes = reinterpret_cast<const char *>(V.bstrVal); + llvm::ArrayRef<char> SrcByteArray(SrcBytes, SysStringByteLen(V.bstrVal)); + std::string Result8; + if (!llvm::convertUTF16ToUTF8String(SrcByteArray, Result8)) + Result.Value.String = nullptr; + Result.Value.String = new char[Result8.length() + 1]; + ::strcpy(Result.Value.String, Result8.c_str()); + Result.Type = PDB_VariantType::String; + break; + } + default: + Result.Type = PDB_VariantType::Unknown; + break; + } + return Result; +} + +template <typename ArgType> +ArgType PrivateGetDIAValue(IDiaSymbol *Symbol, + HRESULT (__stdcall IDiaSymbol::*Method)(ArgType *)) { + ArgType Value; + if (S_OK == (Symbol->*Method)(&Value)) + return static_cast<ArgType>(Value); + + return ArgType(); +} + +template <typename ArgType, typename RetType> +RetType PrivateGetDIAValue(IDiaSymbol *Symbol, + HRESULT (__stdcall IDiaSymbol::*Method)(ArgType *)) { + ArgType Value; + if (S_OK == (Symbol->*Method)(&Value)) + return static_cast<RetType>(Value); + + return RetType(); +} + +std::string +PrivateGetDIAValue(IDiaSymbol *Symbol, + HRESULT (__stdcall IDiaSymbol::*Method)(BSTR *)) { + return invokeBstrMethod(*Symbol, Method); +} + +codeview::GUID +PrivateGetDIAValue(IDiaSymbol *Symbol, + HRESULT (__stdcall IDiaSymbol::*Method)(GUID *)) { + GUID Result; + if (S_OK != (Symbol->*Method)(&Result)) + return codeview::GUID(); + + static_assert(sizeof(codeview::GUID) == sizeof(GUID), + "GUID is the wrong size!"); + codeview::GUID IdResult; + ::memcpy(&IdResult, &Result, sizeof(GUID)); + return IdResult; +} + +template <typename PrintType, typename ArgType> +void DumpDIAValueAs(llvm::raw_ostream &OS, int Indent, StringRef Name, + IDiaSymbol *Symbol, + HRESULT (__stdcall IDiaSymbol::*Method)(ArgType *)) { + ArgType Value; + if (S_OK == (Symbol->*Method)(&Value)) + dumpSymbolField(OS, Name, static_cast<PrintType>(Value), Indent); +} + +void DumpDIAIdValue(llvm::raw_ostream &OS, int Indent, StringRef Name, + IDiaSymbol *Symbol, + HRESULT (__stdcall IDiaSymbol::*Method)(DWORD *), + const IPDBSession &Session, PdbSymbolIdField FieldId, + PdbSymbolIdField ShowFlags, PdbSymbolIdField RecurseFlags) { + DWORD Value; + if (S_OK == (Symbol->*Method)(&Value)) + dumpSymbolIdField(OS, Name, Value, Indent, Session, FieldId, ShowFlags, + RecurseFlags); +} + +template <typename ArgType> +void DumpDIAValue(llvm::raw_ostream &OS, int Indent, StringRef Name, + IDiaSymbol *Symbol, + HRESULT (__stdcall IDiaSymbol::*Method)(ArgType *)) { + ArgType Value; + if (S_OK == (Symbol->*Method)(&Value)) + dumpSymbolField(OS, Name, Value, Indent); +} + +void DumpDIAValue(llvm::raw_ostream &OS, int Indent, StringRef Name, + IDiaSymbol *Symbol, + HRESULT (__stdcall IDiaSymbol::*Method)(BSTR *)) { + BSTR Value = nullptr; + if (S_OK != (Symbol->*Method)(&Value)) + return; + const char *Bytes = reinterpret_cast<const char *>(Value); + ArrayRef<char> ByteArray(Bytes, ::SysStringByteLen(Value)); + std::string Result; + if (llvm::convertUTF16ToUTF8String(ByteArray, Result)) + dumpSymbolField(OS, Name, Result, Indent); + ::SysFreeString(Value); +} + +void DumpDIAValue(llvm::raw_ostream &OS, int Indent, StringRef Name, + IDiaSymbol *Symbol, + HRESULT (__stdcall IDiaSymbol::*Method)(VARIANT *)) { + VARIANT Value; + Value.vt = VT_EMPTY; + if (S_OK != (Symbol->*Method)(&Value)) + return; + Variant V = VariantFromVARIANT(Value); + + dumpSymbolField(OS, Name, V, Indent); +} +} // namespace + +namespace llvm { +llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const GUID &G) { + StringRef GuidBytes(reinterpret_cast<const char *>(&G), sizeof(G)); + codeview::detail::GuidAdapter A(GuidBytes); + A.format(OS, ""); + return OS; +} +} // namespace llvm + +DIARawSymbol::DIARawSymbol(const DIASession &PDBSession, + CComPtr<IDiaSymbol> DiaSymbol) + : Session(PDBSession), Symbol(DiaSymbol) {} + +#define RAW_ID_METHOD_DUMP(Stream, Method, Session, FieldId, ShowFlags, \ + RecurseFlags) \ + DumpDIAIdValue(Stream, Indent, StringRef{#Method}, Symbol, \ + &IDiaSymbol::get_##Method, Session, FieldId, ShowFlags, \ + RecurseFlags); + +#define RAW_METHOD_DUMP(Stream, Method) \ + DumpDIAValue(Stream, Indent, StringRef{#Method}, Symbol, \ + &IDiaSymbol::get_##Method); + +#define RAW_METHOD_DUMP_AS(Stream, Method, Type) \ + DumpDIAValueAs<Type>(Stream, Indent, StringRef{#Method}, Symbol, \ + &IDiaSymbol::get_##Method); + +void DIARawSymbol::dump(raw_ostream &OS, int Indent, + PdbSymbolIdField ShowIdFields, + PdbSymbolIdField RecurseIdFields) const { + RAW_ID_METHOD_DUMP(OS, symIndexId, Session, PdbSymbolIdField::SymIndexId, + ShowIdFields, RecurseIdFields); + RAW_METHOD_DUMP_AS(OS, symTag, PDB_SymType); + + RAW_METHOD_DUMP(OS, access); + RAW_METHOD_DUMP(OS, addressOffset); + RAW_METHOD_DUMP(OS, addressSection); + RAW_METHOD_DUMP(OS, age); + RAW_METHOD_DUMP(OS, arrayIndexTypeId); + RAW_METHOD_DUMP(OS, backEndMajor); + RAW_METHOD_DUMP(OS, backEndMinor); + RAW_METHOD_DUMP(OS, backEndBuild); + RAW_METHOD_DUMP(OS, backEndQFE); + RAW_METHOD_DUMP(OS, baseDataOffset); + RAW_METHOD_DUMP(OS, baseDataSlot); + RAW_METHOD_DUMP(OS, baseSymbolId); + RAW_METHOD_DUMP_AS(OS, baseType, PDB_BuiltinType); + RAW_METHOD_DUMP(OS, bitPosition); + RAW_METHOD_DUMP_AS(OS, callingConvention, PDB_CallingConv); + RAW_ID_METHOD_DUMP(OS, classParentId, Session, PdbSymbolIdField::ClassParent, + ShowIdFields, RecurseIdFields); + RAW_METHOD_DUMP(OS, compilerName); + RAW_METHOD_DUMP(OS, count); + RAW_METHOD_DUMP(OS, countLiveRanges); + RAW_METHOD_DUMP(OS, frontEndMajor); + RAW_METHOD_DUMP(OS, frontEndMinor); + RAW_METHOD_DUMP(OS, frontEndBuild); + RAW_METHOD_DUMP(OS, frontEndQFE); + RAW_ID_METHOD_DUMP(OS, lexicalParentId, Session, + PdbSymbolIdField::LexicalParent, ShowIdFields, + RecurseIdFields); + RAW_METHOD_DUMP(OS, libraryName); + RAW_METHOD_DUMP(OS, liveRangeStartAddressOffset); + RAW_METHOD_DUMP(OS, liveRangeStartAddressSection); + RAW_METHOD_DUMP(OS, liveRangeStartRelativeVirtualAddress); + RAW_METHOD_DUMP(OS, localBasePointerRegisterId); + RAW_METHOD_DUMP(OS, lowerBoundId); + RAW_METHOD_DUMP(OS, memorySpaceKind); + RAW_METHOD_DUMP(OS, name); + RAW_METHOD_DUMP(OS, numberOfAcceleratorPointerTags); + RAW_METHOD_DUMP(OS, numberOfColumns); + RAW_METHOD_DUMP(OS, numberOfModifiers); + RAW_METHOD_DUMP(OS, numberOfRegisterIndices); + RAW_METHOD_DUMP(OS, numberOfRows); + RAW_METHOD_DUMP(OS, objectFileName); + RAW_METHOD_DUMP(OS, oemId); + RAW_METHOD_DUMP(OS, oemSymbolId); + RAW_METHOD_DUMP(OS, offsetInUdt); + RAW_METHOD_DUMP(OS, platform); + RAW_METHOD_DUMP(OS, rank); + RAW_METHOD_DUMP(OS, registerId); + RAW_METHOD_DUMP(OS, registerType); + RAW_METHOD_DUMP(OS, relativeVirtualAddress); + RAW_METHOD_DUMP(OS, samplerSlot); + RAW_METHOD_DUMP(OS, signature); + RAW_METHOD_DUMP(OS, sizeInUdt); + RAW_METHOD_DUMP(OS, slot); + RAW_METHOD_DUMP(OS, sourceFileName); + RAW_METHOD_DUMP(OS, stride); + RAW_METHOD_DUMP(OS, subTypeId); + RAW_METHOD_DUMP(OS, symbolsFileName); + RAW_METHOD_DUMP(OS, targetOffset); + RAW_METHOD_DUMP(OS, targetRelativeVirtualAddress); + RAW_METHOD_DUMP(OS, targetVirtualAddress); + RAW_METHOD_DUMP(OS, targetSection); + RAW_METHOD_DUMP(OS, textureSlot); + RAW_METHOD_DUMP(OS, timeStamp); + RAW_METHOD_DUMP(OS, token); + RAW_ID_METHOD_DUMP(OS, typeId, Session, PdbSymbolIdField::Type, ShowIdFields, + RecurseIdFields); + RAW_METHOD_DUMP(OS, uavSlot); + RAW_METHOD_DUMP(OS, undecoratedName); + RAW_ID_METHOD_DUMP(OS, unmodifiedTypeId, Session, + PdbSymbolIdField::UnmodifiedType, ShowIdFields, + RecurseIdFields); + RAW_METHOD_DUMP(OS, upperBoundId); + RAW_METHOD_DUMP(OS, virtualBaseDispIndex); + RAW_METHOD_DUMP(OS, virtualBaseOffset); + RAW_METHOD_DUMP(OS, virtualTableShapeId); + RAW_METHOD_DUMP_AS(OS, dataKind, PDB_DataKind); + RAW_METHOD_DUMP(OS, guid); + RAW_METHOD_DUMP(OS, offset); + RAW_METHOD_DUMP(OS, thisAdjust); + RAW_METHOD_DUMP(OS, virtualBasePointerOffset); + RAW_METHOD_DUMP_AS(OS, locationType, PDB_LocType); + RAW_METHOD_DUMP(OS, machineType); + RAW_METHOD_DUMP(OS, thunkOrdinal); + RAW_METHOD_DUMP(OS, length); + RAW_METHOD_DUMP(OS, liveRangeLength); + RAW_METHOD_DUMP(OS, virtualAddress); + RAW_METHOD_DUMP_AS(OS, udtKind, PDB_UdtType); + RAW_METHOD_DUMP(OS, constructor); + RAW_METHOD_DUMP(OS, customCallingConvention); + RAW_METHOD_DUMP(OS, farReturn); + RAW_METHOD_DUMP(OS, code); + RAW_METHOD_DUMP(OS, compilerGenerated); + RAW_METHOD_DUMP(OS, constType); + RAW_METHOD_DUMP(OS, editAndContinueEnabled); + RAW_METHOD_DUMP(OS, function); + RAW_METHOD_DUMP(OS, stride); + RAW_METHOD_DUMP(OS, noStackOrdering); + RAW_METHOD_DUMP(OS, hasAlloca); + RAW_METHOD_DUMP(OS, hasAssignmentOperator); + RAW_METHOD_DUMP(OS, isCTypes); + RAW_METHOD_DUMP(OS, hasCastOperator); + RAW_METHOD_DUMP(OS, hasDebugInfo); + RAW_METHOD_DUMP(OS, hasEH); + RAW_METHOD_DUMP(OS, hasEHa); + RAW_METHOD_DUMP(OS, hasInlAsm); + RAW_METHOD_DUMP(OS, framePointerPresent); + RAW_METHOD_DUMP(OS, inlSpec); + RAW_METHOD_DUMP(OS, interruptReturn); + RAW_METHOD_DUMP(OS, hasLongJump); + RAW_METHOD_DUMP(OS, hasManagedCode); + RAW_METHOD_DUMP(OS, hasNestedTypes); + RAW_METHOD_DUMP(OS, noInline); + RAW_METHOD_DUMP(OS, noReturn); + RAW_METHOD_DUMP(OS, optimizedCodeDebugInfo); + RAW_METHOD_DUMP(OS, overloadedOperator); + RAW_METHOD_DUMP(OS, hasSEH); + RAW_METHOD_DUMP(OS, hasSecurityChecks); + RAW_METHOD_DUMP(OS, hasSetJump); + RAW_METHOD_DUMP(OS, strictGSCheck); + RAW_METHOD_DUMP(OS, isAcceleratorGroupSharedLocal); + RAW_METHOD_DUMP(OS, isAcceleratorPointerTagLiveRange); + RAW_METHOD_DUMP(OS, isAcceleratorStubFunction); + RAW_METHOD_DUMP(OS, isAggregated); + RAW_METHOD_DUMP(OS, intro); + RAW_METHOD_DUMP(OS, isCVTCIL); + RAW_METHOD_DUMP(OS, isConstructorVirtualBase); + RAW_METHOD_DUMP(OS, isCxxReturnUdt); + RAW_METHOD_DUMP(OS, isDataAligned); + RAW_METHOD_DUMP(OS, isHLSLData); + RAW_METHOD_DUMP(OS, isHotpatchable); + RAW_METHOD_DUMP(OS, indirectVirtualBaseClass); + RAW_METHOD_DUMP(OS, isInterfaceUdt); + RAW_METHOD_DUMP(OS, intrinsic); + RAW_METHOD_DUMP(OS, isLTCG); + RAW_METHOD_DUMP(OS, isLocationControlFlowDependent); + RAW_METHOD_DUMP(OS, isMSILNetmodule); + RAW_METHOD_DUMP(OS, isMatrixRowMajor); + RAW_METHOD_DUMP(OS, managed); + RAW_METHOD_DUMP(OS, msil); + RAW_METHOD_DUMP(OS, isMultipleInheritance); + RAW_METHOD_DUMP(OS, isNaked); + RAW_METHOD_DUMP(OS, nested); + RAW_METHOD_DUMP(OS, isOptimizedAway); + RAW_METHOD_DUMP(OS, packed); + RAW_METHOD_DUMP(OS, isPointerBasedOnSymbolValue); + RAW_METHOD_DUMP(OS, isPointerToDataMember); + RAW_METHOD_DUMP(OS, isPointerToMemberFunction); + RAW_METHOD_DUMP(OS, pure); + RAW_METHOD_DUMP(OS, RValueReference); + RAW_METHOD_DUMP(OS, isRefUdt); + RAW_METHOD_DUMP(OS, reference); + RAW_METHOD_DUMP(OS, restrictedType); + RAW_METHOD_DUMP(OS, isReturnValue); + RAW_METHOD_DUMP(OS, isSafeBuffers); + RAW_METHOD_DUMP(OS, scoped); + RAW_METHOD_DUMP(OS, isSdl); + RAW_METHOD_DUMP(OS, isSingleInheritance); + RAW_METHOD_DUMP(OS, isSplitted); + RAW_METHOD_DUMP(OS, isStatic); + RAW_METHOD_DUMP(OS, isStripped); + RAW_METHOD_DUMP(OS, unalignedType); + RAW_METHOD_DUMP(OS, notReached); + RAW_METHOD_DUMP(OS, isValueUdt); + RAW_METHOD_DUMP(OS, virtual); + RAW_METHOD_DUMP(OS, virtualBaseClass); + RAW_METHOD_DUMP(OS, isVirtualInheritance); + RAW_METHOD_DUMP(OS, volatileType); + RAW_METHOD_DUMP(OS, wasInlined); + RAW_METHOD_DUMP(OS, unused); + RAW_METHOD_DUMP(OS, value); +} + +std::unique_ptr<IPDBEnumSymbols> +DIARawSymbol::findChildren(PDB_SymType Type) const { + enum SymTagEnum EnumVal = static_cast<enum SymTagEnum>(Type); + + CComPtr<IDiaEnumSymbols> DiaEnumerator; + if (S_OK != + Symbol->findChildrenEx(EnumVal, nullptr, nsNone, &DiaEnumerator)) { + if (S_OK != Symbol->findChildren(EnumVal, nullptr, nsNone, &DiaEnumerator)) + return nullptr; + } + + return std::make_unique<DIAEnumSymbols>(Session, DiaEnumerator); +} + +std::unique_ptr<IPDBEnumSymbols> +DIARawSymbol::findChildren(PDB_SymType Type, StringRef Name, + PDB_NameSearchFlags Flags) 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->findChildrenEx(EnumVal, Name16Str, CompareFlags, &DiaEnumerator)) + return nullptr; + + return std::make_unique<DIAEnumSymbols>(Session, DiaEnumerator); +} + +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 std::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 std::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; + 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->findChildrenExByRVA(EnumVal, Name16Str, CompareFlags, RVA, + &DiaEnumerator)) + return nullptr; + + return std::make_unique<DIAEnumSymbols>(Session, DiaEnumerator); +} + +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 std::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)) + return nullptr; + + return std::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 std::make_unique<DIAEnumSymbols>(Session, DiaEnumerator); +} + +std::unique_ptr<IPDBEnumLineNumbers> DIARawSymbol::findInlineeLines() const { + CComPtr<IDiaEnumLineNumbers> DiaEnumerator; + if (S_OK != Symbol->findInlineeLines(&DiaEnumerator)) + return nullptr; + + return std::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 std::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 std::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 std::make_unique<DIAEnumLineNumbers>(DiaEnumerator); +} + +void DIARawSymbol::getDataBytes(llvm::SmallVector<uint8_t, 32> &bytes) const { + bytes.clear(); + + DWORD DataSize = 0; + Symbol->get_dataBytes(0, &DataSize, nullptr); + if (DataSize == 0) + return; + + bytes.resize(DataSize); + Symbol->get_dataBytes(DataSize, &DataSize, bytes.data()); +} + +std::string DIARawSymbol::getUndecoratedNameEx(PDB_UndnameFlags Flags) const { + CComBSTR Result16; + if (S_OK != Symbol->get_undecoratedNameEx((DWORD)Flags, &Result16)) + return std::string(); + + const char *SrcBytes = reinterpret_cast<const char *>(Result16.m_str); + llvm::ArrayRef<char> SrcByteArray(SrcBytes, Result16.ByteLength()); + std::string Result8; + if (!llvm::convertUTF16ToUTF8String(SrcByteArray, Result8)) + return std::string(); + return Result8; +} + +PDB_MemberAccess DIARawSymbol::getAccess() const { + return PrivateGetDIAValue<DWORD, PDB_MemberAccess>(Symbol, + &IDiaSymbol::get_access); +} + +uint32_t DIARawSymbol::getAddressOffset() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_addressOffset); +} + +uint32_t DIARawSymbol::getAddressSection() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_addressSection); +} + +uint32_t DIARawSymbol::getAge() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_age); +} + +SymIndexId DIARawSymbol::getArrayIndexTypeId() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_arrayIndexTypeId); +} + +void DIARawSymbol::getBackEndVersion(VersionInfo &Version) const { + Version.Major = PrivateGetDIAValue(Symbol, &IDiaSymbol::get_backEndMajor); + Version.Minor = PrivateGetDIAValue(Symbol, &IDiaSymbol::get_backEndMinor); + Version.Build = PrivateGetDIAValue(Symbol, &IDiaSymbol::get_backEndBuild); + Version.QFE = PrivateGetDIAValue(Symbol, &IDiaSymbol::get_backEndQFE); +} + +uint32_t DIARawSymbol::getBaseDataOffset() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_baseDataOffset); +} + +uint32_t DIARawSymbol::getBaseDataSlot() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_baseDataSlot); +} + +SymIndexId DIARawSymbol::getBaseSymbolId() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_baseSymbolId); +} + +PDB_BuiltinType DIARawSymbol::getBuiltinType() const { + return PrivateGetDIAValue<DWORD, PDB_BuiltinType>(Symbol, + &IDiaSymbol::get_baseType); +} + +uint32_t DIARawSymbol::getBitPosition() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_bitPosition); +} + +PDB_CallingConv DIARawSymbol::getCallingConvention() const { + return PrivateGetDIAValue<DWORD, PDB_CallingConv>( + Symbol, &IDiaSymbol::get_callingConvention); +} + +SymIndexId DIARawSymbol::getClassParentId() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_classParentId); +} + +std::string DIARawSymbol::getCompilerName() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_compilerName); +} + +uint32_t DIARawSymbol::getCount() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_count); +} + +uint32_t DIARawSymbol::getCountLiveRanges() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_countLiveRanges); +} + +void DIARawSymbol::getFrontEndVersion(VersionInfo &Version) const { + Version.Major = PrivateGetDIAValue(Symbol, &IDiaSymbol::get_frontEndMajor); + Version.Minor = PrivateGetDIAValue(Symbol, &IDiaSymbol::get_frontEndMinor); + Version.Build = PrivateGetDIAValue(Symbol, &IDiaSymbol::get_frontEndBuild); + Version.QFE = PrivateGetDIAValue(Symbol, &IDiaSymbol::get_frontEndQFE); +} + +PDB_Lang DIARawSymbol::getLanguage() const { + return PrivateGetDIAValue<DWORD, PDB_Lang>(Symbol, &IDiaSymbol::get_language); +} + +SymIndexId DIARawSymbol::getLexicalParentId() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_lexicalParentId); +} + +std::string DIARawSymbol::getLibraryName() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_libraryName); +} + +uint32_t DIARawSymbol::getLiveRangeStartAddressOffset() const { + return PrivateGetDIAValue(Symbol, + &IDiaSymbol::get_liveRangeStartAddressOffset); +} + +uint32_t DIARawSymbol::getLiveRangeStartAddressSection() const { + return PrivateGetDIAValue(Symbol, + &IDiaSymbol::get_liveRangeStartAddressSection); +} + +uint32_t DIARawSymbol::getLiveRangeStartRelativeVirtualAddress() const { + return PrivateGetDIAValue( + Symbol, &IDiaSymbol::get_liveRangeStartRelativeVirtualAddress); +} + +codeview::RegisterId DIARawSymbol::getLocalBasePointerRegisterId() const { + return PrivateGetDIAValue<DWORD, codeview::RegisterId>( + Symbol, &IDiaSymbol::get_localBasePointerRegisterId); +} + +SymIndexId DIARawSymbol::getLowerBoundId() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_lowerBoundId); +} + +uint32_t DIARawSymbol::getMemorySpaceKind() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_memorySpaceKind); +} + +std::string DIARawSymbol::getName() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_name); +} + +uint32_t DIARawSymbol::getNumberOfAcceleratorPointerTags() const { + return PrivateGetDIAValue(Symbol, + &IDiaSymbol::get_numberOfAcceleratorPointerTags); +} + +uint32_t DIARawSymbol::getNumberOfColumns() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_numberOfColumns); +} + +uint32_t DIARawSymbol::getNumberOfModifiers() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_numberOfModifiers); +} + +uint32_t DIARawSymbol::getNumberOfRegisterIndices() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_numberOfRegisterIndices); +} + +uint32_t DIARawSymbol::getNumberOfRows() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_numberOfRows); +} + +std::string DIARawSymbol::getObjectFileName() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_objectFileName); +} + +uint32_t DIARawSymbol::getOemId() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_oemId); +} + +SymIndexId DIARawSymbol::getOemSymbolId() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_oemSymbolId); +} + +uint32_t DIARawSymbol::getOffsetInUdt() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_offsetInUdt); +} + +PDB_Cpu DIARawSymbol::getPlatform() const { + return PrivateGetDIAValue<DWORD, PDB_Cpu>(Symbol, &IDiaSymbol::get_platform); +} + +uint32_t DIARawSymbol::getRank() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_rank); +} + +codeview::RegisterId DIARawSymbol::getRegisterId() const { + return PrivateGetDIAValue<DWORD, codeview::RegisterId>( + Symbol, &IDiaSymbol::get_registerId); +} + +uint32_t DIARawSymbol::getRegisterType() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_registerType); +} + +uint32_t DIARawSymbol::getRelativeVirtualAddress() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_relativeVirtualAddress); +} + +uint32_t DIARawSymbol::getSamplerSlot() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_samplerSlot); +} + +uint32_t DIARawSymbol::getSignature() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_signature); +} + +uint32_t DIARawSymbol::getSizeInUdt() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_sizeInUdt); +} + +uint32_t DIARawSymbol::getSlot() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_slot); +} + +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 std::make_unique<DIALineNumber>(LineNumber); +} + +uint32_t DIARawSymbol::getStride() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_stride); +} + +SymIndexId DIARawSymbol::getSubTypeId() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_subTypeId); +} + +std::string DIARawSymbol::getSymbolsFileName() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_symbolsFileName); +} + +SymIndexId DIARawSymbol::getSymIndexId() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_symIndexId); +} + +uint32_t DIARawSymbol::getTargetOffset() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_targetOffset); +} + +uint32_t DIARawSymbol::getTargetRelativeVirtualAddress() const { + return PrivateGetDIAValue(Symbol, + &IDiaSymbol::get_targetRelativeVirtualAddress); +} + +uint64_t DIARawSymbol::getTargetVirtualAddress() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_targetVirtualAddress); +} + +uint32_t DIARawSymbol::getTargetSection() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_targetSection); +} + +uint32_t DIARawSymbol::getTextureSlot() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_textureSlot); +} + +uint32_t DIARawSymbol::getTimeStamp() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_timeStamp); +} + +uint32_t DIARawSymbol::getToken() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_token); +} + +SymIndexId DIARawSymbol::getTypeId() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_typeId); +} + +uint32_t DIARawSymbol::getUavSlot() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_uavSlot); +} + +std::string DIARawSymbol::getUndecoratedName() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_undecoratedName); +} + +SymIndexId DIARawSymbol::getUnmodifiedTypeId() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_unmodifiedTypeId); +} + +SymIndexId DIARawSymbol::getUpperBoundId() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_upperBoundId); +} + +Variant DIARawSymbol::getValue() const { + VARIANT Value; + Value.vt = VT_EMPTY; + if (S_OK != Symbol->get_value(&Value)) + return Variant(); + + return VariantFromVARIANT(Value); +} + +uint32_t DIARawSymbol::getVirtualBaseDispIndex() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_virtualBaseDispIndex); +} + +uint32_t DIARawSymbol::getVirtualBaseOffset() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_virtualBaseOffset); +} + +SymIndexId DIARawSymbol::getVirtualTableShapeId() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_virtualTableShapeId); +} + +std::unique_ptr<PDBSymbolTypeBuiltin> +DIARawSymbol::getVirtualBaseTableType() const { + CComPtr<IDiaSymbol> TableType; + if (FAILED(Symbol->get_virtualBaseTableType(&TableType)) || !TableType) + return nullptr; + + auto RawVT = std::make_unique<DIARawSymbol>(Session, TableType); + auto Pointer = + PDBSymbol::createAs<PDBSymbolTypePointer>(Session, std::move(RawVT)); + return unique_dyn_cast<PDBSymbolTypeBuiltin>(Pointer->getPointeeType()); +} + +PDB_DataKind DIARawSymbol::getDataKind() const { + return PrivateGetDIAValue<DWORD, PDB_DataKind>(Symbol, + &IDiaSymbol::get_dataKind); +} + +PDB_SymType DIARawSymbol::getSymTag() const { + return PrivateGetDIAValue<DWORD, PDB_SymType>(Symbol, + &IDiaSymbol::get_symTag); +} + +codeview::GUID DIARawSymbol::getGuid() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_guid); +} + +int32_t DIARawSymbol::getOffset() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_offset); +} + +int32_t DIARawSymbol::getThisAdjust() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_thisAdjust); +} + +int32_t DIARawSymbol::getVirtualBasePointerOffset() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_virtualBasePointerOffset); +} + +PDB_LocType DIARawSymbol::getLocationType() const { + return PrivateGetDIAValue<DWORD, PDB_LocType>(Symbol, + &IDiaSymbol::get_locationType); +} + +PDB_Machine DIARawSymbol::getMachineType() const { + return PrivateGetDIAValue<DWORD, PDB_Machine>(Symbol, + &IDiaSymbol::get_machineType); +} + +codeview::ThunkOrdinal DIARawSymbol::getThunkOrdinal() const { + return PrivateGetDIAValue<DWORD, codeview::ThunkOrdinal>( + Symbol, &IDiaSymbol::get_thunkOrdinal); +} + +uint64_t DIARawSymbol::getLength() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_length); +} + +uint64_t DIARawSymbol::getLiveRangeLength() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_liveRangeLength); +} + +uint64_t DIARawSymbol::getVirtualAddress() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_virtualAddress); +} + +PDB_UdtType DIARawSymbol::getUdtKind() const { + return PrivateGetDIAValue<DWORD, PDB_UdtType>(Symbol, + &IDiaSymbol::get_udtKind); +} + +bool DIARawSymbol::hasConstructor() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_constructor); +} + +bool DIARawSymbol::hasCustomCallingConvention() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_customCallingConvention); +} + +bool DIARawSymbol::hasFarReturn() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_farReturn); +} + +bool DIARawSymbol::isCode() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_code); +} + +bool DIARawSymbol::isCompilerGenerated() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_compilerGenerated); +} + +bool DIARawSymbol::isConstType() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_constType); +} + +bool DIARawSymbol::isEditAndContinueEnabled() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_editAndContinueEnabled); +} + +bool DIARawSymbol::isFunction() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_function); +} + +bool DIARawSymbol::getAddressTaken() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_addressTaken); +} + +bool DIARawSymbol::getNoStackOrdering() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_noStackOrdering); +} + +bool DIARawSymbol::hasAlloca() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_hasAlloca); +} + +bool DIARawSymbol::hasAssignmentOperator() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_hasAssignmentOperator); +} + +bool DIARawSymbol::hasCTypes() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_isCTypes); +} + +bool DIARawSymbol::hasCastOperator() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_hasCastOperator); +} + +bool DIARawSymbol::hasDebugInfo() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_hasDebugInfo); +} + +bool DIARawSymbol::hasEH() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_hasEH); +} + +bool DIARawSymbol::hasEHa() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_hasEHa); +} + +bool DIARawSymbol::hasInlAsm() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_hasInlAsm); +} + +bool DIARawSymbol::hasInlineAttribute() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_inlSpec); +} + +bool DIARawSymbol::hasInterruptReturn() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_interruptReturn); +} + +bool DIARawSymbol::hasFramePointer() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_framePointerPresent); +} + +bool DIARawSymbol::hasLongJump() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_hasLongJump); +} + +bool DIARawSymbol::hasManagedCode() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_hasManagedCode); +} + +bool DIARawSymbol::hasNestedTypes() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_hasNestedTypes); +} + +bool DIARawSymbol::hasNoInlineAttribute() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_noInline); +} + +bool DIARawSymbol::hasNoReturnAttribute() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_noReturn); +} + +bool DIARawSymbol::hasOptimizedCodeDebugInfo() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_optimizedCodeDebugInfo); +} + +bool DIARawSymbol::hasOverloadedOperator() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_overloadedOperator); +} + +bool DIARawSymbol::hasSEH() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_hasSEH); +} + +bool DIARawSymbol::hasSecurityChecks() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_hasSecurityChecks); +} + +bool DIARawSymbol::hasSetJump() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_hasSetJump); +} + +bool DIARawSymbol::hasStrictGSCheck() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_strictGSCheck); +} + +bool DIARawSymbol::isAcceleratorGroupSharedLocal() const { + return PrivateGetDIAValue(Symbol, + &IDiaSymbol::get_isAcceleratorGroupSharedLocal); +} + +bool DIARawSymbol::isAcceleratorPointerTagLiveRange() const { + return PrivateGetDIAValue(Symbol, + &IDiaSymbol::get_isAcceleratorPointerTagLiveRange); +} + +bool DIARawSymbol::isAcceleratorStubFunction() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_isAcceleratorStubFunction); +} + +bool DIARawSymbol::isAggregated() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_isAggregated); +} + +bool DIARawSymbol::isIntroVirtualFunction() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_intro); +} + +bool DIARawSymbol::isCVTCIL() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_isCVTCIL); +} + +bool DIARawSymbol::isConstructorVirtualBase() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_isConstructorVirtualBase); +} + +bool DIARawSymbol::isCxxReturnUdt() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_isCxxReturnUdt); +} + +bool DIARawSymbol::isDataAligned() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_isDataAligned); +} + +bool DIARawSymbol::isHLSLData() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_isHLSLData); +} + +bool DIARawSymbol::isHotpatchable() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_isHotpatchable); +} + +bool DIARawSymbol::isIndirectVirtualBaseClass() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_indirectVirtualBaseClass); +} + +bool DIARawSymbol::isInterfaceUdt() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_isInterfaceUdt); +} + +bool DIARawSymbol::isIntrinsic() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_intrinsic); +} + +bool DIARawSymbol::isLTCG() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_isLTCG); +} + +bool DIARawSymbol::isLocationControlFlowDependent() const { + return PrivateGetDIAValue(Symbol, + &IDiaSymbol::get_isLocationControlFlowDependent); +} + +bool DIARawSymbol::isMSILNetmodule() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_isMSILNetmodule); +} + +bool DIARawSymbol::isMatrixRowMajor() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_isMatrixRowMajor); +} + +bool DIARawSymbol::isManagedCode() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_managed); +} + +bool DIARawSymbol::isMSILCode() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_msil); +} + +bool DIARawSymbol::isMultipleInheritance() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_isMultipleInheritance); +} + +bool DIARawSymbol::isNaked() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_isNaked); +} + +bool DIARawSymbol::isNested() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_nested); +} + +bool DIARawSymbol::isOptimizedAway() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_isOptimizedAway); +} + +bool DIARawSymbol::isPacked() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_packed); +} + +bool DIARawSymbol::isPointerBasedOnSymbolValue() const { + return PrivateGetDIAValue(Symbol, + &IDiaSymbol::get_isPointerBasedOnSymbolValue); +} + +bool DIARawSymbol::isPointerToDataMember() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_isPointerToDataMember); +} + +bool DIARawSymbol::isPointerToMemberFunction() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_isPointerToMemberFunction); +} + +bool DIARawSymbol::isPureVirtual() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_pure); +} + +bool DIARawSymbol::isRValueReference() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_RValueReference); +} + +bool DIARawSymbol::isRefUdt() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_isRefUdt); +} + +bool DIARawSymbol::isReference() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_reference); +} + +bool DIARawSymbol::isRestrictedType() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_restrictedType); +} + +bool DIARawSymbol::isReturnValue() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_isReturnValue); +} + +bool DIARawSymbol::isSafeBuffers() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_isSafeBuffers); +} + +bool DIARawSymbol::isScoped() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_scoped); +} + +bool DIARawSymbol::isSdl() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_isSdl); +} + +bool DIARawSymbol::isSingleInheritance() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_isSingleInheritance); +} + +bool DIARawSymbol::isSplitted() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_isSplitted); +} + +bool DIARawSymbol::isStatic() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_isStatic); +} + +bool DIARawSymbol::hasPrivateSymbols() const { + // hasPrivateSymbols is the opposite of isStripped, but we expose + // hasPrivateSymbols as a more intuitive interface. + return !PrivateGetDIAValue(Symbol, &IDiaSymbol::get_isStripped); +} + +bool DIARawSymbol::isUnalignedType() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_unalignedType); +} + +bool DIARawSymbol::isUnreached() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_notReached); +} + +bool DIARawSymbol::isValueUdt() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_isValueUdt); +} + +bool DIARawSymbol::isVirtual() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_virtual); +} + +bool DIARawSymbol::isVirtualBaseClass() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_virtualBaseClass); +} + +bool DIARawSymbol::isVirtualInheritance() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_isVirtualInheritance); +} + +bool DIARawSymbol::isVolatileType() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_volatileType); +} + +bool DIARawSymbol::wasInlined() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_wasInlined); +} + +std::string DIARawSymbol::getUnused() const { + return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_unused); +} diff --git a/llvm/lib/DebugInfo/PDB/DIA/DIASectionContrib.cpp b/llvm/lib/DebugInfo/PDB/DIA/DIASectionContrib.cpp new file mode 100644 index 0000000000000..4f0e078e6712c --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/DIA/DIASectionContrib.cpp @@ -0,0 +1,125 @@ +//===- DIASectionContrib.cpp - DIA impl. of IPDBSectionContrib ---- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#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 = std::make_unique<DIARawSymbol>(Session, Symbol); + return PDBSymbol::createAs<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/llvm/lib/DebugInfo/PDB/DIA/DIASession.cpp b/llvm/lib/DebugInfo/PDB/DIA/DIASession.cpp new file mode 100644 index 0000000000000..64ffa776bbd6f --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/DIA/DIASession.cpp @@ -0,0 +1,423 @@ +//===- DIASession.cpp - DIA implementation of IPDBSession -------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +#include "llvm/DebugInfo/PDB/DIA/DIASession.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/DebugInfo/PDB/DIA/DIAEnumDebugStreams.h" +#include "llvm/DebugInfo/PDB/DIA/DIAEnumFrameData.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" +#include "llvm/DebugInfo/PDB/DIA/DIARawSymbol.h" +#include "llvm/DebugInfo/PDB/DIA/DIASourceFile.h" +#include "llvm/DebugInfo/PDB/DIA/DIASupport.h" +#include "llvm/DebugInfo/PDB/GenericError.h" +#include "llvm/DebugInfo/PDB/PDB.h" +#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" +#include "llvm/DebugInfo/PDB/PDBSymbolExe.h" +#include "llvm/Support/ConvertUTF.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; +using namespace llvm::pdb; + +template <typename... Ts> +static Error ErrorFromHResult(HRESULT Result, const char *Str, Ts &&... Args) { + SmallString<64> MessageStorage; + StringRef Context; + if (sizeof...(Args) > 0) { + MessageStorage = formatv(Str, std::forward<Ts>(Args)...).str(); + Context = MessageStorage; + } else + Context = Str; + + switch (Result) { + case E_PDB_NOT_FOUND: + return errorCodeToError(std::error_code(ENOENT, std::generic_category())); + case E_PDB_FORMAT: + return make_error<DIAError>(dia_error_code::invalid_file_format, Context); + case E_INVALIDARG: + return make_error<DIAError>(dia_error_code::invalid_parameter, Context); + case E_UNEXPECTED: + return make_error<DIAError>(dia_error_code::already_loaded, Context); + case E_PDB_INVALID_SIG: + case E_PDB_INVALID_AGE: + return make_error<DIAError>(dia_error_code::debug_info_mismatch, Context); + default: { + std::string S; + raw_string_ostream OS(S); + OS << "HRESULT: " << format_hex(static_cast<DWORD>(Result), 10, true) + << ": " << Context; + return make_error<DIAError>(dia_error_code::unspecified, OS.str()); + } + } +} + +static Error LoadDIA(CComPtr<IDiaDataSource> &DiaDataSource) { + if (SUCCEEDED(CoCreateInstance(CLSID_DiaSource, nullptr, CLSCTX_INPROC_SERVER, + IID_IDiaDataSource, + reinterpret_cast<LPVOID *>(&DiaDataSource)))) + return Error::success(); + +// If the CoCreateInstance call above failed, msdia*.dll is not registered. +// Try loading the DLL corresponding to the #included DIA SDK. +#if !defined(_MSC_VER) + return llvm::make_error<PDBError>(pdb_error_code::dia_failed_loading); +#else + const wchar_t *msdia_dll = L"msdia140.dll"; + HRESULT HR; + if (FAILED(HR = NoRegCoCreate(msdia_dll, CLSID_DiaSource, IID_IDiaDataSource, + reinterpret_cast<LPVOID *>(&DiaDataSource)))) + return ErrorFromHResult(HR, "Calling NoRegCoCreate"); + return Error::success(); +#endif +} + +DIASession::DIASession(CComPtr<IDiaSession> DiaSession) : Session(DiaSession) {} + +Error DIASession::createFromPdb(StringRef Path, + std::unique_ptr<IPDBSession> &Session) { + CComPtr<IDiaDataSource> DiaDataSource; + CComPtr<IDiaSession> DiaSession; + + // We assume that CoInitializeEx has already been called by the executable. + if (auto E = LoadDIA(DiaDataSource)) + return E; + + llvm::SmallVector<UTF16, 128> Path16; + if (!llvm::convertUTF8ToUTF16String(Path, Path16)) + return make_error<PDBError>(pdb_error_code::invalid_utf8_path, Path); + + 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); + } + + if (FAILED(HR = DiaDataSource->openSession(&DiaSession))) + return ErrorFromHResult(HR, "Calling openSession"); + + Session.reset(new DIASession(DiaSession)); + return Error::success(); +} + +Error DIASession::createFromExe(StringRef Path, + std::unique_ptr<IPDBSession> &Session) { + CComPtr<IDiaDataSource> DiaDataSource; + CComPtr<IDiaSession> DiaSession; + + // We assume that CoInitializeEx has already been called by the executable. + if (auto EC = LoadDIA(DiaDataSource)) + return EC; + + llvm::SmallVector<UTF16, 128> Path16; + if (!llvm::convertUTF8ToUTF16String(Path, Path16)) + return make_error<PDBError>(pdb_error_code::invalid_utf8_path, Path); + + const wchar_t *Path16Str = reinterpret_cast<const wchar_t *>(Path16.data()); + HRESULT HR; + if (FAILED(HR = DiaDataSource->loadDataForExe(Path16Str, nullptr, nullptr))) + return ErrorFromHResult(HR, "Calling loadDataForExe"); + + if (FAILED(HR = DiaDataSource->openSession(&DiaSession))) + return ErrorFromHResult(HR, "Calling openSession"); + + Session.reset(new DIASession(DiaSession)); + return Error::success(); +} + +uint64_t DIASession::getLoadAddress() const { + uint64_t LoadAddress; + bool success = (S_OK == Session->get_loadAddress(&LoadAddress)); + return (success) ? LoadAddress : 0; +} + +bool DIASession::setLoadAddress(uint64_t Address) { + return (S_OK == Session->put_loadAddress(Address)); +} + +std::unique_ptr<PDBSymbolExe> DIASession::getGlobalScope() { + CComPtr<IDiaSymbol> GlobalScope; + if (S_OK != Session->get_globalScope(&GlobalScope)) + return nullptr; + + auto RawSymbol = std::make_unique<DIARawSymbol>(*this, GlobalScope); + auto PdbSymbol(PDBSymbol::create(*this, std::move(RawSymbol))); + std::unique_ptr<PDBSymbolExe> ExeSymbol( + static_cast<PDBSymbolExe *>(PdbSymbol.release())); + 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(SymIndexId SymbolId) const { + CComPtr<IDiaSymbol> LocatedSymbol; + if (S_OK != Session->symbolById(SymbolId, &LocatedSymbol)) + return nullptr; + + auto RawSymbol = std::make_unique<DIARawSymbol>(*this, LocatedSymbol); + return PDBSymbol::create(*this, std::move(RawSymbol)); +} + +std::unique_ptr<PDBSymbol> +DIASession::findSymbolByAddress(uint64_t Address, PDB_SymType Type) const { + enum SymTagEnum EnumVal = static_cast<enum SymTagEnum>(Type); + + CComPtr<IDiaSymbol> Symbol; + if (S_OK != Session->findSymbolByVA(Address, EnumVal, &Symbol)) { + ULONGLONG LoadAddr = 0; + if (S_OK != Session->get_loadAddress(&LoadAddr)) + return nullptr; + DWORD RVA = static_cast<DWORD>(Address - LoadAddr); + if (S_OK != Session->findSymbolByRVA(RVA, EnumVal, &Symbol)) + return nullptr; + } + auto RawSymbol = std::make_unique<DIARawSymbol>(*this, Symbol); + 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 = std::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 = std::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 { + const DIARawSymbol &RawCompiland = + static_cast<const DIARawSymbol &>(Compiland.getRawSymbol()); + const DIASourceFile &RawFile = static_cast<const DIASourceFile &>(File); + + CComPtr<IDiaEnumLineNumbers> LineNumbers; + if (S_OK != Session->findLines(RawCompiland.getDiaSymbol(), + RawFile.getDiaFile(), &LineNumbers)) + return nullptr; + + return std::make_unique<DIAEnumLineNumbers>(LineNumbers); +} + +std::unique_ptr<IPDBEnumLineNumbers> +DIASession::findLineNumbersByAddress(uint64_t Address, uint32_t Length) const { + CComPtr<IDiaEnumLineNumbers> 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 std::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 std::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 std::make_unique<DIAEnumLineNumbers>(LineNumbers); +} + +std::unique_ptr<IPDBEnumSourceFiles> +DIASession::findSourceFiles(const PDBSymbolCompiland *Compiland, + llvm::StringRef Pattern, + PDB_NameSearchFlags Flags) const { + IDiaSymbol *DiaCompiland = nullptr; + CComBSTR Utf16Pattern; + if (!Pattern.empty()) + Utf16Pattern = CComBSTR(Pattern.data()); + + if (Compiland) + DiaCompiland = static_cast<const DIARawSymbol &>(Compiland->getRawSymbol()) + .getDiaSymbol(); + + Flags = static_cast<PDB_NameSearchFlags>( + Flags | PDB_NameSearchFlags::NS_FileNameExtMatch); + CComPtr<IDiaEnumSourceFiles> SourceFiles; + if (S_OK != + Session->findFile(DiaCompiland, Utf16Pattern.m_str, Flags, &SourceFiles)) + return nullptr; + return std::make_unique<DIAEnumSourceFiles>(*this, SourceFiles); +} + +std::unique_ptr<IPDBSourceFile> +DIASession::findOneSourceFile(const PDBSymbolCompiland *Compiland, + llvm::StringRef Pattern, + PDB_NameSearchFlags Flags) const { + auto SourceFiles = findSourceFiles(Compiland, Pattern, Flags); + if (!SourceFiles || SourceFiles->getChildCount() == 0) + return nullptr; + return SourceFiles->getNext(); +} + +std::unique_ptr<IPDBEnumChildren<PDBSymbolCompiland>> +DIASession::findCompilandsForSourceFile(llvm::StringRef Pattern, + PDB_NameSearchFlags Flags) const { + auto File = findOneSourceFile(nullptr, Pattern, Flags); + if (!File) + return nullptr; + return File->getCompilands(); +} + +std::unique_ptr<PDBSymbolCompiland> +DIASession::findOneCompilandForSourceFile(llvm::StringRef Pattern, + PDB_NameSearchFlags Flags) const { + auto Compilands = findCompilandsForSourceFile(Pattern, Flags); + if (!Compilands || Compilands->getChildCount() == 0) + return nullptr; + return Compilands->getNext(); +} + +std::unique_ptr<IPDBEnumSourceFiles> DIASession::getAllSourceFiles() const { + CComPtr<IDiaEnumSourceFiles> Files; + if (S_OK != Session->findFile(nullptr, nullptr, nsNone, &Files)) + return nullptr; + + return std::make_unique<DIAEnumSourceFiles>(*this, Files); +} + +std::unique_ptr<IPDBEnumSourceFiles> DIASession::getSourceFilesForCompiland( + const PDBSymbolCompiland &Compiland) const { + CComPtr<IDiaEnumSourceFiles> Files; + + const DIARawSymbol &RawSymbol = + static_cast<const DIARawSymbol &>(Compiland.getRawSymbol()); + if (S_OK != + Session->findFile(RawSymbol.getDiaSymbol(), nullptr, nsNone, &Files)) + return nullptr; + + return std::make_unique<DIAEnumSourceFiles>(*this, Files); +} + +std::unique_ptr<IPDBSourceFile> +DIASession::getSourceFileById(uint32_t FileId) const { + CComPtr<IDiaSourceFile> LocatedFile; + if (S_OK != Session->findFileById(FileId, &LocatedFile)) + return nullptr; + + return std::make_unique<DIASourceFile>(*this, LocatedFile); +} + +std::unique_ptr<IPDBEnumDataStreams> DIASession::getDebugStreams() const { + CComPtr<IDiaEnumDebugStreams> DiaEnumerator; + if (S_OK != Session->getEnumDebugStreams(&DiaEnumerator)) + return nullptr; + + return std::make_unique<DIAEnumDebugStreams>(DiaEnumerator); +} + +std::unique_ptr<IPDBEnumTables> DIASession::getEnumTables() const { + CComPtr<IDiaEnumTables> DiaEnumerator; + if (S_OK != Session->getEnumTables(&DiaEnumerator)) + return nullptr; + + return std::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 std::make_unique<DIAEnumInjectedSources>(Files); +} + +std::unique_ptr<IPDBEnumSectionContribs> +DIASession::getSectionContribs() const { + CComPtr<IDiaEnumSectionContribs> Sections = + getTableEnumerator<IDiaEnumSectionContribs>(*Session); + if (!Sections) + return nullptr; + + return std::make_unique<DIAEnumSectionContribs>(*this, Sections); +} + +std::unique_ptr<IPDBEnumFrameData> +DIASession::getFrameData() const { + CComPtr<IDiaEnumFrameData> FD = + getTableEnumerator<IDiaEnumFrameData>(*Session); + if (!FD) + return nullptr; + + return std::make_unique<DIAEnumFrameData>(FD); +} diff --git a/llvm/lib/DebugInfo/PDB/DIA/DIASourceFile.cpp b/llvm/lib/DebugInfo/PDB/DIA/DIASourceFile.cpp new file mode 100644 index 0000000000000..21e757c3a0604 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/DIA/DIASourceFile.cpp @@ -0,0 +1,63 @@ +//===- DIASourceFile.cpp - DIA implementation of IPDBSourceFile -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/DIA/DIASourceFile.h" +#include "llvm/DebugInfo/PDB/ConcreteSymbolEnumerator.h" +#include "llvm/DebugInfo/PDB/DIA/DIAEnumSymbols.h" +#include "llvm/DebugInfo/PDB/DIA/DIASession.h" +#include "llvm/DebugInfo/PDB/DIA/DIAUtils.h" +#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" + +using namespace llvm; +using namespace llvm::pdb; + +DIASourceFile::DIASourceFile(const DIASession &PDBSession, + CComPtr<IDiaSourceFile> DiaSourceFile) + : Session(PDBSession), SourceFile(DiaSourceFile) {} + +std::string DIASourceFile::getFileName() const { + return invokeBstrMethod(*SourceFile, &IDiaSourceFile::get_fileName); +} + +uint32_t DIASourceFile::getUniqueId() const { + DWORD Id; + return (S_OK == SourceFile->get_uniqueId(&Id)) ? Id : 0; +} + +std::string DIASourceFile::getChecksum() const { + DWORD ByteSize = 0; + HRESULT Result = SourceFile->get_checksum(0, &ByteSize, nullptr); + if (ByteSize == 0) + return std::string(); + std::vector<BYTE> ChecksumBytes(ByteSize); + Result = SourceFile->get_checksum(ByteSize, &ByteSize, &ChecksumBytes[0]); + if (S_OK != Result) + return std::string(); + return std::string(ChecksumBytes.begin(), ChecksumBytes.end()); +} + +PDB_Checksum DIASourceFile::getChecksumType() const { + DWORD Type; + HRESULT Result = SourceFile->get_checksumType(&Type); + if (S_OK != Result) + return PDB_Checksum::None; + return static_cast<PDB_Checksum>(Type); +} + +std::unique_ptr<IPDBEnumChildren<PDBSymbolCompiland>> +DIASourceFile::getCompilands() const { + CComPtr<IDiaEnumSymbols> DiaEnumerator; + HRESULT Result = SourceFile->get_compilands(&DiaEnumerator); + if (S_OK != Result) + return nullptr; + + auto Enumerator = std::unique_ptr<IPDBEnumSymbols>( + new DIAEnumSymbols(Session, DiaEnumerator)); + return std::unique_ptr<IPDBEnumChildren<PDBSymbolCompiland>>( + new ConcreteSymbolEnumerator<PDBSymbolCompiland>(std::move(Enumerator))); +} diff --git a/llvm/lib/DebugInfo/PDB/DIA/DIATable.cpp b/llvm/lib/DebugInfo/PDB/DIA/DIATable.cpp new file mode 100644 index 0000000000000..33d74abd740e0 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/DIA/DIATable.cpp @@ -0,0 +1,50 @@ +//===- DIATable.cpp - DIA implementation of IPDBTable -----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/DIA/DIATable.h" +#include "llvm/DebugInfo/PDB/DIA/DIAUtils.h" + +using namespace llvm; +using namespace llvm::pdb; + +DIATable::DIATable(CComPtr<IDiaTable> DiaTable) : Table(DiaTable) {} + +uint32_t DIATable::getItemCount() const { + LONG Count = 0; + return (S_OK == Table->get_Count(&Count)) ? Count : 0; +} + +std::string DIATable::getName() const { + return invokeBstrMethod(*Table, &IDiaTable::get_name); +} + +PDB_TableType DIATable::getTableType() const { + CComBSTR Name16; + if (S_OK != Table->get_name(&Name16)) + return PDB_TableType::TableInvalid; + + if (Name16 == DiaTable_Symbols) + return PDB_TableType::Symbols; + if (Name16 == DiaTable_SrcFiles) + return PDB_TableType::SourceFiles; + if (Name16 == DiaTable_Sections) + return PDB_TableType::SectionContribs; + if (Name16 == DiaTable_LineNums) + return PDB_TableType::LineNumbers; + if (Name16 == DiaTable_SegMap) + return PDB_TableType::Segments; + if (Name16 == DiaTable_InjSrc) + return PDB_TableType::InjectedSources; + if (Name16 == DiaTable_FrameData) + return PDB_TableType::FrameData; + if (Name16 == DiaTable_InputAssemblyFiles) + return PDB_TableType::InputAssemblyFiles; + if (Name16 == DiaTable_Dbg) + return PDB_TableType::Dbg; + return PDB_TableType::TableInvalid; +} diff --git a/llvm/lib/DebugInfo/PDB/GenericError.cpp b/llvm/lib/DebugInfo/PDB/GenericError.cpp new file mode 100644 index 0000000000000..0e4cba3174b26 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/GenericError.cpp @@ -0,0 +1,48 @@ +//===- Error.cpp - system_error extensions for PDB --------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/GenericError.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/ManagedStatic.h" + +using namespace llvm; +using namespace llvm::pdb; + +namespace { +// FIXME: This class is only here to support the transition to llvm::Error. It +// will be removed once this transition is complete. Clients should prefer to +// deal with the Error value directly, rather than converting to error_code. +class PDBErrorCategory : public std::error_category { +public: + const char *name() const noexcept override { return "llvm.pdb"; } + std::string message(int Condition) const override { + switch (static_cast<pdb_error_code>(Condition)) { + case pdb_error_code::unspecified: + return "An unknown error has occurred."; + case pdb_error_code::dia_sdk_not_present: + return "LLVM was not compiled with support for DIA. This usually means " + "that you are not using MSVC, or your Visual Studio " + "installation is corrupt."; + case pdb_error_code::dia_failed_loading: + return "DIA is only supported when using MSVC."; + case pdb_error_code::invalid_utf8_path: + return "The PDB file path is an invalid UTF8 sequence."; + case pdb_error_code::signature_out_of_date: + return "The signature does not match; the file(s) might be out of date."; + case pdb_error_code::no_matching_pch: + return "No matching precompiled header could be located."; + } + llvm_unreachable("Unrecognized generic_error_code"); + } +}; +} // namespace + +static llvm::ManagedStatic<PDBErrorCategory> PDBCategory; +const std::error_category &llvm::pdb::PDBErrCategory() { return *PDBCategory; } + +char PDBError::ID; diff --git a/llvm/lib/DebugInfo/PDB/IPDBSourceFile.cpp b/llvm/lib/DebugInfo/PDB/IPDBSourceFile.cpp new file mode 100644 index 0000000000000..113ee04bab952 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/IPDBSourceFile.cpp @@ -0,0 +1,34 @@ +//===- IPDBSourceFile.cpp - base interface for a PDB source file ----------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/IPDBSourceFile.h" +#include "llvm/DebugInfo/PDB/PDBExtras.h" +#include "llvm/DebugInfo/PDB/PDBTypes.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" +#include <cstdint> +#include <string> + +using namespace llvm; +using namespace llvm::pdb; + +IPDBSourceFile::~IPDBSourceFile() = default; + +void IPDBSourceFile::dump(raw_ostream &OS, int Indent) const { + OS.indent(Indent); + PDB_Checksum ChecksumType = getChecksumType(); + OS << "["; + if (ChecksumType != PDB_Checksum::None) { + OS << ChecksumType << ": "; + std::string Checksum = getChecksum(); + for (uint8_t c : Checksum) + OS << format_hex_no_prefix(c, 2, true); + } else + OS << "No checksum"; + OS << "] " << getFileName() << "\n"; +} diff --git a/llvm/lib/DebugInfo/PDB/Native/DbiModuleDescriptor.cpp b/llvm/lib/DebugInfo/PDB/Native/DbiModuleDescriptor.cpp new file mode 100644 index 0000000000000..5095efcdee3cf --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/Native/DbiModuleDescriptor.cpp @@ -0,0 +1,93 @@ +//===- DbiModuleDescriptor.cpp - PDB module information -------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#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; +} + +const SectionContrib &DbiModuleDescriptor::getSectionContrib() const { + return Layout->SC; +} + +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; +} diff --git a/llvm/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp b/llvm/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp new file mode 100644 index 0000000000000..419734771ccd5 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp @@ -0,0 +1,191 @@ +//===- DbiModuleDescriptorBuilder.cpp - PDB Mod Info Creation ---*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#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/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::setFirstSectionContrib( + const SectionContrib &SC) { + Layout.SC = SC; +} + +void DbiModuleDescriptorBuilder::addSymbol(CVSymbol Symbol) { + // Defer to the bulk API. It does the same thing. + addSymbolsInBulk(Symbol.data()); +} + +void DbiModuleDescriptorBuilder::addSymbolsInBulk( + ArrayRef<uint8_t> BulkSymbols) { + // Do nothing for empty runs of symbols. + if (BulkSymbols.empty()) + return; + + Symbols.push_back(BulkSymbols); + // Symbols written to a PDB file are required to be 4 byte aligned. The same + // is not true of object files. + assert(BulkSymbols.size() % alignOf(CodeViewContainer::Pdb) == 0 && + "Invalid Symbol alignment!"); + SymbolByteSize += BulkSymbols.size(); +} + +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.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 = + Layout.ModDiStream == kInvalidStreamIndex ? 0 : getNextSymbolOffset(); +} + +Error DbiModuleDescriptorBuilder::finalizeMsfLayout() { + this->Layout.ModDiStream = kInvalidStreamIndex; + uint32_t C13Size = calculateC13DebugInfoSize(); + if (!C13Size && !SymbolByteSize) + return Error::success(); + 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; + for (ArrayRef<uint8_t> Syms : Symbols) { + if (auto EC = SymbolWriter.writeBytes(Syms)) + return EC; + } + assert(SymbolWriter.getOffset() % alignOf(CodeViewContainer::Pdb) == 0 && + "Invalid debug section alignment!"); + // TODO: Write C11 Line data + 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(std::make_unique<DebugSubsectionRecordBuilder>( + std::move(Subsection), CodeViewContainer::Pdb)); +} + +void DbiModuleDescriptorBuilder::addDebugSubsection( + const DebugSubsectionRecord &SubsectionContents) { + C13Builders.push_back(std::make_unique<DebugSubsectionRecordBuilder>( + SubsectionContents, CodeViewContainer::Pdb)); +} diff --git a/llvm/lib/DebugInfo/PDB/Native/DbiModuleList.cpp b/llvm/lib/DebugInfo/PDB/Native/DbiModuleList.cpp new file mode 100644 index 0000000000000..5cf014e881cde --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/Native/DbiModuleList.cpp @@ -0,0 +1,279 @@ +//===- DbiModuleList.cpp - PDB module information list --------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#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; +} diff --git a/llvm/lib/DebugInfo/PDB/Native/DbiStream.cpp b/llvm/lib/DebugInfo/PDB/Native/DbiStream.cpp new file mode 100644 index 0000000000000..4eb16804171df --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/Native/DbiStream.cpp @@ -0,0 +1,383 @@ +//===- DbiStream.cpp - PDB Dbi Stream (Stream 3) Access -------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#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(std::unique_ptr<BinaryStream> Stream) + : Stream(std::move(Stream)), Header(nullptr) {} + +DbiStream::~DbiStream() = default; + +Error DbiStream::reload(PDBFile *Pdb) { + 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(Pdb)) + return EC; + if (auto EC = initializeSectionMapData()) + return EC; + if (auto EC = initializeOldFpoRecords(Pdb)) + return EC; + if (auto EC = initializeNewFpoRecords(Pdb)) + 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() const { + return SectionHeaders; +} + +bool DbiStream::hasOldFpoRecords() const { return OldFpoStream != nullptr; } + +FixedStreamArray<object::FpoData> DbiStream::getOldFpoRecords() const { + return OldFpoRecords; +} + +bool DbiStream::hasNewFpoRecords() const { return NewFpoStream != nullptr; } + +const DebugFrameDataSubsectionRef &DbiStream::getNewFpoRecords() const { + return NewFpoRecords; +} + +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(PDBFile *Pdb) { + Expected<std::unique_ptr<msf::MappedBlockStream>> ExpectedStream = + createIndexedStreamForHeaderType(Pdb, DbgHeaderType::SectionHdr); + if (auto EC = ExpectedStream.takeError()) + return EC; + + auto &SHS = *ExpectedStream; + if (!SHS) + return Error::success(); + + 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::initializeOldFpoRecords(PDBFile *Pdb) { + Expected<std::unique_ptr<msf::MappedBlockStream>> ExpectedStream = + createIndexedStreamForHeaderType(Pdb, DbgHeaderType::FPO); + if (auto EC = ExpectedStream.takeError()) + return EC; + + auto &FS = *ExpectedStream; + if (!FS) + return Error::success(); + + size_t StreamLen = FS->getLength(); + if (StreamLen % sizeof(object::FpoData)) + return make_error<RawError>(raw_error_code::corrupt_file, + "Corrupted Old FPO stream."); + + size_t NumRecords = StreamLen / sizeof(object::FpoData); + BinaryStreamReader Reader(*FS); + if (auto EC = Reader.readArray(OldFpoRecords, NumRecords)) + return make_error<RawError>(raw_error_code::corrupt_file, + "Corrupted Old FPO stream."); + OldFpoStream = std::move(FS); + return Error::success(); +} + +Error DbiStream::initializeNewFpoRecords(PDBFile *Pdb) { + Expected<std::unique_ptr<msf::MappedBlockStream>> ExpectedStream = + createIndexedStreamForHeaderType(Pdb, DbgHeaderType::NewFPO); + if (auto EC = ExpectedStream.takeError()) + return EC; + + auto &FS = *ExpectedStream; + if (!FS) + return Error::success(); + + if (auto EC = NewFpoRecords.initialize(*FS)) + return EC; + + NewFpoStream = std::move(FS); + return Error::success(); +} + +Expected<std::unique_ptr<msf::MappedBlockStream>> +DbiStream::createIndexedStreamForHeaderType(PDBFile *Pdb, + DbgHeaderType Type) const { + if (!Pdb) + return nullptr; + + if (DbgStreams.empty()) + return nullptr; + + uint32_t StreamNum = getDebugStreamIndex(Type); + + // This means there is no such stream. + if (StreamNum == kInvalidStreamIndex) + return nullptr; + + return Pdb->safelyCreateIndexedStream(StreamNum); +} + +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]; +} diff --git a/llvm/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp b/llvm/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp new file mode 100644 index 0000000000000..0e00c2f7ff98c --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp @@ -0,0 +1,455 @@ +//===- DbiStreamBuilder.cpp - PDB Dbi Stream Creation -----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h" + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/BinaryFormat/COFF.h" +#include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.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) {} + +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::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; } + +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; +} + +void DbiStreamBuilder::setGlobalsStreamIndex(uint32_t Index) { + GlobalsStreamIndex = Index; +} + +void DbiStreamBuilder::setSymbolRecordStreamIndex(uint32_t Index) { + SymRecordStreamIndex = Index; +} + +void DbiStreamBuilder::setPublicsStreamIndex(uint32_t Index) { + PublicsStreamIndex = Index; +} + +void DbiStreamBuilder::addNewFpoData(const codeview::FrameData &FD) { + if (!NewFpoData.hasValue()) + NewFpoData.emplace(false); + + NewFpoData->addFrameData(FD); +} + +void DbiStreamBuilder::addOldFpoData(const object::FpoData &FD) { + OldFpoData.push_back(FD); +} + +Error DbiStreamBuilder::addDbgStream(pdb::DbgHeaderType Type, + ArrayRef<uint8_t> Data) { + assert(Type != DbgHeaderType::NewFPO && + "NewFPO data should be written via addFrameData()!"); + + DbgStreams[(int)Type].emplace(); + DbgStreams[(int)Type]->Size = Data.size(); + DbgStreams[(int)Type]->WriteFn = [Data](BinaryStreamWriter &Writer) { + return Writer.writeArray(Data); + }; + 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( + std::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 = 0; // Not sure what this is, but link.exe writes 0. + H->GlobalSymbolStreamIndex = GlobalsStreamIndex; + + Header = H; + return Error::success(); +} + +Error DbiStreamBuilder::finalizeMsfLayout() { + if (NewFpoData.hasValue()) { + DbgStreams[(int)DbgHeaderType::NewFPO].emplace(); + DbgStreams[(int)DbgHeaderType::NewFPO]->Size = + NewFpoData->calculateSerializedSize(); + DbgStreams[(int)DbgHeaderType::NewFPO]->WriteFn = + [this](BinaryStreamWriter &Writer) { + return NewFpoData->commit(Writer); + }; + } + + if (!OldFpoData.empty()) { + DbgStreams[(int)DbgHeaderType::FPO].emplace(); + DbgStreams[(int)DbgHeaderType::FPO]->Size = + sizeof(object::FpoData) * OldFpoData.size(); + DbgStreams[(int)DbgHeaderType::FPO]->WriteFn = + [this](BinaryStreamWriter &Writer) { + return Writer.writeArray(makeArrayRef(OldFpoData)); + }; + } + + for (auto &S : DbgStreams) { + if (!S.hasValue()) + continue; + auto ExpectedIndex = Msf.addStream(S->Size); + if (!ExpectedIndex) + return ExpectedIndex.takeError(); + S->StreamNumber = *ExpectedIndex; + } + + 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) { + uint16_t StreamNumber = kInvalidStreamIndex; + if (Stream.hasValue()) + StreamNumber = Stream->StreamNumber; + if (auto EC = Writer.writeInteger(StreamNumber)) + return EC; + } + + for (auto &Stream : DbgStreams) { + if (!Stream.hasValue()) + continue; + assert(Stream->StreamNumber != kInvalidStreamIndex); + + auto WritableStream = WritableMappedBlockStream::createIndexedStream( + Layout, MsfBuffer, Stream->StreamNumber, Allocator); + BinaryStreamWriter DbgStreamWriter(*WritableStream); + + if (auto EC = Stream->WriteFn(DbgStreamWriter)) + return EC; + } + + if (Writer.bytesRemaining() > 0) + return make_error<RawError>(raw_error_code::invalid_format, + "Unexpected bytes found in DBI Stream"); + return Error::success(); +} diff --git a/llvm/lib/DebugInfo/PDB/Native/EnumTables.cpp b/llvm/lib/DebugInfo/PDB/Native/EnumTables.cpp new file mode 100644 index 0000000000000..f5125393695bc --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/Native/EnumTables.cpp @@ -0,0 +1,37 @@ +//===- EnumTables.cpp - Enum to string conversion tables --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#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); +} +} +}
\ No newline at end of file diff --git a/llvm/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp b/llvm/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp new file mode 100644 index 0000000000000..432f1e9b24d3a --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp @@ -0,0 +1,378 @@ +//===- DbiStreamBuilder.cpp - PDB Dbi Stream Creation -----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/GSIStreamBuilder.h" + +#include "llvm/ADT/DenseSet.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 "llvm/Support/xxhash.h" +#include <algorithm> +#include <vector> + +using namespace llvm; +using namespace llvm::msf; +using namespace llvm::pdb; +using namespace llvm::codeview; + +struct llvm::pdb::GSIHashStreamBuilder { + struct SymbolDenseMapInfo { + static inline CVSymbol getEmptyKey() { + static CVSymbol Empty; + return Empty; + } + static inline CVSymbol getTombstoneKey() { + static CVSymbol Tombstone( + DenseMapInfo<ArrayRef<uint8_t>>::getTombstoneKey()); + return Tombstone; + } + static unsigned getHashValue(const CVSymbol &Val) { + return xxHash64(Val.RecordData); + } + static bool isEqual(const CVSymbol &LHS, const CVSymbol &RHS) { + return LHS.RecordData == RHS.RecordData; + } + }; + + std::vector<CVSymbol> Records; + uint32_t StreamIndex; + llvm::DenseSet<CVSymbol, SymbolDenseMapInfo> SymbolHashes; + 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); + addSymbol(SymbolSerializer::writeOneSymbol(Copy, Msf.getAllocator(), + CodeViewContainer::Pdb)); + } + void addSymbol(const CVSymbol &Symbol) { + if (Symbol.kind() == S_UDT || Symbol.kind() == S_CONSTANT) { + auto Iter = SymbolHashes.insert(Symbol); + if (!Iter.second) + return; + } + + 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(); +} + +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<std::pair<StringRef, 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(std::make_pair(Name, HR)); + 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); + + // 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, [](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); + } +} + +GSIStreamBuilder::GSIStreamBuilder(msf::MSFBuilder &Msf) + : Msf(Msf), PSH(std::make_unique<GSIHashStreamBuilder>()), + GSH(std::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(calculateGlobalsHashStreamSize()); + if (!Idx) + return Idx.takeError(); + GSH->StreamIndex = *Idx; + Idx = Msf.addStream(calculatePublicsHashStreamSize()); + if (!Idx) + return Idx.takeError(); + PSH->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(); + } + llvm::stable_sort(PublicsByAddr, 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 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.SymHash = PSH->calculateSerializedLength(); + Header.AddrMap = PSH->Records.size() * 4; + Header.NumThunks = 0; + Header.SizeOfThunk = 0; + Header.ISectThunkTable = 0; + memset(Header.Padding, 0, sizeof(Header.Padding)); + Header.OffThunkTable = 0; + Header.NumSections = 0; + 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(); +} diff --git a/llvm/lib/DebugInfo/PDB/Native/GlobalsStream.cpp b/llvm/lib/DebugInfo/PDB/Native/GlobalsStream.cpp new file mode 100644 index 0000000000000..f27d60f468156 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/Native/GlobalsStream.cpp @@ -0,0 +1,181 @@ +//===- GlobalsStream.cpp - PDB Index of Symbols by Name ---------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// 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/CodeView/RecordName.h" +#include "llvm/DebugInfo/PDB/Native/Hash.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/DebugInfo/PDB/Native/SymbolStream.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(); +} + +std::vector<std::pair<uint32_t, codeview::CVSymbol>> +GlobalsStream::findRecordsByName(StringRef Name, + const SymbolStream &Symbols) const { + std::vector<std::pair<uint32_t, codeview::CVSymbol>> Result; + + // Hash the name to figure out which bucket this goes into. + size_t ExpandedBucketIndex = hashStringV1(Name) % IPHR_HASH; + int32_t CompressedBucketIndex = GlobalsTable.BucketMap[ExpandedBucketIndex]; + if (CompressedBucketIndex == -1) + return Result; + + uint32_t LastBucketIndex = GlobalsTable.HashBuckets.size() - 1; + uint32_t StartRecordIndex = + GlobalsTable.HashBuckets[CompressedBucketIndex] / 12; + uint32_t EndRecordIndex = 0; + if (LLVM_LIKELY(uint32_t(CompressedBucketIndex) < LastBucketIndex)) { + EndRecordIndex = GlobalsTable.HashBuckets[CompressedBucketIndex + 1]; + } else { + // If this is the last bucket, it consists of all hash records until the end + // of the HashRecords array. + EndRecordIndex = GlobalsTable.HashRecords.size() * 12; + } + + EndRecordIndex /= 12; + + assert(EndRecordIndex <= GlobalsTable.HashRecords.size()); + while (StartRecordIndex < EndRecordIndex) { + PSHashRecord PSH = GlobalsTable.HashRecords[StartRecordIndex]; + uint32_t Off = PSH.Off - 1; + codeview::CVSymbol Record = Symbols.readRecord(Off); + if (codeview::getSymbolName(Record) == Name) + Result.push_back(std::make_pair(Off, std::move(Record))); + ++StartRecordIndex; + } + return Result; +} + +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, + FixedStreamArray<support::ulittle32_t> &HashBitmap, + const GSIHashHeader *HashHdr, + MutableArrayRef<int32_t> BucketMap, + 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 / 32; + if (auto EC = Reader.readArray(HashBitmap, NumBitmapEntries)) + return joinErrors(std::move(EC), + make_error<RawError>(raw_error_code::corrupt_file, + "Could not read a bitmap.")); + uint32_t NumBuckets1 = 0; + uint32_t CompressedBucketIdx = 0; + for (uint32_t I = 0; I <= IPHR_HASH; ++I) { + uint8_t WordIdx = I / 32; + uint8_t BitIdx = I % 32; + bool IsSet = HashBitmap[WordIdx] & (1U << BitIdx); + if (IsSet) { + ++NumBuckets1; + BucketMap[I] = CompressedBucketIdx++; + } else { + BucketMap[I] = -1; + } + } + + uint32_t NumBuckets = 0; + for (uint32_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, + BucketMap, Reader)) + return EC; + return Error::success(); +} diff --git a/llvm/lib/DebugInfo/PDB/Native/Hash.cpp b/llvm/lib/DebugInfo/PDB/Native/Hash.cpp new file mode 100644 index 0000000000000..7fb6b4bd5d31e --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/Native/Hash.cpp @@ -0,0 +1,84 @@ +//===- Hash.cpp - PDB Hash Functions --------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/Hash.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/CRC.h" +#include "llvm/Support/Endian.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(Buf); + return JC.getCRC(); +} diff --git a/llvm/lib/DebugInfo/PDB/Native/HashTable.cpp b/llvm/lib/DebugInfo/PDB/Native/HashTable.cpp new file mode 100644 index 0000000000000..dfdcdf1f4eafe --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/Native/HashTable.cpp @@ -0,0 +1,71 @@ +//===- HashTable.cpp - PDB Hash Table -------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#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; + +Error llvm::pdb::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 llvm::pdb::writeSparseBitVector(BinaryStreamWriter &Writer, + SparseBitVector<> &Vec) { + constexpr int BitsPerWord = 8 * sizeof(uint32_t); + + int ReqBits = Vec.find_last() + 1; + 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 != ReqWords; ++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(); +} diff --git a/llvm/lib/DebugInfo/PDB/Native/InfoStream.cpp b/llvm/lib/DebugInfo/PDB/Native/InfoStream.cpp new file mode 100644 index 0000000000000..f41bb32d69af8 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/Native/InfoStream.cpp @@ -0,0 +1,131 @@ +//===- InfoStream.cpp - PDB Info Stream (Stream 1) Access -------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#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<BinaryStream> Stream) + : Stream(std::move(Stream)), Header(nullptr) {} + +Error InfoStream::reload() { + BinaryStreamReader Reader(*Stream); + + 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 (Header->Version) { + case PdbImplVC70: + case PdbImplVC80: + case PdbImplVC110: + case PdbImplVC140: + break; + default: + return make_error<RawError>(raw_error_code::corrupt_file, + "Unsupported PDB stream version."); + } + + 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(); } + +Expected<uint32_t> InfoStream::getNamedStreamIndex(llvm::StringRef Name) const { + uint32_t Result; + if (!NamedStreams.get(Name, Result)) + return make_error<RawError>(raw_error_code::no_stream); + return Result; +} + +StringMap<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>(uint32_t(Header->Version)); +} + +uint32_t InfoStream::getSignature() const { + return uint32_t(Header->Signature); +} + +uint32_t InfoStream::getAge() const { return uint32_t(Header->Age); } + +GUID InfoStream::getGuid() const { return Header->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; +} diff --git a/llvm/lib/DebugInfo/PDB/Native/InfoStreamBuilder.cpp b/llvm/lib/DebugInfo/PDB/Native/InfoStreamBuilder.cpp new file mode 100644 index 0000000000000..42daa7cae7997 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/Native/InfoStreamBuilder.cpp @@ -0,0 +1,82 @@ +//===- InfoStreamBuilder.cpp - PDB Info Stream Creation ---------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#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), Age(0), + NamedStreams(NamedStreams) { + ::memset(&Guid, 0, sizeof(Guid)); +} + +void InfoStreamBuilder::setVersion(PdbRaw_ImplVer V) { Ver = V; } + +void InfoStreamBuilder::addFeature(PdbRaw_FeatureSig Sig) { + Features.push_back(Sig); +} + +void InfoStreamBuilder::setHashPDBContentsToGUID(bool B) { + HashPDBContentsToGUID = B; +} + +void InfoStreamBuilder::setAge(uint32_t A) { Age = A; } + +void InfoStreamBuilder::setSignature(uint32_t S) { Signature = S; } + +void InfoStreamBuilder::setGuid(GUID G) { Guid = G; } + + +Error InfoStreamBuilder::finalizeMsfLayout() { + uint32_t Length = sizeof(InfoStreamHeader) + + NamedStreams.calculateSerializedLength() + + (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; + // 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; + 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; + } + assert(Writer.bytesRemaining() == 0); + return Error::success(); +} diff --git a/llvm/lib/DebugInfo/PDB/Native/InjectedSourceStream.cpp b/llvm/lib/DebugInfo/PDB/Native/InjectedSourceStream.cpp new file mode 100644 index 0000000000000..3f4101db7b93e --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/Native/InjectedSourceStream.cpp @@ -0,0 +1,65 @@ +//===- InjectedSourceStream.cpp - PDB Headerblock Stream Access -----------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/InjectedSourceStream.h" + +#include "llvm/DebugInfo/MSF/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Native/Hash.h" +#include "llvm/DebugInfo/PDB/Native/PDBStringTable.h" +#include "llvm/DebugInfo/PDB/Native/RawConstants.h" +#include "llvm/DebugInfo/PDB/Native/RawTypes.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/Endian.h" + +using namespace llvm; +using namespace llvm::msf; +using namespace llvm::support; +using namespace llvm::pdb; + +InjectedSourceStream::InjectedSourceStream( + std::unique_ptr<MappedBlockStream> Stream) + : Stream(std::move(Stream)) {} + +Error InjectedSourceStream::reload(const PDBStringTable &Strings) { + BinaryStreamReader Reader(*Stream); + + if (auto EC = Reader.readObject(Header)) + return EC; + + if (Header->Version != + static_cast<uint32_t>(PdbRaw_SrcHeaderBlockVer::SrcVerOne)) + return make_error<RawError>(raw_error_code::corrupt_file, + "Invalid headerblock header version"); + + if (auto EC = InjectedSourceTable.load(Reader)) + return EC; + + for (const auto& Entry : *this) { + if (Entry.second.Size != sizeof(SrcHeaderBlockEntry)) + return make_error<RawError>(raw_error_code::corrupt_file, + "Invalid headerbock entry size"); + if (Entry.second.Version != + static_cast<uint32_t>(PdbRaw_SrcHeaderBlockVer::SrcVerOne)) + return make_error<RawError>(raw_error_code::corrupt_file, + "Invalid headerbock entry version"); + + // Check that all name references are valid. + auto Name = Strings.getStringForID(Entry.second.FileNI); + if (!Name) + return Name.takeError(); + auto ObjName = Strings.getStringForID(Entry.second.ObjNI); + if (!ObjName) + return ObjName.takeError(); + auto VName = Strings.getStringForID(Entry.second.VFileNI); + if (!VName) + return VName.takeError(); + } + + assert(Reader.bytesRemaining() == 0); + return Error::success(); +} diff --git a/llvm/lib/DebugInfo/PDB/Native/ModuleDebugStream.cpp b/llvm/lib/DebugInfo/PDB/Native/ModuleDebugStream.cpp new file mode 100644 index 0000000000000..1445f0bd9e1be --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/Native/ModuleDebugStream.cpp @@ -0,0 +1,144 @@ +//===- ModuleDebugStream.cpp - PDB Module Info Stream Access --------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#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/SymbolDeserializer.h" +#include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/DebugInfo/CodeView/SymbolRecordHelpers.h" +#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h" +#include "llvm/DebugInfo/PDB/Native/RawConstants.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); + + if (Mod.getModuleStreamIndex() != llvm::pdb::kInvalidStreamIndex) { + if (Error E = reloadSerialize(Reader)) + return E; + } + if (Reader.bytesRemaining() > 0) + return make_error<RawError>(raw_error_code::corrupt_file, + "Unexpected bytes in module stream."); + return Error::success(); +} + +Error ModuleDebugStreamRef::reloadSerialize(BinaryStreamReader &Reader) { + 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; + Reader.setOffset(0); + if (auto EC = Reader.readSubstream(SymbolsSubstream, SymbolSize)) + 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(), sizeof(uint32_t))) + 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; + return Error::success(); +} + +const codeview::CVSymbolArray +ModuleDebugStreamRef::getSymbolArrayForScope(uint32_t ScopeBegin) const { + return limitSymbolArrayToScope(SymbolArray, ScopeBegin); +} + +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()); +} + +CVSymbol ModuleDebugStreamRef::readSymbolAtOffset(uint32_t Offset) const { + auto Iter = SymbolArray.at(Offset); + assert(Iter != SymbolArray.end()); + return *Iter; +} + +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; +} diff --git a/llvm/lib/DebugInfo/PDB/Native/NamedStreamMap.cpp b/llvm/lib/DebugInfo/PDB/Native/NamedStreamMap.cpp new file mode 100644 index 0000000000000..4a88391494cd2 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/Native/NamedStreamMap.cpp @@ -0,0 +1,126 @@ +//===- NamedStreamMap.cpp - PDB Named Stream Map --------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/NamedStreamMap.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/DebugInfo/PDB/Native/Hash.h" +#include "llvm/DebugInfo/PDB/Native/HashTable.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/BinaryStreamRef.h" +#include "llvm/Support/BinaryStreamWriter.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include <algorithm> +#include <cassert> +#include <cstdint> +#include <tuple> + +using namespace llvm; +using namespace llvm::pdb; + +NamedStreamMapTraits::NamedStreamMapTraits(NamedStreamMap &NS) : NS(&NS) {} + +uint16_t NamedStreamMapTraits::hashLookupKey(StringRef S) const { + // In the reference implementation, this uses + // HASH Hasher<ULONG*, USHORT*>::hashPbCb(PB pb, size_t cb, ULONG ulMod). + // Here, the type HASH is a typedef of unsigned short. + // ** It is not a bug that we truncate the result of hashStringV1, in fact + // it is a bug if we do not! ** + // See NMTNI::hash() in the reference implementation. + return static_cast<uint16_t>(hashStringV1(S)); +} + +StringRef NamedStreamMapTraits::storageKeyToLookupKey(uint32_t Offset) const { + return NS->getString(Offset); +} + +uint32_t NamedStreamMapTraits::lookupKeyToStorageKey(StringRef S) { + return NS->appendStringData(S); +} + +NamedStreamMap::NamedStreamMap() : HashTraits(*this), OffsetIndexMap(1) {} + +Error NamedStreamMap::load(BinaryStreamReader &Stream) { + uint32_t StringBufferSize; + if (auto EC = Stream.readInteger(StringBufferSize)) + return joinErrors(std::move(EC), + make_error<RawError>(raw_error_code::corrupt_file, + "Expected string buffer size")); + + StringRef Buffer; + if (auto EC = Stream.readFixedString(Buffer, StringBufferSize)) + return EC; + NamesBuffer.assign(Buffer.begin(), Buffer.end()); + + return OffsetIndexMap.load(Stream); +} + +Error NamedStreamMap::commit(BinaryStreamWriter &Writer) const { + // The first field is the number of bytes of string data. + if (auto EC = Writer.writeInteger<uint32_t>(NamesBuffer.size())) + return EC; + + // Then the actual string data. + StringRef Data(NamesBuffer.data(), NamesBuffer.size()); + if (auto EC = Writer.writeFixedString(Data)) + return EC; + + // And finally the Offset Index map. + if (auto EC = OffsetIndexMap.commit(Writer)) + return EC; + + return Error::success(); +} + +uint32_t NamedStreamMap::calculateSerializedLength() const { + return sizeof(uint32_t) // String data size + + NamesBuffer.size() // String data + + OffsetIndexMap.calculateSerializedLength(); // Offset Index Map +} + +uint32_t NamedStreamMap::size() const { return OffsetIndexMap.size(); } + +StringRef NamedStreamMap::getString(uint32_t Offset) const { + assert(NamesBuffer.size() > Offset); + return StringRef(NamesBuffer.data() + Offset); +} + +uint32_t NamedStreamMap::hashString(uint32_t Offset) const { + return hashStringV1(getString(Offset)); +} + +bool NamedStreamMap::get(StringRef Stream, uint32_t &StreamNo) const { + auto Iter = OffsetIndexMap.find_as(Stream, HashTraits); + if (Iter == OffsetIndexMap.end()) + return false; + StreamNo = (*Iter).second; + return true; +} + +StringMap<uint32_t> NamedStreamMap::entries() const { + StringMap<uint32_t> Result; + for (const auto &Entry : OffsetIndexMap) { + StringRef Stream(NamesBuffer.data() + Entry.first); + Result.try_emplace(Stream, Entry.second); + } + return Result; +} + +uint32_t NamedStreamMap::appendStringData(StringRef S) { + uint32_t Offset = NamesBuffer.size(); + NamesBuffer.insert(NamesBuffer.end(), S.begin(), S.end()); + NamesBuffer.push_back('\0'); + return Offset; +} + +void NamedStreamMap::set(StringRef Stream, uint32_t StreamNo) { + OffsetIndexMap.set_as(Stream, support::ulittle32_t(StreamNo), HashTraits); +} diff --git a/llvm/lib/DebugInfo/PDB/Native/NativeCompilandSymbol.cpp b/llvm/lib/DebugInfo/PDB/Native/NativeCompilandSymbol.cpp new file mode 100644 index 0000000000000..39ae84acba202 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/Native/NativeCompilandSymbol.cpp @@ -0,0 +1,60 @@ +//===- NativeCompilandSymbol.cpp - Native impl for compilands ---*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/NativeCompilandSymbol.h" +#include "llvm/DebugInfo/PDB/Native/NativeSession.h" + +#include "llvm/ADT/STLExtras.h" + +namespace llvm { +namespace pdb { + +NativeCompilandSymbol::NativeCompilandSymbol(NativeSession &Session, + SymIndexId SymbolId, + DbiModuleDescriptor MI) + : NativeRawSymbol(Session, PDB_SymType::Compiland, SymbolId), Module(MI) {} + +PDB_SymType NativeCompilandSymbol::getSymTag() const { + return PDB_SymType::Compiland; +} + +void NativeCompilandSymbol::dump(raw_ostream &OS, int Indent, + PdbSymbolIdField ShowIdFields, + PdbSymbolIdField RecurseIdFields) const { + NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields); + + dumpSymbolIdField(OS, "lexicalParentId", 0, Indent, Session, + PdbSymbolIdField::LexicalParent, ShowIdFields, + RecurseIdFields); + dumpSymbolField(OS, "libraryName", getLibraryName(), Indent); + dumpSymbolField(OS, "name", getName(), Indent); + dumpSymbolField(OS, "editAndContinueEnabled", isEditAndContinueEnabled(), + Indent); +} + +bool NativeCompilandSymbol::isEditAndContinueEnabled() const { + return Module.hasECInfo(); +} + +SymIndexId 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 diff --git a/llvm/lib/DebugInfo/PDB/Native/NativeEnumGlobals.cpp b/llvm/lib/DebugInfo/PDB/Native/NativeEnumGlobals.cpp new file mode 100644 index 0000000000000..54646867bc5ff --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/Native/NativeEnumGlobals.cpp @@ -0,0 +1,54 @@ +//==- NativeEnumGlobals.cpp - Native Global Enumerator impl ------*- C++ -*-==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/NativeEnumGlobals.h" + +#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" +#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" +#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h" +#include "llvm/DebugInfo/PDB/Native/NativeSession.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/SymbolStream.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +NativeEnumGlobals::NativeEnumGlobals(NativeSession &PDBSession, + std::vector<codeview::SymbolKind> Kinds) + : Index(0), Session(PDBSession) { + GlobalsStream &GS = cantFail(Session.getPDBFile().getPDBGlobalsStream()); + SymbolStream &SS = cantFail(Session.getPDBFile().getPDBSymbolStream()); + for (uint32_t Off : GS.getGlobalsTable()) { + CVSymbol S = SS.readRecord(Off); + if (!llvm::is_contained(Kinds, S.kind())) + continue; + MatchOffsets.push_back(Off); + } +} + +uint32_t NativeEnumGlobals::getChildCount() const { + return static_cast<uint32_t>(MatchOffsets.size()); +} + +std::unique_ptr<PDBSymbol> +NativeEnumGlobals::getChildAtIndex(uint32_t N) const { + if (N >= MatchOffsets.size()) + return nullptr; + + SymIndexId Id = + Session.getSymbolCache().getOrCreateGlobalSymbolByOffset(MatchOffsets[N]); + return Session.getSymbolCache().getSymbolById(Id); +} + +std::unique_ptr<PDBSymbol> NativeEnumGlobals::getNext() { + return getChildAtIndex(Index++); +} + +void NativeEnumGlobals::reset() { Index = 0; } diff --git a/llvm/lib/DebugInfo/PDB/Native/NativeEnumInjectedSources.cpp b/llvm/lib/DebugInfo/PDB/Native/NativeEnumInjectedSources.cpp new file mode 100644 index 0000000000000..2f6a5bc3d5744 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/Native/NativeEnumInjectedSources.cpp @@ -0,0 +1,121 @@ +//==- NativeEnumInjectedSources.cpp - Native Injected Source Enumerator --*-==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/NativeEnumInjectedSources.h" + +#include "llvm/DebugInfo/PDB/Native/InfoStream.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/PDBStringTable.h" + +namespace llvm { +namespace pdb { + +namespace { + +Expected<std::string> readStreamData(BinaryStream &Stream, uint32_t Limit) { + uint32_t Offset = 0, DataLength = std::min(Limit, Stream.getLength()); + std::string Result; + Result.reserve(DataLength); + while (Offset < DataLength) { + ArrayRef<uint8_t> Data; + if (auto E = Stream.readLongestContiguousChunk(Offset, Data)) + return std::move(E); + Data = Data.take_front(DataLength - Offset); + Offset += Data.size(); + Result += toStringRef(Data); + } + return Result; +} + +class NativeInjectedSource final : public IPDBInjectedSource { + const SrcHeaderBlockEntry &Entry; + const PDBStringTable &Strings; + PDBFile &File; + +public: + NativeInjectedSource(const SrcHeaderBlockEntry &Entry, + PDBFile &File, const PDBStringTable &Strings) + : Entry(Entry), Strings(Strings), File(File) {} + + uint32_t getCrc32() const override { return Entry.CRC; } + uint64_t getCodeByteSize() const override { return Entry.FileSize; } + + std::string getFileName() const override { + StringRef Ret = cantFail(Strings.getStringForID(Entry.FileNI), + "InjectedSourceStream should have rejected this"); + return Ret; + } + + std::string getObjectFileName() const override { + StringRef Ret = cantFail(Strings.getStringForID(Entry.ObjNI), + "InjectedSourceStream should have rejected this"); + return Ret; + } + + std::string getVirtualFileName() const override { + StringRef Ret = cantFail(Strings.getStringForID(Entry.VFileNI), + "InjectedSourceStream should have rejected this"); + return Ret; + } + + uint32_t getCompression() const override { return Entry.Compression; } + + std::string getCode() const override { + // Get name of stream storing the data. + StringRef VName = + cantFail(Strings.getStringForID(Entry.VFileNI), + "InjectedSourceStream should have rejected this"); + std::string StreamName = ("/src/files/" + VName).str(); + + // Find stream with that name and read its data. + // FIXME: Consider validating (or even loading) all this in + // InjectedSourceStream so that no error can happen here. + auto ExpectedFileStream = File.safelyCreateNamedStream(StreamName); + if (!ExpectedFileStream) { + consumeError(ExpectedFileStream.takeError()); + return "(failed to open data stream)"; + } + + auto Data = readStreamData(**ExpectedFileStream, Entry.FileSize); + if (!Data) { + consumeError(Data.takeError()); + return "(failed to read data)"; + } + return *Data; + } +}; + +} // namespace + +NativeEnumInjectedSources::NativeEnumInjectedSources( + PDBFile &File, const InjectedSourceStream &IJS, + const PDBStringTable &Strings) + : File(File), Stream(IJS), Strings(Strings), Cur(Stream.begin()) {} + +uint32_t NativeEnumInjectedSources::getChildCount() const { + return static_cast<uint32_t>(Stream.size()); +} + +std::unique_ptr<IPDBInjectedSource> +NativeEnumInjectedSources::getChildAtIndex(uint32_t N) const { + if (N >= getChildCount()) + return nullptr; + return std::make_unique<NativeInjectedSource>(std::next(Stream.begin(), N)->second, + File, Strings); +} + +std::unique_ptr<IPDBInjectedSource> NativeEnumInjectedSources::getNext() { + if (Cur == Stream.end()) + return nullptr; + return std::make_unique<NativeInjectedSource>((Cur++)->second, File, Strings); +} + +void NativeEnumInjectedSources::reset() { Cur = Stream.begin(); } + +} +} diff --git a/llvm/lib/DebugInfo/PDB/Native/NativeEnumModules.cpp b/llvm/lib/DebugInfo/PDB/Native/NativeEnumModules.cpp new file mode 100644 index 0000000000000..c6621924b5160 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/Native/NativeEnumModules.cpp @@ -0,0 +1,43 @@ +//==- NativeEnumModules.cpp - Native Symbol Enumerator impl ------*- C++ -*-==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/NativeEnumModules.h" + +#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" +#include "llvm/DebugInfo/PDB/Native/NativeCompilandSymbol.h" +#include "llvm/DebugInfo/PDB/Native/NativeExeSymbol.h" +#include "llvm/DebugInfo/PDB/Native/NativeSession.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" +#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" +#include "llvm/DebugInfo/PDB/PDBSymbolExe.h" + +namespace llvm { +namespace pdb { + +NativeEnumModules::NativeEnumModules(NativeSession &PDBSession, uint32_t Index) + : Session(PDBSession), Index(Index) {} + +uint32_t NativeEnumModules::getChildCount() const { + return Session.getSymbolCache().getNumCompilands(); +} + +std::unique_ptr<PDBSymbol> +NativeEnumModules::getChildAtIndex(uint32_t N) const { + return Session.getSymbolCache().getOrCreateCompiland(N); +} + +std::unique_ptr<PDBSymbol> NativeEnumModules::getNext() { + if (Index >= getChildCount()) + return nullptr; + return getChildAtIndex(Index++); +} + +void NativeEnumModules::reset() { Index = 0; } + +} +} diff --git a/llvm/lib/DebugInfo/PDB/Native/NativeEnumTypes.cpp b/llvm/lib/DebugInfo/PDB/Native/NativeEnumTypes.cpp new file mode 100644 index 0000000000000..ac217df1ee48c --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/Native/NativeEnumTypes.cpp @@ -0,0 +1,70 @@ +//==- NativeEnumTypes.cpp - Native Type Enumerator impl ----------*- C++ -*-==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h" + +#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" +#include "llvm/DebugInfo/CodeView/TypeRecordHelpers.h" +#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" +#include "llvm/DebugInfo/PDB/Native/NativeSession.h" +#include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +NativeEnumTypes::NativeEnumTypes(NativeSession &PDBSession, + LazyRandomTypeCollection &Types, + std::vector<codeview::TypeLeafKind> Kinds) + : Matches(), Index(0), Session(PDBSession) { + Optional<TypeIndex> TI = Types.getFirst(); + while (TI) { + CVType CVT = Types.getType(*TI); + TypeLeafKind K = CVT.kind(); + if (llvm::is_contained(Kinds, K)) { + // Don't add forward refs, we'll find those later while enumerating. + if (!isUdtForwardRef(CVT)) + Matches.push_back(*TI); + } else if (K == TypeLeafKind::LF_MODIFIER) { + TypeIndex ModifiedTI = getModifiedType(CVT); + if (!ModifiedTI.isSimple()) { + CVType UnmodifiedCVT = Types.getType(ModifiedTI); + // LF_MODIFIERs point to forward refs, but don't worry about that + // here. We're pushing the TypeIndex of the LF_MODIFIER itself, + // so we'll worry about resolving forward refs later. + if (llvm::is_contained(Kinds, UnmodifiedCVT.kind())) + Matches.push_back(*TI); + } + } + TI = Types.getNext(*TI); + } +} + +NativeEnumTypes::NativeEnumTypes(NativeSession &PDBSession, + std::vector<codeview::TypeIndex> Indices) + : Matches(std::move(Indices)), Index(0), Session(PDBSession) {} + +uint32_t NativeEnumTypes::getChildCount() const { + return static_cast<uint32_t>(Matches.size()); +} + +std::unique_ptr<PDBSymbol> NativeEnumTypes::getChildAtIndex(uint32_t N) const { + if (N < Matches.size()) { + SymIndexId Id = Session.getSymbolCache().findSymbolByTypeIndex(Matches[N]); + return Session.getSymbolCache().getSymbolById(Id); + } + return nullptr; +} + +std::unique_ptr<PDBSymbol> NativeEnumTypes::getNext() { + return getChildAtIndex(Index++); +} + +void NativeEnumTypes::reset() { Index = 0; } diff --git a/llvm/lib/DebugInfo/PDB/Native/NativeExeSymbol.cpp b/llvm/lib/DebugInfo/PDB/Native/NativeExeSymbol.cpp new file mode 100644 index 0000000000000..3f393409129b1 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/Native/NativeExeSymbol.cpp @@ -0,0 +1,101 @@ +//===- NativeExeSymbol.cpp - native impl for PDBSymbolExe -------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#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/NativeCompilandSymbol.h" +#include "llvm/DebugInfo/PDB/Native/NativeEnumModules.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/SymbolCache.h" +#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" + +using namespace llvm; +using namespace llvm::pdb; + +static DbiStream *getDbiStreamPtr(NativeSession &Session) { + Expected<DbiStream &> DbiS = Session.getPDBFile().getPDBDbiStream(); + if (DbiS) + return &DbiS.get(); + + consumeError(DbiS.takeError()); + return nullptr; +} + +NativeExeSymbol::NativeExeSymbol(NativeSession &Session, SymIndexId SymbolId) + : NativeRawSymbol(Session, PDB_SymType::Exe, SymbolId), + Dbi(getDbiStreamPtr(Session)) {} + +std::unique_ptr<IPDBEnumSymbols> +NativeExeSymbol::findChildren(PDB_SymType Type) const { + switch (Type) { + case PDB_SymType::Compiland: { + return std::unique_ptr<IPDBEnumSymbols>(new NativeEnumModules(Session)); + break; + } + case PDB_SymType::ArrayType: + return Session.getSymbolCache().createTypeEnumerator(codeview::LF_ARRAY); + case PDB_SymType::Enum: + return Session.getSymbolCache().createTypeEnumerator(codeview::LF_ENUM); + case PDB_SymType::PointerType: + return Session.getSymbolCache().createTypeEnumerator(codeview::LF_POINTER); + case PDB_SymType::UDT: + return Session.getSymbolCache().createTypeEnumerator( + {codeview::LF_STRUCTURE, codeview::LF_CLASS, codeview::LF_UNION, + codeview::LF_INTERFACE}); + case PDB_SymType::VTableShape: + return Session.getSymbolCache().createTypeEnumerator(codeview::LF_VTSHAPE); + case PDB_SymType::FunctionSig: + return Session.getSymbolCache().createTypeEnumerator( + {codeview::LF_PROCEDURE, codeview::LF_MFUNCTION}); + case PDB_SymType::Typedef: + return Session.getSymbolCache().createGlobalsEnumerator(codeview::S_UDT); + + default: + break; + } + return nullptr; +} + +uint32_t NativeExeSymbol::getAge() const { + auto IS = Session.getPDBFile().getPDBInfoStream(); + if (IS) + return IS->getAge(); + consumeError(IS.takeError()); + return 0; +} + +std::string NativeExeSymbol::getSymbolsFileName() const { + return Session.getPDBFile().getFilePath(); +} + +codeview::GUID NativeExeSymbol::getGuid() const { + auto IS = Session.getPDBFile().getPDBInfoStream(); + if (IS) + return IS->getGuid(); + consumeError(IS.takeError()); + return codeview::GUID{{0}}; +} + +bool NativeExeSymbol::hasCTypes() const { + auto Dbi = Session.getPDBFile().getPDBDbiStream(); + if (Dbi) + return Dbi->hasCTypes(); + consumeError(Dbi.takeError()); + return false; +} + +bool NativeExeSymbol::hasPrivateSymbols() const { + auto Dbi = Session.getPDBFile().getPDBDbiStream(); + if (Dbi) + return !Dbi->isStripped(); + consumeError(Dbi.takeError()); + return false; +} diff --git a/llvm/lib/DebugInfo/PDB/Native/NativeRawSymbol.cpp b/llvm/lib/DebugInfo/PDB/Native/NativeRawSymbol.cpp new file mode 100644 index 0000000000000..2ad552470b617 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/Native/NativeRawSymbol.cpp @@ -0,0 +1,734 @@ +//===- NativeRawSymbol.cpp - Native implementation of IPDBRawSymbol -------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/NativeRawSymbol.h" +#include "llvm/DebugInfo/PDB/IPDBLineNumber.h" +#include "llvm/DebugInfo/PDB/Native/NativeSession.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" +#include "llvm/Support/FormatVariadic.h" + +using namespace llvm; +using namespace llvm::pdb; + +NativeRawSymbol::NativeRawSymbol(NativeSession &PDBSession, PDB_SymType Tag, + SymIndexId SymbolId) + : Session(PDBSession), Tag(Tag), SymbolId(SymbolId) {} + +void NativeRawSymbol::dump(raw_ostream &OS, int Indent, + PdbSymbolIdField ShowIdFields, + PdbSymbolIdField RecurseIdFields) const { + dumpSymbolIdField(OS, "symIndexId", SymbolId, Indent, Session, + PdbSymbolIdField::SymIndexId, ShowIdFields, + RecurseIdFields); + dumpSymbolField(OS, "symTag", Tag, Indent); +} + +std::unique_ptr<IPDBEnumSymbols> +NativeRawSymbol::findChildren(PDB_SymType Type) const { + return std::make_unique<NullEnumerator<PDBSymbol>>(); +} + +std::unique_ptr<IPDBEnumSymbols> +NativeRawSymbol::findChildren(PDB_SymType Type, StringRef Name, + PDB_NameSearchFlags Flags) const { + return std::make_unique<NullEnumerator<PDBSymbol>>(); +} + +std::unique_ptr<IPDBEnumSymbols> +NativeRawSymbol::findChildrenByAddr(PDB_SymType Type, StringRef Name, + PDB_NameSearchFlags Flags, uint32_t Section, uint32_t Offset) const { + return std::make_unique<NullEnumerator<PDBSymbol>>(); +} + +std::unique_ptr<IPDBEnumSymbols> +NativeRawSymbol::findChildrenByVA(PDB_SymType Type, StringRef Name, + PDB_NameSearchFlags Flags, uint64_t VA) const { + return std::make_unique<NullEnumerator<PDBSymbol>>(); +} + +std::unique_ptr<IPDBEnumSymbols> +NativeRawSymbol::findChildrenByRVA(PDB_SymType Type, StringRef Name, + PDB_NameSearchFlags Flags, uint32_t RVA) const { + return std::make_unique<NullEnumerator<PDBSymbol>>(); +} + +std::unique_ptr<IPDBEnumSymbols> +NativeRawSymbol::findInlineFramesByAddr(uint32_t Section, + uint32_t Offset) const { + return std::make_unique<NullEnumerator<PDBSymbol>>(); +} + +std::unique_ptr<IPDBEnumSymbols> +NativeRawSymbol::findInlineFramesByRVA(uint32_t RVA) const { + return std::make_unique<NullEnumerator<PDBSymbol>>(); +} + +std::unique_ptr<IPDBEnumSymbols> +NativeRawSymbol::findInlineFramesByVA(uint64_t VA) const { + return std::make_unique<NullEnumerator<PDBSymbol>>(); +} + +std::unique_ptr<IPDBEnumLineNumbers> +NativeRawSymbol::findInlineeLines() const { + return std::make_unique<NullEnumerator<IPDBLineNumber>>(); +} + +std::unique_ptr<IPDBEnumLineNumbers> +NativeRawSymbol::findInlineeLinesByAddr(uint32_t Section, uint32_t Offset, + uint32_t Length) const { + return std::make_unique<NullEnumerator<IPDBLineNumber>>(); +} + +std::unique_ptr<IPDBEnumLineNumbers> +NativeRawSymbol::findInlineeLinesByRVA(uint32_t RVA, uint32_t Length) const { + return std::make_unique<NullEnumerator<IPDBLineNumber>>(); +} + +std::unique_ptr<IPDBEnumLineNumbers> +NativeRawSymbol::findInlineeLinesByVA(uint64_t VA, uint32_t Length) const { + return std::make_unique<NullEnumerator<IPDBLineNumber>>(); +} + +void NativeRawSymbol::getDataBytes(SmallVector<uint8_t, 32> &bytes) const { + bytes.clear(); +} + +PDB_MemberAccess NativeRawSymbol::getAccess() const { + return PDB_MemberAccess::Private; +} + +uint32_t NativeRawSymbol::getAddressOffset() const { + return 0; +} + +uint32_t NativeRawSymbol::getAddressSection() const { + return 0; +} + +uint32_t NativeRawSymbol::getAge() const { + return 0; +} + +SymIndexId NativeRawSymbol::getArrayIndexTypeId() const { return 0; } + +void NativeRawSymbol::getBackEndVersion(VersionInfo &Version) const { + Version.Major = 0; + Version.Minor = 0; + Version.Build = 0; + Version.QFE = 0; +} + +uint32_t NativeRawSymbol::getBaseDataOffset() const { + return 0; +} + +uint32_t NativeRawSymbol::getBaseDataSlot() const { + return 0; +} + +SymIndexId NativeRawSymbol::getBaseSymbolId() const { return 0; } + +PDB_BuiltinType NativeRawSymbol::getBuiltinType() const { + return PDB_BuiltinType::None; +} + +uint32_t NativeRawSymbol::getBitPosition() const { + return 0; +} + +PDB_CallingConv NativeRawSymbol::getCallingConvention() const { + return PDB_CallingConv::FarStdCall; +} + +SymIndexId NativeRawSymbol::getClassParentId() const { return 0; } + +std::string NativeRawSymbol::getCompilerName() const { + return {}; +} + +uint32_t NativeRawSymbol::getCount() const { + return 0; +} + +uint32_t NativeRawSymbol::getCountLiveRanges() const { + return 0; +} + +void NativeRawSymbol::getFrontEndVersion(VersionInfo &Version) const { + Version.Major = 0; + Version.Minor = 0; + Version.Build = 0; + Version.QFE = 0; +} + +PDB_Lang NativeRawSymbol::getLanguage() const { + return PDB_Lang::Cobol; +} + +SymIndexId NativeRawSymbol::getLexicalParentId() const { return 0; } + +std::string NativeRawSymbol::getLibraryName() const { + return {}; +} + +uint32_t NativeRawSymbol::getLiveRangeStartAddressOffset() const { + return 0; +} + +uint32_t NativeRawSymbol::getLiveRangeStartAddressSection() const { + return 0; +} + +uint32_t NativeRawSymbol::getLiveRangeStartRelativeVirtualAddress() const { + return 0; +} + +codeview::RegisterId NativeRawSymbol::getLocalBasePointerRegisterId() const { + return codeview::RegisterId::EAX; +} + +SymIndexId NativeRawSymbol::getLowerBoundId() const { return 0; } + +uint32_t NativeRawSymbol::getMemorySpaceKind() const { + return 0; +} + +std::string NativeRawSymbol::getName() const { + return {}; +} + +uint32_t NativeRawSymbol::getNumberOfAcceleratorPointerTags() const { + return 0; +} + +uint32_t NativeRawSymbol::getNumberOfColumns() const { + return 0; +} + +uint32_t NativeRawSymbol::getNumberOfModifiers() const { + return 0; +} + +uint32_t NativeRawSymbol::getNumberOfRegisterIndices() const { + return 0; +} + +uint32_t NativeRawSymbol::getNumberOfRows() const { + return 0; +} + +std::string NativeRawSymbol::getObjectFileName() const { + return {}; +} + +uint32_t NativeRawSymbol::getOemId() const { + return 0; +} + +SymIndexId NativeRawSymbol::getOemSymbolId() const { return 0; } + +uint32_t NativeRawSymbol::getOffsetInUdt() const { + return 0; +} + +PDB_Cpu NativeRawSymbol::getPlatform() const { + return PDB_Cpu::Intel8080; +} + +uint32_t NativeRawSymbol::getRank() const { + return 0; +} + +codeview::RegisterId NativeRawSymbol::getRegisterId() const { + return codeview::RegisterId::EAX; +} + +uint32_t NativeRawSymbol::getRegisterType() const { + return 0; +} + +uint32_t NativeRawSymbol::getRelativeVirtualAddress() const { + return 0; +} + +uint32_t NativeRawSymbol::getSamplerSlot() const { + return 0; +} + +uint32_t NativeRawSymbol::getSignature() const { + return 0; +} + +uint32_t NativeRawSymbol::getSizeInUdt() const { + return 0; +} + +uint32_t NativeRawSymbol::getSlot() const { + return 0; +} + +std::string NativeRawSymbol::getSourceFileName() const { + return {}; +} + +std::unique_ptr<IPDBLineNumber> +NativeRawSymbol::getSrcLineOnTypeDefn() const { + return nullptr; +} + +uint32_t NativeRawSymbol::getStride() const { + return 0; +} + +SymIndexId NativeRawSymbol::getSubTypeId() const { return 0; } + +std::string NativeRawSymbol::getSymbolsFileName() const { return {}; } + +SymIndexId NativeRawSymbol::getSymIndexId() const { return SymbolId; } + +uint32_t NativeRawSymbol::getTargetOffset() const { + return 0; +} + +uint32_t NativeRawSymbol::getTargetRelativeVirtualAddress() const { + return 0; +} + +uint64_t NativeRawSymbol::getTargetVirtualAddress() const { + return 0; +} + +uint32_t NativeRawSymbol::getTargetSection() const { + return 0; +} + +uint32_t NativeRawSymbol::getTextureSlot() const { + return 0; +} + +uint32_t NativeRawSymbol::getTimeStamp() const { + return 0; +} + +uint32_t NativeRawSymbol::getToken() const { + return 0; +} + +SymIndexId NativeRawSymbol::getTypeId() const { return 0; } + +uint32_t NativeRawSymbol::getUavSlot() const { + return 0; +} + +std::string NativeRawSymbol::getUndecoratedName() const { + return {}; +} + +std::string NativeRawSymbol::getUndecoratedNameEx( + PDB_UndnameFlags Flags) const { + return {}; +} + +SymIndexId NativeRawSymbol::getUnmodifiedTypeId() const { return 0; } + +SymIndexId NativeRawSymbol::getUpperBoundId() const { return 0; } + +Variant NativeRawSymbol::getValue() const { + return Variant(); +} + +uint32_t NativeRawSymbol::getVirtualBaseDispIndex() const { + return 0; +} + +uint32_t NativeRawSymbol::getVirtualBaseOffset() const { + return 0; +} + +SymIndexId NativeRawSymbol::getVirtualTableShapeId() const { return 0; } + +std::unique_ptr<PDBSymbolTypeBuiltin> +NativeRawSymbol::getVirtualBaseTableType() const { + return nullptr; +} + +PDB_DataKind NativeRawSymbol::getDataKind() const { + return PDB_DataKind::Unknown; +} + +PDB_SymType NativeRawSymbol::getSymTag() const { return Tag; } + +codeview::GUID NativeRawSymbol::getGuid() const { return codeview::GUID{{0}}; } + +int32_t NativeRawSymbol::getOffset() const { + return 0; +} + +int32_t NativeRawSymbol::getThisAdjust() const { + return 0; +} + +int32_t NativeRawSymbol::getVirtualBasePointerOffset() const { + return 0; +} + +PDB_LocType NativeRawSymbol::getLocationType() const { + return PDB_LocType::Null; +} + +PDB_Machine NativeRawSymbol::getMachineType() const { + return PDB_Machine::Invalid; +} + +codeview::ThunkOrdinal NativeRawSymbol::getThunkOrdinal() const { + return codeview::ThunkOrdinal::Standard; +} + +uint64_t NativeRawSymbol::getLength() const { + return 0; +} + +uint64_t NativeRawSymbol::getLiveRangeLength() const { + return 0; +} + +uint64_t NativeRawSymbol::getVirtualAddress() const { + return 0; +} + +PDB_UdtType NativeRawSymbol::getUdtKind() const { + return PDB_UdtType::Struct; +} + +bool NativeRawSymbol::hasConstructor() const { + return false; +} + +bool NativeRawSymbol::hasCustomCallingConvention() const { + return false; +} + +bool NativeRawSymbol::hasFarReturn() const { + return false; +} + +bool NativeRawSymbol::isCode() const { + return false; +} + +bool NativeRawSymbol::isCompilerGenerated() const { + return false; +} + +bool NativeRawSymbol::isConstType() const { + return false; +} + +bool NativeRawSymbol::isEditAndContinueEnabled() const { + return false; +} + +bool NativeRawSymbol::isFunction() const { + return false; +} + +bool NativeRawSymbol::getAddressTaken() const { + return false; +} + +bool NativeRawSymbol::getNoStackOrdering() const { + return false; +} + +bool NativeRawSymbol::hasAlloca() const { + return false; +} + +bool NativeRawSymbol::hasAssignmentOperator() const { + return false; +} + +bool NativeRawSymbol::hasCTypes() const { + return false; +} + +bool NativeRawSymbol::hasCastOperator() const { + return false; +} + +bool NativeRawSymbol::hasDebugInfo() const { + return false; +} + +bool NativeRawSymbol::hasEH() const { + return false; +} + +bool NativeRawSymbol::hasEHa() const { + return false; +} + +bool NativeRawSymbol::hasInlAsm() const { + return false; +} + +bool NativeRawSymbol::hasInlineAttribute() const { + return false; +} + +bool NativeRawSymbol::hasInterruptReturn() const { + return false; +} + +bool NativeRawSymbol::hasFramePointer() const { + return false; +} + +bool NativeRawSymbol::hasLongJump() const { + return false; +} + +bool NativeRawSymbol::hasManagedCode() const { + return false; +} + +bool NativeRawSymbol::hasNestedTypes() const { + return false; +} + +bool NativeRawSymbol::hasNoInlineAttribute() const { + return false; +} + +bool NativeRawSymbol::hasNoReturnAttribute() const { + return false; +} + +bool NativeRawSymbol::hasOptimizedCodeDebugInfo() const { + return false; +} + +bool NativeRawSymbol::hasOverloadedOperator() const { + return false; +} + +bool NativeRawSymbol::hasSEH() const { + return false; +} + +bool NativeRawSymbol::hasSecurityChecks() const { + return false; +} + +bool NativeRawSymbol::hasSetJump() const { + return false; +} + +bool NativeRawSymbol::hasStrictGSCheck() const { + return false; +} + +bool NativeRawSymbol::isAcceleratorGroupSharedLocal() const { + return false; +} + +bool NativeRawSymbol::isAcceleratorPointerTagLiveRange() const { + return false; +} + +bool NativeRawSymbol::isAcceleratorStubFunction() const { + return false; +} + +bool NativeRawSymbol::isAggregated() const { + return false; +} + +bool NativeRawSymbol::isIntroVirtualFunction() const { + return false; +} + +bool NativeRawSymbol::isCVTCIL() const { + return false; +} + +bool NativeRawSymbol::isConstructorVirtualBase() const { + return false; +} + +bool NativeRawSymbol::isCxxReturnUdt() const { + return false; +} + +bool NativeRawSymbol::isDataAligned() const { + return false; +} + +bool NativeRawSymbol::isHLSLData() const { + return false; +} + +bool NativeRawSymbol::isHotpatchable() const { + return false; +} + +bool NativeRawSymbol::isIndirectVirtualBaseClass() const { + return false; +} + +bool NativeRawSymbol::isInterfaceUdt() const { + return false; +} + +bool NativeRawSymbol::isIntrinsic() const { + return false; +} + +bool NativeRawSymbol::isLTCG() const { + return false; +} + +bool NativeRawSymbol::isLocationControlFlowDependent() const { + return false; +} + +bool NativeRawSymbol::isMSILNetmodule() const { + return false; +} + +bool NativeRawSymbol::isMatrixRowMajor() const { + return false; +} + +bool NativeRawSymbol::isManagedCode() const { + return false; +} + +bool NativeRawSymbol::isMSILCode() const { + return false; +} + +bool NativeRawSymbol::isMultipleInheritance() const { + return false; +} + +bool NativeRawSymbol::isNaked() const { + return false; +} + +bool NativeRawSymbol::isNested() const { + return false; +} + +bool NativeRawSymbol::isOptimizedAway() const { + return false; +} + +bool NativeRawSymbol::isPacked() const { + return false; +} + +bool NativeRawSymbol::isPointerBasedOnSymbolValue() const { + return false; +} + +bool NativeRawSymbol::isPointerToDataMember() const { + return false; +} + +bool NativeRawSymbol::isPointerToMemberFunction() const { + return false; +} + +bool NativeRawSymbol::isPureVirtual() const { + return false; +} + +bool NativeRawSymbol::isRValueReference() const { + return false; +} + +bool NativeRawSymbol::isRefUdt() const { + return false; +} + +bool NativeRawSymbol::isReference() const { + return false; +} + +bool NativeRawSymbol::isRestrictedType() const { + return false; +} + +bool NativeRawSymbol::isReturnValue() const { + return false; +} + +bool NativeRawSymbol::isSafeBuffers() const { + return false; +} + +bool NativeRawSymbol::isScoped() const { + return false; +} + +bool NativeRawSymbol::isSdl() const { + return false; +} + +bool NativeRawSymbol::isSingleInheritance() const { + return false; +} + +bool NativeRawSymbol::isSplitted() const { + return false; +} + +bool NativeRawSymbol::isStatic() const { + return false; +} + +bool NativeRawSymbol::hasPrivateSymbols() const { + return false; +} + +bool NativeRawSymbol::isUnalignedType() const { + return false; +} + +bool NativeRawSymbol::isUnreached() const { + return false; +} + +bool NativeRawSymbol::isValueUdt() const { + return false; +} + +bool NativeRawSymbol::isVirtual() const { + return false; +} + +bool NativeRawSymbol::isVirtualBaseClass() const { + return false; +} + +bool NativeRawSymbol::isVirtualInheritance() const { + return false; +} + +bool NativeRawSymbol::isVolatileType() const { + return false; +} + +bool NativeRawSymbol::wasInlined() const { + return false; +} + +std::string NativeRawSymbol::getUnused() const { + return {}; +} diff --git a/llvm/lib/DebugInfo/PDB/Native/NativeSession.cpp b/llvm/lib/DebugInfo/PDB/Native/NativeSession.cpp new file mode 100644 index 0000000000000..b45a5881dcb5c --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/Native/NativeSession.cpp @@ -0,0 +1,227 @@ +//===- NativeSession.cpp - Native implementation of IPDBSession -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/NativeSession.h" + +#include "llvm/ADT/STLExtras.h" +#include "llvm/DebugInfo/CodeView/TypeIndex.h" +#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" +#include "llvm/DebugInfo/PDB/IPDBSourceFile.h" +#include "llvm/DebugInfo/PDB/Native/NativeCompilandSymbol.h" +#include "llvm/DebugInfo/PDB/Native/NativeEnumInjectedSources.h" +#include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h" +#include "llvm/DebugInfo/PDB/Native/NativeExeSymbol.h" +#include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h" +#include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/DebugInfo/PDB/Native/SymbolCache.h" +#include "llvm/DebugInfo/PDB/Native/TpiStream.h" +#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" +#include "llvm/DebugInfo/PDB/PDBSymbolExe.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/MemoryBuffer.h" + +#include <algorithm> +#include <cassert> +#include <memory> +#include <utility> + +using namespace llvm; +using namespace llvm::msf; +using namespace llvm::pdb; + +static DbiStream *getDbiStreamPtr(PDBFile &File) { + Expected<DbiStream &> DbiS = File.getPDBDbiStream(); + if (DbiS) + return &DbiS.get(); + + consumeError(DbiS.takeError()); + return nullptr; +} + +NativeSession::NativeSession(std::unique_ptr<PDBFile> PdbFile, + std::unique_ptr<BumpPtrAllocator> Allocator) + : Pdb(std::move(PdbFile)), Allocator(std::move(Allocator)), + Cache(*this, getDbiStreamPtr(*Pdb)) {} + +NativeSession::~NativeSession() = default; + +Error NativeSession::createFromPdb(std::unique_ptr<MemoryBuffer> Buffer, + std::unique_ptr<IPDBSession> &Session) { + StringRef Path = Buffer->getBufferIdentifier(); + auto Stream = std::make_unique<MemoryBufferByteStream>( + std::move(Buffer), llvm::support::little); + + auto Allocator = std::make_unique<BumpPtrAllocator>(); + auto File = std::make_unique<PDBFile>(Path, std::move(Stream), *Allocator); + if (auto EC = File->parseFileHeaders()) + return EC; + if (auto EC = File->parseStreamData()) + return EC; + + Session = + std::make_unique<NativeSession>(std::move(File), std::move(Allocator)); + + return Error::success(); +} + +Error NativeSession::createFromExe(StringRef Path, + std::unique_ptr<IPDBSession> &Session) { + return make_error<RawError>(raw_error_code::feature_unsupported); +} + +uint64_t NativeSession::getLoadAddress() const { return 0; } + +bool NativeSession::setLoadAddress(uint64_t Address) { return false; } + +std::unique_ptr<PDBSymbolExe> NativeSession::getGlobalScope() { + return PDBSymbol::createAs<PDBSymbolExe>(*this, getNativeGlobalScope()); +} + +std::unique_ptr<PDBSymbol> +NativeSession::getSymbolById(SymIndexId SymbolId) const { + return Cache.getSymbolById(SymbolId); +} + +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 { + return nullptr; +} + +std::unique_ptr<IPDBEnumLineNumbers> +NativeSession::findLineNumbersByAddress(uint64_t Address, + uint32_t Length) const { + 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, + PDB_NameSearchFlags Flags) const { + return nullptr; +} + +std::unique_ptr<IPDBSourceFile> +NativeSession::findOneSourceFile(const PDBSymbolCompiland *Compiland, + StringRef Pattern, + PDB_NameSearchFlags Flags) const { + return nullptr; +} + +std::unique_ptr<IPDBEnumChildren<PDBSymbolCompiland>> +NativeSession::findCompilandsForSourceFile(StringRef Pattern, + PDB_NameSearchFlags Flags) const { + return nullptr; +} + +std::unique_ptr<PDBSymbolCompiland> +NativeSession::findOneCompilandForSourceFile(StringRef Pattern, + PDB_NameSearchFlags Flags) const { + return nullptr; +} + +std::unique_ptr<IPDBEnumSourceFiles> NativeSession::getAllSourceFiles() const { + return nullptr; +} + +std::unique_ptr<IPDBEnumSourceFiles> NativeSession::getSourceFilesForCompiland( + const PDBSymbolCompiland &Compiland) const { + return nullptr; +} + +std::unique_ptr<IPDBSourceFile> +NativeSession::getSourceFileById(uint32_t FileId) const { + return nullptr; +} + +std::unique_ptr<IPDBEnumDataStreams> NativeSession::getDebugStreams() const { + return nullptr; +} + +std::unique_ptr<IPDBEnumTables> NativeSession::getEnumTables() const { + return nullptr; +} + +std::unique_ptr<IPDBEnumInjectedSources> +NativeSession::getInjectedSources() const { + auto ISS = Pdb->getInjectedSourceStream(); + if (!ISS) { + consumeError(ISS.takeError()); + return nullptr; + } + auto Strings = Pdb->getStringTable(); + if (!Strings) { + consumeError(Strings.takeError()); + return nullptr; + } + return std::make_unique<NativeEnumInjectedSources>(*Pdb, *ISS, *Strings); +} + +std::unique_ptr<IPDBEnumSectionContribs> +NativeSession::getSectionContribs() const { + return nullptr; +} + +std::unique_ptr<IPDBEnumFrameData> +NativeSession::getFrameData() const { + return nullptr; +} + +void NativeSession::initializeExeSymbol() { + if (ExeSymbol == 0) + ExeSymbol = Cache.createSymbol<NativeExeSymbol>(); +} + +NativeExeSymbol &NativeSession::getNativeGlobalScope() const { + const_cast<NativeSession &>(*this).initializeExeSymbol(); + + return Cache.getNativeSymbolById<NativeExeSymbol>(ExeSymbol); +} diff --git a/llvm/lib/DebugInfo/PDB/Native/NativeSymbolEnumerator.cpp b/llvm/lib/DebugInfo/PDB/Native/NativeSymbolEnumerator.cpp new file mode 100644 index 0000000000000..704c1254afbfd --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/Native/NativeSymbolEnumerator.cpp @@ -0,0 +1,122 @@ +//===- NativeSymbolEnumerator.cpp - info about enumerators ------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/NativeSymbolEnumerator.h" + +#include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h" +#include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +NativeSymbolEnumerator::NativeSymbolEnumerator( + NativeSession &Session, SymIndexId Id, const NativeTypeEnum &Parent, + codeview::EnumeratorRecord Record) + : NativeRawSymbol(Session, PDB_SymType::Data, Id), Parent(Parent), + Record(std::move(Record)) {} + +NativeSymbolEnumerator::~NativeSymbolEnumerator() {} + +void NativeSymbolEnumerator::dump(raw_ostream &OS, int Indent, + PdbSymbolIdField ShowIdFields, + PdbSymbolIdField RecurseIdFields) const { + NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields); + dumpSymbolIdField(OS, "classParentId", getClassParentId(), Indent, Session, + PdbSymbolIdField::ClassParent, ShowIdFields, + RecurseIdFields); + dumpSymbolIdField(OS, "lexicalParentId", getLexicalParentId(), Indent, + Session, PdbSymbolIdField::LexicalParent, ShowIdFields, + RecurseIdFields); + dumpSymbolField(OS, "name", getName(), Indent); + dumpSymbolIdField(OS, "typeId", getTypeId(), Indent, Session, + PdbSymbolIdField::Type, ShowIdFields, RecurseIdFields); + dumpSymbolField(OS, "dataKind", getDataKind(), Indent); + dumpSymbolField(OS, "locationType", getLocationType(), Indent); + dumpSymbolField(OS, "constType", isConstType(), Indent); + dumpSymbolField(OS, "unalignedType", isUnalignedType(), Indent); + dumpSymbolField(OS, "volatileType", isVolatileType(), Indent); + dumpSymbolField(OS, "value", getValue(), Indent); +} + +SymIndexId NativeSymbolEnumerator::getClassParentId() const { + return Parent.getSymIndexId(); +} + +SymIndexId NativeSymbolEnumerator::getLexicalParentId() const { return 0; } + +std::string NativeSymbolEnumerator::getName() const { return Record.Name; } + +SymIndexId NativeSymbolEnumerator::getTypeId() const { + return Parent.getTypeId(); +} + +PDB_DataKind NativeSymbolEnumerator::getDataKind() const { + return PDB_DataKind::Constant; +} + +PDB_LocType NativeSymbolEnumerator::getLocationType() const { + return PDB_LocType::Constant; +} + +bool NativeSymbolEnumerator::isConstType() const { return false; } + +bool NativeSymbolEnumerator::isVolatileType() const { return false; } + +bool NativeSymbolEnumerator::isUnalignedType() const { return false; } + +Variant NativeSymbolEnumerator::getValue() const { + const NativeTypeBuiltin &BT = Parent.getUnderlyingBuiltinType(); + + switch (BT.getBuiltinType()) { + case PDB_BuiltinType::Int: + case PDB_BuiltinType::Long: + case PDB_BuiltinType::Char: { + assert(Record.Value.isSignedIntN(BT.getLength() * 8)); + int64_t N = Record.Value.getSExtValue(); + switch (BT.getLength()) { + case 1: + return Variant{static_cast<int8_t>(N)}; + case 2: + return Variant{static_cast<int16_t>(N)}; + case 4: + return Variant{static_cast<int32_t>(N)}; + case 8: + return Variant{static_cast<int64_t>(N)}; + } + break; + } + case PDB_BuiltinType::UInt: + case PDB_BuiltinType::ULong: { + assert(Record.Value.isIntN(BT.getLength() * 8)); + uint64_t U = Record.Value.getZExtValue(); + switch (BT.getLength()) { + case 1: + return Variant{static_cast<uint8_t>(U)}; + case 2: + return Variant{static_cast<uint16_t>(U)}; + case 4: + return Variant{static_cast<uint32_t>(U)}; + case 8: + return Variant{static_cast<uint64_t>(U)}; + } + break; + } + case PDB_BuiltinType::Bool: { + assert(Record.Value.isIntN(BT.getLength() * 8)); + uint64_t U = Record.Value.getZExtValue(); + return Variant{static_cast<bool>(U)}; + } + default: + assert(false && "Invalid enumeration type"); + break; + } + + return Variant{Record.Value.getSExtValue()}; +} diff --git a/llvm/lib/DebugInfo/PDB/Native/NativeTypeArray.cpp b/llvm/lib/DebugInfo/PDB/Native/NativeTypeArray.cpp new file mode 100644 index 0000000000000..80d455ad66e95 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/Native/NativeTypeArray.cpp @@ -0,0 +1,66 @@ +//===- NativeTypeArray.cpp - info about arrays ------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/NativeTypeArray.h" + +#include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h" +#include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +NativeTypeArray::NativeTypeArray(NativeSession &Session, SymIndexId Id, + codeview::TypeIndex TI, + codeview::ArrayRecord Record) + : NativeRawSymbol(Session, PDB_SymType::ArrayType, Id), Record(Record), + Index(TI) {} +NativeTypeArray::~NativeTypeArray() {} + +void NativeTypeArray::dump(raw_ostream &OS, int Indent, + PdbSymbolIdField ShowIdFields, + PdbSymbolIdField RecurseIdFields) const { + NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields); + + dumpSymbolField(OS, "arrayIndexTypeId", getArrayIndexTypeId(), Indent); + dumpSymbolIdField(OS, "elementTypeId", getTypeId(), Indent, Session, + PdbSymbolIdField::Type, ShowIdFields, RecurseIdFields); + + dumpSymbolIdField(OS, "lexicalParentId", 0, Indent, Session, + PdbSymbolIdField::LexicalParent, ShowIdFields, + RecurseIdFields); + dumpSymbolField(OS, "length", getLength(), Indent); + dumpSymbolField(OS, "count", getCount(), Indent); + dumpSymbolField(OS, "constType", isConstType(), Indent); + dumpSymbolField(OS, "unalignedType", isUnalignedType(), Indent); + dumpSymbolField(OS, "volatileType", isVolatileType(), Indent); +} + +SymIndexId NativeTypeArray::getArrayIndexTypeId() const { + return Session.getSymbolCache().findSymbolByTypeIndex(Record.getIndexType()); +} + +bool NativeTypeArray::isConstType() const { return false; } + +bool NativeTypeArray::isUnalignedType() const { return false; } + +bool NativeTypeArray::isVolatileType() const { return false; } + +uint32_t NativeTypeArray::getCount() const { + NativeRawSymbol &Element = + Session.getSymbolCache().getNativeSymbolById(getTypeId()); + return getLength() / Element.getLength(); +} + +SymIndexId NativeTypeArray::getTypeId() const { + return Session.getSymbolCache().findSymbolByTypeIndex( + Record.getElementType()); +} + +uint64_t NativeTypeArray::getLength() const { return Record.Size; }
\ No newline at end of file diff --git a/llvm/lib/DebugInfo/PDB/Native/NativeTypeBuiltin.cpp b/llvm/lib/DebugInfo/PDB/Native/NativeTypeBuiltin.cpp new file mode 100644 index 0000000000000..a08663aa91bad --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/Native/NativeTypeBuiltin.cpp @@ -0,0 +1,46 @@ +//===- NativeTypeBuiltin.cpp -------------------------------------- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h" +#include "llvm/Support/FormatVariadic.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +NativeTypeBuiltin::NativeTypeBuiltin(NativeSession &PDBSession, SymIndexId Id, + ModifierOptions Mods, PDB_BuiltinType T, + uint64_t L) + : NativeRawSymbol(PDBSession, PDB_SymType::BuiltinType, Id), + Session(PDBSession), Mods(Mods), Type(T), Length(L) {} + +NativeTypeBuiltin::~NativeTypeBuiltin() {} + +void NativeTypeBuiltin::dump(raw_ostream &OS, int Indent, + PdbSymbolIdField ShowIdFields, + PdbSymbolIdField RecurseIdFields) const {} + +PDB_SymType NativeTypeBuiltin::getSymTag() const { + return PDB_SymType::BuiltinType; +} + +PDB_BuiltinType NativeTypeBuiltin::getBuiltinType() const { return Type; } + +bool NativeTypeBuiltin::isConstType() const { + return (Mods & ModifierOptions::Const) != ModifierOptions::None; +} + +uint64_t NativeTypeBuiltin::getLength() const { return Length; } + +bool NativeTypeBuiltin::isUnalignedType() const { + return (Mods & ModifierOptions::Unaligned) != ModifierOptions::None; +} + +bool NativeTypeBuiltin::isVolatileType() const { + return (Mods & ModifierOptions::Volatile) != ModifierOptions::None; +} diff --git a/llvm/lib/DebugInfo/PDB/Native/NativeTypeEnum.cpp b/llvm/lib/DebugInfo/PDB/Native/NativeTypeEnum.cpp new file mode 100644 index 0000000000000..26ccb7daece08 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/Native/NativeTypeEnum.cpp @@ -0,0 +1,381 @@ +//===- NativeTypeEnum.cpp - info about enum type ----------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h" + +#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h" +#include "llvm/DebugInfo/PDB/Native/NativeSymbolEnumerator.h" +#include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/SymbolCache.h" +#include "llvm/DebugInfo/PDB/Native/TpiStream.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" + +#include "llvm/Support/FormatVariadic.h" + +#include <cassert> + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +namespace { +// Yea, this is a pretty terrible class name. But if we have an enum: +// +// enum Foo { +// A, +// B +// }; +// +// then A and B are the "enumerators" of the "enum" Foo. And we need +// to enumerate them. +class NativeEnumEnumEnumerators : public IPDBEnumSymbols, TypeVisitorCallbacks { +public: + NativeEnumEnumEnumerators(NativeSession &Session, + const NativeTypeEnum &ClassParent); + + uint32_t getChildCount() const override; + std::unique_ptr<PDBSymbol> getChildAtIndex(uint32_t Index) const override; + std::unique_ptr<PDBSymbol> getNext() override; + void reset() override; + +private: + Error visitKnownMember(CVMemberRecord &CVM, + EnumeratorRecord &Record) override; + Error visitKnownMember(CVMemberRecord &CVM, + ListContinuationRecord &Record) override; + + NativeSession &Session; + const NativeTypeEnum &ClassParent; + std::vector<EnumeratorRecord> Enumerators; + Optional<TypeIndex> ContinuationIndex; + uint32_t Index = 0; +}; +} // namespace + +NativeEnumEnumEnumerators::NativeEnumEnumEnumerators( + NativeSession &Session, const NativeTypeEnum &ClassParent) + : Session(Session), ClassParent(ClassParent) { + TpiStream &Tpi = cantFail(Session.getPDBFile().getPDBTpiStream()); + LazyRandomTypeCollection &Types = Tpi.typeCollection(); + + ContinuationIndex = ClassParent.getEnumRecord().FieldList; + while (ContinuationIndex) { + CVType FieldList = Types.getType(*ContinuationIndex); + assert(FieldList.kind() == LF_FIELDLIST); + ContinuationIndex.reset(); + cantFail(visitMemberRecordStream(FieldList.data(), *this)); + } +} + +Error NativeEnumEnumEnumerators::visitKnownMember(CVMemberRecord &CVM, + EnumeratorRecord &Record) { + Enumerators.push_back(Record); + return Error::success(); +} + +Error NativeEnumEnumEnumerators::visitKnownMember( + CVMemberRecord &CVM, ListContinuationRecord &Record) { + ContinuationIndex = Record.ContinuationIndex; + return Error::success(); +} + +uint32_t NativeEnumEnumEnumerators::getChildCount() const { + return Enumerators.size(); +} + +std::unique_ptr<PDBSymbol> +NativeEnumEnumEnumerators::getChildAtIndex(uint32_t Index) const { + if (Index >= getChildCount()) + return nullptr; + + SymIndexId Id = Session.getSymbolCache() + .getOrCreateFieldListMember<NativeSymbolEnumerator>( + ClassParent.getEnumRecord().FieldList, Index, + ClassParent, Enumerators[Index]); + return Session.getSymbolCache().getSymbolById(Id); +} + +std::unique_ptr<PDBSymbol> NativeEnumEnumEnumerators::getNext() { + if (Index >= getChildCount()) + return nullptr; + + return getChildAtIndex(Index++); +} + +void NativeEnumEnumEnumerators::reset() { Index = 0; } + +NativeTypeEnum::NativeTypeEnum(NativeSession &Session, SymIndexId Id, + TypeIndex Index, EnumRecord Record) + : NativeRawSymbol(Session, PDB_SymType::Enum, Id), Index(Index), + Record(std::move(Record)) {} + +NativeTypeEnum::NativeTypeEnum(NativeSession &Session, SymIndexId Id, + NativeTypeEnum &UnmodifiedType, + codeview::ModifierRecord Modifier) + : NativeRawSymbol(Session, PDB_SymType::Enum, Id), + UnmodifiedType(&UnmodifiedType), Modifiers(std::move(Modifier)) {} + +NativeTypeEnum::~NativeTypeEnum() {} + +void NativeTypeEnum::dump(raw_ostream &OS, int Indent, + PdbSymbolIdField ShowIdFields, + PdbSymbolIdField RecurseIdFields) const { + NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields); + + dumpSymbolField(OS, "baseType", static_cast<uint32_t>(getBuiltinType()), + Indent); + dumpSymbolIdField(OS, "lexicalParentId", 0, Indent, Session, + PdbSymbolIdField::LexicalParent, ShowIdFields, + RecurseIdFields); + dumpSymbolField(OS, "name", getName(), Indent); + dumpSymbolIdField(OS, "typeId", getTypeId(), Indent, Session, + PdbSymbolIdField::Type, ShowIdFields, RecurseIdFields); + if (Modifiers.hasValue()) + dumpSymbolIdField(OS, "unmodifiedTypeId", getUnmodifiedTypeId(), Indent, + Session, PdbSymbolIdField::UnmodifiedType, ShowIdFields, + RecurseIdFields); + dumpSymbolField(OS, "length", getLength(), Indent); + dumpSymbolField(OS, "constructor", hasConstructor(), Indent); + dumpSymbolField(OS, "constType", isConstType(), Indent); + dumpSymbolField(OS, "hasAssignmentOperator", hasAssignmentOperator(), Indent); + dumpSymbolField(OS, "hasCastOperator", hasCastOperator(), Indent); + dumpSymbolField(OS, "hasNestedTypes", hasNestedTypes(), Indent); + dumpSymbolField(OS, "overloadedOperator", hasOverloadedOperator(), Indent); + dumpSymbolField(OS, "isInterfaceUdt", isInterfaceUdt(), Indent); + dumpSymbolField(OS, "intrinsic", isIntrinsic(), Indent); + dumpSymbolField(OS, "nested", isNested(), Indent); + dumpSymbolField(OS, "packed", isPacked(), Indent); + dumpSymbolField(OS, "isRefUdt", isRefUdt(), Indent); + dumpSymbolField(OS, "scoped", isScoped(), Indent); + dumpSymbolField(OS, "unalignedType", isUnalignedType(), Indent); + dumpSymbolField(OS, "isValueUdt", isValueUdt(), Indent); + dumpSymbolField(OS, "volatileType", isVolatileType(), Indent); +} + +std::unique_ptr<IPDBEnumSymbols> +NativeTypeEnum::findChildren(PDB_SymType Type) const { + if (Type != PDB_SymType::Data) + return std::make_unique<NullEnumerator<PDBSymbol>>(); + + const NativeTypeEnum *ClassParent = nullptr; + if (!Modifiers) + ClassParent = this; + else + ClassParent = UnmodifiedType; + return std::make_unique<NativeEnumEnumEnumerators>(Session, *ClassParent); +} + +PDB_SymType NativeTypeEnum::getSymTag() const { return PDB_SymType::Enum; } + +PDB_BuiltinType NativeTypeEnum::getBuiltinType() const { + if (UnmodifiedType) + return UnmodifiedType->getBuiltinType(); + + Session.getSymbolCache().findSymbolByTypeIndex(Record->getUnderlyingType()); + + codeview::TypeIndex Underlying = Record->getUnderlyingType(); + + // This indicates a corrupt record. + if (!Underlying.isSimple() || + Underlying.getSimpleMode() != SimpleTypeMode::Direct) { + return PDB_BuiltinType::None; + } + + switch (Underlying.getSimpleKind()) { + case SimpleTypeKind::Boolean128: + case SimpleTypeKind::Boolean64: + case SimpleTypeKind::Boolean32: + case SimpleTypeKind::Boolean16: + case SimpleTypeKind::Boolean8: + return PDB_BuiltinType::Bool; + case SimpleTypeKind::NarrowCharacter: + case SimpleTypeKind::UnsignedCharacter: + case SimpleTypeKind::SignedCharacter: + return PDB_BuiltinType::Char; + case SimpleTypeKind::WideCharacter: + return PDB_BuiltinType::WCharT; + case SimpleTypeKind::Character16: + return PDB_BuiltinType::Char16; + case SimpleTypeKind::Character32: + return PDB_BuiltinType::Char32; + case SimpleTypeKind::Int128: + case SimpleTypeKind::Int128Oct: + case SimpleTypeKind::Int16: + case SimpleTypeKind::Int16Short: + case SimpleTypeKind::Int32: + case SimpleTypeKind::Int32Long: + case SimpleTypeKind::Int64: + case SimpleTypeKind::Int64Quad: + return PDB_BuiltinType::Int; + case SimpleTypeKind::UInt128: + case SimpleTypeKind::UInt128Oct: + case SimpleTypeKind::UInt16: + case SimpleTypeKind::UInt16Short: + case SimpleTypeKind::UInt32: + case SimpleTypeKind::UInt32Long: + case SimpleTypeKind::UInt64: + case SimpleTypeKind::UInt64Quad: + return PDB_BuiltinType::UInt; + case SimpleTypeKind::HResult: + return PDB_BuiltinType::HResult; + case SimpleTypeKind::Complex16: + case SimpleTypeKind::Complex32: + case SimpleTypeKind::Complex32PartialPrecision: + case SimpleTypeKind::Complex64: + case SimpleTypeKind::Complex80: + case SimpleTypeKind::Complex128: + return PDB_BuiltinType::Complex; + case SimpleTypeKind::Float16: + case SimpleTypeKind::Float32: + case SimpleTypeKind::Float32PartialPrecision: + case SimpleTypeKind::Float48: + case SimpleTypeKind::Float64: + case SimpleTypeKind::Float80: + case SimpleTypeKind::Float128: + return PDB_BuiltinType::Float; + default: + return PDB_BuiltinType::None; + } + llvm_unreachable("Unreachable"); +} + +SymIndexId NativeTypeEnum::getUnmodifiedTypeId() const { + return UnmodifiedType ? UnmodifiedType->getSymIndexId() : 0; +} + +bool NativeTypeEnum::hasConstructor() const { + if (UnmodifiedType) + return UnmodifiedType->hasConstructor(); + + return bool(Record->getOptions() & + codeview::ClassOptions::HasConstructorOrDestructor); +} + +bool NativeTypeEnum::hasAssignmentOperator() const { + if (UnmodifiedType) + return UnmodifiedType->hasAssignmentOperator(); + + return bool(Record->getOptions() & + codeview::ClassOptions::HasOverloadedAssignmentOperator); +} + +bool NativeTypeEnum::hasNestedTypes() const { + if (UnmodifiedType) + return UnmodifiedType->hasNestedTypes(); + + return bool(Record->getOptions() & + codeview::ClassOptions::ContainsNestedClass); +} + +bool NativeTypeEnum::isIntrinsic() const { + if (UnmodifiedType) + return UnmodifiedType->isIntrinsic(); + + return bool(Record->getOptions() & codeview::ClassOptions::Intrinsic); +} + +bool NativeTypeEnum::hasCastOperator() const { + if (UnmodifiedType) + return UnmodifiedType->hasCastOperator(); + + return bool(Record->getOptions() & + codeview::ClassOptions::HasConversionOperator); +} + +uint64_t NativeTypeEnum::getLength() const { + if (UnmodifiedType) + return UnmodifiedType->getLength(); + + const auto Id = Session.getSymbolCache().findSymbolByTypeIndex( + Record->getUnderlyingType()); + const auto UnderlyingType = + Session.getConcreteSymbolById<PDBSymbolTypeBuiltin>(Id); + return UnderlyingType ? UnderlyingType->getLength() : 0; +} + +std::string NativeTypeEnum::getName() const { + if (UnmodifiedType) + return UnmodifiedType->getName(); + + return Record->getName(); +} + +bool NativeTypeEnum::isNested() const { + if (UnmodifiedType) + return UnmodifiedType->isNested(); + + return bool(Record->getOptions() & codeview::ClassOptions::Nested); +} + +bool NativeTypeEnum::hasOverloadedOperator() const { + if (UnmodifiedType) + return UnmodifiedType->hasOverloadedOperator(); + + return bool(Record->getOptions() & + codeview::ClassOptions::HasOverloadedOperator); +} + +bool NativeTypeEnum::isPacked() const { + if (UnmodifiedType) + return UnmodifiedType->isPacked(); + + return bool(Record->getOptions() & codeview::ClassOptions::Packed); +} + +bool NativeTypeEnum::isScoped() const { + if (UnmodifiedType) + return UnmodifiedType->isScoped(); + + return bool(Record->getOptions() & codeview::ClassOptions::Scoped); +} + +SymIndexId NativeTypeEnum::getTypeId() const { + if (UnmodifiedType) + return UnmodifiedType->getTypeId(); + + return Session.getSymbolCache().findSymbolByTypeIndex( + Record->getUnderlyingType()); +} + +bool NativeTypeEnum::isRefUdt() const { return false; } + +bool NativeTypeEnum::isValueUdt() const { return false; } + +bool NativeTypeEnum::isInterfaceUdt() const { return false; } + +bool NativeTypeEnum::isConstType() const { + if (!Modifiers) + return false; + return ((Modifiers->getModifiers() & ModifierOptions::Const) != + ModifierOptions::None); +} + +bool NativeTypeEnum::isVolatileType() const { + if (!Modifiers) + return false; + return ((Modifiers->getModifiers() & ModifierOptions::Volatile) != + ModifierOptions::None); +} + +bool NativeTypeEnum::isUnalignedType() const { + if (!Modifiers) + return false; + return ((Modifiers->getModifiers() & ModifierOptions::Unaligned) != + ModifierOptions::None); +} + +const NativeTypeBuiltin &NativeTypeEnum::getUnderlyingBuiltinType() const { + if (UnmodifiedType) + return UnmodifiedType->getUnderlyingBuiltinType(); + + return Session.getSymbolCache().getNativeSymbolById<NativeTypeBuiltin>( + getTypeId()); +} diff --git a/llvm/lib/DebugInfo/PDB/Native/NativeTypeFunctionSig.cpp b/llvm/lib/DebugInfo/PDB/Native/NativeTypeFunctionSig.cpp new file mode 100644 index 0000000000000..f98a4c3043eb8 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/Native/NativeTypeFunctionSig.cpp @@ -0,0 +1,199 @@ +//===- NativeTypeFunctionSig.cpp - info about function signature -*- C++-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/NativeTypeFunctionSig.h" + +#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" +#include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h" +#include "llvm/DebugInfo/PDB/PDBExtras.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/TpiStream.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +namespace { +// This is kind of a silly class, hence why we keep it private to the file. +// It's only purpose is to wrap the real type record. I guess this is so that +// we can have the lexical parent point to the function instead of the global +// scope. +class NativeTypeFunctionArg : public NativeRawSymbol { +public: + NativeTypeFunctionArg(NativeSession &Session, + std::unique_ptr<PDBSymbol> RealType) + : NativeRawSymbol(Session, PDB_SymType::FunctionArg, 0), + RealType(std::move(RealType)) {} + + void dump(raw_ostream &OS, int Indent, PdbSymbolIdField ShowIdFields, + PdbSymbolIdField RecurseIdFields) const override { + NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields); + + dumpSymbolIdField(OS, "typeId", getTypeId(), Indent, Session, + PdbSymbolIdField::Type, ShowIdFields, RecurseIdFields); + } + + SymIndexId getTypeId() const override { return RealType->getSymIndexId(); } + + std::unique_ptr<PDBSymbol> RealType; +}; + +class NativeEnumFunctionArgs : public IPDBEnumChildren<PDBSymbol> { +public: + NativeEnumFunctionArgs(NativeSession &Session, + std::unique_ptr<NativeEnumTypes> TypeEnumerator) + : Session(Session), TypeEnumerator(std::move(TypeEnumerator)) {} + + uint32_t getChildCount() const override { + return TypeEnumerator->getChildCount(); + } + std::unique_ptr<PDBSymbol> getChildAtIndex(uint32_t Index) const override { + return wrap(TypeEnumerator->getChildAtIndex(Index)); + } + std::unique_ptr<PDBSymbol> getNext() override { + return wrap(TypeEnumerator->getNext()); + } + + void reset() override { TypeEnumerator->reset(); } + +private: + std::unique_ptr<PDBSymbol> wrap(std::unique_ptr<PDBSymbol> S) const { + if (!S) + return nullptr; + auto NTFA = std::make_unique<NativeTypeFunctionArg>(Session, std::move(S)); + return PDBSymbol::create(Session, std::move(NTFA)); + } + NativeSession &Session; + std::unique_ptr<NativeEnumTypes> TypeEnumerator; +}; +} // namespace + +NativeTypeFunctionSig::NativeTypeFunctionSig(NativeSession &Session, + SymIndexId Id, + codeview::TypeIndex Index, + codeview::ProcedureRecord Proc) + : NativeRawSymbol(Session, PDB_SymType::FunctionSig, Id), + Proc(std::move(Proc)), Index(Index), IsMemberFunction(false) {} + +NativeTypeFunctionSig::NativeTypeFunctionSig( + NativeSession &Session, SymIndexId Id, codeview::TypeIndex Index, + codeview::MemberFunctionRecord MemberFunc) + : NativeRawSymbol(Session, PDB_SymType::FunctionSig, Id), + MemberFunc(std::move(MemberFunc)), Index(Index), IsMemberFunction(true) {} + +void NativeTypeFunctionSig::initialize() { + if (IsMemberFunction) { + ClassParentId = + Session.getSymbolCache().findSymbolByTypeIndex(MemberFunc.ClassType); + initializeArgList(MemberFunc.ArgumentList); + } else { + initializeArgList(Proc.ArgumentList); + } +} + +NativeTypeFunctionSig::~NativeTypeFunctionSig() {} + +void NativeTypeFunctionSig::initializeArgList(codeview::TypeIndex ArgListTI) { + TpiStream &Tpi = cantFail(Session.getPDBFile().getPDBTpiStream()); + CVType CVT = Tpi.typeCollection().getType(ArgListTI); + + cantFail(TypeDeserializer::deserializeAs<ArgListRecord>(CVT, ArgList)); +} + +void NativeTypeFunctionSig::dump(raw_ostream &OS, int Indent, + PdbSymbolIdField ShowIdFields, + PdbSymbolIdField RecurseIdFields) const { + + NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields); + + dumpSymbolIdField(OS, "lexicalParentId", 0, Indent, Session, + PdbSymbolIdField::LexicalParent, ShowIdFields, + RecurseIdFields); + + dumpSymbolField(OS, "callingConvention", getCallingConvention(), Indent); + dumpSymbolField(OS, "count", getCount(), Indent); + dumpSymbolIdField(OS, "typeId", getTypeId(), Indent, Session, + PdbSymbolIdField::Type, ShowIdFields, RecurseIdFields); + if (IsMemberFunction) + dumpSymbolField(OS, "thisAdjust", getThisAdjust(), Indent); + dumpSymbolField(OS, "constructor", hasConstructor(), Indent); + dumpSymbolField(OS, "constType", isConstType(), Indent); + dumpSymbolField(OS, "isConstructorVirtualBase", isConstructorVirtualBase(), + Indent); + dumpSymbolField(OS, "isCxxReturnUdt", isCxxReturnUdt(), Indent); + dumpSymbolField(OS, "unalignedType", isUnalignedType(), Indent); + dumpSymbolField(OS, "volatileType", isVolatileType(), Indent); +} + +std::unique_ptr<IPDBEnumSymbols> +NativeTypeFunctionSig::findChildren(PDB_SymType Type) const { + if (Type != PDB_SymType::FunctionArg) + return std::make_unique<NullEnumerator<PDBSymbol>>(); + + auto NET = std::make_unique<NativeEnumTypes>(Session, + /* copy */ ArgList.ArgIndices); + return std::unique_ptr<IPDBEnumSymbols>( + new NativeEnumFunctionArgs(Session, std::move(NET))); +} + +SymIndexId NativeTypeFunctionSig::getClassParentId() const { + if (!IsMemberFunction) + return 0; + + return ClassParentId; +} + +PDB_CallingConv NativeTypeFunctionSig::getCallingConvention() const { + return IsMemberFunction ? MemberFunc.CallConv : Proc.CallConv; +} + +uint32_t NativeTypeFunctionSig::getCount() const { + return IsMemberFunction ? (1 + MemberFunc.getParameterCount()) + : Proc.getParameterCount(); +} + +SymIndexId NativeTypeFunctionSig::getTypeId() const { + TypeIndex ReturnTI = + IsMemberFunction ? MemberFunc.getReturnType() : Proc.getReturnType(); + + SymIndexId Result = Session.getSymbolCache().findSymbolByTypeIndex(ReturnTI); + return Result; +} + +int32_t NativeTypeFunctionSig::getThisAdjust() const { + return IsMemberFunction ? MemberFunc.getThisPointerAdjustment() : 0; +} + +bool NativeTypeFunctionSig::hasConstructor() const { + if (!IsMemberFunction) + return false; + + return (MemberFunc.getOptions() & FunctionOptions::Constructor) != + FunctionOptions::None; +} + +bool NativeTypeFunctionSig::isConstType() const { return false; } + +bool NativeTypeFunctionSig::isConstructorVirtualBase() const { + if (!IsMemberFunction) + return false; + + return (MemberFunc.getOptions() & + FunctionOptions::ConstructorWithVirtualBases) != + FunctionOptions::None; +} + +bool NativeTypeFunctionSig::isCxxReturnUdt() const { + FunctionOptions Options = + IsMemberFunction ? MemberFunc.getOptions() : Proc.getOptions(); + return (Options & FunctionOptions::CxxReturnUdt) != FunctionOptions::None; +} + +bool NativeTypeFunctionSig::isUnalignedType() const { return false; } + +bool NativeTypeFunctionSig::isVolatileType() const { return false; } diff --git a/llvm/lib/DebugInfo/PDB/Native/NativeTypePointer.cpp b/llvm/lib/DebugInfo/PDB/Native/NativeTypePointer.cpp new file mode 100644 index 0000000000000..32dcfc2359541 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/Native/NativeTypePointer.cpp @@ -0,0 +1,193 @@ +//===- NativeTypePointer.cpp - info about pointer type ----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/NativeTypePointer.h" + +#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" + +#include <cassert> + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +NativeTypePointer::NativeTypePointer(NativeSession &Session, SymIndexId Id, + codeview::TypeIndex TI) + : NativeRawSymbol(Session, PDB_SymType::PointerType, Id), TI(TI) { + assert(TI.isSimple()); + assert(TI.getSimpleMode() != SimpleTypeMode::Direct); +} + +NativeTypePointer::NativeTypePointer(NativeSession &Session, SymIndexId Id, + codeview::TypeIndex TI, + codeview::PointerRecord Record) + : NativeRawSymbol(Session, PDB_SymType::PointerType, Id), TI(TI), + Record(std::move(Record)) {} + +NativeTypePointer::~NativeTypePointer() {} + +void NativeTypePointer::dump(raw_ostream &OS, int Indent, + PdbSymbolIdField ShowIdFields, + PdbSymbolIdField RecurseIdFields) const { + NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields); + + if (isMemberPointer()) { + dumpSymbolIdField(OS, "classParentId", getClassParentId(), Indent, Session, + PdbSymbolIdField::ClassParent, ShowIdFields, + RecurseIdFields); + } + dumpSymbolIdField(OS, "lexicalParentId", 0, Indent, Session, + PdbSymbolIdField::LexicalParent, ShowIdFields, + RecurseIdFields); + dumpSymbolIdField(OS, "typeId", getTypeId(), Indent, Session, + PdbSymbolIdField::Type, ShowIdFields, RecurseIdFields); + dumpSymbolField(OS, "length", getLength(), Indent); + dumpSymbolField(OS, "constType", isConstType(), Indent); + dumpSymbolField(OS, "isPointerToDataMember", isPointerToDataMember(), Indent); + dumpSymbolField(OS, "isPointerToMemberFunction", isPointerToMemberFunction(), + Indent); + dumpSymbolField(OS, "RValueReference", isRValueReference(), Indent); + dumpSymbolField(OS, "reference", isReference(), Indent); + dumpSymbolField(OS, "restrictedType", isRestrictedType(), Indent); + if (isMemberPointer()) { + if (isSingleInheritance()) + dumpSymbolField(OS, "isSingleInheritance", 1, Indent); + else if (isMultipleInheritance()) + dumpSymbolField(OS, "isMultipleInheritance", 1, Indent); + else if (isVirtualInheritance()) + dumpSymbolField(OS, "isVirtualInheritance", 1, Indent); + } + dumpSymbolField(OS, "unalignedType", isUnalignedType(), Indent); + dumpSymbolField(OS, "volatileType", isVolatileType(), Indent); +} + +SymIndexId NativeTypePointer::getClassParentId() const { + if (!isMemberPointer()) + return 0; + + assert(Record); + const MemberPointerInfo &MPI = Record->getMemberInfo(); + return Session.getSymbolCache().findSymbolByTypeIndex(MPI.ContainingType); +} + +uint64_t NativeTypePointer::getLength() const { + if (Record) + return Record->getSize(); + + switch (TI.getSimpleMode()) { + case SimpleTypeMode::NearPointer: + case SimpleTypeMode::FarPointer: + case SimpleTypeMode::HugePointer: + return 2; + case SimpleTypeMode::NearPointer32: + case SimpleTypeMode::FarPointer32: + return 4; + case SimpleTypeMode::NearPointer64: + return 8; + case SimpleTypeMode::NearPointer128: + return 16; + default: + assert(false && "invalid simple type mode!"); + } + return 0; +} + +SymIndexId NativeTypePointer::getTypeId() const { + // This is the pointee SymIndexId. + TypeIndex Referent = Record ? Record->ReferentType : TI.makeDirect(); + + return Session.getSymbolCache().findSymbolByTypeIndex(Referent); +} + +bool NativeTypePointer::isReference() const { + if (!Record) + return false; + return Record->getMode() == PointerMode::LValueReference; +} + +bool NativeTypePointer::isRValueReference() const { + if (!Record) + return false; + return Record->getMode() == PointerMode::RValueReference; +} + +bool NativeTypePointer::isPointerToDataMember() const { + if (!Record) + return false; + return Record->getMode() == PointerMode::PointerToDataMember; +} + +bool NativeTypePointer::isPointerToMemberFunction() const { + if (!Record) + return false; + return Record->getMode() == PointerMode::PointerToMemberFunction; +} + +bool NativeTypePointer::isConstType() const { + if (!Record) + return false; + return (Record->getOptions() & PointerOptions::Const) != PointerOptions::None; +} + +bool NativeTypePointer::isRestrictedType() const { + if (!Record) + return false; + return (Record->getOptions() & PointerOptions::Restrict) != + PointerOptions::None; +} + +bool NativeTypePointer::isVolatileType() const { + if (!Record) + return false; + return (Record->getOptions() & PointerOptions::Volatile) != + PointerOptions::None; +} + +bool NativeTypePointer::isUnalignedType() const { + if (!Record) + return false; + return (Record->getOptions() & PointerOptions::Unaligned) != + PointerOptions::None; +} + +static inline bool isInheritanceKind(const MemberPointerInfo &MPI, + PointerToMemberRepresentation P1, + PointerToMemberRepresentation P2) { + return (MPI.getRepresentation() == P1 || MPI.getRepresentation() == P2); +} + +bool NativeTypePointer::isSingleInheritance() const { + if (!isMemberPointer()) + return false; + return isInheritanceKind( + Record->getMemberInfo(), + PointerToMemberRepresentation::SingleInheritanceData, + PointerToMemberRepresentation::SingleInheritanceFunction); +} + +bool NativeTypePointer::isMultipleInheritance() const { + if (!isMemberPointer()) + return false; + return isInheritanceKind( + Record->getMemberInfo(), + PointerToMemberRepresentation::MultipleInheritanceData, + PointerToMemberRepresentation::MultipleInheritanceFunction); +} + +bool NativeTypePointer::isVirtualInheritance() const { + if (!isMemberPointer()) + return false; + return isInheritanceKind( + Record->getMemberInfo(), + PointerToMemberRepresentation::VirtualInheritanceData, + PointerToMemberRepresentation::VirtualInheritanceFunction); +} + +bool NativeTypePointer::isMemberPointer() const { + return isPointerToDataMember() || isPointerToMemberFunction(); +} diff --git a/llvm/lib/DebugInfo/PDB/Native/NativeTypeTypedef.cpp b/llvm/lib/DebugInfo/PDB/Native/NativeTypeTypedef.cpp new file mode 100644 index 0000000000000..60b3732822670 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/Native/NativeTypeTypedef.cpp @@ -0,0 +1,27 @@ +#include "llvm/DebugInfo/PDB/Native/NativeTypeTypedef.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +NativeTypeTypedef::NativeTypeTypedef(NativeSession &Session, SymIndexId Id, + codeview::UDTSym Typedef) + : NativeRawSymbol(Session, PDB_SymType::Typedef, Id), + Record(std::move(Typedef)) {} + +NativeTypeTypedef::~NativeTypeTypedef() {} + +void NativeTypeTypedef::dump(raw_ostream &OS, int Indent, + PdbSymbolIdField ShowIdFields, + PdbSymbolIdField RecurseIdFields) const { + NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields); + dumpSymbolField(OS, "name", getName(), Indent); + dumpSymbolIdField(OS, "typeId", getTypeId(), Indent, Session, + PdbSymbolIdField::Type, ShowIdFields, RecurseIdFields); +} + +std::string NativeTypeTypedef::getName() const { return Record.Name; } + +SymIndexId NativeTypeTypedef::getTypeId() const { + return Session.getSymbolCache().findSymbolByTypeIndex(Record.Type); +} diff --git a/llvm/lib/DebugInfo/PDB/Native/NativeTypeUDT.cpp b/llvm/lib/DebugInfo/PDB/Native/NativeTypeUDT.cpp new file mode 100644 index 0000000000000..be67846c0b246 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/Native/NativeTypeUDT.cpp @@ -0,0 +1,220 @@ +//===- NativeTypeUDT.cpp - info about class/struct type ---------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/NativeTypeUDT.h" + +#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" + +#include <cassert> + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +NativeTypeUDT::NativeTypeUDT(NativeSession &Session, SymIndexId Id, + codeview::TypeIndex TI, codeview::ClassRecord CR) + : NativeRawSymbol(Session, PDB_SymType::UDT, Id), Index(TI), + Class(std::move(CR)), Tag(Class.getPointer()) {} + +NativeTypeUDT::NativeTypeUDT(NativeSession &Session, SymIndexId Id, + codeview::TypeIndex TI, codeview::UnionRecord UR) + : NativeRawSymbol(Session, PDB_SymType::UDT, Id), Index(TI), + Union(std::move(UR)), Tag(Union.getPointer()) {} + +NativeTypeUDT::NativeTypeUDT(NativeSession &Session, SymIndexId Id, + NativeTypeUDT &UnmodifiedType, + codeview::ModifierRecord Modifier) + : NativeRawSymbol(Session, PDB_SymType::UDT, Id), + UnmodifiedType(&UnmodifiedType), Modifiers(std::move(Modifier)) {} + +NativeTypeUDT::~NativeTypeUDT() {} + +void NativeTypeUDT::dump(raw_ostream &OS, int Indent, + PdbSymbolIdField ShowIdFields, + PdbSymbolIdField RecurseIdFields) const { + + NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields); + + dumpSymbolField(OS, "name", getName(), Indent); + dumpSymbolIdField(OS, "lexicalParentId", 0, Indent, Session, + PdbSymbolIdField::LexicalParent, ShowIdFields, + RecurseIdFields); + if (Modifiers.hasValue()) + dumpSymbolIdField(OS, "unmodifiedTypeId", getUnmodifiedTypeId(), Indent, + Session, PdbSymbolIdField::UnmodifiedType, ShowIdFields, + RecurseIdFields); + if (getUdtKind() != PDB_UdtType::Union) + dumpSymbolField(OS, "virtualTableShapeId", getVirtualTableShapeId(), + Indent); + dumpSymbolField(OS, "length", getLength(), Indent); + dumpSymbolField(OS, "udtKind", getUdtKind(), Indent); + dumpSymbolField(OS, "constructor", hasConstructor(), Indent); + dumpSymbolField(OS, "constType", isConstType(), Indent); + dumpSymbolField(OS, "hasAssignmentOperator", hasAssignmentOperator(), Indent); + dumpSymbolField(OS, "hasCastOperator", hasCastOperator(), Indent); + dumpSymbolField(OS, "hasNestedTypes", hasNestedTypes(), Indent); + dumpSymbolField(OS, "overloadedOperator", hasOverloadedOperator(), Indent); + dumpSymbolField(OS, "isInterfaceUdt", isInterfaceUdt(), Indent); + dumpSymbolField(OS, "intrinsic", isIntrinsic(), Indent); + dumpSymbolField(OS, "nested", isNested(), Indent); + dumpSymbolField(OS, "packed", isPacked(), Indent); + dumpSymbolField(OS, "isRefUdt", isRefUdt(), Indent); + dumpSymbolField(OS, "scoped", isScoped(), Indent); + dumpSymbolField(OS, "unalignedType", isUnalignedType(), Indent); + dumpSymbolField(OS, "isValueUdt", isValueUdt(), Indent); + dumpSymbolField(OS, "volatileType", isVolatileType(), Indent); +} + +std::string NativeTypeUDT::getName() const { + if (UnmodifiedType) + return UnmodifiedType->getName(); + + return Tag->getName(); +} + +SymIndexId NativeTypeUDT::getLexicalParentId() const { return 0; } + +SymIndexId NativeTypeUDT::getUnmodifiedTypeId() const { + if (UnmodifiedType) + return UnmodifiedType->getSymIndexId(); + + return 0; +} + +SymIndexId NativeTypeUDT::getVirtualTableShapeId() const { + if (UnmodifiedType) + return UnmodifiedType->getVirtualTableShapeId(); + + if (Class) + return Session.getSymbolCache().findSymbolByTypeIndex(Class->VTableShape); + + return 0; +} + +uint64_t NativeTypeUDT::getLength() const { + if (UnmodifiedType) + return UnmodifiedType->getLength(); + + if (Class) + return Class->getSize(); + + return Union->getSize(); +} + +PDB_UdtType NativeTypeUDT::getUdtKind() const { + if (UnmodifiedType) + return UnmodifiedType->getUdtKind(); + + switch (Tag->Kind) { + case TypeRecordKind::Class: + return PDB_UdtType::Class; + case TypeRecordKind::Union: + return PDB_UdtType::Union; + case TypeRecordKind::Struct: + return PDB_UdtType::Struct; + case TypeRecordKind::Interface: + return PDB_UdtType::Interface; + default: + llvm_unreachable("Unexected udt kind"); + } +} + +bool NativeTypeUDT::hasConstructor() const { + if (UnmodifiedType) + return UnmodifiedType->hasConstructor(); + + return (Tag->Options & ClassOptions::HasConstructorOrDestructor) != + ClassOptions::None; +} + +bool NativeTypeUDT::isConstType() const { + if (!Modifiers) + return false; + return (Modifiers->Modifiers & ModifierOptions::Const) != + ModifierOptions::None; +} + +bool NativeTypeUDT::hasAssignmentOperator() const { + if (UnmodifiedType) + return UnmodifiedType->hasAssignmentOperator(); + + return (Tag->Options & ClassOptions::HasOverloadedAssignmentOperator) != + ClassOptions::None; +} + +bool NativeTypeUDT::hasCastOperator() const { + if (UnmodifiedType) + return UnmodifiedType->hasCastOperator(); + + return (Tag->Options & ClassOptions::HasConversionOperator) != + ClassOptions::None; +} + +bool NativeTypeUDT::hasNestedTypes() const { + if (UnmodifiedType) + return UnmodifiedType->hasNestedTypes(); + + return (Tag->Options & ClassOptions::ContainsNestedClass) != + ClassOptions::None; +} + +bool NativeTypeUDT::hasOverloadedOperator() const { + if (UnmodifiedType) + return UnmodifiedType->hasOverloadedOperator(); + + return (Tag->Options & ClassOptions::HasOverloadedOperator) != + ClassOptions::None; +} + +bool NativeTypeUDT::isInterfaceUdt() const { return false; } + +bool NativeTypeUDT::isIntrinsic() const { + if (UnmodifiedType) + return UnmodifiedType->isIntrinsic(); + + return (Tag->Options & ClassOptions::Intrinsic) != ClassOptions::None; +} + +bool NativeTypeUDT::isNested() const { + if (UnmodifiedType) + return UnmodifiedType->isNested(); + + return (Tag->Options & ClassOptions::Nested) != ClassOptions::None; +} + +bool NativeTypeUDT::isPacked() const { + if (UnmodifiedType) + return UnmodifiedType->isPacked(); + + return (Tag->Options & ClassOptions::Packed) != ClassOptions::None; +} + +bool NativeTypeUDT::isRefUdt() const { return false; } + +bool NativeTypeUDT::isScoped() const { + if (UnmodifiedType) + return UnmodifiedType->isScoped(); + + return (Tag->Options & ClassOptions::Scoped) != ClassOptions::None; +} + +bool NativeTypeUDT::isValueUdt() const { return false; } + +bool NativeTypeUDT::isUnalignedType() const { + if (!Modifiers) + return false; + return (Modifiers->Modifiers & ModifierOptions::Unaligned) != + ModifierOptions::None; +} + +bool NativeTypeUDT::isVolatileType() const { + if (!Modifiers) + return false; + return (Modifiers->Modifiers & ModifierOptions::Volatile) != + ModifierOptions::None; +} diff --git a/llvm/lib/DebugInfo/PDB/Native/NativeTypeVTShape.cpp b/llvm/lib/DebugInfo/PDB/Native/NativeTypeVTShape.cpp new file mode 100644 index 0000000000000..837fe19ec88c0 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/Native/NativeTypeVTShape.cpp @@ -0,0 +1,35 @@ +#include "llvm/DebugInfo/PDB/Native/NativeTypeVTShape.h" + +using namespace llvm; +using namespace llvm::pdb; + +// Create a pointer record for a non-simple type. +NativeTypeVTShape::NativeTypeVTShape(NativeSession &Session, SymIndexId Id, + codeview::TypeIndex TI, + codeview::VFTableShapeRecord SR) + : NativeRawSymbol(Session, PDB_SymType::VTableShape, Id), TI(TI), + Record(std::move(SR)) {} + +NativeTypeVTShape::~NativeTypeVTShape() {} + +void NativeTypeVTShape::dump(raw_ostream &OS, int Indent, + PdbSymbolIdField ShowIdFields, + PdbSymbolIdField RecurseIdFields) const { + NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields); + + dumpSymbolIdField(OS, "lexicalParentId", 0, Indent, Session, + PdbSymbolIdField::LexicalParent, ShowIdFields, + RecurseIdFields); + dumpSymbolField(OS, "count", getCount(), Indent); + dumpSymbolField(OS, "constType", isConstType(), Indent); + dumpSymbolField(OS, "unalignedType", isUnalignedType(), Indent); + dumpSymbolField(OS, "volatileType", isVolatileType(), Indent); +} + +bool NativeTypeVTShape::isConstType() const { return false; } + +bool NativeTypeVTShape::isVolatileType() const { return false; } + +bool NativeTypeVTShape::isUnalignedType() const { return false; } + +uint32_t NativeTypeVTShape::getCount() const { return Record.Slots.size(); } diff --git a/llvm/lib/DebugInfo/PDB/Native/PDBFile.cpp b/llvm/lib/DebugInfo/PDB/Native/PDBFile.cpp new file mode 100644 index 0000000000000..9ac226b89139b --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/Native/PDBFile.cpp @@ -0,0 +1,507 @@ +//===- PDBFile.cpp - Low level interface to a PDB file ----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/DebugInfo/MSF/MSFCommon.h" +#include "llvm/DebugInfo/MSF/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Native/DbiStream.h" +#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h" +#include "llvm/DebugInfo/PDB/Native/InfoStream.h" +#include "llvm/DebugInfo/PDB/Native/InjectedSourceStream.h" +#include "llvm/DebugInfo/PDB/Native/PDBStringTable.h" +#include "llvm/DebugInfo/PDB/Native/PublicsStream.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/DebugInfo/PDB/Native/SymbolStream.h" +#include "llvm/DebugInfo/PDB/Native/TpiStream.h" +#include "llvm/Support/BinaryStream.h" +#include "llvm/Support/BinaryStreamArray.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/Path.h" +#include <algorithm> +#include <cassert> +#include <cstdint> + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::msf; +using namespace llvm::pdb; + +namespace { +typedef FixedStreamArray<support::ulittle32_t> ulittle_array; +} // end anonymous namespace + +PDBFile::PDBFile(StringRef Path, std::unique_ptr<BinaryStream> PdbFileBuffer, + BumpPtrAllocator &Allocator) + : FilePath(Path), Allocator(Allocator), Buffer(std::move(PdbFileBuffer)) {} + +PDBFile::~PDBFile() = default; + +StringRef PDBFile::getFilePath() const { return FilePath; } + +StringRef PDBFile::getFileDirectory() const { + return sys::path::parent_path(FilePath); +} + +uint32_t PDBFile::getBlockSize() const { return ContainerLayout.SB->BlockSize; } + +uint32_t PDBFile::getFreeBlockMapBlock() const { + return ContainerLayout.SB->FreeBlockMapBlock; +} + +uint32_t PDBFile::getBlockCount() const { + return ContainerLayout.SB->NumBlocks; +} + +uint32_t PDBFile::getNumDirectoryBytes() const { + return ContainerLayout.SB->NumDirectoryBytes; +} + +uint32_t PDBFile::getBlockMapIndex() const { + return ContainerLayout.SB->BlockMapAddr; +} + +uint32_t PDBFile::getUnknown1() const { return ContainerLayout.SB->Unknown1; } + +uint32_t PDBFile::getNumDirectoryBlocks() const { + return msf::bytesToBlocks(ContainerLayout.SB->NumDirectoryBytes, + ContainerLayout.SB->BlockSize); +} + +uint64_t PDBFile::getBlockMapOffset() const { + return (uint64_t)ContainerLayout.SB->BlockMapAddr * + ContainerLayout.SB->BlockSize; +} + +uint32_t PDBFile::getNumStreams() const { + return ContainerLayout.StreamSizes.size(); +} + +uint32_t PDBFile::getMaxStreamSize() const { + return *std::max_element(ContainerLayout.StreamSizes.begin(), + ContainerLayout.StreamSizes.end()); +} + +uint32_t PDBFile::getStreamByteSize(uint32_t StreamIndex) const { + return ContainerLayout.StreamSizes[StreamIndex]; +} + +ArrayRef<support::ulittle32_t> +PDBFile::getStreamBlockList(uint32_t StreamIndex) const { + return ContainerLayout.StreamMap[StreamIndex]; +} + +uint32_t PDBFile::getFileSize() const { return Buffer->getLength(); } + +Expected<ArrayRef<uint8_t>> PDBFile::getBlockData(uint32_t BlockIndex, + uint32_t NumBytes) const { + uint64_t StreamBlockOffset = msf::blockToOffset(BlockIndex, getBlockSize()); + + ArrayRef<uint8_t> Result; + if (auto EC = Buffer->readBytes(StreamBlockOffset, NumBytes, Result)) + return std::move(EC); + return Result; +} + +Error PDBFile::setBlockData(uint32_t BlockIndex, uint32_t Offset, + ArrayRef<uint8_t> Data) const { + return make_error<RawError>(raw_error_code::not_writable, + "PDBFile is immutable"); +} + +Error PDBFile::parseFileHeaders() { + BinaryStreamReader Reader(*Buffer); + + // Initialize SB. + const msf::SuperBlock *SB = nullptr; + if (auto EC = Reader.readObject(SB)) { + consumeError(std::move(EC)); + return make_error<RawError>(raw_error_code::corrupt_file, + "MSF superblock is missing"); + } + + if (auto EC = msf::validateSuperBlock(*SB)) + return EC; + + if (Buffer->getLength() % SB->BlockSize != 0) + return make_error<RawError>(raw_error_code::corrupt_file, + "File size is not a multiple of block size"); + ContainerLayout.SB = SB; + + // Initialize Free Page Map. + ContainerLayout.FreePageMap.resize(SB->NumBlocks); + // The Fpm exists either at block 1 or block 2 of the MSF. However, this + // allows for a maximum of getBlockSize() * 8 blocks bits in the Fpm, and + // thusly an equal number of total blocks in the file. For a block size + // of 4KiB (very common), this would yield 32KiB total blocks in file, for a + // maximum file size of 32KiB * 4KiB = 128MiB. Obviously this won't do, so + // the Fpm is split across the file at `getBlockSize()` intervals. As a + // result, every block whose index is of the form |{1,2} + getBlockSize() * k| + // for any non-negative integer k is an Fpm block. In theory, we only really + // need to reserve blocks of the form |{1,2} + getBlockSize() * 8 * k|, but + // current versions of the MSF format already expect the Fpm to be arranged + // at getBlockSize() intervals, so we have to be compatible. + // See the function fpmPn() for more information: + // https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/msf/msf.cpp#L489 + auto FpmStream = + MappedBlockStream::createFpmStream(ContainerLayout, *Buffer, Allocator); + BinaryStreamReader FpmReader(*FpmStream); + ArrayRef<uint8_t> FpmBytes; + if (auto EC = FpmReader.readBytes(FpmBytes, FpmReader.bytesRemaining())) + return EC; + uint32_t BlocksRemaining = getBlockCount(); + uint32_t BI = 0; + for (auto Byte : FpmBytes) { + uint32_t BlocksThisByte = std::min(BlocksRemaining, 8U); + for (uint32_t I = 0; I < BlocksThisByte; ++I) { + if (Byte & (1 << I)) + ContainerLayout.FreePageMap[BI] = true; + --BlocksRemaining; + ++BI; + } + } + + Reader.setOffset(getBlockMapOffset()); + if (auto EC = Reader.readArray(ContainerLayout.DirectoryBlocks, + getNumDirectoryBlocks())) + return EC; + + return Error::success(); +} + +Error PDBFile::parseStreamData() { + assert(ContainerLayout.SB); + if (DirectoryStream) + return Error::success(); + + uint32_t NumStreams = 0; + + // Normally you can't use a MappedBlockStream without having fully parsed the + // PDB file, because it accesses the directory and various other things, which + // is exactly what we are attempting to parse. By specifying a custom + // subclass of IPDBStreamData which only accesses the fields that have already + // been parsed, we can avoid this and reuse MappedBlockStream. + auto DS = MappedBlockStream::createDirectoryStream(ContainerLayout, *Buffer, + Allocator); + BinaryStreamReader Reader(*DS); + if (auto EC = Reader.readInteger(NumStreams)) + return EC; + + if (auto EC = Reader.readArray(ContainerLayout.StreamSizes, NumStreams)) + return EC; + for (uint32_t I = 0; I < NumStreams; ++I) { + uint32_t StreamSize = getStreamByteSize(I); + // FIXME: What does StreamSize ~0U mean? + uint64_t NumExpectedStreamBlocks = + StreamSize == UINT32_MAX + ? 0 + : msf::bytesToBlocks(StreamSize, ContainerLayout.SB->BlockSize); + + // For convenience, we store the block array contiguously. This is because + // if someone calls setStreamMap(), it is more convenient to be able to call + // it with an ArrayRef instead of setting up a StreamRef. Since the + // DirectoryStream is cached in the class and thus lives for the life of the + // class, we can be guaranteed that readArray() will return a stable + // reference, even if it has to allocate from its internal pool. + ArrayRef<support::ulittle32_t> Blocks; + if (auto EC = Reader.readArray(Blocks, NumExpectedStreamBlocks)) + return EC; + for (uint32_t Block : Blocks) { + uint64_t BlockEndOffset = + (uint64_t)(Block + 1) * ContainerLayout.SB->BlockSize; + if (BlockEndOffset > getFileSize()) + return make_error<RawError>(raw_error_code::corrupt_file, + "Stream block map is corrupt."); + } + ContainerLayout.StreamMap.push_back(Blocks); + } + + // We should have read exactly SB->NumDirectoryBytes bytes. + assert(Reader.bytesRemaining() == 0); + DirectoryStream = std::move(DS); + return Error::success(); +} + +ArrayRef<support::ulittle32_t> PDBFile::getDirectoryBlockArray() const { + return ContainerLayout.DirectoryBlocks; +} + +std::unique_ptr<MappedBlockStream> +PDBFile::createIndexedStream(uint16_t SN) const { + if (SN == kInvalidStreamIndex) + return nullptr; + return MappedBlockStream::createIndexedStream(ContainerLayout, *Buffer, SN, + Allocator); +} + +MSFStreamLayout PDBFile::getStreamLayout(uint32_t StreamIdx) const { + MSFStreamLayout Result; + auto Blocks = getStreamBlockList(StreamIdx); + Result.Blocks.assign(Blocks.begin(), Blocks.end()); + Result.Length = getStreamByteSize(StreamIdx); + return Result; +} + +msf::MSFStreamLayout PDBFile::getFpmStreamLayout() const { + return msf::getFpmStreamLayout(ContainerLayout); +} + +Expected<GlobalsStream &> PDBFile::getPDBGlobalsStream() { + if (!Globals) { + auto DbiS = getPDBDbiStream(); + if (!DbiS) + return DbiS.takeError(); + + auto GlobalS = + safelyCreateIndexedStream(DbiS->getGlobalSymbolStreamIndex()); + if (!GlobalS) + return GlobalS.takeError(); + auto TempGlobals = std::make_unique<GlobalsStream>(std::move(*GlobalS)); + if (auto EC = TempGlobals->reload()) + return std::move(EC); + Globals = std::move(TempGlobals); + } + return *Globals; +} + +Expected<InfoStream &> PDBFile::getPDBInfoStream() { + if (!Info) { + auto InfoS = safelyCreateIndexedStream(StreamPDB); + if (!InfoS) + return InfoS.takeError(); + auto TempInfo = std::make_unique<InfoStream>(std::move(*InfoS)); + if (auto EC = TempInfo->reload()) + return std::move(EC); + Info = std::move(TempInfo); + } + return *Info; +} + +Expected<DbiStream &> PDBFile::getPDBDbiStream() { + if (!Dbi) { + auto DbiS = safelyCreateIndexedStream(StreamDBI); + if (!DbiS) + return DbiS.takeError(); + auto TempDbi = std::make_unique<DbiStream>(std::move(*DbiS)); + if (auto EC = TempDbi->reload(this)) + return std::move(EC); + Dbi = std::move(TempDbi); + } + return *Dbi; +} + +Expected<TpiStream &> PDBFile::getPDBTpiStream() { + if (!Tpi) { + auto TpiS = safelyCreateIndexedStream(StreamTPI); + if (!TpiS) + return TpiS.takeError(); + auto TempTpi = std::make_unique<TpiStream>(*this, std::move(*TpiS)); + if (auto EC = TempTpi->reload()) + return std::move(EC); + Tpi = std::move(TempTpi); + } + return *Tpi; +} + +Expected<TpiStream &> PDBFile::getPDBIpiStream() { + if (!Ipi) { + if (!hasPDBIpiStream()) + return make_error<RawError>(raw_error_code::no_stream); + + auto IpiS = safelyCreateIndexedStream(StreamIPI); + if (!IpiS) + return IpiS.takeError(); + auto TempIpi = std::make_unique<TpiStream>(*this, std::move(*IpiS)); + if (auto EC = TempIpi->reload()) + return std::move(EC); + Ipi = std::move(TempIpi); + } + return *Ipi; +} + +Expected<PublicsStream &> PDBFile::getPDBPublicsStream() { + if (!Publics) { + auto DbiS = getPDBDbiStream(); + if (!DbiS) + return DbiS.takeError(); + + auto PublicS = + safelyCreateIndexedStream(DbiS->getPublicSymbolStreamIndex()); + if (!PublicS) + return PublicS.takeError(); + auto TempPublics = std::make_unique<PublicsStream>(std::move(*PublicS)); + if (auto EC = TempPublics->reload()) + return std::move(EC); + Publics = std::move(TempPublics); + } + return *Publics; +} + +Expected<SymbolStream &> PDBFile::getPDBSymbolStream() { + if (!Symbols) { + auto DbiS = getPDBDbiStream(); + if (!DbiS) + return DbiS.takeError(); + + uint32_t SymbolStreamNum = DbiS->getSymRecordStreamIndex(); + auto SymbolS = safelyCreateIndexedStream(SymbolStreamNum); + if (!SymbolS) + return SymbolS.takeError(); + + auto TempSymbols = std::make_unique<SymbolStream>(std::move(*SymbolS)); + if (auto EC = TempSymbols->reload()) + return std::move(EC); + Symbols = std::move(TempSymbols); + } + return *Symbols; +} + +Expected<PDBStringTable &> PDBFile::getStringTable() { + if (!Strings) { + auto NS = safelyCreateNamedStream("/names"); + if (!NS) + return NS.takeError(); + + auto N = std::make_unique<PDBStringTable>(); + BinaryStreamReader Reader(**NS); + if (auto EC = N->reload(Reader)) + return std::move(EC); + assert(Reader.bytesRemaining() == 0); + StringTableStream = std::move(*NS); + Strings = std::move(N); + } + return *Strings; +} + +Expected<InjectedSourceStream &> PDBFile::getInjectedSourceStream() { + if (!InjectedSources) { + auto IJS = safelyCreateNamedStream("/src/headerblock"); + if (!IJS) + return IJS.takeError(); + + auto Strings = getStringTable(); + if (!Strings) + return Strings.takeError(); + + auto IJ = std::make_unique<InjectedSourceStream>(std::move(*IJS)); + if (auto EC = IJ->reload(*Strings)) + return std::move(EC); + InjectedSources = std::move(IJ); + } + return *InjectedSources; +} + +uint32_t PDBFile::getPointerSize() { + auto DbiS = getPDBDbiStream(); + if (!DbiS) + return 0; + PDB_Machine Machine = DbiS->getMachineType(); + if (Machine == PDB_Machine::Amd64) + return 8; + return 4; +} + +bool PDBFile::hasPDBDbiStream() const { + return StreamDBI < getNumStreams() && getStreamByteSize(StreamDBI) > 0; +} + +bool PDBFile::hasPDBGlobalsStream() { + auto DbiS = getPDBDbiStream(); + if (!DbiS) { + consumeError(DbiS.takeError()); + return false; + } + + return DbiS->getGlobalSymbolStreamIndex() < getNumStreams(); +} + +bool PDBFile::hasPDBInfoStream() const { return StreamPDB < getNumStreams(); } + +bool PDBFile::hasPDBIpiStream() const { + if (!hasPDBInfoStream()) + return false; + + if (StreamIPI >= getNumStreams()) + return false; + + auto &InfoStream = cantFail(const_cast<PDBFile *>(this)->getPDBInfoStream()); + return InfoStream.containsIdStream(); +} + +bool PDBFile::hasPDBPublicsStream() { + auto DbiS = getPDBDbiStream(); + if (!DbiS) { + consumeError(DbiS.takeError()); + return false; + } + return DbiS->getPublicSymbolStreamIndex() < getNumStreams(); +} + +bool PDBFile::hasPDBSymbolStream() { + auto DbiS = getPDBDbiStream(); + if (!DbiS) + return false; + return DbiS->getSymRecordStreamIndex() < getNumStreams(); +} + +bool PDBFile::hasPDBTpiStream() const { return StreamTPI < getNumStreams(); } + +bool PDBFile::hasPDBStringTable() { + auto IS = getPDBInfoStream(); + if (!IS) + return false; + Expected<uint32_t> ExpectedNSI = IS->getNamedStreamIndex("/names"); + if (!ExpectedNSI) { + consumeError(ExpectedNSI.takeError()); + return false; + } + assert(*ExpectedNSI < getNumStreams()); + return true; +} + +bool PDBFile::hasPDBInjectedSourceStream() { + auto IS = getPDBInfoStream(); + if (!IS) + return false; + Expected<uint32_t> ExpectedNSI = IS->getNamedStreamIndex("/src/headerblock"); + if (!ExpectedNSI) { + consumeError(ExpectedNSI.takeError()); + return false; + } + assert(*ExpectedNSI < getNumStreams()); + return true; +} + +/// Wrapper around MappedBlockStream::createIndexedStream() that checks if a +/// stream with that index actually exists. If it does not, the return value +/// will have an MSFError with code msf_error_code::no_stream. Else, the return +/// value will contain the stream returned by createIndexedStream(). +Expected<std::unique_ptr<MappedBlockStream>> +PDBFile::safelyCreateIndexedStream(uint32_t StreamIndex) const { + if (StreamIndex >= getNumStreams()) + // This rejects kInvalidStreamIndex with an error as well. + return make_error<RawError>(raw_error_code::no_stream); + return createIndexedStream(StreamIndex); +} + +Expected<std::unique_ptr<MappedBlockStream>> +PDBFile::safelyCreateNamedStream(StringRef Name) { + auto IS = getPDBInfoStream(); + if (!IS) + return IS.takeError(); + + Expected<uint32_t> ExpectedNSI = IS->getNamedStreamIndex(Name); + if (!ExpectedNSI) + return ExpectedNSI.takeError(); + uint32_t NameStreamIndex = *ExpectedNSI; + + return safelyCreateIndexedStream(NameStreamIndex); +} diff --git a/llvm/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp b/llvm/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp new file mode 100644 index 0000000000000..aa32887243900 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp @@ -0,0 +1,357 @@ +//===- PDBFileBuilder.cpp - PDB File Creation -------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h" + +#include "llvm/ADT/BitVector.h" + +#include "llvm/DebugInfo/MSF/MSFBuilder.h" +#include "llvm/DebugInfo/PDB/Native/DbiStream.h" +#include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h" +#include "llvm/DebugInfo/PDB/Native/GSIStreamBuilder.h" +#include "llvm/DebugInfo/PDB/Native/InfoStream.h" +#include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h" +#include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/DebugInfo/PDB/Native/TpiStream.h" +#include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h" +#include "llvm/Support/BinaryStream.h" +#include "llvm/Support/BinaryStreamWriter.h" +#include "llvm/Support/CRC.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/xxhash.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::msf; +using namespace llvm::pdb; +using namespace llvm::support; + +PDBFileBuilder::PDBFileBuilder(BumpPtrAllocator &Allocator) + : Allocator(Allocator), InjectedSourceHashTraits(Strings), + InjectedSourceTable(2) {} + +PDBFileBuilder::~PDBFileBuilder() {} + +Error PDBFileBuilder::initialize(uint32_t BlockSize) { + auto ExpectedMsf = MSFBuilder::create(Allocator, BlockSize); + if (!ExpectedMsf) + return ExpectedMsf.takeError(); + Msf = std::make_unique<MSFBuilder>(std::move(*ExpectedMsf)); + return Error::success(); +} + +MSFBuilder &PDBFileBuilder::getMsfBuilder() { return *Msf; } + +InfoStreamBuilder &PDBFileBuilder::getInfoBuilder() { + if (!Info) + Info = std::make_unique<InfoStreamBuilder>(*Msf, NamedStreams); + return *Info; +} + +DbiStreamBuilder &PDBFileBuilder::getDbiBuilder() { + if (!Dbi) + Dbi = std::make_unique<DbiStreamBuilder>(*Msf); + return *Dbi; +} + +TpiStreamBuilder &PDBFileBuilder::getTpiBuilder() { + if (!Tpi) + Tpi = std::make_unique<TpiStreamBuilder>(*Msf, StreamTPI); + return *Tpi; +} + +TpiStreamBuilder &PDBFileBuilder::getIpiBuilder() { + if (!Ipi) + Ipi = std::make_unique<TpiStreamBuilder>(*Msf, StreamIPI); + return *Ipi; +} + +PDBStringTableBuilder &PDBFileBuilder::getStringTableBuilder() { + return Strings; +} + +GSIStreamBuilder &PDBFileBuilder::getGsiBuilder() { + if (!Gsi) + Gsi = std::make_unique<GSIStreamBuilder>(*Msf); + return *Gsi; +} + +Expected<uint32_t> PDBFileBuilder::allocateNamedStream(StringRef Name, + uint32_t Size) { + auto ExpectedStream = Msf->addStream(Size); + 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(); +} + +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 + // only going to *really* have an ID stream if there is at least one ID + // record, we leave open the opportunity to test older PDBs such as those + // that don't have an ID stream. + auto &Info = getInfoBuilder(); + Info.addFeature(PdbRaw_FeatureSig::VC140); + } + + uint32_t StringsLen = Strings.calculateSerializedSize(); + + Expected<uint32_t> SN = allocateNamedStream("/LinkInfo", 0); + if (!SN) + return SN.takeError(); + + 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 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 EC; + } + + // 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(arrayRefFromStringRef(IS.Content->getBuffer())); + + 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), + InjectedSourceHashTraits); + } + + 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 Error::success(); +} + +Expected<uint32_t> PDBFileBuilder::getNamedStreamIndex(StringRef Name) const { + uint32_t SN = 0; + if (!NamedStreams.get(Name, SN)) + return llvm::make_error<pdb::RawError>(raw_error_code::no_stream); + return SN; +} + +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); +} + +void PDBFileBuilder::commitInjectedSources(WritableBinaryStream &MsfBuffer, + const msf::MSFLayout &Layout) { + if (InjectedSourceTable.empty()) + return; + + commitSrcHeaderBlock(MsfBuffer, Layout); + + for (const auto &IS : InjectedSources) { + uint32_t SN = cantFail(getNamedStreamIndex(IS.StreamName)); + + auto SourceStream = WritableMappedBlockStream::createIndexedStream( + Layout, MsfBuffer, SN, Allocator); + BinaryStreamWriter SourceWriter(*SourceStream); + assert(SourceWriter.bytesRemaining() == IS.Content->getBufferSize()); + cantFail(SourceWriter.writeBytes( + arrayRefFromStringRef(IS.Content->getBuffer()))); + } +} + +Error PDBFileBuilder::commit(StringRef Filename, codeview::GUID *Guid) { + assert(!Filename.empty()); + if (auto EC = finalizeMsfLayout()) + return EC; + + MSFLayout Layout; + Expected<FileBufferByteStream> ExpectedMsfBuffer = + Msf->commit(Filename, Layout); + if (!ExpectedMsfBuffer) + return ExpectedMsfBuffer.takeError(); + FileBufferByteStream Buffer = std::move(*ExpectedMsfBuffer); + + auto ExpectedSN = getNamedStreamIndex("/names"); + if (!ExpectedSN) + return ExpectedSN.takeError(); + + auto NS = WritableMappedBlockStream::createIndexedStream( + Layout, Buffer, *ExpectedSN, Allocator); + BinaryStreamWriter NSWriter(*NS); + 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; + } + + if (Dbi) { + if (auto EC = Dbi->commit(Layout, Buffer)) + return EC; + } + + if (Tpi) { + if (auto EC = Tpi->commit(Layout, Buffer)) + return EC; + } + + if (Ipi) { + if (auto EC = Ipi->commit(Layout, Buffer)) + return EC; + } + + if (Gsi) { + if (auto EC = Gsi->commit(Layout, Buffer)) + 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. + if (Info->hashPDBContentsToGUID()) { + // Compute a hash of all sections of the output file. + uint64_t Digest = + xxHash64({Buffer.getBufferStart(), Buffer.getBufferEnd()}); + + H->Age = 1; + + memcpy(H->Guid.Guid, &Digest, 8); + // xxhash only gives us 8 bytes, so put some fixed data in the other half. + memcpy(H->Guid.Guid + 8, "LLD PDB.", 8); + + // Put the hash in the Signature field too. + H->Signature = static_cast<uint32_t>(Digest); + + // Return GUID to caller. + memcpy(Guid, H->Guid.Guid, 16); + } else { + 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/llvm/lib/DebugInfo/PDB/Native/PDBStringTable.cpp b/llvm/lib/DebugInfo/PDB/Native/PDBStringTable.cpp new file mode 100644 index 0000000000000..2be1656e06bbd --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/Native/PDBStringTable.cpp @@ -0,0 +1,140 @@ +//===- PDBStringTable.cpp - PDB String Table ---------------------*- C++-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/PDBStringTable.h" + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/DebugInfo/PDB/Native/Hash.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/DebugInfo/PDB/Native/RawTypes.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/Endian.h" + +using namespace llvm; +using namespace llvm::support; +using namespace llvm::pdb; + +uint32_t PDBStringTable::getByteSize() const { return Header->ByteSize; } +uint32_t PDBStringTable::getNameCount() const { return NameCount; } +uint32_t PDBStringTable::getHashVersion() const { return Header->HashVersion; } +uint32_t PDBStringTable::getSignature() const { return Header->Signature; } + +Error PDBStringTable::readHeader(BinaryStreamReader &Reader) { + if (auto EC = Reader.readObject(Header)) + return EC; + + if (Header->Signature != PDBStringTableSignature) + return make_error<RawError>(raw_error_code::corrupt_file, + "Invalid hash table signature"); + if (Header->HashVersion != 1 && Header->HashVersion != 2) + return make_error<RawError>(raw_error_code::corrupt_file, + "Unsupported hash version"); + + assert(Reader.bytesRemaining() == 0); + return Error::success(); +} + +Error PDBStringTable::readStrings(BinaryStreamReader &Reader) { + BinaryStreamRef Stream; + if (auto EC = Reader.readStreamRef(Stream)) + return EC; + + if (auto EC = Strings.initialize(Stream)) { + return joinErrors(std::move(EC), + make_error<RawError>(raw_error_code::corrupt_file, + "Invalid hash table byte length")); + } + + assert(Reader.bytesRemaining() == 0); + return Error::success(); +} + +const codeview::DebugStringTableSubsectionRef & +PDBStringTable::getStringTable() const { + return Strings; +} + +Error PDBStringTable::readHashTable(BinaryStreamReader &Reader) { + const support::ulittle32_t *HashCount; + if (auto EC = Reader.readObject(HashCount)) + return EC; + + if (auto EC = Reader.readArray(IDs, *HashCount)) { + return joinErrors(std::move(EC), + make_error<RawError>(raw_error_code::corrupt_file, + "Could not read bucket array")); + } + + return Error::success(); +} + +Error PDBStringTable::readEpilogue(BinaryStreamReader &Reader) { + if (auto EC = Reader.readInteger(NameCount)) + return EC; + + assert(Reader.bytesRemaining() == 0); + return Error::success(); +} + +Error PDBStringTable::reload(BinaryStreamReader &Reader) { + + BinaryStreamReader SectionReader; + + std::tie(SectionReader, Reader) = Reader.split(sizeof(PDBStringTableHeader)); + if (auto EC = readHeader(SectionReader)) + return EC; + + std::tie(SectionReader, Reader) = Reader.split(Header->ByteSize); + if (auto EC = readStrings(SectionReader)) + return EC; + + // We don't know how long the hash table is until we parse it, so let the + // function responsible for doing that figure it out. + if (auto EC = readHashTable(Reader)) + return EC; + + std::tie(SectionReader, Reader) = Reader.split(sizeof(uint32_t)); + if (auto EC = readEpilogue(SectionReader)) + return EC; + + assert(Reader.bytesRemaining() == 0); + return Error::success(); +} + +Expected<StringRef> PDBStringTable::getStringForID(uint32_t ID) const { + return Strings.getString(ID); +} + +Expected<uint32_t> PDBStringTable::getIDForString(StringRef Str) const { + uint32_t Hash = + (Header->HashVersion == 1) ? hashStringV1(Str) : hashStringV2(Str); + size_t Count = IDs.size(); + uint32_t Start = Hash % Count; + for (size_t I = 0; I < Count; ++I) { + // The hash is just a starting point for the search, but if it + // doesn't work we should find the string no matter what, because + // 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(); + + if (*ExpectedStr == Str) + return ID; + } + return make_error<RawError>(raw_error_code::no_entry); +} + +FixedStreamArray<support::ulittle32_t> PDBStringTable::name_ids() const { + return IDs; +} diff --git a/llvm/lib/DebugInfo/PDB/Native/PDBStringTableBuilder.cpp b/llvm/lib/DebugInfo/PDB/Native/PDBStringTableBuilder.cpp new file mode 100644 index 0000000000000..f7f36901e4d49 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/Native/PDBStringTableBuilder.cpp @@ -0,0 +1,229 @@ +//===- PDBStringTableBuilder.cpp - PDB String Table -------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h" + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/DebugInfo/PDB/Native/Hash.h" +#include "llvm/DebugInfo/PDB/Native/RawTypes.h" +#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 { + // The reference implementation doesn't include code for /src/headerblock + // handling, but it can only read natvis entries lld's PDB files if + // this hash function truncates the hash to 16 bit. + // PDB/include/misc.h in the reference implementation has a hashSz() function + // that returns an unsigned short, that seems what's being used for + // /src/headerblock. + return static_cast<uint16_t>(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); +} + +static uint32_t computeBucketCount(uint32_t NumStrings) { + // 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. + // The reference implementation does (in nmt.h, NMT::grow()): + // unsigned StringCount = 0; + // unsigned BucketCount = 1; + // fn insert() { + // ++StringCount; + // if (BucketCount * 3 / 4 < StringCount) + // BucketCount = BucketCount * 3 / 2 + 1; + // } + // This list contains all StringCount, BucketCount pairs where BucketCount was + // just incremented. It ends before the first BucketCount entry where + // BucketCount * 3 would overflow a 32-bit unsigned int. + static std::map<uint32_t, uint32_t> StringsToBuckets = { + {0, 1}, + {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}, + {1163693870, 2327387740}}; + auto Entry = StringsToBuckets.lower_bound(NumStrings); + assert(Entry != StringsToBuckets.end()); + return Entry->second; +} + +uint32_t PDBStringTableBuilder::calculateHashTableSize() const { + uint32_t Size = sizeof(uint32_t); // Hash table begins with 4-byte size field. + Size += sizeof(uint32_t) * computeBucketCount(Strings.size()); + + return Size; +} + +uint32_t PDBStringTableBuilder::calculateSerializedSize() const { + uint32_t Size = 0; + Size += sizeof(PDBStringTableHeader); + Size += Strings.calculateSerializedSize(); + Size += calculateHashTableSize(); + Size += sizeof(uint32_t); // The /names stream ends with the string count. + return Size; +} + +void PDBStringTableBuilder::setStrings( + const codeview::DebugStringTableSubsection &Strings) { + this->Strings = Strings; +} + +Error PDBStringTableBuilder::writeHeader(BinaryStreamWriter &Writer) const { + // Write a header + PDBStringTableHeader H; + H.Signature = PDBStringTableSignature; + H.HashVersion = 1; + H.ByteSize = Strings.calculateSerializedSize(); + if (auto EC = Writer.writeObject(H)) + return EC; + assert(Writer.bytesRemaining() == 0); + return Error::success(); +} + +Error PDBStringTableBuilder::writeStrings(BinaryStreamWriter &Writer) const { + if (auto EC = Strings.commit(Writer)) + return EC; + + assert(Writer.bytesRemaining() == 0); + return Error::success(); +} + +Error PDBStringTableBuilder::writeHashTable(BinaryStreamWriter &Writer) const { + // Write a hash table. + uint32_t BucketCount = computeBucketCount(Strings.size()); + if (auto EC = Writer.writeInteger(BucketCount)) + return EC; + std::vector<ulittle32_t> Buckets(BucketCount); + + for (auto &Pair : Strings) { + StringRef S = Pair.getKey(); + uint32_t Offset = Pair.getValue(); + uint32_t Hash = hashStringV1(S); + + for (uint32_t I = 0; I != BucketCount; ++I) { + uint32_t Slot = (Hash + I) % BucketCount; + if (Buckets[Slot] != 0) + continue; + Buckets[Slot] = Offset; + break; + } + } + + if (auto EC = Writer.writeArray(ArrayRef<ulittle32_t>(Buckets))) + return EC; + + assert(Writer.bytesRemaining() == 0); + return Error::success(); +} + +Error PDBStringTableBuilder::writeEpilogue(BinaryStreamWriter &Writer) const { + if (auto EC = Writer.writeInteger<uint32_t>(Strings.size())) + return EC; + assert(Writer.bytesRemaining() == 0); + return Error::success(); +} + +Error PDBStringTableBuilder::commit(BinaryStreamWriter &Writer) const { + BinaryStreamWriter SectionWriter; + + std::tie(SectionWriter, Writer) = Writer.split(sizeof(PDBStringTableHeader)); + if (auto EC = writeHeader(SectionWriter)) + return EC; + + std::tie(SectionWriter, Writer) = + Writer.split(Strings.calculateSerializedSize()); + if (auto EC = writeStrings(SectionWriter)) + return EC; + + std::tie(SectionWriter, Writer) = Writer.split(calculateHashTableSize()); + if (auto EC = writeHashTable(SectionWriter)) + return EC; + + std::tie(SectionWriter, Writer) = Writer.split(sizeof(uint32_t)); + if (auto EC = writeEpilogue(SectionWriter)) + return EC; + + return Error::success(); +} diff --git a/llvm/lib/DebugInfo/PDB/Native/PublicsStream.cpp b/llvm/lib/DebugInfo/PDB/Native/PublicsStream.cpp new file mode 100644 index 0000000000000..a33bf03bf8fb3 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/Native/PublicsStream.cpp @@ -0,0 +1,101 @@ +//===- PublicsStream.cpp - PDB Public Symbol Stream -----------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// The data structures defined 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. +// +// The reference doesn't compile, so I learned just by reading code. +// It's not guaranteed to be correct. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/PublicsStream.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/DebugInfo/MSF/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include <algorithm> +#include <cstdint> + +using namespace llvm; +using namespace llvm::msf; +using namespace llvm::support; +using namespace llvm::pdb; + +PublicsStream::PublicsStream(std::unique_ptr<MappedBlockStream> Stream) + : Stream(std::move(Stream)) {} + +PublicsStream::~PublicsStream() = default; + +uint32_t PublicsStream::getSymHash() const { return Header->SymHash; } +uint16_t PublicsStream::getThunkTableSection() const { + return Header->ISectThunkTable; +} +uint32_t PublicsStream::getThunkTableOffset() const { + return Header->OffThunkTable; +} + +// Publics stream contains fixed-size headers and a serialized hash table. +// This implementation is not complete yet. It reads till the end of the +// stream so that we verify the stream is at least not corrupted. However, +// we skip over the hash table which we believe contains information about +// public symbols. +Error PublicsStream::reload() { + BinaryStreamReader Reader(*Stream); + + // Check stream size. + if (Reader.bytesRemaining() < + sizeof(PublicsStreamHeader) + sizeof(GSIHashHeader)) + return make_error<RawError>(raw_error_code::corrupt_file, + "Publics Stream does not contain a header."); + + // Read PSGSIHDR struct. + if (Reader.readObject(Header)) + return make_error<RawError>(raw_error_code::corrupt_file, + "Publics Stream does not contain a header."); + + // Read the hash table. + if (auto E = PublicsTable.read(Reader)) + return E; + + // Something called "address map" follows. + uint32_t NumAddressMapEntries = Header->AddrMap / sizeof(uint32_t); + if (auto EC = Reader.readArray(AddressMap, NumAddressMapEntries)) + return joinErrors(std::move(EC), + make_error<RawError>(raw_error_code::corrupt_file, + "Could not read an address map.")); + + // Something called "thunk map" follows. + if (auto EC = Reader.readArray(ThunkMap, Header->NumThunks)) + return joinErrors(std::move(EC), + make_error<RawError>(raw_error_code::corrupt_file, + "Could not read a thunk map.")); + + // Something called "section map" follows. + if (Reader.bytesRemaining() > 0) { + if (auto EC = Reader.readArray(SectionOffsets, Header->NumSections)) + return joinErrors(std::move(EC), + make_error<RawError>(raw_error_code::corrupt_file, + "Could not read a section map.")); + } + + if (Reader.bytesRemaining() > 0) + return make_error<RawError>(raw_error_code::corrupt_file, + "Corrupted publics stream."); + return Error::success(); +} diff --git a/llvm/lib/DebugInfo/PDB/Native/RawError.cpp b/llvm/lib/DebugInfo/PDB/Native/RawError.cpp new file mode 100644 index 0000000000000..ed6cf08396755 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/Native/RawError.cpp @@ -0,0 +1,53 @@ +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/ManagedStatic.h" + +using namespace llvm; +using namespace llvm::pdb; + +namespace { +// FIXME: This class is only here to support the transition to llvm::Error. It +// will be removed once this transition is complete. Clients should prefer to +// deal with the Error value directly, rather than converting to error_code. +class RawErrorCategory : public std::error_category { +public: + const char *name() const noexcept override { return "llvm.pdb.raw"; } + std::string message(int Condition) const override { + switch (static_cast<raw_error_code>(Condition)) { + case raw_error_code::unspecified: + return "An unknown error has occurred."; + case raw_error_code::feature_unsupported: + return "The feature is unsupported by the implementation."; + case raw_error_code::invalid_format: + return "The record is in an unexpected format."; + case raw_error_code::corrupt_file: + return "The PDB file is corrupt."; + case raw_error_code::insufficient_buffer: + return "The buffer is not large enough to read the requested number of " + "bytes."; + case raw_error_code::no_stream: + return "The specified stream could not be loaded."; + case raw_error_code::index_out_of_bounds: + return "The specified item does not exist in the array."; + case raw_error_code::invalid_block_address: + return "The specified block address is not valid."; + case raw_error_code::duplicate_entry: + return "The entry already exists."; + case raw_error_code::no_entry: + return "The entry does not exist."; + case raw_error_code::not_writable: + return "The PDB does not support writing."; + case raw_error_code::stream_too_long: + return "The stream was longer than expected."; + case raw_error_code::invalid_tpi_hash: + return "The Type record has an invalid hash value."; + } + llvm_unreachable("Unrecognized raw_error_code"); + } +}; +} // namespace + +static llvm::ManagedStatic<RawErrorCategory> RawCategory; +const std::error_category &llvm::pdb::RawErrCategory() { return *RawCategory; } + +char RawError::ID; diff --git a/llvm/lib/DebugInfo/PDB/Native/SymbolCache.cpp b/llvm/lib/DebugInfo/PDB/Native/SymbolCache.cpp new file mode 100644 index 0000000000000..5cdd628312fe5 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/Native/SymbolCache.cpp @@ -0,0 +1,299 @@ +#include "llvm/DebugInfo/PDB/Native/SymbolCache.h" + +#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" +#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" +#include "llvm/DebugInfo/CodeView/TypeRecordHelpers.h" +#include "llvm/DebugInfo/PDB/Native/DbiStream.h" +#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h" +#include "llvm/DebugInfo/PDB/Native/NativeCompilandSymbol.h" +#include "llvm/DebugInfo/PDB/Native/NativeEnumGlobals.h" +#include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h" +#include "llvm/DebugInfo/PDB/Native/NativeRawSymbol.h" +#include "llvm/DebugInfo/PDB/Native/NativeSession.h" +#include "llvm/DebugInfo/PDB/Native/NativeTypeArray.h" +#include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h" +#include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h" +#include "llvm/DebugInfo/PDB/Native/NativeTypeFunctionSig.h" +#include "llvm/DebugInfo/PDB/Native/NativeTypePointer.h" +#include "llvm/DebugInfo/PDB/Native/NativeTypeTypedef.h" +#include "llvm/DebugInfo/PDB/Native/NativeTypeUDT.h" +#include "llvm/DebugInfo/PDB/Native/NativeTypeVTShape.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/SymbolStream.h" +#include "llvm/DebugInfo/PDB/Native/TpiStream.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" +#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +// Maps codeview::SimpleTypeKind of a built-in type to the parameters necessary +// to instantiate a NativeBuiltinSymbol for that type. +static const struct BuiltinTypeEntry { + codeview::SimpleTypeKind Kind; + PDB_BuiltinType Type; + uint32_t Size; +} BuiltinTypes[] = { + {codeview::SimpleTypeKind::None, PDB_BuiltinType::None, 0}, + {codeview::SimpleTypeKind::Void, PDB_BuiltinType::Void, 0}, + {codeview::SimpleTypeKind::HResult, PDB_BuiltinType::HResult, 4}, + {codeview::SimpleTypeKind::Int16Short, PDB_BuiltinType::Int, 2}, + {codeview::SimpleTypeKind::UInt16Short, PDB_BuiltinType::UInt, 2}, + {codeview::SimpleTypeKind::Int32, PDB_BuiltinType::Int, 4}, + {codeview::SimpleTypeKind::UInt32, PDB_BuiltinType::UInt, 4}, + {codeview::SimpleTypeKind::Int32Long, PDB_BuiltinType::Int, 4}, + {codeview::SimpleTypeKind::UInt32Long, PDB_BuiltinType::UInt, 4}, + {codeview::SimpleTypeKind::Int64Quad, PDB_BuiltinType::Int, 8}, + {codeview::SimpleTypeKind::UInt64Quad, PDB_BuiltinType::UInt, 8}, + {codeview::SimpleTypeKind::NarrowCharacter, PDB_BuiltinType::Char, 1}, + {codeview::SimpleTypeKind::WideCharacter, PDB_BuiltinType::WCharT, 2}, + {codeview::SimpleTypeKind::Character16, PDB_BuiltinType::Char16, 2}, + {codeview::SimpleTypeKind::Character32, PDB_BuiltinType::Char32, 4}, + {codeview::SimpleTypeKind::SignedCharacter, PDB_BuiltinType::Char, 1}, + {codeview::SimpleTypeKind::UnsignedCharacter, PDB_BuiltinType::UInt, 1}, + {codeview::SimpleTypeKind::Float32, PDB_BuiltinType::Float, 4}, + {codeview::SimpleTypeKind::Float64, PDB_BuiltinType::Float, 8}, + {codeview::SimpleTypeKind::Float80, PDB_BuiltinType::Float, 10}, + {codeview::SimpleTypeKind::Boolean8, PDB_BuiltinType::Bool, 1}, + // This table can be grown as necessary, but these are the only types we've + // needed so far. +}; + +SymbolCache::SymbolCache(NativeSession &Session, DbiStream *Dbi) + : Session(Session), Dbi(Dbi) { + // Id 0 is reserved for the invalid symbol. + Cache.push_back(nullptr); + + if (Dbi) + Compilands.resize(Dbi->modules().getModuleCount()); +} + +std::unique_ptr<IPDBEnumSymbols> +SymbolCache::createTypeEnumerator(TypeLeafKind Kind) { + return createTypeEnumerator(std::vector<TypeLeafKind>{Kind}); +} + +std::unique_ptr<IPDBEnumSymbols> +SymbolCache::createTypeEnumerator(std::vector<TypeLeafKind> Kinds) { + auto Tpi = Session.getPDBFile().getPDBTpiStream(); + if (!Tpi) { + consumeError(Tpi.takeError()); + return nullptr; + } + auto &Types = Tpi->typeCollection(); + return std::unique_ptr<IPDBEnumSymbols>( + new NativeEnumTypes(Session, Types, std::move(Kinds))); +} + +std::unique_ptr<IPDBEnumSymbols> +SymbolCache::createGlobalsEnumerator(codeview::SymbolKind Kind) { + return std::unique_ptr<IPDBEnumSymbols>( + new NativeEnumGlobals(Session, {Kind})); +} + +SymIndexId SymbolCache::createSimpleType(TypeIndex Index, + ModifierOptions Mods) { + if (Index.getSimpleMode() != codeview::SimpleTypeMode::Direct) + return createSymbol<NativeTypePointer>(Index); + + const auto Kind = Index.getSimpleKind(); + const auto It = std::find_if( + std::begin(BuiltinTypes), std::end(BuiltinTypes), + [Kind](const BuiltinTypeEntry &Builtin) { return Builtin.Kind == Kind; }); + if (It == std::end(BuiltinTypes)) + return 0; + return createSymbol<NativeTypeBuiltin>(Mods, It->Type, It->Size); +} + +SymIndexId +SymbolCache::createSymbolForModifiedType(codeview::TypeIndex ModifierTI, + codeview::CVType CVT) { + ModifierRecord Record; + if (auto EC = TypeDeserializer::deserializeAs<ModifierRecord>(CVT, Record)) { + consumeError(std::move(EC)); + return 0; + } + + if (Record.ModifiedType.isSimple()) + return createSimpleType(Record.ModifiedType, Record.Modifiers); + + // Make sure we create and cache a record for the unmodified type. + SymIndexId UnmodifiedId = findSymbolByTypeIndex(Record.ModifiedType); + NativeRawSymbol &UnmodifiedNRS = *Cache[UnmodifiedId]; + + switch (UnmodifiedNRS.getSymTag()) { + case PDB_SymType::Enum: + return createSymbol<NativeTypeEnum>( + static_cast<NativeTypeEnum &>(UnmodifiedNRS), std::move(Record)); + case PDB_SymType::UDT: + return createSymbol<NativeTypeUDT>( + static_cast<NativeTypeUDT &>(UnmodifiedNRS), std::move(Record)); + default: + // No other types can be modified. (LF_POINTER, for example, records + // its modifiers a different way. + assert(false && "Invalid LF_MODIFIER record"); + break; + } + return 0; +} + +SymIndexId SymbolCache::findSymbolByTypeIndex(codeview::TypeIndex Index) { + // First see if it's already in our cache. + const auto Entry = TypeIndexToSymbolId.find(Index); + if (Entry != TypeIndexToSymbolId.end()) + return Entry->second; + + // Symbols for built-in types are created on the fly. + if (Index.isSimple()) { + SymIndexId Result = createSimpleType(Index, ModifierOptions::None); + assert(TypeIndexToSymbolId.count(Index) == 0); + TypeIndexToSymbolId[Index] = Result; + return Result; + } + + // We need to instantiate and cache the desired type symbol. + auto Tpi = Session.getPDBFile().getPDBTpiStream(); + if (!Tpi) { + consumeError(Tpi.takeError()); + return 0; + } + codeview::LazyRandomTypeCollection &Types = Tpi->typeCollection(); + codeview::CVType CVT = Types.getType(Index); + + if (isUdtForwardRef(CVT)) { + Expected<TypeIndex> EFD = Tpi->findFullDeclForForwardRef(Index); + + if (!EFD) + consumeError(EFD.takeError()); + else if (*EFD != Index) { + assert(!isUdtForwardRef(Types.getType(*EFD))); + SymIndexId Result = findSymbolByTypeIndex(*EFD); + // Record a mapping from ForwardRef -> SymIndex of complete type so that + // we'll take the fast path next time. + assert(TypeIndexToSymbolId.count(Index) == 0); + TypeIndexToSymbolId[Index] = Result; + return Result; + } + } + + // At this point if we still have a forward ref udt it means the full decl was + // not in the PDB. We just have to deal with it and use the forward ref. + SymIndexId Id = 0; + switch (CVT.kind()) { + case codeview::LF_ENUM: + Id = createSymbolForType<NativeTypeEnum, EnumRecord>(Index, std::move(CVT)); + break; + case codeview::LF_ARRAY: + Id = createSymbolForType<NativeTypeArray, ArrayRecord>(Index, + std::move(CVT)); + break; + case codeview::LF_CLASS: + case codeview::LF_STRUCTURE: + case codeview::LF_INTERFACE: + Id = createSymbolForType<NativeTypeUDT, ClassRecord>(Index, std::move(CVT)); + break; + case codeview::LF_UNION: + Id = createSymbolForType<NativeTypeUDT, UnionRecord>(Index, std::move(CVT)); + break; + case codeview::LF_POINTER: + Id = createSymbolForType<NativeTypePointer, PointerRecord>(Index, + std::move(CVT)); + break; + case codeview::LF_MODIFIER: + Id = createSymbolForModifiedType(Index, std::move(CVT)); + break; + case codeview::LF_PROCEDURE: + Id = createSymbolForType<NativeTypeFunctionSig, ProcedureRecord>( + Index, std::move(CVT)); + break; + case codeview::LF_MFUNCTION: + Id = createSymbolForType<NativeTypeFunctionSig, MemberFunctionRecord>( + Index, std::move(CVT)); + break; + case codeview::LF_VTSHAPE: + Id = createSymbolForType<NativeTypeVTShape, VFTableShapeRecord>( + Index, std::move(CVT)); + break; + default: + Id = createSymbolPlaceholder(); + break; + } + if (Id != 0) { + assert(TypeIndexToSymbolId.count(Index) == 0); + TypeIndexToSymbolId[Index] = Id; + } + return Id; +} + +std::unique_ptr<PDBSymbol> +SymbolCache::getSymbolById(SymIndexId SymbolId) const { + assert(SymbolId < Cache.size()); + + // Id 0 is reserved. + if (SymbolId == 0 || SymbolId >= Cache.size()) + return nullptr; + + // Make sure to handle the case where we've inserted a placeholder symbol + // for types we don't yet suppport. + NativeRawSymbol *NRS = Cache[SymbolId].get(); + if (!NRS) + return nullptr; + + return PDBSymbol::create(Session, *NRS); +} + +NativeRawSymbol &SymbolCache::getNativeSymbolById(SymIndexId SymbolId) const { + return *Cache[SymbolId]; +} + +uint32_t SymbolCache::getNumCompilands() const { + if (!Dbi) + return 0; + + return Dbi->modules().getModuleCount(); +} + +SymIndexId SymbolCache::getOrCreateGlobalSymbolByOffset(uint32_t Offset) { + auto Iter = GlobalOffsetToSymbolId.find(Offset); + if (Iter != GlobalOffsetToSymbolId.end()) + return Iter->second; + + SymbolStream &SS = cantFail(Session.getPDBFile().getPDBSymbolStream()); + CVSymbol CVS = SS.readRecord(Offset); + SymIndexId Id = 0; + switch (CVS.kind()) { + case SymbolKind::S_UDT: { + UDTSym US = cantFail(SymbolDeserializer::deserializeAs<UDTSym>(CVS)); + Id = createSymbol<NativeTypeTypedef>(std::move(US)); + break; + } + default: + Id = createSymbolPlaceholder(); + break; + } + if (Id != 0) { + assert(GlobalOffsetToSymbolId.count(Offset) == 0); + GlobalOffsetToSymbolId[Offset] = Id; + } + + return Id; +} + +std::unique_ptr<PDBSymbolCompiland> +SymbolCache::getOrCreateCompiland(uint32_t Index) { + if (!Dbi) + return nullptr; + + if (Index >= Compilands.size()) + return nullptr; + + if (Compilands[Index] == 0) { + const DbiModuleList &Modules = Dbi->modules(); + Compilands[Index] = + createSymbol<NativeCompilandSymbol>(Modules.getModuleDescriptor(Index)); + } + + return Session.getConcreteSymbolById<PDBSymbolCompiland>(Compilands[Index]); +} diff --git a/llvm/lib/DebugInfo/PDB/Native/SymbolStream.cpp b/llvm/lib/DebugInfo/PDB/Native/SymbolStream.cpp new file mode 100644 index 0000000000000..003840b6e67e8 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/Native/SymbolStream.cpp @@ -0,0 +1,45 @@ +//===- SymbolStream.cpp - PDB Symbol Stream Access ------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/SymbolStream.h" + +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/DebugInfo/MSF/MappedBlockStream.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/Endian.h" + +using namespace llvm; +using namespace llvm::msf; +using namespace llvm::support; +using namespace llvm::pdb; + +SymbolStream::SymbolStream(std::unique_ptr<MappedBlockStream> Stream) + : Stream(std::move(Stream)) {} + +SymbolStream::~SymbolStream() {} + +Error SymbolStream::reload() { + BinaryStreamReader Reader(*Stream); + + if (auto EC = Reader.readArray(SymbolRecords, Stream->getLength())) + return EC; + + return Error::success(); +} + +iterator_range<codeview::CVSymbolArray::Iterator> +SymbolStream::getSymbols(bool *HadError) const { + return llvm::make_range(SymbolRecords.begin(HadError), SymbolRecords.end()); +} + +Error SymbolStream::commit() { return Error::success(); } + +codeview::CVSymbol SymbolStream::readRecord(uint32_t Offset) const { + return *SymbolRecords.at(Offset); +} diff --git a/llvm/lib/DebugInfo/PDB/Native/TpiHashing.cpp b/llvm/lib/DebugInfo/PDB/Native/TpiHashing.cpp new file mode 100644 index 0000000000000..b71b2b1581441 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/Native/TpiHashing.cpp @@ -0,0 +1,129 @@ +//===- TpiHashing.cpp -----------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/TpiHashing.h" + +#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" +#include "llvm/DebugInfo/PDB/Native/Hash.h" +#include "llvm/Support/CRC.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +// Corresponds to `fUDTAnon`. +static bool isAnonymous(StringRef Name) { + return Name == "<unnamed-tag>" || Name == "__unnamed" || + Name.endswith("::<unnamed-tag>") || Name.endswith("::__unnamed"); +} + +// Computes the hash for a user-defined type record. This could be a struct, +// class, union, or enum. +static uint32_t getHashForUdt(const TagRecord &Rec, + ArrayRef<uint8_t> FullRecord) { + ClassOptions Opts = Rec.getOptions(); + bool ForwardRef = bool(Opts & ClassOptions::ForwardReference); + bool Scoped = bool(Opts & ClassOptions::Scoped); + bool HasUniqueName = bool(Opts & ClassOptions::HasUniqueName); + bool IsAnon = HasUniqueName && isAnonymous(Rec.getName()); + + if (!ForwardRef && !Scoped && !IsAnon) + return hashStringV1(Rec.getName()); + if (!ForwardRef && HasUniqueName && !IsAnon) + return hashStringV1(Rec.getUniqueName()); + return hashBufferV8(FullRecord); +} + +template <typename T> +static Expected<uint32_t> getHashForUdt(const CVType &Rec) { + T Deserialized; + if (auto E = TypeDeserializer::deserializeAs(const_cast<CVType &>(Rec), + Deserialized)) + return std::move(E); + return getHashForUdt(Deserialized, Rec.data()); +} + +template <typename T> +static Expected<TagRecordHash> getTagRecordHashForUdt(const CVType &Rec) { + T Deserialized; + if (auto E = TypeDeserializer::deserializeAs(const_cast<CVType &>(Rec), + Deserialized)) + return std::move(E); + + ClassOptions Opts = Deserialized.getOptions(); + + bool ForwardRef = bool(Opts & ClassOptions::ForwardReference); + + uint32_t ThisRecordHash = getHashForUdt(Deserialized, Rec.data()); + + // If we don't have a forward ref we can't compute the hash of it from the + // full record because it requires hashing the entire buffer. + if (!ForwardRef) + return TagRecordHash{std::move(Deserialized), ThisRecordHash, 0}; + + bool Scoped = bool(Opts & ClassOptions::Scoped); + + StringRef NameToHash = + Scoped ? Deserialized.getUniqueName() : Deserialized.getName(); + uint32_t FullHash = hashStringV1(NameToHash); + return TagRecordHash{std::move(Deserialized), FullHash, ThisRecordHash}; +} + +template <typename T> +static Expected<uint32_t> getSourceLineHash(const CVType &Rec) { + T Deserialized; + if (auto E = TypeDeserializer::deserializeAs(const_cast<CVType &>(Rec), + Deserialized)) + return std::move(E); + char Buf[4]; + support::endian::write32le(Buf, Deserialized.getUDT().getIndex()); + return hashStringV1(StringRef(Buf, 4)); +} + +Expected<TagRecordHash> llvm::pdb::hashTagRecord(const codeview::CVType &Type) { + switch (Type.kind()) { + case LF_CLASS: + case LF_STRUCTURE: + case LF_INTERFACE: + return getTagRecordHashForUdt<ClassRecord>(Type); + case LF_UNION: + return getTagRecordHashForUdt<UnionRecord>(Type); + case LF_ENUM: + return getTagRecordHashForUdt<EnumRecord>(Type); + default: + assert(false && "Type is not a tag record!"); + } + return make_error<StringError>("Invalid record type", + inconvertibleErrorCode()); +} + +Expected<uint32_t> llvm::pdb::hashTypeRecord(const CVType &Rec) { + switch (Rec.kind()) { + case LF_CLASS: + case LF_STRUCTURE: + case LF_INTERFACE: + return getHashForUdt<ClassRecord>(Rec); + case LF_UNION: + return getHashForUdt<UnionRecord>(Rec); + case LF_ENUM: + return getHashForUdt<EnumRecord>(Rec); + + case LF_UDT_SRC_LINE: + return getSourceLineHash<UdtSourceLineRecord>(Rec); + case LF_UDT_MOD_SRC_LINE: + return getSourceLineHash<UdtModSourceLineRecord>(Rec); + + default: + break; + } + + // Run CRC32 over the bytes. This corresponds to `hashBufv8`. + JamCRC JC(/*Init=*/0U); + JC.update(Rec.data()); + return JC.getCRC(); +} diff --git a/llvm/lib/DebugInfo/PDB/Native/TpiStream.cpp b/llvm/lib/DebugInfo/PDB/Native/TpiStream.cpp new file mode 100644 index 0000000000000..ac19db03fab2f --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/Native/TpiStream.cpp @@ -0,0 +1,246 @@ +//===- TpiStream.cpp - PDB Type Info (TPI) Stream 2 Access ----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/TpiStream.h" + +#include "llvm/ADT/iterator_range.h" +#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" +#include "llvm/DebugInfo/CodeView/RecordName.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/CodeView/TypeRecordHelpers.h" +#include "llvm/DebugInfo/MSF/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Native/Hash.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/Native/TpiHashing.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include <algorithm> +#include <cstdint> +#include <vector> + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::support; +using namespace llvm::msf; +using namespace llvm::pdb; + +TpiStream::TpiStream(PDBFile &File, std::unique_ptr<MappedBlockStream> Stream) + : Pdb(File), Stream(std::move(Stream)) {} + +TpiStream::~TpiStream() = default; + +Error TpiStream::reload() { + BinaryStreamReader Reader(*Stream); + + if (Reader.bytesRemaining() < sizeof(TpiStreamHeader)) + return make_error<RawError>(raw_error_code::corrupt_file, + "TPI Stream does not contain a header."); + + if (Reader.readObject(Header)) + return make_error<RawError>(raw_error_code::corrupt_file, + "TPI Stream does not contain a header."); + + if (Header->Version != PdbTpiV80) + return make_error<RawError>(raw_error_code::corrupt_file, + "Unsupported TPI Version."); + + if (Header->HeaderSize != sizeof(TpiStreamHeader)) + return make_error<RawError>(raw_error_code::corrupt_file, + "Corrupt TPI Header size."); + + if (Header->HashKeySize != sizeof(ulittle32_t)) + return make_error<RawError>(raw_error_code::corrupt_file, + "TPI Stream expected 4 byte hash key size."); + + if (Header->NumHashBuckets < MinTpiHashBuckets || + Header->NumHashBuckets > MaxTpiHashBuckets) + return make_error<RawError>(raw_error_code::corrupt_file, + "TPI Stream Invalid number of hash buckets."); + + // The actual type records themselves come from this stream + if (auto EC = + Reader.readSubstream(TypeRecordsSubstream, Header->TypeRecordBytes)) + return EC; + + BinaryStreamReader RecordReader(TypeRecordsSubstream.StreamData); + if (auto EC = + RecordReader.readArray(TypeRecords, TypeRecordsSubstream.size())) + return EC; + + // Hash indices, hash values, etc come from the hash stream. + if (Header->HashStreamIndex != kInvalidStreamIndex) { + auto HS = Pdb.safelyCreateIndexedStream(Header->HashStreamIndex); + if (!HS) { + consumeError(HS.takeError()); + return make_error<RawError>(raw_error_code::corrupt_file, + "Invalid TPI hash stream index."); + } + BinaryStreamReader HSR(**HS); + + // There should be a hash value for every type record, or no hashes at all. + uint32_t NumHashValues = + Header->HashValueBuffer.Length / sizeof(ulittle32_t); + if (NumHashValues != getNumTypeRecords() && NumHashValues != 0) + return make_error<RawError>( + raw_error_code::corrupt_file, + "TPI hash count does not match with the number of type records."); + HSR.setOffset(Header->HashValueBuffer.Off); + if (auto EC = HSR.readArray(HashValues, NumHashValues)) + return EC; + + HSR.setOffset(Header->IndexOffsetBuffer.Off); + uint32_t NumTypeIndexOffsets = + Header->IndexOffsetBuffer.Length / sizeof(TypeIndexOffset); + if (auto EC = HSR.readArray(TypeIndexOffsets, NumTypeIndexOffsets)) + return EC; + + if (Header->HashAdjBuffer.Length > 0) { + HSR.setOffset(Header->HashAdjBuffer.Off); + if (auto EC = HashAdjusters.load(HSR)) + return EC; + } + + HashStream = std::move(*HS); + } + + Types = std::make_unique<LazyRandomTypeCollection>( + TypeRecords, getNumTypeRecords(), getTypeIndexOffsets()); + return Error::success(); +} + +PdbRaw_TpiVer TpiStream::getTpiVersion() const { + uint32_t Value = Header->Version; + return static_cast<PdbRaw_TpiVer>(Value); +} + +uint32_t TpiStream::TypeIndexBegin() const { return Header->TypeIndexBegin; } + +uint32_t TpiStream::TypeIndexEnd() const { return Header->TypeIndexEnd; } + +uint32_t TpiStream::getNumTypeRecords() const { + return TypeIndexEnd() - TypeIndexBegin(); +} + +uint16_t TpiStream::getTypeHashStreamIndex() const { + return Header->HashStreamIndex; +} + +uint16_t TpiStream::getTypeHashStreamAuxIndex() const { + return Header->HashAuxStreamIndex; +} + +uint32_t TpiStream::getNumHashBuckets() const { return Header->NumHashBuckets; } +uint32_t TpiStream::getHashKeySize() const { return Header->HashKeySize; } + +void TpiStream::buildHashMap() { + if (!HashMap.empty()) + return; + if (HashValues.empty()) + return; + + HashMap.resize(Header->NumHashBuckets); + + TypeIndex TIB{Header->TypeIndexBegin}; + TypeIndex TIE{Header->TypeIndexEnd}; + while (TIB < TIE) { + uint32_t HV = HashValues[TIB.toArrayIndex()]; + HashMap[HV].push_back(TIB++); + } +} + +std::vector<TypeIndex> TpiStream::findRecordsByName(StringRef Name) const { + if (!supportsTypeLookup()) + const_cast<TpiStream*>(this)->buildHashMap(); + + uint32_t Bucket = hashStringV1(Name) % Header->NumHashBuckets; + if (Bucket > HashMap.size()) + return {}; + + std::vector<TypeIndex> Result; + for (TypeIndex TI : HashMap[Bucket]) { + std::string ThisName = computeTypeName(*Types, TI); + if (ThisName == Name) + Result.push_back(TI); + } + return Result; +} + +bool TpiStream::supportsTypeLookup() const { return !HashMap.empty(); } + +Expected<TypeIndex> +TpiStream::findFullDeclForForwardRef(TypeIndex ForwardRefTI) const { + if (!supportsTypeLookup()) + const_cast<TpiStream*>(this)->buildHashMap(); + + CVType F = Types->getType(ForwardRefTI); + if (!isUdtForwardRef(F)) + return ForwardRefTI; + + Expected<TagRecordHash> ForwardTRH = hashTagRecord(F); + if (!ForwardTRH) + return ForwardTRH.takeError(); + + uint32_t BucketIdx = ForwardTRH->FullRecordHash % Header->NumHashBuckets; + + for (TypeIndex TI : HashMap[BucketIdx]) { + CVType CVT = Types->getType(TI); + if (CVT.kind() != F.kind()) + continue; + + Expected<TagRecordHash> FullTRH = hashTagRecord(CVT); + if (!FullTRH) + return FullTRH.takeError(); + if (ForwardTRH->FullRecordHash != FullTRH->FullRecordHash) + continue; + TagRecord &ForwardTR = ForwardTRH->getRecord(); + TagRecord &FullTR = FullTRH->getRecord(); + + if (!ForwardTR.hasUniqueName()) { + if (ForwardTR.getName() == FullTR.getName()) + return TI; + continue; + } + + if (!FullTR.hasUniqueName()) + continue; + if (ForwardTR.getUniqueName() == FullTR.getUniqueName()) + return TI; + } + return ForwardRefTI; +} + +codeview::CVType TpiStream::getType(codeview::TypeIndex Index) { + assert(!Index.isSimple()); + return Types->getType(Index); +} + +BinarySubstreamRef TpiStream::getTypeRecordsSubstream() const { + return TypeRecordsSubstream; +} + +FixedStreamArray<support::ulittle32_t> TpiStream::getHashValues() const { + return HashValues; +} + +FixedStreamArray<TypeIndexOffset> TpiStream::getTypeIndexOffsets() const { + return TypeIndexOffsets; +} + +HashTable<support::ulittle32_t> &TpiStream::getHashAdjusters() { + return HashAdjusters; +} + +CVTypeRange TpiStream::types(bool *HadError) const { + return make_range(TypeRecords.begin(HadError), TypeRecords.end()); +} + +Error TpiStream::commit() { return Error::success(); } diff --git a/llvm/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp b/llvm/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp new file mode 100644 index 0000000000000..4f10f8524a9b1 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp @@ -0,0 +1,178 @@ +//===- TpiStreamBuilder.cpp - -------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/DebugInfo/CodeView/TypeIndex.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/MSF/MSFBuilder.h" +#include "llvm/DebugInfo/MSF/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/DebugInfo/PDB/Native/RawTypes.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/BinaryStreamArray.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/BinaryStreamWriter.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include <algorithm> +#include <cstdint> + +using namespace llvm; +using namespace llvm::msf; +using namespace llvm::pdb; +using namespace llvm::support; + +TpiStreamBuilder::TpiStreamBuilder(MSFBuilder &Msf, uint32_t StreamIdx) + : Msf(Msf), Allocator(Msf.getAllocator()), Header(nullptr), Idx(StreamIdx) { +} + +TpiStreamBuilder::~TpiStreamBuilder() = default; + +void TpiStreamBuilder::setVersionHeader(PdbRaw_TpiVer Version) { + VerHeader = Version; +} + +void TpiStreamBuilder::addTypeRecord(ArrayRef<uint8_t> Record, + Optional<uint32_t> Hash) { + // If we just crossed an 8KB threshold, add a type index offset. + size_t NewSize = TypeRecordBytes + Record.size(); + constexpr size_t EightKB = 8 * 1024; + if (NewSize / EightKB > TypeRecordBytes / EightKB || TypeRecords.empty()) { + TypeIndexOffsets.push_back( + {codeview::TypeIndex(codeview::TypeIndex::FirstNonSimpleIndex + + TypeRecords.size()), + ulittle32_t(TypeRecordBytes)}); + } + TypeRecordBytes = NewSize; + + TypeRecords.push_back(Record); + if (Hash) + TypeHashes.push_back(*Hash); +} + +Error TpiStreamBuilder::finalize() { + if (Header) + return Error::success(); + + TpiStreamHeader *H = Allocator.Allocate<TpiStreamHeader>(); + + uint32_t Count = TypeRecords.size(); + + H->Version = VerHeader; + H->HeaderSize = sizeof(TpiStreamHeader); + H->TypeIndexBegin = codeview::TypeIndex::FirstNonSimpleIndex; + H->TypeIndexEnd = H->TypeIndexBegin + Count; + H->TypeRecordBytes = TypeRecordBytes; + + H->HashStreamIndex = HashStreamIndex; + H->HashAuxStreamIndex = kInvalidStreamIndex; + H->HashKeySize = sizeof(ulittle32_t); + H->NumHashBuckets = MaxTpiHashBuckets - 1; + + // Recall that hash values go into a completely different stream identified by + // the `HashStreamIndex` field of the `TpiStreamHeader`. Therefore, the data + // begins at offset 0 of this independent stream. + H->HashValueBuffer.Off = 0; + H->HashValueBuffer.Length = calculateHashBufferSize(); + + // We never write any adjustments into our PDBs, so this is usually some + // offset with zero length. + H->HashAdjBuffer.Off = H->HashValueBuffer.Off + H->HashValueBuffer.Length; + H->HashAdjBuffer.Length = 0; + + H->IndexOffsetBuffer.Off = H->HashAdjBuffer.Off + H->HashAdjBuffer.Length; + H->IndexOffsetBuffer.Length = calculateIndexOffsetSize(); + + Header = H; + return Error::success(); +} + +uint32_t TpiStreamBuilder::calculateSerializedLength() { + return sizeof(TpiStreamHeader) + TypeRecordBytes; +} + +uint32_t TpiStreamBuilder::calculateHashBufferSize() const { + assert((TypeRecords.size() == TypeHashes.size() || TypeHashes.empty()) && + "either all or no type records should have hashes"); + return TypeHashes.size() * sizeof(ulittle32_t); +} + +uint32_t TpiStreamBuilder::calculateIndexOffsetSize() const { + return TypeIndexOffsets.size() * sizeof(codeview::TypeIndexOffset); +} + +Error TpiStreamBuilder::finalizeMsfLayout() { + uint32_t Length = calculateSerializedLength(); + if (auto EC = Msf.setStreamSize(Idx, Length)) + return EC; + + uint32_t HashStreamSize = + calculateHashBufferSize() + calculateIndexOffsetSize(); + + if (HashStreamSize == 0) + return Error::success(); + + auto ExpectedIndex = Msf.addStream(HashStreamSize); + if (!ExpectedIndex) + return ExpectedIndex.takeError(); + HashStreamIndex = *ExpectedIndex; + if (!TypeHashes.empty()) { + ulittle32_t *H = Allocator.Allocate<ulittle32_t>(TypeHashes.size()); + MutableArrayRef<ulittle32_t> HashBuffer(H, TypeHashes.size()); + for (uint32_t I = 0; I < TypeHashes.size(); ++I) { + HashBuffer[I] = TypeHashes[I] % (MaxTpiHashBuckets - 1); + } + ArrayRef<uint8_t> Bytes( + reinterpret_cast<const uint8_t *>(HashBuffer.data()), + calculateHashBufferSize()); + HashValueStream = + std::make_unique<BinaryByteStream>(Bytes, llvm::support::little); + } + return Error::success(); +} + +Error TpiStreamBuilder::commit(const msf::MSFLayout &Layout, + WritableBinaryStreamRef Buffer) { + if (auto EC = finalize()) + return EC; + + auto InfoS = WritableMappedBlockStream::createIndexedStream(Layout, Buffer, + Idx, Allocator); + + BinaryStreamWriter Writer(*InfoS); + if (auto EC = Writer.writeObject(*Header)) + return EC; + + for (auto Rec : TypeRecords) { + assert(!Rec.empty()); // An empty record will not write anything, but it + // would shift all offsets from here on. + if (auto EC = Writer.writeBytes(Rec)) + return EC; + } + + if (HashStreamIndex != kInvalidStreamIndex) { + auto HVS = WritableMappedBlockStream::createIndexedStream( + Layout, Buffer, HashStreamIndex, Allocator); + BinaryStreamWriter HW(*HVS); + if (HashValueStream) { + if (auto EC = HW.writeStreamRef(*HashValueStream)) + return EC; + } + + for (auto &IndexOffset : TypeIndexOffsets) { + if (auto EC = HW.writeObject(IndexOffset)) + return EC; + } + } + + return Error::success(); +} diff --git a/llvm/lib/DebugInfo/PDB/PDB.cpp b/llvm/lib/DebugInfo/PDB/PDB.cpp new file mode 100644 index 0000000000000..e7b968cb7beac --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/PDB.cpp @@ -0,0 +1,54 @@ +//===- PDB.cpp - base header file for creating a PDB reader ---------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDB.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Config/config.h" +#include "llvm/DebugInfo/PDB/GenericError.h" +#if LLVM_ENABLE_DIA_SDK +#include "llvm/DebugInfo/PDB/DIA/DIASession.h" +#endif +#include "llvm/DebugInfo/PDB/Native/NativeSession.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/MemoryBuffer.h" + +using namespace llvm; +using namespace llvm::pdb; + +Error llvm::pdb::loadDataForPDB(PDB_ReaderType Type, StringRef Path, + std::unique_ptr<IPDBSession> &Session) { + // Create the correct concrete instance type based on the value of Type. + if (Type == PDB_ReaderType::Native) { + ErrorOr<std::unique_ptr<MemoryBuffer>> ErrorOrBuffer = + MemoryBuffer::getFileOrSTDIN(Path, /*FileSize=*/-1, + /*RequiresNullTerminator=*/false); + if (!ErrorOrBuffer) + return errorCodeToError(ErrorOrBuffer.getError()); + + return NativeSession::createFromPdb(std::move(*ErrorOrBuffer), Session); + } + +#if LLVM_ENABLE_DIA_SDK + return DIASession::createFromPdb(Path, Session); +#else + return make_error<PDBError>(pdb_error_code::dia_sdk_not_present); +#endif +} + +Error llvm::pdb::loadDataForEXE(PDB_ReaderType Type, StringRef Path, + std::unique_ptr<IPDBSession> &Session) { + // Create the correct concrete instance type based on the value of Type. + if (Type == PDB_ReaderType::Native) + return NativeSession::createFromExe(Path, Session); + +#if LLVM_ENABLE_DIA_SDK + return DIASession::createFromExe(Path, Session); +#else + return make_error<PDBError>(pdb_error_code::dia_sdk_not_present); +#endif +} diff --git a/llvm/lib/DebugInfo/PDB/PDBContext.cpp b/llvm/lib/DebugInfo/PDB/PDBContext.cpp new file mode 100644 index 0000000000000..e452f1d4ced79 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/PDBContext.cpp @@ -0,0 +1,124 @@ +//===-- PDBContext.cpp ------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===/ + +#include "llvm/DebugInfo/PDB/PDBContext.h" +#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" +#include "llvm/DebugInfo/PDB/IPDBLineNumber.h" +#include "llvm/DebugInfo/PDB/IPDBSourceFile.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" +#include "llvm/DebugInfo/PDB/PDBSymbolData.h" +#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h" +#include "llvm/DebugInfo/PDB/PDBSymbolPublicSymbol.h" +#include "llvm/Object/COFF.h" + +using namespace llvm; +using namespace llvm::object; +using namespace llvm::pdb; + +PDBContext::PDBContext(const COFFObjectFile &Object, + std::unique_ptr<IPDBSession> PDBSession) + : DIContext(CK_PDB), Session(std::move(PDBSession)) { + ErrorOr<uint64_t> ImageBase = Object.getImageBase(); + if (ImageBase) + Session->setLoadAddress(ImageBase.get()); +} + +void PDBContext::dump(raw_ostream &OS, DIDumpOptions DumpOpts){} + +DILineInfo PDBContext::getLineInfoForAddress(object::SectionedAddress Address, + DILineInfoSpecifier Specifier) { + DILineInfo Result; + Result.FunctionName = getFunctionName(Address.Address, Specifier.FNKind); + + uint32_t Length = 1; + std::unique_ptr<PDBSymbol> Symbol = + Session->findSymbolByAddress(Address.Address, PDB_SymType::None); + if (auto Func = dyn_cast_or_null<PDBSymbolFunc>(Symbol.get())) { + Length = Func->getLength(); + } else if (auto Data = dyn_cast_or_null<PDBSymbolData>(Symbol.get())) { + Length = Data->getLength(); + } + + // If we couldn't find a symbol, then just assume 1 byte, so that we get + // only the line number of the first instruction. + auto LineNumbers = Session->findLineNumbersByAddress(Address.Address, Length); + if (!LineNumbers || LineNumbers->getChildCount() == 0) + return Result; + + auto LineInfo = LineNumbers->getNext(); + assert(LineInfo); + auto SourceFile = Session->getSourceFileById(LineInfo->getSourceFileId()); + + if (SourceFile && + Specifier.FLIKind != DILineInfoSpecifier::FileLineInfoKind::None) + Result.FileName = SourceFile->getFileName(); + Result.Column = LineInfo->getColumnNumber(); + Result.Line = LineInfo->getLineNumber(); + return Result; +} + +DILineInfoTable +PDBContext::getLineInfoForAddressRange(object::SectionedAddress Address, + uint64_t Size, + DILineInfoSpecifier Specifier) { + if (Size == 0) + return DILineInfoTable(); + + DILineInfoTable Table; + auto LineNumbers = Session->findLineNumbersByAddress(Address.Address, Size); + if (!LineNumbers || LineNumbers->getChildCount() == 0) + return Table; + + while (auto LineInfo = LineNumbers->getNext()) { + DILineInfo LineEntry = getLineInfoForAddress( + {LineInfo->getVirtualAddress(), Address.SectionIndex}, Specifier); + Table.push_back(std::make_pair(LineInfo->getVirtualAddress(), LineEntry)); + } + return Table; +} + +DIInliningInfo +PDBContext::getInliningInfoForAddress(object::SectionedAddress Address, + DILineInfoSpecifier Specifier) { + DIInliningInfo InlineInfo; + DILineInfo Frame = getLineInfoForAddress(Address, Specifier); + InlineInfo.addFrame(Frame); + return InlineInfo; +} + +std::vector<DILocal> +PDBContext::getLocalsForAddress(object::SectionedAddress Address) { + return std::vector<DILocal>(); +} + +std::string PDBContext::getFunctionName(uint64_t Address, + DINameKind NameKind) const { + if (NameKind == DINameKind::None) + return std::string(); + + std::unique_ptr<PDBSymbol> FuncSymbol = + Session->findSymbolByAddress(Address, PDB_SymType::Function); + auto *Func = dyn_cast_or_null<PDBSymbolFunc>(FuncSymbol.get()); + + if (NameKind == DINameKind::LinkageName) { + // It is not possible to get the mangled linkage name through a + // PDBSymbolFunc. For that we have to specifically request a + // PDBSymbolPublicSymbol. + auto PublicSym = + Session->findSymbolByAddress(Address, PDB_SymType::PublicSymbol); + if (auto *PS = dyn_cast_or_null<PDBSymbolPublicSymbol>(PublicSym.get())) { + // If we also have a function symbol, prefer the use of public symbol name + // only if it refers to the same address. The public symbol uses the + // linkage name while the function does not. + if (!Func || Func->getVirtualAddress() == PS->getVirtualAddress()) + return PS->getName(); + } + } + + return Func ? Func->getName() : std::string(); +} diff --git a/llvm/lib/DebugInfo/PDB/PDBExtras.cpp b/llvm/lib/DebugInfo/PDB/PDBExtras.cpp new file mode 100644 index 0000000000000..354a99476c4bf --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/PDBExtras.cpp @@ -0,0 +1,393 @@ +//===- PDBExtras.cpp - helper functions and classes for PDBs --------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBExtras.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; +using namespace llvm::pdb; + +#define CASE_OUTPUT_ENUM_CLASS_STR(Class, Value, Str, Stream) \ + case Class::Value: \ + Stream << Str; \ + break; + +#define CASE_OUTPUT_ENUM_CLASS_NAME(Class, Value, Stream) \ + CASE_OUTPUT_ENUM_CLASS_STR(Class, Value, #Value, Stream) + +raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, + const PDB_VariantType &Type) { + switch (Type) { + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_VariantType, Bool, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_VariantType, Single, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_VariantType, Double, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_VariantType, Int8, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_VariantType, Int16, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_VariantType, Int32, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_VariantType, Int64, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_VariantType, UInt8, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_VariantType, UInt16, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_VariantType, UInt32, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_VariantType, UInt64, OS) + default: + OS << "Unknown"; + } + return OS; +} + +raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, + const PDB_BuiltinType &Type) { + switch (Type) { + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, None, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, Void, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, Char, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, WCharT, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, Int, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, UInt, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, Float, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, BCD, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, Bool, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, Long, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, ULong, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, Currency, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, Date, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, Variant, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, Complex, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, Bitfield, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, BSTR, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, HResult, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, Char16, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, Char32, OS) + } + return OS; +} + +raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, + const PDB_CallingConv &Conv) { + OS << "__"; + switch (Conv) { + CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, NearC , "cdecl", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, FarC , "cdecl", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, NearPascal , "pascal", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, FarPascal , "pascal", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, NearFast , "fastcall", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, FarFast , "fastcall", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, NearStdCall, "stdcall", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, FarStdCall , "stdcall", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, NearSysCall, "syscall", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, FarSysCall , "syscall", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, ThisCall , "thiscall", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, MipsCall , "mipscall", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, Generic , "genericcall", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, AlphaCall , "alphacall", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, PpcCall , "ppccall", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, SHCall , "superhcall", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, ArmCall , "armcall", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, AM33Call , "am33call", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, TriCall , "tricall", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, SH5Call , "sh5call", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, M32RCall , "m32rcall", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, ClrCall , "clrcall", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, Inline , "inlinecall", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, NearVector , "vectorcall", OS) + } + return OS; +} + +raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, const PDB_DataKind &Data) { + switch (Data) { + CASE_OUTPUT_ENUM_CLASS_STR(PDB_DataKind, Unknown, "unknown", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_DataKind, Local, "local", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_DataKind, StaticLocal, "static local", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_DataKind, Param, "param", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_DataKind, ObjectPtr, "this ptr", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_DataKind, FileStatic, "static global", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_DataKind, Global, "global", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_DataKind, Member, "member", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_DataKind, StaticMember, "static member", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_DataKind, Constant, "const", OS) + } + return OS; +} + +raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, + const llvm::codeview::CPURegister &CpuReg) { + if (CpuReg.Cpu == llvm::codeview::CPUType::ARM64) { + switch (CpuReg.Reg) { +#define CV_REGISTERS_ARM64 +#define CV_REGISTER(name, val) \ + case codeview::RegisterId::name: \ + OS << #name; \ + return OS; +#include "llvm/DebugInfo/CodeView/CodeViewRegisters.def" +#undef CV_REGISTER +#undef CV_REGISTERS_ARM64 + + default: + break; + } + } else { + switch (CpuReg.Reg) { +#define CV_REGISTERS_X86 +#define CV_REGISTER(name, val) \ + case codeview::RegisterId::name: \ + OS << #name; \ + return OS; +#include "llvm/DebugInfo/CodeView/CodeViewRegisters.def" +#undef CV_REGISTER +#undef CV_REGISTERS_X86 + + default: + break; + } + } + OS << static_cast<int>(CpuReg.Reg); + return OS; +} + +raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, const PDB_LocType &Loc) { + switch (Loc) { + CASE_OUTPUT_ENUM_CLASS_STR(PDB_LocType, Static, "static", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_LocType, TLS, "tls", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_LocType, RegRel, "regrel", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_LocType, ThisRel, "thisrel", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_LocType, Enregistered, "register", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_LocType, BitField, "bitfield", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_LocType, Slot, "slot", OS) + 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"; + } + return OS; +} + +raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, + const codeview::ThunkOrdinal &Thunk) { + switch (Thunk) { + CASE_OUTPUT_ENUM_CLASS_NAME(codeview::ThunkOrdinal, BranchIsland, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(codeview::ThunkOrdinal, Pcode, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(codeview::ThunkOrdinal, Standard, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(codeview::ThunkOrdinal, ThisAdjustor, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(codeview::ThunkOrdinal, TrampIncremental, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(codeview::ThunkOrdinal, UnknownLoad, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(codeview::ThunkOrdinal, Vcall, OS) + } + return OS; +} + +raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, + const PDB_Checksum &Checksum) { + switch (Checksum) { + 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; +} + +raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, const PDB_Lang &Lang) { + switch (Lang) { + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, C, OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_Lang, Cpp, "C++", OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, Fortran, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, Masm, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, Pascal, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, Basic, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, Cobol, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, Link, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, Cvtres, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, Cvtpgd, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, CSharp, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, VB, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, ILAsm, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, Java, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, JScript, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, MSIL, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, HLSL, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, D, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, Swift, OS) + } + return OS; +} + +raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, const PDB_SymType &Tag) { + switch (Tag) { + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Exe, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Compiland, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, CompilandDetails, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, CompilandEnv, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Function, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Block, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Data, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Annotation, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Label, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, PublicSymbol, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, UDT, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Enum, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, FunctionSig, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, PointerType, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, ArrayType, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, BuiltinType, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Typedef, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, BaseClass, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Friend, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, FunctionArg, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, FuncDebugStart, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, FuncDebugEnd, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, UsingNamespace, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, VTableShape, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, VTable, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Custom, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Thunk, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, CustomType, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, ManagedType, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Dimension, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, CallSite, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, InlineSite, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, BaseInterface, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, VectorType, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, MatrixType, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, HLSLType, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Caller, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Callee, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Export, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, HeapAllocationSite, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, CoffGroup, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Inlinee, OS) + default: + OS << "Unknown SymTag " << uint32_t(Tag); + } + return OS; +} + +raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, + const PDB_MemberAccess &Access) { + switch (Access) { + CASE_OUTPUT_ENUM_CLASS_STR(PDB_MemberAccess, Public, "public", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_MemberAccess, Protected, "protected", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_MemberAccess, Private, "private", OS) + } + return OS; +} + +raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, const PDB_UdtType &Type) { + switch (Type) { + CASE_OUTPUT_ENUM_CLASS_STR(PDB_UdtType, Class, "class", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_UdtType, Struct, "struct", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_UdtType, Interface, "interface", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_UdtType, Union, "union", OS) + } + return OS; +} + +raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, + const PDB_Machine &Machine) { + switch (Machine) { + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, Am33, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, Amd64, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, Arm, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, ArmNT, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, Ebc, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, x86, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, Ia64, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, M32R, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, Mips16, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, MipsFpu, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, MipsFpu16, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, PowerPC, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, PowerPCFP, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, R4000, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, SH3, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, SH3DSP, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, SH4, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, SH5, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, Thumb, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, WceMipsV2, OS) + default: + OS << "Unknown"; + } + return OS; +} + +raw_ostream &llvm::pdb::dumpPDBSourceCompression(raw_ostream &OS, + uint32_t 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) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SourceCompression, DotNet, OS) + default: + OS << "Unknown (" << Compression << ")"; + } + return OS; +} + +raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, const Variant &Value) { + switch (Value.Type) { + case PDB_VariantType::Bool: + OS << (Value.Value.Bool ? "true" : "false"); + break; + case PDB_VariantType::Double: + OS << Value.Value.Double; + break; + case PDB_VariantType::Int16: + OS << Value.Value.Int16; + break; + case PDB_VariantType::Int32: + OS << Value.Value.Int32; + break; + case PDB_VariantType::Int64: + OS << Value.Value.Int64; + break; + case PDB_VariantType::Int8: + OS << static_cast<int>(Value.Value.Int8); + break; + case PDB_VariantType::Single: + OS << Value.Value.Single; + break; + case PDB_VariantType::UInt16: + OS << Value.Value.UInt16; + break; + case PDB_VariantType::UInt32: + OS << Value.Value.UInt32; + break; + case PDB_VariantType::UInt64: + OS << Value.Value.UInt64; + break; + case PDB_VariantType::UInt8: + OS << static_cast<unsigned>(Value.Value.UInt8); + break; + case PDB_VariantType::String: + OS << Value.Value.String; + break; + default: + OS << Value.Type; + } + return OS; +} + +raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, + const VersionInfo &Version) { + OS << Version.Major << "." << Version.Minor << "." << Version.Build; + return OS; +} + +raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, const TagStats &Stats) { + for (auto Tag : Stats) { + OS << Tag.first << ":" << Tag.second << " "; + } + return OS; +} diff --git a/llvm/lib/DebugInfo/PDB/PDBInterfaceAnchors.cpp b/llvm/lib/DebugInfo/PDB/PDBInterfaceAnchors.cpp new file mode 100644 index 0000000000000..8eb3311b09e35 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/PDBInterfaceAnchors.cpp @@ -0,0 +1,39 @@ +//===- PDBInterfaceAnchors.h - defines class anchor funcions ----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// Class anchors are necessary per the LLVM Coding style guide, to ensure that +// the vtable is only generated in this object file, and not in every object +// file that incldues the corresponding header. +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/IPDBDataStream.h" +#include "llvm/DebugInfo/PDB/IPDBFrameData.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" + +using namespace llvm; +using namespace llvm::pdb; + +IPDBSession::~IPDBSession() = default; + +IPDBDataStream::~IPDBDataStream() = default; + +IPDBRawSymbol::~IPDBRawSymbol() = default; + +IPDBLineNumber::~IPDBLineNumber() = default; + +IPDBTable::~IPDBTable() = default; + +IPDBInjectedSource::~IPDBInjectedSource() = default; + +IPDBSectionContrib::~IPDBSectionContrib() = default; + +IPDBFrameData::~IPDBFrameData() = default; diff --git a/llvm/lib/DebugInfo/PDB/PDBSymDumper.cpp b/llvm/lib/DebugInfo/PDB/PDBSymDumper.cpp new file mode 100644 index 0000000000000..0956a32f4a497 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/PDBSymDumper.cpp @@ -0,0 +1,146 @@ +//===- PDBSymDumper.cpp - ---------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" +#include "llvm/Support/ErrorHandling.h" + +using namespace llvm; +using namespace llvm::pdb; + +#define PDB_SYMDUMP_UNREACHABLE(Type) \ + if (RequireImpl) \ + llvm_unreachable("Attempt to dump " #Type " with no dump implementation"); + +PDBSymDumper::PDBSymDumper(bool ShouldRequireImpl) + : RequireImpl(ShouldRequireImpl) {} + +PDBSymDumper::~PDBSymDumper() = default; + +void PDBSymDumper::dump(const PDBSymbolAnnotation &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolAnnotation) +} + +void PDBSymDumper::dump(const PDBSymbolBlock &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolBlock) +} + +void PDBSymDumper::dump(const PDBSymbolCompiland &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolCompiland) +} + +void PDBSymDumper::dump(const PDBSymbolCompilandDetails &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolCompilandDetails) +} + +void PDBSymDumper::dump(const PDBSymbolCompilandEnv &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolCompilandEnv) +} + +void PDBSymDumper::dump(const PDBSymbolCustom &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolCustom) +} + +void PDBSymDumper::dump(const PDBSymbolData &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolData) +} + +void PDBSymDumper::dump(const PDBSymbolExe &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolExe) +} + +void PDBSymDumper::dump(const PDBSymbolFunc &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolFunc) +} + +void PDBSymDumper::dump(const PDBSymbolFuncDebugEnd &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolFuncDebugEnd) +} + +void PDBSymDumper::dump(const PDBSymbolFuncDebugStart &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolFuncDebugStart) +} + +void PDBSymDumper::dump(const PDBSymbolLabel &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolLabel) +} + +void PDBSymDumper::dump(const PDBSymbolPublicSymbol &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolPublicSymbol) +} + +void PDBSymDumper::dump(const PDBSymbolThunk &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolThunk) +} + +void PDBSymDumper::dump(const PDBSymbolTypeArray &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeArray) +} + +void PDBSymDumper::dump(const PDBSymbolTypeBaseClass &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeBaseClass) +} + +void PDBSymDumper::dump(const PDBSymbolTypeBuiltin &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeBuiltin) +} + +void PDBSymDumper::dump(const PDBSymbolTypeCustom &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeCustom) +} + +void PDBSymDumper::dump(const PDBSymbolTypeDimension &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeDimension) +} + +void PDBSymDumper::dump(const PDBSymbolTypeEnum &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeEnum) +} + +void PDBSymDumper::dump(const PDBSymbolTypeFriend &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeFriend) +} + +void PDBSymDumper::dump(const PDBSymbolTypeFunctionArg &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeFunctionArg) +} + +void PDBSymDumper::dump(const PDBSymbolTypeFunctionSig &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeFunctionSig) +} + +void PDBSymDumper::dump(const PDBSymbolTypeManaged &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeManaged) +} + +void PDBSymDumper::dump(const PDBSymbolTypePointer &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypePointer) +} + +void PDBSymDumper::dump(const PDBSymbolTypeTypedef &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeTypedef) +} + +void PDBSymDumper::dump(const PDBSymbolTypeUDT &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeUDT) +} + +void PDBSymDumper::dump(const PDBSymbolTypeVTable &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeVTable) +} + +void PDBSymDumper::dump(const PDBSymbolTypeVTableShape &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeVTableShape) +} + +void PDBSymDumper::dump(const PDBSymbolUnknown &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolUnknown) +} + +void PDBSymDumper::dump(const PDBSymbolUsingNamespace &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolUsingNamespace) +} diff --git a/llvm/lib/DebugInfo/PDB/PDBSymbol.cpp b/llvm/lib/DebugInfo/PDB/PDBSymbol.cpp new file mode 100644 index 0000000000000..34c8ac41d45b4 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/PDBSymbol.cpp @@ -0,0 +1,214 @@ +//===- PDBSymbol.cpp - base class for user-facing symbol types --*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbol.h" +#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" +#include "llvm/DebugInfo/PDB/IPDBRawSymbol.h" +#include "llvm/DebugInfo/PDB/IPDBSession.h" +#include "llvm/DebugInfo/PDB/PDBExtras.h" +#include "llvm/DebugInfo/PDB/PDBSymbolAnnotation.h" +#include "llvm/DebugInfo/PDB/PDBSymbolBlock.h" +#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" +#include "llvm/DebugInfo/PDB/PDBSymbolCompilandDetails.h" +#include "llvm/DebugInfo/PDB/PDBSymbolCompilandEnv.h" +#include "llvm/DebugInfo/PDB/PDBSymbolCustom.h" +#include "llvm/DebugInfo/PDB/PDBSymbolData.h" +#include "llvm/DebugInfo/PDB/PDBSymbolExe.h" +#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h" +#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugEnd.h" +#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugStart.h" +#include "llvm/DebugInfo/PDB/PDBSymbolLabel.h" +#include "llvm/DebugInfo/PDB/PDBSymbolPublicSymbol.h" +#include "llvm/DebugInfo/PDB/PDBSymbolThunk.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeArray.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeCustom.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeDimension.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeFriend.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionArg.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeManaged.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTableShape.h" +#include "llvm/DebugInfo/PDB/PDBSymbolUnknown.h" +#include "llvm/DebugInfo/PDB/PDBSymbolUsingNamespace.h" +#include "llvm/DebugInfo/PDB/PDBTypes.h" +#include <algorithm> +#include <memory> + +using namespace llvm; +using namespace llvm::pdb; + +PDBSymbol::PDBSymbol(const IPDBSession &PDBSession) : Session(PDBSession) {} + +PDBSymbol::PDBSymbol(PDBSymbol &&Other) + : Session(Other.Session), RawSymbol(std::move(Other.RawSymbol)) {} + +PDBSymbol::~PDBSymbol() = default; + +#define FACTORY_SYMTAG_CASE(Tag, Type) \ + case PDB_SymType::Tag: \ + return std::unique_ptr<PDBSymbol>(new Type(PDBSession)); + +std::unique_ptr<PDBSymbol> +PDBSymbol::createSymbol(const IPDBSession &PDBSession, PDB_SymType Tag) { + switch (Tag) { + FACTORY_SYMTAG_CASE(Exe, PDBSymbolExe) + FACTORY_SYMTAG_CASE(Compiland, PDBSymbolCompiland) + FACTORY_SYMTAG_CASE(CompilandDetails, PDBSymbolCompilandDetails) + FACTORY_SYMTAG_CASE(CompilandEnv, PDBSymbolCompilandEnv) + FACTORY_SYMTAG_CASE(Function, PDBSymbolFunc) + FACTORY_SYMTAG_CASE(Block, PDBSymbolBlock) + FACTORY_SYMTAG_CASE(Data, PDBSymbolData) + FACTORY_SYMTAG_CASE(Annotation, PDBSymbolAnnotation) + FACTORY_SYMTAG_CASE(Label, PDBSymbolLabel) + FACTORY_SYMTAG_CASE(PublicSymbol, PDBSymbolPublicSymbol) + FACTORY_SYMTAG_CASE(UDT, PDBSymbolTypeUDT) + FACTORY_SYMTAG_CASE(Enum, PDBSymbolTypeEnum) + FACTORY_SYMTAG_CASE(FunctionSig, PDBSymbolTypeFunctionSig) + FACTORY_SYMTAG_CASE(PointerType, PDBSymbolTypePointer) + FACTORY_SYMTAG_CASE(ArrayType, PDBSymbolTypeArray) + FACTORY_SYMTAG_CASE(BuiltinType, PDBSymbolTypeBuiltin) + FACTORY_SYMTAG_CASE(Typedef, PDBSymbolTypeTypedef) + FACTORY_SYMTAG_CASE(BaseClass, PDBSymbolTypeBaseClass) + FACTORY_SYMTAG_CASE(Friend, PDBSymbolTypeFriend) + FACTORY_SYMTAG_CASE(FunctionArg, PDBSymbolTypeFunctionArg) + FACTORY_SYMTAG_CASE(FuncDebugStart, PDBSymbolFuncDebugStart) + FACTORY_SYMTAG_CASE(FuncDebugEnd, PDBSymbolFuncDebugEnd) + FACTORY_SYMTAG_CASE(UsingNamespace, PDBSymbolUsingNamespace) + FACTORY_SYMTAG_CASE(VTableShape, PDBSymbolTypeVTableShape) + FACTORY_SYMTAG_CASE(VTable, PDBSymbolTypeVTable) + FACTORY_SYMTAG_CASE(Custom, PDBSymbolCustom) + FACTORY_SYMTAG_CASE(Thunk, PDBSymbolThunk) + FACTORY_SYMTAG_CASE(CustomType, PDBSymbolTypeCustom) + FACTORY_SYMTAG_CASE(ManagedType, PDBSymbolTypeManaged) + FACTORY_SYMTAG_CASE(Dimension, PDBSymbolTypeDimension) + default: + return std::unique_ptr<PDBSymbol>(new PDBSymbolUnknown(PDBSession)); + } +} + +std::unique_ptr<PDBSymbol> +PDBSymbol::create(const IPDBSession &PDBSession, + std::unique_ptr<IPDBRawSymbol> RawSymbol) { + auto SymbolPtr = createSymbol(PDBSession, RawSymbol->getSymTag()); + SymbolPtr->RawSymbol = RawSymbol.get(); + SymbolPtr->OwnedRawSymbol = std::move(RawSymbol); + return SymbolPtr; +} + +std::unique_ptr<PDBSymbol> PDBSymbol::create(const IPDBSession &PDBSession, + IPDBRawSymbol &RawSymbol) { + auto SymbolPtr = createSymbol(PDBSession, RawSymbol.getSymTag()); + SymbolPtr->RawSymbol = &RawSymbol; + return SymbolPtr; +} + +void PDBSymbol::defaultDump(raw_ostream &OS, int Indent, + PdbSymbolIdField ShowFlags, + PdbSymbolIdField RecurseFlags) const { + RawSymbol->dump(OS, Indent, ShowFlags, RecurseFlags); +} + +void PDBSymbol::dumpProperties() const { + outs() << "\n"; + defaultDump(outs(), 0, PdbSymbolIdField::All, PdbSymbolIdField::None); + outs().flush(); +} + +void PDBSymbol::dumpChildStats() const { + TagStats Stats; + getChildStats(Stats); + outs() << "\n"; + for (auto &Stat : Stats) { + outs() << Stat.first << ": " << Stat.second << "\n"; + } + outs().flush(); +} + +PDB_SymType PDBSymbol::getSymTag() const { return RawSymbol->getSymTag(); } +uint32_t PDBSymbol::getSymIndexId() const { return RawSymbol->getSymIndexId(); } + +std::unique_ptr<IPDBEnumSymbols> PDBSymbol::findAllChildren() const { + return findAllChildren(PDB_SymType::None); +} + +std::unique_ptr<IPDBEnumSymbols> +PDBSymbol::findAllChildren(PDB_SymType Type) const { + return RawSymbol->findChildren(Type); +} + +std::unique_ptr<IPDBEnumSymbols> +PDBSymbol::findChildren(PDB_SymType Type, StringRef Name, + PDB_NameSearchFlags Flags) const { + return RawSymbol->findChildren(Type, Name, Flags); +} + +std::unique_ptr<IPDBEnumSymbols> +PDBSymbol::findChildrenByRVA(PDB_SymType Type, StringRef Name, + PDB_NameSearchFlags Flags, uint32_t RVA) const { + return RawSymbol->findChildrenByRVA(Type, Name, Flags, RVA); +} + +std::unique_ptr<IPDBEnumSymbols> +PDBSymbol::findInlineFramesByRVA(uint32_t RVA) const { + return RawSymbol->findInlineFramesByRVA(RVA); +} + +std::unique_ptr<IPDBEnumSymbols> +PDBSymbol::getChildStats(TagStats &Stats) const { + std::unique_ptr<IPDBEnumSymbols> Result(findAllChildren()); + if (!Result) + return nullptr; + Stats.clear(); + while (auto Child = Result->getNext()) { + ++Stats[Child->getSymTag()]; + } + Result->reset(); + return Result; +} + +std::unique_ptr<PDBSymbol> PDBSymbol::getSymbolByIdHelper(uint32_t Id) const { + return Session.getSymbolById(Id); +} + +void llvm::pdb::dumpSymbolIdField(raw_ostream &OS, StringRef Name, + SymIndexId Value, int Indent, + const IPDBSession &Session, + PdbSymbolIdField FieldId, + PdbSymbolIdField ShowFlags, + PdbSymbolIdField RecurseFlags) { + if ((FieldId & ShowFlags) == PdbSymbolIdField::None) + return; + + OS << "\n"; + OS.indent(Indent); + OS << Name << ": " << Value; + // Don't recurse unless the user requested it. + if ((FieldId & RecurseFlags) == PdbSymbolIdField::None) + return; + // And obviously don't recurse on the symbol itself. + if (FieldId == PdbSymbolIdField::SymIndexId) + return; + + auto Child = Session.getSymbolById(Value); + + // It could have been a placeholder symbol for a type we don't yet support, + // so just exit in that case. + if (!Child) + return; + + // Don't recurse more than once, so pass PdbSymbolIdField::None) for the + // recurse flags. + Child->defaultDump(OS, Indent + 2, ShowFlags, PdbSymbolIdField::None); +} diff --git a/llvm/lib/DebugInfo/PDB/PDBSymbolAnnotation.cpp b/llvm/lib/DebugInfo/PDB/PDBSymbolAnnotation.cpp new file mode 100644 index 0000000000000..0fa83efb7ae0e --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/PDBSymbolAnnotation.cpp @@ -0,0 +1,20 @@ +//===- PDBSymbolAnnotation.cpp - --------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolAnnotation.h" + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +void PDBSymbolAnnotation::dump(PDBSymDumper &Dumper) const { + Dumper.dump(*this); +} diff --git a/llvm/lib/DebugInfo/PDB/PDBSymbolBlock.cpp b/llvm/lib/DebugInfo/PDB/PDBSymbolBlock.cpp new file mode 100644 index 0000000000000..9452282a8817b --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/PDBSymbolBlock.cpp @@ -0,0 +1,19 @@ +//===- PDBSymbolBlock.cpp - -------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolBlock.h" + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +void PDBSymbolBlock::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); } diff --git a/llvm/lib/DebugInfo/PDB/PDBSymbolCompiland.cpp b/llvm/lib/DebugInfo/PDB/PDBSymbolCompiland.cpp new file mode 100644 index 0000000000000..9b2883546305b --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/PDBSymbolCompiland.cpp @@ -0,0 +1,109 @@ +//===- PDBSymbolCompiland.cpp - compiland details ---------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#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; +using namespace llvm::pdb; + +void PDBSymbolCompiland::dump(PDBSymDumper &Dumper) const { + Dumper.dump(*this); +} + +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 == "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) { + 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", Lang == PDB_Lang::Cpp) + .Case(".cc", Lang == PDB_Lang::Cpp) + .Case(".cxx", Lang == PDB_Lang::Cpp) + .Case(".c", Lang == PDB_Lang::C) + .Case(".asm", Lang == PDB_Lang::Masm) + .Case(".swift", Lang == PDB_Lang::Swift) + .Default(false)) + return File->getFileName(); + } + } + + return SourceFileFullPath; +} diff --git a/llvm/lib/DebugInfo/PDB/PDBSymbolCompilandDetails.cpp b/llvm/lib/DebugInfo/PDB/PDBSymbolCompilandDetails.cpp new file mode 100644 index 0000000000000..0d86dfe1e632a --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/PDBSymbolCompilandDetails.cpp @@ -0,0 +1,21 @@ +//===- PDBSymbolCompilandDetails.cpp - compiland details --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolCompilandDetails.h" + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +void PDBSymbolCompilandDetails::dump(PDBSymDumper &Dumper) const { + Dumper.dump(*this); +} diff --git a/llvm/lib/DebugInfo/PDB/PDBSymbolCompilandEnv.cpp b/llvm/lib/DebugInfo/PDB/PDBSymbolCompilandEnv.cpp new file mode 100644 index 0000000000000..61f119405fd95 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/PDBSymbolCompilandEnv.cpp @@ -0,0 +1,29 @@ +//===- PDBSymbolCompilandEnv.cpp - compiland env variables ------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolCompilandEnv.h" + +#include "llvm/DebugInfo/PDB/IPDBRawSymbol.h" +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +std::string PDBSymbolCompilandEnv::getValue() const { + Variant Value = RawSymbol->getValue(); + if (Value.Type != PDB_VariantType::String) + return std::string(); + return std::string(Value.Value.String); +} + +void PDBSymbolCompilandEnv::dump(PDBSymDumper &Dumper) const { + Dumper.dump(*this); +} diff --git a/llvm/lib/DebugInfo/PDB/PDBSymbolCustom.cpp b/llvm/lib/DebugInfo/PDB/PDBSymbolCustom.cpp new file mode 100644 index 0000000000000..6c9a4aa76c3d7 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/PDBSymbolCustom.cpp @@ -0,0 +1,24 @@ +//===- PDBSymbolCustom.cpp - compiler-specific types ------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolCustom.h" + +#include "llvm/DebugInfo/PDB/IPDBRawSymbol.h" +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +void PDBSymbolCustom::getDataBytes(llvm::SmallVector<uint8_t, 32> &bytes) { + RawSymbol->getDataBytes(bytes); +} + +void PDBSymbolCustom::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); } diff --git a/llvm/lib/DebugInfo/PDB/PDBSymbolData.cpp b/llvm/lib/DebugInfo/PDB/PDBSymbolData.cpp new file mode 100644 index 0000000000000..d2b82111ccd58 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/PDBSymbolData.cpp @@ -0,0 +1,68 @@ +//===- PDBSymbolData.cpp - PDB data (e.g. variable) accessors ---*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolData.h" +#include "llvm/DebugInfo/PDB/IPDBSectionContrib.h" +#include "llvm/DebugInfo/PDB/IPDBSession.h" +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +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/llvm/lib/DebugInfo/PDB/PDBSymbolExe.cpp b/llvm/lib/DebugInfo/PDB/PDBSymbolExe.cpp new file mode 100644 index 0000000000000..c85756c43e479 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/PDBSymbolExe.cpp @@ -0,0 +1,29 @@ +//===- PDBSymbolExe.cpp - ---------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolExe.h" + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +void PDBSymbolExe::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); } + +uint32_t PDBSymbolExe::getPointerByteSize() const { + auto Pointer = findOneChild<PDBSymbolTypePointer>(); + if (Pointer) + return Pointer->getLength(); + + if (getMachineType() == PDB_Machine::x86) + return 4; + return 8; +} diff --git a/llvm/lib/DebugInfo/PDB/PDBSymbolFunc.cpp b/llvm/lib/DebugInfo/PDB/PDBSymbolFunc.cpp new file mode 100644 index 0000000000000..cb0329bc0ed72 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/PDBSymbolFunc.cpp @@ -0,0 +1,111 @@ +//===- PDBSymbolFunc.cpp - --------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h" + +#include "llvm/DebugInfo/PDB/ConcreteSymbolEnumerator.h" +#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" +#include "llvm/DebugInfo/PDB/IPDBSession.h" +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" +#include "llvm/DebugInfo/PDB/PDBSymbolData.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h" +#include "llvm/DebugInfo/PDB/PDBTypes.h" + +#include <unordered_set> +#include <utility> +#include <vector> + +using namespace llvm; +using namespace llvm::pdb; + +namespace { +class FunctionArgEnumerator : public IPDBEnumChildren<PDBSymbolData> { +public: + typedef ConcreteSymbolEnumerator<PDBSymbolData> ArgEnumeratorType; + + FunctionArgEnumerator(const IPDBSession &PDBSession, + const PDBSymbolFunc &PDBFunc) + : Session(PDBSession), Func(PDBFunc) { + // Arguments can appear multiple times if they have live range + // information, so we only take the first occurrence. + std::unordered_set<std::string> SeenNames; + auto DataChildren = Func.findAllChildren<PDBSymbolData>(); + while (auto Child = DataChildren->getNext()) { + if (Child->getDataKind() == PDB_DataKind::Param) { + std::string Name = Child->getName(); + if (SeenNames.find(Name) != SeenNames.end()) + continue; + Args.push_back(std::move(Child)); + SeenNames.insert(Name); + } + } + reset(); + } + + uint32_t getChildCount() const override { return Args.size(); } + + std::unique_ptr<PDBSymbolData> + getChildAtIndex(uint32_t Index) const override { + if (Index >= Args.size()) + return nullptr; + + return Session.getConcreteSymbolById<PDBSymbolData>( + Args[Index]->getSymIndexId()); + } + + std::unique_ptr<PDBSymbolData> getNext() override { + if (CurIter == Args.end()) + return nullptr; + const auto &Result = **CurIter; + ++CurIter; + return Session.getConcreteSymbolById<PDBSymbolData>(Result.getSymIndexId()); + } + + void reset() override { CurIter = Args.empty() ? Args.end() : Args.begin(); } + +private: + typedef std::vector<std::unique_ptr<PDBSymbolData>> ArgListType; + const IPDBSession &Session; + const PDBSymbolFunc &Func; + ArgListType Args; + ArgListType::const_iterator CurIter; +}; +} + +std::unique_ptr<IPDBEnumChildren<PDBSymbolData>> +PDBSymbolFunc::getArguments() const { + return std::make_unique<FunctionArgEnumerator>(Session, *this); +} + +void PDBSymbolFunc::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); } + +bool PDBSymbolFunc::isDestructor() const { + std::string Name = getName(); + if (Name.empty()) + return false; + if (Name[0] == '~') + return true; + if (Name == "__vecDelDtor") + 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/llvm/lib/DebugInfo/PDB/PDBSymbolFuncDebugEnd.cpp b/llvm/lib/DebugInfo/PDB/PDBSymbolFuncDebugEnd.cpp new file mode 100644 index 0000000000000..66433dc17b49c --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/PDBSymbolFuncDebugEnd.cpp @@ -0,0 +1,21 @@ +//===- PDBSymbolFuncDebugEnd.cpp - ------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugEnd.h" + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +void PDBSymbolFuncDebugEnd::dump(PDBSymDumper &Dumper) const { + Dumper.dump(*this); +} diff --git a/llvm/lib/DebugInfo/PDB/PDBSymbolFuncDebugStart.cpp b/llvm/lib/DebugInfo/PDB/PDBSymbolFuncDebugStart.cpp new file mode 100644 index 0000000000000..fe32c93c01211 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/PDBSymbolFuncDebugStart.cpp @@ -0,0 +1,21 @@ +//===- PDBSymbolFuncDebugStart.cpp - ----------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugStart.h" + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +void PDBSymbolFuncDebugStart::dump(PDBSymDumper &Dumper) const { + Dumper.dump(*this); +} diff --git a/llvm/lib/DebugInfo/PDB/PDBSymbolLabel.cpp b/llvm/lib/DebugInfo/PDB/PDBSymbolLabel.cpp new file mode 100644 index 0000000000000..1fffe69a0c830 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/PDBSymbolLabel.cpp @@ -0,0 +1,18 @@ +//===- PDBSymbolLabel.cpp - -------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolLabel.h" + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +void PDBSymbolLabel::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); } diff --git a/llvm/lib/DebugInfo/PDB/PDBSymbolPublicSymbol.cpp b/llvm/lib/DebugInfo/PDB/PDBSymbolPublicSymbol.cpp new file mode 100644 index 0000000000000..08697683f6415 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/PDBSymbolPublicSymbol.cpp @@ -0,0 +1,21 @@ +//===- PDBSymbolPublicSymbol.cpp - ------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolPublicSymbol.h" + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +void PDBSymbolPublicSymbol::dump(PDBSymDumper &Dumper) const { + Dumper.dump(*this); +} diff --git a/llvm/lib/DebugInfo/PDB/PDBSymbolThunk.cpp b/llvm/lib/DebugInfo/PDB/PDBSymbolThunk.cpp new file mode 100644 index 0000000000000..6483858183e53 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/PDBSymbolThunk.cpp @@ -0,0 +1,18 @@ +//===- PDBSymbolThunk.cpp - -------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolThunk.h" + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +void PDBSymbolThunk::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); } diff --git a/llvm/lib/DebugInfo/PDB/PDBSymbolTypeArray.cpp b/llvm/lib/DebugInfo/PDB/PDBSymbolTypeArray.cpp new file mode 100644 index 0000000000000..a0d521abe43f3 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/PDBSymbolTypeArray.cpp @@ -0,0 +1,24 @@ +//===- PDBSymbolTypeArray.cpp - ---------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolTypeArray.h" + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +void PDBSymbolTypeArray::dump(PDBSymDumper &Dumper) const { + Dumper.dump(*this); +} + +void PDBSymbolTypeArray::dumpRight(PDBSymDumper &Dumper) const { + Dumper.dumpRight(*this); +} diff --git a/llvm/lib/DebugInfo/PDB/PDBSymbolTypeBaseClass.cpp b/llvm/lib/DebugInfo/PDB/PDBSymbolTypeBaseClass.cpp new file mode 100644 index 0000000000000..08467059b5e14 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/PDBSymbolTypeBaseClass.cpp @@ -0,0 +1,21 @@ +//===- PDBSymbolTypeBaseClass.cpp - -----------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h" + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +void PDBSymbolTypeBaseClass::dump(PDBSymDumper &Dumper) const { + Dumper.dump(*this); +} diff --git a/llvm/lib/DebugInfo/PDB/PDBSymbolTypeBuiltin.cpp b/llvm/lib/DebugInfo/PDB/PDBSymbolTypeBuiltin.cpp new file mode 100644 index 0000000000000..a0dd9ef601c0b --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/PDBSymbolTypeBuiltin.cpp @@ -0,0 +1,20 @@ +//===- PDBSymbolTypeBuiltin.cpp - ------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +void PDBSymbolTypeBuiltin::dump(PDBSymDumper &Dumper) const { + Dumper.dump(*this); +} diff --git a/llvm/lib/DebugInfo/PDB/PDBSymbolTypeCustom.cpp b/llvm/lib/DebugInfo/PDB/PDBSymbolTypeCustom.cpp new file mode 100644 index 0000000000000..6723894c90ea8 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/PDBSymbolTypeCustom.cpp @@ -0,0 +1,21 @@ +//===- PDBSymbolTypeCustom.cpp - --------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolTypeCustom.h" + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +void PDBSymbolTypeCustom::dump(PDBSymDumper &Dumper) const { + Dumper.dump(*this); +} diff --git a/llvm/lib/DebugInfo/PDB/PDBSymbolTypeDimension.cpp b/llvm/lib/DebugInfo/PDB/PDBSymbolTypeDimension.cpp new file mode 100644 index 0000000000000..4a25a391f278e --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/PDBSymbolTypeDimension.cpp @@ -0,0 +1,21 @@ +//===- PDBSymbolTypeDimension.cpp - --------------------------------*- C++ +//-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolTypeDimension.h" + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; +void PDBSymbolTypeDimension::dump(PDBSymDumper &Dumper) const { + Dumper.dump(*this); +} diff --git a/llvm/lib/DebugInfo/PDB/PDBSymbolTypeEnum.cpp b/llvm/lib/DebugInfo/PDB/PDBSymbolTypeEnum.cpp new file mode 100644 index 0000000000000..b9fdf6aec8114 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/PDBSymbolTypeEnum.cpp @@ -0,0 +1,19 @@ +//===- PDBSymbolTypeEnum.cpp - --------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +void PDBSymbolTypeEnum::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); } diff --git a/llvm/lib/DebugInfo/PDB/PDBSymbolTypeFriend.cpp b/llvm/lib/DebugInfo/PDB/PDBSymbolTypeFriend.cpp new file mode 100644 index 0000000000000..4ffea42cbb0a7 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/PDBSymbolTypeFriend.cpp @@ -0,0 +1,21 @@ +//===- PDBSymbolTypeFriend.cpp - --------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolTypeFriend.h" + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +void PDBSymbolTypeFriend::dump(PDBSymDumper &Dumper) const { + Dumper.dump(*this); +} diff --git a/llvm/lib/DebugInfo/PDB/PDBSymbolTypeFunctionArg.cpp b/llvm/lib/DebugInfo/PDB/PDBSymbolTypeFunctionArg.cpp new file mode 100644 index 0000000000000..683e93548fb14 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/PDBSymbolTypeFunctionArg.cpp @@ -0,0 +1,20 @@ +//===- PDBSymbolTypeFunctionArg.cpp - --------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionArg.h" + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +void PDBSymbolTypeFunctionArg::dump(PDBSymDumper &Dumper) const { + Dumper.dump(*this); +} diff --git a/llvm/lib/DebugInfo/PDB/PDBSymbolTypeFunctionSig.cpp b/llvm/lib/DebugInfo/PDB/PDBSymbolTypeFunctionSig.cpp new file mode 100644 index 0000000000000..1373615522eb2 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/PDBSymbolTypeFunctionSig.cpp @@ -0,0 +1,93 @@ +//===- PDBSymbolTypeFunctionSig.cpp - --------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h" + +#include "llvm/DebugInfo/PDB/ConcreteSymbolEnumerator.h" +#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" +#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> + +using namespace llvm; +using namespace llvm::pdb; + +namespace { +class FunctionArgEnumerator : public IPDBEnumSymbols { +public: + typedef ConcreteSymbolEnumerator<PDBSymbolTypeFunctionArg> ArgEnumeratorType; + + FunctionArgEnumerator(const IPDBSession &PDBSession, + const PDBSymbolTypeFunctionSig &Sig) + : Session(PDBSession), + Enumerator(Sig.findAllChildren<PDBSymbolTypeFunctionArg>()) {} + + FunctionArgEnumerator(const IPDBSession &PDBSession, + std::unique_ptr<ArgEnumeratorType> ArgEnumerator) + : Session(PDBSession), Enumerator(std::move(ArgEnumerator)) {} + + uint32_t getChildCount() const override { + return Enumerator->getChildCount(); + } + + std::unique_ptr<PDBSymbol> getChildAtIndex(uint32_t Index) const override { + auto FunctionArgSymbol = Enumerator->getChildAtIndex(Index); + if (!FunctionArgSymbol) + return nullptr; + return Session.getSymbolById(FunctionArgSymbol->getTypeId()); + } + + std::unique_ptr<PDBSymbol> getNext() override { + auto FunctionArgSymbol = Enumerator->getNext(); + if (!FunctionArgSymbol) + return nullptr; + return Session.getSymbolById(FunctionArgSymbol->getTypeId()); + } + + void reset() override { Enumerator->reset(); } + +private: + const IPDBSession &Session; + std::unique_ptr<ArgEnumeratorType> Enumerator; +}; +} + +std::unique_ptr<IPDBEnumSymbols> +PDBSymbolTypeFunctionSig::getArguments() const { + return std::make_unique<FunctionArgEnumerator>(Session, *this); +} + +void PDBSymbolTypeFunctionSig::dump(PDBSymDumper &Dumper) const { + Dumper.dump(*this); +} + +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; +} diff --git a/llvm/lib/DebugInfo/PDB/PDBSymbolTypeManaged.cpp b/llvm/lib/DebugInfo/PDB/PDBSymbolTypeManaged.cpp new file mode 100644 index 0000000000000..e80e6c716572a --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/PDBSymbolTypeManaged.cpp @@ -0,0 +1,21 @@ +//===- PDBSymboTypelManaged.cpp - ------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolTypeManaged.h" + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +void PDBSymbolTypeManaged::dump(PDBSymDumper &Dumper) const { + Dumper.dump(*this); +} diff --git a/llvm/lib/DebugInfo/PDB/PDBSymbolTypePointer.cpp b/llvm/lib/DebugInfo/PDB/PDBSymbolTypePointer.cpp new file mode 100644 index 0000000000000..462fc315359b5 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/PDBSymbolTypePointer.cpp @@ -0,0 +1,25 @@ +//===- PDBSymbolTypePointer.cpp -----------------------------------*- C++ -===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h" + +#include "llvm/DebugInfo/PDB/IPDBSession.h" +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +void PDBSymbolTypePointer::dump(PDBSymDumper &Dumper) const { + Dumper.dump(*this); +} + +void PDBSymbolTypePointer::dumpRight(PDBSymDumper &Dumper) const { + Dumper.dumpRight(*this); +} diff --git a/llvm/lib/DebugInfo/PDB/PDBSymbolTypeTypedef.cpp b/llvm/lib/DebugInfo/PDB/PDBSymbolTypeTypedef.cpp new file mode 100644 index 0000000000000..70749d9bf5f51 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/PDBSymbolTypeTypedef.cpp @@ -0,0 +1,20 @@ +//===- PDBSymbolTypeTypedef.cpp ---------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h" + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +void PDBSymbolTypeTypedef::dump(PDBSymDumper &Dumper) const { + Dumper.dump(*this); +} diff --git a/llvm/lib/DebugInfo/PDB/PDBSymbolTypeUDT.cpp b/llvm/lib/DebugInfo/PDB/PDBSymbolTypeUDT.cpp new file mode 100644 index 0000000000000..d302c29a3bec3 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/PDBSymbolTypeUDT.cpp @@ -0,0 +1,25 @@ +//===- PDBSymbolTypeUDT.cpp - --------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" + +#include "llvm/DebugInfo/PDB/IPDBSession.h" +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" +#include "llvm/DebugInfo/PDB/PDBSymbolData.h" +#include "llvm/DebugInfo/PDB/PDBSymbolExe.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTableShape.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +void PDBSymbolTypeUDT::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); } diff --git a/llvm/lib/DebugInfo/PDB/PDBSymbolTypeVTable.cpp b/llvm/lib/DebugInfo/PDB/PDBSymbolTypeVTable.cpp new file mode 100644 index 0000000000000..4e2a45116d512 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/PDBSymbolTypeVTable.cpp @@ -0,0 +1,20 @@ +//===- PDBSymbolTypeVTable.cpp - --------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h" + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +void PDBSymbolTypeVTable::dump(PDBSymDumper &Dumper) const { + Dumper.dump(*this); +} diff --git a/llvm/lib/DebugInfo/PDB/PDBSymbolTypeVTableShape.cpp b/llvm/lib/DebugInfo/PDB/PDBSymbolTypeVTableShape.cpp new file mode 100644 index 0000000000000..78957620e0836 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/PDBSymbolTypeVTableShape.cpp @@ -0,0 +1,21 @@ +//===- PDBSymbolTypeVTableShape.cpp - ---------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTableShape.h" + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +void PDBSymbolTypeVTableShape::dump(PDBSymDumper &Dumper) const { + Dumper.dump(*this); +} diff --git a/llvm/lib/DebugInfo/PDB/PDBSymbolUnknown.cpp b/llvm/lib/DebugInfo/PDB/PDBSymbolUnknown.cpp new file mode 100644 index 0000000000000..650d01183171b --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/PDBSymbolUnknown.cpp @@ -0,0 +1,19 @@ +//===- PDBSymbolUnknown.cpp - -----------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolUnknown.h" + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +void PDBSymbolUnknown::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); } diff --git a/llvm/lib/DebugInfo/PDB/PDBSymbolUsingNamespace.cpp b/llvm/lib/DebugInfo/PDB/PDBSymbolUsingNamespace.cpp new file mode 100644 index 0000000000000..74afbdb180865 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/PDBSymbolUsingNamespace.cpp @@ -0,0 +1,21 @@ +//===- PDBSymbolUsingNamespace.cpp - ------------------- --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolUsingNamespace.h" + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +void PDBSymbolUsingNamespace::dump(PDBSymDumper &Dumper) const { + Dumper.dump(*this); +} diff --git a/llvm/lib/DebugInfo/PDB/UDTLayout.cpp b/llvm/lib/DebugInfo/PDB/UDTLayout.cpp new file mode 100644 index 0000000000000..a8e1d0a619cab --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/UDTLayout.cpp @@ -0,0 +1,302 @@ +//===- UDTLayout.cpp ------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/UDTLayout.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/DebugInfo/PDB/IPDBRawSymbol.h" +#include "llvm/DebugInfo/PDB/IPDBSession.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" +#include "llvm/DebugInfo/PDB/PDBSymbolData.h" +#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h" +#include "llvm/DebugInfo/PDB/PDBTypes.h" +#include "llvm/Support/Casting.h" +#include <algorithm> +#include <cassert> +#include <cstdint> +#include <memory> + +using namespace llvm; +using namespace llvm::pdb; + +static std::unique_ptr<PDBSymbol> getSymbolType(const PDBSymbol &Symbol) { + const IPDBSession &Session = Symbol.getSession(); + const IPDBRawSymbol &RawSymbol = Symbol.getRawSymbol(); + uint32_t TypeId = RawSymbol.getTypeId(); + return Session.getSymbolById(TypeId); +} + +static uint32_t getTypeLength(const PDBSymbol &Symbol) { + auto SymbolType = getSymbolType(Symbol); + const IPDBRawSymbol &RawType = SymbolType->getRawSymbol(); + + return RawType.getLength(); +} + +LayoutItemBase::LayoutItemBase(const UDTLayoutBase *Parent, + const PDBSymbol *Symbol, const std::string &Name, + uint32_t OffsetInParent, uint32_t Size, + bool IsElided) + : Symbol(Symbol), Parent(Parent), Name(Name), + OffsetInParent(OffsetInParent), SizeOf(Size), LayoutSize(Size), + IsElided(IsElided) { + UsedBytes.resize(SizeOf, true); +} + +uint32_t LayoutItemBase::deepPaddingSize() const { + return UsedBytes.size() - UsedBytes.count(); +} + +uint32_t LayoutItemBase::tailPadding() const { + int Last = UsedBytes.find_last(); + + return UsedBytes.size() - (Last + 1); +} + +DataMemberLayoutItem::DataMemberLayoutItem( + const UDTLayoutBase &Parent, std::unique_ptr<PDBSymbolData> Member) + : LayoutItemBase(&Parent, Member.get(), Member->getName(), + Member->getOffset(), getTypeLength(*Member), false), + DataMember(std::move(Member)) { + auto Type = DataMember->getType(); + if (auto UDT = unique_dyn_cast<PDBSymbolTypeUDT>(Type)) { + UdtLayout = std::make_unique<ClassLayout>(std::move(UDT)); + UsedBytes = UdtLayout->usedBytes(); + } +} + +VBPtrLayoutItem::VBPtrLayoutItem(const UDTLayoutBase &Parent, + std::unique_ptr<PDBSymbolTypeBuiltin> Sym, + uint32_t Offset, uint32_t Size) + : LayoutItemBase(&Parent, Sym.get(), "<vbptr>", Offset, Size, false), + Type(std::move(Sym)) { +} + +const PDBSymbolData &DataMemberLayoutItem::getDataMember() { + return *cast<PDBSymbolData>(Symbol); +} + +bool DataMemberLayoutItem::hasUDTLayout() const { return UdtLayout != nullptr; } + +const ClassLayout &DataMemberLayoutItem::getUDTLayout() const { + return *UdtLayout; +} + +VTableLayoutItem::VTableLayoutItem(const UDTLayoutBase &Parent, + std::unique_ptr<PDBSymbolTypeVTable> VT) + : LayoutItemBase(&Parent, VT.get(), "<vtbl>", 0, getTypeLength(*VT), false), + VTable(std::move(VT)) { + auto VTableType = cast<PDBSymbolTypePointer>(VTable->getType()); + ElementSize = VTableType->getLength(); +} + +UDTLayoutBase::UDTLayoutBase(const UDTLayoutBase *Parent, const PDBSymbol &Sym, + const std::string &Name, uint32_t OffsetInParent, + uint32_t Size, bool IsElided) + : LayoutItemBase(Parent, &Sym, Name, OffsetInParent, Size, IsElided) { + // UDT storage comes from a union of all the children's storage, so start out + // uninitialized. + UsedBytes.reset(0, Size); + + initializeChildren(Sym); + if (LayoutSize < Size) + UsedBytes.resize(LayoutSize); +} + +uint32_t UDTLayoutBase::tailPadding() const { + uint32_t Abs = LayoutItemBase::tailPadding(); + if (!LayoutItems.empty()) { + const LayoutItemBase *Back = LayoutItems.back(); + uint32_t ChildPadding = Back->LayoutItemBase::tailPadding(); + if (Abs < ChildPadding) + Abs = 0; + else + Abs -= ChildPadding; + } + return Abs; +} + +ClassLayout::ClassLayout(const PDBSymbolTypeUDT &UDT) + : UDTLayoutBase(nullptr, UDT, UDT.getName(), 0, UDT.getLength(), false), + UDT(UDT) { + ImmediateUsedBytes.resize(SizeOf, false); + for (auto &LI : LayoutItems) { + uint32_t Begin = LI->getOffsetInParent(); + uint32_t End = Begin + LI->getLayoutSize(); + End = std::min(SizeOf, End); + ImmediateUsedBytes.set(Begin, End); + } +} + +ClassLayout::ClassLayout(std::unique_ptr<PDBSymbolTypeUDT> UDT) + : ClassLayout(*UDT) { + OwnedStorage = std::move(UDT); +} + +uint32_t ClassLayout::immediatePadding() const { + return SizeOf - ImmediateUsedBytes.count(); +} + +BaseClassLayout::BaseClassLayout(const UDTLayoutBase &Parent, + uint32_t OffsetInParent, bool Elide, + std::unique_ptr<PDBSymbolTypeBaseClass> B) + : UDTLayoutBase(&Parent, *B, B->getName(), OffsetInParent, B->getLength(), + Elide), + Base(std::move(B)) { + if (isEmptyBase()) { + // Special case an empty base so that it doesn't get treated as padding. + UsedBytes.resize(1); + UsedBytes.set(0); + } + IsVirtualBase = Base->isVirtualBaseClass(); +} + +void UDTLayoutBase::initializeChildren(const PDBSymbol &Sym) { + // Handled bases first, followed by VTables, followed by data members, + // followed by functions, followed by other. This ordering is necessary + // so that bases and vtables get initialized before any functions which + // may override them. + UniquePtrVector<PDBSymbolTypeBaseClass> Bases; + UniquePtrVector<PDBSymbolTypeVTable> VTables; + UniquePtrVector<PDBSymbolData> Members; + UniquePtrVector<PDBSymbolTypeBaseClass> VirtualBaseSyms; + + auto Children = Sym.findAllChildren(); + while (auto Child = Children->getNext()) { + if (auto Base = unique_dyn_cast<PDBSymbolTypeBaseClass>(Child)) { + if (Base->isVirtualBaseClass()) + VirtualBaseSyms.push_back(std::move(Base)); + else + Bases.push_back(std::move(Base)); + } + else if (auto Data = unique_dyn_cast<PDBSymbolData>(Child)) { + if (Data->getDataKind() == PDB_DataKind::Member) + Members.push_back(std::move(Data)); + else + Other.push_back(std::move(Data)); + } else if (auto VT = unique_dyn_cast<PDBSymbolTypeVTable>(Child)) + VTables.push_back(std::move(VT)); + else if (auto Func = unique_dyn_cast<PDBSymbolFunc>(Child)) + Funcs.push_back(std::move(Func)); + else { + Other.push_back(std::move(Child)); + } + } + + // We don't want to have any re-allocations in the list of bases, so make + // sure to reserve enough space so that our ArrayRefs don't get invalidated. + AllBases.reserve(Bases.size() + VirtualBaseSyms.size()); + + // Only add non-virtual bases to the class first. Only at the end of the + // class, after all non-virtual bases and data members have been added do we + // add virtual bases. This way the offsets are correctly aligned when we go + // to lay out virtual bases. + for (auto &Base : Bases) { + uint32_t Offset = Base->getOffset(); + // Non-virtual bases never get elided. + auto BL = std::make_unique<BaseClassLayout>(*this, Offset, false, + std::move(Base)); + + AllBases.push_back(BL.get()); + addChildToLayout(std::move(BL)); + } + NonVirtualBases = AllBases; + + assert(VTables.size() <= 1); + if (!VTables.empty()) { + auto VTLayout = + std::make_unique<VTableLayoutItem>(*this, std::move(VTables[0])); + + VTable = VTLayout.get(); + + addChildToLayout(std::move(VTLayout)); + } + + for (auto &Data : Members) { + auto DM = std::make_unique<DataMemberLayoutItem>(*this, std::move(Data)); + + addChildToLayout(std::move(DM)); + } + + // Make sure add virtual bases before adding functions, since functions may be + // overrides of virtual functions declared in a virtual base, so the VTables + // and virtual intros need to be correctly initialized. + for (auto &VB : VirtualBaseSyms) { + int VBPO = VB->getVirtualBasePointerOffset(); + if (!hasVBPtrAtOffset(VBPO)) { + if (auto VBP = VB->getRawSymbol().getVirtualBaseTableType()) { + auto VBPL = std::make_unique<VBPtrLayoutItem>(*this, std::move(VBP), + VBPO, VBP->getLength()); + VBPtr = VBPL.get(); + addChildToLayout(std::move(VBPL)); + } + } + + // Virtual bases always go at the end. So just look for the last place we + // ended when writing something, and put our virtual base there. + // Note that virtual bases get elided unless this is a top-most derived + // class. + uint32_t Offset = UsedBytes.find_last() + 1; + bool Elide = (Parent != nullptr); + auto BL = + std::make_unique<BaseClassLayout>(*this, Offset, Elide, std::move(VB)); + AllBases.push_back(BL.get()); + + // Only lay this virtual base out directly inside of *this* class if this + // is a top-most derived class. Keep track of it regardless, but only + // physically lay it out if it's a topmost derived class. + addChildToLayout(std::move(BL)); + } + VirtualBases = makeArrayRef(AllBases).drop_front(NonVirtualBases.size()); + + if (Parent != nullptr) + LayoutSize = UsedBytes.find_last() + 1; +} + +bool UDTLayoutBase::hasVBPtrAtOffset(uint32_t Off) const { + if (VBPtr && VBPtr->getOffsetInParent() == Off) + return true; + for (BaseClassLayout *BL : AllBases) { + if (BL->hasVBPtrAtOffset(Off - BL->getOffsetInParent())) + return true; + } + return false; +} + +void UDTLayoutBase::addChildToLayout(std::unique_ptr<LayoutItemBase> Child) { + uint32_t Begin = Child->getOffsetInParent(); + + if (!Child->isElided()) { + BitVector ChildBytes = Child->usedBytes(); + + // Suppose the child occupies 4 bytes starting at offset 12 in a 32 byte + // class. When we call ChildBytes.resize(32), the Child's storage will + // still begin at offset 0, so we need to shift it left by offset bytes + // to get it into the right position. + ChildBytes.resize(UsedBytes.size()); + ChildBytes <<= Child->getOffsetInParent(); + UsedBytes |= ChildBytes; + + if (ChildBytes.count() > 0) { + auto Loc = std::upper_bound(LayoutItems.begin(), LayoutItems.end(), Begin, + [](uint32_t Off, const LayoutItemBase *Item) { + return (Off < Item->getOffsetInParent()); + }); + + LayoutItems.insert(Loc, Child.get()); + } + } + + ChildStorage.push_back(std::move(Child)); +} |
