120 changes: 5 additions & 115 deletions llvm/tools/llvm-pdbdump/LLVMOutputStyle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "LLVMOutputStyle.h"

#include "CompactTypeDumpVisitor.h"
#include "StreamUtil.h"
#include "llvm-pdbdump.h"

#include "llvm/DebugInfo/CodeView/CVTypeDumper.h"
Expand Down Expand Up @@ -172,124 +173,12 @@ Error LLVMOutputStyle::dumpFileHeaders() {
return Error::success();
}

void LLVMOutputStyle::discoverStreamPurposes() {
if (!StreamPurposes.empty())
return;

// It's OK if we fail to load some of these streams, we still attempt to print
// what we can.
auto Dbi = File.getPDBDbiStream();
auto Tpi = File.getPDBTpiStream();
auto Ipi = File.getPDBIpiStream();
auto Info = File.getPDBInfoStream();

uint32_t StreamCount = File.getNumStreams();
std::unordered_map<uint16_t, const ModuleInfoEx *> ModStreams;
std::unordered_map<uint16_t, std::string> NamedStreams;

if (Dbi) {
for (auto &ModI : Dbi->modules()) {
uint16_t SN = ModI.Info.getModuleStreamIndex();
ModStreams[SN] = &ModI;
}
}
if (Info) {
for (auto &NSE : Info->named_streams()) {
NamedStreams[NSE.second] = NSE.first();
}
}

StreamPurposes.resize(StreamCount);
for (uint16_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) {
std::string Value;
if (StreamIdx == OldMSFDirectory)
Value = "Old MSF Directory";
else if (StreamIdx == StreamPDB)
Value = "PDB Stream";
else if (StreamIdx == StreamDBI)
Value = "DBI Stream";
else if (StreamIdx == StreamTPI)
Value = "TPI Stream";
else if (StreamIdx == StreamIPI)
Value = "IPI Stream";
else if (Dbi && StreamIdx == Dbi->getGlobalSymbolStreamIndex())
Value = "Global Symbol Hash";
else if (Dbi && StreamIdx == Dbi->getPublicSymbolStreamIndex())
Value = "Public Symbol Hash";
else if (Dbi && StreamIdx == Dbi->getSymRecordStreamIndex())
Value = "Public Symbol Records";
else if (Tpi && StreamIdx == Tpi->getTypeHashStreamIndex())
Value = "TPI Hash";
else if (Tpi && StreamIdx == Tpi->getTypeHashStreamAuxIndex())
Value = "TPI Aux Hash";
else if (Ipi && StreamIdx == Ipi->getTypeHashStreamIndex())
Value = "IPI Hash";
else if (Ipi && StreamIdx == Ipi->getTypeHashStreamAuxIndex())
Value = "IPI Aux Hash";
else if (Dbi &&
StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Exception))
Value = "Exception Data";
else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Fixup))
Value = "Fixup Data";
else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::FPO))
Value = "FPO Data";
else if (Dbi &&
StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::NewFPO))
Value = "New FPO Data";
else if (Dbi &&
StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::OmapFromSrc))
Value = "Omap From Source Data";
else if (Dbi &&
StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::OmapToSrc))
Value = "Omap To Source Data";
else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Pdata))
Value = "Pdata";
else if (Dbi &&
StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::SectionHdr))
Value = "Section Header Data";
else if (Dbi &&
StreamIdx ==
Dbi->getDebugStreamIndex(DbgHeaderType::SectionHdrOrig))
Value = "Section Header Original Data";
else if (Dbi &&
StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::TokenRidMap))
Value = "Token Rid Data";
else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Xdata))
Value = "Xdata";
else {
auto ModIter = ModStreams.find(StreamIdx);
auto NSIter = NamedStreams.find(StreamIdx);
if (ModIter != ModStreams.end()) {
Value = "Module \"";
Value += ModIter->second->Info.getModuleName().str();
Value += "\"";
} else if (NSIter != NamedStreams.end()) {
Value = "Named Stream \"";
Value += NSIter->second;
Value += "\"";
} else {
Value = "???";
}
}
StreamPurposes[StreamIdx] = Value;
}

