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)); +}  | 
