blob: a5f48f058593d8d567ce4453bd0ea05d514f8a7f [file] [log] [blame]
Zachary Turner2d11c202015-02-27 09:15:59 +00001//===- LinePrinter.cpp ------------------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "LinePrinter.h"
11
Zachary Turnerbd336e42017-06-09 20:46:17 +000012#include "llvm-pdbutil.h"
Zachary Turner7797c722015-03-02 04:39:56 +000013
Sanjoy Dasff3b8b42015-12-01 07:49:23 +000014#include "llvm/ADT/STLExtras.h"
Zachary Turner0b36c3e2017-06-23 18:52:13 +000015#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"
Zachary Turner4dc4f012017-04-13 21:11:00 +000019#include "llvm/DebugInfo/PDB/UDTLayout.h"
Zachary Turner0b36c3e2017-06-23 18:52:13 +000020#include "llvm/Support/BinaryStreamReader.h"
Zachary Turner63055452017-06-15 22:24:24 +000021#include "llvm/Support/Format.h"
Zachary Turner0b36c3e2017-06-23 18:52:13 +000022#include "llvm/Support/FormatAdapters.h"
23#include "llvm/Support/FormatVariadic.h"
Zachary Turnerf5abda22015-03-01 06:49:49 +000024#include "llvm/Support/Regex.h"
25
Zachary Turner2d11c202015-02-27 09:15:59 +000026#include <algorithm>
27
Zachary Turnerec28fc32016-05-04 20:32:13 +000028using namespace llvm;
Zachary Turner0b36c3e2017-06-23 18:52:13 +000029using namespace llvm::msf;
Zachary Turnerec28fc32016-05-04 20:32:13 +000030using namespace llvm::pdb;
31
Zachary Turner4dddcc62015-09-29 19:49:06 +000032namespace {
Zachary Turner4dddcc62015-09-29 19:49:06 +000033bool 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 include
42 // filters, and none of them include this item, them item is gone.
Sanjoy Dasff3b8b42015-12-01 07:49:23 +000043 if (!IncludeFilters.empty() && !any_of(IncludeFilters, match_pred))
Zachary Turner4dddcc62015-09-29 19:49:06 +000044 return true;
45
Sanjoy Dasff3b8b42015-12-01 07:49:23 +000046 if (any_of(ExcludeFilters, match_pred))
Zachary Turner4dddcc62015-09-29 19:49:06 +000047 return true;
48
49 return false;
50}
51}
52
Zachary Turner2d11c202015-02-27 09:15:59 +000053using namespace llvm;
54
Adrian McCarthy1aa207d2017-03-23 15:28:15 +000055LinePrinter::LinePrinter(int Indent, bool UseColor, llvm::raw_ostream &Stream)
56 : OS(Stream), IndentSpaces(Indent), CurrentIndent(0), UseColor(UseColor) {
Zachary Turnera30bd1a2016-06-30 17:42:48 +000057 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());
Zachary Turner4dddcc62015-09-29 19:49:06 +000063
Zachary Turnera30bd1a2016-06-30 17:42:48 +000064 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());
Zachary Turner7797c722015-03-02 04:39:56 +000070}
Zachary Turner2d11c202015-02-27 09:15:59 +000071
Zachary Turner63055452017-06-15 22:24:24 +000072void LinePrinter::Indent(uint32_t Amount) {
73 if (Amount == 0)
74 Amount = IndentSpaces;
75 CurrentIndent += Amount;
76}
Zachary Turner2d11c202015-02-27 09:15:59 +000077
Zachary Turner63055452017-06-15 22:24:24 +000078void LinePrinter::Unindent(uint32_t Amount) {
79 if (Amount == 0)
80 Amount = IndentSpaces;
81 CurrentIndent = std::max<int>(0, CurrentIndent - Amount);
Zachary Turner2d11c202015-02-27 09:15:59 +000082}
83
84void LinePrinter::NewLine() {
85 OS << "\n";
86 OS.indent(CurrentIndent);
87}
88
Zachary Turner63055452017-06-15 22:24:24 +000089void LinePrinter::print(const Twine &T) { OS << T; }
90
91void LinePrinter::printLine(const Twine &T) {
92 NewLine();
93 OS << T;
94}
95
Zachary Turner4dc4f012017-04-13 21:11:00 +000096bool LinePrinter::IsClassExcluded(const ClassLayout &Class) {
Zachary Turner16901642017-04-24 17:47:24 +000097 if (IsTypeExcluded(Class.getName(), Class.getSize()))
Zachary Turner4dc4f012017-04-13 21:11:00 +000098 return true;
99 if (Class.deepPaddingSize() < opts::pretty::PaddingThreshold)
100 return true;
101 return false;
102}
103
Zachary Turner63055452017-06-15 22:24:24 +0000104void LinePrinter::formatBinary(StringRef Label, ArrayRef<uint8_t> Data,
105 uint32_t StartOffset) {
106 NewLine();
107 OS << Label << " (";
108 if (!Data.empty()) {
109 OS << "\n";
110 OS << format_bytes_with_ascii(Data, StartOffset, 32, 4,
111 CurrentIndent + IndentSpaces, true);
112 NewLine();
113 }
114 OS << ")";
115}
116
Zachary Turner99402032017-06-22 20:58:11 +0000117void LinePrinter::formatBinary(StringRef Label, ArrayRef<uint8_t> Data,
118 uint64_t Base, uint32_t StartOffset) {
119 NewLine();
120 OS << Label << " (";
121 if (!Data.empty()) {
122 OS << "\n";
123 Base += StartOffset;
124 OS << format_bytes_with_ascii(Data, Base, 32, 4,
125 CurrentIndent + IndentSpaces, true);
126 NewLine();
127 }
128 OS << ")";
129}
130
Zachary Turner0b36c3e2017-06-23 18:52:13 +0000131namespace {
132struct Run {
133 Run() = default;
134 explicit Run(uint32_t Block) : Block(Block) {}
135 uint32_t Block = 0;
136 uint32_t ByteLen = 0;
137};
138} // namespace
139
140static std::vector<Run> computeBlockRuns(uint32_t BlockSize,
141 const msf::MSFStreamLayout &Layout) {
142 std::vector<Run> Runs;
143 if (Layout.Length == 0)
144 return Runs;
145
146 ArrayRef<support::ulittle32_t> Blocks = Layout.Blocks;
147 assert(!Blocks.empty());
148 uint32_t StreamBytesRemaining = Layout.Length;
149 Runs.emplace_back(Blocks[0]);
150 while (!Blocks.empty()) {
151 Run *CurrentRun = &Runs.back();
152 uint32_t NextBlock = Blocks.front();
153 if (NextBlock < CurrentRun->Block || (NextBlock - CurrentRun->Block > 1)) {
154 Runs.emplace_back(NextBlock);
155 CurrentRun = &Runs.back();
156 }
157
158 uint32_t Used = std::min(BlockSize, StreamBytesRemaining);
159 CurrentRun->ByteLen += Used;
160 StreamBytesRemaining -= Used;
161 Blocks = Blocks.drop_front();
162 }
163 return Runs;
164}
165
166static std::pair<Run, uint32_t> findRun(uint32_t Offset, ArrayRef<Run> Runs) {
167 for (const auto &R : Runs) {
168 if (Offset < R.ByteLen)
169 return std::make_pair(R, Offset);
170 Offset -= R.ByteLen;
171 }
172 llvm_unreachable("Invalid offset!");
173}
174
175void LinePrinter::formatMsfStreamData(StringRef Label, PDBFile &File,
176 uint32_t StreamIdx,
177 StringRef StreamPurpose, uint32_t Offset,
178 uint32_t Size) {
179 if (StreamIdx >= File.getNumStreams()) {
180 formatLine("Stream {0}: Not present", StreamIdx);
181 return;
182 }
183 if (Size + Offset > File.getStreamByteSize(StreamIdx)) {
184 formatLine(
185 "Stream {0}: Invalid offset and size, range out of stream bounds",
186 StreamIdx);
187 return;
188 }
189
190 auto S = MappedBlockStream::createIndexedStream(
191 File.getMsfLayout(), File.getMsfBuffer(), StreamIdx, File.getAllocator());
192 if (!S) {
193 NewLine();
194 formatLine("Stream {0}: Not present", StreamIdx);
195 return;
196 }
197
198 uint32_t End =
199 (Size == 0) ? S->getLength() : std::min(Offset + Size, S->getLength());
200 Size = End - Offset;
201
202 formatLine("Stream {0}: {1} (dumping {2:N} / {3:N} bytes)", StreamIdx,
203 StreamPurpose, Size, S->getLength());
204 AutoIndent Indent(*this);
205 BinaryStreamRef Slice(*S);
206 Slice = Slice.keep_front(Offset + Size);
207 BinaryStreamReader Reader(Slice);
208 consumeError(Reader.skip(Offset));
209 auto Layout = File.getStreamLayout(StreamIdx);
210 formatMsfStreamData(Label, File, Layout, Reader);
211}
212
213void LinePrinter::formatMsfStreamData(StringRef Label, PDBFile &File,
214 const msf::MSFStreamLayout &Stream,
215 BinarySubstreamRef Substream) {
216 BinaryStreamReader Reader(Substream.StreamData);
217
218 consumeError(Reader.skip(Substream.Offset));
219 formatMsfStreamData(Label, File, Stream, Reader);
220}
221
222void LinePrinter::formatMsfStreamData(StringRef Label, PDBFile &File,
223 const msf::MSFStreamLayout &Stream,
224 BinaryStreamReader &Reader) {
225 auto Runs = computeBlockRuns(File.getBlockSize(), Stream);
226
227 NewLine();
228 OS << Label << " (";
229 while (Reader.bytesRemaining() > 0) {
230 OS << "\n";
231
232 Run FoundRun;
233 uint32_t RunOffset;
234 std::tie(FoundRun, RunOffset) = findRun(Reader.getOffset(), Runs);
235 assert(FoundRun.ByteLen >= RunOffset);
236 uint32_t Len = FoundRun.ByteLen - RunOffset;
237 Len = std::min(Len, Reader.bytesRemaining());
238 uint64_t Base = FoundRun.Block * File.getBlockSize() + RunOffset;
239 ArrayRef<uint8_t> Data;
240 consumeError(Reader.readBytes(Data, Len));
241 OS << format_bytes_with_ascii(Data, Base, 32, 4,
242 CurrentIndent + IndentSpaces, true);
243 if (Reader.bytesRemaining() > 0) {
244 NewLine();
245 OS << formatv(" {0}",
246 fmt_align("<discontinuity>", AlignStyle::Center, 114, '-'));
247 }
248 }
249 NewLine();
250 OS << ")";
251}
252
Zachary Turner4dc4f012017-04-13 21:11:00 +0000253bool LinePrinter::IsTypeExcluded(llvm::StringRef TypeName, uint32_t Size) {
254 if (IsItemExcluded(TypeName, IncludeTypeFilters, ExcludeTypeFilters))
255 return true;
256 if (Size < opts::pretty::SizeThreshold)
257 return true;
258 return false;
Zachary Turnerf5abda22015-03-01 06:49:49 +0000259}
260
261bool LinePrinter::IsSymbolExcluded(llvm::StringRef SymbolName) {
Zachary Turner4dddcc62015-09-29 19:49:06 +0000262 return IsItemExcluded(SymbolName, IncludeSymbolFilters, ExcludeSymbolFilters);
Zachary Turnerf5abda22015-03-01 06:49:49 +0000263}
264
265bool LinePrinter::IsCompilandExcluded(llvm::StringRef CompilandName) {
Zachary Turner4dddcc62015-09-29 19:49:06 +0000266 return IsItemExcluded(CompilandName, IncludeCompilandFilters,
267 ExcludeCompilandFilters);
Zachary Turnerf5abda22015-03-01 06:49:49 +0000268}
269
Adrian McCarthy5fcfc2c2017-03-29 17:11:27 +0000270WithColor::WithColor(LinePrinter &P, PDB_ColorItem C)
271 : OS(P.OS), UseColor(P.hasColor()) {
272 if (UseColor)
Adrian McCarthy1aa207d2017-03-23 15:28:15 +0000273 applyColor(C);
Zachary Turner2d11c202015-02-27 09:15:59 +0000274}
275
Adrian McCarthy5fcfc2c2017-03-29 17:11:27 +0000276WithColor::~WithColor() {
277 if (UseColor)
278 OS.resetColor();
279}
Zachary Turner2d11c202015-02-27 09:15:59 +0000280
Rui Ueyamafa05aac2015-11-03 01:04:44 +0000281void WithColor::applyColor(PDB_ColorItem C) {
Zachary Turner2d11c202015-02-27 09:15:59 +0000282 switch (C) {
Rui Ueyamafa05aac2015-11-03 01:04:44 +0000283 case PDB_ColorItem::None:
284 OS.resetColor();
285 return;
Zachary Turner0c990bbe2017-04-10 19:33:29 +0000286 case PDB_ColorItem::Comment:
287 OS.changeColor(raw_ostream::GREEN, false);
288 return;
Zachary Turner2d11c202015-02-27 09:15:59 +0000289 case PDB_ColorItem::Address:
Rui Ueyamafa05aac2015-11-03 01:04:44 +0000290 OS.changeColor(raw_ostream::YELLOW, /*bold=*/true);
Zachary Turner2d11c202015-02-27 09:15:59 +0000291 return;
292 case PDB_ColorItem::Keyword:
Rui Ueyamafa05aac2015-11-03 01:04:44 +0000293 OS.changeColor(raw_ostream::MAGENTA, true);
Zachary Turner2d11c202015-02-27 09:15:59 +0000294 return;
Zachary Turner7797c722015-03-02 04:39:56 +0000295 case PDB_ColorItem::Register:
Zachary Turner2d11c202015-02-27 09:15:59 +0000296 case PDB_ColorItem::Offset:
Rui Ueyamafa05aac2015-11-03 01:04:44 +0000297 OS.changeColor(raw_ostream::YELLOW, false);
Zachary Turner2d11c202015-02-27 09:15:59 +0000298 return;
299 case PDB_ColorItem::Type:
Rui Ueyamafa05aac2015-11-03 01:04:44 +0000300 OS.changeColor(raw_ostream::CYAN, true);
Zachary Turner2d11c202015-02-27 09:15:59 +0000301 return;
302 case PDB_ColorItem::Identifier:
Rui Ueyamafa05aac2015-11-03 01:04:44 +0000303 OS.changeColor(raw_ostream::CYAN, false);
Zachary Turner2d11c202015-02-27 09:15:59 +0000304 return;
305 case PDB_ColorItem::Path:
Rui Ueyamafa05aac2015-11-03 01:04:44 +0000306 OS.changeColor(raw_ostream::CYAN, false);
Zachary Turner2d11c202015-02-27 09:15:59 +0000307 return;
Zachary Turner0c990bbe2017-04-10 19:33:29 +0000308 case PDB_ColorItem::Padding:
Zachary Turner2d11c202015-02-27 09:15:59 +0000309 case PDB_ColorItem::SectionHeader:
Rui Ueyamafa05aac2015-11-03 01:04:44 +0000310 OS.changeColor(raw_ostream::RED, true);
Zachary Turner2d11c202015-02-27 09:15:59 +0000311 return;
312 case PDB_ColorItem::LiteralValue:
Rui Ueyamafa05aac2015-11-03 01:04:44 +0000313 OS.changeColor(raw_ostream::GREEN, true);
Zachary Turner2d11c202015-02-27 09:15:59 +0000314 return;
315 }
316}