summaryrefslogtreecommitdiff
path: root/tools/llvm-pdbdump/llvm-pdbdump.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/llvm-pdbdump/llvm-pdbdump.cpp')
-rw-r--r--tools/llvm-pdbdump/llvm-pdbdump.cpp709
1 files changed, 374 insertions, 335 deletions
diff --git a/tools/llvm-pdbdump/llvm-pdbdump.cpp b/tools/llvm-pdbdump/llvm-pdbdump.cpp
index 0e3f0b281fe02..62f215ddc8aef 100644
--- a/tools/llvm-pdbdump/llvm-pdbdump.cpp
+++ b/tools/llvm-pdbdump/llvm-pdbdump.cpp
@@ -17,15 +17,20 @@
#include "CompilandDumper.h"
#include "ExternalSymbolDumper.h"
#include "FunctionDumper.h"
+#include "LLVMOutputStyle.h"
#include "LinePrinter.h"
+#include "OutputStyle.h"
#include "TypeDumper.h"
#include "VariableDumper.h"
+#include "YAMLOutputStyle.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Config/config.h"
+#include "llvm/DebugInfo/CodeView/ByteStream.h"
+#include "llvm/DebugInfo/PDB/GenericError.h"
#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"
#include "llvm/DebugInfo/PDB/IPDBRawSymbol.h"
#include "llvm/DebugInfo/PDB/IPDBSession.h"
@@ -35,388 +40,380 @@
#include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
#include "llvm/DebugInfo/PDB/PDBSymbolThunk.h"
+#include "llvm/DebugInfo/PDB/Raw/DbiStream.h"
+#include "llvm/DebugInfo/PDB/Raw/DbiStreamBuilder.h"
+#include "llvm/DebugInfo/PDB/Raw/InfoStream.h"
+#include "llvm/DebugInfo/PDB/Raw/InfoStreamBuilder.h"
+#include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Raw/PDBFileBuilder.h"
+#include "llvm/DebugInfo/PDB/Raw/RawConstants.h"
+#include "llvm/DebugInfo/PDB/Raw/RawError.h"
+#include "llvm/DebugInfo/PDB/Raw/RawSession.h"
+#include "llvm/Support/COM.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ConvertUTF.h"
+#include "llvm/Support/FileOutputBuffer.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Process.h"
-#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/ScopedPrinter.h"
#include "llvm/Support/Signals.h"
-
-#if defined(HAVE_DIA_SDK)
-#ifndef NOMINMAX
-#define NOMINMAX
-#endif
-#include <Windows.h>
-#endif
+#include "llvm/Support/raw_ostream.h"
using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+namespace {
+// A simple adapter that acts like a ByteStream but holds ownership over
+// and underlying FileOutputBuffer.
+class FileBufferByteStream : public ByteStream<true> {
+public:
+ FileBufferByteStream(std::unique_ptr<FileOutputBuffer> Buffer)
+ : ByteStream(MutableArrayRef<uint8_t>(Buffer->getBufferStart(),
+ Buffer->getBufferEnd())),
+ FileBuffer(std::move(Buffer)) {}
+
+ Error commit() const override {
+ if (FileBuffer->commit())
+ return llvm::make_error<RawError>(raw_error_code::not_writable);
+ return Error::success();
+ }
-namespace opts {
+private:
+ std::unique_ptr<FileOutputBuffer> FileBuffer;
+};
+}
-enum class PDB_DumpType { ByType, ByObjFile, Both };
+namespace opts {
-cl::list<std::string> InputFilenames(cl::Positional,
- cl::desc("<input PDB files>"),
- cl::OneOrMore);
+cl::SubCommand RawSubcommand("raw", "Dump raw structure of the PDB file");
+cl::SubCommand
+ PrettySubcommand("pretty",
+ "Dump semantic information about types and symbols");
+cl::SubCommand
+ YamlToPdbSubcommand("yaml2pdb",
+ "Generate a PDB file from a YAML description");
+cl::SubCommand
+ PdbToYamlSubcommand("pdb2yaml",
+ "Generate a detailed YAML description of a PDB File");
cl::OptionCategory TypeCategory("Symbol Type Options");
cl::OptionCategory FilterCategory("Filtering Options");
cl::OptionCategory OtherOptions("Other Options");
+namespace pretty {
+cl::list<std::string> InputFilenames(cl::Positional,
+ cl::desc("<input PDB files>"),
+ cl::OneOrMore, cl::sub(PrettySubcommand));
+
cl::opt<bool> Compilands("compilands", cl::desc("Display compilands"),
- cl::cat(TypeCategory));
+ cl::cat(TypeCategory), cl::sub(PrettySubcommand));
cl::opt<bool> Symbols("symbols", cl::desc("Display symbols for each compiland"),
- cl::cat(TypeCategory));
+ cl::cat(TypeCategory), cl::sub(PrettySubcommand));
cl::opt<bool> Globals("globals", cl::desc("Dump global symbols"),
- cl::cat(TypeCategory));
+ cl::cat(TypeCategory), cl::sub(PrettySubcommand));
cl::opt<bool> Externals("externals", cl::desc("Dump external symbols"),
- cl::cat(TypeCategory));
-cl::opt<bool> Types("types", cl::desc("Display types"), cl::cat(TypeCategory));
+ cl::cat(TypeCategory), cl::sub(PrettySubcommand));
+cl::opt<bool> Types("types", cl::desc("Display types"), cl::cat(TypeCategory),
+ cl::sub(PrettySubcommand));
+cl::opt<bool> Lines("lines", cl::desc("Line tables"), cl::cat(TypeCategory),
+ cl::sub(PrettySubcommand));
cl::opt<bool>
All("all", cl::desc("Implies all other options in 'Symbol Types' category"),
- cl::cat(TypeCategory));
+ cl::cat(TypeCategory), cl::sub(PrettySubcommand));
cl::opt<uint64_t> LoadAddress(
"load-address",
cl::desc("Assume the module is loaded at the specified address"),
- cl::cat(OtherOptions));
-
-cl::opt<bool> DumpHeaders("dump-headers", cl::desc("dump PDB headers"),
- cl::cat(OtherOptions));
-cl::opt<bool> DumpStreamSizes("dump-stream-sizes",
- cl::desc("dump PDB stream sizes"),
- cl::cat(OtherOptions));
-cl::opt<bool> DumpStreamBlocks("dump-stream-blocks",
- cl::desc("dump PDB stream blocks"),
- cl::cat(OtherOptions));
-cl::opt<std::string> DumpStreamData("dump-stream", cl::desc("dump stream data"),
- cl::cat(OtherOptions));
-
-cl::list<std::string>
- ExcludeTypes("exclude-types",
- cl::desc("Exclude types by regular expression"),
- cl::ZeroOrMore, cl::cat(FilterCategory));
-cl::list<std::string>
- ExcludeSymbols("exclude-symbols",
- cl::desc("Exclude symbols by regular expression"),
- cl::ZeroOrMore, cl::cat(FilterCategory));
-cl::list<std::string>
- ExcludeCompilands("exclude-compilands",
- cl::desc("Exclude compilands by regular expression"),
- cl::ZeroOrMore, cl::cat(FilterCategory));
+ cl::cat(OtherOptions), cl::sub(PrettySubcommand));
+cl::list<std::string> ExcludeTypes(
+ "exclude-types", cl::desc("Exclude types by regular expression"),
+ cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand));
+cl::list<std::string> ExcludeSymbols(
+ "exclude-symbols", cl::desc("Exclude symbols by regular expression"),
+ cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand));
+cl::list<std::string> ExcludeCompilands(
+ "exclude-compilands", cl::desc("Exclude compilands by regular expression"),
+ cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand));
cl::list<std::string> IncludeTypes(
"include-types",
cl::desc("Include only types which match a regular expression"),
- cl::ZeroOrMore, cl::cat(FilterCategory));
+ cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand));
cl::list<std::string> IncludeSymbols(
"include-symbols",
cl::desc("Include only symbols which match a regular expression"),
- cl::ZeroOrMore, cl::cat(FilterCategory));
+ cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand));
cl::list<std::string> IncludeCompilands(
"include-compilands",
cl::desc("Include only compilands those which match a regular expression"),
- cl::ZeroOrMore, cl::cat(FilterCategory));
+ cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand));
cl::opt<bool> ExcludeCompilerGenerated(
"no-compiler-generated",
cl::desc("Don't show compiler generated types and symbols"),
- cl::cat(FilterCategory));
+ cl::cat(FilterCategory), cl::sub(PrettySubcommand));
cl::opt<bool>
ExcludeSystemLibraries("no-system-libs",
cl::desc("Don't show symbols from system libraries"),
- cl::cat(FilterCategory));
+ cl::cat(FilterCategory), cl::sub(PrettySubcommand));
cl::opt<bool> NoClassDefs("no-class-definitions",
cl::desc("Don't display full class definitions"),
- cl::cat(FilterCategory));
+ cl::cat(FilterCategory), cl::sub(PrettySubcommand));
cl::opt<bool> NoEnumDefs("no-enum-definitions",
cl::desc("Don't display full enum definitions"),
- cl::cat(FilterCategory));
+ cl::cat(FilterCategory), cl::sub(PrettySubcommand));
}
+namespace raw {
-static void reportError(StringRef Input, StringRef Message) {
- if (Input == "-")
- Input = "<stdin>";
- errs() << Input << ": " << Message << "\n";
- errs().flush();
- exit(1);
-}
+cl::OptionCategory MsfOptions("MSF Container Options");
+cl::OptionCategory TypeOptions("Type Record Options");
+cl::OptionCategory FileOptions("Module & File Options");
+cl::OptionCategory SymbolOptions("Symbol Options");
+cl::OptionCategory MiscOptions("Miscellaneous Options");
-static void reportError(StringRef Input, std::error_code EC) {
- reportError(Input, EC.message());
-}
+// MSF OPTIONS
+cl::opt<bool> DumpHeaders("headers", cl::desc("dump PDB headers"),
+ cl::cat(MsfOptions), cl::sub(RawSubcommand));
+cl::opt<bool> DumpStreamBlocks("stream-blocks",
+ cl::desc("dump PDB stream blocks"),
+ cl::cat(MsfOptions), cl::sub(RawSubcommand));
+cl::opt<bool> DumpStreamSummary("stream-summary",
+ cl::desc("dump summary of the PDB streams"),
+ cl::cat(MsfOptions), cl::sub(RawSubcommand));
-static std::error_code checkOffset(MemoryBufferRef M, uintptr_t Addr,
- const uint64_t Size) {
- if (Addr + Size < Addr || Addr + Size < Size ||
- Addr + Size > uintptr_t(M.getBufferEnd()) ||
- Addr < uintptr_t(M.getBufferStart())) {
- return std::make_error_code(std::errc::bad_address);
- }
- return std::error_code();
-}
+// TYPE OPTIONS
+cl::opt<bool>
+ DumpTpiRecords("tpi-records",
+ cl::desc("dump CodeView type records from TPI stream"),
+ cl::cat(TypeOptions), cl::sub(RawSubcommand));
+cl::opt<bool> DumpTpiRecordBytes(
+ "tpi-record-bytes",
+ cl::desc("dump CodeView type record raw bytes from TPI stream"),
+ cl::cat(TypeOptions), cl::sub(RawSubcommand));
+cl::opt<bool> DumpTpiHash("tpi-hash", cl::desc("dump CodeView TPI hash stream"),
+ cl::cat(TypeOptions), cl::sub(RawSubcommand));
+cl::opt<bool>
+ DumpIpiRecords("ipi-records",
+ cl::desc("dump CodeView type records from IPI stream"),
+ cl::cat(TypeOptions), cl::sub(RawSubcommand));
+cl::opt<bool> DumpIpiRecordBytes(
+ "ipi-record-bytes",
+ cl::desc("dump CodeView type record raw bytes from IPI stream"),
+ cl::cat(TypeOptions), cl::sub(RawSubcommand));
+
+// MODULE & FILE OPTIONS
+cl::opt<bool> DumpModules("modules", cl::desc("dump compiland information"),
+ cl::cat(FileOptions), cl::sub(RawSubcommand));
+cl::opt<bool> DumpModuleFiles("module-files", cl::desc("dump file information"),
+ cl::cat(FileOptions), cl::sub(RawSubcommand));
+cl::opt<bool> DumpLineInfo("line-info",
+ cl::desc("dump file and line information"),
+ cl::cat(FileOptions), cl::sub(RawSubcommand));
+
+// SYMBOL OPTIONS
+cl::opt<bool> DumpModuleSyms("module-syms", cl::desc("dump module symbols"),
+ cl::cat(SymbolOptions), cl::sub(RawSubcommand));
+cl::opt<bool> DumpPublics("publics", cl::desc("dump Publics stream data"),
+ cl::cat(SymbolOptions), cl::sub(RawSubcommand));
+cl::opt<bool>
+ DumpSymRecordBytes("sym-record-bytes",
+ cl::desc("dump CodeView symbol record raw bytes"),
+ cl::cat(SymbolOptions), cl::sub(RawSubcommand));
+
+// MISCELLANEOUS OPTIONS
+cl::opt<bool> DumpSectionContribs("section-contribs",
+ cl::desc("dump section contributions"),
+ cl::cat(MiscOptions), cl::sub(RawSubcommand));
+cl::opt<bool> DumpSectionMap("section-map", cl::desc("dump section map"),
+ cl::cat(MiscOptions), cl::sub(RawSubcommand));
+cl::opt<bool> DumpSectionHeaders("section-headers",
+ cl::desc("dump section headers"),
+ cl::cat(MiscOptions), cl::sub(RawSubcommand));
+cl::opt<bool> DumpFpo("fpo", cl::desc("dump FPO records"), cl::cat(MiscOptions),
+ cl::sub(RawSubcommand));
+
+cl::opt<std::string> DumpStreamDataIdx("stream", cl::desc("dump stream data"),
+ cl::cat(MiscOptions),
+ cl::sub(RawSubcommand));
+cl::opt<std::string> DumpStreamDataName("stream-name",
+ cl::desc("dump stream data"),
+ cl::cat(MiscOptions),
+ cl::sub(RawSubcommand));
+
+cl::opt<bool> RawAll("all", cl::desc("Implies most other options."),
+ cl::cat(MiscOptions), cl::sub(RawSubcommand));
-template <typename T>
-static std::error_code checkOffset(MemoryBufferRef M, ArrayRef<T> AR) {
- return checkOffset(M, uintptr_t(AR.data()), (uint64_t)AR.size() * sizeof(T));
+cl::list<std::string> InputFilenames(cl::Positional,
+ cl::desc("<input PDB files>"),
+ cl::OneOrMore, cl::sub(RawSubcommand));
}
-static std::error_code checkOffset(MemoryBufferRef M, StringRef SR) {
- return checkOffset(M, uintptr_t(SR.data()), SR.size());
-}
+namespace yaml2pdb {
+cl::opt<std::string>
+ YamlPdbOutputFile("pdb", cl::desc("the name of the PDB file to write"),
+ cl::sub(YamlToPdbSubcommand));
-// Sets Obj unless any bytes in [addr, addr + size) fall outsize of m.
-// Returns unexpected_eof if error.
-template <typename T>
-static std::error_code getObject(const T *&Obj, MemoryBufferRef M,
- const void *Ptr,
- const uint64_t Size = sizeof(T)) {
- uintptr_t Addr = uintptr_t(Ptr);
- if (std::error_code EC = checkOffset(M, Addr, Size))
- return EC;
- Obj = reinterpret_cast<const T *>(Addr);
- return std::error_code();
+cl::list<std::string> InputFilename(cl::Positional,
+ cl::desc("<input YAML file>"), cl::Required,
+ cl::sub(YamlToPdbSubcommand));
}
-static uint64_t bytesToBlocks(uint64_t NumBytes, uint64_t BlockSize) {
- return RoundUpToAlignment(NumBytes, BlockSize) / BlockSize;
+namespace pdb2yaml {
+cl::opt<bool>
+ NoFileHeaders("no-file-headers",
+ cl::desc("Do not dump MSF file headers (you will not be able "
+ "to generate a fresh PDB from the resulting YAML)"),
+ cl::sub(PdbToYamlSubcommand), cl::init(false));
+
+cl::opt<bool> StreamMetadata(
+ "stream-metadata",
+ cl::desc("Dump the number of streams and each stream's size"),
+ cl::sub(PdbToYamlSubcommand), cl::init(false));
+cl::opt<bool> StreamDirectory(
+ "stream-directory",
+ cl::desc("Dump each stream's block map (implies -stream-metadata)"),
+ cl::sub(PdbToYamlSubcommand), cl::init(false));
+cl::opt<bool> PdbStream("pdb-stream",
+ cl::desc("Dump the PDB Stream (Stream 1)"),
+ cl::sub(PdbToYamlSubcommand), cl::init(false));
+cl::opt<bool> DbiStream("dbi-stream",
+ cl::desc("Dump the DBI Stream (Stream 2)"),
+ cl::sub(PdbToYamlSubcommand), cl::init(false));
+
+cl::list<std::string> InputFilename(cl::Positional,
+ cl::desc("<input PDB file>"), cl::Required,
+ cl::sub(PdbToYamlSubcommand));
}
-
-static uint64_t blockToOffset(uint64_t BlockNumber, uint64_t BlockSize) {
- return BlockNumber * BlockSize;
}
-static void dumpStructure(MemoryBufferRef M) {
- const PDB::SuperBlock *SB;
- if (auto EC = getObject(SB, M, M.getBufferStart()))
- reportError(M.getBufferIdentifier(), EC);
-
- if (opts::DumpHeaders) {
- outs() << "BlockSize: " << SB->BlockSize << '\n';
- outs() << "Unknown0: " << SB->Unknown0 << '\n';
- outs() << "NumBlocks: " << SB->NumBlocks << '\n';
- outs() << "NumDirectoryBytes: " << SB->NumDirectoryBytes << '\n';
- outs() << "Unknown1: " << SB->Unknown1 << '\n';
- outs() << "BlockMapAddr: " << SB->BlockMapAddr << '\n';
- }
+static ExitOnError ExitOnErr;
- // We don't support blocksizes which aren't a multiple of four bytes.
- if (SB->BlockSize % sizeof(support::ulittle32_t) != 0)
- reportError(M.getBufferIdentifier(),
- std::make_error_code(std::errc::illegal_byte_sequence));
-
- // We don't support directories whose sizes aren't a multiple of four bytes.
- if (SB->NumDirectoryBytes % sizeof(support::ulittle32_t) != 0)
- reportError(M.getBufferIdentifier(),
- std::make_error_code(std::errc::illegal_byte_sequence));
-
- // The number of blocks which comprise the directory is a simple function of
- // the number of bytes it contains.
- uint64_t NumDirectoryBlocks =
- bytesToBlocks(SB->NumDirectoryBytes, SB->BlockSize);
- if (opts::DumpHeaders)
- outs() << "NumDirectoryBlocks: " << NumDirectoryBlocks << '\n';
-
- // The block map, as we understand it, is a block which consists of a list of
- // block numbers.
- // It is unclear what would happen if the number of blocks couldn't fit on a
- // single block.
- if (NumDirectoryBlocks > SB->BlockSize / sizeof(support::ulittle32_t))
- reportError(M.getBufferIdentifier(),
- std::make_error_code(std::errc::illegal_byte_sequence));
-
-
- uint64_t BlockMapOffset = (uint64_t)SB->BlockMapAddr * SB->BlockSize;
- if (opts::DumpHeaders)
- outs() << "BlockMapOffset: " << BlockMapOffset << '\n';
-
- // The directory is not contiguous. Instead, the block map contains a
- // contiguous list of block numbers whose contents, when concatenated in
- // order, make up the directory.
- auto DirectoryBlocks =
- makeArrayRef(reinterpret_cast<const support::ulittle32_t *>(
- M.getBufferStart() + BlockMapOffset),
- NumDirectoryBlocks);
- if (auto EC = checkOffset(M, DirectoryBlocks))
- reportError(M.getBufferIdentifier(), EC);
-
- if (opts::DumpHeaders) {
- outs() << "DirectoryBlocks: [";
- for (const support::ulittle32_t &DirectoryBlockAddr : DirectoryBlocks) {
- if (&DirectoryBlockAddr != &DirectoryBlocks.front())
- outs() << ", ";
- outs() << DirectoryBlockAddr;
- }
- outs() << "]\n";
+static void yamlToPdb(StringRef Path) {
+ ErrorOr<std::unique_ptr<MemoryBuffer>> ErrorOrBuffer =
+ MemoryBuffer::getFileOrSTDIN(Path, /*FileSize=*/-1,
+ /*RequiresNullTerminator=*/false);
+
+ if (ErrorOrBuffer.getError()) {
+ ExitOnErr(make_error<GenericError>(generic_error_code::invalid_path, Path));
}
- bool SeenNumStreams = false;
- uint32_t NumStreams = 0;
- std::vector<uint32_t> StreamSizes;
- DenseMap<uint32_t, std::vector<uint32_t>> StreamMap;
- uint32_t StreamIdx = 0;
- uint64_t DirectoryBytesRead = 0;
- // The structure of the directory is as follows:
- // struct PDBDirectory {
- // uint32_t NumStreams;
- // uint32_t StreamSizes[NumStreams];
- // uint32_t StreamMap[NumStreams][];
- // };
- //
- // Empty streams don't consume entries in the StreamMap.
- for (uint32_t DirectoryBlockAddr : DirectoryBlocks) {
- uint64_t DirectoryBlockOffset =
- blockToOffset(DirectoryBlockAddr, SB->BlockSize);
- auto DirectoryBlock =
- makeArrayRef(reinterpret_cast<const support::ulittle32_t *>(
- M.getBufferStart() + DirectoryBlockOffset),
- SB->BlockSize / sizeof(support::ulittle32_t));
- if (auto EC = checkOffset(M, DirectoryBlock))
- reportError(M.getBufferIdentifier(), EC);
-
- // We read data out of the directory four bytes at a time. Depending on
- // where we are in the directory, the contents may be: the number of streams
- // in the directory, a stream's size, or a block in the stream map.
- for (uint32_t Data : DirectoryBlock) {
- // Don't read beyond the end of the directory.
- if (DirectoryBytesRead == SB->NumDirectoryBytes)
- break;
-
- DirectoryBytesRead += sizeof(Data);
-
- // This data must be the number of streams if we haven't seen it yet.
- if (!SeenNumStreams) {
- NumStreams = Data;
- SeenNumStreams = true;
- continue;
- }
- // This data must be a stream size if we have not seen them all yet.
- if (StreamSizes.size() < NumStreams) {
- // It seems like some streams have their set to -1 when their contents
- // are not present. Treat them like empty streams for now.
- if (Data == UINT32_MAX)
- StreamSizes.push_back(0);
- else
- StreamSizes.push_back(Data);
- continue;
- }
+ std::unique_ptr<MemoryBuffer> &Buffer = ErrorOrBuffer.get();
+
+ llvm::yaml::Input In(Buffer->getBuffer());
+ pdb::yaml::PdbObject YamlObj;
+ In >> YamlObj;
+ if (!YamlObj.Headers.hasValue())
+ ExitOnErr(make_error<GenericError>(generic_error_code::unspecified,
+ "Yaml does not contain MSF headers"));
+
+ auto OutFileOrError = FileOutputBuffer::create(
+ opts::yaml2pdb::YamlPdbOutputFile, YamlObj.Headers->FileSize);
+ if (OutFileOrError.getError())
+ ExitOnErr(make_error<GenericError>(generic_error_code::invalid_path,
+ opts::yaml2pdb::YamlPdbOutputFile));
+
+ auto FileByteStream =
+ llvm::make_unique<FileBufferByteStream>(std::move(*OutFileOrError));
+ PDBFileBuilder Builder(std::move(FileByteStream));
+
+ ExitOnErr(Builder.initialize(YamlObj.Headers->SuperBlock));
+ ExitOnErr(Builder.getMsfBuilder().setDirectoryBlocksHint(
+ YamlObj.Headers->DirectoryBlocks));
+ if (!YamlObj.StreamSizes.hasValue()) {
+ ExitOnErr(make_error<GenericError>(
+ generic_error_code::unspecified,
+ "Cannot generate a PDB when stream sizes are not known"));
+ }
- // This data must be a stream block number if we have seen all of the
- // stream sizes.
- std::vector<uint32_t> *StreamBlocks = nullptr;
- // Figure out which stream this block number belongs to.
- while (StreamIdx < NumStreams) {
- uint64_t NumExpectedStreamBlocks =
- bytesToBlocks(StreamSizes[StreamIdx], SB->BlockSize);
- StreamBlocks = &StreamMap[StreamIdx];
- if (NumExpectedStreamBlocks > StreamBlocks->size())
- break;
- ++StreamIdx;
- }
- // It seems this block doesn't belong to any stream? The stream is either
- // corrupt or something more mysterious is going on.
- if (StreamIdx == NumStreams)
- reportError(M.getBufferIdentifier(),
- std::make_error_code(std::errc::illegal_byte_sequence));
+ if (YamlObj.StreamMap.hasValue()) {
+ if (YamlObj.StreamMap->size() != YamlObj.StreamSizes->size()) {
+ ExitOnErr(make_error<GenericError>(generic_error_code::unspecified,
+ "YAML specifies different number of "
+ "streams in stream sizes and stream "
+ "map"));
+ }
- StreamBlocks->push_back(Data);
+ auto &Sizes = *YamlObj.StreamSizes;
+ auto &Map = *YamlObj.StreamMap;
+ for (uint32_t I = 0; I < Sizes.size(); ++I) {
+ uint32_t Size = Sizes[I];
+ std::vector<uint32_t> Blocks;
+ for (auto E : Map[I].Blocks)
+ Blocks.push_back(E);
+ ExitOnErr(Builder.getMsfBuilder().addStream(Size, Blocks));
+ }
+ } else {
+ auto &Sizes = *YamlObj.StreamSizes;
+ for (auto S : Sizes) {
+ ExitOnErr(Builder.getMsfBuilder().addStream(S));
}
}
- // We should have read exactly SB->NumDirectoryBytes bytes.
- assert(DirectoryBytesRead == SB->NumDirectoryBytes);
-
- if (opts::DumpHeaders)
- outs() << "NumStreams: " << NumStreams << '\n';
- if (opts::DumpStreamSizes)
- for (uint32_t StreamIdx = 0; StreamIdx < NumStreams; ++StreamIdx)
- outs() << "StreamSizes[" << StreamIdx << "]: " << StreamSizes[StreamIdx]
- << '\n';
-
- if (opts::DumpStreamBlocks) {
- for (uint32_t StreamIdx = 0; StreamIdx < NumStreams; ++StreamIdx) {
- outs() << "StreamBlocks[" << StreamIdx << "]: [";
- std::vector<uint32_t> &StreamBlocks = StreamMap[StreamIdx];
- for (uint32_t &StreamBlock : StreamBlocks) {
- if (&StreamBlock != &StreamBlocks.front())
- outs() << ", ";
- outs() << StreamBlock;
- }
- outs() << "]\n";
- }
+ if (YamlObj.PdbStream.hasValue()) {
+ auto &InfoBuilder = Builder.getInfoBuilder();
+ InfoBuilder.setAge(YamlObj.PdbStream->Age);
+ InfoBuilder.setGuid(YamlObj.PdbStream->Guid);
+ InfoBuilder.setSignature(YamlObj.PdbStream->Signature);
+ InfoBuilder.setVersion(YamlObj.PdbStream->Version);
+ for (auto &NM : YamlObj.PdbStream->NamedStreams)
+ InfoBuilder.getNamedStreamsBuilder().addMapping(NM.StreamName,
+ NM.StreamNumber);
}
- StringRef DumpStreamStr = opts::DumpStreamData;
- uint32_t DumpStreamNum;
- if (!DumpStreamStr.getAsInteger(/*Radix=*/0U, DumpStreamNum) &&
- DumpStreamNum < NumStreams) {
- uint32_t StreamBytesRead = 0;
- uint32_t StreamSize = StreamSizes[DumpStreamNum];
- std::vector<uint32_t> &StreamBlocks = StreamMap[DumpStreamNum];
- for (uint32_t &StreamBlockAddr : StreamBlocks) {
- uint64_t StreamBlockOffset = blockToOffset(StreamBlockAddr, SB->BlockSize);
- uint32_t BytesLeftToReadInStream = StreamSize - StreamBytesRead;
- if (BytesLeftToReadInStream == 0)
- break;
-
- uint32_t BytesToReadInBlock = std::min(
- BytesLeftToReadInStream, static_cast<uint32_t>(SB->BlockSize));
- auto StreamBlockData =
- StringRef(M.getBufferStart() + StreamBlockOffset, BytesToReadInBlock);
- if (auto EC = checkOffset(M, StreamBlockData))
- reportError(M.getBufferIdentifier(), EC);
-
- outs() << StreamBlockData;
- StreamBytesRead += StreamBlockData.size();
- }
+ if (YamlObj.DbiStream.hasValue()) {
+ auto &DbiBuilder = Builder.getDbiBuilder();
+ DbiBuilder.setAge(YamlObj.DbiStream->Age);
+ DbiBuilder.setBuildNumber(YamlObj.DbiStream->BuildNumber);
+ DbiBuilder.setFlags(YamlObj.DbiStream->Flags);
+ DbiBuilder.setMachineType(YamlObj.DbiStream->MachineType);
+ DbiBuilder.setPdbDllRbld(YamlObj.DbiStream->PdbDllRbld);
+ DbiBuilder.setPdbDllVersion(YamlObj.DbiStream->PdbDllVersion);
+ DbiBuilder.setVersionHeader(YamlObj.DbiStream->VerHeader);
}
+
+ auto Pdb = Builder.build();
+ ExitOnErr(Pdb.takeError());
+
+ auto &PdbFile = *Pdb;
+ ExitOnErr(PdbFile->commit());
}
-static void dumpInput(StringRef Path) {
- if (opts::DumpHeaders || !opts::DumpStreamData.empty()) {
- ErrorOr<std::unique_ptr<MemoryBuffer>> ErrorOrBuffer =
- MemoryBuffer::getFileOrSTDIN(Path, /*FileSize=*/-1,
- /*RequiresNullTerminator=*/false);
+static void pdb2Yaml(StringRef Path) {
+ std::unique_ptr<IPDBSession> Session;
+ ExitOnErr(loadDataForPDB(PDB_ReaderType::Raw, Path, Session));
+
+ RawSession *RS = static_cast<RawSession *>(Session.get());
+ PDBFile &File = RS->getPDBFile();
+ auto O = llvm::make_unique<YAMLOutputStyle>(File);
+ O = llvm::make_unique<YAMLOutputStyle>(File);
- if (std::error_code EC = ErrorOrBuffer.getError())
- reportError(Path, EC);
+ ExitOnErr(O->dump());
+}
- std::unique_ptr<MemoryBuffer> &Buffer = ErrorOrBuffer.get();
+static void dumpRaw(StringRef Path) {
+ std::unique_ptr<IPDBSession> Session;
+ ExitOnErr(loadDataForPDB(PDB_ReaderType::Raw, Path, Session));
- dumpStructure(Buffer->getMemBufferRef());
+ RawSession *RS = static_cast<RawSession *>(Session.get());
+ PDBFile &File = RS->getPDBFile();
+ auto O = llvm::make_unique<LLVMOutputStyle>(File);
- outs().flush();
- return;
- }
+ ExitOnErr(O->dump());
+}
+static void dumpPretty(StringRef Path) {
std::unique_ptr<IPDBSession> Session;
- PDB_ErrorCode Error = loadDataForPDB(PDB_ReaderType::DIA, Path, Session);
- switch (Error) {
- case PDB_ErrorCode::Success:
- break;
- case PDB_ErrorCode::NoPdbImpl:
- outs() << "Reading PDBs is not supported on this platform.\n";
- return;
- case PDB_ErrorCode::InvalidPath:
- outs() << "Unable to load PDB at '" << Path
- << "'. Check that the file exists and is readable.\n";
- return;
- case PDB_ErrorCode::InvalidFileFormat:
- outs() << "Unable to load PDB at '" << Path
- << "'. The file has an unrecognized format.\n";
- return;
- default:
- outs() << "Unable to load PDB at '" << Path
- << "'. An unknown error occured.\n";
- return;
- }
- if (opts::LoadAddress)
- Session->setLoadAddress(opts::LoadAddress);
+
+ ExitOnErr(loadDataForPDB(PDB_ReaderType::DIA, Path, Session));
+
+ if (opts::pretty::LoadAddress)
+ Session->setLoadAddress(opts::pretty::LoadAddress);
LinePrinter Printer(2, outs());
@@ -453,19 +450,22 @@ static void dumpInput(StringRef Path) {
outs() << "HasPrivateSymbols ";
Printer.Unindent();
- if (opts::Compilands) {
+ if (opts::pretty::Compilands) {
Printer.NewLine();
WithColor(Printer, PDB_ColorItem::SectionHeader).get()
<< "---COMPILANDS---";
Printer.Indent();
auto Compilands = GlobalScope->findAllChildren<PDBSymbolCompiland>();
CompilandDumper Dumper(Printer);
+ CompilandDumpFlags options = CompilandDumper::Flags::None;
+ if (opts::pretty::Lines)
+ options = options | CompilandDumper::Flags::Lines;
while (auto Compiland = Compilands->getNext())
- Dumper.start(*Compiland, false);
+ Dumper.start(*Compiland, options);
Printer.Unindent();
}
- if (opts::Types) {
+ if (opts::pretty::Types) {
Printer.NewLine();
WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---TYPES---";
Printer.Indent();
@@ -474,7 +474,7 @@ static void dumpInput(StringRef Path) {
Printer.Unindent();
}
- if (opts::Symbols) {
+ if (opts::pretty::Symbols) {
Printer.NewLine();
WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---SYMBOLS---";
Printer.Indent();
@@ -485,7 +485,7 @@ static void dumpInput(StringRef Path) {
Printer.Unindent();
}
- if (opts::Globals) {
+ if (opts::pretty::Globals) {
Printer.NewLine();
WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---GLOBALS---";
Printer.Indent();
@@ -511,59 +511,98 @@ static void dumpInput(StringRef Path) {
}
Printer.Unindent();
}
- if (opts::Externals) {
+ if (opts::pretty::Externals) {
Printer.NewLine();
WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---EXTERNALS---";
Printer.Indent();
ExternalSymbolDumper Dumper(Printer);
Dumper.start(*GlobalScope);
}
+ if (opts::pretty::Lines) {
+ Printer.NewLine();
+ }
outs().flush();
}
int main(int argc_, const char *argv_[]) {
// Print a stack trace if we signal out.
- sys::PrintStackTraceOnErrorSignal();
+ sys::PrintStackTraceOnErrorSignal(argv_[0]);
PrettyStackTraceProgram X(argc_, argv_);
+ ExitOnErr.setBanner("llvm-pdbdump: ");
+
SmallVector<const char *, 256> argv;
SpecificBumpPtrAllocator<char> ArgAllocator;
- std::error_code EC = sys::Process::GetArgumentVector(
- argv, makeArrayRef(argv_, argc_), ArgAllocator);
- if (EC) {
- errs() << "error: couldn't get arguments: " << EC.message() << '\n';
- return 1;
- }
+ ExitOnErr(errorCodeToError(sys::Process::GetArgumentVector(
+ argv, makeArrayRef(argv_, argc_), ArgAllocator)));
llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
cl::ParseCommandLineOptions(argv.size(), argv.data(), "LLVM PDB Dumper\n");
- if (opts::All) {
- opts::Compilands = true;
- opts::Symbols = true;
- opts::Globals = true;
- opts::Types = true;
- opts::Externals = true;
- }
- if (opts::ExcludeCompilerGenerated) {
- opts::ExcludeTypes.push_back("__vc_attributes");
- opts::ExcludeCompilands.push_back("* Linker *");
- }
- if (opts::ExcludeSystemLibraries) {
- opts::ExcludeCompilands.push_back(
- "f:\\binaries\\Intermediate\\vctools\\crt_bld");
- }
-#if defined(HAVE_DIA_SDK)
- CoInitializeEx(nullptr, COINIT_MULTITHREADED);
-#endif
+ // These options are shared by two subcommands.
+ if ((opts::PdbToYamlSubcommand || opts::RawSubcommand) && opts::raw::RawAll) {
+ opts::raw::DumpHeaders = true;
+ opts::raw::DumpModules = true;
+ opts::raw::DumpModuleFiles = true;
+ opts::raw::DumpModuleSyms = true;
+ opts::raw::DumpPublics = true;
+ opts::raw::DumpSectionHeaders = true;
+ opts::raw::DumpStreamSummary = true;
+ opts::raw::DumpStreamBlocks = true;
+ opts::raw::DumpTpiRecords = true;
+ opts::raw::DumpTpiHash = true;
+ opts::raw::DumpIpiRecords = true;
+ opts::raw::DumpSectionMap = true;
+ opts::raw::DumpSectionContribs = true;
+ opts::raw::DumpLineInfo = true;
+ opts::raw::DumpFpo = true;
+ }
- std::for_each(opts::InputFilenames.begin(), opts::InputFilenames.end(),
- dumpInput);
+ llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::MultiThreaded);
+
+ if (opts::PdbToYamlSubcommand) {
+ pdb2Yaml(opts::pdb2yaml::InputFilename.front());
+ } else if (opts::YamlToPdbSubcommand) {
+ yamlToPdb(opts::yaml2pdb::InputFilename.front());
+ } else if (opts::PrettySubcommand) {
+ if (opts::pretty::Lines)
+ opts::pretty::Compilands = true;
+
+ if (opts::pretty::All) {
+ opts::pretty::Compilands = true;
+ opts::pretty::Symbols = true;
+ opts::pretty::Globals = true;
+ opts::pretty::Types = true;
+ opts::pretty::Externals = true;
+ opts::pretty::Lines = true;
+ }
-#if defined(HAVE_DIA_SDK)
- CoUninitialize();
-#endif
+ // When adding filters for excluded compilands and types, we need to
+ // remember
+ // that these are regexes. So special characters such as * and \ need to be
+ // escaped in the regex. In the case of a literal \, this means it needs to
+ // be escaped again in the C++. So matching a single \ in the input
+ // requires
+ // 4 \es in the C++.
+ if (opts::pretty::ExcludeCompilerGenerated) {
+ opts::pretty::ExcludeTypes.push_back("__vc_attributes");
+ opts::pretty::ExcludeCompilands.push_back("\\* Linker \\*");
+ }
+ if (opts::pretty::ExcludeSystemLibraries) {
+ opts::pretty::ExcludeCompilands.push_back(
+ "f:\\\\binaries\\\\Intermediate\\\\vctools\\\\crt_bld");
+ opts::pretty::ExcludeCompilands.push_back("f:\\\\dd\\\\vctools\\\\crt");
+ opts::pretty::ExcludeCompilands.push_back(
+ "d:\\\\th.obj.x86fre\\\\minkernel");
+ }
+ std::for_each(opts::pretty::InputFilenames.begin(),
+ opts::pretty::InputFilenames.end(), dumpPretty);
+ } else if (opts::RawSubcommand) {
+ std::for_each(opts::raw::InputFilenames.begin(),
+ opts::raw::InputFilenames.end(), dumpRaw);
+ }
+ outs().flush();
return 0;
}