OSDN Git Service

[CodeView] Add support for random access type visitors.
authorZachary Turner <zturner@google.com>
Mon, 8 May 2017 18:38:43 +0000 (18:38 +0000)
committerZachary Turner <zturner@google.com>
Mon, 8 May 2017 18:38:43 +0000 (18:38 +0000)
Previously type visitation was done strictly sequentially, and
TypeIndexes were computed by incrementing the TypeIndex of the
last visited record.  This works fine for situations like dumping,
but not when you want to visit types in random order.  For example,
in a debug session someone might lookup a symbol by name, find that
it has TypeIndex 10,000 and then want to go straight to TypeIndex
10,000.

In order to make this work, the visitation framework needs a mode
where it can plumb TypeIndices through the callback pipeline.  This
patch adds such a mode.  In doing so, it is necessary to provide
an alternative implementation of TypeDatabase that supports random
access, so that is done as well.

Nothing actually uses these random access capabilities yet, but
this will be done in subsequent patches.

Differential Revision: https://reviews.llvm.org/D32928

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@302454 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/DebugInfo/CodeView/CVTypeVisitor.h
include/llvm/DebugInfo/CodeView/TypeDatabase.h
include/llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h
include/llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h
include/llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h
lib/DebugInfo/CodeView/CVTypeVisitor.cpp
lib/DebugInfo/CodeView/TypeDatabase.cpp
lib/DebugInfo/CodeView/TypeDatabaseVisitor.cpp

index e9012db..f3122f0 100644 (file)
@@ -26,6 +26,7 @@ public:
 
   void addTypeServerHandler(TypeServerHandler &Handler);
 
+  Error visitTypeRecord(CVType &Record, TypeIndex Index);
   Error visitTypeRecord(CVType &Record);
   Error visitMemberRecord(CVMemberRecord &Record);
 
@@ -37,6 +38,9 @@ public:
   Error visitFieldListMemberStream(BinaryStreamReader Reader);
 
 private:
+  Expected<bool> handleTypeServer(CVType &Record);
+  Error finishVisitation(CVType &Record);
+
   /// The interface to the class that gets notified of each visitation.
   TypeVisitorCallbacks &Callbacks;
 
index be7b19e..c4fb636 100644 (file)
@@ -10,6 +10,7 @@
 #ifndef LLVM_DEBUGINFO_CODEVIEW_TYPEDATABASE_H
 #define LLVM_DEBUGINFO_CODEVIEW_TYPEDATABASE_H
 
+#include "llvm/ADT/BitVector.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
@@ -20,6 +21,8 @@
 namespace llvm {
 namespace codeview {
 class TypeDatabase {
+  friend class RandomAccessTypeVisitor;
+
 public:
   explicit TypeDatabase(uint32_t ExpectedSize);
 
@@ -41,7 +44,9 @@ public:
 
   uint32_t size() const;
 
-private:
+protected:
+  uint32_t toArrayIndex(TypeIndex Index) const;
+
   BumpPtrAllocator Allocator;
 
   /// All user defined type records in .debug$T live in here. Type indices
@@ -52,6 +57,28 @@ private:
 
   StringSaver TypeNameStorage;
 };
+
+class RandomAccessTypeDatabase : private TypeDatabase {
+public:
+  explicit RandomAccessTypeDatabase(uint32_t ExpectedSize);
+
+  /// Records the name of a type, and reserves its type index.
+  void recordType(StringRef Name, TypeIndex Index, const CVType &Data);
+
+  using TypeDatabase::saveTypeName;
+
+  StringRef getTypeName(TypeIndex Index) const;
+
+  const CVType &getTypeRecord(TypeIndex Index) const;
+  CVType &getTypeRecord(TypeIndex Index);
+
+  bool containsTypeIndex(TypeIndex Index) const;
+
+  uint32_t size() const;
+
+private:
+  BitVector ValidRecords;
+};
 }
 }
 
index 39d234c..cbb5096 100644 (file)
@@ -10,6 +10,8 @@
 #ifndef LLVM_DEBUGINFO_CODEVIEW_TYPEDATABASEVISITOR_H
 #define LLVM_DEBUGINFO_CODEVIEW_TYPEDATABASEVISITOR_H
 
+#include "llvm/ADT/PointerUnion.h"
+
 #include "llvm/DebugInfo/CodeView/TypeDatabase.h"
 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
