diff options
| author | Zachary Turner <zturner@google.com> | 2017-06-15 19:34:41 +0000 |
|---|---|---|
| committer | Zachary Turner <zturner@google.com> | 2017-06-15 19:34:41 +0000 |
| commit | b560fdf3b84e18e3fb19d12cb2bd610dc2316118 (patch) | |
| tree | 2101ce83d45cf3ffdc394dd3b3925ee12ea05dc7 /llvm/tools | |
| parent | 0f9c84cd936b6532495673613d9390efdc85cb3c (diff) | |
| download | bcm5719-llvm-b560fdf3b84e18e3fb19d12cb2bd610dc2316118.tar.gz bcm5719-llvm-b560fdf3b84e18e3fb19d12cb2bd610dc2316118.zip | |
[llvm-pdbutil] rewrite the "raw" output style.
After some internal discussions, we agreed that the raw output style had
outlived its usefulness. It was originally created before we had even
thought of dumping to YAML, and it was intended to give us some insight
into the internals of a PDB file. Now we have YAML mode which does
almost exactly this but is more powerful in that it can round-trip back
to a PDB, which the raw mode could not do. So the raw mode had become
purely a maintenance burden.
One option was to just delete it. However, its original goal was to be
as readable as possible while staying close to the "metal" - i.e.
presenting the output in a way that maps directly to the underlying file
format. We don't actually need that last requirement anymore since it's
covered by the yaml mode, so we could repurpose "raw" mode to actually
just be as readable as possible.
This patch implements about 80% of the functionality previously in raw
mode, but in a completely different style that is more akin to what
cvdump outputs. Records are very compressed, often times appearing on
just one line. One nice thing about this is that it makes full record
matching easier, because you can grep for indices, names, and leaf types
on a single line often.
See the tests for some examples of what the new output looks like.
Note that this patch actually regresses the functionality of raw mode in
a few areas, but only because the patch was already unreasonably large
and going 100% would have been even worse. Specifically, this patch is
missing:
The ability to dump module debug subsections (checksums, lines, etc)
The ability to dump section headers
Aside from that everything is here. While goign through the tests fixing
them all up, I found many duplicate tests. They've been deleted. In
subsequent patches I will go through and re-add the missing
functionality.
Differential Revision: https://reviews.llvm.org/D34191
llvm-svn: 305495
Diffstat (limited to 'llvm/tools')
| -rw-r--r-- | llvm/tools/llvm-pdbutil/CMakeLists.txt | 5 | ||||
| -rw-r--r-- | llvm/tools/llvm-pdbutil/FormatUtil.cpp | 49 | ||||
| -rw-r--r-- | llvm/tools/llvm-pdbutil/FormatUtil.h | 92 | ||||
| -rw-r--r-- | llvm/tools/llvm-pdbutil/LLVMOutputStyle.cpp | 1198 | ||||
| -rw-r--r-- | llvm/tools/llvm-pdbutil/LinePrinter.cpp | 33 | ||||
| -rw-r--r-- | llvm/tools/llvm-pdbutil/LinePrinter.h | 31 | ||||
| -rw-r--r-- | llvm/tools/llvm-pdbutil/MinimalSymbolDumper.cpp | 753 | ||||
| -rw-r--r-- | llvm/tools/llvm-pdbutil/MinimalSymbolDumper.h | 49 | ||||
| -rw-r--r-- | llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp | 535 | ||||
| -rw-r--r-- | llvm/tools/llvm-pdbutil/MinimalTypeDumper.h | 56 | ||||
| -rw-r--r-- | llvm/tools/llvm-pdbutil/RawOutputStyle.cpp | 669 | ||||
| -rw-r--r-- | llvm/tools/llvm-pdbutil/RawOutputStyle.h (renamed from llvm/tools/llvm-pdbutil/LLVMOutputStyle.h) | 35 | ||||
| -rw-r--r-- | llvm/tools/llvm-pdbutil/YAMLOutputStyle.cpp | 21 | ||||
| -rw-r--r-- | llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp | 172 | ||||
| -rw-r--r-- | llvm/tools/llvm-pdbutil/llvm-pdbutil.h | 45 |
15 files changed, 2380 insertions, 1363 deletions
diff --git a/llvm/tools/llvm-pdbutil/CMakeLists.txt b/llvm/tools/llvm-pdbutil/CMakeLists.txt index 9875dfb5a25..d09fa31d8b6 100644 --- a/llvm/tools/llvm-pdbutil/CMakeLists.txt +++ b/llvm/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/llvm/tools/llvm-pdbutil/FormatUtil.cpp b/llvm/tools/llvm-pdbutil/FormatUtil.cpp new file mode 100644 index 00000000000..007db9ee9f9 --- /dev/null +++ b/llvm/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/llvm/tools/llvm-pdbutil/FormatUtil.h b/llvm/tools/llvm-pdbutil/FormatUtil.h new file mode 100644 index 00000000000..5c9807e33b5 --- /dev/null +++ b/llvm/tools/llvm-pdbutil/FormatUtil.h @@ -0,0 +1,92 @@ +//===- 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/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<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 llvm +#endif diff --git a/llvm/tools/llvm-pdbutil/LLVMOutputStyle.cpp b/llvm/tools/llvm-pdbutil/LLVMOutputStyle.cpp deleted file mode 100644 index c4af4583a10..00000000000 --- a/llvm/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/llvm/tools/llvm-pdbutil/LinePrinter.cpp b/llvm/tools/llvm-pdbutil/LinePrinter.cpp index ef56b5fe8e6..718d3394e21 100644 --- a/llvm/tools/llvm-pdbutil/LinePrinter.cpp +++ b/llvm/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/llvm/tools/llvm-pdbutil/LinePrinter.h b/llvm/tools/llvm-pdbutil/LinePrinter.h index 1a922feb1e6..f4fd22bcb6f 100644 --- a/llvm/tools/llvm-pdbutil/LinePrinter.h +++ b/llvm/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/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.cpp b/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.cpp new file mode 100644 index 00000000000..013f89bf2d6 --- /dev/null +++ b/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.cpp @@ -0,0 +1,753 @@ +//===- 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"); + default: + return formatUnknownEnum(Ordinal); + } +} + +static std::string formatTrampolineType(TrampolineType Tramp) { + switch (Tramp) { + RETURN_CASE(TrampolineType, TrampIncremental, "tramp incremental"); + RETURN_CASE(TrampolineType, BranchIsland, "branch island"); + default: + 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, 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"); + default: + 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"); + default: + 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"); + default: + 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/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.h b/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.h new file mode 100644 index 00000000000..d1851119d33 --- /dev/null +++ b/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.h @@ -0,0 +1,49 @@ +//===- 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), RecordBytes(RecordBytes), Types(Types) {} + + virtual Error visitSymbolBegin(codeview::CVSymbol &Record); + virtual Error visitSymbolEnd(codeview::CVSymbol &Record); + +#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; + + uint32_t Width; + LinePrinter &P; + bool RecordBytes = false; + codeview::LazyRandomTypeCollection &Types; +}; +} // namespace pdb +} // namespace llvm + +#endif
\ No newline at end of file diff --git a/llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp b/llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp new file mode 100644 index 00000000000..185dd40e7a9 --- /dev/null +++ b/llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp @@ -0,0 +1,535 @@ +//===- 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, NearVector, "vectorcall"); + RETURN_CASE(CallingConvention, PpcCall, "ppccall"); + RETURN_CASE(CallingConvention, SH5Call, "sh5call"); + RETURN_CASE(CallingConvention, ThisCall, "thiscall"); + RETURN_CASE(CallingConvention, TriCall, "tricall"); + default: + return formatUnknownEnum(Convention); + } + return ""; +} + +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"); + default: + return formatUnknownEnum(Mode); + } +} + +static std::string memberAccess(MemberAccess Access) { + switch (Access) { + RETURN_CASE(MemberAccess, Private, "private"); + RETURN_CASE(MemberAccess, Protected, "protected"); + RETURN_CASE(MemberAccess, Public, "public"); + default: + 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"); + default: + 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"); + default: + 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/llvm/tools/llvm-pdbutil/MinimalTypeDumper.h b/llvm/tools/llvm-pdbutil/MinimalTypeDumper.h new file mode 100644 index 00000000000..f494aaf61ea --- /dev/null +++ b/llvm/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; + + uint32_t Width; + LinePrinter &P; + bool RecordBytes = false; + codeview::LazyRandomTypeCollection &Types; +}; +} // namespace pdb +} // namespace llvm + +#endif diff --git a/llvm/tools/llvm-pdbutil/RawOutputStyle.cpp b/llvm/tools/llvm-pdbutil/RawOutputStyle.cpp new file mode 100644 index 00000000000..aba34c1dba6 --- /dev/null +++ b/llvm/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, DbiStream &DS) : P(P), DS(DS) {} + 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), SC.Size, SC.Imod, SC.DataCrc, + 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), + SC.Base.Size, SC.Base.Imod, SC.Base.DataCrc, + SC.Base.RelocCrc, SC.ISectCoff); + P.formatLine(" {0}", + formatSectionCharacteristics(P.getIndentLevel() + 6, + SC.Base.Characteristics)); + } + + private: + LinePrinter &P; + DbiStream &DS; + }; + + Visitor V(P, Dbi); + 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, + M.Ovl, M.Group, M.Frame, M.SecName); + P.formatLine(" class = {0}, offset = {1}, size = {2}", + M.ClassName, M.Offset, M.SecByteLength); + P.formatLine(" flags = {0}", + formatSegMapDescriptorFlag( + P.getIndentLevel() + 13, + static_cast<OMFSegDescFlags>(uint16_t(M.Flags)))); + ++I; + } + return Error::success(); +} diff --git a/llvm/tools/llvm-pdbutil/LLVMOutputStyle.h b/llvm/tools/llvm-pdbutil/RawOutputStyle.h index 184dc4e1f44..4c381c2a80b 100644 --- a/llvm/tools/llvm-pdbutil/LLVMOutputStyle.h +++ b/llvm/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/llvm/tools/llvm-pdbutil/YAMLOutputStyle.cpp b/llvm/tools/llvm-pdbutil/YAMLOutputStyle.cpp index 8f7aba6d30c..ae3138efb13 100644 --- a/llvm/tools/llvm-pdbutil/YAMLOutputStyle.cpp +++ b/llvm/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/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp b/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp index 3826ba79a20..18fda036ee7 100644 --- a/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp +++ b/llvm/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/llvm/tools/llvm-pdbutil/llvm-pdbutil.h b/llvm/tools/llvm-pdbutil/llvm-pdbutil.h index f1699d0bb55..37c4ca3ee5d 100644 --- a/llvm/tools/llvm-pdbutil/llvm-pdbutil.h +++ b/llvm/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 |

