[PDB] Split item and type records when merging type streams
authorReid Kleckner <rnk@google.com>
Fri, 24 Mar 2017 17:26:38 +0000 (17:26 +0000)
committerReid Kleckner <rnk@google.com>
Fri, 24 Mar 2017 17:26:38 +0000 (17:26 +0000)
Summary: MSVC does this when producing a PDB.

Reviewers: ruiu

Subscribers: llvm-commits

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

llvm-svn: 298717

lld/COFF/PDB.cpp
lld/test/COFF/pdb.test
llvm/include/llvm/DebugInfo/CodeView/TypeStreamMerger.h
llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp
llvm/test/tools/llvm-readobj/codeview-merging.test
llvm/tools/llvm-readobj/COFFDumper.cpp
llvm/tools/llvm-readobj/ObjDumper.h
llvm/tools/llvm-readobj/llvm-readobj.cpp

index 5af93e8..79c798c 100644 (file)
@@ -82,18 +82,40 @@ static ArrayRef<uint8_t> getDebugSection(ObjectFile *File, StringRef SecName) {
   return Data.slice(4);
 }
 
-// Merge .debug$T sections and returns it.
-static std::vector<uint8_t> mergeDebugT(SymbolTable *Symtab) {
-  ScopedPrinter W(outs());
+static void addTypeInfo(pdb::TpiStreamBuilder &TpiBuilder,
+                        codeview::TypeTableBuilder &TypeTable,
+                        std::vector<uint8_t> &Data) {
+  // Start the TPI or IPI stream header.
+  TpiBuilder.setVersionHeader(pdb::PdbTpiV80);
+
+  // Flatten the in memory type table.
+  // FIXME: Avoid this copy.
+  TypeTable.ForEachRecord([&](TypeIndex TI, ArrayRef<uint8_t> Rec) {
+    Data.insert(Data.end(), Rec.begin(), Rec.end());
+  });
 
+  BinaryByteStream Stream(Data, support::little);
+  codeview::CVTypeArray Records;
+  BinaryStreamReader Reader(Stream);
+  if (auto EC = Reader.readArray(Records, Reader.getLength()))
+    fatal(EC, "Reader.readArray failed");
+  for (const codeview::CVType &Rec : Records)
+    TpiBuilder.addTypeRecord(Rec);
+}
+
+// Merge .debug$T sections into IpiData and TpiData.
+static void mergeDebugT(SymbolTable *Symtab, pdb::PDBFileBuilder &Builder,
+                        std::vector<uint8_t> &TpiData,
+                        std::vector<uint8_t> &IpiData) {
   // Visit all .debug$T sections to add them to Builder.
-  codeview::TypeTableBuilder Builder(BAlloc);
+  codeview::TypeTableBuilder IDTable(BAlloc);
+  codeview::TypeTableBuilder TypeTable(BAlloc);
   for (ObjectFile *File : Symtab->ObjectFiles) {
     ArrayRef<uint8_t> Data = getDebugSection(File, ".debug$T");
     if (Data.empty())
       continue;
 
-    BinaryByteStream Stream(Data, llvm::support::little);
+    BinaryByteStream Stream(Data, support::little);
     codeview::CVTypeArray Types;
     BinaryStreamReader Reader(Stream);
     // Follow type servers.  If the same type server is encountered more than
@@ -104,16 +126,16 @@ static std::vector<uint8_t> mergeDebugT(SymbolTable *Symtab) {
     Handler.addSearchPath(llvm::sys::path::parent_path(File->getName()));
     if (auto EC = Reader.readArray(Types, Reader.getLength()))
       fatal(EC, "Reader::readArray failed");
-    if (auto Err = codeview::mergeTypeStreams(Builder, &Handler, Types))
+    if (auto Err =
+            codeview::mergeTypeStreams(IDTable, TypeTable, &Handler, Types))
       fatal(Err, "codeview::mergeTypeStreams failed");
   }
 
-  // Construct section contents.
-  std::vector<uint8_t> V;
-  Builder.ForEachRecord([&](TypeIndex TI, ArrayRef<uint8_t> Rec) {
-    V.insert(V.end(), Rec.begin(), Rec.end());
-  });
-  return V;
+  // Construct TPI stream contents.
+  addTypeInfo(Builder.getTpiBuilder(), TypeTable, TpiData);
+
+  // Construct IPI stream contents.
+  addTypeInfo(Builder.getIpiBuilder(), IDTable, IpiData);
 }
 
 static void dumpDebugT(ScopedPrinter &W, ObjectFile *File) {
@@ -159,17 +181,6 @@ static void dumpCodeView(SymbolTable *Symtab) {
   }
 }
 
-static void addTypeInfo(pdb::TpiStreamBuilder &TpiBuilder,
-                        ArrayRef<uint8_t> Data) {
-  BinaryByteStream Stream(Data, llvm::support::little);
-  codeview::CVTypeArray Records;
-  BinaryStreamReader Reader(Stream);
-  if (auto EC = Reader.readArray(Records, Reader.getLength()))
-    fatal(EC, "Reader.readArray failed");
-  for (const codeview::CVType &Rec : Records)
-    TpiBuilder.addTypeRecord(Rec);
-}
-
 // Creates a PDB file.
 void coff::createPDB(StringRef Path, SymbolTable *Symtab,
                      ArrayRef<uint8_t> SectionTable,
@@ -202,18 +213,9 @@ void coff::createPDB(StringRef Path, SymbolTable *Symtab,
   auto &DbiBuilder = Builder.getDbiBuilder();
   DbiBuilder.setVersionHeader(pdb::PdbDbiV110);
 
-  // Add an empty TPI stream.
-  auto &TpiBuilder = Builder.getTpiBuilder();
-  TpiBuilder.setVersionHeader(pdb::PdbTpiV80);
   std::vector<uint8_t> TpiData;
-  if (Config->DebugPdb) {
-    TpiData = mergeDebugT(Symtab);
-    addTypeInfo(TpiBuilder, TpiData);
-  }
-
-  // Add an empty IPI stream.
-  auto &IpiBuilder = Builder.getIpiBuilder();
-  IpiBuilder.setVersionHeader(pdb::PdbTpiV80);
+  std::vector<uint8_t> IpiData;
+  mergeDebugT(Symtab, Builder, TpiData, IpiData);
 
   // Add Section Contributions.
   std::vector<pdb::SectionContrib> Contribs =
index 27f3ae3..45e8908 100644 (file)
@@ -60,6 +60,9 @@
 # CHECK-NEXT:         Options:         [ None ]
 # CHECK-NEXT:         ParameterCount:  0
 # CHECK-NEXT:         ArgumentList:    4099
+# CHECK-NEXT: IpiStream:
+# CHECK-NEXT:   Version:         VC80
+# CHECK-NEXT:   Records:
 # CHECK-NEXT:     - Kind:            LF_FUNC_ID
 # CHECK-NEXT:       FuncId:
 # CHECK-NEXT:         ParentScope:     0
 # CHECK-NEXT:         String:          '-Z7 -c -MT -IC:\vs14\VC\INCLUDE -IC:\vs14\VC\ATLMFC\INCLUDE -I"C:\Program Files (x86)\Windows Kits\10\include\10.0.10150.0\ucrt" -I"C:\Program Files (x86)\Windows Kits\NETFXSDK\4.6\include\um" -I"C:\Program Files (x86)\Windows Kits\8.1\include\shared"'
 # CHECK-NEXT:     - Kind:            LF_SUBSTR_LIST
 # CHECK-NEXT:       StringList:
-# CHECK-NEXT:         StringIndices:      [ 4105 ]
+# CHECK-NEXT:         StringIndices:   [ 4100 ]
 # CHECK-NEXT:     - Kind:            LF_STRING_ID
 # CHECK-NEXT:       StringId:
-# CHECK-NEXT:         Id:              4106
+# CHECK-NEXT:         Id:              4101
 # CHECK-NEXT:         String:          ' -I"C:\Program Files (x86)\Windows Kits\8.1\include\um" -I"C:\Program Files (x86)\Windows Kits\8.1\include\winrt" -TC -X'
 # CHECK-NEXT:     - Kind:            LF_STRING_ID
 # CHECK-NEXT:       StringId:
 # CHECK-NEXT:         String:          'D:\b\vc140.pdb'
 # CHECK-NEXT:     - Kind:            LF_BUILDINFO
 # CHECK-NEXT:       BuildInfo:
-# CHECK-NEXT:         ArgIndices:      [ 4103, 4104, 4108, 4109, 4107 ]
+# CHECK-NEXT:         ArgIndices:      [ 4098, 4099, 4103, 4104, 4102 ]
 # CHECK-NEXT:     - Kind:            LF_STRING_ID
 # CHECK-NEXT:       StringId:
 # CHECK-NEXT:         Id:              0
 # CHECK-NEXT:         String:          ret42-sub.c
 # CHECK-NEXT:     - Kind:            LF_BUILDINFO
 # CHECK-NEXT:       BuildInfo:
-# CHECK-NEXT:         ArgIndices:      [ 4103, 4104, 4111, 4109, 4107 ]
-# CHECK-NEXT: IpiStream:
-# CHECK-NEXT:   Version:         VC80
-# CHECK-NEXT:   Records:
+# CHECK-NEXT:         ArgIndices:      [ 4098, 4099, 4106, 4104, 4102 ]
 
 # RAW:      FileHeaders {
 # RAW-NEXT:   BlockSize: 4096
index a06b5b7..2246f19 100644 (file)
@@ -21,8 +21,9 @@ namespace codeview {
 class TypeServerHandler;
 
 /// Merges one type stream into another. Returns true on success.
-Error mergeTypeStreams(TypeTableBuilder &DestStream, TypeServerHandler *Handler,
-                       const CVTypeArray &Types);
+Error mergeTypeStreams(TypeTableBuilder &DestIdStream,
+                       TypeTableBuilder &DestTypeStream,
+                       TypeServerHandler *Handler, const CVTypeArray &Types);
 
 } // end namespace codeview
 } // end namespace llvm
index b01eaa8..07d6a56 100644 (file)
@@ -52,11 +52,17 @@ namespace {
 /// - If the type record already exists in the destination stream, discard it
 ///   and update the type index map to forward the source type index to the
 ///   existing destination type index.
+///
+/// As an additional complication, type stream merging actually produces two
+/// streams: an item (or IPI) stream and a type stream, as this is what is
+/// actually stored in the final PDB. We choose which records go where by
+/// looking at the record kind.
 class TypeStreamMerger : public TypeVisitorCallbacks {
 public:
-  TypeStreamMerger(TypeTableBuilder &DestStream, TypeServerHandler *Handler)
-      : DestStream(DestStream), FieldListBuilder(DestStream), Handler(Handler) {
-  }
+  TypeStreamMerger(TypeTableBuilder &DestIdStream,
+                   TypeTableBuilder &DestTypeStream, TypeServerHandler *Handler)
+      : DestIdStream(DestIdStream), DestTypeStream(DestTypeStream),
+        FieldListBuilder(DestTypeStream), Handler(Handler) {}
 
 /// TypeVisitorCallbacks overrides.
 #define TYPE_RECORD(EnumName, EnumVal, Name)                                   \
@@ -85,7 +91,18 @@ private:
           std::move(*LastError),
           llvm::make_error<CodeViewError>(cv_error_code::corrupt_record));
     }
-    IndexMap.push_back(DestStream.writeKnownType(R));
+    IndexMap.push_back(DestTypeStream.writeKnownType(R));
+    return Error::success();
+  }
+
+  template <typename RecordType>
+  Error writeIdRecord(RecordType &R, bool RemapSuccess) {
+    if (!RemapSuccess) {
+      LastError = joinErrors(
+          std::move(*LastError),
+          llvm::make_error<CodeViewError>(cv_error_code::corrupt_record));
+    }
+    IndexMap.push_back(DestIdStream.writeKnownType(R));
     return Error::success();
   }
 
@@ -104,7 +121,8 @@ private:
 
   BumpPtrAllocator Allocator;
 
-  TypeTableBuilder &DestStream;
+  TypeTableBuilder &DestIdStream;
+  TypeTableBuilder &DestTypeStream;
   FieldListRecordBuilder FieldListBuilder;
   TypeServerHandler *Handler;
 
@@ -158,6 +176,62 @@ bool TypeStreamMerger::remapIndex(TypeIndex &Idx) {
   return false;
 }
 
+//----------------------------------------------------------------------------//
+// Item records
+//----------------------------------------------------------------------------//
+
+Error TypeStreamMerger::visitKnownRecord(CVType &, FuncIdRecord &R) {
+  bool Success = true;
+  Success &= remapIndex(R.ParentScope);
+  Success &= remapIndex(R.FunctionType);
+  return writeIdRecord(R, Success);
+}
+
+Error TypeStreamMerger::visitKnownRecord(CVType &, MemberFuncIdRecord &R) {
+  bool Success = true;
+  Success &= remapIndex(R.ClassType);
+  Success &= remapIndex(R.FunctionType);
+  return writeIdRecord(R, Success);
+}
+
+Error TypeStreamMerger::visitKnownRecord(CVType &, StringIdRecord &R) {
+  return writeIdRecord(R, remapIndex(R.Id));
+}
+
+Error TypeStreamMerger::visitKnownRecord(CVType &, StringListRecord &R) {
+  bool Success = true;
+  for (TypeIndex &Str : R.StringIndices)
+    Success &= remapIndex(Str);
+  return writeIdRecord(R, Success);
+}
+
+Error TypeStreamMerger::visitKnownRecord(CVType &, BuildInfoRecord &R) {
+  bool Success = true;
+  for (TypeIndex &Arg : R.ArgIndices)
+    Success &= remapIndex(Arg);
+  return writeIdRecord(R, Success);
+}
+
+Error TypeStreamMerger::visitKnownRecord(CVType &, UdtSourceLineRecord &R) {
+  bool Success = true;
+  Success &= remapIndex(R.UDT);
+  Success &= remapIndex(R.SourceFile);
+  // FIXME: Translate UdtSourceLineRecord into UdtModSourceLineRecords in the
+  // IPI stream.
+  return writeIdRecord(R, Success);
+}
+
+Error TypeStreamMerger::visitKnownRecord(CVType &, UdtModSourceLineRecord &R) {
+  bool Success = true;
+  Success &= remapIndex(R.UDT);
+  Success &= remapIndex(R.SourceFile);
+  return writeIdRecord(R, Success);
+}
+
+//----------------------------------------------------------------------------//
+// Type records
+//----------------------------------------------------------------------------//
+
 Error TypeStreamMerger::visitKnownRecord(CVType &, ModifierRecord &R) {
   return writeRecord(R, remapIndex(R.ModifiedType));
 }
@@ -178,13 +252,6 @@ Error TypeStreamMerger::visitKnownRecord(CVType &, MemberFunctionRecord &R) {
   return writeRecord(R, Success);
 }
 
-Error TypeStreamMerger::visitKnownRecord(CVType &, MemberFuncIdRecord &R) {
-  bool Success = true;
-  Success &= remapIndex(R.ClassType);
-  Success &= remapIndex(R.FunctionType);
-  return writeRecord(R, Success);
-}
-
 Error TypeStreamMerger::visitKnownRecord(CVType &, ArgListRecord &R) {
   bool Success = true;
   for (TypeIndex &Arg : R.ArgIndices)
@@ -192,13 +259,6 @@ Error TypeStreamMerger::visitKnownRecord(CVType &, ArgListRecord &R) {
   return writeRecord(R, Success);
 }
 
-Error TypeStreamMerger::visitKnownRecord(CVType &, StringListRecord &R) {
-  bool Success = true;
-  for (TypeIndex &Str : R.StringIndices)
-    Success &= remapIndex(Str);
-  return writeRecord(R, Success);
-}
-
 Error TypeStreamMerger::visitKnownRecord(CVType &, PointerRecord &R) {
   bool Success = true;
   Success &= remapIndex(R.ReferentType);
@@ -245,38 +305,6 @@ Error TypeStreamMerger::visitKnownRecord(CVType &, TypeServer2Record &R) {
   return writeRecord(R, true);
 }
 
-Error TypeStreamMerger::visitKnownRecord(CVType &, StringIdRecord &R) {
-  return writeRecord(R, remapIndex(R.Id));
-}
-
-Error TypeStreamMerger::visitKnownRecord(CVType &, FuncIdRecord &R) {
-  bool Success = true;
-  Success &= remapIndex(R.ParentScope);
-  Success &= remapIndex(R.FunctionType);
-  return writeRecord(R, Success);
-}
-
-Error TypeStreamMerger::visitKnownRecord(CVType &, UdtSourceLineRecord &R) {
-  bool Success = true;
-  Success &= remapIndex(R.UDT);
-  Success &= remapIndex(R.SourceFile);
-  return writeRecord(R, Success);
-}
-
-Error TypeStreamMerger::visitKnownRecord(CVType &, UdtModSourceLineRecord &R) {
-  bool Success = true;
-  Success &= remapIndex(R.UDT);
-  Success &= remapIndex(R.SourceFile);
-  return writeRecord(R, Success);
-}
-
-Error TypeStreamMerger::visitKnownRecord(CVType &, BuildInfoRecord &R) {
-  bool Success = true;
-  for (TypeIndex &Arg : R.ArgIndices)
-    Success &= remapIndex(Arg);
-  return writeRecord(R, Success);
-}
-
 Error TypeStreamMerger::visitKnownRecord(CVType &, VFTableRecord &R) {
   bool Success = true;
   Success &= remapIndex(R.CompleteClass);
@@ -300,6 +328,10 @@ Error TypeStreamMerger::visitKnownRecord(CVType &, FieldListRecord &R) {
   return Error::success();
 }
 
+//----------------------------------------------------------------------------//
+// Member records
+//----------------------------------------------------------------------------//
+
 Error TypeStreamMerger::visitKnownMember(CVMemberRecord &,
                                          NestedTypeRecord &R) {
   return writeMember(R, remapIndex(R.Type));
@@ -381,8 +413,10 @@ Error TypeStreamMerger::mergeStream(const CVTypeArray &Types) {
   return Ret;
 }
 
-Error llvm::codeview::mergeTypeStreams(TypeTableBuilder &DestStream,
+Error llvm::codeview::mergeTypeStreams(TypeTableBuilder &DestIdStream,
+                                       TypeTableBuilder &DestTypeStream,
                                        TypeServerHandler *Handler,
                                        const CVTypeArray &Types) {
-  return TypeStreamMerger(DestStream, Handler).mergeStream(Types);
+  return TypeStreamMerger(DestIdStream, DestTypeStream, Handler)
+      .mergeStream(Types);
 }
index 60894ef..4d453e5 100644 (file)
@@ -21,6 +21,15 @@ RUN: llvm-readobj -codeview %S/Inputs/codeview-merging-1.obj | FileCheck %s --ch
 RUN: llvm-readobj -codeview %S/Inputs/codeview-merging-2.obj | FileCheck %s --check-prefix=OBJ2
 RUN: llvm-readobj -codeview-merged-types %S/Inputs/codeview-merging-1.obj %S/Inputs/codeview-merging-2.obj | FileCheck %s
 
+OBJ1:       Procedure ({{.*}}) {
+OBJ1-NEXT:    TypeLeafKind: LF_PROCEDURE (0x1008)
+OBJ1-NEXT:    ReturnType: int (0x74)
+OBJ1-NEXT:    CallingConvention: NearC (0x0)
+OBJ1-NEXT:    FunctionOptions [ (0x0)
+OBJ1-NEXT:    ]
+OBJ1-NEXT:    NumParameters: 1
+OBJ1-NEXT:    ArgListType: (A*) (0x1002)
+OBJ1-NEXT:  }
 OBJ1:       FuncId (0x100D) {
 OBJ1-NEXT:    TypeLeafKind: LF_FUNC_ID (0x1601)
 OBJ1-NEXT:    ParentScope: 0x0
@@ -50,16 +59,55 @@ OBJ2-NEXT:    Name: g
 OBJ2-NEXT:  }
 OBJ2-NOT: FuncId
 
-CHECK:       FuncId (0x100D) {
+CHECK: MergedTypeStream [
+CHECK:       Procedure ({{.*}}) {
+CHECK-NEXT:    TypeLeafKind: LF_PROCEDURE (0x1008)
+CHECK-NEXT:    ReturnType: int (0x74)
+CHECK-NEXT:    CallingConvention: NearC (0x0)
+CHECK-NEXT:    FunctionOptions [ (0x0)
+CHECK-NEXT:    ]
+CHECK-NEXT:    NumParameters: 1
+CHECK-NEXT:    ArgListType: (A*) (0x1002)
+CHECK-NEXT:  }
+CHECK:       Struct (0x1007) {
+CHECK-NEXT:    TypeLeafKind: LF_STRUCTURE (0x1505)
+CHECK-NEXT:    MemberCount: 1
+CHECK-NEXT:    Properties [ (0x200)
+CHECK-NEXT:      HasUniqueName (0x200)
+CHECK-NEXT:    ]
+CHECK-NEXT:    FieldList: <field list> (0x1006)
+CHECK-NEXT:    DerivedFrom: 0x0
+CHECK-NEXT:    VShape: 0x0
+CHECK-NEXT:    SizeOf: 8
+CHECK-NEXT:    Name: B
+CHECK-NEXT:    LinkageName: .?AUB@@
+CHECK-NEXT:  }
+CHECK: ]
+
+CHECK: MergedIDStream [
+CHECK-NEXT:  StringId (0x1000) {
+CHECK-NEXT:    TypeLeafKind: LF_STRING_ID (0x1605)
+CHECK-NEXT:    Id: 0x0
+CHECK-NEXT:    StringData: d:\src\llvm\build\t.cpp
+CHECK-NEXT:  }
+# Test that we contextually dump item ids and type ids from different databases.
+CHECK-NEXT:  UdtSourceLine (0x1001) {
+CHECK-NEXT:    TypeLeafKind: LF_UDT_SRC_LINE (0x1606)
+CHECK-NEXT:    UDT: B (0x1007)
+CHECK-NEXT:    SourceFile: d:\src\llvm\build\t.cpp (0x1000)
+CHECK-NEXT:    LineNumber: 3
+CHECK-NEXT:  }
+CHECK:       FuncId (0x1002) {
 CHECK-NEXT:    TypeLeafKind: LF_FUNC_ID (0x1601)
 CHECK-NEXT:    ParentScope: 0x0
-CHECK-NEXT:    FunctionType: int (B*) (0x100C)
+CHECK-NEXT:    FunctionType: int (B*)
 CHECK-NEXT:    Name: g
 CHECK-NEXT:  }
-CHECK-NEXT:  FuncId (0x100E) {
+CHECK-NEXT:  FuncId (0x1003) {
 CHECK-NEXT:    TypeLeafKind: LF_FUNC_ID (0x1601)
 CHECK-NEXT:    ParentScope: 0x0
-CHECK-NEXT:    FunctionType: int (A*) (0x1003)
+CHECK-NEXT:    FunctionType: int (A*)
 CHECK-NEXT:    Name: f
 CHECK-NEXT:  }
 CHECK-NOT: FuncId
+CHECK: ]
index 263f666..1042765 100644 (file)
@@ -79,7 +79,8 @@ public:
   void printCOFFBaseReloc() override;
   void printCOFFDebugDirectory() override;
   void printCodeViewDebugInfo() override;
-  void mergeCodeViewTypes(llvm::codeview::TypeTableBuilder &CVTypes) override;
+  void mergeCodeViewTypes(llvm::codeview::TypeTableBuilder &CVIDs,
+                          llvm::codeview::TypeTableBuilder &CVTypes) override;
   void printStackMap() const override;
 private:
   void printSymbol(const SymbolRef &Sym);
@@ -1064,7 +1065,8 @@ void COFFDumper::printFileNameForOffset(StringRef Label, uint32_t FileOffset) {
   W.printHex(Label, getFileNameForFileOffset(FileOffset), FileOffset);
 }
 
-void COFFDumper::mergeCodeViewTypes(TypeTableBuilder &CVTypes) {
+void COFFDumper::mergeCodeViewTypes(TypeTableBuilder &CVIDs,
+                                    TypeTableBuilder &CVTypes) {
   for (const SectionRef &S : Obj->sections()) {
     StringRef SectionName;
     error(S.getName(SectionName));
@@ -1086,7 +1088,7 @@ void COFFDumper::mergeCodeViewTypes(TypeTableBuilder &CVTypes) {
         error(object_error::parse_failed);
       }
 
-      if (auto EC = mergeTypeStreams(CVTypes, nullptr, Types)) {
+      if (auto EC = mergeTypeStreams(CVIDs, CVTypes, nullptr, Types)) {
         consumeError(std::move(EC));
         return error(object_error::parse_failed);
       }
@@ -1551,20 +1553,43 @@ void COFFDumper::printStackMap() const {
 }
 
 void llvm::dumpCodeViewMergedTypes(ScopedPrinter &Writer,
+                                   llvm::codeview::TypeTableBuilder &IDTable,
                                    llvm::codeview::TypeTableBuilder &CVTypes) {
   // Flatten it first, then run our dumper on it.
-  ListScope S(Writer, "MergedTypeStream");
-  SmallString<0> Buf;
+  SmallString<0> TypeBuf;
   CVTypes.ForEachRecord([&](TypeIndex TI, ArrayRef<uint8_t> Record) {
-    Buf.append(Record.begin(), Record.end());
+    TypeBuf.append(Record.begin(), Record.end());
   });
 
   TypeDatabase TypeDB;
-  CVTypeDumper CVTD(TypeDB);
-  TypeDumpVisitor TDV(TypeDB, &Writer, opts::CodeViewSubsectionBytes);
-  if (auto EC =
-          CVTD.dump({Buf.str().bytes_begin(), Buf.str().bytes_end()}, TDV)) {
-    Writer.flush();
-    error(llvm::errorToErrorCode(std::move(EC)));
+  {
+    ListScope S(Writer, "MergedTypeStream");
+    CVTypeDumper CVTD(TypeDB);
+    TypeDumpVisitor TDV(TypeDB, &Writer, opts::CodeViewSubsectionBytes);
+    if (auto EC = CVTD.dump(
+            {TypeBuf.str().bytes_begin(), TypeBuf.str().bytes_end()}, TDV)) {
+      Writer.flush();
+      error(llvm::errorToErrorCode(std::move(EC)));
+    }
+  }
+
+  // Flatten the id stream and print it next. The ID stream refers to names from
+  // the type stream.
+  SmallString<0> IDBuf;
+  IDTable.ForEachRecord([&](TypeIndex TI, ArrayRef<uint8_t> Record) {
+    IDBuf.append(Record.begin(), Record.end());
+  });
+
+  {
+    ListScope S(Writer, "MergedIDStream");
+    TypeDatabase IDDB;
+    CVTypeDumper CVTD(IDDB);
+    TypeDumpVisitor TDV(TypeDB, &Writer, opts::CodeViewSubsectionBytes);
+    TDV.setItemDB(IDDB);
+    if (auto EC = CVTD.dump(
+            {IDBuf.str().bytes_begin(), IDBuf.str().bytes_end()}, TDV)) {
+      Writer.flush();
+      error(llvm::errorToErrorCode(std::move(EC)));
+    }
   }
 }
index 109087b..ff780da 100644 (file)
@@ -68,7 +68,8 @@ public:
   virtual void printCOFFBaseReloc() { }
   virtual void printCOFFDebugDirectory() { }
   virtual void printCodeViewDebugInfo() { }
-  virtual void mergeCodeViewTypes(llvm::codeview::TypeTableBuilder &CVTypes) {}
+  virtual void mergeCodeViewTypes(llvm::codeview::TypeTableBuilder &CVIDs,
+                                  llvm::codeview::TypeTableBuilder &CVTypes) {}
 
   // Only implemented for MachO.
   virtual void printMachODataInCode() { }
@@ -103,7 +104,8 @@ std::error_code createWasmDumper(const object::ObjectFile *Obj,
 void dumpCOFFImportFile(const object::COFFImportFile *File);
 
 void dumpCodeViewMergedTypes(ScopedPrinter &Writer,
-                             llvm::codeview::TypeTableBuilder &CVTypes);
+                             llvm::codeview::TypeTableBuilder &IDTable,
+                             llvm::codeview::TypeTableBuilder &TypeTable);
 
 } // namespace llvm
 
index d917828..bc2a62e 100644 (file)
@@ -338,10 +338,12 @@ static bool isMipsArch(unsigned Arch) {
 }
 namespace {
 struct ReadObjTypeTableBuilder {
-  ReadObjTypeTableBuilder() : Allocator(), Builder(Allocator) {}
+  ReadObjTypeTableBuilder()
+      : Allocator(), IDTable(Allocator), TypeTable(Allocator) {}
 
   llvm::BumpPtrAllocator Allocator;
-  llvm::codeview::TypeTableBuilder Builder;
+  llvm::codeview::TypeTableBuilder IDTable;
+  llvm::codeview::TypeTableBuilder TypeTable;
 };
 }
 static ReadObjTypeTableBuilder CVTypes;
@@ -446,7 +448,7 @@ static void dumpObject(const ObjectFile *Obj) {
     if (opts::CodeView)
       Dumper->printCodeViewDebugInfo();
     if (opts::CodeViewMergedTypes)
-      Dumper->mergeCodeViewTypes(CVTypes.Builder);
+      Dumper->mergeCodeViewTypes(CVTypes.IDTable, CVTypes.TypeTable);
   }
   if (Obj->isMachO()) {
     if (opts::MachODataInCode)
@@ -551,7 +553,7 @@ int main(int argc, const char *argv[]) {
 
   if (opts::CodeViewMergedTypes) {
     ScopedPrinter W(outs());
-    dumpCodeViewMergedTypes(W, CVTypes.Builder);
+    dumpCodeViewMergedTypes(W, CVTypes.IDTable, CVTypes.TypeTable);
   }
 
   return 0;