[llvm] r342656 - [PDB] Add the ability to map forward references to full decls.

Zachary Turner via llvm-commits llvm-commits at lists.llvm.org
Thu Sep 20 08:50:14 PDT 2018


Author: zturner
Date: Thu Sep 20 08:50:13 2018
New Revision: 342656

URL: http://llvm.org/viewvc/llvm-project?rev=342656&view=rev
Log:
[PDB] Add the ability to map forward references to full decls.

Some records point to an LF_CLASS, LF_UNION, LF_STRUCTURE, or LF_ENUM
which is a forward reference and doesn't contain complete debug
information. In these cases, we'd like to be able to quickly locate the
full record. The TPI stream stores an array of pre-computed record hash
values, one for each type record. If we pre-process this on startup, we
can build a mapping from hash value -> {list of possible matching type
indices}. Since hashes of full records are only based on the name and or
unique name and not the full record contents, we can then use forward
ref record to compute the hash of what *would* be the full record by
just hashing the name, use this to get the list of possible matches, and
iterate those looking for a match on name or unique name.

llvm-pdbutil is updated to resolve forward references for the purposes
of testing (plus it's just useful).

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

Added:
    llvm/trunk/test/DebugInfo/PDB/Inputs/every-class.cpp
    llvm/trunk/test/DebugInfo/PDB/Inputs/every-class.pdb   (with props)
    llvm/trunk/test/DebugInfo/PDB/pdb-resolve-forward-refs.test
Modified:
    llvm/trunk/include/llvm/DebugInfo/PDB/Native/RawTypes.h
    llvm/trunk/include/llvm/DebugInfo/PDB/Native/TpiHashing.h
    llvm/trunk/include/llvm/DebugInfo/PDB/Native/TpiStream.h
    llvm/trunk/lib/DebugInfo/PDB/Native/TpiHashing.cpp
    llvm/trunk/lib/DebugInfo/PDB/Native/TpiStream.cpp
    llvm/trunk/test/DebugInfo/PDB/every-type.test
    llvm/trunk/test/DebugInfo/PDB/pdbdump-headers.test
    llvm/trunk/tools/llvm-pdbutil/DumpOutputStyle.cpp
    llvm/trunk/tools/llvm-pdbutil/MinimalTypeDumper.cpp
    llvm/trunk/tools/llvm-pdbutil/MinimalTypeDumper.h
    llvm/trunk/tools/llvm-pdbutil/llvm-pdbutil.cpp
    llvm/trunk/tools/llvm-pdbutil/llvm-pdbutil.h

Modified: llvm/trunk/include/llvm/DebugInfo/PDB/Native/RawTypes.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/PDB/Native/RawTypes.h?rev=342656&r1=342655&r2=342656&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/PDB/Native/RawTypes.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/PDB/Native/RawTypes.h Thu Sep 20 08:50:13 2018
@@ -343,7 +343,6 @@ struct SrcHeaderBlockEntry {
   char Reserved[8];
 };
 
-constexpr int I = sizeof(SrcHeaderBlockEntry);
 static_assert(sizeof(SrcHeaderBlockEntry) == 40, "Incorrect struct size!");
 
 } // namespace pdb

Modified: llvm/trunk/include/llvm/DebugInfo/PDB/Native/TpiHashing.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/PDB/Native/TpiHashing.h?rev=342656&r1=342655&r2=342656&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/PDB/Native/TpiHashing.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/PDB/Native/TpiHashing.h Thu Sep 20 08:50:13 2018
@@ -18,6 +18,54 @@ namespace pdb {
 
 Expected<uint32_t> hashTypeRecord(const llvm::codeview::CVType &Type);
 
+struct TagRecordHash {
+  explicit TagRecordHash(codeview::ClassRecord CR, uint32_t Full,
+                         uint32_t Forward)
+      : Class(std::move(CR)), FullRecordHash(Full), ForwardDeclHash(Forward) {
+    State = 0;
+  }
+
+  explicit TagRecordHash(codeview::EnumRecord ER, uint32_t Full,
+                         uint32_t Forward)
+      : Enum(std::move(ER)), FullRecordHash(Full), ForwardDeclHash(Forward) {
+    State = 1;
+  }
+
+  explicit TagRecordHash(codeview::UnionRecord UR, uint32_t Full,
+                         uint32_t Forward)
+      : Union(std::move(UR)), FullRecordHash(Full), ForwardDeclHash(Forward) {
+    State = 2;
+  }
+
+  uint32_t FullRecordHash;
+  uint32_t ForwardDeclHash;
+
+  codeview::TagRecord &getRecord() {
+    switch (State) {
+    case 0:
+      return Class;
+    case 1:
+      return Enum;
+    case 2:
+      return Union;
+    }
+    llvm_unreachable("unreachable!");
+  }
+
+private:
+  union {
+    codeview::ClassRecord Class;
+    codeview::EnumRecord Enum;
+    codeview::UnionRecord Union;
+  };
+
+  uint8_t State = 0;
+};
+
+/// Given a CVType referring to a class, structure, union, or enum, compute
+/// the hash of its forward decl and full decl.
+Expected<TagRecordHash> hashTagRecord(const codeview::CVType &Type);
+
 } // end namespace pdb
 } // end namespace llvm
 

