diff options
Diffstat (limited to 'llvm/tools/llvm-pdbutil/LinePrinter.cpp')
| -rw-r--r-- | llvm/tools/llvm-pdbutil/LinePrinter.cpp | 333 | 
1 files changed, 333 insertions, 0 deletions
diff --git a/llvm/tools/llvm-pdbutil/LinePrinter.cpp b/llvm/tools/llvm-pdbutil/LinePrinter.cpp new file mode 100644 index 000000000000..280c000bd65f --- /dev/null +++ b/llvm/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; +  } +}  | 
