From ee6fb7079a3303b705fd3385e4d56dcb468c3b30 Mon Sep 17 00:00:00 2001 From: Adrian McCarthy Date: Fri, 4 Aug 2017 22:37:58 +0000 Subject: [PATCH] Enable llvm-pdbutil to list enumerations using native PDB reader This extends the native reader to enable llvm-pdbutil to list the enums in a PDB and it includes a simple test. It does not yet list the values in the enumerations, which requires an actual implementation of NativeEnumSymbol::FindChildren. To exercise this code, use a command like: llvm-pdbutil pretty -native -enums foo.pdb Differential Revision: https://reviews.llvm.org/D35738 llvm-svn: 310144 --- .../DebugInfo/PDB/Native/NativeEnumSymbol.h | 60 ++++++++++ .../DebugInfo/PDB/Native/NativeEnumTypes.h | 51 +++++++++ .../llvm/DebugInfo/PDB/Native/NativeSession.h | 6 + include/llvm/DebugInfo/PDB/PDBSymbol.h | 4 +- lib/DebugInfo/PDB/CMakeLists.txt | 2 + lib/DebugInfo/PDB/Native/NativeEnumSymbol.cpp | 108 ++++++++++++++++++ lib/DebugInfo/PDB/Native/NativeEnumTypes.cpp | 59 ++++++++++ lib/DebugInfo/PDB/Native/NativeExeSymbol.cpp | 4 + lib/DebugInfo/PDB/Native/NativeSession.cpp | 41 ++++++- .../PDB/Native/pdb-native-enums.test | 6 + tools/llvm-pdbutil/PrettyEnumDumper.cpp | 32 +++--- 11 files changed, 354 insertions(+), 19 deletions(-) create mode 100644 include/llvm/DebugInfo/PDB/Native/NativeEnumSymbol.h create mode 100644 include/llvm/DebugInfo/PDB/Native/NativeEnumTypes.h create mode 100644 lib/DebugInfo/PDB/Native/NativeEnumSymbol.cpp create mode 100644 lib/DebugInfo/PDB/Native/NativeEnumTypes.cpp create mode 100644 test/DebugInfo/PDB/Native/pdb-native-enums.test diff --git a/include/llvm/DebugInfo/PDB/Native/NativeEnumSymbol.h b/include/llvm/DebugInfo/PDB/Native/NativeEnumSymbol.h new file mode 100644 index 00000000000..41b7b78b8d8 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Native/NativeEnumSymbol.h @@ -0,0 +1,60 @@ +//===- NativeEnumSymbol.h - info about enum type ----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_NATIVE_NATIVEENUMSYMBOL_H +#define LLVM_DEBUGINFO_PDB_NATIVE_NATIVEENUMSYMBOL_H + +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" +#include "llvm/DebugInfo/PDB/Native/NativeRawSymbol.h" +#include "llvm/DebugInfo/PDB/Native/NativeSession.h" + +namespace llvm { +namespace pdb { + +class NativeEnumSymbol : public NativeRawSymbol, + public codeview::TypeVisitorCallbacks { +public: + NativeEnumSymbol(NativeSession &Session, SymIndexId Id, + const codeview::CVType &CV); + ~NativeEnumSymbol() override; + + std::unique_ptr clone() const override; + + std::unique_ptr + findChildren(PDB_SymType Type) const override; + + Error visitKnownRecord(codeview::CVType &CVR, + codeview::EnumRecord &Record) override; + Error visitKnownMember(codeview::CVMemberRecord &CVM, + codeview::EnumeratorRecord &Record) override; + + PDB_SymType getSymTag() const override; + uint32_t getClassParentId() const override; + uint32_t getUnmodifiedTypeId() const override; + bool hasConstructor() const override; + bool hasAssignmentOperator() const override; + bool hasCastOperator() const override; + uint64_t getLength() const override; + std::string getName() const override; + bool isNested() const override; + bool hasOverloadedOperator() const override; + bool isPacked() const override; + bool isScoped() const override; + uint32_t getTypeId() const override; + +protected: + codeview::CVType CV; + codeview::EnumRecord Record; +}; + +} // namespace pdb +} // namespace llvm + +#endif // LLVM_DEBUGINFO_PDB_NATIVE_NATIVEENUMSYMBOL_H diff --git a/include/llvm/DebugInfo/PDB/Native/NativeEnumTypes.h b/include/llvm/DebugInfo/PDB/Native/NativeEnumTypes.h new file mode 100644 index 00000000000..e0a5c8d9ad8 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Native/NativeEnumTypes.h @@ -0,0 +1,51 @@ +//==- NativeEnumTypes.h - Native Type Enumerator impl ------------*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_NATIVE_NATIVEENUMTYPES_H +#define LLVM_DEBUGINFO_PDB_NATIVE_NATIVEENUMTYPES_H + +#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" + +#include + +namespace llvm { +namespace pdb { + +class NativeSession; + +class NativeEnumTypes : public IPDBEnumChildren { +public: + NativeEnumTypes(NativeSession &Session, + codeview::LazyRandomTypeCollection &TypeCollection, + codeview::TypeLeafKind Kind); + + uint32_t getChildCount() const override; + std::unique_ptr getChildAtIndex(uint32_t Index) const override; + std::unique_ptr getNext() override; + void reset() override; + NativeEnumTypes *clone() const override; + +private: + NativeEnumTypes(NativeSession &Session, + const std::vector &Matches, + codeview::TypeLeafKind Kind); + + std::vector Matches; + uint32_t Index; + NativeSession &Session; + codeview::TypeLeafKind Kind; +}; + +} // namespace pdb +} // namespace llvm + +#endif diff --git a/include/llvm/DebugInfo/PDB/Native/NativeSession.h b/include/llvm/DebugInfo/PDB/Native/NativeSession.h index b16ce231c34..77067311550 100644 --- a/include/llvm/DebugInfo/PDB/Native/NativeSession.h +++ b/include/llvm/DebugInfo/PDB/Native/NativeSession.h @@ -39,6 +39,12 @@ public: std::unique_ptr createCompilandSymbol(DbiModuleDescriptor MI); + std::unique_ptr + createEnumSymbol(codeview::TypeIndex Index); + + std::unique_ptr + createTypeEnumerator(codeview::TypeLeafKind Kind); + SymIndexId findSymbolByTypeIndex(codeview::TypeIndex TI); uint64_t getLoadAddress() const override; diff --git a/include/llvm/DebugInfo/PDB/PDBSymbol.h b/include/llvm/DebugInfo/PDB/PDBSymbol.h index 9e883d2f99a..04373463212 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbol.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbol.h @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_DEBUGINFO_PDB_IPDBSYMBOL_H -#define LLVM_DEBUGINFO_PDB_IPDBSYMBOL_H +#ifndef LLVM_DEBUGINFO_PDB_PDBSYMBOL_H +#define LLVM_DEBUGINFO_PDB_PDBSYMBOL_H #include "ConcreteSymbolEnumerator.h" #include "IPDBRawSymbol.h" diff --git a/lib/DebugInfo/PDB/CMakeLists.txt b/lib/DebugInfo/PDB/CMakeLists.txt index 2658584639c..37eca01f81c 100644 --- a/lib/DebugInfo/PDB/CMakeLists.txt +++ b/lib/DebugInfo/PDB/CMakeLists.txt @@ -44,6 +44,8 @@ add_pdb_impl_folder(Native Native/NativeBuiltinSymbol.cpp Native/NativeCompilandSymbol.cpp Native/NativeEnumModules.cpp + Native/NativeEnumSymbol.cpp + Native/NativeEnumTypes.cpp Native/NativeExeSymbol.cpp Native/NativeRawSymbol.cpp Native/NamedStreamMap.cpp diff --git a/lib/DebugInfo/PDB/Native/NativeEnumSymbol.cpp b/lib/DebugInfo/PDB/Native/NativeEnumSymbol.cpp new file mode 100644 index 00000000000..38d65917306 --- /dev/null +++ b/lib/DebugInfo/PDB/Native/NativeEnumSymbol.cpp @@ -0,0 +1,108 @@ +//===- NativeEnumSymbol.cpp - info about enum type --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/NativeEnumSymbol.h" + +#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" + +#include + +using namespace llvm; +using namespace llvm::pdb; + +NativeEnumSymbol::NativeEnumSymbol(NativeSession &Session, SymIndexId Id, + const codeview::CVType &CVT) + : NativeRawSymbol(Session, Id), CV(CVT), + Record(codeview::TypeRecordKind::Enum) { + assert(CV.kind() == codeview::TypeLeafKind::LF_ENUM); + cantFail(visitTypeRecord(CV, *this)); +} + +NativeEnumSymbol::~NativeEnumSymbol() {} + +std::unique_ptr NativeEnumSymbol::clone() const { + return llvm::make_unique(Session, SymbolId, CV); +} + +std::unique_ptr +NativeEnumSymbol::findChildren(PDB_SymType Type) const { + switch (Type) { + case PDB_SymType::Data: { + // TODO(amccarth): Provide an actual implementation. + return nullptr; + } + default: + return nullptr; + } +} + +Error NativeEnumSymbol::visitKnownRecord(codeview::CVType &CVR, + codeview::EnumRecord &ER) { + Record = ER; + return Error::success(); +} + +Error NativeEnumSymbol::visitKnownMember(codeview::CVMemberRecord &CVM, + codeview::EnumeratorRecord &R) { + return Error::success(); +} + +PDB_SymType NativeEnumSymbol::getSymTag() const { return PDB_SymType::Enum; } + +uint32_t NativeEnumSymbol::getClassParentId() const { return 0xFFFFFFFF; } + +uint32_t NativeEnumSymbol::getUnmodifiedTypeId() const { return 0; } + +bool NativeEnumSymbol::hasConstructor() const { + return bool(Record.getOptions() & + codeview::ClassOptions::HasConstructorOrDestructor); +} + +bool NativeEnumSymbol::hasAssignmentOperator() const { + return bool(Record.getOptions() & + codeview::ClassOptions::HasOverloadedAssignmentOperator); +} + +bool NativeEnumSymbol::hasCastOperator() const { + return bool(Record.getOptions() & + codeview::ClassOptions::HasConversionOperator); +} + +uint64_t NativeEnumSymbol::getLength() const { + const auto Id = Session.findSymbolByTypeIndex(Record.getUnderlyingType()); + const auto UnderlyingType = + Session.getConcreteSymbolById(Id); + return UnderlyingType ? UnderlyingType->getLength() : 0; +} + +std::string NativeEnumSymbol::getName() const { return Record.getName(); } + +bool NativeEnumSymbol::isNested() const { + return bool(Record.getOptions() & codeview::ClassOptions::Nested); +} + +bool NativeEnumSymbol::hasOverloadedOperator() const { + return bool(Record.getOptions() & + codeview::ClassOptions::HasOverloadedOperator); +} + +bool NativeEnumSymbol::isPacked() const { + return bool(Record.getOptions() & codeview::ClassOptions::Packed); +} + +bool NativeEnumSymbol::isScoped() const { + return bool(Record.getOptions() & codeview::ClassOptions::Scoped); +} + +uint32_t NativeEnumSymbol::getTypeId() const { + return Session.findSymbolByTypeIndex(Record.getUnderlyingType()); +} diff --git a/lib/DebugInfo/PDB/Native/NativeEnumTypes.cpp b/lib/DebugInfo/PDB/Native/NativeEnumTypes.cpp new file mode 100644 index 00000000000..36a68a1c62d --- /dev/null +++ b/lib/DebugInfo/PDB/Native/NativeEnumTypes.cpp @@ -0,0 +1,59 @@ +//==- NativeEnumTypes.cpp - Native Type Enumerator impl ----------*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h" + +#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" +#include "llvm/DebugInfo/PDB/Native/NativeEnumSymbol.h" +#include "llvm/DebugInfo/PDB/Native/NativeSession.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" + +namespace llvm { +namespace pdb { + +NativeEnumTypes::NativeEnumTypes(NativeSession &PDBSession, + codeview::LazyRandomTypeCollection &Types, + codeview::TypeLeafKind Kind) + : Matches(), Index(0), Session(PDBSession), Kind(Kind) { + for (auto Index = Types.getFirst(); Index; + Index = Types.getNext(Index.getValue())) { + if (Types.getType(Index.getValue()).kind() == Kind) + Matches.push_back(Index.getValue()); + } +} + +NativeEnumTypes::NativeEnumTypes( + NativeSession &PDBSession, const std::vector &Matches, + codeview::TypeLeafKind Kind) + : Matches(Matches), Index(0), Session(PDBSession), Kind(Kind) {} + +uint32_t NativeEnumTypes::getChildCount() const { + return static_cast(Matches.size()); +} + +std::unique_ptr +NativeEnumTypes::getChildAtIndex(uint32_t Index) const { + if (Index < Matches.size()) + return Session.createEnumSymbol(Matches[Index]); + return nullptr; +} + +std::unique_ptr NativeEnumTypes::getNext() { + return getChildAtIndex(Index++); +} + +void NativeEnumTypes::reset() { Index = 0; } + +NativeEnumTypes *NativeEnumTypes::clone() const { + return new NativeEnumTypes(Session, Matches, Kind); +} + +} // namespace pdb +} // namespace llvm diff --git a/lib/DebugInfo/PDB/Native/NativeExeSymbol.cpp b/lib/DebugInfo/PDB/Native/NativeExeSymbol.cpp index 3241000b06d..b29d589eaa9 100644 --- a/lib/DebugInfo/PDB/Native/NativeExeSymbol.cpp +++ b/lib/DebugInfo/PDB/Native/NativeExeSymbol.cpp @@ -13,7 +13,9 @@ #include "llvm/DebugInfo/PDB/Native/DbiStream.h" #include "llvm/DebugInfo/PDB/Native/InfoStream.h" #include "llvm/DebugInfo/PDB/Native/NativeEnumModules.h" +#include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h" #include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/TpiStream.h" namespace llvm { namespace pdb { @@ -38,6 +40,8 @@ NativeExeSymbol::findChildren(PDB_SymType Type) const { consumeError(Dbi.takeError()); break; } + case PDB_SymType::Enum: + return Session.createTypeEnumerator(codeview::LF_ENUM); default: break; } diff --git a/lib/DebugInfo/PDB/Native/NativeSession.cpp b/lib/DebugInfo/PDB/Native/NativeSession.cpp index 76de0d8f9e7..d7be2d576c2 100644 --- a/lib/DebugInfo/PDB/Native/NativeSession.cpp +++ b/lib/DebugInfo/PDB/Native/NativeSession.cpp @@ -16,11 +16,15 @@ #include "llvm/DebugInfo/PDB/IPDBSourceFile.h" #include "llvm/DebugInfo/PDB/Native/NativeBuiltinSymbol.h" #include "llvm/DebugInfo/PDB/Native/NativeCompilandSymbol.h" +#include "llvm/DebugInfo/PDB/Native/NativeEnumSymbol.h" +#include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h" #include "llvm/DebugInfo/PDB/Native/NativeExeSymbol.h" #include "llvm/DebugInfo/PDB/Native/PDBFile.h" #include "llvm/DebugInfo/PDB/Native/RawError.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" @@ -28,6 +32,7 @@ #include "llvm/Support/MemoryBuffer.h" #include +#include #include #include @@ -102,6 +107,25 @@ NativeSession::createCompilandSymbol(DbiModuleDescriptor MI) { *this, std::unique_ptr(SymbolCache[Id]->clone())); } +std::unique_ptr +NativeSession::createEnumSymbol(codeview::TypeIndex Index) { + const auto Id = findSymbolByTypeIndex(Index); + return llvm::make_unique( + *this, std::unique_ptr(SymbolCache[Id]->clone())); +} + +std::unique_ptr +NativeSession::createTypeEnumerator(codeview::TypeLeafKind Kind) { + auto Tpi = Pdb->getPDBTpiStream(); + if (!Tpi) { + consumeError(Tpi.takeError()); + return nullptr; + } + auto &Types = Tpi->typeCollection(); + return std::unique_ptr( + new NativeEnumTypes(*this, Types, codeview::LF_ENUM)); +} + SymIndexId NativeSession::findSymbolByTypeIndex(codeview::TypeIndex Index) { // First see if it's already in our cache. const auto Entry = TypeIndexToSymbolId.find(Index); @@ -129,9 +153,20 @@ SymIndexId NativeSession::findSymbolByTypeIndex(codeview::TypeIndex Index) { return Id; } - // TODO: Look up PDB type by type index - - return 0; + // We need to instantiate and cache the desired type symbol. + auto Tpi = Pdb->getPDBTpiStream(); + if (!Tpi) { + consumeError(Tpi.takeError()); + return 0; + } + auto &Types = Tpi->typeCollection(); + const auto &I = Types.getType(Index); + const auto Id = static_cast(SymbolCache.size()); + // TODO(amccarth): Make this handle all types, not just LF_ENUMs. + assert(I.kind() == codeview::LF_ENUM); + SymbolCache.emplace_back(llvm::make_unique(*this, Id, I)); + TypeIndexToSymbolId[Index] = Id; + return Id; } uint64_t NativeSession::getLoadAddress() const { return 0; } diff --git a/test/DebugInfo/PDB/Native/pdb-native-enums.test b/test/DebugInfo/PDB/Native/pdb-native-enums.test new file mode 100644 index 00000000000..90581537aa1 --- /dev/null +++ b/test/DebugInfo/PDB/Native/pdb-native-enums.test @@ -0,0 +1,6 @@ +; Test that the native PDB reader can enumerate the enum types. +; RUN: llvm-pdbutil pretty -native -enums %p/../Inputs/every-type.pdb \ +; RUN: | FileCheck -check-prefix=ENUMS %s + +ENUMS: enum FooClass::NestedEnum { +ENUMS-NEXT: } diff --git a/tools/llvm-pdbutil/PrettyEnumDumper.cpp b/tools/llvm-pdbutil/PrettyEnumDumper.cpp index 7aff5b93d98..bf22e75e394 100644 --- a/tools/llvm-pdbutil/PrettyEnumDumper.cpp +++ b/tools/llvm-pdbutil/PrettyEnumDumper.cpp @@ -26,25 +26,29 @@ void EnumDumper::start(const PDBSymbolTypeEnum &Symbol) { WithColor(Printer, PDB_ColorItem::Keyword).get() << "enum "; WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName(); if (!opts::pretty::NoEnumDefs) { - auto BuiltinType = Symbol.getUnderlyingType(); - if (BuiltinType->getBuiltinType() != PDB_BuiltinType::Int || - BuiltinType->getLength() != 4) { + auto UnderlyingType = Symbol.getUnderlyingType(); + if (!UnderlyingType) + return; + if (UnderlyingType->getBuiltinType() != PDB_BuiltinType::Int || + UnderlyingType->getLength() != 4) { Printer << " : "; BuiltinDumper Dumper(Printer); - Dumper.start(*BuiltinType); + Dumper.start(*UnderlyingType); } + auto EnumValues = Symbol.findAllChildren(); Printer << " {"; Printer.Indent(); - auto EnumValues = Symbol.findAllChildren(); - while (auto EnumValue = EnumValues->getNext()) { - if (EnumValue->getDataKind() != PDB_DataKind::Constant) - continue; - Printer.NewLine(); - WithColor(Printer, PDB_ColorItem::Identifier).get() - << EnumValue->getName(); - Printer << " = "; - WithColor(Printer, PDB_ColorItem::LiteralValue).get() - << EnumValue->getValue(); + if (EnumValues && EnumValues->getChildCount() > 0) { + while (auto EnumValue = EnumValues->getNext()) { + if (EnumValue->getDataKind() != PDB_DataKind::Constant) + continue; + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::Identifier).get() + << EnumValue->getName(); + Printer << " = "; + WithColor(Printer, PDB_ColorItem::LiteralValue).get() + << EnumValue->getValue(); + } } Printer.Unindent(); Printer.NewLine();