diff options
author | monster <monster@ydb.tech> | 2022-07-07 14:41:37 +0300 |
---|---|---|
committer | monster <monster@ydb.tech> | 2022-07-07 14:41:37 +0300 |
commit | 06e5c21a835c0e923506c4ff27929f34e00761c2 (patch) | |
tree | 75efcbc6854ef9bd476eb8bf00cc5c900da436a2 /contrib/libs/llvm12/tools/llvm-pdbutil | |
parent | 03f024c4412e3aa613bb543cf1660176320ba8f4 (diff) | |
download | ydb-06e5c21a835c0e923506c4ff27929f34e00761c2.tar.gz |
fix ya.make
Diffstat (limited to 'contrib/libs/llvm12/tools/llvm-pdbutil')
47 files changed, 11551 insertions, 0 deletions
diff --git a/contrib/libs/llvm12/tools/llvm-pdbutil/BytesOutputStyle.cpp b/contrib/libs/llvm12/tools/llvm-pdbutil/BytesOutputStyle.cpp new file mode 100644 index 0000000000..ffc907e09f --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-pdbutil/BytesOutputStyle.cpp @@ -0,0 +1,491 @@ +//===- BytesOutputStyle.cpp ----------------------------------- *- C++ --*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "BytesOutputStyle.h" + +#include "FormatUtil.h" +#include "StreamUtil.h" +#include "llvm-pdbutil.h" + +#include "llvm/DebugInfo/CodeView/Formatters.h" +#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" +#include "llvm/DebugInfo/MSF/MSFCommon.h" +#include "llvm/DebugInfo/MSF/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Native/DbiStream.h" +#include "llvm/DebugInfo/PDB/Native/InfoStream.h" +#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/DebugInfo/PDB/Native/TpiStream.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/FormatAdapters.h" +#include "llvm/Support/FormatVariadic.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::msf; +using namespace llvm::pdb; + +namespace { +struct StreamSpec { + uint32_t SI = 0; + uint32_t Begin = 0; + uint32_t Size = 0; +}; +} // namespace + +static Expected<StreamSpec> parseStreamSpec(StringRef Str) { + StreamSpec Result; + if (Str.consumeInteger(0, Result.SI)) + return make_error<RawError>(raw_error_code::invalid_format, + "Invalid Stream Specification"); + if (Str.consume_front(":")) { + if (Str.consumeInteger(0, Result.Begin)) + return make_error<RawError>(raw_error_code::invalid_format, + "Invalid Stream Specification"); + } + if (Str.consume_front("@")) { + if (Str.consumeInteger(0, Result.Size)) + return make_error<RawError>(raw_error_code::invalid_format, + "Invalid Stream Specification"); + } + + if (!Str.empty()) + return make_error<RawError>(raw_error_code::invalid_format, + "Invalid Stream Specification"); + return Result; +} + +static SmallVector<StreamSpec, 2> parseStreamSpecs(LinePrinter &P) { + SmallVector<StreamSpec, 2> Result; + + for (auto &Str : opts::bytes::DumpStreamData) { + auto ESS = parseStreamSpec(Str); + if (!ESS) { + P.formatLine("Error parsing stream spec {0}: {1}", Str, + toString(ESS.takeError())); + continue; + } + Result.push_back(*ESS); + } + return Result; +} + +static void printHeader(LinePrinter &P, const Twine &S) { + P.NewLine(); + P.formatLine("{0,=60}", S); + P.formatLine("{0}", fmt_repeat('=', 60)); +} + +BytesOutputStyle::BytesOutputStyle(PDBFile &File) + : File(File), P(2, false, outs()) {} + +Error BytesOutputStyle::dump() { + + if (opts::bytes::DumpBlockRange.hasValue()) { + auto &R = *opts::bytes::DumpBlockRange; + uint32_t Max = R.Max.getValueOr(R.Min); + + if (Max < R.Min) + return make_error<StringError>( + "Invalid block range specified. Max < Min", + inconvertibleErrorCode()); + if (Max >= File.getBlockCount()) + return make_error<StringError>( + "Invalid block range specified. Requested block out of bounds", + inconvertibleErrorCode()); + + dumpBlockRanges(R.Min, Max); + P.NewLine(); + } + + if (opts::bytes::DumpByteRange.hasValue()) { + auto &R = *opts::bytes::DumpByteRange; + uint32_t Max = R.Max.getValueOr(File.getFileSize()); + + if (Max < R.Min) + return make_error<StringError>("Invalid byte range specified. Max < Min", + inconvertibleErrorCode()); + if (Max >= File.getFileSize()) + return make_error<StringError>( + "Invalid byte range specified. Requested byte larger than file size", + inconvertibleErrorCode()); + + dumpByteRanges(R.Min, Max); + P.NewLine(); + } + + if (opts::bytes::Fpm) { + dumpFpm(); + P.NewLine(); + } + + if (!opts::bytes::DumpStreamData.empty()) { + dumpStreamBytes(); + P.NewLine(); + } + + if (opts::bytes::NameMap) { + dumpNameMap(); + P.NewLine(); + } + + if (opts::bytes::SectionContributions) { + dumpSectionContributions(); + P.NewLine(); + } + + if (opts::bytes::SectionMap) { + dumpSectionMap(); + P.NewLine(); + } + + if (opts::bytes::ModuleInfos) { + dumpModuleInfos(); + P.NewLine(); + } + + if (opts::bytes::FileInfo) { + dumpFileInfo(); + P.NewLine(); + } + + if (opts::bytes::TypeServerMap) { + dumpTypeServerMap(); + P.NewLine(); + } + + if (opts::bytes::ECData) { + dumpECData(); + P.NewLine(); + } + + if (!opts::bytes::TypeIndex.empty()) { + dumpTypeIndex(StreamTPI, opts::bytes::TypeIndex); + P.NewLine(); + } + + if (!opts::bytes::IdIndex.empty()) { + dumpTypeIndex(StreamIPI, opts::bytes::IdIndex); + P.NewLine(); + } + + if (opts::bytes::ModuleSyms) { + dumpModuleSyms(); + P.NewLine(); + } + + if (opts::bytes::ModuleC11) { + dumpModuleC11(); + P.NewLine(); + } + + if (opts::bytes::ModuleC13) { + dumpModuleC13(); + P.NewLine(); + } + + return Error::success(); +} + +void BytesOutputStyle::dumpNameMap() { + printHeader(P, "Named Stream Map"); + + AutoIndent Indent(P); + + auto &InfoS = Err(File.getPDBInfoStream()); + BinarySubstreamRef NS = InfoS.getNamedStreamsBuffer(); + auto Layout = File.getStreamLayout(StreamPDB); + P.formatMsfStreamData("Named Stream Map", File, Layout, NS); +} + +void BytesOutputStyle::dumpBlockRanges(uint32_t Min, uint32_t Max) { + printHeader(P, "MSF Blocks"); + + AutoIndent Indent(P); + for (uint32_t I = Min; I <= Max; ++I) { + uint64_t Base = I; + Base *= File.getBlockSize(); + + auto ExpectedData = File.getBlockData(I, File.getBlockSize()); + if (!ExpectedData) { + P.formatLine("Could not get block {0}. Reason = {1}", I, + toString(ExpectedData.takeError())); + continue; + } + std::string Label = formatv("Block {0}", I).str(); + P.formatBinary(Label, *ExpectedData, Base, 0); + } +} + +void BytesOutputStyle::dumpSectionContributions() { + printHeader(P, "Section Contributions"); + + AutoIndent Indent(P); + + auto &DbiS = Err(File.getPDBDbiStream()); + BinarySubstreamRef NS = DbiS.getSectionContributionData(); + auto Layout = File.getStreamLayout(StreamDBI); + P.formatMsfStreamData("Section Contributions", File, Layout, NS); +} + +void BytesOutputStyle::dumpSectionMap() { + printHeader(P, "Section Map"); + + AutoIndent Indent(P); + + auto &DbiS = Err(File.getPDBDbiStream()); + BinarySubstreamRef NS = DbiS.getSecMapSubstreamData(); + auto Layout = File.getStreamLayout(StreamDBI); + P.formatMsfStreamData("Section Map", File, Layout, NS); +} + +void BytesOutputStyle::dumpModuleInfos() { + printHeader(P, "Module Infos"); + + AutoIndent Indent(P); + + auto &DbiS = Err(File.getPDBDbiStream()); + BinarySubstreamRef NS = DbiS.getModiSubstreamData(); + auto Layout = File.getStreamLayout(StreamDBI); + P.formatMsfStreamData("Module Infos", File, Layout, NS); +} + +void BytesOutputStyle::dumpFileInfo() { + printHeader(P, "File Info"); + + AutoIndent Indent(P); + + auto &DbiS = Err(File.getPDBDbiStream()); + BinarySubstreamRef NS = DbiS.getFileInfoSubstreamData(); + auto Layout = File.getStreamLayout(StreamDBI); + P.formatMsfStreamData("File Info", File, Layout, NS); +} + +void BytesOutputStyle::dumpTypeServerMap() { + printHeader(P, "Type Server Map"); + + AutoIndent Indent(P); + + auto &DbiS = Err(File.getPDBDbiStream()); + BinarySubstreamRef NS = DbiS.getTypeServerMapSubstreamData(); + auto Layout = File.getStreamLayout(StreamDBI); + P.formatMsfStreamData("Type Server Map", File, Layout, NS); +} + +void BytesOutputStyle::dumpECData() { + printHeader(P, "Edit and Continue Data"); + + AutoIndent Indent(P); + + auto &DbiS = Err(File.getPDBDbiStream()); + BinarySubstreamRef NS = DbiS.getECSubstreamData(); + auto Layout = File.getStreamLayout(StreamDBI); + P.formatMsfStreamData("Edit and Continue Data", File, Layout, NS); +} + +void BytesOutputStyle::dumpTypeIndex(uint32_t StreamIdx, + ArrayRef<uint32_t> Indices) { + assert(StreamIdx == StreamTPI || StreamIdx == StreamIPI); + assert(!Indices.empty()); + + bool IsTpi = (StreamIdx == StreamTPI); + + StringRef Label = IsTpi ? "Type (TPI) Records" : "Index (IPI) Records"; + printHeader(P, Label); + auto &Stream = Err(IsTpi ? File.getPDBTpiStream() : File.getPDBIpiStream()); + + AutoIndent Indent(P); + + auto Substream = Stream.getTypeRecordsSubstream(); + auto &Types = Err(initializeTypes(StreamIdx)); + auto Layout = File.getStreamLayout(StreamIdx); + for (const auto &Id : Indices) { + TypeIndex TI(Id); + if (TI.toArrayIndex() >= Types.capacity()) { + P.formatLine("Error: TypeIndex {0} does not exist", TI); + continue; + } + + auto Type = Types.getType(TI); + uint32_t Offset = Types.getOffsetOfType(TI); + auto OneType = Substream.slice(Offset, Type.length()); + P.formatMsfStreamData(formatv("Type {0}", TI).str(), File, Layout, OneType); + } +} + +template <typename CallbackT> +static void iterateOneModule(PDBFile &File, LinePrinter &P, + const DbiModuleList &Modules, uint32_t I, + uint32_t Digits, uint32_t IndentLevel, + CallbackT Callback) { + if (I >= Modules.getModuleCount()) { + P.formatLine("Mod {0:4} | Invalid module index ", + fmt_align(I, AlignStyle::Right, std::max(Digits, 4U))); + return; + } + + auto Modi = Modules.getModuleDescriptor(I); + P.formatLine("Mod {0:4} | `{1}`: ", + fmt_align(I, AlignStyle::Right, std::max(Digits, 4U)), + Modi.getModuleName()); + + uint16_t ModiStream = Modi.getModuleStreamIndex(); + AutoIndent Indent2(P, IndentLevel); + if (ModiStream == kInvalidStreamIndex) + return; + + auto ModStreamData = File.createIndexedStream(ModiStream); + ModuleDebugStreamRef ModStream(Modi, std::move(ModStreamData)); + if (auto EC = ModStream.reload()) { + P.formatLine("Could not parse debug information."); + return; + } + auto Layout = File.getStreamLayout(ModiStream); + Callback(I, ModStream, Layout); +} + +template <typename CallbackT> +static void iterateModules(PDBFile &File, LinePrinter &P, uint32_t IndentLevel, + CallbackT Callback) { + AutoIndent Indent(P); + if (!File.hasPDBDbiStream()) { + P.formatLine("DBI Stream not present"); + return; + } + + ExitOnError Err("Unexpected error processing modules"); + + auto &Stream = Err(File.getPDBDbiStream()); + + const DbiModuleList &Modules = Stream.modules(); + + if (opts::bytes::ModuleIndex.getNumOccurrences() > 0) { + iterateOneModule(File, P, Modules, opts::bytes::ModuleIndex, 1, IndentLevel, + Callback); + } else { + uint32_t Count = Modules.getModuleCount(); + uint32_t Digits = NumDigits(Count); + for (uint32_t I = 0; I < Count; ++I) { + iterateOneModule(File, P, Modules, I, Digits, IndentLevel, Callback); + } + } +} + +void BytesOutputStyle::dumpModuleSyms() { + printHeader(P, "Module Symbols"); + + AutoIndent Indent(P); + + iterateModules(File, P, 2, + [this](uint32_t Modi, const ModuleDebugStreamRef &Stream, + const MSFStreamLayout &Layout) { + auto Symbols = Stream.getSymbolsSubstream(); + P.formatMsfStreamData("Symbols", File, Layout, Symbols); + }); +} + +void BytesOutputStyle::dumpModuleC11() { + printHeader(P, "C11 Debug Chunks"); + + AutoIndent Indent(P); + + iterateModules(File, P, 2, + [this](uint32_t Modi, const ModuleDebugStreamRef &Stream, + const MSFStreamLayout &Layout) { + auto Chunks = Stream.getC11LinesSubstream(); + P.formatMsfStreamData("C11 Debug Chunks", File, Layout, + Chunks); + }); +} + +void BytesOutputStyle::dumpModuleC13() { + printHeader(P, "Debug Chunks"); + + AutoIndent Indent(P); + + iterateModules( + File, P, 2, + [this](uint32_t Modi, const ModuleDebugStreamRef &Stream, + const MSFStreamLayout &Layout) { + auto Chunks = Stream.getC13LinesSubstream(); + if (opts::bytes::SplitChunks) { + for (const auto &SS : Stream.subsections()) { + BinarySubstreamRef ThisChunk; + std::tie(ThisChunk, Chunks) = Chunks.split(SS.getRecordLength()); + P.formatMsfStreamData(formatChunkKind(SS.kind()), File, Layout, + ThisChunk); + } + } else { + P.formatMsfStreamData("Debug Chunks", File, Layout, Chunks); + } + }); +} + +void BytesOutputStyle::dumpByteRanges(uint32_t Min, uint32_t Max) { + printHeader(P, "MSF Bytes"); + + AutoIndent Indent(P); + + BinaryStreamReader Reader(File.getMsfBuffer()); + ArrayRef<uint8_t> Data; + consumeError(Reader.skip(Min)); + uint32_t Size = Max - Min + 1; + auto EC = Reader.readBytes(Data, Size); + assert(!EC); + consumeError(std::move(EC)); + P.formatBinary("Bytes", Data, Min); +} + +Expected<codeview::LazyRandomTypeCollection &> +BytesOutputStyle::initializeTypes(uint32_t StreamIdx) { + auto &TypeCollection = (StreamIdx == StreamTPI) ? TpiTypes : IpiTypes; + if (TypeCollection) + return *TypeCollection; + + auto Tpi = (StreamIdx == StreamTPI) ? File.getPDBTpiStream() + : File.getPDBIpiStream(); + if (!Tpi) + return Tpi.takeError(); + + auto &Types = Tpi->typeArray(); + uint32_t Count = Tpi->getNumTypeRecords(); + auto Offsets = Tpi->getTypeIndexOffsets(); + TypeCollection = + std::make_unique<LazyRandomTypeCollection>(Types, Count, Offsets); + + return *TypeCollection; +} + +void BytesOutputStyle::dumpFpm() { + printHeader(P, "Free Page Map"); + + msf::MSFStreamLayout FpmLayout = File.getFpmStreamLayout(); + P.formatMsfStreamBlocks(File, FpmLayout); +} + +void BytesOutputStyle::dumpStreamBytes() { + if (StreamPurposes.empty()) + discoverStreamPurposes(File, StreamPurposes); + + printHeader(P, "Stream Data"); + ExitOnError Err("Unexpected error reading stream data"); + + auto Specs = parseStreamSpecs(P); + + for (const auto &Spec : Specs) { + AutoIndent Indent(P); + if (Spec.SI >= StreamPurposes.size()) { + P.formatLine("Stream {0}: Not present", Spec.SI); + continue; + } + P.formatMsfStreamData("Data", File, Spec.SI, + StreamPurposes[Spec.SI].getShortName(), Spec.Begin, + Spec.Size); + } +} diff --git a/contrib/libs/llvm12/tools/llvm-pdbutil/BytesOutputStyle.h b/contrib/libs/llvm12/tools/llvm-pdbutil/BytesOutputStyle.h new file mode 100644 index 0000000000..d3aceb4767 --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-pdbutil/BytesOutputStyle.h @@ -0,0 +1,68 @@ +//===- BytesOutputStyle.h ------------------------------------- *- C++ --*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMPDBDUMP_BYTESOUTPUTSTYLE_H +#define LLVM_TOOLS_LLVMPDBDUMP_BYTESOUTPUTSTYLE_H + +#include "LinePrinter.h" +#include "OutputStyle.h" +#include "StreamUtil.h" + +#include "llvm/Support/Error.h" + +namespace llvm { + +namespace codeview { +class LazyRandomTypeCollection; +} + +namespace pdb { + +class PDBFile; + +class BytesOutputStyle : public OutputStyle { +public: + BytesOutputStyle(PDBFile &File); + + Error dump() override; + +private: + void dumpNameMap(); + void dumpBlockRanges(uint32_t Min, uint32_t Max); + void dumpByteRanges(uint32_t Min, uint32_t Max); + void dumpFpm(); + void dumpStreamBytes(); + + void dumpSectionContributions(); + void dumpSectionMap(); + void dumpModuleInfos(); + void dumpFileInfo(); + void dumpTypeServerMap(); + void dumpECData(); + + void dumpModuleSyms(); + void dumpModuleC11(); + void dumpModuleC13(); + + void dumpTypeIndex(uint32_t StreamIdx, ArrayRef<uint32_t> Indices); + + Expected<codeview::LazyRandomTypeCollection &> + initializeTypes(uint32_t StreamIdx); + + std::unique_ptr<codeview::LazyRandomTypeCollection> TpiTypes; + std::unique_ptr<codeview::LazyRandomTypeCollection> IpiTypes; + + PDBFile &File; + LinePrinter P; + ExitOnError Err; + SmallVector<StreamInfo, 8> StreamPurposes; +}; +} // namespace pdb +} // namespace llvm + +#endif diff --git a/contrib/libs/llvm12/tools/llvm-pdbutil/DumpOutputStyle.cpp b/contrib/libs/llvm12/tools/llvm-pdbutil/DumpOutputStyle.cpp new file mode 100644 index 0000000000..babdb56a71 --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-pdbutil/DumpOutputStyle.cpp @@ -0,0 +1,1989 @@ +//===- DumpOutputStyle.cpp ------------------------------------ *- C++ --*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "DumpOutputStyle.h" + +#include "FormatUtil.h" +#include "InputFile.h" +#include "MinimalSymbolDumper.h" +#include "MinimalTypeDumper.h" +#include "StreamUtil.h" +#include "TypeReferenceTracker.h" +#include "llvm-pdbutil.h" + +#include "llvm/ADT/STLExtras.h" +#include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h" +#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" +#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h" +#include "llvm/DebugInfo/CodeView/DebugCrossExSubsection.h" +#include "llvm/DebugInfo/CodeView/DebugCrossImpSubsection.h" +#include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h" +#include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h" +#include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h" +#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h" +#include "llvm/DebugInfo/CodeView/DebugSymbolsSubsection.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/SymbolVisitorCallbackPipeline.h" +#include "llvm/DebugInfo/CodeView/SymbolVisitorCallbacks.h" +#include "llvm/DebugInfo/CodeView/TypeHashing.h" +#include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.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/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/SymbolStream.h" +#include "llvm/DebugInfo/PDB/Native/TpiHashing.h" +#include "llvm/DebugInfo/PDB/Native/TpiStream.h" +#include "llvm/Object/COFF.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/FormatAdapters.h" +#include "llvm/Support/FormatVariadic.h" + +#include <cctype> + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::msf; +using namespace llvm::pdb; + +DumpOutputStyle::DumpOutputStyle(InputFile &File) + : File(File), P(2, false, outs()) { + if (opts::dump::DumpTypeRefStats) + RefTracker.reset(new TypeReferenceTracker(File)); +} + +DumpOutputStyle::~DumpOutputStyle() {} + +PDBFile &DumpOutputStyle::getPdb() { return File.pdb(); } +object::COFFObjectFile &DumpOutputStyle::getObj() { return File.obj(); } + +void DumpOutputStyle::printStreamNotValidForObj() { + AutoIndent Indent(P, 4); + P.formatLine("Dumping this stream is not valid for object files"); +} + +void DumpOutputStyle::printStreamNotPresent(StringRef StreamName) { + AutoIndent Indent(P, 4); + P.formatLine("{0} stream not present", StreamName); +} + +Error DumpOutputStyle::dump() { + // Walk symbols & globals if we are supposed to mark types referenced. + if (opts::dump::DumpTypeRefStats) + RefTracker->mark(); + + if (opts::dump::DumpSummary) { + if (auto EC = dumpFileSummary()) + return EC; + P.NewLine(); + } + + if (opts::dump::DumpStreams) { + if (auto EC = dumpStreamSummary()) + return EC; + P.NewLine(); + } + + if (opts::dump::DumpSymbolStats) { + if (auto EC = dumpSymbolStats()) + return EC; + P.NewLine(); + } + + if (opts::dump::DumpUdtStats) { + if (auto EC = dumpUdtStats()) + return EC; + P.NewLine(); + } + + if (opts::dump::DumpTypeStats || opts::dump::DumpIDStats) { + if (auto EC = dumpTypeStats()) + return EC; + P.NewLine(); + } + + if (opts::dump::DumpNamedStreams) { + if (auto EC = dumpNamedStreams()) + return EC; + P.NewLine(); + } + + if (opts::dump::DumpStringTable || opts::dump::DumpStringTableDetails) { + if (auto EC = dumpStringTable()) + return EC; + P.NewLine(); + } + + if (opts::dump::DumpModules) { + if (auto EC = dumpModules()) + return EC; + } + + if (opts::dump::DumpModuleFiles) { + if (auto EC = dumpModuleFiles()) + return EC; + } + + if (opts::dump::DumpLines) { + if (auto EC = dumpLines()) + return EC; + } + + if (opts::dump::DumpInlineeLines) { + if (auto EC = dumpInlineeLines()) + return EC; + } + + if (opts::dump::DumpXmi) { + if (auto EC = dumpXmi()) + return EC; + } + + if (opts::dump::DumpXme) { + if (auto EC = dumpXme()) + return EC; + } + + if (opts::dump::DumpFpo) { + if (auto EC = dumpFpo()) + return EC; + } + + if (File.isObj()) { + if (opts::dump::DumpTypes || !opts::dump::DumpTypeIndex.empty() || + opts::dump::DumpTypeExtras) + if (auto EC = dumpTypesFromObjectFile()) + return EC; + } else { + if (opts::dump::DumpTypes || !opts::dump::DumpTypeIndex.empty() || + opts::dump::DumpTypeExtras) { + if (auto EC = dumpTpiStream(StreamTPI)) + return EC; + } + + if (opts::dump::DumpIds || !opts::dump::DumpIdIndex.empty() || + opts::dump::DumpIdExtras) { + if (auto EC = dumpTpiStream(StreamIPI)) + return EC; + } + } + + if (opts::dump::DumpGSIRecords) { + if (auto EC = dumpGSIRecords()) + return EC; + } + + if (opts::dump::DumpGlobals) { + if (auto EC = dumpGlobals()) + return EC; + } + + if (opts::dump::DumpPublics) { + if (auto EC = dumpPublics()) + return EC; + } + + if (opts::dump::DumpSymbols) { + auto EC = File.isPdb() ? dumpModuleSymsForPdb() : dumpModuleSymsForObj(); + if (EC) + return EC; + } + + if (opts::dump::DumpTypeRefStats) { + if (auto EC = dumpTypeRefStats()) + return EC; + } + + if (opts::dump::DumpSectionHeaders) { + if (auto EC = dumpSectionHeaders()) + return EC; + } + + if (opts::dump::DumpSectionContribs) { + if (auto EC = dumpSectionContribs()) + return EC; + } + + if (opts::dump::DumpSectionMap) { + if (auto EC = dumpSectionMap()) + return EC; + } + + P.NewLine(); + + return Error::success(); +} + +static void printHeader(LinePrinter &P, const Twine &S) { + P.NewLine(); + P.formatLine("{0,=60}", S); + P.formatLine("{0}", fmt_repeat('=', 60)); +} + +Error DumpOutputStyle::dumpFileSummary() { + printHeader(P, "Summary"); + + if (File.isObj()) { + printStreamNotValidForObj(); + return Error::success(); + } + + AutoIndent Indent(P); + ExitOnError Err("Invalid PDB Format: "); + + P.formatLine("Block Size: {0}", getPdb().getBlockSize()); + P.formatLine("Number of blocks: {0}", getPdb().getBlockCount()); + P.formatLine("Number of streams: {0}", getPdb().getNumStreams()); + + auto &PS = Err(getPdb().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}", getPdb().hasPDBDbiStream()); + P.formatLine("Has Types: {0}", getPdb().hasPDBTpiStream()); + P.formatLine("Has IDs: {0}", getPdb().hasPDBIpiStream()); + P.formatLine("Has Globals: {0}", getPdb().hasPDBGlobalsStream()); + P.formatLine("Has Publics: {0}", getPdb().hasPDBPublicsStream()); + if (getPdb().hasPDBDbiStream()) { + auto &DBI = Err(getPdb().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(); +} + +static StatCollection getSymbolStats(const SymbolGroup &SG, + StatCollection &CumulativeStats) { + StatCollection Stats; + if (SG.getFile().isPdb() && SG.hasDebugStream()) { + // For PDB files, all symbols are packed into one stream. + for (const auto &S : SG.getPdbModuleStream().symbols(nullptr)) { + Stats.update(S.kind(), S.length()); + CumulativeStats.update(S.kind(), S.length()); + } + return Stats; + } + + for (const auto &SS : SG.getDebugSubsections()) { + // For object files, all symbols are spread across multiple Symbol + // subsections of a given .debug$S section. + if (SS.kind() != DebugSubsectionKind::Symbols) + continue; + DebugSymbolsSubsectionRef Symbols; + BinaryStreamReader Reader(SS.getRecordData()); + cantFail(Symbols.initialize(Reader)); + for (const auto &S : Symbols) { + Stats.update(S.kind(), S.length()); + CumulativeStats.update(S.kind(), S.length()); + } + } + return Stats; +} + +static StatCollection getChunkStats(const SymbolGroup &SG, + StatCollection &CumulativeStats) { + StatCollection Stats; + for (const auto &Chunk : SG.getDebugSubsections()) { + Stats.update(uint32_t(Chunk.kind()), Chunk.getRecordLength()); + CumulativeStats.update(uint32_t(Chunk.kind()), Chunk.getRecordLength()); + } + return Stats; +} + +static inline std::string formatModuleDetailKind(DebugSubsectionKind K) { + return formatChunkKind(K, false); +} + +static inline std::string formatModuleDetailKind(SymbolKind K) { + return formatSymbolKind(K); +} + +// Get the stats sorted by size, descending. +std::vector<StatCollection::KindAndStat> +StatCollection::getStatsSortedBySize() const { + std::vector<KindAndStat> SortedStats(Individual.begin(), Individual.end()); + llvm::stable_sort(SortedStats, + [](const KindAndStat &LHS, const KindAndStat &RHS) { + return LHS.second.Size > RHS.second.Size; + }); + return SortedStats; +} + +template <typename Kind> +static void printModuleDetailStats(LinePrinter &P, StringRef Label, + const StatCollection &Stats) { + P.NewLine(); + P.formatLine(" {0}", Label); + AutoIndent Indent(P); + P.formatLine("{0,40}: {1,7} entries ({2,12:N} bytes)", "Total", + Stats.Totals.Count, Stats.Totals.Size); + P.formatLine("{0}", fmt_repeat('-', 74)); + + for (const auto &K : Stats.getStatsSortedBySize()) { + std::string KindName = formatModuleDetailKind(Kind(K.first)); + P.formatLine("{0,40}: {1,7} entries ({2,12:N} bytes)", KindName, + K.second.Count, K.second.Size); + } +} + +static bool isMyCode(const SymbolGroup &Group) { + if (Group.getFile().isObj()) + return true; + + StringRef Name = Group.name(); + if (Name.startswith("Import:")) + return false; + if (Name.endswith_lower(".dll")) + return false; + if (Name.equals_lower("* linker *")) + return false; + if (Name.startswith_lower("f:\\binaries\\Intermediate\\vctools")) + return false; + if (Name.startswith_lower("f:\\dd\\vctools\\crt")) + return false; + return true; +} + +static bool shouldDumpSymbolGroup(uint32_t Idx, const SymbolGroup &Group) { + if (opts::dump::JustMyCode && !isMyCode(Group)) + return false; + + // If the arg was not specified on the command line, always dump all modules. + if (opts::dump::DumpModi.getNumOccurrences() == 0) + return true; + + // Otherwise, only dump if this is the same module specified. + return (opts::dump::DumpModi == Idx); +} + +Error DumpOutputStyle::dumpStreamSummary() { + printHeader(P, "Streams"); + + if (File.isObj()) { + printStreamNotValidForObj(); + return Error::success(); + } + + AutoIndent Indent(P); + + if (StreamPurposes.empty()) + discoverStreamPurposes(getPdb(), StreamPurposes); + + uint32_t StreamCount = getPdb().getNumStreams(); + uint32_t MaxStreamSize = getPdb().getMaxStreamSize(); + + for (uint16_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) { + P.formatLine( + "Stream {0} ({1} bytes): [{2}]", + fmt_align(StreamIdx, AlignStyle::Right, NumDigits(StreamCount)), + fmt_align(getPdb().getStreamByteSize(StreamIdx), AlignStyle::Right, + NumDigits(MaxStreamSize)), + StreamPurposes[StreamIdx].getLongName()); + + if (opts::dump::DumpStreamBlocks) { + auto Blocks = getPdb().getStreamBlockList(StreamIdx); + std::vector<uint32_t> BV(Blocks.begin(), Blocks.end()); + P.formatLine(" {0} Blocks: [{1}]", + fmt_repeat(' ', NumDigits(StreamCount)), + make_range(BV.begin(), BV.end())); + } + } + + return Error::success(); +} + +static Expected<ModuleDebugStreamRef> getModuleDebugStream(PDBFile &File, + uint32_t Index) { + ExitOnError Err("Unexpected error: "); + + auto &Dbi = Err(File.getPDBDbiStream()); + const auto &Modules = Dbi.modules(); + auto Modi = Modules.getModuleDescriptor(Index); + + uint16_t ModiStream = Modi.getModuleStreamIndex(); + if (ModiStream == kInvalidStreamIndex) + return make_error<RawError>(raw_error_code::no_stream, + "Module stream not present"); + + auto ModStreamData = File.createIndexedStream(ModiStream); + + ModuleDebugStreamRef ModS(Modi, std::move(ModStreamData)); + if (auto EC = ModS.reload()) + return make_error<RawError>(raw_error_code::corrupt_file, + "Invalid module stream"); + + return std::move(ModS); +} + +template <typename CallbackT> +static void +iterateOneModule(InputFile &File, const Optional<PrintScope> &HeaderScope, + const SymbolGroup &SG, uint32_t Modi, CallbackT Callback) { + if (HeaderScope) { + HeaderScope->P.formatLine( + "Mod {0:4} | `{1}`: ", + fmt_align(Modi, AlignStyle::Right, HeaderScope->LabelWidth), SG.name()); + } + + AutoIndent Indent(HeaderScope); + Callback(Modi, SG); +} + +template <typename CallbackT> +static void iterateSymbolGroups(InputFile &Input, + const Optional<PrintScope> &HeaderScope, + CallbackT Callback) { + AutoIndent Indent(HeaderScope); + + ExitOnError Err("Unexpected error processing modules: "); + + if (opts::dump::DumpModi.getNumOccurrences() > 0) { + assert(opts::dump::DumpModi.getNumOccurrences() == 1); + uint32_t Modi = opts::dump::DumpModi; + SymbolGroup SG(&Input, Modi); + iterateOneModule(Input, withLabelWidth(HeaderScope, NumDigits(Modi)), SG, + Modi, Callback); + return; + } + + uint32_t I = 0; + + for (const auto &SG : Input.symbol_groups()) { + if (shouldDumpSymbolGroup(I, SG)) + iterateOneModule(Input, withLabelWidth(HeaderScope, NumDigits(I)), SG, I, + Callback); + + ++I; + } +} + +template <typename SubsectionT> +static void iterateModuleSubsections( + InputFile &File, const Optional<PrintScope> &HeaderScope, + llvm::function_ref<void(uint32_t, const SymbolGroup &, SubsectionT &)> + Callback) { + + iterateSymbolGroups(File, HeaderScope, + [&](uint32_t Modi, const SymbolGroup &SG) { + for (const auto &SS : SG.getDebugSubsections()) { + SubsectionT Subsection; + + if (SS.kind() != Subsection.kind()) + continue; + + BinaryStreamReader Reader(SS.getRecordData()); + if (auto EC = Subsection.initialize(Reader)) + continue; + Callback(Modi, SG, Subsection); + } + }); +} + +static Expected<std::pair<std::unique_ptr<MappedBlockStream>, + ArrayRef<llvm::object::coff_section>>> +loadSectionHeaders(PDBFile &File, DbgHeaderType Type) { + if (!File.hasPDBDbiStream()) + return make_error<StringError>( + "Section headers require a DBI Stream, which could not be loaded", + inconvertibleErrorCode()); + + auto &Dbi = cantFail(File.getPDBDbiStream()); + uint32_t SI = Dbi.getDebugStreamIndex(Type); + + if (SI == kInvalidStreamIndex) + return make_error<StringError>( + "PDB does not contain the requested image section header type", + inconvertibleErrorCode()); + + auto Stream = File.createIndexedStream(SI); + if (!Stream) + return make_error<StringError>("Could not load the required stream data", + inconvertibleErrorCode()); + + ArrayRef<object::coff_section> Headers; + if (Stream->getLength() % sizeof(object::coff_section) != 0) + return make_error<StringError>( + "Section header array size is not a multiple of section header size", + inconvertibleErrorCode()); + + uint32_t NumHeaders = Stream->getLength() / sizeof(object::coff_section); + BinaryStreamReader Reader(*Stream); + cantFail(Reader.readArray(Headers, NumHeaders)); + return std::make_pair(std::move(Stream), Headers); +} + +static std::vector<std::string> getSectionNames(PDBFile &File) { + auto ExpectedHeaders = loadSectionHeaders(File, DbgHeaderType::SectionHdr); + if (!ExpectedHeaders) + return {}; + + std::unique_ptr<MappedBlockStream> Stream; + ArrayRef<object::coff_section> Headers; + std::tie(Stream, Headers) = std::move(*ExpectedHeaders); + std::vector<std::string> Names; + for (const auto &H : Headers) + Names.push_back(H.Name); + return Names; +} + +static void dumpSectionContrib(LinePrinter &P, const SectionContrib &SC, + ArrayRef<std::string> SectionNames, + uint32_t FieldWidth) { + std::string NameInsert; + if (SC.ISect > 0 && SC.ISect <= SectionNames.size()) { + StringRef SectionName = SectionNames[SC.ISect - 1]; + NameInsert = formatv("[{0}]", SectionName).str(); + } else + NameInsert = "[???]"; + P.formatLine("SC{5} | mod = {2}, {0}, size = {1}, data crc = {3}, reloc " + "crc = {4}", + formatSegmentOffset(SC.ISect, SC.Off), fmtle(SC.Size), + fmtle(SC.Imod), fmtle(SC.DataCrc), fmtle(SC.RelocCrc), + fmt_align(NameInsert, AlignStyle::Left, FieldWidth + 2)); + AutoIndent Indent(P, FieldWidth + 2); + P.formatLine(" {0}", + formatSectionCharacteristics(P.getIndentLevel() + 6, + SC.Characteristics, 3, " | ")); +} + +static void dumpSectionContrib(LinePrinter &P, const SectionContrib2 &SC, + ArrayRef<std::string> SectionNames, + uint32_t FieldWidth) { + P.formatLine("SC2[{6}] | mod = {2}, {0}, size = {1}, data crc = {3}, reloc " + "crc = {4}, coff section = {5}", + formatSegmentOffset(SC.Base.ISect, SC.Base.Off), + fmtle(SC.Base.Size), fmtle(SC.Base.Imod), fmtle(SC.Base.DataCrc), + fmtle(SC.Base.RelocCrc), fmtle(SC.ISectCoff)); + P.formatLine(" {0}", + formatSectionCharacteristics(P.getIndentLevel() + 6, + SC.Base.Characteristics, 3, " | ")); +} + +Error DumpOutputStyle::dumpModules() { + printHeader(P, "Modules"); + + if (File.isObj()) { + printStreamNotValidForObj(); + return Error::success(); + } + + if (!getPdb().hasPDBDbiStream()) { + printStreamNotPresent("DBI"); + return Error::success(); + } + + AutoIndent Indent(P); + ExitOnError Err("Unexpected error processing modules: "); + + auto &Stream = Err(getPdb().getPDBDbiStream()); + + const DbiModuleList &Modules = Stream.modules(); + iterateSymbolGroups( + File, PrintScope{P, 11}, [&](uint32_t Modi, const SymbolGroup &Strings) { + auto Desc = Modules.getModuleDescriptor(Modi); + if (opts::dump::DumpSectionContribs) { + std::vector<std::string> Sections = getSectionNames(getPdb()); + dumpSectionContrib(P, Desc.getSectionContrib(), Sections, 0); + } + P.formatLine("Obj: `{0}`: ", Desc.getObjFileName()); + P.formatLine("debug stream: {0}, # files: {1}, has ec info: {2}", + Desc.getModuleStreamIndex(), Desc.getNumberOfFiles(), + Desc.hasECInfo()); + StringRef PdbFilePath = + Err(Stream.getECName(Desc.getPdbFilePathNameIndex())); + StringRef SrcFilePath = + Err(Stream.getECName(Desc.getSourceFileNameIndex())); + P.formatLine("pdb file ni: {0} `{1}`, src file ni: {2} `{3}`", + Desc.getPdbFilePathNameIndex(), PdbFilePath, + Desc.getSourceFileNameIndex(), SrcFilePath); + }); + return Error::success(); +} + +Error DumpOutputStyle::dumpModuleFiles() { + printHeader(P, "Files"); + + if (File.isObj()) { + printStreamNotValidForObj(); + return Error::success(); + } + + if (!getPdb().hasPDBDbiStream()) { + printStreamNotPresent("DBI"); + return Error::success(); + } + + ExitOnError Err("Unexpected error processing modules: "); + + iterateSymbolGroups(File, PrintScope{P, 11}, + [this, &Err](uint32_t Modi, const SymbolGroup &Strings) { + auto &Stream = Err(getPdb().getPDBDbiStream()); + + const DbiModuleList &Modules = Stream.modules(); + for (const auto &F : Modules.source_files(Modi)) { + Strings.formatFromFileName(P, F); + } + }); + return Error::success(); +} + +Error DumpOutputStyle::dumpSymbolStats() { + printHeader(P, "Module Stats"); + + if (File.isPdb() && !getPdb().hasPDBDbiStream()) { + printStreamNotPresent("DBI"); + return Error::success(); + } + + ExitOnError Err("Unexpected error processing modules: "); + + StatCollection SymStats; + StatCollection ChunkStats; + + Optional<PrintScope> Scope; + if (File.isPdb()) + Scope.emplace(P, 2); + + iterateSymbolGroups(File, Scope, [&](uint32_t Modi, const SymbolGroup &SG) { + StatCollection SS = getSymbolStats(SG, SymStats); + StatCollection CS = getChunkStats(SG, ChunkStats); + + if (SG.getFile().isPdb()) { + AutoIndent Indent(P); + auto Modules = cantFail(File.pdb().getPDBDbiStream()).modules(); + uint32_t ModCount = Modules.getModuleCount(); + DbiModuleDescriptor Desc = Modules.getModuleDescriptor(Modi); + uint32_t StreamIdx = Desc.getModuleStreamIndex(); + + if (StreamIdx == kInvalidStreamIndex) { + P.formatLine("Mod {0} (debug info not present): [{1}]", + fmt_align(Modi, AlignStyle::Right, NumDigits(ModCount)), + Desc.getModuleName()); + return; + } + P.formatLine("Stream {0}, {1} bytes", StreamIdx, + getPdb().getStreamByteSize(StreamIdx)); + + printModuleDetailStats<SymbolKind>(P, "Symbols", SS); + printModuleDetailStats<DebugSubsectionKind>(P, "Chunks", CS); + } + }); + + if (SymStats.Totals.Count > 0) { + P.printLine(" Summary |"); + AutoIndent Indent(P, 4); + printModuleDetailStats<SymbolKind>(P, "Symbols", SymStats); + printModuleDetailStats<DebugSubsectionKind>(P, "Chunks", ChunkStats); + } + + return Error::success(); +} + +Error DumpOutputStyle::dumpTypeStats() { + printHeader(P, "Type Record Stats"); + + // Iterate the types, categorize by kind, accumulate size stats. + StatCollection TypeStats; + LazyRandomTypeCollection &Types = + opts::dump::DumpTypeStats ? File.types() : File.ids(); + for (Optional<TypeIndex> TI = Types.getFirst(); TI; TI = Types.getNext(*TI)) { + CVType Type = Types.getType(*TI); + TypeStats.update(uint32_t(Type.kind()), Type.length()); + } + + P.NewLine(); + P.formatLine(" Types"); + AutoIndent Indent(P); + P.formatLine("{0,16}: {1,7} entries ({2,12:N} bytes, {3,7} avg)", "Total", + TypeStats.Totals.Count, TypeStats.Totals.Size, + (double)TypeStats.Totals.Size / TypeStats.Totals.Count); + P.formatLine("{0}", fmt_repeat('-', 74)); + + for (const auto &K : TypeStats.getStatsSortedBySize()) { + P.formatLine("{0,16}: {1,7} entries ({2,12:N} bytes, {3,7} avg)", + formatTypeLeafKind(TypeLeafKind(K.first)), K.second.Count, + K.second.Size, (double)K.second.Size / K.second.Count); + } + return Error::success(); +} + +static bool isValidNamespaceIdentifier(StringRef S) { + if (S.empty()) + return false; + + if (std::isdigit(S[0])) + return false; + + return llvm::all_of(S, [](char C) { return std::isalnum(C); }); +} + +namespace { +constexpr uint32_t kNoneUdtKind = 0; +constexpr uint32_t kSimpleUdtKind = 1; +constexpr uint32_t kUnknownUdtKind = 2; +} // namespace + +static std::string getUdtStatLabel(uint32_t Kind) { + if (Kind == kNoneUdtKind) + return "<none type>"; + + if (Kind == kSimpleUdtKind) + return "<simple type>"; + + if (Kind == kUnknownUdtKind) + return "<unknown type>"; + + return formatTypeLeafKind(static_cast<TypeLeafKind>(Kind)); +} + +static uint32_t getLongestTypeLeafName(const StatCollection &Stats) { + size_t L = 0; + for (const auto &Stat : Stats.Individual) { + std::string Label = getUdtStatLabel(Stat.first); + L = std::max(L, Label.size()); + } + return static_cast<uint32_t>(L); +} + +Error DumpOutputStyle::dumpUdtStats() { + printHeader(P, "S_UDT Record Stats"); + + if (File.isPdb() && !getPdb().hasPDBGlobalsStream()) { + printStreamNotPresent("Globals"); + return Error::success(); + } + + StatCollection UdtStats; + StatCollection UdtTargetStats; + AutoIndent Indent(P, 4); + + auto &TpiTypes = File.types(); + + StringMap<StatCollection::Stat> NamespacedStats; + + size_t LongestNamespace = 0; + auto HandleOneSymbol = [&](const CVSymbol &Sym) { + if (Sym.kind() != SymbolKind::S_UDT) + return; + UdtStats.update(SymbolKind::S_UDT, Sym.length()); + + UDTSym UDT = cantFail(SymbolDeserializer::deserializeAs<UDTSym>(Sym)); + + uint32_t Kind = 0; + uint32_t RecordSize = 0; + + if (UDT.Type.isNoneType()) + Kind = kNoneUdtKind; + else if (UDT.Type.isSimple()) + Kind = kSimpleUdtKind; + else if (Optional<CVType> T = TpiTypes.tryGetType(UDT.Type)) { + Kind = T->kind(); + RecordSize = T->length(); + } else + Kind = kUnknownUdtKind; + + UdtTargetStats.update(Kind, RecordSize); + + size_t Pos = UDT.Name.find("::"); + if (Pos == StringRef::npos) + return; + + StringRef Scope = UDT.Name.take_front(Pos); + if (Scope.empty() || !isValidNamespaceIdentifier(Scope)) + return; + + LongestNamespace = std::max(LongestNamespace, Scope.size()); + NamespacedStats[Scope].update(RecordSize); + }; + + P.NewLine(); + + if (File.isPdb()) { + auto &SymbolRecords = cantFail(getPdb().getPDBSymbolStream()); + auto ExpGlobals = getPdb().getPDBGlobalsStream(); + if (!ExpGlobals) + return ExpGlobals.takeError(); + + for (uint32_t PubSymOff : ExpGlobals->getGlobalsTable()) { + CVSymbol Sym = SymbolRecords.readRecord(PubSymOff); + HandleOneSymbol(Sym); + } + } else { + for (const auto &Sec : File.symbol_groups()) { + for (const auto &SS : Sec.getDebugSubsections()) { + if (SS.kind() != DebugSubsectionKind::Symbols) + continue; + + DebugSymbolsSubsectionRef Symbols; + BinaryStreamReader Reader(SS.getRecordData()); + cantFail(Symbols.initialize(Reader)); + for (const auto &S : Symbols) + HandleOneSymbol(S); + } + } + } + + LongestNamespace += StringRef(" namespace ''").size(); + size_t LongestTypeLeafKind = getLongestTypeLeafName(UdtTargetStats); + size_t FieldWidth = std::max(LongestNamespace, LongestTypeLeafKind); + + // Compute the max number of digits for count and size fields, including comma + // separators. + StringRef CountHeader("Count"); + StringRef SizeHeader("Size"); + size_t CD = NumDigits(UdtStats.Totals.Count); + CD += (CD - 1) / 3; + CD = std::max(CD, CountHeader.size()); + + size_t SD = NumDigits(UdtStats.Totals.Size); + SD += (SD - 1) / 3; + SD = std::max(SD, SizeHeader.size()); + + uint32_t TableWidth = FieldWidth + 3 + CD + 2 + SD + 1; + + P.formatLine("{0} | {1} {2}", + fmt_align("Record Kind", AlignStyle::Right, FieldWidth), + fmt_align(CountHeader, AlignStyle::Right, CD), + fmt_align(SizeHeader, AlignStyle::Right, SD)); + + P.formatLine("{0}", fmt_repeat('-', TableWidth)); + for (const auto &Stat : UdtTargetStats.getStatsSortedBySize()) { + std::string Label = getUdtStatLabel(Stat.first); + P.formatLine("{0} | {1:N} {2:N}", + fmt_align(Label, AlignStyle::Right, FieldWidth), + fmt_align(Stat.second.Count, AlignStyle::Right, CD), + fmt_align(Stat.second.Size, AlignStyle::Right, SD)); + } + P.formatLine("{0}", fmt_repeat('-', TableWidth)); + P.formatLine("{0} | {1:N} {2:N}", + fmt_align("Total (S_UDT)", AlignStyle::Right, FieldWidth), + fmt_align(UdtStats.Totals.Count, AlignStyle::Right, CD), + fmt_align(UdtStats.Totals.Size, AlignStyle::Right, SD)); + P.formatLine("{0}", fmt_repeat('-', TableWidth)); + struct StrAndStat { + StringRef Key; + StatCollection::Stat Stat; + }; + + // Print namespace stats in descending order of size. + std::vector<StrAndStat> NamespacedStatsSorted; + for (const auto &Stat : NamespacedStats) + NamespacedStatsSorted.push_back({Stat.getKey(), Stat.second}); + llvm::stable_sort(NamespacedStatsSorted, + [](const StrAndStat &L, const StrAndStat &R) { + return L.Stat.Size > R.Stat.Size; + }); + for (const auto &Stat : NamespacedStatsSorted) { + std::string Label = std::string(formatv("namespace '{0}'", Stat.Key)); + P.formatLine("{0} | {1:N} {2:N}", + fmt_align(Label, AlignStyle::Right, FieldWidth), + fmt_align(Stat.Stat.Count, AlignStyle::Right, CD), + fmt_align(Stat.Stat.Size, AlignStyle::Right, SD)); + } + return Error::success(); +} + +static void typesetLinesAndColumns(LinePrinter &P, uint32_t Start, + const LineColumnEntry &E) { + const uint32_t kMaxCharsPerLineNumber = 4; // 4 digit line number + uint32_t MinColumnWidth = kMaxCharsPerLineNumber + 5; + + // Let's try to keep it under 100 characters + constexpr uint32_t kMaxRowLength = 100; + // At least 3 spaces between columns. + uint32_t ColumnsPerRow = kMaxRowLength / (MinColumnWidth + 3); + uint32_t ItemsLeft = E.LineNumbers.size(); + auto LineIter = E.LineNumbers.begin(); + while (ItemsLeft != 0) { + uint32_t RowColumns = std::min(ItemsLeft, ColumnsPerRow); + for (uint32_t I = 0; I < RowColumns; ++I) { + LineInfo Line(LineIter->Flags); + std::string LineStr; + if (Line.isAlwaysStepInto()) + LineStr = "ASI"; + else if (Line.isNeverStepInto()) + LineStr = "NSI"; + else + LineStr = utostr(Line.getStartLine()); + char Statement = Line.isStatement() ? ' ' : '!'; + P.format("{0} {1:X-} {2} ", + fmt_align(LineStr, AlignStyle::Right, kMaxCharsPerLineNumber), + fmt_align(Start + LineIter->Offset, AlignStyle::Right, 8, '0'), + Statement); + ++LineIter; + --ItemsLeft; + } + P.NewLine(); + } +} + +Error DumpOutputStyle::dumpLines() { + printHeader(P, "Lines"); + + if (File.isPdb() && !getPdb().hasPDBDbiStream()) { + printStreamNotPresent("DBI"); + return Error::success(); + } + + uint32_t LastModi = UINT32_MAX; + uint32_t LastNameIndex = UINT32_MAX; + iterateModuleSubsections<DebugLinesSubsectionRef>( + File, PrintScope{P, 4}, + [this, &LastModi, &LastNameIndex](uint32_t Modi, + const SymbolGroup &Strings, + DebugLinesSubsectionRef &Lines) { + uint16_t Segment = Lines.header()->RelocSegment; + uint32_t Begin = Lines.header()->RelocOffset; + uint32_t End = Begin + Lines.header()->CodeSize; + for (const auto &Block : Lines) { + if (LastModi != Modi || LastNameIndex != Block.NameIndex) { + LastModi = Modi; + LastNameIndex = Block.NameIndex; + Strings.formatFromChecksumsOffset(P, Block.NameIndex); + } + + AutoIndent Indent(P, 2); + P.formatLine("{0:X-4}:{1:X-8}-{2:X-8}, ", Segment, Begin, End); + uint32_t Count = Block.LineNumbers.size(); + if (Lines.hasColumnInfo()) + P.format("line/column/addr entries = {0}", Count); + else + P.format("line/addr entries = {0}", Count); + + P.NewLine(); + typesetLinesAndColumns(P, Begin, Block); + } + }); + + return Error::success(); +} + +Error DumpOutputStyle::dumpInlineeLines() { + printHeader(P, "Inlinee Lines"); + + if (File.isPdb() && !getPdb().hasPDBDbiStream()) { + printStreamNotPresent("DBI"); + return Error::success(); + } + + iterateModuleSubsections<DebugInlineeLinesSubsectionRef>( + File, PrintScope{P, 2}, + [this](uint32_t Modi, const SymbolGroup &Strings, + DebugInlineeLinesSubsectionRef &Lines) { + P.formatLine("{0,+8} | {1,+5} | {2}", "Inlinee", "Line", "Source File"); + for (const auto &Entry : Lines) { + P.formatLine("{0,+8} | {1,+5} | ", Entry.Header->Inlinee, + fmtle(Entry.Header->SourceLineNum)); + Strings.formatFromChecksumsOffset(P, Entry.Header->FileID, true); + for (const auto &ExtraFileID : Entry.ExtraFiles) { + P.formatLine(" "); + Strings.formatFromChecksumsOffset(P, ExtraFileID, true); + } + } + P.NewLine(); + }); + + return Error::success(); +} + +Error DumpOutputStyle::dumpXmi() { + printHeader(P, "Cross Module Imports"); + + if (File.isPdb() && !getPdb().hasPDBDbiStream()) { + printStreamNotPresent("DBI"); + return Error::success(); + } + + iterateModuleSubsections<DebugCrossModuleImportsSubsectionRef>( + File, PrintScope{P, 2}, + [this](uint32_t Modi, const SymbolGroup &Strings, + DebugCrossModuleImportsSubsectionRef &Imports) { + P.formatLine("{0,=32} | {1}", "Imported Module", "Type IDs"); + + for (const auto &Xmi : Imports) { + auto ExpectedModule = + Strings.getNameFromStringTable(Xmi.Header->ModuleNameOffset); + StringRef Module; + SmallString<32> ModuleStorage; + if (!ExpectedModule) { + Module = "(unknown module)"; + consumeError(ExpectedModule.takeError()); + } else + Module = *ExpectedModule; + if (Module.size() > 32) { + ModuleStorage = "..."; + ModuleStorage += Module.take_back(32 - 3); + Module = ModuleStorage; + } + std::vector<std::string> TIs; + for (const auto I : Xmi.Imports) + TIs.push_back(std::string(formatv("{0,+10:X+}", fmtle(I)))); + std::string Result = + typesetItemList(TIs, P.getIndentLevel() + 35, 12, " "); + P.formatLine("{0,+32} | {1}", Module, Result); + } + }); + + return Error::success(); +} + +Error DumpOutputStyle::dumpXme() { + printHeader(P, "Cross Module Exports"); + + if (File.isPdb() && !getPdb().hasPDBDbiStream()) { + printStreamNotPresent("DBI"); + return Error::success(); + } + + iterateModuleSubsections<DebugCrossModuleExportsSubsectionRef>( + File, PrintScope{P, 2}, + [this](uint32_t Modi, const SymbolGroup &Strings, + DebugCrossModuleExportsSubsectionRef &Exports) { + P.formatLine("{0,-10} | {1}", "Local ID", "Global ID"); + for (const auto &Export : Exports) { + P.formatLine("{0,+10:X+} | {1}", TypeIndex(Export.Local), + TypeIndex(Export.Global)); + } + }); + + return Error::success(); +} + +std::string formatFrameType(object::frame_type FT) { + switch (FT) { + case object::frame_type::Fpo: + return "FPO"; + case object::frame_type::NonFpo: + return "Non-FPO"; + case object::frame_type::Trap: + return "Trap"; + case object::frame_type::Tss: + return "TSS"; + } + return "<unknown>"; +} + +Error DumpOutputStyle::dumpOldFpo(PDBFile &File) { + printHeader(P, "Old FPO Data"); + + ExitOnError Err("Error dumping old fpo data:"); + auto &Dbi = Err(File.getPDBDbiStream()); + + if (!Dbi.hasOldFpoRecords()) { + printStreamNotPresent("FPO"); + return Error::success(); + } + + const FixedStreamArray<object::FpoData>& Records = Dbi.getOldFpoRecords(); + + P.printLine(" RVA | Code | Locals | Params | Prolog | Saved Regs | Use " + "BP | Has SEH | Frame Type"); + + for (const object::FpoData &FD : Records) { + P.formatLine("{0:X-8} | {1,4} | {2,6} | {3,6} | {4,6} | {5,10} | {6,6} | " + "{7,7} | {8,9}", + uint32_t(FD.Offset), uint32_t(FD.Size), uint32_t(FD.NumLocals), + uint32_t(FD.NumParams), FD.getPrologSize(), + FD.getNumSavedRegs(), FD.useBP(), FD.hasSEH(), + formatFrameType(FD.getFP())); + } + return Error::success(); +} + +Error DumpOutputStyle::dumpNewFpo(PDBFile &File) { + printHeader(P, "New FPO Data"); + + ExitOnError Err("Error dumping new fpo data:"); + auto &Dbi = Err(File.getPDBDbiStream()); + + if (!Dbi.hasNewFpoRecords()) { + printStreamNotPresent("New FPO"); + return Error::success(); + } + + const DebugFrameDataSubsectionRef& FDS = Dbi.getNewFpoRecords(); + + P.printLine(" RVA | Code | Locals | Params | Stack | Prolog | Saved Regs " + "| Has SEH | Has C++EH | Start | Program"); + for (const FrameData &FD : FDS) { + bool IsFuncStart = FD.Flags & FrameData::IsFunctionStart; + bool HasEH = FD.Flags & FrameData::HasEH; + bool HasSEH = FD.Flags & FrameData::HasSEH; + + auto &StringTable = Err(File.getStringTable()); + + auto Program = Err(StringTable.getStringForID(FD.FrameFunc)); + P.formatLine("{0:X-8} | {1,4} | {2,6} | {3,6} | {4,5} | {5,6} | {6,10} | " + "{7,7} | {8,9} | {9,5} | {10}", + uint32_t(FD.RvaStart), uint32_t(FD.CodeSize), + uint32_t(FD.LocalSize), uint32_t(FD.ParamsSize), + uint32_t(FD.MaxStackSize), uint16_t(FD.PrologSize), + uint16_t(FD.SavedRegsSize), HasSEH, HasEH, IsFuncStart, + Program); + } + return Error::success(); +} + +Error DumpOutputStyle::dumpFpo() { + if (!File.isPdb()) { + printStreamNotValidForObj(); + return Error::success(); + } + + PDBFile &File = getPdb(); + if (!File.hasPDBDbiStream()) { + printStreamNotPresent("DBI"); + return Error::success(); + } + + if (auto EC = dumpOldFpo(File)) + return EC; + if (auto EC = dumpNewFpo(File)) + return EC; + return Error::success(); +} + +Error DumpOutputStyle::dumpStringTableFromPdb() { + AutoIndent Indent(P); + auto IS = getPdb().getStringTable(); + if (!IS) { + P.formatLine("Not present in file"); + consumeError(IS.takeError()); + return Error::success(); + } + + if (opts::dump::DumpStringTable) { + if (IS->name_ids().empty()) + P.formatLine("Empty"); + else { + 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()); + llvm::sort(SortedIDs); + 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); + } + } + } + + if (opts::dump::DumpStringTableDetails) { + P.NewLine(); + { + P.printLine("String Table Header:"); + AutoIndent Indent(P); + P.formatLine("Signature: {0}", IS->getSignature()); + P.formatLine("Hash Version: {0}", IS->getHashVersion()); + P.formatLine("Name Buffer Size: {0}", IS->getByteSize()); + P.NewLine(); + } + + BinaryStreamRef NameBuffer = IS->getStringTable().getBuffer(); + ArrayRef<uint8_t> Contents; + cantFail(NameBuffer.readBytes(0, NameBuffer.getLength(), Contents)); + P.formatBinary("Name Buffer", Contents, 0); + P.NewLine(); + { + P.printLine("Hash Table:"); + AutoIndent Indent(P); + P.formatLine("Bucket Count: {0}", IS->name_ids().size()); + for (const auto &Entry : enumerate(IS->name_ids())) + P.formatLine("Bucket[{0}] : {1}", Entry.index(), + uint32_t(Entry.value())); + P.formatLine("Name Count: {0}", IS->getNameCount()); + } + } + return Error::success(); +} + +Error DumpOutputStyle::dumpStringTableFromObj() { + iterateModuleSubsections<DebugStringTableSubsectionRef>( + File, PrintScope{P, 4}, + [&](uint32_t Modi, const SymbolGroup &Strings, + DebugStringTableSubsectionRef &Strings2) { + BinaryStreamRef StringTableBuffer = Strings2.getBuffer(); + BinaryStreamReader Reader(StringTableBuffer); + while (Reader.bytesRemaining() > 0) { + StringRef Str; + uint32_t Offset = Reader.getOffset(); + cantFail(Reader.readCString(Str)); + if (Str.empty()) + continue; + + P.formatLine("{0} | {1}", fmt_align(Offset, AlignStyle::Right, 4), + Str); + } + }); + return Error::success(); +} + +Error DumpOutputStyle::dumpNamedStreams() { + printHeader(P, "Named Streams"); + + if (File.isObj()) { + printStreamNotValidForObj(); + return Error::success(); + } + + AutoIndent Indent(P); + ExitOnError Err("Invalid PDB File: "); + + auto &IS = Err(File.pdb().getPDBInfoStream()); + const NamedStreamMap &NS = IS.getNamedStreams(); + for (const auto &Entry : NS.entries()) { + P.printLine(Entry.getKey()); + AutoIndent Indent2(P, 2); + P.formatLine("Index: {0}", Entry.getValue()); + P.formatLine("Size in bytes: {0}", + File.pdb().getStreamByteSize(Entry.getValue())); + } + + return Error::success(); +} + +Error DumpOutputStyle::dumpStringTable() { + printHeader(P, "String Table"); + + if (File.isPdb()) + return dumpStringTableFromPdb(); + + return dumpStringTableFromObj(); +} + +static void buildDepSet(LazyRandomTypeCollection &Types, + ArrayRef<TypeIndex> Indices, + std::map<TypeIndex, CVType> &DepSet) { + SmallVector<TypeIndex, 4> DepList; + for (const auto &I : Indices) { + TypeIndex TI(I); + if (DepSet.find(TI) != DepSet.end() || TI.isSimple() || TI.isNoneType()) + continue; + + CVType Type = Types.getType(TI); + DepSet[TI] = Type; + codeview::discoverTypeIndices(Type, DepList); + buildDepSet(Types, DepList, DepSet); + } +} + +static void +dumpFullTypeStream(LinePrinter &Printer, LazyRandomTypeCollection &Types, + TypeReferenceTracker *RefTracker, uint32_t NumTypeRecords, + uint32_t NumHashBuckets, + FixedStreamArray<support::ulittle32_t> HashValues, + TpiStream *Stream, bool Bytes, bool Extras) { + + Printer.formatLine("Showing {0:N} records", NumTypeRecords); + uint32_t Width = NumDigits(TypeIndex::FirstNonSimpleIndex + NumTypeRecords); + + MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types, RefTracker, + NumHashBuckets, HashValues, Stream); + + if (auto EC = codeview::visitTypeStream(Types, V)) { + Printer.formatLine("An error occurred dumping type records: {0}", + toString(std::move(EC))); + } +} + +static void dumpPartialTypeStream(LinePrinter &Printer, + LazyRandomTypeCollection &Types, + TypeReferenceTracker *RefTracker, + TpiStream &Stream, ArrayRef<TypeIndex> TiList, + bool Bytes, bool Extras, bool Deps) { + uint32_t Width = + NumDigits(TypeIndex::FirstNonSimpleIndex + Stream.getNumTypeRecords()); + + MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types, RefTracker, + Stream.getNumHashBuckets(), Stream.getHashValues(), + &Stream); + + if (opts::dump::DumpTypeDependents) { + // If we need to dump all dependents, then iterate each index and find + // all dependents, adding them to a map ordered by TypeIndex. + std::map<TypeIndex, CVType> DepSet; + buildDepSet(Types, TiList, DepSet); + + Printer.formatLine( + "Showing {0:N} records and their dependents ({1:N} records total)", + TiList.size(), DepSet.size()); + + for (auto &Dep : DepSet) { + if (auto EC = codeview::visitTypeRecord(Dep.second, Dep.first, V)) + Printer.formatLine("An error occurred dumping type record {0}: {1}", + Dep.first, toString(std::move(EC))); + } + } else { + Printer.formatLine("Showing {0:N} records.", TiList.size()); + + for (const auto &I : TiList) { + TypeIndex TI(I); + CVType Type = Types.getType(TI); + if (auto EC = codeview::visitTypeRecord(Type, TI, V)) + Printer.formatLine("An error occurred dumping type record {0}: {1}", TI, + toString(std::move(EC))); + } + } +} + +Error DumpOutputStyle::dumpTypesFromObjectFile() { + LazyRandomTypeCollection Types(100); + + for (const auto &S : getObj().sections()) { + Expected<StringRef> NameOrErr = S.getName(); + if (!NameOrErr) + return NameOrErr.takeError(); + StringRef SectionName = *NameOrErr; + + // .debug$T is a standard CodeView type section, while .debug$P is the same + // format but used for MSVC precompiled header object files. + if (SectionName == ".debug$T") + printHeader(P, "Types (.debug$T)"); + else if (SectionName == ".debug$P") + printHeader(P, "Precompiled Types (.debug$P)"); + else + continue; + + Expected<StringRef> ContentsOrErr = S.getContents(); + if (!ContentsOrErr) + return ContentsOrErr.takeError(); + + uint32_t Magic; + BinaryStreamReader Reader(*ContentsOrErr, llvm::support::little); + if (auto EC = Reader.readInteger(Magic)) + return EC; + if (Magic != COFF::DEBUG_SECTION_MAGIC) + return make_error<StringError>("Invalid CodeView debug section.", + inconvertibleErrorCode()); + + Types.reset(Reader, 100); + + if (opts::dump::DumpTypes) { + dumpFullTypeStream(P, Types, RefTracker.get(), 0, 0, {}, nullptr, + opts::dump::DumpTypeData, false); + } else if (opts::dump::DumpTypeExtras) { + auto LocalHashes = LocallyHashedType::hashTypeCollection(Types); + auto GlobalHashes = GloballyHashedType::hashTypeCollection(Types); + assert(LocalHashes.size() == GlobalHashes.size()); + + P.formatLine("Local / Global hashes:"); + TypeIndex TI(TypeIndex::FirstNonSimpleIndex); + for (auto H : zip(LocalHashes, GlobalHashes)) { + AutoIndent Indent2(P); + LocallyHashedType &L = std::get<0>(H); + GloballyHashedType &G = std::get<1>(H); + + P.formatLine("TI: {0}, LocalHash: {1:X}, GlobalHash: {2}", TI, L, G); + + ++TI; + } + P.NewLine(); + } + } + + return Error::success(); +} + +Error DumpOutputStyle::dumpTpiStream(uint32_t StreamIdx) { + assert(StreamIdx == StreamTPI || StreamIdx == StreamIPI); + + if (StreamIdx == StreamTPI) { + printHeader(P, "Types (TPI Stream)"); + } else if (StreamIdx == StreamIPI) { + printHeader(P, "Types (IPI Stream)"); + } + + assert(!File.isObj()); + + bool Present = false; + bool DumpTypes = false; + bool DumpBytes = false; + bool DumpExtras = false; + std::vector<uint32_t> Indices; + if (StreamIdx == StreamTPI) { + Present = getPdb().hasPDBTpiStream(); + DumpTypes = opts::dump::DumpTypes; + DumpBytes = opts::dump::DumpTypeData; + DumpExtras = opts::dump::DumpTypeExtras; + Indices.assign(opts::dump::DumpTypeIndex.begin(), + opts::dump::DumpTypeIndex.end()); + } else if (StreamIdx == StreamIPI) { + Present = getPdb().hasPDBIpiStream(); + DumpTypes = opts::dump::DumpIds; + DumpBytes = opts::dump::DumpIdData; + DumpExtras = opts::dump::DumpIdExtras; + Indices.assign(opts::dump::DumpIdIndex.begin(), + opts::dump::DumpIdIndex.end()); + } + + if (!Present) { + printStreamNotPresent(StreamIdx == StreamTPI ? "TPI" : "IPI"); + return Error::success(); + } + + AutoIndent Indent(P); + ExitOnError Err("Unexpected error processing types: "); + + auto &Stream = Err((StreamIdx == StreamTPI) ? getPdb().getPDBTpiStream() + : getPdb().getPDBIpiStream()); + + auto &Types = (StreamIdx == StreamTPI) ? File.types() : File.ids(); + + // Only emit notes about referenced/unreferenced for types. + TypeReferenceTracker *MaybeTracker = + (StreamIdx == StreamTPI) ? RefTracker.get() : nullptr; + + // Enable resolving forward decls. + Stream.buildHashMap(); + + if (DumpTypes || !Indices.empty()) { + if (Indices.empty()) + dumpFullTypeStream(P, Types, MaybeTracker, Stream.getNumTypeRecords(), + Stream.getNumHashBuckets(), Stream.getHashValues(), + &Stream, DumpBytes, DumpExtras); + else { + std::vector<TypeIndex> TiList(Indices.begin(), Indices.end()); + dumpPartialTypeStream(P, Types, MaybeTracker, Stream, TiList, DumpBytes, + DumpExtras, opts::dump::DumpTypeDependents); + } + } + + if (DumpExtras) { + P.NewLine(); + + P.formatLine("Header Version: {0}", + static_cast<uint32_t>(Stream.getTpiVersion())); + P.formatLine("Hash Stream Index: {0}", Stream.getTypeHashStreamIndex()); + P.formatLine("Aux Hash Stream Index: {0}", + Stream.getTypeHashStreamAuxIndex()); + P.formatLine("Hash Key Size: {0}", Stream.getHashKeySize()); + P.formatLine("Num Hash Buckets: {0}", Stream.getNumHashBuckets()); + + auto IndexOffsets = Stream.getTypeIndexOffsets(); + P.formatLine("Type Index Offsets:"); + for (const auto &IO : IndexOffsets) { + AutoIndent Indent2(P); + P.formatLine("TI: {0}, Offset: {1}", IO.Type, fmtle(IO.Offset)); + } + + if (getPdb().hasPDBStringTable()) { + P.NewLine(); + P.formatLine("Hash Adjusters:"); + auto &Adjusters = Stream.getHashAdjusters(); + auto &Strings = Err(getPdb().getStringTable()); + for (const auto &A : Adjusters) { + AutoIndent Indent2(P); + auto ExpectedStr = Strings.getStringForID(A.first); + TypeIndex TI(A.second); + if (ExpectedStr) + P.formatLine("`{0}` -> {1}", *ExpectedStr, TI); + else { + P.formatLine("unknown str id ({0}) -> {1}", A.first, TI); + consumeError(ExpectedStr.takeError()); + } + } + } + } + return Error::success(); +} + +Error DumpOutputStyle::dumpModuleSymsForObj() { + printHeader(P, "Symbols"); + + AutoIndent Indent(P); + + ExitOnError Err("Unexpected error processing symbols: "); + + auto &Types = File.types(); + + SymbolVisitorCallbackPipeline Pipeline; + SymbolDeserializer Deserializer(nullptr, CodeViewContainer::ObjectFile); + MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Types, Types); + + Pipeline.addCallbackToPipeline(Deserializer); + Pipeline.addCallbackToPipeline(Dumper); + CVSymbolVisitor Visitor(Pipeline); + + std::unique_ptr<llvm::Error> SymbolError; + + iterateModuleSubsections<DebugSymbolsSubsectionRef>( + File, PrintScope{P, 2}, + [&](uint32_t Modi, const SymbolGroup &Strings, + DebugSymbolsSubsectionRef &Symbols) { + Dumper.setSymbolGroup(&Strings); + for (auto Symbol : Symbols) { + if (auto EC = Visitor.visitSymbolRecord(Symbol)) { + SymbolError = std::make_unique<Error>(std::move(EC)); + return; + } + } + }); + + if (SymbolError) + return std::move(*SymbolError); + + return Error::success(); +} + +Error DumpOutputStyle::dumpModuleSymsForPdb() { + printHeader(P, "Symbols"); + + if (File.isPdb() && !getPdb().hasPDBDbiStream()) { + printStreamNotPresent("DBI"); + return Error::success(); + } + + AutoIndent Indent(P); + ExitOnError Err("Unexpected error processing symbols: "); + + auto &Ids = File.ids(); + auto &Types = File.types(); + + iterateSymbolGroups( + File, PrintScope{P, 2}, [&](uint32_t I, const SymbolGroup &Strings) { + auto ExpectedModS = getModuleDebugStream(File.pdb(), I); + if (!ExpectedModS) { + P.formatLine("Error loading module stream {0}. {1}", I, + toString(ExpectedModS.takeError())); + return; + } + + ModuleDebugStreamRef &ModS = *ExpectedModS; + + SymbolVisitorCallbackPipeline Pipeline; + SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb); + MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Strings, + Ids, Types); + + Pipeline.addCallbackToPipeline(Deserializer); + Pipeline.addCallbackToPipeline(Dumper); + CVSymbolVisitor Visitor(Pipeline); + auto SS = ModS.getSymbolsSubstream(); + if (auto EC = + Visitor.visitSymbolStream(ModS.getSymbolArray(), SS.Offset)) { + P.formatLine("Error while processing symbol records. {0}", + toString(std::move(EC))); + return; + } + }); + return Error::success(); +} + +Error DumpOutputStyle::dumpTypeRefStats() { + printHeader(P, "Type Reference Statistics"); + AutoIndent Indent(P); + + // Sum the byte size of all type records, and the size and count of all + // referenced records. + size_t TotalRecs = File.types().size(); + size_t RefRecs = 0; + size_t TotalBytes = 0; + size_t RefBytes = 0; + auto &Types = File.types(); + for (Optional<TypeIndex> TI = Types.getFirst(); TI; TI = Types.getNext(*TI)) { + CVType Type = File.types().getType(*TI); + TotalBytes += Type.length(); + if (RefTracker->isTypeReferenced(*TI)) { + ++RefRecs; + RefBytes += Type.length(); + } + } + + P.formatLine("Records referenced: {0:N} / {1:N} {2:P}", RefRecs, TotalRecs, + (double)RefRecs / TotalRecs); + P.formatLine("Bytes referenced: {0:N} / {1:N} {2:P}", RefBytes, TotalBytes, + (double)RefBytes / TotalBytes); + + return Error::success(); +} + +Error DumpOutputStyle::dumpGSIRecords() { + printHeader(P, "GSI Records"); + + if (File.isObj()) { + printStreamNotValidForObj(); + return Error::success(); + } + + if (!getPdb().hasPDBSymbolStream()) { + printStreamNotPresent("GSI Common Symbol"); + return Error::success(); + } + + AutoIndent Indent(P); + + auto &Records = cantFail(getPdb().getPDBSymbolStream()); + auto &Types = File.types(); + auto &Ids = File.ids(); + + P.printLine("Records"); + SymbolVisitorCallbackPipeline Pipeline; + SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb); + MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Ids, Types); + + Pipeline.addCallbackToPipeline(Deserializer); + Pipeline.addCallbackToPipeline(Dumper); + CVSymbolVisitor Visitor(Pipeline); + + BinaryStreamRef SymStream = Records.getSymbolArray().getUnderlyingStream(); + if (auto E = Visitor.visitSymbolStream(Records.getSymbolArray(), 0)) + return E; + return Error::success(); +} + +Error DumpOutputStyle::dumpGlobals() { + printHeader(P, "Global Symbols"); + + if (File.isObj()) { + printStreamNotValidForObj(); + return Error::success(); + } + + if (!getPdb().hasPDBGlobalsStream()) { + printStreamNotPresent("Globals"); + return Error::success(); + } + + AutoIndent Indent(P); + ExitOnError Err("Error dumping globals stream: "); + auto &Globals = Err(getPdb().getPDBGlobalsStream()); + + if (opts::dump::DumpGlobalNames.empty()) { + const GSIHashTable &Table = Globals.getGlobalsTable(); + Err(dumpSymbolsFromGSI(Table, opts::dump::DumpGlobalExtras)); + } else { + SymbolStream &SymRecords = cantFail(getPdb().getPDBSymbolStream()); + auto &Types = File.types(); + auto &Ids = File.ids(); + + SymbolVisitorCallbackPipeline Pipeline; + SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb); + MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Ids, Types); + + Pipeline.addCallbackToPipeline(Deserializer); + Pipeline.addCallbackToPipeline(Dumper); + CVSymbolVisitor Visitor(Pipeline); + + using ResultEntryType = std::pair<uint32_t, CVSymbol>; + for (StringRef Name : opts::dump::DumpGlobalNames) { + AutoIndent Indent(P); + P.formatLine("Global Name `{0}`", Name); + std::vector<ResultEntryType> Results = + Globals.findRecordsByName(Name, SymRecords); + if (Results.empty()) { + AutoIndent Indent(P); + P.printLine("(no matching records found)"); + continue; + } + + for (ResultEntryType Result : Results) { + if (auto E = Visitor.visitSymbolRecord(Result.second, Result.first)) + return E; + } + } + } + return Error::success(); +} + +Error DumpOutputStyle::dumpPublics() { + printHeader(P, "Public Symbols"); + + if (File.isObj()) { + printStreamNotValidForObj(); + return Error::success(); + } + + if (!getPdb().hasPDBPublicsStream()) { + printStreamNotPresent("Publics"); + return Error::success(); + } + + AutoIndent Indent(P); + ExitOnError Err("Error dumping publics stream: "); + auto &Publics = Err(getPdb().getPDBPublicsStream()); + + const GSIHashTable &PublicsTable = Publics.getPublicsTable(); + if (opts::dump::DumpPublicExtras) { + P.printLine("Publics Header"); + AutoIndent Indent(P); + P.formatLine("sym hash = {0}, thunk table addr = {1}", Publics.getSymHash(), + formatSegmentOffset(Publics.getThunkTableSection(), + Publics.getThunkTableOffset())); + } + Err(dumpSymbolsFromGSI(PublicsTable, opts::dump::DumpPublicExtras)); + + // Skip the rest if we aren't dumping extras. + if (!opts::dump::DumpPublicExtras) + return Error::success(); + + P.formatLine("Address Map"); + { + // These are offsets into the publics stream sorted by secidx:secrel. + AutoIndent Indent2(P); + for (uint32_t Addr : Publics.getAddressMap()) + P.formatLine("off = {0}", Addr); + } + + // The thunk map is optional debug info used for ILT thunks. + if (!Publics.getThunkMap().empty()) { + P.formatLine("Thunk Map"); + AutoIndent Indent2(P); + for (uint32_t Addr : Publics.getThunkMap()) + P.formatLine("{0:x8}", Addr); + } + + // The section offsets table appears to be empty when incremental linking + // isn't in use. + if (!Publics.getSectionOffsets().empty()) { + P.formatLine("Section Offsets"); + AutoIndent Indent2(P); + for (const SectionOffset &SO : Publics.getSectionOffsets()) + P.formatLine("{0:x4}:{1:x8}", uint16_t(SO.Isect), uint32_t(SO.Off)); + } + + return Error::success(); +} + +Error DumpOutputStyle::dumpSymbolsFromGSI(const GSIHashTable &Table, + bool HashExtras) { + auto ExpectedSyms = getPdb().getPDBSymbolStream(); + if (!ExpectedSyms) + return ExpectedSyms.takeError(); + auto &Types = File.types(); + auto &Ids = File.ids(); + + if (HashExtras) { + P.printLine("GSI Header"); + AutoIndent Indent(P); + P.formatLine("sig = {0:X}, hdr = {1:X}, hr size = {2}, num buckets = {3}", + Table.getVerSignature(), Table.getVerHeader(), + Table.getHashRecordSize(), Table.getNumBuckets()); + } + + { + P.printLine("Records"); + SymbolVisitorCallbackPipeline Pipeline; + SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb); + MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Ids, Types); + + Pipeline.addCallbackToPipeline(Deserializer); + Pipeline.addCallbackToPipeline(Dumper); + CVSymbolVisitor Visitor(Pipeline); + + + BinaryStreamRef SymStream = + ExpectedSyms->getSymbolArray().getUnderlyingStream(); + for (uint32_t PubSymOff : Table) { + Expected<CVSymbol> Sym = readSymbolFromStream(SymStream, PubSymOff); + if (!Sym) + return Sym.takeError(); + if (auto E = Visitor.visitSymbolRecord(*Sym, PubSymOff)) + return E; + } + } + + // Return early if we aren't dumping public hash table and address map info. + if (HashExtras) { + P.formatLine("Hash Entries"); + { + AutoIndent Indent2(P); + for (const PSHashRecord &HR : Table.HashRecords) + P.formatLine("off = {0}, refcnt = {1}", uint32_t(HR.Off), + uint32_t(HR.CRef)); + } + + P.formatLine("Hash Buckets"); + { + AutoIndent Indent2(P); + for (uint32_t Hash : Table.HashBuckets) + P.formatLine("{0:x8}", Hash); + } + } + + return Error::success(); +} + +static std::string formatSegMapDescriptorFlag(uint32_t IndentLevel, + OMFSegDescFlags Flags) { + std::vector<std::string> Opts; + if (Flags == OMFSegDescFlags::None) + return "none"; + + PUSH_FLAG(OMFSegDescFlags, Read, Flags, "read"); + PUSH_FLAG(OMFSegDescFlags, Write, Flags, "write"); + PUSH_FLAG(OMFSegDescFlags, Execute, Flags, "execute"); + PUSH_FLAG(OMFSegDescFlags, AddressIs32Bit, Flags, "32 bit addr"); + PUSH_FLAG(OMFSegDescFlags, IsSelector, Flags, "selector"); + PUSH_FLAG(OMFSegDescFlags, IsAbsoluteAddress, Flags, "absolute addr"); + PUSH_FLAG(OMFSegDescFlags, IsGroup, Flags, "group"); + return typesetItemList(Opts, IndentLevel, 4, " | "); +} + +Error DumpOutputStyle::dumpSectionHeaders() { + dumpSectionHeaders("Section Headers", DbgHeaderType::SectionHdr); + dumpSectionHeaders("Original Section Headers", DbgHeaderType::SectionHdrOrig); + return Error::success(); +} + +void DumpOutputStyle::dumpSectionHeaders(StringRef Label, DbgHeaderType Type) { + printHeader(P, Label); + + if (File.isObj()) { + printStreamNotValidForObj(); + return; + } + + if (!getPdb().hasPDBDbiStream()) { + printStreamNotPresent("DBI"); + return; + } + + AutoIndent Indent(P); + ExitOnError Err("Error dumping section headers: "); + std::unique_ptr<MappedBlockStream> Stream; + ArrayRef<object::coff_section> Headers; + auto ExpectedHeaders = loadSectionHeaders(getPdb(), Type); + if (!ExpectedHeaders) { + P.printLine(toString(ExpectedHeaders.takeError())); + return; + } + std::tie(Stream, Headers) = std::move(*ExpectedHeaders); + + uint32_t I = 1; + for (const auto &Header : Headers) { + P.NewLine(); + P.formatLine("SECTION HEADER #{0}", I); + P.formatLine("{0,8} name", Header.Name); + P.formatLine("{0,8:X-} virtual size", uint32_t(Header.VirtualSize)); + P.formatLine("{0,8:X-} virtual address", uint32_t(Header.VirtualAddress)); + P.formatLine("{0,8:X-} size of raw data", uint32_t(Header.SizeOfRawData)); + P.formatLine("{0,8:X-} file pointer to raw data", + uint32_t(Header.PointerToRawData)); + P.formatLine("{0,8:X-} file pointer to relocation table", + uint32_t(Header.PointerToRelocations)); + P.formatLine("{0,8:X-} file pointer to line numbers", + uint32_t(Header.PointerToLinenumbers)); + P.formatLine("{0,8:X-} number of relocations", + uint32_t(Header.NumberOfRelocations)); + P.formatLine("{0,8:X-} number of line numbers", + uint32_t(Header.NumberOfLinenumbers)); + P.formatLine("{0,8:X-} flags", uint32_t(Header.Characteristics)); + AutoIndent IndentMore(P, 9); + P.formatLine("{0}", formatSectionCharacteristics( + P.getIndentLevel(), Header.Characteristics, 1, "")); + ++I; + } +} + +Error DumpOutputStyle::dumpSectionContribs() { + printHeader(P, "Section Contributions"); + + if (File.isObj()) { + printStreamNotValidForObj(); + return Error::success(); + } + + if (!getPdb().hasPDBDbiStream()) { + printStreamNotPresent("DBI"); + return Error::success(); + } + + AutoIndent Indent(P); + ExitOnError Err("Error dumping section contributions: "); + + auto &Dbi = Err(getPdb().getPDBDbiStream()); + + class Visitor : public ISectionContribVisitor { + public: + Visitor(LinePrinter &P, ArrayRef<std::string> Names) : P(P), Names(Names) { + auto Max = std::max_element( + Names.begin(), Names.end(), + [](StringRef S1, StringRef S2) { return S1.size() < S2.size(); }); + MaxNameLen = (Max == Names.end() ? 0 : Max->size()); + } + void visit(const SectionContrib &SC) override { + dumpSectionContrib(P, SC, Names, MaxNameLen); + } + void visit(const SectionContrib2 &SC) override { + dumpSectionContrib(P, SC, Names, MaxNameLen); + } + + private: + LinePrinter &P; + uint32_t MaxNameLen; + ArrayRef<std::string> Names; + }; + + std::vector<std::string> Names = getSectionNames(getPdb()); + Visitor V(P, makeArrayRef(Names)); + Dbi.visitSectionContributions(V); + return Error::success(); +} + +Error DumpOutputStyle::dumpSectionMap() { + printHeader(P, "Section Map"); + + if (File.isObj()) { + printStreamNotValidForObj(); + return Error::success(); + } + + if (!getPdb().hasPDBDbiStream()) { + printStreamNotPresent("DBI"); + return Error::success(); + } + + AutoIndent Indent(P); + ExitOnError Err("Error dumping section map: "); + + auto &Dbi = Err(getPdb().getPDBDbiStream()); + + uint32_t I = 0; + for (auto &M : Dbi.getSectionMap()) { + P.formatLine( + "Section {0:4} | ovl = {1}, group = {2}, frame = {3}, name = {4}", I, + fmtle(M.Ovl), fmtle(M.Group), fmtle(M.Frame), fmtle(M.SecName)); + P.formatLine(" class = {0}, offset = {1}, size = {2}", + fmtle(M.ClassName), fmtle(M.Offset), fmtle(M.SecByteLength)); + P.formatLine(" flags = {0}", + formatSegMapDescriptorFlag( + P.getIndentLevel() + 13, + static_cast<OMFSegDescFlags>(uint16_t(M.Flags)))); + ++I; + } + return Error::success(); +} diff --git a/contrib/libs/llvm12/tools/llvm-pdbutil/DumpOutputStyle.h b/contrib/libs/llvm12/tools/llvm-pdbutil/DumpOutputStyle.h new file mode 100644 index 0000000000..796cd7a10c --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-pdbutil/DumpOutputStyle.h @@ -0,0 +1,122 @@ +//===- DumpOutputStyle.h -------------------------------------- *- C++ --*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMPDBDUMP_DUMPOUTPUTSTYLE_H +#define LLVM_TOOLS_LLVMPDBDUMP_DUMPOUTPUTSTYLE_H + +#include "LinePrinter.h" +#include "OutputStyle.h" +#include "StreamUtil.h" + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/DebugInfo/PDB/Native/RawConstants.h" + +#include <string> + +namespace llvm { +class BitVector; + +namespace codeview { +class LazyRandomTypeCollection; +} + +namespace object { +class COFFObjectFile; +} + +namespace pdb { +class GSIHashTable; +class InputFile; +class TypeReferenceTracker; + +struct StatCollection { + struct Stat { + Stat() {} + Stat(uint32_t Count, uint32_t Size) : Count(Count), Size(Size) {} + uint32_t Count = 0; + uint32_t Size = 0; + + void update(uint32_t RecordSize) { + ++Count; + Size += RecordSize; + } + }; + + using KindAndStat = std::pair<uint32_t, Stat>; + + void update(uint32_t Kind, uint32_t RecordSize) { + Totals.update(RecordSize); + auto Iter = Individual.try_emplace(Kind, 1, RecordSize); + if (!Iter.second) + Iter.first->second.update(RecordSize); + } + Stat Totals; + DenseMap<uint32_t, Stat> Individual; + + std::vector<KindAndStat> getStatsSortedBySize() const; +}; + +class DumpOutputStyle : public OutputStyle { + +public: + DumpOutputStyle(InputFile &File); + ~DumpOutputStyle() override; + + Error dump() override; + +private: + PDBFile &getPdb(); + object::COFFObjectFile &getObj(); + + void printStreamNotValidForObj(); + void printStreamNotPresent(StringRef StreamName); + + Error dumpFileSummary(); + Error dumpStreamSummary(); + Error dumpSymbolStats(); + Error dumpUdtStats(); + Error dumpTypeStats(); + Error dumpNamedStreams(); + Error dumpStringTable(); + Error dumpStringTableFromPdb(); + Error dumpStringTableFromObj(); + Error dumpLines(); + Error dumpInlineeLines(); + Error dumpXmi(); + Error dumpXme(); + Error dumpFpo(); + Error dumpOldFpo(PDBFile &File); + Error dumpNewFpo(PDBFile &File); + Error dumpTpiStream(uint32_t StreamIdx); + Error dumpTypesFromObjectFile(); + Error dumpTypeRefStats(); + Error dumpModules(); + Error dumpModuleFiles(); + Error dumpModuleSymsForPdb(); + Error dumpModuleSymsForObj(); + Error dumpGSIRecords(); + Error dumpGlobals(); + Error dumpPublics(); + Error dumpSymbolsFromGSI(const GSIHashTable &Table, bool HashExtras); + Error dumpSectionHeaders(); + Error dumpSectionContribs(); + Error dumpSectionMap(); + + void dumpSectionHeaders(StringRef Label, DbgHeaderType Type); + + InputFile &File; + std::unique_ptr<TypeReferenceTracker> RefTracker; + LinePrinter P; + SmallVector<StreamInfo, 32> StreamPurposes; +}; +} // namespace pdb +} // namespace llvm + +#endif diff --git a/contrib/libs/llvm12/tools/llvm-pdbutil/ExplainOutputStyle.cpp b/contrib/libs/llvm12/tools/llvm-pdbutil/ExplainOutputStyle.cpp new file mode 100644 index 0000000000..3d2490509c --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-pdbutil/ExplainOutputStyle.cpp @@ -0,0 +1,468 @@ +//===- ExplainOutputStyle.cpp --------------------------------- *- C++ --*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "ExplainOutputStyle.h" + +#include "FormatUtil.h" +#include "InputFile.h" +#include "StreamUtil.h" +#include "llvm-pdbutil.h" + +#include "llvm/DebugInfo/CodeView/Formatters.h" +#include "llvm/DebugInfo/MSF/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Native/DbiStream.h" +#include "llvm/DebugInfo/PDB/Native/InfoStream.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/RawTypes.h" +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/BinaryStreamArray.h" +#include "llvm/Support/Error.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::msf; +using namespace llvm::pdb; + +ExplainOutputStyle::ExplainOutputStyle(InputFile &File, uint64_t FileOffset) + : File(File), FileOffset(FileOffset), P(2, false, outs()) {} + +Error ExplainOutputStyle::dump() { + P.formatLine("Explaining file offset {0} of file '{1}'.", FileOffset, + File.getFilePath()); + + if (File.isPdb()) + return explainPdbFile(); + + return explainBinaryFile(); +} + +Error ExplainOutputStyle::explainPdbFile() { + bool IsAllocated = explainPdbBlockStatus(); + if (!IsAllocated) + return Error::success(); + + AutoIndent Indent(P); + if (isPdbSuperBlock()) + explainPdbSuperBlockOffset(); + else if (isPdbFpmBlock()) + explainPdbFpmBlockOffset(); + else if (isPdbBlockMapBlock()) + explainPdbBlockMapOffset(); + else if (isPdbStreamDirectoryBlock()) + explainPdbStreamDirectoryOffset(); + else if (auto Index = getPdbBlockStreamIndex()) + explainPdbStreamOffset(*Index); + else + explainPdbUnknownBlock(); + return Error::success(); +} + +Error ExplainOutputStyle::explainBinaryFile() { + std::unique_ptr<BinaryByteStream> Stream = + std::make_unique<BinaryByteStream>(File.unknown().getBuffer(), + llvm::support::little); + switch (opts::explain::InputType) { + case opts::explain::InputFileType::DBIStream: { + DbiStream Dbi(std::move(Stream)); + if (auto EC = Dbi.reload(nullptr)) + return EC; + explainStreamOffset(Dbi, FileOffset); + break; + } + case opts::explain::InputFileType::PDBStream: { + InfoStream Info(std::move(Stream)); + if (auto EC = Info.reload()) + return EC; + explainStreamOffset(Info, FileOffset); + break; + } + default: + llvm_unreachable("Invalid input file type!"); + } + return Error::success(); +} + +uint32_t ExplainOutputStyle::pdbBlockIndex() const { + return FileOffset / File.pdb().getBlockSize(); +} + +uint32_t ExplainOutputStyle::pdbBlockOffset() const { + uint64_t BlockStart = pdbBlockIndex() * File.pdb().getBlockSize(); + assert(FileOffset >= BlockStart); + return FileOffset - BlockStart; +} + +bool ExplainOutputStyle::isPdbSuperBlock() const { + return pdbBlockIndex() == 0; +} + +bool ExplainOutputStyle::isPdbFpm1() const { + return ((pdbBlockIndex() - 1) % File.pdb().getBlockSize() == 0); +} +bool ExplainOutputStyle::isPdbFpm2() const { + return ((pdbBlockIndex() - 2) % File.pdb().getBlockSize() == 0); +} + +bool ExplainOutputStyle::isPdbFpmBlock() const { + return isPdbFpm1() || isPdbFpm2(); +} + +bool ExplainOutputStyle::isPdbBlockMapBlock() const { + return pdbBlockIndex() == File.pdb().getBlockMapIndex(); +} + +bool ExplainOutputStyle::isPdbStreamDirectoryBlock() const { + const auto &Layout = File.pdb().getMsfLayout(); + return llvm::is_contained(Layout.DirectoryBlocks, pdbBlockIndex()); +} + +Optional<uint32_t> ExplainOutputStyle::getPdbBlockStreamIndex() const { + const auto &Layout = File.pdb().getMsfLayout(); + for (const auto &Entry : enumerate(Layout.StreamMap)) { + if (!llvm::is_contained(Entry.value(), pdbBlockIndex())) + continue; + return Entry.index(); + } + return None; +} + +bool ExplainOutputStyle::explainPdbBlockStatus() { + if (FileOffset >= File.pdb().getFileSize()) { + P.formatLine("Address {0} is not in the file (file size = {1}).", + FileOffset, File.pdb().getFileSize()); + return false; + } + P.formatLine("Block:Offset = {2:X-}:{1:X-4}.", FileOffset, pdbBlockOffset(), + pdbBlockIndex()); + + bool IsFree = File.pdb().getMsfLayout().FreePageMap[pdbBlockIndex()]; + P.formatLine("Address is in block {0} ({1}allocated).", pdbBlockIndex(), + IsFree ? "un" : ""); + return !IsFree; +} + +#define endof(Class, Field) (offsetof(Class, Field) + sizeof(Class::Field)) + +void ExplainOutputStyle::explainPdbSuperBlockOffset() { + P.formatLine("This corresponds to offset {0} of the MSF super block, ", + pdbBlockOffset()); + if (pdbBlockOffset() < endof(SuperBlock, MagicBytes)) + P.printLine("which is part of the MSF file magic."); + else if (pdbBlockOffset() < endof(SuperBlock, BlockSize)) { + P.printLine("which contains the block size of the file."); + P.formatLine("The current value is {0}.", + uint32_t(File.pdb().getMsfLayout().SB->BlockSize)); + } else if (pdbBlockOffset() < endof(SuperBlock, FreeBlockMapBlock)) { + P.printLine("which contains the index of the FPM block (e.g. 1 or 2)."); + P.formatLine("The current value is {0}.", + uint32_t(File.pdb().getMsfLayout().SB->FreeBlockMapBlock)); + } else if (pdbBlockOffset() < endof(SuperBlock, NumBlocks)) { + P.printLine("which contains the number of blocks in the file."); + P.formatLine("The current value is {0}.", + uint32_t(File.pdb().getMsfLayout().SB->NumBlocks)); + } else if (pdbBlockOffset() < endof(SuperBlock, NumDirectoryBytes)) { + P.printLine("which contains the number of bytes in the stream directory."); + P.formatLine("The current value is {0}.", + uint32_t(File.pdb().getMsfLayout().SB->NumDirectoryBytes)); + } else if (pdbBlockOffset() < endof(SuperBlock, Unknown1)) { + P.printLine("whose purpose is unknown."); + P.formatLine("The current value is {0}.", + uint32_t(File.pdb().getMsfLayout().SB->Unknown1)); + } else if (pdbBlockOffset() < endof(SuperBlock, BlockMapAddr)) { + P.printLine("which contains the file offset of the block map."); + P.formatLine("The current value is {0}.", + uint32_t(File.pdb().getMsfLayout().SB->BlockMapAddr)); + } else { + assert(pdbBlockOffset() > sizeof(SuperBlock)); + P.printLine( + "which is outside the range of valid data for the super block."); + } +} + +static std::string toBinaryString(uint8_t Byte) { + char Result[9] = {0}; + for (int I = 0; I < 8; ++I) { + char C = (Byte & 1) ? '1' : '0'; + Result[I] = C; + Byte >>= 1; + } + return std::string(Result); +} + +void ExplainOutputStyle::explainPdbFpmBlockOffset() { + const MSFLayout &Layout = File.pdb().getMsfLayout(); + uint32_t MainFpm = Layout.mainFpmBlock(); + uint32_t AltFpm = Layout.alternateFpmBlock(); + + assert(isPdbFpmBlock()); + uint32_t Fpm = isPdbFpm1() ? 1 : 2; + uint32_t FpmChunk = pdbBlockIndex() / File.pdb().getBlockSize(); + assert((Fpm == MainFpm) || (Fpm == AltFpm)); + (void)AltFpm; + bool IsMain = (Fpm == MainFpm); + P.formatLine("Address is in FPM{0} ({1} FPM)", Fpm, IsMain ? "Main" : "Alt"); + uint32_t DescribedBlockStart = + 8 * (FpmChunk * File.pdb().getBlockSize() + pdbBlockOffset()); + if (DescribedBlockStart > File.pdb().getBlockCount()) { + P.printLine("Address is in extraneous FPM space."); + return; + } + + P.formatLine("Address describes the allocation status of blocks [{0},{1})", + DescribedBlockStart, DescribedBlockStart + 8); + ArrayRef<uint8_t> Bytes; + cantFail(File.pdb().getMsfBuffer().readBytes(FileOffset, 1, Bytes)); + P.formatLine("Status = {0} (Note: 0 = allocated, 1 = free)", + toBinaryString(Bytes[0])); +} + +void ExplainOutputStyle::explainPdbBlockMapOffset() { + uint64_t BlockMapOffset = File.pdb().getBlockMapOffset(); + uint32_t OffsetInBlock = FileOffset - BlockMapOffset; + P.formatLine("Address is at offset {0} of the directory block list", + OffsetInBlock); +} + +static uint32_t getOffsetInStream(ArrayRef<support::ulittle32_t> StreamBlocks, + uint64_t FileOffset, uint32_t BlockSize) { + uint32_t BlockIndex = FileOffset / BlockSize; + uint32_t OffsetInBlock = FileOffset - BlockIndex * BlockSize; + + auto Iter = llvm::find(StreamBlocks, BlockIndex); + assert(Iter != StreamBlocks.end()); + uint32_t StreamBlockIndex = std::distance(StreamBlocks.begin(), Iter); + return StreamBlockIndex * BlockSize + OffsetInBlock; +} + +void ExplainOutputStyle::explainPdbStreamOffset(uint32_t Stream) { + SmallVector<StreamInfo, 12> Streams; + discoverStreamPurposes(File.pdb(), Streams); + + assert(Stream <= Streams.size()); + const StreamInfo &S = Streams[Stream]; + const auto &Layout = File.pdb().getStreamLayout(Stream); + uint32_t StreamOff = + getOffsetInStream(Layout.Blocks, FileOffset, File.pdb().getBlockSize()); + P.formatLine("Address is at offset {0}/{1} of Stream {2} ({3}){4}.", + StreamOff, Layout.Length, Stream, S.getLongName(), + (StreamOff > Layout.Length) ? " in unused space" : ""); + switch (S.getPurpose()) { + case StreamPurpose::DBI: { + DbiStream &Dbi = cantFail(File.pdb().getPDBDbiStream()); + explainStreamOffset(Dbi, StreamOff); + break; + } + case StreamPurpose::PDB: { + InfoStream &Info = cantFail(File.pdb().getPDBInfoStream()); + explainStreamOffset(Info, StreamOff); + break; + } + case StreamPurpose::IPI: + case StreamPurpose::TPI: + case StreamPurpose::ModuleStream: + case StreamPurpose::NamedStream: + default: + break; + } +} + +void ExplainOutputStyle::explainPdbStreamDirectoryOffset() { + auto DirectoryBlocks = File.pdb().getDirectoryBlockArray(); + const auto &Layout = File.pdb().getMsfLayout(); + uint32_t StreamOff = + getOffsetInStream(DirectoryBlocks, FileOffset, File.pdb().getBlockSize()); + P.formatLine("Address is at offset {0}/{1} of Stream Directory{2}.", + StreamOff, uint32_t(Layout.SB->NumDirectoryBytes), + uint32_t(StreamOff > Layout.SB->NumDirectoryBytes) + ? " in unused space" + : ""); +} + +void ExplainOutputStyle::explainPdbUnknownBlock() { + P.formatLine("Address has unknown purpose."); +} + +template <typename T> +static void printStructField(LinePrinter &P, StringRef Label, T Value) { + P.formatLine("which contains {0}.", Label); + P.formatLine("The current value is {0}.", Value); +} + +static void explainDbiHeaderOffset(LinePrinter &P, DbiStream &Dbi, + uint32_t Offset) { + const DbiStreamHeader *Header = Dbi.getHeader(); + assert(Header != nullptr); + + if (Offset < endof(DbiStreamHeader, VersionSignature)) + printStructField(P, "the DBI Stream Version Signature", + int32_t(Header->VersionSignature)); + else if (Offset < endof(DbiStreamHeader, VersionHeader)) + printStructField(P, "the DBI Stream Version Header", + uint32_t(Header->VersionHeader)); + else if (Offset < endof(DbiStreamHeader, Age)) + printStructField(P, "the age of the DBI Stream", uint32_t(Header->Age)); + else if (Offset < endof(DbiStreamHeader, GlobalSymbolStreamIndex)) + printStructField(P, "the index of the Global Symbol Stream", + uint16_t(Header->GlobalSymbolStreamIndex)); + else if (Offset < endof(DbiStreamHeader, BuildNumber)) + printStructField(P, "the build number", uint16_t(Header->BuildNumber)); + else if (Offset < endof(DbiStreamHeader, PublicSymbolStreamIndex)) + printStructField(P, "the index of the Public Symbol Stream", + uint16_t(Header->PublicSymbolStreamIndex)); + else if (Offset < endof(DbiStreamHeader, PdbDllVersion)) + printStructField(P, "the version of mspdb.dll", + uint16_t(Header->PdbDllVersion)); + else if (Offset < endof(DbiStreamHeader, SymRecordStreamIndex)) + printStructField(P, "the index of the Symbol Record Stream", + uint16_t(Header->SymRecordStreamIndex)); + else if (Offset < endof(DbiStreamHeader, PdbDllRbld)) + printStructField(P, "the rbld of mspdb.dll", uint16_t(Header->PdbDllRbld)); + else if (Offset < endof(DbiStreamHeader, ModiSubstreamSize)) + printStructField(P, "the size of the Module Info Substream", + int32_t(Header->ModiSubstreamSize)); + else if (Offset < endof(DbiStreamHeader, SecContrSubstreamSize)) + printStructField(P, "the size of the Section Contribution Substream", + int32_t(Header->SecContrSubstreamSize)); + else if (Offset < endof(DbiStreamHeader, SectionMapSize)) + printStructField(P, "the size of the Section Map Substream", + int32_t(Header->SectionMapSize)); + else if (Offset < endof(DbiStreamHeader, FileInfoSize)) + printStructField(P, "the size of the File Info Substream", + int32_t(Header->FileInfoSize)); + else if (Offset < endof(DbiStreamHeader, TypeServerSize)) + printStructField(P, "the size of the Type Server Map", + int32_t(Header->TypeServerSize)); + else if (Offset < endof(DbiStreamHeader, MFCTypeServerIndex)) + printStructField(P, "the index of the MFC Type Server stream", + uint32_t(Header->MFCTypeServerIndex)); + else if (Offset < endof(DbiStreamHeader, OptionalDbgHdrSize)) + printStructField(P, "the size of the Optional Debug Stream array", + int32_t(Header->OptionalDbgHdrSize)); + else if (Offset < endof(DbiStreamHeader, ECSubstreamSize)) + printStructField(P, "the size of the Edit & Continue Substream", + int32_t(Header->ECSubstreamSize)); + else if (Offset < endof(DbiStreamHeader, Flags)) + printStructField(P, "the DBI Stream flags", uint16_t(Header->Flags)); + else if (Offset < endof(DbiStreamHeader, MachineType)) + printStructField(P, "the machine type", uint16_t(Header->MachineType)); + else if (Offset < endof(DbiStreamHeader, Reserved)) + printStructField(P, "reserved data", uint32_t(Header->Reserved)); +} + +static void explainDbiModiSubstreamOffset(LinePrinter &P, DbiStream &Dbi, + uint32_t Offset) { + VarStreamArray<DbiModuleDescriptor> ModuleDescriptors; + BinaryStreamRef ModiSubstreamData = Dbi.getModiSubstreamData().StreamData; + BinaryStreamReader Reader(ModiSubstreamData); + + cantFail(Reader.readArray(ModuleDescriptors, ModiSubstreamData.getLength())); + auto Prev = ModuleDescriptors.begin(); + assert(Prev.offset() == 0); + auto Current = Prev; + uint32_t Index = 0; + while (true) { + Prev = Current; + ++Current; + if (Current == ModuleDescriptors.end() || Offset < Current.offset()) + break; + ++Index; + } + + DbiModuleDescriptor &Descriptor = *Prev; + P.formatLine("which contains the descriptor for module {0} ({1}).", Index, + Descriptor.getModuleName()); +} + +template <typename T> +static void dontExplain(LinePrinter &Printer, T &Stream, uint32_t Offset) {} + +template <typename T, typename SubstreamRangeT> +static void explainSubstreamOffset(LinePrinter &P, uint32_t OffsetInStream, + T &Stream, + const SubstreamRangeT &Substreams) { + uint32_t SubOffset = OffsetInStream; + for (const auto &Entry : Substreams) { + if (Entry.Size <= 0) + continue; + uint32_t S = static_cast<uint32_t>(Entry.Size); + if (SubOffset < S) { + P.formatLine("address is at offset {0}/{1} of the {2}.", SubOffset, S, + Entry.Label); + Entry.Explain(P, Stream, SubOffset); + return; + } + SubOffset -= S; + } +} + +void ExplainOutputStyle::explainStreamOffset(DbiStream &Dbi, + uint32_t OffsetInStream) { + P.printLine("Within the DBI stream:"); + AutoIndent Indent(P); + const DbiStreamHeader *Header = Dbi.getHeader(); + assert(Header != nullptr); + + struct SubstreamInfo { + int32_t Size; + StringRef Label; + void (*Explain)(LinePrinter &, DbiStream &, uint32_t); + } Substreams[] = { + {sizeof(DbiStreamHeader), "DBI Stream Header", explainDbiHeaderOffset}, + {int32_t(Header->ModiSubstreamSize), "Module Info Substream", + explainDbiModiSubstreamOffset}, + {int32_t(Header->SecContrSubstreamSize), "Section Contribution Substream", + dontExplain<DbiStream>}, + {int32_t(Header->SectionMapSize), "Section Map", dontExplain<DbiStream>}, + {int32_t(Header->FileInfoSize), "File Info Substream", + dontExplain<DbiStream>}, + {int32_t(Header->TypeServerSize), "Type Server Map Substream", + dontExplain<DbiStream>}, + {int32_t(Header->ECSubstreamSize), "Edit & Continue Substream", + dontExplain<DbiStream>}, + {int32_t(Header->OptionalDbgHdrSize), "Optional Debug Stream Array", + dontExplain<DbiStream>}, + }; + + explainSubstreamOffset(P, OffsetInStream, Dbi, Substreams); +} + +static void explainPdbStreamHeaderOffset(LinePrinter &P, InfoStream &Info, + uint32_t Offset) { + const InfoStreamHeader *Header = Info.getHeader(); + assert(Header != nullptr); + + if (Offset < endof(InfoStreamHeader, Version)) + printStructField(P, "the PDB Stream Version Signature", + uint32_t(Header->Version)); + else if (Offset < endof(InfoStreamHeader, Signature)) + printStructField(P, "the signature of the PDB Stream", + uint32_t(Header->Signature)); + else if (Offset < endof(InfoStreamHeader, Age)) + printStructField(P, "the age of the PDB", uint32_t(Header->Age)); + else if (Offset < endof(InfoStreamHeader, Guid)) + printStructField(P, "the guid of the PDB", fmt_guid(Header->Guid.Guid)); +} + +void ExplainOutputStyle::explainStreamOffset(InfoStream &Info, + uint32_t OffsetInStream) { + P.printLine("Within the PDB stream:"); + AutoIndent Indent(P); + + struct SubstreamInfo { + uint32_t Size; + StringRef Label; + void (*Explain)(LinePrinter &, InfoStream &, uint32_t); + } Substreams[] = {{sizeof(InfoStreamHeader), "PDB Stream Header", + explainPdbStreamHeaderOffset}, + {Info.getNamedStreamMapByteSize(), "Named Stream Map", + dontExplain<InfoStream>}, + {Info.getStreamSize(), "PDB Feature Signatures", + dontExplain<InfoStream>}}; + + explainSubstreamOffset(P, OffsetInStream, Info, Substreams); +} diff --git a/contrib/libs/llvm12/tools/llvm-pdbutil/ExplainOutputStyle.h b/contrib/libs/llvm12/tools/llvm-pdbutil/ExplainOutputStyle.h new file mode 100644 index 0000000000..f405cf615e --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-pdbutil/ExplainOutputStyle.h @@ -0,0 +1,67 @@ +//===- ExplainOutputStyle.h ----------------------------------- *- C++ --*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMPDBDUMP_EXPLAINOUTPUTSTYLE_H +#define LLVM_TOOLS_LLVMPDBDUMP_EXPLAINOUTPUTSTYLE_H + +#include "LinePrinter.h" +#include "OutputStyle.h" + +#include <string> + +namespace llvm { + +namespace pdb { + +class DbiStream; +class InfoStream; +class InputFile; + +class ExplainOutputStyle : public OutputStyle { + +public: + ExplainOutputStyle(InputFile &File, uint64_t FileOffset); + + Error dump() override; + +private: + Error explainPdbFile(); + Error explainBinaryFile(); + + bool explainPdbBlockStatus(); + + bool isPdbFpm1() const; + bool isPdbFpm2() const; + + bool isPdbSuperBlock() const; + bool isPdbFpmBlock() const; + bool isPdbBlockMapBlock() const; + bool isPdbStreamDirectoryBlock() const; + Optional<uint32_t> getPdbBlockStreamIndex() const; + + void explainPdbSuperBlockOffset(); + void explainPdbFpmBlockOffset(); + void explainPdbBlockMapOffset(); + void explainPdbStreamDirectoryOffset(); + void explainPdbStreamOffset(uint32_t Stream); + void explainPdbUnknownBlock(); + + void explainStreamOffset(DbiStream &Stream, uint32_t OffsetInStream); + void explainStreamOffset(InfoStream &Stream, uint32_t OffsetInStream); + + uint32_t pdbBlockIndex() const; + uint32_t pdbBlockOffset() const; + + InputFile &File; + const uint64_t FileOffset; + LinePrinter P; +}; +} // namespace pdb +} // namespace llvm + +#endif diff --git a/contrib/libs/llvm12/tools/llvm-pdbutil/FormatUtil.cpp b/contrib/libs/llvm12/tools/llvm-pdbutil/FormatUtil.cpp new file mode 100644 index 0000000000..b4837398f1 --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-pdbutil/FormatUtil.cpp @@ -0,0 +1,258 @@ +//===- FormatUtil.cpp ----------------------------------------- *- C++ --*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "FormatUtil.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/BinaryFormat/COFF.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/Support/FormatAdapters.h" +#include "llvm/Support/FormatVariadic.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +std::string llvm::pdb::truncateStringBack(StringRef S, uint32_t MaxLen) { + if (MaxLen == 0 || S.size() <= MaxLen || S.size() <= 3) + return std::string(S); + + assert(MaxLen >= 3); + uint32_t FinalLen = std::min<size_t>(S.size(), MaxLen - 3); + S = S.take_front(FinalLen); + return std::string(S) + std::string("..."); +} + +std::string llvm::pdb::truncateStringMiddle(StringRef S, uint32_t MaxLen) { + if (MaxLen == 0 || S.size() <= MaxLen || S.size() <= 3) + return std::string(S); + + assert(MaxLen >= 3); + uint32_t FinalLen = std::min<size_t>(S.size(), MaxLen - 3); + StringRef Front = S.take_front(FinalLen / 2); + StringRef Back = S.take_back(Front.size()); + return std::string(Front) + std::string("...") + std::string(Back); +} + +std::string llvm::pdb::truncateStringFront(StringRef S, uint32_t MaxLen) { + if (MaxLen == 0 || S.size() <= MaxLen || S.size() <= 3) + return std::string(S); + + assert(MaxLen >= 3); + S = S.take_back(MaxLen - 3); + return std::string("...") + std::string(S); +} + +std::string llvm::pdb::truncateQuotedNameFront(StringRef Label, StringRef Name, + uint32_t MaxLen) { + uint32_t RequiredExtraChars = Label.size() + 1 + 2; + if (MaxLen == 0 || RequiredExtraChars + Name.size() <= MaxLen) + return formatv("{0} \"{1}\"", Label, Name).str(); + + assert(MaxLen >= RequiredExtraChars); + std::string TN = truncateStringFront(Name, MaxLen - RequiredExtraChars); + return formatv("{0} \"{1}\"", Label, TN).str(); +} + +std::string llvm::pdb::truncateQuotedNameBack(StringRef Label, StringRef Name, + uint32_t MaxLen) { + uint32_t RequiredExtraChars = Label.size() + 1 + 2; + if (MaxLen == 0 || RequiredExtraChars + Name.size() <= MaxLen) + return formatv("{0} \"{1}\"", Label, Name).str(); + + assert(MaxLen >= RequiredExtraChars); + std::string TN = truncateStringBack(Name, MaxLen - RequiredExtraChars); + return formatv("{0} \"{1}\"", Label, TN).str(); +} + +std::string llvm::pdb::typesetItemList(ArrayRef<std::string> Opts, + uint32_t IndentLevel, uint32_t GroupSize, + StringRef Sep) { + std::string Result; + while (!Opts.empty()) { + ArrayRef<std::string> ThisGroup; + ThisGroup = Opts.take_front(GroupSize); + Opts = Opts.drop_front(ThisGroup.size()); + Result += join(ThisGroup, Sep); + if (!Opts.empty()) { + Result += Sep; + Result += "\n"; + Result += std::string(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 += std::string(formatv("\n{0}{1}", fmt_repeat(' ', IndentLevel), S)); + } + Result += "]"; + return Result; +} + +std::string llvm::pdb::formatChunkKind(DebugSubsectionKind Kind, + bool Friendly) { + if (Friendly) { + switch (Kind) { + RETURN_CASE(DebugSubsectionKind, None, "none"); + RETURN_CASE(DebugSubsectionKind, Symbols, "symbols"); + RETURN_CASE(DebugSubsectionKind, Lines, "lines"); + RETURN_CASE(DebugSubsectionKind, StringTable, "strings"); + RETURN_CASE(DebugSubsectionKind, FileChecksums, "checksums"); + RETURN_CASE(DebugSubsectionKind, FrameData, "frames"); + RETURN_CASE(DebugSubsectionKind, InlineeLines, "inlinee lines"); + RETURN_CASE(DebugSubsectionKind, CrossScopeImports, "xmi"); + RETURN_CASE(DebugSubsectionKind, CrossScopeExports, "xme"); + RETURN_CASE(DebugSubsectionKind, ILLines, "il lines"); + RETURN_CASE(DebugSubsectionKind, FuncMDTokenMap, "func md token map"); + RETURN_CASE(DebugSubsectionKind, TypeMDTokenMap, "type md token map"); + RETURN_CASE(DebugSubsectionKind, MergedAssemblyInput, + "merged assembly input"); + RETURN_CASE(DebugSubsectionKind, CoffSymbolRVA, "coff symbol rva"); + } + } else { + switch (Kind) { + RETURN_CASE(DebugSubsectionKind, None, "none"); + RETURN_CASE(DebugSubsectionKind, Symbols, "DEBUG_S_SYMBOLS"); + RETURN_CASE(DebugSubsectionKind, Lines, "DEBUG_S_LINES"); + RETURN_CASE(DebugSubsectionKind, StringTable, "DEBUG_S_STRINGTABLE"); + RETURN_CASE(DebugSubsectionKind, FileChecksums, "DEBUG_S_FILECHKSMS"); + RETURN_CASE(DebugSubsectionKind, FrameData, "DEBUG_S_FRAMEDATA"); + RETURN_CASE(DebugSubsectionKind, InlineeLines, "DEBUG_S_INLINEELINES"); + RETURN_CASE(DebugSubsectionKind, CrossScopeImports, + "DEBUG_S_CROSSSCOPEIMPORTS"); + RETURN_CASE(DebugSubsectionKind, CrossScopeExports, + "DEBUG_S_CROSSSCOPEEXPORTS"); + RETURN_CASE(DebugSubsectionKind, ILLines, "DEBUG_S_IL_LINES"); + RETURN_CASE(DebugSubsectionKind, FuncMDTokenMap, + "DEBUG_S_FUNC_MDTOKEN_MAP"); + RETURN_CASE(DebugSubsectionKind, TypeMDTokenMap, + "DEBUG_S_TYPE_MDTOKEN_MAP"); + RETURN_CASE(DebugSubsectionKind, MergedAssemblyInput, + "DEBUG_S_MERGED_ASSEMBLYINPUT"); + RETURN_CASE(DebugSubsectionKind, CoffSymbolRVA, + "DEBUG_S_COFF_SYMBOL_RVA"); + } + } + return formatUnknownEnum(Kind); +} + +std::string llvm::pdb::formatSymbolKind(SymbolKind K) { + switch (uint32_t(K)) { +#define SYMBOL_RECORD(EnumName, value, name) \ + case EnumName: \ + return #EnumName; +#define CV_SYMBOL(EnumName, value) SYMBOL_RECORD(EnumName, value, EnumName) +#include "llvm/DebugInfo/CodeView/CodeViewSymbols.def" + } + return formatUnknownEnum(K); +} + +std::string llvm::pdb::formatTypeLeafKind(TypeLeafKind K) { + switch (K) { +#define TYPE_RECORD(EnumName, value, name) \ + case EnumName: \ + return #EnumName; +#include "llvm/DebugInfo/CodeView/CodeViewTypes.def" + default: + return formatv("UNKNOWN RECORD ({0:X})", + static_cast<std::underlying_type_t<TypeLeafKind>>(K)) + .str(); + } +} + +std::string llvm::pdb::formatSegmentOffset(uint16_t Segment, uint32_t Offset) { + return std::string(formatv("{0:4}:{1:4}", Segment, Offset)); +} + +#define PUSH_CHARACTERISTIC_FLAG(Enum, TheOpt, Value, Style, Descriptive) \ + PUSH_FLAG(Enum, TheOpt, Value, \ + ((Style == CharacteristicStyle::HeaderDefinition) ? #TheOpt \ + : Descriptive)) + +#define PUSH_MASKED_CHARACTERISTIC_FLAG(Enum, Mask, TheOpt, Value, Style, \ + Descriptive) \ + PUSH_MASKED_FLAG(Enum, Mask, TheOpt, Value, \ + ((Style == CharacteristicStyle::HeaderDefinition) \ + ? #TheOpt \ + : Descriptive)) + +std::string llvm::pdb::formatSectionCharacteristics(uint32_t IndentLevel, + uint32_t C, + uint32_t FlagsPerLine, + StringRef Separator, + CharacteristicStyle Style) { + using SC = COFF::SectionCharacteristics; + std::vector<std::string> Opts; + if (C == COFF::SC_Invalid) + return "invalid"; + if (C == 0) + return "none"; + PUSH_CHARACTERISTIC_FLAG(SC, IMAGE_SCN_TYPE_NOLOAD, C, Style, "noload"); + PUSH_CHARACTERISTIC_FLAG(SC, IMAGE_SCN_TYPE_NO_PAD, C, Style, "no padding"); + PUSH_CHARACTERISTIC_FLAG(SC, IMAGE_SCN_CNT_CODE, C, Style, "code"); + PUSH_CHARACTERISTIC_FLAG(SC, IMAGE_SCN_CNT_INITIALIZED_DATA, C, Style, + "initialized data"); + PUSH_CHARACTERISTIC_FLAG(SC, IMAGE_SCN_CNT_UNINITIALIZED_DATA, C, Style, + "uninitialized data"); + PUSH_CHARACTERISTIC_FLAG(SC, IMAGE_SCN_LNK_OTHER, C, Style, "other"); + PUSH_CHARACTERISTIC_FLAG(SC, IMAGE_SCN_LNK_INFO, C, Style, "info"); + PUSH_CHARACTERISTIC_FLAG(SC, IMAGE_SCN_LNK_REMOVE, C, Style, "remove"); + PUSH_CHARACTERISTIC_FLAG(SC, IMAGE_SCN_LNK_COMDAT, C, Style, "comdat"); + PUSH_CHARACTERISTIC_FLAG(SC, IMAGE_SCN_GPREL, C, Style, "gp rel"); + PUSH_CHARACTERISTIC_FLAG(SC, IMAGE_SCN_MEM_PURGEABLE, C, Style, "purgeable"); + PUSH_CHARACTERISTIC_FLAG(SC, IMAGE_SCN_MEM_16BIT, C, Style, "16-bit"); + PUSH_CHARACTERISTIC_FLAG(SC, IMAGE_SCN_MEM_LOCKED, C, Style, "locked"); + PUSH_CHARACTERISTIC_FLAG(SC, IMAGE_SCN_MEM_PRELOAD, C, Style, "preload"); + PUSH_MASKED_CHARACTERISTIC_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_1BYTES, C, + Style, "1 byte align"); + PUSH_MASKED_CHARACTERISTIC_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_2BYTES, C, + Style, "2 byte align"); + PUSH_MASKED_CHARACTERISTIC_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_4BYTES, C, + Style, "4 byte align"); + PUSH_MASKED_CHARACTERISTIC_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_8BYTES, C, + Style, "8 byte align"); + PUSH_MASKED_CHARACTERISTIC_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_16BYTES, C, + Style, "16 byte align"); + PUSH_MASKED_CHARACTERISTIC_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_32BYTES, C, + Style, "32 byte align"); + PUSH_MASKED_CHARACTERISTIC_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_64BYTES, C, + Style, "64 byte align"); + PUSH_MASKED_CHARACTERISTIC_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_128BYTES, C, + Style, "128 byte align"); + PUSH_MASKED_CHARACTERISTIC_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_256BYTES, C, + Style, "256 byte align"); + PUSH_MASKED_CHARACTERISTIC_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_512BYTES, C, + Style, "512 byte align"); + PUSH_MASKED_CHARACTERISTIC_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_1024BYTES, C, + Style, "1024 byte align"); + PUSH_MASKED_CHARACTERISTIC_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_2048BYTES, C, + Style, "2048 byte align"); + PUSH_MASKED_CHARACTERISTIC_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_4096BYTES, C, + Style, "4096 byte align"); + PUSH_MASKED_CHARACTERISTIC_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_8192BYTES, C, + Style, "8192 byte align"); + PUSH_CHARACTERISTIC_FLAG(SC, IMAGE_SCN_LNK_NRELOC_OVFL, C, Style, + "noreloc overflow"); + PUSH_CHARACTERISTIC_FLAG(SC, IMAGE_SCN_MEM_DISCARDABLE, C, Style, + "discardable"); + PUSH_CHARACTERISTIC_FLAG(SC, IMAGE_SCN_MEM_NOT_CACHED, C, Style, + "not cached"); + PUSH_CHARACTERISTIC_FLAG(SC, IMAGE_SCN_MEM_NOT_PAGED, C, Style, "not paged"); + PUSH_CHARACTERISTIC_FLAG(SC, IMAGE_SCN_MEM_SHARED, C, Style, "shared"); + PUSH_CHARACTERISTIC_FLAG(SC, IMAGE_SCN_MEM_EXECUTE, C, Style, + "execute permissions"); + PUSH_CHARACTERISTIC_FLAG(SC, IMAGE_SCN_MEM_READ, C, Style, + "read permissions"); + PUSH_CHARACTERISTIC_FLAG(SC, IMAGE_SCN_MEM_WRITE, C, Style, + "write permissions"); + return typesetItemList(Opts, IndentLevel, FlagsPerLine, Separator); +} diff --git a/contrib/libs/llvm12/tools/llvm-pdbutil/FormatUtil.h b/contrib/libs/llvm12/tools/llvm-pdbutil/FormatUtil.h new file mode 100644 index 0000000000..b99ccec215 --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-pdbutil/FormatUtil.h @@ -0,0 +1,141 @@ +//===- FormatUtil.h ------------------------------------------- *- C++ --*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#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/DebugInfo/CodeView/CodeView.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/FormatAdapters.h" +#include "llvm/Support/FormatVariadic.h" + +#include <string> +#include <type_traits> + +namespace llvm { +namespace pdb { + +std::string truncateStringBack(StringRef S, uint32_t MaxLen); +std::string truncateStringMiddle(StringRef S, uint32_t MaxLen); +std::string truncateStringFront(StringRef S, uint32_t MaxLen); +std::string truncateQuotedNameFront(StringRef Label, StringRef Name, + uint32_t MaxLen); +std::string truncateQuotedNameBack(StringRef Label, StringRef Name, + uint32_t MaxLen); + +#define PUSH_MASKED_FLAG(Enum, Mask, TheOpt, Value, Text) \ + if (Enum::TheOpt == (Value & Mask)) \ + Opts.push_back(Text); + +#define PUSH_FLAG(Enum, TheOpt, Value, Text) \ + PUSH_MASKED_FLAG(Enum, Enum::TheOpt, TheOpt, Value, Text) + +#define RETURN_CASE(Enum, X, Ret) \ + case Enum::X: \ + return Ret; + +template <typename T> std::string formatUnknownEnum(T Value) { + return formatv("unknown ({0})", static_cast<std::underlying_type_t<T>>(Value)) + .str(); +} + +std::string formatSegmentOffset(uint16_t Segment, uint32_t Offset); + +enum class CharacteristicStyle { + HeaderDefinition, // format as windows header definition + Descriptive, // format as human readable words +}; +std::string formatSectionCharacteristics( + uint32_t IndentLevel, uint32_t C, uint32_t FlagsPerLine, + StringRef Separator, + CharacteristicStyle Style = CharacteristicStyle::HeaderDefinition); + +std::string typesetItemList(ArrayRef<std::string> Opts, uint32_t IndentLevel, + uint32_t GroupSize, StringRef Sep); + +std::string typesetStringList(uint32_t IndentLevel, + ArrayRef<StringRef> Strings); + +std::string formatChunkKind(codeview::DebugSubsectionKind Kind, + bool Friendly = true); +std::string formatSymbolKind(codeview::SymbolKind K); +std::string formatTypeLeafKind(codeview::TypeLeafKind K); + +/// Returns the number of digits in the given integer. +inline int NumDigits(uint64_t N) { + if (N < 10ULL) + return 1; + if (N < 100ULL) + return 2; + if (N < 1000ULL) + return 3; + if (N < 10000ULL) + return 4; + if (N < 100000ULL) + return 5; + if (N < 1000000ULL) + return 6; + if (N < 10000000ULL) + return 7; + if (N < 100000000ULL) + return 8; + if (N < 1000000000ULL) + return 9; + if (N < 10000000000ULL) + return 10; + if (N < 100000000000ULL) + return 11; + if (N < 1000000000000ULL) + return 12; + if (N < 10000000000000ULL) + return 13; + if (N < 100000000000000ULL) + return 14; + if (N < 1000000000000000ULL) + return 15; + if (N < 10000000000000000ULL) + return 16; + if (N < 100000000000000000ULL) + return 17; + if (N < 1000000000000000000ULL) + return 18; + if (N < 10000000000000000000ULL) + return 19; + return 20; +} + +namespace detail { +template <typename T> +struct EndianAdapter final + : public FormatAdapter<support::detail::packed_endian_specific_integral< + T, support::little, support::unaligned>> { + using EndianType = + support::detail::packed_endian_specific_integral<T, support::little, + support::unaligned>; + + explicit EndianAdapter(EndianType &&Item) + : FormatAdapter<EndianType>(std::move(Item)) {} + + void format(llvm::raw_ostream &Stream, StringRef Style) override { + format_provider<T>::format(static_cast<T>(this->Item), Stream, Style); + } +}; +} // namespace detail + +template <typename T> +detail::EndianAdapter<T> +fmtle(support::detail::packed_endian_specific_integral<T, support::little, + support::unaligned> + Value) { + return detail::EndianAdapter<T>(std::move(Value)); +} +} +} // namespace llvm +#endif diff --git a/contrib/libs/llvm12/tools/llvm-pdbutil/InputFile.cpp b/contrib/libs/llvm12/tools/llvm-pdbutil/InputFile.cpp new file mode 100644 index 0000000000..b316882de6 --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-pdbutil/InputFile.cpp @@ -0,0 +1,509 @@ +//===- InputFile.cpp ------------------------------------------ *- C++ --*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "InputFile.h" + +#include "FormatUtil.h" +#include "LinePrinter.h" + +#include "llvm/BinaryFormat/Magic.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" +#include "llvm/DebugInfo/CodeView/StringsAndChecksums.h" +#include "llvm/DebugInfo/PDB/Native/DbiStream.h" +#include "llvm/DebugInfo/PDB/Native/NativeSession.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/PDBStringTable.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/DebugInfo/PDB/Native/TpiStream.h" +#include "llvm/DebugInfo/PDB/PDB.h" +#include "llvm/Object/COFF.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/FormatVariadic.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::object; +using namespace llvm::pdb; + +InputFile::InputFile() {} +InputFile::~InputFile() {} + +static Expected<ModuleDebugStreamRef> +getModuleDebugStream(PDBFile &File, StringRef &ModuleName, uint32_t Index) { + ExitOnError Err("Unexpected error: "); + + auto &Dbi = Err(File.getPDBDbiStream()); + const auto &Modules = Dbi.modules(); + if (Index >= Modules.getModuleCount()) + return make_error<RawError>(raw_error_code::index_out_of_bounds, + "Invalid module index"); + + auto Modi = Modules.getModuleDescriptor(Index); + + ModuleName = Modi.getModuleName(); + + uint16_t ModiStream = Modi.getModuleStreamIndex(); + if (ModiStream == kInvalidStreamIndex) + return make_error<RawError>(raw_error_code::no_stream, + "Module stream not present"); + + auto ModStreamData = File.createIndexedStream(ModiStream); + + ModuleDebugStreamRef ModS(Modi, std::move(ModStreamData)); + if (auto EC = ModS.reload()) + return make_error<RawError>(raw_error_code::corrupt_file, + "Invalid module stream"); + + return std::move(ModS); +} + +static inline bool isCodeViewDebugSubsection(object::SectionRef Section, + StringRef Name, + BinaryStreamReader &Reader) { + if (Expected<StringRef> NameOrErr = Section.getName()) { + if (*NameOrErr != Name) + return false; + } else { + consumeError(NameOrErr.takeError()); + return false; + } + + Expected<StringRef> ContentsOrErr = Section.getContents(); + if (!ContentsOrErr) { + consumeError(ContentsOrErr.takeError()); + return false; + } + + Reader = BinaryStreamReader(*ContentsOrErr, support::little); + uint32_t Magic; + if (Reader.bytesRemaining() < sizeof(uint32_t)) + return false; + cantFail(Reader.readInteger(Magic)); + if (Magic != COFF::DEBUG_SECTION_MAGIC) + return false; + return true; +} + +static inline bool isDebugSSection(object::SectionRef Section, + DebugSubsectionArray &Subsections) { + BinaryStreamReader Reader; + if (!isCodeViewDebugSubsection(Section, ".debug$S", Reader)) + return false; + + cantFail(Reader.readArray(Subsections, Reader.bytesRemaining())); + return true; +} + +static bool isDebugTSection(SectionRef Section, CVTypeArray &Types) { + BinaryStreamReader Reader; + if (!isCodeViewDebugSubsection(Section, ".debug$T", Reader) && + !isCodeViewDebugSubsection(Section, ".debug$P", Reader)) + return false; + cantFail(Reader.readArray(Types, Reader.bytesRemaining())); + return true; +} + +static std::string formatChecksumKind(FileChecksumKind Kind) { + switch (Kind) { + RETURN_CASE(FileChecksumKind, None, "None"); + RETURN_CASE(FileChecksumKind, MD5, "MD5"); + RETURN_CASE(FileChecksumKind, SHA1, "SHA-1"); + RETURN_CASE(FileChecksumKind, SHA256, "SHA-256"); + } + return formatUnknownEnum(Kind); +} + +template <typename... Args> +static void formatInternal(LinePrinter &Printer, bool Append, Args &&... args) { + if (Append) + Printer.format(std::forward<Args>(args)...); + else + Printer.formatLine(std::forward<Args>(args)...); +} + +SymbolGroup::SymbolGroup(InputFile *File, uint32_t GroupIndex) : File(File) { + if (!File) + return; + + if (File->isPdb()) + initializeForPdb(GroupIndex); + else { + Name = ".debug$S"; + uint32_t I = 0; + for (const auto &S : File->obj().sections()) { + DebugSubsectionArray SS; + if (!isDebugSSection(S, SS)) + continue; + + if (!SC.hasChecksums() || !SC.hasStrings()) + SC.initialize(SS); + + if (I == GroupIndex) + Subsections = SS; + + if (SC.hasChecksums() && SC.hasStrings()) + break; + } + rebuildChecksumMap(); + } +} + +StringRef SymbolGroup::name() const { return Name; } + +void SymbolGroup::updateDebugS(const codeview::DebugSubsectionArray &SS) { + Subsections = SS; +} + +void SymbolGroup::updatePdbModi(uint32_t Modi) { initializeForPdb(Modi); } + +void SymbolGroup::initializeForPdb(uint32_t Modi) { + assert(File && File->isPdb()); + + // PDB always uses the same string table, but each module has its own + // checksums. So we only set the strings if they're not already set. + if (!SC.hasStrings()) { + auto StringTable = File->pdb().getStringTable(); + if (StringTable) + SC.setStrings(StringTable->getStringTable()); + else + consumeError(StringTable.takeError()); + } + + SC.resetChecksums(); + auto MDS = getModuleDebugStream(File->pdb(), Name, Modi); + if (!MDS) { + consumeError(MDS.takeError()); + return; + } + + DebugStream = std::make_shared<ModuleDebugStreamRef>(std::move(*MDS)); + Subsections = DebugStream->getSubsectionsArray(); + SC.initialize(Subsections); + rebuildChecksumMap(); +} + +void SymbolGroup::rebuildChecksumMap() { + if (!SC.hasChecksums()) + return; + + for (const auto &Entry : SC.checksums()) { + auto S = SC.strings().getString(Entry.FileNameOffset); + if (!S) + continue; + ChecksumsByFile[*S] = Entry; + } +} + +const ModuleDebugStreamRef &SymbolGroup::getPdbModuleStream() const { + assert(File && File->isPdb() && DebugStream); + return *DebugStream; +} + +Expected<StringRef> SymbolGroup::getNameFromStringTable(uint32_t Offset) const { + return SC.strings().getString(Offset); +} + +void SymbolGroup::formatFromFileName(LinePrinter &Printer, StringRef File, + bool Append) const { + auto FC = ChecksumsByFile.find(File); + if (FC == ChecksumsByFile.end()) { + formatInternal(Printer, Append, "- (no checksum) {0}", File); + return; + } + + formatInternal(Printer, Append, "- ({0}: {1}) {2}", + formatChecksumKind(FC->getValue().Kind), + toHex(FC->getValue().Checksum), File); +} + +void SymbolGroup::formatFromChecksumsOffset(LinePrinter &Printer, + uint32_t Offset, + bool Append) const { + if (!SC.hasChecksums()) { + formatInternal(Printer, Append, "(unknown file name offset {0})", Offset); + return; + } + + auto Iter = SC.checksums().getArray().at(Offset); + if (Iter == SC.checksums().getArray().end()) { + formatInternal(Printer, Append, "(unknown file name offset {0})", Offset); + return; + } + + uint32_t FO = Iter->FileNameOffset; + auto ExpectedFile = getNameFromStringTable(FO); + if (!ExpectedFile) { + formatInternal(Printer, Append, "(unknown file name offset {0})", Offset); + consumeError(ExpectedFile.takeError()); + return; + } + if (Iter->Kind == FileChecksumKind::None) { + formatInternal(Printer, Append, "{0} (no checksum)", *ExpectedFile); + } else { + formatInternal(Printer, Append, "{0} ({1}: {2})", *ExpectedFile, + formatChecksumKind(Iter->Kind), toHex(Iter->Checksum)); + } +} + +Expected<InputFile> InputFile::open(StringRef Path, bool AllowUnknownFile) { + InputFile IF; + if (!llvm::sys::fs::exists(Path)) + return make_error<StringError>(formatv("File {0} not found", Path), + inconvertibleErrorCode()); + + file_magic Magic; + if (auto EC = identify_magic(Path, Magic)) + return make_error<StringError>( + formatv("Unable to identify file type for file {0}", Path), EC); + + if (Magic == file_magic::coff_object) { + Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(Path); + if (!BinaryOrErr) + return BinaryOrErr.takeError(); + + IF.CoffObject = std::move(*BinaryOrErr); + IF.PdbOrObj = llvm::cast<COFFObjectFile>(IF.CoffObject.getBinary()); + return std::move(IF); + } + + if (Magic == file_magic::pdb) { + std::unique_ptr<IPDBSession> Session; + if (auto Err = loadDataForPDB(PDB_ReaderType::Native, Path, Session)) + return std::move(Err); + + IF.PdbSession.reset(static_cast<NativeSession *>(Session.release())); + IF.PdbOrObj = &IF.PdbSession->getPDBFile(); + + return std::move(IF); + } + + if (!AllowUnknownFile) + return make_error<StringError>( + formatv("File {0} is not a supported file type", Path), + inconvertibleErrorCode()); + + auto Result = MemoryBuffer::getFile(Path, -1LL, false); + if (!Result) + return make_error<StringError>( + formatv("File {0} could not be opened", Path), Result.getError()); + + IF.UnknownFile = std::move(*Result); + IF.PdbOrObj = IF.UnknownFile.get(); + return std::move(IF); +} + +PDBFile &InputFile::pdb() { + assert(isPdb()); + return *PdbOrObj.get<PDBFile *>(); +} + +const PDBFile &InputFile::pdb() const { + assert(isPdb()); + return *PdbOrObj.get<PDBFile *>(); +} + +object::COFFObjectFile &InputFile::obj() { + assert(isObj()); + return *PdbOrObj.get<object::COFFObjectFile *>(); +} + +const object::COFFObjectFile &InputFile::obj() const { + assert(isObj()); + return *PdbOrObj.get<object::COFFObjectFile *>(); +} + +MemoryBuffer &InputFile::unknown() { + assert(isUnknown()); + return *PdbOrObj.get<MemoryBuffer *>(); +} + +const MemoryBuffer &InputFile::unknown() const { + assert(isUnknown()); + return *PdbOrObj.get<MemoryBuffer *>(); +} + +StringRef InputFile::getFilePath() const { + if (isPdb()) + return pdb().getFilePath(); + if (isObj()) + return obj().getFileName(); + assert(isUnknown()); + return unknown().getBufferIdentifier(); +} + +bool InputFile::hasTypes() const { + if (isPdb()) + return pdb().hasPDBTpiStream(); + + for (const auto &Section : obj().sections()) { + CVTypeArray Types; + if (isDebugTSection(Section, Types)) + return true; + } + return false; +} + +bool InputFile::hasIds() const { + if (isObj()) + return false; + return pdb().hasPDBIpiStream(); +} + +bool InputFile::isPdb() const { return PdbOrObj.is<PDBFile *>(); } + +bool InputFile::isObj() const { + return PdbOrObj.is<object::COFFObjectFile *>(); +} + +bool InputFile::isUnknown() const { return PdbOrObj.is<MemoryBuffer *>(); } + +codeview::LazyRandomTypeCollection & +InputFile::getOrCreateTypeCollection(TypeCollectionKind Kind) { + if (Types && Kind == kTypes) + return *Types; + if (Ids && Kind == kIds) + return *Ids; + + if (Kind == kIds) { + assert(isPdb() && pdb().hasPDBIpiStream()); + } + + // If the collection was already initialized, we should have just returned it + // in step 1. + if (isPdb()) { + TypeCollectionPtr &Collection = (Kind == kIds) ? Ids : Types; + auto &Stream = cantFail((Kind == kIds) ? pdb().getPDBIpiStream() + : pdb().getPDBTpiStream()); + + auto &Array = Stream.typeArray(); + uint32_t Count = Stream.getNumTypeRecords(); + auto Offsets = Stream.getTypeIndexOffsets(); + Collection = + std::make_unique<LazyRandomTypeCollection>(Array, Count, Offsets); + return *Collection; + } + + assert(isObj()); + assert(Kind == kTypes); + assert(!Types); + + for (const auto &Section : obj().sections()) { + CVTypeArray Records; + if (!isDebugTSection(Section, Records)) + continue; + + Types = std::make_unique<LazyRandomTypeCollection>(Records, 100); + return *Types; + } + + Types = std::make_unique<LazyRandomTypeCollection>(100); + return *Types; +} + +codeview::LazyRandomTypeCollection &InputFile::types() { + return getOrCreateTypeCollection(kTypes); +} + +codeview::LazyRandomTypeCollection &InputFile::ids() { + // Object files have only one type stream that contains both types and ids. + // Similarly, some PDBs don't contain an IPI stream, and for those both types + // and IDs are in the same stream. + if (isObj() || !pdb().hasPDBIpiStream()) + return types(); + + return getOrCreateTypeCollection(kIds); +} + +iterator_range<SymbolGroupIterator> InputFile::symbol_groups() { + return make_range<SymbolGroupIterator>(symbol_groups_begin(), + symbol_groups_end()); +} + +SymbolGroupIterator InputFile::symbol_groups_begin() { + return SymbolGroupIterator(*this); +} + +SymbolGroupIterator InputFile::symbol_groups_end() { + return SymbolGroupIterator(); +} + +SymbolGroupIterator::SymbolGroupIterator() : Value(nullptr) {} + +SymbolGroupIterator::SymbolGroupIterator(InputFile &File) : Value(&File) { + if (File.isObj()) { + SectionIter = File.obj().section_begin(); + scanToNextDebugS(); + } +} + +bool SymbolGroupIterator::operator==(const SymbolGroupIterator &R) const { + bool E = isEnd(); + bool RE = R.isEnd(); + if (E || RE) + return E == RE; + + if (Value.File != R.Value.File) + return false; + return Index == R.Index; +} + +const SymbolGroup &SymbolGroupIterator::operator*() const { + assert(!isEnd()); + return Value; +} +SymbolGroup &SymbolGroupIterator::operator*() { + assert(!isEnd()); + return Value; +} + +SymbolGroupIterator &SymbolGroupIterator::operator++() { + assert(Value.File && !isEnd()); + ++Index; + if (isEnd()) + return *this; + + if (Value.File->isPdb()) { + Value.updatePdbModi(Index); + return *this; + } + + scanToNextDebugS(); + return *this; +} + +void SymbolGroupIterator::scanToNextDebugS() { + assert(SectionIter.hasValue()); + auto End = Value.File->obj().section_end(); + auto &Iter = *SectionIter; + assert(!isEnd()); + + while (++Iter != End) { + DebugSubsectionArray SS; + SectionRef SR = *Iter; + if (!isDebugSSection(SR, SS)) + continue; + + Value.updateDebugS(SS); + return; + } +} + +bool SymbolGroupIterator::isEnd() const { + if (!Value.File) + return true; + if (Value.File->isPdb()) { + auto &Dbi = cantFail(Value.File->pdb().getPDBDbiStream()); + uint32_t Count = Dbi.modules().getModuleCount(); + assert(Index <= Count); + return Index == Count; + } + + assert(SectionIter.hasValue()); + return *SectionIter == Value.File->obj().section_end(); +} diff --git a/contrib/libs/llvm12/tools/llvm-pdbutil/InputFile.h b/contrib/libs/llvm12/tools/llvm-pdbutil/InputFile.h new file mode 100644 index 0000000000..a5d2897f56 --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-pdbutil/InputFile.h @@ -0,0 +1,155 @@ +//===- InputFile.h -------------------------------------------- *- C++ --*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMPDBDUMP_INPUTFILE_H +#define LLVM_TOOLS_LLVMPDBDUMP_INPUTFILE_H + +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/iterator.h" +#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h" +#include "llvm/DebugInfo/CodeView/StringsAndChecksums.h" +#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h" +#include "llvm/Object/Binary.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/Error.h" + +namespace llvm { +namespace codeview { +class LazyRandomTypeCollection; +} +namespace object { +class COFFObjectFile; +class SectionRef; +} // namespace object + +namespace pdb { +class InputFile; +class LinePrinter; +class PDBFile; +class NativeSession; +class SymbolGroupIterator; +class SymbolGroup; + +class InputFile { + InputFile(); + + std::unique_ptr<NativeSession> PdbSession; + object::OwningBinary<object::Binary> CoffObject; + std::unique_ptr<MemoryBuffer> UnknownFile; + PointerUnion<PDBFile *, object::COFFObjectFile *, MemoryBuffer *> PdbOrObj; + + using TypeCollectionPtr = std::unique_ptr<codeview::LazyRandomTypeCollection>; + + TypeCollectionPtr Types; + TypeCollectionPtr Ids; + + enum TypeCollectionKind { kTypes, kIds }; + codeview::LazyRandomTypeCollection & + getOrCreateTypeCollection(TypeCollectionKind Kind); + +public: + ~InputFile(); + InputFile(InputFile &&Other) = default; + + static Expected<InputFile> open(StringRef Path, + bool AllowUnknownFile = false); + + PDBFile &pdb(); + const PDBFile &pdb() const; + object::COFFObjectFile &obj(); + const object::COFFObjectFile &obj() const; + MemoryBuffer &unknown(); + const MemoryBuffer &unknown() const; + + StringRef getFilePath() const; + + bool hasTypes() const; + bool hasIds() const; + + codeview::LazyRandomTypeCollection &types(); + codeview::LazyRandomTypeCollection &ids(); + + iterator_range<SymbolGroupIterator> symbol_groups(); + SymbolGroupIterator symbol_groups_begin(); + SymbolGroupIterator symbol_groups_end(); + + bool isPdb() const; + bool isObj() const; + bool isUnknown() const; +}; + +class SymbolGroup { + friend class SymbolGroupIterator; + +public: + explicit SymbolGroup(InputFile *File, uint32_t GroupIndex = 0); + + Expected<StringRef> getNameFromStringTable(uint32_t Offset) const; + + void formatFromFileName(LinePrinter &Printer, StringRef File, + bool Append = false) const; + + void formatFromChecksumsOffset(LinePrinter &Printer, uint32_t Offset, + bool Append = false) const; + + StringRef name() const; + + codeview::DebugSubsectionArray getDebugSubsections() const { + return Subsections; + } + const ModuleDebugStreamRef &getPdbModuleStream() const; + + const InputFile &getFile() const { return *File; } + InputFile &getFile() { return *File; } + + bool hasDebugStream() const { return DebugStream != nullptr; } + +private: + void initializeForPdb(uint32_t Modi); + void updatePdbModi(uint32_t Modi); + void updateDebugS(const codeview::DebugSubsectionArray &SS); + + void rebuildChecksumMap(); + InputFile *File = nullptr; + StringRef Name; + codeview::DebugSubsectionArray Subsections; + std::shared_ptr<ModuleDebugStreamRef> DebugStream; + codeview::StringsAndChecksumsRef SC; + StringMap<codeview::FileChecksumEntry> ChecksumsByFile; +}; + +class SymbolGroupIterator + : public iterator_facade_base<SymbolGroupIterator, + std::forward_iterator_tag, SymbolGroup> { +public: + SymbolGroupIterator(); + explicit SymbolGroupIterator(InputFile &File); + SymbolGroupIterator(const SymbolGroupIterator &Other) = default; + SymbolGroupIterator &operator=(const SymbolGroupIterator &R) = default; + + const SymbolGroup &operator*() const; + SymbolGroup &operator*(); + + bool operator==(const SymbolGroupIterator &R) const; + SymbolGroupIterator &operator++(); + +private: + void scanToNextDebugS(); + bool isEnd() const; + + uint32_t Index = 0; + Optional<object::section_iterator> SectionIter; + SymbolGroup Value; +}; + +} // namespace pdb +} // namespace llvm + +#endif diff --git a/contrib/libs/llvm12/tools/llvm-pdbutil/LinePrinter.cpp b/contrib/libs/llvm12/tools/llvm-pdbutil/LinePrinter.cpp new file mode 100644 index 0000000000..280c000bd6 --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-pdbutil/LinePrinter.cpp @@ -0,0 +1,333 @@ +//===- LinePrinter.cpp ------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "LinePrinter.h" + +#include "llvm-pdbutil.h" + +#include "llvm/ADT/STLExtras.h" +#include "llvm/DebugInfo/MSF/MSFCommon.h" +#include "llvm/DebugInfo/MSF/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/UDTLayout.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/FormatAdapters.h" +#include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/Regex.h" + +#include <algorithm> + +using namespace llvm; +using namespace llvm::msf; +using namespace llvm::pdb; + +namespace { +bool IsItemExcluded(llvm::StringRef Item, + std::list<llvm::Regex> &IncludeFilters, + std::list<llvm::Regex> &ExcludeFilters) { + if (Item.empty()) + return false; + + auto match_pred = [Item](llvm::Regex &R) { return R.match(Item); }; + + // Include takes priority over exclude. If the user specified include + // filters, and none of them include this item, them item is gone. + if (!IncludeFilters.empty() && !any_of(IncludeFilters, match_pred)) + return true; + + if (any_of(ExcludeFilters, match_pred)) + return true; + + return false; +} +} + +using namespace llvm; + +LinePrinter::LinePrinter(int Indent, bool UseColor, llvm::raw_ostream &Stream) + : OS(Stream), IndentSpaces(Indent), CurrentIndent(0), UseColor(UseColor) { + SetFilters(ExcludeTypeFilters, opts::pretty::ExcludeTypes.begin(), + opts::pretty::ExcludeTypes.end()); + SetFilters(ExcludeSymbolFilters, opts::pretty::ExcludeSymbols.begin(), + opts::pretty::ExcludeSymbols.end()); + SetFilters(ExcludeCompilandFilters, opts::pretty::ExcludeCompilands.begin(), + opts::pretty::ExcludeCompilands.end()); + + SetFilters(IncludeTypeFilters, opts::pretty::IncludeTypes.begin(), + opts::pretty::IncludeTypes.end()); + SetFilters(IncludeSymbolFilters, opts::pretty::IncludeSymbols.begin(), + opts::pretty::IncludeSymbols.end()); + SetFilters(IncludeCompilandFilters, opts::pretty::IncludeCompilands.begin(), + opts::pretty::IncludeCompilands.end()); +} + +void LinePrinter::Indent(uint32_t Amount) { + if (Amount == 0) + Amount = IndentSpaces; + CurrentIndent += Amount; +} + +void LinePrinter::Unindent(uint32_t Amount) { + if (Amount == 0) + Amount = IndentSpaces; + CurrentIndent = std::max<int>(0, CurrentIndent - Amount); +} + +void LinePrinter::NewLine() { + OS << "\n"; + OS.indent(CurrentIndent); +} + +void LinePrinter::print(const Twine &T) { OS << T; } + +void LinePrinter::printLine(const Twine &T) { + NewLine(); + OS << T; +} + +bool LinePrinter::IsClassExcluded(const ClassLayout &Class) { + if (IsTypeExcluded(Class.getName(), Class.getSize())) + return true; + if (Class.deepPaddingSize() < opts::pretty::PaddingThreshold) + return true; + return false; +} + +void LinePrinter::formatBinary(StringRef Label, ArrayRef<uint8_t> Data, + uint32_t StartOffset) { + NewLine(); + OS << Label << " ("; + if (!Data.empty()) { + OS << "\n"; + OS << format_bytes_with_ascii(Data, StartOffset, 32, 4, + CurrentIndent + IndentSpaces, true); + NewLine(); + } + OS << ")"; +} + +void LinePrinter::formatBinary(StringRef Label, ArrayRef<uint8_t> Data, + uint64_t Base, uint32_t StartOffset) { + NewLine(); + OS << Label << " ("; + if (!Data.empty()) { + OS << "\n"; + Base += StartOffset; + OS << format_bytes_with_ascii(Data, Base, 32, 4, + CurrentIndent + IndentSpaces, true); + NewLine(); + } + OS << ")"; +} + +namespace { +struct Run { + Run() = default; + explicit Run(uint32_t Block) : Block(Block) {} + uint32_t Block = 0; + uint32_t ByteLen = 0; +}; +} // namespace + +static std::vector<Run> computeBlockRuns(uint32_t BlockSize, + const msf::MSFStreamLayout &Layout) { + std::vector<Run> Runs; + if (Layout.Length == 0) + return Runs; + + ArrayRef<support::ulittle32_t> Blocks = Layout.Blocks; + assert(!Blocks.empty()); + uint32_t StreamBytesRemaining = Layout.Length; + uint32_t CurrentBlock = Blocks[0]; + Runs.emplace_back(CurrentBlock); + while (!Blocks.empty()) { + Run *CurrentRun = &Runs.back(); + uint32_t NextBlock = Blocks.front(); + if (NextBlock < CurrentBlock || (NextBlock - CurrentBlock > 1)) { + Runs.emplace_back(NextBlock); + CurrentRun = &Runs.back(); + } + uint32_t Used = std::min(BlockSize, StreamBytesRemaining); + CurrentRun->ByteLen += Used; + StreamBytesRemaining -= Used; + CurrentBlock = NextBlock; + Blocks = Blocks.drop_front(); + } + return Runs; +} + +static std::pair<Run, uint32_t> findRun(uint32_t Offset, ArrayRef<Run> Runs) { + for (const auto &R : Runs) { + if (Offset < R.ByteLen) + return std::make_pair(R, Offset); + Offset -= R.ByteLen; + } + llvm_unreachable("Invalid offset!"); +} + +void LinePrinter::formatMsfStreamData(StringRef Label, PDBFile &File, + uint32_t StreamIdx, + StringRef StreamPurpose, uint32_t Offset, + uint32_t Size) { + if (StreamIdx >= File.getNumStreams()) { + formatLine("Stream {0}: Not present", StreamIdx); + return; + } + if (Size + Offset > File.getStreamByteSize(StreamIdx)) { + formatLine( + "Stream {0}: Invalid offset and size, range out of stream bounds", + StreamIdx); + return; + } + + auto S = File.createIndexedStream(StreamIdx); + if (!S) { + NewLine(); + formatLine("Stream {0}: Not present", StreamIdx); + return; + } + + uint32_t End = + (Size == 0) ? S->getLength() : std::min(Offset + Size, S->getLength()); + Size = End - Offset; + + formatLine("Stream {0}: {1} (dumping {2:N} / {3:N} bytes)", StreamIdx, + StreamPurpose, Size, S->getLength()); + AutoIndent Indent(*this); + BinaryStreamRef Slice(*S); + BinarySubstreamRef Substream; + Substream.Offset = Offset; + Substream.StreamData = Slice.drop_front(Offset).keep_front(Size); + + auto Layout = File.getStreamLayout(StreamIdx); + formatMsfStreamData(Label, File, Layout, Substream); +} + +void LinePrinter::formatMsfStreamData(StringRef Label, PDBFile &File, + const msf::MSFStreamLayout &Stream, + BinarySubstreamRef Substream) { + BinaryStreamReader Reader(Substream.StreamData); + + auto Runs = computeBlockRuns(File.getBlockSize(), Stream); + + NewLine(); + OS << Label << " ("; + while (Reader.bytesRemaining() > 0) { + OS << "\n"; + + Run FoundRun; + uint32_t RunOffset; + std::tie(FoundRun, RunOffset) = findRun(Substream.Offset, Runs); + assert(FoundRun.ByteLen >= RunOffset); + uint32_t Len = FoundRun.ByteLen - RunOffset; + Len = std::min(Len, Reader.bytesRemaining()); + uint64_t Base = FoundRun.Block * File.getBlockSize() + RunOffset; + ArrayRef<uint8_t> Data; + consumeError(Reader.readBytes(Data, Len)); + OS << format_bytes_with_ascii(Data, Base, 32, 4, + CurrentIndent + IndentSpaces, true); + if (Reader.bytesRemaining() > 0) { + NewLine(); + OS << formatv(" {0}", + fmt_align("<discontinuity>", AlignStyle::Center, 114, '-')); + } + Substream.Offset += Len; + } + NewLine(); + OS << ")"; +} + +void LinePrinter::formatMsfStreamBlocks( + PDBFile &File, const msf::MSFStreamLayout &StreamLayout) { + auto Blocks = makeArrayRef(StreamLayout.Blocks); + uint32_t L = StreamLayout.Length; + + while (L > 0) { + NewLine(); + assert(!Blocks.empty()); + OS << formatv("Block {0} (\n", uint32_t(Blocks.front())); + uint32_t UsedBytes = std::min(L, File.getBlockSize()); + ArrayRef<uint8_t> BlockData = + cantFail(File.getBlockData(Blocks.front(), File.getBlockSize())); + uint64_t BaseOffset = Blocks.front(); + BaseOffset *= File.getBlockSize(); + OS << format_bytes_with_ascii(BlockData, BaseOffset, 32, 4, + CurrentIndent + IndentSpaces, true); + NewLine(); + OS << ")"; + NewLine(); + L -= UsedBytes; + Blocks = Blocks.drop_front(); + } +} + +bool LinePrinter::IsTypeExcluded(llvm::StringRef TypeName, uint32_t Size) { + if (IsItemExcluded(TypeName, IncludeTypeFilters, ExcludeTypeFilters)) + return true; + if (Size < opts::pretty::SizeThreshold) + return true; + return false; +} + +bool LinePrinter::IsSymbolExcluded(llvm::StringRef SymbolName) { + return IsItemExcluded(SymbolName, IncludeSymbolFilters, ExcludeSymbolFilters); +} + +bool LinePrinter::IsCompilandExcluded(llvm::StringRef CompilandName) { + return IsItemExcluded(CompilandName, IncludeCompilandFilters, + ExcludeCompilandFilters); +} + +WithColor::WithColor(LinePrinter &P, PDB_ColorItem C) + : OS(P.OS), UseColor(P.hasColor()) { + if (UseColor) + applyColor(C); +} + +WithColor::~WithColor() { + if (UseColor) + OS.resetColor(); +} + +void WithColor::applyColor(PDB_ColorItem C) { + switch (C) { + case PDB_ColorItem::None: + OS.resetColor(); + return; + case PDB_ColorItem::Comment: + OS.changeColor(raw_ostream::GREEN, false); + return; + case PDB_ColorItem::Address: + OS.changeColor(raw_ostream::YELLOW, /*bold=*/true); + return; + case PDB_ColorItem::Keyword: + OS.changeColor(raw_ostream::MAGENTA, true); + return; + case PDB_ColorItem::Register: + case PDB_ColorItem::Offset: + OS.changeColor(raw_ostream::YELLOW, false); + return; + case PDB_ColorItem::Type: + OS.changeColor(raw_ostream::CYAN, true); + return; + case PDB_ColorItem::Identifier: + OS.changeColor(raw_ostream::CYAN, false); + return; + case PDB_ColorItem::Path: + OS.changeColor(raw_ostream::CYAN, false); + return; + case PDB_ColorItem::Padding: + case PDB_ColorItem::SectionHeader: + OS.changeColor(raw_ostream::RED, true); + return; + case PDB_ColorItem::LiteralValue: + OS.changeColor(raw_ostream::GREEN, true); + return; + } +} diff --git a/contrib/libs/llvm12/tools/llvm-pdbutil/LinePrinter.h b/contrib/libs/llvm12/tools/llvm-pdbutil/LinePrinter.h new file mode 100644 index 0000000000..7ecfae1735 --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-pdbutil/LinePrinter.h @@ -0,0 +1,168 @@ +//===- LinePrinter.h ------------------------------------------ *- C++ --*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMPDBDUMP_LINEPRINTER_H +#define LLVM_TOOLS_LLVMPDBDUMP_LINEPRINTER_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/BinaryStreamRef.h" +#include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/Regex.h" +#include "llvm/Support/raw_ostream.h" + +#include <list> + +namespace llvm { +class BinaryStreamReader; +namespace msf { +class MSFStreamLayout; +} // namespace msf +namespace pdb { + +class ClassLayout; +class PDBFile; + +class LinePrinter { + friend class WithColor; + +public: + LinePrinter(int Indent, bool UseColor, raw_ostream &Stream); + + void Indent(uint32_t Amount = 0); + void Unindent(uint32_t Amount = 0); + void NewLine(); + + void printLine(const Twine &T); + void print(const Twine &T); + template <typename... Ts> void formatLine(const char *Fmt, Ts &&... Items) { + printLine(formatv(Fmt, std::forward<Ts>(Items)...)); + } + template <typename... Ts> void format(const char *Fmt, Ts &&... Items) { + print(formatv(Fmt, std::forward<Ts>(Items)...)); + } + + void formatBinary(StringRef Label, ArrayRef<uint8_t> Data, + uint32_t StartOffset); + void formatBinary(StringRef Label, ArrayRef<uint8_t> Data, uint64_t BaseAddr, + uint32_t StartOffset); + + void formatMsfStreamData(StringRef Label, PDBFile &File, uint32_t StreamIdx, + StringRef StreamPurpose, uint32_t Offset, + uint32_t Size); + void formatMsfStreamData(StringRef Label, PDBFile &File, + const msf::MSFStreamLayout &Stream, + BinarySubstreamRef Substream); + void formatMsfStreamBlocks(PDBFile &File, const msf::MSFStreamLayout &Stream); + + bool hasColor() const { return UseColor; } + raw_ostream &getStream() { return OS; } + int getIndentLevel() const { return CurrentIndent; } + + bool IsClassExcluded(const ClassLayout &Class); + bool IsTypeExcluded(llvm::StringRef TypeName, uint32_t Size); + bool IsSymbolExcluded(llvm::StringRef SymbolName); + bool IsCompilandExcluded(llvm::StringRef CompilandName); + +private: + template <typename Iter> + void SetFilters(std::list<Regex> &List, Iter Begin, Iter End) { + List.clear(); + for (; Begin != End; ++Begin) + List.emplace_back(StringRef(*Begin)); + } + + raw_ostream &OS; + int IndentSpaces; + int CurrentIndent; + bool UseColor; + + std::list<Regex> ExcludeCompilandFilters; + std::list<Regex> ExcludeTypeFilters; + std::list<Regex> ExcludeSymbolFilters; + + std::list<Regex> IncludeCompilandFilters; + std::list<Regex> IncludeTypeFilters; + std::list<Regex> IncludeSymbolFilters; +}; + +struct PrintScope { + explicit PrintScope(LinePrinter &P, uint32_t IndentLevel) + : P(P), IndentLevel(IndentLevel) {} + explicit PrintScope(const PrintScope &Other, uint32_t LabelWidth) + : P(Other.P), IndentLevel(Other.IndentLevel), LabelWidth(LabelWidth) {} + + LinePrinter &P; + uint32_t IndentLevel; + uint32_t LabelWidth = 0; +}; + +inline Optional<PrintScope> withLabelWidth(const Optional<PrintScope> &Scope, + uint32_t W) { + if (!Scope) + return None; + return PrintScope{*Scope, W}; +} + +struct AutoIndent { + explicit AutoIndent(LinePrinter &L, uint32_t Amount = 0) + : L(&L), Amount(Amount) { + L.Indent(Amount); + } + explicit AutoIndent(const Optional<PrintScope> &Scope) { + if (Scope.hasValue()) { + L = &Scope->P; + Amount = Scope->IndentLevel; + } + } + ~AutoIndent() { + if (L) + L->Unindent(Amount); + } + + LinePrinter *L = nullptr; + uint32_t Amount = 0; +}; + +template <class T> +inline raw_ostream &operator<<(LinePrinter &Printer, const T &Item) { + return Printer.getStream() << Item; +} + +enum class PDB_ColorItem { + None, + Address, + Type, + Comment, + Padding, + Keyword, + Offset, + Identifier, + Path, + SectionHeader, + LiteralValue, + Register, +}; + +class WithColor { +public: + WithColor(LinePrinter &P, PDB_ColorItem C); + ~WithColor(); + + raw_ostream &get() { return OS; } + +private: + void applyColor(PDB_ColorItem C); + raw_ostream &OS; + bool UseColor; +}; +} +} + +#endif diff --git a/contrib/libs/llvm12/tools/llvm-pdbutil/MinimalSymbolDumper.cpp b/contrib/libs/llvm12/tools/llvm-pdbutil/MinimalSymbolDumper.cpp new file mode 100644 index 0000000000..787785c34b --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-pdbutil/MinimalSymbolDumper.cpp @@ -0,0 +1,899 @@ +//===- MinimalSymbolDumper.cpp -------------------------------- *- C++ --*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "MinimalSymbolDumper.h" + +#include "FormatUtil.h" +#include "InputFile.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/DebugInfo/PDB/Native/PDBStringTable.h" +#include "llvm/Support/FormatVariadic.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +static std::string formatLocalSymFlags(uint32_t IndentLevel, + LocalSymFlags Flags) { + std::vector<std::string> Opts; + if (Flags == LocalSymFlags::None) + return "none"; + + PUSH_FLAG(LocalSymFlags, IsParameter, Flags, "param"); + PUSH_FLAG(LocalSymFlags, IsAddressTaken, Flags, "address is taken"); + PUSH_FLAG(LocalSymFlags, IsCompilerGenerated, Flags, "compiler generated"); + PUSH_FLAG(LocalSymFlags, IsAggregate, Flags, "aggregate"); + PUSH_FLAG(LocalSymFlags, IsAggregated, Flags, "aggregated"); + PUSH_FLAG(LocalSymFlags, IsAliased, Flags, "aliased"); + PUSH_FLAG(LocalSymFlags, IsAlias, Flags, "alias"); + PUSH_FLAG(LocalSymFlags, IsReturnValue, Flags, "return val"); + PUSH_FLAG(LocalSymFlags, IsOptimizedOut, Flags, "optimized away"); + PUSH_FLAG(LocalSymFlags, IsEnregisteredGlobal, Flags, "enreg global"); + PUSH_FLAG(LocalSymFlags, IsEnregisteredStatic, Flags, "enreg static"); + return typesetItemList(Opts, 4, IndentLevel, " | "); +} + +static std::string formatExportFlags(uint32_t IndentLevel, ExportFlags Flags) { + std::vector<std::string> Opts; + if (Flags == ExportFlags::None) + return "none"; + + PUSH_FLAG(ExportFlags, IsConstant, Flags, "constant"); + PUSH_FLAG(ExportFlags, IsData, Flags, "data"); + PUSH_FLAG(ExportFlags, IsPrivate, Flags, "private"); + PUSH_FLAG(ExportFlags, HasNoName, Flags, "no name"); + PUSH_FLAG(ExportFlags, HasExplicitOrdinal, Flags, "explicit ord"); + PUSH_FLAG(ExportFlags, IsForwarder, Flags, "forwarder"); + + return typesetItemList(Opts, 4, IndentLevel, " | "); +} + +static std::string formatCompileSym2Flags(uint32_t IndentLevel, + CompileSym2Flags Flags) { + std::vector<std::string> Opts; + Flags &= ~CompileSym2Flags::SourceLanguageMask; + if (Flags == CompileSym2Flags::None) + return "none"; + + PUSH_FLAG(CompileSym2Flags, EC, Flags, "edit and continue"); + PUSH_FLAG(CompileSym2Flags, NoDbgInfo, Flags, "no dbg info"); + PUSH_FLAG(CompileSym2Flags, LTCG, Flags, "ltcg"); + PUSH_FLAG(CompileSym2Flags, NoDataAlign, Flags, "no data align"); + PUSH_FLAG(CompileSym2Flags, ManagedPresent, Flags, "has managed code"); + PUSH_FLAG(CompileSym2Flags, SecurityChecks, Flags, "security checks"); + PUSH_FLAG(CompileSym2Flags, HotPatch, Flags, "hot patchable"); + PUSH_FLAG(CompileSym2Flags, CVTCIL, Flags, "cvtcil"); + PUSH_FLAG(CompileSym2Flags, MSILModule, Flags, "msil module"); + return typesetItemList(Opts, 4, IndentLevel, " | "); +} + +static std::string formatCompileSym3Flags(uint32_t IndentLevel, + CompileSym3Flags Flags) { + std::vector<std::string> Opts; + Flags &= ~CompileSym3Flags::SourceLanguageMask; + + if (Flags == CompileSym3Flags::None) + return "none"; + + PUSH_FLAG(CompileSym3Flags, EC, Flags, "edit and continue"); + PUSH_FLAG(CompileSym3Flags, NoDbgInfo, Flags, "no dbg info"); + PUSH_FLAG(CompileSym3Flags, LTCG, Flags, "ltcg"); + PUSH_FLAG(CompileSym3Flags, NoDataAlign, Flags, "no data align"); + PUSH_FLAG(CompileSym3Flags, ManagedPresent, Flags, "has managed code"); + PUSH_FLAG(CompileSym3Flags, SecurityChecks, Flags, "security checks"); + PUSH_FLAG(CompileSym3Flags, HotPatch, Flags, "hot patchable"); + PUSH_FLAG(CompileSym3Flags, CVTCIL, Flags, "cvtcil"); + PUSH_FLAG(CompileSym3Flags, MSILModule, Flags, "msil module"); + PUSH_FLAG(CompileSym3Flags, Sdl, Flags, "sdl"); + PUSH_FLAG(CompileSym3Flags, PGO, Flags, "pgo"); + PUSH_FLAG(CompileSym3Flags, Exp, Flags, "exp"); + return typesetItemList(Opts, 4, IndentLevel, " | "); +} + +static std::string formatFrameProcedureOptions(uint32_t IndentLevel, + FrameProcedureOptions FPO) { + std::vector<std::string> Opts; + if (FPO == FrameProcedureOptions::None) + return "none"; + + PUSH_FLAG(FrameProcedureOptions, HasAlloca, FPO, "has alloca"); + PUSH_FLAG(FrameProcedureOptions, HasSetJmp, FPO, "has setjmp"); + PUSH_FLAG(FrameProcedureOptions, HasLongJmp, FPO, "has longjmp"); + PUSH_FLAG(FrameProcedureOptions, HasInlineAssembly, FPO, "has inline asm"); + PUSH_FLAG(FrameProcedureOptions, HasExceptionHandling, FPO, "has eh"); + PUSH_FLAG(FrameProcedureOptions, MarkedInline, FPO, "marked inline"); + PUSH_FLAG(FrameProcedureOptions, HasStructuredExceptionHandling, FPO, + "has seh"); + PUSH_FLAG(FrameProcedureOptions, Naked, FPO, "naked"); + PUSH_FLAG(FrameProcedureOptions, SecurityChecks, FPO, "secure checks"); + PUSH_FLAG(FrameProcedureOptions, AsynchronousExceptionHandling, FPO, + "has async eh"); + PUSH_FLAG(FrameProcedureOptions, NoStackOrderingForSecurityChecks, FPO, + "no stack order"); + PUSH_FLAG(FrameProcedureOptions, Inlined, FPO, "inlined"); + PUSH_FLAG(FrameProcedureOptions, StrictSecurityChecks, FPO, + "strict secure checks"); + PUSH_FLAG(FrameProcedureOptions, SafeBuffers, FPO, "safe buffers"); + PUSH_FLAG(FrameProcedureOptions, ProfileGuidedOptimization, FPO, "pgo"); + PUSH_FLAG(FrameProcedureOptions, ValidProfileCounts, FPO, + "has profile counts"); + PUSH_FLAG(FrameProcedureOptions, OptimizedForSpeed, FPO, "opt speed"); + PUSH_FLAG(FrameProcedureOptions, GuardCfg, FPO, "guard cfg"); + PUSH_FLAG(FrameProcedureOptions, GuardCfw, FPO, "guard cfw"); + return typesetItemList(Opts, 4, IndentLevel, " | "); +} + +static std::string formatPublicSymFlags(uint32_t IndentLevel, + PublicSymFlags Flags) { + std::vector<std::string> Opts; + if (Flags == PublicSymFlags::None) + return "none"; + + PUSH_FLAG(PublicSymFlags, Code, Flags, "code"); + PUSH_FLAG(PublicSymFlags, Function, Flags, "function"); + PUSH_FLAG(PublicSymFlags, Managed, Flags, "managed"); + PUSH_FLAG(PublicSymFlags, MSIL, Flags, "msil"); + return typesetItemList(Opts, 4, IndentLevel, " | "); +} + +static std::string formatProcSymFlags(uint32_t IndentLevel, + ProcSymFlags Flags) { + std::vector<std::string> Opts; + if (Flags == ProcSymFlags::None) + return "none"; + + PUSH_FLAG(ProcSymFlags, HasFP, Flags, "has fp"); + PUSH_FLAG(ProcSymFlags, HasIRET, Flags, "has iret"); + PUSH_FLAG(ProcSymFlags, HasFRET, Flags, "has fret"); + PUSH_FLAG(ProcSymFlags, IsNoReturn, Flags, "noreturn"); + PUSH_FLAG(ProcSymFlags, IsUnreachable, Flags, "unreachable"); + PUSH_FLAG(ProcSymFlags, HasCustomCallingConv, Flags, "custom calling conv"); + PUSH_FLAG(ProcSymFlags, IsNoInline, Flags, "noinline"); + PUSH_FLAG(ProcSymFlags, HasOptimizedDebugInfo, Flags, "opt debuginfo"); + return typesetItemList(Opts, 4, IndentLevel, " | "); +} + +static std::string formatThunkOrdinal(ThunkOrdinal Ordinal) { + switch (Ordinal) { + RETURN_CASE(ThunkOrdinal, Standard, "thunk"); + RETURN_CASE(ThunkOrdinal, ThisAdjustor, "this adjustor"); + RETURN_CASE(ThunkOrdinal, Vcall, "vcall"); + RETURN_CASE(ThunkOrdinal, Pcode, "pcode"); + RETURN_CASE(ThunkOrdinal, UnknownLoad, "unknown load"); + RETURN_CASE(ThunkOrdinal, TrampIncremental, "tramp incremental"); + RETURN_CASE(ThunkOrdinal, BranchIsland, "branch island"); + } + return formatUnknownEnum(Ordinal); +} + +static std::string formatTrampolineType(TrampolineType Tramp) { + switch (Tramp) { + RETURN_CASE(TrampolineType, TrampIncremental, "tramp incremental"); + RETURN_CASE(TrampolineType, BranchIsland, "branch island"); + } + return formatUnknownEnum(Tramp); +} + +static std::string formatSourceLanguage(SourceLanguage Lang) { + switch (Lang) { + RETURN_CASE(SourceLanguage, C, "c"); + RETURN_CASE(SourceLanguage, Cpp, "c++"); + RETURN_CASE(SourceLanguage, Fortran, "fortran"); + RETURN_CASE(SourceLanguage, Masm, "masm"); + RETURN_CASE(SourceLanguage, Pascal, "pascal"); + RETURN_CASE(SourceLanguage, Basic, "basic"); + RETURN_CASE(SourceLanguage, Cobol, "cobol"); + RETURN_CASE(SourceLanguage, Link, "link"); + RETURN_CASE(SourceLanguage, VB, "vb"); + RETURN_CASE(SourceLanguage, Cvtres, "cvtres"); + RETURN_CASE(SourceLanguage, Cvtpgd, "cvtpgd"); + RETURN_CASE(SourceLanguage, CSharp, "c#"); + RETURN_CASE(SourceLanguage, ILAsm, "il asm"); + RETURN_CASE(SourceLanguage, Java, "java"); + RETURN_CASE(SourceLanguage, JScript, "javascript"); + RETURN_CASE(SourceLanguage, MSIL, "msil"); + RETURN_CASE(SourceLanguage, HLSL, "hlsl"); + RETURN_CASE(SourceLanguage, D, "d"); + RETURN_CASE(SourceLanguage, Swift, "swift"); + } + 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, ARM64, "arm64"); + RETURN_CASE(CPUType, Omni, "omni"); + RETURN_CASE(CPUType, Ia64, "intel itanium ia64"); + RETURN_CASE(CPUType, Ia64_2, "intel itanium ia64 2"); + RETURN_CASE(CPUType, CEE, "cee"); + RETURN_CASE(CPUType, AM33, "am33"); + RETURN_CASE(CPUType, M32R, "m32r"); + RETURN_CASE(CPUType, TriCore, "tri-core"); + RETURN_CASE(CPUType, X64, "intel x86-x64"); + RETURN_CASE(CPUType, EBC, "ebc"); + RETURN_CASE(CPUType, Thumb, "thumb"); + RETURN_CASE(CPUType, ARMNT, "arm nt"); + RETURN_CASE(CPUType, D3D11_Shader, "d3d11 shader"); + } + return formatUnknownEnum(Cpu); +} + +static std::string formatCookieKind(FrameCookieKind Kind) { + switch (Kind) { + RETURN_CASE(FrameCookieKind, Copy, "copy"); + RETURN_CASE(FrameCookieKind, XorStackPointer, "xor stack ptr"); + RETURN_CASE(FrameCookieKind, XorFramePointer, "xor frame ptr"); + RETURN_CASE(FrameCookieKind, XorR13, "xor rot13"); + } + return formatUnknownEnum(Kind); +} + +static std::string formatRegisterId(RegisterId Id, CPUType Cpu) { + if (Cpu == CPUType::ARMNT) { + switch (Id) { +#define CV_REGISTERS_ARM +#define CV_REGISTER(name, val) RETURN_CASE(RegisterId, name, #name) +#include "llvm/DebugInfo/CodeView/CodeViewRegisters.def" +#undef CV_REGISTER +#undef CV_REGISTERS_ARM + + default: + break; + } + } else if (Cpu == CPUType::ARM64) { + switch (Id) { +#define CV_REGISTERS_ARM64 +#define CV_REGISTER(name, val) RETURN_CASE(RegisterId, name, #name) +#include "llvm/DebugInfo/CodeView/CodeViewRegisters.def" +#undef CV_REGISTER +#undef CV_REGISTERS_ARM64 + + default: + break; + } + } else { + switch (Id) { +#define CV_REGISTERS_X86 +#define CV_REGISTER(name, val) RETURN_CASE(RegisterId, name, #name) +#include "llvm/DebugInfo/CodeView/CodeViewRegisters.def" +#undef CV_REGISTER +#undef CV_REGISTERS_X86 + + default: + break; + } + } + return formatUnknownEnum(Id); +} + +static std::string formatRegisterId(uint16_t Reg16, CPUType Cpu) { + return formatRegisterId(RegisterId(Reg16), Cpu); +} + +static std::string formatRegisterId(ulittle16_t &Reg16, CPUType Cpu) { + return formatRegisterId(uint16_t(Reg16), Cpu); +} + +static std::string formatRange(LocalVariableAddrRange Range) { + return formatv("[{0},+{1})", + formatSegmentOffset(Range.ISectStart, Range.OffsetStart), + Range.Range) + .str(); +} + +static std::string formatGaps(uint32_t IndentLevel, + ArrayRef<LocalVariableAddrGap> Gaps) { + std::vector<std::string> GapStrs; + for (const auto &G : Gaps) { + GapStrs.push_back(formatv("({0},{1})", G.GapStartOffset, G.Range).str()); + } + return typesetItemList(GapStrs, 7, IndentLevel, ", "); +} + +Error MinimalSymbolDumper::visitSymbolBegin(codeview::CVSymbol &Record) { + return visitSymbolBegin(Record, 0); +} + +Error MinimalSymbolDumper::visitSymbolBegin(codeview::CVSymbol &Record, + uint32_t Offset) { + // formatLine puts the newline at the beginning, so we use formatLine here + // to start a new line, and then individual visit methods use format to + // append to the existing line. + P.formatLine("{0} | {1} [size = {2}]", + fmt_align(Offset, AlignStyle::Right, 6), + formatSymbolKind(Record.kind()), Record.length()); + P.Indent(); + return Error::success(); +} + +Error MinimalSymbolDumper::visitSymbolEnd(CVSymbol &Record) { + if (RecordBytes) { + AutoIndent Indent(P, 7); + P.formatBinary("bytes", Record.content(), 0); + } + P.Unindent(); + return Error::success(); +} + +std::string MinimalSymbolDumper::typeOrIdIndex(codeview::TypeIndex TI, + bool IsType) const { + if (TI.isSimple() || TI.isDecoratedItemId()) + return formatv("{0}", TI).str(); + auto &Container = IsType ? Types : Ids; + StringRef Name = Container.getTypeName(TI); + if (Name.size() > 32) { + Name = Name.take_front(32); + return std::string(formatv("{0} ({1}...)", TI, Name)); + } else + return std::string(formatv("{0} ({1})", TI, Name)); +} + +std::string MinimalSymbolDumper::idIndex(codeview::TypeIndex TI) const { + return typeOrIdIndex(TI, false); +} + +std::string MinimalSymbolDumper::typeIndex(TypeIndex TI) const { + return typeOrIdIndex(TI, true); +} + +Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, BlockSym &Block) { + P.format(" `{0}`", Block.Name); + AutoIndent Indent(P, 7); + P.formatLine("parent = {0}, end = {1}", Block.Parent, Block.End); + P.formatLine("code size = {0}, addr = {1}", Block.CodeSize, + formatSegmentOffset(Block.Segment, Block.CodeOffset)); + return Error::success(); +} + +Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, Thunk32Sym &Thunk) { + P.format(" `{0}`", Thunk.Name); + AutoIndent Indent(P, 7); + P.formatLine("parent = {0}, end = {1}, next = {2}", Thunk.Parent, Thunk.End, + Thunk.Next); + P.formatLine("kind = {0}, size = {1}, addr = {2}", + formatThunkOrdinal(Thunk.Thunk), Thunk.Length, + formatSegmentOffset(Thunk.Segment, Thunk.Offset)); + + return Error::success(); +} + +Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, + TrampolineSym &Tramp) { + AutoIndent Indent(P, 7); + P.formatLine("type = {0}, size = {1}, source = {2}, target = {3}", + formatTrampolineType(Tramp.Type), Tramp.Size, + formatSegmentOffset(Tramp.ThunkSection, Tramp.ThunkOffset), + formatSegmentOffset(Tramp.TargetSection, Tramp.ThunkOffset)); + + return Error::success(); +} + +Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, + SectionSym &Section) { + P.format(" `{0}`", Section.Name); + AutoIndent Indent(P, 7); + P.formatLine("length = {0}, alignment = {1}, rva = {2}, section # = {3}", + Section.Length, Section.Alignment, Section.Rva, + Section.SectionNumber); + P.printLine("characteristics ="); + AutoIndent Indent2(P, 2); + P.printLine(formatSectionCharacteristics(P.getIndentLevel(), + Section.Characteristics, 1, "", + CharacteristicStyle::Descriptive)); + return Error::success(); +} + +Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, CoffGroupSym &CG) { + P.format(" `{0}`", CG.Name); + AutoIndent Indent(P, 7); + P.formatLine("length = {0}, addr = {1}", CG.Size, + formatSegmentOffset(CG.Segment, CG.Offset)); + P.printLine("characteristics ="); + AutoIndent Indent2(P, 2); + P.printLine(formatSectionCharacteristics(P.getIndentLevel(), + CG.Characteristics, 1, "", + CharacteristicStyle::Descriptive)); + return Error::success(); +} + +Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, + BPRelativeSym &BPRel) { + P.format(" `{0}`", BPRel.Name); + AutoIndent Indent(P, 7); + P.formatLine("type = {0}, offset = {1}", typeIndex(BPRel.Type), BPRel.Offset); + return Error::success(); +} + +Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, + BuildInfoSym &BuildInfo) { + P.format(" BuildId = `{0}`", BuildInfo.BuildId); + return Error::success(); +} + +Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, + CallSiteInfoSym &CSI) { + AutoIndent Indent(P, 7); + P.formatLine("type = {0}, addr = {1}", typeIndex(CSI.Type), + formatSegmentOffset(CSI.Segment, CSI.CodeOffset)); + return Error::success(); +} + +Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, + EnvBlockSym &EnvBlock) { + AutoIndent Indent(P, 7); + for (const auto &Entry : EnvBlock.Fields) { + P.formatLine("- {0}", Entry); + } + return Error::success(); +} + +Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, FileStaticSym &FS) { + P.format(" `{0}`", FS.Name); + AutoIndent Indent(P, 7); + if (SymGroup) { + Expected<StringRef> FileName = + SymGroup->getNameFromStringTable(FS.ModFilenameOffset); + if (FileName) { + P.formatLine("type = {0}, file name = {1} ({2}), flags = {3}", + typeIndex(FS.Index), FS.ModFilenameOffset, *FileName, + formatLocalSymFlags(P.getIndentLevel() + 9, FS.Flags)); + } + return Error::success(); + } + + P.formatLine("type = {0}, file name offset = {1}, flags = {2}", + typeIndex(FS.Index), FS.ModFilenameOffset, + formatLocalSymFlags(P.getIndentLevel() + 9, FS.Flags)); + return Error::success(); +} + +Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, ExportSym &Export) { + P.format(" `{0}`", Export.Name); + AutoIndent Indent(P, 7); + P.formatLine("ordinal = {0}, flags = {1}", Export.Ordinal, + formatExportFlags(P.getIndentLevel() + 9, Export.Flags)); + return Error::success(); +} + +Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, + Compile2Sym &Compile2) { + AutoIndent Indent(P, 7); + SourceLanguage Lang = static_cast<SourceLanguage>( + Compile2.Flags & CompileSym2Flags::SourceLanguageMask); + CompilationCPU = Compile2.Machine; + P.formatLine("machine = {0}, ver = {1}, language = {2}", + formatMachineType(Compile2.Machine), Compile2.Version, + formatSourceLanguage(Lang)); + P.formatLine("frontend = {0}.{1}.{2}, backend = {3}.{4}.{5}", + Compile2.VersionFrontendMajor, Compile2.VersionFrontendMinor, + Compile2.VersionFrontendBuild, Compile2.VersionBackendMajor, + Compile2.VersionBackendMinor, Compile2.VersionBackendBuild); + P.formatLine("flags = {0}", + formatCompileSym2Flags(P.getIndentLevel() + 9, Compile2.Flags)); + P.formatLine( + "extra strings = {0}", + typesetStringList(P.getIndentLevel() + 9 + 2, Compile2.ExtraStrings)); + return Error::success(); +} + +Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, + Compile3Sym &Compile3) { + AutoIndent Indent(P, 7); + SourceLanguage Lang = static_cast<SourceLanguage>( + Compile3.Flags & CompileSym3Flags::SourceLanguageMask); + CompilationCPU = Compile3.Machine; + P.formatLine("machine = {0}, Ver = {1}, language = {2}", + formatMachineType(Compile3.Machine), Compile3.Version, + formatSourceLanguage(Lang)); + P.formatLine("frontend = {0}.{1}.{2}.{3}, backend = {4}.{5}.{6}.{7}", + Compile3.VersionFrontendMajor, Compile3.VersionFrontendMinor, + Compile3.VersionFrontendBuild, Compile3.VersionFrontendQFE, + Compile3.VersionBackendMajor, Compile3.VersionBackendMinor, + Compile3.VersionBackendBuild, Compile3.VersionBackendQFE); + P.formatLine("flags = {0}", + formatCompileSym3Flags(P.getIndentLevel() + 9, Compile3.Flags)); + return Error::success(); +} + +Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, + ConstantSym &Constant) { + P.format(" `{0}`", Constant.Name); + AutoIndent Indent(P, 7); + P.formatLine("type = {0}, value = {1}", typeIndex(Constant.Type), + Constant.Value.toString(10)); + return Error::success(); +} + +Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, DataSym &Data) { + P.format(" `{0}`", Data.Name); + AutoIndent Indent(P, 7); + P.formatLine("type = {0}, addr = {1}", typeIndex(Data.Type), + formatSegmentOffset(Data.Segment, Data.DataOffset)); + return Error::success(); +} + +Error MinimalSymbolDumper::visitKnownRecord( + CVSymbol &CVR, DefRangeFramePointerRelFullScopeSym &Def) { + P.format(" offset = {0}", Def.Offset); + return Error::success(); +} + +Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, + DefRangeFramePointerRelSym &Def) { + AutoIndent Indent(P, 7); + P.formatLine("offset = {0}, range = {1}", Def.Hdr.Offset, + formatRange(Def.Range)); + P.formatLine("gaps = {2}", Def.Hdr.Offset, + formatGaps(P.getIndentLevel() + 9, Def.Gaps)); + return Error::success(); +} + +Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, + DefRangeRegisterRelSym &Def) { + AutoIndent Indent(P, 7); + P.formatLine("register = {0}, offset = {1}, offset in parent = {2}, has " + "spilled udt = {3}", + formatRegisterId(Def.Hdr.Register, CompilationCPU), + int32_t(Def.Hdr.BasePointerOffset), Def.offsetInParent(), + Def.hasSpilledUDTMember()); + P.formatLine("range = {0}, gaps = {1}", formatRange(Def.Range), + formatGaps(P.getIndentLevel() + 9, Def.Gaps)); + return Error::success(); +} + +Error MinimalSymbolDumper::visitKnownRecord( + CVSymbol &CVR, DefRangeRegisterSym &DefRangeRegister) { + AutoIndent Indent(P, 7); + P.formatLine("register = {0}, may have no name = {1}, range start = " + "{2}, length = {3}", + formatRegisterId(DefRangeRegister.Hdr.Register, CompilationCPU), + bool(DefRangeRegister.Hdr.MayHaveNoName), + formatSegmentOffset(DefRangeRegister.Range.ISectStart, + DefRangeRegister.Range.OffsetStart), + DefRangeRegister.Range.Range); + P.formatLine("gaps = [{0}]", + formatGaps(P.getIndentLevel() + 9, DefRangeRegister.Gaps)); + return Error::success(); +} + +Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, + DefRangeSubfieldRegisterSym &Def) { + AutoIndent Indent(P, 7); + bool NoName = !!(Def.Hdr.MayHaveNoName == 0); + P.formatLine("register = {0}, may have no name = {1}, offset in parent = {2}", + formatRegisterId(Def.Hdr.Register, CompilationCPU), NoName, + uint32_t(Def.Hdr.OffsetInParent)); + P.formatLine("range = {0}, gaps = {1}", formatRange(Def.Range), + formatGaps(P.getIndentLevel() + 9, Def.Gaps)); + return Error::success(); +} + +Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, + DefRangeSubfieldSym &Def) { + AutoIndent Indent(P, 7); + P.formatLine("program = {0}, offset in parent = {1}, range = {2}", + Def.Program, Def.OffsetInParent, formatRange(Def.Range)); + P.formatLine("gaps = {0}", formatGaps(P.getIndentLevel() + 9, Def.Gaps)); + return Error::success(); +} + +Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, DefRangeSym &Def) { + AutoIndent Indent(P, 7); + P.formatLine("program = {0}, range = {1}", Def.Program, + formatRange(Def.Range)); + P.formatLine("gaps = {0}", formatGaps(P.getIndentLevel() + 9, Def.Gaps)); + return Error::success(); +} + +Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, FrameCookieSym &FC) { + AutoIndent Indent(P, 7); + P.formatLine("code offset = {0}, Register = {1}, kind = {2}, flags = {3}", + FC.CodeOffset, formatRegisterId(FC.Register, CompilationCPU), + formatCookieKind(FC.CookieKind), FC.Flags); + return Error::success(); +} + +Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, FrameProcSym &FP) { + AutoIndent Indent(P, 7); + P.formatLine("size = {0}, padding size = {1}, offset to padding = {2}", + FP.TotalFrameBytes, FP.PaddingFrameBytes, FP.OffsetToPadding); + P.formatLine("bytes of callee saved registers = {0}, exception handler addr " + "= {1}", + FP.BytesOfCalleeSavedRegisters, + formatSegmentOffset(FP.SectionIdOfExceptionHandler, + FP.OffsetOfExceptionHandler)); + P.formatLine( + "local fp reg = {0}, param fp reg = {1}", + formatRegisterId(FP.getLocalFramePtrReg(CompilationCPU), CompilationCPU), + formatRegisterId(FP.getParamFramePtrReg(CompilationCPU), CompilationCPU)); + P.formatLine("flags = {0}", + formatFrameProcedureOptions(P.getIndentLevel() + 9, FP.Flags)); + return Error::success(); +} + +Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, + HeapAllocationSiteSym &HAS) { + AutoIndent Indent(P, 7); + P.formatLine("type = {0}, addr = {1} call size = {2}", typeIndex(HAS.Type), + formatSegmentOffset(HAS.Segment, HAS.CodeOffset), + HAS.CallInstructionSize); + return Error::success(); +} + +Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, InlineSiteSym &IS) { + AutoIndent Indent(P, 7); + P.formatLine("inlinee = {0}, parent = {1}, end = {2}", idIndex(IS.Inlinee), + IS.Parent, IS.End); + + // Break down the annotation byte code and calculate code and line offsets. + // FIXME: It would be helpful if we could look up the initial file and inlinee + // lines offset using the inlinee index above. + uint32_t CodeOffset = 0; + int32_t LineOffset = 0; + for (auto &Annot : IS.annotations()) { + P.formatLine(" {0}", fmt_align(toHex(Annot.Bytes), AlignStyle::Left, 9)); + + auto formatCodeOffset = [&](uint32_t Delta) { + CodeOffset += Delta; + P.format(" code 0x{0} (+0x{1})", utohexstr(CodeOffset), utohexstr(Delta)); + }; + auto formatCodeLength = [&](uint32_t Length) { + // Notably, changing the code length does not affect the code offset. + P.format(" code end 0x{0} (+0x{1})", utohexstr(CodeOffset + Length), + utohexstr(Length)); + }; + auto formatLineOffset = [&](int32_t Delta) { + LineOffset += Delta; + char Sign = Delta > 0 ? '+' : '-'; + P.format(" line {0} ({1}{2})", LineOffset, Sign, std::abs(Delta)); + }; + + // Use the opcode to interpret the integer values. + switch (Annot.OpCode) { + case BinaryAnnotationsOpCode::Invalid: + break; + case BinaryAnnotationsOpCode::CodeOffset: + case BinaryAnnotationsOpCode::ChangeCodeOffset: + formatCodeOffset(Annot.U1); + break; + case BinaryAnnotationsOpCode::ChangeLineOffset: + formatLineOffset(Annot.S1); + break; + case BinaryAnnotationsOpCode::ChangeCodeLength: + formatCodeLength(Annot.U1); + // Apparently this annotation updates the code offset. It's hard to make + // MSVC produce this opcode, but clang uses it, and debuggers seem to use + // this interpretation. + CodeOffset += Annot.U1; + break; + case BinaryAnnotationsOpCode::ChangeCodeOffsetAndLineOffset: + formatCodeOffset(Annot.U1); + formatLineOffset(Annot.S1); + break; + case BinaryAnnotationsOpCode::ChangeCodeLengthAndCodeOffset: + formatCodeOffset(Annot.U2); + formatCodeLength(Annot.U1); + break; + + case BinaryAnnotationsOpCode::ChangeFile: { + uint32_t FileOffset = Annot.U1; + StringRef Filename = "<unknown>"; + if (SymGroup) { + if (Expected<StringRef> MaybeFile = + SymGroup->getNameFromStringTable(FileOffset)) + Filename = *MaybeFile; + else + return MaybeFile.takeError(); + } + P.format(" setfile {0} 0x{1}", utohexstr(FileOffset)); + break; + } + + // The rest of these are hard to convince MSVC to emit, so they are not as + // well understood. + case BinaryAnnotationsOpCode::ChangeCodeOffsetBase: + formatCodeOffset(Annot.U1); + break; + case BinaryAnnotationsOpCode::ChangeLineEndDelta: + case BinaryAnnotationsOpCode::ChangeRangeKind: + case BinaryAnnotationsOpCode::ChangeColumnStart: + case BinaryAnnotationsOpCode::ChangeColumnEnd: + P.format(" {0} {1}", Annot.Name, Annot.U1); + break; + case BinaryAnnotationsOpCode::ChangeColumnEndDelta: + P.format(" {0} {1}", Annot.Name, Annot.S1); + break; + } + } + return Error::success(); +} + +Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, + RegisterSym &Register) { + P.format(" `{0}`", Register.Name); + AutoIndent Indent(P, 7); + P.formatLine("register = {0}, type = {1}", + formatRegisterId(Register.Register, CompilationCPU), + typeIndex(Register.Index)); + return Error::success(); +} + +Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, + PublicSym32 &Public) { + P.format(" `{0}`", Public.Name); + AutoIndent Indent(P, 7); + P.formatLine("flags = {0}, addr = {1}", + formatPublicSymFlags(P.getIndentLevel() + 9, Public.Flags), + formatSegmentOffset(Public.Segment, Public.Offset)); + return Error::success(); +} + +Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, ProcRefSym &PR) { + P.format(" `{0}`", PR.Name); + AutoIndent Indent(P, 7); + P.formatLine("module = {0}, sum name = {1}, offset = {2}", PR.Module, + PR.SumName, PR.SymOffset); + return Error::success(); +} + +Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, LabelSym &Label) { + P.format(" `{0}` (addr = {1})", Label.Name, + formatSegmentOffset(Label.Segment, Label.CodeOffset)); + AutoIndent Indent(P, 7); + P.formatLine("flags = {0}", + formatProcSymFlags(P.getIndentLevel() + 9, Label.Flags)); + return Error::success(); +} + +Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, LocalSym &Local) { + P.format(" `{0}`", Local.Name); + AutoIndent Indent(P, 7); + + std::string FlagStr = + formatLocalSymFlags(P.getIndentLevel() + 9, Local.Flags); + P.formatLine("type={0}, flags = {1}", typeIndex(Local.Type), FlagStr); + return Error::success(); +} + +Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, + ObjNameSym &ObjName) { + P.format(" sig={0}, `{1}`", ObjName.Signature, ObjName.Name); + return Error::success(); +} + +Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, ProcSym &Proc) { + P.format(" `{0}`", Proc.Name); + AutoIndent Indent(P, 7); + P.formatLine("parent = {0}, end = {1}, addr = {2}, code size = {3}", + Proc.Parent, Proc.End, + formatSegmentOffset(Proc.Segment, Proc.CodeOffset), + Proc.CodeSize); + bool IsType = true; + switch (Proc.getKind()) { + case SymbolRecordKind::GlobalProcIdSym: + case SymbolRecordKind::ProcIdSym: + case SymbolRecordKind::DPCProcIdSym: + IsType = false; + break; + default: + break; + } + P.formatLine("type = `{0}`, debug start = {1}, debug end = {2}, flags = {3}", + typeOrIdIndex(Proc.FunctionType, IsType), Proc.DbgStart, + Proc.DbgEnd, + formatProcSymFlags(P.getIndentLevel() + 9, Proc.Flags)); + return Error::success(); +} + +Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, + ScopeEndSym &ScopeEnd) { + return Error::success(); +} + +Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, CallerSym &Caller) { + AutoIndent Indent(P, 7); + for (const auto &I : Caller.Indices) { + P.formatLine("callee: {0}", idIndex(I)); + } + return Error::success(); +} + +Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, + RegRelativeSym &RegRel) { + P.format(" `{0}`", RegRel.Name); + AutoIndent Indent(P, 7); + P.formatLine( + "type = {0}, register = {1}, offset = {2}", typeIndex(RegRel.Type), + formatRegisterId(RegRel.Register, CompilationCPU), RegRel.Offset); + return Error::success(); +} + +Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, + ThreadLocalDataSym &Data) { + P.format(" `{0}`", Data.Name); + AutoIndent Indent(P, 7); + P.formatLine("type = {0}, addr = {1}", typeIndex(Data.Type), + formatSegmentOffset(Data.Segment, Data.DataOffset)); + return Error::success(); +} + +Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, UDTSym &UDT) { + P.format(" `{0}`", UDT.Name); + AutoIndent Indent(P, 7); + P.formatLine("original type = {0}", UDT.Type); + return Error::success(); +} + +Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, + UsingNamespaceSym &UN) { + P.format(" `{0}`", UN.Name); + return Error::success(); +} + +Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, + AnnotationSym &Annot) { + AutoIndent Indent(P, 7); + P.formatLine("addr = {0}", formatSegmentOffset(Annot.Segment, Annot.CodeOffset)); + P.formatLine("strings = {0}", typesetStringList(P.getIndentLevel() + 9 + 2, + Annot.Strings)); + return Error::success(); +} diff --git a/contrib/libs/llvm12/tools/llvm-pdbutil/MinimalSymbolDumper.h b/contrib/libs/llvm12/tools/llvm-pdbutil/MinimalSymbolDumper.h new file mode 100644 index 0000000000..cdc75c1cfb --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-pdbutil/MinimalSymbolDumper.h @@ -0,0 +1,68 @@ +//===- MinimalSymbolDumper.h ---------------------------------- *- C++ --*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#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 SymbolGroup; + +class MinimalSymbolDumper : public codeview::SymbolVisitorCallbacks { +public: + MinimalSymbolDumper(LinePrinter &P, bool RecordBytes, + codeview::LazyRandomTypeCollection &Ids, + codeview::LazyRandomTypeCollection &Types) + : P(P), RecordBytes(RecordBytes), Ids(Ids), Types(Types) {} + MinimalSymbolDumper(LinePrinter &P, bool RecordBytes, + const SymbolGroup &SymGroup, + codeview::LazyRandomTypeCollection &Ids, + codeview::LazyRandomTypeCollection &Types) + : P(P), RecordBytes(RecordBytes), SymGroup(&SymGroup), Ids(Ids), + Types(Types) {} + + Error visitSymbolBegin(codeview::CVSymbol &Record) override; + Error visitSymbolBegin(codeview::CVSymbol &Record, uint32_t Offset) override; + Error visitSymbolEnd(codeview::CVSymbol &Record) override; + + void setSymbolGroup(const SymbolGroup *Group) { SymGroup = Group; } + +#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 typeOrIdIndex(codeview::TypeIndex TI, bool IsType) const; + + std::string typeIndex(codeview::TypeIndex TI) const; + std::string idIndex(codeview::TypeIndex TI) const; + + LinePrinter &P; + + /// Dumping certain records requires knowing what machine this is. The + /// S_COMPILE3 record will tell us, but if we don't see one, default to X64. + codeview::CPUType CompilationCPU = codeview::CPUType::X64; + + bool RecordBytes; + const SymbolGroup *SymGroup = nullptr; + codeview::LazyRandomTypeCollection &Ids; + codeview::LazyRandomTypeCollection &Types; +}; +} // namespace pdb +} // namespace llvm + +#endif diff --git a/contrib/libs/llvm12/tools/llvm-pdbutil/MinimalTypeDumper.cpp b/contrib/libs/llvm12/tools/llvm-pdbutil/MinimalTypeDumper.cpp new file mode 100644 index 0000000000..8e46a97272 --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-pdbutil/MinimalTypeDumper.cpp @@ -0,0 +1,592 @@ +//===- MinimalTypeDumper.cpp ---------------------------------- *- C++ --*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "MinimalTypeDumper.h" + +#include "FormatUtil.h" +#include "LinePrinter.h" +#include "TypeReferenceTracker.h" + +#include "llvm-pdbutil.h" +#include "llvm/DebugInfo/CodeView/CVRecord.h" +#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/Formatters.h" +#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/PDB/Native/TpiHashing.h" +#include "llvm/DebugInfo/PDB/Native/TpiStream.h" +#include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/MathExtras.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +static std::string formatClassOptions(uint32_t IndentLevel, + ClassOptions Options, TpiStream *Stream, + TypeIndex CurrentTypeIndex) { + std::vector<std::string> Opts; + + if (Stream && Stream->supportsTypeLookup() && + !opts::dump::DontResolveForwardRefs && + ((Options & ClassOptions::ForwardReference) != ClassOptions::None)) { + // If we're able to resolve forward references, do that. + Expected<TypeIndex> ETI = + Stream->findFullDeclForForwardRef(CurrentTypeIndex); + if (!ETI) { + consumeError(ETI.takeError()); + PUSH_FLAG(ClassOptions, ForwardReference, Options, "forward ref (??\?)"); + } else { + const char *Direction = (*ETI == CurrentTypeIndex) + ? "=" + : ((*ETI < CurrentTypeIndex) ? "<-" : "->"); + std::string Formatted = + formatv("forward ref ({0} {1})", Direction, *ETI).str(); + PUSH_FLAG(ClassOptions, ForwardReference, Options, std::move(Formatted)); + } + } else { + PUSH_FLAG(ClassOptions, ForwardReference, Options, "forward ref"); + } + + 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, HasUniqueName, Options, "has unique name"); + PUSH_FLAG(ClassOptions, Intrinsic, Options, "intrin"); + PUSH_FLAG(ClassOptions, Nested, Options, "is nested"); + PUSH_FLAG(ClassOptions, HasOverloadedOperator, Options, + "overloaded operator"); + PUSH_FLAG(ClassOptions, HasOverloadedAssignmentOperator, Options, + "overloaded operator="); + PUSH_FLAG(ClassOptions, Packed, Options, "packed"); + PUSH_FLAG(ClassOptions, Scoped, Options, "scoped"); + PUSH_FLAG(ClassOptions, Sealed, Options, "sealed"); + + return typesetItemList(Opts, 4, IndentLevel, " | "); +} + +static std::string pointerOptions(PointerOptions Options) { + std::vector<std::string> Opts; + PUSH_FLAG(PointerOptions, Flat32, Options, "flat32"); + PUSH_FLAG(PointerOptions, Volatile, Options, "volatile"); + PUSH_FLAG(PointerOptions, Const, Options, "const"); + PUSH_FLAG(PointerOptions, Unaligned, Options, "unaligned"); + PUSH_FLAG(PointerOptions, Restrict, Options, "restrict"); + PUSH_FLAG(PointerOptions, WinRTSmartPointer, Options, "winrt"); + if (Opts.empty()) + return "None"; + return join(Opts, " | "); +} + +static std::string modifierOptions(ModifierOptions Options) { + std::vector<std::string> Opts; + PUSH_FLAG(ModifierOptions, Const, Options, "const"); + PUSH_FLAG(ModifierOptions, Volatile, Options, "volatile"); + PUSH_FLAG(ModifierOptions, Unaligned, Options, "unaligned"); + if (Opts.empty()) + return "None"; + return join(Opts, " | "); +} + +static std::string formatCallingConvention(CallingConvention Convention) { + switch (Convention) { + RETURN_CASE(CallingConvention, AlphaCall, "alphacall"); + RETURN_CASE(CallingConvention, AM33Call, "am33call"); + RETURN_CASE(CallingConvention, ArmCall, "armcall"); + RETURN_CASE(CallingConvention, ClrCall, "clrcall"); + RETURN_CASE(CallingConvention, FarC, "far cdecl"); + RETURN_CASE(CallingConvention, FarFast, "far fastcall"); + RETURN_CASE(CallingConvention, FarPascal, "far pascal"); + RETURN_CASE(CallingConvention, FarStdCall, "far stdcall"); + RETURN_CASE(CallingConvention, FarSysCall, "far syscall"); + RETURN_CASE(CallingConvention, Generic, "generic"); + RETURN_CASE(CallingConvention, Inline, "inline"); + RETURN_CASE(CallingConvention, M32RCall, "m32rcall"); + RETURN_CASE(CallingConvention, MipsCall, "mipscall"); + RETURN_CASE(CallingConvention, NearC, "cdecl"); + RETURN_CASE(CallingConvention, NearFast, "fastcall"); + RETURN_CASE(CallingConvention, NearPascal, "pascal"); + RETURN_CASE(CallingConvention, NearStdCall, "stdcall"); + RETURN_CASE(CallingConvention, NearSysCall, "near syscall"); + RETURN_CASE(CallingConvention, NearVector, "vectorcall"); + RETURN_CASE(CallingConvention, PpcCall, "ppccall"); + RETURN_CASE(CallingConvention, SHCall, "shcall"); + RETURN_CASE(CallingConvention, SH5Call, "sh5call"); + RETURN_CASE(CallingConvention, ThisCall, "thiscall"); + RETURN_CASE(CallingConvention, TriCall, "tricall"); + } + return formatUnknownEnum(Convention); +} + +static std::string formatPointerMode(PointerMode Mode) { + switch (Mode) { + RETURN_CASE(PointerMode, LValueReference, "ref"); + RETURN_CASE(PointerMode, Pointer, "pointer"); + RETURN_CASE(PointerMode, PointerToDataMember, "data member pointer"); + RETURN_CASE(PointerMode, PointerToMemberFunction, "member fn pointer"); + RETURN_CASE(PointerMode, RValueReference, "rvalue ref"); + } + return formatUnknownEnum(Mode); +} + +static std::string memberAccess(MemberAccess Access) { + switch (Access) { + RETURN_CASE(MemberAccess, None, ""); + RETURN_CASE(MemberAccess, Private, "private"); + RETURN_CASE(MemberAccess, Protected, "protected"); + RETURN_CASE(MemberAccess, Public, "public"); + } + return formatUnknownEnum(Access); +} + +static std::string methodKind(MethodKind Kind) { + switch (Kind) { + RETURN_CASE(MethodKind, Vanilla, ""); + RETURN_CASE(MethodKind, Virtual, "virtual"); + RETURN_CASE(MethodKind, Static, "static"); + RETURN_CASE(MethodKind, Friend, "friend"); + RETURN_CASE(MethodKind, IntroducingVirtual, "intro virtual"); + RETURN_CASE(MethodKind, PureVirtual, "pure virtual"); + RETURN_CASE(MethodKind, PureIntroducingVirtual, "pure intro virtual"); + } + return formatUnknownEnum(Kind); +} + +static std::string pointerKind(PointerKind Kind) { + switch (Kind) { + RETURN_CASE(PointerKind, Near16, "ptr16"); + RETURN_CASE(PointerKind, Far16, "far ptr16"); + RETURN_CASE(PointerKind, Huge16, "huge ptr16"); + RETURN_CASE(PointerKind, BasedOnSegment, "segment based"); + RETURN_CASE(PointerKind, BasedOnValue, "value based"); + RETURN_CASE(PointerKind, BasedOnSegmentValue, "segment value based"); + RETURN_CASE(PointerKind, BasedOnAddress, "address based"); + RETURN_CASE(PointerKind, BasedOnSegmentAddress, "segment address based"); + RETURN_CASE(PointerKind, BasedOnType, "type based"); + RETURN_CASE(PointerKind, BasedOnSelf, "self based"); + RETURN_CASE(PointerKind, Near32, "ptr32"); + RETURN_CASE(PointerKind, Far32, "far ptr32"); + RETURN_CASE(PointerKind, Near64, "ptr64"); + } + return formatUnknownEnum(Kind); +} + +static std::string memberAttributes(const MemberAttributes &Attrs) { + std::vector<std::string> Opts; + std::string Access = memberAccess(Attrs.getAccess()); + std::string Kind = methodKind(Attrs.getMethodKind()); + if (!Access.empty()) + Opts.push_back(Access); + if (!Kind.empty()) + Opts.push_back(Kind); + MethodOptions Flags = Attrs.getFlags(); + PUSH_FLAG(MethodOptions, Pseudo, Flags, "pseudo"); + PUSH_FLAG(MethodOptions, NoInherit, Flags, "noinherit"); + PUSH_FLAG(MethodOptions, NoConstruct, Flags, "noconstruct"); + PUSH_FLAG(MethodOptions, CompilerGenerated, Flags, "compiler-generated"); + PUSH_FLAG(MethodOptions, Sealed, Flags, "sealed"); + return join(Opts, " "); +} + +static std::string formatPointerAttrs(const PointerRecord &Record) { + PointerMode Mode = Record.getMode(); + PointerOptions Opts = Record.getOptions(); + PointerKind Kind = Record.getPointerKind(); + return std::string(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) { + CurrentTypeIndex = 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), + formatTypeLeafKind(Record.kind()), Record.length()); + if (Hashes) { + std::string H; + if (Index.toArrayIndex() >= HashValues.size()) { + H = "(not present)"; + } else { + uint32_t Hash = HashValues[Index.toArrayIndex()]; + Expected<uint32_t> MaybeHash = hashTypeRecord(Record); + if (!MaybeHash) + return MaybeHash.takeError(); + uint32_t OurHash = *MaybeHash; + OurHash %= NumHashBuckets; + if (Hash == OurHash) + H = "0x" + utohexstr(Hash); + else + H = "0x" + utohexstr(Hash) + ", our hash = 0x" + utohexstr(OurHash); + } + P.format(", hash = {0}", H); + } + if (RefTracker) { + if (RefTracker->isTypeReferenced(Index)) + P.format(", referenced"); + else + P.format(", unreferenced"); + } + P.format("]"); + 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}", formatTypeLeafKind(Record.Kind)); + return Error::success(); +} + +Error MinimalTypeDumpVisitor::visitMemberEnd(CVMemberRecord &Record) { + if (RecordBytes) { + AutoIndent Indent(P, 2); + P.formatBinary("Bytes", Record.Data, 0); + } + return Error::success(); +} + +StringRef MinimalTypeDumpVisitor::getTypeName(TypeIndex TI) const { + if (TI.isNoneType()) + return ""; + return Types.getTypeName(TI); +} + +Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, + FieldListRecord &FieldList) { + if (auto EC = codeview::visitMemberRecordStream(FieldList.Data, *this)) + return EC; + + return Error::success(); +} + +Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, + StringIdRecord &String) { + P.format(" ID: {0}, String: {1}", String.getId(), String.getString()); + return Error::success(); +} + +Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, + ArgListRecord &Args) { + auto Indices = Args.getIndices(); + if (Indices.empty()) + return Error::success(); + + auto Max = std::max_element(Indices.begin(), Indices.end()); + uint32_t W = NumDigits(Max->getIndex()) + 2; + + for (auto I : Indices) + P.formatLine("{0}: `{1}`", fmt_align(I, AlignStyle::Right, W), + getTypeName(I)); + return Error::success(); +} + +Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, + StringListRecord &Strings) { + auto Indices = Strings.getIndices(); + if (Indices.empty()) + return Error::success(); + + auto Max = std::max_element(Indices.begin(), Indices.end()); + uint32_t W = NumDigits(Max->getIndex()) + 2; + + for (auto I : Indices) + P.formatLine("{0}: `{1}`", fmt_align(I, AlignStyle::Right, W), + getTypeName(I)); + return Error::success(); +} + +Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, + ClassRecord &Class) { + P.format(" `{0}`", Class.Name); + if (Class.hasUniqueName()) + P.formatLine("unique name: `{0}`", Class.UniqueName); + P.formatLine("vtable: {0}, base list: {1}, field list: {2}", + Class.VTableShape, Class.DerivationList, Class.FieldList); + P.formatLine("options: {0}, sizeof {1}", + formatClassOptions(P.getIndentLevel(), Class.Options, Stream, + CurrentTypeIndex), + Class.Size); + return Error::success(); +} + +Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, + UnionRecord &Union) { + P.format(" `{0}`", Union.Name); + if (Union.hasUniqueName()) + P.formatLine("unique name: `{0}`", Union.UniqueName); + P.formatLine("field list: {0}", Union.FieldList); + P.formatLine("options: {0}, sizeof {1}", + formatClassOptions(P.getIndentLevel(), Union.Options, Stream, + CurrentTypeIndex), + Union.Size); + return Error::success(); +} + +Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, EnumRecord &Enum) { + P.format(" `{0}`", Enum.Name); + if (Enum.hasUniqueName()) + P.formatLine("unique name: `{0}`", Enum.UniqueName); + P.formatLine("field list: {0}, underlying type: {1}", Enum.FieldList, + Enum.UnderlyingType); + P.formatLine("options: {0}", + formatClassOptions(P.getIndentLevel(), Enum.Options, Stream, + CurrentTypeIndex)); + return Error::success(); +} + +Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, ArrayRecord &AT) { + if (AT.Name.empty()) { + P.formatLine("size: {0}, index type: {1}, element type: {2}", AT.Size, + AT.IndexType, AT.ElementType); + } else { + P.formatLine("name: {0}, size: {1}, index type: {2}, element type: {3}", + AT.Name, AT.Size, AT.IndexType, AT.ElementType); + } + return Error::success(); +} + +Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, + VFTableRecord &VFT) { + P.formatLine("offset: {0}, complete class: {1}, overridden vftable: {2}", + VFT.VFPtrOffset, VFT.CompleteClass, VFT.OverriddenVFTable); + P.formatLine("method names: "); + if (!VFT.MethodNames.empty()) { + std::string Sep = + formatv("\n{0}", + fmt_repeat(' ', P.getIndentLevel() + strlen("method names: "))) + .str(); + P.print(join(VFT.MethodNames, Sep)); + } + return Error::success(); +} + +Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, + MemberFuncIdRecord &Id) { + P.formatLine("name = {0}, type = {1}, class type = {2}", Id.Name, + Id.FunctionType, Id.ClassType); + return Error::success(); +} + +Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, + ProcedureRecord &Proc) { + P.formatLine("return type = {0}, # args = {1}, param list = {2}", + Proc.ReturnType, Proc.ParameterCount, Proc.ArgumentList); + P.formatLine("calling conv = {0}, options = {1}", + formatCallingConvention(Proc.CallConv), + formatFunctionOptions(Proc.Options)); + return Error::success(); +} + +Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, + MemberFunctionRecord &MF) { + P.formatLine("return type = {0}, # args = {1}, param list = {2}", + MF.ReturnType, MF.ParameterCount, MF.ArgumentList); + P.formatLine("class type = {0}, this type = {1}, this adjust = {2}", + MF.ClassType, MF.ThisType, MF.ThisPointerAdjustment); + P.formatLine("calling conv = {0}, options = {1}", + formatCallingConvention(MF.CallConv), + formatFunctionOptions(MF.Options)); + return Error::success(); +} + +Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, + FuncIdRecord &Func) { + P.formatLine("name = {0}, type = {1}, parent scope = {2}", Func.Name, + Func.FunctionType, Func.ParentScope); + return Error::success(); +} + +Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, + TypeServer2Record &TS) { + P.formatLine("name = {0}, age = {1}, guid = {2}", TS.Name, TS.Age, TS.Guid); + return Error::success(); +} + +Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, + PointerRecord &Ptr) { + P.formatLine("referent = {0}, {1}", Ptr.ReferentType, + formatPointerAttrs(Ptr)); + return Error::success(); +} + +Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, + ModifierRecord &Mod) { + P.formatLine("referent = {0}, modifiers = {1}", Mod.ModifiedType, + modifierOptions(Mod.Modifiers)); + return Error::success(); +} + +Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, + VFTableShapeRecord &Shape) { + return Error::success(); +} + +Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, + UdtModSourceLineRecord &U) { + P.formatLine("udt = {0}, mod = {1}, file = {2}, line = {3}", U.UDT, U.Module, + U.SourceFile.getIndex(), U.LineNumber); + return Error::success(); +} + +Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, + UdtSourceLineRecord &U) { + P.formatLine("udt = {0}, file = {1}, line = {2}", U.UDT, + U.SourceFile.getIndex(), U.LineNumber); + return Error::success(); +} + +Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, + BitFieldRecord &BF) { + P.formatLine("type = {0}, bit offset = {1}, # bits = {2}", BF.Type, + BF.BitOffset, BF.BitSize); + return Error::success(); +} + +Error MinimalTypeDumpVisitor::visitKnownRecord( + CVType &CVR, MethodOverloadListRecord &Overloads) { + for (auto &M : Overloads.Methods) + P.formatLine("- Method [type = {0}, vftable offset = {1}, attrs = {2}]", + M.Type, M.VFTableOffset, memberAttributes(M.Attrs)); + return Error::success(); +} + +Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, + BuildInfoRecord &BI) { + auto Indices = BI.ArgIndices; + if (Indices.empty()) + return Error::success(); + + auto Max = std::max_element(Indices.begin(), Indices.end()); + uint32_t W = NumDigits(Max->getIndex()) + 2; + + for (auto I : Indices) + P.formatLine("{0}: `{1}`", fmt_align(I, AlignStyle::Right, W), + getTypeName(I)); + return Error::success(); +} + +Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, LabelRecord &R) { + std::string Type = (R.Mode == LabelType::Far) ? "far" : "near"; + P.format(" type = {0}", Type); + return Error::success(); +} + +Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, + PrecompRecord &Precomp) { + P.format(" start index = {0:X+}, types count = {1:X+}, signature = {2:X+}," + " precomp path = {3}", + Precomp.StartTypeIndex, Precomp.TypesCount, Precomp.Signature, + Precomp.PrecompFilePath); + return Error::success(); +} + +Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, + EndPrecompRecord &EP) { + P.format(" signature = {0:X+}", EP.Signature); + return Error::success(); +} + +Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, + NestedTypeRecord &Nested) { + P.format(" [name = `{0}`, parent = {1}]", Nested.Name, Nested.Type); + return Error::success(); +} + +Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, + OneMethodRecord &Method) { + P.format(" [name = `{0}`]", Method.Name); + AutoIndent Indent(P); + P.formatLine("type = {0}, vftable offset = {1}, attrs = {2}", Method.Type, + Method.VFTableOffset, memberAttributes(Method.Attrs)); + return Error::success(); +} + +Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, + OverloadedMethodRecord &Method) { + P.format(" [name = `{0}`, # overloads = {1}, overload list = {2}]", + Method.Name, Method.NumOverloads, Method.MethodList); + return Error::success(); +} + +Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, + DataMemberRecord &Field) { + P.format(" [name = `{0}`, Type = {1}, offset = {2}, attrs = {3}]", Field.Name, + Field.Type, Field.FieldOffset, memberAttributes(Field.Attrs)); + return Error::success(); +} + +Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, + StaticDataMemberRecord &Field) { + P.format(" [name = `{0}`, type = {1}, attrs = {2}]", Field.Name, Field.Type, + memberAttributes(Field.Attrs)); + return Error::success(); +} + +Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, + EnumeratorRecord &Enum) { + P.format(" [{0} = {1}]", Enum.Name, + Enum.Value.toString(10, Enum.Value.isSigned())); + return Error::success(); +} + +Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, + BaseClassRecord &Base) { + AutoIndent Indent(P); + P.formatLine("type = {0}, offset = {1}, attrs = {2}", Base.Type, Base.Offset, + memberAttributes(Base.Attrs)); + return Error::success(); +} + +Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, + VirtualBaseClassRecord &Base) { + AutoIndent Indent(P); + P.formatLine( + "base = {0}, vbptr = {1}, vbptr offset = {2}, vtable index = {3}", + Base.BaseType, Base.VBPtrType, Base.VBPtrOffset, Base.VTableIndex); + P.formatLine("attrs = {0}", memberAttributes(Base.Attrs)); + return Error::success(); +} + +Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, + ListContinuationRecord &Cont) { + P.format(" continuation = {0}", Cont.ContinuationIndex); + return Error::success(); +} + +Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, + VFPtrRecord &VFP) { + P.format(" type = {0}", VFP.Type); + return Error::success(); +} diff --git a/contrib/libs/llvm12/tools/llvm-pdbutil/MinimalTypeDumper.h b/contrib/libs/llvm12/tools/llvm-pdbutil/MinimalTypeDumper.h new file mode 100644 index 0000000000..6bc456d47a --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-pdbutil/MinimalTypeDumper.h @@ -0,0 +1,70 @@ +//===- MinimalTypeDumper.h ------------------------------------ *- C++ --*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMPDBUTIL_MINIMAL_TYPE_DUMPER_H +#define LLVM_TOOLS_LLVMPDBUTIL_MINIMAL_TYPE_DUMPER_H + +#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" +#include "llvm/Support/BinaryStreamArray.h" + +namespace llvm { +namespace codeview { +class LazyRandomTypeCollection; +} + +namespace pdb { +class LinePrinter; +class TpiStream; +class TypeReferenceTracker; + +class MinimalTypeDumpVisitor : public codeview::TypeVisitorCallbacks { +public: + MinimalTypeDumpVisitor(LinePrinter &P, uint32_t Width, bool RecordBytes, + bool Hashes, codeview::LazyRandomTypeCollection &Types, + TypeReferenceTracker *RefTracker, + uint32_t NumHashBuckets, + FixedStreamArray<support::ulittle32_t> HashValues, + pdb::TpiStream *Stream) + : P(P), Width(Width), RecordBytes(RecordBytes), Hashes(Hashes), + Types(Types), RefTracker(RefTracker), NumHashBuckets(NumHashBuckets), + HashValues(HashValues), Stream(Stream) {} + + Error visitTypeBegin(codeview::CVType &Record, + codeview::TypeIndex Index) override; + Error visitTypeEnd(codeview::CVType &Record) override; + Error visitMemberBegin(codeview::CVMemberRecord &Record) override; + Error visitMemberEnd(codeview::CVMemberRecord &Record) override; + +#define TYPE_RECORD(EnumName, EnumVal, Name) \ + Error visitKnownRecord(codeview::CVType &CVR, \ + codeview::Name##Record &Record) override; +#define MEMBER_RECORD(EnumName, EnumVal, Name) \ + Error visitKnownMember(codeview::CVMemberRecord &CVR, \ + codeview::Name##Record &Record) override; +#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) +#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) +#include "llvm/DebugInfo/CodeView/CodeViewTypes.def" + +private: + StringRef getTypeName(codeview::TypeIndex TI) const; + + LinePrinter &P; + uint32_t Width; + bool RecordBytes = false; + bool Hashes = false; + codeview::LazyRandomTypeCollection &Types; + pdb::TypeReferenceTracker *RefTracker = nullptr; + uint32_t NumHashBuckets; + codeview::TypeIndex CurrentTypeIndex; + FixedStreamArray<support::ulittle32_t> HashValues; + pdb::TpiStream *Stream = nullptr; +}; +} // namespace pdb +} // namespace llvm + +#endif diff --git a/contrib/libs/llvm12/tools/llvm-pdbutil/OutputStyle.h b/contrib/libs/llvm12/tools/llvm-pdbutil/OutputStyle.h new file mode 100644 index 0000000000..40b0de8bdf --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-pdbutil/OutputStyle.h @@ -0,0 +1,27 @@ +//===- OutputStyle.h ------------------------------------------ *- C++ --*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMPDBDUMP_OUTPUTSTYLE_H +#define LLVM_TOOLS_LLVMPDBDUMP_OUTPUTSTYLE_H + +#include "llvm/Support/Error.h" + +namespace llvm { +namespace pdb { +class PDBFile; + +class OutputStyle { +public: + virtual ~OutputStyle() {} + + virtual Error dump() = 0; +}; +} +} + +#endif diff --git a/contrib/libs/llvm12/tools/llvm-pdbutil/PdbYaml.cpp b/contrib/libs/llvm12/tools/llvm-pdbutil/PdbYaml.cpp new file mode 100644 index 0000000000..a26241967b --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-pdbutil/PdbYaml.cpp @@ -0,0 +1,189 @@ +//===-- PdbYaml.cpp ------------------------------------------- *- C++ --*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "PdbYaml.h" + +#include "llvm/ADT/StringExtras.h" +#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/RawTypes.h" +#include "llvm/DebugInfo/PDB/Native/TpiHashing.h" +#include "llvm/DebugInfo/PDB/PDBTypes.h" +#include "llvm/ObjectYAML/CodeViewYAMLDebugSections.h" +#include "llvm/ObjectYAML/CodeViewYAMLTypes.h" + +using namespace llvm; +using namespace llvm::pdb; +using namespace llvm::pdb::yaml; +using namespace llvm::yaml; + +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::NamedStreamMapping) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::PdbDbiModuleInfo) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::StreamBlockList) +LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::pdb::PdbRaw_FeatureSig) + +namespace llvm { +namespace yaml { + +template <> struct ScalarEnumerationTraits<llvm::pdb::PDB_Machine> { + static void enumeration(IO &io, llvm::pdb::PDB_Machine &Value) { + io.enumCase(Value, "Invalid", PDB_Machine::Invalid); + io.enumCase(Value, "Am33", PDB_Machine::Am33); + io.enumCase(Value, "Amd64", PDB_Machine::Amd64); + io.enumCase(Value, "Arm", PDB_Machine::Arm); + io.enumCase(Value, "ArmNT", PDB_Machine::ArmNT); + io.enumCase(Value, "Ebc", PDB_Machine::Ebc); + io.enumCase(Value, "x86", PDB_Machine::x86); + io.enumCase(Value, "Ia64", PDB_Machine::Ia64); + io.enumCase(Value, "M32R", PDB_Machine::M32R); + io.enumCase(Value, "Mips16", PDB_Machine::Mips16); + io.enumCase(Value, "MipsFpu", PDB_Machine::MipsFpu); + io.enumCase(Value, "MipsFpu16", PDB_Machine::MipsFpu16); + io.enumCase(Value, "PowerPCFP", PDB_Machine::PowerPCFP); + io.enumCase(Value, "R4000", PDB_Machine::R4000); + io.enumCase(Value, "SH3", PDB_Machine::SH3); + io.enumCase(Value, "SH3DSP", PDB_Machine::SH3DSP); + io.enumCase(Value, "Thumb", PDB_Machine::Thumb); + io.enumCase(Value, "WceMipsV2", PDB_Machine::WceMipsV2); + io.enumCase(Value, "Arm64", PDB_Machine::Arm64); + } +}; + +template <> struct ScalarEnumerationTraits<llvm::pdb::PdbRaw_DbiVer> { + static void enumeration(IO &io, llvm::pdb::PdbRaw_DbiVer &Value) { + io.enumCase(Value, "V41", llvm::pdb::PdbRaw_DbiVer::PdbDbiVC41); + io.enumCase(Value, "V50", llvm::pdb::PdbRaw_DbiVer::PdbDbiV50); + io.enumCase(Value, "V60", llvm::pdb::PdbRaw_DbiVer::PdbDbiV60); + io.enumCase(Value, "V70", llvm::pdb::PdbRaw_DbiVer::PdbDbiV70); + io.enumCase(Value, "V110", llvm::pdb::PdbRaw_DbiVer::PdbDbiV110); + } +}; + +template <> struct ScalarEnumerationTraits<llvm::pdb::PdbRaw_ImplVer> { + static void enumeration(IO &io, llvm::pdb::PdbRaw_ImplVer &Value) { + io.enumCase(Value, "VC2", llvm::pdb::PdbRaw_ImplVer::PdbImplVC2); + io.enumCase(Value, "VC4", llvm::pdb::PdbRaw_ImplVer::PdbImplVC4); + io.enumCase(Value, "VC41", llvm::pdb::PdbRaw_ImplVer::PdbImplVC41); + io.enumCase(Value, "VC50", llvm::pdb::PdbRaw_ImplVer::PdbImplVC50); + io.enumCase(Value, "VC98", llvm::pdb::PdbRaw_ImplVer::PdbImplVC98); + io.enumCase(Value, "VC70Dep", llvm::pdb::PdbRaw_ImplVer::PdbImplVC70Dep); + io.enumCase(Value, "VC70", llvm::pdb::PdbRaw_ImplVer::PdbImplVC70); + io.enumCase(Value, "VC80", llvm::pdb::PdbRaw_ImplVer::PdbImplVC80); + io.enumCase(Value, "VC110", llvm::pdb::PdbRaw_ImplVer::PdbImplVC110); + io.enumCase(Value, "VC140", llvm::pdb::PdbRaw_ImplVer::PdbImplVC140); + } +}; + +template <> struct ScalarEnumerationTraits<llvm::pdb::PdbRaw_TpiVer> { + static void enumeration(IO &io, llvm::pdb::PdbRaw_TpiVer &Value) { + io.enumCase(Value, "VC40", llvm::pdb::PdbRaw_TpiVer::PdbTpiV40); + io.enumCase(Value, "VC41", llvm::pdb::PdbRaw_TpiVer::PdbTpiV41); + io.enumCase(Value, "VC50", llvm::pdb::PdbRaw_TpiVer::PdbTpiV50); + io.enumCase(Value, "VC70", llvm::pdb::PdbRaw_TpiVer::PdbTpiV70); + io.enumCase(Value, "VC80", llvm::pdb::PdbRaw_TpiVer::PdbTpiV80); + } +}; + +template <> struct ScalarEnumerationTraits<llvm::pdb::PdbRaw_FeatureSig> { + static void enumeration(IO &io, PdbRaw_FeatureSig &Features) { + io.enumCase(Features, "MinimalDebugInfo", + PdbRaw_FeatureSig::MinimalDebugInfo); + io.enumCase(Features, "NoTypeMerge", PdbRaw_FeatureSig::NoTypeMerge); + io.enumCase(Features, "VC110", PdbRaw_FeatureSig::VC110); + io.enumCase(Features, "VC140", PdbRaw_FeatureSig::VC140); + } +}; +} +} + +void MappingTraits<PdbObject>::mapping(IO &IO, PdbObject &Obj) { + IO.mapOptional("MSF", Obj.Headers); + IO.mapOptional("StreamSizes", Obj.StreamSizes); + IO.mapOptional("StreamMap", Obj.StreamMap); + IO.mapOptional("StringTable", Obj.StringTable); + IO.mapOptional("PdbStream", Obj.PdbStream); + IO.mapOptional("DbiStream", Obj.DbiStream); + IO.mapOptional("TpiStream", Obj.TpiStream); + IO.mapOptional("IpiStream", Obj.IpiStream); + IO.mapOptional("PublicsStream", Obj.PublicsStream); +} + +void MappingTraits<MSFHeaders>::mapping(IO &IO, MSFHeaders &Obj) { + IO.mapOptional("SuperBlock", Obj.SuperBlock); + IO.mapOptional("NumDirectoryBlocks", Obj.NumDirectoryBlocks); + IO.mapOptional("DirectoryBlocks", Obj.DirectoryBlocks); + IO.mapOptional("NumStreams", Obj.NumStreams); + IO.mapOptional("FileSize", Obj.FileSize); +} + +void MappingTraits<msf::SuperBlock>::mapping(IO &IO, msf::SuperBlock &SB) { + if (!IO.outputting()) { + ::memcpy(SB.MagicBytes, msf::Magic, sizeof(msf::Magic)); + } + + using u32 = support::ulittle32_t; + IO.mapOptional("BlockSize", SB.BlockSize, u32(4096U)); + IO.mapOptional("FreeBlockMap", SB.FreeBlockMapBlock, u32(0U)); + IO.mapOptional("NumBlocks", SB.NumBlocks, u32(0U)); + IO.mapOptional("NumDirectoryBytes", SB.NumDirectoryBytes, u32(0U)); + IO.mapOptional("Unknown1", SB.Unknown1, u32(0U)); + IO.mapOptional("BlockMapAddr", SB.BlockMapAddr, u32(0U)); +} + +void MappingTraits<StreamBlockList>::mapping(IO &IO, StreamBlockList &SB) { + IO.mapRequired("Stream", SB.Blocks); +} + +void MappingTraits<PdbInfoStream>::mapping(IO &IO, PdbInfoStream &Obj) { + IO.mapOptional("Age", Obj.Age, 1U); + IO.mapOptional("Guid", Obj.Guid); + IO.mapOptional("Signature", Obj.Signature, 0U); + IO.mapOptional("Features", Obj.Features); + IO.mapOptional("Version", Obj.Version, PdbImplVC70); +} + +void MappingTraits<PdbDbiStream>::mapping(IO &IO, PdbDbiStream &Obj) { + IO.mapOptional("VerHeader", Obj.VerHeader, PdbDbiV70); + IO.mapOptional("Age", Obj.Age, 1U); + IO.mapOptional("BuildNumber", Obj.BuildNumber, uint16_t(0U)); + IO.mapOptional("PdbDllVersion", Obj.PdbDllVersion, 0U); + IO.mapOptional("PdbDllRbld", Obj.PdbDllRbld, uint16_t(0U)); + IO.mapOptional("Flags", Obj.Flags, uint16_t(1U)); + IO.mapOptional("MachineType", Obj.MachineType, PDB_Machine::x86); + IO.mapOptional("Modules", Obj.ModInfos); +} + +void MappingTraits<PdbTpiStream>::mapping(IO &IO, + pdb::yaml::PdbTpiStream &Obj) { + IO.mapOptional("Version", Obj.Version, PdbTpiV80); + IO.mapRequired("Records", Obj.Records); +} + +void MappingTraits<PdbPublicsStream>::mapping( + IO &IO, pdb::yaml::PdbPublicsStream &Obj) { + IO.mapRequired("Records", Obj.PubSyms); +} + +void MappingTraits<NamedStreamMapping>::mapping(IO &IO, + NamedStreamMapping &Obj) { + IO.mapRequired("Name", Obj.StreamName); + IO.mapRequired("StreamNum", Obj.StreamNumber); +} + +void MappingTraits<PdbModiStream>::mapping(IO &IO, PdbModiStream &Obj) { + IO.mapOptional("Signature", Obj.Signature, 4U); + IO.mapRequired("Records", Obj.Symbols); +} + +void MappingTraits<PdbDbiModuleInfo>::mapping(IO &IO, PdbDbiModuleInfo &Obj) { + IO.mapRequired("Module", Obj.Mod); + IO.mapOptional("ObjFile", Obj.Obj, Obj.Mod); + IO.mapOptional("SourceFiles", Obj.SourceFiles); + IO.mapOptional("Subsections", Obj.Subsections); + IO.mapOptional("Modi", Obj.Modi); +} diff --git a/contrib/libs/llvm12/tools/llvm-pdbutil/PdbYaml.h b/contrib/libs/llvm12/tools/llvm-pdbutil/PdbYaml.h new file mode 100644 index 0000000000..ed6346c2c4 --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-pdbutil/PdbYaml.h @@ -0,0 +1,130 @@ +//===- PdbYAML.h ---------------------------------------------- *- C++ --*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMPDBDUMP_PDBYAML_H +#define LLVM_TOOLS_LLVMPDBDUMP_PDBYAML_H + +#include "OutputStyle.h" + +#include "llvm/ADT/Optional.h" +#include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/MSF/MSFCommon.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/RawConstants.h" +#include "llvm/DebugInfo/PDB/PDBTypes.h" +#include "llvm/ObjectYAML/CodeViewYAMLDebugSections.h" +#include "llvm/ObjectYAML/CodeViewYAMLSymbols.h" +#include "llvm/ObjectYAML/CodeViewYAMLTypes.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/YAMLTraits.h" + +#include <vector> + +namespace llvm { +namespace codeview { +class DebugStringTableSubsection; +} +namespace pdb { + +namespace yaml { +struct SerializationContext; + +struct MSFHeaders { + msf::SuperBlock SuperBlock; + uint32_t NumDirectoryBlocks = 0; + std::vector<uint32_t> DirectoryBlocks; + uint32_t NumStreams = 0; + uint32_t FileSize = 0; +}; + +struct StreamBlockList { + std::vector<uint32_t> Blocks; +}; + +struct NamedStreamMapping { + StringRef StreamName; + uint32_t StreamNumber; +}; + +struct PdbInfoStream { + PdbRaw_ImplVer Version = PdbImplVC70; + uint32_t Signature = 0; + uint32_t Age = 1; + codeview::GUID Guid; + std::vector<PdbRaw_FeatureSig> Features; + std::vector<NamedStreamMapping> NamedStreams; +}; + +struct PdbModiStream { + uint32_t Signature; + std::vector<CodeViewYAML::SymbolRecord> Symbols; +}; + +struct PdbDbiModuleInfo { + StringRef Obj; + StringRef Mod; + std::vector<StringRef> SourceFiles; + std::vector<CodeViewYAML::YAMLDebugSubsection> Subsections; + Optional<PdbModiStream> Modi; +}; + +struct PdbDbiStream { + PdbRaw_DbiVer VerHeader = PdbDbiV70; + uint32_t Age = 1; + uint16_t BuildNumber = 0; + uint32_t PdbDllVersion = 0; + uint16_t PdbDllRbld = 0; + uint16_t Flags = 1; + PDB_Machine MachineType = PDB_Machine::x86; + + std::vector<PdbDbiModuleInfo> ModInfos; +}; + +struct PdbTpiStream { + PdbRaw_TpiVer Version = PdbTpiV80; + std::vector<CodeViewYAML::LeafRecord> Records; +}; + +struct PdbPublicsStream { + std::vector<CodeViewYAML::SymbolRecord> PubSyms; +}; + +struct PdbObject { + explicit PdbObject(BumpPtrAllocator &Allocator) : Allocator(Allocator) {} + + Optional<MSFHeaders> Headers; + Optional<std::vector<uint32_t>> StreamSizes; + Optional<std::vector<StreamBlockList>> StreamMap; + Optional<PdbInfoStream> PdbStream; + Optional<PdbDbiStream> DbiStream; + Optional<PdbTpiStream> TpiStream; + Optional<PdbTpiStream> IpiStream; + Optional<PdbPublicsStream> PublicsStream; + + Optional<std::vector<StringRef>> StringTable; + + BumpPtrAllocator &Allocator; +}; +} +} +} + +LLVM_YAML_DECLARE_MAPPING_TRAITS(pdb::yaml::PdbObject) +LLVM_YAML_DECLARE_MAPPING_TRAITS(pdb::yaml::MSFHeaders) +LLVM_YAML_DECLARE_MAPPING_TRAITS(msf::SuperBlock) +LLVM_YAML_DECLARE_MAPPING_TRAITS(pdb::yaml::StreamBlockList) +LLVM_YAML_DECLARE_MAPPING_TRAITS(pdb::yaml::PdbInfoStream) +LLVM_YAML_DECLARE_MAPPING_TRAITS(pdb::yaml::PdbDbiStream) +LLVM_YAML_DECLARE_MAPPING_TRAITS(pdb::yaml::PdbTpiStream) +LLVM_YAML_DECLARE_MAPPING_TRAITS(pdb::yaml::PdbPublicsStream) +LLVM_YAML_DECLARE_MAPPING_TRAITS(pdb::yaml::NamedStreamMapping) +LLVM_YAML_DECLARE_MAPPING_TRAITS(pdb::yaml::PdbModiStream) +LLVM_YAML_DECLARE_MAPPING_TRAITS(pdb::yaml::PdbDbiModuleInfo) + +#endif // LLVM_TOOLS_LLVMPDBDUMP_PDBYAML_H diff --git a/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyBuiltinDumper.cpp b/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyBuiltinDumper.cpp new file mode 100644 index 0000000000..cd01a40048 --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyBuiltinDumper.cpp @@ -0,0 +1,97 @@ +//===- PrettyBuiltinDumper.cpp ---------------------------------- *- C++ *-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "PrettyBuiltinDumper.h" +#include "LinePrinter.h" + +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" + +using namespace llvm; +using namespace llvm::pdb; + +BuiltinDumper::BuiltinDumper(LinePrinter &P) + : PDBSymDumper(false), Printer(P) {} + +void BuiltinDumper::start(const PDBSymbolTypeBuiltin &Symbol) { + if (Symbol.isConstType()) + WithColor(Printer, PDB_ColorItem::Keyword).get() << "const "; + if (Symbol.isVolatileType()) + WithColor(Printer, PDB_ColorItem::Keyword).get() << "volatile "; + WithColor(Printer, PDB_ColorItem::Type).get() << getTypeName(Symbol); +} + +StringRef BuiltinDumper::getTypeName(const PDBSymbolTypeBuiltin &Symbol) { + PDB_BuiltinType Type = Symbol.getBuiltinType(); + switch (Type) { + case PDB_BuiltinType::Float: + if (Symbol.getLength() == 4) + return "float"; + return "double"; + case PDB_BuiltinType::UInt: + switch (Symbol.getLength()) { + case 8: + return "unsigned __int64"; + case 4: + return "unsigned int"; + case 2: + return "unsigned short"; + case 1: + return "unsigned char"; + default: + return "unsigned"; + } + case PDB_BuiltinType::Int: + switch (Symbol.getLength()) { + case 8: + return "__int64"; + case 4: + return "int"; + case 2: + return "short"; + case 1: + return "char"; + default: + return "int"; + } + case PDB_BuiltinType::Char: + return "char"; + case PDB_BuiltinType::WCharT: + return "wchar_t"; + case PDB_BuiltinType::Void: + return "void"; + case PDB_BuiltinType::Long: + return "long"; + case PDB_BuiltinType::ULong: + return "unsigned long"; + case PDB_BuiltinType::Bool: + return "bool"; + case PDB_BuiltinType::Currency: + return "CURRENCY"; + case PDB_BuiltinType::Date: + return "DATE"; + case PDB_BuiltinType::Variant: + return "VARIANT"; + case PDB_BuiltinType::Complex: + return "complex"; + case PDB_BuiltinType::Bitfield: + return "bitfield"; + case PDB_BuiltinType::BSTR: + return "BSTR"; + case PDB_BuiltinType::HResult: + return "HRESULT"; + case PDB_BuiltinType::BCD: + return "HRESULT"; + case PDB_BuiltinType::Char16: + return "char16_t"; + case PDB_BuiltinType::Char32: + return "char32_t"; + case PDB_BuiltinType::None: + return "..."; + } + llvm_unreachable("Unknown PDB_BuiltinType"); +} diff --git a/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyBuiltinDumper.h b/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyBuiltinDumper.h new file mode 100644 index 0000000000..3bdef34c48 --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyBuiltinDumper.h @@ -0,0 +1,34 @@ +//===- PrettyBuiltinDumper.h ---------------------------------- *- C++ --*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMPDBDUMP_PRETTYBUILTINDUMPER_H +#define LLVM_TOOLS_LLVMPDBDUMP_PRETTYBUILTINDUMPER_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" + +namespace llvm { +namespace pdb { + +class LinePrinter; + +class BuiltinDumper : public PDBSymDumper { +public: + BuiltinDumper(LinePrinter &P); + + void start(const PDBSymbolTypeBuiltin &Symbol); + +private: + StringRef getTypeName(const PDBSymbolTypeBuiltin &Symbol); + + LinePrinter &Printer; +}; +} +} + +#endif diff --git a/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyClassDefinitionDumper.cpp b/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyClassDefinitionDumper.cpp new file mode 100644 index 0000000000..b7eccac598 --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyClassDefinitionDumper.cpp @@ -0,0 +1,114 @@ +//===- PrettyClassDefinitionDumper.cpp --------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "PrettyClassDefinitionDumper.h" + +#include "LinePrinter.h" +#include "PrettyClassLayoutGraphicalDumper.h" +#include "llvm-pdbutil.h" + +#include "llvm/ADT/APFloat.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" +#include "llvm/DebugInfo/PDB/UDTLayout.h" + +#include "llvm/Support/Format.h" + +using namespace llvm; +using namespace llvm::pdb; + +ClassDefinitionDumper::ClassDefinitionDumper(LinePrinter &P) + : PDBSymDumper(true), Printer(P) {} + +void ClassDefinitionDumper::start(const PDBSymbolTypeUDT &Class) { + assert(opts::pretty::ClassFormat != + opts::pretty::ClassDefinitionFormat::None); + + ClassLayout Layout(Class); + start(Layout); +} + +void ClassDefinitionDumper::start(const ClassLayout &Layout) { + prettyPrintClassIntro(Layout); + + PrettyClassLayoutGraphicalDumper Dumper(Printer, 1, 0); + DumpedAnything |= Dumper.start(Layout); + + prettyPrintClassOutro(Layout); +} + +void ClassDefinitionDumper::prettyPrintClassIntro(const ClassLayout &Layout) { + DumpedAnything = false; + Printer.NewLine(); + + uint32_t Size = Layout.getSize(); + const PDBSymbolTypeUDT &Class = Layout.getClass(); + + if (Layout.getClass().isConstType()) + WithColor(Printer, PDB_ColorItem::Keyword).get() << "const "; + if (Layout.getClass().isVolatileType()) + WithColor(Printer, PDB_ColorItem::Keyword).get() << "volatile "; + if (Layout.getClass().isUnalignedType()) + WithColor(Printer, PDB_ColorItem::Keyword).get() << "unaligned "; + + WithColor(Printer, PDB_ColorItem::Keyword).get() << Class.getUdtKind() << " "; + WithColor(Printer, PDB_ColorItem::Type).get() << Class.getName(); + WithColor(Printer, PDB_ColorItem::Comment).get() << " [sizeof = " << Size + << "]"; + uint32_t BaseCount = Layout.bases().size(); + if (BaseCount > 0) { + Printer.Indent(); + char NextSeparator = ':'; + for (auto BC : Layout.bases()) { + const auto &Base = BC->getBase(); + if (Base.isIndirectVirtualBaseClass()) + continue; + + Printer.NewLine(); + Printer << NextSeparator << " "; + WithColor(Printer, PDB_ColorItem::Keyword).get() << Base.getAccess(); + if (BC->isVirtualBase()) + WithColor(Printer, PDB_ColorItem::Keyword).get() << " virtual"; + + WithColor(Printer, PDB_ColorItem::Type).get() << " " << Base.getName(); + NextSeparator = ','; + } + + Printer.Unindent(); + } + + Printer << " {"; + Printer.Indent(); +} + +void ClassDefinitionDumper::prettyPrintClassOutro(const ClassLayout &Layout) { + Printer.Unindent(); + if (DumpedAnything) + Printer.NewLine(); + Printer << "}"; + Printer.NewLine(); + if (Layout.deepPaddingSize() > 0) { + APFloat Pct(100.0 * (double)Layout.deepPaddingSize() / + (double)Layout.getSize()); + SmallString<8> PctStr; + Pct.toString(PctStr, 4); + WithColor(Printer, PDB_ColorItem::Padding).get() + << "Total padding " << Layout.deepPaddingSize() << " bytes (" << PctStr + << "% of class size)"; + Printer.NewLine(); + APFloat Pct2(100.0 * (double)Layout.immediatePadding() / + (double)Layout.getSize()); + PctStr.clear(); + Pct2.toString(PctStr, 4); + WithColor(Printer, PDB_ColorItem::Padding).get() + << "Immediate padding " << Layout.immediatePadding() << " bytes (" + << PctStr << "% of class size)"; + Printer.NewLine(); + } +} diff --git a/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyClassDefinitionDumper.h b/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyClassDefinitionDumper.h new file mode 100644 index 0000000000..f43c5c11bd --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyClassDefinitionDumper.h @@ -0,0 +1,46 @@ +//===- PrettyClassDefinitionDumper.h ----------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMPDBDUMP_PRETTYCLASSDEFINITIONDUMPER_H +#define LLVM_TOOLS_LLVMPDBDUMP_PRETTYCLASSDEFINITIONDUMPER_H + +#include "llvm/ADT/BitVector.h" + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" +#include "llvm/DebugInfo/PDB/PDBSymbolData.h" +#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h" + +#include <list> +#include <memory> +#include <unordered_map> + +namespace llvm { +class BitVector; + +namespace pdb { + +class ClassLayout; +class LinePrinter; + +class ClassDefinitionDumper : public PDBSymDumper { +public: + ClassDefinitionDumper(LinePrinter &P); + + void start(const PDBSymbolTypeUDT &Class); + void start(const ClassLayout &Class); + +private: + void prettyPrintClassIntro(const ClassLayout &Class); + void prettyPrintClassOutro(const ClassLayout &Class); + + LinePrinter &Printer; + bool DumpedAnything = false; +}; +} +} +#endif diff --git a/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyClassLayoutGraphicalDumper.cpp b/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyClassLayoutGraphicalDumper.cpp new file mode 100644 index 0000000000..a522935e34 --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyClassLayoutGraphicalDumper.cpp @@ -0,0 +1,212 @@ +//===- PrettyClassLayoutGraphicalDumper.h -----------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "PrettyClassLayoutGraphicalDumper.h" + +#include "LinePrinter.h" +#include "PrettyClassDefinitionDumper.h" +#include "PrettyEnumDumper.h" +#include "PrettyFunctionDumper.h" +#include "PrettyTypedefDumper.h" +#include "PrettyVariableDumper.h" +#include "PrettyVariableDumper.h" +#include "llvm-pdbutil.h" + +#include "llvm/DebugInfo/PDB/PDBSymbolData.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" +#include "llvm/DebugInfo/PDB/UDTLayout.h" +#include "llvm/Support/Format.h" + +using namespace llvm; +using namespace llvm::pdb; + +PrettyClassLayoutGraphicalDumper::PrettyClassLayoutGraphicalDumper( + LinePrinter &P, uint32_t RecurseLevel, uint32_t InitialOffset) + : PDBSymDumper(true), Printer(P), RecursionLevel(RecurseLevel), + ClassOffsetZero(InitialOffset), CurrentAbsoluteOffset(InitialOffset) {} + +bool PrettyClassLayoutGraphicalDumper::start(const UDTLayoutBase &Layout) { + + if (RecursionLevel == 1 && + opts::pretty::ClassFormat == opts::pretty::ClassDefinitionFormat::All) { + for (auto &Other : Layout.other_items()) + Other->dump(*this); + for (auto &Func : Layout.funcs()) + Func->dump(*this); + } + + const BitVector &UseMap = Layout.usedBytes(); + int NextPaddingByte = UseMap.find_first_unset(); + + for (auto &Item : Layout.layout_items()) { + // Calculate the absolute offset of the first byte of the next field. + uint32_t RelativeOffset = Item->getOffsetInParent(); + CurrentAbsoluteOffset = ClassOffsetZero + RelativeOffset; + + // This might be an empty base, in which case it could extend outside the + // bounds of the parent class. + if (RelativeOffset < UseMap.size() && (Item->getSize() > 0)) { + // If there is any remaining padding in this class, and the offset of the + // new item is after the padding, then we must have just jumped over some + // padding. Print a padding row and then look for where the next block + // of padding begins. + if ((NextPaddingByte >= 0) && + (RelativeOffset > uint32_t(NextPaddingByte))) { + printPaddingRow(RelativeOffset - NextPaddingByte); + NextPaddingByte = UseMap.find_next_unset(RelativeOffset); + } + } + + CurrentItem = Item; + if (Item->isVBPtr()) { + VTableLayoutItem &Layout = static_cast<VTableLayoutItem &>(*CurrentItem); + + VariableDumper VarDumper(Printer); + VarDumper.startVbptr(CurrentAbsoluteOffset, Layout.getSize()); + } else { + if (auto Sym = Item->getSymbol()) + Sym->dump(*this); + } + + if (Item->getLayoutSize() > 0) { + uint32_t Prev = RelativeOffset + Item->getLayoutSize() - 1; + if (Prev < UseMap.size()) + NextPaddingByte = UseMap.find_next_unset(Prev); + } + } + + auto TailPadding = Layout.tailPadding(); + if (TailPadding > 0) { + if (TailPadding != 1 || Layout.getSize() != 1) { + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::Padding).get() + << "<padding> (" << TailPadding << " bytes)"; + DumpedAnything = true; + } + } + + return DumpedAnything; +} + +void PrettyClassLayoutGraphicalDumper::printPaddingRow(uint32_t Amount) { + if (Amount == 0) + return; + + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::Padding).get() << "<padding> (" << Amount + << " bytes)"; + DumpedAnything = true; +} + +void PrettyClassLayoutGraphicalDumper::dump( + const PDBSymbolTypeBaseClass &Symbol) { + assert(CurrentItem != nullptr); + + Printer.NewLine(); + BaseClassLayout &Layout = static_cast<BaseClassLayout &>(*CurrentItem); + + std::string Label = "base"; + if (Layout.isVirtualBase()) { + Label.insert(Label.begin(), 'v'); + if (Layout.getBase().isIndirectVirtualBaseClass()) + Label.insert(Label.begin(), 'i'); + } + Printer << Label << " "; + + uint32_t Size = Layout.isEmptyBase() ? 1 : Layout.getLayoutSize(); + + WithColor(Printer, PDB_ColorItem::Offset).get() + << "+" << format_hex(CurrentAbsoluteOffset, 4) << " [sizeof=" << Size + << "] "; + + WithColor(Printer, PDB_ColorItem::Identifier).get() << Layout.getName(); + + if (shouldRecurse()) { + Printer.Indent(); + uint32_t ChildOffsetZero = ClassOffsetZero + Layout.getOffsetInParent(); + PrettyClassLayoutGraphicalDumper BaseDumper(Printer, RecursionLevel + 1, + ChildOffsetZero); + DumpedAnything |= BaseDumper.start(Layout); + Printer.Unindent(); + } + + DumpedAnything = true; +} + +bool PrettyClassLayoutGraphicalDumper::shouldRecurse() const { + uint32_t Limit = opts::pretty::ClassRecursionDepth; + if (Limit == 0) + return true; + return RecursionLevel < Limit; +} + +void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolData &Symbol) { + VariableDumper VarDumper(Printer); + VarDumper.start(Symbol, ClassOffsetZero); + + if (CurrentItem != nullptr) { + DataMemberLayoutItem &Layout = + static_cast<DataMemberLayoutItem &>(*CurrentItem); + + if (Layout.hasUDTLayout() && shouldRecurse()) { + uint32_t ChildOffsetZero = ClassOffsetZero + Layout.getOffsetInParent(); + Printer.Indent(); + PrettyClassLayoutGraphicalDumper TypeDumper(Printer, RecursionLevel + 1, + ChildOffsetZero); + TypeDumper.start(Layout.getUDTLayout()); + Printer.Unindent(); + } + } + + DumpedAnything = true; +} + +void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeVTable &Symbol) { + assert(CurrentItem != nullptr); + + VariableDumper VarDumper(Printer); + VarDumper.start(Symbol, ClassOffsetZero); + + DumpedAnything = true; +} + +void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeEnum &Symbol) { + DumpedAnything = true; + Printer.NewLine(); + EnumDumper Dumper(Printer); + Dumper.start(Symbol); +} + +void PrettyClassLayoutGraphicalDumper::dump( + const PDBSymbolTypeTypedef &Symbol) { + DumpedAnything = true; + Printer.NewLine(); + TypedefDumper Dumper(Printer); + Dumper.start(Symbol); +} + +void PrettyClassLayoutGraphicalDumper::dump( + const PDBSymbolTypeBuiltin &Symbol) {} + +void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeUDT &Symbol) {} + +void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolFunc &Symbol) { + if (Printer.IsSymbolExcluded(Symbol.getName())) + return; + if (Symbol.isCompilerGenerated() && opts::pretty::ExcludeCompilerGenerated) + return; + if (Symbol.getLength() == 0 && !Symbol.isPureVirtual() && + !Symbol.isIntroVirtualFunction()) + return; + + DumpedAnything = true; + Printer.NewLine(); + FunctionDumper Dumper(Printer); + Dumper.start(Symbol, FunctionDumper::PointerType::None); +} diff --git a/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyClassLayoutGraphicalDumper.h b/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyClassLayoutGraphicalDumper.h new file mode 100644 index 0000000000..8f78b3b503 --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyClassLayoutGraphicalDumper.h @@ -0,0 +1,57 @@ +//===- PrettyClassLayoutGraphicalDumper.h -----------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMPDBDUMP_PRETTYCLASSLAYOUTGRAPHICALDUMPER_H +#define LLVM_TOOLS_LLVMPDBDUMP_PRETTYCLASSLAYOUTGRAPHICALDUMPER_H + +#include "llvm/ADT/BitVector.h" + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" + +namespace llvm { + +namespace pdb { + +class UDTLayoutBase; +class LayoutItemBase; +class LinePrinter; + +class PrettyClassLayoutGraphicalDumper : public PDBSymDumper { +public: + PrettyClassLayoutGraphicalDumper(LinePrinter &P, uint32_t RecurseLevel, + uint32_t InitialOffset); + + bool start(const UDTLayoutBase &Layout); + + // Layout based symbol types. + void dump(const PDBSymbolTypeBaseClass &Symbol) override; + void dump(const PDBSymbolData &Symbol) override; + void dump(const PDBSymbolTypeVTable &Symbol) override; + + // Non layout-based symbol types. + void dump(const PDBSymbolTypeEnum &Symbol) override; + void dump(const PDBSymbolFunc &Symbol) override; + void dump(const PDBSymbolTypeTypedef &Symbol) override; + void dump(const PDBSymbolTypeUDT &Symbol) override; + void dump(const PDBSymbolTypeBuiltin &Symbol) override; + +private: + bool shouldRecurse() const; + void printPaddingRow(uint32_t Amount); + + LinePrinter &Printer; + + LayoutItemBase *CurrentItem = nullptr; + uint32_t RecursionLevel = 0; + uint32_t ClassOffsetZero = 0; + uint32_t CurrentAbsoluteOffset = 0; + bool DumpedAnything = false; +}; +} +} +#endif diff --git a/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyCompilandDumper.cpp b/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyCompilandDumper.cpp new file mode 100644 index 0000000000..cf769ff664 --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyCompilandDumper.cpp @@ -0,0 +1,228 @@ +//===- PrettyCompilandDumper.cpp - llvm-pdbutil compiland dumper -*- C++ *-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "PrettyCompilandDumper.h" + +#include "LinePrinter.h" +#include "PrettyFunctionDumper.h" +#include "llvm-pdbutil.h" + +#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" +#include "llvm/DebugInfo/PDB/IPDBLineNumber.h" +#include "llvm/DebugInfo/PDB/IPDBSession.h" +#include "llvm/DebugInfo/PDB/IPDBSourceFile.h" +#include "llvm/DebugInfo/PDB/PDBExtras.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" +#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" +#include "llvm/DebugInfo/PDB/PDBSymbolData.h" +#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h" +#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugEnd.h" +#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugStart.h" +#include "llvm/DebugInfo/PDB/PDBSymbolLabel.h" +#include "llvm/DebugInfo/PDB/PDBSymbolThunk.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h" +#include "llvm/DebugInfo/PDB/PDBSymbolUnknown.h" +#include "llvm/DebugInfo/PDB/PDBSymbolUsingNamespace.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +CompilandDumper::CompilandDumper(LinePrinter &P) + : PDBSymDumper(true), Printer(P) {} + +void CompilandDumper::dump(const PDBSymbolCompilandDetails &Symbol) {} + +void CompilandDumper::dump(const PDBSymbolCompilandEnv &Symbol) {} + +void CompilandDumper::start(const PDBSymbolCompiland &Symbol, + CompilandDumpFlags opts) { + std::string FullName = Symbol.getName(); + if (Printer.IsCompilandExcluded(FullName)) + return; + + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::Path).get() << FullName; + + if (opts & Flags::Lines) { + const IPDBSession &Session = Symbol.getSession(); + if (auto Files = Session.getSourceFilesForCompiland(Symbol)) { + Printer.Indent(); + while (auto File = Files->getNext()) { + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::Path).get() << File->getFileName(); + if (File->getChecksumType() != PDB_Checksum::None) { + auto ChecksumType = File->getChecksumType(); + auto ChecksumHexString = toHex(File->getChecksum()); + WithColor(Printer, PDB_ColorItem::Comment).get() + << " (" << ChecksumType << ": " << ChecksumHexString << ")"; + } + + auto Lines = Session.findLineNumbers(Symbol, *File); + if (!Lines) + continue; + + Printer.Indent(); + while (auto Line = Lines->getNext()) { + Printer.NewLine(); + uint32_t LineStart = Line->getLineNumber(); + uint32_t LineEnd = Line->getLineNumberEnd(); + + Printer << "Line "; + PDB_ColorItem StatementColor = Line->isStatement() + ? PDB_ColorItem::Keyword + : PDB_ColorItem::LiteralValue; + WithColor(Printer, StatementColor).get() << LineStart; + if (LineStart != LineEnd) + WithColor(Printer, StatementColor).get() << " - " << LineEnd; + + uint32_t ColumnStart = Line->getColumnNumber(); + uint32_t ColumnEnd = Line->getColumnNumberEnd(); + if (ColumnStart != 0 || ColumnEnd != 0) { + Printer << ", Column: "; + WithColor(Printer, StatementColor).get() << ColumnStart; + if (ColumnEnd != ColumnStart) + WithColor(Printer, StatementColor).get() << " - " << ColumnEnd; + } + + Printer << ", Address: "; + if (Line->getLength() > 0) { + uint64_t AddrStart = Line->getVirtualAddress(); + uint64_t AddrEnd = AddrStart + Line->getLength() - 1; + WithColor(Printer, PDB_ColorItem::Address).get() + << "[" << format_hex(AddrStart, 10) << " - " + << format_hex(AddrEnd, 10) << "]"; + Printer << " (" << Line->getLength() << " bytes)"; + } else { + uint64_t AddrStart = Line->getVirtualAddress(); + WithColor(Printer, PDB_ColorItem::Address).get() + << "[" << format_hex(AddrStart, 10) << "] "; + Printer << "(0 bytes)"; + } + } + Printer.Unindent(); + } + Printer.Unindent(); + } + } + + if (opts & Flags::Children) { + if (auto ChildrenEnum = Symbol.findAllChildren()) { + Printer.Indent(); + while (auto Child = ChildrenEnum->getNext()) + Child->dump(*this); + Printer.Unindent(); + } + } +} + +void CompilandDumper::dump(const PDBSymbolData &Symbol) { + if (!shouldDumpSymLevel(opts::pretty::SymLevel::Data)) + return; + if (Printer.IsSymbolExcluded(Symbol.getName())) + return; + + Printer.NewLine(); + + switch (auto LocType = Symbol.getLocationType()) { + case PDB_LocType::Static: + Printer << "data: "; + WithColor(Printer, PDB_ColorItem::Address).get() + << "[" << format_hex(Symbol.getVirtualAddress(), 10) << "]"; + + WithColor(Printer, PDB_ColorItem::Comment).get() + << " [sizeof = " << getTypeLength(Symbol) << "]"; + + break; + case PDB_LocType::Constant: + Printer << "constant: "; + WithColor(Printer, PDB_ColorItem::LiteralValue).get() + << "[" << Symbol.getValue() << "]"; + WithColor(Printer, PDB_ColorItem::Comment).get() + << " [sizeof = " << getTypeLength(Symbol) << "]"; + break; + default: + Printer << "data(unexpected type=" << LocType << ")"; + } + + Printer << " "; + WithColor(Printer, PDB_ColorItem::Identifier).get() << Symbol.getName(); +} + +void CompilandDumper::dump(const PDBSymbolFunc &Symbol) { + if (!shouldDumpSymLevel(opts::pretty::SymLevel::Functions)) + return; + if (Symbol.getLength() == 0) + return; + if (Printer.IsSymbolExcluded(Symbol.getName())) + return; + + Printer.NewLine(); + FunctionDumper Dumper(Printer); + Dumper.start(Symbol, FunctionDumper::PointerType::None); +} + +void CompilandDumper::dump(const PDBSymbolLabel &Symbol) { + if (Printer.IsSymbolExcluded(Symbol.getName())) + return; + + Printer.NewLine(); + Printer << "label "; + WithColor(Printer, PDB_ColorItem::Address).get() + << "[" << format_hex(Symbol.getVirtualAddress(), 10) << "] "; + WithColor(Printer, PDB_ColorItem::Identifier).get() << Symbol.getName(); +} + +void CompilandDumper::dump(const PDBSymbolThunk &Symbol) { + if (!shouldDumpSymLevel(opts::pretty::SymLevel::Thunks)) + return; + if (Printer.IsSymbolExcluded(Symbol.getName())) + return; + + Printer.NewLine(); + Printer << "thunk "; + codeview::ThunkOrdinal Ordinal = Symbol.getThunkOrdinal(); + uint64_t VA = Symbol.getVirtualAddress(); + if (Ordinal == codeview::ThunkOrdinal::TrampIncremental) { + uint64_t Target = Symbol.getTargetVirtualAddress(); + WithColor(Printer, PDB_ColorItem::Address).get() << format_hex(VA, 10); + Printer << " -> "; + WithColor(Printer, PDB_ColorItem::Address).get() << format_hex(Target, 10); + } else { + WithColor(Printer, PDB_ColorItem::Address).get() + << "[" << format_hex(VA, 10) << " - " + << format_hex(VA + Symbol.getLength(), 10) << "]"; + } + Printer << " ("; + WithColor(Printer, PDB_ColorItem::Register).get() << Ordinal; + Printer << ") "; + std::string Name = Symbol.getName(); + if (!Name.empty()) + WithColor(Printer, PDB_ColorItem::Identifier).get() << Name; +} + +void CompilandDumper::dump(const PDBSymbolTypeTypedef &Symbol) {} + +void CompilandDumper::dump(const PDBSymbolUnknown &Symbol) { + Printer.NewLine(); + Printer << "unknown (" << Symbol.getSymTag() << ")"; +} + +void CompilandDumper::dump(const PDBSymbolUsingNamespace &Symbol) { + if (Printer.IsSymbolExcluded(Symbol.getName())) + return; + + Printer.NewLine(); + Printer << "using namespace "; + std::string Name = Symbol.getName(); + WithColor(Printer, PDB_ColorItem::Identifier).get() << Name; +} diff --git a/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyCompilandDumper.h b/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyCompilandDumper.h new file mode 100644 index 0000000000..c83a58672d --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyCompilandDumper.h @@ -0,0 +1,44 @@ +//===- PrettyCompilandDumper.h - llvm-pdbutil compiland dumper -*- C++ --*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMPDBDUMP_PRETTYCOMPILANDDUMPER_H +#define LLVM_TOOLS_LLVMPDBDUMP_PRETTYCOMPILANDDUMPER_H + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" + +namespace llvm { +namespace pdb { + +class LinePrinter; + +typedef int CompilandDumpFlags; +class CompilandDumper : public PDBSymDumper { +public: + enum Flags { None = 0x0, Children = 0x1, Symbols = 0x2, Lines = 0x4 }; + + CompilandDumper(LinePrinter &P); + + void start(const PDBSymbolCompiland &Symbol, CompilandDumpFlags flags); + + void dump(const PDBSymbolCompilandDetails &Symbol) override; + void dump(const PDBSymbolCompilandEnv &Symbol) override; + void dump(const PDBSymbolData &Symbol) override; + void dump(const PDBSymbolFunc &Symbol) override; + void dump(const PDBSymbolLabel &Symbol) override; + void dump(const PDBSymbolThunk &Symbol) override; + void dump(const PDBSymbolTypeTypedef &Symbol) override; + void dump(const PDBSymbolUnknown &Symbol) override; + void dump(const PDBSymbolUsingNamespace &Symbol) override; + +private: + LinePrinter &Printer; +}; +} +} + +#endif diff --git a/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyEnumDumper.cpp b/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyEnumDumper.cpp new file mode 100644 index 0000000000..9ed5893f25 --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyEnumDumper.cpp @@ -0,0 +1,68 @@ +//===- PrettyEnumDumper.cpp -------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "PrettyEnumDumper.h" + +#include "LinePrinter.h" +#include "PrettyBuiltinDumper.h" +#include "llvm-pdbutil.h" + +#include "llvm/DebugInfo/PDB/PDBSymbolData.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" + +using namespace llvm; +using namespace llvm::pdb; + +EnumDumper::EnumDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {} + +void EnumDumper::start(const PDBSymbolTypeEnum &Symbol) { + if (Symbol.getUnmodifiedTypeId() != 0) { + if (Symbol.isConstType()) + WithColor(Printer, PDB_ColorItem::Keyword).get() << "const "; + if (Symbol.isVolatileType()) + WithColor(Printer, PDB_ColorItem::Keyword).get() << "volatile "; + if (Symbol.isUnalignedType()) + WithColor(Printer, PDB_ColorItem::Keyword).get() << "unaligned "; + WithColor(Printer, PDB_ColorItem::Keyword).get() << "enum "; + WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName(); + return; + } + + WithColor(Printer, PDB_ColorItem::Keyword).get() << "enum "; + WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName(); + if (!opts::pretty::NoEnumDefs) { + auto UnderlyingType = Symbol.getUnderlyingType(); + if (!UnderlyingType) + return; + if (UnderlyingType->getBuiltinType() != PDB_BuiltinType::Int || + UnderlyingType->getLength() != 4) { + Printer << " : "; + BuiltinDumper Dumper(Printer); + Dumper.start(*UnderlyingType); + } + auto EnumValues = Symbol.findAllChildren<PDBSymbolData>(); + Printer << " {"; + Printer.Indent(); + if (EnumValues && EnumValues->getChildCount() > 0) { + while (auto EnumValue = EnumValues->getNext()) { + if (EnumValue->getDataKind() != PDB_DataKind::Constant) + continue; + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::Identifier).get() + << EnumValue->getName(); + Printer << " = "; + WithColor(Printer, PDB_ColorItem::LiteralValue).get() + << EnumValue->getValue(); + } + } + Printer.Unindent(); + Printer.NewLine(); + Printer << "}"; + } +} diff --git a/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyEnumDumper.h b/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyEnumDumper.h new file mode 100644 index 0000000000..e7c5c1aeb0 --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyEnumDumper.h @@ -0,0 +1,30 @@ +//===- PrettyEnumDumper.h ---------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMPDBDUMP_PRETTYENUMDUMPER_H +#define LLVM_TOOLS_LLVMPDBDUMP_PRETTYENUMDUMPER_H + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" + +namespace llvm { +namespace pdb { + +class LinePrinter; + +class EnumDumper : public PDBSymDumper { +public: + EnumDumper(LinePrinter &P); + + void start(const PDBSymbolTypeEnum &Symbol); + +private: + LinePrinter &Printer; +}; +} +} +#endif diff --git a/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyExternalSymbolDumper.cpp b/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyExternalSymbolDumper.cpp new file mode 100644 index 0000000000..fede031ec0 --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyExternalSymbolDumper.cpp @@ -0,0 +1,41 @@ +//===- PrettyExternalSymbolDumper.cpp -------------------------- *- C++ *-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "PrettyExternalSymbolDumper.h" +#include "LinePrinter.h" + +#include "llvm/DebugInfo/PDB/PDBSymbolExe.h" +#include "llvm/DebugInfo/PDB/PDBSymbolPublicSymbol.h" +#include "llvm/Support/Format.h" + +using namespace llvm; +using namespace llvm::pdb; + +ExternalSymbolDumper::ExternalSymbolDumper(LinePrinter &P) + : PDBSymDumper(true), Printer(P) {} + +void ExternalSymbolDumper::start(const PDBSymbolExe &Symbol) { + if (auto Vars = Symbol.findAllChildren<PDBSymbolPublicSymbol>()) { + while (auto Var = Vars->getNext()) + Var->dump(*this); + } +} + +void ExternalSymbolDumper::dump(const PDBSymbolPublicSymbol &Symbol) { + std::string LinkageName = Symbol.getName(); + if (Printer.IsSymbolExcluded(LinkageName)) + return; + + Printer.NewLine(); + uint64_t Addr = Symbol.getVirtualAddress(); + + Printer << "public ["; + WithColor(Printer, PDB_ColorItem::Address).get() << format_hex(Addr, 10); + Printer << "] "; + WithColor(Printer, PDB_ColorItem::Identifier).get() << LinkageName; +} diff --git a/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyExternalSymbolDumper.h b/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyExternalSymbolDumper.h new file mode 100644 index 0000000000..58fafe9433 --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyExternalSymbolDumper.h @@ -0,0 +1,33 @@ +//===- PrettyExternalSymbolDumper.h --------------------------- *- C++ --*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMPDBDUMP_PRETTYEXTERNALSYMBOLDUMPER_H +#define LLVM_TOOLS_LLVMPDBDUMP_PRETTYEXTERNALSYMBOLDUMPER_H + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" + +namespace llvm { +namespace pdb { + +class LinePrinter; + +class ExternalSymbolDumper : public PDBSymDumper { +public: + ExternalSymbolDumper(LinePrinter &P); + + void start(const PDBSymbolExe &Symbol); + + void dump(const PDBSymbolPublicSymbol &Symbol) override; + +private: + LinePrinter &Printer; +}; +} +} + +#endif diff --git a/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyFunctionDumper.cpp b/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyFunctionDumper.cpp new file mode 100644 index 0000000000..b820ca3339 --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyFunctionDumper.cpp @@ -0,0 +1,267 @@ +//===- PrettyFunctionDumper.cpp --------------------------------- *- C++ *-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "PrettyFunctionDumper.h" +#include "LinePrinter.h" +#include "PrettyBuiltinDumper.h" + +#include "llvm/DebugInfo/PDB/IPDBSession.h" +#include "llvm/DebugInfo/PDB/PDBExtras.h" +#include "llvm/DebugInfo/PDB/PDBSymbolData.h" +#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h" +#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugEnd.h" +#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugStart.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeArray.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionArg.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/FormatVariadic.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +namespace { +template <class T> +void dumpClassParentWithScopeOperator(const T &Symbol, LinePrinter &Printer, + FunctionDumper &Dumper) { + uint32_t ClassParentId = Symbol.getClassParentId(); + auto ClassParent = + Symbol.getSession().template getConcreteSymbolById<PDBSymbolTypeUDT>( + ClassParentId); + if (!ClassParent) + return; + + WithColor(Printer, PDB_ColorItem::Type).get() << ClassParent->getName(); + Printer << "::"; +} +} + +FunctionDumper::FunctionDumper(LinePrinter &P) + : PDBSymDumper(true), Printer(P) {} + +void FunctionDumper::start(const PDBSymbolTypeFunctionSig &Symbol, + const char *Name, PointerType Pointer) { + auto ReturnType = Symbol.getReturnType(); + if (!ReturnType) + Printer << "<unknown-type>"; + else + ReturnType->dump(*this); + Printer << " "; + uint32_t ClassParentId = Symbol.getClassParentId(); + auto ClassParent = + Symbol.getSession().getConcreteSymbolById<PDBSymbolTypeUDT>( + ClassParentId); + + PDB_CallingConv CC = Symbol.getCallingConvention(); + bool ShouldDumpCallingConvention = true; + if ((ClassParent && CC == CallingConvention::ThisCall) || + (!ClassParent && CC == CallingConvention::NearStdCall)) { + ShouldDumpCallingConvention = false; + } + + if (Pointer == PointerType::None) { + if (ShouldDumpCallingConvention) + WithColor(Printer, PDB_ColorItem::Keyword).get() << CC << " "; + if (ClassParent) { + Printer << "("; + WithColor(Printer, PDB_ColorItem::Identifier).get() + << ClassParent->getName(); + Printer << "::)"; + } + } else { + Printer << "("; + if (ShouldDumpCallingConvention) + WithColor(Printer, PDB_ColorItem::Keyword).get() << CC << " "; + if (ClassParent) { + WithColor(Printer, PDB_ColorItem::Identifier).get() + << ClassParent->getName(); + Printer << "::"; + } + if (Pointer == PointerType::Reference) + Printer << "&"; + else + Printer << "*"; + if (Name) + WithColor(Printer, PDB_ColorItem::Identifier).get() << Name; + Printer << ")"; + } + + Printer << "("; + if (auto ChildEnum = Symbol.getArguments()) { + uint32_t Index = 0; + while (auto Arg = ChildEnum->getNext()) { + Arg->dump(*this); + if (++Index < ChildEnum->getChildCount()) + Printer << ", "; + } + } + Printer << ")"; + + if (Symbol.isConstType()) + WithColor(Printer, PDB_ColorItem::Keyword).get() << " const"; + if (Symbol.isVolatileType()) + WithColor(Printer, PDB_ColorItem::Keyword).get() << " volatile"; +} + +void FunctionDumper::start(const PDBSymbolFunc &Symbol, PointerType Pointer) { + uint64_t FuncStart = Symbol.getVirtualAddress(); + uint64_t FuncEnd = FuncStart + Symbol.getLength(); + + Printer << "func ["; + WithColor(Printer, PDB_ColorItem::Address).get() << format_hex(FuncStart, 10); + if (auto DebugStart = Symbol.findOneChild<PDBSymbolFuncDebugStart>()) { + uint64_t Prologue = DebugStart->getVirtualAddress() - FuncStart; + WithColor(Printer, PDB_ColorItem::Offset).get() + << formatv("+{0,2}", Prologue); + } + Printer << " - "; + WithColor(Printer, PDB_ColorItem::Address).get() << format_hex(FuncEnd, 10); + if (auto DebugEnd = Symbol.findOneChild<PDBSymbolFuncDebugEnd>()) { + uint64_t Epilogue = FuncEnd - DebugEnd->getVirtualAddress(); + WithColor(Printer, PDB_ColorItem::Offset).get() + << formatv("-{0,2}", Epilogue); + } + + WithColor(Printer, PDB_ColorItem::Comment).get() + << formatv(" | sizeof={0,3}", Symbol.getLength()); + Printer << "] ("; + + if (Symbol.hasFramePointer()) { + WithColor(Printer, PDB_ColorItem::Register).get() + << CPURegister{Symbol.getRawSymbol().getPlatform(), + Symbol.getLocalBasePointerRegisterId()}; + } else { + WithColor(Printer, PDB_ColorItem::Register).get() << "FPO"; + } + Printer << ") "; + + if (Symbol.isVirtual() || Symbol.isPureVirtual()) + WithColor(Printer, PDB_ColorItem::Keyword).get() << "virtual "; + + auto Signature = Symbol.getSignature(); + if (!Signature) { + WithColor(Printer, PDB_ColorItem::Identifier).get() << Symbol.getName(); + if (Pointer == PointerType::Pointer) + Printer << "*"; + else if (Pointer == FunctionDumper::PointerType::Reference) + Printer << "&"; + return; + } + + auto ReturnType = Signature->getReturnType(); + ReturnType->dump(*this); + Printer << " "; + + auto ClassParent = Symbol.getClassParent(); + CallingConvention CC = Signature->getCallingConvention(); + if (Pointer != FunctionDumper::PointerType::None) + Printer << "("; + + if ((ClassParent && CC != CallingConvention::ThisCall) || + (!ClassParent && CC != CallingConvention::NearStdCall)) { + WithColor(Printer, PDB_ColorItem::Keyword).get() + << Signature->getCallingConvention() << " "; + } + WithColor(Printer, PDB_ColorItem::Identifier).get() << Symbol.getName(); + if (Pointer != FunctionDumper::PointerType::None) { + if (Pointer == PointerType::Pointer) + Printer << "*"; + else if (Pointer == FunctionDumper::PointerType::Reference) + Printer << "&"; + Printer << ")"; + } + + Printer << "("; + if (auto Arguments = Symbol.getArguments()) { + uint32_t Index = 0; + while (auto Arg = Arguments->getNext()) { + auto ArgType = Arg->getType(); + ArgType->dump(*this); + WithColor(Printer, PDB_ColorItem::Identifier).get() << " " + << Arg->getName(); + if (++Index < Arguments->getChildCount()) + Printer << ", "; + } + if (Signature->isCVarArgs()) + Printer << ", ..."; + } + Printer << ")"; + if (Symbol.isConstType()) + WithColor(Printer, PDB_ColorItem::Keyword).get() << " const"; + if (Symbol.isVolatileType()) + WithColor(Printer, PDB_ColorItem::Keyword).get() << " volatile"; + if (Symbol.isPureVirtual()) + Printer << " = 0"; +} + +void FunctionDumper::dump(const PDBSymbolTypeArray &Symbol) { + auto ElementType = Symbol.getElementType(); + + ElementType->dump(*this); + Printer << "["; + WithColor(Printer, PDB_ColorItem::LiteralValue).get() << Symbol.getLength(); + Printer << "]"; +} + +void FunctionDumper::dump(const PDBSymbolTypeBuiltin &Symbol) { + BuiltinDumper Dumper(Printer); + Dumper.start(Symbol); +} + +void FunctionDumper::dump(const PDBSymbolTypeEnum &Symbol) { + dumpClassParentWithScopeOperator(Symbol, Printer, *this); + WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName(); +} + +void FunctionDumper::dump(const PDBSymbolTypeFunctionArg &Symbol) { + // PDBSymbolTypeFunctionArg is just a shim over the real argument. Just drill + // through to the real thing and dump it. + uint32_t TypeId = Symbol.getTypeId(); + auto Type = Symbol.getSession().getSymbolById(TypeId); + if (Type) + Type->dump(*this); + else + Printer << "<unknown-type>"; +} + +void FunctionDumper::dump(const PDBSymbolTypeTypedef &Symbol) { + dumpClassParentWithScopeOperator(Symbol, Printer, *this); + WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName(); +} + +void FunctionDumper::dump(const PDBSymbolTypePointer &Symbol) { + auto PointeeType = Symbol.getPointeeType(); + if (!PointeeType) + return; + + if (auto FuncSig = unique_dyn_cast<PDBSymbolTypeFunctionSig>(PointeeType)) { + FunctionDumper NestedDumper(Printer); + PointerType Pointer = + Symbol.isReference() ? PointerType::Reference : PointerType::Pointer; + NestedDumper.start(*FuncSig, nullptr, Pointer); + } else { + if (Symbol.isConstType()) + WithColor(Printer, PDB_ColorItem::Keyword).get() << "const "; + if (Symbol.isVolatileType()) + WithColor(Printer, PDB_ColorItem::Keyword).get() << "volatile "; + PointeeType->dump(*this); + Printer << (Symbol.isReference() ? "&" : "*"); + + if (Symbol.getRawSymbol().isRestrictedType()) + WithColor(Printer, PDB_ColorItem::Keyword).get() << " __restrict"; + } +} + +void FunctionDumper::dump(const PDBSymbolTypeUDT &Symbol) { + WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName(); +} diff --git a/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyFunctionDumper.h b/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyFunctionDumper.h new file mode 100644 index 0000000000..df62604ac8 --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyFunctionDumper.h @@ -0,0 +1,42 @@ +//===- PrettyFunctionDumper.h --------------------------------- *- C++ --*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMPDBDUMP_PRETTYFUNCTIONDUMPER_H +#define LLVM_TOOLS_LLVMPDBDUMP_PRETTYFUNCTIONDUMPER_H + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" + +namespace llvm { +namespace pdb { +class LinePrinter; + +class FunctionDumper : public PDBSymDumper { +public: + FunctionDumper(LinePrinter &P); + + enum class PointerType { None, Pointer, Reference }; + + void start(const PDBSymbolTypeFunctionSig &Symbol, const char *Name, + PointerType Pointer); + void start(const PDBSymbolFunc &Symbol, PointerType Pointer); + + void dump(const PDBSymbolTypeArray &Symbol) override; + void dump(const PDBSymbolTypeBuiltin &Symbol) override; + void dump(const PDBSymbolTypeEnum &Symbol) override; + void dump(const PDBSymbolTypeFunctionArg &Symbol) override; + void dump(const PDBSymbolTypePointer &Symbol) override; + void dump(const PDBSymbolTypeTypedef &Symbol) override; + void dump(const PDBSymbolTypeUDT &Symbol) override; + +private: + LinePrinter &Printer; +}; +} +} + +#endif diff --git a/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyTypeDumper.cpp b/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyTypeDumper.cpp new file mode 100644 index 0000000000..2f7a39803c --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyTypeDumper.cpp @@ -0,0 +1,359 @@ +//===- PrettyTypeDumper.cpp - PDBSymDumper type dumper *------------ C++ *-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "PrettyTypeDumper.h" + +#include "LinePrinter.h" +#include "PrettyBuiltinDumper.h" +#include "PrettyClassDefinitionDumper.h" +#include "PrettyEnumDumper.h" +#include "PrettyFunctionDumper.h" +#include "PrettyTypedefDumper.h" +#include "llvm-pdbutil.h" + +#include "llvm/DebugInfo/PDB/IPDBSession.h" +#include "llvm/DebugInfo/PDB/PDBSymbolExe.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeArray.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" +#include "llvm/DebugInfo/PDB/UDTLayout.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/FormatVariadic.h" + +using namespace llvm; +using namespace llvm::pdb; + +using LayoutPtr = std::unique_ptr<ClassLayout>; + +typedef bool (*CompareFunc)(const LayoutPtr &S1, const LayoutPtr &S2); + +static bool CompareNames(const LayoutPtr &S1, const LayoutPtr &S2) { + return S1->getName() < S2->getName(); +} + +static bool CompareSizes(const LayoutPtr &S1, const LayoutPtr &S2) { + return S1->getSize() < S2->getSize(); +} + +static bool ComparePadding(const LayoutPtr &S1, const LayoutPtr &S2) { + return S1->deepPaddingSize() < S2->deepPaddingSize(); +} + +static bool ComparePaddingPct(const LayoutPtr &S1, const LayoutPtr &S2) { + double Pct1 = (double)S1->deepPaddingSize() / (double)S1->getSize(); + double Pct2 = (double)S2->deepPaddingSize() / (double)S2->getSize(); + return Pct1 < Pct2; +} + +static bool ComparePaddingImmediate(const LayoutPtr &S1, const LayoutPtr &S2) { + return S1->immediatePadding() < S2->immediatePadding(); +} + +static bool ComparePaddingPctImmediate(const LayoutPtr &S1, + const LayoutPtr &S2) { + double Pct1 = (double)S1->immediatePadding() / (double)S1->getSize(); + double Pct2 = (double)S2->immediatePadding() / (double)S2->getSize(); + return Pct1 < Pct2; +} + +static CompareFunc getComparisonFunc(opts::pretty::ClassSortMode Mode) { + switch (Mode) { + case opts::pretty::ClassSortMode::Name: + return CompareNames; + case opts::pretty::ClassSortMode::Size: + return CompareSizes; + case opts::pretty::ClassSortMode::Padding: + return ComparePadding; + case opts::pretty::ClassSortMode::PaddingPct: + return ComparePaddingPct; + case opts::pretty::ClassSortMode::PaddingImmediate: + return ComparePaddingImmediate; + case opts::pretty::ClassSortMode::PaddingPctImmediate: + return ComparePaddingPctImmediate; + default: + return nullptr; + } +} + +template <typename Enumerator> +static std::vector<std::unique_ptr<ClassLayout>> +filterAndSortClassDefs(LinePrinter &Printer, Enumerator &E, + uint32_t UnfilteredCount) { + std::vector<std::unique_ptr<ClassLayout>> Filtered; + + Filtered.reserve(UnfilteredCount); + CompareFunc Comp = getComparisonFunc(opts::pretty::ClassOrder); + + if (UnfilteredCount > 10000) { + errs() << formatv("Filtering and sorting {0} types", UnfilteredCount); + errs().flush(); + } + uint32_t Examined = 0; + uint32_t Discarded = 0; + while (auto Class = E.getNext()) { + ++Examined; + if (Examined % 10000 == 0) { + errs() << formatv("Examined {0}/{1} items. {2} items discarded\n", + Examined, UnfilteredCount, Discarded); + errs().flush(); + } + + if (Class->getUnmodifiedTypeId() != 0) { + ++Discarded; + continue; + } + + if (Printer.IsTypeExcluded(Class->getName(), Class->getLength())) { + ++Discarded; + continue; + } + + auto Layout = std::make_unique<ClassLayout>(std::move(Class)); + if (Layout->deepPaddingSize() < opts::pretty::PaddingThreshold) { + ++Discarded; + continue; + } + if (Layout->immediatePadding() < opts::pretty::ImmediatePaddingThreshold) { + ++Discarded; + continue; + } + + Filtered.push_back(std::move(Layout)); + } + + if (Comp) + llvm::sort(Filtered, Comp); + return Filtered; +} + +TypeDumper::TypeDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {} + +template <typename T> +static bool isTypeExcluded(LinePrinter &Printer, const T &Symbol) { + return false; +} + +static bool isTypeExcluded(LinePrinter &Printer, + const PDBSymbolTypeEnum &Enum) { + if (Printer.IsTypeExcluded(Enum.getName(), Enum.getLength())) + return true; + // Dump member enums when dumping their class definition. + if (nullptr != Enum.getClassParent()) + return true; + return false; +} + +static bool isTypeExcluded(LinePrinter &Printer, + const PDBSymbolTypeTypedef &Typedef) { + return Printer.IsTypeExcluded(Typedef.getName(), Typedef.getLength()); +} + +template <typename SymbolT> +static void dumpSymbolCategory(LinePrinter &Printer, const PDBSymbolExe &Exe, + TypeDumper &TD, StringRef Label) { + if (auto Children = Exe.findAllChildren<SymbolT>()) { + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::Identifier).get() << Label; + Printer << ": (" << Children->getChildCount() << " items)"; + Printer.Indent(); + while (auto Child = Children->getNext()) { + if (isTypeExcluded(Printer, *Child)) + continue; + + Printer.NewLine(); + Child->dump(TD); + } + Printer.Unindent(); + } +} + +static void printClassDecl(LinePrinter &Printer, + const PDBSymbolTypeUDT &Class) { + if (Class.getUnmodifiedTypeId() != 0) { + if (Class.isConstType()) + WithColor(Printer, PDB_ColorItem::Keyword).get() << "const "; + if (Class.isVolatileType()) + WithColor(Printer, PDB_ColorItem::Keyword).get() << "volatile "; + if (Class.isUnalignedType()) + WithColor(Printer, PDB_ColorItem::Keyword).get() << "unaligned "; + } + WithColor(Printer, PDB_ColorItem::Keyword).get() << Class.getUdtKind() << " "; + WithColor(Printer, PDB_ColorItem::Type).get() << Class.getName(); +} + +void TypeDumper::start(const PDBSymbolExe &Exe) { + if (opts::pretty::Enums) + dumpSymbolCategory<PDBSymbolTypeEnum>(Printer, Exe, *this, "Enums"); + + if (opts::pretty::Funcsigs) + dumpSymbolCategory<PDBSymbolTypeFunctionSig>(Printer, Exe, *this, + "Function Signatures"); + + if (opts::pretty::Typedefs) + dumpSymbolCategory<PDBSymbolTypeTypedef>(Printer, Exe, *this, "Typedefs"); + + if (opts::pretty::Arrays) + dumpSymbolCategory<PDBSymbolTypeArray>(Printer, Exe, *this, "Arrays"); + + if (opts::pretty::Pointers) + dumpSymbolCategory<PDBSymbolTypePointer>(Printer, Exe, *this, "Pointers"); + + if (opts::pretty::VTShapes) + dumpSymbolCategory<PDBSymbolTypeVTableShape>(Printer, Exe, *this, + "VFTable Shapes"); + + if (opts::pretty::Classes) { + if (auto Classes = Exe.findAllChildren<PDBSymbolTypeUDT>()) { + uint32_t All = Classes->getChildCount(); + + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::Identifier).get() << "Classes"; + + bool Precompute = false; + Precompute = + (opts::pretty::ClassOrder != opts::pretty::ClassSortMode::None); + + // If we're using no sort mode, then we can start getting immediate output + // from the tool by just filtering as we go, rather than processing + // everything up front so that we can sort it. This makes the tool more + // responsive. So only precompute the filtered/sorted set of classes if + // necessary due to the specified options. + std::vector<LayoutPtr> Filtered; + uint32_t Shown = All; + if (Precompute) { + Filtered = filterAndSortClassDefs(Printer, *Classes, All); + + Shown = Filtered.size(); + } + + Printer << ": (Showing " << Shown << " items"; + if (Shown < All) + Printer << ", " << (All - Shown) << " filtered"; + Printer << ")"; + Printer.Indent(); + + // If we pre-computed, iterate the filtered/sorted list, otherwise iterate + // the DIA enumerator and filter on the fly. + if (Precompute) { + for (auto &Class : Filtered) + dumpClassLayout(*Class); + } else { + while (auto Class = Classes->getNext()) { + if (Printer.IsTypeExcluded(Class->getName(), Class->getLength())) + continue; + + // No point duplicating a full class layout. Just print the modified + // declaration and continue. + if (Class->getUnmodifiedTypeId() != 0) { + Printer.NewLine(); + printClassDecl(Printer, *Class); + continue; + } + + auto Layout = std::make_unique<ClassLayout>(std::move(Class)); + if (Layout->deepPaddingSize() < opts::pretty::PaddingThreshold) + continue; + + dumpClassLayout(*Layout); + } + } + + Printer.Unindent(); + } + } +} + +void TypeDumper::dump(const PDBSymbolTypeEnum &Symbol) { + assert(opts::pretty::Enums); + + EnumDumper Dumper(Printer); + Dumper.start(Symbol); +} + +void TypeDumper::dump(const PDBSymbolTypeBuiltin &Symbol) { + BuiltinDumper BD(Printer); + BD.start(Symbol); +} + +void TypeDumper::dump(const PDBSymbolTypeUDT &Symbol) { + printClassDecl(Printer, Symbol); +} + +void TypeDumper::dump(const PDBSymbolTypeTypedef &Symbol) { + assert(opts::pretty::Typedefs); + + TypedefDumper Dumper(Printer); + Dumper.start(Symbol); +} + +void TypeDumper::dump(const PDBSymbolTypeArray &Symbol) { + auto ElementType = Symbol.getElementType(); + + ElementType->dump(*this); + Printer << "["; + WithColor(Printer, PDB_ColorItem::LiteralValue).get() << Symbol.getCount(); + Printer << "]"; +} + +void TypeDumper::dump(const PDBSymbolTypeFunctionSig &Symbol) { + FunctionDumper Dumper(Printer); + Dumper.start(Symbol, nullptr, FunctionDumper::PointerType::None); +} + +void TypeDumper::dump(const PDBSymbolTypePointer &Symbol) { + std::unique_ptr<PDBSymbol> P = Symbol.getPointeeType(); + + if (auto *FS = dyn_cast<PDBSymbolTypeFunctionSig>(P.get())) { + FunctionDumper Dumper(Printer); + FunctionDumper::PointerType PT = + Symbol.isReference() ? FunctionDumper::PointerType::Reference + : FunctionDumper::PointerType::Pointer; + Dumper.start(*FS, nullptr, PT); + return; + } + + if (auto *UDT = dyn_cast<PDBSymbolTypeUDT>(P.get())) { + printClassDecl(Printer, *UDT); + } else if (P) { + P->dump(*this); + } + + if (auto Parent = Symbol.getClassParent()) { + auto UDT = llvm::unique_dyn_cast<PDBSymbolTypeUDT>(std::move(Parent)); + if (UDT) + Printer << " " << UDT->getName() << "::"; + } + + if (Symbol.isReference()) + Printer << "&"; + else if (Symbol.isRValueReference()) + Printer << "&&"; + else + Printer << "*"; +} + +void TypeDumper::dump(const PDBSymbolTypeVTableShape &Symbol) { + Printer.format("<vtshape ({0} methods)>", Symbol.getCount()); +} + +void TypeDumper::dumpClassLayout(const ClassLayout &Class) { + assert(opts::pretty::Classes); + + if (opts::pretty::ClassFormat == opts::pretty::ClassDefinitionFormat::None) { + WithColor(Printer, PDB_ColorItem::Keyword).get() + << Class.getClass().getUdtKind() << " "; + WithColor(Printer, PDB_ColorItem::Type).get() << Class.getName(); + } else { + ClassDefinitionDumper Dumper(Printer); + Dumper.start(Class); + } +} diff --git a/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyTypeDumper.h b/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyTypeDumper.h new file mode 100644 index 0000000000..b6539d95bf --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyTypeDumper.h @@ -0,0 +1,41 @@ +//===- PrettyTypeDumper.h - PDBSymDumper implementation for types *- C++ *-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMPDBDUMP_PRETTYTYPEDUMPER_H +#define LLVM_TOOLS_LLVMPDBDUMP_PRETTYTYPEDUMPER_H + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" + +namespace llvm { +namespace pdb { +class LinePrinter; +class ClassLayout; + +class TypeDumper : public PDBSymDumper { +public: + TypeDumper(LinePrinter &P); + + void start(const PDBSymbolExe &Exe); + + void dump(const PDBSymbolTypeEnum &Symbol) override; + void dump(const PDBSymbolTypeTypedef &Symbol) override; + void dump(const PDBSymbolTypeFunctionSig &Symbol) override; + void dump(const PDBSymbolTypeArray &Symbol) override; + void dump(const PDBSymbolTypeBuiltin &Symbol) override; + void dump(const PDBSymbolTypePointer &Symbol) override; + void dump(const PDBSymbolTypeVTableShape &Symbol) override; + void dump(const PDBSymbolTypeUDT &Symbol) override; + + void dumpClassLayout(const ClassLayout &Class); + +private: + LinePrinter &Printer; +}; +} +} +#endif diff --git a/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyTypedefDumper.cpp b/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyTypedefDumper.cpp new file mode 100644 index 0000000000..ef73a8cdf9 --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyTypedefDumper.cpp @@ -0,0 +1,82 @@ +//===- PrettyTypedefDumper.cpp - PDBSymDumper impl for typedefs -- * C++ *-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "PrettyTypedefDumper.h" + +#include "LinePrinter.h" +#include "PrettyBuiltinDumper.h" +#include "PrettyFunctionDumper.h" +#include "PrettyTypeDumper.h" + +#include "llvm/DebugInfo/PDB/IPDBSession.h" +#include "llvm/DebugInfo/PDB/PDBExtras.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" + +using namespace llvm; +using namespace llvm::pdb; + +TypedefDumper::TypedefDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {} + +void TypedefDumper::start(const PDBSymbolTypeTypedef &Symbol) { + WithColor(Printer, PDB_ColorItem::Keyword).get() << "typedef "; + uint32_t TargetId = Symbol.getTypeId(); + if (auto TypeSymbol = Symbol.getSession().getSymbolById(TargetId)) + TypeSymbol->dump(*this); + WithColor(Printer, PDB_ColorItem::Identifier).get() << " " + << Symbol.getName(); +} + +void TypedefDumper::dump(const PDBSymbolTypeArray &Symbol) { + TypeDumper Dumper(Printer); + Dumper.dump(Symbol); +} + +void TypedefDumper::dump(const PDBSymbolTypeBuiltin &Symbol) { + BuiltinDumper Dumper(Printer); + Dumper.start(Symbol); +} + +void TypedefDumper::dump(const PDBSymbolTypeEnum &Symbol) { + WithColor(Printer, PDB_ColorItem::Keyword).get() << "enum "; + WithColor(Printer, PDB_ColorItem::Type).get() << " " << Symbol.getName(); +} + +void TypedefDumper::dump(const PDBSymbolTypePointer &Symbol) { + if (Symbol.isConstType()) + WithColor(Printer, PDB_ColorItem::Keyword).get() << "const "; + if (Symbol.isVolatileType()) + WithColor(Printer, PDB_ColorItem::Keyword).get() << "volatile "; + auto PointeeType = Symbol.getPointeeType(); + if (auto FuncSig = unique_dyn_cast<PDBSymbolTypeFunctionSig>(PointeeType)) { + FunctionDumper::PointerType Pointer = FunctionDumper::PointerType::Pointer; + if (Symbol.isReference()) + Pointer = FunctionDumper::PointerType::Reference; + FunctionDumper NestedDumper(Printer); + NestedDumper.start(*FuncSig, nullptr, Pointer); + } else { + PointeeType->dump(*this); + Printer << ((Symbol.isReference()) ? "&" : "*"); + } + + if (Symbol.getRawSymbol().isRestrictedType()) + WithColor(Printer, PDB_ColorItem::Keyword).get() << " __restrict"; +} + +void TypedefDumper::dump(const PDBSymbolTypeFunctionSig &Symbol) { + FunctionDumper Dumper(Printer); + Dumper.start(Symbol, nullptr, FunctionDumper::PointerType::None); +} + +void TypedefDumper::dump(const PDBSymbolTypeUDT &Symbol) { + WithColor(Printer, PDB_ColorItem::Keyword).get() << "class "; + WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName(); +} diff --git a/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyTypedefDumper.h b/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyTypedefDumper.h new file mode 100644 index 0000000000..ad8b3f37dc --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyTypedefDumper.h @@ -0,0 +1,38 @@ +//===- PrettyTypedefDumper.h - llvm-pdbutil typedef dumper ---*- C++ ----*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMPDBDUMP_PRETTYTYPEDEFDUMPER_H +#define LLVM_TOOLS_LLVMPDBDUMP_PRETTYTYPEDEFDUMPER_H + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" + +namespace llvm { +namespace pdb { + +class LinePrinter; + +class TypedefDumper : public PDBSymDumper { +public: + TypedefDumper(LinePrinter &P); + + void start(const PDBSymbolTypeTypedef &Symbol); + + void dump(const PDBSymbolTypeArray &Symbol) override; + void dump(const PDBSymbolTypeBuiltin &Symbol) override; + void dump(const PDBSymbolTypeEnum &Symbol) override; + void dump(const PDBSymbolTypeFunctionSig &Symbol) override; + void dump(const PDBSymbolTypePointer &Symbol) override; + void dump(const PDBSymbolTypeUDT &Symbol) override; + +private: + LinePrinter &Printer; +}; +} +} + +#endif diff --git a/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyVariableDumper.cpp b/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyVariableDumper.cpp new file mode 100644 index 0000000000..6dd7cc384c --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyVariableDumper.cpp @@ -0,0 +1,225 @@ +//===- PrettyVariableDumper.cpp ---------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "PrettyVariableDumper.h" + +#include "LinePrinter.h" +#include "PrettyBuiltinDumper.h" +#include "PrettyFunctionDumper.h" +#include "llvm-pdbutil.h" + +#include "llvm/DebugInfo/PDB/IPDBSession.h" +#include "llvm/DebugInfo/PDB/PDBSymbolData.h" +#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeArray.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" +#include "llvm/DebugInfo/PDB/PDBTypes.h" + +#include "llvm/Support/Format.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +VariableDumper::VariableDumper(LinePrinter &P) + : PDBSymDumper(true), Printer(P) {} + +void VariableDumper::start(const PDBSymbolData &Var, uint32_t Offset) { + if (Var.isCompilerGenerated() && opts::pretty::ExcludeCompilerGenerated) + return; + if (Printer.IsSymbolExcluded(Var.getName())) + return; + + auto VarType = Var.getType(); + + uint64_t Length = VarType->getRawSymbol().getLength(); + + switch (auto LocType = Var.getLocationType()) { + case PDB_LocType::Static: + Printer.NewLine(); + Printer << "data ["; + WithColor(Printer, PDB_ColorItem::Address).get() + << format_hex(Var.getVirtualAddress(), 10); + Printer << ", sizeof=" << Length << "] "; + WithColor(Printer, PDB_ColorItem::Keyword).get() << "static "; + dumpSymbolTypeAndName(*VarType, Var.getName()); + break; + case PDB_LocType::Constant: + if (isa<PDBSymbolTypeEnum>(*VarType)) + break; + Printer.NewLine(); + Printer << "data [sizeof=" << Length << "] "; + dumpSymbolTypeAndName(*VarType, Var.getName()); + Printer << " = "; + WithColor(Printer, PDB_ColorItem::LiteralValue).get() << Var.getValue(); + break; + case PDB_LocType::ThisRel: + Printer.NewLine(); + Printer << "data "; + WithColor(Printer, PDB_ColorItem::Offset).get() + << "+" << format_hex(Offset + Var.getOffset(), 4) + << " [sizeof=" << Length << "] "; + dumpSymbolTypeAndName(*VarType, Var.getName()); + break; + case PDB_LocType::BitField: + Printer.NewLine(); + Printer << "data "; + WithColor(Printer, PDB_ColorItem::Offset).get() + << "+" << format_hex(Offset + Var.getOffset(), 4) + << " [sizeof=" << Length << "] "; + dumpSymbolTypeAndName(*VarType, Var.getName()); + Printer << " : "; + WithColor(Printer, PDB_ColorItem::LiteralValue).get() << Var.getLength(); + break; + default: + Printer.NewLine(); + Printer << "data [sizeof=" << Length << "] "; + Printer << "unknown(" << LocType << ") "; + WithColor(Printer, PDB_ColorItem::Identifier).get() << Var.getName(); + break; + } +} + +void VariableDumper::startVbptr(uint32_t Offset, uint32_t Size) { + Printer.NewLine(); + Printer << "vbptr "; + + WithColor(Printer, PDB_ColorItem::Offset).get() + << "+" << format_hex(Offset, 4) << " [sizeof=" << Size << "] "; +} + +void VariableDumper::start(const PDBSymbolTypeVTable &Var, uint32_t Offset) { + Printer.NewLine(); + Printer << "vfptr "; + auto VTableType = cast<PDBSymbolTypePointer>(Var.getType()); + uint32_t PointerSize = VTableType->getLength(); + + WithColor(Printer, PDB_ColorItem::Offset).get() + << "+" << format_hex(Offset + Var.getOffset(), 4) + << " [sizeof=" << PointerSize << "] "; +} + +void VariableDumper::dump(const PDBSymbolTypeArray &Symbol) { + auto ElementType = Symbol.getElementType(); + assert(ElementType); + if (!ElementType) + return; + ElementType->dump(*this); +} + +void VariableDumper::dumpRight(const PDBSymbolTypeArray &Symbol) { + auto ElementType = Symbol.getElementType(); + assert(ElementType); + if (!ElementType) + return; + Printer << '[' << Symbol.getCount() << ']'; + ElementType->dumpRight(*this); +} + +void VariableDumper::dump(const PDBSymbolTypeBuiltin &Symbol) { + BuiltinDumper Dumper(Printer); + Dumper.start(Symbol); +} + +void VariableDumper::dump(const PDBSymbolTypeEnum &Symbol) { + WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName(); +} + +void VariableDumper::dump(const PDBSymbolTypeFunctionSig &Symbol) { + auto ReturnType = Symbol.getReturnType(); + ReturnType->dump(*this); + Printer << " "; + + uint32_t ClassParentId = Symbol.getClassParentId(); + auto ClassParent = + Symbol.getSession().getConcreteSymbolById<PDBSymbolTypeUDT>( + ClassParentId); + + if (ClassParent) { + WithColor(Printer, PDB_ColorItem::Identifier).get() + << ClassParent->getName(); + Printer << "::"; + } +} + +void VariableDumper::dumpRight(const PDBSymbolTypeFunctionSig &Symbol) { + Printer << "("; + if (auto Arguments = Symbol.getArguments()) { + uint32_t Index = 0; + while (auto Arg = Arguments->getNext()) { + Arg->dump(*this); + if (++Index < Arguments->getChildCount()) + Printer << ", "; + } + } + Printer << ")"; + + if (Symbol.isConstType()) + WithColor(Printer, PDB_ColorItem::Keyword).get() << " const"; + if (Symbol.isVolatileType()) + WithColor(Printer, PDB_ColorItem::Keyword).get() << " volatile"; + + if (Symbol.getRawSymbol().isRestrictedType()) + WithColor(Printer, PDB_ColorItem::Keyword).get() << " __restrict"; +} + +void VariableDumper::dump(const PDBSymbolTypePointer &Symbol) { + auto PointeeType = Symbol.getPointeeType(); + if (!PointeeType) + return; + PointeeType->dump(*this); + if (auto FuncSig = unique_dyn_cast<PDBSymbolTypeFunctionSig>(PointeeType)) { + // A hack to get the calling convention in the right spot. + Printer << " ("; + PDB_CallingConv CC = FuncSig->getCallingConvention(); + WithColor(Printer, PDB_ColorItem::Keyword).get() << CC << " "; + } else if (isa<PDBSymbolTypeArray>(PointeeType)) { + Printer << " ("; + } + Printer << (Symbol.isReference() ? "&" : "*"); + if (Symbol.isConstType()) + WithColor(Printer, PDB_ColorItem::Keyword).get() << " const "; + if (Symbol.isVolatileType()) + WithColor(Printer, PDB_ColorItem::Keyword).get() << " volatile "; + + if (Symbol.getRawSymbol().isRestrictedType()) + WithColor(Printer, PDB_ColorItem::Keyword).get() << " __restrict "; +} + +void VariableDumper::dumpRight(const PDBSymbolTypePointer &Symbol) { + auto PointeeType = Symbol.getPointeeType(); + assert(PointeeType); + if (!PointeeType) + return; + if (isa<PDBSymbolTypeFunctionSig>(PointeeType) || + isa<PDBSymbolTypeArray>(PointeeType)) { + Printer << ")"; + } + PointeeType->dumpRight(*this); +} + +void VariableDumper::dump(const PDBSymbolTypeTypedef &Symbol) { + WithColor(Printer, PDB_ColorItem::Keyword).get() << "typedef "; + WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName(); +} + +void VariableDumper::dump(const PDBSymbolTypeUDT &Symbol) { + WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName(); +} + +void VariableDumper::dumpSymbolTypeAndName(const PDBSymbol &Type, + StringRef Name) { + Type.dump(*this); + WithColor(Printer, PDB_ColorItem::Identifier).get() << " " << Name; + Type.dumpRight(*this); +} diff --git a/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyVariableDumper.h b/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyVariableDumper.h new file mode 100644 index 0000000000..65cf5cd2cf --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-pdbutil/PrettyVariableDumper.h @@ -0,0 +1,49 @@ +//===- PrettyVariableDumper.h - PDBSymDumper variable dumper ----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMPDBDUMP_PRETTYVARIABLEDUMPER_H +#define LLVM_TOOLS_LLVMPDBDUMP_PRETTYVARIABLEDUMPER_H + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" + +namespace llvm { + +class StringRef; + +namespace pdb { + +class LinePrinter; + +class VariableDumper : public PDBSymDumper { +public: + VariableDumper(LinePrinter &P); + + void start(const PDBSymbolData &Var, uint32_t Offset = 0); + void start(const PDBSymbolTypeVTable &Var, uint32_t Offset = 0); + void startVbptr(uint32_t Offset, uint32_t Size); + + void dump(const PDBSymbolTypeArray &Symbol) override; + void dump(const PDBSymbolTypeBuiltin &Symbol) override; + void dump(const PDBSymbolTypeEnum &Symbol) override; + void dump(const PDBSymbolTypeFunctionSig &Symbol) override; + void dump(const PDBSymbolTypePointer &Symbol) override; + void dump(const PDBSymbolTypeTypedef &Symbol) override; + void dump(const PDBSymbolTypeUDT &Symbol) override; + + void dumpRight(const PDBSymbolTypeArray &Symbol) override; + void dumpRight(const PDBSymbolTypeFunctionSig &Symbol) override; + void dumpRight(const PDBSymbolTypePointer &Symbol) override; + +private: + void dumpSymbolTypeAndName(const PDBSymbol &Type, StringRef Name); + + LinePrinter &Printer; +}; +} +} +#endif diff --git a/contrib/libs/llvm12/tools/llvm-pdbutil/StreamUtil.cpp b/contrib/libs/llvm12/tools/llvm-pdbutil/StreamUtil.cpp new file mode 100644 index 0000000000..d0d0a9fbe9 --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-pdbutil/StreamUtil.cpp @@ -0,0 +1,194 @@ +//===- StreamUtil.cpp - PDB stream utilities --------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "StreamUtil.h" +#include "FormatUtil.h" + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseMapInfo.h" +#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h" +#include "llvm/DebugInfo/PDB/Native/DbiModuleList.h" +#include "llvm/DebugInfo/PDB/Native/DbiStream.h" +#include "llvm/DebugInfo/PDB/Native/InfoStream.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/TpiStream.h" + +using namespace llvm; +using namespace llvm::pdb; + +std::string StreamInfo::getLongName() const { + if (Purpose == StreamPurpose::NamedStream) + return formatv("Named Stream \"{0}\"", Name).str(); + if (Purpose == StreamPurpose::ModuleStream) + return formatv("Module \"{0}\"", Name).str(); + return Name; +} + +StreamInfo StreamInfo::createStream(StreamPurpose Purpose, StringRef Name, + uint32_t StreamIndex) { + StreamInfo Result; + Result.Name = std::string(Name); + Result.StreamIndex = StreamIndex; + Result.Purpose = Purpose; + return Result; +} + +StreamInfo StreamInfo::createModuleStream(StringRef Module, + uint32_t StreamIndex, uint32_t Modi) { + StreamInfo Result; + Result.Name = std::string(Module); + Result.StreamIndex = StreamIndex; + Result.ModuleIndex = Modi; + Result.Purpose = StreamPurpose::ModuleStream; + return Result; +} + +static inline StreamInfo stream(StreamPurpose Purpose, StringRef Label, + uint32_t Idx) { + return StreamInfo::createStream(Purpose, Label, Idx); +} + +static inline StreamInfo moduleStream(StringRef Label, uint32_t StreamIdx, + uint32_t Modi) { + return StreamInfo::createModuleStream(Label, StreamIdx, Modi); +} + +struct IndexedModuleDescriptor { + uint32_t Modi; + DbiModuleDescriptor Descriptor; +}; + +void llvm::pdb::discoverStreamPurposes(PDBFile &File, + SmallVectorImpl<StreamInfo> &Streams) { + // It's OK if we fail to load some of these streams, we still attempt to print + // what we can. + auto Dbi = File.getPDBDbiStream(); + auto Tpi = File.getPDBTpiStream(); + auto Ipi = File.getPDBIpiStream(); + auto Info = File.getPDBInfoStream(); + + uint32_t StreamCount = File.getNumStreams(); + DenseMap<uint16_t, IndexedModuleDescriptor> ModStreams; + DenseMap<uint16_t, std::string> NamedStreams; + + if (Dbi) { + const DbiModuleList &Modules = Dbi->modules(); + for (uint32_t I = 0; I < Modules.getModuleCount(); ++I) { + IndexedModuleDescriptor IMD; + IMD.Modi = I; + IMD.Descriptor = Modules.getModuleDescriptor(I); + uint16_t SN = IMD.Descriptor.getModuleStreamIndex(); + if (SN != kInvalidStreamIndex) + ModStreams[SN] = IMD; + } + } + if (Info) { + for (auto &NSE : Info->named_streams()) { + if (NSE.second != kInvalidStreamIndex) + NamedStreams[NSE.second] = std::string(NSE.first()); + } + } + + Streams.resize(StreamCount); + for (uint16_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) { + if (StreamIdx == OldMSFDirectory) + Streams[StreamIdx] = + stream(StreamPurpose::Other, "Old MSF Directory", StreamIdx); + else if (StreamIdx == StreamPDB) + Streams[StreamIdx] = stream(StreamPurpose::PDB, "PDB Stream", StreamIdx); + else if (StreamIdx == StreamDBI) + Streams[StreamIdx] = stream(StreamPurpose::DBI, "DBI Stream", StreamIdx); + else if (StreamIdx == StreamTPI) + Streams[StreamIdx] = stream(StreamPurpose::TPI, "TPI Stream", StreamIdx); + else if (StreamIdx == StreamIPI) + Streams[StreamIdx] = stream(StreamPurpose::IPI, "IPI Stream", StreamIdx); + else if (Dbi && StreamIdx == Dbi->getGlobalSymbolStreamIndex()) + Streams[StreamIdx] = + stream(StreamPurpose::GlobalHash, "Global Symbol Hash", StreamIdx); + else if (Dbi && StreamIdx == Dbi->getPublicSymbolStreamIndex()) + Streams[StreamIdx] = + stream(StreamPurpose::PublicHash, "Public Symbol Hash", StreamIdx); + else if (Dbi && StreamIdx == Dbi->getSymRecordStreamIndex()) + Streams[StreamIdx] = + stream(StreamPurpose::Symbols, "Symbol Records", StreamIdx); + else if (Tpi && StreamIdx == Tpi->getTypeHashStreamIndex()) + Streams[StreamIdx] = + stream(StreamPurpose::TpiHash, "TPI Hash", StreamIdx); + else if (Tpi && StreamIdx == Tpi->getTypeHashStreamAuxIndex()) + Streams[StreamIdx] = + stream(StreamPurpose::Other, "TPI Aux Hash", StreamIdx); + else if (Ipi && StreamIdx == Ipi->getTypeHashStreamIndex()) + Streams[StreamIdx] = + stream(StreamPurpose::IpiHash, "IPI Hash", StreamIdx); + else if (Ipi && StreamIdx == Ipi->getTypeHashStreamAuxIndex()) + Streams[StreamIdx] = + stream(StreamPurpose::Other, "IPI Aux Hash", StreamIdx); + else if (Dbi && + StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Exception)) + Streams[StreamIdx] = + stream(StreamPurpose::Other, "Exception Data", StreamIdx); + else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Fixup)) + Streams[StreamIdx] = + stream(StreamPurpose::Other, "Fixup Data", StreamIdx); + else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::FPO)) + Streams[StreamIdx] = stream(StreamPurpose::Other, "FPO Data", StreamIdx); + else if (Dbi && + StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::NewFPO)) + Streams[StreamIdx] = + stream(StreamPurpose::Other, "New FPO Data", StreamIdx); + else if (Dbi && + StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::OmapFromSrc)) + Streams[StreamIdx] = + stream(StreamPurpose::Other, "Omap From Source Data", StreamIdx); + else if (Dbi && + StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::OmapToSrc)) + Streams[StreamIdx] = + stream(StreamPurpose::Other, "Omap To Source Data", StreamIdx); + else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Pdata)) + Streams[StreamIdx] = stream(StreamPurpose::Other, "Pdata", StreamIdx); + else if (Dbi && + StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::SectionHdr)) + Streams[StreamIdx] = + stream(StreamPurpose::Other, "Section Header Data", StreamIdx); + else if (Dbi && + StreamIdx == + Dbi->getDebugStreamIndex(DbgHeaderType::SectionHdrOrig)) + Streams[StreamIdx] = stream(StreamPurpose::Other, + "Section Header Original Data", StreamIdx); + else if (Dbi && + StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::TokenRidMap)) + Streams[StreamIdx] = + stream(StreamPurpose::Other, "Token Rid Data", StreamIdx); + else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Xdata)) + Streams[StreamIdx] = stream(StreamPurpose::Other, "Xdata", StreamIdx); + else { + auto ModIter = ModStreams.find(StreamIdx); + auto NSIter = NamedStreams.find(StreamIdx); + if (ModIter != ModStreams.end()) { + Streams[StreamIdx] = + moduleStream(ModIter->second.Descriptor.getModuleName(), StreamIdx, + ModIter->second.Modi); + } else if (NSIter != NamedStreams.end()) { + Streams[StreamIdx] = + stream(StreamPurpose::NamedStream, NSIter->second, StreamIdx); + } else { + Streams[StreamIdx] = stream(StreamPurpose::Other, "???", StreamIdx); + } + } + } + + // Consume errors from missing streams. + if (!Dbi) + consumeError(Dbi.takeError()); + if (!Tpi) + consumeError(Tpi.takeError()); + if (!Ipi) + consumeError(Ipi.takeError()); + if (!Info) + consumeError(Info.takeError()); +} diff --git a/contrib/libs/llvm12/tools/llvm-pdbutil/StreamUtil.h b/contrib/libs/llvm12/tools/llvm-pdbutil/StreamUtil.h new file mode 100644 index 0000000000..f810f7dc15 --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-pdbutil/StreamUtil.h @@ -0,0 +1,63 @@ +//===- Streamutil.h - PDB stream utilities ----------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMPDBDUMP_STREAMUTIL_H +#define LLVM_TOOLS_LLVMPDBDUMP_STREAMUTIL_H + +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" + +#include <string> + +namespace llvm { +namespace pdb { +class PDBFile; +enum class StreamPurpose { + NamedStream, + ModuleStream, + Symbols, + PDB, + DBI, + TPI, + IPI, + GlobalHash, + PublicHash, + TpiHash, + IpiHash, + Other +}; + +struct StreamInfo { +public: + StreamInfo() {} + + uint32_t getModuleIndex() const { return *ModuleIndex; } + StreamPurpose getPurpose() const { return Purpose; } + StringRef getShortName() const { return Name; } + uint32_t getStreamIndex() const { return StreamIndex; } + std::string getLongName() const; + + static StreamInfo createStream(StreamPurpose Purpose, StringRef Name, + uint32_t StreamIndex); + static StreamInfo createModuleStream(StringRef Module, uint32_t StreamIndex, + uint32_t Modi); + +private: + StreamPurpose Purpose; + uint32_t StreamIndex; + std::string Name; + Optional<uint32_t> ModuleIndex; +}; + +void discoverStreamPurposes(PDBFile &File, + SmallVectorImpl<StreamInfo> &Streams); +} +} + +#endif diff --git a/contrib/libs/llvm12/tools/llvm-pdbutil/TypeReferenceTracker.cpp b/contrib/libs/llvm12/tools/llvm-pdbutil/TypeReferenceTracker.cpp new file mode 100644 index 0000000000..f184f02e01 --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-pdbutil/TypeReferenceTracker.cpp @@ -0,0 +1,160 @@ +//===- TypeReferenceTracker.cpp ------------------------------- *- C++ --*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "TypeReferenceTracker.h" + +#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/TpiStream.h" +#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h" +#include "llvm/DebugInfo/PDB/Native/SymbolStream.h" + +using namespace llvm; +using namespace llvm::pdb; +using namespace llvm::codeview; + +// LazyRandomTypeCollection doesn't appear to expose the number of records, so +// just iterate up front to find out. +static uint32_t getNumRecordsInCollection(LazyRandomTypeCollection &Types) { + uint32_t NumTypes = 0; + for (Optional<TypeIndex> TI = Types.getFirst(); TI; TI = Types.getNext(*TI)) + ++NumTypes; + return NumTypes; +} + +TypeReferenceTracker::TypeReferenceTracker(InputFile &File) + : File(File), Types(File.types()), + Ids(File.isPdb() ? &File.ids() : nullptr) { + NumTypeRecords = getNumRecordsInCollection(Types); + TypeReferenced.resize(NumTypeRecords, false); + + // If this is a PDB, ids are stored separately, so make a separate bit vector. + if (Ids) { + NumIdRecords = getNumRecordsInCollection(*Ids); + IdReferenced.resize(NumIdRecords, false); + } + + // Get the TpiStream pointer for forward decl resolution if this is a pdb. + // Build the hash map to enable resolving forward decls. + if (File.isPdb()) { + Tpi = &cantFail(File.pdb().getPDBTpiStream()); + Tpi->buildHashMap(); + } +} + +void TypeReferenceTracker::mark() { + // Walk type roots: + // - globals + // - modi symbols + // - LF_UDT_MOD_SRC_LINE? VC always links these in. + for (SymbolGroup SG : File.symbol_groups()) { + if (File.isObj()) { + for (const auto &SS : SG.getDebugSubsections()) { + // FIXME: Are there other type-referencing subsections? Inlinees? + // Probably for IDs. + if (SS.kind() != DebugSubsectionKind::Symbols) + continue; + + CVSymbolArray Symbols; + BinaryStreamReader Reader(SS.getRecordData()); + cantFail(Reader.readArray(Symbols, Reader.getLength())); + for (const CVSymbol &S : Symbols) + addTypeRefsFromSymbol(S); + } + } else if (SG.hasDebugStream()) { + for (const CVSymbol &S : SG.getPdbModuleStream().getSymbolArray()) + addTypeRefsFromSymbol(S); + } + } + + // Walk globals and mark types referenced from globals. + if (File.isPdb() && File.pdb().hasPDBGlobalsStream()) { + SymbolStream &SymStream = cantFail(File.pdb().getPDBSymbolStream()); + GlobalsStream &GS = cantFail(File.pdb().getPDBGlobalsStream()); + for (uint32_t PubSymOff : GS.getGlobalsTable()) { + CVSymbol Sym = SymStream.readRecord(PubSymOff); + addTypeRefsFromSymbol(Sym); + } + } + + // FIXME: Should we walk Ids? +} + +void TypeReferenceTracker::addOneTypeRef(TiRefKind RefKind, TypeIndex RefTI) { + // If it's simple or already seen, no need to add to work list. + BitVector &TypeOrIdReferenced = + (Ids && RefKind == TiRefKind::IndexRef) ? IdReferenced : TypeReferenced; + if (RefTI.isSimple() || TypeOrIdReferenced.test(RefTI.toArrayIndex())) + return; + + // Otherwise, mark it seen and add it to the work list. + TypeOrIdReferenced.set(RefTI.toArrayIndex()); + RefWorklist.push_back({RefKind, RefTI}); +} + +void TypeReferenceTracker::addTypeRefsFromSymbol(const CVSymbol &Sym) { + SmallVector<TiReference, 4> DepList; + // FIXME: Check for failure. + discoverTypeIndicesInSymbol(Sym, DepList); + addReferencedTypes(Sym.content(), DepList); + markReferencedTypes(); +} + +void TypeReferenceTracker::addReferencedTypes(ArrayRef<uint8_t> RecData, + ArrayRef<TiReference> DepList) { + for (const auto &Ref : DepList) { + // FIXME: Report OOB slice instead of truncating. + ArrayRef<uint8_t> ByteSlice = + RecData.drop_front(Ref.Offset).take_front(4 * Ref.Count); + ArrayRef<TypeIndex> TIs( + reinterpret_cast<const TypeIndex *>(ByteSlice.data()), + ByteSlice.size() / 4); + + // If this is a PDB and this is an item reference, track it in the IPI + // bitvector. Otherwise, it's a type ref, or there is only one stream. + for (TypeIndex RefTI : TIs) + addOneTypeRef(Ref.Kind, RefTI); + } +} + +void TypeReferenceTracker::markReferencedTypes() { + while (!RefWorklist.empty()) { + TiRefKind RefKind; + TypeIndex RefTI; + std::tie(RefKind, RefTI) = RefWorklist.pop_back_val(); + Optional<CVType> Rec = (Ids && RefKind == TiRefKind::IndexRef) + ? Ids->tryGetType(RefTI) + : Types.tryGetType(RefTI); + if (!Rec) + continue; // FIXME: Report a reference to a non-existant type. + + SmallVector<TiReference, 4> DepList; + // FIXME: Check for failure. + discoverTypeIndices(*Rec, DepList); + addReferencedTypes(Rec->content(), DepList); + + // If this is a tag kind and this is a PDB input, mark the complete type as + // referenced. + // FIXME: This limitation makes this feature somewhat useless on object file + // inputs. + if (Tpi) { + switch (Rec->kind()) { + default: + break; + case LF_CLASS: + case LF_INTERFACE: + case LF_STRUCTURE: + case LF_UNION: + case LF_ENUM: + addOneTypeRef(TiRefKind::TypeRef, + cantFail(Tpi->findFullDeclForForwardRef(RefTI))); + break; + } + } + } +} diff --git a/contrib/libs/llvm12/tools/llvm-pdbutil/TypeReferenceTracker.h b/contrib/libs/llvm12/tools/llvm-pdbutil/TypeReferenceTracker.h new file mode 100644 index 0000000000..8861731ab6 --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-pdbutil/TypeReferenceTracker.h @@ -0,0 +1,69 @@ +//===- TypeReferenceTracker.h --------------------------------- *- C++ --*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMPDBDUMP_TYPEREFERENCETRACKER_H +#define LLVM_TOOLS_LLVMPDBDUMP_TYPEREFERENCETRACKER_H + +#include "InputFile.h" + +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/DebugInfo/CodeView/CVRecord.h" +#include "llvm/DebugInfo/CodeView/TypeIndex.h" +#include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h" +#include "llvm/Support/Error.h" + +namespace llvm { +namespace pdb { + +class TpiStream; + +/// Maintains bitvector to track whether a type was referenced by a symbol +/// record. +class TypeReferenceTracker { +public: + TypeReferenceTracker(InputFile &File); + + // Do the work of marking referenced types. + void mark(); + + // Return true if a symbol record transitively references this type. + bool isTypeReferenced(codeview::TypeIndex TI) { + return TI.toArrayIndex() <= NumTypeRecords && + TypeReferenced.test(TI.toArrayIndex()); + } + +private: + void addTypeRefsFromSymbol(const codeview::CVSymbol &Sym); + + // Mark types on this list as referenced. + void addReferencedTypes(ArrayRef<uint8_t> RecData, + ArrayRef<codeview::TiReference> Refs); + + // Consume all types on the worklist. + void markReferencedTypes(); + + void addOneTypeRef(codeview::TiRefKind RefKind, codeview::TypeIndex RefTI); + + InputFile &File; + codeview::LazyRandomTypeCollection &Types; + codeview::LazyRandomTypeCollection *Ids = nullptr; + TpiStream *Tpi = nullptr; + BitVector TypeReferenced; + BitVector IdReferenced; + SmallVector<std::pair<codeview::TiRefKind, codeview::TypeIndex>, 10> + RefWorklist; + uint32_t NumTypeRecords = 0; + uint32_t NumIdRecords = 0; +}; + +} // namespace pdb +} // namespace llvm + +#endif // LLVM_TOOLS_LLVMPDBDUMP_TYPEREFERENCETRACKER_H diff --git a/contrib/libs/llvm12/tools/llvm-pdbutil/YAMLOutputStyle.cpp b/contrib/libs/llvm12/tools/llvm-pdbutil/YAMLOutputStyle.cpp new file mode 100644 index 0000000000..80b76657fa --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-pdbutil/YAMLOutputStyle.cpp @@ -0,0 +1,370 @@ +//===- YAMLOutputStyle.cpp ------------------------------------ *- C++ --*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "YAMLOutputStyle.h" + +#include "PdbYaml.h" +#include "llvm-pdbutil.h" + +#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h" +#include "llvm/DebugInfo/CodeView/DebugSubsection.h" +#include "llvm/DebugInfo/CodeView/DebugUnknownSubsection.h" +#include "llvm/DebugInfo/CodeView/StringsAndChecksums.h" +#include "llvm/DebugInfo/MSF/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Native/DbiStream.h" +#include "llvm/DebugInfo/PDB/Native/GlobalsStream.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/RawConstants.h" +#include "llvm/DebugInfo/PDB/Native/SymbolStream.h" +#include "llvm/DebugInfo/PDB/Native/TpiStream.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +static bool checkModuleSubsection(opts::ModuleSubsection MS) { + return any_of(opts::pdb2yaml::DumpModuleSubsections, + [=](opts::ModuleSubsection M) { + return M == MS || M == opts::ModuleSubsection::All; + }); +} + +YAMLOutputStyle::YAMLOutputStyle(PDBFile &File) + : File(File), Out(outs()), Obj(File.getAllocator()) { + Out.setWriteDefaultValues(!opts::pdb2yaml::Minimal); +} + +Error YAMLOutputStyle::dump() { + if (opts::pdb2yaml::StreamDirectory) + opts::pdb2yaml::StreamMetadata = true; + + if (auto EC = dumpFileHeaders()) + return EC; + + if (auto EC = dumpStreamMetadata()) + return EC; + + if (auto EC = dumpStreamDirectory()) + return EC; + + if (auto EC = dumpStringTable()) + return EC; + + if (auto EC = dumpPDBStream()) + return EC; + + if (auto EC = dumpDbiStream()) + return EC; + + if (auto EC = dumpTpiStream()) + return EC; + + if (auto EC = dumpIpiStream()) + return EC; + + if (auto EC = dumpPublics()) + return EC; + + flush(); + return Error::success(); +} + + +Error YAMLOutputStyle::dumpFileHeaders() { + if (opts::pdb2yaml::NoFileHeaders) + return Error::success(); + + yaml::MSFHeaders Headers; + Obj.Headers.emplace(); + Obj.Headers->SuperBlock.NumBlocks = File.getBlockCount(); + Obj.Headers->SuperBlock.BlockMapAddr = File.getBlockMapIndex(); + Obj.Headers->SuperBlock.BlockSize = File.getBlockSize(); + auto Blocks = File.getDirectoryBlockArray(); + Obj.Headers->DirectoryBlocks.assign(Blocks.begin(), Blocks.end()); + Obj.Headers->NumDirectoryBlocks = File.getNumDirectoryBlocks(); + Obj.Headers->SuperBlock.NumDirectoryBytes = File.getNumDirectoryBytes(); + Obj.Headers->NumStreams = + opts::pdb2yaml::StreamMetadata ? File.getNumStreams() : 0; + Obj.Headers->SuperBlock.FreeBlockMapBlock = File.getFreeBlockMapBlock(); + Obj.Headers->SuperBlock.Unknown1 = File.getUnknown1(); + Obj.Headers->FileSize = File.getFileSize(); + + return Error::success(); +} + +Error YAMLOutputStyle::dumpStringTable() { + bool RequiresStringTable = opts::pdb2yaml::DumpModuleFiles || + !opts::pdb2yaml::DumpModuleSubsections.empty(); + bool RequestedStringTable = opts::pdb2yaml::StringTable; + if (!RequiresStringTable && !RequestedStringTable) + return Error::success(); + + auto ExpectedST = File.getStringTable(); + if (!ExpectedST) + return ExpectedST.takeError(); + + Obj.StringTable.emplace(); + const auto &ST = ExpectedST.get(); + for (auto ID : ST.name_ids()) { + auto S = ST.getStringForID(ID); + if (!S) + return S.takeError(); + if (S->empty()) + continue; + Obj.StringTable->push_back(*S); + } + return Error::success(); +} + +Error YAMLOutputStyle::dumpStreamMetadata() { + if (!opts::pdb2yaml::StreamMetadata) + return Error::success(); + + Obj.StreamSizes.emplace(); + Obj.StreamSizes->assign(File.getStreamSizes().begin(), + File.getStreamSizes().end()); + return Error::success(); +} + +Error YAMLOutputStyle::dumpStreamDirectory() { + if (!opts::pdb2yaml::StreamDirectory) + return Error::success(); + + auto StreamMap = File.getStreamMap(); + Obj.StreamMap.emplace(); + for (auto &Stream : StreamMap) { + pdb::yaml::StreamBlockList BlockList; + BlockList.Blocks.assign(Stream.begin(), Stream.end()); + Obj.StreamMap->push_back(BlockList); + } + + return Error::success(); +} + +Error YAMLOutputStyle::dumpPDBStream() { + if (!opts::pdb2yaml::PdbStream) + return Error::success(); + + auto IS = File.getPDBInfoStream(); + if (!IS) + return IS.takeError(); + + auto &InfoS = IS.get(); + Obj.PdbStream.emplace(); + Obj.PdbStream->Age = InfoS.getAge(); + Obj.PdbStream->Guid = InfoS.getGuid(); + Obj.PdbStream->Signature = InfoS.getSignature(); + Obj.PdbStream->Version = InfoS.getVersion(); + Obj.PdbStream->Features = InfoS.getFeatureSignatures(); + + return Error::success(); +} + +static opts::ModuleSubsection convertSubsectionKind(DebugSubsectionKind K) { + switch (K) { + case DebugSubsectionKind::CrossScopeExports: + return opts::ModuleSubsection::CrossScopeExports; + case DebugSubsectionKind::CrossScopeImports: + return opts::ModuleSubsection::CrossScopeImports; + case DebugSubsectionKind::FileChecksums: + return opts::ModuleSubsection::FileChecksums; + case DebugSubsectionKind::InlineeLines: + return opts::ModuleSubsection::InlineeLines; + case DebugSubsectionKind::Lines: + return opts::ModuleSubsection::Lines; + case DebugSubsectionKind::Symbols: + return opts::ModuleSubsection::Symbols; + case DebugSubsectionKind::StringTable: + return opts::ModuleSubsection::StringTable; + case DebugSubsectionKind::FrameData: + return opts::ModuleSubsection::FrameData; + default: + return opts::ModuleSubsection::Unknown; + } + llvm_unreachable("Unreachable!"); +} + +Error YAMLOutputStyle::dumpDbiStream() { + if (!opts::pdb2yaml::DbiStream) + return Error::success(); + + if (!File.hasPDBDbiStream()) + return Error::success(); + + auto DbiS = File.getPDBDbiStream(); + if (!DbiS) + return DbiS.takeError(); + + auto &DS = DbiS.get(); + Obj.DbiStream.emplace(); + Obj.DbiStream->Age = DS.getAge(); + Obj.DbiStream->BuildNumber = DS.getBuildNumber(); + Obj.DbiStream->Flags = DS.getFlags(); + Obj.DbiStream->MachineType = DS.getMachineType(); + Obj.DbiStream->PdbDllRbld = DS.getPdbDllRbld(); + Obj.DbiStream->PdbDllVersion = DS.getPdbDllVersion(); + Obj.DbiStream->VerHeader = DS.getDbiVersion(); + if (opts::pdb2yaml::DumpModules) { + const auto &Modules = DS.modules(); + for (uint32_t I = 0; I < Modules.getModuleCount(); ++I) { + DbiModuleDescriptor MI = Modules.getModuleDescriptor(I); + + Obj.DbiStream->ModInfos.emplace_back(); + yaml::PdbDbiModuleInfo &DMI = Obj.DbiStream->ModInfos.back(); + + DMI.Mod = MI.getModuleName(); + DMI.Obj = MI.getObjFileName(); + if (opts::pdb2yaml::DumpModuleFiles) { + auto Files = Modules.source_files(I); + DMI.SourceFiles.assign(Files.begin(), Files.end()); + } + + uint16_t ModiStream = MI.getModuleStreamIndex(); + if (ModiStream == kInvalidStreamIndex) + continue; + + auto ModStreamData = File.createIndexedStream(ModiStream); + pdb::ModuleDebugStreamRef ModS(MI, std::move(ModStreamData)); + if (auto EC = ModS.reload()) + return EC; + + auto ExpectedST = File.getStringTable(); + if (!ExpectedST) + return ExpectedST.takeError(); + if (!opts::pdb2yaml::DumpModuleSubsections.empty() && + ModS.hasDebugSubsections()) { + auto ExpectedChecksums = ModS.findChecksumsSubsection(); + if (!ExpectedChecksums) + return ExpectedChecksums.takeError(); + + StringsAndChecksumsRef SC(ExpectedST->getStringTable(), + *ExpectedChecksums); + + for (const auto &SS : ModS.subsections()) { + opts::ModuleSubsection OptionKind = convertSubsectionKind(SS.kind()); + if (!checkModuleSubsection(OptionKind)) + continue; + + auto Converted = + CodeViewYAML::YAMLDebugSubsection::fromCodeViewSubection(SC, SS); + if (!Converted) + return Converted.takeError(); + DMI.Subsections.push_back(*Converted); + } + } + + if (opts::pdb2yaml::DumpModuleSyms) { + DMI.Modi.emplace(); + + DMI.Modi->Signature = ModS.signature(); + bool HadError = false; + for (auto &Sym : ModS.symbols(&HadError)) { + auto ES = CodeViewYAML::SymbolRecord::fromCodeViewSymbol(Sym); + if (!ES) + return ES.takeError(); + + DMI.Modi->Symbols.push_back(*ES); + } + } + } + } + return Error::success(); +} + +Error YAMLOutputStyle::dumpTpiStream() { + if (!opts::pdb2yaml::TpiStream) + return Error::success(); + + auto TpiS = File.getPDBTpiStream(); + if (!TpiS) + return TpiS.takeError(); + + auto &TS = TpiS.get(); + Obj.TpiStream.emplace(); + Obj.TpiStream->Version = TS.getTpiVersion(); + for (auto &Record : TS.types(nullptr)) { + auto ExpectedRecord = CodeViewYAML::LeafRecord::fromCodeViewRecord(Record); + if (!ExpectedRecord) + return ExpectedRecord.takeError(); + Obj.TpiStream->Records.push_back(*ExpectedRecord); + } + + return Error::success(); +} + +Error YAMLOutputStyle::dumpIpiStream() { + if (!opts::pdb2yaml::IpiStream) + return Error::success(); + + auto InfoS = File.getPDBInfoStream(); + if (!InfoS) + return InfoS.takeError(); + if (!InfoS->containsIdStream()) + return Error::success(); + + auto IpiS = File.getPDBIpiStream(); + if (!IpiS) + return IpiS.takeError(); + + auto &IS = IpiS.get(); + Obj.IpiStream.emplace(); + Obj.IpiStream->Version = IS.getTpiVersion(); + for (auto &Record : IS.types(nullptr)) { + auto ExpectedRecord = CodeViewYAML::LeafRecord::fromCodeViewRecord(Record); + if (!ExpectedRecord) + return ExpectedRecord.takeError(); + + Obj.IpiStream->Records.push_back(*ExpectedRecord); + } + + return Error::success(); +} + +Error YAMLOutputStyle::dumpPublics() { + if (!opts::pdb2yaml::PublicsStream) + return Error::success(); + + Obj.PublicsStream.emplace(); + auto ExpectedPublics = File.getPDBPublicsStream(); + if (!ExpectedPublics) { + llvm::consumeError(ExpectedPublics.takeError()); + return Error::success(); + } + + PublicsStream &Publics = *ExpectedPublics; + const GSIHashTable &PublicsTable = Publics.getPublicsTable(); + + auto ExpectedSyms = File.getPDBSymbolStream(); + if (!ExpectedSyms) { + llvm::consumeError(ExpectedSyms.takeError()); + return Error::success(); + } + + BinaryStreamRef SymStream = + ExpectedSyms->getSymbolArray().getUnderlyingStream(); + for (uint32_t PubSymOff : PublicsTable) { + Expected<CVSymbol> Sym = readSymbolFromStream(SymStream, PubSymOff); + if (!Sym) + return Sym.takeError(); + auto ES = CodeViewYAML::SymbolRecord::fromCodeViewSymbol(*Sym); + if (!ES) + return ES.takeError(); + + Obj.PublicsStream->PubSyms.push_back(*ES); + } + + return Error::success(); +} + +void YAMLOutputStyle::flush() { + Out << Obj; + outs().flush(); +} diff --git a/contrib/libs/llvm12/tools/llvm-pdbutil/YAMLOutputStyle.h b/contrib/libs/llvm12/tools/llvm-pdbutil/YAMLOutputStyle.h new file mode 100644 index 0000000000..7a50af1abe --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-pdbutil/YAMLOutputStyle.h @@ -0,0 +1,49 @@ +//===- YAMLOutputStyle.h -------------------------------------- *- C++ --*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMPDBDUMP_YAMLOUTPUTSTYLE_H +#define LLVM_TOOLS_LLVMPDBDUMP_YAMLOUTPUTSTYLE_H + +#include "OutputStyle.h" +#include "PdbYaml.h" + +#include "llvm/Support/ScopedPrinter.h" +#include "llvm/Support/YAMLTraits.h" + +namespace llvm { +namespace pdb { +class ModuleDebugStreamRef; + +class YAMLOutputStyle : public OutputStyle { +public: + YAMLOutputStyle(PDBFile &File); + + Error dump() override; + +private: + Error dumpStringTable(); + Error dumpFileHeaders(); + Error dumpStreamMetadata(); + Error dumpStreamDirectory(); + Error dumpPDBStream(); + Error dumpDbiStream(); + Error dumpTpiStream(); + Error dumpIpiStream(); + Error dumpPublics(); + + void flush(); + + PDBFile &File; + llvm::yaml::Output Out; + + yaml::PdbObject Obj; +}; +} // namespace pdb +} // namespace llvm + +#endif // LLVM_TOOLS_LLVMPDBDUMP_YAMLOUTPUTSTYLE_H diff --git a/contrib/libs/llvm12/tools/llvm-pdbutil/llvm-pdbutil.cpp b/contrib/libs/llvm12/tools/llvm-pdbutil/llvm-pdbutil.cpp new file mode 100644 index 0000000000..19f4880ab5 --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-pdbutil/llvm-pdbutil.cpp @@ -0,0 +1,1575 @@ +//===- llvm-pdbutil.cpp - Dump debug info from a PDB file -------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Dumps debug information present in PDB files. +// +//===----------------------------------------------------------------------===// + +#include "llvm-pdbutil.h" + +#include "BytesOutputStyle.h" +#include "DumpOutputStyle.h" +#include "ExplainOutputStyle.h" +#include "InputFile.h" +#include "LinePrinter.h" +#include "OutputStyle.h" +#include "PrettyClassDefinitionDumper.h" +#include "PrettyCompilandDumper.h" +#include "PrettyEnumDumper.h" +#include "PrettyExternalSymbolDumper.h" +#include "PrettyFunctionDumper.h" +#include "PrettyTypeDumper.h" +#include "PrettyTypedefDumper.h" +#include "PrettyVariableDumper.h" +#include "YAMLOutputStyle.h" + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/BinaryFormat/Magic.h" +#include "llvm/Config/config.h" +#include "llvm/DebugInfo/CodeView/AppendingTypeTableBuilder.h" +#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h" +#include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h" +#include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h" +#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" +#include "llvm/DebugInfo/CodeView/MergingTypeTableBuilder.h" +#include "llvm/DebugInfo/CodeView/StringsAndChecksums.h" +#include "llvm/DebugInfo/CodeView/TypeStreamMerger.h" +#include "llvm/DebugInfo/MSF/MSFBuilder.h" +#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" +#include "llvm/DebugInfo/PDB/IPDBInjectedSource.h" +#include "llvm/DebugInfo/PDB/IPDBRawSymbol.h" +#include "llvm/DebugInfo/PDB/IPDBSession.h" +#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h" +#include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h" +#include "llvm/DebugInfo/PDB/Native/InfoStream.h" +#include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h" +#include "llvm/DebugInfo/PDB/Native/NativeSession.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h" +#include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h" +#include "llvm/DebugInfo/PDB/Native/RawConstants.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/DebugInfo/PDB/Native/TpiStream.h" +#include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h" +#include "llvm/DebugInfo/PDB/PDB.h" +#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" +#include "llvm/DebugInfo/PDB/PDBSymbolData.h" +#include "llvm/DebugInfo/PDB/PDBSymbolExe.h" +#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h" +#include "llvm/DebugInfo/PDB/PDBSymbolPublicSymbol.h" +#include "llvm/DebugInfo/PDB/PDBSymbolThunk.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionArg.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/COM.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/ConvertUTF.h" +#include "llvm/Support/FileOutputBuffer.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/InitLLVM.h" +#include "llvm/Support/LineIterator.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/Process.h" +#include "llvm/Support/Regex.h" +#include "llvm/Support/ScopedPrinter.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::msf; +using namespace llvm::pdb; + +namespace opts { + +cl::SubCommand DumpSubcommand("dump", "Dump MSF and CodeView debug info"); +cl::SubCommand BytesSubcommand("bytes", "Dump raw bytes from the PDB file"); + +cl::SubCommand DiaDumpSubcommand("diadump", + "Dump debug information using a DIA-like API"); + +cl::SubCommand + PrettySubcommand("pretty", + "Dump semantic information about types and symbols"); + +cl::SubCommand + YamlToPdbSubcommand("yaml2pdb", + "Generate a PDB file from a YAML description"); +cl::SubCommand + PdbToYamlSubcommand("pdb2yaml", + "Generate a detailed YAML description of a PDB File"); + +cl::SubCommand MergeSubcommand("merge", + "Merge multiple PDBs into a single PDB"); + +cl::SubCommand ExplainSubcommand("explain", + "Explain the meaning of a file offset"); + +cl::SubCommand ExportSubcommand("export", + "Write binary data from a stream to a file"); + +cl::OptionCategory TypeCategory("Symbol Type Options"); +cl::OptionCategory FilterCategory("Filtering and Sorting Options"); +cl::OptionCategory OtherOptions("Other Options"); + +cl::ValuesClass ChunkValues = cl::values( + clEnumValN(ModuleSubsection::CrossScopeExports, "cme", + "Cross module exports (DEBUG_S_CROSSSCOPEEXPORTS subsection)"), + clEnumValN(ModuleSubsection::CrossScopeImports, "cmi", + "Cross module imports (DEBUG_S_CROSSSCOPEIMPORTS subsection)"), + clEnumValN(ModuleSubsection::FileChecksums, "fc", + "File checksums (DEBUG_S_CHECKSUMS subsection)"), + clEnumValN(ModuleSubsection::InlineeLines, "ilines", + "Inlinee lines (DEBUG_S_INLINEELINES subsection)"), + clEnumValN(ModuleSubsection::Lines, "lines", + "Lines (DEBUG_S_LINES subsection)"), + clEnumValN(ModuleSubsection::StringTable, "strings", + "String Table (DEBUG_S_STRINGTABLE subsection) (not " + "typically present in PDB file)"), + clEnumValN(ModuleSubsection::FrameData, "frames", + "Frame Data (DEBUG_S_FRAMEDATA subsection)"), + clEnumValN(ModuleSubsection::Symbols, "symbols", + "Symbols (DEBUG_S_SYMBOLS subsection) (not typically " + "present in PDB file)"), + clEnumValN(ModuleSubsection::CoffSymbolRVAs, "rvas", + "COFF Symbol RVAs (DEBUG_S_COFF_SYMBOL_RVA subsection)"), + clEnumValN(ModuleSubsection::Unknown, "unknown", + "Any subsection not covered by another option"), + clEnumValN(ModuleSubsection::All, "all", "All known subsections")); + +namespace diadump { +cl::list<std::string> InputFilenames(cl::Positional, + cl::desc("<input PDB files>"), + cl::OneOrMore, cl::sub(DiaDumpSubcommand)); + +cl::opt<bool> Native("native", cl::desc("Use native PDB reader instead of DIA"), + cl::sub(DiaDumpSubcommand)); + +static cl::opt<bool> + ShowClassHierarchy("hierarchy", cl::desc("Show lexical and class parents"), + cl::sub(DiaDumpSubcommand)); +static cl::opt<bool> NoSymIndexIds( + "no-ids", + cl::desc("Don't show any SymIndexId fields (overrides -hierarchy)"), + cl::sub(DiaDumpSubcommand)); + +static cl::opt<bool> + Recurse("recurse", + cl::desc("When dumping a SymIndexId, dump the full details of the " + "corresponding record"), + cl::sub(DiaDumpSubcommand)); + +static cl::opt<bool> Enums("enums", cl::desc("Dump enum types"), + cl::sub(DiaDumpSubcommand)); +static cl::opt<bool> Pointers("pointers", cl::desc("Dump enum types"), + cl::sub(DiaDumpSubcommand)); +static cl::opt<bool> UDTs("udts", cl::desc("Dump udt types"), + cl::sub(DiaDumpSubcommand)); +static cl::opt<bool> Compilands("compilands", + cl::desc("Dump compiland information"), + cl::sub(DiaDumpSubcommand)); +static cl::opt<bool> Funcsigs("funcsigs", + cl::desc("Dump function signature information"), + cl::sub(DiaDumpSubcommand)); +static cl::opt<bool> Arrays("arrays", cl::desc("Dump array types"), + cl::sub(DiaDumpSubcommand)); +static cl::opt<bool> VTShapes("vtshapes", cl::desc("Dump virtual table shapes"), + cl::sub(DiaDumpSubcommand)); +static cl::opt<bool> Typedefs("typedefs", cl::desc("Dump typedefs"), + cl::sub(DiaDumpSubcommand)); +} // namespace diadump + +namespace pretty { +cl::list<std::string> InputFilenames(cl::Positional, + cl::desc("<input PDB files>"), + cl::OneOrMore, cl::sub(PrettySubcommand)); + +cl::opt<bool> InjectedSources("injected-sources", + cl::desc("Display injected sources"), + cl::cat(OtherOptions), cl::sub(PrettySubcommand)); +cl::opt<bool> ShowInjectedSourceContent( + "injected-source-content", + cl::desc("When displaying an injected source, display the file content"), + cl::cat(OtherOptions), cl::sub(PrettySubcommand)); + +cl::list<std::string> WithName( + "with-name", + cl::desc("Display any symbol or type with the specified exact name"), + cl::cat(TypeCategory), cl::ZeroOrMore, cl::sub(PrettySubcommand)); + +cl::opt<bool> Compilands("compilands", cl::desc("Display compilands"), + cl::cat(TypeCategory), cl::sub(PrettySubcommand)); +cl::opt<bool> Symbols("module-syms", + cl::desc("Display symbols for each compiland"), + cl::cat(TypeCategory), cl::sub(PrettySubcommand)); +cl::opt<bool> Globals("globals", cl::desc("Dump global symbols"), + cl::cat(TypeCategory), cl::sub(PrettySubcommand)); +cl::opt<bool> Externals("externals", cl::desc("Dump external symbols"), + cl::cat(TypeCategory), cl::sub(PrettySubcommand)); +cl::list<SymLevel> SymTypes( + "sym-types", cl::desc("Type of symbols to dump (default all)"), + cl::cat(TypeCategory), cl::sub(PrettySubcommand), cl::ZeroOrMore, + cl::values( + clEnumValN(SymLevel::Thunks, "thunks", "Display thunk symbols"), + clEnumValN(SymLevel::Data, "data", "Display data symbols"), + clEnumValN(SymLevel::Functions, "funcs", "Display function symbols"), + clEnumValN(SymLevel::All, "all", "Display all symbols (default)"))); + +cl::opt<bool> + Types("types", + cl::desc("Display all types (implies -classes, -enums, -typedefs)"), + cl::cat(TypeCategory), cl::sub(PrettySubcommand)); +cl::opt<bool> Classes("classes", cl::desc("Display class types"), + cl::cat(TypeCategory), cl::sub(PrettySubcommand)); +cl::opt<bool> Enums("enums", cl::desc("Display enum types"), + cl::cat(TypeCategory), cl::sub(PrettySubcommand)); +cl::opt<bool> Typedefs("typedefs", cl::desc("Display typedef types"), + cl::cat(TypeCategory), cl::sub(PrettySubcommand)); +cl::opt<bool> Funcsigs("funcsigs", cl::desc("Display function signatures"), + cl::cat(TypeCategory), cl::sub(PrettySubcommand)); +cl::opt<bool> Pointers("pointers", cl::desc("Display pointer types"), + cl::cat(TypeCategory), cl::sub(PrettySubcommand)); +cl::opt<bool> Arrays("arrays", cl::desc("Display arrays"), + cl::cat(TypeCategory), cl::sub(PrettySubcommand)); +cl::opt<bool> VTShapes("vtshapes", cl::desc("Display vftable shapes"), + cl::cat(TypeCategory), cl::sub(PrettySubcommand)); + +cl::opt<SymbolSortMode> SymbolOrder( + "symbol-order", cl::desc("symbol sort order"), + cl::init(SymbolSortMode::None), + cl::values(clEnumValN(SymbolSortMode::None, "none", + "Undefined / no particular sort order"), + clEnumValN(SymbolSortMode::Name, "name", "Sort symbols by name"), + clEnumValN(SymbolSortMode::Size, "size", + "Sort symbols by size")), + cl::cat(TypeCategory), cl::sub(PrettySubcommand)); + +cl::opt<ClassSortMode> ClassOrder( + "class-order", cl::desc("Class sort order"), cl::init(ClassSortMode::None), + cl::values( + clEnumValN(ClassSortMode::None, "none", + "Undefined / no particular sort order"), + clEnumValN(ClassSortMode::Name, "name", "Sort classes by name"), + clEnumValN(ClassSortMode::Size, "size", "Sort classes by size"), + clEnumValN(ClassSortMode::Padding, "padding", + "Sort classes by amount of padding"), + clEnumValN(ClassSortMode::PaddingPct, "padding-pct", + "Sort classes by percentage of space consumed by padding"), + clEnumValN(ClassSortMode::PaddingImmediate, "padding-imm", + "Sort classes by amount of immediate padding"), + clEnumValN(ClassSortMode::PaddingPctImmediate, "padding-pct-imm", + "Sort classes by percentage of space consumed by immediate " + "padding")), + cl::cat(TypeCategory), cl::sub(PrettySubcommand)); + +cl::opt<ClassDefinitionFormat> ClassFormat( + "class-definitions", cl::desc("Class definition format"), + cl::init(ClassDefinitionFormat::All), + cl::values( + clEnumValN(ClassDefinitionFormat::All, "all", + "Display all class members including data, constants, " + "typedefs, functions, etc"), + clEnumValN(ClassDefinitionFormat::Layout, "layout", + "Only display members that contribute to class size."), + clEnumValN(ClassDefinitionFormat::None, "none", + "Don't display class definitions")), + cl::cat(TypeCategory), cl::sub(PrettySubcommand)); +cl::opt<uint32_t> ClassRecursionDepth( + "class-recurse-depth", cl::desc("Class recursion depth (0=no limit)"), + cl::init(0), cl::cat(TypeCategory), cl::sub(PrettySubcommand)); + +cl::opt<bool> Lines("lines", cl::desc("Line tables"), cl::cat(TypeCategory), + cl::sub(PrettySubcommand)); +cl::opt<bool> + All("all", cl::desc("Implies all other options in 'Symbol Types' category"), + cl::cat(TypeCategory), cl::sub(PrettySubcommand)); + +cl::opt<uint64_t> LoadAddress( + "load-address", + cl::desc("Assume the module is loaded at the specified address"), + cl::cat(OtherOptions), cl::sub(PrettySubcommand)); +cl::opt<bool> Native("native", cl::desc("Use native PDB reader instead of DIA"), + cl::cat(OtherOptions), cl::sub(PrettySubcommand)); +cl::opt<cl::boolOrDefault> + ColorOutput("color-output", + cl::desc("Override use of color (default = isatty)"), + cl::cat(OtherOptions), cl::sub(PrettySubcommand)); +cl::list<std::string> ExcludeTypes( + "exclude-types", cl::desc("Exclude types by regular expression"), + cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand)); +cl::list<std::string> ExcludeSymbols( + "exclude-symbols", cl::desc("Exclude symbols by regular expression"), + cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand)); +cl::list<std::string> ExcludeCompilands( + "exclude-compilands", cl::desc("Exclude compilands by regular expression"), + cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand)); + +cl::list<std::string> IncludeTypes( + "include-types", + cl::desc("Include only types which match a regular expression"), + cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand)); +cl::list<std::string> IncludeSymbols( + "include-symbols", + cl::desc("Include only symbols which match a regular expression"), + cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand)); +cl::list<std::string> IncludeCompilands( + "include-compilands", + cl::desc("Include only compilands those which match a regular expression"), + cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand)); +cl::opt<uint32_t> SizeThreshold( + "min-type-size", cl::desc("Displays only those types which are greater " + "than or equal to the specified size."), + cl::init(0), cl::cat(FilterCategory), cl::sub(PrettySubcommand)); +cl::opt<uint32_t> PaddingThreshold( + "min-class-padding", cl::desc("Displays only those classes which have at " + "least the specified amount of padding."), + cl::init(0), cl::cat(FilterCategory), cl::sub(PrettySubcommand)); +cl::opt<uint32_t> ImmediatePaddingThreshold( + "min-class-padding-imm", + cl::desc("Displays only those classes which have at least the specified " + "amount of immediate padding, ignoring padding internal to bases " + "and aggregates."), + cl::init(0), cl::cat(FilterCategory), cl::sub(PrettySubcommand)); + +cl::opt<bool> ExcludeCompilerGenerated( + "no-compiler-generated", + cl::desc("Don't show compiler generated types and symbols"), + cl::cat(FilterCategory), cl::sub(PrettySubcommand)); +cl::opt<bool> + ExcludeSystemLibraries("no-system-libs", + cl::desc("Don't show symbols from system libraries"), + cl::cat(FilterCategory), cl::sub(PrettySubcommand)); + +cl::opt<bool> NoEnumDefs("no-enum-definitions", + cl::desc("Don't display full enum definitions"), + cl::cat(FilterCategory), cl::sub(PrettySubcommand)); +} + +cl::OptionCategory FileOptions("Module & File Options"); + +namespace bytes { +cl::OptionCategory MsfBytes("MSF File Options"); +cl::OptionCategory DbiBytes("Dbi Stream Options"); +cl::OptionCategory PdbBytes("PDB Stream Options"); +cl::OptionCategory Types("Type Options"); +cl::OptionCategory ModuleCategory("Module Options"); + +llvm::Optional<NumberRange> DumpBlockRange; +llvm::Optional<NumberRange> DumpByteRange; + +cl::opt<std::string> DumpBlockRangeOpt( + "block-range", cl::value_desc("start[-end]"), + cl::desc("Dump binary data from specified range of blocks."), + cl::sub(BytesSubcommand), cl::cat(MsfBytes)); + +cl::opt<std::string> + DumpByteRangeOpt("byte-range", cl::value_desc("start[-end]"), + cl::desc("Dump binary data from specified range of bytes"), + cl::sub(BytesSubcommand), cl::cat(MsfBytes)); + +cl::list<std::string> + DumpStreamData("stream-data", cl::CommaSeparated, cl::ZeroOrMore, + cl::desc("Dump binary data from specified streams. Format " + "is SN[:Start][@Size]"), + cl::sub(BytesSubcommand), cl::cat(MsfBytes)); + +cl::opt<bool> NameMap("name-map", cl::desc("Dump bytes of PDB Name Map"), + cl::sub(BytesSubcommand), cl::cat(PdbBytes)); +cl::opt<bool> Fpm("fpm", cl::desc("Dump free page map"), + cl::sub(BytesSubcommand), cl::cat(MsfBytes)); + +cl::opt<bool> SectionContributions("sc", cl::desc("Dump section contributions"), + cl::sub(BytesSubcommand), cl::cat(DbiBytes)); +cl::opt<bool> SectionMap("sm", cl::desc("Dump section map"), + cl::sub(BytesSubcommand), cl::cat(DbiBytes)); +cl::opt<bool> ModuleInfos("modi", cl::desc("Dump module info"), + cl::sub(BytesSubcommand), cl::cat(DbiBytes)); +cl::opt<bool> FileInfo("files", cl::desc("Dump source file info"), + cl::sub(BytesSubcommand), cl::cat(DbiBytes)); +cl::opt<bool> TypeServerMap("type-server", cl::desc("Dump type server map"), + cl::sub(BytesSubcommand), cl::cat(DbiBytes)); +cl::opt<bool> ECData("ec", cl::desc("Dump edit and continue map"), + cl::sub(BytesSubcommand), cl::cat(DbiBytes)); + +cl::list<uint32_t> + TypeIndex("type", + cl::desc("Dump the type record with the given type index"), + cl::ZeroOrMore, cl::CommaSeparated, cl::sub(BytesSubcommand), + cl::cat(TypeCategory)); +cl::list<uint32_t> + IdIndex("id", cl::desc("Dump the id record with the given type index"), + cl::ZeroOrMore, cl::CommaSeparated, cl::sub(BytesSubcommand), + cl::cat(TypeCategory)); + +cl::opt<uint32_t> ModuleIndex( + "mod", + cl::desc( + "Limit options in the Modules category to the specified module index"), + cl::Optional, cl::sub(BytesSubcommand), cl::cat(ModuleCategory)); +cl::opt<bool> ModuleSyms("syms", cl::desc("Dump symbol record substream"), + cl::sub(BytesSubcommand), cl::cat(ModuleCategory)); +cl::opt<bool> ModuleC11("c11-chunks", cl::Hidden, + cl::desc("Dump C11 CodeView debug chunks"), + cl::sub(BytesSubcommand), cl::cat(ModuleCategory)); +cl::opt<bool> ModuleC13("chunks", + cl::desc("Dump C13 CodeView debug chunk subsection"), + cl::sub(BytesSubcommand), cl::cat(ModuleCategory)); +cl::opt<bool> SplitChunks( + "split-chunks", + cl::desc( + "When dumping debug chunks, show a different section for each chunk"), + cl::sub(BytesSubcommand), cl::cat(ModuleCategory)); +cl::list<std::string> InputFilenames(cl::Positional, + cl::desc("<input PDB files>"), + cl::OneOrMore, cl::sub(BytesSubcommand)); + +} // namespace bytes + +namespace dump { + +cl::OptionCategory MsfOptions("MSF Container Options"); +cl::OptionCategory TypeOptions("Type Record Options"); +cl::OptionCategory SymbolOptions("Symbol Options"); +cl::OptionCategory MiscOptions("Miscellaneous Options"); + +// MSF OPTIONS +cl::opt<bool> DumpSummary("summary", cl::desc("dump file summary"), + cl::cat(MsfOptions), cl::sub(DumpSubcommand)); +cl::opt<bool> DumpStreams("streams", + cl::desc("dump summary of the PDB streams"), + cl::cat(MsfOptions), cl::sub(DumpSubcommand)); +cl::opt<bool> DumpStreamBlocks( + "stream-blocks", + cl::desc("Add block information to the output of -streams"), + cl::cat(MsfOptions), cl::sub(DumpSubcommand)); +cl::opt<bool> DumpSymbolStats( + "sym-stats", + cl::desc("Dump a detailed breakdown of symbol usage/size for each module"), + cl::cat(MsfOptions), cl::sub(DumpSubcommand)); +cl::opt<bool> DumpTypeStats( + "type-stats", + cl::desc("Dump a detailed breakdown of type usage/size"), + cl::cat(MsfOptions), cl::sub(DumpSubcommand)); +cl::opt<bool> DumpIDStats( + "id-stats", + cl::desc("Dump a detailed breakdown of IPI types usage/size"), + cl::cat(MsfOptions), cl::sub(DumpSubcommand)); +cl::opt<bool> DumpUdtStats( + "udt-stats", + cl::desc("Dump a detailed breakdown of S_UDT record usage / stats"), + cl::cat(MsfOptions), cl::sub(DumpSubcommand)); + +// TYPE OPTIONS +cl::opt<bool> DumpTypes("types", + cl::desc("dump CodeView type records from TPI stream"), + cl::cat(TypeOptions), cl::sub(DumpSubcommand)); +cl::opt<bool> DumpTypeData( + "type-data", + cl::desc("dump CodeView type record raw bytes from TPI stream"), + cl::cat(TypeOptions), cl::sub(DumpSubcommand)); +cl::opt<bool> + DumpTypeRefStats("type-ref-stats", + cl::desc("dump statistics on the number and size of types " + "transitively referenced by symbol records"), + cl::cat(TypeOptions), cl::sub(DumpSubcommand)); + +cl::opt<bool> DumpTypeExtras("type-extras", + cl::desc("dump type hashes and index offsets"), + cl::cat(TypeOptions), cl::sub(DumpSubcommand)); + +cl::opt<bool> DontResolveForwardRefs( + "dont-resolve-forward-refs", + cl::desc("When dumping type records for classes, unions, enums, and " + "structs, don't try to resolve forward references"), + cl::cat(TypeOptions), cl::sub(DumpSubcommand)); + +cl::list<uint32_t> DumpTypeIndex( + "type-index", cl::ZeroOrMore, cl::CommaSeparated, + cl::desc("only dump types with the specified hexadecimal type index"), + cl::cat(TypeOptions), cl::sub(DumpSubcommand)); + +cl::opt<bool> DumpIds("ids", + cl::desc("dump CodeView type records from IPI stream"), + cl::cat(TypeOptions), cl::sub(DumpSubcommand)); +cl::opt<bool> + DumpIdData("id-data", + cl::desc("dump CodeView type record raw bytes from IPI stream"), + cl::cat(TypeOptions), cl::sub(DumpSubcommand)); + +cl::opt<bool> DumpIdExtras("id-extras", + cl::desc("dump id hashes and index offsets"), + cl::cat(TypeOptions), cl::sub(DumpSubcommand)); +cl::list<uint32_t> DumpIdIndex( + "id-index", cl::ZeroOrMore, cl::CommaSeparated, + cl::desc("only dump ids with the specified hexadecimal type index"), + cl::cat(TypeOptions), cl::sub(DumpSubcommand)); + +cl::opt<bool> DumpTypeDependents( + "dependents", + cl::desc("In conjunection with -type-index and -id-index, dumps the entire " + "dependency graph for the specified index instead of " + "just the single record with the specified index"), + cl::cat(TypeOptions), cl::sub(DumpSubcommand)); + +// SYMBOL OPTIONS +cl::opt<bool> DumpGlobals("globals", cl::desc("dump Globals symbol records"), + cl::cat(SymbolOptions), cl::sub(DumpSubcommand)); +cl::opt<bool> DumpGlobalExtras("global-extras", cl::desc("dump Globals hashes"), + cl::cat(SymbolOptions), cl::sub(DumpSubcommand)); +cl::list<std::string> DumpGlobalNames( + "global-name", + cl::desc( + "With -globals, only dump globals whose name matches the given value"), + cl::cat(SymbolOptions), cl::sub(DumpSubcommand), cl::ZeroOrMore); +cl::opt<bool> DumpPublics("publics", cl::desc("dump Publics stream data"), + cl::cat(SymbolOptions), cl::sub(DumpSubcommand)); +cl::opt<bool> DumpPublicExtras("public-extras", + cl::desc("dump Publics hashes and address maps"), + cl::cat(SymbolOptions), cl::sub(DumpSubcommand)); +cl::opt<bool> + DumpGSIRecords("gsi-records", + cl::desc("dump public / global common record stream"), + cl::cat(SymbolOptions), cl::sub(DumpSubcommand)); +cl::opt<bool> DumpSymbols("symbols", cl::desc("dump module symbols"), + cl::cat(SymbolOptions), cl::sub(DumpSubcommand)); + +cl::opt<bool> + DumpSymRecordBytes("sym-data", + cl::desc("dump CodeView symbol record raw bytes"), + cl::cat(SymbolOptions), cl::sub(DumpSubcommand)); + +cl::opt<bool> DumpFpo("fpo", cl::desc("dump FPO records"), + cl::cat(SymbolOptions), cl::sub(DumpSubcommand)); + +// MODULE & FILE OPTIONS +cl::opt<bool> DumpModules("modules", cl::desc("dump compiland information"), + cl::cat(FileOptions), cl::sub(DumpSubcommand)); +cl::opt<bool> DumpModuleFiles( + "files", + cl::desc("Dump the source files that contribute to each module's."), + cl::cat(FileOptions), cl::sub(DumpSubcommand)); +cl::opt<bool> DumpLines( + "l", + cl::desc("dump source file/line information (DEBUG_S_LINES subsection)"), + cl::cat(FileOptions), cl::sub(DumpSubcommand)); +cl::opt<bool> DumpInlineeLines( + "il", + cl::desc("dump inlinee line information (DEBUG_S_INLINEELINES subsection)"), + cl::cat(FileOptions), cl::sub(DumpSubcommand)); +cl::opt<bool> DumpXmi( + "xmi", + cl::desc( + "dump cross module imports (DEBUG_S_CROSSSCOPEIMPORTS subsection)"), + cl::cat(FileOptions), cl::sub(DumpSubcommand)); +cl::opt<bool> DumpXme( + "xme", + cl::desc( + "dump cross module exports (DEBUG_S_CROSSSCOPEEXPORTS subsection)"), + cl::cat(FileOptions), cl::sub(DumpSubcommand)); +cl::opt<uint32_t> DumpModi("modi", cl::Optional, + cl::desc("For all options that iterate over " + "modules, limit to the specified module"), + cl::cat(FileOptions), cl::sub(DumpSubcommand)); +cl::opt<bool> JustMyCode("jmc", cl::Optional, + cl::desc("For all options that iterate over modules, " + "ignore modules from system libraries"), + cl::cat(FileOptions), cl::sub(DumpSubcommand)); + +// MISCELLANEOUS OPTIONS +cl::opt<bool> DumpNamedStreams("named-streams", + cl::desc("dump PDB named stream table"), + cl::cat(MiscOptions), cl::sub(DumpSubcommand)); + +cl::opt<bool> DumpStringTable("string-table", cl::desc("dump PDB String Table"), + cl::cat(MiscOptions), cl::sub(DumpSubcommand)); +cl::opt<bool> DumpStringTableDetails("string-table-details", + cl::desc("dump PDB String Table Details"), + cl::cat(MiscOptions), + cl::sub(DumpSubcommand)); + +cl::opt<bool> DumpSectionContribs("section-contribs", + cl::desc("dump section contributions"), + cl::cat(MiscOptions), + cl::sub(DumpSubcommand)); +cl::opt<bool> DumpSectionMap("section-map", cl::desc("dump section map"), + cl::cat(MiscOptions), cl::sub(DumpSubcommand)); +cl::opt<bool> DumpSectionHeaders("section-headers", + cl::desc("Dump image section headers"), + cl::cat(MiscOptions), cl::sub(DumpSubcommand)); + +cl::opt<bool> RawAll("all", cl::desc("Implies most other options."), + cl::cat(MiscOptions), cl::sub(DumpSubcommand)); + +cl::list<std::string> InputFilenames(cl::Positional, + cl::desc("<input PDB files>"), + cl::OneOrMore, cl::sub(DumpSubcommand)); +} + +namespace yaml2pdb { +cl::opt<std::string> + YamlPdbOutputFile("pdb", cl::desc("the name of the PDB file to write"), + cl::sub(YamlToPdbSubcommand)); + +cl::opt<std::string> InputFilename(cl::Positional, + cl::desc("<input YAML file>"), cl::Required, + cl::sub(YamlToPdbSubcommand)); +} + +namespace pdb2yaml { +cl::opt<bool> All("all", + cl::desc("Dump everything we know how to dump."), + cl::sub(PdbToYamlSubcommand), cl::init(false)); +cl::opt<bool> NoFileHeaders("no-file-headers", + cl::desc("Do not dump MSF file headers"), + cl::sub(PdbToYamlSubcommand), cl::init(false)); +cl::opt<bool> Minimal("minimal", + cl::desc("Don't write fields with default values"), + cl::sub(PdbToYamlSubcommand), cl::init(false)); + +cl::opt<bool> StreamMetadata( + "stream-metadata", + cl::desc("Dump the number of streams and each stream's size"), + cl::sub(PdbToYamlSubcommand), cl::init(false)); +cl::opt<bool> StreamDirectory( + "stream-directory", + cl::desc("Dump each stream's block map (implies -stream-metadata)"), + cl::sub(PdbToYamlSubcommand), cl::init(false)); +cl::opt<bool> PdbStream("pdb-stream", + cl::desc("Dump the PDB Stream (Stream 1)"), + cl::sub(PdbToYamlSubcommand), cl::init(false)); + +cl::opt<bool> StringTable("string-table", cl::desc("Dump the PDB String Table"), + cl::sub(PdbToYamlSubcommand), cl::init(false)); + +cl::opt<bool> DbiStream("dbi-stream", + cl::desc("Dump the DBI Stream Headers (Stream 2)"), + cl::sub(PdbToYamlSubcommand), cl::init(false)); + +cl::opt<bool> TpiStream("tpi-stream", + cl::desc("Dump the TPI Stream (Stream 3)"), + cl::sub(PdbToYamlSubcommand), cl::init(false)); + +cl::opt<bool> IpiStream("ipi-stream", + cl::desc("Dump the IPI Stream (Stream 5)"), + cl::sub(PdbToYamlSubcommand), cl::init(false)); + +cl::opt<bool> PublicsStream("publics-stream", + cl::desc("Dump the Publics Stream"), + cl::sub(PdbToYamlSubcommand), cl::init(false)); + +// MODULE & FILE OPTIONS +cl::opt<bool> DumpModules("modules", cl::desc("dump compiland information"), + cl::cat(FileOptions), cl::sub(PdbToYamlSubcommand)); +cl::opt<bool> DumpModuleFiles("module-files", cl::desc("dump file information"), + cl::cat(FileOptions), + cl::sub(PdbToYamlSubcommand)); +cl::list<ModuleSubsection> DumpModuleSubsections( + "subsections", cl::ZeroOrMore, cl::CommaSeparated, + cl::desc("dump subsections from each module's debug stream"), ChunkValues, + cl::cat(FileOptions), cl::sub(PdbToYamlSubcommand)); +cl::opt<bool> DumpModuleSyms("module-syms", cl::desc("dump module symbols"), + cl::cat(FileOptions), + cl::sub(PdbToYamlSubcommand)); + +cl::list<std::string> InputFilename(cl::Positional, + cl::desc("<input PDB file>"), cl::Required, + cl::sub(PdbToYamlSubcommand)); +} // namespace pdb2yaml + +namespace merge { +cl::list<std::string> InputFilenames(cl::Positional, + cl::desc("<input PDB files>"), + cl::OneOrMore, cl::sub(MergeSubcommand)); +cl::opt<std::string> + PdbOutputFile("pdb", cl::desc("the name of the PDB file to write"), + cl::sub(MergeSubcommand)); +} + +namespace explain { +cl::list<std::string> InputFilename(cl::Positional, + cl::desc("<input PDB file>"), cl::Required, + cl::sub(ExplainSubcommand)); + +cl::list<uint64_t> Offsets("offset", cl::desc("The file offset to explain"), + cl::sub(ExplainSubcommand), cl::OneOrMore); + +cl::opt<InputFileType> InputType( + "input-type", cl::desc("Specify how to interpret the input file"), + cl::init(InputFileType::PDBFile), cl::Optional, cl::sub(ExplainSubcommand), + cl::values(clEnumValN(InputFileType::PDBFile, "pdb-file", + "Treat input as a PDB file (default)"), + clEnumValN(InputFileType::PDBStream, "pdb-stream", + "Treat input as raw contents of PDB stream"), + clEnumValN(InputFileType::DBIStream, "dbi-stream", + "Treat input as raw contents of DBI stream"), + clEnumValN(InputFileType::Names, "names-stream", + "Treat input as raw contents of /names named stream"), + clEnumValN(InputFileType::ModuleStream, "mod-stream", + "Treat input as raw contents of a module stream"))); +} // namespace explain + +namespace exportstream { +cl::list<std::string> InputFilename(cl::Positional, + cl::desc("<input PDB file>"), cl::Required, + cl::sub(ExportSubcommand)); +cl::opt<std::string> OutputFile("out", + cl::desc("The file to write the stream to"), + cl::Required, cl::sub(ExportSubcommand)); +cl::opt<std::string> + Stream("stream", cl::Required, + cl::desc("The index or name of the stream whose contents to export"), + cl::sub(ExportSubcommand)); +cl::opt<bool> ForceName("name", + cl::desc("Force the interpretation of -stream as a " + "string, even if it is a valid integer"), + cl::sub(ExportSubcommand), cl::Optional, + cl::init(false)); +} // namespace exportstream +} + +static ExitOnError ExitOnErr; + +static void yamlToPdb(StringRef Path) { + BumpPtrAllocator Allocator; + ErrorOr<std::unique_ptr<MemoryBuffer>> ErrorOrBuffer = + MemoryBuffer::getFileOrSTDIN(Path, /*FileSize=*/-1, + /*RequiresNullTerminator=*/false); + + if (ErrorOrBuffer.getError()) { + ExitOnErr(createFileError(Path, errorCodeToError(ErrorOrBuffer.getError()))); + } + + std::unique_ptr<MemoryBuffer> &Buffer = ErrorOrBuffer.get(); + + llvm::yaml::Input In(Buffer->getBuffer()); + pdb::yaml::PdbObject YamlObj(Allocator); + In >> YamlObj; + + PDBFileBuilder Builder(Allocator); + + uint32_t BlockSize = 4096; + if (YamlObj.Headers.hasValue()) + BlockSize = YamlObj.Headers->SuperBlock.BlockSize; + ExitOnErr(Builder.initialize(BlockSize)); + // Add each of the reserved streams. We ignore stream metadata in the + // yaml, because we will reconstruct our own view of the streams. For + // example, the YAML may say that there were 20 streams in the original + // PDB, but maybe we only dump a subset of those 20 streams, so we will + // have fewer, and the ones we do have may end up with different indices + // than the ones in the original PDB. So we just start with a clean slate. + for (uint32_t I = 0; I < kSpecialStreamCount; ++I) + ExitOnErr(Builder.getMsfBuilder().addStream(0)); + + StringsAndChecksums Strings; + Strings.setStrings(std::make_shared<DebugStringTableSubsection>()); + + if (YamlObj.StringTable.hasValue()) { + for (auto S : *YamlObj.StringTable) + Strings.strings()->insert(S); + } + + pdb::yaml::PdbInfoStream DefaultInfoStream; + pdb::yaml::PdbDbiStream DefaultDbiStream; + pdb::yaml::PdbTpiStream DefaultTpiStream; + pdb::yaml::PdbTpiStream DefaultIpiStream; + + const auto &Info = YamlObj.PdbStream.getValueOr(DefaultInfoStream); + + auto &InfoBuilder = Builder.getInfoBuilder(); + InfoBuilder.setAge(Info.Age); + InfoBuilder.setGuid(Info.Guid); + InfoBuilder.setSignature(Info.Signature); + InfoBuilder.setVersion(Info.Version); + for (auto F : Info.Features) + InfoBuilder.addFeature(F); + + const auto &Dbi = YamlObj.DbiStream.getValueOr(DefaultDbiStream); + auto &DbiBuilder = Builder.getDbiBuilder(); + DbiBuilder.setAge(Dbi.Age); + DbiBuilder.setBuildNumber(Dbi.BuildNumber); + DbiBuilder.setFlags(Dbi.Flags); + DbiBuilder.setMachineType(Dbi.MachineType); + DbiBuilder.setPdbDllRbld(Dbi.PdbDllRbld); + DbiBuilder.setPdbDllVersion(Dbi.PdbDllVersion); + DbiBuilder.setVersionHeader(Dbi.VerHeader); + for (const auto &MI : Dbi.ModInfos) { + auto &ModiBuilder = ExitOnErr(DbiBuilder.addModuleInfo(MI.Mod)); + ModiBuilder.setObjFileName(MI.Obj); + + for (auto S : MI.SourceFiles) + ExitOnErr(DbiBuilder.addModuleSourceFile(ModiBuilder, S)); + if (MI.Modi.hasValue()) { + const auto &ModiStream = *MI.Modi; + for (auto Symbol : ModiStream.Symbols) { + ModiBuilder.addSymbol( + Symbol.toCodeViewSymbol(Allocator, CodeViewContainer::Pdb)); + } + } + + // Each module has its own checksum subsection, so scan for it every time. + Strings.setChecksums(nullptr); + CodeViewYAML::initializeStringsAndChecksums(MI.Subsections, Strings); + + auto CodeViewSubsections = ExitOnErr(CodeViewYAML::toCodeViewSubsectionList( + Allocator, MI.Subsections, Strings)); + for (auto &SS : CodeViewSubsections) { + ModiBuilder.addDebugSubsection(SS); + } + } + + auto &TpiBuilder = Builder.getTpiBuilder(); + const auto &Tpi = YamlObj.TpiStream.getValueOr(DefaultTpiStream); + TpiBuilder.setVersionHeader(Tpi.Version); + AppendingTypeTableBuilder TS(Allocator); + for (const auto &R : Tpi.Records) { + CVType Type = R.toCodeViewRecord(TS); + TpiBuilder.addTypeRecord(Type.RecordData, None); + } + + const auto &Ipi = YamlObj.IpiStream.getValueOr(DefaultIpiStream); + auto &IpiBuilder = Builder.getIpiBuilder(); + IpiBuilder.setVersionHeader(Ipi.Version); + for (const auto &R : Ipi.Records) { + CVType Type = R.toCodeViewRecord(TS); + IpiBuilder.addTypeRecord(Type.RecordData, None); + } + + Builder.getStringTableBuilder().setStrings(*Strings.strings()); + + codeview::GUID IgnoredOutGuid; + ExitOnErr(Builder.commit(opts::yaml2pdb::YamlPdbOutputFile, &IgnoredOutGuid)); +} + +static PDBFile &loadPDB(StringRef Path, std::unique_ptr<IPDBSession> &Session) { + ExitOnErr(loadDataForPDB(PDB_ReaderType::Native, Path, Session)); + + NativeSession *NS = static_cast<NativeSession *>(Session.get()); + return NS->getPDBFile(); +} + +static void pdb2Yaml(StringRef Path) { + std::unique_ptr<IPDBSession> Session; + auto &File = loadPDB(Path, Session); + + auto O = std::make_unique<YAMLOutputStyle>(File); + O = std::make_unique<YAMLOutputStyle>(File); + + ExitOnErr(O->dump()); +} + +static void dumpRaw(StringRef Path) { + InputFile IF = ExitOnErr(InputFile::open(Path)); + + auto O = std::make_unique<DumpOutputStyle>(IF); + ExitOnErr(O->dump()); +} + +static void dumpBytes(StringRef Path) { + std::unique_ptr<IPDBSession> Session; + auto &File = loadPDB(Path, Session); + + auto O = std::make_unique<BytesOutputStyle>(File); + + ExitOnErr(O->dump()); +} + +bool opts::pretty::shouldDumpSymLevel(SymLevel Search) { + if (SymTypes.empty()) + return true; + if (llvm::is_contained(SymTypes, Search)) + return true; + if (llvm::is_contained(SymTypes, SymLevel::All)) + return true; + return false; +} + +uint32_t llvm::pdb::getTypeLength(const PDBSymbolData &Symbol) { + auto SymbolType = Symbol.getType(); + const IPDBRawSymbol &RawType = SymbolType->getRawSymbol(); + + return RawType.getLength(); +} + +bool opts::pretty::compareFunctionSymbols( + const std::unique_ptr<PDBSymbolFunc> &F1, + const std::unique_ptr<PDBSymbolFunc> &F2) { + assert(opts::pretty::SymbolOrder != opts::pretty::SymbolSortMode::None); + + if (opts::pretty::SymbolOrder == opts::pretty::SymbolSortMode::Name) + return F1->getName() < F2->getName(); + + // Note that we intentionally sort in descending order on length, since + // long functions are more interesting than short functions. + return F1->getLength() > F2->getLength(); +} + +bool opts::pretty::compareDataSymbols( + const std::unique_ptr<PDBSymbolData> &F1, + const std::unique_ptr<PDBSymbolData> &F2) { + assert(opts::pretty::SymbolOrder != opts::pretty::SymbolSortMode::None); + + if (opts::pretty::SymbolOrder == opts::pretty::SymbolSortMode::Name) + return F1->getName() < F2->getName(); + + // Note that we intentionally sort in descending order on length, since + // large types are more interesting than short ones. + return getTypeLength(*F1) > getTypeLength(*F2); +} + +static std::string stringOr(std::string Str, std::string IfEmpty) { + return (Str.empty()) ? IfEmpty : Str; +} + +static void dumpInjectedSources(LinePrinter &Printer, IPDBSession &Session) { + auto Sources = Session.getInjectedSources(); + if (!Sources || !Sources->getChildCount()) { + Printer.printLine("There are no injected sources."); + return; + } + + while (auto IS = Sources->getNext()) { + Printer.NewLine(); + std::string File = stringOr(IS->getFileName(), "<null>"); + uint64_t Size = IS->getCodeByteSize(); + std::string Obj = stringOr(IS->getObjectFileName(), "<null>"); + std::string VFName = stringOr(IS->getVirtualFileName(), "<null>"); + uint32_t CRC = IS->getCrc32(); + + WithColor(Printer, PDB_ColorItem::Path).get() << File; + Printer << " ("; + WithColor(Printer, PDB_ColorItem::LiteralValue).get() << Size; + Printer << " bytes): "; + WithColor(Printer, PDB_ColorItem::Keyword).get() << "obj"; + Printer << "="; + WithColor(Printer, PDB_ColorItem::Path).get() << Obj; + Printer << ", "; + WithColor(Printer, PDB_ColorItem::Keyword).get() << "vname"; + Printer << "="; + WithColor(Printer, PDB_ColorItem::Path).get() << VFName; + Printer << ", "; + WithColor(Printer, PDB_ColorItem::Keyword).get() << "crc"; + Printer << "="; + WithColor(Printer, PDB_ColorItem::LiteralValue).get() << CRC; + Printer << ", "; + WithColor(Printer, PDB_ColorItem::Keyword).get() << "compression"; + Printer << "="; + dumpPDBSourceCompression( + WithColor(Printer, PDB_ColorItem::LiteralValue).get(), + IS->getCompression()); + + if (!opts::pretty::ShowInjectedSourceContent) + continue; + + // Set the indent level to 0 when printing file content. + int Indent = Printer.getIndentLevel(); + Printer.Unindent(Indent); + + if (IS->getCompression() == PDB_SourceCompression::None) + Printer.printLine(IS->getCode()); + else + Printer.formatBinary("Compressed data", + arrayRefFromStringRef(IS->getCode()), + /*StartOffset=*/0); + + // Re-indent back to the original level. + Printer.Indent(Indent); + } +} + +template <typename OuterT, typename ChildT> +void diaDumpChildren(PDBSymbol &Outer, PdbSymbolIdField Ids, + PdbSymbolIdField Recurse) { + OuterT *ConcreteOuter = dyn_cast<OuterT>(&Outer); + if (!ConcreteOuter) + return; + + auto Children = ConcreteOuter->template findAllChildren<ChildT>(); + while (auto Child = Children->getNext()) { + outs() << " {"; + Child->defaultDump(outs(), 4, Ids, Recurse); + outs() << "\n }\n"; + } +} + +static void dumpDia(StringRef Path) { + std::unique_ptr<IPDBSession> Session; + + const auto ReaderType = + opts::diadump::Native ? PDB_ReaderType::Native : PDB_ReaderType::DIA; + ExitOnErr(loadDataForPDB(ReaderType, Path, Session)); + + auto GlobalScope = Session->getGlobalScope(); + + std::vector<PDB_SymType> SymTypes; + + if (opts::diadump::Compilands) + SymTypes.push_back(PDB_SymType::Compiland); + if (opts::diadump::Enums) + SymTypes.push_back(PDB_SymType::Enum); + if (opts::diadump::Pointers) + SymTypes.push_back(PDB_SymType::PointerType); + if (opts::diadump::UDTs) + SymTypes.push_back(PDB_SymType::UDT); + if (opts::diadump::Funcsigs) + SymTypes.push_back(PDB_SymType::FunctionSig); + if (opts::diadump::Arrays) + SymTypes.push_back(PDB_SymType::ArrayType); + if (opts::diadump::VTShapes) + SymTypes.push_back(PDB_SymType::VTableShape); + if (opts::diadump::Typedefs) + SymTypes.push_back(PDB_SymType::Typedef); + PdbSymbolIdField Ids = opts::diadump::NoSymIndexIds ? PdbSymbolIdField::None + : PdbSymbolIdField::All; + + PdbSymbolIdField Recurse = PdbSymbolIdField::None; + if (opts::diadump::Recurse) + Recurse = PdbSymbolIdField::All; + if (!opts::diadump::ShowClassHierarchy) + Ids &= ~(PdbSymbolIdField::ClassParent | PdbSymbolIdField::LexicalParent); + + for (PDB_SymType ST : SymTypes) { + auto Children = GlobalScope->findAllChildren(ST); + while (auto Child = Children->getNext()) { + outs() << "{"; + Child->defaultDump(outs(), 2, Ids, Recurse); + + diaDumpChildren<PDBSymbolTypeEnum, PDBSymbolData>(*Child, Ids, Recurse); + outs() << "\n}\n"; + } + } +} + +static void dumpPretty(StringRef Path) { + std::unique_ptr<IPDBSession> Session; + + const auto ReaderType = + opts::pretty::Native ? PDB_ReaderType::Native : PDB_ReaderType::DIA; + ExitOnErr(loadDataForPDB(ReaderType, Path, Session)); + + if (opts::pretty::LoadAddress) + Session->setLoadAddress(opts::pretty::LoadAddress); + + auto &Stream = outs(); + const bool UseColor = opts::pretty::ColorOutput == cl::BOU_UNSET + ? Stream.has_colors() + : opts::pretty::ColorOutput == cl::BOU_TRUE; + LinePrinter Printer(2, UseColor, Stream); + + auto GlobalScope(Session->getGlobalScope()); + if (!GlobalScope) + return; + std::string FileName(GlobalScope->getSymbolsFileName()); + + WithColor(Printer, PDB_ColorItem::None).get() << "Summary for "; + WithColor(Printer, PDB_ColorItem::Path).get() << FileName; + Printer.Indent(); + uint64_t FileSize = 0; + + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::Identifier).get() << "Size"; + if (!sys::fs::file_size(FileName, FileSize)) { + Printer << ": " << FileSize << " bytes"; + } else { + Printer << ": (Unable to obtain file size)"; + } + + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::Identifier).get() << "Guid"; + Printer << ": " << GlobalScope->getGuid(); + + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::Identifier).get() << "Age"; + Printer << ": " << GlobalScope->getAge(); + + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::Identifier).get() << "Attributes"; + Printer << ": "; + if (GlobalScope->hasCTypes()) + outs() << "HasCTypes "; + if (GlobalScope->hasPrivateSymbols()) + outs() << "HasPrivateSymbols "; + Printer.Unindent(); + + if (!opts::pretty::WithName.empty()) { + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::SectionHeader).get() + << "---SYMBOLS & TYPES BY NAME---"; + + for (StringRef Name : opts::pretty::WithName) { + auto Symbols = GlobalScope->findChildren( + PDB_SymType::None, Name, PDB_NameSearchFlags::NS_CaseSensitive); + if (!Symbols || Symbols->getChildCount() == 0) { + Printer.formatLine("[not found] - {0}", Name); + continue; + } + Printer.formatLine("[{0} occurrences] - {1}", Symbols->getChildCount(), + Name); + + AutoIndent Indent(Printer); + Printer.NewLine(); + + while (auto Symbol = Symbols->getNext()) { + switch (Symbol->getSymTag()) { + case PDB_SymType::Typedef: { + TypedefDumper TD(Printer); + std::unique_ptr<PDBSymbolTypeTypedef> T = + llvm::unique_dyn_cast<PDBSymbolTypeTypedef>(std::move(Symbol)); + TD.start(*T); + break; + } + case PDB_SymType::Enum: { + EnumDumper ED(Printer); + std::unique_ptr<PDBSymbolTypeEnum> E = + llvm::unique_dyn_cast<PDBSymbolTypeEnum>(std::move(Symbol)); + ED.start(*E); + break; + } + case PDB_SymType::UDT: { + ClassDefinitionDumper CD(Printer); + std::unique_ptr<PDBSymbolTypeUDT> C = + llvm::unique_dyn_cast<PDBSymbolTypeUDT>(std::move(Symbol)); + CD.start(*C); + break; + } + case PDB_SymType::BaseClass: + case PDB_SymType::Friend: { + TypeDumper TD(Printer); + Symbol->dump(TD); + break; + } + case PDB_SymType::Function: { + FunctionDumper FD(Printer); + std::unique_ptr<PDBSymbolFunc> F = + llvm::unique_dyn_cast<PDBSymbolFunc>(std::move(Symbol)); + FD.start(*F, FunctionDumper::PointerType::None); + break; + } + case PDB_SymType::Data: { + VariableDumper VD(Printer); + std::unique_ptr<PDBSymbolData> D = + llvm::unique_dyn_cast<PDBSymbolData>(std::move(Symbol)); + VD.start(*D); + break; + } + case PDB_SymType::PublicSymbol: { + ExternalSymbolDumper ED(Printer); + std::unique_ptr<PDBSymbolPublicSymbol> PS = + llvm::unique_dyn_cast<PDBSymbolPublicSymbol>(std::move(Symbol)); + ED.dump(*PS); + break; + } + default: + llvm_unreachable("Unexpected symbol tag!"); + } + } + } + llvm::outs().flush(); + } + + if (opts::pretty::Compilands) { + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::SectionHeader).get() + << "---COMPILANDS---"; + auto Compilands = GlobalScope->findAllChildren<PDBSymbolCompiland>(); + + if (Compilands) { + Printer.Indent(); + CompilandDumper Dumper(Printer); + CompilandDumpFlags options = CompilandDumper::Flags::None; + if (opts::pretty::Lines) + options = options | CompilandDumper::Flags::Lines; + while (auto Compiland = Compilands->getNext()) + Dumper.start(*Compiland, options); + Printer.Unindent(); + } + } + + if (opts::pretty::Classes || opts::pretty::Enums || opts::pretty::Typedefs || + opts::pretty::Funcsigs || opts::pretty::Pointers || + opts::pretty::Arrays || opts::pretty::VTShapes) { + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---TYPES---"; + Printer.Indent(); + TypeDumper Dumper(Printer); + Dumper.start(*GlobalScope); + Printer.Unindent(); + } + + if (opts::pretty::Symbols) { + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---SYMBOLS---"; + if (auto Compilands = GlobalScope->findAllChildren<PDBSymbolCompiland>()) { + Printer.Indent(); + CompilandDumper Dumper(Printer); + while (auto Compiland = Compilands->getNext()) + Dumper.start(*Compiland, true); + Printer.Unindent(); + } + } + + if (opts::pretty::Globals) { + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---GLOBALS---"; + Printer.Indent(); + if (shouldDumpSymLevel(opts::pretty::SymLevel::Functions)) { + if (auto Functions = GlobalScope->findAllChildren<PDBSymbolFunc>()) { + FunctionDumper Dumper(Printer); + if (opts::pretty::SymbolOrder == opts::pretty::SymbolSortMode::None) { + while (auto Function = Functions->getNext()) { + Printer.NewLine(); + Dumper.start(*Function, FunctionDumper::PointerType::None); + } + } else { + std::vector<std::unique_ptr<PDBSymbolFunc>> Funcs; + while (auto Func = Functions->getNext()) + Funcs.push_back(std::move(Func)); + llvm::sort(Funcs, opts::pretty::compareFunctionSymbols); + for (const auto &Func : Funcs) { + Printer.NewLine(); + Dumper.start(*Func, FunctionDumper::PointerType::None); + } + } + } + } + if (shouldDumpSymLevel(opts::pretty::SymLevel::Data)) { + if (auto Vars = GlobalScope->findAllChildren<PDBSymbolData>()) { + VariableDumper Dumper(Printer); + if (opts::pretty::SymbolOrder == opts::pretty::SymbolSortMode::None) { + while (auto Var = Vars->getNext()) + Dumper.start(*Var); + } else { + std::vector<std::unique_ptr<PDBSymbolData>> Datas; + while (auto Var = Vars->getNext()) + Datas.push_back(std::move(Var)); + llvm::sort(Datas, opts::pretty::compareDataSymbols); + for (const auto &Var : Datas) + Dumper.start(*Var); + } + } + } + if (shouldDumpSymLevel(opts::pretty::SymLevel::Thunks)) { + if (auto Thunks = GlobalScope->findAllChildren<PDBSymbolThunk>()) { + CompilandDumper Dumper(Printer); + while (auto Thunk = Thunks->getNext()) + Dumper.dump(*Thunk); + } + } + Printer.Unindent(); + } + if (opts::pretty::Externals) { + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---EXTERNALS---"; + Printer.Indent(); + ExternalSymbolDumper Dumper(Printer); + Dumper.start(*GlobalScope); + } + if (opts::pretty::Lines) { + Printer.NewLine(); + } + if (opts::pretty::InjectedSources) { + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::SectionHeader).get() + << "---INJECTED SOURCES---"; + AutoIndent Indent1(Printer); + dumpInjectedSources(Printer, *Session); + } + + Printer.NewLine(); + outs().flush(); +} + +static void mergePdbs() { + BumpPtrAllocator Allocator; + MergingTypeTableBuilder MergedTpi(Allocator); + MergingTypeTableBuilder MergedIpi(Allocator); + + // Create a Tpi and Ipi type table with all types from all input files. + for (const auto &Path : opts::merge::InputFilenames) { + std::unique_ptr<IPDBSession> Session; + auto &File = loadPDB(Path, Session); + SmallVector<TypeIndex, 128> TypeMap; + SmallVector<TypeIndex, 128> IdMap; + if (File.hasPDBTpiStream()) { + auto &Tpi = ExitOnErr(File.getPDBTpiStream()); + ExitOnErr( + codeview::mergeTypeRecords(MergedTpi, TypeMap, Tpi.typeArray())); + } + if (File.hasPDBIpiStream()) { + auto &Ipi = ExitOnErr(File.getPDBIpiStream()); + ExitOnErr(codeview::mergeIdRecords(MergedIpi, TypeMap, IdMap, + Ipi.typeArray())); + } + } + + // Then write the PDB. + PDBFileBuilder Builder(Allocator); + ExitOnErr(Builder.initialize(4096)); + // Add each of the reserved streams. We might not put any data in them, + // but at least they have to be present. + for (uint32_t I = 0; I < kSpecialStreamCount; ++I) + ExitOnErr(Builder.getMsfBuilder().addStream(0)); + + auto &DestTpi = Builder.getTpiBuilder(); + auto &DestIpi = Builder.getIpiBuilder(); + MergedTpi.ForEachRecord([&DestTpi](TypeIndex TI, const CVType &Type) { + DestTpi.addTypeRecord(Type.RecordData, None); + }); + MergedIpi.ForEachRecord([&DestIpi](TypeIndex TI, const CVType &Type) { + DestIpi.addTypeRecord(Type.RecordData, None); + }); + Builder.getInfoBuilder().addFeature(PdbRaw_FeatureSig::VC140); + + SmallString<64> OutFile(opts::merge::PdbOutputFile); + if (OutFile.empty()) { + OutFile = opts::merge::InputFilenames[0]; + llvm::sys::path::replace_extension(OutFile, "merged.pdb"); + } + + codeview::GUID IgnoredOutGuid; + ExitOnErr(Builder.commit(OutFile, &IgnoredOutGuid)); +} + +static void explain() { + std::unique_ptr<IPDBSession> Session; + InputFile IF = + ExitOnErr(InputFile::open(opts::explain::InputFilename.front(), true)); + + for (uint64_t Off : opts::explain::Offsets) { + auto O = std::make_unique<ExplainOutputStyle>(IF, Off); + + ExitOnErr(O->dump()); + } +} + +static void exportStream() { + std::unique_ptr<IPDBSession> Session; + PDBFile &File = loadPDB(opts::exportstream::InputFilename.front(), Session); + + std::unique_ptr<MappedBlockStream> SourceStream; + uint32_t Index = 0; + bool Success = false; + std::string OutFileName = opts::exportstream::OutputFile; + + if (!opts::exportstream::ForceName) { + // First try to parse it as an integer, if it fails fall back to treating it + // as a named stream. + if (to_integer(opts::exportstream::Stream, Index)) { + if (Index >= File.getNumStreams()) { + errs() << "Error: " << Index << " is not a valid stream index.\n"; + exit(1); + } + Success = true; + outs() << "Dumping contents of stream index " << Index << " to file " + << OutFileName << ".\n"; + } + } + + if (!Success) { + InfoStream &IS = cantFail(File.getPDBInfoStream()); + Index = ExitOnErr(IS.getNamedStreamIndex(opts::exportstream::Stream)); + outs() << "Dumping contents of stream '" << opts::exportstream::Stream + << "' (index " << Index << ") to file " << OutFileName << ".\n"; + } + + SourceStream = File.createIndexedStream(Index); + auto OutFile = ExitOnErr( + FileOutputBuffer::create(OutFileName, SourceStream->getLength())); + FileBufferByteStream DestStream(std::move(OutFile), llvm::support::little); + BinaryStreamWriter Writer(DestStream); + ExitOnErr(Writer.writeStreamRef(*SourceStream)); + ExitOnErr(DestStream.commit()); +} + +static bool parseRange(StringRef Str, + Optional<opts::bytes::NumberRange> &Parsed) { + if (Str.empty()) + return true; + + llvm::Regex R("^([^-]+)(-([^-]+))?$"); + llvm::SmallVector<llvm::StringRef, 2> Matches; + if (!R.match(Str, &Matches)) + return false; + + Parsed.emplace(); + if (!to_integer(Matches[1], Parsed->Min)) + return false; + + if (!Matches[3].empty()) { + Parsed->Max.emplace(); + if (!to_integer(Matches[3], *Parsed->Max)) + return false; + } + return true; +} + +static void simplifyChunkList(llvm::cl::list<opts::ModuleSubsection> &Chunks) { + // If this list contains "All" plus some other stuff, remove the other stuff + // and just keep "All" in the list. + if (!llvm::is_contained(Chunks, opts::ModuleSubsection::All)) + return; + Chunks.reset(); + Chunks.push_back(opts::ModuleSubsection::All); +} + +int main(int Argc, const char **Argv) { + InitLLVM X(Argc, Argv); + ExitOnErr.setBanner("llvm-pdbutil: "); + + cl::ParseCommandLineOptions(Argc, Argv, "LLVM PDB Dumper\n"); + + if (opts::BytesSubcommand) { + if (!parseRange(opts::bytes::DumpBlockRangeOpt, + opts::bytes::DumpBlockRange)) { + errs() << "Argument '" << opts::bytes::DumpBlockRangeOpt + << "' invalid format.\n"; + errs().flush(); + exit(1); + } + if (!parseRange(opts::bytes::DumpByteRangeOpt, + opts::bytes::DumpByteRange)) { + errs() << "Argument '" << opts::bytes::DumpByteRangeOpt + << "' invalid format.\n"; + errs().flush(); + exit(1); + } + } + + if (opts::DumpSubcommand) { + if (opts::dump::RawAll) { + opts::dump::DumpGlobals = true; + opts::dump::DumpFpo = true; + opts::dump::DumpInlineeLines = true; + opts::dump::DumpIds = true; + opts::dump::DumpIdExtras = true; + opts::dump::DumpLines = true; + opts::dump::DumpModules = true; + opts::dump::DumpModuleFiles = true; + opts::dump::DumpPublics = true; + opts::dump::DumpSectionContribs = true; + opts::dump::DumpSectionHeaders = true; + opts::dump::DumpSectionMap = true; + opts::dump::DumpStreams = true; + opts::dump::DumpStreamBlocks = true; + opts::dump::DumpStringTable = true; + opts::dump::DumpStringTableDetails = true; + opts::dump::DumpSummary = true; + opts::dump::DumpSymbols = true; + opts::dump::DumpSymbolStats = true; + opts::dump::DumpTypes = true; + opts::dump::DumpTypeExtras = true; + opts::dump::DumpUdtStats = true; + opts::dump::DumpXme = true; + opts::dump::DumpXmi = true; + } + } + if (opts::PdbToYamlSubcommand) { + if (opts::pdb2yaml::All) { + opts::pdb2yaml::StreamMetadata = true; + opts::pdb2yaml::StreamDirectory = true; + opts::pdb2yaml::PdbStream = true; + opts::pdb2yaml::StringTable = true; + opts::pdb2yaml::DbiStream = true; + opts::pdb2yaml::TpiStream = true; + opts::pdb2yaml::IpiStream = true; + opts::pdb2yaml::PublicsStream = true; + opts::pdb2yaml::DumpModules = true; + opts::pdb2yaml::DumpModuleFiles = true; + opts::pdb2yaml::DumpModuleSyms = true; + opts::pdb2yaml::DumpModuleSubsections.push_back( + opts::ModuleSubsection::All); + } + simplifyChunkList(opts::pdb2yaml::DumpModuleSubsections); + + if (opts::pdb2yaml::DumpModuleSyms || opts::pdb2yaml::DumpModuleFiles) + opts::pdb2yaml::DumpModules = true; + + if (opts::pdb2yaml::DumpModules) + opts::pdb2yaml::DbiStream = true; + } + + llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::MultiThreaded); + + if (opts::PdbToYamlSubcommand) { + pdb2Yaml(opts::pdb2yaml::InputFilename.front()); + } else if (opts::YamlToPdbSubcommand) { + if (opts::yaml2pdb::YamlPdbOutputFile.empty()) { + SmallString<16> OutputFilename(opts::yaml2pdb::InputFilename.getValue()); + sys::path::replace_extension(OutputFilename, ".pdb"); + opts::yaml2pdb::YamlPdbOutputFile = std::string(OutputFilename.str()); + } + yamlToPdb(opts::yaml2pdb::InputFilename); + } else if (opts::DiaDumpSubcommand) { + llvm::for_each(opts::diadump::InputFilenames, dumpDia); + } else if (opts::PrettySubcommand) { + if (opts::pretty::Lines) + opts::pretty::Compilands = true; + + if (opts::pretty::All) { + opts::pretty::Compilands = true; + opts::pretty::Symbols = true; + opts::pretty::Globals = true; + opts::pretty::Types = true; + opts::pretty::Externals = true; + opts::pretty::Lines = true; + } + + if (opts::pretty::Types) { + opts::pretty::Classes = true; + opts::pretty::Typedefs = true; + opts::pretty::Enums = true; + opts::pretty::Pointers = true; + opts::pretty::Funcsigs = true; + } + + // When adding filters for excluded compilands and types, we need to + // remember that these are regexes. So special characters such as * and \ + // need to be escaped in the regex. In the case of a literal \, this means + // it needs to be escaped again in the C++. So matching a single \ in the + // input requires 4 \es in the C++. + if (opts::pretty::ExcludeCompilerGenerated) { + opts::pretty::ExcludeTypes.push_back("__vc_attributes"); + opts::pretty::ExcludeCompilands.push_back("\\* Linker \\*"); + } + if (opts::pretty::ExcludeSystemLibraries) { + opts::pretty::ExcludeCompilands.push_back( + "f:\\\\binaries\\\\Intermediate\\\\vctools\\\\crt_bld"); + opts::pretty::ExcludeCompilands.push_back("f:\\\\dd\\\\vctools\\\\crt"); + opts::pretty::ExcludeCompilands.push_back( + "d:\\\\th.obj.x86fre\\\\minkernel"); + } + llvm::for_each(opts::pretty::InputFilenames, dumpPretty); + } else if (opts::DumpSubcommand) { + llvm::for_each(opts::dump::InputFilenames, dumpRaw); + } else if (opts::BytesSubcommand) { + llvm::for_each(opts::bytes::InputFilenames, dumpBytes); + } else if (opts::MergeSubcommand) { + if (opts::merge::InputFilenames.size() < 2) { + errs() << "merge subcommand requires at least 2 input files.\n"; + exit(1); + } + mergePdbs(); + } else if (opts::ExplainSubcommand) { + explain(); + } else if (opts::ExportSubcommand) { + exportStream(); + } + + outs().flush(); + return 0; +} diff --git a/contrib/libs/llvm12/tools/llvm-pdbutil/llvm-pdbutil.h b/contrib/libs/llvm12/tools/llvm-pdbutil/llvm-pdbutil.h new file mode 100644 index 0000000000..9fe92c2c9d --- /dev/null +++ b/contrib/libs/llvm12/tools/llvm-pdbutil/llvm-pdbutil.h @@ -0,0 +1,220 @@ +//===- llvm-pdbutil.h ----------------------------------------- *- C++ --*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMPDBDUMP_LLVMPDBDUMP_H +#define LLVM_TOOLS_LLVMPDBDUMP_LLVMPDBDUMP_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/raw_ostream.h" + +#include <memory> +#include <stdint.h> + +namespace llvm { +namespace object { +class COFFObjectFile; +} +namespace pdb { +class PDBSymbolData; +class PDBSymbolFunc; +class PDBFile; +uint32_t getTypeLength(const PDBSymbolData &Symbol); +} +typedef llvm::PointerUnion<object::COFFObjectFile *, pdb::PDBFile *> + PdbOrCoffObj; +} + +namespace opts { + +enum class DumpLevel { None, Basic, Verbose }; + +enum class ModuleSubsection { + Unknown, + Lines, + FileChecksums, + InlineeLines, + CrossScopeImports, + CrossScopeExports, + StringTable, + Symbols, + FrameData, + CoffSymbolRVAs, + All +}; + +namespace pretty { + +enum class ClassDefinitionFormat { None, Layout, All }; +enum class ClassSortMode { + None, + Name, + Size, + Padding, + PaddingPct, + PaddingImmediate, + PaddingPctImmediate +}; + +enum class SymbolSortMode { None, Name, Size }; + +enum class SymLevel { Functions, Data, Thunks, All }; + +bool shouldDumpSymLevel(SymLevel Level); +bool compareFunctionSymbols( + const std::unique_ptr<llvm::pdb::PDBSymbolFunc> &F1, + const std::unique_ptr<llvm::pdb::PDBSymbolFunc> &F2); +bool compareDataSymbols(const std::unique_ptr<llvm::pdb::PDBSymbolData> &F1, + const std::unique_ptr<llvm::pdb::PDBSymbolData> &F2); + +extern llvm::cl::list<std::string> WithName; + +extern llvm::cl::opt<bool> Compilands; +extern llvm::cl::opt<bool> Symbols; +extern llvm::cl::opt<bool> Globals; +extern llvm::cl::opt<bool> Classes; +extern llvm::cl::opt<bool> Enums; +extern llvm::cl::opt<bool> Funcsigs; +extern llvm::cl::opt<bool> Arrays; +extern llvm::cl::opt<bool> Typedefs; +extern llvm::cl::opt<bool> Pointers; +extern llvm::cl::opt<bool> VTShapes; +extern llvm::cl::opt<bool> All; +extern llvm::cl::opt<bool> ExcludeCompilerGenerated; + +extern llvm::cl::opt<bool> NoEnumDefs; +extern llvm::cl::list<std::string> ExcludeTypes; +extern llvm::cl::list<std::string> ExcludeSymbols; +extern llvm::cl::list<std::string> ExcludeCompilands; +extern llvm::cl::list<std::string> IncludeTypes; +extern llvm::cl::list<std::string> IncludeSymbols; +extern llvm::cl::list<std::string> IncludeCompilands; +extern llvm::cl::opt<SymbolSortMode> SymbolOrder; +extern llvm::cl::opt<ClassSortMode> ClassOrder; +extern llvm::cl::opt<uint32_t> SizeThreshold; +extern llvm::cl::opt<uint32_t> PaddingThreshold; +extern llvm::cl::opt<uint32_t> ImmediatePaddingThreshold; +extern llvm::cl::opt<ClassDefinitionFormat> ClassFormat; +extern llvm::cl::opt<uint32_t> ClassRecursionDepth; +} + +namespace bytes { +struct NumberRange { + uint64_t Min; + llvm::Optional<uint64_t> Max; +}; + +extern llvm::Optional<NumberRange> DumpBlockRange; +extern llvm::Optional<NumberRange> DumpByteRange; +extern llvm::cl::list<std::string> DumpStreamData; +extern llvm::cl::opt<bool> NameMap; +extern llvm::cl::opt<bool> Fpm; + +extern llvm::cl::opt<bool> SectionContributions; +extern llvm::cl::opt<bool> SectionMap; +extern llvm::cl::opt<bool> ModuleInfos; +extern llvm::cl::opt<bool> FileInfo; +extern llvm::cl::opt<bool> TypeServerMap; +extern llvm::cl::opt<bool> ECData; + +extern llvm::cl::list<uint32_t> TypeIndex; +extern llvm::cl::list<uint32_t> IdIndex; + +extern llvm::cl::opt<uint32_t> ModuleIndex; +extern llvm::cl::opt<bool> ModuleSyms; +extern llvm::cl::opt<bool> ModuleC11; +extern llvm::cl::opt<bool> ModuleC13; +extern llvm::cl::opt<bool> SplitChunks; +} // namespace bytes + +namespace dump { + +extern llvm::cl::opt<bool> DumpSummary; +extern llvm::cl::opt<bool> DumpFpm; +extern llvm::cl::opt<bool> DumpStreams; +extern llvm::cl::opt<bool> DumpSymbolStats; +extern llvm::cl::opt<bool> DumpTypeStats; +extern llvm::cl::opt<bool> DumpIDStats; +extern llvm::cl::opt<bool> DumpUdtStats; +extern llvm::cl::opt<bool> DumpStreamBlocks; + +extern llvm::cl::opt<bool> DumpLines; +extern llvm::cl::opt<bool> DumpInlineeLines; +extern llvm::cl::opt<bool> DumpXmi; +extern llvm::cl::opt<bool> DumpXme; +extern llvm::cl::opt<bool> DumpNamedStreams; +extern llvm::cl::opt<bool> DumpStringTable; +extern llvm::cl::opt<bool> DumpStringTableDetails; +extern llvm::cl::opt<bool> DumpTypes; +extern llvm::cl::opt<bool> DumpTypeData; +extern llvm::cl::opt<bool> DumpTypeExtras; +extern llvm::cl::list<uint32_t> DumpTypeIndex; +extern llvm::cl::opt<bool> DumpTypeDependents; +extern llvm::cl::opt<bool> DumpTypeRefStats; +extern llvm::cl::opt<bool> DumpSectionHeaders; + +extern llvm::cl::opt<bool> DumpIds; +extern llvm::cl::opt<bool> DumpIdData; +extern llvm::cl::opt<bool> DumpIdExtras; +extern llvm::cl::list<uint32_t> DumpIdIndex; +extern llvm::cl::opt<uint32_t> DumpModi; +extern llvm::cl::opt<bool> JustMyCode; +extern llvm::cl::opt<bool> DontResolveForwardRefs; +extern llvm::cl::opt<bool> DumpSymbols; +extern llvm::cl::opt<bool> DumpSymRecordBytes; +extern llvm::cl::opt<bool> DumpGSIRecords; +extern llvm::cl::opt<bool> DumpGlobals; +extern llvm::cl::list<std::string> DumpGlobalNames; +extern llvm::cl::opt<bool> DumpGlobalExtras; +extern llvm::cl::opt<bool> DumpPublics; +extern llvm::cl::opt<bool> DumpPublicExtras; +extern llvm::cl::opt<bool> DumpSectionContribs; +extern llvm::cl::opt<bool> DumpSectionMap; +extern llvm::cl::opt<bool> DumpModules; +extern llvm::cl::opt<bool> DumpModuleFiles; +extern llvm::cl::opt<bool> DumpFpo; +extern llvm::cl::opt<bool> RawAll; +} + +namespace pdb2yaml { +extern llvm::cl::opt<bool> All; +extern llvm::cl::opt<bool> NoFileHeaders; +extern llvm::cl::opt<bool> Minimal; +extern llvm::cl::opt<bool> StreamMetadata; +extern llvm::cl::opt<bool> StreamDirectory; +extern llvm::cl::opt<bool> StringTable; +extern llvm::cl::opt<bool> PdbStream; +extern llvm::cl::opt<bool> DbiStream; +extern llvm::cl::opt<bool> TpiStream; +extern llvm::cl::opt<bool> IpiStream; +extern llvm::cl::opt<bool> PublicsStream; +extern llvm::cl::list<std::string> InputFilename; +extern llvm::cl::opt<bool> DumpModules; +extern llvm::cl::opt<bool> DumpModuleFiles; +extern llvm::cl::list<ModuleSubsection> DumpModuleSubsections; +extern llvm::cl::opt<bool> DumpModuleSyms; +} // namespace pdb2yaml + +namespace explain { +enum class InputFileType { PDBFile, PDBStream, DBIStream, Names, ModuleStream }; + +extern llvm::cl::list<std::string> InputFilename; +extern llvm::cl::list<uint64_t> Offsets; +extern llvm::cl::opt<InputFileType> InputType; +} // namespace explain + +namespace exportstream { +extern llvm::cl::opt<std::string> OutputFile; +extern llvm::cl::opt<std::string> Stream; +extern llvm::cl::opt<bool> ForceName; +} // namespace exportstream +} + +#endif |