340 lines · cpp
1//===- LinePrinter.cpp ------------------------------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/DebugInfo/PDB/Native/LinePrinter.h"10 11#include "llvm/ADT/STLExtras.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"25 26#include <algorithm>27 28using namespace llvm;29using namespace llvm::msf;30using namespace llvm::pdb;31 32namespace {33bool IsItemExcluded(llvm::StringRef Item,34 std::list<llvm::Regex> &IncludeFilters,35 std::list<llvm::Regex> &ExcludeFilters) {36 if (Item.empty())37 return false;38 39 auto match_pred = [Item](llvm::Regex &R) { return R.match(Item); };40 41 // Include takes priority over exclude. If the user specified include42 // filters, and none of them include this item, them item is gone.43 if (!IncludeFilters.empty() && !any_of(IncludeFilters, match_pred))44 return true;45 46 if (any_of(ExcludeFilters, match_pred))47 return true;48 49 return false;50}51} // namespace52 53using namespace llvm;54 55LinePrinter::LinePrinter(int Indent, bool UseColor, llvm::raw_ostream &Stream,56 const FilterOptions &Filters)57 : OS(Stream), IndentSpaces(Indent), CurrentIndent(0), UseColor(UseColor),58 Filters(Filters) {59 SetFilters(ExcludeTypeFilters, Filters.ExcludeTypes.begin(),60 Filters.ExcludeTypes.end());61 SetFilters(ExcludeSymbolFilters, Filters.ExcludeSymbols.begin(),62 Filters.ExcludeSymbols.end());63 SetFilters(ExcludeCompilandFilters, Filters.ExcludeCompilands.begin(),64 Filters.ExcludeCompilands.end());65 66 SetFilters(IncludeTypeFilters, Filters.IncludeTypes.begin(),67 Filters.IncludeTypes.end());68 SetFilters(IncludeSymbolFilters, Filters.IncludeSymbols.begin(),69 Filters.IncludeSymbols.end());70 SetFilters(IncludeCompilandFilters, Filters.IncludeCompilands.begin(),71 Filters.IncludeCompilands.end());72}73 74void LinePrinter::Indent(uint32_t Amount) {75 if (Amount == 0)76 Amount = IndentSpaces;77 CurrentIndent += Amount;78}79 80void LinePrinter::Unindent(uint32_t Amount) {81 if (Amount == 0)82 Amount = IndentSpaces;83 CurrentIndent = std::max<int>(0, CurrentIndent - Amount);84}85 86void LinePrinter::NewLine() {87 OS << "\n";88 OS.indent(CurrentIndent);89}90 91void LinePrinter::print(const Twine &T) { OS << T; }92 93void LinePrinter::printLine(const Twine &T) {94 NewLine();95 OS << T;96}97 98bool LinePrinter::IsClassExcluded(const ClassLayout &Class) {99 if (IsTypeExcluded(Class.getName(), Class.getSize()))100 return true;101 if (Class.deepPaddingSize() < Filters.PaddingThreshold)102 return true;103 return false;104}105 106void LinePrinter::formatBinary(StringRef Label, ArrayRef<uint8_t> Data,107 uint64_t StartOffset) {108 NewLine();109 OS << Label << " (";110 if (!Data.empty()) {111 OS << "\n";112 OS << format_bytes_with_ascii(Data, StartOffset, 32, 4,113 CurrentIndent + IndentSpaces, true);114 NewLine();115 }116 OS << ")";117}118 119void LinePrinter::formatBinary(StringRef Label, ArrayRef<uint8_t> Data,120 uint64_t Base, uint64_t StartOffset) {121 NewLine();122 OS << Label << " (";123 if (!Data.empty()) {124 OS << "\n";125 Base += StartOffset;126 OS << format_bytes_with_ascii(Data, Base, 32, 4,127 CurrentIndent + IndentSpaces, true);128 NewLine();129 }130 OS << ")";131}132 133namespace {134struct Run {135 Run() = default;136 explicit Run(uint32_t Block) : Block(Block) {}137 uint32_t Block = 0;138 uint64_t ByteLen = 0;139};140} // namespace141 142static std::vector<Run> computeBlockRuns(uint32_t BlockSize,143 const msf::MSFStreamLayout &Layout) {144 std::vector<Run> Runs;145 if (Layout.Length == 0)146 return Runs;147 148 ArrayRef<support::ulittle32_t> Blocks = Layout.Blocks;149 assert(!Blocks.empty());150 uint64_t StreamBytesRemaining = Layout.Length;151 uint32_t CurrentBlock = Blocks[0];152 Runs.emplace_back(CurrentBlock);153 while (!Blocks.empty()) {154 Run *CurrentRun = &Runs.back();155 uint32_t NextBlock = Blocks.front();156 if (NextBlock < CurrentBlock || (NextBlock - CurrentBlock > 1)) {157 Runs.emplace_back(NextBlock);158 CurrentRun = &Runs.back();159 }160 uint64_t Used =161 std::min(static_cast<uint64_t>(BlockSize), StreamBytesRemaining);162 CurrentRun->ByteLen += Used;163 StreamBytesRemaining -= Used;164 CurrentBlock = NextBlock;165 Blocks = Blocks.drop_front();166 }167 return Runs;168}169 170static std::pair<Run, uint64_t> findRun(uint64_t Offset, ArrayRef<Run> Runs) {171 for (const auto &R : Runs) {172 if (Offset < R.ByteLen)173 return std::make_pair(R, Offset);174 Offset -= R.ByteLen;175 }176 llvm_unreachable("Invalid offset!");177}178 179void LinePrinter::formatMsfStreamData(StringRef Label, PDBFile &File,180 uint32_t StreamIdx,181 StringRef StreamPurpose, uint64_t Offset,182 uint64_t Size) {183 if (StreamIdx >= File.getNumStreams()) {184 formatLine("Stream {0}: Not present", StreamIdx);185 return;186 }187 if (Size + Offset > File.getStreamByteSize(StreamIdx)) {188 formatLine(189 "Stream {0}: Invalid offset and size, range out of stream bounds",190 StreamIdx);191 return;192 }193 194 auto S = File.createIndexedStream(StreamIdx);195 if (!S) {196 NewLine();197 formatLine("Stream {0}: Not present", StreamIdx);198 return;199 }200 201 uint64_t End =202 (Size == 0) ? S->getLength() : std::min(Offset + Size, S->getLength());203 Size = End - Offset;204 205 formatLine("Stream {0}: {1} (dumping {2:N} / {3:N} bytes)", StreamIdx,206 StreamPurpose, Size, S->getLength());207 AutoIndent Indent(*this);208 BinaryStreamRef Slice(*S);209 BinarySubstreamRef Substream;210 Substream.Offset = Offset;211 Substream.StreamData = Slice.drop_front(Offset).keep_front(Size);212 213 auto Layout = File.getStreamLayout(StreamIdx);214 formatMsfStreamData(Label, File, Layout, Substream);215}216 217void LinePrinter::formatMsfStreamData(StringRef Label, PDBFile &File,218 const msf::MSFStreamLayout &Stream,219 BinarySubstreamRef Substream) {220 BinaryStreamReader Reader(Substream.StreamData);221 222 auto Runs = computeBlockRuns(File.getBlockSize(), Stream);223 224 NewLine();225 OS << Label << " (";226 while (Reader.bytesRemaining() > 0) {227 OS << "\n";228 229 Run FoundRun;230 uint64_t RunOffset;231 std::tie(FoundRun, RunOffset) = findRun(Substream.Offset, Runs);232 assert(FoundRun.ByteLen >= RunOffset);233 uint64_t Len = FoundRun.ByteLen - RunOffset;234 Len = std::min(Len, Reader.bytesRemaining());235 uint64_t Base = FoundRun.Block * File.getBlockSize() + RunOffset;236 ArrayRef<uint8_t> Data;237 consumeError(Reader.readBytes(Data, Len));238 OS << format_bytes_with_ascii(Data, Base, 32, 4,239 CurrentIndent + IndentSpaces, true);240 if (Reader.bytesRemaining() > 0) {241 NewLine();242 OS << formatv(" {0}",243 fmt_align("<discontinuity>", AlignStyle::Center, 114, '-'));244 }245 Substream.Offset += Len;246 }247 NewLine();248 OS << ")";249}250 251void LinePrinter::formatMsfStreamBlocks(252 PDBFile &File, const msf::MSFStreamLayout &StreamLayout) {253 auto Blocks = ArrayRef(StreamLayout.Blocks);254 uint64_t L = StreamLayout.Length;255 256 while (L > 0) {257 NewLine();258 assert(!Blocks.empty());259 OS << formatv("Block {0} (\n", uint32_t(Blocks.front()));260 uint64_t UsedBytes =261 std::min(L, static_cast<uint64_t>(File.getBlockSize()));262 ArrayRef<uint8_t> BlockData =263 cantFail(File.getBlockData(Blocks.front(), File.getBlockSize()));264 uint64_t BaseOffset = Blocks.front();265 BaseOffset *= File.getBlockSize();266 OS << format_bytes_with_ascii(BlockData, BaseOffset, 32, 4,267 CurrentIndent + IndentSpaces, true);268 NewLine();269 OS << ")";270 NewLine();271 L -= UsedBytes;272 Blocks = Blocks.drop_front();273 }274}275 276bool LinePrinter::IsTypeExcluded(llvm::StringRef TypeName, uint64_t Size) {277 if (IsItemExcluded(TypeName, IncludeTypeFilters, ExcludeTypeFilters))278 return true;279 if (Size < Filters.SizeThreshold)280 return true;281 return false;282}283 284bool LinePrinter::IsSymbolExcluded(llvm::StringRef SymbolName) {285 return IsItemExcluded(SymbolName, IncludeSymbolFilters, ExcludeSymbolFilters);286}287 288bool LinePrinter::IsCompilandExcluded(llvm::StringRef CompilandName) {289 return IsItemExcluded(CompilandName, IncludeCompilandFilters,290 ExcludeCompilandFilters);291}292 293WithColor::WithColor(LinePrinter &P, PDB_ColorItem C)294 : OS(P.OS), UseColor(P.hasColor()) {295 if (UseColor)296 applyColor(C);297}298 299WithColor::~WithColor() {300 if (UseColor)301 OS.resetColor();302}303 304void WithColor::applyColor(PDB_ColorItem C) {305 switch (C) {306 case PDB_ColorItem::None:307 OS.resetColor();308 return;309 case PDB_ColorItem::Comment:310 OS.changeColor(raw_ostream::GREEN, false);311 return;312 case PDB_ColorItem::Address:313 OS.changeColor(raw_ostream::YELLOW, /*bold=*/true);314 return;315 case PDB_ColorItem::Keyword:316 OS.changeColor(raw_ostream::MAGENTA, true);317 return;318 case PDB_ColorItem::Register:319 case PDB_ColorItem::Offset:320 OS.changeColor(raw_ostream::YELLOW, false);321 return;322 case PDB_ColorItem::Type:323 OS.changeColor(raw_ostream::CYAN, true);324 return;325 case PDB_ColorItem::Identifier:326 OS.changeColor(raw_ostream::CYAN, false);327 return;328 case PDB_ColorItem::Path:329 OS.changeColor(raw_ostream::CYAN, false);330 return;331 case PDB_ColorItem::Padding:332 case PDB_ColorItem::SectionHeader:333 OS.changeColor(raw_ostream::RED, true);334 return;335 case PDB_ColorItem::LiteralValue:336 OS.changeColor(raw_ostream::GREEN, true);337 return;338 }339}340