Path: blob/main/contrib/llvm-project/llvm/lib/DebugInfo/PDB/Native/LinePrinter.cpp
35293 views
//===- LinePrinter.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 "llvm/DebugInfo/PDB/Native/LinePrinter.h"910#include "llvm/ADT/STLExtras.h"11#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"12#include "llvm/DebugInfo/MSF/MSFCommon.h"13#include "llvm/DebugInfo/MSF/MappedBlockStream.h"14#include "llvm/DebugInfo/PDB/IPDBLineNumber.h"15#include "llvm/DebugInfo/PDB/Native/InputFile.h"16#include "llvm/DebugInfo/PDB/Native/NativeSession.h"17#include "llvm/DebugInfo/PDB/Native/PDBFile.h"18#include "llvm/DebugInfo/PDB/UDTLayout.h"19#include "llvm/Object/COFF.h"20#include "llvm/Support/BinaryStreamReader.h"21#include "llvm/Support/Format.h"22#include "llvm/Support/FormatAdapters.h"23#include "llvm/Support/FormatVariadic.h"24#include "llvm/Support/Regex.h"2526#include <algorithm>2728using namespace llvm;29using namespace llvm::msf;30using namespace llvm::pdb;3132namespace {33bool IsItemExcluded(llvm::StringRef Item,34std::list<llvm::Regex> &IncludeFilters,35std::list<llvm::Regex> &ExcludeFilters) {36if (Item.empty())37return false;3839auto match_pred = [Item](llvm::Regex &R) { return R.match(Item); };4041// Include takes priority over exclude. If the user specified include42// filters, and none of them include this item, them item is gone.43if (!IncludeFilters.empty() && !any_of(IncludeFilters, match_pred))44return true;4546if (any_of(ExcludeFilters, match_pred))47return true;4849return false;50}51} // namespace5253using namespace llvm;5455LinePrinter::LinePrinter(int Indent, bool UseColor, llvm::raw_ostream &Stream,56const FilterOptions &Filters)57: OS(Stream), IndentSpaces(Indent), CurrentIndent(0), UseColor(UseColor),58Filters(Filters) {59SetFilters(ExcludeTypeFilters, Filters.ExcludeTypes.begin(),60Filters.ExcludeTypes.end());61SetFilters(ExcludeSymbolFilters, Filters.ExcludeSymbols.begin(),62Filters.ExcludeSymbols.end());63SetFilters(ExcludeCompilandFilters, Filters.ExcludeCompilands.begin(),64Filters.ExcludeCompilands.end());6566SetFilters(IncludeTypeFilters, Filters.IncludeTypes.begin(),67Filters.IncludeTypes.end());68SetFilters(IncludeSymbolFilters, Filters.IncludeSymbols.begin(),69Filters.IncludeSymbols.end());70SetFilters(IncludeCompilandFilters, Filters.IncludeCompilands.begin(),71Filters.IncludeCompilands.end());72}7374void LinePrinter::Indent(uint32_t Amount) {75if (Amount == 0)76Amount = IndentSpaces;77CurrentIndent += Amount;78}7980void LinePrinter::Unindent(uint32_t Amount) {81if (Amount == 0)82Amount = IndentSpaces;83CurrentIndent = std::max<int>(0, CurrentIndent - Amount);84}8586void LinePrinter::NewLine() {87OS << "\n";88OS.indent(CurrentIndent);89}9091void LinePrinter::print(const Twine &T) { OS << T; }9293void LinePrinter::printLine(const Twine &T) {94NewLine();95OS << T;96}9798bool LinePrinter::IsClassExcluded(const ClassLayout &Class) {99if (IsTypeExcluded(Class.getName(), Class.getSize()))100return true;101if (Class.deepPaddingSize() < Filters.PaddingThreshold)102return true;103return false;104}105106void LinePrinter::formatBinary(StringRef Label, ArrayRef<uint8_t> Data,107uint64_t StartOffset) {108NewLine();109OS << Label << " (";110if (!Data.empty()) {111OS << "\n";112OS << format_bytes_with_ascii(Data, StartOffset, 32, 4,113CurrentIndent + IndentSpaces, true);114NewLine();115}116OS << ")";117}118119void LinePrinter::formatBinary(StringRef Label, ArrayRef<uint8_t> Data,120uint64_t Base, uint64_t StartOffset) {121NewLine();122OS << Label << " (";123if (!Data.empty()) {124OS << "\n";125Base += StartOffset;126OS << format_bytes_with_ascii(Data, Base, 32, 4,127CurrentIndent + IndentSpaces, true);128NewLine();129}130OS << ")";131}132133namespace {134struct Run {135Run() = default;136explicit Run(uint32_t Block) : Block(Block) {}137uint32_t Block = 0;138uint64_t ByteLen = 0;139};140} // namespace141142static std::vector<Run> computeBlockRuns(uint32_t BlockSize,143const msf::MSFStreamLayout &Layout) {144std::vector<Run> Runs;145if (Layout.Length == 0)146return Runs;147148ArrayRef<support::ulittle32_t> Blocks = Layout.Blocks;149assert(!Blocks.empty());150uint64_t StreamBytesRemaining = Layout.Length;151uint32_t CurrentBlock = Blocks[0];152Runs.emplace_back(CurrentBlock);153while (!Blocks.empty()) {154Run *CurrentRun = &Runs.back();155uint32_t NextBlock = Blocks.front();156if (NextBlock < CurrentBlock || (NextBlock - CurrentBlock > 1)) {157Runs.emplace_back(NextBlock);158CurrentRun = &Runs.back();159}160uint64_t Used =161std::min(static_cast<uint64_t>(BlockSize), StreamBytesRemaining);162CurrentRun->ByteLen += Used;163StreamBytesRemaining -= Used;164CurrentBlock = NextBlock;165Blocks = Blocks.drop_front();166}167return Runs;168}169170static std::pair<Run, uint64_t> findRun(uint64_t Offset, ArrayRef<Run> Runs) {171for (const auto &R : Runs) {172if (Offset < R.ByteLen)173return std::make_pair(R, Offset);174Offset -= R.ByteLen;175}176llvm_unreachable("Invalid offset!");177}178179void LinePrinter::formatMsfStreamData(StringRef Label, PDBFile &File,180uint32_t StreamIdx,181StringRef StreamPurpose, uint64_t Offset,182uint64_t Size) {183if (StreamIdx >= File.getNumStreams()) {184formatLine("Stream {0}: Not present", StreamIdx);185return;186}187if (Size + Offset > File.getStreamByteSize(StreamIdx)) {188formatLine(189"Stream {0}: Invalid offset and size, range out of stream bounds",190StreamIdx);191return;192}193194auto S = File.createIndexedStream(StreamIdx);195if (!S) {196NewLine();197formatLine("Stream {0}: Not present", StreamIdx);198return;199}200201uint64_t End =202(Size == 0) ? S->getLength() : std::min(Offset + Size, S->getLength());203Size = End - Offset;204205formatLine("Stream {0}: {1} (dumping {2:N} / {3:N} bytes)", StreamIdx,206StreamPurpose, Size, S->getLength());207AutoIndent Indent(*this);208BinaryStreamRef Slice(*S);209BinarySubstreamRef Substream;210Substream.Offset = Offset;211Substream.StreamData = Slice.drop_front(Offset).keep_front(Size);212213auto Layout = File.getStreamLayout(StreamIdx);214formatMsfStreamData(Label, File, Layout, Substream);215}216217void LinePrinter::formatMsfStreamData(StringRef Label, PDBFile &File,218const msf::MSFStreamLayout &Stream,219BinarySubstreamRef Substream) {220BinaryStreamReader Reader(Substream.StreamData);221222auto Runs = computeBlockRuns(File.getBlockSize(), Stream);223224NewLine();225OS << Label << " (";226while (Reader.bytesRemaining() > 0) {227OS << "\n";228229Run FoundRun;230uint64_t RunOffset;231std::tie(FoundRun, RunOffset) = findRun(Substream.Offset, Runs);232assert(FoundRun.ByteLen >= RunOffset);233uint64_t Len = FoundRun.ByteLen - RunOffset;234Len = std::min(Len, Reader.bytesRemaining());235uint64_t Base = FoundRun.Block * File.getBlockSize() + RunOffset;236ArrayRef<uint8_t> Data;237consumeError(Reader.readBytes(Data, Len));238OS << format_bytes_with_ascii(Data, Base, 32, 4,239CurrentIndent + IndentSpaces, true);240if (Reader.bytesRemaining() > 0) {241NewLine();242OS << formatv(" {0}",243fmt_align("<discontinuity>", AlignStyle::Center, 114, '-'));244}245Substream.Offset += Len;246}247NewLine();248OS << ")";249}250251void LinePrinter::formatMsfStreamBlocks(252PDBFile &File, const msf::MSFStreamLayout &StreamLayout) {253auto Blocks = ArrayRef(StreamLayout.Blocks);254uint64_t L = StreamLayout.Length;255256while (L > 0) {257NewLine();258assert(!Blocks.empty());259OS << formatv("Block {0} (\n", uint32_t(Blocks.front()));260uint64_t UsedBytes =261std::min(L, static_cast<uint64_t>(File.getBlockSize()));262ArrayRef<uint8_t> BlockData =263cantFail(File.getBlockData(Blocks.front(), File.getBlockSize()));264uint64_t BaseOffset = Blocks.front();265BaseOffset *= File.getBlockSize();266OS << format_bytes_with_ascii(BlockData, BaseOffset, 32, 4,267CurrentIndent + IndentSpaces, true);268NewLine();269OS << ")";270NewLine();271L -= UsedBytes;272Blocks = Blocks.drop_front();273}274}275276bool LinePrinter::IsTypeExcluded(llvm::StringRef TypeName, uint64_t Size) {277if (IsItemExcluded(TypeName, IncludeTypeFilters, ExcludeTypeFilters))278return true;279if (Size < Filters.SizeThreshold)280return true;281return false;282}283284bool LinePrinter::IsSymbolExcluded(llvm::StringRef SymbolName) {285return IsItemExcluded(SymbolName, IncludeSymbolFilters, ExcludeSymbolFilters);286}287288bool LinePrinter::IsCompilandExcluded(llvm::StringRef CompilandName) {289return IsItemExcluded(CompilandName, IncludeCompilandFilters,290ExcludeCompilandFilters);291}292293WithColor::WithColor(LinePrinter &P, PDB_ColorItem C)294: OS(P.OS), UseColor(P.hasColor()) {295if (UseColor)296applyColor(C);297}298299WithColor::~WithColor() {300if (UseColor)301OS.resetColor();302}303304void WithColor::applyColor(PDB_ColorItem C) {305switch (C) {306case PDB_ColorItem::None:307OS.resetColor();308return;309case PDB_ColorItem::Comment:310OS.changeColor(raw_ostream::GREEN, false);311return;312case PDB_ColorItem::Address:313OS.changeColor(raw_ostream::YELLOW, /*bold=*/true);314return;315case PDB_ColorItem::Keyword:316OS.changeColor(raw_ostream::MAGENTA, true);317return;318case PDB_ColorItem::Register:319case PDB_ColorItem::Offset:320OS.changeColor(raw_ostream::YELLOW, false);321return;322case PDB_ColorItem::Type:323OS.changeColor(raw_ostream::CYAN, true);324return;325case PDB_ColorItem::Identifier:326OS.changeColor(raw_ostream::CYAN, false);327return;328case PDB_ColorItem::Path:329OS.changeColor(raw_ostream::CYAN, false);330return;331case PDB_ColorItem::Padding:332case PDB_ColorItem::SectionHeader:333OS.changeColor(raw_ostream::RED, true);334return;335case PDB_ColorItem::LiteralValue:336OS.changeColor(raw_ostream::GREEN, true);337return;338}339}340341342