diff options
| -rw-r--r-- | llvm/include/llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h | 2 | ||||
| -rw-r--r-- | llvm/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp | 2 | ||||
| -rw-r--r-- | llvm/test/DebugInfo/PDB/Inputs/merge1.yaml | 52 | ||||
| -rw-r--r-- | llvm/test/DebugInfo/PDB/Inputs/merge2.yaml | 52 | ||||
| -rw-r--r-- | llvm/test/DebugInfo/PDB/pdbdump-mergetypes.test | 24 | ||||
| -rw-r--r-- | llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp | 68 |
6 files changed, 198 insertions, 2 deletions
diff --git a/llvm/include/llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h b/llvm/include/llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h index 6c609c34665..21cfa83e6af 100644 --- a/llvm/include/llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h +++ b/llvm/include/llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h @@ -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; diff --git a/llvm/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp b/llvm/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp index 701a318511b..20456cc9782 100644 --- a/llvm/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp +++ b/llvm/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp @@ -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; diff --git a/llvm/test/DebugInfo/PDB/Inputs/merge1.yaml b/llvm/test/DebugInfo/PDB/Inputs/merge1.yaml new file mode 100644 index 00000000000..89d471e3343 --- /dev/null +++ b/llvm/test/DebugInfo/PDB/Inputs/merge1.yaml @@ -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
+...
diff --git a/llvm/test/DebugInfo/PDB/Inputs/merge2.yaml b/llvm/test/DebugInfo/PDB/Inputs/merge2.yaml new file mode 100644 index 00000000000..b6cbdb98f0c --- /dev/null +++ b/llvm/test/DebugInfo/PDB/Inputs/merge2.yaml @@ -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
+...
diff --git a/llvm/test/DebugInfo/PDB/pdbdump-mergetypes.test b/llvm/test/DebugInfo/PDB/pdbdump-mergetypes.test new file mode 100644 index 00000000000..96f6316d476 --- /dev/null +++ b/llvm/test/DebugInfo/PDB/pdbdump-mergetypes.test @@ -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**
diff --git a/llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp b/llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp index dc3e15a89af..d3c6a799ac4 100644 --- a/llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp +++ b/llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp @@ -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(); |

