summaryrefslogtreecommitdiff
path: root/tools/llvm-pdbutil
diff options
context:
space:
mode:
authorZachary Turner <zturner@google.com>2017-06-15 22:24:24 +0000
committerZachary Turner <zturner@google.com>2017-06-15 22:24:24 +0000
commit7e5d31edd7148213417aa3a99615eea97f8b279e (patch)
tree488fa65c324e5dfe14bce399902da1675373cabd /tools/llvm-pdbutil
parent02688b00ef03018033c601d8d83c6baf7a596c7f (diff)
Resubmit "[llvm-pdbutil] rewrite the "raw" output style."
This resubmits commit c0c249e9f2ef83e1d1e5f166b50673d92f3579d7. It was broken due to some weird template issues, which have since been fixed. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@305517 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'tools/llvm-pdbutil')
-rw-r--r--tools/llvm-pdbutil/CMakeLists.txt5
-rw-r--r--tools/llvm-pdbutil/FormatUtil.cpp49
-rw-r--r--tools/llvm-pdbutil/FormatUtil.h120
-rw-r--r--tools/llvm-pdbutil/LLVMOutputStyle.cpp1198
-rw-r--r--tools/llvm-pdbutil/LinePrinter.cpp33
-rw-r--r--tools/llvm-pdbutil/LinePrinter.h31
-rw-r--r--tools/llvm-pdbutil/MinimalSymbolDumper.cpp749
-rw-r--r--tools/llvm-pdbutil/MinimalSymbolDumper.h47
-rw-r--r--tools/llvm-pdbutil/MinimalTypeDumper.cpp532
-rw-r--r--tools/llvm-pdbutil/MinimalTypeDumper.h56
-rw-r--r--tools/llvm-pdbutil/RawOutputStyle.cpp669
-rw-r--r--tools/llvm-pdbutil/RawOutputStyle.h (renamed from tools/llvm-pdbutil/LLVMOutputStyle.h)35
-rw-r--r--tools/llvm-pdbutil/YAMLOutputStyle.cpp21
-rw-r--r--tools/llvm-pdbutil/llvm-pdbutil.cpp172
-rw-r--r--tools/llvm-pdbutil/llvm-pdbutil.h45
15 files changed, 2399 insertions, 1363 deletions
diff --git a/tools/llvm-pdbutil/CMakeLists.txt b/tools/llvm-pdbutil/CMakeLists.txt
index 9875dfb5a25..d09fa31d8b6 100644
--- a/tools/llvm-pdbutil/CMakeLists.txt
+++ b/tools/llvm-pdbutil/CMakeLists.txt
@@ -12,8 +12,10 @@ add_llvm_tool(llvm-pdbutil
CompactTypeDumpVisitor.cpp
Diff.cpp
llvm-pdbutil.cpp
+ FormatUtil.cpp
LinePrinter.cpp
- LLVMOutputStyle.cpp
+ MinimalSymbolDumper.cpp
+ MinimalTypeDumper.cpp
PdbYaml.cpp
PrettyBuiltinDumper.cpp
PrettyClassDefinitionDumper.cpp
@@ -25,6 +27,7 @@ add_llvm_tool(llvm-pdbutil
PrettyTypeDumper.cpp
PrettyTypedefDumper.cpp
PrettyVariableDumper.cpp
+ RawOutputStyle.cpp
StreamUtil.cpp
YAMLOutputStyle.cpp
)
diff --git a/tools/llvm-pdbutil/FormatUtil.cpp b/tools/llvm-pdbutil/FormatUtil.cpp
new file mode 100644
index 00000000000..007db9ee9f9
--- /dev/null
+++ b/tools/llvm-pdbutil/FormatUtil.cpp
@@ -0,0 +1,49 @@
+//===- 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::typesetItemList(ArrayRef<std::string> Opts,
+ uint32_t GroupSize, uint32_t IndentLevel,
+ 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/tools/llvm-pdbutil/FormatUtil.h b/tools/llvm-pdbutil/FormatUtil.h
new file mode 100644
index 00000000000..3db2dbacc57
--- /dev/null
+++ b/tools/llvm-pdbutil/FormatUtil.h
@@ -0,0 +1,120 @@
+//===- 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 {
+
+#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> static 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/tools/llvm-pdbutil/LLVMOutputStyle.cpp b/tools/llvm-pdbutil/LLVMOutputStyle.cpp
deleted file mode 100644
index c4af4583a10..00000000000
--- a/tools/llvm-pdbutil/LLVMOutputStyle.cpp
+++ /dev/null
@@ -1,1198 +0,0 @@
-//===- LLVMOutputStyle.cpp ------------------------------------ *- C++ --*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "LLVMOutputStyle.h"
-
-#include "CompactTypeDumpVisitor.h"
-#include "StreamUtil.h"
-#include "llvm-pdbutil.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/DebugSymbolRVASubsection.h"
-#include "llvm/DebugInfo/CodeView/DebugSymbolsSubsection.h"
-#include "llvm/DebugInfo/CodeView/DebugUnknownSubsection.h"
-#include "llvm/DebugInfo/CodeView/EnumTables.h"
-#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
-#include "llvm/DebugInfo/CodeView/Line.h"
-#include "llvm/DebugInfo/CodeView/StringsAndChecksums.h"
-#include "llvm/DebugInfo/CodeView/SymbolDumper.h"
-#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h"
-#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.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/FormatVariadic.h"
-
-#include <unordered_map>
-
-using namespace llvm;
-using namespace llvm::codeview;
-using namespace llvm::msf;
-using namespace llvm::pdb;
-
-namespace {
-struct PageStats {
- explicit PageStats(const BitVector &FreePages)
- : Upm(FreePages), ActualUsedPages(FreePages.size()),
- MultiUsePages(FreePages.size()), UseAfterFreePages(FreePages.size()) {
- const_cast<BitVector &>(Upm).flip();
- // To calculate orphaned pages, we start with the set of pages that the
- // MSF thinks are used. Each time we find one that actually *is* used,
- // we unset it. Whichever bits remain set at the end are orphaned.
- OrphanedPages = Upm;
- }
-
- // The inverse of the MSF File's copy of the Fpm. The basis for which we
- // determine the allocation status of each page.
- const BitVector Upm;
-
- // Pages which are marked as used in the FPM and are used at least once.
- BitVector ActualUsedPages;
-
- // Pages which are marked as used in the FPM but are used more than once.
- BitVector MultiUsePages;
-
- // Pages which are marked as used in the FPM but are not used at all.
- BitVector OrphanedPages;
-
- // Pages which are marked free in the FPM but are used.
- BitVector UseAfterFreePages;
-};
-
-class C13RawVisitor : public DebugSubsectionVisitor {
-public:
- C13RawVisitor(ScopedPrinter &P, LazyRandomTypeCollection &TPI,
- LazyRandomTypeCollection *IPI)
- : P(P), TPI(TPI), IPI(IPI) {}
-
- Error visitUnknown(DebugUnknownSubsectionRef &Unknown) override {
- if (!opts::checkModuleSubsection(opts::ModuleSubsection::Unknown))
- return Error::success();
- DictScope DD(P, "Unknown");
- P.printHex("Kind", static_cast<uint32_t>(Unknown.kind()));
- ArrayRef<uint8_t> Data;
- BinaryStreamReader Reader(Unknown.getData());
- consumeError(Reader.readBytes(Data, Reader.bytesRemaining()));
- P.printBinaryBlock("Data", Data);
- return Error::success();
- }
-
- Error visitLines(DebugLinesSubsectionRef &Lines,
- const StringsAndChecksumsRef &State) override {
- if (!opts::checkModuleSubsection(opts::ModuleSubsection::Lines))
- return Error::success();
-
- DictScope DD(P, "Lines");
-
- P.printNumber("RelocSegment", Lines.header()->RelocSegment);
- P.printNumber("RelocOffset", Lines.header()->RelocOffset);
- P.printNumber("CodeSize", Lines.header()->CodeSize);
- P.printBoolean("HasColumns", Lines.hasColumnInfo());
-
- for (const auto &L : Lines) {
- DictScope DDDD(P, "FileEntry");
-
- if (auto EC = printFileName("FileName", L.NameIndex, State))
- return EC;
-
- for (const auto &N : L.LineNumbers) {
- DictScope DDD(P, "Line");
- LineInfo LI(N.Flags);
- P.printNumber("Offset", N.Offset);
- if (LI.isAlwaysStepInto())
- P.printString("StepInto", StringRef("Always"));
- else if (LI.isNeverStepInto())
- P.printString("StepInto", StringRef("Never"));
- else
- P.printNumber("LineNumberStart", LI.getStartLine());
- P.printNumber("EndDelta", LI.getLineDelta());
- P.printBoolean("IsStatement", LI.isStatement());
- }
- for (const auto &C : L.Columns) {
- DictScope DDD(P, "Column");
- P.printNumber("Start", C.StartColumn);
- P.printNumber("End", C.EndColumn);
- }
- }
-
- return Error::success();
- }
-
- Error visitFileChecksums(DebugChecksumsSubsectionRef &Checksums,
- const StringsAndChecksumsRef &State) override {
- if (!opts::checkModuleSubsection(opts::ModuleSubsection::FileChecksums))
- return Error::success();
-
- DictScope DD(P, "FileChecksums");
- for (const auto &CS : Checksums) {
- DictScope DDD(P, "Checksum");
- if (auto Result = getNameFromStringTable(CS.FileNameOffset, State))
- P.printString("FileName", *Result);
- else
- return Result.takeError();
- P.printEnum("Kind", uint8_t(CS.Kind), getFileChecksumNames());
- P.printBinaryBlock("Checksum", CS.Checksum);
- }
- return Error::success();
- }
-
- Error visitInlineeLines(DebugInlineeLinesSubsectionRef &Inlinees,
- const StringsAndChecksumsRef &State) override {
- if (!opts::checkModuleSubsection(opts::ModuleSubsection::InlineeLines))
- return Error::success();
-
- DictScope D(P, "InlineeLines");
- P.printBoolean("HasExtraFiles", Inlinees.hasExtraFiles());
- ListScope LS(P, "Lines");
- for (const auto &L : Inlinees) {
- DictScope DDD(P, "Inlinee");
- if (auto EC = printFileName("FileName", L.Header->FileID, State))
- return EC;
-
- if (auto EC = dumpTypeRecord("Function", L.Header->Inlinee))
- return EC;
- P.printNumber("SourceLine", L.Header->SourceLineNum);
- if (Inlinees.hasExtraFiles()) {
- ListScope DDDD(P, "ExtraFiles");
- for (const auto &EF : L.ExtraFiles) {
- if (auto EC = printFileName("File", EF, State))
- return EC;
- }
- }
- }
- return Error::success();
- }
-
- Error visitCrossModuleExports(DebugCrossModuleExportsSubsectionRef &CSE,
- const StringsAndChecksumsRef &State) override {
- if (!opts::checkModuleSubsection(opts::ModuleSubsection::CrossScopeExports))
- return Error::success();
-
- ListScope D(P, "CrossModuleExports");
- for (const auto &M : CSE) {
- DictScope D(P, "Export");
- P.printHex("Local", M.Local);
- P.printHex("Global", M.Global);
- }
- return Error::success();
- }
-
- Error visitCrossModuleImports(DebugCrossModuleImportsSubsectionRef &CSI,
- const StringsAndChecksumsRef &State) override {
- if (!opts::checkModuleSubsection(opts::ModuleSubsection::CrossScopeImports))
- return Error::success();
-
- ListScope L(P, "CrossModuleImports");
- for (const auto &M : CSI) {
- DictScope D(P, "ModuleImport");
- auto Name = getNameFromStringTable(M.Header->ModuleNameOffset, State);
- if (!Name)
- return Name.takeError();
- P.printString("Module", *Name);
- P.printHexList("Imports", M.Imports);
- }
- return Error::success();
- }
-
- Error visitFrameData(DebugFrameDataSubsectionRef &FD,
- const StringsAndChecksumsRef &State) override {
- if (!opts::checkModuleSubsection(opts::ModuleSubsection::FrameData))
- return Error::success();
-
- ListScope L(P, "FrameData");
- for (const auto &Frame : FD) {
- DictScope D(P, "Frame");
- auto Name = getNameFromStringTable(Frame.FrameFunc, State);
- if (!Name)
- return joinErrors(make_error<RawError>(raw_error_code::invalid_format,
- "Invalid Frame.FrameFunc index"),
- Name.takeError());
- P.printNumber("Rva", Frame.RvaStart);
- P.printNumber("CodeSize", Frame.CodeSize);
- P.printNumber("LocalSize", Frame.LocalSize);
- P.printNumber("ParamsSize", Frame.ParamsSize);
- P.printNumber("MaxStackSize", Frame.MaxStackSize);
- P.printString("FrameFunc", *Name);
- P.printNumber("PrologSize", Frame.PrologSize);
- P.printNumber("SavedRegsSize", Frame.SavedRegsSize);
- P.printNumber("Flags", Frame.Flags);
- }
- return Error::success();
- }
-
- Error visitSymbols(DebugSymbolsSubsectionRef &Symbols,
- const StringsAndChecksumsRef &State) override {
- if (!opts::checkModuleSubsection(opts::ModuleSubsection::Symbols))
- return Error::success();
- ListScope L(P, "Symbols");
-
- // This section should not actually appear in a PDB file, it really only
- // appears in object files. But we support it here for testing. So we
- // specify the Object File container type.
- codeview::CVSymbolDumper SD(P, TPI, CodeViewContainer::ObjectFile, nullptr,
- false);
- for (auto S : Symbols) {
- DictScope LL(P, "");
- if (auto EC = SD.dump(S)) {
- return make_error<RawError>(
- raw_error_code::corrupt_file,
- "DEBUG_S_SYMBOLS subsection contained corrupt symbol record");
- }
- }
- return Error::success();
- }
-
- Error visitStringTable(DebugStringTableSubsectionRef &Strings,
- const StringsAndChecksumsRef &State) override {
- if (!opts::checkModuleSubsection(opts::ModuleSubsection::StringTable))
- return Error::success();
-
- ListScope D(P, "String Table");
- BinaryStreamReader Reader(Strings.getBuffer());
- StringRef S;
- consumeError(Reader.readCString(S));
- while (Reader.bytesRemaining() > 0) {
- consumeError(Reader.readCString(S));
- if (S.empty() && Reader.bytesRemaining() < 4)
- break;
- P.printString(S);
- }
- return Error::success();
- }
-
- Error visitCOFFSymbolRVAs(DebugSymbolRVASubsectionRef &RVAs,
- const StringsAndChecksumsRef &State) override {
- if (!opts::checkModuleSubsection(opts::ModuleSubsection::CoffSymbolRVAs))
- return Error::success();
-
- ListScope D(P, "COFF Symbol RVAs");
- P.printHexList("RVAs", RVAs);
- return Error::success();
- }
-
-private:
- Error dumpTypeRecord(StringRef Label, TypeIndex Index) {
- bool Success = false;
- DictScope D(P, Label);
- if (IPI) {
- CompactTypeDumpVisitor CTDV(*IPI, Index, &P);
- if (IPI->contains(Index)) {
- CVType Type = IPI->getType(Index);
- if (auto EC = codeview::visitTypeRecord(Type, CTDV))
- return EC;
- }
- }
-
- if (!Success) {
- P.printString(
- llvm::formatv("Index: {0:x} (unknown function)", Index.getIndex())
- .str());
- }
- return Error::success();
- }
- Error printFileName(StringRef Label, uint32_t Offset,
- const StringsAndChecksumsRef &State) {
- if (auto Result = getNameFromChecksumsBuffer(Offset, State)) {
- P.printString(Label, *Result);
- return Error::success();
- } else
- return Result.takeError();
- }
-
- Expected<StringRef>
- getNameFromStringTable(uint32_t Offset, const StringsAndChecksumsRef &State) {
- return State.strings().getString(Offset);
- }
-
- Expected<StringRef>
- getNameFromChecksumsBuffer(uint32_t Offset,
- const StringsAndChecksumsRef &State) {
- auto Array = State.checksums().getArray();
- auto ChecksumIter = Array.at(Offset);
- if (ChecksumIter == Array.end())
- return make_error<RawError>(raw_error_code::invalid_format);
- const auto &Entry = *ChecksumIter;
- return getNameFromStringTable(Entry.FileNameOffset, State);
- }
-
- ScopedPrinter &P;
- LazyRandomTypeCollection &TPI;
- LazyRandomTypeCollection *IPI;
-};
-}
-
-static void recordKnownUsedPage(PageStats &Stats, uint32_t UsedIndex) {
- if (Stats.Upm.test(UsedIndex)) {
- if (Stats.ActualUsedPages.test(UsedIndex))
- Stats.MultiUsePages.set(UsedIndex);
- Stats.ActualUsedPages.set(UsedIndex);
- Stats.OrphanedPages.reset(UsedIndex);
- } else {
- // The MSF doesn't think this page is used, but it is.
- Stats.UseAfterFreePages.set(UsedIndex);
- }
-}
-
-static void printSectionOffset(llvm::raw_ostream &OS,
- const SectionOffset &Off) {
- OS << Off.Off << ", " << Off.Isect;
-}
-
-LLVMOutputStyle::LLVMOutputStyle(PDBFile &File) : File(File), P(outs()) {}
-
-Error LLVMOutputStyle::dump() {
- if (auto EC = dumpFileHeaders())
- return EC;
-
- if (auto EC = dumpStreamSummary())
- return EC;
-
- if (auto EC = dumpFreePageMap())
- return EC;
-
- if (auto EC = dumpStreamBlocks())
- return EC;
-
- if (auto EC = dumpBlockRanges())
- return EC;
-
- if (auto EC = dumpStreamBytes())
- return EC;
-
- if (auto EC = dumpStringTable())
- return EC;
-
- if (auto EC = dumpInfoStream())
- return EC;
-
- if (auto EC = dumpTpiStream(StreamTPI))
- return EC;
-
- if (auto EC = dumpTpiStream(StreamIPI))
- return EC;
-
- if (auto EC = dumpDbiStream())
- return EC;
-
- if (auto EC = dumpSectionContribs())
- return EC;
-
- if (auto EC = dumpSectionMap())
- return EC;
-
- if (auto EC = dumpGlobalsStream())
- return EC;
-
- if (auto EC = dumpPublicsStream())
- return EC;
-
- if (auto EC = dumpSectionHeaders())
- return EC;
-
- if (auto EC = dumpFpoStream())
- return EC;
-
- flush();
-
- return Error::success();
-}
-
-Error LLVMOutputStyle::dumpFileHeaders() {
- if (!opts::raw::DumpHeaders)
- return Error::success();
-
- DictScope D(P, "FileHeaders");
- P.printNumber("BlockSize", File.getBlockSize());
- P.printNumber("FreeBlockMap", File.getFreeBlockMapBlock());
- P.printNumber("NumBlocks", File.getBlockCount());
- P.printNumber("NumDirectoryBytes", File.getNumDirectoryBytes());
- P.printNumber("Unknown1", File.getUnknown1());
- P.printNumber("BlockMapAddr", File.getBlockMapIndex());
- P.printNumber("NumDirectoryBlocks", File.getNumDirectoryBlocks());
-
- // The directory is not contiguous. Instead, the block map contains a
- // contiguous list of block numbers whose contents, when concatenated in
- // order, make up the directory.
- P.printList("DirectoryBlocks", File.getDirectoryBlockArray());
- P.printNumber("NumStreams", File.getNumStreams());
- return Error::success();
-}
-
-Error LLVMOutputStyle::dumpStreamSummary() {
- if (!opts::raw::DumpStreamSummary)
- return Error::success();
-
- if (StreamPurposes.empty())
- discoverStreamPurposes(File, StreamPurposes);
-
- uint32_t StreamCount = File.getNumStreams();
-
- ListScope L(P, "Streams");
- for (uint16_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) {
- std::string Label("Stream ");
- Label += to_string(StreamIdx);
-
- std::string Value = "[" + StreamPurposes[StreamIdx] + "] (";
- Value += to_string(File.getStreamByteSize(StreamIdx));
- Value += " bytes)";
-
- P.printString(Label, Value);
- }
-
- P.flush();
- return Error::success();
-}
-
-Error LLVMOutputStyle::dumpFreePageMap() {
- if (!opts::raw::DumpPageStats)
- return Error::success();
-
- // Start with used pages instead of free pages because
- // the number of free pages is far larger than used pages.
- BitVector FPM = File.getMsfLayout().FreePageMap;
-
- PageStats PS(FPM);
-
- recordKnownUsedPage(PS, 0); // MSF Super Block
-
- uint32_t BlocksPerSection = msf::getFpmIntervalLength(File.getMsfLayout());
- uint32_t NumSections = msf::getNumFpmIntervals(File.getMsfLayout());
- for (uint32_t I = 0; I < NumSections; ++I) {
- uint32_t Fpm0 = 1 + BlocksPerSection * I;
- // 2 Fpm blocks spaced at `getBlockSize()` block intervals
- recordKnownUsedPage(PS, Fpm0);
- recordKnownUsedPage(PS, Fpm0 + 1);
- }
-
- recordKnownUsedPage(PS, File.getBlockMapIndex()); // Stream Table
-
- for (auto DB : File.getDirectoryBlockArray())
- recordKnownUsedPage(PS, DB);
-
- // Record pages used by streams. Note that pages for stream 0
- // are considered being unused because that's what MSVC tools do.
- // Stream 0 doesn't contain actual data, so it makes some sense,
- // though it's a bit confusing to us.
- for (auto &SE : File.getStreamMap().drop_front(1))
- for (auto &S : SE)
- recordKnownUsedPage(PS, S);
-
- dumpBitVector("Msf Free Pages", FPM);
- dumpBitVector("Orphaned Pages", PS.OrphanedPages);
- dumpBitVector("Multiply Used Pages", PS.MultiUsePages);
- dumpBitVector("Use After Free Pages", PS.UseAfterFreePages);
- return Error::success();
-}
-
-void LLVMOutputStyle::dumpBitVector(StringRef Name, const BitVector &V) {
- std::vector<uint32_t> Vec;
- for (uint32_t I = 0, E = V.size(); I != E; ++I)
- if (V[I])
- Vec.push_back(I);
- P.printList(Name, Vec);
-}
-
-Error LLVMOutputStyle::dumpGlobalsStream() {
- if (!opts::raw::DumpGlobals)
- return Error::success();
- if (!File.hasPDBGlobalsStream()) {
- P.printString("Globals Stream not present");
- return Error::success();
- }
-
- auto Globals = File.getPDBGlobalsStream();
- if (!Globals)
- return Globals.takeError();
- DictScope D(P, "Globals Stream");
-
- auto Dbi = File.getPDBDbiStream();
- if (!Dbi)
- return Dbi.takeError();
-
- P.printNumber("Stream number", Dbi->getGlobalSymbolStreamIndex());
- P.printNumber("Number of buckets", Globals->getNumBuckets());
- P.printList("Hash Buckets", Globals->getHashBuckets());
-
- return Error::success();
-}
-
-Error LLVMOutputStyle::dumpStreamBlocks() {
- if (!opts::raw::DumpStreamBlocks)
- return Error::success();
-
- ListScope L(P, "StreamBlocks");
- uint32_t StreamCount = File.getNumStreams();
- for (uint32_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) {
- std::string Name("Stream ");
- Name += to_string(StreamIdx);
- auto StreamBlocks = File.getStreamBlockList(StreamIdx);
- P.printList(Name, StreamBlocks);
- }
- return Error::success();
-}
-
-Error LLVMOutputStyle::dumpBlockRanges() {
- if (!opts::raw::DumpBlockRange.hasValue())
- return Error::success();
- auto &R = *opts::raw::DumpBlockRange;
- uint32_t Max = R.Max.getValueOr(R.Min);
-
- if (Max < R.Min)
- return make_error<StringError>(
- "Invalid block range specified. Max < Min",
- std::make_error_code(std::errc::bad_address));
- if (Max >= File.getBlockCount())
- return make_error<StringError>(
- "Invalid block range specified. Requested block out of bounds",
- std::make_error_code(std::errc::bad_address));
-
- DictScope D(P, "Block Data");
- for (uint32_t I = R.Min; I <= Max; ++I) {
- auto ExpectedData = File.getBlockData(I, File.getBlockSize());
- if (!ExpectedData)
- return ExpectedData.takeError();
- std::string Label;
- llvm::raw_string_ostream S(Label);
- S << "Block " << I;
- S.flush();
- P.printBinaryBlock(Label, *ExpectedData);
- }
-
- return Error::success();
-}
-
-static Error parseStreamSpec(StringRef Str, uint32_t &SI, uint32_t &Offset,
- uint32_t &Size) {
- if (Str.consumeInteger(0, SI))
- return make_error<RawError>(raw_error_code::invalid_format,
- "Invalid Stream Specification");
- if (Str.consume_front(":")) {
- if (Str.consumeInteger(0, Offset))
- return make_error<RawError>(raw_error_code::invalid_format,
- "Invalid Stream Specification");
- }
- if (Str.consume_front("@")) {
- if (Str.consumeInteger(0, 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 Error::success();
-}
-
-Error LLVMOutputStyle::dumpStreamBytes() {
- if (opts::raw::DumpStreamData.empty())
- return Error::success();
-
- if (StreamPurposes.empty())
- discoverStreamPurposes(File, StreamPurposes);
-
- DictScope D(P, "Stream Data");
- for (auto &Str : opts::raw::DumpStreamData) {
- uint32_t SI = 0;
- uint32_t Begin = 0;
- uint32_t Size = 0;
- uint32_t End = 0;
-
- if (auto EC = parseStreamSpec(Str, SI, Begin, Size))
- return EC;
-
- if (SI >= File.getNumStreams())
- return make_error<RawError>(raw_error_code::no_stream);
-
- auto S = MappedBlockStream::createIndexedStream(
- File.getMsfLayout(), File.getMsfBuffer(), SI, File.getAllocator());
- if (!S)
- continue;
- DictScope DD(P, "Stream");
- if (Size == 0)
- End = S->getLength();
- else {
- End = Begin + Size;
- if (End >= S->getLength())
- return make_error<RawError>(raw_error_code::index_out_of_bounds,
- "Stream is not long enough!");
- }
-
- P.printNumber("Index", SI);
- P.printString("Type", StreamPurposes[SI]);
- P.printNumber("Size", S->getLength());
- auto Blocks = File.getMsfLayout().StreamMap[SI];
- P.printList("Blocks", Blocks);
-
- BinaryStreamReader R(*S);
- ArrayRef<uint8_t> StreamData;
- if (auto EC = R.readBytes(StreamData, S->getLength()))
- return EC;
- Size = End - Begin;
- StreamData = StreamData.slice(Begin, Size);
- P.printBinaryBlock("Data", StreamData, Begin);
- }
- return Error::success();
-}
-
-Error LLVMOutputStyle::dumpStringTable() {
- if (!opts::raw::DumpStringTable)
- return Error::success();
-
- auto IS = File.getStringTable();
- if (!IS)
- return IS.takeError();
-
- DictScope D(P, "String Table");
- for (uint32_t I : IS->name_ids()) {
- auto ES = IS->getStringForID(I);
- if (!ES)
- return ES.takeError();
-
- if (ES->empty())
- continue;
- llvm::SmallString<32> Str;
- Str.append("'");
- Str.append(*ES);
- Str.append("'");
- P.printString(Str);
- }
- return Error::success();
-}
-
-Error LLVMOutputStyle::dumpInfoStream() {
- if (!opts::raw::DumpHeaders)
- return Error::success();
- if (!File.hasPDBInfoStream()) {
- P.printString("PDB Stream not present");
- return Error::success();
- }
- auto IS = File.getPDBInfoStream();
- if (!IS)
- return IS.takeError();
-
- DictScope D(P, "PDB Stream");
- P.printNumber("Version", IS->getVersion());
- P.printHex("Signature", IS->getSignature());
- P.printNumber("Age", IS->getAge());
- P.printObject("Guid", IS->getGuid());
- P.printHex("Features", IS->getFeatures());
- {
- DictScope DD(P, "Named Streams");
- for (const auto &S : IS->getNamedStreams().entries())
- P.printObject(S.getKey(), S.getValue());
- }
- return Error::success();
-}
-
-namespace {
-class RecordBytesVisitor : public TypeVisitorCallbacks {
-public:
- explicit RecordBytesVisitor(ScopedPrinter &P) : P(P) {}
-
- Error visitTypeEnd(CVType &Record) override {
- P.printBinaryBlock("Bytes", Record.content());
- return Error::success();
- }
-
-private:
- ScopedPrinter &P;
-};
-}
-
-Error LLVMOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
- assert(StreamIdx == StreamTPI || StreamIdx == StreamIPI);
-
- bool DumpRecordBytes = false;
- bool DumpRecords = false;
- bool DumpTpiHash = false;
- StringRef Label;
- StringRef VerLabel;
- if (StreamIdx == StreamTPI) {
- if (!File.hasPDBTpiStream()) {
- P.printString("Type Info Stream (TPI) not present");
- return Error::success();
- }
- DumpRecordBytes = opts::raw::DumpTpiRecordBytes;
- DumpRecords = opts::raw::DumpTpiRecords;
- DumpTpiHash = opts::raw::DumpTpiHash;
- Label = "Type Info Stream (TPI)";
- VerLabel = "TPI Version";
- } else if (StreamIdx == StreamIPI) {
- auto InfoS = File.getPDBInfoStream();
- if (!InfoS)
- return InfoS.takeError();
-
- if (!File.hasPDBIpiStream() || !InfoS->containsIdStream())
- return Error::success();
- DumpRecordBytes = opts::raw::DumpIpiRecordBytes;
- DumpRecords = opts::raw::DumpIpiRecords;
- Label = "Type Info Stream (IPI)";
- VerLabel = "IPI Version";
- }
-
- auto Tpi = (StreamIdx == StreamTPI) ? File.getPDBTpiStream()
- : File.getPDBIpiStream();
- if (!Tpi)
- return Tpi.takeError();
-
- auto ExpectedTypes = initializeTypeDatabase(StreamIdx);
- if (!ExpectedTypes)
- return ExpectedTypes.takeError();
- auto &Types = *ExpectedTypes;
-
- if (!DumpRecordBytes && !DumpRecords && !DumpTpiHash)
- return Error::success();
-
- std::unique_ptr<DictScope> StreamScope;
- std::unique_ptr<ListScope> RecordScope;
-
- StreamScope = llvm::make_unique<DictScope>(P, Label);
- P.printNumber(VerLabel, Tpi->getTpiVersion());
- P.printNumber("Record count", Tpi->getNumTypeRecords());
-
- std::vector<std::unique_ptr<TypeVisitorCallbacks>> Visitors;
-
- // If we're in dump mode, add a dumper with the appropriate detail level.
- if (DumpRecords) {
- std::unique_ptr<TypeVisitorCallbacks> Dumper;
- if (opts::raw::CompactRecords)
- Dumper = make_unique<CompactTypeDumpVisitor>(Types, &P);
- else {
- assert(TpiTypes);
-
- auto X = make_unique<TypeDumpVisitor>(*TpiTypes, &P, false);
- if (StreamIdx == StreamIPI)
- X->setIpiTypes(*IpiTypes);
- Dumper = std::move(X);
- }
- Visitors.push_back(std::move(Dumper));
- }
- if (DumpRecordBytes)
- Visitors.push_back(make_unique<RecordBytesVisitor>(P));
-
- // We always need to deserialize and add it to the type database. This is
- // true if even if we're not dumping anything, because we could need the
- // type database for the purposes of dumping symbols.
- TypeVisitorCallbackPipeline Pipeline;
- for (const auto &V : Visitors)
- Pipeline.addCallbackToPipeline(*V);
-
- if (DumpRecords || DumpRecordBytes)
- RecordScope = llvm::make_unique<ListScope>(P, "Records");
-
- Optional<TypeIndex> I = Types.getFirst();
- while (I) {
- std::unique_ptr<DictScope> OneRecordScope;
-
- if ((DumpRecords || DumpRecordBytes) && !opts::raw::CompactRecords)
- OneRecordScope = llvm::make_unique<DictScope>(P, "");
-
- auto T = Types.getType(*I);
- if (auto EC = codeview::visitTypeRecord(T, *I, Pipeline))
- return EC;
- I = Types.getNext(*I);
- }
-
- if (DumpTpiHash) {
- DictScope DD(P, "Hash");
- P.printNumber("Number of Hash Buckets", Tpi->getNumHashBuckets());
- P.printNumber("Hash Key Size", Tpi->getHashKeySize());
- P.printList("Values", Tpi->getHashValues());
-
- ListScope LHA(P, "Adjusters");
- auto ExpectedST = File.getStringTable();
- if (!ExpectedST)
- return ExpectedST.takeError();
- const auto &ST = *ExpectedST;
- for (const auto &E : Tpi->getHashAdjusters()) {
- DictScope DHA(P);
- auto Name = ST.getStringForID(E.first);
- if (!Name)
- return Name.takeError();
-
- P.printString("Type", *Name);
- P.printHex("TI", E.second);
- }
- }
-
- ListScope L(P, "TypeIndexOffsets");
- for (const auto &IO : Tpi->getTypeIndexOffsets()) {
- P.printString(formatv("Index: {0:x}, Offset: {1:N}", IO.Type.getIndex(),
- (uint32_t)IO.Offset)
- .str());
- }
-
- P.flush();
- return Error::success();
-}
-
-Expected<codeview::LazyRandomTypeCollection &>
-LLVMOutputStyle::initializeTypeDatabase(uint32_t SN) {
- auto &TypeCollection = (SN == StreamTPI) ? TpiTypes : IpiTypes;
- auto Tpi =
- (SN == StreamTPI) ? File.getPDBTpiStream() : File.getPDBIpiStream();
- if (!Tpi)
- return Tpi.takeError();
-
- if (!TypeCollection) {
- // Initialize the type collection, even if we're not going to dump it. This
- // way if some other part of the dumper decides it wants to use some or all
- // of the records for whatever purposes, it can still access them lazily.
- auto &Types = Tpi->typeArray();
- uint32_t Count = Tpi->getNumTypeRecords();
- auto Offsets = Tpi->getTypeIndexOffsets();
- TypeCollection =
- llvm::make_unique<LazyRandomTypeCollection>(Types, Count, Offsets);
- }
-
- return *TypeCollection;
-}
-
-Error LLVMOutputStyle::dumpDbiStream() {
- bool DumpModules = opts::shared::DumpModules ||
- opts::shared::DumpModuleSyms ||
- opts::shared::DumpModuleFiles ||
- !opts::shared::DumpModuleSubsections.empty();
- if (!opts::raw::DumpHeaders && !DumpModules)
- return Error::success();
- if (!File.hasPDBDbiStream()) {
- P.printString("DBI Stream not present");
- return Error::success();
- }
-
- ExitOnError Err("Error while processing DBI Stream");
-
- auto DS = File.getPDBDbiStream();
- if (!DS)
- return DS.takeError();
-
- DictScope D(P, "DBI Stream");
- P.printNumber("Dbi Version", DS->getDbiVersion());
- P.printNumber("Age", DS->getAge());
- P.printBoolean("Incremental Linking", DS->isIncrementallyLinked());
- P.printBoolean("Has CTypes", DS->hasCTypes());
- P.printBoolean("Is Stripped", DS->isStripped());
- P.printObject("Machine Type", DS->getMachineType());
- P.printNumber("Symbol Record Stream Index", DS->getSymRecordStreamIndex());
- P.printNumber("Public Symbol Stream Index", DS->getPublicSymbolStreamIndex());
- P.printNumber("Global Symbol Stream Index", DS->getGlobalSymbolStreamIndex());
-
- uint16_t Major = DS->getBuildMajorVersion();
- uint16_t Minor = DS->getBuildMinorVersion();
- P.printVersion("Toolchain Version", Major, Minor);
-
- std::string DllName;
- raw_string_ostream DllStream(DllName);
- DllStream << "mspdb" << Major << Minor << ".dll version";
- DllStream.flush();
- P.printVersion(DllName, Major, Minor, DS->getPdbDllVersion());
-
- if (DumpModules) {
- ListScope L(P, "Modules");
- const DbiModuleList &Modules = DS->modules();
- for (uint32_t I = 0; I < Modules.getModuleCount(); ++I) {
- const DbiModuleDescriptor &Modi = Modules.getModuleDescriptor(I);
- DictScope DD(P);
- P.printString("Name", Modi.getModuleName().str());
- P.printNumber("Debug Stream Index", Modi.getModuleStreamIndex());
- P.printString("Object File Name", Modi.getObjFileName().str());
- P.printNumber("Num Files", Modi.getNumberOfFiles());
- P.printNumber("Source File Name Idx", Modi.getSourceFileNameIndex());
- P.printNumber("Pdb File Name Idx", Modi.getPdbFilePathNameIndex());
- P.printNumber("Line Info Byte Size", Modi.getC11LineInfoByteSize());
- P.printNumber("C13 Line Info Byte Size", Modi.getC13LineInfoByteSize());
- P.printNumber("Symbol Byte Size", Modi.getSymbolDebugInfoByteSize());
- P.printNumber("Type Server Index", Modi.getTypeServerIndex());
- P.printBoolean("Has EC Info", Modi.hasECInfo());
- if (opts::shared::DumpModuleFiles) {
- std::string FileListName = to_string(Modules.getSourceFileCount(I)) +
- " Contributing Source Files";
- ListScope LL(P, FileListName);
- for (auto File : Modules.source_files(I))
- P.printString(File);
- }
- bool HasModuleDI = (Modi.getModuleStreamIndex() < File.getNumStreams());
- bool ShouldDumpSymbols =
- (opts::shared::DumpModuleSyms || opts::raw::DumpSymRecordBytes);
- if (HasModuleDI &&
- (ShouldDumpSymbols || !opts::shared::DumpModuleSubsections.empty())) {
- auto ModStreamData = MappedBlockStream::createIndexedStream(
- File.getMsfLayout(), File.getMsfBuffer(),
- Modi.getModuleStreamIndex(), File.getAllocator());
-
- ModuleDebugStreamRef ModS(Modi, std::move(ModStreamData));
- if (auto EC = ModS.reload())
- return EC;
-
- auto ExpectedTpi = initializeTypeDatabase(StreamTPI);
- if (!ExpectedTpi)
- return ExpectedTpi.takeError();
- auto &Tpi = *ExpectedTpi;
- if (ShouldDumpSymbols) {
-
- ListScope SS(P, "Symbols");
- codeview::CVSymbolDumper SD(P, Tpi, CodeViewContainer::Pdb, nullptr,
- false);
- bool HadError = false;
- for (auto S : ModS.symbols(&HadError)) {
- DictScope LL(P, "");
- if (opts::shared::DumpModuleSyms) {
- if (auto EC = SD.dump(S)) {
- llvm::consumeError(std::move(EC));
- HadError = true;
- break;
- }
- }
- if (opts::raw::DumpSymRecordBytes)
- P.printBinaryBlock("Bytes", S.content());
- }
- if (HadError)
- return make_error<RawError>(
- raw_error_code::corrupt_file,
- "DBI stream contained corrupt symbol record");
- }
- if (!opts::shared::DumpModuleSubsections.empty()) {
- ListScope SS(P, "Subsections");
- auto &InfoS = Err(File.getPDBInfoStream());
- LazyRandomTypeCollection *Ipi = nullptr;
- if (InfoS.containsIdStream())
- Ipi = &Err(initializeTypeDatabase(StreamIPI));
- auto ExpectedStrings = File.getStringTable();
- if (!ExpectedStrings)
- return joinErrors(
- make_error<RawError>(raw_error_code::no_stream,
- "Could not get string table!"),
- ExpectedStrings.takeError());
-
- C13RawVisitor V(P, Tpi, Ipi);
- if (auto EC = codeview::visitDebugSubsections(
- ModS.subsections(), V, ExpectedStrings->getStringTable()))
- return EC;
- }
- }
- }
- }
- return Error::success();
-}
-
-Error LLVMOutputStyle::dumpSectionContribs() {
- if (!opts::raw::DumpSectionContribs)
- return Error::success();
- if (!File.hasPDBDbiStream()) {
- P.printString("DBI Stream not present");
- return Error::success();
- }
-
- auto Dbi = File.getPDBDbiStream();
- if (!Dbi)
- return Dbi.takeError();
-
- ListScope L(P, "Section Contributions");
- class Visitor : public ISectionContribVisitor {
- public:
- Visitor(ScopedPrinter &P, DbiStream &DS) : P(P), DS(DS) {}
- void visit(const SectionContrib &SC) override {
- DictScope D(P, "Contribution");
- P.printNumber("ISect", SC.ISect);
- P.printNumber("Off", SC.Off);
- P.printNumber("Size", SC.Size);
- P.printFlags("Characteristics", SC.Characteristics,
- codeview::getImageSectionCharacteristicNames(),
- COFF::SectionCharacteristics(0x00F00000));
- {
- DictScope DD(P, "Module");
- P.printNumber("Index", SC.Imod);
- const DbiModuleList &Modules = DS.modules();
- if (Modules.getModuleCount() > SC.Imod) {
- P.printString("Name",
- Modules.getModuleDescriptor(SC.Imod).getModuleName());
- }
- }
- P.printNumber("Data CRC", SC.DataCrc);
- P.printNumber("Reloc CRC", SC.RelocCrc);
- P.flush();
- }
- void visit(const SectionContrib2 &SC) override {
- visit(SC.Base);
- P.printNumber("ISect Coff", SC.ISectCoff);
- P.flush();
- }
-
- private:
- ScopedPrinter &P;
- DbiStream &DS;
- };
- Visitor V(P, *Dbi);
- Dbi->visitSectionContributions(V);
- return Error::success();
-}
-
-Error LLVMOutputStyle::dumpSectionMap() {
- if (!opts::raw::DumpSectionMap)
- return Error::success();
- if (!File.hasPDBDbiStream()) {
- P.printString("DBI Stream not present");
- return Error::success();
- }
-
- auto Dbi = File.getPDBDbiStream();
- if (!Dbi)
- return Dbi.takeError();
-
- ListScope L(P, "Section Map");
- for (auto &M : Dbi->getSectionMap()) {
- DictScope D(P, "Entry");
- P.printFlags("Flags", M.Flags, getOMFSegMapDescFlagNames());
- P.printNumber("Ovl", M.Ovl);
- P.printNumber("Group", M.Group);
- P.printNumber("Frame", M.Frame);
- P.printNumber("SecName", M.SecName);
- P.printNumber("ClassName", M.ClassName);
- P.printNumber("Offset", M.Offset);
- P.printNumber("SecByteLength", M.SecByteLength);
- P.flush();
- }
- return Error::success();
-}
-
-Error LLVMOutputStyle::dumpPublicsStream() {
- if (!opts::raw::DumpPublics)
- return Error::success();
- if (!File.hasPDBPublicsStream()) {
- P.printString("Publics Stream not present");
- return Error::success();
- }
-
- auto Publics = File.getPDBPublicsStream();
- if (!Publics)
- return Publics.takeError();
- DictScope D(P, "Publics Stream");
-
- auto Dbi = File.getPDBDbiStream();
- if (!Dbi)
- return Dbi.takeError();
-
- P.printNumber("Stream number", Dbi->getPublicSymbolStreamIndex());
- P.printNumber("SymHash", Publics->getSymHash());
- P.printNumber("AddrMap", Publics->getAddrMap());
- P.printNumber("Number of buckets", Publics->getNumBuckets());
- P.printList("Hash Buckets", Publics->getHashBuckets());
- P.printList("Address Map", Publics->getAddressMap());
- P.printList("Thunk Map", Publics->getThunkMap());
- P.printList("Section Offsets", Publics->getSectionOffsets(),
- printSectionOffset);
- ListScope L(P, "Symbols");
- auto ExpectedTypes = initializeTypeDatabase(StreamTPI);
- if (!ExpectedTypes)
- return ExpectedTypes.takeError();
- auto &Tpi = *ExpectedTypes;
-
- codeview::CVSymbolDumper SD(P, Tpi, CodeViewContainer::Pdb, nullptr, false);
- bool HadError = false;
- for (auto S : Publics->getSymbols(&HadError)) {
- DictScope DD(P, "");
-
- if (auto EC = SD.dump(S)) {
- HadError = true;
- break;
- }
- if (opts::raw::DumpSymRecordBytes)
- P.printBinaryBlock("Bytes", S.content());
- }
- if (HadError)
- return make_error<RawError>(
- raw_error_code::corrupt_file,
- "Public symbol stream contained corrupt record");
-
- return Error::success();
-}
-
-Error LLVMOutputStyle::dumpSectionHeaders() {
- if (!opts::raw::DumpSectionHeaders)
- return Error::success();
- if (!File.hasPDBDbiStream()) {
- P.printString("DBI Stream not present");
- return Error::success();
- }
-
- auto Dbi = File.getPDBDbiStream();
- if (!Dbi)
- return Dbi.takeError();
-
- ListScope D(P, "Section Headers");
- for (const object::coff_section &Section : Dbi->getSectionHeaders()) {
- DictScope DD(P, "");
-
- // If a name is 8 characters long, there is no NUL character at end.
- StringRef Name(Section.Name, strnlen(Section.Name, sizeof(Section.Name)));
- P.printString("Name", Name);
- P.printNumber("Virtual Size", Section.VirtualSize);
- P.printNumber("Virtual Address", Section.VirtualAddress);
- P.printNumber("Size of Raw Data", Section.SizeOfRawData);
- P.printNumber("File Pointer to Raw Data", Section.PointerToRawData);
- P.printNumber("File Pointer to Relocations", Section.PointerToRelocations);
- P.printNumber("File Pointer to Linenumbers", Section.PointerToLinenumbers);
- P.printNumber("Number of Relocations", Section.NumberOfRelocations);
- P.printNumber("Number of Linenumbers", Section.NumberOfLinenumbers);
- P.printFlags("Characteristics", Section.Characteristics,
- getImageSectionCharacteristicNames());
- }
- return Error::success();
-}
-
-Error LLVMOutputStyle::dumpFpoStream() {
- if (!opts::raw::DumpFpo)
- return Error::success();
- if (!File.hasPDBDbiStream()) {
- P.printString("DBI Stream not present");
- return Error::success();
- }
-
- auto Dbi = File.getPDBDbiStream();
- if (!Dbi)
- return Dbi.takeError();
-
- ListScope D(P, "New FPO");
- for (const object::FpoData &Fpo : Dbi->getFpoRecords()) {
- DictScope DD(P, "");
- P.printNumber("Offset", Fpo.Offset);
- P.printNumber("Size", Fpo.Size);
- P.printNumber("Number of locals", Fpo.NumLocals);
- P.printNumber("Number of params", Fpo.NumParams);
- P.printNumber("Size of Prolog", Fpo.getPrologSize());
- P.printNumber("Number of Saved Registers", Fpo.getNumSavedRegs());
- P.printBoolean("Has SEH", Fpo.hasSEH());
- P.printBoolean("Use BP", Fpo.useBP());
- P.printNumber("Frame Pointer", Fpo.getFP());
- }
- return Error::success();
-}
-
-void LLVMOutputStyle::flush() { P.flush(); }
diff --git a/tools/llvm-pdbutil/LinePrinter.cpp b/tools/llvm-pdbutil/LinePrinter.cpp
index ef56b5fe8e6..718d3394e21 100644
--- a/tools/llvm-pdbutil/LinePrinter.cpp
+++ b/tools/llvm-pdbutil/LinePrinter.cpp
@@ -13,6 +13,7 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/DebugInfo/PDB/UDTLayout.h"
+#include "llvm/Support/Format.h"
#include "llvm/Support/Regex.h"
#include <algorithm>
@@ -60,10 +61,16 @@ LinePrinter::LinePrinter(int Indent, bool UseColor, llvm::raw_ostream &Stream)
opts::pretty::IncludeCompilands.end());
}
-void LinePrinter::Indent() { CurrentIndent += IndentSpaces; }
+void LinePrinter::Indent(uint32_t Amount) {
+ if (Amount == 0)
+ Amount = IndentSpaces;
+ CurrentIndent += Amount;
+}
-void LinePrinter::Unindent() {
- CurrentIndent = std::max(0, CurrentIndent - IndentSpaces);
+void LinePrinter::Unindent(uint32_t Amount) {
+ if (Amount == 0)
+ Amount = IndentSpaces;
+ CurrentIndent = std::max<int>(0, CurrentIndent - Amount);
}
void LinePrinter::NewLine() {
@@ -71,6 +78,13 @@ void LinePrinter::NewLine() {
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;
@@ -79,6 +93,19 @@ bool LinePrinter::IsClassExcluded(const ClassLayout &Class) {
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 << ")";
+}
+
bool LinePrinter::IsTypeExcluded(llvm::StringRef TypeName, uint32_t Size) {
if (IsItemExcluded(TypeName, IncludeTypeFilters, ExcludeTypeFilters))
return true;
diff --git a/tools/llvm-pdbutil/LinePrinter.h b/tools/llvm-pdbutil/LinePrinter.h
index 1a922feb1e6..f4fd22bcb6f 100644
--- a/tools/llvm-pdbutil/LinePrinter.h
+++ b/tools/llvm-pdbutil/LinePrinter.h
@@ -10,10 +10,12 @@
#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/raw_ostream.h"
+#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/Regex.h"
+#include "llvm/Support/raw_ostream.h"
#include <list>
@@ -28,10 +30,22 @@ class LinePrinter {
public:
LinePrinter(int Indent, bool UseColor, raw_ostream &Stream);
- void Indent();
- void Unindent();
+ 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);
+
bool hasColor() const { return UseColor; }
raw_ostream &getStream() { return OS; }
int getIndentLevel() const { return CurrentIndent; }
@@ -63,6 +77,17 @@ private:
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;
diff --git a/tools/llvm-pdbutil/MinimalSymbolDumper.cpp b/tools/llvm-pdbutil/MinimalSymbolDumper.cpp
new file mode 100644
index 00000000000..8b36de0b715
--- /dev/null
+++ b/tools/llvm-pdbutil/MinimalSymbolDumper.cpp
@@ -0,0 +1,749 @@
+//===- 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 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) {
+ // 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} [size = {1}]", 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);
+ P.formatLine("parent = {0}, addr = {1}", Block.Parent,
+ formatSegmentOffset(Block.Segment, Block.CodeOffset));
+ P.formatLine("code size = {0}, end = {1}", Block.CodeSize, Block.End);
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, Thunk32Sym &Thunk) {
+ P.format(" `{0}`", Thunk.Name);
+ AutoIndent Indent(P);
+ P.formatLine("parent = {0}, addr = {1}", Thunk.Parent,
+ formatSegmentOffset(Thunk.Segment, Thunk.Offset));
+ P.formatLine("kind = {0}, size = {1}, end = {2}, next = {3}",
+ formatThunkOrdinal(Thunk.Thunk), Thunk.Length, Thunk.End,
+ Thunk.Next);
+
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
+ TrampolineSym &Tramp) {
+ AutoIndent Indent(P);
+ 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);
+ 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);
+ 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);
+ 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);
+ P.formatLine("type = {0}, addr = {1}", typeIndex(CSI.Type),
+ formatSegmentOffset(CSI.Segment, CSI.CodeOffset));
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
+ EnvBlockSym &EnvBlock) {
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ P.formatLine("type = {0}, addr = {1}", typeIndex(Public.Index),
+ formatSegmentOffset(Public.Segment, Public.Offset));
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, ProcRefSym &PR) {
+ P.format(" `{0}`", PR.Name);
+ AutoIndent Indent(P);
+ 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);
+ 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);
+
+ 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);
+ P.formatLine("parent = {0}, addr = {1}, code size = {2}, end = {3}",
+ Proc.Parent, formatSegmentOffset(Proc.Segment, Proc.CodeOffset),
+ Proc.CodeSize, Proc.End);
+ P.formatLine("debug start = {0}, debug end = {1}, flags = {2}", 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);
+ 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);
+ 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);
+ 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);
+ P.formatLine("original type = {0}", UDT.Type);
+ return Error::success();
+}
diff --git a/tools/llvm-pdbutil/MinimalSymbolDumper.h b/tools/llvm-pdbutil/MinimalSymbolDumper.h
new file mode 100644
index 00000000000..451f2da6fd1
--- /dev/null
+++ b/tools/llvm-pdbutil/MinimalSymbolDumper.h
@@ -0,0 +1,47 @@
+//===- 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 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/tools/llvm-pdbutil/MinimalTypeDumper.cpp b/tools/llvm-pdbutil/MinimalTypeDumper.cpp
new file mode 100644
index 00000000000..98813e03c38
--- /dev/null
+++ b/tools/llvm-pdbutil/MinimalTypeDumper.cpp
@@ -0,0 +1,532 @@
+//===- 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/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.
+ P.formatLine("{0} | {1} [size = {2}]",
+ fmt_align(Index, AlignStyle::Right, Width),
+ getLeafTypeName(Record.Type), Record.length());
+ 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.formatLine("class name: `{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.formatLine("class name: `{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.formatLine("name: `{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.ParameterCount, MF.ArgumentList, MF.ReturnType);
+ 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,
+ fmt_guid(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/tools/llvm-pdbutil/MinimalTypeDumper.h b/tools/llvm-pdbutil/MinimalTypeDumper.h
new file mode 100644
index 00000000000..47f6781e3ca
--- /dev/null
+++ b/tools/llvm-pdbutil/MinimalTypeDumper.h
@@ -0,0 +1,56 @@
+//===- 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"
+
+namespace llvm {
+namespace codeview {
+class LazyRandomTypeCollection;
+}
+
+namespace pdb {
+class LinePrinter;
+
+class MinimalTypeDumpVisitor : public codeview::TypeVisitorCallbacks {
+public:
+ MinimalTypeDumpVisitor(LinePrinter &P, uint32_t Width, bool RecordBytes,
+ codeview::LazyRandomTypeCollection &Types)
+ : P(P), Width(Width), RecordBytes(RecordBytes), Types(Types) {}
+
+ 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;
+ codeview::LazyRandomTypeCollection &Types;
+};
+} // namespace pdb
+} // namespace llvm
+
+#endif
diff --git a/tools/llvm-pdbutil/RawOutputStyle.cpp b/tools/llvm-pdbutil/RawOutputStyle.cpp
new file mode 100644
index 00000000000..e37b0b6763a
--- /dev/null
+++ b/tools/llvm-pdbutil/RawOutputStyle.cpp
@@ -0,0 +1,669 @@
+//===- RawOutputStyle.cpp ------------------------------------ *- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "RawOutputStyle.h"
+
+#include "CompactTypeDumpVisitor.h"
+#include "FormatUtil.h"
+#include "MinimalSymbolDumper.h"
+#include "MinimalTypeDumper.h"
+#include "StreamUtil.h"
+#include "llvm-pdbutil.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/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;
+
+RawOutputStyle::RawOutputStyle(PDBFile &File)
+ : File(File), P(2, false, outs()) {}
+
+Error RawOutputStyle::dump() {
+ if (opts::raw::DumpSummary) {
+ if (auto EC = dumpFileSummary())
+ return EC;
+ P.NewLine();
+ }
+
+ if (opts::raw::DumpStreams) {
+ if (auto EC = dumpStreamSummary())
+ return EC;
+ P.NewLine();
+ }
+
+ if (opts::raw::DumpBlockRange.hasValue()) {
+ if (auto EC = dumpBlockRanges())
+ return EC;
+ P.NewLine();
+ }
+
+ if (!opts::raw::DumpStreamData.empty()) {
+ if (auto EC = dumpStreamBytes())
+ return EC;
+ P.NewLine();
+ }
+
+ if (opts::raw::DumpStringTable) {
+ if (auto EC = dumpStringTable())
+ return EC;
+ P.NewLine();
+ }
+
+ if (opts::raw::DumpModules) {
+ if (auto EC = dumpModules())
+ return EC;
+ }
+
+ if (opts::raw::DumpTypes) {
+ if (auto EC = dumpTpiStream(StreamTPI))
+ return EC;
+ }
+
+ if (opts::raw::DumpIds) {
+ if (auto EC = dumpTpiStream(StreamIPI))
+ return EC;
+ }
+
+ if (opts::raw::DumpPublics) {
+ if (auto EC = dumpPublics())
+ return EC;
+ }
+
+ if (opts::raw::DumpSymbols) {
+ if (auto EC = dumpModuleSyms())
+ return EC;
+ }
+
+ if (opts::raw::DumpSectionContribs) {
+ if (auto EC = dumpSectionContribs())
+ return EC;
+ }
+
+ if (opts::raw::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 RawOutputStyle::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 RawOutputStyle::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));
+ }
+
+ return Error::success();
+}
+
+Error RawOutputStyle::dumpBlockRanges() {
+ printHeader(P, "MSF Blocks");
+
+ auto &R = *opts::raw::DumpBlockRange;
+ uint32_t Max = R.Max.getValueOr(R.Min);
+
+ AutoIndent Indent(P);
+ if (Max < R.Min)
+ return make_error<StringError>(
+ "Invalid block range specified. Max < Min",
+ std::make_error_code(std::errc::bad_address));
+ if (Max >= File.getBlockCount())
+ return make_error<StringError>(
+ "Invalid block range specified. Requested block out of bounds",
+ std::make_error_code(std::errc::bad_address));
+
+ for (uint32_t I = R.Min; I <= Max; ++I) {
+ auto ExpectedData = File.getBlockData(I, File.getBlockSize());
+ if (!ExpectedData)
+ return ExpectedData.takeError();
+ std::string Label = formatv("Block {0}", I).str();
+ P.formatBinary(Label, *ExpectedData, 0);
+ }
+
+ return Error::success();
+}
+
+static Error parseStreamSpec(StringRef Str, uint32_t &SI, uint32_t &Offset,
+ uint32_t &Size) {
+ if (Str.consumeInteger(0, SI))
+ return make_error<RawError>(raw_error_code::invalid_format,
+ "Invalid Stream Specification");
+ if (Str.consume_front(":")) {
+ if (Str.consumeInteger(0, Offset))
+ return make_error<RawError>(raw_error_code::invalid_format,
+ "Invalid Stream Specification");
+ }
+ if (Str.consume_front("@")) {
+ if (Str.consumeInteger(0, 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 Error::success();
+}
+
+Error RawOutputStyle::dumpStreamBytes() {
+ if (StreamPurposes.empty())
+ discoverStreamPurposes(File, StreamPurposes);
+
+ printHeader(P, "Stream Data");
+ ExitOnError Err("Unexpected error reading stream data");
+
+ for (auto &Str : opts::raw::DumpStreamData) {
+ uint32_t SI = 0;
+ uint32_t Begin = 0;
+ uint32_t Size = 0;
+ uint32_t End = 0;
+
+ if (auto EC = parseStreamSpec(Str, SI, Begin, Size))
+ return EC;
+
+ AutoIndent Indent(P);
+ if (SI >= File.getNumStreams()) {
+ P.formatLine("Stream {0}: Not present", SI);
+ continue;
+ }
+
+ auto S = MappedBlockStream::createIndexedStream(
+ File.getMsfLayout(), File.getMsfBuffer(), SI, File.getAllocator());
+ if (!S) {
+ P.NewLine();
+ P.formatLine("Stream {0}: Not present", SI);
+ continue;
+ }
+
+ if (Size == 0)
+ End = S->getLength();
+ else
+ End = std::min(Begin + Size, S->getLength());
+
+ P.formatLine("Stream {0} ({1:N} bytes): {2}", SI, S->getLength(),
+ StreamPurposes[SI]);
+ AutoIndent Indent2(P);
+
+ BinaryStreamReader R(*S);
+ ArrayRef<uint8_t> StreamData;
+ Err(R.readBytes(StreamData, S->getLength()));
+ Size = End - Begin;
+ StreamData = StreamData.slice(Begin, Size);
+ P.formatBinary("Data", StreamData, Begin);
+ }
+ return Error::success();
+}
+
+Error RawOutputStyle::dumpModules() {
+ printHeader(P, "Modules");
+
+ 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());
+
+ 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());
+ if (opts::raw::DumpModuleFiles) {
+ P.formatLine(" contributing source files:");
+ for (const auto &F : Modules.source_files(I)) {
+ P.formatLine(" - {0}", F);
+ }
+ }
+ }
+ return Error::success();
+}
+Error RawOutputStyle::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();
+}
+
+Error RawOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
+ assert(StreamIdx == StreamTPI || StreamIdx == StreamIPI);
+
+ bool Present = false;
+ bool DumpBytes = false;
+ if (StreamIdx == StreamTPI) {
+ printHeader(P, "Types (TPI Stream)");
+ Present = File.hasPDBTpiStream();
+ DumpBytes = opts::raw::DumpTypeData;
+ } else if (StreamIdx == StreamIPI) {
+ printHeader(P, "Types (IPI Stream)");
+ Present = File.hasPDBIpiStream();
+ DumpBytes = opts::raw::DumpIdData;
+ }
+
+ 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(initializeTypeDatabase(StreamIdx));
+
+ P.formatLine("Showing {0:N} records", Stream.getNumTypeRecords());
+ uint32_t Width =
+ NumDigits(TypeIndex::FirstNonSimpleIndex + Stream.getNumTypeRecords());
+
+ MinimalTypeDumpVisitor V(P, Width + 2, DumpBytes, Types);
+
+ Optional<TypeIndex> I = Types.getFirst();
+ if (auto EC = codeview::visitTypeStream(Types, V)) {
+ P.formatLine("An error occurred dumping type records: {0}",
+ toString(std::move(EC)));
+ }
+ return Error::success();
+}
+
+Expected<codeview::LazyRandomTypeCollection &>
+RawOutputStyle::initializeTypeDatabase(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 RawOutputStyle::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(initializeTypeDatabase(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::raw::DumpSymRecordBytes, Types);
+
+ Pipeline.addCallbackToPipeline(Deserializer);
+ Pipeline.addCallbackToPipeline(Dumper);
+ CVSymbolVisitor Visitor(Pipeline);
+ if (auto EC = Visitor.visitSymbolStream(ModS.getSymbolArray())) {
+ P.formatLine("Error while processing symbol records. {0}",
+ toString(std::move(EC)));
+ continue;
+ }
+ }
+ return Error::success();
+}
+
+Error RawOutputStyle::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(initializeTypeDatabase(StreamTPI));
+ auto &Publics = Err(File.getPDBPublicsStream());
+ SymbolVisitorCallbackPipeline Pipeline;
+ SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb);
+ MinimalSymbolDumper Dumper(P, opts::raw::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))
+ 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, 3, IndentLevel, " | ");
+}
+
+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, 4, IndentLevel, " | ");
+}
+
+Error RawOutputStyle::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 RawOutputStyle::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/tools/llvm-pdbutil/LLVMOutputStyle.h b/tools/llvm-pdbutil/RawOutputStyle.h
index 184dc4e1f44..4c381c2a80b 100644
--- a/tools/llvm-pdbutil/LLVMOutputStyle.h
+++ b/tools/llvm-pdbutil/RawOutputStyle.h
@@ -1,4 +1,4 @@
-//===- LLVMOutputStyle.h -------------------------------------- *- C++ --*-===//
+//===- RawOutputStyle.h -------------------------------------- *- C++ --*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,15 +7,15 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_TOOLS_LLVMPDBDUMP_LLVMOUTPUTSTYLE_H
-#define LLVM_TOOLS_LLVMPDBDUMP_LLVMOUTPUTSTYLE_H
+#ifndef LLVM_TOOLS_LLVMPDBDUMP_RAWOUTPUTSTYLE_H
+#define LLVM_TOOLS_LLVMPDBDUMP_RAWOUTPUTSTYLE_H
+#include "LinePrinter.h"
#include "OutputStyle.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
-#include "llvm/Support/ScopedPrinter.h"
#include <string>
@@ -27,9 +27,9 @@ class LazyRandomTypeCollection;
}
namespace pdb {
-class LLVMOutputStyle : public OutputStyle {
+class RawOutputStyle : public OutputStyle {
public:
- LLVMOutputStyle(PDBFile &File);
+ RawOutputStyle(PDBFile &File);
Error dump() override;
@@ -37,34 +37,25 @@ private:
Expected<codeview::LazyRandomTypeCollection &>
initializeTypeDatabase(uint32_t SN);
- Error dumpFileHeaders();
+ Error dumpFileSummary();
Error dumpStreamSummary();
- Error dumpFreePageMap();
Error dumpBlockRanges();
- Error dumpGlobalsStream();
Error dumpStreamBytes();
- Error dumpStreamBlocks();
Error dumpStringTable();
- Error dumpInfoStream();
Error dumpTpiStream(uint32_t StreamIdx);
- Error dumpDbiStream();
+ Error dumpModules();
+ Error dumpModuleSyms();
+ Error dumpPublics();
Error dumpSectionContribs();
Error dumpSectionMap();
- Error dumpPublicsStream();
- Error dumpSectionHeaders();
- Error dumpFpoStream();
-
- void dumpBitVector(StringRef Name, const BitVector &V);
-
- void flush();
PDBFile &File;
- ScopedPrinter P;
+ 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/tools/llvm-pdbutil/YAMLOutputStyle.cpp b/tools/llvm-pdbutil/YAMLOutputStyle.cpp
index 8f7aba6d30c..ae3138efb13 100644
--- a/tools/llvm-pdbutil/YAMLOutputStyle.cpp
+++ b/tools/llvm-pdbutil/YAMLOutputStyle.cpp
@@ -32,6 +32,13 @@ 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);
@@ -93,8 +100,8 @@ Error YAMLOutputStyle::dumpFileHeaders() {
}
Error YAMLOutputStyle::dumpStringTable() {
- bool RequiresStringTable = opts::shared::DumpModuleFiles ||
- !opts::shared::DumpModuleSubsections.empty();
+ bool RequiresStringTable = opts::pdb2yaml::DumpModuleFiles ||
+ !opts::pdb2yaml::DumpModuleSubsections.empty();
bool RequestedStringTable = opts::pdb2yaml::StringTable;
if (!RequiresStringTable && !RequestedStringTable)
return Error::success();
@@ -201,7 +208,7 @@ Error YAMLOutputStyle::dumpDbiStream() {
Obj.DbiStream->PdbDllRbld = DS.getPdbDllRbld();
Obj.DbiStream->PdbDllVersion = DS.getPdbDllVersion();
Obj.DbiStream->VerHeader = DS.getDbiVersion();
- if (opts::shared::DumpModules) {
+ if (opts::pdb2yaml::DumpModules) {
const auto &Modules = DS.modules();
for (uint32_t I = 0; I < Modules.getModuleCount(); ++I) {
DbiModuleDescriptor MI = Modules.getModuleDescriptor(I);
@@ -211,7 +218,7 @@ Error YAMLOutputStyle::dumpDbiStream() {
DMI.Mod = MI.getModuleName();
DMI.Obj = MI.getObjFileName();
- if (opts::shared::DumpModuleFiles) {
+ if (opts::pdb2yaml::DumpModuleFiles) {
auto Files = Modules.source_files(I);
DMI.SourceFiles.assign(Files.begin(), Files.end());
}
@@ -231,7 +238,7 @@ Error YAMLOutputStyle::dumpDbiStream() {
auto ExpectedST = File.getStringTable();
if (!ExpectedST)
return ExpectedST.takeError();
- if (!opts::shared::DumpModuleSubsections.empty() &&
+ if (!opts::pdb2yaml::DumpModuleSubsections.empty() &&
ModS.hasDebugSubsections()) {
auto ExpectedChecksums = ModS.findChecksumsSubsection();
if (!ExpectedChecksums)
@@ -242,7 +249,7 @@ Error YAMLOutputStyle::dumpDbiStream() {
for (const auto &SS : ModS.subsections()) {
opts::ModuleSubsection OptionKind = convertSubsectionKind(SS.kind());
- if (!opts::checkModuleSubsection(OptionKind))
+ if (!checkModuleSubsection(OptionKind))
continue;
auto Converted =
@@ -253,7 +260,7 @@ Error YAMLOutputStyle::dumpDbiStream() {
}
}
- if (opts::shared::DumpModuleSyms) {
+ if (opts::pdb2yaml::DumpModuleSyms) {
DMI.Modi.emplace();
DMI.Modi->Signature = ModS.signature();
diff --git a/tools/llvm-pdbutil/llvm-pdbutil.cpp b/tools/llvm-pdbutil/llvm-pdbutil.cpp
index 3826ba79a20..18fda036ee7 100644
--- a/tools/llvm-pdbutil/llvm-pdbutil.cpp
+++ b/tools/llvm-pdbutil/llvm-pdbutil.cpp
@@ -15,7 +15,6 @@
#include "Analyze.h"
#include "Diff.h"
-#include "LLVMOutputStyle.h"
#include "LinePrinter.h"
#include "OutputStyle.h"
#include "PrettyCompilandDumper.h"
@@ -23,6 +22,7 @@
#include "PrettyFunctionDumper.h"
#include "PrettyTypeDumper.h"
#include "PrettyVariableDumper.h"
+#include "RawOutputStyle.h"
#include "YAMLOutputStyle.h"
#include "llvm/ADT/ArrayRef.h"
@@ -266,6 +266,8 @@ cl::list<std::string> InputFilenames(cl::Positional,
cl::OneOrMore, cl::sub(DiffSubcommand));
}
+cl::OptionCategory FileOptions("Module & File Options");
+
namespace raw {
cl::OptionCategory MsfOptions("MSF Container Options");
@@ -274,18 +276,11 @@ cl::OptionCategory SymbolOptions("Symbol Options");
cl::OptionCategory MiscOptions("Miscellaneous Options");
// MSF OPTIONS
-cl::opt<bool> DumpHeaders("headers", cl::desc("dump PDB headers"),
+cl::opt<bool> DumpSummary("summary", cl::desc("dump file summary"),
+ cl::cat(MsfOptions), cl::sub(RawSubcommand));
+cl::opt<bool> DumpStreams("streams",
+ cl::desc("dump summary of the PDB streams"),
cl::cat(MsfOptions), cl::sub(RawSubcommand));
-cl::opt<bool> DumpStreamBlocks("stream-blocks",
- cl::desc("dump PDB stream blocks"),
- cl::cat(MsfOptions), cl::sub(RawSubcommand));
-cl::opt<bool> DumpStreamSummary("stream-summary",
- cl::desc("dump summary of the PDB streams"),
- cl::cat(MsfOptions), cl::sub(RawSubcommand));
-cl::opt<bool> DumpPageStats(
- "page-stats",
- cl::desc("dump allocation stats of the pages in the MSF file"),
- cl::cat(MsfOptions), cl::sub(RawSubcommand));
cl::opt<std::string>
DumpBlockRangeOpt("block-data", cl::value_desc("start[-end]"),
cl::desc("Dump binary data from specified range."),
@@ -299,40 +294,45 @@ cl::list<std::string>
cl::cat(MsfOptions), cl::sub(RawSubcommand));
// TYPE OPTIONS
-cl::opt<bool>
- CompactRecords("compact-records",
- cl::desc("Dump type and symbol records with less detail"),
- cl::cat(TypeOptions), cl::sub(RawSubcommand));
-
-cl::opt<bool>
- DumpTpiRecords("tpi-records",
- cl::desc("dump CodeView type records from TPI stream"),
- cl::cat(TypeOptions), cl::sub(RawSubcommand));
-cl::opt<bool> DumpTpiRecordBytes(
- "tpi-record-bytes",
+cl::opt<bool> DumpTypes("types",
+ cl::desc("dump CodeView type records from TPI stream"),
+ cl::cat(TypeOptions), cl::sub(RawSubcommand));
+cl::opt<bool> DumpTypeData(
+ "type-data",
cl::desc("dump CodeView type record raw bytes from TPI stream"),
cl::cat(TypeOptions), cl::sub(RawSubcommand));
-cl::opt<bool> DumpTpiHash("tpi-hash", cl::desc("dump CodeView TPI hash stream"),
- cl::cat(TypeOptions), cl::sub(RawSubcommand));
+
+cl::opt<bool> DumpTypeHashes("type-hash",
+ cl::desc("dump CodeView TPI hash stream"),
+ cl::cat(TypeOptions), cl::sub(RawSubcommand));
+
+cl::opt<bool> DumpIds("ids",
+ cl::desc("dump CodeView type records from IPI stream"),
+ cl::cat(TypeOptions), cl::sub(RawSubcommand));
cl::opt<bool>
- DumpIpiRecords("ipi-records",
- cl::desc("dump CodeView type records from IPI stream"),
- cl::cat(TypeOptions), cl::sub(RawSubcommand));
-cl::opt<bool> DumpIpiRecordBytes(
- "ipi-record-bytes",
- cl::desc("dump CodeView type record raw bytes from IPI stream"),
- cl::cat(TypeOptions), cl::sub(RawSubcommand));
+ DumpIdData("id-data",
+ cl::desc("dump CodeView type record raw bytes from IPI stream"),
+ cl::cat(TypeOptions), cl::sub(RawSubcommand));
// SYMBOL OPTIONS
-cl::opt<bool> DumpGlobals("globals", cl::desc("dump globals stream data"),
- cl::cat(SymbolOptions), cl::sub(RawSubcommand));
cl::opt<bool> DumpPublics("publics", cl::desc("dump Publics stream data"),
cl::cat(SymbolOptions), cl::sub(RawSubcommand));
+cl::opt<bool> DumpSymbols("symbols", cl::desc("dump module symbols"),
+ cl::cat(SymbolOptions), cl::sub(RawSubcommand));
+
cl::opt<bool>
- DumpSymRecordBytes("sym-record-bytes",
+ DumpSymRecordBytes("sym-data",
cl::desc("dump CodeView symbol record raw bytes"),
cl::cat(SymbolOptions), cl::sub(RawSubcommand));
+// MODULE & FILE OPTIONS
+cl::opt<bool> DumpModules("modules", cl::desc("dump compiland information"),
+ cl::cat(FileOptions), cl::sub(RawSubcommand));
+cl::opt<bool> DumpModuleFiles(
+ "files",
+ cl::desc("for each module dumped, dump the contributing source files"),
+ cl::cat(FileOptions), cl::sub(RawSubcommand));
+
// MISCELLANEOUS OPTIONS
cl::opt<bool> DumpStringTable("string-table", cl::desc("dump PDB String Table"),
cl::cat(MiscOptions), cl::sub(RawSubcommand));
@@ -342,11 +342,6 @@ cl::opt<bool> DumpSectionContribs("section-contribs",
cl::cat(MiscOptions), cl::sub(RawSubcommand));
cl::opt<bool> DumpSectionMap("section-map", cl::desc("dump section map"),
cl::cat(MiscOptions), cl::sub(RawSubcommand));
-cl::opt<bool> DumpSectionHeaders("section-headers",
- cl::desc("dump section headers"),
- cl::cat(MiscOptions), cl::sub(RawSubcommand));
-cl::opt<bool> DumpFpo("fpo", cl::desc("dump FPO records"), cl::cat(MiscOptions),
- cl::sub(RawSubcommand));
cl::opt<bool> RawAll("all", cl::desc("Implies most other options."),
cl::cat(MiscOptions), cl::sub(RawSubcommand));
@@ -404,20 +399,11 @@ cl::opt<bool> IpiStream("ipi-stream",
cl::desc("Dump the IPI Stream (Stream 5)"),
cl::sub(PdbToYamlSubcommand), cl::init(false));
-cl::list<std::string> InputFilename(cl::Positional,
- cl::desc("<input PDB file>"), cl::Required,
- cl::sub(PdbToYamlSubcommand));
-}
-
-namespace shared {
-cl::OptionCategory FileOptions("Module & File Options");
-
// MODULE & FILE OPTIONS
cl::opt<bool> DumpModules("modules", cl::desc("dump compiland information"),
- cl::cat(FileOptions), cl::sub(RawSubcommand),
- cl::sub(PdbToYamlSubcommand));
+ cl::cat(FileOptions), cl::sub(PdbToYamlSubcommand));
cl::opt<bool> DumpModuleFiles("module-files", cl::desc("dump file information"),
- cl::cat(FileOptions), cl::sub(RawSubcommand),
+ cl::cat(FileOptions),
cl::sub(PdbToYamlSubcommand));
cl::list<ModuleSubsection> DumpModuleSubsections(
"subsections", cl::ZeroOrMore, cl::CommaSeparated,
@@ -448,11 +434,15 @@ cl::list<ModuleSubsection> DumpModuleSubsections(
clEnumValN(ModuleSubsection::Unknown, "unknown",
"Any subsection not covered by another option"),
clEnumValN(ModuleSubsection::All, "all", "All known subsections")),
- cl::cat(FileOptions), cl::sub(RawSubcommand), cl::sub(PdbToYamlSubcommand));
+ cl::cat(FileOptions), cl::sub(PdbToYamlSubcommand));
cl::opt<bool> DumpModuleSyms("module-syms", cl::desc("dump module symbols"),
- cl::cat(FileOptions), cl::sub(RawSubcommand),
+ cl::cat(FileOptions),
cl::sub(PdbToYamlSubcommand));
-} // namespace shared
+
+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"),
@@ -474,13 +464,6 @@ cl::opt<std::string>
static ExitOnError ExitOnErr;
-bool opts::checkModuleSubsection(opts::ModuleSubsection MS) {
- return any_of(opts::shared::DumpModuleSubsections,
- [=](opts::ModuleSubsection M) {
- return M == MS || M == opts::ModuleSubsection::All;
- });
-}
-
static void yamlToPdb(StringRef Path) {
BumpPtrAllocator Allocator;
ErrorOr<std::unique_ptr<MemoryBuffer>> ErrorOrBuffer =
@@ -611,7 +594,7 @@ static void dumpRaw(StringRef Path) {
std::unique_ptr<IPDBSession> Session;
auto &File = loadPDB(Path, Session);
- auto O = llvm::make_unique<LLVMOutputStyle>(File);
+ auto O = llvm::make_unique<RawOutputStyle>(File);
ExitOnErr(O->dump());
}
@@ -904,49 +887,21 @@ int main(int argc_, const char *argv_[]) {
}
}
- if ((opts::RawSubcommand && opts::raw::RawAll) ||
- (opts::PdbToYamlSubcommand && opts::pdb2yaml::All)) {
- opts::shared::DumpModules = true;
- opts::shared::DumpModuleFiles = true;
- opts::shared::DumpModuleSyms = true;
- opts::shared::DumpModuleSubsections.push_back(opts::ModuleSubsection::All);
- if (llvm::is_contained(opts::shared::DumpModuleSubsections,
- opts::ModuleSubsection::All)) {
- opts::shared::DumpModuleSubsections.reset();
- opts::shared::DumpModuleSubsections.push_back(
- opts::ModuleSubsection::All);
- }
- }
-
- if (opts::shared::DumpModuleSyms || opts::shared::DumpModuleFiles)
- opts::shared::DumpModules = true;
-
- if (opts::shared::DumpModules)
- opts::pdb2yaml::DbiStream = true;
-
if (opts::RawSubcommand) {
if (opts::raw::RawAll) {
- opts::raw::DumpHeaders = true;
- opts::raw::DumpGlobals = true;
+ opts::raw::DumpIds = true;
opts::raw::DumpPublics = true;
- opts::raw::DumpSectionHeaders = true;
- opts::raw::DumpStreamSummary = true;
- opts::raw::DumpPageStats = true;
- opts::raw::DumpStreamBlocks = true;
- opts::raw::DumpTpiRecords = true;
- opts::raw::DumpTpiHash = true;
- opts::raw::DumpIpiRecords = true;
- opts::raw::DumpSectionMap = true;
opts::raw::DumpSectionContribs = true;
- opts::raw::DumpFpo = true;
+ opts::raw::DumpSectionMap = true;
+ opts::raw::DumpStreams = true;
opts::raw::DumpStringTable = true;
- }
-
- if (opts::raw::CompactRecords &&
- (opts::raw::DumpTpiRecordBytes || opts::raw::DumpIpiRecordBytes)) {
- errs() << "-compact-records is incompatible with -tpi-record-bytes and "
- "-ipi-record-bytes.\n";
- exit(1);
+ opts::raw::DumpSummary = true;
+ opts::raw::DumpSymbols = true;
+ opts::raw::DumpIds = true;
+ opts::raw::DumpTypes = true;
+ opts::raw::DumpTypeHashes = true;
+ opts::raw::DumpModules = true;
+ opts::raw::DumpModuleFiles = true;
}
}
if (opts::PdbToYamlSubcommand) {
@@ -958,7 +913,24 @@ int main(int argc_, const char *argv_[]) {
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);
+ if (llvm::is_contained(opts::pdb2yaml::DumpModuleSubsections,
+ opts::ModuleSubsection::All)) {
+ opts::pdb2yaml::DumpModuleSubsections.reset();
+ opts::pdb2yaml::DumpModuleSubsections.push_back(
+ opts::ModuleSubsection::All);
+ }
}
+
+ if (opts::pdb2yaml::DumpModuleSyms || opts::pdb2yaml::DumpModuleFiles)
+ opts::pdb2yaml::DumpModules = true;
+
+ if (opts::pdb2yaml::DumpModules)
+ opts::pdb2yaml::DbiStream = true;
}
llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::MultiThreaded);
diff --git a/tools/llvm-pdbutil/llvm-pdbutil.h b/tools/llvm-pdbutil/llvm-pdbutil.h
index f1699d0bb55..37c4ca3ee5d 100644
--- a/tools/llvm-pdbutil/llvm-pdbutil.h
+++ b/tools/llvm-pdbutil/llvm-pdbutil.h
@@ -27,6 +27,8 @@ uint32_t getTypeLength(const PDBSymbolData &Symbol);
namespace opts {
+enum class DumpLevel { None, Basic, Verbose };
+
enum class ModuleSubsection {
Unknown,
Lines,
@@ -41,15 +43,6 @@ enum class ModuleSubsection {
All
};
-bool checkModuleSubsection(ModuleSubsection Kind);
-
-template <typename... Ts>
-bool checkModuleSubsection(ModuleSubsection K1, ModuleSubsection K2,
- Ts &&... Rest) {
- return checkModuleSubsection(K1) ||
- checkModuleSubsection(K2, std::forward<Ts>(Rest)...);
-}
-
namespace pretty {
enum class ClassDefinitionFormat { None, Layout, All };
@@ -105,27 +98,24 @@ struct BlockRange {
llvm::Optional<uint32_t> Max;
};
+extern llvm::cl::opt<bool> DumpSummary;
+extern llvm::cl::opt<bool> DumpStreams;
extern llvm::Optional<BlockRange> DumpBlockRange;
extern llvm::cl::list<std::string> DumpStreamData;
-
-extern llvm::cl::opt<bool> CompactRecords;
-extern llvm::cl::opt<bool> DumpGlobals;
-extern llvm::cl::opt<bool> DumpHeaders;
-extern llvm::cl::opt<bool> DumpStreamBlocks;
-extern llvm::cl::opt<bool> DumpStreamSummary;
-extern llvm::cl::opt<bool> DumpPageStats;
-extern llvm::cl::opt<bool> DumpTpiHash;
-extern llvm::cl::opt<bool> DumpTpiRecordBytes;
-extern llvm::cl::opt<bool> DumpTpiRecords;
-extern llvm::cl::opt<bool> DumpIpiRecords;
-extern llvm::cl::opt<bool> DumpIpiRecordBytes;
+extern llvm::cl::opt<bool> DumpStringTable;
+extern llvm::cl::opt<bool> DumpTypes;
+extern llvm::cl::opt<bool> DumpTypeData;
+extern llvm::cl::opt<bool> DumpTypeHashes;
+extern llvm::cl::opt<bool> DumpIds;
+extern llvm::cl::opt<bool> DumpIdData;
+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> DumpSymRecordBytes;
-extern llvm::cl::opt<bool> DumpSectionHeaders;
-extern llvm::cl::opt<bool> DumpFpo;
-extern llvm::cl::opt<bool> DumpStringTable;
+extern llvm::cl::opt<bool> DumpModules;
+extern llvm::cl::opt<bool> DumpModuleFiles;
+extern llvm::cl::opt<bool> RawAll;
}
namespace diff {
@@ -144,14 +134,11 @@ 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;
-}
-
-namespace shared {
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 shared
+} // namespace pdb2yaml
}
#endif