1 //===- LinePrinter.cpp ------------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "LinePrinter.h"
12 #include "llvm-pdbutil.h"
14 #include "llvm/ADT/STLExtras.h"
15 #include "llvm/DebugInfo/MSF/MSFCommon.h"
16 #include "llvm/DebugInfo/MSF/MSFStreamLayout.h"
17 #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
18 #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
19 #include "llvm/DebugInfo/PDB/UDTLayout.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"
29 using namespace llvm::msf;
30 using namespace llvm::pdb;
33 bool IsItemExcluded(llvm::StringRef Item,
34 std::list<llvm::Regex> &IncludeFilters,
35 std::list<llvm::Regex> &ExcludeFilters) {
39 auto match_pred = [Item](llvm::Regex &R) { return R.match(Item); };
41 // Include takes priority over exclude. If the user specified include
42 // filters, and none of them include this item, them item is gone.
43 if (!IncludeFilters.empty() && !any_of(IncludeFilters, match_pred))
46 if (any_of(ExcludeFilters, match_pred))
55 LinePrinter::LinePrinter(int Indent, bool UseColor, llvm::raw_ostream &Stream)
56 : OS(Stream), IndentSpaces(Indent), CurrentIndent(0), UseColor(UseColor) {
57 SetFilters(ExcludeTypeFilters, opts::pretty::ExcludeTypes.begin(),
58 opts::pretty::ExcludeTypes.end());
59 SetFilters(ExcludeSymbolFilters, opts::pretty::ExcludeSymbols.begin(),
60 opts::pretty::ExcludeSymbols.end());
61 SetFilters(ExcludeCompilandFilters, opts::pretty::ExcludeCompilands.begin(),
62 opts::pretty::ExcludeCompilands.end());
64 SetFilters(IncludeTypeFilters, opts::pretty::IncludeTypes.begin(),
65 opts::pretty::IncludeTypes.end());
66 SetFilters(IncludeSymbolFilters, opts::pretty::IncludeSymbols.begin(),
67 opts::pretty::IncludeSymbols.end());
68 SetFilters(IncludeCompilandFilters, opts::pretty::IncludeCompilands.begin(),
69 opts::pretty::IncludeCompilands.end());
72 void LinePrinter::Indent(uint32_t Amount) {
74 Amount = IndentSpaces;
75 CurrentIndent += Amount;
78 void LinePrinter::Unindent(uint32_t Amount) {
80 Amount = IndentSpaces;
81 CurrentIndent = std::max<int>(0, CurrentIndent - Amount);
84 void LinePrinter::NewLine() {
86 OS.indent(CurrentIndent);
89 void LinePrinter::print(const Twine &T) { OS << T; }
91 void LinePrinter::printLine(const Twine &T) {
96 bool LinePrinter::IsClassExcluded(const ClassLayout &Class) {
97 if (IsTypeExcluded(Class.getName(), Class.getSize()))
99 if (Class.deepPaddingSize() < opts::pretty::PaddingThreshold)
104 void LinePrinter::formatBinary(StringRef Label, ArrayRef<uint8_t> Data,
105 uint32_t StartOffset) {
110 OS << format_bytes_with_ascii(Data, StartOffset, 32, 4,
111 CurrentIndent + IndentSpaces, true);
117 void LinePrinter::formatBinary(StringRef Label, ArrayRef<uint8_t> Data,
118 uint64_t Base, uint32_t StartOffset) {
124 OS << format_bytes_with_ascii(Data, Base, 32, 4,
125 CurrentIndent + IndentSpaces, true);
134 explicit Run(uint32_t Block) : Block(Block) {}
136 uint32_t ByteLen = 0;
140 static std::vector<Run> computeBlockRuns(uint32_t BlockSize,
141 const msf::MSFStreamLayout &Layout) {
142 std::vector<Run> Runs;
143 if (Layout.Length == 0)
146 ArrayRef<support::ulittle32_t> Blocks = Layout.Blocks;
147 assert(!Blocks.empty());
148 uint32_t StreamBytesRemaining = Layout.Length;
149 uint32_t CurrentBlock = Blocks[0];
150 Runs.emplace_back(CurrentBlock);
151 while (!Blocks.empty()) {
152 Run *CurrentRun = &Runs.back();
153 uint32_t NextBlock = Blocks.front();
154 if (NextBlock < CurrentBlock || (NextBlock - CurrentBlock > 1)) {
155 Runs.emplace_back(NextBlock);
156 CurrentRun = &Runs.back();
158 uint32_t Used = std::min(BlockSize, StreamBytesRemaining);
159 CurrentRun->ByteLen += Used;
160 StreamBytesRemaining -= Used;
161 CurrentBlock = NextBlock;
162 Blocks = Blocks.drop_front();
167 static std::pair<Run, uint32_t> findRun(uint32_t Offset, ArrayRef<Run> Runs) {
168 for (const auto &R : Runs) {
169 if (Offset < R.ByteLen)
170 return std::make_pair(R, Offset);
173 llvm_unreachable("Invalid offset!");
176 void LinePrinter::formatMsfStreamData(StringRef Label, PDBFile &File,
178 StringRef StreamPurpose, uint32_t Offset,
180 if (StreamIdx >= File.getNumStreams()) {
181 formatLine("Stream {0}: Not present", StreamIdx);
184 if (Size + Offset > File.getStreamByteSize(StreamIdx)) {
186 "Stream {0}: Invalid offset and size, range out of stream bounds",
191 auto S = MappedBlockStream::createIndexedStream(
192 File.getMsfLayout(), File.getMsfBuffer(), StreamIdx, File.getAllocator());
195 formatLine("Stream {0}: Not present", StreamIdx);
200 (Size == 0) ? S->getLength() : std::min(Offset + Size, S->getLength());
203 formatLine("Stream {0}: {1} (dumping {2:N} / {3:N} bytes)", StreamIdx,
204 StreamPurpose, Size, S->getLength());
205 AutoIndent Indent(*this);
206 BinaryStreamRef Slice(*S);
207 BinarySubstreamRef Substream;
208 Substream.Offset = Offset;
209 Substream.StreamData = Slice.drop_front(Offset).keep_front(Size);
211 auto Layout = File.getStreamLayout(StreamIdx);
212 formatMsfStreamData(Label, File, Layout, Substream);
215 void LinePrinter::formatMsfStreamData(StringRef Label, PDBFile &File,
216 const msf::MSFStreamLayout &Stream,
217 BinarySubstreamRef Substream) {
218 BinaryStreamReader Reader(Substream.StreamData);
220 auto Runs = computeBlockRuns(File.getBlockSize(), Stream);
224 while (Reader.bytesRemaining() > 0) {
229 std::tie(FoundRun, RunOffset) = findRun(Substream.Offset, Runs);
230 assert(FoundRun.ByteLen >= RunOffset);
231 uint32_t Len = FoundRun.ByteLen - RunOffset;
232 Len = std::min(Len, Reader.bytesRemaining());
233 uint64_t Base = FoundRun.Block * File.getBlockSize() + RunOffset;
234 ArrayRef<uint8_t> Data;
235 consumeError(Reader.readBytes(Data, Len));
236 OS << format_bytes_with_ascii(Data, Base, 32, 4,
237 CurrentIndent + IndentSpaces, true);
238 if (Reader.bytesRemaining() > 0) {
240 OS << formatv(" {0}",
241 fmt_align("<discontinuity>", AlignStyle::Center, 114, '-'));
243 Substream.Offset += Len;
249 bool LinePrinter::IsTypeExcluded(llvm::StringRef TypeName, uint32_t Size) {
250 if (IsItemExcluded(TypeName, IncludeTypeFilters, ExcludeTypeFilters))
252 if (Size < opts::pretty::SizeThreshold)
257 bool LinePrinter::IsSymbolExcluded(llvm::StringRef SymbolName) {
258 return IsItemExcluded(SymbolName, IncludeSymbolFilters, ExcludeSymbolFilters);
261 bool LinePrinter::IsCompilandExcluded(llvm::StringRef CompilandName) {
262 return IsItemExcluded(CompilandName, IncludeCompilandFilters,
263 ExcludeCompilandFilters);
266 WithColor::WithColor(LinePrinter &P, PDB_ColorItem C)
267 : OS(P.OS), UseColor(P.hasColor()) {
272 WithColor::~WithColor() {
277 void WithColor::applyColor(PDB_ColorItem C) {
279 case PDB_ColorItem::None:
282 case PDB_ColorItem::Comment:
283 OS.changeColor(raw_ostream::GREEN, false);
285 case PDB_ColorItem::Address:
286 OS.changeColor(raw_ostream::YELLOW, /*bold=*/true);
288 case PDB_ColorItem::Keyword:
289 OS.changeColor(raw_ostream::MAGENTA, true);
291 case PDB_ColorItem::Register:
292 case PDB_ColorItem::Offset:
293 OS.changeColor(raw_ostream::YELLOW, false);
295 case PDB_ColorItem::Type:
296 OS.changeColor(raw_ostream::CYAN, true);
298 case PDB_ColorItem::Identifier:
299 OS.changeColor(raw_ostream::CYAN, false);
301 case PDB_ColorItem::Path:
302 OS.changeColor(raw_ostream::CYAN, false);
304 case PDB_ColorItem::Padding:
305 case PDB_ColorItem::SectionHeader:
306 OS.changeColor(raw_ostream::RED, true);
308 case PDB_ColorItem::LiteralValue:
309 OS.changeColor(raw_ostream::GREEN, true);