Path: blob/main/contrib/llvm-project/llvm/tools/llvm-pdbutil/BytesOutputStyle.cpp
35259 views
//===- BytesOutputStyle.cpp ----------------------------------- *- C++ --*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "BytesOutputStyle.h"910#include "StreamUtil.h"11#include "llvm-pdbutil.h"1213#include "llvm/DebugInfo/CodeView/Formatters.h"14#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"15#include "llvm/DebugInfo/MSF/MSFCommon.h"16#include "llvm/DebugInfo/MSF/MappedBlockStream.h"17#include "llvm/DebugInfo/PDB/Native/DbiStream.h"18#include "llvm/DebugInfo/PDB/Native/FormatUtil.h"19#include "llvm/DebugInfo/PDB/Native/InfoStream.h"20#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"21#include "llvm/DebugInfo/PDB/Native/PDBFile.h"22#include "llvm/DebugInfo/PDB/Native/RawError.h"23#include "llvm/DebugInfo/PDB/Native/TpiStream.h"24#include "llvm/Support/BinaryStreamReader.h"25#include "llvm/Support/FormatAdapters.h"26#include "llvm/Support/FormatVariadic.h"2728using namespace llvm;29using namespace llvm::codeview;30using namespace llvm::msf;31using namespace llvm::pdb;3233namespace {34struct StreamSpec {35uint32_t SI = 0;36uint32_t Begin = 0;37uint32_t Size = 0;38};39} // namespace4041static Expected<StreamSpec> parseStreamSpec(StringRef Str) {42StreamSpec Result;43if (Str.consumeInteger(0, Result.SI))44return make_error<RawError>(raw_error_code::invalid_format,45"Invalid Stream Specification");46if (Str.consume_front(":")) {47if (Str.consumeInteger(0, Result.Begin))48return make_error<RawError>(raw_error_code::invalid_format,49"Invalid Stream Specification");50}51if (Str.consume_front("@")) {52if (Str.consumeInteger(0, Result.Size))53return make_error<RawError>(raw_error_code::invalid_format,54"Invalid Stream Specification");55}5657if (!Str.empty())58return make_error<RawError>(raw_error_code::invalid_format,59"Invalid Stream Specification");60return Result;61}6263static SmallVector<StreamSpec, 2> parseStreamSpecs(LinePrinter &P) {64SmallVector<StreamSpec, 2> Result;6566for (auto &Str : opts::bytes::DumpStreamData) {67auto ESS = parseStreamSpec(Str);68if (!ESS) {69P.formatLine("Error parsing stream spec {0}: {1}", Str,70toString(ESS.takeError()));71continue;72}73Result.push_back(*ESS);74}75return Result;76}7778static void printHeader(LinePrinter &P, const Twine &S) {79P.NewLine();80P.formatLine("{0,=60}", S);81P.formatLine("{0}", fmt_repeat('=', 60));82}8384BytesOutputStyle::BytesOutputStyle(PDBFile &File)85: File(File), P(2, false, outs(), opts::Filters) {}8687Error BytesOutputStyle::dump() {8889if (opts::bytes::DumpBlockRange) {90auto &R = *opts::bytes::DumpBlockRange;91uint32_t Max = R.Max.value_or(R.Min);9293if (Max < R.Min)94return make_error<StringError>(95"Invalid block range specified. Max < Min",96inconvertibleErrorCode());97if (Max >= File.getBlockCount())98return make_error<StringError>(99"Invalid block range specified. Requested block out of bounds",100inconvertibleErrorCode());101102dumpBlockRanges(R.Min, Max);103P.NewLine();104}105106if (opts::bytes::DumpByteRange) {107auto &R = *opts::bytes::DumpByteRange;108uint32_t Max = R.Max.value_or(File.getFileSize());109110if (Max < R.Min)111return make_error<StringError>("Invalid byte range specified. Max < Min",112inconvertibleErrorCode());113if (Max >= File.getFileSize())114return make_error<StringError>(115"Invalid byte range specified. Requested byte larger than file size",116inconvertibleErrorCode());117118dumpByteRanges(R.Min, Max);119P.NewLine();120}121122if (opts::bytes::Fpm) {123dumpFpm();124P.NewLine();125}126127if (!opts::bytes::DumpStreamData.empty()) {128dumpStreamBytes();129P.NewLine();130}131132if (opts::bytes::NameMap) {133dumpNameMap();134P.NewLine();135}136137if (opts::bytes::SectionContributions) {138dumpSectionContributions();139P.NewLine();140}141142if (opts::bytes::SectionMap) {143dumpSectionMap();144P.NewLine();145}146147if (opts::bytes::ModuleInfos) {148dumpModuleInfos();149P.NewLine();150}151152if (opts::bytes::FileInfo) {153dumpFileInfo();154P.NewLine();155}156157if (opts::bytes::TypeServerMap) {158dumpTypeServerMap();159P.NewLine();160}161162if (opts::bytes::ECData) {163dumpECData();164P.NewLine();165}166167if (!opts::bytes::TypeIndex.empty()) {168dumpTypeIndex(StreamTPI, opts::bytes::TypeIndex);169P.NewLine();170}171172if (!opts::bytes::IdIndex.empty()) {173dumpTypeIndex(StreamIPI, opts::bytes::IdIndex);174P.NewLine();175}176177if (opts::bytes::ModuleSyms) {178dumpModuleSyms();179P.NewLine();180}181182if (opts::bytes::ModuleC11) {183dumpModuleC11();184P.NewLine();185}186187if (opts::bytes::ModuleC13) {188dumpModuleC13();189P.NewLine();190}191192return Error::success();193}194195void BytesOutputStyle::dumpNameMap() {196printHeader(P, "Named Stream Map");197198AutoIndent Indent(P);199200auto &InfoS = Err(File.getPDBInfoStream());201BinarySubstreamRef NS = InfoS.getNamedStreamsBuffer();202auto Layout = File.getStreamLayout(StreamPDB);203P.formatMsfStreamData("Named Stream Map", File, Layout, NS);204}205206void BytesOutputStyle::dumpBlockRanges(uint32_t Min, uint32_t Max) {207printHeader(P, "MSF Blocks");208209AutoIndent Indent(P);210for (uint32_t I = Min; I <= Max; ++I) {211uint64_t Base = I;212Base *= File.getBlockSize();213214auto ExpectedData = File.getBlockData(I, File.getBlockSize());215if (!ExpectedData) {216P.formatLine("Could not get block {0}. Reason = {1}", I,217toString(ExpectedData.takeError()));218continue;219}220std::string Label = formatv("Block {0}", I).str();221P.formatBinary(Label, *ExpectedData, Base, 0);222}223}224225void BytesOutputStyle::dumpSectionContributions() {226printHeader(P, "Section Contributions");227228AutoIndent Indent(P);229230auto &DbiS = Err(File.getPDBDbiStream());231BinarySubstreamRef NS = DbiS.getSectionContributionData();232auto Layout = File.getStreamLayout(StreamDBI);233P.formatMsfStreamData("Section Contributions", File, Layout, NS);234}235236void BytesOutputStyle::dumpSectionMap() {237printHeader(P, "Section Map");238239AutoIndent Indent(P);240241auto &DbiS = Err(File.getPDBDbiStream());242BinarySubstreamRef NS = DbiS.getSecMapSubstreamData();243auto Layout = File.getStreamLayout(StreamDBI);244P.formatMsfStreamData("Section Map", File, Layout, NS);245}246247void BytesOutputStyle::dumpModuleInfos() {248printHeader(P, "Module Infos");249250AutoIndent Indent(P);251252auto &DbiS = Err(File.getPDBDbiStream());253BinarySubstreamRef NS = DbiS.getModiSubstreamData();254auto Layout = File.getStreamLayout(StreamDBI);255P.formatMsfStreamData("Module Infos", File, Layout, NS);256}257258void BytesOutputStyle::dumpFileInfo() {259printHeader(P, "File Info");260261AutoIndent Indent(P);262263auto &DbiS = Err(File.getPDBDbiStream());264BinarySubstreamRef NS = DbiS.getFileInfoSubstreamData();265auto Layout = File.getStreamLayout(StreamDBI);266P.formatMsfStreamData("File Info", File, Layout, NS);267}268269void BytesOutputStyle::dumpTypeServerMap() {270printHeader(P, "Type Server Map");271272AutoIndent Indent(P);273274auto &DbiS = Err(File.getPDBDbiStream());275BinarySubstreamRef NS = DbiS.getTypeServerMapSubstreamData();276auto Layout = File.getStreamLayout(StreamDBI);277P.formatMsfStreamData("Type Server Map", File, Layout, NS);278}279280void BytesOutputStyle::dumpECData() {281printHeader(P, "Edit and Continue Data");282283AutoIndent Indent(P);284285auto &DbiS = Err(File.getPDBDbiStream());286BinarySubstreamRef NS = DbiS.getECSubstreamData();287auto Layout = File.getStreamLayout(StreamDBI);288P.formatMsfStreamData("Edit and Continue Data", File, Layout, NS);289}290291void BytesOutputStyle::dumpTypeIndex(uint32_t StreamIdx,292ArrayRef<uint32_t> Indices) {293assert(StreamIdx == StreamTPI || StreamIdx == StreamIPI);294assert(!Indices.empty());295296bool IsTpi = (StreamIdx == StreamTPI);297298StringRef Label = IsTpi ? "Type (TPI) Records" : "Index (IPI) Records";299printHeader(P, Label);300auto &Stream = Err(IsTpi ? File.getPDBTpiStream() : File.getPDBIpiStream());301302AutoIndent Indent(P);303304auto Substream = Stream.getTypeRecordsSubstream();305auto &Types = Err(initializeTypes(StreamIdx));306auto Layout = File.getStreamLayout(StreamIdx);307for (const auto &Id : Indices) {308TypeIndex TI(Id);309if (TI.toArrayIndex() >= Types.capacity()) {310P.formatLine("Error: TypeIndex {0} does not exist", TI);311continue;312}313314auto Type = Types.getType(TI);315uint32_t Offset = Types.getOffsetOfType(TI);316auto OneType = Substream.slice(Offset, Type.length());317P.formatMsfStreamData(formatv("Type {0}", TI).str(), File, Layout, OneType);318}319}320321template <typename CallbackT>322static void iterateOneModule(PDBFile &File, LinePrinter &P,323const DbiModuleList &Modules, uint32_t I,324uint32_t Digits, uint32_t IndentLevel,325CallbackT Callback) {326if (I >= Modules.getModuleCount()) {327P.formatLine("Mod {0:4} | Invalid module index ",328fmt_align(I, AlignStyle::Right, std::max(Digits, 4U)));329return;330}331332auto Modi = Modules.getModuleDescriptor(I);333P.formatLine("Mod {0:4} | `{1}`: ",334fmt_align(I, AlignStyle::Right, std::max(Digits, 4U)),335Modi.getModuleName());336337uint16_t ModiStream = Modi.getModuleStreamIndex();338AutoIndent Indent2(P, IndentLevel);339if (ModiStream == kInvalidStreamIndex)340return;341342auto ModStreamData = File.createIndexedStream(ModiStream);343ModuleDebugStreamRef ModStream(Modi, std::move(ModStreamData));344if (auto EC = ModStream.reload()) {345P.formatLine("Could not parse debug information.");346return;347}348auto Layout = File.getStreamLayout(ModiStream);349Callback(I, ModStream, Layout);350}351352template <typename CallbackT>353static void iterateModules(PDBFile &File, LinePrinter &P, uint32_t IndentLevel,354CallbackT Callback) {355AutoIndent Indent(P);356if (!File.hasPDBDbiStream()) {357P.formatLine("DBI Stream not present");358return;359}360361ExitOnError Err("Unexpected error processing modules");362363auto &Stream = Err(File.getPDBDbiStream());364365const DbiModuleList &Modules = Stream.modules();366367if (opts::bytes::ModuleIndex.getNumOccurrences() > 0) {368iterateOneModule(File, P, Modules, opts::bytes::ModuleIndex, 1, IndentLevel,369Callback);370} else {371uint32_t Count = Modules.getModuleCount();372uint32_t Digits = NumDigits(Count);373for (uint32_t I = 0; I < Count; ++I) {374iterateOneModule(File, P, Modules, I, Digits, IndentLevel, Callback);375}376}377}378379void BytesOutputStyle::dumpModuleSyms() {380printHeader(P, "Module Symbols");381382AutoIndent Indent(P);383384iterateModules(File, P, 2,385[this](uint32_t Modi, const ModuleDebugStreamRef &Stream,386const MSFStreamLayout &Layout) {387auto Symbols = Stream.getSymbolsSubstream();388P.formatMsfStreamData("Symbols", File, Layout, Symbols);389});390}391392void BytesOutputStyle::dumpModuleC11() {393printHeader(P, "C11 Debug Chunks");394395AutoIndent Indent(P);396397iterateModules(File, P, 2,398[this](uint32_t Modi, const ModuleDebugStreamRef &Stream,399const MSFStreamLayout &Layout) {400auto Chunks = Stream.getC11LinesSubstream();401P.formatMsfStreamData("C11 Debug Chunks", File, Layout,402Chunks);403});404}405406void BytesOutputStyle::dumpModuleC13() {407printHeader(P, "Debug Chunks");408409AutoIndent Indent(P);410411iterateModules(412File, P, 2,413[this](uint32_t Modi, const ModuleDebugStreamRef &Stream,414const MSFStreamLayout &Layout) {415auto Chunks = Stream.getC13LinesSubstream();416if (opts::bytes::SplitChunks) {417for (const auto &SS : Stream.subsections()) {418BinarySubstreamRef ThisChunk;419std::tie(ThisChunk, Chunks) = Chunks.split(SS.getRecordLength());420P.formatMsfStreamData(formatChunkKind(SS.kind()), File, Layout,421ThisChunk);422}423} else {424P.formatMsfStreamData("Debug Chunks", File, Layout, Chunks);425}426});427}428429void BytesOutputStyle::dumpByteRanges(uint32_t Min, uint32_t Max) {430printHeader(P, "MSF Bytes");431432AutoIndent Indent(P);433434BinaryStreamReader Reader(File.getMsfBuffer());435ArrayRef<uint8_t> Data;436consumeError(Reader.skip(Min));437uint32_t Size = Max - Min + 1;438auto EC = Reader.readBytes(Data, Size);439assert(!EC);440consumeError(std::move(EC));441P.formatBinary("Bytes", Data, Min);442}443444Expected<codeview::LazyRandomTypeCollection &>445BytesOutputStyle::initializeTypes(uint32_t StreamIdx) {446auto &TypeCollection = (StreamIdx == StreamTPI) ? TpiTypes : IpiTypes;447if (TypeCollection)448return *TypeCollection;449450auto Tpi = (StreamIdx == StreamTPI) ? File.getPDBTpiStream()451: File.getPDBIpiStream();452if (!Tpi)453return Tpi.takeError();454455auto &Types = Tpi->typeArray();456uint32_t Count = Tpi->getNumTypeRecords();457auto Offsets = Tpi->getTypeIndexOffsets();458TypeCollection =459std::make_unique<LazyRandomTypeCollection>(Types, Count, Offsets);460461return *TypeCollection;462}463464void BytesOutputStyle::dumpFpm() {465printHeader(P, "Free Page Map");466467msf::MSFStreamLayout FpmLayout = File.getFpmStreamLayout();468P.formatMsfStreamBlocks(File, FpmLayout);469}470471void BytesOutputStyle::dumpStreamBytes() {472if (StreamPurposes.empty())473discoverStreamPurposes(File, StreamPurposes);474475printHeader(P, "Stream Data");476ExitOnError Err("Unexpected error reading stream data");477478auto Specs = parseStreamSpecs(P);479480for (const auto &Spec : Specs) {481AutoIndent Indent(P);482if (Spec.SI >= StreamPurposes.size()) {483P.formatLine("Stream {0}: Not present", Spec.SI);484continue;485}486P.formatMsfStreamData("Data", File, Spec.SI,487StreamPurposes[Spec.SI].getShortName(), Spec.Begin,488Spec.Size);489}490}491492493