Enable llvm-pdbutil to list enumerations using native PDB reader
authorAdrian McCarthy <amccarth@google.com>
Fri, 4 Aug 2017 22:37:58 +0000 (22:37 +0000)
committerAdrian McCarthy <amccarth@google.com>
Fri, 4 Aug 2017 22:37:58 +0000 (22:37 +0000)
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

llvm/include/llvm/DebugInfo/PDB/Native/NativeEnumSymbol.h [new file with mode: 0644]
llvm/include/llvm/DebugInfo/PDB/Native/NativeEnumTypes.h [new file with mode: 0644]
llvm/include/llvm/DebugInfo/PDB/Native/NativeSession.h
llvm/include/llvm/DebugInfo/PDB/PDBSymbol.h
llvm/lib/DebugInfo/PDB/CMakeLists.txt
llvm/lib/DebugInfo/PDB/Native/NativeEnumSymbol.cpp [new file with mode: 0644]
llvm/lib/DebugInfo/PDB/Native/NativeEnumTypes.cpp [new file with mode: 0644]
llvm/lib/DebugInfo/PDB/Native/NativeExeSymbol.cpp
llvm/lib/DebugInfo/PDB/Native/NativeSession.cpp
llvm/test/DebugInfo/PDB/Native/pdb-native-enums.test [new file with mode: 0644]
llvm/tools/llvm-pdbutil/PrettyEnumDumper.cpp

diff --git a/llvm/include/llvm/DebugInfo/PDB/Native/NativeEnumSymbol.h b/llvm/include/llvm/DebugInfo/PDB/Native/NativeEnumSymbol.h
new file mode 100644 (file)
index 0000000..41b7b78
--- /dev/null
@@ -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<NativeRawSymbol> clone() const override;
+
+  std::unique_ptr<IPDBEnumSymbols>
+  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/llvm/include/llvm/DebugInfo/PDB/Native/NativeEnumTypes.h b/llvm/include/llvm/DebugInfo/PDB/Native/NativeEnumTypes.h
new file mode 100644 (file)
index 0000000..e0a5c8d
--- /dev/null
@@ -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 <vector>
+
+namespace llvm {
+namespace pdb {
+
+class NativeSession;
+
+class NativeEnumTypes : public IPDBEnumChildren<PDBSymbol> {
+public:
+  NativeEnumTypes(NativeSession &Session,
+                  codeview::LazyRandomTypeCollection &TypeCollection,
+                  codeview::TypeLeafKind Kind);
+
+  uint32_t getChildCount() const override;
+  std::unique_ptr<PDBSymbol> getChildAtIndex(uint32_t Index) const override;
+  std::unique_ptr<PDBSymbol> getNext() override;
+  void reset() override;
+  NativeEnumTypes *clone() const override;
+
+private:
+  NativeEnumTypes(NativeSession &Session,
+                  const std::vector<codeview::TypeIndex> &Matches,
+                  codeview::TypeLeafKind Kind);
+
+  std::vector<codeview::TypeIndex> Matches;
+  uint32_t Index;
+  NativeSession &Session;
+  codeview::TypeLeafKind Kind;
+};
+
+} // namespace pdb
+} // namespace llvm
+
+#endif
index b16ce23..7706731 100644 (file)
@@ -39,6 +39,12 @@ public:
   std::unique_ptr<PDBSymbolCompiland>
   createCompilandSymbol(DbiModuleDescriptor MI);
 
+  std::unique_ptr<PDBSymbolTypeEnum>
+  createEnumSymbol(codeview::TypeIndex Index);
+
+  std::unique_ptr<IPDBEnumSymbols>
+  createTypeEnumerator(codeview::TypeLeafKind Kind);
+
   SymIndexId findSymbolByTypeIndex(codeview::TypeIndex TI);
 
   uint64_t getLoadAddress() const override;
