mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 19:23:23 +01:00
[llvm-pdbdump] Add the ability to merge PDBs.
Merging PDBs is a feature that will be used heavily by the linker. The functionality already exists but does not have deep test coverage because it's not easily exposed through any tools. This patch aims to address that by adding the ability to merge PDBs via llvm-pdbdump. It takes arbitrarily many PDBs and outputs a single PDB. Using this new functionality, a test is added for merging type records. Future patches will add the ability to merge symbol records, module information, etc. llvm-svn: 303389
This commit is contained in:
parent
05edea832d
commit
1c726a40b8
@ -72,7 +72,7 @@ private:
|
||||
|
||||
size_t TypeRecordBytes = 0;
|
||||
|
||||
Optional<PdbRaw_TpiVer> VerHeader;
|
||||
PdbRaw_TpiVer VerHeader = PdbRaw_TpiVer::PdbTpiV80;
|
||||
std::vector<ArrayRef<uint8_t>> TypeRecords;
|
||||
std::vector<uint32_t> TypeHashes;
|
||||
std::vector<codeview::TypeIndexOffset> TypeIndexOffsets;
|
||||
|
@ -69,7 +69,7 @@ Error TpiStreamBuilder::finalize() {
|
||||
|
||||
uint32_t Count = TypeRecords.size();
|
||||
|
||||
H->Version = *VerHeader;
|
||||
H->Version = VerHeader;
|
||||
H->HeaderSize = sizeof(TpiStreamHeader);
|
||||
H->TypeIndexBegin = codeview::TypeIndex::FirstNonSimpleIndex;
|
||||
H->TypeIndexEnd = H->TypeIndexBegin + Count;
|
||||
|
52
test/DebugInfo/PDB/Inputs/merge1.yaml
Normal file
52
test/DebugInfo/PDB/Inputs/merge1.yaml
Normal file
@ -0,0 +1,52 @@
|
||||
---
|
||||
TpiStream:
|
||||
Records:
|
||||
# uint32_t* [Index: 0x1000]
|
||||
- Kind: LF_POINTER
|
||||
Pointer:
|
||||
ReferentType: 117
|
||||
Attrs: 32778
|
||||
# int64_t* [Index: 0x1001]
|
||||
- Kind: LF_POINTER
|
||||
Pointer:
|
||||
ReferentType: 118
|
||||
Attrs: 32778
|
||||
# struct OnlyInMerge1 [Index: 0x1002]
|
||||
- Kind: LF_STRUCTURE
|
||||
Class:
|
||||
MemberCount: 0
|
||||
Options: [ None, ForwardReference, HasUniqueName ]
|
||||
FieldList: 0
|
||||
Name: 'OnlyInMerge1'
|
||||
UniqueName: 'OnlyInMerge1'
|
||||
DerivationList: 0
|
||||
VTableShape: 0
|
||||
Size: 0
|
||||
# uint32_t** [Index: 0x1003]
|
||||
- Kind: LF_POINTER
|
||||
Pointer:
|
||||
ReferentType: 4096
|
||||
Attrs: 32778
|
||||
# uint32_t*** [Index: 0x1004]
|
||||
- Kind: LF_POINTER
|
||||
Pointer:
|
||||
ReferentType: 4099
|
||||
Attrs: 32778
|
||||
# int64_t* [Index: 0x1005]
|
||||
- Kind: LF_POINTER
|
||||
Pointer:
|
||||
ReferentType: 4097
|
||||
Attrs: 32778
|
||||
# [uint32_t, uint32_t*, uint32_t**] [Index: 0x1006]
|
||||
- Kind: LF_ARGLIST
|
||||
ArgList:
|
||||
ArgIndices: [ 117, 4096, 4099 ]
|
||||
# uint32_t (uint32_t, uint32_t*, uint32_t**) [Index: 0x1007]
|
||||
- Kind: LF_PROCEDURE
|
||||
Procedure:
|
||||
ReturnType: 117
|
||||
CallConv: NearC
|
||||
Options: [ None ]
|
||||
ParameterCount: 0
|
||||
ArgumentList: 4102
|
||||
...
|
52
test/DebugInfo/PDB/Inputs/merge2.yaml
Normal file
52
test/DebugInfo/PDB/Inputs/merge2.yaml
Normal file
@ -0,0 +1,52 @@
|
||||
---
|
||||
TpiStream:
|
||||
Records:
|
||||
# uint32_t* [Index: 0x1000]
|
||||
- Kind: LF_POINTER
|
||||
Pointer:
|
||||
ReferentType: 117
|
||||
Attrs: 32778
|
||||
# uint32_t** [Index: 0x1001]
|
||||
- Kind: LF_POINTER
|
||||
Pointer:
|
||||
ReferentType: 4096
|
||||
Attrs: 32778
|
||||
# uint32_t*** [Index: 0x1002]
|
||||
- Kind: LF_POINTER
|
||||
Pointer:
|
||||
ReferentType: 4097
|
||||
Attrs: 32778
|
||||
# [uint32_t, uint32_t*, uint32_t**] [Index: 0x1003]
|
||||
- Kind: LF_ARGLIST
|
||||
ArgList:
|
||||
ArgIndices: [ 117, 4096, 4097 ]
|
||||
# uint32_t (uint32_t, uint32_t*, uint32_t**) [Index: 0x1004]
|
||||
- Kind: LF_PROCEDURE
|
||||
Procedure:
|
||||
ReturnType: 117
|
||||
CallConv: NearC
|
||||
Options: [ None ]
|
||||
ParameterCount: 0
|
||||
ArgumentList: 4099
|
||||
# int64_t* [Index: 0x1005]
|
||||
- Kind: LF_POINTER
|
||||
Pointer:
|
||||
ReferentType: 118
|
||||
Attrs: 32778
|
||||
# int64_t** [Index: 0x1006]
|
||||
- Kind: LF_POINTER
|
||||
Pointer:
|
||||
ReferentType: 4101
|
||||
Attrs: 32778
|
||||
# struct OnlyInMerge2 [Index: 0x1007]
|
||||
- Kind: LF_STRUCTURE
|
||||
Class:
|
||||
MemberCount: 0
|
||||
Options: [ None, ForwardReference, HasUniqueName ]
|
||||
FieldList: 0
|
||||
Name: 'OnlyInMerge2'
|
||||
UniqueName: 'OnlyInMerge2'
|
||||
DerivationList: 0
|
||||
VTableShape: 0
|
||||
Size: 0
|
||||
...
|
24
test/DebugInfo/PDB/pdbdump-mergetypes.test
Normal file
24
test/DebugInfo/PDB/pdbdump-mergetypes.test
Normal file
@ -0,0 +1,24 @@
|
||||
; RUN: llvm-pdbdump yaml2pdb -pdb=%t.1.pdb %p/Inputs/merge1.yaml
|
||||
; RUN: llvm-pdbdump yaml2pdb -pdb=%t.2.pdb %p/Inputs/merge2.yaml
|
||||
; RUN: llvm-pdbdump merge -pdb=%t.3.pdb %t.1.pdb %t.2.pdb
|
||||
; RUN: llvm-pdbdump raw -tpi-records %t.3.pdb | FileCheck -check-prefix=MERGED %s
|
||||
; RUN: llvm-pdbdump raw -tpi-records %t.3.pdb | FileCheck -check-prefix=ARGLIST %s
|
||||
|
||||
|
||||
MERGED: Type Info Stream (TPI)
|
||||
MERGED: Record count: 9
|
||||
MERGED-DAG: PointeeType: unsigned
|
||||
MERGED-DAG: PointeeType: unsigned*
|
||||
MERGED-DAG: PointeeType: unsigned**
|
||||
MERGED-DAG: PointeeType: __int64
|
||||
MERGED-DAG: PointeeType: __int64*
|
||||
MERGED-DAG: Name: OnlyInMerge1
|
||||
MERGED-DAG: Name: OnlyInMerge2
|
||||
MERGED-DAG: TypeLeafKind: LF_ARGLIST
|
||||
|
||||
ARGLIST: TypeLeafKind: LF_ARGLIST
|
||||
ARGLIST-NEXT: NumArgs: 3
|
||||
ARGLIST-NEXT: Arguments [
|
||||
ARGLIST-NEXT: ArgType: unsigned
|
||||
ARGLIST-NEXT: ArgType: unsigned*
|
||||
ARGLIST-NEXT: ArgType: unsigned**
|
@ -31,9 +31,11 @@
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/Config/config.h"
|
||||
#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
|
||||
#include "llvm/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.h"
|
||||
#include "llvm/DebugInfo/CodeView/ModuleDebugInlineeLinesFragment.h"
|
||||
#include "llvm/DebugInfo/CodeView/ModuleDebugLineFragment.h"
|
||||
#include "llvm/DebugInfo/CodeView/TypeStreamMerger.h"
|
||||
#include "llvm/DebugInfo/MSF/MSFBuilder.h"
|
||||
#include "llvm/DebugInfo/PDB/GenericError.h"
|
||||
#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"
|
||||
@ -100,6 +102,9 @@ cl::SubCommand
|
||||
AnalyzeSubcommand("analyze",
|
||||
"Analyze various aspects of a PDB's structure");
|
||||
|
||||
cl::SubCommand MergeSubcommand("merge",
|
||||
"Merge multiple PDBs into a single PDB");
|
||||
|
||||
cl::OptionCategory TypeCategory("Symbol Type Options");
|
||||
cl::OptionCategory FilterCategory("Filtering and Sorting Options");
|
||||
cl::OptionCategory OtherOptions("Other Options");
|
||||
@ -441,6 +446,15 @@ cl::list<std::string> InputFilename(cl::Positional,
|
||||
cl::desc("<input PDB file>"), cl::Required,
|
||||
cl::sub(AnalyzeSubcommand));
|
||||
}
|
||||
|
||||
namespace merge {
|
||||
cl::list<std::string> InputFilenames(cl::Positional,
|
||||
cl::desc("<input PDB files>"),
|
||||
cl::OneOrMore, cl::sub(MergeSubcommand));
|
||||
cl::opt<std::string>
|
||||
PdbOutputFile("pdb", cl::desc("the name of the PDB file to write"),
|
||||
cl::sub(MergeSubcommand));
|
||||
}
|
||||
}
|
||||
|
||||
static ExitOnError ExitOnErr;
|
||||
@ -828,6 +842,54 @@ static void dumpPretty(StringRef Path) {
|
||||
outs().flush();
|
||||
}
|
||||
|
||||
static void mergePdbs() {
|
||||
BumpPtrAllocator Allocator;
|
||||
TypeTableBuilder MergedTpi(Allocator);
|
||||
TypeTableBuilder MergedIpi(Allocator);
|
||||
|
||||
// Create a Tpi and Ipi type table with all types from all input files.
|
||||
for (const auto &Path : opts::merge::InputFilenames) {
|
||||
std::unique_ptr<IPDBSession> Session;
|
||||
auto &File = loadPDB(Path, Session);
|
||||
if (File.hasPDBTpiStream()) {
|
||||
auto &Tpi = ExitOnErr(File.getPDBTpiStream());
|
||||
ExitOnErr(codeview::mergeTypeStreams(MergedIpi, MergedTpi, nullptr,
|
||||
Tpi.typeArray()));
|
||||
}
|
||||
if (File.hasPDBIpiStream()) {
|
||||
auto &Ipi = ExitOnErr(File.getPDBIpiStream());
|
||||
ExitOnErr(codeview::mergeTypeStreams(MergedIpi, MergedTpi, nullptr,
|
||||
Ipi.typeArray()));
|
||||
}
|
||||
}
|
||||
|
||||
// Then write the PDB.
|
||||
PDBFileBuilder Builder(Allocator);
|
||||
ExitOnErr(Builder.initialize(4096));
|
||||
// Add each of the reserved streams. We might not put any data in them,
|
||||
// but at least they have to be present.
|
||||
for (uint32_t I = 0; I < kSpecialStreamCount; ++I)
|
||||
ExitOnErr(Builder.getMsfBuilder().addStream(0));
|
||||
|
||||
auto &DestTpi = Builder.getTpiBuilder();
|
||||
auto &DestIpi = Builder.getIpiBuilder();
|
||||
MergedTpi.ForEachRecord(
|
||||
[&DestTpi](TypeIndex TI, MutableArrayRef<uint8_t> Data) {
|
||||
DestTpi.addTypeRecord(Data, None);
|
||||
});
|
||||
MergedIpi.ForEachRecord(
|
||||
[&DestIpi](TypeIndex TI, MutableArrayRef<uint8_t> Data) {
|
||||
DestIpi.addTypeRecord(Data, None);
|
||||
});
|
||||
|
||||
SmallString<64> OutFile = opts::merge::PdbOutputFile;
|
||||
if (OutFile.empty()) {
|
||||
OutFile = opts::merge::InputFilenames[0];
|
||||
llvm::sys::path::replace_extension(OutFile, "merged.pdb");
|
||||
}
|
||||
ExitOnErr(Builder.commit(OutFile));
|
||||
}
|
||||
|
||||
int main(int argc_, const char *argv_[]) {
|
||||
// Print a stack trace if we signal out.
|
||||
sys::PrintStackTraceOnErrorSignal(argv_[0]);
|
||||
@ -949,6 +1011,12 @@ int main(int argc_, const char *argv_[]) {
|
||||
exit(1);
|
||||
}
|
||||
diff(opts::diff::InputFilenames[0], opts::diff::InputFilenames[1]);
|
||||
} else if (opts::MergeSubcommand) {
|
||||
if (opts::merge::InputFilenames.size() < 2) {
|
||||
errs() << "merge subcommand requires at least 2 input files.\n";
|
||||
exit(1);
|
||||
}
|
||||
mergePdbs();
|
||||
}
|
||||
|
||||
outs().flush();
|
||||
|
Loading…
Reference in New Issue
Block a user