1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-19 02:52:53 +02:00

[PDB] Split item and type records when merging type streams

Summary: MSVC does this when producing a PDB.

Reviewers: ruiu

Subscribers: llvm-commits

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

llvm-svn: 298717
This commit is contained in:
Reid Kleckner 2017-03-24 17:26:38 +00:00
parent 9b09f080bf
commit 5da414c396
6 changed files with 189 additions and 77 deletions

View 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

View 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);
}

View 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: ]

View 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)));
}
}
}

View 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

View 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;