index 9e883d2..0437346 100644 (file)
@@ -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"
index 2658584..37eca01 100644 (file)
@@ -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/llvm/lib/DebugInfo/PDB/Native/NativeEnumSymbol.cpp b/llvm/lib/DebugInfo/PDB/Native/NativeEnumSymbol.cpp
new file mode 100644 (file)
index 0000000..38d6591
--- /dev/null
@@ -0,0 +1,108 @@
+//===- NativeEnumSymbol.cpp - info about enum type --------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/PDB/Native/NativeEnumSymbol.h"
+
+#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h"
+
+#include <cassert>
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+NativeEnumSymbol::NativeEnumSymbol(NativeSession &Session, SymIndexId Id,
+                                   const codeview::CVType &CVT)
+    : NativeRawSymbol(Session, Id), CV(CVT),
+      Record(codeview::TypeRecordKind::Enum) {
+  assert(CV.kind() == codeview::TypeLeafKind::LF_ENUM);
+  cantFail(visitTypeRecord(CV, *this));
+}
+
+NativeEnumSymbol::~NativeEnumSymbol() {}
+
+std::unique_ptr<NativeRawSymbol> NativeEnumSymbol::clone() const {
+  return llvm::make_unique<NativeEnumSymbol>(Session, SymbolId, CV);
+}
+
+std::unique_ptr<IPDBEnumSymbols>
+NativeEnumSymbol::findChildren(PDB_SymType Type) const {
+  switch (Type) {
+  case PDB_SymType::Data: {
+    // TODO(amccarth):  Provide an actual implementation.
+    return nullptr;
+  }
+  default:
+    return nullptr;
+  }
+}
+
+Error NativeEnumSymbol::visitKnownRecord(codeview::CVType &CVR,
+                                         codeview::EnumRecord &ER) {
+  Record = ER;
+  return Error::success();
+}
+
+Error NativeEnumSymbol::visitKnownMember(codeview::CVMemberRecord &CVM,
+                                         codeview::EnumeratorRecord &R) {
+  return Error::success();
+}
+
+PDB_SymType NativeEnumSymbol::getSymTag() const { return PDB_SymType::Enum; }
+
+uint32_t NativeEnumSymbol::getClassParentId() const { return 0xFFFFFFFF; }
+
+uint32_t NativeEnumSymbol::getUnmodifiedTypeId() const { return 0; }
+
+bool NativeEnumSymbol::hasConstructor() const {
+  return bool(Record.getOptions() &
+              codeview::ClassOptions::HasConstructorOrDestructor);
+}
+
+bool NativeEnumSymbol::hasAssignmentOperator() const {
+  return bool(Record.getOptions() &
+              codeview::ClassOptions::HasOverloadedAssignmentOperator);
+}
+
+bool NativeEnumSymbol::hasCastOperator() const {
+  return bool(Record.getOptions() &
+              codeview::ClassOptions::HasConversionOperator);
+}
+
+uint64_t NativeEnumSymbol::getLength() const {
+  const auto Id = Session.findSymbolByTypeIndex(Record.getUnderlyingType());
+  const auto UnderlyingType =
+      Session.getConcreteSymbolById<PDBSymbolTypeBuiltin>(Id);
+  return UnderlyingType ? UnderlyingType->getLength() : 0;
+}
+
+std::string NativeEnumSymbol::getName() const { return Record.getName(); }
+
+bool NativeEnumSymbol::isNested() const {
+  return bool(Record.getOptions() & codeview::ClassOptions::Nested);
+}
+
+bool NativeEnumSymbol::hasOverloadedOperator() const {
+  return bool(Record.getOptions() &
+              codeview::ClassOptions::HasOverloadedOperator);
+}
+
+bool NativeEnumSymbol::isPacked() const {
+  return bool(Record.getOptions() & codeview::ClassOptions::Packed);
+}
+
+bool NativeEnumSymbol::isScoped() const {
+  return bool(Record.getOptions() & codeview::ClassOptions::Scoped);
+}
+
+uint32_t NativeEnumSymbol::getTypeId() const {
+  return Session.findSymbolByTypeIndex(Record.getUnderlyingType());
+}
diff --git a/llvm/lib/DebugInfo/PDB/Native/NativeEnumTypes.cpp b/llvm/lib/DebugInfo/PDB/Native/NativeEnumTypes.cpp
new file mode 100644 (file)
index 0000000..36a68a1
--- /dev/null
@@ -0,0 +1,59 @@
+//==- NativeEnumTypes.cpp - Native Type Enumerator impl ----------*- C++ -*-==//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h"
+
+#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"
+#include "llvm/DebugInfo/PDB/Native/NativeEnumSymbol.h"
+#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
+#include "llvm/DebugInfo/PDB/PDBSymbol.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
+
+namespace llvm {
+namespace pdb {
+
+NativeEnumTypes::NativeEnumTypes(NativeSession &PDBSession,
+                                 codeview::LazyRandomTypeCollection &Types,
+                                 codeview::TypeLeafKind Kind)
+    : Matches(), Index(0), Session(PDBSession), Kind(Kind) {
+  for (auto Index = Types.getFirst(); Index;
+       Index = Types.getNext(Index.getValue())) {
+    if (Types.getType(Index.getValue()).kind() == Kind)
+      Matches.push_back(Index.getValue());
+  }
+}
+
+NativeEnumTypes::NativeEnumTypes(
+    NativeSession &PDBSession, const std::vector<codeview::TypeIndex> &Matches,
+    codeview::TypeLeafKind Kind)
+    : Matches(Matches), Index(0), Session(PDBSession), Kind(Kind) {}
+
+uint32_t NativeEnumTypes::getChildCount() const {
+  return static_cast<uint32_t>(Matches.size());
+}
+
+std::unique_ptr<PDBSymbol>
+NativeEnumTypes::getChildAtIndex(uint32_t Index) const {
+  if (Index < Matches.size())
+    return Session.createEnumSymbol(Matches[Index]);
+  return nullptr;
+}
+
+std::unique_ptr<PDBSymbol> NativeEnumTypes::getNext() {
+  return getChildAtIndex(Index++);
+}
+
+void NativeEnumTypes::reset() { Index = 0; }
+
+NativeEnumTypes *NativeEnumTypes::clone() const {
+  return new NativeEnumTypes(Session, Matches, Kind);
+}
+
+} // namespace pdb
+} // namespace llvm
index 3241000..b29d589 100644 (file)
@@ -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;
   }