@@ -21,11 +23,14 @@ namespace codeview {
 /// Dumper for CodeView type streams found in COFF object files and PDB files.
 class TypeDatabaseVisitor : public TypeVisitorCallbacks {
 public:
-  explicit TypeDatabaseVisitor(TypeDatabase &TypeDB) : TypeDB(TypeDB) {}
+  explicit TypeDatabaseVisitor(TypeDatabase &TypeDB) : TypeDB(&TypeDB) {}
+  explicit TypeDatabaseVisitor(RandomAccessTypeDatabase &TypeDB)
+      : TypeDB(&TypeDB) {}
 
   /// Paired begin/end actions for all types. Receives all record data,
   /// including the fixed-length record prefix.
   Error visitTypeBegin(CVType &Record) override;
+  Error visitTypeBegin(CVType &Record, TypeIndex Index) override;
   Error visitTypeEnd(CVType &Record) override;
   Error visitMemberBegin(CVMemberRecord &Record) override;
   Error visitMemberEnd(CVMemberRecord &Record) override;
@@ -39,12 +44,18 @@ public:
 #include "TypeRecords.def"
 
 private:
+  StringRef getTypeName(TypeIndex Index) const;
+  StringRef saveTypeName(StringRef Name);
+
   bool IsInFieldList = false;
 
   /// Name of the current type. Only valid before visitTypeEnd.
   StringRef Name;
+  /// Current type index.  Only valid before visitTypeEnd, and if we are
+  /// visiting a random access type database.
+  TypeIndex CurrentTypeIndex;
 
-  TypeDatabase &TypeDB;
+  PointerUnion<TypeDatabase *, RandomAccessTypeDatabase *> TypeDB;
 };
 
 } // end namespace codeview
index f251296..ed48df3 100644 (file)
@@ -47,6 +47,14 @@ public:
     return Error::success();
   }
 