Modified: llvm/trunk/include/llvm/DebugInfo/PDB/Native/TpiStream.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/PDB/Native/TpiStream.h?rev=342656&r1=342655&r2=342656&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/PDB/Native/TpiStream.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/PDB/Native/TpiStream.h Thu Sep 20 08:50:13 2018
@@ -58,10 +58,17 @@ public:
 
   codeview::LazyRandomTypeCollection &typeCollection() { return *Types; }
 
+  Expected<codeview::TypeIndex>
+  findFullDeclForForwardRef(codeview::TypeIndex ForwardRefTI) const;
+
   BinarySubstreamRef getTypeRecordsSubstream() const;
 
   Error commit();
 
+  void buildHashMap();
+
+  bool supportsTypeLookup() const;
+
 private:
   PDBFile &Pdb;
   std::unique_ptr<msf::MappedBlockStream> Stream;
@@ -77,6 +84,8 @@ private:
   FixedStreamArray<codeview::TypeIndexOffset> TypeIndexOffsets;
   HashTable<support::ulittle32_t> HashAdjusters;
 
+  std::vector<std::vector<codeview::TypeIndex>> HashMap;
+
   const TpiStreamHeader *Header;
 };
 }

Modified: llvm/trunk/lib/DebugInfo/PDB/Native/TpiHashing.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/PDB/Native/TpiHashing.cpp?rev=342656&r1=342655&r2=342656&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/PDB/Native/TpiHashing.cpp (original)
+++ llvm/trunk/lib/DebugInfo/PDB/Native/TpiHashing.cpp Thu Sep 20 08:50:13 2018
@@ -50,6 +50,32 @@ static Expected<uint32_t> getHashForUdt(
 }
 
 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),
@@ -60,6 +86,23 @@ static Expected<uint32_t> getSourceLineH
   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:

Modified: llvm/trunk/lib/DebugInfo/PDB/Native/TpiStream.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/PDB/Native/TpiStream.cpp?rev=342656&r1=342655&r2=342656&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/PDB/Native/TpiStream.cpp (original)
+++ llvm/trunk/lib/DebugInfo/PDB/Native/TpiStream.cpp Thu Sep 20 08:50:13 2018
@@ -11,8 +11,11 @@
 
 #include "llvm/ADT/iterator_range.h"
 #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
+#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
+#include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"
 #include "llvm/DebugInfo/CodeView/TypeRecord.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"
@@ -140,6 +143,93 @@ uint16_t TpiStream::getTypeHashStreamAux
 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++);
+  }
+}
+
+bool TpiStream::supportsTypeLookup() const { return !HashMap.empty(); }
+
+template <typename RecordT> static ClassOptions getUdtOptions(CVType CVT) {
+  RecordT Record;
+  if (auto EC = TypeDeserializer::deserializeAs<RecordT>(CVT, Record)) {
+    consumeError(std::move(EC));
+    return ClassOptions::None;
+  }
+  return Record.getOptions();
+}
+
+static bool isUdtForwardRef(CVType CVT) {
+  ClassOptions UdtOptions = ClassOptions::None;
+  switch (CVT.kind()) {
+  case LF_STRUCTURE:
+  case LF_CLASS:
+  case LF_INTERFACE:
+    UdtOptions = getUdtOptions<ClassRecord>(std::move(CVT));
+    break;
+  case LF_ENUM:
+    UdtOptions = getUdtOptions<EnumRecord>(std::move(CVT));
+    break;
+  case LF_UNION:
+    UdtOptions = getUdtOptions<UnionRecord>(std::move(CVT));
+    break;
+  default:
+    return false;
+  }
+  return (UdtOptions & ClassOptions::ForwardReference) != ClassOptions::None;
+}
+
+Expected<TypeIndex>
+TpiStream::findFullDeclForForwardRef(TypeIndex ForwardRefTI) const {
+  CVType F = Types->getType(ForwardRefTI);
+  if (!isUdtForwardRef(F))
+    return ForwardRefTI;
+
+  Expected<TagRecordHash> ForwardTRH = hashTagRecord(F);
+  if (!ForwardTRH)
+    return ForwardTRH.takeError();
+
+  TagRecordHash Copy = std::move(*ForwardTRH);
+  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;
+}
+
 BinarySubstreamRef TpiStream::getTypeRecordsSubstream() const {
   return TypeRecordsSubstream;
 }

