blob: e80a1762450b9d85c34660dddc1d9a304f5c9b29 [file] [log] [blame]
Zachary Turner756b8232015-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 Turnercfb13562017-06-09 20:46:17 +000012#include "llvm-pdbutil.h"
Zachary Turner0c7c98a2015-03-02 04:39:56 +000013
Sanjoy Dasb1ce35c2015-12-01 07:49:23 +000014#include "llvm/ADT/STLExtras.h"
Zachary Turner35abb612017-06-23 18:52:13 +000015#include "llvm/DebugInfo/MSF/MSFCommon.h"
Zachary Turner35abb612017-06-23 18:52:13 +000016#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
17#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
Zachary Turner10683342017-04-13 21:11:00 +000018#include "llvm/DebugInfo/PDB/UDTLayout.h"
Zachary Turner35abb612017-06-23 18:52:13 +000019#include "llvm/Support/BinaryStreamReader.h"
Zachary Turner7e5d31e2017-06-15 22:24:24 +000020#include "llvm/Support/Format.h"
Zachary Turner35abb612017-06-23 18:52:13 +000021#include "llvm/Support/FormatAdapters.h"
22#include "llvm/Support/FormatVariadic.h"
Zachary Turner91491392015-03-01 06:49:49 +000023#include "llvm/Support/Regex.h"
24
Zachary Turner756b8232015-02-27 09:15:59 +000025#include <algorithm>
26
Zachary Turnerc95df942016-05-04 20:32:13 +000027using namespace llvm;
Zachary Turner35abb612017-06-23 18:52:13 +000028using namespace llvm::msf;
Zachary Turnerc95df942016-05-04 20:32:13 +000029using namespace llvm::pdb;
30
Zachary Turnerc9736fb2015-09-29 19:49:06 +000031namespace {
Zachary Turnerc9736fb2015-09-29 19:49:06 +000032bool IsItemExcluded(llvm::StringRef Item,
33 std::list<llvm::Regex> &IncludeFilters,
34 std::list<llvm::Regex> &ExcludeFilters) {
35 if (Item.empty())
36 return false;
37
38 auto match_pred = [Item](llvm::Regex &R) { return R.match(Item); };
39
40 // Include takes priority over exclude. If the user specified include
41 // filters, and none of them include this item, them item is gone.
Sanjoy Dasb1ce35c2015-12-01 07:49:23 +000042 if (!IncludeFilters.empty() && !any_of(IncludeFilters, match_pred))
Zachary Turnerc9736fb2015-09-29 19:49:06 +000043 return true;
44
Sanjoy Dasb1ce35c2015-12-01 07:49:23 +000045 if (any_of(ExcludeFilters, match_pred))
Zachary Turnerc9736fb2015-09-29 19:49:06 +000046 return true;
47
48 return false;
49}
50}
51
Zachary Turner756b8232015-02-27 09:15:59 +000052using namespace llvm;
53
Adrian McCarthy99f73dd2017-03-23 15:28:15 +000054LinePrinter::LinePrinter(int Indent, bool UseColor, llvm::raw_ostream &Stream)
55 : OS(Stream), IndentSpaces(Indent), CurrentIndent(0), UseColor(UseColor) {
Zachary Turner3a4681d2016-06-30 17:42:48 +000056 SetFilters(ExcludeTypeFilters, opts::pretty::ExcludeTypes.begin(),
57 opts::pretty::ExcludeTypes.end());
58 SetFilters(ExcludeSymbolFilters, opts::pretty::ExcludeSymbols.begin(),
59 opts::pretty::ExcludeSymbols.end());
60 SetFilters(ExcludeCompilandFilters, opts::pretty::ExcludeCompilands.begin(),
61 opts::pretty::ExcludeCompilands.end());
Zachary Turnerc9736fb2015-09-29 19:49:06 +000062
Zachary Turner3a4681d2016-06-30 17:42:48 +000063 SetFilters(IncludeTypeFilters, opts::pretty::IncludeTypes.begin(),
64 opts::pretty::IncludeTypes.end());
65 SetFilters(IncludeSymbolFilters, opts::pretty::IncludeSymbols.begin(),
66 opts::pretty::IncludeSymbols.end());
67 SetFilters(IncludeCompilandFilters, opts::pretty::IncludeCompilands.begin(),
68 opts::pretty::IncludeCompilands.end());
Zachary Turner0c7c98a2015-03-02 04:39:56 +000069}
Zachary Turner756b8232015-02-27 09:15:59 +000070
Zachary Turner7e5d31e2017-06-15 22:24:24 +000071void LinePrinter::Indent(uint32_t Amount) {
72 if (Amount == 0)
73 Amount = IndentSpaces;
74 CurrentIndent += Amount;
75}
Zachary Turner756b8232015-02-27 09:15:59 +000076
Zachary Turner7e5d31e2017-06-15 22:24:24 +000077void LinePrinter::Unindent(uint32_t Amount) {
78 if (Amount == 0)
79 Amount = IndentSpaces;
80 CurrentIndent = std::max<int>(0, CurrentIndent - Amount);
Zachary Turner756b8232015-02-27 09:15:59 +000081}
82
83void LinePrinter::NewLine() {
84 OS << "\n";
85 OS.indent(CurrentIndent);
86}
87
Zachary Turner7e5d31e2017-06-15 22:24:24 +000088void LinePrinter::print(const Twine &T) { OS << T; }
89
90void LinePrinter::printLine(const Twine &T) {
91 NewLine();
92 OS << T;
93}
94
Zachary Turner10683342017-04-13 21:11:00 +000095bool LinePrinter::IsClassExcluded(const ClassLayout &Class) {
Zachary Turner0e8b7072017-04-24 17:47:24 +000096 if (IsTypeExcluded(Class.getName(), Class.getSize()))
Zachary Turner10683342017-04-13 21:11:00 +000097 return true;
98 if (Class.deepPaddingSize() < opts::pretty::PaddingThreshold)
99 return true;
100 return false;
101}
102
Zachary Turner7e5d31e2017-06-15 22:24:24 +0000103void LinePrinter::formatBinary(StringRef Label, ArrayRef<uint8_t> Data,
104 uint32_t StartOffset) {
105 NewLine();
106 OS << Label << " (";
107 if (!Data.empty()) {
108 OS << "\n";
109 OS << format_bytes_with_ascii(Data, StartOffset, 32, 4,
110 CurrentIndent + IndentSpaces, true);
111 NewLine();
112 }
113 OS << ")";
114}
115
Zachary Turner08bb54f2017-06-22 20:58:11 +0000116void LinePrinter::formatBinary(StringRef Label, ArrayRef<uint8_t> Data,
117 uint64_t Base, uint32_t StartOffset) {
118 NewLine();
119 OS << Label << " (";
120 if (!Data.empty()) {
121 OS << "\n";
122 Base += StartOffset;
123 OS << format_bytes_with_ascii(Data, Base, 32, 4,
124 CurrentIndent + IndentSpaces, true);
125 NewLine();
126 }
127 OS << ")";
128}
129
Zachary Turner35abb612017-06-23 18:52:13 +0000130namespace {
131struct Run {
132 Run() = default;
133 explicit Run(uint32_t Block) : Block(Block) {}
134 uint32_t Block = 0;
135 uint32_t ByteLen = 0;
136};
137} // namespace
138
139static std::vector<Run> computeBlockRuns(uint32_t BlockSize,
140 const msf::MSFStreamLayout &Layout) {
141 std::vector<Run> Runs;
142 if (Layout.Length == 0)
143 return Runs;
144
145 ArrayRef<support::ulittle32_t> Blocks = Layout.Blocks;
146 assert(!Blocks.empty());
147 uint32_t StreamBytesRemaining = Layout.Length;
Zachary Turner777bbb52017-06-23 21:11:54 +0000148 uint32_t CurrentBlock = Blocks[0];
149 Runs.emplace_back(CurrentBlock);
Zachary Turner35abb612017-06-23 18:52:13 +0000150 while (!Blocks.empty()) {
151 Run *CurrentRun = &Runs.back();
152 uint32_t NextBlock = Blocks.front();
Zachary Turner777bbb52017-06-23 21:11:54 +0000153 if (NextBlock < CurrentBlock || (NextBlock - CurrentBlock > 1)) {
Zachary Turner35abb612017-06-23 18:52:13 +0000154 Runs.emplace_back(NextBlock);
155 CurrentRun = &Runs.back();
156 }
Zachary Turner35abb612017-06-23 18:52:13 +0000157 uint32_t Used = std::min(BlockSize, StreamBytesRemaining);
158 CurrentRun->ByteLen += Used;
159 StreamBytesRemaining -= Used;
Zachary Turner777bbb52017-06-23 21:11:54 +0000160 CurrentBlock = NextBlock;
Zachary Turner35abb612017-06-23 18:52:13 +0000161 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);
Zachary Turnera77c3fd2017-06-23 20:18:38 +0000206 BinarySubstreamRef Substream;
207 Substream.Offset = Offset;
208 Substream.StreamData = Slice.drop_front(Offset).keep_front(Size);
209
Zachary Turner35abb612017-06-23 18:52:13 +0000210 auto Layout = File.getStreamLayout(StreamIdx);
Zachary Turnera77c3fd2017-06-23 20:18:38 +0000211 formatMsfStreamData(Label, File, Layout, Substream);
Zachary Turner35abb612017-06-23 18:52:13 +0000212}
213
214void LinePrinter::formatMsfStreamData(StringRef Label, PDBFile &File,
215 const msf::MSFStreamLayout &Stream,
216 BinarySubstreamRef Substream) {
217 BinaryStreamReader Reader(Substream.StreamData);
218
Zachary Turner35abb612017-06-23 18:52:13 +0000219 auto Runs = computeBlockRuns(File.getBlockSize(), Stream);
220
221 NewLine();
222 OS << Label << " (";
223 while (Reader.bytesRemaining() > 0) {
224 OS << "\n";
225
226 Run FoundRun;
227 uint32_t RunOffset;
Zachary Turnera77c3fd2017-06-23 20:18:38 +0000228 std::tie(FoundRun, RunOffset) = findRun(Substream.Offset, Runs);
Zachary Turner35abb612017-06-23 18:52:13 +0000229 assert(FoundRun.ByteLen >= RunOffset);
230 uint32_t Len = FoundRun.ByteLen - RunOffset;
231 Len = std::min(Len, Reader.bytesRemaining());
232 uint64_t Base = FoundRun.Block * File.getBlockSize() + RunOffset;
233 ArrayRef<uint8_t> Data;
234 consumeError(Reader.readBytes(Data, Len));
235 OS << format_bytes_with_ascii(Data, Base, 32, 4,
236 CurrentIndent + IndentSpaces, true);
237 if (Reader.bytesRemaining() > 0) {
238 NewLine();
239 OS << formatv(" {0}",
240 fmt_align("<discontinuity>", AlignStyle::Center, 114, '-'));
241 }
Zachary Turnera77c3fd2017-06-23 20:18:38 +0000242 Substream.Offset += Len;
Zachary Turner35abb612017-06-23 18:52:13 +0000243 }
244 NewLine();
245 OS << ")";
246}
247
Zachary Turner34173de2017-08-02 22:25:52 +0000248void LinePrinter::formatMsfStreamBlocks(
249 PDBFile &File, const msf::MSFStreamLayout &StreamLayout) {
250 auto Blocks = makeArrayRef(StreamLayout.Blocks);
251 uint32_t L = StreamLayout.Length;
252
253 while (L > 0) {
254 NewLine();
255 assert(!Blocks.empty());
256 OS << formatv("Block {0} (\n", uint32_t(Blocks.front()));
257 uint32_t UsedBytes = std::min(L, File.getBlockSize());
258 ArrayRef<uint8_t> BlockData =
259 cantFail(File.getBlockData(Blocks.front(), File.getBlockSize()));
260 uint64_t BaseOffset = Blocks.front();
261 BaseOffset *= File.getBlockSize();
262 OS << format_bytes_with_ascii(BlockData, BaseOffset, 32, 4,
263 CurrentIndent + IndentSpaces, true);
264 NewLine();
265 OS << ")";
266 NewLine();
267 L -= UsedBytes;
268 Blocks = Blocks.drop_front();
269 }
270}
271
Zachary Turner10683342017-04-13 21:11:00 +0000272bool LinePrinter::IsTypeExcluded(llvm::StringRef TypeName, uint32_t Size) {
273 if (IsItemExcluded(TypeName, IncludeTypeFilters, ExcludeTypeFilters))
274 return true;
275 if (Size < opts::pretty::SizeThreshold)
276 return true;
277 return false;
Zachary Turner91491392015-03-01 06:49:49 +0000278}
279
280bool LinePrinter::IsSymbolExcluded(llvm::StringRef SymbolName) {
Zachary Turnerc9736fb2015-09-29 19:49:06 +0000281 return IsItemExcluded(SymbolName, IncludeSymbolFilters, ExcludeSymbolFilters);
Zachary Turner91491392015-03-01 06:49:49 +0000282}
283
284bool LinePrinter::IsCompilandExcluded(llvm::StringRef CompilandName) {
Zachary Turnerc9736fb2015-09-29 19:49:06 +0000285 return IsItemExcluded(CompilandName, IncludeCompilandFilters,
286 ExcludeCompilandFilters);
Zachary Turner91491392015-03-01 06:49:49 +0000287}
288
Adrian McCarthyebe3d552017-03-29 17:11:27 +0000289WithColor::WithColor(LinePrinter &P, PDB_ColorItem C)
290 : OS(P.OS), UseColor(P.hasColor()) {
291 if (UseColor)
Adrian McCarthy99f73dd2017-03-23 15:28:15 +0000292 applyColor(C);
Zachary Turner756b8232015-02-27 09:15:59 +0000293}
294
Adrian McCarthyebe3d552017-03-29 17:11:27 +0000295WithColor::~WithColor() {
296 if (UseColor)
297 OS.resetColor();
298}
Zachary Turner756b8232015-02-27 09:15:59 +0000299
Rui Ueyama55861d02015-11-03 01:04:44 +0000300void WithColor::applyColor(PDB_ColorItem C) {
Zachary Turner756b8232015-02-27 09:15:59 +0000301 switch (C) {
Rui Ueyama55861d02015-11-03 01:04:44 +0000302 case PDB_ColorItem::None:
303 OS.resetColor();
304 return;
Zachary Turnere98c9132017-04-10 19:33:29 +0000305 case PDB_ColorItem::Comment:
306 OS.changeColor(raw_ostream::GREEN, false);
307 return;
Zachary Turner756b8232015-02-27 09:15:59 +0000308 case PDB_ColorItem::Address:
Rui Ueyama55861d02015-11-03 01:04:44 +0000309 OS.changeColor(raw_ostream::YELLOW, /*bold=*/true);
Zachary Turner756b8232015-02-27 09:15:59 +0000310 return;
311 case PDB_ColorItem::Keyword:
Rui Ueyama55861d02015-11-03 01:04:44 +0000312 OS.changeColor(raw_ostream::MAGENTA, true);
Zachary Turner756b8232015-02-27 09:15:59 +0000313 return;
Zachary Turner0c7c98a2015-03-02 04:39:56 +0000314 case PDB_ColorItem::Register:
Zachary Turner756b8232015-02-27 09:15:59 +0000315 case PDB_ColorItem::Offset:
Rui Ueyama55861d02015-11-03 01:04:44 +0000316 OS.changeColor(raw_ostream::YELLOW, false);
Zachary Turner756b8232015-02-27 09:15:59 +0000317 return;
318 case PDB_ColorItem::Type:
Rui Ueyama55861d02015-11-03 01:04:44 +0000319 OS.changeColor(raw_ostream::CYAN, true);
Zachary Turner756b8232015-02-27 09:15:59 +0000320 return;
321 case PDB_ColorItem::Identifier:
Rui Ueyama55861d02015-11-03 01:04:44 +0000322 OS.changeColor(raw_ostream::CYAN, false);
Zachary Turner756b8232015-02-27 09:15:59 +0000323 return;
324 case PDB_ColorItem::Path:
Rui Ueyama55861d02015-11-03 01:04:44 +0000325 OS.changeColor(raw_ostream::CYAN, false);
Zachary Turner756b8232015-02-27 09:15:59 +0000326 return;
Zachary Turnere98c9132017-04-10 19:33:29 +0000327 case PDB_ColorItem::Padding:
Zachary Turner756b8232015-02-27 09:15:59 +0000328 case PDB_ColorItem::SectionHeader:
Rui Ueyama55861d02015-11-03 01:04:44 +0000329 OS.changeColor(raw_ostream::RED, true);
Zachary Turner756b8232015-02-27 09:15:59 +0000330 return;
331 case PDB_ColorItem::LiteralValue:
Rui Ueyama55861d02015-11-03 01:04:44 +0000332 OS.changeColor(raw_ostream::GREEN, true);
Zachary Turner756b8232015-02-27 09:15:59 +0000333 return;
334 }
335}