+  Error visitTypeBegin(CVType &Record, TypeIndex Index) override {
+    for (auto Visitor : Pipeline) {
+      if (auto EC = Visitor->visitTypeBegin(Record, Index))
+        return EC;
+    }
+    return Error::success();
+  }
+
   Error visitTypeEnd(CVType &Record) override {
     for (auto Visitor : Pipeline) {
       if (auto EC = Visitor->visitTypeEnd(Record))
index 5e27df3..2950c7d 100644 (file)
@@ -26,8 +26,15 @@ public:
   virtual Error visitUnknownType(CVType &Record) { return Error::success(); }
   /// Paired begin/end actions for all types. Receives all record data,
   /// including the fixed-length record prefix.  visitTypeBegin() should return
-  /// the type of the Record, or an error if it cannot be determined.
+  /// the type of the Record, or an error if it cannot be determined.  Exactly
+  /// one of the two visitTypeBegin methods will be called, depending on whether
+  /// records are being visited sequentially or randomly.  An implementation
+  /// should be prepared to handle both (or assert if it can't handle random
+  /// access visitation).
   virtual Error visitTypeBegin(CVType &Record) { return Error::success(); }
+  virtual Error visitTypeBegin(CVType &Record, TypeIndex Index) {
+    return Error::success();
+  }
   virtual Error visitTypeEnd(CVType &Record) { return Error::success(); }
 
   virtual Error visitUnknownMember(CVMemberRecord &Record) {
index 0069ee3..23f2c40 100644 (file)
@@ -76,7 +76,7 @@ void CVTypeVisitor::addTypeServerHandler(TypeServerHandler &Handler) {
   Handlers.push_back(&Handler);
 }
 
-Error CVTypeVisitor::visitTypeRecord(CVType &Record) {
+Expected<bool> CVTypeVisitor::handleTypeServer(CVType &Record) {
   if (Record.Type == TypeLeafKind::LF_TYPESERVER2 && !Handlers.empty()) {
     auto TS = deserializeTypeServerRecord(Record);
     if (!TS)
@@ -90,16 +90,16 @@ Error CVTypeVisitor::visitTypeRecord(CVType &Record) {
 
       // If the handler processed the record, return success.
       if (*ExpectedResult)
-        return Error::success();
+        return true;
 
       // Otherwise keep searching for a handler, eventually falling out and
       // using the default record handler.
     }
   }
+  return false;
+}
 
-  if (auto EC = Callbacks.visitTypeBegin(Record))
-    return EC;
-
+Error CVTypeVisitor::finishVisitation(CVType &Record) {
   switch (Record.Type) {
   default:
     if (auto EC = Callbacks.visitUnknownType(Record))
@@ -124,6 +124,32 @@ Error CVTypeVisitor::visitTypeRecord(CVType &Record) {
   return Error::success();
 }
 
+Error CVTypeVisitor::visitTypeRecord(CVType &Record, TypeIndex Index) {
+  auto ExpectedResult = handleTypeServer(Record);
+  if (!ExpectedResult)
+    return ExpectedResult.takeError();
+  if (*ExpectedResult)
+    return Error::success();
+
+  if (auto EC = Callbacks.visitTypeBegin(Record, Index))
+    return EC;
+
+  return finishVisitation(Record);
+}
+
+Error CVTypeVisitor::visitTypeRecord(CVType &Record) {
+  auto ExpectedResult = handleTypeServer(Record);
+  if (!ExpectedResult)
+    return ExpectedResult.takeError();
+  if (*ExpectedResult)
+    return Error::success();
+
+  if (auto EC = Callbacks.visitTypeBegin(Record))
+    return EC;
+
+  return finishVisitation(Record);
+}
+
 static Error visitMemberRecord(CVMemberRecord &Record,
                                TypeVisitorCallbacks &Callbacks) {
   if (auto EC = Callbacks.visitMemberBegin(Record))
index 5b88410..1f2a5d7 100644 (file)
@@ -112,16 +112,61 @@ StringRef TypeDatabase::getTypeName(TypeIndex Index) const {
 }
 
 const CVType &TypeDatabase::getTypeRecord(TypeIndex Index) const {
-  return TypeRecords[Index.getIndex() - TypeIndex::FirstNonSimpleIndex];
+  return TypeRecords[toArrayIndex(Index)];
 }
 
 CVType &TypeDatabase::getTypeRecord(TypeIndex Index) {
-  return TypeRecords[Index.getIndex() - TypeIndex::FirstNonSimpleIndex];
+  return TypeRecords[toArrayIndex(Index)];
 }
 
 bool TypeDatabase::containsTypeIndex(TypeIndex Index) const {
-  uint32_t I = Index.getIndex() - TypeIndex::FirstNonSimpleIndex;
-  return I < CVUDTNames.size();
+  return toArrayIndex(Index) < CVUDTNames.size();
 }
 
 uint32_t TypeDatabase::size() const { return CVUDTNames.size(); }
+
+uint32_t TypeDatabase::toArrayIndex(TypeIndex Index) const {
+  assert(Index.getIndex() >= TypeIndex::FirstNonSimpleIndex);
+  return Index.getIndex() - TypeIndex::FirstNonSimpleIndex;
+}
+
+RandomAccessTypeDatabase::RandomAccessTypeDatabase(uint32_t ExpectedSize)
+    : TypeDatabase(ExpectedSize) {
+  ValidRecords.resize(ExpectedSize);
+  CVUDTNames.resize(ExpectedSize);
+  TypeRecords.resize(ExpectedSize);
+}
+
+void RandomAccessTypeDatabase::recordType(StringRef Name, TypeIndex Index,
+                                          const CVType &Data) {
+  assert(!containsTypeIndex(Index));
+  uint32_t ZI = Index.getIndex() - TypeIndex::FirstNonSimpleIndex;
+
+  CVUDTNames[ZI] = Name;
+  TypeRecords[ZI] = Data;
+  ValidRecords.set(ZI);
+}
+
+StringRef RandomAccessTypeDatabase::getTypeName(TypeIndex Index) const {
+  assert(containsTypeIndex(Index));
+  return TypeDatabase::getTypeName(Index);
+}
+
+const CVType &RandomAccessTypeDatabase::getTypeRecord(TypeIndex Index) const {
+  assert(containsTypeIndex(Index));
+  return TypeDatabase::getTypeRecord(Index);
+}
+
+CVType &RandomAccessTypeDatabase::getTypeRecord(TypeIndex Index) {
+  assert(containsTypeIndex(Index));
+  return TypeDatabase::getTypeRecord(Index);
+}
+
+bool RandomAccessTypeDatabase::containsTypeIndex(TypeIndex Index) const {
+  if (Index.isSimple())
+    return true;
+
+  return ValidRecords.test(toArrayIndex(Index));
+}
+
+uint32_t RandomAccessTypeDatabase::size() const { return ValidRecords.count(); }
index c234afd..8c1a651 100644 (file)
@@ -15,7 +15,9 @@ using namespace llvm;
 
 using namespace llvm::codeview;
 
-Error TypeDatabaseVisitor::visitTypeBegin(CVRecord<TypeLeafKind> &Record) {
+Error TypeDatabaseVisitor::visitTypeBegin(CVType &Record) {
+  assert(TypeDB.is<TypeDatabase *>());
+
   assert(!IsInFieldList);
   // Reset Name to the empty string. If the visitor sets it, we know it.
   Name = "";
@@ -28,6 +30,34 @@ Error TypeDatabaseVisitor::visitTypeBegin(CVRecord<TypeLeafKind> &Record) {
   return Error::success();
 }
 
+StringRef TypeDatabaseVisitor::getTypeName(TypeIndex Index) const {
+  if (auto DB = TypeDB.get<TypeDatabase *>())
+    return DB->getTypeName(Index);
+  else if (auto DB = TypeDB.get<RandomAccessTypeDatabase *>())
+    return DB->getTypeName(Index);
+
+  llvm_unreachable("Invalid TypeDB Kind!");
+}
+
+StringRef TypeDatabaseVisitor::saveTypeName(StringRef Name) {
+  if (auto DB = TypeDB.get<TypeDatabase *>())
+    return DB->saveTypeName(Name);
+  else if (auto DB = TypeDB.get<RandomAccessTypeDatabase *>())
+    return DB->saveTypeName(Name);
+
+  llvm_unreachable("Invalid TypeDB Kind!");
+}
+
+Error TypeDatabaseVisitor::visitTypeBegin(CVType &Record, TypeIndex Index) {
+  assert(TypeDB.is<RandomAccessTypeDatabase *>());
+
+  if (auto EC = visitTypeBegin(Record))
+    return EC;
+
+  CurrentTypeIndex = Index;
+  return Error::success();
+}
+
 Error TypeDatabaseVisitor::visitTypeEnd(CVType &CVR) {
   if (CVR.Type == LF_FIELDLIST) {
     assert(IsInFieldList);
@@ -39,7 +69,11 @@ Error TypeDatabaseVisitor::visitTypeEnd(CVType &CVR) {
   // CVUDTNames is indexed by type index, and must have one entry for every
   // type.  Field list members are not recorded, and are only referenced by
   // their containing field list record.
-  TypeDB.recordType(Name, CVR);
+  if (auto DB = TypeDB.get<TypeDatabase *>())
+    DB->recordType(Name, CVR);
+  else if (auto DB = TypeDB.get<RandomAccessTypeDatabase *>())
+    DB->recordType(Name, CurrentTypeIndex, CVR);
+
   return Error::success();
 }
 
@@ -73,13 +107,13 @@ Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, ArgListRecord &Args) {
   uint32_t Size = Indices.size();
   SmallString<256> TypeName("(");
   for (uint32_t I = 0; I < Size; ++I) {
-    StringRef ArgTypeName = TypeDB.getTypeName(Indices[I]);
+    StringRef ArgTypeName = getTypeName(Indices[I]);
     TypeName.append(ArgTypeName);
     if (I + 1 != Size)
       TypeName.append(", ");
   }
   TypeName.push_back(')');
-  Name = TypeDB.saveTypeName(TypeName);
+  Name = saveTypeName(TypeName);
   return Error::success();
 }
 
@@ -89,13 +123,13 @@ Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR,
   uint32_t Size = Indices.size();
   SmallString<256> TypeName("\"");
   for (uint32_t I = 0; I < Size; ++I) {
-    StringRef ArgTypeName = TypeDB.getTypeName(Indices[I]);
+    StringRef ArgTypeName = getTypeName(Indices[I]);
     TypeName.append(ArgTypeName);
     if (I + 1 != Size)
       TypeName.append("\" \"");
   }
   TypeName.push_back('\"');
-  Name = TypeDB.saveTypeName(TypeName);
+  Name = saveTypeName(TypeName);
   return Error::success();
 }
 
@@ -132,26 +166,26 @@ Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR,
 
 Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR,
                                             ProcedureRecord &Proc) {
-  StringRef ReturnTypeName = TypeDB.getTypeName(Proc.getReturnType());
-  StringRef ArgListTypeName = TypeDB.getTypeName(Proc.getArgumentList());
+  StringRef ReturnTypeName = getTypeName(Proc.getReturnType());
+  StringRef ArgListTypeName = getTypeName(Proc.getArgumentList());
   SmallString<256> TypeName(ReturnTypeName);
   TypeName.push_back(' ');
   TypeName.append(ArgListTypeName);
-  Name = TypeDB.saveTypeName(TypeName);
+  Name = saveTypeName(TypeName);
   return Error::success();
 }
 
 Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR,
                                             MemberFunctionRecord &MF) {
-  StringRef ReturnTypeName = TypeDB.getTypeName(MF.getReturnType());
-  StringRef ClassTypeName = TypeDB.getTypeName(MF.getClassType());
-  StringRef ArgListTypeName = TypeDB.getTypeName(MF.getArgumentList());
+  StringRef ReturnTypeName = getTypeName(MF.getReturnType());
+  StringRef ClassTypeName = getTypeName(MF.getClassType());
+  StringRef ArgListTypeName = getTypeName(MF.getArgumentList());
   SmallString<256> TypeName(ReturnTypeName);
   TypeName.push_back(' ');
   TypeName.append(ClassTypeName);
   TypeName.append("::");
   TypeName.append(ArgListTypeName);
-  Name = TypeDB.saveTypeName(TypeName);
+  Name = saveTypeName(TypeName);
   return Error::success();
 }
 
@@ -171,13 +205,13 @@ Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, PointerRecord &Ptr) {
   if (Ptr.isPointerToMember()) {
     const MemberPointerInfo &MI = Ptr.getMemberInfo();
 
-    StringRef PointeeName = TypeDB.getTypeName(Ptr.getReferentType());
-    StringRef ClassName = TypeDB.getTypeName(MI.getContainingType());
+    StringRef PointeeName = getTypeName(Ptr.getReferentType());
+    StringRef ClassName = getTypeName(MI.getContainingType());
     SmallString<256> TypeName(PointeeName);
     TypeName.push_back(' ');
     TypeName.append(ClassName);
     TypeName.append("::*");
-    Name = TypeDB.saveTypeName(TypeName);
+    Name = saveTypeName(TypeName);
   } else {
     SmallString<256> TypeName;
     if (Ptr.isConst())
@@ -187,7 +221,7 @@ Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, PointerRecord &Ptr) {
     if (Ptr.isUnaligned())
       TypeName.append("__unaligned ");
 
-    TypeName.append(TypeDB.getTypeName(Ptr.getReferentType()));
+    TypeName.append(getTypeName(Ptr.getReferentType()));
 
     if (Ptr.getMode() == PointerMode::LValueReference)
       TypeName.append("&");
@@ -197,7 +231,7 @@ Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, PointerRecord &Ptr) {
       TypeName.append("*");
 
     if (!TypeName.empty())
-      Name = TypeDB.saveTypeName(TypeName);
+      Name = saveTypeName(TypeName);
   }
   return Error::success();
 }
@@ -205,7 +239,7 @@ Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, PointerRecord &Ptr) {
 Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, ModifierRecord &Mod) {
   uint16_t Mods = static_cast<uint16_t>(Mod.getModifiers());
 
-  StringRef ModifiedName = TypeDB.getTypeName(Mod.getModifiedType());
+  StringRef ModifiedName = getTypeName(Mod.getModifiedType());
   SmallString<256> TypeName;
   if (Mods & uint16_t(ModifierOptions::Const))
     TypeName.append("const ");
@@ -214,14 +248,14 @@ Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, ModifierRecord &Mod) {
   if (Mods & uint16_t(ModifierOptions::Unaligned))
     TypeName.append("__unaligned ");
   TypeName.append(ModifiedName);
-  Name = TypeDB.saveTypeName(TypeName);
+  Name = saveTypeName(TypeName);
   return Error::success();
 }
 
 Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR,
                                             VFTableShapeRecord &Shape) {
-  Name = TypeDB.saveTypeName("<vftable " + utostr(Shape.getEntryCount()) +
-                             " methods>");
+  Name =
+      saveTypeName("<vftable " + utostr(Shape.getEntryCount()) + " methods>");
   return Error::success();
 }