Added: llvm/trunk/test/DebugInfo/PDB/Inputs/every-class.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/PDB/Inputs/every-class.cpp?rev=342656&view=auto
==============================================================================
--- llvm/trunk/test/DebugInfo/PDB/Inputs/every-class.cpp (added)
+++ llvm/trunk/test/DebugInfo/PDB/Inputs/every-class.cpp Thu Sep 20 08:50:13 2018
@@ -0,0 +1,61 @@
+// Build with "cl.exe /Z7 /GR- /GS- /GX- every-class.cpp /link /debug:full /nodefaultlib /incremental:no /entry:main"
+
+#include <stdint.h>
+
+// clang-format off
+void *__purecall = 0;
+
+void __cdecl operator delete(void *, unsigned int) {}
+void __cdecl operator delete(void *, unsigned __int64) {}
+
+struct Nothing {};
+struct Constructor { Constructor() {} };
+struct Assignment {
+  Assignment &operator=(Assignment Other) { return *this; }
+};
+struct Cast {
+  operator int() { return 42; }
+};
+
+struct Nested {
+  struct F {};
+};
+struct Operator {
+  int operator+(int X) { return 42; }
+};
+
+class Class {};
+
+union Union {};
+
+enum class Enum {A};
+
+
+template<typename T> void f(T t) {}
+
+int main(int argc, char **argv) {
+  struct Scoped {};
+  
+  struct { } Anonymous;
+
+  f(Nothing{});
+  f(Constructor{});
+  f(Assignment{});
+  f(Cast{});
+  f(Nested{});
+  f(Operator{});
+  f(Nested::F{});
+  f(Scoped{});
+  f(Class{});
+  f(Union{});
+  f(Anonymous);
+  f(Enum::A);
+  
+
+  f<const Nothing>(Nothing{});
+  f<volatile Nothing>(Nothing{});
+  f<const volatile Nothing>(Nothing{});
+  f<__unaligned Nothing>(Nothing{});
+
+  return 0;
+}

Added: llvm/trunk/test/DebugInfo/PDB/Inputs/every-class.pdb
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/PDB/Inputs/every-class.pdb?rev=342656&view=auto
==============================================================================
Binary file - no diff available.

Propchange: llvm/trunk/test/DebugInfo/PDB/Inputs/every-class.pdb
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Modified: llvm/trunk/test/DebugInfo/PDB/every-type.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/PDB/every-type.test?rev=342656&r1=342655&r2=342656&view=diff
==============================================================================
--- llvm/trunk/test/DebugInfo/PDB/every-type.test (original)
+++ llvm/trunk/test/DebugInfo/PDB/every-type.test Thu Sep 20 08:50:13 2018
@@ -9,12 +9,14 @@ we claim to understand.  We then test th
 
 
 RUN: llvm-pdbutil dump -type-index=0x101A,0x102C,0x103D,0x104D,0x1098,0x10AA,0x10AC \
-RUN:   -dependents %p/Inputs/every-type.pdb | FileCheck --check-prefix=TYPES %s
+RUN:   -dont-resolve-forward-refs -dependents %p/Inputs/every-type.pdb \
+RUN:   | FileCheck --check-prefix=TYPES %s
 
 RUN: llvm-pdbutil pdb2yaml -tpi-stream -ipi-stream %p/Inputs/every-type.pdb > %t.pdb.yaml
 RUN: llvm-pdbutil yaml2pdb -pdb=%t.yaml.pdb %t.pdb.yaml
 RUN: llvm-pdbutil dump -type-index=0x101A,0x102C,0x103D,0x104D,0x1098,0x10AA,0x10AC \
-RUN:   -dependents %t.yaml.pdb | FileCheck --check-prefix=TYPES %s
+RUN:   -dependents -dont-resolve-forward-refs %t.yaml.pdb \
+RUN:   | FileCheck --check-prefix=TYPES %s
 
 TYPES:                           Types (TPI Stream)
 TYPES-NEXT: ============================================================

