#include "llvm/DebugInfo/PDB/IPDBSession.h"
#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h"
#include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h"
+#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
#include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h"
#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
cl::SubCommand ExplainSubcommand("explain",
"Explain the meaning of a file offset");
+cl::SubCommand ExportSubcommand("export",
+ "Write binary data from a stream to a file");
+
cl::OptionCategory TypeCategory("Symbol Type Options");
cl::OptionCategory FilterCategory("Filtering and Sorting Options");
cl::OptionCategory OtherOptions("Other Options");
cl::list<uint64_t> Offsets("offset", cl::desc("The file offset to explain"),
cl::sub(ExplainSubcommand), cl::OneOrMore);
} // namespace explain
+
+namespace exportstream {
+cl::list<std::string> InputFilename(cl::Positional,
+ cl::desc("<input PDB file>"), cl::Required,
+ cl::sub(ExportSubcommand));
+cl::opt<std::string> OutputFile("out",
+ cl::desc("The file to write the stream to"),
+ cl::Required, cl::sub(ExportSubcommand));
+cl::opt<std::string>
+ Stream("stream", cl::Required,
+ cl::desc("The index or name of the stream whose contents to export"),
+ cl::sub(ExportSubcommand));
+cl::opt<bool> ForceName("name",
+ cl::desc("Force the interpretation of -stream as a "
+ "string, even if it is a valid integer"),
+ cl::sub(ExportSubcommand), cl::Optional,
+ cl::init(false));
+} // namespace exportstream
}
static ExitOnError ExitOnErr;
}
}
+static void exportStream() {
+ std::unique_ptr<IPDBSession> Session;
+ PDBFile &File = loadPDB(opts::exportstream::InputFilename.front(), Session);
+
+ std::unique_ptr<MappedBlockStream> SourceStream;
+ uint32_t Index = 0;
+ bool Success = false;
+ std::string OutFileName = opts::exportstream::OutputFile;
+
+ if (!opts::exportstream::ForceName) {
+ // First try to parse it as an integer, if it fails fall back to treating it
+ // as a named stream.
+ if (to_integer(opts::exportstream::Stream, Index)) {
+ if (Index >= File.getNumStreams()) {
+ errs() << "Error: " << Index << " is not a valid stream index.\n";
+ exit(1);
+ }
+ Success = true;
+ outs() << "Dumping contents of stream index " << Index << " to file "
+ << OutFileName << ".\n";
+ }
+ }
+
+ if (!Success) {
+ InfoStream &IS = cantFail(File.getPDBInfoStream());
+ Index = ExitOnErr(IS.getNamedStreamIndex(opts::exportstream::Stream));
+ outs() << "Dumping contents of stream '" << opts::exportstream::Stream
+ << "' (index " << Index << ") to file " << OutFileName << ".\n";
+ }
+
+ SourceStream = MappedBlockStream::createIndexedStream(
+ File.getMsfLayout(), File.getMsfBuffer(), Index, File.getAllocator());
+ auto OutFile = ExitOnErr(
+ FileOutputBuffer::create(OutFileName, SourceStream->getLength()));
+ FileBufferByteStream DestStream(std::move(OutFile), llvm::support::little);
+ BinaryStreamWriter Writer(DestStream);
+ ExitOnErr(Writer.writeStreamRef(*SourceStream));
+ ExitOnErr(DestStream.commit());
+}
+
static bool parseRange(StringRef Str,
Optional<opts::bytes::NumberRange> &Parsed) {
if (Str.empty())
mergePdbs();
} else if (opts::ExplainSubcommand) {
explain();
+ } else if (opts::ExportSubcommand) {
+ exportStream();
}
outs().flush();