// Consume errors from missing streams.
if (!Dbi)
consumeError(Dbi.takeError());
if (!Tpi)
consumeError(Tpi.takeError());
if (!Ipi)
consumeError(Ipi.takeError());
if (!Info)
consumeError(Info.takeError());
}

Error LLVMOutputStyle::dumpStreamSummary() {
if (!opts::raw::DumpStreamSummary)
return Error::success();

discoverStreamPurposes();
if (StreamPurposes.empty())
discoverStreamPurposes(File, StreamPurposes);

uint32_t StreamCount = File.getNumStreams();

Expand Down Expand Up @@ -431,7 +320,8 @@ Error LLVMOutputStyle::dumpStreamBytes() {
if (opts::raw::DumpStreamData.empty())
return Error::success();

discoverStreamPurposes();
if (StreamPurposes.empty())
discoverStreamPurposes(File, StreamPurposes);

DictScope D(P, "Stream Data");
for (uint32_t SI : opts::raw::DumpStreamData) {
Expand Down
7 changes: 4 additions & 3 deletions llvm/tools/llvm-pdbdump/LLVMOutputStyle.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,12 @@

#include "OutputStyle.h"

#include "llvm/ADT/SmallVector.h"
#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
#include "llvm/Support/ScopedPrinter.h"

#include <string>

namespace llvm {
class BitVector;
namespace pdb {
Expand All @@ -25,8 +28,6 @@ class LLVMOutputStyle : public OutputStyle {
Error dump() override;

private:
void discoverStreamPurposes();

Error dumpFileHeaders();
Error dumpStreamSummary();
Error dumpFreePageMap();
Expand All @@ -51,7 +52,7 @@ class LLVMOutputStyle : public OutputStyle {
PDBFile &File;
ScopedPrinter P;
codeview::TypeDatabase TypeDB;
std::vector<std::string> StreamPurposes;
SmallVector<std::string, 32> StreamPurposes;
};
}
}
Expand Down
136 changes: 136 additions & 0 deletions llvm/tools/llvm-pdbdump/StreamUtil.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
//===- StreamUtil.cpp - PDB stream utilities --------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "StreamUtil.h"

#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseMapInfo.h"
#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
#include "llvm/DebugInfo/PDB/Native/ModInfo.h"
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
#include "llvm/DebugInfo/PDB/Native/TpiStream.h"

namespace llvm {
namespace pdb {
void discoverStreamPurposes(PDBFile &File,
SmallVectorImpl<std::string> &Purposes) {

// It's OK if we fail to load some of these streams, we still attempt to print
// what we can.
auto Dbi = File.getPDBDbiStream();
auto Tpi = File.getPDBTpiStream();
auto Ipi = File.getPDBIpiStream();
auto Info = File.getPDBInfoStream();

uint32_t StreamCount = File.getNumStreams();
DenseMap<uint16_t, const ModuleInfoEx *> ModStreams;
DenseMap<uint16_t, std::string> NamedStreams;

if (Dbi) {
for (auto &ModI : Dbi->modules()) {
uint16_t SN = ModI.Info.getModuleStreamIndex();
if (SN != kInvalidStreamIndex)
ModStreams[SN] = &ModI;
}
}
if (Info) {
for (auto &NSE : Info->named_streams()) {
if (NSE.second != kInvalidStreamIndex)
NamedStreams[NSE.second] = NSE.first();
}
}

Purposes.resize(StreamCount);
for (uint16_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) {
std::string Value;
if (StreamIdx == OldMSFDirectory)
Value = "Old MSF Directory";
else if (StreamIdx == StreamPDB)
Value = "PDB Stream";
else if (StreamIdx == StreamDBI)
Value = "DBI Stream";
else if (StreamIdx == StreamTPI)
Value = "TPI Stream";
else if (StreamIdx == StreamIPI)
Value = "IPI Stream";
else if (Dbi && StreamIdx == Dbi->getGlobalSymbolStreamIndex())
Value = "Global Symbol Hash";
else if (Dbi && StreamIdx == Dbi->getPublicSymbolStreamIndex())
Value = "Public Symbol Hash";
else if (Dbi && StreamIdx == Dbi->getSymRecordStreamIndex())
Value = "Public Symbol Records";
else if (Tpi && StreamIdx == Tpi->getTypeHashStreamIndex())
Value = "TPI Hash";
else if (Tpi && StreamIdx == Tpi->getTypeHashStreamAuxIndex())
Value = "TPI Aux Hash";
else if (Ipi && StreamIdx == Ipi->getTypeHashStreamIndex())
Value = "IPI Hash";
else if (Ipi && StreamIdx == Ipi->getTypeHashStreamAuxIndex())
Value = "IPI Aux Hash";
else if (Dbi &&
StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Exception))
Value = "Exception Data";
else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Fixup))
Value = "Fixup Data";
else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::FPO))
Value = "FPO Data";
else if (Dbi &&
StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::NewFPO))
Value = "New FPO Data";
else if (Dbi &&
StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::OmapFromSrc))
Value = "Omap From Source Data";
else if (Dbi &&
StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::OmapToSrc))
Value = "Omap To Source Data";
else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Pdata))
Value = "Pdata";
else if (Dbi &&
StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::SectionHdr))
Value = "Section Header Data";
else if (Dbi &&
StreamIdx ==
Dbi->getDebugStreamIndex(DbgHeaderType::SectionHdrOrig))
Value = "Section Header Original Data";
else if (Dbi &&
StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::TokenRidMap))
Value = "Token Rid Data";
else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Xdata))
Value = "Xdata";
else {
auto ModIter = ModStreams.find(StreamIdx);
auto NSIter = NamedStreams.find(StreamIdx);
if (ModIter != ModStreams.end()) {
Value = "Module \"";
Value += ModIter->second->Info.getModuleName().str();
Value += "\"";
} else if (NSIter != NamedStreams.end()) {
Value = "Named Stream \"";
Value += NSIter->second;
Value += "\"";
} else {
Value = "???";
}
}
Purposes[StreamIdx] = Value;
}