Added: llvm/trunk/test/DebugInfo/PDB/pdb-resolve-forward-refs.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/PDB/pdb-resolve-forward-refs.test?rev=342656&view=auto
==============================================================================
--- llvm/trunk/test/DebugInfo/PDB/pdb-resolve-forward-refs.test (added)
+++ llvm/trunk/test/DebugInfo/PDB/pdb-resolve-forward-refs.test Thu Sep 20 08:50:13 2018
@@ -0,0 +1,98 @@
+; RUN: llvm-pdbutil dump -types %p/Inputs/every-class.pdb \
+; RUN:   | FileCheck %s
+
+; CHECK:                      Types (TPI Stream)                     
+; CHECK: ============================================================
+; CHECK:   Showing 157 records
+; CHECK:   0x1008 | LF_STRUCTURE [size = 124] `main::__l2::<unnamed-type-Anonymous>`
+; CHECK:            unique name: `.?AU<unnamed-type-Anonymous>@?1??main@@YAHHPEAPEAD at Z@`aa6523bc`
+; CHECK:            vtable: <no type>, base list: <no type>, field list: 0x1007
+; CHECK:            options: has unique name | scoped, sizeof 1
+; CHECK:   0x1009 | LF_STRUCTURE [size = 88] `main::__l2::Scoped`
+; CHECK:            unique name: `.?AUScoped@?1??main@@YAHHPEAPEAD at Z@`aa6523bc`
+; CHECK:            vtable: <no type>, base list: <no type>, field list: 0x1007
+; CHECK:            options: has unique name | scoped, sizeof 1
+; CHECK:   0x1054 | LF_STRUCTURE [size = 48] `Nested::F`
+; CHECK:            unique name: `.?AUF at Nested@@`
+; CHECK:            vtable: <no type>, base list: <no type>, field list: <no type>
+; CHECK:            options: forward ref (-> 0x1057) | has unique name | is nested, sizeof 0
+; CHECK:   0x1056 | LF_STRUCTURE [size = 44] `Nested`
+; CHECK:            unique name: `.?AUNested@@`
+; CHECK:            vtable: <no type>, base list: <no type>, field list: 0x1055
+; CHECK:            options: contains nested class | has unique name, sizeof 1
+; CHECK:   0x1057 | LF_STRUCTURE [size = 48] `Nested::F`
+; CHECK:            unique name: `.?AUF at Nested@@`
+; CHECK:            vtable: <no type>, base list: <no type>, field list: 0x1007
+; CHECK:            options: has unique name | is nested, sizeof 1
+; CHECK:   0x1058 | LF_STRUCTURE [size = 52] `Constructor`
+; CHECK:            unique name: `.?AUConstructor@@`
+; CHECK:            vtable: <no type>, base list: <no type>, field list: <no type>
+; CHECK:            options: forward ref (-> 0x105C) | has unique name, sizeof 0
+; CHECK:   0x105C | LF_STRUCTURE [size = 52] `Constructor`
+; CHECK:            unique name: `.?AUConstructor@@`
+; CHECK:            vtable: <no type>, base list: <no type>, field list: 0x105B
+; CHECK:            options: has ctor / dtor | has unique name, sizeof 1
+; CHECK:   0x105D | LF_CLASS [size = 40] `Class`
+; CHECK:            unique name: `.?AVClass@@`
+; CHECK:            vtable: <no type>, base list: <no type>, field list: 0x1007
+; CHECK:            options: has unique name, sizeof 1
+; CHECK:   0x105E | LF_UNION [size = 32] `Union`
+; CHECK:            unique name: `.?ATUnion@@`
+; CHECK:            field list: 0x1007
+; CHECK:            options: has unique name | sealed, sizeof 1
+; CHECK:   0x105F | LF_STRUCTURE [size = 48] `Operator`
+; CHECK:            unique name: `.?AUOperator@@`
+; CHECK:            vtable: <no type>, base list: <no type>, field list: <no type>
+; CHECK:            options: forward ref (-> 0x1064) | has unique name, sizeof 0
+; CHECK:   0x1064 | LF_STRUCTURE [size = 48] `Operator`
+; CHECK:            unique name: `.?AUOperator@@`
+; CHECK:            vtable: <no type>, base list: <no type>, field list: 0x1063
+; CHECK:            options: has unique name | overloaded operator, sizeof 1
+; CHECK:   0x1066 | LF_ENUM [size = 36] `Enum`
+; CHECK:            unique name: `.?AW4Enum@@`
+; CHECK:            field list: 0x1065, underlying type: 0x0074 (int)
+; CHECK:            options: has unique name
+; CHECK:   0x1067 | LF_STRUCTURE [size = 40] `Cast`
+; CHECK:            unique name: `.?AUCast@@`
+; CHECK:            vtable: <no type>, base list: <no type>, field list: <no type>
+; CHECK:            options: forward ref (-> 0x106B) | has unique name, sizeof 0
+; CHECK:   0x106B | LF_STRUCTURE [size = 40] `Cast`
+; CHECK:            unique name: `.?AUCast@@`
+; CHECK:            vtable: <no type>, base list: <no type>, field list: 0x106A
+; CHECK:            options: conversion operator | has unique name | overloaded operator, sizeof 1
+; CHECK:   0x106C | LF_STRUCTURE [size = 44] `Nothing`
+; CHECK:            unique name: `.?AUNothing@@`
+; CHECK:            vtable: <no type>, base list: <no type>, field list: 0x1007
+; CHECK:            options: has unique name, sizeof 1
+; CHECK:   0x106D | LF_STRUCTURE [size = 52] `Assignment`
+; CHECK:            unique name: `.?AUAssignment@@`
+; CHECK:            vtable: <no type>, base list: <no type>, field list: <no type>
+; CHECK:            options: forward ref (-> 0x1073) | has unique name, sizeof 0
+; CHECK:   0x1073 | LF_STRUCTURE [size = 52] `Assignment`
+; CHECK:            unique name: `.?AUAssignment@@`
+; CHECK:            vtable: <no type>, base list: <no type>, field list: 0x1072
+; CHECK:            options: has unique name | overloaded operator | overloaded operator=, sizeof 1
+; CHECK:   0x1074 | LF_STRUCTURE [size = 44] `Nothing`
+; CHECK:            unique name: `.?AUNothing@@`
+; CHECK:            vtable: <no type>, base list: <no type>, field list: <no type>
+; CHECK:            options: forward ref (<- 0x106C) | has unique name, sizeof 0
+; CHECK:   0x1081 | LF_UNION [size = 32] `Union`
+; CHECK:            unique name: `.?ATUnion@@`
+; CHECK:            field list: <no type>
+; CHECK:            options: forward ref (<- 0x105E) | has unique name, sizeof 0
+; CHECK:   0x1084 | LF_STRUCTURE [size = 124] `main::__l2::<unnamed-type-Anonymous>`
+; CHECK:            unique name: `.?AU<unnamed-type-Anonymous>@?1??main@@YAHHPEAPEAD at Z@`aa6523bc`
+; CHECK:            vtable: <no type>, base list: <no type>, field list: <no type>
+; CHECK:            options: forward ref (<- 0x1008) | has unique name | scoped, sizeof 0
+; CHECK:   0x108E | LF_STRUCTURE [size = 44] `Nested`
+; CHECK:            unique name: `.?AUNested@@`
+; CHECK:            vtable: <no type>, base list: <no type>, field list: <no type>
+; CHECK:            options: forward ref (<- 0x1056) | has unique name, sizeof 0
+; CHECK:   0x1095 | LF_STRUCTURE [size = 88] `main::__l2::Scoped`
+; CHECK:            unique name: `.?AUScoped@?1??main@@YAHHPEAPEAD at Z@`aa6523bc`
+; CHECK:            vtable: <no type>, base list: <no type>, field list: <no type>
+; CHECK:            options: forward ref (<- 0x1009) | has unique name | scoped, sizeof 0
+; CHECK:   0x1098 | LF_CLASS [size = 40] `Class`
+; CHECK:            unique name: `.?AVClass@@`
+; CHECK:            vtable: <no type>, base list: <no type>, field list: <no type>
+; CHECK:            options: forward ref (<- 0x105D) | has unique name, sizeof 0

