summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/tools/llvm-pdbutil
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/tools/llvm-pdbutil')
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/Analyze.cpp148
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/Analyze.h30
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/BytesOutputStyle.cpp501
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/BytesOutputStyle.h67
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/Diff.cpp608
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/Diff.h45
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/DiffPrinter.cpp147
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/DiffPrinter.h172
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp1043
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/DumpOutputStyle.h62
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/FormatUtil.cpp101
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/FormatUtil.h128
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/LinePrinter.cpp312
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/LinePrinter.h142
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.cpp772
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.h48
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp553
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/MinimalTypeDumper.h63
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/OutputStyle.h28
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PdbYaml.cpp190
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PdbYaml.h125
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyBuiltinDumper.cpp94
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyBuiltinDumper.h35
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyClassDefinitionDumper.cpp108
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyClassDefinitionDumper.h47
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyClassLayoutGraphicalDumper.cpp216
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyClassLayoutGraphicalDumper.h58
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyCompilandDumper.cpp207
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyCompilandDumper.h44
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyEnumDumper.cpp53
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyEnumDumper.h31
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyExternalSymbolDumper.cpp41
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyExternalSymbolDumper.h34
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyFunctionDumper.cpp259
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyFunctionDumper.h43
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyTypeDumper.cpp255
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyTypeDumper.h36
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyTypedefDumper.cpp77
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyTypedefDumper.h39
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyVariableDumper.cpp220
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyVariableDumper.h50
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/StreamUtil.cpp152
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/StreamUtil.h30
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/YAMLOutputStyle.cpp333
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/YAMLOutputStyle.h49
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp1179
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/llvm-pdbutil.h180
47 files changed, 9155 insertions, 0 deletions
diff --git a/contrib/llvm/tools/llvm-pdbutil/Analyze.cpp b/contrib/llvm/tools/llvm-pdbutil/Analyze.cpp
new file mode 100644
index 0000000..6c603dd
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/Analyze.cpp
@@ -0,0 +1,148 @@
+//===- Analyze.cpp - PDB analysis functions ---------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Analyze.h"
+
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
+#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/RawError.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
+
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <list>
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+static StringRef getLeafTypeName(TypeLeafKind LT) {
+ switch (LT) {
+#define TYPE_RECORD(ename, value, name) \
+ case ename: \
+ return #name;
+#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
+ default:
+ break;
+ }
+ return "UnknownLeaf";
+}
+
+namespace {
+struct HashLookupVisitor : public TypeVisitorCallbacks {
+ struct Entry {
+ TypeIndex TI;
+ CVType Record;
+ };
+
+ explicit HashLookupVisitor(TpiStream &Tpi) : Tpi(Tpi) {}
+
+ Error visitTypeBegin(CVType &Record) override {
+ uint32_t H = Tpi.getHashValues()[I];
+ Record.Hash = H;
+ TypeIndex TI(I + TypeIndex::FirstNonSimpleIndex);
+ Lookup[H].push_back(Entry{TI, Record});
+ ++I;
+ return Error::success();
+ }
+
+ uint32_t I = 0;
+ DenseMap<uint32_t, std::list<Entry>> Lookup;
+ TpiStream &Tpi;
+};
+}
+
+AnalysisStyle::AnalysisStyle(PDBFile &File) : File(File) {}
+
+Error AnalysisStyle::dump() {
+ auto Tpi = File.getPDBTpiStream();
+ if (!Tpi)
+ return Tpi.takeError();
+
+ HashLookupVisitor Hasher(*Tpi);
+
+ uint32_t RecordCount = Tpi->getNumTypeRecords();
+ auto Offsets = Tpi->getTypeIndexOffsets();
+ auto Types = llvm::make_unique<LazyRandomTypeCollection>(
+ Tpi->typeArray(), RecordCount, Offsets);
+
+ if (auto EC = codeview::visitTypeStream(*Types, Hasher))
+ return EC;
+
+ auto &Adjusters = Tpi->getHashAdjusters();
+ DenseSet<uint32_t> AdjusterSet;
+ for (const auto &Adj : Adjusters) {
+ assert(AdjusterSet.find(Adj.second) == AdjusterSet.end());
+ AdjusterSet.insert(Adj.second);
+ }
+
+ uint32_t Count = 0;
+ outs() << "Searching for hash collisions\n";
+ for (const auto &H : Hasher.Lookup) {
+ if (H.second.size() <= 1)
+ continue;
+ ++Count;
+ outs() << formatv("Hash: {0}, Count: {1} records\n", H.first,
+ H.second.size());
+ for (const auto &R : H.second) {
+ auto Iter = AdjusterSet.find(R.TI.getIndex());
+ StringRef Prefix;
+ if (Iter != AdjusterSet.end()) {
+ Prefix = "[HEAD]";
+ AdjusterSet.erase(Iter);
+ }
+ StringRef LeafName = getLeafTypeName(R.Record.Type);
+ uint32_t TI = R.TI.getIndex();
+ StringRef TypeName = Types->getTypeName(R.TI);
+ outs() << formatv("{0,-6} {1} ({2:x}) {3}\n", Prefix, LeafName, TI,
+ TypeName);
+ }
+ }
+
+ outs() << "\n";
+ outs() << "Dumping hash adjustment chains\n";
+ for (const auto &A : Tpi->getHashAdjusters()) {
+ TypeIndex TI(A.second);
+ StringRef TypeName = Types->getTypeName(TI);
+ const CVType &HeadRecord = Types->getType(TI);
+ assert(HeadRecord.Hash.hasValue());
+
+ auto CollisionsIter = Hasher.Lookup.find(*HeadRecord.Hash);
+ if (CollisionsIter == Hasher.Lookup.end())
+ continue;
+
+ const auto &Collisions = CollisionsIter->second;
+ outs() << TypeName << "\n";
+ outs() << formatv(" [HEAD] {0:x} {1} {2}\n", A.second,
+ getLeafTypeName(HeadRecord.Type), TypeName);
+ for (const auto &Chain : Collisions) {
+ if (Chain.TI == TI)
+ continue;
+ const CVType &TailRecord = Types->getType(Chain.TI);
+ outs() << formatv(" {0:x} {1} {2}\n", Chain.TI.getIndex(),
+ getLeafTypeName(TailRecord.Type),
+ Types->getTypeName(Chain.TI));
+ }
+ }
+ outs() << formatv("There are {0} orphaned hash adjusters\n",
+ AdjusterSet.size());
+ for (const auto &Adj : AdjusterSet) {
+ outs() << formatv(" {0}\n", Adj);
+ }
+
+ uint32_t DistinctHashValues = Hasher.Lookup.size();
+ outs() << formatv("{0}/{1} hash collisions", Count, DistinctHashValues);
+ return Error::success();
+}
diff --git a/contrib/llvm/tools/llvm-pdbutil/Analyze.h b/contrib/llvm/tools/llvm-pdbutil/Analyze.h
new file mode 100644
index 0000000..7230ae4
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/Analyze.h
@@ -0,0 +1,30 @@
+//===- Analyze.h - PDB analysis functions -----------------------*- 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_ANALYSIS_H
+#define LLVM_TOOLS_LLVMPDBDUMP_ANALYSIS_H
+
+#include "OutputStyle.h"
+
+namespace llvm {
+namespace pdb {
+class PDBFile;
+class AnalysisStyle : public OutputStyle {
+public:
+ explicit AnalysisStyle(PDBFile &File);
+
+ Error dump() override;
+
+private:
+ PDBFile &File;
+};
+}
+}
+
+#endif
diff --git a/contrib/llvm/tools/llvm-pdbutil/BytesOutputStyle.cpp b/contrib/llvm/tools/llvm-pdbutil/BytesOutputStyle.cpp
new file mode 100644
index 0000000..9e5a28c
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/BytesOutputStyle.cpp
@@ -0,0 +1,501 @@
+//===- BytesOutputStyle.cpp ----------------------------------- *- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "BytesOutputStyle.h"
+
+#include "FormatUtil.h"
+#include "StreamUtil.h"
+#include "llvm-pdbutil.h"
+
+#include "llvm/DebugInfo/CodeView/Formatters.h"
+#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
+#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
+#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
+#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
+#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/RawError.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/FormatAdapters.h"
+#include "llvm/Support/FormatVariadic.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::msf;
+using namespace llvm::pdb;
+
+namespace {
+struct StreamSpec {
+ uint32_t SI = 0;
+ uint32_t Begin = 0;
+ uint32_t Size = 0;
+};
+} // namespace
+
+static Expected<StreamSpec> parseStreamSpec(StringRef Str) {
+ StreamSpec Result;
+ if (Str.consumeInteger(0, Result.SI))
+ return make_error<RawError>(raw_error_code::invalid_format,
+ "Invalid Stream Specification");
+ if (Str.consume_front(":")) {
+ if (Str.consumeInteger(0, Result.Begin))
+ return make_error<RawError>(raw_error_code::invalid_format,
+ "Invalid Stream Specification");
+ }
+ if (Str.consume_front("@")) {
+ if (Str.consumeInteger(0, Result.Size))
+ return make_error<RawError>(raw_error_code::invalid_format,
+ "Invalid Stream Specification");
+ }
+
+ if (!Str.empty())
+ return make_error<RawError>(raw_error_code::invalid_format,
+ "Invalid Stream Specification");
+ return Result;
+}
+
+static SmallVector<StreamSpec, 2> parseStreamSpecs(LinePrinter &P) {
+ SmallVector<StreamSpec, 2> Result;
+
+ for (auto &Str : opts::bytes::DumpStreamData) {
+ auto ESS = parseStreamSpec(Str);
+ if (!ESS) {
+ P.formatLine("Error parsing stream spec {0}: {1}", Str,
+ toString(ESS.takeError()));
+ continue;
+ }
+ Result.push_back(*ESS);
+ }
+ return Result;
+}
+
+static void printHeader(LinePrinter &P, const Twine &S) {
+ P.NewLine();
+ P.formatLine("{0,=60}", S);
+ P.formatLine("{0}", fmt_repeat('=', 60));
+}
+
+BytesOutputStyle::BytesOutputStyle(PDBFile &File)
+ : File(File), P(2, false, outs()) {}
+
+Error BytesOutputStyle::dump() {
+
+ if (opts::bytes::DumpBlockRange.hasValue()) {
+ auto &R = *opts::bytes::DumpBlockRange;
+ uint32_t Max = R.Max.getValueOr(R.Min);
+
+ if (Max < R.Min)
+ return make_error<StringError>(
+ "Invalid block range specified. Max < Min",
+ inconvertibleErrorCode());
+ if (Max >= File.getBlockCount())
+ return make_error<StringError>(
+ "Invalid block range specified. Requested block out of bounds",
+ inconvertibleErrorCode());
+
+ dumpBlockRanges(R.Min, Max);
+ P.NewLine();
+ }
+
+ if (opts::bytes::DumpByteRange.hasValue()) {
+ auto &R = *opts::bytes::DumpByteRange;
+ uint32_t Max = R.Max.getValueOr(File.getFileSize());
+
+ if (Max < R.Min)
+ return make_error<StringError>("Invalid byte range specified. Max < Min",
+ inconvertibleErrorCode());
+ if (Max >= File.getFileSize())
+ return make_error<StringError>(
+ "Invalid byte range specified. Requested byte larger than file size",
+ inconvertibleErrorCode());
+
+ dumpByteRanges(R.Min, Max);
+ P.NewLine();
+ }
+
+ if (!opts::bytes::DumpStreamData.empty()) {
+ dumpStreamBytes();
+ P.NewLine();
+ }
+
+ if (opts::bytes::NameMap) {
+ dumpNameMap();
+ P.NewLine();
+ }
+
+ if (opts::bytes::SectionContributions) {
+ dumpSectionContributions();
+ P.NewLine();
+ }
+
+ if (opts::bytes::SectionMap) {
+ dumpSectionMap();
+ P.NewLine();
+ }
+
+ if (opts::bytes::ModuleInfos) {
+ dumpModuleInfos();
+ P.NewLine();
+ }
+
+ if (opts::bytes::FileInfo) {
+ dumpFileInfo();
+ P.NewLine();
+ }
+
+ if (opts::bytes::TypeServerMap) {
+ dumpTypeServerMap();
+ P.NewLine();
+ }
+
+ if (opts::bytes::ECData) {
+ dumpECData();
+ P.NewLine();
+ }
+
+ if (!opts::bytes::TypeIndex.empty()) {
+ dumpTypeIndex(StreamTPI, opts::bytes::TypeIndex);
+ P.NewLine();
+ }
+
+ if (!opts::bytes::IdIndex.empty()) {
+ dumpTypeIndex(StreamIPI, opts::bytes::IdIndex);
+ P.NewLine();
+ }
+
+ if (opts::bytes::ModuleSyms) {
+ dumpModuleSyms();
+ P.NewLine();
+ }
+
+ if (opts::bytes::ModuleC11) {
+ dumpModuleC11();
+ P.NewLine();
+ }
+
+ if (opts::bytes::ModuleC13) {
+ dumpModuleC13();
+ P.NewLine();
+ }
+
+ return Error::success();
+}
+
+void BytesOutputStyle::dumpNameMap() {
+ printHeader(P, "Named Stream Map");
+
+ AutoIndent Indent(P);
+
+ auto &InfoS = Err(File.getPDBInfoStream());
+ BinarySubstreamRef NS = InfoS.getNamedStreamsBuffer();
+ auto Layout = File.getStreamLayout(StreamPDB);
+ P.formatMsfStreamData("Named Stream Map", File, Layout, NS);
+}
+
+void BytesOutputStyle::dumpBlockRanges(uint32_t Min, uint32_t Max) {
+ printHeader(P, "MSF Blocks");
+
+ AutoIndent Indent(P);
+ for (uint32_t I = Min; I <= Max; ++I) {
+ uint64_t Base = I;
+ Base *= File.getBlockSize();
+
+ auto ExpectedData = File.getBlockData(I, File.getBlockSize());
+ if (!ExpectedData) {
+ P.formatLine("Could not get block {0}. Reason = {1}", I,
+ toString(ExpectedData.takeError()));
+ continue;
+ }
+ std::string Label = formatv("Block {0}", I).str();
+ P.formatBinary(Label, *ExpectedData, Base, 0);
+ }
+}
+
+void BytesOutputStyle::dumpSectionContributions() {
+ printHeader(P, "Section Contributions");
+
+ AutoIndent Indent(P);
+
+ auto &DbiS = Err(File.getPDBDbiStream());
+ BinarySubstreamRef NS = DbiS.getSectionContributionData();
+ auto Layout = File.getStreamLayout(StreamDBI);
+ P.formatMsfStreamData("Section Contributions", File, Layout, NS);
+}
+
+void BytesOutputStyle::dumpSectionMap() {
+ printHeader(P, "Section Map");
+
+ AutoIndent Indent(P);
+
+ auto &DbiS = Err(File.getPDBDbiStream());
+ BinarySubstreamRef NS = DbiS.getSecMapSubstreamData();
+ auto Layout = File.getStreamLayout(StreamDBI);
+ P.formatMsfStreamData("Section Map", File, Layout, NS);
+}
+
+void BytesOutputStyle::dumpModuleInfos() {
+ printHeader(P, "Module Infos");
+
+ AutoIndent Indent(P);
+
+ auto &DbiS = Err(File.getPDBDbiStream());
+ BinarySubstreamRef NS = DbiS.getModiSubstreamData();
+ auto Layout = File.getStreamLayout(StreamDBI);
+ P.formatMsfStreamData("Module Infos", File, Layout, NS);
+}
+
+void BytesOutputStyle::dumpFileInfo() {
+ printHeader(P, "File Info");
+
+ AutoIndent Indent(P);
+
+ auto &DbiS = Err(File.getPDBDbiStream());
+ BinarySubstreamRef NS = DbiS.getFileInfoSubstreamData();
+ auto Layout = File.getStreamLayout(StreamDBI);
+ P.formatMsfStreamData("File Info", File, Layout, NS);
+}
+
+void BytesOutputStyle::dumpTypeServerMap() {
+ printHeader(P, "Type Server Map");
+
+ AutoIndent Indent(P);
+
+ auto &DbiS = Err(File.getPDBDbiStream());
+ BinarySubstreamRef NS = DbiS.getTypeServerMapSubstreamData();
+ auto Layout = File.getStreamLayout(StreamDBI);
+ P.formatMsfStreamData("Type Server Map", File, Layout, NS);
+}
+
+void BytesOutputStyle::dumpECData() {
+ printHeader(P, "Edit and Continue Data");
+
+ AutoIndent Indent(P);
+
+ auto &DbiS = Err(File.getPDBDbiStream());
+ BinarySubstreamRef NS = DbiS.getECSubstreamData();
+ auto Layout = File.getStreamLayout(StreamDBI);
+ P.formatMsfStreamData("Edit and Continue Data", File, Layout, NS);
+}
+
+void BytesOutputStyle::dumpTypeIndex(uint32_t StreamIdx,
+ ArrayRef<uint32_t> Indices) {
+ assert(StreamIdx == StreamTPI || StreamIdx == StreamIPI);
+ assert(!Indices.empty());
+
+ bool IsTpi = (StreamIdx == StreamTPI);
+
+ StringRef Label = IsTpi ? "Type (TPI) Records" : "Index (IPI) Records";
+ printHeader(P, Label);
+ auto &Stream = Err(IsTpi ? File.getPDBTpiStream() : File.getPDBIpiStream());
+
+ AutoIndent Indent(P);
+
+ auto Substream = Stream.getTypeRecordsSubstream();
+ auto &Types = Err(initializeTypes(StreamIdx));
+ auto Layout = File.getStreamLayout(StreamIdx);
+ for (const auto &Id : Indices) {
+ TypeIndex TI(Id);
+ if (TI.toArrayIndex() >= Types.capacity()) {
+ P.formatLine("Error: TypeIndex {0} does not exist", TI);
+ continue;
+ }
+
+ auto Type = Types.getType(TI);
+ uint32_t Offset = Types.getOffsetOfType(TI);
+ auto OneType = Substream.slice(Offset, Type.length());
+ P.formatMsfStreamData(formatv("Type {0}", TI).str(), File, Layout, OneType);
+ }
+}
+
+template <typename CallbackT>
+static void iterateOneModule(PDBFile &File, LinePrinter &P,
+ const DbiModuleList &Modules, uint32_t I,
+ uint32_t Digits, uint32_t IndentLevel,
+ CallbackT Callback) {
+ if (I >= Modules.getModuleCount()) {
+ P.formatLine("Mod {0:4} | Invalid module index ",
+ fmt_align(I, AlignStyle::Right, std::max(Digits, 4U)));
+ return;
+ }
+
+ auto Modi = Modules.getModuleDescriptor(I);
+ P.formatLine("Mod {0:4} | `{1}`: ",
+ fmt_align(I, AlignStyle::Right, std::max(Digits, 4U)),
+ Modi.getModuleName());
+
+ uint16_t ModiStream = Modi.getModuleStreamIndex();
+ AutoIndent Indent2(P, IndentLevel);
+ if (ModiStream == kInvalidStreamIndex)
+ return;
+
+ auto ModStreamData = MappedBlockStream::createIndexedStream(
+ File.getMsfLayout(), File.getMsfBuffer(), ModiStream,
+ File.getAllocator());
+ ModuleDebugStreamRef ModStream(Modi, std::move(ModStreamData));
+ if (auto EC = ModStream.reload()) {
+ P.formatLine("Could not parse debug information.");
+ return;
+ }
+ auto Layout = File.getStreamLayout(ModiStream);
+ Callback(I, ModStream, Layout);
+}
+
+template <typename CallbackT>
+static void iterateModules(PDBFile &File, LinePrinter &P, uint32_t IndentLevel,
+ CallbackT Callback) {
+ AutoIndent Indent(P);
+ if (!File.hasPDBDbiStream()) {
+ P.formatLine("DBI Stream not present");
+ return;
+ }
+
+ ExitOnError Err("Unexpected error processing modules");
+
+ auto &Stream = Err(File.getPDBDbiStream());
+
+ const DbiModuleList &Modules = Stream.modules();
+
+ if (opts::bytes::ModuleIndex.getNumOccurrences() > 0) {
+ iterateOneModule(File, P, Modules, opts::bytes::ModuleIndex, 1, IndentLevel,
+ Callback);
+ } else {
+ uint32_t Count = Modules.getModuleCount();
+ uint32_t Digits = NumDigits(Count);
+ for (uint32_t I = 0; I < Count; ++I) {
+ iterateOneModule(File, P, Modules, I, Digits, IndentLevel, Callback);
+ }
+ }
+}
+
+void BytesOutputStyle::dumpModuleSyms() {
+ printHeader(P, "Module Symbols");
+
+ AutoIndent Indent(P);
+
+ iterateModules(File, P, 2,
+ [this](uint32_t Modi, const ModuleDebugStreamRef &Stream,
+ const MSFStreamLayout &Layout) {
+ auto Symbols = Stream.getSymbolsSubstream();
+ P.formatMsfStreamData("Symbols", File, Layout, Symbols);
+ });
+}
+
+void BytesOutputStyle::dumpModuleC11() {
+ printHeader(P, "C11 Debug Chunks");
+
+ AutoIndent Indent(P);
+
+ iterateModules(File, P, 2,
+ [this](uint32_t Modi, const ModuleDebugStreamRef &Stream,
+ const MSFStreamLayout &Layout) {
+ auto Chunks = Stream.getC11LinesSubstream();
+ P.formatMsfStreamData("C11 Debug Chunks", File, Layout,
+ Chunks);
+ });
+}
+
+static std::string formatChunkKind(DebugSubsectionKind Kind) {
+ switch (Kind) {
+ RETURN_CASE(DebugSubsectionKind, None, "none");
+ RETURN_CASE(DebugSubsectionKind, Symbols, "symbols");
+ RETURN_CASE(DebugSubsectionKind, Lines, "lines");
+ RETURN_CASE(DebugSubsectionKind, StringTable, "strings");
+ RETURN_CASE(DebugSubsectionKind, FileChecksums, "checksums");
+ RETURN_CASE(DebugSubsectionKind, FrameData, "frames");
+ RETURN_CASE(DebugSubsectionKind, InlineeLines, "inlinee lines");
+ RETURN_CASE(DebugSubsectionKind, CrossScopeImports, "xmi");
+ RETURN_CASE(DebugSubsectionKind, CrossScopeExports, "xme");
+ RETURN_CASE(DebugSubsectionKind, ILLines, "il lines");
+ RETURN_CASE(DebugSubsectionKind, FuncMDTokenMap, "func md token map");
+ RETURN_CASE(DebugSubsectionKind, TypeMDTokenMap, "type md token map");
+ RETURN_CASE(DebugSubsectionKind, MergedAssemblyInput,
+ "merged assembly input");
+ RETURN_CASE(DebugSubsectionKind, CoffSymbolRVA, "coff symbol rva");
+ }
+ return formatUnknownEnum(Kind);
+}
+
+void BytesOutputStyle::dumpModuleC13() {
+ printHeader(P, "Debug Chunks");
+
+ AutoIndent Indent(P);
+
+ iterateModules(
+ File, P, 2,
+ [this](uint32_t Modi, const ModuleDebugStreamRef &Stream,
+ const MSFStreamLayout &Layout) {
+ auto Chunks = Stream.getC13LinesSubstream();
+ if (opts::bytes::SplitChunks) {
+ for (const auto &SS : Stream.subsections()) {
+ BinarySubstreamRef ThisChunk;
+ std::tie(ThisChunk, Chunks) = Chunks.split(SS.getRecordLength());
+ P.formatMsfStreamData(formatChunkKind(SS.kind()), File, Layout,
+ ThisChunk);
+ }
+ } else {
+ P.formatMsfStreamData("Debug Chunks", File, Layout, Chunks);
+ }
+ });
+}
+
+void BytesOutputStyle::dumpByteRanges(uint32_t Min, uint32_t Max) {
+ printHeader(P, "MSF Bytes");
+
+ AutoIndent Indent(P);
+
+ BinaryStreamReader Reader(File.getMsfBuffer());
+ ArrayRef<uint8_t> Data;
+ consumeError(Reader.skip(Min));
+ uint32_t Size = Max - Min + 1;
+ auto EC = Reader.readBytes(Data, Size);
+ assert(!EC);
+ consumeError(std::move(EC));
+ P.formatBinary("Bytes", Data, Min);
+}
+
+Expected<codeview::LazyRandomTypeCollection &>
+BytesOutputStyle::initializeTypes(uint32_t StreamIdx) {
+ auto &TypeCollection = (StreamIdx == StreamTPI) ? TpiTypes : IpiTypes;
+ if (TypeCollection)
+ return *TypeCollection;
+
+ auto Tpi = (StreamIdx == StreamTPI) ? File.getPDBTpiStream()
+ : File.getPDBIpiStream();
+ if (!Tpi)
+ return Tpi.takeError();
+
+ auto &Types = Tpi->typeArray();
+ uint32_t Count = Tpi->getNumTypeRecords();
+ auto Offsets = Tpi->getTypeIndexOffsets();
+ TypeCollection =
+ llvm::make_unique<LazyRandomTypeCollection>(Types, Count, Offsets);
+
+ return *TypeCollection;
+}
+
+void BytesOutputStyle::dumpStreamBytes() {
+ if (StreamPurposes.empty())
+ discoverStreamPurposes(File, StreamPurposes);
+
+ printHeader(P, "Stream Data");
+ ExitOnError Err("Unexpected error reading stream data");
+
+ auto Specs = parseStreamSpecs(P);
+
+ for (const auto &Spec : Specs) {
+ AutoIndent Indent(P);
+ if (Spec.SI >= StreamPurposes.size()) {
+ P.formatLine("Stream {0}: Not present", Spec.SI);
+ continue;
+ }
+ P.formatMsfStreamData("Data", File, Spec.SI, StreamPurposes[Spec.SI],
+ Spec.Begin, Spec.Size);
+ }
+}
diff --git a/contrib/llvm/tools/llvm-pdbutil/BytesOutputStyle.h b/contrib/llvm/tools/llvm-pdbutil/BytesOutputStyle.h
new file mode 100644
index 0000000..c162163
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/BytesOutputStyle.h
@@ -0,0 +1,67 @@
+//===- BytesOutputStyle.h ------------------------------------- *- 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_BYTESOUTPUTSTYLE_H
+#define LLVM_TOOLS_LLVMPDBDUMP_BYTESOUTPUTSTYLE_H
+
+#include "LinePrinter.h"
+#include "OutputStyle.h"
+
+#include "llvm/Support/Error.h"
+
+namespace llvm {
+
+namespace codeview {
+class LazyRandomTypeCollection;
+}
+
+namespace pdb {
+
+class PDBFile;
+
+class BytesOutputStyle : public OutputStyle {
+public:
+ BytesOutputStyle(PDBFile &File);
+
+ Error dump() override;
+
+private:
+ void dumpNameMap();
+ void dumpBlockRanges(uint32_t Min, uint32_t Max);
+ void dumpByteRanges(uint32_t Min, uint32_t Max);
+ void dumpStreamBytes();
+
+ void dumpSectionContributions();
+ void dumpSectionMap();
+ void dumpModuleInfos();
+ void dumpFileInfo();
+ void dumpTypeServerMap();
+ void dumpECData();
+
+ void dumpModuleSyms();
+ void dumpModuleC11();
+ void dumpModuleC13();
+
+ void dumpTypeIndex(uint32_t StreamIdx, ArrayRef<uint32_t> Indices);
+
+ Expected<codeview::LazyRandomTypeCollection &>
+ initializeTypes(uint32_t StreamIdx);
+
+ std::unique_ptr<codeview::LazyRandomTypeCollection> TpiTypes;
+ std::unique_ptr<codeview::LazyRandomTypeCollection> IpiTypes;
+
+ PDBFile &File;
+ LinePrinter P;
+ ExitOnError Err;
+ SmallVector<std::string, 8> StreamPurposes;
+};
+} // namespace pdb
+} // namespace llvm
+
+#endif
diff --git a/contrib/llvm/tools/llvm-pdbutil/Diff.cpp b/contrib/llvm/tools/llvm-pdbutil/Diff.cpp
new file mode 100644
index 0000000..aad4e1b
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/Diff.cpp
@@ -0,0 +1,608 @@
+//===- Diff.cpp - PDB diff utility ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Diff.h"
+
+#include "DiffPrinter.h"
+#include "FormatUtil.h"
+#include "StreamUtil.h"
+#include "llvm-pdbutil.h"
+
+#include "llvm/ADT/StringSet.h"
+
+#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
+#include "llvm/DebugInfo/PDB/Native/Formatters.h"
+#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/PDBStringTable.h"
+#include "llvm/DebugInfo/PDB/Native/RawConstants.h"
+
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/FormatAdapters.h"
+#include "llvm/Support/FormatProviders.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/Path.h"
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+namespace {
+// Compare and format two stream numbers. Stream numbers are considered
+// identical if they contain the same value, equivalent if they are both
+// the invalid stream or neither is the invalid stream, and different if
+// one is the invalid stream and another isn't.
+struct StreamNumberProvider {
+ static DiffResult compare(uint16_t L, uint16_t R) {
+ if (L == R)
+ return DiffResult::IDENTICAL;
+ bool LP = L != kInvalidStreamIndex;
+ bool RP = R != kInvalidStreamIndex;
+ if (LP != RP)
+ return DiffResult::DIFFERENT;
+ return DiffResult::EQUIVALENT;
+ }
+
+ static std::string format(uint16_t SN, bool Right) {
+ if (SN == kInvalidStreamIndex)
+ return "(not present)";
+ return formatv("{0}", SN).str();
+ }
+};
+
+// Compares and formats two module indices. Modis are considered identical
+// if they are identical, equivalent if they either both contain a value or
+// both don't contain a value, and different if one contains a value and the
+// other doesn't.
+struct ModiProvider {
+ DiffResult compare(Optional<uint32_t> L, Optional<uint32_t> R) {
+ if (L == R)
+ return DiffResult::IDENTICAL;
+ if (L.hasValue() != R.hasValue())
+ return DiffResult::DIFFERENT;
+ return DiffResult::EQUIVALENT;
+ }
+
+ std::string format(Optional<uint32_t> Modi, bool Right) {
+ if (!Modi.hasValue())
+ return "(not present)";
+ return formatv("{0}", *Modi).str();
+ }
+};
+
+// Compares and formats two paths embedded in the PDB, ignoring the beginning
+// of the path if the user specified it as a "root path" on the command line.
+struct BinaryPathProvider {
+ explicit BinaryPathProvider(uint32_t MaxLen) : MaxLen(MaxLen) {}
+
+ DiffResult compare(StringRef L, StringRef R) {
+ if (L == R)
+ return DiffResult::IDENTICAL;
+
+ SmallString<64> LN = removeRoot(L, false);
+ SmallString<64> RN = removeRoot(R, true);
+
+ return (LN.equals_lower(RN)) ? DiffResult::EQUIVALENT
+ : DiffResult::DIFFERENT;
+ }
+
+ std::string format(StringRef S, bool Right) {
+ if (S.empty())
+ return "(empty)";
+
+ SmallString<64> Native = removeRoot(S, Right);
+ return truncateStringFront(Native.str(), MaxLen);
+ }
+
+ SmallString<64> removeRoot(StringRef Path, bool IsRight) const {
+ SmallString<64> Native(Path);
+ auto &RootOpt = IsRight ? opts::diff::RightRoot : opts::diff::LeftRoot;
+ SmallString<64> Root(static_cast<std::string>(RootOpt));
+ // pdb paths always use windows syntax, convert slashes to backslashes.
+ sys::path::native(Root, sys::path::Style::windows);
+ if (sys::path::has_stem(Root, sys::path::Style::windows))
+ sys::path::append(Root, sys::path::Style::windows,
+ sys::path::get_separator(sys::path::Style::windows));
+
+ sys::path::replace_path_prefix(Native, Root, "", sys::path::Style::windows);
+ return Native;
+ }
+ uint32_t MaxLen;
+};
+
+// Compare and format two stream purposes. For general streams, this just
+// compares the description. For module streams it uses the path comparison
+// algorithm taking into consideration the binary root, described above.
+// Formatting stream purposes just prints the stream purpose, except for
+// module streams and named streams, where it prefixes the name / module
+// with an identifier. Example:
+//
+// Named Stream "\names"
+// Module Stream "foo.obj"
+//
+// If a named stream is too long to fit in a column, it is truncated at the
+// end, and if a module is too long to fit in a column, it is truncated at the
+// beginning. Example:
+//
+// Named Stream "\Really Long Str..."
+// Module Stream "...puts\foo.obj"
+//
+struct StreamPurposeProvider {
+ explicit StreamPurposeProvider(uint32_t MaxLen) : MaxLen(MaxLen) {}
+
+ DiffResult compare(const std::pair<StreamPurpose, std::string> &L,
+ const std::pair<StreamPurpose, std::string> &R) {
+ if (L.first != R.first)
+ return DiffResult::DIFFERENT;
+ if (L.first == StreamPurpose::ModuleStream) {
+ BinaryPathProvider PathProvider(MaxLen);
+ return PathProvider.compare(L.second, R.second);
+ }
+ return (L.second == R.second) ? DiffResult::IDENTICAL
+ : DiffResult::DIFFERENT;
+ }
+
+ std::string format(const std::pair<StreamPurpose, std::string> &P,
+ bool Right) {
+ if (P.first == StreamPurpose::Other)
+ return truncateStringBack(P.second, MaxLen);
+ if (P.first == StreamPurpose::NamedStream)
+ return truncateQuotedNameBack("Named Stream", P.second, MaxLen);
+
+ assert(P.first == StreamPurpose::ModuleStream);
+ uint32_t ExtraChars = strlen("Module \"\"");
+ BinaryPathProvider PathProvider(MaxLen - ExtraChars);
+ std::string Result = PathProvider.format(P.second, Right);
+ return formatv("Module \"{0}\"", Result);
+ }
+
+ uint32_t MaxLen;
+};
+} // namespace
+
+namespace llvm {
+template <> struct format_provider<PdbRaw_FeatureSig> {
+ static void format(const PdbRaw_FeatureSig &Sig, raw_ostream &Stream,
+ StringRef Style) {
+ switch (Sig) {
+ case PdbRaw_FeatureSig::MinimalDebugInfo:
+ Stream << "MinimalDebugInfo";
+ break;
+ case PdbRaw_FeatureSig::NoTypeMerge:
+ Stream << "NoTypeMerge";
+ break;
+ case PdbRaw_FeatureSig::VC110:
+ Stream << "VC110";
+ break;
+ case PdbRaw_FeatureSig::VC140:
+ Stream << "VC140";
+ break;
+ }
+ }
+};
+}
+
+template <typename R> using ValueOfRange = llvm::detail::ValueOfRange<R>;
+
+DiffStyle::DiffStyle(PDBFile &File1, PDBFile &File2)
+ : File1(File1), File2(File2) {}
+
+Error DiffStyle::dump() {
+ if (auto EC = diffSuperBlock())
+ return EC;
+
+ if (auto EC = diffFreePageMap())
+ return EC;
+
+ if (auto EC = diffStreamDirectory())
+ return EC;
+
+ if (auto EC = diffStringTable())
+ return EC;
+
+ if (auto EC = diffInfoStream())
+ return EC;
+
+ if (auto EC = diffDbiStream())
+ return EC;
+
+ if (auto EC = diffSectionContribs())
+ return EC;
+
+ if (auto EC = diffSectionMap())
+ return EC;
+
+ if (auto EC = diffFpoStream())
+ return EC;
+
+ if (auto EC = diffTpiStream(StreamTPI))
+ return EC;
+
+ if (auto EC = diffTpiStream(StreamIPI))
+ return EC;
+
+ if (auto EC = diffPublics())
+ return EC;
+
+ if (auto EC = diffGlobals())
+ return EC;
+
+ return Error::success();
+}
+
+Error DiffStyle::diffSuperBlock() {
+ DiffPrinter D(2, "MSF Super Block", 16, 20, opts::diff::PrintResultColumn,
+ opts::diff::PrintValueColumns, outs());
+ D.printExplicit("File", DiffResult::UNSPECIFIED,
+ truncateStringFront(File1.getFilePath(), 18),
+ truncateStringFront(File2.getFilePath(), 18));
+ D.print("Block Size", File1.getBlockSize(), File2.getBlockSize());
+ D.print("Block Count", File1.getBlockCount(), File2.getBlockCount());
+ D.print("Unknown 1", File1.getUnknown1(), File2.getUnknown1());
+ D.print("Directory Size", File1.getNumDirectoryBytes(),
+ File2.getNumDirectoryBytes());
+ return Error::success();
+}
+
+Error DiffStyle::diffStreamDirectory() {
+ DiffPrinter D(2, "Stream Directory", 30, 20, opts::diff::PrintResultColumn,
+ opts::diff::PrintValueColumns, outs());
+ D.printExplicit("File", DiffResult::UNSPECIFIED,
+ truncateStringFront(File1.getFilePath(), 18),
+ truncateStringFront(File2.getFilePath(), 18));
+
+ SmallVector<std::pair<StreamPurpose, std::string>, 32> P;
+ SmallVector<std::pair<StreamPurpose, std::string>, 32> Q;
+ discoverStreamPurposes(File1, P);
+ discoverStreamPurposes(File2, Q);
+ D.print("Stream Count", File1.getNumStreams(), File2.getNumStreams());
+ auto PI = to_vector<32>(enumerate(P));
+ auto QI = to_vector<32>(enumerate(Q));
+
+ // Scan all streams in the left hand side, looking for ones that are also
+ // in the right. Each time we find one, remove it. When we're done, Q
+ // should contain all the streams that are in the right but not in the left.
+ StreamPurposeProvider StreamProvider(28);
+ for (const auto &P : PI) {
+ typedef decltype(PI) ContainerType;
+ typedef typename ContainerType::value_type value_type;
+
+ auto Iter = llvm::find_if(QI, [P, &StreamProvider](const value_type &V) {
+ DiffResult Result = StreamProvider.compare(P.value(), V.value());
+ return Result == DiffResult::EQUIVALENT ||
+ Result == DiffResult::IDENTICAL;
+ });
+
+ if (Iter == QI.end()) {
+ D.printExplicit(StreamProvider.format(P.value(), false),
+ DiffResult::DIFFERENT, P.index(), "(not present)");
+ continue;
+ }
+
+ D.print<EquivalentDiffProvider>(StreamProvider.format(P.value(), false),
+ P.index(), Iter->index());
+ QI.erase(Iter);
+ }
+
+ for (const auto &Q : QI) {
+ D.printExplicit(StreamProvider.format(Q.value(), true),
+ DiffResult::DIFFERENT, "(not present)", Q.index());
+ }
+
+ return Error::success();
+}
+
+Error DiffStyle::diffStringTable() {
+ DiffPrinter D(2, "String Table", 30, 20, opts::diff::PrintResultColumn,
+ opts::diff::PrintValueColumns, outs());
+ D.printExplicit("File", DiffResult::UNSPECIFIED,
+ truncateStringFront(File1.getFilePath(), 18),
+ truncateStringFront(File2.getFilePath(), 18));
+
+ auto ExpectedST1 = File1.getStringTable();
+ auto ExpectedST2 = File2.getStringTable();
+ bool Has1 = !!ExpectedST1;
+ bool Has2 = !!ExpectedST2;
+ std::string Count1 = Has1 ? llvm::utostr(ExpectedST1->getNameCount())
+ : "(string table not present)";
+ std::string Count2 = Has2 ? llvm::utostr(ExpectedST2->getNameCount())
+ : "(string table not present)";
+ D.print("Number of Strings", Count1, Count2);
+
+ if (!Has1 || !Has2) {
+ consumeError(ExpectedST1.takeError());
+ consumeError(ExpectedST2.takeError());
+ return Error::success();
+ }
+
+ auto &ST1 = *ExpectedST1;
+ auto &ST2 = *ExpectedST2;
+
+ D.print("Hash Version", ST1.getHashVersion(), ST2.getHashVersion());
+ D.print("Byte Size", ST1.getByteSize(), ST2.getByteSize());
+ D.print("Signature", ST1.getSignature(), ST2.getSignature());
+
+ // Both have a valid string table, dive in and compare individual strings.
+
+ auto IdList1 = ST1.name_ids();
+ auto IdList2 = ST2.name_ids();
+ StringSet<> LS;
+ StringSet<> RS;
+ uint32_t Empty1 = 0;
+ uint32_t Empty2 = 0;
+ for (auto ID : IdList1) {
+ auto S = ST1.getStringForID(ID);
+ if (!S)
+ return S.takeError();
+ if (S->empty())
+ ++Empty1;
+ else
+ LS.insert(*S);
+ }
+ for (auto ID : IdList2) {
+ auto S = ST2.getStringForID(ID);
+ if (!S)
+ return S.takeError();
+ if (S->empty())
+ ++Empty2;
+ else
+ RS.insert(*S);
+ }
+ D.print("Empty Strings", Empty1, Empty2);
+
+ for (const auto &S : LS) {
+ auto R = RS.find(S.getKey());
+ std::string Truncated = truncateStringMiddle(S.getKey(), 28);
+ uint32_t I = cantFail(ST1.getIDForString(S.getKey()));
+ if (R == RS.end()) {
+ D.printExplicit(Truncated, DiffResult::DIFFERENT, I, "(not present)");
+ continue;
+ }
+
+ uint32_t J = cantFail(ST2.getIDForString(R->getKey()));
+ D.print<EquivalentDiffProvider>(Truncated, I, J);
+ RS.erase(R);
+ }
+
+ for (const auto &S : RS) {
+ auto L = LS.find(S.getKey());
+ std::string Truncated = truncateStringMiddle(S.getKey(), 28);
+ uint32_t J = cantFail(ST2.getIDForString(S.getKey()));
+ if (L == LS.end()) {
+ D.printExplicit(Truncated, DiffResult::DIFFERENT, "(not present)", J);
+ continue;
+ }
+
+ uint32_t I = cantFail(ST1.getIDForString(L->getKey()));
+ D.print<EquivalentDiffProvider>(Truncated, I, J);
+ }
+ return Error::success();
+}
+
+Error DiffStyle::diffFreePageMap() { return Error::success(); }
+
+Error DiffStyle::diffInfoStream() {
+ DiffPrinter D(2, "PDB Stream", 22, 40, opts::diff::PrintResultColumn,
+ opts::diff::PrintValueColumns, outs());
+ D.printExplicit("File", DiffResult::UNSPECIFIED,
+ truncateStringFront(File1.getFilePath(), 38),
+ truncateStringFront(File2.getFilePath(), 38));
+
+ auto ExpectedInfo1 = File1.getPDBInfoStream();
+ auto ExpectedInfo2 = File2.getPDBInfoStream();
+
+ bool Has1 = !!ExpectedInfo1;
+ bool Has2 = !!ExpectedInfo2;
+ if (!(Has1 && Has2)) {
+ std::string L = Has1 ? "(present)" : "(not present)";
+ std::string R = Has2 ? "(present)" : "(not present)";
+ D.print("Stream", L, R);
+
+ consumeError(ExpectedInfo1.takeError());
+ consumeError(ExpectedInfo2.takeError());
+ return Error::success();
+ }
+
+ auto &IS1 = *ExpectedInfo1;
+ auto &IS2 = *ExpectedInfo2;
+ D.print("Stream Size", IS1.getStreamSize(), IS2.getStreamSize());
+ D.print("Age", IS1.getAge(), IS2.getAge());
+ D.print("Guid", IS1.getGuid(), IS2.getGuid());
+ D.print("Signature", IS1.getSignature(), IS2.getSignature());
+ D.print("Version", IS1.getVersion(), IS2.getVersion());
+ D.diffUnorderedArray("Feature", IS1.getFeatureSignatures(),
+ IS2.getFeatureSignatures());
+ D.print("Named Stream Size", IS1.getNamedStreamMapByteSize(),
+ IS2.getNamedStreamMapByteSize());
+ StringMap<uint32_t> NSL = IS1.getNamedStreams().getStringMap();
+ StringMap<uint32_t> NSR = IS2.getNamedStreams().getStringMap();
+ D.diffUnorderedMap<EquivalentDiffProvider>("Named Stream", NSL, NSR);
+ return Error::success();
+}
+
+static std::vector<std::pair<uint32_t, DbiModuleDescriptor>>
+getModuleDescriptors(const DbiModuleList &ML) {
+ std::vector<std::pair<uint32_t, DbiModuleDescriptor>> List;
+ List.reserve(ML.getModuleCount());
+ for (uint32_t I = 0; I < ML.getModuleCount(); ++I)
+ List.emplace_back(I, ML.getModuleDescriptor(I));
+ return List;
+}
+
+static void
+diffOneModule(DiffPrinter &D,
+ const std::pair<uint32_t, DbiModuleDescriptor> Item,
+ std::vector<std::pair<uint32_t, DbiModuleDescriptor>> &Other,
+ bool ItemIsRight) {
+ StreamPurposeProvider HeaderProvider(70);
+ std::pair<StreamPurpose, std::string> Header;
+ Header.first = StreamPurpose::ModuleStream;
+ Header.second = Item.second.getModuleName();
+ D.printFullRow(HeaderProvider.format(Header, ItemIsRight));
+
+ const auto *L = &Item;
+
+ BinaryPathProvider PathProvider(28);
+ auto Iter = llvm::find_if(
+ Other, [&PathProvider, ItemIsRight,
+ L](const std::pair<uint32_t, DbiModuleDescriptor> &Other) {
+ const auto *Left = L;
+ const auto *Right = &Other;
+ if (ItemIsRight)
+ std::swap(Left, Right);
+ DiffResult Result = PathProvider.compare(Left->second.getModuleName(),
+ Right->second.getModuleName());
+ return Result == DiffResult::EQUIVALENT ||
+ Result == DiffResult::IDENTICAL;
+ });
+ if (Iter == Other.end()) {
+ // We didn't find this module at all on the other side. Just print one row
+ // and continue.
+ D.print<ModiProvider>("- Modi", Item.first, None);
+ return;
+ }
+
+ // We did find this module. Go through and compare each field.
+ const auto *R = &*Iter;
+ if (ItemIsRight)
+ std::swap(L, R);
+
+ D.print<ModiProvider>("- Modi", L->first, R->first);
+ D.print<BinaryPathProvider>("- Obj File Name", L->second.getObjFileName(),
+ R->second.getObjFileName(), PathProvider);
+ D.print<StreamNumberProvider>("- Debug Stream",
+ L->second.getModuleStreamIndex(),
+ R->second.getModuleStreamIndex());
+ D.print("- C11 Byte Size", L->second.getC11LineInfoByteSize(),
+ R->second.getC11LineInfoByteSize());
+ D.print("- C13 Byte Size", L->second.getC13LineInfoByteSize(),
+ R->second.getC13LineInfoByteSize());
+ D.print("- # of files", L->second.getNumberOfFiles(),
+ R->second.getNumberOfFiles());
+ D.print("- Pdb File Path Index", L->second.getPdbFilePathNameIndex(),
+ R->second.getPdbFilePathNameIndex());
+ D.print("- Source File Name Index", L->second.getSourceFileNameIndex(),
+ R->second.getSourceFileNameIndex());
+ D.print("- Symbol Byte Size", L->second.getSymbolDebugInfoByteSize(),
+ R->second.getSymbolDebugInfoByteSize());
+ Other.erase(Iter);
+}
+
+Error DiffStyle::diffDbiStream() {
+ DiffPrinter D(2, "DBI Stream", 40, 30, opts::diff::PrintResultColumn,
+ opts::diff::PrintValueColumns, outs());
+ D.printExplicit("File", DiffResult::UNSPECIFIED,
+ truncateStringFront(File1.getFilePath(), 28),
+ truncateStringFront(File2.getFilePath(), 28));
+
+ auto ExpectedDbi1 = File1.getPDBDbiStream();
+ auto ExpectedDbi2 = File2.getPDBDbiStream();
+
+ bool Has1 = !!ExpectedDbi1;
+ bool Has2 = !!ExpectedDbi2;
+ if (!(Has1 && Has2)) {
+ std::string L = Has1 ? "(present)" : "(not present)";
+ std::string R = Has2 ? "(present)" : "(not present)";
+ D.print("Stream", L, R);
+
+ consumeError(ExpectedDbi1.takeError());
+ consumeError(ExpectedDbi2.takeError());
+ return Error::success();
+ }
+
+ auto &DL = *ExpectedDbi1;
+ auto &DR = *ExpectedDbi2;
+
+ D.print("Dbi Version", (uint32_t)DL.getDbiVersion(),
+ (uint32_t)DR.getDbiVersion());
+ D.print("Age", DL.getAge(), DR.getAge());
+ D.print("Machine", (uint16_t)DL.getMachineType(),
+ (uint16_t)DR.getMachineType());
+ D.print("Flags", DL.getFlags(), DR.getFlags());
+ D.print("Build Major", DL.getBuildMajorVersion(), DR.getBuildMajorVersion());
+ D.print("Build Minor", DL.getBuildMinorVersion(), DR.getBuildMinorVersion());
+ D.print("Build Number", DL.getBuildNumber(), DR.getBuildNumber());
+ D.print("PDB DLL Version", DL.getPdbDllVersion(), DR.getPdbDllVersion());
+ D.print("PDB DLL RBLD", DL.getPdbDllRbld(), DR.getPdbDllRbld());
+ D.print<StreamNumberProvider>("DBG (FPO)",
+ DL.getDebugStreamIndex(DbgHeaderType::FPO),
+ DR.getDebugStreamIndex(DbgHeaderType::FPO));
+ D.print<StreamNumberProvider>(
+ "DBG (Exception)", DL.getDebugStreamIndex(DbgHeaderType::Exception),
+ DR.getDebugStreamIndex(DbgHeaderType::Exception));
+ D.print<StreamNumberProvider>("DBG (Fixup)",
+ DL.getDebugStreamIndex(DbgHeaderType::Fixup),
+ DR.getDebugStreamIndex(DbgHeaderType::Fixup));
+ D.print<StreamNumberProvider>(
+ "DBG (OmapToSrc)", DL.getDebugStreamIndex(DbgHeaderType::OmapToSrc),
+ DR.getDebugStreamIndex(DbgHeaderType::OmapToSrc));
+ D.print<StreamNumberProvider>(
+ "DBG (OmapFromSrc)", DL.getDebugStreamIndex(DbgHeaderType::OmapFromSrc),
+ DR.getDebugStreamIndex(DbgHeaderType::OmapFromSrc));
+ D.print<StreamNumberProvider>(
+ "DBG (SectionHdr)", DL.getDebugStreamIndex(DbgHeaderType::SectionHdr),
+ DR.getDebugStreamIndex(DbgHeaderType::SectionHdr));
+ D.print<StreamNumberProvider>(
+ "DBG (TokenRidMap)", DL.getDebugStreamIndex(DbgHeaderType::TokenRidMap),
+ DR.getDebugStreamIndex(DbgHeaderType::TokenRidMap));
+ D.print<StreamNumberProvider>("DBG (Xdata)",
+ DL.getDebugStreamIndex(DbgHeaderType::Xdata),
+ DR.getDebugStreamIndex(DbgHeaderType::Xdata));
+ D.print<StreamNumberProvider>("DBG (Pdata)",
+ DL.getDebugStreamIndex(DbgHeaderType::Pdata),
+ DR.getDebugStreamIndex(DbgHeaderType::Pdata));
+ D.print<StreamNumberProvider>("DBG (NewFPO)",
+ DL.getDebugStreamIndex(DbgHeaderType::NewFPO),
+ DR.getDebugStreamIndex(DbgHeaderType::NewFPO));
+ D.print<StreamNumberProvider>(
+ "DBG (SectionHdrOrig)",
+ DL.getDebugStreamIndex(DbgHeaderType::SectionHdrOrig),
+ DR.getDebugStreamIndex(DbgHeaderType::SectionHdrOrig));
+ D.print<StreamNumberProvider>("Globals Stream",
+ DL.getGlobalSymbolStreamIndex(),
+ DR.getGlobalSymbolStreamIndex());
+ D.print<StreamNumberProvider>("Publics Stream",
+ DL.getPublicSymbolStreamIndex(),
+ DR.getPublicSymbolStreamIndex());
+ D.print<StreamNumberProvider>("Symbol Records", DL.getSymRecordStreamIndex(),
+ DR.getSymRecordStreamIndex());
+ D.print("Has CTypes", DL.hasCTypes(), DR.hasCTypes());
+ D.print("Is Incrementally Linked", DL.isIncrementallyLinked(),
+ DR.isIncrementallyLinked());
+ D.print("Is Stripped", DL.isStripped(), DR.isStripped());
+ const DbiModuleList &ML = DL.modules();
+ const DbiModuleList &MR = DR.modules();
+ D.print("Module Count", ML.getModuleCount(), MR.getModuleCount());
+ D.print("Source File Count", ML.getSourceFileCount(),
+ MR.getSourceFileCount());
+ auto MDL = getModuleDescriptors(ML);
+ auto MDR = getModuleDescriptors(MR);
+ // Scan all module descriptors from the left, and look for corresponding
+ // module descriptors on the right.
+ for (const auto &L : MDL)
+ diffOneModule(D, L, MDR, false);
+
+ for (const auto &R : MDR)
+ diffOneModule(D, R, MDL, true);
+
+ return Error::success();
+}
+
+Error DiffStyle::diffSectionContribs() { return Error::success(); }
+
+Error DiffStyle::diffSectionMap() { return Error::success(); }
+
+Error DiffStyle::diffFpoStream() { return Error::success(); }
+
+Error DiffStyle::diffTpiStream(int Index) { return Error::success(); }
+
+Error DiffStyle::diffModuleInfoStream(int Index) { return Error::success(); }
+
+Error DiffStyle::diffPublics() { return Error::success(); }
+
+Error DiffStyle::diffGlobals() { return Error::success(); }
diff --git a/contrib/llvm/tools/llvm-pdbutil/Diff.h b/contrib/llvm/tools/llvm-pdbutil/Diff.h
new file mode 100644
index 0000000..6037576
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/Diff.h
@@ -0,0 +1,45 @@
+//===- Diff.h - PDB diff utility --------------------------------*- 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_DIFF_H
+#define LLVM_TOOLS_LLVMPDBDUMP_DIFF_H
+
+#include "OutputStyle.h"
+
+namespace llvm {
+namespace pdb {
+class PDBFile;
+class DiffStyle : public OutputStyle {
+public:
+ explicit DiffStyle(PDBFile &File1, PDBFile &File2);
+
+ Error dump() override;
+
+private:
+ Error diffSuperBlock();
+ Error diffStreamDirectory();
+ Error diffStringTable();
+ Error diffFreePageMap();
+ Error diffInfoStream();
+ Error diffDbiStream();
+ Error diffSectionContribs();
+ Error diffSectionMap();
+ Error diffFpoStream();
+ Error diffTpiStream(int Index);
+ Error diffModuleInfoStream(int Index);
+ Error diffPublics();
+ Error diffGlobals();
+
+ PDBFile &File1;
+ PDBFile &File2;
+};
+}
+}
+
+#endif
diff --git a/contrib/llvm/tools/llvm-pdbutil/DiffPrinter.cpp b/contrib/llvm/tools/llvm-pdbutil/DiffPrinter.cpp
new file mode 100644
index 0000000..dd61cc1
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/DiffPrinter.cpp
@@ -0,0 +1,147 @@
+
+#include "DiffPrinter.h"
+
+#include "llvm/Support/FormatAdapters.h"
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+namespace {
+struct Colorize {
+ Colorize(raw_ostream &OS, DiffResult Result) : OS(OS) {
+ if (!OS.has_colors())
+ return;
+ switch (Result) {
+ case DiffResult::IDENTICAL:
+ OS.changeColor(raw_ostream::Colors::GREEN, false);
+ break;
+ case DiffResult::EQUIVALENT:
+ OS.changeColor(raw_ostream::Colors::YELLOW, true);
+ break;
+ default:
+ OS.changeColor(raw_ostream::Colors::RED, false);
+ break;
+ }
+ }
+
+ ~Colorize() {
+ if (OS.has_colors())
+ OS.resetColor();
+ }
+
+ raw_ostream &OS;
+};
+}
+
+DiffPrinter::DiffPrinter(uint32_t Indent, StringRef Header,
+ uint32_t PropertyWidth, uint32_t FieldWidth,
+ bool Result, bool Fields, raw_ostream &Stream)
+ : PrintResult(Result), PrintValues(Fields), Indent(Indent),
+ PropertyWidth(PropertyWidth), FieldWidth(FieldWidth), OS(Stream) {
+ printHeaderRow();
+ printFullRow(Header);
+}
+
+DiffPrinter::~DiffPrinter() {}
+
+uint32_t DiffPrinter::tableWidth() const {
+ // `|`
+ uint32_t W = 1;
+
+ // `<width>|`
+ W += PropertyWidth + 1;
+
+ if (PrintResult) {
+ // ` I |`
+ W += 4;
+ }
+
+ if (PrintValues) {
+ // `<width>|<width>|`
+ W += 2 * (FieldWidth + 1);
+ }
+ return W;
+}
+
+void DiffPrinter::printFullRow(StringRef Text) {
+ newLine();
+ printValue(Text, DiffResult::UNSPECIFIED, AlignStyle::Center,
+ tableWidth() - 2, true);
+ printSeparatorRow();
+}
+
+void DiffPrinter::printSeparatorRow() {
+ newLine();
+ OS << formatv("{0}", fmt_repeat('-', PropertyWidth));
+ if (PrintResult) {
+ OS << '+';
+ OS << formatv("{0}", fmt_repeat('-', 3));
+ }
+ if (PrintValues) {
+ OS << '+';
+ OS << formatv("{0}", fmt_repeat('-', FieldWidth));
+ OS << '+';
+ OS << formatv("{0}", fmt_repeat('-', FieldWidth));
+ }
+ OS << '|';
+}
+
+void DiffPrinter::printHeaderRow() {
+ newLine('-');
+ OS << formatv("{0}", fmt_repeat('-', tableWidth() - 1));
+}
+
+void DiffPrinter::newLine(char InitialChar) {
+ OS << "\n";
+ OS.indent(Indent) << InitialChar;
+}
+
+void DiffPrinter::printExplicit(StringRef Property, DiffResult C,
+ StringRef Left, StringRef Right) {
+ newLine();
+ printValue(Property, DiffResult::UNSPECIFIED, AlignStyle::Right,
+ PropertyWidth, true);
+ printResult(C);
+ printValue(Left, C, AlignStyle::Center, FieldWidth, false);
+ printValue(Right, C, AlignStyle::Center, FieldWidth, false);
+ printSeparatorRow();
+}
+
+void DiffPrinter::printResult(DiffResult Result) {
+ if (!PrintResult)
+ return;
+ switch (Result) {
+ case DiffResult::DIFFERENT:
+ printValue("D", Result, AlignStyle::Center, 3, true);
+ break;
+ case DiffResult::EQUIVALENT:
+ printValue("E", Result, AlignStyle::Center, 3, true);
+ break;
+ case DiffResult::IDENTICAL:
+ printValue("I", Result, AlignStyle::Center, 3, true);
+ break;
+ case DiffResult::UNSPECIFIED:
+ printValue(" ", Result, AlignStyle::Center, 3, true);
+ break;
+ }
+}
+
+void DiffPrinter::printValue(StringRef Value, DiffResult C, AlignStyle Style,
+ uint32_t Width, bool Force) {
+ if (!Force && !PrintValues)
+ return;
+
+ if (Style == AlignStyle::Right)
+ --Width;
+
+ std::string FormattedItem =
+ formatv("{0}", fmt_align(Value, Style, Width)).str();
+ if (C != DiffResult::UNSPECIFIED) {
+ Colorize Color(OS, C);
+ OS << FormattedItem;
+ } else
+ OS << FormattedItem;
+ if (Style == AlignStyle::Right)
+ OS << ' ';
+ OS << '|';
+}
diff --git a/contrib/llvm/tools/llvm-pdbutil/DiffPrinter.h b/contrib/llvm/tools/llvm-pdbutil/DiffPrinter.h
new file mode 100644
index 0000000..475747d
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/DiffPrinter.h
@@ -0,0 +1,172 @@
+//===- DiffPrinter.h ------------------------------------------ *- 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_DIFFPRINTER_H
+#define LLVM_TOOLS_LLVMPDBDUMP_DIFFPRINTER_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/DebugInfo/PDB/Native/RawConstants.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <list>
+#include <unordered_set>
+
+namespace std {
+template <> struct hash<llvm::pdb::PdbRaw_FeatureSig> {
+ typedef llvm::pdb::PdbRaw_FeatureSig argument_type;
+ typedef std::size_t result_type;
+ result_type operator()(argument_type Item) const {
+ return std::hash<uint32_t>{}(uint32_t(Item));
+ }
+};
+} // namespace std
+
+namespace llvm {
+namespace pdb {
+
+class PDBFile;
+
+enum class DiffResult { UNSPECIFIED, IDENTICAL, EQUIVALENT, DIFFERENT };
+
+struct IdenticalDiffProvider {
+ template <typename T, typename U>
+ DiffResult compare(const T &Left, const U &Right) {
+ return (Left == Right) ? DiffResult::IDENTICAL : DiffResult::DIFFERENT;
+ }
+
+ template <typename T> std::string format(const T &Item, bool Right) {
+ return formatv("{0}", Item).str();
+ }
+};
+
+struct EquivalentDiffProvider {
+ template <typename T, typename U>
+ DiffResult compare(const T &Left, const U &Right) {
+ return (Left == Right) ? DiffResult::IDENTICAL : DiffResult::EQUIVALENT;
+ }
+
+ template <typename T> std::string format(const T &Item, bool Right) {
+ return formatv("{0}", Item).str();
+ }
+};
+
+class DiffPrinter {
+public:
+ DiffPrinter(uint32_t Indent, StringRef Header, uint32_t PropertyWidth,
+ uint32_t FieldWidth, bool Result, bool Values,
+ raw_ostream &Stream);
+ ~DiffPrinter();
+
+ template <typename T, typename U> struct Identical {};
+
+ template <typename Provider = IdenticalDiffProvider, typename T, typename U>
+ void print(StringRef Property, const T &Left, const U &Right,
+ Provider P = Provider()) {
+ std::string L = P.format(Left, false);
+ std::string R = P.format(Right, true);
+
+ DiffResult Result = P.compare(Left, Right);
+ printExplicit(Property, Result, L, R);
+ }
+
+ void printExplicit(StringRef Property, DiffResult C, StringRef Left,
+ StringRef Right);
+
+ template <typename T, typename U>
+ void printExplicit(StringRef Property, DiffResult C, const T &Left,
+ const U &Right) {
+ std::string L = formatv("{0}", Left).str();
+ std::string R = formatv("{0}", Right).str();
+ printExplicit(Property, C, StringRef(L), StringRef(R));
+ }
+
+ template <typename T, typename U>
+ void diffUnorderedArray(StringRef Property, ArrayRef<T> Left,
+ ArrayRef<U> Right) {
+ std::unordered_set<T> LS(Left.begin(), Left.end());
+ std::unordered_set<U> RS(Right.begin(), Right.end());
+ std::string Count1 = formatv("{0} element(s)", Left.size());
+ std::string Count2 = formatv("{0} element(s)", Right.size());
+ print(std::string(Property) + "s (set)", Count1, Count2);
+ for (const auto &L : LS) {
+ auto Iter = RS.find(L);
+ std::string Text = formatv("{0}", L).str();
+ if (Iter == RS.end()) {
+ print(Property, Text, "(not present)");
+ continue;
+ }
+ print(Property, Text, Text);
+ RS.erase(Iter);
+ }
+ for (const auto &R : RS) {
+ auto Iter = LS.find(R);
+ std::string Text = formatv("{0}", R).str();
+ if (Iter == LS.end()) {
+ print(Property, "(not present)", Text);
+ continue;
+ }
+ print(Property, Text, Text);
+ }
+ }
+
+ template <typename ValueProvider = IdenticalDiffProvider, typename T,
+ typename U>
+ void diffUnorderedMap(StringRef Property, const StringMap<T> &Left,
+ const StringMap<U> &Right,
+ ValueProvider P = ValueProvider()) {
+ StringMap<U> RightCopy(Right);
+
+ std::string Count1 = formatv("{0} element(s)", Left.size());
+ std::string Count2 = formatv("{0} element(s)", Right.size());
+ print(std::string(Property) + "s (map)", Count1, Count2);
+
+ for (const auto &L : Left) {
+ auto Iter = RightCopy.find(L.getKey());
+ if (Iter == RightCopy.end()) {
+ printExplicit(L.getKey(), DiffResult::DIFFERENT, L.getValue(),
+ "(not present)");
+ continue;
+ }
+
+ print(L.getKey(), L.getValue(), Iter->getValue(), P);
+ RightCopy.erase(Iter);
+ }
+
+ for (const auto &R : RightCopy) {
+ printExplicit(R.getKey(), DiffResult::DIFFERENT, "(not present)",
+ R.getValue());
+ }
+ }
+
+ void printFullRow(StringRef Text);
+
+private:
+ uint32_t tableWidth() const;
+
+ void printHeaderRow();
+ void printSeparatorRow();
+ void newLine(char InitialChar = '|');
+ void printValue(StringRef Value, DiffResult C, AlignStyle Style,
+ uint32_t Width, bool Force);
+ void printResult(DiffResult Result);
+
+ bool PrintResult;
+ bool PrintValues;
+ uint32_t Indent;
+ uint32_t PropertyWidth;
+ uint32_t FieldWidth;
+ raw_ostream &OS;
+};
+} // namespace pdb
+} // namespace llvm
+
+#endif
diff --git a/contrib/llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp b/contrib/llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp
new file mode 100644
index 0000000..01c7481
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp
@@ -0,0 +1,1043 @@
+//===- DumpOutputStyle.cpp ------------------------------------ *- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DumpOutputStyle.h"
+
+#include "FormatUtil.h"
+#include "MinimalSymbolDumper.h"
+#include "MinimalTypeDumper.h"
+#include "StreamUtil.h"
+#include "llvm-pdbutil.h"
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h"
+#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
+#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugCrossExSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugCrossImpSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugSubsectionVisitor.h"
+#include "llvm/DebugInfo/CodeView/DebugSymbolsSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugUnknownSubsection.h"
+#include "llvm/DebugInfo/CodeView/EnumTables.h"
+#include "llvm/DebugInfo/CodeView/Formatters.h"
+#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
+#include "llvm/DebugInfo/CodeView/Line.h"
+#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
+#include "llvm/DebugInfo/CodeView/SymbolDumper.h"
+#include "llvm/DebugInfo/CodeView/SymbolVisitorCallbackPipeline.h"
+#include "llvm/DebugInfo/CodeView/SymbolVisitorCallbacks.h"
+#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
+#include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"
+#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
+#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
+#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h"
+#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
+#include "llvm/DebugInfo/PDB/Native/EnumTables.h"
+#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
+#include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h"
+#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
+#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/PublicsStream.h"
+#include "llvm/DebugInfo/PDB/Native/RawError.h"
+#include "llvm/DebugInfo/PDB/Native/TpiHashing.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
+#include "llvm/DebugInfo/PDB/PDBExtras.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/FormatAdapters.h"
+#include "llvm/Support/FormatVariadic.h"
+
+#include <unordered_map>
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::msf;
+using namespace llvm::pdb;
+
+DumpOutputStyle::DumpOutputStyle(PDBFile &File)
+ : File(File), P(2, false, outs()) {}
+
+Error DumpOutputStyle::dump() {
+ if (opts::dump::DumpSummary) {
+ if (auto EC = dumpFileSummary())
+ return EC;
+ P.NewLine();
+ }
+
+ if (opts::dump::DumpStreams) {
+ if (auto EC = dumpStreamSummary())
+ return EC;
+ P.NewLine();
+ }
+
+ if (opts::dump::DumpStringTable) {
+ if (auto EC = dumpStringTable())
+ return EC;
+ P.NewLine();
+ }
+
+ if (opts::dump::DumpModules) {
+ if (auto EC = dumpModules())
+ return EC;
+ }
+
+ if (opts::dump::DumpModuleFiles) {
+ if (auto EC = dumpModuleFiles())
+ return EC;
+ }
+
+ if (opts::dump::DumpLines) {
+ if (auto EC = dumpLines())
+ return EC;
+ }
+
+ if (opts::dump::DumpInlineeLines) {
+ if (auto EC = dumpInlineeLines())
+ return EC;
+ }
+
+ if (opts::dump::DumpXmi) {
+ if (auto EC = dumpXmi())
+ return EC;
+ }
+
+ if (opts::dump::DumpXme) {
+ if (auto EC = dumpXme())
+ return EC;
+ }
+
+ if (opts::dump::DumpTypes || !opts::dump::DumpTypeIndex.empty() ||
+ opts::dump::DumpTypeExtras) {
+ if (auto EC = dumpTpiStream(StreamTPI))
+ return EC;
+ }
+
+ if (opts::dump::DumpIds || !opts::dump::DumpIdIndex.empty() ||
+ opts::dump::DumpIdExtras) {
+ if (auto EC = dumpTpiStream(StreamIPI))
+ return EC;
+ }
+
+ if (opts::dump::DumpPublics) {
+ if (auto EC = dumpPublics())
+ return EC;
+ }
+
+ if (opts::dump::DumpSymbols) {
+ if (auto EC = dumpModuleSyms())
+ return EC;
+ }
+
+ if (opts::dump::DumpSectionContribs) {
+ if (auto EC = dumpSectionContribs())
+ return EC;
+ }
+
+ if (opts::dump::DumpSectionMap) {
+ if (auto EC = dumpSectionMap())
+ return EC;
+ }
+
+ return Error::success();
+}
+
+static void printHeader(LinePrinter &P, const Twine &S) {
+ P.NewLine();
+ P.formatLine("{0,=60}", S);
+ P.formatLine("{0}", fmt_repeat('=', 60));
+}
+
+Error DumpOutputStyle::dumpFileSummary() {
+ printHeader(P, "Summary");
+
+ ExitOnError Err("Invalid PDB Format");
+
+ AutoIndent Indent(P);
+ P.formatLine("Block Size: {0}", File.getBlockSize());
+ P.formatLine("Number of blocks: {0}", File.getBlockCount());
+ P.formatLine("Number of streams: {0}", File.getNumStreams());
+
+ auto &PS = Err(File.getPDBInfoStream());
+ P.formatLine("Signature: {0}", PS.getSignature());
+ P.formatLine("Age: {0}", PS.getAge());
+ P.formatLine("GUID: {0}", fmt_guid(PS.getGuid().Guid));
+ P.formatLine("Features: {0:x+}", static_cast<uint32_t>(PS.getFeatures()));
+ P.formatLine("Has Debug Info: {0}", File.hasPDBDbiStream());
+ P.formatLine("Has Types: {0}", File.hasPDBTpiStream());
+ P.formatLine("Has IDs: {0}", File.hasPDBIpiStream());
+ P.formatLine("Has Globals: {0}", File.hasPDBGlobalsStream());
+ P.formatLine("Has Publics: {0}", File.hasPDBPublicsStream());
+ if (File.hasPDBDbiStream()) {
+ auto &DBI = Err(File.getPDBDbiStream());
+ P.formatLine("Is incrementally linked: {0}", DBI.isIncrementallyLinked());
+ P.formatLine("Has conflicting types: {0}", DBI.hasCTypes());
+ P.formatLine("Is stripped: {0}", DBI.isStripped());
+ }
+
+ return Error::success();
+}
+
+Error DumpOutputStyle::dumpStreamSummary() {
+ printHeader(P, "Streams");
+
+ if (StreamPurposes.empty())
+ discoverStreamPurposes(File, StreamPurposes);
+
+ AutoIndent Indent(P);
+ uint32_t StreamCount = File.getNumStreams();
+
+ for (uint16_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) {
+ P.formatLine(
+ "Stream {0}: [{1}] ({2} bytes)",
+ fmt_align(StreamIdx, AlignStyle::Right, NumDigits(StreamCount)),
+ StreamPurposes[StreamIdx], File.getStreamByteSize(StreamIdx));
+ if (opts::dump::DumpStreamBlocks) {
+ auto Blocks = File.getStreamBlockList(StreamIdx);
+ std::vector<uint32_t> BV(Blocks.begin(), Blocks.end());
+ P.formatLine(" {0} Blocks: [{1}]",
+ fmt_repeat(' ', NumDigits(StreamCount)),
+ make_range(BV.begin(), BV.end()));
+ }
+ }
+
+ return Error::success();
+}
+
+static Expected<ModuleDebugStreamRef> getModuleDebugStream(PDBFile &File,
+ uint32_t Index) {
+ ExitOnError Err("Unexpected error");
+
+ auto &Dbi = Err(File.getPDBDbiStream());
+ const auto &Modules = Dbi.modules();
+ auto Modi = Modules.getModuleDescriptor(Index);
+
+ uint16_t ModiStream = Modi.getModuleStreamIndex();
+ if (ModiStream == kInvalidStreamIndex)
+ return make_error<RawError>(raw_error_code::no_stream,
+ "Module stream not present");
+
+ auto ModStreamData = MappedBlockStream::createIndexedStream(
+ File.getMsfLayout(), File.getMsfBuffer(), ModiStream,
+ File.getAllocator());
+
+ ModuleDebugStreamRef ModS(Modi, std::move(ModStreamData));
+ if (auto EC = ModS.reload())
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Invalid module stream");
+
+ return std::move(ModS);
+}
+
+static std::string formatChecksumKind(FileChecksumKind Kind) {
+ switch (Kind) {
+ RETURN_CASE(FileChecksumKind, None, "None");
+ RETURN_CASE(FileChecksumKind, MD5, "MD5");
+ RETURN_CASE(FileChecksumKind, SHA1, "SHA-1");
+ RETURN_CASE(FileChecksumKind, SHA256, "SHA-256");
+ }
+ return formatUnknownEnum(Kind);
+}
+
+namespace {
+class StringsAndChecksumsPrinter {
+ const DebugStringTableSubsectionRef &extractStringTable(PDBFile &File) {
+ ExitOnError Err("Unexpected error processing modules");
+ return Err(File.getStringTable()).getStringTable();
+ }
+
+ template <typename... Args>
+ void formatInternal(LinePrinter &Printer, bool Append,
+ Args &&... args) const {
+ if (Append)
+ Printer.format(std::forward<Args>(args)...);
+ else
+ Printer.formatLine(std::forward<Args>(args)...);
+ }
+
+public:
+ StringsAndChecksumsPrinter(PDBFile &File, uint32_t Modi)
+ : Records(extractStringTable(File)) {
+ auto MDS = getModuleDebugStream(File, Modi);
+ if (!MDS) {
+ consumeError(MDS.takeError());
+ return;
+ }
+
+ DebugStream = llvm::make_unique<ModuleDebugStreamRef>(std::move(*MDS));
+ Records.initialize(MDS->subsections());
+ if (Records.hasChecksums()) {
+ for (const auto &Entry : Records.checksums()) {
+ auto S = Records.strings().getString(Entry.FileNameOffset);
+ if (!S)
+ continue;
+ ChecksumsByFile[*S] = Entry;
+ }
+ }
+ }
+
+ Expected<StringRef> getNameFromStringTable(uint32_t Offset) const {
+ return Records.strings().getString(Offset);
+ }
+
+ void formatFromFileName(LinePrinter &Printer, StringRef File,
+ bool Append = false) const {
+ auto FC = ChecksumsByFile.find(File);
+ if (FC == ChecksumsByFile.end()) {
+ formatInternal(Printer, Append, "- (no checksum) {0}", File);
+ return;
+ }
+
+ formatInternal(Printer, Append, "- ({0}: {1}) {2}",
+ formatChecksumKind(FC->getValue().Kind),
+ toHex(FC->getValue().Checksum), File);
+ }
+
+ void formatFromChecksumsOffset(LinePrinter &Printer, uint32_t Offset,
+ bool Append = false) const {
+ if (!Records.hasChecksums()) {
+ formatInternal(Printer, Append, "(unknown file name offset {0})", Offset);
+ return;
+ }
+
+ auto Iter = Records.checksums().getArray().at(Offset);
+ if (Iter == Records.checksums().getArray().end()) {
+ formatInternal(Printer, Append, "(unknown file name offset {0})", Offset);
+ return;
+ }
+
+ uint32_t FO = Iter->FileNameOffset;
+ auto ExpectedFile = getNameFromStringTable(FO);
+ if (!ExpectedFile) {
+ formatInternal(Printer, Append, "(unknown file name offset {0})", Offset);
+ consumeError(ExpectedFile.takeError());
+ return;
+ }
+ if (Iter->Kind == FileChecksumKind::None) {
+ formatInternal(Printer, Append, "{0} (no checksum)", *ExpectedFile);
+ } else {
+ formatInternal(Printer, Append, "{0} ({1}: {2})", *ExpectedFile,
+ formatChecksumKind(Iter->Kind), toHex(Iter->Checksum));
+ }
+ }
+
+ std::unique_ptr<ModuleDebugStreamRef> DebugStream;
+ StringsAndChecksumsRef Records;
+ StringMap<FileChecksumEntry> ChecksumsByFile;
+};
+} // namespace
+
+template <typename CallbackT>
+static void iterateModules(PDBFile &File, LinePrinter &P, uint32_t IndentLevel,
+ CallbackT Callback) {
+ AutoIndent Indent(P);
+ if (!File.hasPDBDbiStream()) {
+ P.formatLine("DBI Stream not present");
+ return;
+ }
+
+ ExitOnError Err("Unexpected error processing modules");
+
+ auto &Stream = Err(File.getPDBDbiStream());
+
+ const DbiModuleList &Modules = Stream.modules();
+ uint32_t Count = Modules.getModuleCount();
+ uint32_t Digits = NumDigits(Count);
+ for (uint32_t I = 0; I < Count; ++I) {
+ auto Modi = Modules.getModuleDescriptor(I);
+ P.formatLine("Mod {0:4} | `{1}`: ", fmt_align(I, AlignStyle::Right, Digits),
+ Modi.getModuleName());
+
+ StringsAndChecksumsPrinter Strings(File, I);
+ AutoIndent Indent2(P, IndentLevel);
+ Callback(I, Strings);
+ }
+}
+
+template <typename SubsectionT>
+static void iterateModuleSubsections(
+ PDBFile &File, LinePrinter &P, uint32_t IndentLevel,
+ llvm::function_ref<void(uint32_t, StringsAndChecksumsPrinter &,
+ SubsectionT &)>
+ Callback) {
+
+ iterateModules(
+ File, P, IndentLevel,
+ [&File, &Callback](uint32_t Modi, StringsAndChecksumsPrinter &Strings) {
+ auto MDS = getModuleDebugStream(File, Modi);
+ if (!MDS) {
+ consumeError(MDS.takeError());
+ return;
+ }
+
+ for (const auto &SS : MDS->subsections()) {
+ SubsectionT Subsection;
+
+ if (SS.kind() != Subsection.kind())
+ continue;
+
+ BinaryStreamReader Reader(SS.getRecordData());
+ if (auto EC = Subsection.initialize(Reader))
+ continue;
+ Callback(Modi, Strings, Subsection);
+ }
+ });
+}
+
+Error DumpOutputStyle::dumpModules() {
+ printHeader(P, "Modules");
+
+ AutoIndent Indent(P);
+ if (!File.hasPDBDbiStream()) {
+ P.formatLine("DBI Stream not present");
+ return Error::success();
+ }
+
+ ExitOnError Err("Unexpected error processing modules");
+
+ auto &Stream = Err(File.getPDBDbiStream());
+
+ const DbiModuleList &Modules = Stream.modules();
+ uint32_t Count = Modules.getModuleCount();
+ uint32_t Digits = NumDigits(Count);
+ for (uint32_t I = 0; I < Count; ++I) {
+ auto Modi = Modules.getModuleDescriptor(I);
+ P.formatLine("Mod {0:4} | Name: `{1}`: ",
+ fmt_align(I, AlignStyle::Right, Digits), Modi.getModuleName());
+ P.formatLine(" Obj: `{0}`: ", Modi.getObjFileName());
+ P.formatLine(" debug stream: {0}, # files: {1}, has ec info: {2}",
+ Modi.getModuleStreamIndex(), Modi.getNumberOfFiles(),
+ Modi.hasECInfo());
+ StringRef PdbFilePath =
+ Err(Stream.getECName(Modi.getPdbFilePathNameIndex()));
+ StringRef SrcFilePath =
+ Err(Stream.getECName(Modi.getSourceFileNameIndex()));
+ P.formatLine(" pdb file ni: {0} `{1}`, src file ni: {2} `{3}`",
+ Modi.getPdbFilePathNameIndex(), PdbFilePath,
+ Modi.getSourceFileNameIndex(), SrcFilePath);
+ }
+ return Error::success();
+}
+
+Error DumpOutputStyle::dumpModuleFiles() {
+ printHeader(P, "Files");
+
+ ExitOnError Err("Unexpected error processing modules");
+
+ iterateModules(
+ File, P, 11,
+ [this, &Err](uint32_t Modi, StringsAndChecksumsPrinter &Strings) {
+ auto &Stream = Err(File.getPDBDbiStream());
+
+ const DbiModuleList &Modules = Stream.modules();
+ for (const auto &F : Modules.source_files(Modi)) {
+ Strings.formatFromFileName(P, F);
+ }
+ });
+ return Error::success();
+}
+
+static void typesetLinesAndColumns(PDBFile &File, LinePrinter &P,
+ uint32_t Start, const LineColumnEntry &E) {
+ const uint32_t kMaxCharsPerLineNumber = 4; // 4 digit line number
+ uint32_t MinColumnWidth = kMaxCharsPerLineNumber + 5;
+
+ // Let's try to keep it under 100 characters
+ constexpr uint32_t kMaxRowLength = 100;
+ // At least 3 spaces between columns.
+ uint32_t ColumnsPerRow = kMaxRowLength / (MinColumnWidth + 3);
+ uint32_t ItemsLeft = E.LineNumbers.size();
+ auto LineIter = E.LineNumbers.begin();
+ while (ItemsLeft != 0) {
+ uint32_t RowColumns = std::min(ItemsLeft, ColumnsPerRow);
+ for (uint32_t I = 0; I < RowColumns; ++I) {
+ LineInfo Line(LineIter->Flags);
+ std::string LineStr;
+ if (Line.isAlwaysStepInto())
+ LineStr = "ASI";
+ else if (Line.isNeverStepInto())
+ LineStr = "NSI";
+ else
+ LineStr = utostr(Line.getStartLine());
+ char Statement = Line.isStatement() ? ' ' : '!';
+ P.format("{0} {1:X-} {2} ",
+ fmt_align(LineStr, AlignStyle::Right, kMaxCharsPerLineNumber),
+ fmt_align(Start + LineIter->Offset, AlignStyle::Right, 8, '0'),
+ Statement);
+ ++LineIter;
+ --ItemsLeft;
+ }
+ P.NewLine();
+ }
+}
+
+Error DumpOutputStyle::dumpLines() {
+ printHeader(P, "Lines");
+
+ uint32_t LastModi = UINT32_MAX;
+ uint32_t LastNameIndex = UINT32_MAX;
+ iterateModuleSubsections<DebugLinesSubsectionRef>(
+ File, P, 4,
+ [this, &LastModi, &LastNameIndex](uint32_t Modi,
+ StringsAndChecksumsPrinter &Strings,
+ DebugLinesSubsectionRef &Lines) {
+ uint16_t Segment = Lines.header()->RelocSegment;
+ uint32_t Begin = Lines.header()->RelocOffset;
+ uint32_t End = Begin + Lines.header()->CodeSize;
+ for (const auto &Block : Lines) {
+ if (LastModi != Modi || LastNameIndex != Block.NameIndex) {
+ LastModi = Modi;
+ LastNameIndex = Block.NameIndex;
+ Strings.formatFromChecksumsOffset(P, Block.NameIndex);
+ }
+
+ AutoIndent Indent(P, 2);
+ P.formatLine("{0:X-4}:{1:X-8}-{2:X-8}, ", Segment, Begin, End);
+ uint32_t Count = Block.LineNumbers.size();
+ if (Lines.hasColumnInfo())
+ P.format("line/column/addr entries = {0}", Count);
+ else
+ P.format("line/addr entries = {0}", Count);
+
+ P.NewLine();
+ typesetLinesAndColumns(File, P, Begin, Block);
+ }
+ });
+
+ return Error::success();
+}
+
+Error DumpOutputStyle::dumpInlineeLines() {
+ printHeader(P, "Inlinee Lines");
+
+ iterateModuleSubsections<DebugInlineeLinesSubsectionRef>(
+ File, P, 2,
+ [this](uint32_t Modi, StringsAndChecksumsPrinter &Strings,
+ DebugInlineeLinesSubsectionRef &Lines) {
+ P.formatLine("{0,+8} | {1,+5} | {2}", "Inlinee", "Line", "Source File");
+ for (const auto &Entry : Lines) {
+ P.formatLine("{0,+8} | {1,+5} | ", Entry.Header->Inlinee,
+ fmtle(Entry.Header->SourceLineNum));
+ Strings.formatFromChecksumsOffset(P, Entry.Header->FileID, true);
+ }
+ P.NewLine();
+ });
+
+ return Error::success();
+}
+
+Error DumpOutputStyle::dumpXmi() {
+ printHeader(P, "Cross Module Imports");
+ iterateModuleSubsections<DebugCrossModuleImportsSubsectionRef>(
+ File, P, 2,
+ [this](uint32_t Modi, StringsAndChecksumsPrinter &Strings,
+ DebugCrossModuleImportsSubsectionRef &Imports) {
+ P.formatLine("{0,=32} | {1}", "Imported Module", "Type IDs");
+
+ for (const auto &Xmi : Imports) {
+ auto ExpectedModule =
+ Strings.getNameFromStringTable(Xmi.Header->ModuleNameOffset);
+ StringRef Module;
+ SmallString<32> ModuleStorage;
+ if (!ExpectedModule) {
+ Module = "(unknown module)";
+ consumeError(ExpectedModule.takeError());
+ } else
+ Module = *ExpectedModule;
+ if (Module.size() > 32) {
+ ModuleStorage = "...";
+ ModuleStorage += Module.take_back(32 - 3);
+ Module = ModuleStorage;
+ }
+ std::vector<std::string> TIs;
+ for (const auto I : Xmi.Imports)
+ TIs.push_back(formatv("{0,+10:X+}", fmtle(I)));
+ std::string Result =
+ typesetItemList(TIs, P.getIndentLevel() + 35, 12, " ");
+ P.formatLine("{0,+32} | {1}", Module, Result);
+ }
+ });
+
+ return Error::success();
+}
+
+Error DumpOutputStyle::dumpXme() {
+ printHeader(P, "Cross Module Exports");
+
+ iterateModuleSubsections<DebugCrossModuleExportsSubsectionRef>(
+ File, P, 2,
+ [this](uint32_t Modi, StringsAndChecksumsPrinter &Strings,
+ DebugCrossModuleExportsSubsectionRef &Exports) {
+ P.formatLine("{0,-10} | {1}", "Local ID", "Global ID");
+ for (const auto &Export : Exports) {
+ P.formatLine("{0,+10:X+} | {1}", TypeIndex(Export.Local),
+ TypeIndex(Export.Global));
+ }
+ });
+
+ return Error::success();
+}
+
+Error DumpOutputStyle::dumpStringTable() {
+ printHeader(P, "String Table");
+
+ AutoIndent Indent(P);
+ auto IS = File.getStringTable();
+ if (!IS) {
+ P.formatLine("Not present in file");
+ consumeError(IS.takeError());
+ return Error::success();
+ }
+
+ if (IS->name_ids().empty()) {
+ P.formatLine("Empty");
+ return Error::success();
+ }
+
+ auto MaxID = std::max_element(IS->name_ids().begin(), IS->name_ids().end());
+ uint32_t Digits = NumDigits(*MaxID);
+
+ P.formatLine("{0} | {1}", fmt_align("ID", AlignStyle::Right, Digits),
+ "String");
+
+ std::vector<uint32_t> SortedIDs(IS->name_ids().begin(), IS->name_ids().end());
+ std::sort(SortedIDs.begin(), SortedIDs.end());
+ for (uint32_t I : SortedIDs) {
+ auto ES = IS->getStringForID(I);
+ llvm::SmallString<32> Str;
+ if (!ES) {
+ consumeError(ES.takeError());
+ Str = "Error reading string";
+ } else if (!ES->empty()) {
+ Str.append("'");
+ Str.append(*ES);
+ Str.append("'");
+ }
+
+ if (!Str.empty())
+ P.formatLine("{0} | {1}", fmt_align(I, AlignStyle::Right, Digits), Str);
+ }
+ return Error::success();
+}
+
+static void buildDepSet(LazyRandomTypeCollection &Types,
+ ArrayRef<TypeIndex> Indices,
+ std::map<TypeIndex, CVType> &DepSet) {
+ SmallVector<TypeIndex, 4> DepList;
+ for (const auto &I : Indices) {
+ TypeIndex TI(I);
+ if (DepSet.find(TI) != DepSet.end() || TI.isSimple() || TI.isNoneType())
+ continue;
+
+ CVType Type = Types.getType(TI);
+ DepSet[TI] = Type;
+ codeview::discoverTypeIndices(Type, DepList);
+ buildDepSet(Types, DepList, DepSet);
+ }
+}
+
+static void dumpFullTypeStream(LinePrinter &Printer,
+ LazyRandomTypeCollection &Types,
+ TpiStream &Stream, bool Bytes, bool Extras) {
+ Printer.formatLine("Showing {0:N} records", Stream.getNumTypeRecords());
+ uint32_t Width =
+ NumDigits(TypeIndex::FirstNonSimpleIndex + Stream.getNumTypeRecords());
+
+ MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types,
+ Stream.getNumHashBuckets(), Stream.getHashValues());
+
+ if (auto EC = codeview::visitTypeStream(Types, V)) {
+ Printer.formatLine("An error occurred dumping type records: {0}",
+ toString(std::move(EC)));
+ }
+}
+
+static void dumpPartialTypeStream(LinePrinter &Printer,
+ LazyRandomTypeCollection &Types,
+ TpiStream &Stream, ArrayRef<TypeIndex> TiList,
+ bool Bytes, bool Extras, bool Deps) {
+ uint32_t Width =
+ NumDigits(TypeIndex::FirstNonSimpleIndex + Stream.getNumTypeRecords());
+
+ MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types,
+ Stream.getNumHashBuckets(), Stream.getHashValues());
+
+ if (opts::dump::DumpTypeDependents) {
+ // If we need to dump all dependents, then iterate each index and find
+ // all dependents, adding them to a map ordered by TypeIndex.
+ std::map<TypeIndex, CVType> DepSet;
+ buildDepSet(Types, TiList, DepSet);
+
+ Printer.formatLine(
+ "Showing {0:N} records and their dependents ({1:N} records total)",
+ TiList.size(), DepSet.size());
+
+ for (auto &Dep : DepSet) {
+ if (auto EC = codeview::visitTypeRecord(Dep.second, Dep.first, V))
+ Printer.formatLine("An error occurred dumping type record {0}: {1}",
+ Dep.first, toString(std::move(EC)));
+ }
+ } else {
+ Printer.formatLine("Showing {0:N} records.", TiList.size());
+
+ for (const auto &I : TiList) {
+ TypeIndex TI(I);
+ CVType Type = Types.getType(TI);
+ if (auto EC = codeview::visitTypeRecord(Type, TI, V))
+ Printer.formatLine("An error occurred dumping type record {0}: {1}", TI,
+ toString(std::move(EC)));
+ }
+ }
+}
+
+Error DumpOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
+ assert(StreamIdx == StreamTPI || StreamIdx == StreamIPI);
+
+ bool Present = false;
+ bool DumpTypes = false;
+ bool DumpBytes = false;
+ bool DumpExtras = false;
+ std::vector<uint32_t> Indices;
+ if (StreamIdx == StreamTPI) {
+ printHeader(P, "Types (TPI Stream)");
+ Present = File.hasPDBTpiStream();
+ DumpTypes = opts::dump::DumpTypes;
+ DumpBytes = opts::dump::DumpTypeData;
+ DumpExtras = opts::dump::DumpTypeExtras;
+ Indices.assign(opts::dump::DumpTypeIndex.begin(),
+ opts::dump::DumpTypeIndex.end());
+ } else if (StreamIdx == StreamIPI) {
+ printHeader(P, "Types (IPI Stream)");
+ Present = File.hasPDBIpiStream();
+ DumpTypes = opts::dump::DumpIds;
+ DumpBytes = opts::dump::DumpIdData;
+ DumpExtras = opts::dump::DumpIdExtras;
+ Indices.assign(opts::dump::DumpIdIndex.begin(),
+ opts::dump::DumpIdIndex.end());
+ }
+
+ AutoIndent Indent(P);
+ if (!Present) {
+ P.formatLine("Stream not present");
+ return Error::success();
+ }
+
+ ExitOnError Err("Unexpected error processing types");
+
+ auto &Stream = Err((StreamIdx == StreamTPI) ? File.getPDBTpiStream()
+ : File.getPDBIpiStream());
+
+ auto &Types = Err(initializeTypes(StreamIdx));
+
+ if (DumpTypes || !Indices.empty()) {
+ if (Indices.empty())
+ dumpFullTypeStream(P, Types, Stream, DumpBytes, DumpExtras);
+ else {
+ std::vector<TypeIndex> TiList(Indices.begin(), Indices.end());
+ dumpPartialTypeStream(P, Types, Stream, TiList, DumpBytes, DumpExtras,
+ opts::dump::DumpTypeDependents);
+ }
+ }
+
+ if (DumpExtras) {
+ P.NewLine();
+ auto IndexOffsets = Stream.getTypeIndexOffsets();
+ P.formatLine("Type Index Offsets:");
+ for (const auto &IO : IndexOffsets) {
+ AutoIndent Indent2(P);
+ P.formatLine("TI: {0}, Offset: {1}", IO.Type, fmtle(IO.Offset));
+ }
+
+ P.NewLine();
+ P.formatLine("Hash Adjusters:");
+ auto &Adjusters = Stream.getHashAdjusters();
+ auto &Strings = Err(File.getStringTable());
+ for (const auto &A : Adjusters) {
+ AutoIndent Indent2(P);
+ auto ExpectedStr = Strings.getStringForID(A.first);
+ TypeIndex TI(A.second);
+ if (ExpectedStr)
+ P.formatLine("`{0}` -> {1}", *ExpectedStr, TI);
+ else {
+ P.formatLine("unknown str id ({0}) -> {1}", A.first, TI);
+ consumeError(ExpectedStr.takeError());
+ }
+ }
+ }
+ return Error::success();
+}
+
+Expected<codeview::LazyRandomTypeCollection &>
+DumpOutputStyle::initializeTypes(uint32_t SN) {
+ auto &TypeCollection = (SN == StreamTPI) ? TpiTypes : IpiTypes;
+ auto Tpi =
+ (SN == StreamTPI) ? File.getPDBTpiStream() : File.getPDBIpiStream();
+ if (!Tpi)
+ return Tpi.takeError();
+
+ if (!TypeCollection) {
+ auto &Types = Tpi->typeArray();
+ uint32_t Count = Tpi->getNumTypeRecords();
+ auto Offsets = Tpi->getTypeIndexOffsets();
+ TypeCollection =
+ llvm::make_unique<LazyRandomTypeCollection>(Types, Count, Offsets);
+ }
+
+ return *TypeCollection;
+}
+
+Error DumpOutputStyle::dumpModuleSyms() {
+ printHeader(P, "Symbols");
+
+ AutoIndent Indent(P);
+ if (!File.hasPDBDbiStream()) {
+ P.formatLine("DBI Stream not present");
+ return Error::success();
+ }
+
+ ExitOnError Err("Unexpected error processing symbols");
+
+ auto &Stream = Err(File.getPDBDbiStream());
+
+ auto &Types = Err(initializeTypes(StreamTPI));
+
+ const DbiModuleList &Modules = Stream.modules();
+ uint32_t Count = Modules.getModuleCount();
+ uint32_t Digits = NumDigits(Count);
+ for (uint32_t I = 0; I < Count; ++I) {
+ auto Modi = Modules.getModuleDescriptor(I);
+ P.formatLine("Mod {0:4} | `{1}`: ", fmt_align(I, AlignStyle::Right, Digits),
+ Modi.getModuleName());
+ uint16_t ModiStream = Modi.getModuleStreamIndex();
+ if (ModiStream == kInvalidStreamIndex) {
+ P.formatLine(" <symbols not present>");
+ continue;
+ }
+ auto ModStreamData = MappedBlockStream::createIndexedStream(
+ File.getMsfLayout(), File.getMsfBuffer(), ModiStream,
+ File.getAllocator());
+
+ ModuleDebugStreamRef ModS(Modi, std::move(ModStreamData));
+ if (auto EC = ModS.reload()) {
+ P.formatLine("Error loading module stream {0}. {1}", I,
+ toString(std::move(EC)));
+ continue;
+ }
+
+ SymbolVisitorCallbackPipeline Pipeline;
+ SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb);
+ MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Types);
+
+ Pipeline.addCallbackToPipeline(Deserializer);
+ Pipeline.addCallbackToPipeline(Dumper);
+ CVSymbolVisitor Visitor(Pipeline);
+ auto SS = ModS.getSymbolsSubstream();
+ if (auto EC = Visitor.visitSymbolStream(ModS.getSymbolArray(), SS.Offset)) {
+ P.formatLine("Error while processing symbol records. {0}",
+ toString(std::move(EC)));
+ continue;
+ }
+ }
+ return Error::success();
+}
+
+Error DumpOutputStyle::dumpPublics() {
+ printHeader(P, "Public Symbols");
+
+ AutoIndent Indent(P);
+ if (!File.hasPDBPublicsStream()) {
+ P.formatLine("Publics stream not present");
+ return Error::success();
+ }
+
+ ExitOnError Err("Error dumping publics stream");
+
+ auto &Types = Err(initializeTypes(StreamTPI));
+ auto &Publics = Err(File.getPDBPublicsStream());
+ SymbolVisitorCallbackPipeline Pipeline;
+ SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb);
+ MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Types);
+
+ Pipeline.addCallbackToPipeline(Deserializer);
+ Pipeline.addCallbackToPipeline(Dumper);
+ CVSymbolVisitor Visitor(Pipeline);
+
+ auto ExpectedSymbols = Publics.getSymbolArray();
+ if (!ExpectedSymbols) {
+ P.formatLine("Could not read public symbol record stream");
+ return Error::success();
+ }
+
+ if (auto EC = Visitor.visitSymbolStream(*ExpectedSymbols, 0))
+ P.formatLine("Error while processing public symbol records. {0}",
+ toString(std::move(EC)));
+
+ return Error::success();
+}
+
+static std::string formatSectionCharacteristics(uint32_t IndentLevel,
+ uint32_t C) {
+ using SC = COFF::SectionCharacteristics;
+ std::vector<std::string> Opts;
+ if (C == COFF::SC_Invalid)
+ return "invalid";
+ if (C == 0)
+ return "none";
+
+ PUSH_FLAG(SC, IMAGE_SCN_TYPE_NOLOAD, C, "IMAGE_SCN_TYPE_NOLOAD");
+ PUSH_FLAG(SC, IMAGE_SCN_TYPE_NO_PAD, C, "IMAGE_SCN_TYPE_NO_PAD");
+ PUSH_FLAG(SC, IMAGE_SCN_CNT_CODE, C, "IMAGE_SCN_CNT_CODE");
+ PUSH_FLAG(SC, IMAGE_SCN_CNT_INITIALIZED_DATA, C,
+ "IMAGE_SCN_CNT_INITIALIZED_DATA");
+ PUSH_FLAG(SC, IMAGE_SCN_CNT_UNINITIALIZED_DATA, C,
+ "IMAGE_SCN_CNT_UNINITIALIZED_DATA");
+ PUSH_FLAG(SC, IMAGE_SCN_LNK_OTHER, C, "IMAGE_SCN_LNK_OTHER");
+ PUSH_FLAG(SC, IMAGE_SCN_LNK_INFO, C, "IMAGE_SCN_LNK_INFO");
+ PUSH_FLAG(SC, IMAGE_SCN_LNK_REMOVE, C, "IMAGE_SCN_LNK_REMOVE");
+ PUSH_FLAG(SC, IMAGE_SCN_LNK_COMDAT, C, "IMAGE_SCN_LNK_COMDAT");
+ PUSH_FLAG(SC, IMAGE_SCN_GPREL, C, "IMAGE_SCN_GPREL");
+ PUSH_FLAG(SC, IMAGE_SCN_MEM_PURGEABLE, C, "IMAGE_SCN_MEM_PURGEABLE");
+ PUSH_FLAG(SC, IMAGE_SCN_MEM_16BIT, C, "IMAGE_SCN_MEM_16BIT");
+ PUSH_FLAG(SC, IMAGE_SCN_MEM_LOCKED, C, "IMAGE_SCN_MEM_LOCKED");
+ PUSH_FLAG(SC, IMAGE_SCN_MEM_PRELOAD, C, "IMAGE_SCN_MEM_PRELOAD");
+ PUSH_FLAG(SC, IMAGE_SCN_GPREL, C, "IMAGE_SCN_GPREL");
+ PUSH_FLAG(SC, IMAGE_SCN_GPREL, C, "IMAGE_SCN_GPREL");
+ PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_1BYTES, C,
+ "IMAGE_SCN_ALIGN_1BYTES");
+ PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_2BYTES, C,
+ "IMAGE_SCN_ALIGN_2BYTES");
+ PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_4BYTES, C,
+ "IMAGE_SCN_ALIGN_4BYTES");
+ PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_8BYTES, C,
+ "IMAGE_SCN_ALIGN_8BYTES");
+ PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_16BYTES, C,
+ "IMAGE_SCN_ALIGN_16BYTES");
+ PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_32BYTES, C,
+ "IMAGE_SCN_ALIGN_32BYTES");
+ PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_64BYTES, C,
+ "IMAGE_SCN_ALIGN_64BYTES");
+ PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_128BYTES, C,
+ "IMAGE_SCN_ALIGN_128BYTES");
+ PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_256BYTES, C,
+ "IMAGE_SCN_ALIGN_256BYTES");
+ PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_512BYTES, C,
+ "IMAGE_SCN_ALIGN_512BYTES");
+ PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_1024BYTES, C,
+ "IMAGE_SCN_ALIGN_1024BYTES");
+ PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_2048BYTES, C,
+ "IMAGE_SCN_ALIGN_2048BYTES");
+ PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_4096BYTES, C,
+ "IMAGE_SCN_ALIGN_4096BYTES");
+ PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_8192BYTES, C,
+ "IMAGE_SCN_ALIGN_8192BYTES");
+ PUSH_FLAG(SC, IMAGE_SCN_LNK_NRELOC_OVFL, C, "IMAGE_SCN_LNK_NRELOC_OVFL");
+ PUSH_FLAG(SC, IMAGE_SCN_MEM_DISCARDABLE, C, "IMAGE_SCN_MEM_DISCARDABLE");
+ PUSH_FLAG(SC, IMAGE_SCN_MEM_NOT_CACHED, C, "IMAGE_SCN_MEM_NOT_CACHED");
+ PUSH_FLAG(SC, IMAGE_SCN_MEM_NOT_PAGED, C, "IMAGE_SCN_MEM_NOT_PAGED");
+ PUSH_FLAG(SC, IMAGE_SCN_MEM_SHARED, C, "IMAGE_SCN_MEM_SHARED");
+ PUSH_FLAG(SC, IMAGE_SCN_MEM_EXECUTE, C, "IMAGE_SCN_MEM_EXECUTE");
+ PUSH_FLAG(SC, IMAGE_SCN_MEM_READ, C, "IMAGE_SCN_MEM_READ");
+ PUSH_FLAG(SC, IMAGE_SCN_MEM_WRITE, C, "IMAGE_SCN_MEM_WRITE");
+ return typesetItemList(Opts, IndentLevel, 3, " | ");
+}
+
+static std::string formatSegMapDescriptorFlag(uint32_t IndentLevel,
+ OMFSegDescFlags Flags) {
+ std::vector<std::string> Opts;
+ if (Flags == OMFSegDescFlags::None)
+ return "none";
+
+ PUSH_FLAG(OMFSegDescFlags, Read, Flags, "read");
+ PUSH_FLAG(OMFSegDescFlags, Write, Flags, "write");
+ PUSH_FLAG(OMFSegDescFlags, Execute, Flags, "execute");
+ PUSH_FLAG(OMFSegDescFlags, AddressIs32Bit, Flags, "32 bit addr");
+ PUSH_FLAG(OMFSegDescFlags, IsSelector, Flags, "selector");
+ PUSH_FLAG(OMFSegDescFlags, IsAbsoluteAddress, Flags, "absolute addr");
+ PUSH_FLAG(OMFSegDescFlags, IsGroup, Flags, "group");
+ return typesetItemList(Opts, IndentLevel, 4, " | ");
+}
+
+Error DumpOutputStyle::dumpSectionContribs() {
+ printHeader(P, "Section Contributions");
+ ExitOnError Err("Error dumping publics stream");
+
+ AutoIndent Indent(P);
+ if (!File.hasPDBDbiStream()) {
+ P.formatLine(
+ "Section contribs require a DBI Stream, which could not be loaded");
+ return Error::success();
+ }
+
+ auto &Dbi = Err(File.getPDBDbiStream());
+
+ class Visitor : public ISectionContribVisitor {
+ public:
+ Visitor(LinePrinter &P) : P(P) {}
+ void visit(const SectionContrib &SC) override {
+ P.formatLine(
+ "SC | mod = {2}, {0}, size = {1}, data crc = {3}, reloc crc = {4}",
+ formatSegmentOffset(SC.ISect, SC.Off), fmtle(SC.Size), fmtle(SC.Imod),
+ fmtle(SC.DataCrc), fmtle(SC.RelocCrc));
+ P.formatLine(" {0}",
+ formatSectionCharacteristics(P.getIndentLevel() + 6,
+ SC.Characteristics));
+ }
+ void visit(const SectionContrib2 &SC) override {
+ P.formatLine("SC2 | mod = {2}, {0}, size = {1}, data crc = {3}, reloc "
+ "crc = {4}, coff section = {5}",
+ formatSegmentOffset(SC.Base.ISect, SC.Base.Off),
+ fmtle(SC.Base.Size), fmtle(SC.Base.Imod),
+ fmtle(SC.Base.DataCrc), fmtle(SC.Base.RelocCrc),
+ fmtle(SC.ISectCoff));
+ P.formatLine(" {0}",
+ formatSectionCharacteristics(P.getIndentLevel() + 6,
+ SC.Base.Characteristics));
+ }
+
+ private:
+ LinePrinter &P;
+ };
+
+ Visitor V(P);
+ Dbi.visitSectionContributions(V);
+ return Error::success();
+}
+
+Error DumpOutputStyle::dumpSectionMap() {
+ printHeader(P, "Section Map");
+ ExitOnError Err("Error dumping section map");
+
+ AutoIndent Indent(P);
+ if (!File.hasPDBDbiStream()) {
+ P.formatLine("Dumping the section map requires a DBI Stream, which could "
+ "not be loaded");
+ return Error::success();
+ }
+
+ auto &Dbi = Err(File.getPDBDbiStream());
+
+ uint32_t I = 0;
+ for (auto &M : Dbi.getSectionMap()) {
+ P.formatLine(
+ "Section {0:4} | ovl = {0}, group = {1}, frame = {2}, name = {3}", I,
+ fmtle(M.Ovl), fmtle(M.Group), fmtle(M.Frame), fmtle(M.SecName));
+ P.formatLine(" class = {0}, offset = {1}, size = {2}",
+ fmtle(M.ClassName), fmtle(M.Offset), fmtle(M.SecByteLength));
+ P.formatLine(" flags = {0}",
+ formatSegMapDescriptorFlag(
+ P.getIndentLevel() + 13,
+ static_cast<OMFSegDescFlags>(uint16_t(M.Flags))));
+ ++I;
+ }
+ return Error::success();
+}
diff --git a/contrib/llvm/tools/llvm-pdbutil/DumpOutputStyle.h b/contrib/llvm/tools/llvm-pdbutil/DumpOutputStyle.h
new file mode 100644
index 0000000..4c52289
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/DumpOutputStyle.h
@@ -0,0 +1,62 @@
+//===- DumpOutputStyle.h -------------------------------------- *- 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_DUMPOUTPUTSTYLE_H
+#define LLVM_TOOLS_LLVMPDBDUMP_DUMPOUTPUTSTYLE_H
+
+#include "LinePrinter.h"
+#include "OutputStyle.h"
+
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallVector.h"
+
+#include <string>
+
+namespace llvm {
+class BitVector;
+
+namespace codeview {
+class LazyRandomTypeCollection;
+}
+
+namespace pdb {
+class DumpOutputStyle : public OutputStyle {
+public:
+ DumpOutputStyle(PDBFile &File);
+
+ Error dump() override;
+
+private:
+ Expected<codeview::LazyRandomTypeCollection &> initializeTypes(uint32_t SN);
+
+ Error dumpFileSummary();
+ Error dumpStreamSummary();
+ Error dumpStringTable();
+ Error dumpLines();
+ Error dumpInlineeLines();
+ Error dumpXmi();
+ Error dumpXme();
+ Error dumpTpiStream(uint32_t StreamIdx);
+ Error dumpModules();
+ Error dumpModuleFiles();
+ Error dumpModuleSyms();
+ Error dumpPublics();
+ Error dumpSectionContribs();
+ Error dumpSectionMap();
+
+ PDBFile &File;
+ LinePrinter P;
+ std::unique_ptr<codeview::LazyRandomTypeCollection> TpiTypes;
+ std::unique_ptr<codeview::LazyRandomTypeCollection> IpiTypes;
+ SmallVector<std::string, 32> StreamPurposes;
+};
+} // namespace pdb
+} // namespace llvm
+
+#endif
diff --git a/contrib/llvm/tools/llvm-pdbutil/FormatUtil.cpp b/contrib/llvm/tools/llvm-pdbutil/FormatUtil.cpp
new file mode 100644
index 0000000..0203027
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/FormatUtil.cpp
@@ -0,0 +1,101 @@
+//===- FormatUtil.cpp ----------------------------------------- *- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "FormatUtil.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/FormatAdapters.h"
+#include "llvm/Support/FormatVariadic.h"
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+std::string llvm::pdb::truncateStringBack(StringRef S, uint32_t MaxLen) {
+ if (MaxLen == 0 || S.size() <= MaxLen || S.size() <= 3)
+ return S;
+
+ assert(MaxLen >= 3);
+ uint32_t FinalLen = std::min<size_t>(S.size(), MaxLen - 3);
+ S = S.take_front(FinalLen);
+ return std::string(S) + std::string("...");
+}
+
+std::string llvm::pdb::truncateStringMiddle(StringRef S, uint32_t MaxLen) {
+ if (MaxLen == 0 || S.size() <= MaxLen || S.size() <= 3)
+ return S;
+
+ assert(MaxLen >= 3);
+ uint32_t FinalLen = std::min<size_t>(S.size(), MaxLen - 3);
+ StringRef Front = S.take_front(FinalLen / 2);
+ StringRef Back = S.take_back(Front.size());
+ return std::string(Front) + std::string("...") + std::string(Back);
+}
+
+std::string llvm::pdb::truncateStringFront(StringRef S, uint32_t MaxLen) {
+ if (MaxLen == 0 || S.size() <= MaxLen || S.size() <= 3)
+ return S;
+
+ assert(MaxLen >= 3);
+ S = S.take_back(MaxLen - 3);
+ return std::string("...") + std::string(S);
+}
+
+std::string llvm::pdb::truncateQuotedNameFront(StringRef Label, StringRef Name,
+ uint32_t MaxLen) {
+ uint32_t RequiredExtraChars = Label.size() + 1 + 2;
+ if (MaxLen == 0 || RequiredExtraChars + Name.size() <= MaxLen)
+ return formatv("{0} \"{1}\"", Label, Name).str();
+
+ assert(MaxLen >= RequiredExtraChars);
+ std::string TN = truncateStringFront(Name, MaxLen - RequiredExtraChars);
+ return formatv("{0} \"{1}\"", Label, TN).str();
+}
+
+std::string llvm::pdb::truncateQuotedNameBack(StringRef Label, StringRef Name,
+ uint32_t MaxLen) {
+ uint32_t RequiredExtraChars = Label.size() + 1 + 2;
+ if (MaxLen == 0 || RequiredExtraChars + Name.size() <= MaxLen)
+ return formatv("{0} \"{1}\"", Label, Name).str();
+
+ assert(MaxLen >= RequiredExtraChars);
+ std::string TN = truncateStringBack(Name, MaxLen - RequiredExtraChars);
+ return formatv("{0} \"{1}\"", Label, TN).str();
+}
+
+std::string llvm::pdb::typesetItemList(ArrayRef<std::string> Opts,
+ uint32_t IndentLevel, uint32_t GroupSize,
+ StringRef Sep) {
+ std::string Result;
+ while (!Opts.empty()) {
+ ArrayRef<std::string> ThisGroup;
+ ThisGroup = Opts.take_front(GroupSize);
+ Opts = Opts.drop_front(ThisGroup.size());
+ Result += join(ThisGroup, Sep);
+ if (!Opts.empty()) {
+ Result += Sep;
+ Result += "\n";
+ Result += formatv("{0}", fmt_repeat(' ', IndentLevel));
+ }
+ }
+ return Result;
+}
+
+std::string llvm::pdb::typesetStringList(uint32_t IndentLevel,
+ ArrayRef<StringRef> Strings) {
+ std::string Result = "[";
+ for (const auto &S : Strings) {
+ Result += formatv("\n{0}{1}", fmt_repeat(' ', IndentLevel), S);
+ }
+ Result += "]";
+ return Result;
+}
+
+std::string llvm::pdb::formatSegmentOffset(uint16_t Segment, uint32_t Offset) {
+ return formatv("{0:4}:{1:4}", Segment, Offset);
+}
diff --git a/contrib/llvm/tools/llvm-pdbutil/FormatUtil.h b/contrib/llvm/tools/llvm-pdbutil/FormatUtil.h
new file mode 100644
index 0000000..df32ed9
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/FormatUtil.h
@@ -0,0 +1,128 @@
+//===- FormatUtil.h ------------------------------------------- *- 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_LLVMPDBUTIL_FORMAT_UTIL_H
+#define LLVM_TOOLS_LLVMPDBUTIL_FORMAT_UTIL_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/FormatAdapters.h"
+#include "llvm/Support/FormatVariadic.h"
+
+#include <string>
+#include <type_traits>
+
+namespace llvm {
+namespace pdb {
+
+std::string truncateStringBack(StringRef S, uint32_t MaxLen);
+std::string truncateStringMiddle(StringRef S, uint32_t MaxLen);
+std::string truncateStringFront(StringRef S, uint32_t MaxLen);
+std::string truncateQuotedNameFront(StringRef Label, StringRef Name,
+ uint32_t MaxLen);
+std::string truncateQuotedNameBack(StringRef Label, StringRef Name,
+ uint32_t MaxLen);
+
+#define PUSH_MASKED_FLAG(Enum, Mask, TheOpt, Value, Text) \
+ if (Enum::TheOpt == (Value & Mask)) \
+ Opts.push_back(Text);
+
+#define PUSH_FLAG(Enum, TheOpt, Value, Text) \
+ PUSH_MASKED_FLAG(Enum, Enum::TheOpt, TheOpt, Value, Text)
+
+#define RETURN_CASE(Enum, X, Ret) \
+ case Enum::X: \
+ return Ret;
+
+template <typename T> std::string formatUnknownEnum(T Value) {
+ return formatv("unknown ({0})",
+ static_cast<typename std::underlying_type<T>::type>(Value))
+ .str();
+}
+
+std::string formatSegmentOffset(uint16_t Segment, uint32_t Offset);
+
+std::string typesetItemList(ArrayRef<std::string> Opts, uint32_t IndentLevel,
+ uint32_t GroupSize, StringRef Sep);
+
+std::string typesetStringList(uint32_t IndentLevel,
+ ArrayRef<StringRef> Strings);
+
+/// Returns the number of digits in the given integer.
+inline int NumDigits(uint64_t N) {
+ if (N < 10ULL)
+ return 1;
+ if (N < 100ULL)
+ return 2;
+ if (N < 1000ULL)
+ return 3;
+ if (N < 10000ULL)
+ return 4;
+ if (N < 100000ULL)
+ return 5;
+ if (N < 1000000ULL)
+ return 6;
+ if (N < 10000000ULL)
+ return 7;
+ if (N < 100000000ULL)
+ return 8;
+ if (N < 1000000000ULL)
+ return 9;
+ if (N < 10000000000ULL)
+ return 10;
+ if (N < 100000000000ULL)
+ return 11;
+ if (N < 1000000000000ULL)
+ return 12;
+ if (N < 10000000000000ULL)
+ return 13;
+ if (N < 100000000000000ULL)
+ return 14;
+ if (N < 1000000000000000ULL)
+ return 15;
+ if (N < 10000000000000000ULL)
+ return 16;
+ if (N < 100000000000000000ULL)
+ return 17;
+ if (N < 1000000000000000000ULL)
+ return 18;
+ if (N < 10000000000000000000ULL)
+ return 19;
+ return 20;
+}
+
+namespace detail {
+template <typename T>
+struct EndianAdapter final
+ : public FormatAdapter<support::detail::packed_endian_specific_integral<
+ T, support::little, support::unaligned>> {
+ using EndianType =
+ support::detail::packed_endian_specific_integral<T, support::little,
+ support::unaligned>;
+
+ explicit EndianAdapter(EndianType &&Item)
+ : FormatAdapter<EndianType>(std::move(Item)) {}
+
+ void format(llvm::raw_ostream &Stream, StringRef Style) {
+ format_provider<T>::format(static_cast<T>(this->Item), Stream, Style);
+ }
+};
+} // namespace detail
+
+template <typename T>
+detail::EndianAdapter<T>
+fmtle(support::detail::packed_endian_specific_integral<T, support::little,
+ support::unaligned>
+ Value) {
+ return detail::EndianAdapter<T>(std::move(Value));
+}
+}
+} // namespace llvm
+#endif
diff --git a/contrib/llvm/tools/llvm-pdbutil/LinePrinter.cpp b/contrib/llvm/tools/llvm-pdbutil/LinePrinter.cpp
new file mode 100644
index 0000000..6e4d95a
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/LinePrinter.cpp
@@ -0,0 +1,312 @@
+//===- LinePrinter.cpp ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "LinePrinter.h"
+
+#include "llvm-pdbutil.h"
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/DebugInfo/MSF/MSFCommon.h"
+#include "llvm/DebugInfo/MSF/MSFStreamLayout.h"
+#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/UDTLayout.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/FormatAdapters.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/Regex.h"
+
+#include <algorithm>
+
+using namespace llvm;
+using namespace llvm::msf;
+using namespace llvm::pdb;
+
+namespace {
+bool IsItemExcluded(llvm::StringRef Item,
+ std::list<llvm::Regex> &IncludeFilters,
+ std::list<llvm::Regex> &ExcludeFilters) {
+ if (Item.empty())
+ return false;
+
+ auto match_pred = [Item](llvm::Regex &R) { return R.match(Item); };
+
+ // Include takes priority over exclude. If the user specified include
+ // filters, and none of them include this item, them item is gone.
+ if (!IncludeFilters.empty() && !any_of(IncludeFilters, match_pred))
+ return true;
+
+ if (any_of(ExcludeFilters, match_pred))
+ return true;
+
+ return false;
+}
+}
+
+using namespace llvm;
+
+LinePrinter::LinePrinter(int Indent, bool UseColor, llvm::raw_ostream &Stream)
+ : OS(Stream), IndentSpaces(Indent), CurrentIndent(0), UseColor(UseColor) {
+ SetFilters(ExcludeTypeFilters, opts::pretty::ExcludeTypes.begin(),
+ opts::pretty::ExcludeTypes.end());
+ SetFilters(ExcludeSymbolFilters, opts::pretty::ExcludeSymbols.begin(),
+ opts::pretty::ExcludeSymbols.end());
+ SetFilters(ExcludeCompilandFilters, opts::pretty::ExcludeCompilands.begin(),
+ opts::pretty::ExcludeCompilands.end());
+
+ SetFilters(IncludeTypeFilters, opts::pretty::IncludeTypes.begin(),
+ opts::pretty::IncludeTypes.end());
+ SetFilters(IncludeSymbolFilters, opts::pretty::IncludeSymbols.begin(),
+ opts::pretty::IncludeSymbols.end());
+ SetFilters(IncludeCompilandFilters, opts::pretty::IncludeCompilands.begin(),
+ opts::pretty::IncludeCompilands.end());
+}
+
+void LinePrinter::Indent(uint32_t Amount) {
+ if (Amount == 0)
+ Amount = IndentSpaces;
+ CurrentIndent += Amount;
+}
+
+void LinePrinter::Unindent(uint32_t Amount) {
+ if (Amount == 0)
+ Amount = IndentSpaces;
+ CurrentIndent = std::max<int>(0, CurrentIndent - Amount);
+}
+
+void LinePrinter::NewLine() {
+ OS << "\n";
+ OS.indent(CurrentIndent);
+}
+
+void LinePrinter::print(const Twine &T) { OS << T; }
+
+void LinePrinter::printLine(const Twine &T) {
+ NewLine();
+ OS << T;
+}
+
+bool LinePrinter::IsClassExcluded(const ClassLayout &Class) {
+ if (IsTypeExcluded(Class.getName(), Class.getSize()))
+ return true;
+ if (Class.deepPaddingSize() < opts::pretty::PaddingThreshold)
+ return true;
+ return false;
+}
+
+void LinePrinter::formatBinary(StringRef Label, ArrayRef<uint8_t> Data,
+ uint32_t StartOffset) {
+ NewLine();
+ OS << Label << " (";
+ if (!Data.empty()) {
+ OS << "\n";
+ OS << format_bytes_with_ascii(Data, StartOffset, 32, 4,
+ CurrentIndent + IndentSpaces, true);
+ NewLine();
+ }
+ OS << ")";
+}
+
+void LinePrinter::formatBinary(StringRef Label, ArrayRef<uint8_t> Data,
+ uint64_t Base, uint32_t StartOffset) {
+ NewLine();
+ OS << Label << " (";
+ if (!Data.empty()) {
+ OS << "\n";
+ Base += StartOffset;
+ OS << format_bytes_with_ascii(Data, Base, 32, 4,
+ CurrentIndent + IndentSpaces, true);
+ NewLine();
+ }
+ OS << ")";
+}
+
+namespace {
+struct Run {
+ Run() = default;
+ explicit Run(uint32_t Block) : Block(Block) {}
+ uint32_t Block = 0;
+ uint32_t ByteLen = 0;
+};
+} // namespace
+
+static std::vector<Run> computeBlockRuns(uint32_t BlockSize,
+ const msf::MSFStreamLayout &Layout) {
+ std::vector<Run> Runs;
+ if (Layout.Length == 0)
+ return Runs;
+
+ ArrayRef<support::ulittle32_t> Blocks = Layout.Blocks;
+ assert(!Blocks.empty());
+ uint32_t StreamBytesRemaining = Layout.Length;
+ uint32_t CurrentBlock = Blocks[0];
+ Runs.emplace_back(CurrentBlock);
+ while (!Blocks.empty()) {
+ Run *CurrentRun = &Runs.back();
+ uint32_t NextBlock = Blocks.front();
+ if (NextBlock < CurrentBlock || (NextBlock - CurrentBlock > 1)) {
+ Runs.emplace_back(NextBlock);
+ CurrentRun = &Runs.back();
+ }
+ uint32_t Used = std::min(BlockSize, StreamBytesRemaining);
+ CurrentRun->ByteLen += Used;
+ StreamBytesRemaining -= Used;
+ CurrentBlock = NextBlock;
+ Blocks = Blocks.drop_front();
+ }
+ return Runs;
+}
+
+static std::pair<Run, uint32_t> findRun(uint32_t Offset, ArrayRef<Run> Runs) {
+ for (const auto &R : Runs) {
+ if (Offset < R.ByteLen)
+ return std::make_pair(R, Offset);
+ Offset -= R.ByteLen;
+ }
+ llvm_unreachable("Invalid offset!");
+}
+
+void LinePrinter::formatMsfStreamData(StringRef Label, PDBFile &File,
+ uint32_t StreamIdx,
+ StringRef StreamPurpose, uint32_t Offset,
+ uint32_t Size) {
+ if (StreamIdx >= File.getNumStreams()) {
+ formatLine("Stream {0}: Not present", StreamIdx);
+ return;
+ }
+ if (Size + Offset > File.getStreamByteSize(StreamIdx)) {
+ formatLine(
+ "Stream {0}: Invalid offset and size, range out of stream bounds",
+ StreamIdx);
+ return;
+ }
+
+ auto S = MappedBlockStream::createIndexedStream(
+ File.getMsfLayout(), File.getMsfBuffer(), StreamIdx, File.getAllocator());
+ if (!S) {
+ NewLine();
+ formatLine("Stream {0}: Not present", StreamIdx);
+ return;
+ }
+
+ uint32_t End =
+ (Size == 0) ? S->getLength() : std::min(Offset + Size, S->getLength());
+ Size = End - Offset;
+
+ formatLine("Stream {0}: {1} (dumping {2:N} / {3:N} bytes)", StreamIdx,
+ StreamPurpose, Size, S->getLength());
+ AutoIndent Indent(*this);
+ BinaryStreamRef Slice(*S);
+ BinarySubstreamRef Substream;
+ Substream.Offset = Offset;
+ Substream.StreamData = Slice.drop_front(Offset).keep_front(Size);
+
+ auto Layout = File.getStreamLayout(StreamIdx);
+ formatMsfStreamData(Label, File, Layout, Substream);
+}
+
+void LinePrinter::formatMsfStreamData(StringRef Label, PDBFile &File,
+ const msf::MSFStreamLayout &Stream,
+ BinarySubstreamRef Substream) {
+ BinaryStreamReader Reader(Substream.StreamData);
+
+ auto Runs = computeBlockRuns(File.getBlockSize(), Stream);
+
+ NewLine();
+ OS << Label << " (";
+ while (Reader.bytesRemaining() > 0) {
+ OS << "\n";
+
+ Run FoundRun;
+ uint32_t RunOffset;
+ std::tie(FoundRun, RunOffset) = findRun(Substream.Offset, Runs);
+ assert(FoundRun.ByteLen >= RunOffset);
+ uint32_t Len = FoundRun.ByteLen - RunOffset;
+ Len = std::min(Len, Reader.bytesRemaining());
+ uint64_t Base = FoundRun.Block * File.getBlockSize() + RunOffset;
+ ArrayRef<uint8_t> Data;
+ consumeError(Reader.readBytes(Data, Len));
+ OS << format_bytes_with_ascii(Data, Base, 32, 4,
+ CurrentIndent + IndentSpaces, true);
+ if (Reader.bytesRemaining() > 0) {
+ NewLine();
+ OS << formatv(" {0}",
+ fmt_align("<discontinuity>", AlignStyle::Center, 114, '-'));
+ }
+ Substream.Offset += Len;
+ }
+ NewLine();
+ OS << ")";
+}
+
+bool LinePrinter::IsTypeExcluded(llvm::StringRef TypeName, uint32_t Size) {
+ if (IsItemExcluded(TypeName, IncludeTypeFilters, ExcludeTypeFilters))
+ return true;
+ if (Size < opts::pretty::SizeThreshold)
+ return true;
+ return false;
+}
+
+bool LinePrinter::IsSymbolExcluded(llvm::StringRef SymbolName) {
+ return IsItemExcluded(SymbolName, IncludeSymbolFilters, ExcludeSymbolFilters);
+}
+
+bool LinePrinter::IsCompilandExcluded(llvm::StringRef CompilandName) {
+ return IsItemExcluded(CompilandName, IncludeCompilandFilters,
+ ExcludeCompilandFilters);
+}
+
+WithColor::WithColor(LinePrinter &P, PDB_ColorItem C)
+ : OS(P.OS), UseColor(P.hasColor()) {
+ if (UseColor)
+ applyColor(C);
+}
+
+WithColor::~WithColor() {
+ if (UseColor)
+ OS.resetColor();
+}
+
+void WithColor::applyColor(PDB_ColorItem C) {
+ switch (C) {
+ case PDB_ColorItem::None:
+ OS.resetColor();
+ return;
+ case PDB_ColorItem::Comment:
+ OS.changeColor(raw_ostream::GREEN, false);
+ return;
+ case PDB_ColorItem::Address:
+ OS.changeColor(raw_ostream::YELLOW, /*bold=*/true);
+ return;
+ case PDB_ColorItem::Keyword:
+ OS.changeColor(raw_ostream::MAGENTA, true);
+ return;
+ case PDB_ColorItem::Register:
+ case PDB_ColorItem::Offset:
+ OS.changeColor(raw_ostream::YELLOW, false);
+ return;
+ case PDB_ColorItem::Type:
+ OS.changeColor(raw_ostream::CYAN, true);
+ return;
+ case PDB_ColorItem::Identifier:
+ OS.changeColor(raw_ostream::CYAN, false);
+ return;
+ case PDB_ColorItem::Path:
+ OS.changeColor(raw_ostream::CYAN, false);
+ return;
+ case PDB_ColorItem::Padding:
+ case PDB_ColorItem::SectionHeader:
+ OS.changeColor(raw_ostream::RED, true);
+ return;
+ case PDB_ColorItem::LiteralValue:
+ OS.changeColor(raw_ostream::GREEN, true);
+ return;
+ }
+}
diff --git a/contrib/llvm/tools/llvm-pdbutil/LinePrinter.h b/contrib/llvm/tools/llvm-pdbutil/LinePrinter.h
new file mode 100644
index 0000000..68ce321
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/LinePrinter.h
@@ -0,0 +1,142 @@
+//===- LinePrinter.h ------------------------------------------ *- 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_LINEPRINTER_H
+#define LLVM_TOOLS_LLVMPDBDUMP_LINEPRINTER_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/BinaryStreamRef.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/Regex.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <list>
+
+namespace llvm {
+class BinaryStreamReader;
+namespace msf {
+class MSFStreamLayout;
+} // namespace msf
+namespace pdb {
+
+class ClassLayout;
+class PDBFile;
+
+class LinePrinter {
+ friend class WithColor;
+
+public:
+ LinePrinter(int Indent, bool UseColor, raw_ostream &Stream);
+
+ void Indent(uint32_t Amount = 0);
+ void Unindent(uint32_t Amount = 0);
+ void NewLine();
+
+ void printLine(const Twine &T);
+ void print(const Twine &T);
+ template <typename... Ts> void formatLine(const char *Fmt, Ts &&... Items) {
+ printLine(formatv(Fmt, std::forward<Ts>(Items)...));
+ }
+ template <typename... Ts> void format(const char *Fmt, Ts &&... Items) {
+ print(formatv(Fmt, std::forward<Ts>(Items)...));
+ }
+
+ void formatBinary(StringRef Label, ArrayRef<uint8_t> Data,
+ uint32_t StartOffset);
+ void formatBinary(StringRef Label, ArrayRef<uint8_t> Data, uint64_t BaseAddr,
+ uint32_t StartOffset);
+
+ void formatMsfStreamData(StringRef Label, PDBFile &File, uint32_t StreamIdx,
+ StringRef StreamPurpose, uint32_t Offset,
+ uint32_t Size);
+ void formatMsfStreamData(StringRef Label, PDBFile &File,
+ const msf::MSFStreamLayout &Stream,
+ BinarySubstreamRef Substream);
+
+ bool hasColor() const { return UseColor; }
+ raw_ostream &getStream() { return OS; }
+ int getIndentLevel() const { return CurrentIndent; }
+
+ bool IsClassExcluded(const ClassLayout &Class);
+ bool IsTypeExcluded(llvm::StringRef TypeName, uint32_t Size);
+ bool IsSymbolExcluded(llvm::StringRef SymbolName);
+ bool IsCompilandExcluded(llvm::StringRef CompilandName);
+
+private:
+ template <typename Iter>
+ void SetFilters(std::list<Regex> &List, Iter Begin, Iter End) {
+ List.clear();
+ for (; Begin != End; ++Begin)
+ List.emplace_back(StringRef(*Begin));
+ }
+
+ raw_ostream &OS;
+ int IndentSpaces;
+ int CurrentIndent;
+ bool UseColor;
+
+ std::list<Regex> ExcludeCompilandFilters;
+ std::list<Regex> ExcludeTypeFilters;
+ std::list<Regex> ExcludeSymbolFilters;
+
+ std::list<Regex> IncludeCompilandFilters;
+ std::list<Regex> IncludeTypeFilters;
+ std::list<Regex> IncludeSymbolFilters;
+};
+
+struct AutoIndent {
+ explicit AutoIndent(LinePrinter &L, uint32_t Amount = 0)
+ : L(L), Amount(Amount) {
+ L.Indent(Amount);
+ }
+ ~AutoIndent() { L.Unindent(Amount); }
+
+ LinePrinter &L;
+ uint32_t Amount = 0;
+};
+
+template <class T>
+inline raw_ostream &operator<<(LinePrinter &Printer, const T &Item) {
+ Printer.getStream() << Item;
+ return Printer.getStream();
+}
+
+enum class PDB_ColorItem {
+ None,
+ Address,
+ Type,
+ Comment,
+ Padding,
+ Keyword,
+ Offset,
+ Identifier,
+ Path,
+ SectionHeader,
+ LiteralValue,
+ Register,
+};
+
+class WithColor {
+public:
+ WithColor(LinePrinter &P, PDB_ColorItem C);
+ ~WithColor();
+
+ raw_ostream &get() { return OS; }
+
+private:
+ void applyColor(PDB_ColorItem C);
+ raw_ostream &OS;
+ bool UseColor;
+};
+}
+}
+
+#endif
diff --git a/contrib/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.cpp b/contrib/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.cpp
new file mode 100644
index 0000000..d938436
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.cpp
@@ -0,0 +1,772 @@
+//===- MinimalSymbolDumper.cpp -------------------------------- *- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MinimalSymbolDumper.h"
+
+#include "FormatUtil.h"
+#include "LinePrinter.h"
+
+#include "llvm/DebugInfo/CodeView/CVRecord.h"
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/Formatters.h"
+#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
+#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/Support/FormatVariadic.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+static StringRef getSymbolKindName(SymbolKind K) {
+ switch (K) {
+#define SYMBOL_RECORD(EnumName, value, name) \
+ case EnumName: \
+ return #EnumName;
+#include "llvm/DebugInfo/CodeView/CodeViewSymbols.def"
+ default:
+ llvm_unreachable("Unknown symbol kind!");
+ }
+ return "";
+}
+
+static std::string formatLocalSymFlags(uint32_t IndentLevel,
+ LocalSymFlags Flags) {
+ std::vector<std::string> Opts;
+ if (Flags == LocalSymFlags::None)
+ return "none";
+
+ PUSH_FLAG(LocalSymFlags, IsParameter, Flags, "param");
+ PUSH_FLAG(LocalSymFlags, IsAddressTaken, Flags, "address is taken");
+ PUSH_FLAG(LocalSymFlags, IsCompilerGenerated, Flags, "compiler generated");
+ PUSH_FLAG(LocalSymFlags, IsAggregate, Flags, "aggregate");
+ PUSH_FLAG(LocalSymFlags, IsAggregated, Flags, "aggregated");
+ PUSH_FLAG(LocalSymFlags, IsAliased, Flags, "aliased");
+ PUSH_FLAG(LocalSymFlags, IsAlias, Flags, "alias");
+ PUSH_FLAG(LocalSymFlags, IsReturnValue, Flags, "return val");
+ PUSH_FLAG(LocalSymFlags, IsOptimizedOut, Flags, "optimized away");
+ PUSH_FLAG(LocalSymFlags, IsEnregisteredGlobal, Flags, "enreg global");
+ PUSH_FLAG(LocalSymFlags, IsEnregisteredStatic, Flags, "enreg static");
+ return typesetItemList(Opts, 4, IndentLevel, " | ");
+}
+
+static std::string formatExportFlags(uint32_t IndentLevel, ExportFlags Flags) {
+ std::vector<std::string> Opts;
+ if (Flags == ExportFlags::None)
+ return "none";
+
+ PUSH_FLAG(ExportFlags, IsConstant, Flags, "constant");
+ PUSH_FLAG(ExportFlags, IsData, Flags, "data");
+ PUSH_FLAG(ExportFlags, IsPrivate, Flags, "private");
+ PUSH_FLAG(ExportFlags, HasNoName, Flags, "no name");
+ PUSH_FLAG(ExportFlags, HasExplicitOrdinal, Flags, "explicit ord");
+ PUSH_FLAG(ExportFlags, IsForwarder, Flags, "forwarder");
+
+ return typesetItemList(Opts, 4, IndentLevel, " | ");
+}
+
+static std::string formatCompileSym2Flags(uint32_t IndentLevel,
+ CompileSym2Flags Flags) {
+ std::vector<std::string> Opts;
+ Flags &= ~CompileSym2Flags::SourceLanguageMask;
+ if (Flags == CompileSym2Flags::None)
+ return "none";
+
+ PUSH_FLAG(CompileSym2Flags, EC, Flags, "edit and continue");
+ PUSH_FLAG(CompileSym2Flags, NoDbgInfo, Flags, "no dbg info");
+ PUSH_FLAG(CompileSym2Flags, LTCG, Flags, "ltcg");
+ PUSH_FLAG(CompileSym2Flags, NoDataAlign, Flags, "no data align");
+ PUSH_FLAG(CompileSym2Flags, ManagedPresent, Flags, "has managed code");
+ PUSH_FLAG(CompileSym2Flags, SecurityChecks, Flags, "security checks");
+ PUSH_FLAG(CompileSym2Flags, HotPatch, Flags, "hot patchable");
+ PUSH_FLAG(CompileSym2Flags, CVTCIL, Flags, "cvtcil");
+ PUSH_FLAG(CompileSym2Flags, MSILModule, Flags, "msil module");
+ return typesetItemList(Opts, 4, IndentLevel, " | ");
+}
+
+static std::string formatCompileSym3Flags(uint32_t IndentLevel,
+ CompileSym3Flags Flags) {
+ std::vector<std::string> Opts;
+ Flags &= ~CompileSym3Flags::SourceLanguageMask;
+
+ if (Flags == CompileSym3Flags::None)
+ return "none";
+
+ PUSH_FLAG(CompileSym3Flags, EC, Flags, "edit and continue");
+ PUSH_FLAG(CompileSym3Flags, NoDbgInfo, Flags, "no dbg info");
+ PUSH_FLAG(CompileSym3Flags, LTCG, Flags, "ltcg");
+ PUSH_FLAG(CompileSym3Flags, NoDataAlign, Flags, "no data align");
+ PUSH_FLAG(CompileSym3Flags, ManagedPresent, Flags, "has managed code");
+ PUSH_FLAG(CompileSym3Flags, SecurityChecks, Flags, "security checks");
+ PUSH_FLAG(CompileSym3Flags, HotPatch, Flags, "hot patchable");
+ PUSH_FLAG(CompileSym3Flags, CVTCIL, Flags, "cvtcil");
+ PUSH_FLAG(CompileSym3Flags, MSILModule, Flags, "msil module");
+ PUSH_FLAG(CompileSym3Flags, Sdl, Flags, "sdl");
+ PUSH_FLAG(CompileSym3Flags, PGO, Flags, "pgo");
+ PUSH_FLAG(CompileSym3Flags, Exp, Flags, "exp");
+ return typesetItemList(Opts, 4, IndentLevel, " | ");
+}
+
+static std::string formatFrameProcedureOptions(uint32_t IndentLevel,
+ FrameProcedureOptions FPO) {
+ std::vector<std::string> Opts;
+ if (FPO == FrameProcedureOptions::None)
+ return "none";
+
+ PUSH_FLAG(FrameProcedureOptions, HasAlloca, FPO, "has alloca");
+ PUSH_FLAG(FrameProcedureOptions, HasSetJmp, FPO, "has setjmp");
+ PUSH_FLAG(FrameProcedureOptions, HasLongJmp, FPO, "has longjmp");
+ PUSH_FLAG(FrameProcedureOptions, HasInlineAssembly, FPO, "has inline asm");
+ PUSH_FLAG(FrameProcedureOptions, HasExceptionHandling, FPO, "has eh");
+ PUSH_FLAG(FrameProcedureOptions, MarkedInline, FPO, "marked inline");
+ PUSH_FLAG(FrameProcedureOptions, HasStructuredExceptionHandling, FPO,
+ "has seh");
+ PUSH_FLAG(FrameProcedureOptions, Naked, FPO, "naked");
+ PUSH_FLAG(FrameProcedureOptions, SecurityChecks, FPO, "secure checks");
+ PUSH_FLAG(FrameProcedureOptions, AsynchronousExceptionHandling, FPO,
+ "has async eh");
+ PUSH_FLAG(FrameProcedureOptions, NoStackOrderingForSecurityChecks, FPO,
+ "no stack order");
+ PUSH_FLAG(FrameProcedureOptions, Inlined, FPO, "inlined");
+ PUSH_FLAG(FrameProcedureOptions, StrictSecurityChecks, FPO,
+ "strict secure checks");
+ PUSH_FLAG(FrameProcedureOptions, SafeBuffers, FPO, "safe buffers");
+ PUSH_FLAG(FrameProcedureOptions, ProfileGuidedOptimization, FPO, "pgo");
+ PUSH_FLAG(FrameProcedureOptions, ValidProfileCounts, FPO,
+ "has profile counts");
+ PUSH_FLAG(FrameProcedureOptions, OptimizedForSpeed, FPO, "opt speed");
+ PUSH_FLAG(FrameProcedureOptions, GuardCfg, FPO, "guard cfg");
+ PUSH_FLAG(FrameProcedureOptions, GuardCfw, FPO, "guard cfw");
+ return typesetItemList(Opts, 4, IndentLevel, " | ");
+}
+
+static std::string formatPublicSymFlags(uint32_t IndentLevel,
+ PublicSymFlags Flags) {
+ std::vector<std::string> Opts;
+ if (Flags == PublicSymFlags::None)
+ return "none";
+
+ PUSH_FLAG(PublicSymFlags, Code, Flags, "code");
+ PUSH_FLAG(PublicSymFlags, Function, Flags, "function");
+ PUSH_FLAG(PublicSymFlags, Managed, Flags, "managed");
+ PUSH_FLAG(PublicSymFlags, MSIL, Flags, "msil");
+ return typesetItemList(Opts, 4, IndentLevel, " | ");
+}
+
+static std::string formatProcSymFlags(uint32_t IndentLevel,
+ ProcSymFlags Flags) {
+ std::vector<std::string> Opts;
+ if (Flags == ProcSymFlags::None)
+ return "none";
+
+ PUSH_FLAG(ProcSymFlags, HasFP, Flags, "has fp");
+ PUSH_FLAG(ProcSymFlags, HasIRET, Flags, "has iret");
+ PUSH_FLAG(ProcSymFlags, HasFRET, Flags, "has fret");
+ PUSH_FLAG(ProcSymFlags, IsNoReturn, Flags, "noreturn");
+ PUSH_FLAG(ProcSymFlags, IsUnreachable, Flags, "unreachable");
+ PUSH_FLAG(ProcSymFlags, HasCustomCallingConv, Flags, "custom calling conv");
+ PUSH_FLAG(ProcSymFlags, IsNoInline, Flags, "noinline");
+ PUSH_FLAG(ProcSymFlags, HasOptimizedDebugInfo, Flags, "opt debuginfo");
+ return typesetItemList(Opts, 4, IndentLevel, " | ");
+}
+
+static std::string formatThunkOrdinal(ThunkOrdinal Ordinal) {
+ switch (Ordinal) {
+ RETURN_CASE(ThunkOrdinal, Standard, "thunk");
+ RETURN_CASE(ThunkOrdinal, ThisAdjustor, "this adjustor");
+ RETURN_CASE(ThunkOrdinal, Vcall, "vcall");
+ RETURN_CASE(ThunkOrdinal, Pcode, "pcode");
+ RETURN_CASE(ThunkOrdinal, UnknownLoad, "unknown load");
+ RETURN_CASE(ThunkOrdinal, TrampIncremental, "tramp incremental");
+ RETURN_CASE(ThunkOrdinal, BranchIsland, "branch island");
+ }
+ return formatUnknownEnum(Ordinal);
+}
+
+static std::string formatTrampolineType(TrampolineType Tramp) {
+ switch (Tramp) {
+ RETURN_CASE(TrampolineType, TrampIncremental, "tramp incremental");
+ RETURN_CASE(TrampolineType, BranchIsland, "branch island");
+ }
+ return formatUnknownEnum(Tramp);
+}
+
+static std::string formatSourceLanguage(SourceLanguage Lang) {
+ switch (Lang) {
+ RETURN_CASE(SourceLanguage, C, "c");
+ RETURN_CASE(SourceLanguage, Cpp, "c++");
+ RETURN_CASE(SourceLanguage, Fortran, "fortran");
+ RETURN_CASE(SourceLanguage, Masm, "masm");
+ RETURN_CASE(SourceLanguage, Pascal, "pascal");
+ RETURN_CASE(SourceLanguage, Basic, "basic");
+ RETURN_CASE(SourceLanguage, Cobol, "cobol");
+ RETURN_CASE(SourceLanguage, Link, "link");
+ RETURN_CASE(SourceLanguage, VB, "vb");
+ RETURN_CASE(SourceLanguage, Cvtres, "cvtres");
+ RETURN_CASE(SourceLanguage, Cvtpgd, "cvtpgd");
+ RETURN_CASE(SourceLanguage, CSharp, "c#");
+ RETURN_CASE(SourceLanguage, ILAsm, "il asm");
+ RETURN_CASE(SourceLanguage, Java, "java");
+ RETURN_CASE(SourceLanguage, JScript, "javascript");
+ RETURN_CASE(SourceLanguage, MSIL, "msil");
+ RETURN_CASE(SourceLanguage, HLSL, "hlsl");
+ }
+ return formatUnknownEnum(Lang);
+}
+
+static std::string formatMachineType(CPUType Cpu) {
+ switch (Cpu) {
+ RETURN_CASE(CPUType, Intel8080, "intel 8080");
+ RETURN_CASE(CPUType, Intel8086, "intel 8086");
+ RETURN_CASE(CPUType, Intel80286, "intel 80286");
+ RETURN_CASE(CPUType, Intel80386, "intel 80386");
+ RETURN_CASE(CPUType, Intel80486, "intel 80486");
+ RETURN_CASE(CPUType, Pentium, "intel pentium");
+ RETURN_CASE(CPUType, PentiumPro, "intel pentium pro");
+ RETURN_CASE(CPUType, Pentium3, "intel pentium 3");
+ RETURN_CASE(CPUType, MIPS, "mips");
+ RETURN_CASE(CPUType, MIPS16, "mips-16");
+ RETURN_CASE(CPUType, MIPS32, "mips-32");
+ RETURN_CASE(CPUType, MIPS64, "mips-64");
+ RETURN_CASE(CPUType, MIPSI, "mips i");
+ RETURN_CASE(CPUType, MIPSII, "mips ii");
+ RETURN_CASE(CPUType, MIPSIII, "mips iii");
+ RETURN_CASE(CPUType, MIPSIV, "mips iv");
+ RETURN_CASE(CPUType, MIPSV, "mips v");
+ RETURN_CASE(CPUType, M68000, "motorola 68000");
+ RETURN_CASE(CPUType, M68010, "motorola 68010");
+ RETURN_CASE(CPUType, M68020, "motorola 68020");
+ RETURN_CASE(CPUType, M68030, "motorola 68030");
+ RETURN_CASE(CPUType, M68040, "motorola 68040");
+ RETURN_CASE(CPUType, Alpha, "alpha");
+ RETURN_CASE(CPUType, Alpha21164, "alpha 21164");
+ RETURN_CASE(CPUType, Alpha21164A, "alpha 21164a");
+ RETURN_CASE(CPUType, Alpha21264, "alpha 21264");
+ RETURN_CASE(CPUType, Alpha21364, "alpha 21364");
+ RETURN_CASE(CPUType, PPC601, "powerpc 601");
+ RETURN_CASE(CPUType, PPC603, "powerpc 603");
+ RETURN_CASE(CPUType, PPC604, "powerpc 604");
+ RETURN_CASE(CPUType, PPC620, "powerpc 620");
+ RETURN_CASE(CPUType, PPCFP, "powerpc fp");
+ RETURN_CASE(CPUType, PPCBE, "powerpc be");
+ RETURN_CASE(CPUType, SH3, "sh3");
+ RETURN_CASE(CPUType, SH3E, "sh3e");
+ RETURN_CASE(CPUType, SH3DSP, "sh3 dsp");
+ RETURN_CASE(CPUType, SH4, "sh4");
+ RETURN_CASE(CPUType, SHMedia, "shmedia");
+ RETURN_CASE(CPUType, ARM3, "arm 3");
+ RETURN_CASE(CPUType, ARM4, "arm 4");
+ RETURN_CASE(CPUType, ARM4T, "arm 4t");
+ RETURN_CASE(CPUType, ARM5, "arm 5");
+ RETURN_CASE(CPUType, ARM5T, "arm 5t");
+ RETURN_CASE(CPUType, ARM6, "arm 6");
+ RETURN_CASE(CPUType, ARM_XMAC, "arm xmac");
+ RETURN_CASE(CPUType, ARM_WMMX, "arm wmmx");
+ RETURN_CASE(CPUType, ARM7, "arm 7");
+ RETURN_CASE(CPUType, Omni, "omni");
+ RETURN_CASE(CPUType, Ia64, "intel itanium ia64");
+ RETURN_CASE(CPUType, Ia64_2, "intel itanium ia64 2");
+ RETURN_CASE(CPUType, CEE, "cee");
+ RETURN_CASE(CPUType, AM33, "am33");
+ RETURN_CASE(CPUType, M32R, "m32r");
+ RETURN_CASE(CPUType, TriCore, "tri-core");
+ RETURN_CASE(CPUType, X64, "intel x86-x64");
+ RETURN_CASE(CPUType, EBC, "ebc");
+ RETURN_CASE(CPUType, Thumb, "thumb");
+ RETURN_CASE(CPUType, ARMNT, "arm nt");
+ RETURN_CASE(CPUType, D3D11_Shader, "d3d11 shader");
+ }
+ return formatUnknownEnum(Cpu);
+}
+
+static std::string formatCookieKind(FrameCookieKind Kind) {
+ switch (Kind) {
+ RETURN_CASE(FrameCookieKind, Copy, "copy");
+ RETURN_CASE(FrameCookieKind, XorStackPointer, "xor stack ptr");
+ RETURN_CASE(FrameCookieKind, XorFramePointer, "xor frame ptr");
+ RETURN_CASE(FrameCookieKind, XorR13, "xor rot13");
+ }
+ return formatUnknownEnum(Kind);
+}
+
+static std::string formatRegisterId(RegisterId Id) {
+ switch (Id) {
+ RETURN_CASE(RegisterId, VFrame, "vframe");
+ RETURN_CASE(RegisterId, AL, "al");
+ RETURN_CASE(RegisterId, CL, "cl");
+ RETURN_CASE(RegisterId, DL, "dl");
+ RETURN_CASE(RegisterId, BL, "bl");
+ RETURN_CASE(RegisterId, AH, "ah");
+ RETURN_CASE(RegisterId, CH, "ch");
+ RETURN_CASE(RegisterId, DH, "dh");
+ RETURN_CASE(RegisterId, BH, "bh");
+ RETURN_CASE(RegisterId, AX, "ax");
+ RETURN_CASE(RegisterId, CX, "cx");
+ RETURN_CASE(RegisterId, DX, "dx");
+ RETURN_CASE(RegisterId, BX, "bx");
+ RETURN_CASE(RegisterId, SP, "sp");
+ RETURN_CASE(RegisterId, BP, "bp");
+ RETURN_CASE(RegisterId, SI, "si");
+ RETURN_CASE(RegisterId, DI, "di");
+ RETURN_CASE(RegisterId, EAX, "eax");
+ RETURN_CASE(RegisterId, ECX, "ecx");
+ RETURN_CASE(RegisterId, EDX, "edx");
+ RETURN_CASE(RegisterId, EBX, "ebx");
+ RETURN_CASE(RegisterId, ESP, "esp");
+ RETURN_CASE(RegisterId, EBP, "ebp");
+ RETURN_CASE(RegisterId, ESI, "esi");
+ RETURN_CASE(RegisterId, EDI, "edi");
+ RETURN_CASE(RegisterId, ES, "es");
+ RETURN_CASE(RegisterId, CS, "cs");
+ RETURN_CASE(RegisterId, SS, "ss");
+ RETURN_CASE(RegisterId, DS, "ds");
+ RETURN_CASE(RegisterId, FS, "fs");
+ RETURN_CASE(RegisterId, GS, "gs");
+ RETURN_CASE(RegisterId, IP, "ip");
+ RETURN_CASE(RegisterId, RAX, "rax");
+ RETURN_CASE(RegisterId, RBX, "rbx");
+ RETURN_CASE(RegisterId, RCX, "rcx");
+ RETURN_CASE(RegisterId, RDX, "rdx");
+ RETURN_CASE(RegisterId, RSI, "rsi");
+ RETURN_CASE(RegisterId, RDI, "rdi");
+ RETURN_CASE(RegisterId, RBP, "rbp");
+ RETURN_CASE(RegisterId, RSP, "rsp");
+ RETURN_CASE(RegisterId, R8, "r8");
+ RETURN_CASE(RegisterId, R9, "r9");
+ RETURN_CASE(RegisterId, R10, "r10");
+ RETURN_CASE(RegisterId, R11, "r11");
+ RETURN_CASE(RegisterId, R12, "r12");
+ RETURN_CASE(RegisterId, R13, "r13");
+ RETURN_CASE(RegisterId, R14, "r14");
+ RETURN_CASE(RegisterId, R15, "r15");
+ default:
+ return formatUnknownEnum(Id);
+ }
+}
+
+static std::string formatRange(LocalVariableAddrRange Range) {
+ return formatv("[{0},+{1})",
+ formatSegmentOffset(Range.ISectStart, Range.OffsetStart),
+ Range.Range)
+ .str();
+}
+
+static std::string formatGaps(uint32_t IndentLevel,
+ ArrayRef<LocalVariableAddrGap> Gaps) {
+ std::vector<std::string> GapStrs;
+ for (const auto &G : Gaps) {
+ GapStrs.push_back(formatv("({0},{1})", G.GapStartOffset, G.Range).str());
+ }
+ return typesetItemList(GapStrs, 7, IndentLevel, ", ");
+}
+
+Error MinimalSymbolDumper::visitSymbolBegin(codeview::CVSymbol &Record) {
+ return visitSymbolBegin(Record, 0);
+}
+
+Error MinimalSymbolDumper::visitSymbolBegin(codeview::CVSymbol &Record,
+ uint32_t Offset) {
+ // formatLine puts the newline at the beginning, so we use formatLine here
+ // to start a new line, and then individual visit methods use format to
+ // append to the existing line.
+ P.formatLine("{0} | {1} [size = {2}]",
+ fmt_align(Offset, AlignStyle::Right, 6),
+ getSymbolKindName(Record.Type), Record.length());
+ P.Indent();
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitSymbolEnd(CVSymbol &Record) {
+ P.Unindent();
+ return Error::success();
+}
+
+std::string MinimalSymbolDumper::typeIndex(TypeIndex TI) const {
+ if (TI.isSimple())
+ return formatv("{0}", TI).str();
+ StringRef Name = Types.getTypeName(TI);
+ if (Name.size() > 32) {
+ Name = Name.take_front(32);
+ return formatv("{0} ({1}...)", TI, Name);
+ } else
+ return formatv("{0} ({1})", TI, Name);
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, BlockSym &Block) {
+ P.format(" `{0}`", Block.Name);
+ AutoIndent Indent(P, 7);
+ P.formatLine("parent = {0}, end = {1}", Block.Parent, Block.End);
+ P.formatLine("code size = {0}, addr = {1}", Block.CodeSize,
+ formatSegmentOffset(Block.Segment, Block.CodeOffset));
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, Thunk32Sym &Thunk) {
+ P.format(" `{0}`", Thunk.Name);
+ AutoIndent Indent(P, 7);
+ P.formatLine("parent = {0}, end = {1}, next = {2}", Thunk.Parent, Thunk.End,
+ Thunk.Next);
+ P.formatLine("kind = {0}, size = {1}, addr = {2}",
+ formatThunkOrdinal(Thunk.Thunk), Thunk.Length,
+ formatSegmentOffset(Thunk.Segment, Thunk.Offset));
+
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
+ TrampolineSym &Tramp) {
+ AutoIndent Indent(P, 7);
+ P.formatLine("type = {0}, size = {1}, source = {2}, target = {3}",
+ formatTrampolineType(Tramp.Type), Tramp.Size,
+ formatSegmentOffset(Tramp.ThunkSection, Tramp.ThunkOffset),
+ formatSegmentOffset(Tramp.TargetSection, Tramp.ThunkOffset));
+
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
+ SectionSym &Section) {
+ P.format(" `{0}`", Section.Name);
+ AutoIndent Indent(P, 7);
+ P.formatLine("length = {0}, alignment = {1}, rva = {2}, section # = {3}, "
+ "characteristics = {4}",
+ Section.Length, Section.Alignment, Section.Rva,
+ Section.SectionNumber, Section.Characteristics);
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, CoffGroupSym &CG) {
+ P.format(" `{0}`", CG.Name);
+ AutoIndent Indent(P, 7);
+ P.formatLine("length = {0}, addr = {1}, characteristics = {2}", CG.Size,
+ formatSegmentOffset(CG.Segment, CG.Offset), CG.Characteristics);
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
+ BPRelativeSym &BPRel) {
+ P.format(" `{0}`", BPRel.Name);
+ AutoIndent Indent(P, 7);
+ P.formatLine("type = {0}, offset = {1}", typeIndex(BPRel.Type), BPRel.Offset);
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
+ BuildInfoSym &BuildInfo) {
+ P.format(" BuildId = `{0}`", BuildInfo.BuildId);
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
+ CallSiteInfoSym &CSI) {
+ AutoIndent Indent(P, 7);
+ P.formatLine("type = {0}, addr = {1}", typeIndex(CSI.Type),
+ formatSegmentOffset(CSI.Segment, CSI.CodeOffset));
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
+ EnvBlockSym &EnvBlock) {
+ AutoIndent Indent(P, 7);
+ for (const auto &Entry : EnvBlock.Fields) {
+ P.formatLine("- {0}", Entry);
+ }
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, FileStaticSym &FS) {
+ P.format(" `{0}`", FS.Name);
+ AutoIndent Indent(P, 7);
+ P.formatLine("type = {0}, file name offset = {1}, flags = {2}",
+ typeIndex(FS.Index), FS.ModFilenameOffset,
+ formatLocalSymFlags(P.getIndentLevel() + 9, FS.Flags));
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, ExportSym &Export) {
+ P.format(" `{0}`", Export.Name);
+ AutoIndent Indent(P, 7);
+ P.formatLine("ordinal = {0}, flags = {1}", Export.Ordinal,
+ formatExportFlags(P.getIndentLevel() + 9, Export.Flags));
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
+ Compile2Sym &Compile2) {
+ AutoIndent Indent(P, 7);
+ SourceLanguage Lang = static_cast<SourceLanguage>(
+ Compile2.Flags & CompileSym2Flags::SourceLanguageMask);
+ P.formatLine("machine = {0}, ver = {1}, language = {2}",
+ formatMachineType(Compile2.Machine), Compile2.Version,
+ formatSourceLanguage(Lang));
+ P.formatLine("frontend = {0}.{1}.{2}, backend = {3}.{4}.{5}",
+ Compile2.VersionFrontendMajor, Compile2.VersionFrontendMinor,
+ Compile2.VersionFrontendBuild, Compile2.VersionBackendMajor,
+ Compile2.VersionBackendMinor, Compile2.VersionBackendBuild);
+ P.formatLine("flags = {0}",
+ formatCompileSym2Flags(P.getIndentLevel() + 9, Compile2.Flags));
+ P.formatLine(
+ "extra strings = {0}",
+ typesetStringList(P.getIndentLevel() + 9 + 2, Compile2.ExtraStrings));
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
+ Compile3Sym &Compile3) {
+ AutoIndent Indent(P, 7);
+ SourceLanguage Lang = static_cast<SourceLanguage>(
+ Compile3.Flags & CompileSym3Flags::SourceLanguageMask);
+ P.formatLine("machine = {0}, Ver = {1}, language = {2}",
+ formatMachineType(Compile3.Machine), Compile3.Version,
+ formatSourceLanguage(Lang));
+ P.formatLine("frontend = {0}.{1}.{2}.{3}, backend = {4}.{5}.{6}.{7}",
+ Compile3.VersionFrontendMajor, Compile3.VersionFrontendMinor,
+ Compile3.VersionFrontendBuild, Compile3.VersionFrontendQFE,
+ Compile3.VersionBackendMajor, Compile3.VersionBackendMinor,
+ Compile3.VersionBackendBuild, Compile3.VersionBackendQFE);
+ P.formatLine("flags = {0}",
+ formatCompileSym3Flags(P.getIndentLevel() + 9, Compile3.Flags));
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
+ ConstantSym &Constant) {
+ P.format(" `{0}`", Constant.Name);
+ AutoIndent Indent(P, 7);
+ P.formatLine("type = {0}, value = {1}", typeIndex(Constant.Type),
+ Constant.Value.toString(10));
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, DataSym &Data) {
+ P.format(" `{0}`", Data.Name);
+ AutoIndent Indent(P, 7);
+ P.formatLine("type = {0}, addr = {1}", typeIndex(Data.Type),
+ formatSegmentOffset(Data.Segment, Data.DataOffset));
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(
+ CVSymbol &CVR, DefRangeFramePointerRelFullScopeSym &Def) {
+ P.format(" offset = {0}", Def.Offset);
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
+ DefRangeFramePointerRelSym &Def) {
+ AutoIndent Indent(P, 7);
+ P.formatLine("offset = {0}, range = {1}", Def.Offset, formatRange(Def.Range));
+ P.formatLine("gaps = {2}", Def.Offset,
+ formatGaps(P.getIndentLevel() + 9, Def.Gaps));
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
+ DefRangeRegisterRelSym &Def) {
+ AutoIndent Indent(P, 7);
+ P.formatLine("register = {0}, base ptr = {1}, offset in parent = {2}, has "
+ "spilled udt = {3}",
+ uint16_t(Def.Hdr.Register), int32_t(Def.Hdr.BasePointerOffset),
+ Def.offsetInParent(), Def.hasSpilledUDTMember());
+ P.formatLine("range = {0}, gaps = {1}", formatRange(Def.Range),
+ formatGaps(P.getIndentLevel() + 9, Def.Gaps));
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(
+ CVSymbol &CVR, DefRangeRegisterSym &DefRangeRegister) {
+ AutoIndent Indent(P, 7);
+ P.formatLine("register = {0}, may have no name = {1}, range start = "
+ "{2}, length = {3}",
+ uint16_t(DefRangeRegister.Hdr.Register),
+ uint16_t(DefRangeRegister.Hdr.MayHaveNoName),
+ formatSegmentOffset(DefRangeRegister.Range.ISectStart,
+ DefRangeRegister.Range.OffsetStart),
+ DefRangeRegister.Range.Range);
+ P.formatLine("gaps = [{0}]",
+ formatGaps(P.getIndentLevel() + 9, DefRangeRegister.Gaps));
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
+ DefRangeSubfieldRegisterSym &Def) {
+ AutoIndent Indent(P, 7);
+ bool NoName = !!(Def.Hdr.MayHaveNoName == 0);
+ P.formatLine("register = {0}, may have no name = {1}, offset in parent = {2}",
+ uint16_t(Def.Hdr.Register), NoName,
+ uint32_t(Def.Hdr.OffsetInParent));
+ P.formatLine("range = {0}, gaps = {1}", formatRange(Def.Range),
+ formatGaps(P.getIndentLevel() + 9, Def.Gaps));
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
+ DefRangeSubfieldSym &Def) {
+ AutoIndent Indent(P, 7);
+ P.formatLine("program = {0}, offset in parent = {1}, range = {2}",
+ Def.Program, Def.OffsetInParent, formatRange(Def.Range));
+ P.formatLine("gaps = {0}", formatGaps(P.getIndentLevel() + 9, Def.Gaps));
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, DefRangeSym &Def) {
+ AutoIndent Indent(P, 7);
+ P.formatLine("program = {0}, range = {1}", Def.Program,
+ formatRange(Def.Range));
+ P.formatLine("gaps = {0}", formatGaps(P.getIndentLevel() + 9, Def.Gaps));
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, FrameCookieSym &FC) {
+ AutoIndent Indent(P, 7);
+ P.formatLine("code offset = {0}, Register = {1}, kind = {2}, flags = {3}",
+ FC.CodeOffset, FC.Register, formatCookieKind(FC.CookieKind),
+ FC.Flags);
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, FrameProcSym &FP) {
+ AutoIndent Indent(P, 7);
+ P.formatLine("size = {0}, padding size = {1}, offset to padding = {2}",
+ FP.TotalFrameBytes, FP.PaddingFrameBytes, FP.OffsetToPadding);
+ P.formatLine("bytes of callee saved registers = {0}, exception handler addr "
+ "= {1}",
+ FP.BytesOfCalleeSavedRegisters,
+ formatSegmentOffset(FP.SectionIdOfExceptionHandler,
+ FP.OffsetOfExceptionHandler));
+ P.formatLine("flags = {0}",
+ formatFrameProcedureOptions(P.getIndentLevel() + 9, FP.Flags));
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
+ HeapAllocationSiteSym &HAS) {
+ AutoIndent Indent(P, 7);
+ P.formatLine("type = {0}, addr = {1} call size = {2}", typeIndex(HAS.Type),
+ formatSegmentOffset(HAS.Segment, HAS.CodeOffset),
+ HAS.CallInstructionSize);
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, InlineSiteSym &IS) {
+ AutoIndent Indent(P, 7);
+ auto Bytes = makeArrayRef(IS.AnnotationData);
+ StringRef Annotations(reinterpret_cast<const char *>(Bytes.begin()),
+ Bytes.size());
+
+ P.formatLine("inlinee = {0}, parent = {1}, end = {2}", typeIndex(IS.Inlinee),
+ IS.Parent, IS.End);
+ P.formatLine("annotations = {0}", toHex(Annotations));
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
+ RegisterSym &Register) {
+ P.format(" `{0}`", Register.Name);
+ AutoIndent Indent(P, 7);
+ P.formatLine("register = {0}, type = {1}",
+ formatRegisterId(Register.Register), typeIndex(Register.Index));
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
+ PublicSym32 &Public) {
+ P.format(" `{0}`", Public.Name);
+ AutoIndent Indent(P, 7);
+ P.formatLine("flags = {0}, addr = {1}",
+ formatPublicSymFlags(P.getIndentLevel() + 9, Public.Flags),
+ formatSegmentOffset(Public.Segment, Public.Offset));
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, ProcRefSym &PR) {
+ P.format(" `{0}`", PR.Name);
+ AutoIndent Indent(P, 7);
+ P.formatLine("module = {0}, sum name = {1}, offset = {2}", PR.Module,
+ PR.SumName, PR.SymOffset);
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, LabelSym &Label) {
+ P.format(" `{0}` (addr = {1})", Label.Name,
+ formatSegmentOffset(Label.Segment, Label.CodeOffset));
+ AutoIndent Indent(P, 7);
+ P.formatLine("flags = {0}",
+ formatProcSymFlags(P.getIndentLevel() + 9, Label.Flags));
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, LocalSym &Local) {
+ P.format(" `{0}`", Local.Name);
+ AutoIndent Indent(P, 7);
+
+ std::string FlagStr =
+ formatLocalSymFlags(P.getIndentLevel() + 9, Local.Flags);
+ P.formatLine("type={0}, flags = {1}", typeIndex(Local.Type), FlagStr);
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
+ ObjNameSym &ObjName) {
+ P.format(" sig={0}, `{1}`", ObjName.Signature, ObjName.Name);
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, ProcSym &Proc) {
+ P.format(" `{0}`", Proc.Name);
+ AutoIndent Indent(P, 7);
+ P.formatLine("parent = {0}, end = {1}, addr = {2}, code size = {3}",
+ Proc.Parent, Proc.End,
+ formatSegmentOffset(Proc.Segment, Proc.CodeOffset),
+ Proc.CodeSize);
+ // FIXME: It seems FunctionType is sometimes an id and sometimes a type.
+ P.formatLine("type = `{0}`, debug start = {1}, debug end = {2}, flags = {3}",
+ typeIndex(Proc.FunctionType), Proc.DbgStart, Proc.DbgEnd,
+ formatProcSymFlags(P.getIndentLevel() + 9, Proc.Flags));
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
+ ScopeEndSym &ScopeEnd) {
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, CallerSym &Caller) {
+ AutoIndent Indent(P, 7);
+ for (const auto &I : Caller.Indices) {
+ P.formatLine("callee: {0}", typeIndex(I));
+ }
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
+ RegRelativeSym &RegRel) {
+ P.format(" `{0}`", RegRel.Name);
+ AutoIndent Indent(P, 7);
+ P.formatLine("type = {0}, register = {1}, offset = {2}",
+ typeIndex(RegRel.Type), formatRegisterId(RegRel.Register),
+ RegRel.Offset);
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
+ ThreadLocalDataSym &Data) {
+ P.format(" `{0}`", Data.Name);
+ AutoIndent Indent(P, 7);
+ P.formatLine("type = {0}, addr = {1}", typeIndex(Data.Type),
+ formatSegmentOffset(Data.Segment, Data.DataOffset));
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, UDTSym &UDT) {
+ P.format(" `{0}`", UDT.Name);
+ AutoIndent Indent(P, 7);
+ P.formatLine("original type = {0}", UDT.Type);
+ return Error::success();
+}
diff --git a/contrib/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.h b/contrib/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.h
new file mode 100644
index 0000000..5e30959
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.h
@@ -0,0 +1,48 @@
+//===- MinimalSymbolDumper.h ---------------------------------- *- 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_LLVMPDBUTIL_MINIMAL_SYMBOL_DUMPER_H
+#define LLVM_TOOLS_LLVMPDBUTIL_MINIMAL_SYMBOL_DUMPER_H
+
+#include "llvm/DebugInfo/CodeView/SymbolVisitorCallbacks.h"
+
+namespace llvm {
+namespace codeview {
+class LazyRandomTypeCollection;
+}
+
+namespace pdb {
+class LinePrinter;
+
+class MinimalSymbolDumper : public codeview::SymbolVisitorCallbacks {
+public:
+ MinimalSymbolDumper(LinePrinter &P, bool RecordBytes,
+ codeview::LazyRandomTypeCollection &Types)
+ : P(P), Types(Types) {}
+
+ Error visitSymbolBegin(codeview::CVSymbol &Record) override;
+ Error visitSymbolBegin(codeview::CVSymbol &Record, uint32_t Offset) override;
+ Error visitSymbolEnd(codeview::CVSymbol &Record) override;
+
+#define SYMBOL_RECORD(EnumName, EnumVal, Name) \
+ virtual Error visitKnownRecord(codeview::CVSymbol &CVR, \
+ codeview::Name &Record) override;
+#define SYMBOL_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
+#include "llvm/DebugInfo/CodeView/CodeViewSymbols.def"
+
+private:
+ std::string typeIndex(codeview::TypeIndex TI) const;
+
+ LinePrinter &P;
+ codeview::LazyRandomTypeCollection &Types;
+};
+} // namespace pdb
+} // namespace llvm
+
+#endif \ No newline at end of file
diff --git a/contrib/llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp b/contrib/llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp
new file mode 100644
index 0000000..0079b9e
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp
@@ -0,0 +1,553 @@
+//===- MinimalTypeDumper.cpp ---------------------------------- *- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MinimalTypeDumper.h"
+
+#include "FormatUtil.h"
+#include "LinePrinter.h"
+
+#include "llvm/DebugInfo/CodeView/CVRecord.h"
+#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/Formatters.h"
+#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/DebugInfo/PDB/Native/TpiHashing.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/MathExtras.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+static StringRef getLeafTypeName(TypeLeafKind K) {
+ switch (K) {
+#define TYPE_RECORD(EnumName, value, name) \
+ case EnumName: \
+ return #EnumName;
+#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
+ default:
+ llvm_unreachable("Unknown type leaf kind!");
+ }
+ return "";
+}
+
+static std::string formatClassOptions(uint32_t IndentLevel,
+ ClassOptions Options) {
+ std::vector<std::string> Opts;
+ PUSH_FLAG(ClassOptions, HasConstructorOrDestructor, Options,
+ "has ctor / dtor");
+ PUSH_FLAG(ClassOptions, ContainsNestedClass, Options,
+ "contains nested class");
+ PUSH_FLAG(ClassOptions, HasConversionOperator, Options,
+ "conversion operator");
+ PUSH_FLAG(ClassOptions, ForwardReference, Options, "forward ref");
+ PUSH_FLAG(ClassOptions, HasUniqueName, Options, "has unique name");
+ PUSH_FLAG(ClassOptions, Intrinsic, Options, "intrin");
+ PUSH_FLAG(ClassOptions, Nested, Options, "is nested");
+ PUSH_FLAG(ClassOptions, HasOverloadedOperator, Options,
+ "overloaded operator");
+ PUSH_FLAG(ClassOptions, HasOverloadedAssignmentOperator, Options,
+ "overloaded operator=");
+ PUSH_FLAG(ClassOptions, Packed, Options, "packed");
+ PUSH_FLAG(ClassOptions, Scoped, Options, "scoped");
+ PUSH_FLAG(ClassOptions, Sealed, Options, "sealed");
+
+ return typesetItemList(Opts, 4, IndentLevel, " | ");
+}
+
+static std::string pointerOptions(PointerOptions Options) {
+ std::vector<std::string> Opts;
+ PUSH_FLAG(PointerOptions, Flat32, Options, "flat32");
+ PUSH_FLAG(PointerOptions, Volatile, Options, "volatile");
+ PUSH_FLAG(PointerOptions, Const, Options, "const");
+ PUSH_FLAG(PointerOptions, Unaligned, Options, "unaligned");
+ PUSH_FLAG(PointerOptions, Restrict, Options, "restrict");
+ PUSH_FLAG(PointerOptions, WinRTSmartPointer, Options, "winrt");
+ if (Opts.empty())
+ return "None";
+ return join(Opts, " | ");
+}
+
+static std::string modifierOptions(ModifierOptions Options) {
+ std::vector<std::string> Opts;
+ PUSH_FLAG(ModifierOptions, Const, Options, "const");
+ PUSH_FLAG(ModifierOptions, Volatile, Options, "volatile");
+ PUSH_FLAG(ModifierOptions, Unaligned, Options, "unaligned");
+ if (Opts.empty())
+ return "None";
+ return join(Opts, " | ");
+}
+
+static std::string formatCallingConvention(CallingConvention Convention) {
+ switch (Convention) {
+ RETURN_CASE(CallingConvention, AlphaCall, "alphacall");
+ RETURN_CASE(CallingConvention, AM33Call, "am33call");
+ RETURN_CASE(CallingConvention, ArmCall, "armcall");
+ RETURN_CASE(CallingConvention, ClrCall, "clrcall");
+ RETURN_CASE(CallingConvention, FarC, "far cdecl");
+ RETURN_CASE(CallingConvention, FarFast, "far fastcall");
+ RETURN_CASE(CallingConvention, FarPascal, "far pascal");
+ RETURN_CASE(CallingConvention, FarStdCall, "far stdcall");
+ RETURN_CASE(CallingConvention, FarSysCall, "far syscall");
+ RETURN_CASE(CallingConvention, Generic, "generic");
+ RETURN_CASE(CallingConvention, Inline, "inline");
+ RETURN_CASE(CallingConvention, M32RCall, "m32rcall");
+ RETURN_CASE(CallingConvention, MipsCall, "mipscall");
+ RETURN_CASE(CallingConvention, NearC, "cdecl");
+ RETURN_CASE(CallingConvention, NearFast, "fastcall");
+ RETURN_CASE(CallingConvention, NearPascal, "pascal");
+ RETURN_CASE(CallingConvention, NearStdCall, "stdcall");
+ RETURN_CASE(CallingConvention, NearSysCall, "near syscall");
+ RETURN_CASE(CallingConvention, NearVector, "vectorcall");
+ RETURN_CASE(CallingConvention, PpcCall, "ppccall");
+ RETURN_CASE(CallingConvention, SHCall, "shcall");
+ RETURN_CASE(CallingConvention, SH5Call, "sh5call");
+ RETURN_CASE(CallingConvention, ThisCall, "thiscall");
+ RETURN_CASE(CallingConvention, TriCall, "tricall");
+ }
+ return formatUnknownEnum(Convention);
+}
+
+static std::string formatPointerMode(PointerMode Mode) {
+ switch (Mode) {
+ RETURN_CASE(PointerMode, LValueReference, "ref");
+ RETURN_CASE(PointerMode, Pointer, "pointer");
+ RETURN_CASE(PointerMode, PointerToDataMember, "data member pointer");
+ RETURN_CASE(PointerMode, PointerToMemberFunction, "member fn pointer");
+ RETURN_CASE(PointerMode, RValueReference, "rvalue ref");
+ }
+ return formatUnknownEnum(Mode);
+}
+
+static std::string memberAccess(MemberAccess Access) {
+ switch (Access) {
+ RETURN_CASE(MemberAccess, None, "");
+ RETURN_CASE(MemberAccess, Private, "private");
+ RETURN_CASE(MemberAccess, Protected, "protected");
+ RETURN_CASE(MemberAccess, Public, "public");
+ }
+ return formatUnknownEnum(Access);
+}
+
+static std::string methodKind(MethodKind Kind) {
+ switch (Kind) {
+ RETURN_CASE(MethodKind, Vanilla, "");
+ RETURN_CASE(MethodKind, Virtual, "virtual");
+ RETURN_CASE(MethodKind, Static, "static");
+ RETURN_CASE(MethodKind, Friend, "friend");
+ RETURN_CASE(MethodKind, IntroducingVirtual, "intro virtual");
+ RETURN_CASE(MethodKind, PureVirtual, "pure virtual");
+ RETURN_CASE(MethodKind, PureIntroducingVirtual, "pure intro virtual");
+ }
+ return formatUnknownEnum(Kind);
+}
+
+static std::string pointerKind(PointerKind Kind) {
+ switch (Kind) {
+ RETURN_CASE(PointerKind, Near16, "ptr16");
+ RETURN_CASE(PointerKind, Far16, "far ptr16");
+ RETURN_CASE(PointerKind, Huge16, "huge ptr16");
+ RETURN_CASE(PointerKind, BasedOnSegment, "segment based");
+ RETURN_CASE(PointerKind, BasedOnValue, "value based");
+ RETURN_CASE(PointerKind, BasedOnSegmentValue, "segment value based");
+ RETURN_CASE(PointerKind, BasedOnAddress, "address based");
+ RETURN_CASE(PointerKind, BasedOnSegmentAddress, "segment address based");
+ RETURN_CASE(PointerKind, BasedOnType, "type based");
+ RETURN_CASE(PointerKind, BasedOnSelf, "self based");
+ RETURN_CASE(PointerKind, Near32, "ptr32");
+ RETURN_CASE(PointerKind, Far32, "far ptr32");
+ RETURN_CASE(PointerKind, Near64, "ptr64");
+ }
+ return formatUnknownEnum(Kind);
+}
+
+static std::string memberAttributes(const MemberAttributes &Attrs) {
+ std::vector<std::string> Opts;
+ std::string Access = memberAccess(Attrs.getAccess());
+ std::string Kind = methodKind(Attrs.getMethodKind());
+ if (!Access.empty())
+ Opts.push_back(Access);
+ if (!Kind.empty())
+ Opts.push_back(Kind);
+ MethodOptions Flags = Attrs.getFlags();
+ PUSH_FLAG(MethodOptions, Pseudo, Flags, "pseudo");
+ PUSH_FLAG(MethodOptions, NoInherit, Flags, "noinherit");
+ PUSH_FLAG(MethodOptions, NoConstruct, Flags, "noconstruct");
+ PUSH_FLAG(MethodOptions, CompilerGenerated, Flags, "compiler-generated");
+ PUSH_FLAG(MethodOptions, Sealed, Flags, "sealed");
+ return join(Opts, " ");
+}
+
+static std::string formatPointerAttrs(const PointerRecord &Record) {
+ PointerMode Mode = Record.getMode();
+ PointerOptions Opts = Record.getOptions();
+ PointerKind Kind = Record.getPointerKind();
+ return formatv("mode = {0}, opts = {1}, kind = {2}", formatPointerMode(Mode),
+ pointerOptions(Opts), pointerKind(Kind));
+}
+
+static std::string formatFunctionOptions(FunctionOptions Options) {
+ std::vector<std::string> Opts;
+
+ PUSH_FLAG(FunctionOptions, CxxReturnUdt, Options, "returns cxx udt");
+ PUSH_FLAG(FunctionOptions, ConstructorWithVirtualBases, Options,
+ "constructor with virtual bases");
+ PUSH_FLAG(FunctionOptions, Constructor, Options, "constructor");
+ if (Opts.empty())
+ return "None";
+ return join(Opts, " | ");
+}
+
+Error MinimalTypeDumpVisitor::visitTypeBegin(CVType &Record, TypeIndex Index) {
+ // formatLine puts the newline at the beginning, so we use formatLine here
+ // to start a new line, and then individual visit methods use format to
+ // append to the existing line.
+ if (!Hashes) {
+ P.formatLine("{0} | {1} [size = {2}]",
+ fmt_align(Index, AlignStyle::Right, Width),
+ getLeafTypeName(Record.Type), Record.length());
+ } else {
+ std::string H;
+ if (Index.toArrayIndex() >= HashValues.size()) {
+ H = "(not present)";
+ } else {
+ uint32_t Hash = HashValues[Index.toArrayIndex()];
+ Expected<uint32_t> MaybeHash = hashTypeRecord(Record);
+ if (!MaybeHash)
+ return MaybeHash.takeError();
+ uint32_t OurHash = *MaybeHash;
+ OurHash %= NumHashBuckets;
+ if (Hash == OurHash)
+ H = "0x" + utohexstr(Hash);
+ else
+ H = "0x" + utohexstr(Hash) + ", our hash = 0x" + utohexstr(OurHash);
+ }
+ P.formatLine("{0} | {1} [size = {2}, hash = {3}]",
+ fmt_align(Index, AlignStyle::Right, Width),
+ getLeafTypeName(Record.Type), Record.length(), H);
+ }
+ P.Indent(Width + 3);
+ return Error::success();
+}
+Error MinimalTypeDumpVisitor::visitTypeEnd(CVType &Record) {
+ P.Unindent(Width + 3);
+ if (RecordBytes) {
+ AutoIndent Indent(P, 9);
+ P.formatBinary("Bytes", Record.RecordData, 0);
+ }
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitMemberBegin(CVMemberRecord &Record) {
+ P.formatLine("- {0}", getLeafTypeName(Record.Kind));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitMemberEnd(CVMemberRecord &Record) {
+ if (RecordBytes) {
+ AutoIndent Indent(P, 2);
+ P.formatBinary("Bytes", Record.Data, 0);
+ }
+ return Error::success();
+}
+
+StringRef MinimalTypeDumpVisitor::getTypeName(TypeIndex TI) const {
+ if (TI.isNoneType())
+ return "";
+ return Types.getTypeName(TI);
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ FieldListRecord &FieldList) {
+ if (auto EC = codeview::visitMemberRecordStream(FieldList.Data, *this))
+ return EC;
+
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ StringIdRecord &String) {
+ P.format(" ID: {0}, String: {1}", String.getId(), String.getString());
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ ArgListRecord &Args) {
+ auto Indices = Args.getIndices();
+ if (Indices.empty())
+ return Error::success();
+
+ auto Max = std::max_element(Indices.begin(), Indices.end());
+ uint32_t W = NumDigits(Max->getIndex()) + 2;
+
+ for (auto I : Indices)
+ P.formatLine("{0}: `{1}`", fmt_align(I, AlignStyle::Right, W),
+ getTypeName(I));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ StringListRecord &Strings) {
+ auto Indices = Strings.getIndices();
+ if (Indices.empty())
+ return Error::success();
+
+ auto Max = std::max_element(Indices.begin(), Indices.end());
+ uint32_t W = NumDigits(Max->getIndex()) + 2;
+
+ for (auto I : Indices)
+ P.formatLine("{0}: `{1}`", fmt_align(I, AlignStyle::Right, W),
+ getTypeName(I));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ ClassRecord &Class) {
+ P.format(" `{0}`", Class.Name);
+ if (Class.hasUniqueName())
+ P.formatLine("unique name: `{0}`", Class.UniqueName);
+ P.formatLine("vtable: {0}, base list: {1}, field list: {2}",
+ Class.VTableShape, Class.DerivationList, Class.FieldList);
+ P.formatLine("options: {0}",
+ formatClassOptions(P.getIndentLevel(), Class.Options));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ UnionRecord &Union) {
+ P.format(" `{0}`", Union.Name);
+ if (Union.hasUniqueName())
+ P.formatLine("unique name: `{0}`", Union.UniqueName);
+ P.formatLine("field list: {0}", Union.FieldList);
+ P.formatLine("options: {0}",
+ formatClassOptions(P.getIndentLevel(), Union.Options));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, EnumRecord &Enum) {
+ P.format(" `{0}`", Enum.Name);
+ if (Enum.hasUniqueName())
+ P.formatLine("unique name: `{0}`", Enum.UniqueName);
+ P.formatLine("field list: {0}, underlying type: {1}", Enum.FieldList,
+ Enum.UnderlyingType);
+ P.formatLine("options: {0}",
+ formatClassOptions(P.getIndentLevel(), Enum.Options));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, ArrayRecord &AT) {
+ if (AT.Name.empty()) {
+ P.formatLine("size: {0}, index type: {1}, element type: {2}", AT.Size,
+ AT.IndexType, AT.ElementType);
+ } else {
+ P.formatLine("name: {0}, size: {1}, index type: {2}, element type: {3}",
+ AT.Name, AT.Size, AT.IndexType, AT.ElementType);
+ }
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ VFTableRecord &VFT) {
+ P.formatLine("offset: {0}, complete class: {1}, overridden vftable: {2}",
+ VFT.VFPtrOffset, VFT.CompleteClass, VFT.OverriddenVFTable);
+ P.formatLine("method names: ");
+ if (!VFT.MethodNames.empty()) {
+ std::string Sep =
+ formatv("\n{0}",
+ fmt_repeat(' ', P.getIndentLevel() + strlen("method names: ")))
+ .str();
+ P.print(join(VFT.MethodNames, Sep));
+ }
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ MemberFuncIdRecord &Id) {
+ P.formatLine("name = {0}, type = {1}, class type = {2}", Id.Name,
+ Id.FunctionType, Id.ClassType);
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ ProcedureRecord &Proc) {
+ P.formatLine("return type = {0}, # args = {1}, param list = {2}",
+ Proc.ReturnType, Proc.ParameterCount, Proc.ArgumentList);
+ P.formatLine("calling conv = {0}, options = {1}",
+ formatCallingConvention(Proc.CallConv),
+ formatFunctionOptions(Proc.Options));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ MemberFunctionRecord &MF) {
+ P.formatLine("return type = {0}, # args = {1}, param list = {2}",
+ MF.ReturnType, MF.ParameterCount, MF.ArgumentList);
+ P.formatLine("class type = {0}, this type = {1}, this adjust = {2}",
+ MF.ClassType, MF.ThisType, MF.ThisPointerAdjustment);
+ P.formatLine("calling conv = {0}, options = {1}",
+ formatCallingConvention(MF.CallConv),
+ formatFunctionOptions(MF.Options));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ FuncIdRecord &Func) {
+ P.formatLine("name = {0}, type = {1}, parent scope = {2}", Func.Name,
+ Func.FunctionType, Func.ParentScope);
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ TypeServer2Record &TS) {
+ P.formatLine("name = {0}, age = {1}, guid = {2}", TS.Name, TS.Age, TS.Guid);
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ PointerRecord &Ptr) {
+ P.formatLine("referent = {0}, {1}", Ptr.ReferentType,
+ formatPointerAttrs(Ptr));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ ModifierRecord &Mod) {
+ P.formatLine("referent = {0}, modifiers = {1}", Mod.ModifiedType,
+ modifierOptions(Mod.Modifiers));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ VFTableShapeRecord &Shape) {
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ UdtModSourceLineRecord &U) {
+ P.formatLine("udt = {0}, mod = {1}, file = {2}, line = {3}", U.UDT, U.Module,
+ U.SourceFile.getIndex(), U.LineNumber);
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ UdtSourceLineRecord &U) {
+ P.formatLine("udt = {0}, file = {1}, line = {2}", U.UDT,
+ U.SourceFile.getIndex(), U.LineNumber);
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ BitFieldRecord &BF) {
+ P.formatLine("type = {0}, bit offset = {1}, # bits = {2}", BF.Type,
+ BF.BitOffset, BF.BitSize);
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(
+ CVType &CVR, MethodOverloadListRecord &Overloads) {
+ for (auto &M : Overloads.Methods)
+ P.formatLine("- Method [type = {0}, vftable offset = {1}, attrs = {2}]",
+ M.Type, M.VFTableOffset, memberAttributes(M.Attrs));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ BuildInfoRecord &BI) {
+ auto Indices = BI.ArgIndices;
+ if (Indices.empty())
+ return Error::success();
+
+ auto Max = std::max_element(Indices.begin(), Indices.end());
+ uint32_t W = NumDigits(Max->getIndex()) + 2;
+
+ for (auto I : Indices)
+ P.formatLine("{0}: `{1}`", fmt_align(I, AlignStyle::Right, W),
+ getTypeName(I));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, LabelRecord &R) {
+ std::string Type = (R.Mode == LabelType::Far) ? "far" : "near";
+ P.format(" type = {0}", Type);
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+ NestedTypeRecord &Nested) {
+ P.format(" [name = `{0}`, parent = {1}]", Nested.Name, Nested.Type);
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+ OneMethodRecord &Method) {
+ P.format(" [name = `{0}`]", Method.Name);
+ AutoIndent Indent(P);
+ P.formatLine("type = {0}, vftable offset = {1}, attrs = {2}", Method.Type,
+ Method.VFTableOffset, memberAttributes(Method.Attrs));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+ OverloadedMethodRecord &Method) {
+ P.format(" [name = `{0}`, # overloads = {1}, overload list = {2}]",
+ Method.Name, Method.NumOverloads, Method.MethodList);
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+ DataMemberRecord &Field) {
+ P.format(" [name = `{0}`, Type = {1}, offset = {2}, attrs = {3}]", Field.Name,
+ Field.Type, Field.FieldOffset, memberAttributes(Field.Attrs));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+ StaticDataMemberRecord &Field) {
+ P.format(" [name = `{0}`, type = {1}, attrs = {2}]", Field.Name, Field.Type,
+ memberAttributes(Field.Attrs));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+ EnumeratorRecord &Enum) {
+ P.format(" [{0} = {1}]", Enum.Name,
+ Enum.Value.toString(10, Enum.Value.isSigned()));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+ BaseClassRecord &Base) {
+ AutoIndent Indent(P);
+ P.formatLine("type = {0}, offset = {1}, attrs = {2}", Base.Type, Base.Offset,
+ memberAttributes(Base.Attrs));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+ VirtualBaseClassRecord &Base) {
+ AutoIndent Indent(P);
+ P.formatLine(
+ "base = {0}, vbptr = {1}, vbptr offset = {2}, vtable index = {3}",
+ Base.BaseType, Base.VBPtrType, Base.VBPtrOffset, Base.VTableIndex);
+ P.formatLine("attrs = {0}", memberAttributes(Base.Attrs));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+ ListContinuationRecord &Cont) {
+ P.format(" continuation = {0}", Cont.ContinuationIndex);
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+ VFPtrRecord &VFP) {
+ P.format(" type = {0}", VFP.Type);
+ return Error::success();
+}
diff --git a/contrib/llvm/tools/llvm-pdbutil/MinimalTypeDumper.h b/contrib/llvm/tools/llvm-pdbutil/MinimalTypeDumper.h
new file mode 100644
index 0000000..4227688
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/MinimalTypeDumper.h
@@ -0,0 +1,63 @@
+//===- MinimalTypeDumper.h ------------------------------------ *- 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_LLVMPDBUTIL_MINIMAL_TYPE_DUMPER_H
+#define LLVM_TOOLS_LLVMPDBUTIL_MINIMAL_TYPE_DUMPER_H
+
+#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
+#include "llvm/Support/BinaryStreamArray.h"
+
+namespace llvm {
+namespace codeview {
+class LazyRandomTypeCollection;
+}
+
+namespace pdb {
+class LinePrinter;
+
+class MinimalTypeDumpVisitor : public codeview::TypeVisitorCallbacks {
+public:
+ MinimalTypeDumpVisitor(LinePrinter &P, uint32_t Width, bool RecordBytes,
+ bool Hashes, codeview::LazyRandomTypeCollection &Types,
+ uint32_t NumHashBuckets,
+ FixedStreamArray<support::ulittle32_t> HashValues)
+ : P(P), Width(Width), RecordBytes(RecordBytes), Hashes(Hashes),
+ Types(Types), NumHashBuckets(NumHashBuckets), HashValues(HashValues) {}
+
+ Error visitTypeBegin(codeview::CVType &Record,
+ codeview::TypeIndex Index) override;
+ Error visitTypeEnd(codeview::CVType &Record) override;
+ Error visitMemberBegin(codeview::CVMemberRecord &Record) override;
+ Error visitMemberEnd(codeview::CVMemberRecord &Record) override;
+
+#define TYPE_RECORD(EnumName, EnumVal, Name) \
+ Error visitKnownRecord(codeview::CVType &CVR, \
+ codeview::Name##Record &Record) override;
+#define MEMBER_RECORD(EnumName, EnumVal, Name) \
+ Error visitKnownMember(codeview::CVMemberRecord &CVR, \
+ codeview::Name##Record &Record) override;
+#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
+#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
+#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
+
+private:
+ StringRef getTypeName(codeview::TypeIndex TI) const;
+
+ LinePrinter &P;
+ uint32_t Width;
+ bool RecordBytes = false;
+ bool Hashes = false;
+ codeview::LazyRandomTypeCollection &Types;
+ uint32_t NumHashBuckets;
+ FixedStreamArray<support::ulittle32_t> HashValues;
+};
+} // namespace pdb
+} // namespace llvm
+
+#endif
diff --git a/contrib/llvm/tools/llvm-pdbutil/OutputStyle.h b/contrib/llvm/tools/llvm-pdbutil/OutputStyle.h
new file mode 100644
index 0000000..dfefc25
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/OutputStyle.h
@@ -0,0 +1,28 @@
+//===- OutputStyle.h ------------------------------------------ *- 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_OUTPUTSTYLE_H
+#define LLVM_TOOLS_LLVMPDBDUMP_OUTPUTSTYLE_H
+
+#include "llvm/Support/Error.h"
+
+namespace llvm {
+namespace pdb {
+class PDBFile;
+
+class OutputStyle {
+public:
+ virtual ~OutputStyle() {}
+
+ virtual Error dump() = 0;
+};
+}
+}
+
+#endif
diff --git a/contrib/llvm/tools/llvm-pdbutil/PdbYaml.cpp b/contrib/llvm/tools/llvm-pdbutil/PdbYaml.cpp
new file mode 100644
index 0000000..9c3beb5
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/PdbYaml.cpp
@@ -0,0 +1,190 @@
+//===- PdbYAML.cpp -------------------------------------------- *- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PdbYaml.h"
+
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h"
+#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
+#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"
+#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
+#include "llvm/DebugInfo/CodeView/SymbolVisitorCallbackPipeline.h"
+#include "llvm/DebugInfo/CodeView/TypeSerializer.h"
+#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/RawTypes.h"
+#include "llvm/DebugInfo/PDB/Native/TpiHashing.h"
+#include "llvm/DebugInfo/PDB/PDBExtras.h"
+#include "llvm/DebugInfo/PDB/PDBTypes.h"
+#include "llvm/ObjectYAML/CodeViewYAMLDebugSections.h"
+#include "llvm/ObjectYAML/CodeViewYAMLTypes.h"
+
+using namespace llvm;
+using namespace llvm::pdb;
+using namespace llvm::pdb::yaml;
+using namespace llvm::yaml;
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::NamedStreamMapping)
+LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::PdbDbiModuleInfo)
+LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::StreamBlockList)
+LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::pdb::PdbRaw_FeatureSig)
+
+namespace llvm {
+namespace yaml {
+
+template <> struct ScalarEnumerationTraits<llvm::pdb::PDB_Machine> {
+ static void enumeration(IO &io, llvm::pdb::PDB_Machine &Value) {
+ io.enumCase(Value, "Invalid", PDB_Machine::Invalid);
+ io.enumCase(Value, "Am33", PDB_Machine::Am33);
+ io.enumCase(Value, "Amd64", PDB_Machine::Amd64);
+ io.enumCase(Value, "Arm", PDB_Machine::Arm);
+ io.enumCase(Value, "ArmNT", PDB_Machine::ArmNT);
+ io.enumCase(Value, "Ebc", PDB_Machine::Ebc);
+ io.enumCase(Value, "x86", PDB_Machine::x86);
+ io.enumCase(Value, "Ia64", PDB_Machine::Ia64);
+ io.enumCase(Value, "M32R", PDB_Machine::M32R);
+ io.enumCase(Value, "Mips16", PDB_Machine::Mips16);
+ io.enumCase(Value, "MipsFpu", PDB_Machine::MipsFpu);
+ io.enumCase(Value, "MipsFpu16", PDB_Machine::MipsFpu16);
+ io.enumCase(Value, "PowerPCFP", PDB_Machine::PowerPCFP);
+ io.enumCase(Value, "R4000", PDB_Machine::R4000);
+ io.enumCase(Value, "SH3", PDB_Machine::SH3);
+ io.enumCase(Value, "SH3DSP", PDB_Machine::SH3DSP);
+ io.enumCase(Value, "Thumb", PDB_Machine::Thumb);
+ io.enumCase(Value, "WceMipsV2", PDB_Machine::WceMipsV2);
+ }
+};
+
+template <> struct ScalarEnumerationTraits<llvm::pdb::PdbRaw_DbiVer> {
+ static void enumeration(IO &io, llvm::pdb::PdbRaw_DbiVer &Value) {
+ io.enumCase(Value, "V41", llvm::pdb::PdbRaw_DbiVer::PdbDbiVC41);
+ io.enumCase(Value, "V50", llvm::pdb::PdbRaw_DbiVer::PdbDbiV50);
+ io.enumCase(Value, "V60", llvm::pdb::PdbRaw_DbiVer::PdbDbiV60);
+ io.enumCase(Value, "V70", llvm::pdb::PdbRaw_DbiVer::PdbDbiV70);
+ io.enumCase(Value, "V110", llvm::pdb::PdbRaw_DbiVer::PdbDbiV110);
+ }
+};
+
+template <> struct ScalarEnumerationTraits<llvm::pdb::PdbRaw_ImplVer> {
+ static void enumeration(IO &io, llvm::pdb::PdbRaw_ImplVer &Value) {
+ io.enumCase(Value, "VC2", llvm::pdb::PdbRaw_ImplVer::PdbImplVC2);
+ io.enumCase(Value, "VC4", llvm::pdb::PdbRaw_ImplVer::PdbImplVC4);
+ io.enumCase(Value, "VC41", llvm::pdb::PdbRaw_ImplVer::PdbImplVC41);
+ io.enumCase(Value, "VC50", llvm::pdb::PdbRaw_ImplVer::PdbImplVC50);
+ io.enumCase(Value, "VC98", llvm::pdb::PdbRaw_ImplVer::PdbImplVC98);
+ io.enumCase(Value, "VC70Dep", llvm::pdb::PdbRaw_ImplVer::PdbImplVC70Dep);
+ io.enumCase(Value, "VC70", llvm::pdb::PdbRaw_ImplVer::PdbImplVC70);
+ io.enumCase(Value, "VC80", llvm::pdb::PdbRaw_ImplVer::PdbImplVC80);
+ io.enumCase(Value, "VC110", llvm::pdb::PdbRaw_ImplVer::PdbImplVC110);
+ io.enumCase(Value, "VC140", llvm::pdb::PdbRaw_ImplVer::PdbImplVC140);
+ }
+};
+
+template <> struct ScalarEnumerationTraits<llvm::pdb::PdbRaw_TpiVer> {
+ static void enumeration(IO &io, llvm::pdb::PdbRaw_TpiVer &Value) {
+ io.enumCase(Value, "VC40", llvm::pdb::PdbRaw_TpiVer::PdbTpiV40);
+ io.enumCase(Value, "VC41", llvm::pdb::PdbRaw_TpiVer::PdbTpiV41);
+ io.enumCase(Value, "VC50", llvm::pdb::PdbRaw_TpiVer::PdbTpiV50);
+ io.enumCase(Value, "VC70", llvm::pdb::PdbRaw_TpiVer::PdbTpiV70);
+ io.enumCase(Value, "VC80", llvm::pdb::PdbRaw_TpiVer::PdbTpiV80);
+ }
+};
+
+template <> struct ScalarEnumerationTraits<llvm::pdb::PdbRaw_FeatureSig> {
+ static void enumeration(IO &io, PdbRaw_FeatureSig &Features) {
+ io.enumCase(Features, "MinimalDebugInfo",
+ PdbRaw_FeatureSig::MinimalDebugInfo);
+ io.enumCase(Features, "NoTypeMerge", PdbRaw_FeatureSig::NoTypeMerge);
+ io.enumCase(Features, "VC110", PdbRaw_FeatureSig::VC110);
+ io.enumCase(Features, "VC140", PdbRaw_FeatureSig::VC140);
+ }
+};
+}
+}
+
+void MappingTraits<PdbObject>::mapping(IO &IO, PdbObject &Obj) {
+ IO.mapOptional("MSF", Obj.Headers);
+ IO.mapOptional("StreamSizes", Obj.StreamSizes);
+ IO.mapOptional("StreamMap", Obj.StreamMap);
+ IO.mapOptional("StringTable", Obj.StringTable);
+ IO.mapOptional("PdbStream", Obj.PdbStream);
+ IO.mapOptional("DbiStream", Obj.DbiStream);
+ IO.mapOptional("TpiStream", Obj.TpiStream);
+ IO.mapOptional("IpiStream", Obj.IpiStream);
+}
+
+void MappingTraits<MSFHeaders>::mapping(IO &IO, MSFHeaders &Obj) {
+ IO.mapOptional("SuperBlock", Obj.SuperBlock);
+ IO.mapOptional("NumDirectoryBlocks", Obj.NumDirectoryBlocks);
+ IO.mapOptional("DirectoryBlocks", Obj.DirectoryBlocks);
+ IO.mapOptional("NumStreams", Obj.NumStreams);
+ IO.mapOptional("FileSize", Obj.FileSize);
+}
+
+void MappingTraits<msf::SuperBlock>::mapping(IO &IO, msf::SuperBlock &SB) {
+ if (!IO.outputting()) {
+ ::memcpy(SB.MagicBytes, msf::Magic, sizeof(msf::Magic));
+ }
+
+ using u32 = support::ulittle32_t;
+ IO.mapOptional("BlockSize", SB.BlockSize, u32(4096U));
+ IO.mapOptional("FreeBlockMap", SB.FreeBlockMapBlock, u32(0U));
+ IO.mapOptional("NumBlocks", SB.NumBlocks, u32(0U));
+ IO.mapOptional("NumDirectoryBytes", SB.NumDirectoryBytes, u32(0U));
+ IO.mapOptional("Unknown1", SB.Unknown1, u32(0U));
+ IO.mapOptional("BlockMapAddr", SB.BlockMapAddr, u32(0U));
+}
+
+void MappingTraits<StreamBlockList>::mapping(IO &IO, StreamBlockList &SB) {
+ IO.mapRequired("Stream", SB.Blocks);
+}
+
+void MappingTraits<PdbInfoStream>::mapping(IO &IO, PdbInfoStream &Obj) {
+ IO.mapOptional("Age", Obj.Age, 1U);
+ IO.mapOptional("Guid", Obj.Guid);
+ IO.mapOptional("Signature", Obj.Signature, 0U);
+ IO.mapOptional("Features", Obj.Features);
+ IO.mapOptional("Version", Obj.Version, PdbImplVC70);
+}
+
+void MappingTraits<PdbDbiStream>::mapping(IO &IO, PdbDbiStream &Obj) {
+ IO.mapOptional("VerHeader", Obj.VerHeader, PdbDbiV70);
+ IO.mapOptional("Age", Obj.Age, 1U);
+ IO.mapOptional("BuildNumber", Obj.BuildNumber, uint16_t(0U));
+ IO.mapOptional("PdbDllVersion", Obj.PdbDllVersion, 0U);
+ IO.mapOptional("PdbDllRbld", Obj.PdbDllRbld, uint16_t(0U));
+ IO.mapOptional("Flags", Obj.Flags, uint16_t(1U));
+ IO.mapOptional("MachineType", Obj.MachineType, PDB_Machine::x86);
+ IO.mapOptional("Modules", Obj.ModInfos);
+}
+
+void MappingTraits<PdbTpiStream>::mapping(IO &IO,
+ pdb::yaml::PdbTpiStream &Obj) {
+ IO.mapOptional("Version", Obj.Version, PdbTpiV80);
+ IO.mapRequired("Records", Obj.Records);
+}
+
+void MappingTraits<NamedStreamMapping>::mapping(IO &IO,
+ NamedStreamMapping &Obj) {
+ IO.mapRequired("Name", Obj.StreamName);
+ IO.mapRequired("StreamNum", Obj.StreamNumber);
+}
+
+void MappingTraits<PdbModiStream>::mapping(IO &IO, PdbModiStream &Obj) {
+ IO.mapOptional("Signature", Obj.Signature, 4U);
+ IO.mapRequired("Records", Obj.Symbols);
+}
+
+void MappingTraits<PdbDbiModuleInfo>::mapping(IO &IO, PdbDbiModuleInfo &Obj) {
+ IO.mapRequired("Module", Obj.Mod);
+ IO.mapOptional("ObjFile", Obj.Obj, Obj.Mod);
+ IO.mapOptional("SourceFiles", Obj.SourceFiles);
+ IO.mapOptional("Subsections", Obj.Subsections);
+ IO.mapOptional("Modi", Obj.Modi);
+}
diff --git a/contrib/llvm/tools/llvm-pdbutil/PdbYaml.h b/contrib/llvm/tools/llvm-pdbutil/PdbYaml.h
new file mode 100644
index 0000000..91e0544
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/PdbYaml.h
@@ -0,0 +1,125 @@
+//===- PdbYAML.h ---------------------------------------------- *- 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_PDBYAML_H
+#define LLVM_TOOLS_LLVMPDBDUMP_PDBYAML_H
+
+#include "OutputStyle.h"
+
+#include "llvm/ADT/Optional.h"
+#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/DebugInfo/MSF/MSFCommon.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/RawConstants.h"
+#include "llvm/DebugInfo/PDB/PDBTypes.h"
+#include "llvm/ObjectYAML/CodeViewYAMLDebugSections.h"
+#include "llvm/ObjectYAML/CodeViewYAMLSymbols.h"
+#include "llvm/ObjectYAML/CodeViewYAMLTypes.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/YAMLTraits.h"
+
+#include <vector>
+
+namespace llvm {
+namespace codeview {
+class DebugStringTableSubsection;
+}
+namespace pdb {
+
+namespace yaml {
+struct SerializationContext;
+
+struct MSFHeaders {
+ msf::SuperBlock SuperBlock;
+ uint32_t NumDirectoryBlocks = 0;
+ std::vector<uint32_t> DirectoryBlocks;
+ uint32_t NumStreams = 0;
+ uint32_t FileSize = 0;
+};
+
+struct StreamBlockList {
+ std::vector<uint32_t> Blocks;
+};
+
+struct NamedStreamMapping {
+ StringRef StreamName;
+ uint32_t StreamNumber;
+};
+
+struct PdbInfoStream {
+ PdbRaw_ImplVer Version = PdbImplVC70;
+ uint32_t Signature = 0;
+ uint32_t Age = 1;
+ codeview::GUID Guid;
+ std::vector<PdbRaw_FeatureSig> Features;
+ std::vector<NamedStreamMapping> NamedStreams;
+};
+
+struct PdbModiStream {
+ uint32_t Signature;
+ std::vector<CodeViewYAML::SymbolRecord> Symbols;
+};
+
+struct PdbDbiModuleInfo {
+ StringRef Obj;
+ StringRef Mod;
+ std::vector<StringRef> SourceFiles;
+ std::vector<CodeViewYAML::YAMLDebugSubsection> Subsections;
+ Optional<PdbModiStream> Modi;
+};
+
+struct PdbDbiStream {
+ PdbRaw_DbiVer VerHeader = PdbDbiV70;
+ uint32_t Age = 1;
+ uint16_t BuildNumber = 0;
+ uint32_t PdbDllVersion = 0;
+ uint16_t PdbDllRbld = 0;
+ uint16_t Flags = 1;
+ PDB_Machine MachineType = PDB_Machine::x86;
+
+ std::vector<PdbDbiModuleInfo> ModInfos;
+};
+
+struct PdbTpiStream {
+ PdbRaw_TpiVer Version = PdbTpiV80;
+ std::vector<CodeViewYAML::LeafRecord> Records;
+};
+
+struct PdbObject {
+ explicit PdbObject(BumpPtrAllocator &Allocator) : Allocator(Allocator) {}
+
+ Optional<MSFHeaders> Headers;
+ Optional<std::vector<uint32_t>> StreamSizes;
+ Optional<std::vector<StreamBlockList>> StreamMap;
+ Optional<PdbInfoStream> PdbStream;
+ Optional<PdbDbiStream> DbiStream;
+ Optional<PdbTpiStream> TpiStream;
+ Optional<PdbTpiStream> IpiStream;
+
+ Optional<std::vector<StringRef>> StringTable;
+
+ BumpPtrAllocator &Allocator;
+};
+}
+}
+}
+
+LLVM_YAML_DECLARE_MAPPING_TRAITS(pdb::yaml::PdbObject)
+LLVM_YAML_DECLARE_MAPPING_TRAITS(pdb::yaml::MSFHeaders)
+LLVM_YAML_DECLARE_MAPPING_TRAITS(msf::SuperBlock)
+LLVM_YAML_DECLARE_MAPPING_TRAITS(pdb::yaml::StreamBlockList)
+LLVM_YAML_DECLARE_MAPPING_TRAITS(pdb::yaml::PdbInfoStream)
+LLVM_YAML_DECLARE_MAPPING_TRAITS(pdb::yaml::PdbDbiStream)
+LLVM_YAML_DECLARE_MAPPING_TRAITS(pdb::yaml::PdbTpiStream)
+LLVM_YAML_DECLARE_MAPPING_TRAITS(pdb::yaml::NamedStreamMapping)
+LLVM_YAML_DECLARE_MAPPING_TRAITS(pdb::yaml::PdbModiStream)
+LLVM_YAML_DECLARE_MAPPING_TRAITS(pdb::yaml::PdbDbiModuleInfo)
+
+#endif // LLVM_TOOLS_LLVMPDBDUMP_PDBYAML_H
diff --git a/contrib/llvm/tools/llvm-pdbutil/PrettyBuiltinDumper.cpp b/contrib/llvm/tools/llvm-pdbutil/PrettyBuiltinDumper.cpp
new file mode 100644
index 0000000..fcda312
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyBuiltinDumper.cpp
@@ -0,0 +1,94 @@
+//===- PrettyBuiltinDumper.cpp ---------------------------------- *- C++ *-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PrettyBuiltinDumper.h"
+#include "LinePrinter.h"
+#include "llvm-pdbutil.h"
+
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h"
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+BuiltinDumper::BuiltinDumper(LinePrinter &P)
+ : PDBSymDumper(false), Printer(P) {}
+
+void BuiltinDumper::start(const PDBSymbolTypeBuiltin &Symbol) {
+ if (Symbol.isConstType())
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << "const ";
+ if (Symbol.isVolatileType())
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << "volatile ";
+ WithColor(Printer, PDB_ColorItem::Type).get() << getTypeName(Symbol);
+}
+
+StringRef BuiltinDumper::getTypeName(const PDBSymbolTypeBuiltin &Symbol) {
+ PDB_BuiltinType Type = Symbol.getBuiltinType();
+ switch (Type) {
+ case PDB_BuiltinType::Float:
+ if (Symbol.getLength() == 4)
+ return "float";
+ return "double";
+ case PDB_BuiltinType::UInt:
+ switch (Symbol.getLength()) {
+ case 8:
+ return "unsigned __int64";
+ case 4:
+ return "unsigned int";
+ case 2:
+ return "unsigned short";
+ case 1:
+ return "unsigned char";
+ default:
+ return "unsigned";
+ }
+ case PDB_BuiltinType::Int:
+ switch (Symbol.getLength()) {
+ case 8:
+ return "__int64";
+ case 4:
+ return "int";
+ case 2:
+ return "short";
+ case 1:
+ return "char";
+ default:
+ return "int";
+ }
+ case PDB_BuiltinType::Char:
+ return "char";
+ case PDB_BuiltinType::WCharT:
+ return "wchar_t";
+ case PDB_BuiltinType::Void:
+ return "void";
+ case PDB_BuiltinType::Long:
+ return "long";
+ case PDB_BuiltinType::ULong:
+ return "unsigned long";
+ case PDB_BuiltinType::Bool:
+ return "bool";
+ case PDB_BuiltinType::Currency:
+ return "CURRENCY";
+ case PDB_BuiltinType::Date:
+ return "DATE";
+ case PDB_BuiltinType::Variant:
+ return "VARIANT";
+ case PDB_BuiltinType::Complex:
+ return "complex";
+ case PDB_BuiltinType::Bitfield:
+ return "bitfield";
+ case PDB_BuiltinType::BSTR:
+ return "BSTR";
+ case PDB_BuiltinType::HResult:
+ return "HRESULT";
+ case PDB_BuiltinType::BCD:
+ return "HRESULT";
+ default:
+ return "void";
+ }
+}
diff --git a/contrib/llvm/tools/llvm-pdbutil/PrettyBuiltinDumper.h b/contrib/llvm/tools/llvm-pdbutil/PrettyBuiltinDumper.h
new file mode 100644
index 0000000..fb6b0b1
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyBuiltinDumper.h
@@ -0,0 +1,35 @@
+//===- PrettyBuiltinDumper.h ---------------------------------- *- 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_PRETTYBUILTINDUMPER_H
+#define LLVM_TOOLS_LLVMPDBDUMP_PRETTYBUILTINDUMPER_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+
+namespace llvm {
+namespace pdb {
+
+class LinePrinter;
+
+class BuiltinDumper : public PDBSymDumper {
+public:
+ BuiltinDumper(LinePrinter &P);
+
+ void start(const PDBSymbolTypeBuiltin &Symbol);
+
+private:
+ StringRef getTypeName(const PDBSymbolTypeBuiltin &Symbol);
+
+ LinePrinter &Printer;
+};
+}
+}
+
+#endif
diff --git a/contrib/llvm/tools/llvm-pdbutil/PrettyClassDefinitionDumper.cpp b/contrib/llvm/tools/llvm-pdbutil/PrettyClassDefinitionDumper.cpp
new file mode 100644
index 0000000..651cb8b
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyClassDefinitionDumper.cpp
@@ -0,0 +1,108 @@
+//===- PrettyClassDefinitionDumper.cpp --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PrettyClassDefinitionDumper.h"
+
+#include "LinePrinter.h"
+#include "PrettyClassLayoutGraphicalDumper.h"
+#include "llvm-pdbutil.h"
+
+#include "llvm/ADT/APFloat.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
+#include "llvm/DebugInfo/PDB/UDTLayout.h"
+
+#include "llvm/Support/Format.h"
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+ClassDefinitionDumper::ClassDefinitionDumper(LinePrinter &P)
+ : PDBSymDumper(true), Printer(P) {}
+
+void ClassDefinitionDumper::start(const PDBSymbolTypeUDT &Class) {
+ assert(opts::pretty::ClassFormat !=
+ opts::pretty::ClassDefinitionFormat::None);
+
+ ClassLayout Layout(Class);
+ start(Layout);
+}
+
+void ClassDefinitionDumper::start(const ClassLayout &Layout) {
+ prettyPrintClassIntro(Layout);
+
+ PrettyClassLayoutGraphicalDumper Dumper(Printer, 1, 0);
+ DumpedAnything |= Dumper.start(Layout);
+
+ prettyPrintClassOutro(Layout);
+}
+
+void ClassDefinitionDumper::prettyPrintClassIntro(const ClassLayout &Layout) {
+ DumpedAnything = false;
+ Printer.NewLine();
+
+ uint32_t Size = Layout.getSize();
+ const PDBSymbolTypeUDT &Class = Layout.getClass();
+
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << Class.getUdtKind() << " ";
+ WithColor(Printer, PDB_ColorItem::Type).get() << Class.getName();
+ WithColor(Printer, PDB_ColorItem::Comment).get() << " [sizeof = " << Size
+ << "]";
+ uint32_t BaseCount = Layout.bases().size();
+ if (BaseCount > 0) {
+ Printer.Indent();
+ char NextSeparator = ':';
+ for (auto BC : Layout.bases()) {
+ const auto &Base = BC->getBase();
+ if (Base.isIndirectVirtualBaseClass())
+ continue;
+
+ Printer.NewLine();
+ Printer << NextSeparator << " ";
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << Base.getAccess();
+ if (BC->isVirtualBase())
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << " virtual";
+
+ WithColor(Printer, PDB_ColorItem::Type).get() << " " << Base.getName();
+ NextSeparator = ',';
+ }
+
+ Printer.Unindent();
+ }
+
+ Printer << " {";
+ Printer.Indent();
+}
+
+void ClassDefinitionDumper::prettyPrintClassOutro(const ClassLayout &Layout) {
+ Printer.Unindent();
+ if (DumpedAnything)
+ Printer.NewLine();
+ Printer << "}";
+ Printer.NewLine();
+ if (Layout.deepPaddingSize() > 0) {
+ APFloat Pct(100.0 * (double)Layout.deepPaddingSize() /
+ (double)Layout.getSize());
+ SmallString<8> PctStr;
+ Pct.toString(PctStr, 4);
+ WithColor(Printer, PDB_ColorItem::Padding).get()
+ << "Total padding " << Layout.deepPaddingSize() << " bytes (" << PctStr
+ << "% of class size)";
+ Printer.NewLine();
+ APFloat Pct2(100.0 * (double)Layout.immediatePadding() /
+ (double)Layout.getSize());
+ PctStr.clear();
+ Pct2.toString(PctStr, 4);
+ WithColor(Printer, PDB_ColorItem::Padding).get()
+ << "Immediate padding " << Layout.immediatePadding() << " bytes ("
+ << PctStr << "% of class size)";
+ Printer.NewLine();
+ }
+}
diff --git a/contrib/llvm/tools/llvm-pdbutil/PrettyClassDefinitionDumper.h b/contrib/llvm/tools/llvm-pdbutil/PrettyClassDefinitionDumper.h
new file mode 100644
index 0000000..6569a1d
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyClassDefinitionDumper.h
@@ -0,0 +1,47 @@
+//===- PrettyClassDefinitionDumper.h ----------------------------*- 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_PRETTYCLASSDEFINITIONDUMPER_H
+#define LLVM_TOOLS_LLVMPDBDUMP_PRETTYCLASSDEFINITIONDUMPER_H
+
+#include "llvm/ADT/BitVector.h"
+
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
+
+#include <list>
+#include <memory>
+#include <unordered_map>
+
+namespace llvm {
+class BitVector;
+
+namespace pdb {
+
+class ClassLayout;
+class LinePrinter;
+
+class ClassDefinitionDumper : public PDBSymDumper {
+public:
+ ClassDefinitionDumper(LinePrinter &P);
+
+ void start(const PDBSymbolTypeUDT &Class);
+ void start(const ClassLayout &Class);
+
+private:
+ void prettyPrintClassIntro(const ClassLayout &Class);
+ void prettyPrintClassOutro(const ClassLayout &Class);
+
+ LinePrinter &Printer;
+ bool DumpedAnything = false;
+};
+}
+}
+#endif
diff --git a/contrib/llvm/tools/llvm-pdbutil/PrettyClassLayoutGraphicalDumper.cpp b/contrib/llvm/tools/llvm-pdbutil/PrettyClassLayoutGraphicalDumper.cpp
new file mode 100644
index 0000000..66c29fc
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyClassLayoutGraphicalDumper.cpp
@@ -0,0 +1,216 @@
+//===- PrettyClassLayoutGraphicalDumper.h -----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PrettyClassLayoutGraphicalDumper.h"
+
+#include "LinePrinter.h"
+#include "PrettyClassDefinitionDumper.h"
+#include "PrettyEnumDumper.h"
+#include "PrettyFunctionDumper.h"
+#include "PrettyTypedefDumper.h"
+#include "PrettyVariableDumper.h"
+#include "PrettyVariableDumper.h"
+#include "llvm-pdbutil.h"
+
+#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
+#include "llvm/DebugInfo/PDB/UDTLayout.h"
+#include "llvm/Support/Format.h"
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+PrettyClassLayoutGraphicalDumper::PrettyClassLayoutGraphicalDumper(
+ LinePrinter &P, uint32_t RecurseLevel, uint32_t InitialOffset)
+ : PDBSymDumper(true), Printer(P), RecursionLevel(RecurseLevel),
+ ClassOffsetZero(InitialOffset), CurrentAbsoluteOffset(InitialOffset) {}
+
+bool PrettyClassLayoutGraphicalDumper::start(const UDTLayoutBase &Layout) {
+
+ if (RecursionLevel == 1 &&
+ opts::pretty::ClassFormat == opts::pretty::ClassDefinitionFormat::All) {
+ for (auto &Other : Layout.other_items())
+ Other->dump(*this);
+ for (auto &Func : Layout.funcs())
+ Func->dump(*this);
+ }
+
+ const BitVector &UseMap = Layout.usedBytes();
+ int NextPaddingByte = UseMap.find_first_unset();
+
+ for (auto &Item : Layout.layout_items()) {
+ // Calculate the absolute offset of the first byte of the next field.
+ uint32_t RelativeOffset = Item->getOffsetInParent();
+ CurrentAbsoluteOffset = ClassOffsetZero + RelativeOffset;
+
+ // Since there is storage there, it should be set! However, this might
+ // be an empty base, in which case it could extend outside the bounds of
+ // the parent class.
+ if (RelativeOffset < UseMap.size() && (Item->getSize() > 0)) {
+ assert(UseMap.test(RelativeOffset));
+
+ // If there is any remaining padding in this class, and the offset of the
+ // new item is after the padding, then we must have just jumped over some
+ // padding. Print a padding row and then look for where the next block
+ // of padding begins.
+ if ((NextPaddingByte >= 0) &&
+ (RelativeOffset > uint32_t(NextPaddingByte))) {
+ printPaddingRow(RelativeOffset - NextPaddingByte);
+ NextPaddingByte = UseMap.find_next_unset(RelativeOffset);
+ }
+ }
+
+ CurrentItem = Item;
+ if (Item->isVBPtr()) {
+ VTableLayoutItem &Layout = static_cast<VTableLayoutItem &>(*CurrentItem);
+
+ VariableDumper VarDumper(Printer);
+ VarDumper.startVbptr(CurrentAbsoluteOffset, Layout.getSize());
+ } else {
+ if (auto Sym = Item->getSymbol())
+ Sym->dump(*this);
+ }
+
+ if (Item->getLayoutSize() > 0) {
+ uint32_t Prev = RelativeOffset + Item->getLayoutSize() - 1;
+ if (Prev < UseMap.size())
+ NextPaddingByte = UseMap.find_next_unset(Prev);
+ }
+ }
+
+ auto TailPadding = Layout.tailPadding();
+ if (TailPadding > 0) {
+ if (TailPadding != 1 || Layout.getSize() != 1) {
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::Padding).get()
+ << "<padding> (" << TailPadding << " bytes)";
+ DumpedAnything = true;
+ }
+ }
+
+ return DumpedAnything;
+}
+
+void PrettyClassLayoutGraphicalDumper::printPaddingRow(uint32_t Amount) {
+ if (Amount == 0)
+ return;
+
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::Padding).get() << "<padding> (" << Amount
+ << " bytes)";
+ DumpedAnything = true;
+}
+
+void PrettyClassLayoutGraphicalDumper::dump(
+ const PDBSymbolTypeBaseClass &Symbol) {
+ assert(CurrentItem != nullptr);
+
+ Printer.NewLine();
+ BaseClassLayout &Layout = static_cast<BaseClassLayout &>(*CurrentItem);
+
+ std::string Label = "base";
+ if (Layout.isVirtualBase()) {
+ Label.insert(Label.begin(), 'v');
+ if (Layout.getBase().isIndirectVirtualBaseClass())
+ Label.insert(Label.begin(), 'i');
+ }
+ Printer << Label << " ";
+
+ uint32_t Size = Layout.isEmptyBase() ? 1 : Layout.getLayoutSize();
+
+ WithColor(Printer, PDB_ColorItem::Offset).get()
+ << "+" << format_hex(CurrentAbsoluteOffset, 4) << " [sizeof=" << Size
+ << "] ";
+
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << Layout.getName();
+
+ if (shouldRecurse()) {
+ Printer.Indent();
+ uint32_t ChildOffsetZero = ClassOffsetZero + Layout.getOffsetInParent();
+ PrettyClassLayoutGraphicalDumper BaseDumper(Printer, RecursionLevel + 1,
+ ChildOffsetZero);
+ DumpedAnything |= BaseDumper.start(Layout);
+ Printer.Unindent();
+ }
+
+ DumpedAnything = true;
+}
+
+bool PrettyClassLayoutGraphicalDumper::shouldRecurse() const {
+ uint32_t Limit = opts::pretty::ClassRecursionDepth;
+ if (Limit == 0)
+ return true;
+ return RecursionLevel < Limit;
+}
+
+void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolData &Symbol) {
+ VariableDumper VarDumper(Printer);
+ VarDumper.start(Symbol, ClassOffsetZero);
+
+ if (CurrentItem != nullptr) {
+ DataMemberLayoutItem &Layout =
+ static_cast<DataMemberLayoutItem &>(*CurrentItem);
+
+ if (Layout.hasUDTLayout() && shouldRecurse()) {
+ uint32_t ChildOffsetZero = ClassOffsetZero + Layout.getOffsetInParent();
+ Printer.Indent();
+ PrettyClassLayoutGraphicalDumper TypeDumper(Printer, RecursionLevel + 1,
+ ChildOffsetZero);
+ TypeDumper.start(Layout.getUDTLayout());
+ Printer.Unindent();
+ }
+ }
+
+ DumpedAnything = true;
+}
+
+void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeVTable &Symbol) {
+ assert(CurrentItem != nullptr);
+
+ VariableDumper VarDumper(Printer);
+ VarDumper.start(Symbol, ClassOffsetZero);
+
+ DumpedAnything = true;
+}
+
+void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeEnum &Symbol) {
+ DumpedAnything = true;
+ Printer.NewLine();
+ EnumDumper Dumper(Printer);
+ Dumper.start(Symbol);
+}
+
+void PrettyClassLayoutGraphicalDumper::dump(
+ const PDBSymbolTypeTypedef &Symbol) {
+ DumpedAnything = true;
+ Printer.NewLine();
+ TypedefDumper Dumper(Printer);
+ Dumper.start(Symbol);
+}
+
+void PrettyClassLayoutGraphicalDumper::dump(
+ const PDBSymbolTypeBuiltin &Symbol) {}
+
+void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeUDT &Symbol) {}
+
+void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolFunc &Symbol) {
+ if (Printer.IsSymbolExcluded(Symbol.getName()))
+ return;
+ if (Symbol.isCompilerGenerated() && opts::pretty::ExcludeCompilerGenerated)
+ return;
+ if (Symbol.getLength() == 0 && !Symbol.isPureVirtual() &&
+ !Symbol.isIntroVirtualFunction())
+ return;
+
+ DumpedAnything = true;
+ Printer.NewLine();
+ FunctionDumper Dumper(Printer);
+ Dumper.start(Symbol, FunctionDumper::PointerType::None);
+}
diff --git a/contrib/llvm/tools/llvm-pdbutil/PrettyClassLayoutGraphicalDumper.h b/contrib/llvm/tools/llvm-pdbutil/PrettyClassLayoutGraphicalDumper.h
new file mode 100644
index 0000000..f83f1a6
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyClassLayoutGraphicalDumper.h
@@ -0,0 +1,58 @@
+//===- PrettyClassLayoutGraphicalDumper.h -----------------------*- 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_PRETTYCLASSLAYOUTGRAPHICALDUMPER_H
+#define LLVM_TOOLS_LLVMPDBDUMP_PRETTYCLASSLAYOUTGRAPHICALDUMPER_H
+
+#include "llvm/ADT/BitVector.h"
+
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+
+namespace llvm {
+
+namespace pdb {
+
+class UDTLayoutBase;
+class LayoutItemBase;
+class LinePrinter;
+
+class PrettyClassLayoutGraphicalDumper : public PDBSymDumper {
+public:
+ PrettyClassLayoutGraphicalDumper(LinePrinter &P, uint32_t RecurseLevel,
+ uint32_t InitialOffset);
+
+ bool start(const UDTLayoutBase &Layout);
+
+ // Layout based symbol types.
+ void dump(const PDBSymbolTypeBaseClass &Symbol) override;
+ void dump(const PDBSymbolData &Symbol) override;
+ void dump(const PDBSymbolTypeVTable &Symbol) override;
+
+ // Non layout-based symbol types.
+ void dump(const PDBSymbolTypeEnum &Symbol) override;
+ void dump(const PDBSymbolFunc &Symbol) override;
+ void dump(const PDBSymbolTypeTypedef &Symbol) override;
+ void dump(const PDBSymbolTypeUDT &Symbol) override;
+ void dump(const PDBSymbolTypeBuiltin &Symbol) override;
+
+private:
+ bool shouldRecurse() const;
+ void printPaddingRow(uint32_t Amount);
+
+ LinePrinter &Printer;
+
+ LayoutItemBase *CurrentItem = nullptr;
+ uint32_t RecursionLevel = 0;
+ uint32_t ClassOffsetZero = 0;
+ uint32_t CurrentAbsoluteOffset = 0;
+ bool DumpedAnything = false;
+};
+}
+}
+#endif
diff --git a/contrib/llvm/tools/llvm-pdbutil/PrettyCompilandDumper.cpp b/contrib/llvm/tools/llvm-pdbutil/PrettyCompilandDumper.cpp
new file mode 100644
index 0000000..65e8bad
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyCompilandDumper.cpp
@@ -0,0 +1,207 @@
+//===- PrettyCompilandDumper.cpp - llvm-pdbutil compiland dumper -*- C++ *-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PrettyCompilandDumper.h"
+
+#include "LinePrinter.h"
+#include "PrettyFunctionDumper.h"
+#include "llvm-pdbutil.h"
+
+#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"
+#include "llvm/DebugInfo/PDB/IPDBLineNumber.h"
+#include "llvm/DebugInfo/PDB/IPDBSession.h"
+#include "llvm/DebugInfo/PDB/IPDBSourceFile.h"
+#include "llvm/DebugInfo/PDB/PDBExtras.h"
+#include "llvm/DebugInfo/PDB/PDBSymbol.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugEnd.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugStart.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolLabel.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolThunk.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolUnknown.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <utility>
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+CompilandDumper::CompilandDumper(LinePrinter &P)
+ : PDBSymDumper(true), Printer(P) {}
+
+void CompilandDumper::dump(const PDBSymbolCompilandDetails &Symbol) {}
+
+void CompilandDumper::dump(const PDBSymbolCompilandEnv &Symbol) {}
+
+void CompilandDumper::start(const PDBSymbolCompiland &Symbol,
+ CompilandDumpFlags opts) {
+ std::string FullName = Symbol.getName();
+ if (Printer.IsCompilandExcluded(FullName))
+ return;
+
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::Path).get() << FullName;
+
+ if (opts & Flags::Lines) {
+ const IPDBSession &Session = Symbol.getSession();
+ auto Files = Session.getSourceFilesForCompiland(Symbol);
+ Printer.Indent();
+ while (auto File = Files->getNext()) {
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::Path).get() << File->getFileName();
+
+ auto Lines = Session.findLineNumbers(Symbol, *File);
+ Printer.Indent();
+ while (auto Line = Lines->getNext()) {
+ Printer.NewLine();
+ uint32_t LineStart = Line->getLineNumber();
+ uint32_t LineEnd = Line->getLineNumberEnd();
+
+ Printer << "Line ";
+ PDB_ColorItem StatementColor = Line->isStatement()
+ ? PDB_ColorItem::Keyword
+ : PDB_ColorItem::LiteralValue;
+ WithColor(Printer, StatementColor).get() << LineStart;
+ if (LineStart != LineEnd)
+ WithColor(Printer, StatementColor).get() << " - " << LineEnd;
+
+ uint32_t ColumnStart = Line->getColumnNumber();
+ uint32_t ColumnEnd = Line->getColumnNumberEnd();
+ if (ColumnStart != 0 || ColumnEnd != 0) {
+ Printer << ", Column: ";
+ WithColor(Printer, StatementColor).get() << ColumnStart;
+ if (ColumnEnd != ColumnStart)
+ WithColor(Printer, StatementColor).get() << " - " << ColumnEnd;
+ }
+
+ Printer << ", Address: ";
+ if (Line->getLength() > 0) {
+ uint64_t AddrStart = Line->getVirtualAddress();
+ uint64_t AddrEnd = AddrStart + Line->getLength() - 1;
+ WithColor(Printer, PDB_ColorItem::Address).get()
+ << "[" << format_hex(AddrStart, 10) << " - "
+ << format_hex(AddrEnd, 10) << "]";
+ Printer << " (" << Line->getLength() << " bytes)";
+ } else {
+ uint64_t AddrStart = Line->getVirtualAddress();
+ WithColor(Printer, PDB_ColorItem::Address).get()
+ << "[" << format_hex(AddrStart, 10) << "] ";
+ Printer << "(0 bytes)";
+ }
+ }
+ Printer.Unindent();
+ }
+ Printer.Unindent();
+ }
+
+ if (opts & Flags::Children) {
+ auto ChildrenEnum = Symbol.findAllChildren();
+ Printer.Indent();
+ while (auto Child = ChildrenEnum->getNext())
+ Child->dump(*this);
+ Printer.Unindent();
+ }
+}
+
+void CompilandDumper::dump(const PDBSymbolData &Symbol) {
+ if (!shouldDumpSymLevel(opts::pretty::SymLevel::Data))
+ return;
+ if (Printer.IsSymbolExcluded(Symbol.getName()))
+ return;
+
+ Printer.NewLine();
+
+ switch (auto LocType = Symbol.getLocationType()) {
+ case PDB_LocType::Static:
+ Printer << "data: ";
+ WithColor(Printer, PDB_ColorItem::Address).get()
+ << "[" << format_hex(Symbol.getVirtualAddress(), 10) << "]";
+
+ WithColor(Printer, PDB_ColorItem::Comment).get()
+ << " [sizeof = " << getTypeLength(Symbol) << "]";
+
+ break;
+ case PDB_LocType::Constant:
+ Printer << "constant: ";
+ WithColor(Printer, PDB_ColorItem::LiteralValue).get()
+ << "[" << Symbol.getValue() << "]";
+ WithColor(Printer, PDB_ColorItem::Comment).get()
+ << " [sizeof = " << getTypeLength(Symbol) << "]";
+ break;
+ default:
+ Printer << "data(unexpected type=" << LocType << ")";
+ }
+
+ Printer << " ";
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << Symbol.getName();
+}
+
+void CompilandDumper::dump(const PDBSymbolFunc &Symbol) {
+ if (!shouldDumpSymLevel(opts::pretty::SymLevel::Functions))
+ return;
+ if (Symbol.getLength() == 0)
+ return;
+ if (Printer.IsSymbolExcluded(Symbol.getName()))
+ return;
+
+ Printer.NewLine();
+ FunctionDumper Dumper(Printer);
+ Dumper.start(Symbol, FunctionDumper::PointerType::None);
+}
+
+void CompilandDumper::dump(const PDBSymbolLabel &Symbol) {
+ if (Printer.IsSymbolExcluded(Symbol.getName()))
+ return;
+
+ Printer.NewLine();
+ Printer << "label ";
+ WithColor(Printer, PDB_ColorItem::Address).get()
+ << "[" << format_hex(Symbol.getVirtualAddress(), 10) << "] ";
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << Symbol.getName();
+}
+
+void CompilandDumper::dump(const PDBSymbolThunk &Symbol) {
+ if (!shouldDumpSymLevel(opts::pretty::SymLevel::Thunks))
+ return;
+ if (Printer.IsSymbolExcluded(Symbol.getName()))
+ return;
+
+ Printer.NewLine();
+ Printer << "thunk ";
+ codeview::ThunkOrdinal Ordinal = Symbol.getThunkOrdinal();
+ uint64_t VA = Symbol.getVirtualAddress();
+ if (Ordinal == codeview::ThunkOrdinal::TrampIncremental) {
+ uint64_t Target = Symbol.getTargetVirtualAddress();
+ WithColor(Printer, PDB_ColorItem::Address).get() << format_hex(VA, 10);
+ Printer << " -> ";
+ WithColor(Printer, PDB_ColorItem::Address).get() << format_hex(Target, 10);
+ } else {
+ WithColor(Printer, PDB_ColorItem::Address).get()
+ << "[" << format_hex(VA, 10) << " - "
+ << format_hex(VA + Symbol.getLength(), 10) << "]";
+ }
+ Printer << " (";
+ WithColor(Printer, PDB_ColorItem::Register).get() << Ordinal;
+ Printer << ") ";
+ std::string Name = Symbol.getName();
+ if (!Name.empty())
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << Name;
+}
+
+void CompilandDumper::dump(const PDBSymbolTypeTypedef &Symbol) {}
+
+void CompilandDumper::dump(const PDBSymbolUnknown &Symbol) {
+ Printer.NewLine();
+ Printer << "unknown (" << Symbol.getSymTag() << ")";
+}
diff --git a/contrib/llvm/tools/llvm-pdbutil/PrettyCompilandDumper.h b/contrib/llvm/tools/llvm-pdbutil/PrettyCompilandDumper.h
new file mode 100644
index 0000000..cae196e
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyCompilandDumper.h
@@ -0,0 +1,44 @@
+//===- PrettyCompilandDumper.h - llvm-pdbutil compiland dumper -*- 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_PRETTYCOMPILANDDUMPER_H
+#define LLVM_TOOLS_LLVMPDBDUMP_PRETTYCOMPILANDDUMPER_H
+
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+
+namespace llvm {
+namespace pdb {
+
+class LinePrinter;
+
+typedef int CompilandDumpFlags;
+class CompilandDumper : public PDBSymDumper {
+public:
+ enum Flags { None = 0x0, Children = 0x1, Symbols = 0x2, Lines = 0x4 };
+
+ CompilandDumper(LinePrinter &P);
+
+ void start(const PDBSymbolCompiland &Symbol, CompilandDumpFlags flags);
+
+ void dump(const PDBSymbolCompilandDetails &Symbol) override;
+ void dump(const PDBSymbolCompilandEnv &Symbol) override;
+ void dump(const PDBSymbolData &Symbol) override;
+ void dump(const PDBSymbolFunc &Symbol) override;
+ void dump(const PDBSymbolLabel &Symbol) override;
+ void dump(const PDBSymbolThunk &Symbol) override;
+ void dump(const PDBSymbolTypeTypedef &Symbol) override;
+ void dump(const PDBSymbolUnknown &Symbol) override;
+
+private:
+ LinePrinter &Printer;
+};
+}
+}
+
+#endif
diff --git a/contrib/llvm/tools/llvm-pdbutil/PrettyEnumDumper.cpp b/contrib/llvm/tools/llvm-pdbutil/PrettyEnumDumper.cpp
new file mode 100644
index 0000000..7aff5b9
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyEnumDumper.cpp
@@ -0,0 +1,53 @@
+//===- PrettyEnumDumper.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PrettyEnumDumper.h"
+
+#include "LinePrinter.h"
+#include "PrettyBuiltinDumper.h"
+#include "llvm-pdbutil.h"
+
+#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+EnumDumper::EnumDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {}
+
+void EnumDumper::start(const PDBSymbolTypeEnum &Symbol) {
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << "enum ";
+ WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName();
+ if (!opts::pretty::NoEnumDefs) {
+ auto BuiltinType = Symbol.getUnderlyingType();
+ if (BuiltinType->getBuiltinType() != PDB_BuiltinType::Int ||
+ BuiltinType->getLength() != 4) {
+ Printer << " : ";
+ BuiltinDumper Dumper(Printer);
+ Dumper.start(*BuiltinType);
+ }
+ Printer << " {";
+ Printer.Indent();
+ auto EnumValues = Symbol.findAllChildren<PDBSymbolData>();
+ while (auto EnumValue = EnumValues->getNext()) {
+ if (EnumValue->getDataKind() != PDB_DataKind::Constant)
+ continue;
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::Identifier).get()
+ << EnumValue->getName();
+ Printer << " = ";
+ WithColor(Printer, PDB_ColorItem::LiteralValue).get()
+ << EnumValue->getValue();
+ }
+ Printer.Unindent();
+ Printer.NewLine();
+ Printer << "}";
+ }
+}
diff --git a/contrib/llvm/tools/llvm-pdbutil/PrettyEnumDumper.h b/contrib/llvm/tools/llvm-pdbutil/PrettyEnumDumper.h
new file mode 100644
index 0000000..c6e65a6
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyEnumDumper.h
@@ -0,0 +1,31 @@
+//===- PrettyEnumDumper.h ---------------------------------------*- 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_PRETTYENUMDUMPER_H
+#define LLVM_TOOLS_LLVMPDBDUMP_PRETTYENUMDUMPER_H
+
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+
+namespace llvm {
+namespace pdb {
+
+class LinePrinter;
+
+class EnumDumper : public PDBSymDumper {
+public:
+ EnumDumper(LinePrinter &P);
+
+ void start(const PDBSymbolTypeEnum &Symbol);
+
+private:
+ LinePrinter &Printer;
+};
+}
+}
+#endif
diff --git a/contrib/llvm/tools/llvm-pdbutil/PrettyExternalSymbolDumper.cpp b/contrib/llvm/tools/llvm-pdbutil/PrettyExternalSymbolDumper.cpp
new file mode 100644
index 0000000..fc40d90
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyExternalSymbolDumper.cpp
@@ -0,0 +1,41 @@
+//===- PrettyExternalSymbolDumper.cpp -------------------------- *- C++ *-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PrettyExternalSymbolDumper.h"
+#include "LinePrinter.h"
+
+#include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolPublicSymbol.h"
+#include "llvm/Support/Format.h"
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+ExternalSymbolDumper::ExternalSymbolDumper(LinePrinter &P)
+ : PDBSymDumper(true), Printer(P) {}
+
+void ExternalSymbolDumper::start(const PDBSymbolExe &Symbol) {
+ auto Vars = Symbol.findAllChildren<PDBSymbolPublicSymbol>();
+ while (auto Var = Vars->getNext())
+ Var->dump(*this);
+}
+
+void ExternalSymbolDumper::dump(const PDBSymbolPublicSymbol &Symbol) {
+ std::string LinkageName = Symbol.getName();
+ if (Printer.IsSymbolExcluded(LinkageName))
+ return;
+
+ Printer.NewLine();
+ uint64_t Addr = Symbol.getVirtualAddress();
+
+ Printer << "[";
+ WithColor(Printer, PDB_ColorItem::Address).get() << format_hex(Addr, 10);
+ Printer << "] ";
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << LinkageName;
+}
diff --git a/contrib/llvm/tools/llvm-pdbutil/PrettyExternalSymbolDumper.h b/contrib/llvm/tools/llvm-pdbutil/PrettyExternalSymbolDumper.h
new file mode 100644
index 0000000..6a00986
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyExternalSymbolDumper.h
@@ -0,0 +1,34 @@
+//===- PrettyExternalSymbolDumper.h --------------------------- *- 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_PRETTYEXTERNALSYMBOLDUMPER_H
+#define LLVM_TOOLS_LLVMPDBDUMP_PRETTYEXTERNALSYMBOLDUMPER_H
+
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+
+namespace llvm {
+namespace pdb {
+
+class LinePrinter;
+
+class ExternalSymbolDumper : public PDBSymDumper {
+public:
+ ExternalSymbolDumper(LinePrinter &P);
+
+ void start(const PDBSymbolExe &Symbol);
+
+ void dump(const PDBSymbolPublicSymbol &Symbol) override;
+
+private:
+ LinePrinter &Printer;
+};
+}
+}
+
+#endif
diff --git a/contrib/llvm/tools/llvm-pdbutil/PrettyFunctionDumper.cpp b/contrib/llvm/tools/llvm-pdbutil/PrettyFunctionDumper.cpp
new file mode 100644
index 0000000..06d7241
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyFunctionDumper.cpp
@@ -0,0 +1,259 @@
+//===- PrettyFunctionDumper.cpp --------------------------------- *- C++ *-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PrettyFunctionDumper.h"
+#include "LinePrinter.h"
+#include "PrettyBuiltinDumper.h"
+#include "llvm-pdbutil.h"
+
+#include "llvm/DebugInfo/PDB/IPDBSession.h"
+#include "llvm/DebugInfo/PDB/PDBExtras.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugEnd.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugStart.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeArray.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionArg.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/FormatVariadic.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+namespace {
+template <class T>
+void dumpClassParentWithScopeOperator(const T &Symbol, LinePrinter &Printer,
+ FunctionDumper &Dumper) {
+ uint32_t ClassParentId = Symbol.getClassParentId();
+ auto ClassParent =
+ Symbol.getSession().template getConcreteSymbolById<PDBSymbolTypeUDT>(
+ ClassParentId);
+ if (!ClassParent)
+ return;
+
+ WithColor(Printer, PDB_ColorItem::Type).get() << ClassParent->getName();
+ Printer << "::";
+}
+}
+
+FunctionDumper::FunctionDumper(LinePrinter &P)
+ : PDBSymDumper(true), Printer(P) {}
+
+void FunctionDumper::start(const PDBSymbolTypeFunctionSig &Symbol,
+ const char *Name, PointerType Pointer) {
+ auto ReturnType = Symbol.getReturnType();
+ ReturnType->dump(*this);
+ Printer << " ";
+ uint32_t ClassParentId = Symbol.getClassParentId();
+ auto ClassParent =
+ Symbol.getSession().getConcreteSymbolById<PDBSymbolTypeUDT>(
+ ClassParentId);
+
+ PDB_CallingConv CC = Symbol.getCallingConvention();
+ bool ShouldDumpCallingConvention = true;
+ if ((ClassParent && CC == CallingConvention::ThisCall) ||
+ (!ClassParent && CC == CallingConvention::NearStdCall)) {
+ ShouldDumpCallingConvention = false;
+ }
+
+ if (Pointer == PointerType::None) {
+ if (ShouldDumpCallingConvention)
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << CC << " ";
+ if (ClassParent) {
+ Printer << "(";
+ WithColor(Printer, PDB_ColorItem::Identifier).get()
+ << ClassParent->getName();
+ Printer << "::)";
+ }
+ } else {
+ Printer << "(";
+ if (ShouldDumpCallingConvention)
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << CC << " ";
+ if (ClassParent) {
+ WithColor(Printer, PDB_ColorItem::Identifier).get()
+ << ClassParent->getName();
+ Printer << "::";
+ }
+ if (Pointer == PointerType::Reference)
+ Printer << "&";
+ else
+ Printer << "*";
+ if (Name)
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << Name;
+ Printer << ")";
+ }
+
+ Printer << "(";
+ if (auto ChildEnum = Symbol.getArguments()) {
+ uint32_t Index = 0;
+ while (auto Arg = ChildEnum->getNext()) {
+ Arg->dump(*this);
+ if (++Index < ChildEnum->getChildCount())
+ Printer << ", ";
+ }
+ }
+ Printer << ")";
+
+ if (Symbol.isConstType())
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << " const";
+ if (Symbol.isVolatileType())
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << " volatile";
+}
+
+void FunctionDumper::start(const PDBSymbolFunc &Symbol, PointerType Pointer) {
+ uint64_t FuncStart = Symbol.getVirtualAddress();
+ uint64_t FuncEnd = FuncStart + Symbol.getLength();
+
+ Printer << "func [";
+ WithColor(Printer, PDB_ColorItem::Address).get() << format_hex(FuncStart, 10);
+ if (auto DebugStart = Symbol.findOneChild<PDBSymbolFuncDebugStart>()) {
+ uint64_t Prologue = DebugStart->getVirtualAddress() - FuncStart;
+ WithColor(Printer, PDB_ColorItem::Offset).get()
+ << formatv("+{0,2}", Prologue);
+ }
+ Printer << " - ";
+ WithColor(Printer, PDB_ColorItem::Address).get() << format_hex(FuncEnd, 10);
+ if (auto DebugEnd = Symbol.findOneChild<PDBSymbolFuncDebugEnd>()) {
+ uint64_t Epilogue = FuncEnd - DebugEnd->getVirtualAddress();
+ WithColor(Printer, PDB_ColorItem::Offset).get()
+ << formatv("-{0,2}", Epilogue);
+ }
+
+ WithColor(Printer, PDB_ColorItem::Comment).get()
+ << formatv(" | sizeof={0,3}", Symbol.getLength());
+ Printer << "] (";
+
+ if (Symbol.hasFramePointer()) {
+ WithColor(Printer, PDB_ColorItem::Register).get()
+ << Symbol.getLocalBasePointerRegisterId();
+ } else {
+ WithColor(Printer, PDB_ColorItem::Register).get() << "FPO";
+ }
+ Printer << ") ";
+
+ if (Symbol.isVirtual() || Symbol.isPureVirtual())
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << "virtual ";
+
+ auto Signature = Symbol.getSignature();
+ if (!Signature) {
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << Symbol.getName();
+ if (Pointer == PointerType::Pointer)
+ Printer << "*";
+ else if (Pointer == FunctionDumper::PointerType::Reference)
+ Printer << "&";
+ return;
+ }
+
+ auto ReturnType = Signature->getReturnType();
+ ReturnType->dump(*this);
+ Printer << " ";
+
+ auto ClassParent = Symbol.getClassParent();
+ CallingConvention CC = Signature->getCallingConvention();
+ if (Pointer != FunctionDumper::PointerType::None)
+ Printer << "(";
+
+ if ((ClassParent && CC != CallingConvention::ThisCall) ||
+ (!ClassParent && CC != CallingConvention::NearStdCall)) {
+ WithColor(Printer, PDB_ColorItem::Keyword).get()
+ << Signature->getCallingConvention() << " ";
+ }
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << Symbol.getName();
+ if (Pointer != FunctionDumper::PointerType::None) {
+ if (Pointer == PointerType::Pointer)
+ Printer << "*";
+ else if (Pointer == FunctionDumper::PointerType::Reference)
+ Printer << "&";
+ Printer << ")";
+ }
+
+ Printer << "(";
+ if (auto Arguments = Symbol.getArguments()) {
+ uint32_t Index = 0;
+ while (auto Arg = Arguments->getNext()) {
+ auto ArgType = Arg->getType();
+ ArgType->dump(*this);
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << " "
+ << Arg->getName();
+ if (++Index < Arguments->getChildCount())
+ Printer << ", ";
+ }
+ }
+ Printer << ")";
+ if (Symbol.isConstType())
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << " const";
+ if (Symbol.isVolatileType())
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << " volatile";
+ if (Symbol.isPureVirtual())
+ Printer << " = 0";
+}
+
+void FunctionDumper::dump(const PDBSymbolTypeArray &Symbol) {
+ auto ElementType = Symbol.getElementType();
+
+ ElementType->dump(*this);
+ Printer << "[";
+ WithColor(Printer, PDB_ColorItem::LiteralValue).get() << Symbol.getLength();
+ Printer << "]";
+}
+
+void FunctionDumper::dump(const PDBSymbolTypeBuiltin &Symbol) {
+ BuiltinDumper Dumper(Printer);
+ Dumper.start(Symbol);
+}
+
+void FunctionDumper::dump(const PDBSymbolTypeEnum &Symbol) {
+ dumpClassParentWithScopeOperator(Symbol, Printer, *this);
+ WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName();
+}
+
+void FunctionDumper::dump(const PDBSymbolTypeFunctionArg &Symbol) {
+ // PDBSymbolTypeFunctionArg is just a shim over the real argument. Just drill
+ // through to the real thing and dump it.
+ uint32_t TypeId = Symbol.getTypeId();
+ auto Type = Symbol.getSession().getSymbolById(TypeId);
+ if (!Type)
+ return;
+ Type->dump(*this);
+}
+
+void FunctionDumper::dump(const PDBSymbolTypeTypedef &Symbol) {
+ dumpClassParentWithScopeOperator(Symbol, Printer, *this);
+ WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName();
+}
+
+void FunctionDumper::dump(const PDBSymbolTypePointer &Symbol) {
+ auto PointeeType = Symbol.getPointeeType();
+ if (!PointeeType)
+ return;
+
+ if (auto FuncSig = unique_dyn_cast<PDBSymbolTypeFunctionSig>(PointeeType)) {
+ FunctionDumper NestedDumper(Printer);
+ PointerType Pointer =
+ Symbol.isReference() ? PointerType::Reference : PointerType::Pointer;
+ NestedDumper.start(*FuncSig, nullptr, Pointer);
+ } else {
+ if (Symbol.isConstType())
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << "const ";
+ if (Symbol.isVolatileType())
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << "volatile ";
+ PointeeType->dump(*this);
+ Printer << (Symbol.isReference() ? "&" : "*");
+ }
+}
+
+void FunctionDumper::dump(const PDBSymbolTypeUDT &Symbol) {
+ WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName();
+}
diff --git a/contrib/llvm/tools/llvm-pdbutil/PrettyFunctionDumper.h b/contrib/llvm/tools/llvm-pdbutil/PrettyFunctionDumper.h
new file mode 100644
index 0000000..1a6f543
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyFunctionDumper.h
@@ -0,0 +1,43 @@
+//===- PrettyFunctionDumper.h --------------------------------- *- 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_PRETTYFUNCTIONDUMPER_H
+#define LLVM_TOOLS_LLVMPDBDUMP_PRETTYFUNCTIONDUMPER_H
+
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+
+namespace llvm {
+namespace pdb {
+class LinePrinter;
+
+class FunctionDumper : public PDBSymDumper {
+public:
+ FunctionDumper(LinePrinter &P);
+
+ enum class PointerType { None, Pointer, Reference };
+
+ void start(const PDBSymbolTypeFunctionSig &Symbol, const char *Name,
+ PointerType Pointer);
+ void start(const PDBSymbolFunc &Symbol, PointerType Pointer);
+
+ void dump(const PDBSymbolTypeArray &Symbol) override;
+ void dump(const PDBSymbolTypeBuiltin &Symbol) override;
+ void dump(const PDBSymbolTypeEnum &Symbol) override;
+ void dump(const PDBSymbolTypeFunctionArg &Symbol) override;
+ void dump(const PDBSymbolTypePointer &Symbol) override;
+ void dump(const PDBSymbolTypeTypedef &Symbol) override;
+ void dump(const PDBSymbolTypeUDT &Symbol) override;
+
+private:
+ LinePrinter &Printer;
+};
+}
+}
+
+#endif
diff --git a/contrib/llvm/tools/llvm-pdbutil/PrettyTypeDumper.cpp b/contrib/llvm/tools/llvm-pdbutil/PrettyTypeDumper.cpp
new file mode 100644
index 0000000..0f60863
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyTypeDumper.cpp
@@ -0,0 +1,255 @@
+//===- PrettyTypeDumper.cpp - PDBSymDumper type dumper *------------ C++ *-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PrettyTypeDumper.h"
+
+#include "LinePrinter.h"
+#include "PrettyBuiltinDumper.h"
+#include "PrettyClassDefinitionDumper.h"
+#include "PrettyEnumDumper.h"
+#include "PrettyTypedefDumper.h"
+#include "llvm-pdbutil.h"
+
+#include "llvm/DebugInfo/PDB/IPDBSession.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
+#include "llvm/DebugInfo/PDB/UDTLayout.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/FormatVariadic.h"
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+using LayoutPtr = std::unique_ptr<ClassLayout>;
+
+typedef bool (*CompareFunc)(const LayoutPtr &S1, const LayoutPtr &S2);
+
+static bool CompareNames(const LayoutPtr &S1, const LayoutPtr &S2) {
+ return S1->getName() < S2->getName();
+}
+
+static bool CompareSizes(const LayoutPtr &S1, const LayoutPtr &S2) {
+ return S1->getSize() < S2->getSize();
+}
+
+static bool ComparePadding(const LayoutPtr &S1, const LayoutPtr &S2) {
+ return S1->deepPaddingSize() < S2->deepPaddingSize();
+}
+
+static bool ComparePaddingPct(const LayoutPtr &S1, const LayoutPtr &S2) {
+ double Pct1 = (double)S1->deepPaddingSize() / (double)S1->getSize();
+ double Pct2 = (double)S2->deepPaddingSize() / (double)S2->getSize();
+ return Pct1 < Pct2;
+}
+
+static bool ComparePaddingImmediate(const LayoutPtr &S1, const LayoutPtr &S2) {
+ return S1->immediatePadding() < S2->immediatePadding();
+}
+
+static bool ComparePaddingPctImmediate(const LayoutPtr &S1,
+ const LayoutPtr &S2) {
+ double Pct1 = (double)S1->immediatePadding() / (double)S1->getSize();
+ double Pct2 = (double)S2->immediatePadding() / (double)S2->getSize();
+ return Pct1 < Pct2;
+}
+
+static CompareFunc getComparisonFunc(opts::pretty::ClassSortMode Mode) {
+ switch (Mode) {
+ case opts::pretty::ClassSortMode::Name:
+ return CompareNames;
+ case opts::pretty::ClassSortMode::Size:
+ return CompareSizes;
+ case opts::pretty::ClassSortMode::Padding:
+ return ComparePadding;
+ case opts::pretty::ClassSortMode::PaddingPct:
+ return ComparePaddingPct;
+ case opts::pretty::ClassSortMode::PaddingImmediate:
+ return ComparePaddingImmediate;
+ case opts::pretty::ClassSortMode::PaddingPctImmediate:
+ return ComparePaddingPctImmediate;
+ default:
+ return nullptr;
+ }
+}
+
+template <typename Enumerator>
+static std::vector<std::unique_ptr<ClassLayout>>
+filterAndSortClassDefs(LinePrinter &Printer, Enumerator &E,
+ uint32_t UnfilteredCount) {
+ std::vector<std::unique_ptr<ClassLayout>> Filtered;
+
+ Filtered.reserve(UnfilteredCount);
+ CompareFunc Comp = getComparisonFunc(opts::pretty::ClassOrder);
+
+ if (UnfilteredCount > 10000) {
+ errs() << formatv("Filtering and sorting {0} types", UnfilteredCount);
+ errs().flush();
+ }
+ uint32_t Examined = 0;
+ uint32_t Discarded = 0;
+ while (auto Class = E.getNext()) {
+ ++Examined;
+ if (Examined % 10000 == 0) {
+ errs() << formatv("Examined {0}/{1} items. {2} items discarded\n",
+ Examined, UnfilteredCount, Discarded);
+ errs().flush();
+ }
+
+ if (Class->getUnmodifiedTypeId() != 0) {
+ ++Discarded;
+ continue;
+ }
+
+ if (Printer.IsTypeExcluded(Class->getName(), Class->getLength())) {
+ ++Discarded;
+ continue;
+ }
+
+ auto Layout = llvm::make_unique<ClassLayout>(std::move(Class));
+ if (Layout->deepPaddingSize() < opts::pretty::PaddingThreshold) {
+ ++Discarded;
+ continue;
+ }
+ if (Layout->immediatePadding() < opts::pretty::ImmediatePaddingThreshold) {
+ ++Discarded;
+ continue;
+ }
+
+ Filtered.push_back(std::move(Layout));
+ }
+
+ if (Comp)
+ std::sort(Filtered.begin(), Filtered.end(), Comp);
+ return Filtered;
+}
+
+TypeDumper::TypeDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {}
+
+void TypeDumper::start(const PDBSymbolExe &Exe) {
+ auto Children = Exe.findAllChildren();
+ if (opts::pretty::Enums) {
+ if (auto Enums = Exe.findAllChildren<PDBSymbolTypeEnum>()) {
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << "Enums";
+ Printer << ": (" << Enums->getChildCount() << " items)";
+ Printer.Indent();
+ while (auto Enum = Enums->getNext())
+ Enum->dump(*this);
+ Printer.Unindent();
+ }
+ }
+
+ if (opts::pretty::Typedefs) {
+ if (auto Typedefs = Exe.findAllChildren<PDBSymbolTypeTypedef>()) {
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << "Typedefs";
+ Printer << ": (" << Typedefs->getChildCount() << " items)";
+ Printer.Indent();
+ while (auto Typedef = Typedefs->getNext())
+ Typedef->dump(*this);
+ Printer.Unindent();
+ }
+ }
+
+ if (opts::pretty::Classes) {
+ if (auto Classes = Exe.findAllChildren<PDBSymbolTypeUDT>()) {
+ uint32_t All = Classes->getChildCount();
+
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << "Classes";
+
+ bool Precompute = false;
+ Precompute =
+ (opts::pretty::ClassOrder != opts::pretty::ClassSortMode::None);
+
+ // If we're using no sort mode, then we can start getting immediate output
+ // from the tool by just filtering as we go, rather than processing
+ // everything up front so that we can sort it. This makes the tool more
+ // responsive. So only precompute the filtered/sorted set of classes if
+ // necessary due to the specified options.
+ std::vector<LayoutPtr> Filtered;
+ uint32_t Shown = All;
+ if (Precompute) {
+ Filtered = filterAndSortClassDefs(Printer, *Classes, All);
+
+ Shown = Filtered.size();
+ }
+
+ Printer << ": (Showing " << Shown << " items";
+ if (Shown < All)
+ Printer << ", " << (All - Shown) << " filtered";
+ Printer << ")";
+ Printer.Indent();
+
+ // If we pre-computed, iterate the filtered/sorted list, otherwise iterate
+ // the DIA enumerator and filter on the fly.
+ if (Precompute) {
+ for (auto &Class : Filtered)
+ dumpClassLayout(*Class);
+ } else {
+ while (auto Class = Classes->getNext()) {
+ if (Class->getUnmodifiedTypeId() != 0)
+ continue;
+
+ if (Printer.IsTypeExcluded(Class->getName(), Class->getLength()))
+ continue;
+
+ auto Layout = llvm::make_unique<ClassLayout>(std::move(Class));
+ if (Layout->deepPaddingSize() < opts::pretty::PaddingThreshold)
+ continue;
+
+ dumpClassLayout(*Layout);
+ }
+ }
+
+ Printer.Unindent();
+ }
+ }
+}
+
+void TypeDumper::dump(const PDBSymbolTypeEnum &Symbol) {
+ assert(opts::pretty::Enums);
+
+ if (Printer.IsTypeExcluded(Symbol.getName(), Symbol.getLength()))
+ return;
+ // Dump member enums when dumping their class definition.
+ if (nullptr != Symbol.getClassParent())
+ return;
+
+ Printer.NewLine();
+ EnumDumper Dumper(Printer);
+ Dumper.start(Symbol);
+}
+
+void TypeDumper::dump(const PDBSymbolTypeTypedef &Symbol) {
+ assert(opts::pretty::Typedefs);
+
+ if (Printer.IsTypeExcluded(Symbol.getName(), Symbol.getLength()))
+ return;
+
+ Printer.NewLine();
+ TypedefDumper Dumper(Printer);
+ Dumper.start(Symbol);
+}
+
+void TypeDumper::dumpClassLayout(const ClassLayout &Class) {
+ assert(opts::pretty::Classes);
+
+ if (opts::pretty::ClassFormat == opts::pretty::ClassDefinitionFormat::None) {
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << "class ";
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << Class.getName();
+ } else {
+ ClassDefinitionDumper Dumper(Printer);
+ Dumper.start(Class);
+ }
+}
diff --git a/contrib/llvm/tools/llvm-pdbutil/PrettyTypeDumper.h b/contrib/llvm/tools/llvm-pdbutil/PrettyTypeDumper.h
new file mode 100644
index 0000000..68a2f02
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyTypeDumper.h
@@ -0,0 +1,36 @@
+//===- PrettyTypeDumper.h - PDBSymDumper implementation for types *- 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_PRETTYTYPEDUMPER_H
+#define LLVM_TOOLS_LLVMPDBDUMP_PRETTYTYPEDUMPER_H
+
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+
+namespace llvm {
+namespace pdb {
+class LinePrinter;
+class ClassLayout;
+
+class TypeDumper : public PDBSymDumper {
+public:
+ TypeDumper(LinePrinter &P);
+
+ void start(const PDBSymbolExe &Exe);
+
+ void dump(const PDBSymbolTypeEnum &Symbol) override;
+ void dump(const PDBSymbolTypeTypedef &Symbol) override;
+
+ void dumpClassLayout(const ClassLayout &Class);
+
+private:
+ LinePrinter &Printer;
+};
+}
+}
+#endif
diff --git a/contrib/llvm/tools/llvm-pdbutil/PrettyTypedefDumper.cpp b/contrib/llvm/tools/llvm-pdbutil/PrettyTypedefDumper.cpp
new file mode 100644
index 0000000..2266e6e
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyTypedefDumper.cpp
@@ -0,0 +1,77 @@
+//===- PrettyTypedefDumper.cpp - PDBSymDumper impl for typedefs -- * C++ *-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PrettyTypedefDumper.h"
+
+#include "LinePrinter.h"
+#include "PrettyBuiltinDumper.h"
+#include "PrettyFunctionDumper.h"
+#include "llvm-pdbutil.h"
+
+#include "llvm/DebugInfo/PDB/IPDBSession.h"
+#include "llvm/DebugInfo/PDB/PDBExtras.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+TypedefDumper::TypedefDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {}
+
+void TypedefDumper::start(const PDBSymbolTypeTypedef &Symbol) {
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << "typedef ";
+ uint32_t TargetId = Symbol.getTypeId();
+ if (auto TypeSymbol = Symbol.getSession().getSymbolById(TargetId))
+ TypeSymbol->dump(*this);
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << " "
+ << Symbol.getName();
+}
+
+void TypedefDumper::dump(const PDBSymbolTypeArray &Symbol) {}
+
+void TypedefDumper::dump(const PDBSymbolTypeBuiltin &Symbol) {
+ BuiltinDumper Dumper(Printer);
+ Dumper.start(Symbol);
+}
+
+void TypedefDumper::dump(const PDBSymbolTypeEnum &Symbol) {
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << "enum ";
+ WithColor(Printer, PDB_ColorItem::Type).get() << " " << Symbol.getName();
+}
+
+void TypedefDumper::dump(const PDBSymbolTypePointer &Symbol) {
+ if (Symbol.isConstType())
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << "const ";
+ if (Symbol.isVolatileType())
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << "volatile ";
+ auto PointeeType = Symbol.getPointeeType();
+ if (auto FuncSig = unique_dyn_cast<PDBSymbolTypeFunctionSig>(PointeeType)) {
+ FunctionDumper::PointerType Pointer = FunctionDumper::PointerType::Pointer;
+ if (Symbol.isReference())
+ Pointer = FunctionDumper::PointerType::Reference;
+ FunctionDumper NestedDumper(Printer);
+ NestedDumper.start(*FuncSig, nullptr, Pointer);
+ } else {
+ PointeeType->dump(*this);
+ Printer << ((Symbol.isReference()) ? "&" : "*");
+ }
+}
+
+void TypedefDumper::dump(const PDBSymbolTypeFunctionSig &Symbol) {
+ FunctionDumper Dumper(Printer);
+ Dumper.start(Symbol, nullptr, FunctionDumper::PointerType::None);
+}
+
+void TypedefDumper::dump(const PDBSymbolTypeUDT &Symbol) {
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << "class ";
+ WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName();
+}
diff --git a/contrib/llvm/tools/llvm-pdbutil/PrettyTypedefDumper.h b/contrib/llvm/tools/llvm-pdbutil/PrettyTypedefDumper.h
new file mode 100644
index 0000000..133bbfb
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyTypedefDumper.h
@@ -0,0 +1,39 @@
+//===- PrettyTypedefDumper.h - llvm-pdbutil typedef dumper ---*- 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_PRETTYTYPEDEFDUMPER_H
+#define LLVM_TOOLS_LLVMPDBDUMP_PRETTYTYPEDEFDUMPER_H
+
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+
+namespace llvm {
+namespace pdb {
+
+class LinePrinter;
+
+class TypedefDumper : public PDBSymDumper {
+public:
+ TypedefDumper(LinePrinter &P);
+
+ void start(const PDBSymbolTypeTypedef &Symbol);
+
+ void dump(const PDBSymbolTypeArray &Symbol) override;
+ void dump(const PDBSymbolTypeBuiltin &Symbol) override;
+ void dump(const PDBSymbolTypeEnum &Symbol) override;
+ void dump(const PDBSymbolTypeFunctionSig &Symbol) override;
+ void dump(const PDBSymbolTypePointer &Symbol) override;
+ void dump(const PDBSymbolTypeUDT &Symbol) override;
+
+private:
+ LinePrinter &Printer;
+};
+}
+}
+
+#endif
diff --git a/contrib/llvm/tools/llvm-pdbutil/PrettyVariableDumper.cpp b/contrib/llvm/tools/llvm-pdbutil/PrettyVariableDumper.cpp
new file mode 100644
index 0000000..4884fc8
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyVariableDumper.cpp
@@ -0,0 +1,220 @@
+//===- PrettyVariableDumper.cpp ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PrettyVariableDumper.h"
+
+#include "LinePrinter.h"
+#include "PrettyBuiltinDumper.h"
+#include "PrettyFunctionDumper.h"
+#include "llvm-pdbutil.h"
+
+#include "llvm/DebugInfo/PDB/IPDBSession.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeArray.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
+#include "llvm/DebugInfo/PDB/PDBTypes.h"
+
+#include "llvm/Support/Format.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+VariableDumper::VariableDumper(LinePrinter &P)
+ : PDBSymDumper(true), Printer(P) {}
+
+void VariableDumper::start(const PDBSymbolData &Var, uint32_t Offset) {
+ if (Var.isCompilerGenerated() && opts::pretty::ExcludeCompilerGenerated)
+ return;
+ if (Printer.IsSymbolExcluded(Var.getName()))
+ return;
+
+ auto VarType = Var.getType();
+
+ uint64_t Length = VarType->getRawSymbol().getLength();
+
+ switch (auto LocType = Var.getLocationType()) {
+ case PDB_LocType::Static:
+ Printer.NewLine();
+ Printer << "data [";
+ WithColor(Printer, PDB_ColorItem::Address).get()
+ << format_hex(Var.getVirtualAddress(), 10);
+ Printer << ", sizeof=" << Length << "] ";
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << "static ";
+ dumpSymbolTypeAndName(*VarType, Var.getName());
+ break;
+ case PDB_LocType::Constant:
+ if (isa<PDBSymbolTypeEnum>(*VarType))
+ break;
+ Printer.NewLine();
+ Printer << "data [sizeof=" << Length << "] ";
+ dumpSymbolTypeAndName(*VarType, Var.getName());
+ Printer << " = ";
+ WithColor(Printer, PDB_ColorItem::LiteralValue).get() << Var.getValue();
+ break;
+ case PDB_LocType::ThisRel:
+ Printer.NewLine();
+ Printer << "data ";
+ WithColor(Printer, PDB_ColorItem::Offset).get()
+ << "+" << format_hex(Offset + Var.getOffset(), 4)
+ << " [sizeof=" << Length << "] ";
+ dumpSymbolTypeAndName(*VarType, Var.getName());
+ break;
+ case PDB_LocType::BitField:
+ Printer.NewLine();
+ Printer << "data ";
+ WithColor(Printer, PDB_ColorItem::Offset).get()
+ << "+" << format_hex(Offset + Var.getOffset(), 4)
+ << " [sizeof=" << Length << "] ";
+ dumpSymbolTypeAndName(*VarType, Var.getName());
+ Printer << " : ";
+ WithColor(Printer, PDB_ColorItem::LiteralValue).get() << Var.getLength();
+ break;
+ default:
+ Printer.NewLine();
+ Printer << "data [sizeof=" << Length << "] ";
+ Printer << "unknown(" << LocType << ") ";
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << Var.getName();
+ break;
+ }
+}
+
+void VariableDumper::startVbptr(uint32_t Offset, uint32_t Size) {
+ Printer.NewLine();
+ Printer << "vbptr ";
+
+ WithColor(Printer, PDB_ColorItem::Offset).get()
+ << "+" << format_hex(Offset, 4) << " [sizeof=" << Size << "] ";
+}
+
+void VariableDumper::start(const PDBSymbolTypeVTable &Var, uint32_t Offset) {
+ Printer.NewLine();
+ Printer << "vfptr ";
+ auto VTableType = cast<PDBSymbolTypePointer>(Var.getType());
+ uint32_t PointerSize = VTableType->getLength();
+
+ WithColor(Printer, PDB_ColorItem::Offset).get()
+ << "+" << format_hex(Offset + Var.getOffset(), 4)
+ << " [sizeof=" << PointerSize << "] ";
+}
+
+void VariableDumper::dump(const PDBSymbolTypeArray &Symbol) {
+ auto ElementType = Symbol.getElementType();
+ assert(ElementType);
+ if (!ElementType)
+ return;
+ ElementType->dump(*this);
+}
+
+void VariableDumper::dumpRight(const PDBSymbolTypeArray &Symbol) {
+ auto ElementType = Symbol.getElementType();
+ assert(ElementType);
+ if (!ElementType)
+ return;
+ Printer << '[' << Symbol.getCount() << ']';
+ ElementType->dumpRight(*this);
+}
+
+void VariableDumper::dump(const PDBSymbolTypeBuiltin &Symbol) {
+ BuiltinDumper Dumper(Printer);
+ Dumper.start(Symbol);
+}
+
+void VariableDumper::dump(const PDBSymbolTypeEnum &Symbol) {
+ WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName();
+}
+
+void VariableDumper::dump(const PDBSymbolTypeFunctionSig &Symbol) {
+ auto ReturnType = Symbol.getReturnType();
+ ReturnType->dump(*this);
+ Printer << " ";
+
+ uint32_t ClassParentId = Symbol.getClassParentId();
+ auto ClassParent =
+ Symbol.getSession().getConcreteSymbolById<PDBSymbolTypeUDT>(
+ ClassParentId);
+
+ if (ClassParent) {
+ WithColor(Printer, PDB_ColorItem::Identifier).get()
+ << ClassParent->getName();
+ Printer << "::";
+ }
+}
+
+void VariableDumper::dumpRight(const PDBSymbolTypeFunctionSig &Symbol) {
+ Printer << "(";
+ if (auto Arguments = Symbol.getArguments()) {
+ uint32_t Index = 0;
+ while (auto Arg = Arguments->getNext()) {
+ Arg->dump(*this);
+ if (++Index < Arguments->getChildCount())
+ Printer << ", ";
+ }
+ }
+ Printer << ")";
+
+ if (Symbol.isConstType())
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << " const";
+ if (Symbol.isVolatileType())
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << " volatile";
+}
+
+void VariableDumper::dump(const PDBSymbolTypePointer &Symbol) {
+ auto PointeeType = Symbol.getPointeeType();
+ if (!PointeeType)
+ return;
+ PointeeType->dump(*this);
+ if (auto FuncSig = unique_dyn_cast<PDBSymbolTypeFunctionSig>(PointeeType)) {
+ // A hack to get the calling convention in the right spot.
+ Printer << " (";
+ PDB_CallingConv CC = FuncSig->getCallingConvention();
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << CC << " ";
+ } else if (isa<PDBSymbolTypeArray>(PointeeType)) {
+ Printer << " (";
+ }
+ Printer << (Symbol.isReference() ? "&" : "*");
+ if (Symbol.isConstType())
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << " const ";
+ if (Symbol.isVolatileType())
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << " volatile ";
+}
+
+void VariableDumper::dumpRight(const PDBSymbolTypePointer &Symbol) {
+ auto PointeeType = Symbol.getPointeeType();
+ assert(PointeeType);
+ if (!PointeeType)
+ return;
+ if (isa<PDBSymbolTypeFunctionSig>(PointeeType) ||
+ isa<PDBSymbolTypeArray>(PointeeType)) {
+ Printer << ")";
+ }
+ PointeeType->dumpRight(*this);
+}
+
+void VariableDumper::dump(const PDBSymbolTypeTypedef &Symbol) {
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << "typedef ";
+ WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName();
+}
+
+void VariableDumper::dump(const PDBSymbolTypeUDT &Symbol) {
+ WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName();
+}
+
+void VariableDumper::dumpSymbolTypeAndName(const PDBSymbol &Type,
+ StringRef Name) {
+ Type.dump(*this);
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << " " << Name;
+ Type.dumpRight(*this);
+}
diff --git a/contrib/llvm/tools/llvm-pdbutil/PrettyVariableDumper.h b/contrib/llvm/tools/llvm-pdbutil/PrettyVariableDumper.h
new file mode 100644
index 0000000..cacf1ce
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyVariableDumper.h
@@ -0,0 +1,50 @@
+//===- PrettyVariableDumper.h - PDBSymDumper variable dumper ----*- 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_PRETTYVARIABLEDUMPER_H
+#define LLVM_TOOLS_LLVMPDBDUMP_PRETTYVARIABLEDUMPER_H
+
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+
+namespace llvm {
+
+class StringRef;
+
+namespace pdb {
+
+class LinePrinter;
+
+class VariableDumper : public PDBSymDumper {
+public:
+ VariableDumper(LinePrinter &P);
+
+ void start(const PDBSymbolData &Var, uint32_t Offset = 0);
+ void start(const PDBSymbolTypeVTable &Var, uint32_t Offset = 0);
+ void startVbptr(uint32_t Offset, uint32_t Size);
+
+ void dump(const PDBSymbolTypeArray &Symbol) override;
+ void dump(const PDBSymbolTypeBuiltin &Symbol) override;
+ void dump(const PDBSymbolTypeEnum &Symbol) override;
+ void dump(const PDBSymbolTypeFunctionSig &Symbol) override;
+ void dump(const PDBSymbolTypePointer &Symbol) override;
+ void dump(const PDBSymbolTypeTypedef &Symbol) override;
+ void dump(const PDBSymbolTypeUDT &Symbol) override;
+
+ void dumpRight(const PDBSymbolTypeArray &Symbol) override;
+ void dumpRight(const PDBSymbolTypeFunctionSig &Symbol) override;
+ void dumpRight(const PDBSymbolTypePointer &Symbol) override;
+
+private:
+ void dumpSymbolTypeAndName(const PDBSymbol &Type, StringRef Name);
+
+ LinePrinter &Printer;
+};
+}
+}
+#endif
diff --git a/contrib/llvm/tools/llvm-pdbutil/StreamUtil.cpp b/contrib/llvm/tools/llvm-pdbutil/StreamUtil.cpp
new file mode 100644
index 0000000..4d35200
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/StreamUtil.cpp
@@ -0,0 +1,152 @@
+//===- 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 "FormatUtil.h"
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseMapInfo.h"
+#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h"
+#include "llvm/DebugInfo/PDB/Native/DbiModuleList.h"
+#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
+#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+void llvm::pdb::discoverStreamPurposes(
+ PDBFile &File,
+ SmallVectorImpl<std::pair<StreamPurpose, 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, DbiModuleDescriptor> ModStreams;
+ DenseMap<uint16_t, std::string> NamedStreams;
+
+ if (Dbi) {
+ const DbiModuleList &Modules = Dbi->modules();
+ for (uint32_t I = 0; I < Modules.getModuleCount(); ++I) {
+ DbiModuleDescriptor Descriptor = Modules.getModuleDescriptor(I);
+ uint16_t SN = Descriptor.getModuleStreamIndex();
+ if (SN != kInvalidStreamIndex)
+ ModStreams[SN] = Descriptor;
+ }
+ }
+ 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::pair<StreamPurpose, std::string> Value;
+ if (StreamIdx == OldMSFDirectory)
+ Value = std::make_pair(StreamPurpose::Other, "Old MSF Directory");
+ else if (StreamIdx == StreamPDB)
+ Value = std::make_pair(StreamPurpose::Other, "PDB Stream");
+ else if (StreamIdx == StreamDBI)
+ Value = std::make_pair(StreamPurpose::Other, "DBI Stream");
+ else if (StreamIdx == StreamTPI)
+ Value = std::make_pair(StreamPurpose::Other, "TPI Stream");
+ else if (StreamIdx == StreamIPI)
+ Value = std::make_pair(StreamPurpose::Other, "IPI Stream");
+ else if (Dbi && StreamIdx == Dbi->getGlobalSymbolStreamIndex())
+ Value = std::make_pair(StreamPurpose::Other, "Global Symbol Hash");
+ else if (Dbi && StreamIdx == Dbi->getPublicSymbolStreamIndex())
+ Value = std::make_pair(StreamPurpose::Other, "Public Symbol Hash");
+ else if (Dbi && StreamIdx == Dbi->getSymRecordStreamIndex())
+ Value = std::make_pair(StreamPurpose::Other, "Public Symbol Records");
+ else if (Tpi && StreamIdx == Tpi->getTypeHashStreamIndex())
+ Value = std::make_pair(StreamPurpose::Other, "TPI Hash");
+ else if (Tpi && StreamIdx == Tpi->getTypeHashStreamAuxIndex())
+ Value = std::make_pair(StreamPurpose::Other, "TPI Aux Hash");
+ else if (Ipi && StreamIdx == Ipi->getTypeHashStreamIndex())
+ Value = std::make_pair(StreamPurpose::Other, "IPI Hash");
+ else if (Ipi && StreamIdx == Ipi->getTypeHashStreamAuxIndex())
+ Value = std::make_pair(StreamPurpose::Other, "IPI Aux Hash");
+ else if (Dbi &&
+ StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Exception))
+ Value = std::make_pair(StreamPurpose::Other, "Exception Data");
+ else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Fixup))
+ Value = std::make_pair(StreamPurpose::Other, "Fixup Data");
+ else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::FPO))
+ Value = std::make_pair(StreamPurpose::Other, "FPO Data");
+ else if (Dbi &&
+ StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::NewFPO))
+ Value = std::make_pair(StreamPurpose::Other, "New FPO Data");
+ else if (Dbi &&
+ StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::OmapFromSrc))
+ Value = std::make_pair(StreamPurpose::Other, "Omap From Source Data");
+ else if (Dbi &&
+ StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::OmapToSrc))
+ Value = std::make_pair(StreamPurpose::Other, "Omap To Source Data");
+ else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Pdata))
+ Value = std::make_pair(StreamPurpose::Other, "Pdata");
+ else if (Dbi &&
+ StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::SectionHdr))
+ Value = std::make_pair(StreamPurpose::Other, "Section Header Data");
+ else if (Dbi &&
+ StreamIdx ==
+ Dbi->getDebugStreamIndex(DbgHeaderType::SectionHdrOrig))
+ Value =
+ std::make_pair(StreamPurpose::Other, "Section Header Original Data");
+ else if (Dbi &&
+ StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::TokenRidMap))
+ Value = std::make_pair(StreamPurpose::Other, "Token Rid Data");
+ else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Xdata))
+ Value = std::make_pair(StreamPurpose::Other, "Xdata");
+ else {
+ auto ModIter = ModStreams.find(StreamIdx);
+ auto NSIter = NamedStreams.find(StreamIdx);
+ if (ModIter != ModStreams.end()) {
+ Value = std::make_pair(StreamPurpose::ModuleStream,
+ ModIter->second.getModuleName());
+ } else if (NSIter != NamedStreams.end()) {
+ Value = std::make_pair(StreamPurpose::NamedStream, NSIter->second);
+ } else {
+ Value = std::make_pair(StreamPurpose::Other, "???");
+ }
+ }
+ 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());
+}
+
+void llvm::pdb::discoverStreamPurposes(PDBFile &File,
+ SmallVectorImpl<std::string> &Purposes) {
+ SmallVector<std::pair<StreamPurpose, std::string>, 24> SP;
+ discoverStreamPurposes(File, SP);
+ Purposes.reserve(SP.size());
+ for (const auto &P : SP) {
+ if (P.first == StreamPurpose::NamedStream)
+ Purposes.push_back(formatv("Named Stream \"{0}\"", P.second));
+ else if (P.first == StreamPurpose::ModuleStream)
+ Purposes.push_back(formatv("Module \"{0}\"", P.second));
+ else
+ Purposes.push_back(P.second);
+ }
+}
diff --git a/contrib/llvm/tools/llvm-pdbutil/StreamUtil.h b/contrib/llvm/tools/llvm-pdbutil/StreamUtil.h
new file mode 100644
index 0000000..f49c0a0
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/StreamUtil.h
@@ -0,0 +1,30 @@
+//===- 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;
+enum class StreamPurpose { NamedStream, ModuleStream, Other };
+
+void discoverStreamPurposes(PDBFile &File,
+ SmallVectorImpl<std::string> &Purposes);
+void discoverStreamPurposes(
+ PDBFile &File,
+ SmallVectorImpl<std::pair<StreamPurpose, std::string>> &Purposes);
+}
+}
+
+#endif
diff --git a/contrib/llvm/tools/llvm-pdbutil/YAMLOutputStyle.cpp b/contrib/llvm/tools/llvm-pdbutil/YAMLOutputStyle.cpp
new file mode 100644
index 0000000..ae3138e
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/YAMLOutputStyle.cpp
@@ -0,0 +1,333 @@
+//===- YAMLOutputStyle.cpp ------------------------------------ *- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "YAMLOutputStyle.h"
+
+#include "PdbYaml.h"
+#include "llvm-pdbutil.h"
+
+#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugUnknownSubsection.h"
+#include "llvm/DebugInfo/CodeView/Line.h"
+#include "llvm/DebugInfo/CodeView/StringsAndChecksums.h"
+#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
+#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
+#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
+#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/RawConstants.h"
+#include "llvm/DebugInfo/PDB/Native/RawError.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+static bool checkModuleSubsection(opts::ModuleSubsection MS) {
+ return any_of(opts::pdb2yaml::DumpModuleSubsections,
+ [=](opts::ModuleSubsection M) {
+ return M == MS || M == opts::ModuleSubsection::All;
+ });
+}
+
+YAMLOutputStyle::YAMLOutputStyle(PDBFile &File)
+ : File(File), Out(outs()), Obj(File.getAllocator()) {
+ Out.setWriteDefaultValues(!opts::pdb2yaml::Minimal);
+}
+
+Error YAMLOutputStyle::dump() {
+ if (opts::pdb2yaml::StreamDirectory)
+ opts::pdb2yaml::StreamMetadata = true;
+
+ if (auto EC = dumpFileHeaders())
+ return EC;
+
+ if (auto EC = dumpStreamMetadata())
+ return EC;
+
+ if (auto EC = dumpStreamDirectory())
+ return EC;
+
+ if (auto EC = dumpStringTable())
+ return EC;
+
+ if (auto EC = dumpPDBStream())
+ return EC;
+
+ if (auto EC = dumpDbiStream())
+ return EC;
+
+ if (auto EC = dumpTpiStream())
+ return EC;
+
+ if (auto EC = dumpIpiStream())
+ return EC;
+
+ flush();
+ return Error::success();
+}
+
+
+Error YAMLOutputStyle::dumpFileHeaders() {
+ if (opts::pdb2yaml::NoFileHeaders)
+ return Error::success();
+
+ yaml::MSFHeaders Headers;
+ Obj.Headers.emplace();
+ Obj.Headers->SuperBlock.NumBlocks = File.getBlockCount();
+ Obj.Headers->SuperBlock.BlockMapAddr = File.getBlockMapIndex();
+ Obj.Headers->SuperBlock.BlockSize = File.getBlockSize();
+ auto Blocks = File.getDirectoryBlockArray();
+ Obj.Headers->DirectoryBlocks.assign(Blocks.begin(), Blocks.end());
+ Obj.Headers->NumDirectoryBlocks = File.getNumDirectoryBlocks();
+ Obj.Headers->SuperBlock.NumDirectoryBytes = File.getNumDirectoryBytes();
+ Obj.Headers->NumStreams =
+ opts::pdb2yaml::StreamMetadata ? File.getNumStreams() : 0;
+ Obj.Headers->SuperBlock.FreeBlockMapBlock = File.getFreeBlockMapBlock();
+ Obj.Headers->SuperBlock.Unknown1 = File.getUnknown1();
+ Obj.Headers->FileSize = File.getFileSize();
+
+ return Error::success();
+}
+
+Error YAMLOutputStyle::dumpStringTable() {
+ bool RequiresStringTable = opts::pdb2yaml::DumpModuleFiles ||
+ !opts::pdb2yaml::DumpModuleSubsections.empty();
+ bool RequestedStringTable = opts::pdb2yaml::StringTable;
+ if (!RequiresStringTable && !RequestedStringTable)
+ return Error::success();
+
+ auto ExpectedST = File.getStringTable();
+ if (!ExpectedST)
+ return ExpectedST.takeError();
+
+ Obj.StringTable.emplace();
+ const auto &ST = ExpectedST.get();
+ for (auto ID : ST.name_ids()) {
+ auto S = ST.getStringForID(ID);
+ if (!S)
+ return S.takeError();
+ if (S->empty())
+ continue;
+ Obj.StringTable->push_back(*S);
+ }
+ return Error::success();
+}
+
+Error YAMLOutputStyle::dumpStreamMetadata() {
+ if (!opts::pdb2yaml::StreamMetadata)
+ return Error::success();
+
+ Obj.StreamSizes.emplace();
+ Obj.StreamSizes->assign(File.getStreamSizes().begin(),
+ File.getStreamSizes().end());
+ return Error::success();
+}
+
+Error YAMLOutputStyle::dumpStreamDirectory() {
+ if (!opts::pdb2yaml::StreamDirectory)
+ return Error::success();
+
+ auto StreamMap = File.getStreamMap();
+ Obj.StreamMap.emplace();
+ for (auto &Stream : StreamMap) {
+ pdb::yaml::StreamBlockList BlockList;
+ BlockList.Blocks.assign(Stream.begin(), Stream.end());
+ Obj.StreamMap->push_back(BlockList);
+ }
+
+ return Error::success();
+}
+
+Error YAMLOutputStyle::dumpPDBStream() {
+ if (!opts::pdb2yaml::PdbStream)
+ return Error::success();
+
+ auto IS = File.getPDBInfoStream();
+ if (!IS)
+ return IS.takeError();
+
+ auto &InfoS = IS.get();
+ Obj.PdbStream.emplace();
+ Obj.PdbStream->Age = InfoS.getAge();
+ Obj.PdbStream->Guid = InfoS.getGuid();
+ Obj.PdbStream->Signature = InfoS.getSignature();
+ Obj.PdbStream->Version = InfoS.getVersion();
+ Obj.PdbStream->Features = InfoS.getFeatureSignatures();
+
+ return Error::success();
+}
+
+static opts::ModuleSubsection convertSubsectionKind(DebugSubsectionKind K) {
+ switch (K) {
+ case DebugSubsectionKind::CrossScopeExports:
+ return opts::ModuleSubsection::CrossScopeExports;
+ case DebugSubsectionKind::CrossScopeImports:
+ return opts::ModuleSubsection::CrossScopeImports;
+ case DebugSubsectionKind::FileChecksums:
+ return opts::ModuleSubsection::FileChecksums;
+ case DebugSubsectionKind::InlineeLines:
+ return opts::ModuleSubsection::InlineeLines;
+ case DebugSubsectionKind::Lines:
+ return opts::ModuleSubsection::Lines;
+ case DebugSubsectionKind::Symbols:
+ return opts::ModuleSubsection::Symbols;
+ case DebugSubsectionKind::StringTable:
+ return opts::ModuleSubsection::StringTable;
+ case DebugSubsectionKind::FrameData:
+ return opts::ModuleSubsection::FrameData;
+ default:
+ return opts::ModuleSubsection::Unknown;
+ }
+ llvm_unreachable("Unreachable!");
+}
+
+Error YAMLOutputStyle::dumpDbiStream() {
+ if (!opts::pdb2yaml::DbiStream)
+ return Error::success();
+
+ auto DbiS = File.getPDBDbiStream();
+ if (!DbiS)
+ return DbiS.takeError();
+
+ auto &DS = DbiS.get();
+ Obj.DbiStream.emplace();
+ Obj.DbiStream->Age = DS.getAge();
+ Obj.DbiStream->BuildNumber = DS.getBuildNumber();
+ Obj.DbiStream->Flags = DS.getFlags();
+ Obj.DbiStream->MachineType = DS.getMachineType();
+ Obj.DbiStream->PdbDllRbld = DS.getPdbDllRbld();
+ Obj.DbiStream->PdbDllVersion = DS.getPdbDllVersion();
+ Obj.DbiStream->VerHeader = DS.getDbiVersion();
+ if (opts::pdb2yaml::DumpModules) {
+ const auto &Modules = DS.modules();
+ for (uint32_t I = 0; I < Modules.getModuleCount(); ++I) {
+ DbiModuleDescriptor MI = Modules.getModuleDescriptor(I);
+
+ Obj.DbiStream->ModInfos.emplace_back();
+ yaml::PdbDbiModuleInfo &DMI = Obj.DbiStream->ModInfos.back();
+
+ DMI.Mod = MI.getModuleName();
+ DMI.Obj = MI.getObjFileName();
+ if (opts::pdb2yaml::DumpModuleFiles) {
+ auto Files = Modules.source_files(I);
+ DMI.SourceFiles.assign(Files.begin(), Files.end());
+ }
+
+ uint16_t ModiStream = MI.getModuleStreamIndex();
+ if (ModiStream == kInvalidStreamIndex)
+ continue;
+
+ auto ModStreamData = msf::MappedBlockStream::createIndexedStream(
+ File.getMsfLayout(), File.getMsfBuffer(), ModiStream,
+ File.getAllocator());
+
+ pdb::ModuleDebugStreamRef ModS(MI, std::move(ModStreamData));
+ if (auto EC = ModS.reload())
+ return EC;
+
+ auto ExpectedST = File.getStringTable();
+ if (!ExpectedST)
+ return ExpectedST.takeError();
+ if (!opts::pdb2yaml::DumpModuleSubsections.empty() &&
+ ModS.hasDebugSubsections()) {
+ auto ExpectedChecksums = ModS.findChecksumsSubsection();
+ if (!ExpectedChecksums)
+ return ExpectedChecksums.takeError();
+
+ StringsAndChecksumsRef SC(ExpectedST->getStringTable(),
+ *ExpectedChecksums);
+
+ for (const auto &SS : ModS.subsections()) {
+ opts::ModuleSubsection OptionKind = convertSubsectionKind(SS.kind());
+ if (!checkModuleSubsection(OptionKind))
+ continue;
+
+ auto Converted =
+ CodeViewYAML::YAMLDebugSubsection::fromCodeViewSubection(SC, SS);
+ if (!Converted)
+ return Converted.takeError();
+ DMI.Subsections.push_back(*Converted);
+ }
+ }
+
+ if (opts::pdb2yaml::DumpModuleSyms) {
+ DMI.Modi.emplace();
+
+ DMI.Modi->Signature = ModS.signature();
+ bool HadError = false;
+ for (auto &Sym : ModS.symbols(&HadError)) {
+ auto ES = CodeViewYAML::SymbolRecord::fromCodeViewSymbol(Sym);
+ if (!ES)
+ return ES.takeError();
+
+ DMI.Modi->Symbols.push_back(*ES);
+ }
+ }
+ }
+ }
+ return Error::success();
+}
+
+Error YAMLOutputStyle::dumpTpiStream() {
+ if (!opts::pdb2yaml::TpiStream)
+ return Error::success();
+
+ auto TpiS = File.getPDBTpiStream();
+ if (!TpiS)
+ return TpiS.takeError();
+
+ auto &TS = TpiS.get();
+ Obj.TpiStream.emplace();
+ Obj.TpiStream->Version = TS.getTpiVersion();
+ for (auto &Record : TS.types(nullptr)) {
+ auto ExpectedRecord = CodeViewYAML::LeafRecord::fromCodeViewRecord(Record);
+ if (!ExpectedRecord)
+ return ExpectedRecord.takeError();
+ Obj.TpiStream->Records.push_back(*ExpectedRecord);
+ }
+
+ return Error::success();
+}
+
+Error YAMLOutputStyle::dumpIpiStream() {
+ if (!opts::pdb2yaml::IpiStream)
+ return Error::success();
+
+ auto InfoS = File.getPDBInfoStream();
+ if (!InfoS)
+ return InfoS.takeError();
+ if (!InfoS->containsIdStream())
+ return Error::success();
+
+ auto IpiS = File.getPDBIpiStream();
+ if (!IpiS)
+ return IpiS.takeError();
+
+ auto &IS = IpiS.get();
+ Obj.IpiStream.emplace();
+ Obj.IpiStream->Version = IS.getTpiVersion();
+ for (auto &Record : IS.types(nullptr)) {
+ auto ExpectedRecord = CodeViewYAML::LeafRecord::fromCodeViewRecord(Record);
+ if (!ExpectedRecord)
+ return ExpectedRecord.takeError();
+
+ Obj.IpiStream->Records.push_back(*ExpectedRecord);
+ }
+
+ return Error::success();
+}
+
+void YAMLOutputStyle::flush() {
+ Out << Obj;
+ outs().flush();
+}
diff --git a/contrib/llvm/tools/llvm-pdbutil/YAMLOutputStyle.h b/contrib/llvm/tools/llvm-pdbutil/YAMLOutputStyle.h
new file mode 100644
index 0000000..3690e35
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/YAMLOutputStyle.h
@@ -0,0 +1,49 @@
+//===- YAMLOutputStyle.h -------------------------------------- *- 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_YAMLOUTPUTSTYLE_H
+#define LLVM_TOOLS_LLVMPDBDUMP_YAMLOUTPUTSTYLE_H
+
+#include "OutputStyle.h"
+#include "PdbYaml.h"
+
+#include "llvm/Support/ScopedPrinter.h"
+#include "llvm/Support/YAMLTraits.h"
+
+namespace llvm {
+namespace pdb {
+class ModuleDebugStreamRef;
+
+class YAMLOutputStyle : public OutputStyle {
+public:
+ YAMLOutputStyle(PDBFile &File);
+
+ Error dump() override;
+
+private:
+ Error dumpStringTable();
+ Error dumpFileHeaders();
+ Error dumpStreamMetadata();
+ Error dumpStreamDirectory();
+ Error dumpPDBStream();
+ Error dumpDbiStream();
+ Error dumpTpiStream();
+ Error dumpIpiStream();
+
+ void flush();
+
+ PDBFile &File;
+ llvm::yaml::Output Out;
+
+ yaml::PdbObject Obj;
+};
+} // namespace pdb
+} // namespace llvm
+
+#endif // LLVM_TOOLS_LLVMPDBDUMP_YAMLOUTPUTSTYLE_H
diff --git a/contrib/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp b/contrib/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp
new file mode 100644
index 0000000..f2bd194
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp
@@ -0,0 +1,1179 @@
+//===- llvm-pdbutil.cpp - Dump debug info from a PDB file -------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Dumps debug information present in PDB files.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm-pdbutil.h"
+
+#include "Analyze.h"
+#include "BytesOutputStyle.h"
+#include "Diff.h"
+#include "DumpOutputStyle.h"
+#include "LinePrinter.h"
+#include "OutputStyle.h"
+#include "PrettyCompilandDumper.h"
+#include "PrettyExternalSymbolDumper.h"
+#include "PrettyFunctionDumper.h"
+#include "PrettyTypeDumper.h"
+#include "PrettyVariableDumper.h"
+#include "YAMLOutputStyle.h"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/BitVector.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Config/config.h"
+#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h"
+#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
+#include "llvm/DebugInfo/CodeView/StringsAndChecksums.h"
+#include "llvm/DebugInfo/CodeView/TypeStreamMerger.h"
+#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
+#include "llvm/DebugInfo/MSF/MSFBuilder.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"
+#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h"
+#include "llvm/DebugInfo/PDB/Native/DbiStream.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"
+#include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h"
+#include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h"
+#include "llvm/DebugInfo/PDB/Native/RawConstants.h"
+#include "llvm/DebugInfo/PDB/Native/RawError.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h"
+#include "llvm/DebugInfo/PDB/PDB.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolThunk.h"
+#include "llvm/Support/BinaryByteStream.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/Path.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/Regex.h"
+#include "llvm/Support/ScopedPrinter.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::msf;
+using namespace llvm::pdb;
+
+namespace opts {
+
+cl::SubCommand DumpSubcommand("dump", "Dump MSF and CodeView debug info");
+cl::SubCommand BytesSubcommand("bytes", "Dump raw bytes from 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");
+cl::SubCommand
+ PdbToYamlSubcommand("pdb2yaml",
+ "Generate a detailed YAML description of a PDB File");
+
+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");
+
+cl::ValuesClass ChunkValues = cl::values(
+ clEnumValN(ModuleSubsection::CrossScopeExports, "cme",
+ "Cross module exports (DEBUG_S_CROSSSCOPEEXPORTS subsection)"),
+ clEnumValN(ModuleSubsection::CrossScopeImports, "cmi",
+ "Cross module imports (DEBUG_S_CROSSSCOPEIMPORTS subsection)"),
+ clEnumValN(ModuleSubsection::FileChecksums, "fc",
+ "File checksums (DEBUG_S_CHECKSUMS subsection)"),
+ clEnumValN(ModuleSubsection::InlineeLines, "ilines",
+ "Inlinee lines (DEBUG_S_INLINEELINES subsection)"),
+ clEnumValN(ModuleSubsection::Lines, "lines",
+ "Lines (DEBUG_S_LINES subsection)"),
+ clEnumValN(ModuleSubsection::StringTable, "strings",
+ "String Table (DEBUG_S_STRINGTABLE subsection) (not "
+ "typically present in PDB file)"),
+ clEnumValN(ModuleSubsection::FrameData, "frames",
+ "Frame Data (DEBUG_S_FRAMEDATA subsection)"),
+ clEnumValN(ModuleSubsection::Symbols, "symbols",
+ "Symbols (DEBUG_S_SYMBOLS subsection) (not typically "
+ "present in PDB file)"),
+ clEnumValN(ModuleSubsection::CoffSymbolRVAs, "rvas",
+ "COFF Symbol RVAs (DEBUG_S_COFF_SYMBOL_RVA subsection)"),
+ clEnumValN(ModuleSubsection::Unknown, "unknown",
+ "Any subsection not covered by another option"),
+ clEnumValN(ModuleSubsection::All, "all", "All known subsections"));
+
+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::sub(PrettySubcommand));
+cl::opt<bool> Symbols("module-syms",
+ cl::desc("Display symbols for each compiland"),
+ cl::cat(TypeCategory), cl::sub(PrettySubcommand));
+cl::opt<bool> Globals("globals", cl::desc("Dump global symbols"),
+ cl::cat(TypeCategory), cl::sub(PrettySubcommand));
+cl::opt<bool> Externals("externals", cl::desc("Dump external symbols"),
+ cl::cat(TypeCategory), cl::sub(PrettySubcommand));
+cl::list<SymLevel> SymTypes(
+ "sym-types", cl::desc("Type of symbols to dump (default all)"),
+ cl::cat(TypeCategory), cl::sub(PrettySubcommand), cl::ZeroOrMore,
+ cl::values(
+ clEnumValN(SymLevel::Thunks, "thunks", "Display thunk symbols"),
+ clEnumValN(SymLevel::Data, "data", "Display data symbols"),
+ clEnumValN(SymLevel::Functions, "funcs", "Display function symbols"),
+ clEnumValN(SymLevel::All, "all", "Display all symbols (default)")));
+
+cl::opt<bool>
+ Types("types",
+ cl::desc("Display all types (implies -classes, -enums, -typedefs)"),
+ cl::cat(TypeCategory), cl::sub(PrettySubcommand));
+cl::opt<bool> Classes("classes", cl::desc("Display class types"),
+ cl::cat(TypeCategory), cl::sub(PrettySubcommand));
+cl::opt<bool> Enums("enums", cl::desc("Display enum types"),
+ cl::cat(TypeCategory), cl::sub(PrettySubcommand));
+cl::opt<bool> Typedefs("typedefs", cl::desc("Display typedef types"),
+ cl::cat(TypeCategory), cl::sub(PrettySubcommand));
+cl::opt<SymbolSortMode> SymbolOrder(
+ "symbol-order", cl::desc("symbol sort order"),
+ cl::init(SymbolSortMode::None),
+ cl::values(clEnumValN(SymbolSortMode::None, "none",
+ "Undefined / no particular sort order"),
+ clEnumValN(SymbolSortMode::Name, "name", "Sort symbols by name"),
+ clEnumValN(SymbolSortMode::Size, "size",
+ "Sort symbols by size")),
+ cl::cat(TypeCategory), cl::sub(PrettySubcommand));
+
+cl::opt<ClassSortMode> ClassOrder(
+ "class-order", cl::desc("Class sort order"), cl::init(ClassSortMode::None),
+ cl::values(
+ clEnumValN(ClassSortMode::None, "none",
+ "Undefined / no particular sort order"),
+ clEnumValN(ClassSortMode::Name, "name", "Sort classes by name"),
+ clEnumValN(ClassSortMode::Size, "size", "Sort classes by size"),
+ clEnumValN(ClassSortMode::Padding, "padding",
+ "Sort classes by amount of padding"),
+ clEnumValN(ClassSortMode::PaddingPct, "padding-pct",
+ "Sort classes by percentage of space consumed by padding"),
+ clEnumValN(ClassSortMode::PaddingImmediate, "padding-imm",
+ "Sort classes by amount of immediate padding"),
+ clEnumValN(ClassSortMode::PaddingPctImmediate, "padding-pct-imm",
+ "Sort classes by percentage of space consumed by immediate "
+ "padding")),
+ cl::cat(TypeCategory), cl::sub(PrettySubcommand));
+
+cl::opt<ClassDefinitionFormat> ClassFormat(
+ "class-definitions", cl::desc("Class definition format"),
+ cl::init(ClassDefinitionFormat::All),
+ cl::values(
+ clEnumValN(ClassDefinitionFormat::All, "all",
+ "Display all class members including data, constants, "
+ "typedefs, functions, etc"),
+ clEnumValN(ClassDefinitionFormat::Layout, "layout",
+ "Only display members that contribute to class size."),
+ clEnumValN(ClassDefinitionFormat::None, "none",
+ "Don't display class definitions")),
+ cl::cat(TypeCategory), cl::sub(PrettySubcommand));
+cl::opt<uint32_t> ClassRecursionDepth(
+ "class-recurse-depth", cl::desc("Class recursion depth (0=no limit)"),
+ cl::init(0), 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::sub(PrettySubcommand));
+
+cl::opt<uint64_t> LoadAddress(
+ "load-address",
+ cl::desc("Assume the module is loaded at the specified address"),
+ cl::cat(OtherOptions), cl::sub(PrettySubcommand));
+cl::opt<bool> Native("native", cl::desc("Use native PDB reader instead of DIA"),
+ cl::cat(OtherOptions), cl::sub(PrettySubcommand));
+cl::opt<cl::boolOrDefault>
+ ColorOutput("color-output",
+ cl::desc("Override use of color (default = isatty)"),
+ 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::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::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::sub(PrettySubcommand));
+cl::opt<uint32_t> SizeThreshold(
+ "min-type-size", cl::desc("Displays only those types which are greater "
+ "than or equal to the specified size."),
+ cl::init(0), cl::cat(FilterCategory), cl::sub(PrettySubcommand));
+cl::opt<uint32_t> PaddingThreshold(
+ "min-class-padding", cl::desc("Displays only those classes which have at "
+ "least the specified amount of padding."),
+ cl::init(0), cl::cat(FilterCategory), cl::sub(PrettySubcommand));
+cl::opt<uint32_t> ImmediatePaddingThreshold(
+ "min-class-padding-imm",
+ cl::desc("Displays only those classes which have at least the specified "
+ "amount of immediate padding, ignoring padding internal to bases "
+ "and aggregates."),
+ cl::init(0), 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::sub(PrettySubcommand));
+cl::opt<bool>
+ ExcludeSystemLibraries("no-system-libs",
+ cl::desc("Don't show symbols from system libraries"),
+ 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::sub(PrettySubcommand));
+}
+
+namespace diff {
+cl::opt<bool> PrintValueColumns(
+ "values", cl::init(true),
+ cl::desc("Print one column for each PDB with the field value"),
+ cl::Optional, cl::sub(DiffSubcommand));
+cl::opt<bool>
+ PrintResultColumn("result", cl::init(false),
+ cl::desc("Print a column with the result status"),
+ cl::Optional, cl::sub(DiffSubcommand));
+
+cl::opt<std::string> LeftRoot(
+ "left-bin-root", cl::Optional,
+ cl::desc("Treats the specified path as the root of the tree containing "
+ "binaries referenced by the left PDB. The root is stripped from "
+ "embedded paths when doing equality comparisons."),
+ cl::sub(DiffSubcommand));
+cl::opt<std::string> RightRoot(
+ "right-bin-root", cl::Optional,
+ cl::desc("Treats the specified path as the root of the tree containing "
+ "binaries referenced by the right PDB. The root is stripped from "
+ "embedded paths when doing equality comparisons"),
+ cl::sub(DiffSubcommand));
+
+cl::opt<std::string> Left(cl::Positional, cl::desc("<left>"),
+ cl::sub(DiffSubcommand));
+cl::opt<std::string> Right(cl::Positional, cl::desc("<right>"),
+ cl::sub(DiffSubcommand));
+}
+
+cl::OptionCategory FileOptions("Module & File Options");
+
+namespace bytes {
+cl::OptionCategory MsfBytes("MSF File Options");
+cl::OptionCategory DbiBytes("Dbi Stream Options");
+cl::OptionCategory PdbBytes("PDB Stream Options");
+cl::OptionCategory Types("Type Options");
+cl::OptionCategory ModuleCategory("Module Options");
+
+llvm::Optional<NumberRange> DumpBlockRange;
+llvm::Optional<NumberRange> DumpByteRange;
+
+cl::opt<std::string> DumpBlockRangeOpt(
+ "block-range", cl::value_desc("start[-end]"),
+ cl::desc("Dump binary data from specified range of blocks."),
+ cl::sub(BytesSubcommand), cl::cat(MsfBytes));
+
+cl::opt<std::string>
+ DumpByteRangeOpt("byte-range", cl::value_desc("start[-end]"),
+ cl::desc("Dump binary data from specified range of bytes"),
+ cl::sub(BytesSubcommand), cl::cat(MsfBytes));
+
+cl::list<std::string>
+ DumpStreamData("stream-data", cl::CommaSeparated, cl::ZeroOrMore,
+ cl::desc("Dump binary data from specified streams. Format "
+ "is SN[:Start][@Size]"),
+ cl::sub(BytesSubcommand), cl::cat(MsfBytes));
+
+cl::opt<bool> NameMap("name-map", cl::desc("Dump bytes of PDB Name Map"),
+ cl::sub(BytesSubcommand), cl::cat(PdbBytes));
+
+cl::opt<bool> SectionContributions("sc", cl::desc("Dump section contributions"),
+ cl::sub(BytesSubcommand), cl::cat(DbiBytes));
+cl::opt<bool> SectionMap("sm", cl::desc("Dump section map"),
+ cl::sub(BytesSubcommand), cl::cat(DbiBytes));
+cl::opt<bool> ModuleInfos("modi", cl::desc("Dump module info"),
+ cl::sub(BytesSubcommand), cl::cat(DbiBytes));
+cl::opt<bool> FileInfo("files", cl::desc("Dump source file info"),
+ cl::sub(BytesSubcommand), cl::cat(DbiBytes));
+cl::opt<bool> TypeServerMap("type-server", cl::desc("Dump type server map"),
+ cl::sub(BytesSubcommand), cl::cat(DbiBytes));
+cl::opt<bool> ECData("ec", cl::desc("Dump edit and continue map"),
+ cl::sub(BytesSubcommand), cl::cat(DbiBytes));
+
+cl::list<uint32_t>
+ TypeIndex("type",
+ cl::desc("Dump the type record with the given type index"),
+ cl::ZeroOrMore, cl::CommaSeparated, cl::sub(BytesSubcommand),
+ cl::cat(TypeCategory));
+cl::list<uint32_t>
+ IdIndex("id", cl::desc("Dump the id record with the given type index"),
+ cl::ZeroOrMore, cl::CommaSeparated, cl::sub(BytesSubcommand),
+ cl::cat(TypeCategory));
+
+cl::opt<uint32_t> ModuleIndex(
+ "mod",
+ cl::desc(
+ "Limit options in the Modules category to the specified module index"),
+ cl::Optional, cl::sub(BytesSubcommand), cl::cat(ModuleCategory));
+cl::opt<bool> ModuleSyms("syms", cl::desc("Dump symbol record substream"),
+ cl::sub(BytesSubcommand), cl::cat(ModuleCategory));
+cl::opt<bool> ModuleC11("c11-chunks", cl::Hidden,
+ cl::desc("Dump C11 CodeView debug chunks"),
+ cl::sub(BytesSubcommand), cl::cat(ModuleCategory));
+cl::opt<bool> ModuleC13("chunks",
+ cl::desc("Dump C13 CodeView debug chunk subsection"),
+ cl::sub(BytesSubcommand), cl::cat(ModuleCategory));
+cl::opt<bool> SplitChunks(
+ "split-chunks",
+ cl::desc(
+ "When dumping debug chunks, show a different section for each chunk"),
+ cl::sub(BytesSubcommand), cl::cat(ModuleCategory));
+cl::list<std::string> InputFilenames(cl::Positional,
+ cl::desc("<input PDB files>"),
+ cl::OneOrMore, cl::sub(BytesSubcommand));
+
+} // namespace bytes
+
+namespace dump {
+
+cl::OptionCategory MsfOptions("MSF Container Options");
+cl::OptionCategory TypeOptions("Type Record Options");
+cl::OptionCategory SymbolOptions("Symbol Options");
+cl::OptionCategory MiscOptions("Miscellaneous Options");
+
+// MSF OPTIONS
+cl::opt<bool> DumpSummary("summary", cl::desc("dump file summary"),
+ cl::cat(MsfOptions), cl::sub(DumpSubcommand));
+cl::opt<bool> DumpStreams("streams",
+ cl::desc("dump summary of the PDB streams"),
+ cl::cat(MsfOptions), cl::sub(DumpSubcommand));
+cl::opt<bool> DumpStreamBlocks(
+ "stream-blocks",
+ cl::desc("Add block information to the output of -streams"),
+ cl::cat(MsfOptions), cl::sub(DumpSubcommand));
+
+// TYPE OPTIONS
+cl::opt<bool> DumpTypes("types",
+ cl::desc("dump CodeView type records from TPI stream"),
+ cl::cat(TypeOptions), cl::sub(DumpSubcommand));
+cl::opt<bool> DumpTypeData(
+ "type-data",
+ cl::desc("dump CodeView type record raw bytes from TPI stream"),
+ cl::cat(TypeOptions), cl::sub(DumpSubcommand));
+
+cl::opt<bool> DumpTypeExtras("type-extras",
+ cl::desc("dump type hashes and index offsets"),
+ cl::cat(TypeOptions), cl::sub(DumpSubcommand));
+
+cl::list<uint32_t> DumpTypeIndex(
+ "type-index", cl::ZeroOrMore, cl::CommaSeparated,
+ cl::desc("only dump types with the specified hexadecimal type index"),
+ cl::cat(TypeOptions), cl::sub(DumpSubcommand));
+
+cl::opt<bool> DumpIds("ids",
+ cl::desc("dump CodeView type records from IPI stream"),
+ cl::cat(TypeOptions), cl::sub(DumpSubcommand));
+cl::opt<bool>
+ DumpIdData("id-data",
+ cl::desc("dump CodeView type record raw bytes from IPI stream"),
+ cl::cat(TypeOptions), cl::sub(DumpSubcommand));
+
+cl::opt<bool> DumpIdExtras("id-extras",
+ cl::desc("dump id hashes and index offsets"),
+ cl::cat(TypeOptions), cl::sub(DumpSubcommand));
+cl::list<uint32_t> DumpIdIndex(
+ "id-index", cl::ZeroOrMore, cl::CommaSeparated,
+ cl::desc("only dump ids with the specified hexadecimal type index"),
+ cl::cat(TypeOptions), cl::sub(DumpSubcommand));
+
+cl::opt<bool> DumpTypeDependents(
+ "dependents",
+ cl::desc("In conjunection with -type-index and -id-index, dumps the entire "
+ "dependency graph for the specified index instead of "
+ "just the single record with the specified index"),
+ cl::cat(TypeOptions), cl::sub(DumpSubcommand));
+
+// SYMBOL OPTIONS
+cl::opt<bool> DumpPublics("publics", cl::desc("dump Publics stream data"),
+ cl::cat(SymbolOptions), cl::sub(DumpSubcommand));
+cl::opt<bool> DumpSymbols("symbols", cl::desc("dump module symbols"),
+ cl::cat(SymbolOptions), cl::sub(DumpSubcommand));
+
+cl::opt<bool>
+ DumpSymRecordBytes("sym-data",
+ cl::desc("dump CodeView symbol record raw bytes"),
+ cl::cat(SymbolOptions), cl::sub(DumpSubcommand));
+
+// MODULE & FILE OPTIONS
+cl::opt<bool> DumpModules("modules", cl::desc("dump compiland information"),
+ cl::cat(FileOptions), cl::sub(DumpSubcommand));
+cl::opt<bool> DumpModuleFiles(
+ "files",
+ cl::desc("Dump the source files that contribute to each module's."),
+ cl::cat(FileOptions), cl::sub(DumpSubcommand));
+cl::opt<bool> DumpLines(
+ "l",
+ cl::desc("dump source file/line information (DEBUG_S_LINES subsection)"),
+ cl::cat(FileOptions), cl::sub(DumpSubcommand));
+cl::opt<bool> DumpInlineeLines(
+ "il",
+ cl::desc("dump inlinee line information (DEBUG_S_INLINEELINES subsection)"),
+ cl::cat(FileOptions), cl::sub(DumpSubcommand));
+cl::opt<bool> DumpXmi(
+ "xmi",
+ cl::desc(
+ "dump cross module imports (DEBUG_S_CROSSSCOPEIMPORTS subsection)"),
+ cl::cat(FileOptions), cl::sub(DumpSubcommand));
+cl::opt<bool> DumpXme(
+ "xme",
+ cl::desc(
+ "dump cross module exports (DEBUG_S_CROSSSCOPEEXPORTS subsection)"),
+ cl::cat(FileOptions), cl::sub(DumpSubcommand));
+
+// MISCELLANEOUS OPTIONS
+cl::opt<bool> DumpStringTable("string-table", cl::desc("dump PDB String Table"),
+ cl::cat(MiscOptions), cl::sub(DumpSubcommand));
+
+cl::opt<bool> DumpSectionContribs("section-contribs",
+ cl::desc("dump section contributions"),
+ cl::cat(MiscOptions),
+ cl::sub(DumpSubcommand));
+cl::opt<bool> DumpSectionMap("section-map", cl::desc("dump section map"),
+ cl::cat(MiscOptions), cl::sub(DumpSubcommand));
+
+cl::opt<bool> RawAll("all", cl::desc("Implies most other options."),
+ cl::cat(MiscOptions), cl::sub(DumpSubcommand));
+
+cl::list<std::string> InputFilenames(cl::Positional,
+ cl::desc("<input PDB files>"),
+ cl::OneOrMore, cl::sub(DumpSubcommand));
+}
+
+namespace yaml2pdb {
+cl::opt<std::string>
+ YamlPdbOutputFile("pdb", cl::desc("the name of the PDB file to write"),
+ cl::sub(YamlToPdbSubcommand));
+
+cl::opt<std::string> InputFilename(cl::Positional,
+ cl::desc("<input YAML file>"), cl::Required,
+ cl::sub(YamlToPdbSubcommand));
+}
+
+namespace pdb2yaml {
+cl::opt<bool> All("all",
+ cl::desc("Dump everything we know how to dump."),
+ cl::sub(PdbToYamlSubcommand), cl::init(false));
+cl::opt<bool> NoFileHeaders("no-file-headers",
+ cl::desc("Do not dump MSF file headers"),
+ cl::sub(PdbToYamlSubcommand), cl::init(false));
+cl::opt<bool> Minimal("minimal",
+ cl::desc("Don't write fields with default values"),
+ 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> StringTable("string-table", cl::desc("Dump the PDB String Table"),
+ cl::sub(PdbToYamlSubcommand), cl::init(false));
+
+cl::opt<bool> DbiStream("dbi-stream",
+ cl::desc("Dump the DBI Stream Headers (Stream 2)"),
+ cl::sub(PdbToYamlSubcommand), cl::init(false));
+
+cl::opt<bool> TpiStream("tpi-stream",
+ cl::desc("Dump the TPI Stream (Stream 3)"),
+ cl::sub(PdbToYamlSubcommand), cl::init(false));
+
+cl::opt<bool> IpiStream("ipi-stream",
+ cl::desc("Dump the IPI Stream (Stream 5)"),
+ cl::sub(PdbToYamlSubcommand), cl::init(false));
+
+// MODULE & FILE OPTIONS
+cl::opt<bool> DumpModules("modules", cl::desc("dump compiland information"),
+ cl::cat(FileOptions), cl::sub(PdbToYamlSubcommand));
+cl::opt<bool> DumpModuleFiles("module-files", cl::desc("dump file information"),
+ cl::cat(FileOptions),
+ cl::sub(PdbToYamlSubcommand));
+cl::list<ModuleSubsection> DumpModuleSubsections(
+ "subsections", cl::ZeroOrMore, cl::CommaSeparated,
+ cl::desc("dump subsections from each module's debug stream"), ChunkValues,
+ cl::cat(FileOptions), cl::sub(PdbToYamlSubcommand));
+cl::opt<bool> DumpModuleSyms("module-syms", cl::desc("dump module symbols"),
+ cl::cat(FileOptions),
+ cl::sub(PdbToYamlSubcommand));
+
+cl::list<std::string> InputFilename(cl::Positional,
+ cl::desc("<input PDB file>"), cl::Required,
+ cl::sub(PdbToYamlSubcommand));
+} // namespace pdb2yaml
+
+namespace analyze {
+cl::opt<bool> StringTable("hash-collisions", cl::desc("Find hash collisions"),
+ cl::sub(AnalyzeSubcommand), cl::init(false));
+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;
+
+static void yamlToPdb(StringRef Path) {
+ BumpPtrAllocator Allocator;
+ 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));
+ }
+
+ std::unique_ptr<MemoryBuffer> &Buffer = ErrorOrBuffer.get();
+
+ llvm::yaml::Input In(Buffer->getBuffer());
+ pdb::yaml::PdbObject YamlObj(Allocator);
+ In >> YamlObj;
+
+ PDBFileBuilder Builder(Allocator);
+
+ uint32_t BlockSize = 4096;
+ if (YamlObj.Headers.hasValue())
+ BlockSize = YamlObj.Headers->SuperBlock.BlockSize;
+ ExitOnErr(Builder.initialize(BlockSize));
+ // Add each of the reserved streams. We ignore stream metadata in the
+ // yaml, because we will reconstruct our own view of the streams. For
+ // example, the YAML may say that there were 20 streams in the original
+ // PDB, but maybe we only dump a subset of those 20 streams, so we will
+ // have fewer, and the ones we do have may end up with different indices
+ // than the ones in the original PDB. So we just start with a clean slate.
+ for (uint32_t I = 0; I < kSpecialStreamCount; ++I)
+ ExitOnErr(Builder.getMsfBuilder().addStream(0));
+
+ StringsAndChecksums Strings;
+ Strings.setStrings(std::make_shared<DebugStringTableSubsection>());
+
+ if (YamlObj.StringTable.hasValue()) {
+ for (auto S : *YamlObj.StringTable)
+ Strings.strings()->insert(S);
+ }
+
+ pdb::yaml::PdbInfoStream DefaultInfoStream;
+ pdb::yaml::PdbDbiStream DefaultDbiStream;
+ pdb::yaml::PdbTpiStream DefaultTpiStream;
+ pdb::yaml::PdbTpiStream DefaultIpiStream;
+
+ const auto &Info = YamlObj.PdbStream.getValueOr(DefaultInfoStream);
+
+ auto &InfoBuilder = Builder.getInfoBuilder();
+ InfoBuilder.setAge(Info.Age);
+ InfoBuilder.setGuid(Info.Guid);
+ InfoBuilder.setSignature(Info.Signature);
+ InfoBuilder.setVersion(Info.Version);
+ for (auto F : Info.Features)
+ InfoBuilder.addFeature(F);
+
+ const auto &Dbi = YamlObj.DbiStream.getValueOr(DefaultDbiStream);
+ auto &DbiBuilder = Builder.getDbiBuilder();
+ DbiBuilder.setAge(Dbi.Age);
+ DbiBuilder.setBuildNumber(Dbi.BuildNumber);
+ DbiBuilder.setFlags(Dbi.Flags);
+ DbiBuilder.setMachineType(Dbi.MachineType);
+ DbiBuilder.setPdbDllRbld(Dbi.PdbDllRbld);
+ DbiBuilder.setPdbDllVersion(Dbi.PdbDllVersion);
+ DbiBuilder.setVersionHeader(Dbi.VerHeader);
+ for (const auto &MI : Dbi.ModInfos) {
+ auto &ModiBuilder = ExitOnErr(DbiBuilder.addModuleInfo(MI.Mod));
+ ModiBuilder.setObjFileName(MI.Obj);
+
+ for (auto S : MI.SourceFiles)
+ ExitOnErr(DbiBuilder.addModuleSourceFile(MI.Mod, S));
+ if (MI.Modi.hasValue()) {
+ const auto &ModiStream = *MI.Modi;
+ for (auto Symbol : ModiStream.Symbols) {
+ ModiBuilder.addSymbol(
+ Symbol.toCodeViewSymbol(Allocator, CodeViewContainer::Pdb));
+ }
+ }
+
+ // Each module has its own checksum subsection, so scan for it every time.
+ Strings.setChecksums(nullptr);
+ CodeViewYAML::initializeStringsAndChecksums(MI.Subsections, Strings);
+
+ auto CodeViewSubsections = ExitOnErr(CodeViewYAML::toCodeViewSubsectionList(
+ Allocator, MI.Subsections, Strings));
+ for (auto &SS : CodeViewSubsections) {
+ ModiBuilder.addDebugSubsection(SS);
+ }
+ }
+
+ auto &TpiBuilder = Builder.getTpiBuilder();
+ const auto &Tpi = YamlObj.TpiStream.getValueOr(DefaultTpiStream);
+ TpiBuilder.setVersionHeader(Tpi.Version);
+ for (const auto &R : Tpi.Records) {
+ CVType Type = R.toCodeViewRecord(Allocator);
+ TpiBuilder.addTypeRecord(Type.RecordData, None);
+ }
+
+ const auto &Ipi = YamlObj.IpiStream.getValueOr(DefaultIpiStream);
+ auto &IpiBuilder = Builder.getIpiBuilder();
+ IpiBuilder.setVersionHeader(Ipi.Version);
+ for (const auto &R : Ipi.Records) {
+ CVType Type = R.toCodeViewRecord(Allocator);
+ IpiBuilder.addTypeRecord(Type.RecordData, None);
+ }
+
+ Builder.getStringTableBuilder().setStrings(*Strings.strings());
+
+ 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;
+ auto &File = loadPDB(Path, Session);
+
+ auto O = llvm::make_unique<YAMLOutputStyle>(File);
+ O = llvm::make_unique<YAMLOutputStyle>(File);
+
+ ExitOnErr(O->dump());
+}
+
+static void dumpRaw(StringRef Path) {
+ std::unique_ptr<IPDBSession> Session;
+ auto &File = loadPDB(Path, Session);
+
+ auto O = llvm::make_unique<DumpOutputStyle>(File);
+
+ ExitOnErr(O->dump());
+}
+
+static void dumpBytes(StringRef Path) {
+ std::unique_ptr<IPDBSession> Session;
+ auto &File = loadPDB(Path, Session);
+
+ auto O = llvm::make_unique<BytesOutputStyle>(File);
+
+ ExitOnErr(O->dump());
+}
+
+static void dumpAnalysis(StringRef Path) {
+ std::unique_ptr<IPDBSession> Session;
+ 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());
+}
+
+bool opts::pretty::shouldDumpSymLevel(SymLevel Search) {
+ if (SymTypes.empty())
+ return true;
+ if (llvm::find(SymTypes, Search) != SymTypes.end())
+ return true;
+ if (llvm::find(SymTypes, SymLevel::All) != SymTypes.end())
+ return true;
+ return false;
+}
+
+uint32_t llvm::pdb::getTypeLength(const PDBSymbolData &Symbol) {
+ auto SymbolType = Symbol.getType();
+ const IPDBRawSymbol &RawType = SymbolType->getRawSymbol();
+
+ return RawType.getLength();
+}
+
+bool opts::pretty::compareFunctionSymbols(
+ const std::unique_ptr<PDBSymbolFunc> &F1,
+ const std::unique_ptr<PDBSymbolFunc> &F2) {
+ assert(opts::pretty::SymbolOrder != opts::pretty::SymbolSortMode::None);
+
+ if (opts::pretty::SymbolOrder == opts::pretty::SymbolSortMode::Name)
+ return F1->getName() < F2->getName();
+
+ // Note that we intentionally sort in descending order on length, since
+ // long functions are more interesting than short functions.
+ return F1->getLength() > F2->getLength();
+}
+
+bool opts::pretty::compareDataSymbols(
+ const std::unique_ptr<PDBSymbolData> &F1,
+ const std::unique_ptr<PDBSymbolData> &F2) {
+ assert(opts::pretty::SymbolOrder != opts::pretty::SymbolSortMode::None);
+
+ if (opts::pretty::SymbolOrder == opts::pretty::SymbolSortMode::Name)
+ return F1->getName() < F2->getName();
+
+ // Note that we intentionally sort in descending order on length, since
+ // large types are more interesting than short ones.
+ return getTypeLength(*F1) > getTypeLength(*F2);
+}
+
+static void dumpPretty(StringRef Path) {
+ std::unique_ptr<IPDBSession> Session;
+
+ const auto ReaderType =
+ opts::pretty::Native ? PDB_ReaderType::Native : PDB_ReaderType::DIA;
+ ExitOnErr(loadDataForPDB(ReaderType, Path, Session));
+
+ if (opts::pretty::LoadAddress)
+ Session->setLoadAddress(opts::pretty::LoadAddress);
+
+ auto &Stream = outs();
+ const bool UseColor = opts::pretty::ColorOutput == cl::BOU_UNSET
+ ? Stream.has_colors()
+ : opts::pretty::ColorOutput == cl::BOU_TRUE;
+ LinePrinter Printer(2, UseColor, Stream);
+
+ auto GlobalScope(Session->getGlobalScope());
+ std::string FileName(GlobalScope->getSymbolsFileName());
+
+ WithColor(Printer, PDB_ColorItem::None).get() << "Summary for ";
+ WithColor(Printer, PDB_ColorItem::Path).get() << FileName;
+ Printer.Indent();
+ uint64_t FileSize = 0;
+
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << "Size";
+ if (!sys::fs::file_size(FileName, FileSize)) {
+ Printer << ": " << FileSize << " bytes";
+ } else {
+ Printer << ": (Unable to obtain file size)";
+ }
+
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << "Guid";
+ Printer << ": " << GlobalScope->getGuid();
+
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << "Age";
+ Printer << ": " << GlobalScope->getAge();
+
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << "Attributes";
+ Printer << ": ";
+ if (GlobalScope->hasCTypes())
+ outs() << "HasCTypes ";
+ if (GlobalScope->hasPrivateSymbols())
+ outs() << "HasPrivateSymbols ";
+ Printer.Unindent();
+
+ 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, options);
+ Printer.Unindent();
+ }
+
+ if (opts::pretty::Classes || opts::pretty::Enums || opts::pretty::Typedefs) {
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---TYPES---";
+ Printer.Indent();
+ TypeDumper Dumper(Printer);
+ Dumper.start(*GlobalScope);
+ Printer.Unindent();
+ }
+
+ if (opts::pretty::Symbols) {
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---SYMBOLS---";
+ Printer.Indent();
+ auto Compilands = GlobalScope->findAllChildren<PDBSymbolCompiland>();
+ CompilandDumper Dumper(Printer);
+ while (auto Compiland = Compilands->getNext())
+ Dumper.start(*Compiland, true);
+ Printer.Unindent();
+ }
+
+ if (opts::pretty::Globals) {
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---GLOBALS---";
+ Printer.Indent();
+ if (shouldDumpSymLevel(opts::pretty::SymLevel::Functions)) {
+ FunctionDumper Dumper(Printer);
+ auto Functions = GlobalScope->findAllChildren<PDBSymbolFunc>();
+ if (opts::pretty::SymbolOrder == opts::pretty::SymbolSortMode::None) {
+ while (auto Function = Functions->getNext()) {
+ Printer.NewLine();
+ Dumper.start(*Function, FunctionDumper::PointerType::None);
+ }
+ } else {
+ std::vector<std::unique_ptr<PDBSymbolFunc>> Funcs;
+ while (auto Func = Functions->getNext())
+ Funcs.push_back(std::move(Func));
+ std::sort(Funcs.begin(), Funcs.end(),
+ opts::pretty::compareFunctionSymbols);
+ for (const auto &Func : Funcs) {
+ Printer.NewLine();
+ Dumper.start(*Func, FunctionDumper::PointerType::None);
+ }
+ }
+ }
+ if (shouldDumpSymLevel(opts::pretty::SymLevel::Data)) {
+ auto Vars = GlobalScope->findAllChildren<PDBSymbolData>();
+ VariableDumper Dumper(Printer);
+ if (opts::pretty::SymbolOrder == opts::pretty::SymbolSortMode::None) {
+ while (auto Var = Vars->getNext())
+ Dumper.start(*Var);
+ } else {
+ std::vector<std::unique_ptr<PDBSymbolData>> Datas;
+ while (auto Var = Vars->getNext())
+ Datas.push_back(std::move(Var));
+ std::sort(Datas.begin(), Datas.end(), opts::pretty::compareDataSymbols);
+ for (const auto &Var : Datas)
+ Dumper.start(*Var);
+ }
+ }
+ if (shouldDumpSymLevel(opts::pretty::SymLevel::Thunks)) {
+ auto Thunks = GlobalScope->findAllChildren<PDBSymbolThunk>();
+ CompilandDumper Dumper(Printer);
+ while (auto Thunk = Thunks->getNext())
+ Dumper.dump(*Thunk);
+ }
+ Printer.Unindent();
+ }
+ 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();
+}
+
+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);
+ SmallVector<TypeIndex, 128> TypeMap;
+ SmallVector<TypeIndex, 128> IdMap;
+ if (File.hasPDBTpiStream()) {
+ auto &Tpi = ExitOnErr(File.getPDBTpiStream());
+ ExitOnErr(
+ codeview::mergeTypeRecords(MergedTpi, TypeMap, Tpi.typeArray()));
+ }
+ if (File.hasPDBIpiStream()) {
+ auto &Ipi = ExitOnErr(File.getPDBIpiStream());
+ ExitOnErr(codeview::mergeIdRecords(MergedIpi, TypeMap, IdMap,
+ 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, ArrayRef<uint8_t> Data) {
+ DestTpi.addTypeRecord(Data, None);
+ });
+ MergedIpi.ForEachRecord([&DestIpi](TypeIndex TI, ArrayRef<uint8_t> Data) {
+ DestIpi.addTypeRecord(Data, None);
+ });
+ Builder.getInfoBuilder().addFeature(PdbRaw_FeatureSig::VC140);
+
+ 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));
+}
+
+static bool parseRange(StringRef Str,
+ Optional<opts::bytes::NumberRange> &Parsed) {
+ if (Str.empty())
+ return true;
+
+ llvm::Regex R("^([^-]+)(-([^-]+))?$");
+ llvm::SmallVector<llvm::StringRef, 2> Matches;
+ if (!R.match(Str, &Matches))
+ return false;
+
+ Parsed.emplace();
+ if (!to_integer(Matches[1], Parsed->Min))
+ return false;
+
+ if (!Matches[3].empty()) {
+ Parsed->Max.emplace();
+ if (!to_integer(Matches[3], *Parsed->Max))
+ return false;
+ }
+ return true;
+}
+
+static void simplifyChunkList(llvm::cl::list<opts::ModuleSubsection> &Chunks) {
+ // If this list contains "All" plus some other stuff, remove the other stuff
+ // and just keep "All" in the list.
+ if (!llvm::is_contained(Chunks, opts::ModuleSubsection::All))
+ return;
+ Chunks.reset();
+ Chunks.push_back(opts::ModuleSubsection::All);
+}
+
+int main(int argc_, const char *argv_[]) {
+ // Print a stack trace if we signal out.
+ sys::PrintStackTraceOnErrorSignal(argv_[0]);
+ PrettyStackTraceProgram X(argc_, argv_);
+
+ ExitOnErr.setBanner("llvm-pdbutil: ");
+
+ SmallVector<const char *, 256> argv;
+ SpecificBumpPtrAllocator<char> ArgAllocator;
+ 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::BytesSubcommand) {
+ if (!parseRange(opts::bytes::DumpBlockRangeOpt,
+ opts::bytes::DumpBlockRange)) {
+ errs() << "Argument '" << opts::bytes::DumpBlockRangeOpt
+ << "' invalid format.\n";
+ errs().flush();
+ exit(1);
+ }
+ if (!parseRange(opts::bytes::DumpByteRangeOpt,
+ opts::bytes::DumpByteRange)) {
+ errs() << "Argument '" << opts::bytes::DumpByteRangeOpt
+ << "' invalid format.\n";
+ errs().flush();
+ exit(1);
+ }
+ }
+
+ if (opts::DumpSubcommand) {
+ if (opts::dump::RawAll) {
+ opts::dump::DumpLines = true;
+ opts::dump::DumpInlineeLines = true;
+ opts::dump::DumpXme = true;
+ opts::dump::DumpXmi = true;
+ opts::dump::DumpIds = true;
+ opts::dump::DumpPublics = true;
+ opts::dump::DumpSectionContribs = true;
+ opts::dump::DumpSectionMap = true;
+ opts::dump::DumpStreams = true;
+ opts::dump::DumpStreamBlocks = true;
+ opts::dump::DumpStringTable = true;
+ opts::dump::DumpSummary = true;
+ opts::dump::DumpSymbols = true;
+ opts::dump::DumpIds = true;
+ opts::dump::DumpIdExtras = true;
+ opts::dump::DumpTypes = true;
+ opts::dump::DumpTypeExtras = true;
+ opts::dump::DumpModules = true;
+ opts::dump::DumpModuleFiles = true;
+ }
+ }
+ if (opts::PdbToYamlSubcommand) {
+ if (opts::pdb2yaml::All) {
+ opts::pdb2yaml::StreamMetadata = true;
+ opts::pdb2yaml::StreamDirectory = true;
+ opts::pdb2yaml::PdbStream = true;
+ opts::pdb2yaml::StringTable = true;
+ opts::pdb2yaml::DbiStream = true;
+ opts::pdb2yaml::TpiStream = true;
+ opts::pdb2yaml::IpiStream = true;
+ opts::pdb2yaml::DumpModules = true;
+ opts::pdb2yaml::DumpModuleFiles = true;
+ opts::pdb2yaml::DumpModuleSyms = true;
+ opts::pdb2yaml::DumpModuleSubsections.push_back(
+ opts::ModuleSubsection::All);
+ }
+ simplifyChunkList(opts::pdb2yaml::DumpModuleSubsections);
+
+ if (opts::pdb2yaml::DumpModuleSyms || opts::pdb2yaml::DumpModuleFiles)
+ opts::pdb2yaml::DumpModules = true;
+
+ if (opts::pdb2yaml::DumpModules)
+ opts::pdb2yaml::DbiStream = true;
+ }
+ if (opts::DiffSubcommand) {
+ if (!opts::diff::PrintResultColumn && !opts::diff::PrintValueColumns) {
+ llvm::errs() << "WARNING: No diff columns specified\n";
+ }
+ }
+
+ llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::MultiThreaded);
+
+ if (opts::PdbToYamlSubcommand) {
+ pdb2Yaml(opts::pdb2yaml::InputFilename.front());
+ } else if (opts::YamlToPdbSubcommand) {
+ if (opts::yaml2pdb::YamlPdbOutputFile.empty()) {
+ SmallString<16> OutputFilename(opts::yaml2pdb::InputFilename.getValue());
+ sys::path::replace_extension(OutputFilename, ".pdb");
+ opts::yaml2pdb::YamlPdbOutputFile = OutputFilename.str();
+ }
+ yamlToPdb(opts::yaml2pdb::InputFilename);
+ } else if (opts::AnalyzeSubcommand) {
+ dumpAnalysis(opts::analyze::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 (opts::pretty::Types) {
+ opts::pretty::Classes = true;
+ opts::pretty::Typedefs = true;
+ opts::pretty::Enums = true;
+ }
+
+ // 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::DumpSubcommand) {
+ std::for_each(opts::dump::InputFilenames.begin(),
+ opts::dump::InputFilenames.end(), dumpRaw);
+ } else if (opts::BytesSubcommand) {
+ std::for_each(opts::bytes::InputFilenames.begin(),
+ opts::bytes::InputFilenames.end(), dumpBytes);
+ } else if (opts::DiffSubcommand) {
+ diff(opts::diff::Left, opts::diff::Right);
+ } 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();
+ return 0;
+}
diff --git a/contrib/llvm/tools/llvm-pdbutil/llvm-pdbutil.h b/contrib/llvm/tools/llvm-pdbutil/llvm-pdbutil.h
new file mode 100644
index 0000000..4e92e63
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/llvm-pdbutil.h
@@ -0,0 +1,180 @@
+//===- llvm-pdbutil.h ----------------------------------------- *- 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_LLVMPDBDUMP_H
+#define LLVM_TOOLS_LLVMPDBDUMP_LLVMPDBDUMP_H
+
+#include "llvm/ADT/Optional.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <memory>
+#include <stdint.h>
+
+namespace llvm {
+namespace pdb {
+class PDBSymbolData;
+class PDBSymbolFunc;
+uint32_t getTypeLength(const PDBSymbolData &Symbol);
+}
+}
+
+namespace opts {
+
+enum class DumpLevel { None, Basic, Verbose };
+
+enum class ModuleSubsection {
+ Unknown,
+ Lines,
+ FileChecksums,
+ InlineeLines,
+ CrossScopeImports,
+ CrossScopeExports,
+ StringTable,
+ Symbols,
+ FrameData,
+ CoffSymbolRVAs,
+ All
+};
+
+namespace pretty {
+
+enum class ClassDefinitionFormat { None, Layout, All };
+enum class ClassSortMode {
+ None,
+ Name,
+ Size,
+ Padding,
+ PaddingPct,
+ PaddingImmediate,
+ PaddingPctImmediate
+};
+
+enum class SymbolSortMode { None, Name, Size };
+
+enum class SymLevel { Functions, Data, Thunks, All };
+
+bool shouldDumpSymLevel(SymLevel Level);
+bool compareFunctionSymbols(
+ const std::unique_ptr<llvm::pdb::PDBSymbolFunc> &F1,
+ const std::unique_ptr<llvm::pdb::PDBSymbolFunc> &F2);
+bool compareDataSymbols(const std::unique_ptr<llvm::pdb::PDBSymbolData> &F1,
+ const std::unique_ptr<llvm::pdb::PDBSymbolData> &F2);
+
+extern llvm::cl::opt<bool> Compilands;
+extern llvm::cl::opt<bool> Symbols;
+extern llvm::cl::opt<bool> Globals;
+extern llvm::cl::opt<bool> Classes;
+extern llvm::cl::opt<bool> Enums;
+extern llvm::cl::opt<bool> Typedefs;
+extern llvm::cl::opt<bool> All;
+extern llvm::cl::opt<bool> ExcludeCompilerGenerated;
+
+extern llvm::cl::opt<bool> NoEnumDefs;
+extern llvm::cl::list<std::string> ExcludeTypes;
+extern llvm::cl::list<std::string> ExcludeSymbols;
+extern llvm::cl::list<std::string> ExcludeCompilands;
+extern llvm::cl::list<std::string> IncludeTypes;
+extern llvm::cl::list<std::string> IncludeSymbols;
+extern llvm::cl::list<std::string> IncludeCompilands;
+extern llvm::cl::opt<SymbolSortMode> SymbolOrder;
+extern llvm::cl::opt<ClassSortMode> ClassOrder;
+extern llvm::cl::opt<uint32_t> SizeThreshold;
+extern llvm::cl::opt<uint32_t> PaddingThreshold;
+extern llvm::cl::opt<uint32_t> ImmediatePaddingThreshold;
+extern llvm::cl::opt<ClassDefinitionFormat> ClassFormat;
+extern llvm::cl::opt<uint32_t> ClassRecursionDepth;
+}
+
+namespace bytes {
+struct NumberRange {
+ uint64_t Min;
+ llvm::Optional<uint64_t> Max;
+};
+
+extern llvm::Optional<NumberRange> DumpBlockRange;
+extern llvm::Optional<NumberRange> DumpByteRange;
+extern llvm::cl::list<std::string> DumpStreamData;
+extern llvm::cl::opt<bool> NameMap;
+
+extern llvm::cl::opt<bool> SectionContributions;
+extern llvm::cl::opt<bool> SectionMap;
+extern llvm::cl::opt<bool> ModuleInfos;
+extern llvm::cl::opt<bool> FileInfo;
+extern llvm::cl::opt<bool> TypeServerMap;
+extern llvm::cl::opt<bool> ECData;
+
+extern llvm::cl::list<uint32_t> TypeIndex;
+extern llvm::cl::list<uint32_t> IdIndex;
+
+extern llvm::cl::opt<uint32_t> ModuleIndex;
+extern llvm::cl::opt<bool> ModuleSyms;
+extern llvm::cl::opt<bool> ModuleC11;
+extern llvm::cl::opt<bool> ModuleC13;
+extern llvm::cl::opt<bool> SplitChunks;
+} // namespace bytes
+
+namespace dump {
+
+extern llvm::cl::opt<bool> DumpSummary;
+extern llvm::cl::opt<bool> DumpStreams;
+extern llvm::cl::opt<bool> DumpStreamBlocks;
+
+extern llvm::cl::opt<bool> DumpLines;
+extern llvm::cl::opt<bool> DumpInlineeLines;
+extern llvm::cl::opt<bool> DumpXmi;
+extern llvm::cl::opt<bool> DumpXme;
+extern llvm::cl::opt<bool> DumpStringTable;
+extern llvm::cl::opt<bool> DumpTypes;
+extern llvm::cl::opt<bool> DumpTypeData;
+extern llvm::cl::opt<bool> DumpTypeExtras;
+extern llvm::cl::list<uint32_t> DumpTypeIndex;
+extern llvm::cl::opt<bool> DumpTypeDependents;
+
+extern llvm::cl::opt<bool> DumpIds;
+extern llvm::cl::opt<bool> DumpIdData;
+extern llvm::cl::opt<bool> DumpIdExtras;
+extern llvm::cl::list<uint32_t> DumpIdIndex;
+extern llvm::cl::opt<bool> DumpSymbols;
+extern llvm::cl::opt<bool> DumpSymRecordBytes;
+extern llvm::cl::opt<bool> DumpPublics;
+extern llvm::cl::opt<bool> DumpSectionContribs;
+extern llvm::cl::opt<bool> DumpSectionMap;
+extern llvm::cl::opt<bool> DumpModules;
+extern llvm::cl::opt<bool> DumpModuleFiles;
+extern llvm::cl::opt<bool> RawAll;
+}
+
+namespace pdb2yaml {
+extern llvm::cl::opt<bool> All;
+extern llvm::cl::opt<bool> NoFileHeaders;
+extern llvm::cl::opt<bool> Minimal;
+extern llvm::cl::opt<bool> StreamMetadata;
+extern llvm::cl::opt<bool> StreamDirectory;
+extern llvm::cl::opt<bool> StringTable;
+extern llvm::cl::opt<bool> PdbStream;
+extern llvm::cl::opt<bool> DbiStream;
+extern llvm::cl::opt<bool> TpiStream;
+extern llvm::cl::opt<bool> IpiStream;
+extern llvm::cl::list<std::string> InputFilename;
+extern llvm::cl::opt<bool> DumpModules;
+extern llvm::cl::opt<bool> DumpModuleFiles;
+extern llvm::cl::list<ModuleSubsection> DumpModuleSubsections;
+extern llvm::cl::opt<bool> DumpModuleSyms;
+} // namespace pdb2yaml
+
+namespace diff {
+extern llvm::cl::opt<bool> PrintValueColumns;
+extern llvm::cl::opt<bool> PrintResultColumn;
+extern llvm::cl::opt<std::string> LeftRoot;
+extern llvm::cl::opt<std::string> RightRoot;
+} // namespace diff
+}
+
+#endif
OpenPOWER on IntegriCloud