summaryrefslogtreecommitdiff
path: root/tools/llvm-pdbutil/BytesOutputStyle.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/llvm-pdbutil/BytesOutputStyle.cpp')
-rw-r--r--tools/llvm-pdbutil/BytesOutputStyle.cpp501
1 files changed, 501 insertions, 0 deletions
diff --git a/tools/llvm-pdbutil/BytesOutputStyle.cpp b/tools/llvm-pdbutil/BytesOutputStyle.cpp
new file mode 100644
index 0000000000000..9e5a28c2b98ba
--- /dev/null
+++ b/tools/llvm-pdbutil/BytesOutputStyle.cpp
@@ -0,0 +1,501 @@
+//===- BytesOutputStyle.cpp ----------------------------------- *- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "BytesOutputStyle.h"
+
+#include "FormatUtil.h"
+#include "StreamUtil.h"
+#include "llvm-pdbutil.h"
+
+#include "llvm/DebugInfo/CodeView/Formatters.h"
+#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
+#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
+#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
+#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
+#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/RawError.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/FormatAdapters.h"
+#include "llvm/Support/FormatVariadic.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::msf;
+using namespace llvm::pdb;
+
+namespace {
+struct StreamSpec {
+ uint32_t SI = 0;
+ uint32_t Begin = 0;
+ uint32_t Size = 0;
+};
+} // namespace
+
+static Expected<StreamSpec> parseStreamSpec(StringRef Str) {
+ StreamSpec Result;
+ if (Str.consumeInteger(0, Result.SI))
+ return make_error<RawError>(raw_error_code::invalid_format,
+ "Invalid Stream Specification");
+ if (Str.consume_front(":")) {
+ if (Str.consumeInteger(0, Result.Begin))
+ return make_error<RawError>(raw_error_code::invalid_format,
+ "Invalid Stream Specification");
+ }
+ if (Str.consume_front("@")) {
+ if (Str.consumeInteger(0, Result.Size))
+ return make_error<RawError>(raw_error_code::invalid_format,
+ "Invalid Stream Specification");
+ }
+
+ if (!Str.empty())
+ return make_error<RawError>(raw_error_code::invalid_format,
+ "Invalid Stream Specification");
+ return Result;
+}
+
+static SmallVector<StreamSpec, 2> parseStreamSpecs(LinePrinter &P) {
+ SmallVector<StreamSpec, 2> Result;
+
+ for (auto &Str : opts::bytes::DumpStreamData) {
+ auto ESS = parseStreamSpec(Str);
+ if (!ESS) {
+ P.formatLine("Error parsing stream spec {0}: {1}", Str,
+ toString(ESS.takeError()));
+ continue;
+ }
+ Result.push_back(*ESS);
+ }
+ return Result;
+}
+
+static void printHeader(LinePrinter &P, const Twine &S) {
+ P.NewLine();
+ P.formatLine("{0,=60}", S);
+ P.formatLine("{0}", fmt_repeat('=', 60));
+}
+
+BytesOutputStyle::BytesOutputStyle(PDBFile &File)
+ : File(File), P(2, false, outs()) {}
+
+Error BytesOutputStyle::dump() {
+
+ if (opts::bytes::DumpBlockRange.hasValue()) {
+ auto &R = *opts::bytes::DumpBlockRange;
+ uint32_t Max = R.Max.getValueOr(R.Min);
+
+ if (Max < R.Min)
+ return make_error<StringError>(
+ "Invalid block range specified. Max < Min",
+ inconvertibleErrorCode());
+ if (Max >= File.getBlockCount())
+ return make_error<StringError>(
+ "Invalid block range specified. Requested block out of bounds",
+ inconvertibleErrorCode());
+
+ dumpBlockRanges(R.Min, Max);
+ P.NewLine();
+ }
+
+ if (opts::bytes::DumpByteRange.hasValue()) {
+ auto &R = *opts::bytes::DumpByteRange;
+ uint32_t Max = R.Max.getValueOr(File.getFileSize());
+
+ if (Max < R.Min)
+ return make_error<StringError>("Invalid byte range specified. Max < Min",
+ inconvertibleErrorCode());
+ if (Max >= File.getFileSize())
+ return make_error<StringError>(
+ "Invalid byte range specified. Requested byte larger than file size",
+ inconvertibleErrorCode());
+
+ dumpByteRanges(R.Min, Max);
+ P.NewLine();
+ }
+
+ if (!opts::bytes::DumpStreamData.empty()) {
+ dumpStreamBytes();
+ P.NewLine();
+ }
+
+ if (opts::bytes::NameMap) {
+ dumpNameMap();
+ P.NewLine();
+ }
+
+ if (opts::bytes::SectionContributions) {
+ dumpSectionContributions();
+ P.NewLine();
+ }
+
+ if (opts::bytes::SectionMap) {
+ dumpSectionMap();
+ P.NewLine();
+ }
+
+ if (opts::bytes::ModuleInfos) {
+ dumpModuleInfos();
+ P.NewLine();
+ }
+
+ if (opts::bytes::FileInfo) {
+ dumpFileInfo();
+ P.NewLine();
+ }
+
+ if (opts::bytes::TypeServerMap) {
+ dumpTypeServerMap();
+ P.NewLine();
+ }
+
+ if (opts::bytes::ECData) {
+ dumpECData();
+ P.NewLine();
+ }
+
+ if (!opts::bytes::TypeIndex.empty()) {
+ dumpTypeIndex(StreamTPI, opts::bytes::TypeIndex);
+ P.NewLine();
+ }
+
+ if (!opts::bytes::IdIndex.empty()) {
+ dumpTypeIndex(StreamIPI, opts::bytes::IdIndex);
+ P.NewLine();
+ }
+
+ if (opts::bytes::ModuleSyms) {
+ dumpModuleSyms();
+ P.NewLine();
+ }
+
+ if (opts::bytes::ModuleC11) {
+ dumpModuleC11();
+ P.NewLine();
+ }
+
+ if (opts::bytes::ModuleC13) {
+ dumpModuleC13();
+ P.NewLine();
+ }
+
+ return Error::success();
+}
+
+void BytesOutputStyle::dumpNameMap() {
+ printHeader(P, "Named Stream Map");
+
+ AutoIndent Indent(P);
+
+ auto &InfoS = Err(File.getPDBInfoStream());
+ BinarySubstreamRef NS = InfoS.getNamedStreamsBuffer();
+ auto Layout = File.getStreamLayout(StreamPDB);
+ P.formatMsfStreamData("Named Stream Map", File, Layout, NS);
+}
+
+void BytesOutputStyle::dumpBlockRanges(uint32_t Min, uint32_t Max) {
+ printHeader(P, "MSF Blocks");
+
+ AutoIndent Indent(P);
+ for (uint32_t I = Min; I <= Max; ++I) {
+ uint64_t Base = I;
+ Base *= File.getBlockSize();
+
+ auto ExpectedData = File.getBlockData(I, File.getBlockSize());
+ if (!ExpectedData) {
+ P.formatLine("Could not get block {0}. Reason = {1}", I,
+ toString(ExpectedData.takeError()));
+ continue;
+ }
+ std::string Label = formatv("Block {0}", I).str();
+ P.formatBinary(Label, *ExpectedData, Base, 0);
+ }
+}
+
+void BytesOutputStyle::dumpSectionContributions() {
+ printHeader(P, "Section Contributions");
+
+ AutoIndent Indent(P);
+
+ auto &DbiS = Err(File.getPDBDbiStream());
+ BinarySubstreamRef NS = DbiS.getSectionContributionData();
+ auto Layout = File.getStreamLayout(StreamDBI);
+ P.formatMsfStreamData("Section Contributions", File, Layout, NS);
+}
+
+void BytesOutputStyle::dumpSectionMap() {
+ printHeader(P, "Section Map");
+
+ AutoIndent Indent(P);
+
+ auto &DbiS = Err(File.getPDBDbiStream());
+ BinarySubstreamRef NS = DbiS.getSecMapSubstreamData();
+ auto Layout = File.getStreamLayout(StreamDBI);
+ P.formatMsfStreamData("Section Map", File, Layout, NS);
+}
+
+void BytesOutputStyle::dumpModuleInfos() {
+ printHeader(P, "Module Infos");
+
+ AutoIndent Indent(P);
+
+ auto &DbiS = Err(File.getPDBDbiStream());
+ BinarySubstreamRef NS = DbiS.getModiSubstreamData();
+ auto Layout = File.getStreamLayout(StreamDBI);
+ P.formatMsfStreamData("Module Infos", File, Layout, NS);
+}
+
+void BytesOutputStyle::dumpFileInfo() {
+ printHeader(P, "File Info");
+
+ AutoIndent Indent(P);
+
+ auto &DbiS = Err(File.getPDBDbiStream());
+ BinarySubstreamRef NS = DbiS.getFileInfoSubstreamData();
+ auto Layout = File.getStreamLayout(StreamDBI);
+ P.formatMsfStreamData("File Info", File, Layout, NS);
+}
+
+void BytesOutputStyle::dumpTypeServerMap() {
+ printHeader(P, "Type Server Map");
+
+ AutoIndent Indent(P);
+
+ auto &DbiS = Err(File.getPDBDbiStream());
+ BinarySubstreamRef NS = DbiS.getTypeServerMapSubstreamData();
+ auto Layout = File.getStreamLayout(StreamDBI);
+ P.formatMsfStreamData("Type Server Map", File, Layout, NS);
+}
+
+void BytesOutputStyle::dumpECData() {
+ printHeader(P, "Edit and Continue Data");
+
+ AutoIndent Indent(P);
+
+ auto &DbiS = Err(File.getPDBDbiStream());
+ BinarySubstreamRef NS = DbiS.getECSubstreamData();
+ auto Layout = File.getStreamLayout(StreamDBI);
+ P.formatMsfStreamData("Edit and Continue Data", File, Layout, NS);
+}
+
+void BytesOutputStyle::dumpTypeIndex(uint32_t StreamIdx,
+ ArrayRef<uint32_t> Indices) {
+ assert(StreamIdx == StreamTPI || StreamIdx == StreamIPI);
+ assert(!Indices.empty());
+
+ bool IsTpi = (StreamIdx == StreamTPI);
+
+ StringRef Label = IsTpi ? "Type (TPI) Records" : "Index (IPI) Records";
+ printHeader(P, Label);
+ auto &Stream = Err(IsTpi ? File.getPDBTpiStream() : File.getPDBIpiStream());
+
+ AutoIndent Indent(P);
+
+ auto Substream = Stream.getTypeRecordsSubstream();
+ auto &Types = Err(initializeTypes(StreamIdx));
+ auto Layout = File.getStreamLayout(StreamIdx);
+ for (const auto &Id : Indices) {
+ TypeIndex TI(Id);
+ if (TI.toArrayIndex() >= Types.capacity()) {
+ P.formatLine("Error: TypeIndex {0} does not exist", TI);
+ continue;
+ }
+
+ auto Type = Types.getType(TI);
+ uint32_t Offset = Types.getOffsetOfType(TI);
+ auto OneType = Substream.slice(Offset, Type.length());
+ P.formatMsfStreamData(formatv("Type {0}", TI).str(), File, Layout, OneType);
+ }
+}
+
+template <typename CallbackT>
+static void iterateOneModule(PDBFile &File, LinePrinter &P,
+ const DbiModuleList &Modules, uint32_t I,
+ uint32_t Digits, uint32_t IndentLevel,
+ CallbackT Callback) {
+ if (I >= Modules.getModuleCount()) {
+ P.formatLine("Mod {0:4} | Invalid module index ",
+ fmt_align(I, AlignStyle::Right, std::max(Digits, 4U)));
+ return;
+ }
+
+ auto Modi = Modules.getModuleDescriptor(I);
+ P.formatLine("Mod {0:4} | `{1}`: ",
+ fmt_align(I, AlignStyle::Right, std::max(Digits, 4U)),
+ Modi.getModuleName());
+
+ uint16_t ModiStream = Modi.getModuleStreamIndex();
+ AutoIndent Indent2(P, IndentLevel);
+ if (ModiStream == kInvalidStreamIndex)
+ return;
+
+ auto ModStreamData = MappedBlockStream::createIndexedStream(
+ File.getMsfLayout(), File.getMsfBuffer(), ModiStream,
+ File.getAllocator());
+ ModuleDebugStreamRef ModStream(Modi, std::move(ModStreamData));
+ if (auto EC = ModStream.reload()) {
+ P.formatLine("Could not parse debug information.");
+ return;
+ }
+ auto Layout = File.getStreamLayout(ModiStream);
+ Callback(I, ModStream, Layout);
+}
+
+template <typename CallbackT>
+static void iterateModules(PDBFile &File, LinePrinter &P, uint32_t IndentLevel,
+ CallbackT Callback) {
+ AutoIndent Indent(P);
+ if (!File.hasPDBDbiStream()) {
+ P.formatLine("DBI Stream not present");
+ return;
+ }
+
+ ExitOnError Err("Unexpected error processing modules");
+
+ auto &Stream = Err(File.getPDBDbiStream());
+
+ const DbiModuleList &Modules = Stream.modules();
+
+ if (opts::bytes::ModuleIndex.getNumOccurrences() > 0) {
+ iterateOneModule(File, P, Modules, opts::bytes::ModuleIndex, 1, IndentLevel,
+ Callback);
+ } else {
+ uint32_t Count = Modules.getModuleCount();
+ uint32_t Digits = NumDigits(Count);
+ for (uint32_t I = 0; I < Count; ++I) {
+ iterateOneModule(File, P, Modules, I, Digits, IndentLevel, Callback);
+ }
+ }
+}
+
+void BytesOutputStyle::dumpModuleSyms() {
+ printHeader(P, "Module Symbols");
+
+ AutoIndent Indent(P);
+
+ iterateModules(File, P, 2,
+ [this](uint32_t Modi, const ModuleDebugStreamRef &Stream,
+ const MSFStreamLayout &Layout) {
+ auto Symbols = Stream.getSymbolsSubstream();
+ P.formatMsfStreamData("Symbols", File, Layout, Symbols);
+ });
+}
+
+void BytesOutputStyle::dumpModuleC11() {
+ printHeader(P, "C11 Debug Chunks");
+
+ AutoIndent Indent(P);
+
+ iterateModules(File, P, 2,
+ [this](uint32_t Modi, const ModuleDebugStreamRef &Stream,
+ const MSFStreamLayout &Layout) {
+ auto Chunks = Stream.getC11LinesSubstream();
+ P.formatMsfStreamData("C11 Debug Chunks", File, Layout,
+ Chunks);
+ });
+}
+
+static std::string formatChunkKind(DebugSubsectionKind Kind) {
+ switch (Kind) {
+ RETURN_CASE(DebugSubsectionKind, None, "none");
+ RETURN_CASE(DebugSubsectionKind, Symbols, "symbols");
+ RETURN_CASE(DebugSubsectionKind, Lines, "lines");
+ RETURN_CASE(DebugSubsectionKind, StringTable, "strings");
+ RETURN_CASE(DebugSubsectionKind, FileChecksums, "checksums");
+ RETURN_CASE(DebugSubsectionKind, FrameData, "frames");
+ RETURN_CASE(DebugSubsectionKind, InlineeLines, "inlinee lines");
+ RETURN_CASE(DebugSubsectionKind, CrossScopeImports, "xmi");
+ RETURN_CASE(DebugSubsectionKind, CrossScopeExports, "xme");
+ RETURN_CASE(DebugSubsectionKind, ILLines, "il lines");
+ RETURN_CASE(DebugSubsectionKind, FuncMDTokenMap, "func md token map");
+ RETURN_CASE(DebugSubsectionKind, TypeMDTokenMap, "type md token map");
+ RETURN_CASE(DebugSubsectionKind, MergedAssemblyInput,
+ "merged assembly input");
+ RETURN_CASE(DebugSubsectionKind, CoffSymbolRVA, "coff symbol rva");
+ }
+ return formatUnknownEnum(Kind);
+}
+
+void BytesOutputStyle::dumpModuleC13() {
+ printHeader(P, "Debug Chunks");
+
+ AutoIndent Indent(P);
+
+ iterateModules(
+ File, P, 2,
+ [this](uint32_t Modi, const ModuleDebugStreamRef &Stream,
+ const MSFStreamLayout &Layout) {
+ auto Chunks = Stream.getC13LinesSubstream();
+ if (opts::bytes::SplitChunks) {
+ for (const auto &SS : Stream.subsections()) {
+ BinarySubstreamRef ThisChunk;
+ std::tie(ThisChunk, Chunks) = Chunks.split(SS.getRecordLength());
+ P.formatMsfStreamData(formatChunkKind(SS.kind()), File, Layout,
+ ThisChunk);
+ }
+ } else {
+ P.formatMsfStreamData("Debug Chunks", File, Layout, Chunks);
+ }
+ });
+}
+
+void BytesOutputStyle::dumpByteRanges(uint32_t Min, uint32_t Max) {
+ printHeader(P, "MSF Bytes");
+
+ AutoIndent Indent(P);
+
+ BinaryStreamReader Reader(File.getMsfBuffer());
+ ArrayRef<uint8_t> Data;
+ consumeError(Reader.skip(Min));
+ uint32_t Size = Max - Min + 1;
+ auto EC = Reader.readBytes(Data, Size);
+ assert(!EC);
+ consumeError(std::move(EC));
+ P.formatBinary("Bytes", Data, Min);
+}
+
+Expected<codeview::LazyRandomTypeCollection &>
+BytesOutputStyle::initializeTypes(uint32_t StreamIdx) {
+ auto &TypeCollection = (StreamIdx == StreamTPI) ? TpiTypes : IpiTypes;
+ if (TypeCollection)
+ return *TypeCollection;
+
+ auto Tpi = (StreamIdx == StreamTPI) ? File.getPDBTpiStream()
+ : File.getPDBIpiStream();
+ if (!Tpi)
+ return Tpi.takeError();
+
+ auto &Types = Tpi->typeArray();
+ uint32_t Count = Tpi->getNumTypeRecords();
+ auto Offsets = Tpi->getTypeIndexOffsets();
+ TypeCollection =
+ llvm::make_unique<LazyRandomTypeCollection>(Types, Count, Offsets);
+
+ return *TypeCollection;
+}
+
+void BytesOutputStyle::dumpStreamBytes() {
+ if (StreamPurposes.empty())
+ discoverStreamPurposes(File, StreamPurposes);
+
+ printHeader(P, "Stream Data");
+ ExitOnError Err("Unexpected error reading stream data");
+
+ auto Specs = parseStreamSpecs(P);
+
+ for (const auto &Spec : Specs) {
+ AutoIndent Indent(P);
+ if (Spec.SI >= StreamPurposes.size()) {
+ P.formatLine("Stream {0}: Not present", Spec.SI);
+ continue;
+ }
+ P.formatMsfStreamData("Data", File, Spec.SI, StreamPurposes[Spec.SI],
+ Spec.Begin, Spec.Size);
+ }
+}