// Consume errors from missing streams.
if (!Dbi)
consumeError(Dbi.takeError());
if (!Tpi)
consumeError(Tpi.takeError());
if (!Ipi)
consumeError(Ipi.takeError());
if (!Info)
consumeError(Info.takeError());
}
}
}
25 changes: 25 additions & 0 deletions llvm/tools/llvm-pdbdump/StreamUtil.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//===- Streamutil.h - PDB stream utilities ----------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_TOOLS_LLVMPDBDUMP_STREAMUTIL_H
#define LLVM_TOOLS_LLVMPDBDUMP_STREAMUTIL_H

#include "llvm/ADT/SmallVector.h"

#include <string>

namespace llvm {
namespace pdb {
class PDBFile;
void discoverStreamPurposes(PDBFile &File,
SmallVectorImpl<std::string> &Purposes);
}
}

#endif
57 changes: 44 additions & 13 deletions llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,14 @@
//
//===----------------------------------------------------------------------===//
//
// Dumps debug information present in PDB files. This utility makes use of
// the Microsoft Windows SDK, so will not compile or run on non-Windows
// platforms.
// Dumps debug information present in PDB files.
//
//===----------------------------------------------------------------------===//

#include "llvm-pdbdump.h"

#include "Analyze.h"
#include "Diff.h"
#include "LLVMOutputStyle.h"
#include "LinePrinter.h"
#include "OutputStyle.h"
Expand Down Expand Up @@ -81,6 +80,9 @@ cl::SubCommand RawSubcommand("raw", "Dump raw structure of the PDB file");
cl::SubCommand
PrettySubcommand("pretty",
"Dump semantic information about types and symbols");

cl::SubCommand DiffSubcommand("diff", "Diff the contents of 2 PDB files");

cl::SubCommand
YamlToPdbSubcommand("yaml2pdb",
"Generate a PDB file from a YAML description");
Expand Down Expand Up @@ -160,6 +162,17 @@ cl::opt<bool> NoEnumDefs("no-enum-definitions",
cl::cat(FilterCategory), cl::sub(PrettySubcommand));
}

