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:
parent
9b09f080bf
commit
5da414c396
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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: ]
|
||||
|
@ -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)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user