Summary: MSVC does this when producing a PDB.
Reviewers: ruiu
Subscribers: llvm-commits
Differential Revision: https://reviews.llvm.org/D31316
llvm-svn: 298717
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
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) {
}
}
-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,
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 =
# 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
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
/// - 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) \
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();
}
BumpPtrAllocator Allocator;
- TypeTableBuilder &DestStream;
+ TypeTableBuilder &DestIdStream;
+ TypeTableBuilder &DestTypeStream;
FieldListRecordBuilder FieldListBuilder;
TypeServerHandler *Handler;
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));
}
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)
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);
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);
return Error::success();
}
+//----------------------------------------------------------------------------//
+// Member records
+//----------------------------------------------------------------------------//
+
Error TypeStreamMerger::visitKnownMember(CVMemberRecord &,
NestedTypeRecord &R) {
return writeMember(R, remapIndex(R.Type));
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);
}
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
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: ]
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);
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));
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);
}
}
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)));
+ }
}
}
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() { }
void dumpCOFFImportFile(const object::COFFImportFile *File);
void dumpCodeViewMergedTypes(ScopedPrinter &Writer,
- llvm::codeview::TypeTableBuilder &CVTypes);
+ llvm::codeview::TypeTableBuilder &IDTable,
+ llvm::codeview::TypeTableBuilder &TypeTable);
} // namespace llvm
}
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;
if (opts::CodeView)
Dumper->printCodeViewDebugInfo();
if (opts::CodeViewMergedTypes)
- Dumper->mergeCodeViewTypes(CVTypes.Builder);
+ Dumper->mergeCodeViewTypes(CVTypes.IDTable, CVTypes.TypeTable);
}
if (Obj->isMachO()) {
if (opts::MachODataInCode)
if (opts::CodeViewMergedTypes) {
ScopedPrinter W(outs());
- dumpCodeViewMergedTypes(W, CVTypes.Builder);
+ dumpCodeViewMergedTypes(W, CVTypes.IDTable, CVTypes.TypeTable);
}
return 0;