121
|
1 //===- 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
|
|
12 #include "llvm-pdbutil.h"
|
|
13
|
|
14 #include "llvm/ADT/STLExtras.h"
|
|
15 #include "llvm/DebugInfo/MSF/MSFCommon.h"
|
|
16 #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
|
|
17 #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
|
|
18 #include "llvm/DebugInfo/PDB/UDTLayout.h"
|
|
19 #include "llvm/Support/BinaryStreamReader.h"
|
|
20 #include "llvm/Support/Format.h"
|
|
21 #include "llvm/Support/FormatAdapters.h"
|
|
22 #include "llvm/Support/FormatVariadic.h"
|
|
23 #include "llvm/Support/Regex.h"
|
|
24
|
|
25 #include <algorithm>
|
|
26
|
|
27 using namespace llvm;
|
|
28 using namespace llvm::msf;
|
|
29 using namespace llvm::pdb;
|
|
30
|
|
31 namespace {
|
|
32 bool 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.
|
|
42 if (!IncludeFilters.empty() && !any_of(IncludeFilters, match_pred))
|
|
43 return true;
|
|
44
|
|
45 if (any_of(ExcludeFilters, match_pred))
|
|
46 return true;
|
|
47
|
|
48 return false;
|
|
49 }
|
|
50 }
|
|
51
|
|
52 using namespace llvm;
|
|
53
|
|
54 LinePrinter::LinePrinter(int Indent, bool UseColor, llvm::raw_ostream &Stream)
|
|
55 : OS(Stream), IndentSpaces(Indent), CurrentIndent(0), UseColor(UseColor) {
|
|
56 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());
|
|
62
|
|
63 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());
|
|
69 }
|
|
70
|
|
71 void LinePrinter::Indent(uint32_t Amount) {
|
|
72 if (Amount == 0)
|
|
73 Amount = IndentSpaces;
|
|
74 CurrentIndent += Amount;
|
|
75 }
|
|
76
|
|
77 void LinePrinter::Unindent(uint32_t Amount) {
|
|
78 if (Amount == 0)
|
|
79 Amount = IndentSpaces;
|
|
80 CurrentIndent = std::max<int>(0, CurrentIndent - Amount);
|
|
81 }
|
|
82
|
|
83 void LinePrinter::NewLine() {
|
|
84 OS << "\n";
|
|
85 OS.indent(CurrentIndent);
|
|
86 }
|
|
87
|
|
88 void LinePrinter::print(const Twine &T) { OS << T; }
|
|
89
|
|
90 void LinePrinter::printLine(const Twine &T) {
|
|
91 NewLine();
|
|
92 OS << T;
|
|
93 }
|
|
94
|
|
95 bool LinePrinter::IsClassExcluded(const ClassLayout &Class) {
|
|
96 if (IsTypeExcluded(Class.getName(), Class.getSize()))
|
|
97 return true;
|
|
98 if (Class.deepPaddingSize() < opts::pretty::PaddingThreshold)
|
|
99 return true;
|
|
100 return false;
|
|
101 }
|
|
102
|
|
103 void 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
|
|
116 void 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
|
|
130 namespace {
|
|
131 struct 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
|
|
139 static 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;
|
|
148 uint32_t CurrentBlock = Blocks[0];
|
|
149 Runs.emplace_back(CurrentBlock);
|
|
150 while (!Blocks.empty()) {
|
|
151 Run *CurrentRun = &Runs.back();
|
|
152 uint32_t NextBlock = Blocks.front();
|
|
153 if (NextBlock < CurrentBlock || (NextBlock - CurrentBlock > 1)) {
|
|
154 Runs.emplace_back(NextBlock);
|
|
155 CurrentRun = &Runs.back();
|
|
156 }
|
|
157 uint32_t Used = std::min(BlockSize, StreamBytesRemaining);
|
|
158 CurrentRun->ByteLen += Used;
|
|
159 StreamBytesRemaining -= Used;
|
|
160 CurrentBlock = NextBlock;
|
|
161 Blocks = Blocks.drop_front();
|
|
162 }
|
|
163 return Runs;
|
|
164 }
|
|
165
|
|
166 static 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
|
|
175 void 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 BinarySubstreamRef Substream;
|
|
207 Substream.Offset = Offset;
|
|
208 Substream.StreamData = Slice.drop_front(Offset).keep_front(Size);
|
|
209
|
|
210 auto Layout = File.getStreamLayout(StreamIdx);
|
|
211 formatMsfStreamData(Label, File, Layout, Substream);
|
|
212 }
|
|
213
|
|
214 void LinePrinter::formatMsfStreamData(StringRef Label, PDBFile &File,
|
|
215 const msf::MSFStreamLayout &Stream,
|
|
216 BinarySubstreamRef Substream) {
|
|
217 BinaryStreamReader Reader(Substream.StreamData);
|
|
218
|
|
219 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;
|
|
228 std::tie(FoundRun, RunOffset) = findRun(Substream.Offset, Runs);
|
|
229 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 }
|
|
242 Substream.Offset += Len;
|
|
243 }
|
|
244 NewLine();
|
|
245 OS << ")";
|
|
246 }
|
|
247
|
|
248 void 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
|
|
272 bool 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;
|
|
278 }
|
|
279
|
|
280 bool LinePrinter::IsSymbolExcluded(llvm::StringRef SymbolName) {
|
|
281 return IsItemExcluded(SymbolName, IncludeSymbolFilters, ExcludeSymbolFilters);
|
|
282 }
|
|
283
|
|
284 bool LinePrinter::IsCompilandExcluded(llvm::StringRef CompilandName) {
|
|
285 return IsItemExcluded(CompilandName, IncludeCompilandFilters,
|
|
286 ExcludeCompilandFilters);
|
|
287 }
|
|
288
|
|
289 WithColor::WithColor(LinePrinter &P, PDB_ColorItem C)
|
|
290 : OS(P.OS), UseColor(P.hasColor()) {
|
|
291 if (UseColor)
|
|
292 applyColor(C);
|
|
293 }
|
|
294
|
|
295 WithColor::~WithColor() {
|
|
296 if (UseColor)
|
|
297 OS.resetColor();
|
|
298 }
|
|
299
|
|
300 void WithColor::applyColor(PDB_ColorItem C) {
|
|
301 switch (C) {
|
|
302 case PDB_ColorItem::None:
|
|
303 OS.resetColor();
|
|
304 return;
|
|
305 case PDB_ColorItem::Comment:
|
|
306 OS.changeColor(raw_ostream::GREEN, false);
|
|
307 return;
|
|
308 case PDB_ColorItem::Address:
|
|
309 OS.changeColor(raw_ostream::YELLOW, /*bold=*/true);
|
|
310 return;
|
|
311 case PDB_ColorItem::Keyword:
|
|
312 OS.changeColor(raw_ostream::MAGENTA, true);
|
|
313 return;
|
|
314 case PDB_ColorItem::Register:
|
|
315 case PDB_ColorItem::Offset:
|
|
316 OS.changeColor(raw_ostream::YELLOW, false);
|
|
317 return;
|
|
318 case PDB_ColorItem::Type:
|
|
319 OS.changeColor(raw_ostream::CYAN, true);
|
|
320 return;
|
|
321 case PDB_ColorItem::Identifier:
|
|
322 OS.changeColor(raw_ostream::CYAN, false);
|
|
323 return;
|
|
324 case PDB_ColorItem::Path:
|
|
325 OS.changeColor(raw_ostream::CYAN, false);
|
|
326 return;
|
|
327 case PDB_ColorItem::Padding:
|
|
328 case PDB_ColorItem::SectionHeader:
|
|
329 OS.changeColor(raw_ostream::RED, true);
|
|
330 return;
|
|
331 case PDB_ColorItem::LiteralValue:
|
|
332 OS.changeColor(raw_ostream::GREEN, true);
|
|
333 return;
|
|
334 }
|
|
335 }
|