index 76de0d8..d7be2d5 100644 (file)
 #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 <algorithm>
+#include <cassert>
 #include <memory>
 #include <utility>
 
@@ -102,6 +107,25 @@ NativeSession::createCompilandSymbol(DbiModuleDescriptor MI) {
       *this, std::unique_ptr<IPDBRawSymbol>(SymbolCache[Id]->clone()));
 }
 
+std::unique_ptr<PDBSymbolTypeEnum>
+NativeSession::createEnumSymbol(codeview::TypeIndex Index) {
+  const auto Id = findSymbolByTypeIndex(Index);
+  return llvm::make_unique<PDBSymbolTypeEnum>(
+      *this, std::unique_ptr<IPDBRawSymbol>(SymbolCache[Id]->clone()));
+}
+
+std::unique_ptr<IPDBEnumSymbols>
+NativeSession::createTypeEnumerator(codeview::TypeLeafKind Kind) {
+  auto Tpi = Pdb->getPDBTpiStream();
+  if (!Tpi) {
+    consumeError(Tpi.takeError());
+    return nullptr;
+  }
+  auto &Types = Tpi->typeCollection();
+  return std::unique_ptr<IPDBEnumSymbols>(
+      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<SymIndexId>(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<NativeEnumSymbol>(*this, Id, I));
+  TypeIndexToSymbolId[Index] = Id;
+  return Id;
 }
 
 uint64_t NativeSession::getLoadAddress() const { return 0; }
diff --git a/llvm/test/DebugInfo/PDB/Native/pdb-native-enums.test b/llvm/test/DebugInfo/PDB/Native/pdb-native-enums.test
new file mode 100644 (file)
index 0000000..9058153
--- /dev/null
@@ -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:  }
index 7aff5b9..bf22e75 100644 (file)
@@ -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<PDBSymbolData>();
     Printer << " {";
     Printer.Indent();
-    auto EnumValues = Symbol.findAllChildren<PDBSymbolData>();
-    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();