Modified: llvm/trunk/test/DebugInfo/PDB/pdbdump-headers.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/PDB/pdbdump-headers.test?rev=342656&r1=342655&r2=342656&view=diff
==============================================================================
--- llvm/trunk/test/DebugInfo/PDB/pdbdump-headers.test (original)
+++ llvm/trunk/test/DebugInfo/PDB/pdbdump-headers.test Thu Sep 20 08:50:13 2018
@@ -1,7 +1,9 @@
-; RUN: llvm-pdbutil dump -all %p/Inputs/empty.pdb | FileCheck -check-prefix=ALL %s
+; RUN: llvm-pdbutil dump -all -dont-resolve-forward-refs %p/Inputs/empty.pdb \
+; RUN:   | FileCheck -check-prefix=ALL %s
 ; RUN: llvm-pdbutil dump -summary -modules -files \
 ; RUN:              %p/Inputs/big-read.pdb | FileCheck -check-prefix=BIG %s
-; RUN: not llvm-pdbutil dump -summary %p/Inputs/bad-block-size.pdb 2>&1 | FileCheck -check-prefix=BAD-BLOCK-SIZE %s
+; RUN: not llvm-pdbutil dump -summary %p/Inputs/bad-block-size.pdb 2>&1 \
+; RUN:   | FileCheck -check-prefix=BAD-BLOCK-SIZE %s
 
 ALL:                                Summary
 ALL-NEXT: ============================================================