namespace diff {
cl::opt<bool> Pedantic("pedantic",
cl::desc("Finds all differences (even structural ones "
"that produce otherwise identical PDBs)"),
cl::sub(DiffSubcommand));

cl::list<std::string> InputFilenames(cl::Positional,
cl::desc("<first> <second>"),
cl::OneOrMore, cl::sub(DiffSubcommand));
}

namespace raw {

cl::OptionCategory MsfOptions("MSF Container Options");
Expand Down Expand Up @@ -414,12 +427,17 @@ static void yamlToPdb(StringRef Path) {
ExitOnErr(Builder.commit(opts::yaml2pdb::YamlPdbOutputFile));
}

static PDBFile &loadPDB(StringRef Path, std::unique_ptr<IPDBSession> &Session) {
ExitOnErr(loadDataForPDB(PDB_ReaderType::Native, Path, Session));

NativeSession *NS = static_cast<NativeSession *>(Session.get());
return NS->getPDBFile();
}

static void pdb2Yaml(StringRef Path) {
std::unique_ptr<IPDBSession> Session;
ExitOnErr(loadDataForPDB(PDB_ReaderType::Native, Path, Session));
auto &File = loadPDB(Path, Session);

NativeSession *RS = static_cast<NativeSession *>(Session.get());
PDBFile &File = RS->getPDBFile();
auto O = llvm::make_unique<YAMLOutputStyle>(File);
O = llvm::make_unique<YAMLOutputStyle>(File);

Expand All @@ -428,26 +446,33 @@ static void pdb2Yaml(StringRef Path) {

static void dumpRaw(StringRef Path) {
std::unique_ptr<IPDBSession> Session;
ExitOnErr(loadDataForPDB(PDB_ReaderType::Native, Path, Session));
auto &File = loadPDB(Path, Session);

NativeSession *RS = static_cast<NativeSession *>(Session.get());
PDBFile &File = RS->getPDBFile();
auto O = llvm::make_unique<LLVMOutputStyle>(File);

ExitOnErr(O->dump());
}

static void dumpAnalysis(StringRef Path) {
std::unique_ptr<IPDBSession> Session;
ExitOnErr(loadDataForPDB(PDB_ReaderType::Native, Path, Session));

NativeSession *NS = static_cast<NativeSession *>(Session.get());
PDBFile &File = NS->getPDBFile();
auto &File = loadPDB(Path, Session);
auto O = llvm::make_unique<AnalysisStyle>(File);

ExitOnErr(O->dump());
}

static void diff(StringRef Path1, StringRef Path2) {
std::unique_ptr<IPDBSession> Session1;
std::unique_ptr<IPDBSession> Session2;

auto &File1 = loadPDB(Path1, Session1);
auto &File2 = loadPDB(Path2, Session2);

auto O = llvm::make_unique<DiffStyle>(File1, File2);

ExitOnErr(O->dump());
}

static void dumpPretty(StringRef Path) {
std::unique_ptr<IPDBSession> Session;

Expand Down Expand Up @@ -669,6 +694,12 @@ int main(int argc_, const char *argv_[]) {
} else if (opts::RawSubcommand) {
std::for_each(opts::raw::InputFilenames.begin(),
opts::raw::InputFilenames.end(), dumpRaw);
} else if (opts::DiffSubcommand) {
if (opts::diff::InputFilenames.size() != 2) {
errs() << "diff subcommand expects exactly 2 arguments.\n";
exit(1);
}
diff(opts::diff::InputFilenames[0], opts::diff::InputFilenames[1]);
}

outs().flush();
Expand Down
4 changes: 4 additions & 0 deletions llvm/tools/llvm-pdbdump/llvm-pdbdump.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ extern llvm::cl::opt<bool> DumpFpo;
extern llvm::cl::opt<bool> DumpStringTable;
}

namespace diff {
extern llvm::cl::opt<bool> Pedantic;
}

namespace pdb2yaml {
extern llvm::cl::opt<bool> NoFileHeaders;
extern llvm::cl::opt<bool> StreamMetadata;
Expand Down