Modified: llvm/trunk/tools/llvm-pdbutil/DumpOutputStyle.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-pdbutil/DumpOutputStyle.cpp?rev=342656&r1=342655&r2=342656&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-pdbutil/DumpOutputStyle.cpp (original)
+++ llvm/trunk/tools/llvm-pdbutil/DumpOutputStyle.cpp Thu Sep 20 08:50:13 2018
@@ -1241,13 +1241,13 @@ static void
 dumpFullTypeStream(LinePrinter &Printer, LazyRandomTypeCollection &Types,
                    uint32_t NumTypeRecords, uint32_t NumHashBuckets,
                    FixedStreamArray<support::ulittle32_t> HashValues,
-                   bool Bytes, bool Extras) {
+                   TpiStream *Stream, bool Bytes, bool Extras) {
 
   Printer.formatLine("Showing {0:N} records", NumTypeRecords);
   uint32_t Width = NumDigits(TypeIndex::FirstNonSimpleIndex + NumTypeRecords);
 
   MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types,
-                           NumHashBuckets, HashValues);
+                           NumHashBuckets, HashValues, Stream);
 
   if (auto EC = codeview::visitTypeStream(Types, V)) {
     Printer.formatLine("An error occurred dumping type records: {0}",
@@ -1263,7 +1263,8 @@ static void dumpPartialTypeStream(LinePr
       NumDigits(TypeIndex::FirstNonSimpleIndex + Stream.getNumTypeRecords());
 
   MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types,
-                           Stream.getNumHashBuckets(), Stream.getHashValues());
+                           Stream.getNumHashBuckets(), Stream.getHashValues(),
+                           &Stream);
 
   if (opts::dump::DumpTypeDependents) {
     // If we need to dump all dependents, then iterate each index and find
@@ -1325,7 +1326,8 @@ Error DumpOutputStyle::dumpTypesFromObje
     Types.reset(Reader, 100);
 
     if (opts::dump::DumpTypes) {
-      dumpFullTypeStream(P, Types, 0, 0, {}, opts::dump::DumpTypeData, false);
+      dumpFullTypeStream(P, Types, 0, 0, {}, nullptr, opts::dump::DumpTypeData,
+                         false);
     } else if (opts::dump::DumpTypeExtras) {
       auto LocalHashes = LocallyHashedType::hashTypeCollection(Types);
       auto GlobalHashes = GloballyHashedType::hashTypeCollection(Types);
@@ -1394,11 +1396,14 @@ Error DumpOutputStyle::dumpTpiStream(uin
 
   auto &Types = (StreamIdx == StreamTPI) ? File.types() : File.ids();
 
+  // Enable resolving forward decls.
+  Stream.buildHashMap();
+
   if (DumpTypes || !Indices.empty()) {
     if (Indices.empty())
       dumpFullTypeStream(P, Types, Stream.getNumTypeRecords(),
                          Stream.getNumHashBuckets(), Stream.getHashValues(),
-                         DumpBytes, DumpExtras);
+                         &Stream, DumpBytes, DumpExtras);
     else {
       std::vector<TypeIndex> TiList(Indices.begin(), Indices.end());
       dumpPartialTypeStream(P, Types, Stream, TiList, DumpBytes, DumpExtras,

Modified: llvm/trunk/tools/llvm-pdbutil/MinimalTypeDumper.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-pdbutil/MinimalTypeDumper.cpp?rev=342656&r1=342655&r2=342656&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-pdbutil/MinimalTypeDumper.cpp (original)
+++ llvm/trunk/tools/llvm-pdbutil/MinimalTypeDumper.cpp Thu Sep 20 08:50:13 2018
@@ -12,6 +12,7 @@
 #include "FormatUtil.h"
 #include "LinePrinter.h"
 
+#include "llvm-pdbutil.h"
 #include "llvm/DebugInfo/CodeView/CVRecord.h"
 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
 #include "llvm/DebugInfo/CodeView/CodeView.h"
@@ -19,6 +20,7 @@
 #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
 #include "llvm/DebugInfo/PDB/Native/TpiHashing.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
 #include "llvm/Support/FormatVariadic.h"
 #include "llvm/Support/MathExtras.h"
 
@@ -27,15 +29,37 @@ using namespace llvm::codeview;
 using namespace llvm::pdb;
 
 static std::string formatClassOptions(uint32_t IndentLevel,
-                                      ClassOptions Options) {
+                                      ClassOptions Options, TpiStream *Stream,
+                                      TypeIndex CurrentTypeIndex) {
   std::vector<std::string> Opts;
+
+  if (Stream && Stream->supportsTypeLookup() &&
+      !opts::dump::DontResolveForwardRefs &&
+      ((Options & ClassOptions::ForwardReference) != ClassOptions::None)) {
+    // If we're able to resolve forward references, do that.
+    Expected<TypeIndex> ETI =
+        Stream->findFullDeclForForwardRef(CurrentTypeIndex);
+    if (!ETI) {
+      consumeError(ETI.takeError());
+      PUSH_FLAG(ClassOptions, ForwardReference, Options, "forward ref (???)");
+    } else {
+      const char *Direction = (*ETI == CurrentTypeIndex)
+                                  ? "="
+                                  : ((*ETI < CurrentTypeIndex) ? "<-" : "->");
+      std::string Formatted =
+          formatv("forward ref ({0} {1})", Direction, *ETI).str();
+      PUSH_FLAG(ClassOptions, ForwardReference, Options, std::move(Formatted));
+    }
+  } else {
+    PUSH_FLAG(ClassOptions, ForwardReference, Options, "forward ref");
+  }
+
   PUSH_FLAG(ClassOptions, HasConstructorOrDestructor, Options,
             "has ctor / dtor");
   PUSH_FLAG(ClassOptions, ContainsNestedClass, Options,
             "contains nested class");
   PUSH_FLAG(ClassOptions, HasConversionOperator, Options,
             "conversion operator");
-  PUSH_FLAG(ClassOptions, ForwardReference, Options, "forward ref");
   PUSH_FLAG(ClassOptions, HasUniqueName, Options, "has unique name");
   PUSH_FLAG(ClassOptions, Intrinsic, Options, "intrin");
   PUSH_FLAG(ClassOptions, Nested, Options, "is nested");
@@ -194,6 +218,7 @@ static std::string formatFunctionOptions
 }
 
 Error MinimalTypeDumpVisitor::visitTypeBegin(CVType &Record, TypeIndex Index) {
+  CurrentTypeIndex = Index;
   // formatLine puts the newline at the beginning, so we use formatLine here
   // to start a new line, and then individual visit methods use format to
   // append to the existing line.
@@ -304,7 +329,8 @@ Error MinimalTypeDumpVisitor::visitKnown
   P.formatLine("vtable: {0}, base list: {1}, field list: {2}",
                Class.VTableShape, Class.DerivationList, Class.FieldList);
   P.formatLine("options: {0}, sizeof {1}",
-               formatClassOptions(P.getIndentLevel(), Class.Options),
+               formatClassOptions(P.getIndentLevel(), Class.Options, Stream,
+                                  CurrentTypeIndex),
                Class.Size);
   return Error::success();
 }
@@ -316,7 +342,8 @@ Error MinimalTypeDumpVisitor::visitKnown
     P.formatLine("unique name: `{0}`", Union.UniqueName);
   P.formatLine("field list: {0}", Union.FieldList);
   P.formatLine("options: {0}, sizeof {1}",
-               formatClassOptions(P.getIndentLevel(), Union.Options),
+               formatClassOptions(P.getIndentLevel(), Union.Options, Stream,
+                                  CurrentTypeIndex),
                Union.Size);
   return Error::success();
 }
@@ -328,7 +355,8 @@ Error MinimalTypeDumpVisitor::visitKnown
   P.formatLine("field list: {0}, underlying type: {1}", Enum.FieldList,
                Enum.UnderlyingType);
   P.formatLine("options: {0}",
-               formatClassOptions(P.getIndentLevel(), Enum.Options));
+               formatClassOptions(P.getIndentLevel(), Enum.Options, Stream,
+                                  CurrentTypeIndex));
   return Error::success();
 }
 

Modified: llvm/trunk/tools/llvm-pdbutil/MinimalTypeDumper.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-pdbutil/MinimalTypeDumper.h?rev=342656&r1=342655&r2=342656&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-pdbutil/MinimalTypeDumper.h (original)
+++ llvm/trunk/tools/llvm-pdbutil/MinimalTypeDumper.h Thu Sep 20 08:50:13 2018
@@ -20,15 +20,18 @@ class LazyRandomTypeCollection;
 
 namespace pdb {
 class LinePrinter;
+class TpiStream;
 
 class MinimalTypeDumpVisitor : public codeview::TypeVisitorCallbacks {
 public:
   MinimalTypeDumpVisitor(LinePrinter &P, uint32_t Width, bool RecordBytes,
                          bool Hashes, codeview::LazyRandomTypeCollection &Types,
                          uint32_t NumHashBuckets,
-                         FixedStreamArray<support::ulittle32_t> HashValues)
+                         FixedStreamArray<support::ulittle32_t> HashValues,
+                         pdb::TpiStream *Stream)
       : P(P), Width(Width), RecordBytes(RecordBytes), Hashes(Hashes),
-        Types(Types), NumHashBuckets(NumHashBuckets), HashValues(HashValues) {}
+        Types(Types), NumHashBuckets(NumHashBuckets), HashValues(HashValues),
+        Stream(Stream) {}
 
   Error visitTypeBegin(codeview::CVType &Record,
                        codeview::TypeIndex Index) override;
@@ -55,7 +58,9 @@ private:
   bool Hashes = false;
   codeview::LazyRandomTypeCollection &Types;
   uint32_t NumHashBuckets;
+  codeview::TypeIndex CurrentTypeIndex;
   FixedStreamArray<support::ulittle32_t> HashValues;
+  pdb::TpiStream *Stream = nullptr;
 };
 } // namespace pdb
 } // namespace llvm

Modified: llvm/trunk/tools/llvm-pdbutil/llvm-pdbutil.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-pdbutil/llvm-pdbutil.cpp?rev=342656&r1=342655&r2=342656&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-pdbutil/llvm-pdbutil.cpp (original)
+++ llvm/trunk/tools/llvm-pdbutil/llvm-pdbutil.cpp Thu Sep 20 08:50:13 2018
@@ -183,6 +183,8 @@ static cl::opt<bool> Enums("enums", cl::
                            cl::sub(DiaDumpSubcommand));
 static cl::opt<bool> Pointers("pointers", cl::desc("Dump enum types"),
                               cl::sub(DiaDumpSubcommand));
+static cl::opt<bool> UDTs("udts", cl::desc("Dump udt types"),
+                          cl::sub(DiaDumpSubcommand));
 static cl::opt<bool> Compilands("compilands",
                                 cl::desc("Dump compiland information"),
                                 cl::sub(DiaDumpSubcommand));
@@ -465,6 +467,12 @@ cl::opt<bool> DumpTypeExtras("type-extra
                              cl::desc("dump type hashes and index offsets"),
                              cl::cat(TypeOptions), cl::sub(DumpSubcommand));
 
+cl::opt<bool> DontResolveForwardRefs(
+    "dont-resolve-forward-refs",
+    cl::desc("When dumping type records for classes, unions, enums, and "
+             "structs, don't try to resolve forward references"),
+    cl::cat(TypeOptions), cl::sub(DumpSubcommand));
+
 cl::list<uint32_t> DumpTypeIndex(
     "type-index", cl::ZeroOrMore, cl::CommaSeparated,
     cl::desc("only dump types with the specified hexadecimal type index"),

Modified: llvm/trunk/tools/llvm-pdbutil/llvm-pdbutil.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-pdbutil/llvm-pdbutil.h?rev=342656&r1=342655&r2=342656&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-pdbutil/llvm-pdbutil.h (original)
+++ llvm/trunk/tools/llvm-pdbutil/llvm-pdbutil.h Thu Sep 20 08:50:13 2018
@@ -160,6 +160,7 @@ extern llvm::cl::opt<bool> DumpIdExtras;
 extern llvm::cl::list<uint32_t> DumpIdIndex;
 extern llvm::cl::opt<uint32_t> DumpModi;
 extern llvm::cl::opt<bool> JustMyCode;
+extern llvm::cl::opt<bool> DontResolveForwardRefs;
 extern llvm::cl::opt<bool> DumpSymbols;
 extern llvm::cl::opt<bool> DumpSymRecordBytes;
 extern llvm::cl::opt<bool> DumpGSIRecords;




More information about the llvm-commits mailing list