Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/DebugInfo/PDB/Native/LinePrinter.cpp
35293 views
1
//===- LinePrinter.cpp ------------------------------------------*- C++ -*-===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
9
#include "llvm/DebugInfo/PDB/Native/LinePrinter.h"
10
11
#include "llvm/ADT/STLExtras.h"
12
#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
13
#include "llvm/DebugInfo/MSF/MSFCommon.h"
14
#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
15
#include "llvm/DebugInfo/PDB/IPDBLineNumber.h"
16
#include "llvm/DebugInfo/PDB/Native/InputFile.h"
17
#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
18
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
19
#include "llvm/DebugInfo/PDB/UDTLayout.h"
20
#include "llvm/Object/COFF.h"
21
#include "llvm/Support/BinaryStreamReader.h"
22
#include "llvm/Support/Format.h"
23
#include "llvm/Support/FormatAdapters.h"
24
#include "llvm/Support/FormatVariadic.h"
25
#include "llvm/Support/Regex.h"
26
27
#include <algorithm>
28
29
using namespace llvm;
30
using namespace llvm::msf;
31
using namespace llvm::pdb;
32
33
namespace {
34
bool IsItemExcluded(llvm::StringRef Item,
35
std::list<llvm::Regex> &IncludeFilters,
36
std::list<llvm::Regex> &ExcludeFilters) {
37
if (Item.empty())
38
return false;
39
40
auto match_pred = [Item](llvm::Regex &R) { return R.match(Item); };
41
42
// Include takes priority over exclude. If the user specified include
43
// filters, and none of them include this item, them item is gone.
44
if (!IncludeFilters.empty() && !any_of(IncludeFilters, match_pred))
45
return true;
46
47
if (any_of(ExcludeFilters, match_pred))
48
return true;
49
50
return false;
51
}
52
} // namespace
53
54
using namespace llvm;
55
56
LinePrinter::LinePrinter(int Indent, bool UseColor, llvm::raw_ostream &Stream,
57
const FilterOptions &Filters)
58
: OS(Stream), IndentSpaces(Indent), CurrentIndent(0), UseColor(UseColor),
59
Filters(Filters) {
60
SetFilters(ExcludeTypeFilters, Filters.ExcludeTypes.begin(),
61
Filters.ExcludeTypes.end());
62
SetFilters(ExcludeSymbolFilters, Filters.ExcludeSymbols.begin(),
63
Filters.ExcludeSymbols.end());
64
SetFilters(ExcludeCompilandFilters, Filters.ExcludeCompilands.begin(),
65
Filters.ExcludeCompilands.end());
66
67
SetFilters(IncludeTypeFilters, Filters.IncludeTypes.begin(),
68
Filters.IncludeTypes.end());
69
SetFilters(IncludeSymbolFilters, Filters.IncludeSymbols.begin(),
70
Filters.IncludeSymbols.end());
71
SetFilters(IncludeCompilandFilters, Filters.IncludeCompilands.begin(),
72
Filters.IncludeCompilands.end());
73
}
74
75
void LinePrinter::Indent(uint32_t Amount) {
76
if (Amount == 0)
77
Amount = IndentSpaces;
78
CurrentIndent += Amount;
79
}
80
81
void LinePrinter::Unindent(uint32_t Amount) {
82
if (Amount == 0)
83
Amount = IndentSpaces;
84
CurrentIndent = std::max<int>(0, CurrentIndent - Amount);
85
}
86
87
void LinePrinter::NewLine() {
88
OS << "\n";
89
OS.indent(CurrentIndent);
90
}
91
92
void LinePrinter::print(const Twine &T) { OS << T; }
93
94
void LinePrinter::printLine(const Twine &T) {
95
NewLine();
96
OS << T;
97
}
98
99
bool LinePrinter::IsClassExcluded(const ClassLayout &Class) {
100
if (IsTypeExcluded(Class.getName(), Class.getSize()))
101
return true;
102
if (Class.deepPaddingSize() < Filters.PaddingThreshold)
103
return true;
104
return false;
105
}
106
107
void LinePrinter::formatBinary(StringRef Label, ArrayRef<uint8_t> Data,
108
uint64_t StartOffset) {
109
NewLine();
110
OS << Label << " (";
111
if (!Data.empty()) {
112
OS << "\n";
113
OS << format_bytes_with_ascii(Data, StartOffset, 32, 4,
114
CurrentIndent + IndentSpaces, true);
115
NewLine();
116
}
117
OS << ")";
118
}
119
120
void LinePrinter::formatBinary(StringRef Label, ArrayRef<uint8_t> Data,
121
uint64_t Base, uint64_t StartOffset) {
122
NewLine();
123
OS << Label << " (";
124
if (!Data.empty()) {
125
OS << "\n";
126
Base += StartOffset;
127
OS << format_bytes_with_ascii(Data, Base, 32, 4,
128
CurrentIndent + IndentSpaces, true);
129
NewLine();
130
}
131
OS << ")";
132
}
133
134
namespace {
135
struct Run {
136
Run() = default;
137
explicit Run(uint32_t Block) : Block(Block) {}
138
uint32_t Block = 0;
139
uint64_t ByteLen = 0;
140
};
141
} // namespace
142
143
static std::vector<Run> computeBlockRuns(uint32_t BlockSize,
144
const msf::MSFStreamLayout &Layout) {
145
std::vector<Run> Runs;
146
if (Layout.Length == 0)
147
return Runs;
148
149
ArrayRef<support::ulittle32_t> Blocks = Layout.Blocks;
150
assert(!Blocks.empty());
151
uint64_t StreamBytesRemaining = Layout.Length;
152
uint32_t CurrentBlock = Blocks[0];
153
Runs.emplace_back(CurrentBlock);
154
while (!Blocks.empty()) {
155
Run *CurrentRun = &Runs.back();
156
uint32_t NextBlock = Blocks.front();
157
if (NextBlock < CurrentBlock || (NextBlock - CurrentBlock > 1)) {
158
Runs.emplace_back(NextBlock);
159
CurrentRun = &Runs.back();
160
}
161
uint64_t Used =
162
std::min(static_cast<uint64_t>(BlockSize), StreamBytesRemaining);
163
CurrentRun->ByteLen += Used;
164
StreamBytesRemaining -= Used;
165
CurrentBlock = NextBlock;
166
Blocks = Blocks.drop_front();
167
}
168
return Runs;
169
}
170
171
static std::pair<Run, uint64_t> findRun(uint64_t Offset, ArrayRef<Run> Runs) {
172
for (const auto &R : Runs) {
173
if (Offset < R.ByteLen)
174
return std::make_pair(R, Offset);
175
Offset -= R.ByteLen;
176
}
177
llvm_unreachable("Invalid offset!");
178
}
179
180
void LinePrinter::formatMsfStreamData(StringRef Label, PDBFile &File,
181
uint32_t StreamIdx,
182
StringRef StreamPurpose, uint64_t Offset,
183
uint64_t Size) {
184
if (StreamIdx >= File.getNumStreams()) {
185
formatLine("Stream {0}: Not present", StreamIdx);
186
return;
187
}
188
if (Size + Offset > File.getStreamByteSize(StreamIdx)) {
189
formatLine(
190
"Stream {0}: Invalid offset and size, range out of stream bounds",
191
StreamIdx);
192
return;
193
}
194
195
auto S = File.createIndexedStream(StreamIdx);
196
if (!S) {
197
NewLine();
198
formatLine("Stream {0}: Not present", StreamIdx);
199
return;
200
}
201
202
uint64_t End =
203
(Size == 0) ? S->getLength() : std::min(Offset + Size, S->getLength());
204
Size = End - Offset;
205
206
formatLine("Stream {0}: {1} (dumping {2:N} / {3:N} bytes)", StreamIdx,
207
StreamPurpose, Size, S->getLength());
208
AutoIndent Indent(*this);
209
BinaryStreamRef Slice(*S);
210
BinarySubstreamRef Substream;
211
Substream.Offset = Offset;
212
Substream.StreamData = Slice.drop_front(Offset).keep_front(Size);
213
214
auto Layout = File.getStreamLayout(StreamIdx);
215
formatMsfStreamData(Label, File, Layout, Substream);
216
}
217
218
void LinePrinter::formatMsfStreamData(StringRef Label, PDBFile &File,
219
const msf::MSFStreamLayout &Stream,
220
BinarySubstreamRef Substream) {
221
BinaryStreamReader Reader(Substream.StreamData);
222
223
auto Runs = computeBlockRuns(File.getBlockSize(), Stream);
224
225
NewLine();
226
OS << Label << " (";
227
while (Reader.bytesRemaining() > 0) {
228
OS << "\n";
229
230
Run FoundRun;
231
uint64_t RunOffset;
232
std::tie(FoundRun, RunOffset) = findRun(Substream.Offset, Runs);
233
assert(FoundRun.ByteLen >= RunOffset);
234
uint64_t Len = FoundRun.ByteLen - RunOffset;
235
Len = std::min(Len, Reader.bytesRemaining());
236
uint64_t Base = FoundRun.Block * File.getBlockSize() + RunOffset;
237
ArrayRef<uint8_t> Data;
238
consumeError(Reader.readBytes(Data, Len));
239
OS << format_bytes_with_ascii(Data, Base, 32, 4,
240
CurrentIndent + IndentSpaces, true);
241
if (Reader.bytesRemaining() > 0) {
242
NewLine();
243
OS << formatv(" {0}",
244
fmt_align("<discontinuity>", AlignStyle::Center, 114, '-'));
245
}
246
Substream.Offset += Len;
247
}
248
NewLine();
249
OS << ")";
250
}
251
252
void LinePrinter::formatMsfStreamBlocks(
253
PDBFile &File, const msf::MSFStreamLayout &StreamLayout) {
254
auto Blocks = ArrayRef(StreamLayout.Blocks);
255
uint64_t L = StreamLayout.Length;
256
257
while (L > 0) {
258
NewLine();
259
assert(!Blocks.empty());
260
OS << formatv("Block {0} (\n", uint32_t(Blocks.front()));
261
uint64_t UsedBytes =
262
std::min(L, static_cast<uint64_t>(File.getBlockSize()));
263
ArrayRef<uint8_t> BlockData =
264
cantFail(File.getBlockData(Blocks.front(), File.getBlockSize()));
265
uint64_t BaseOffset = Blocks.front();
266
BaseOffset *= File.getBlockSize();
267
OS << format_bytes_with_ascii(BlockData, BaseOffset, 32, 4,
268
CurrentIndent + IndentSpaces, true);
269
NewLine();
270
OS << ")";
271
NewLine();
272
L -= UsedBytes;
273
Blocks = Blocks.drop_front();
274
}
275
}
276
277
bool LinePrinter::IsTypeExcluded(llvm::StringRef TypeName, uint64_t Size) {
278
if (IsItemExcluded(TypeName, IncludeTypeFilters, ExcludeTypeFilters))
279
return true;
280
if (Size < Filters.SizeThreshold)
281
return true;
282
return false;
283
}
284
285
bool LinePrinter::IsSymbolExcluded(llvm::StringRef SymbolName) {
286
return IsItemExcluded(SymbolName, IncludeSymbolFilters, ExcludeSymbolFilters);
287
}
288
289
bool LinePrinter::IsCompilandExcluded(llvm::StringRef CompilandName) {
290
return IsItemExcluded(CompilandName, IncludeCompilandFilters,
291
ExcludeCompilandFilters);
292
}
293
294
WithColor::WithColor(LinePrinter &P, PDB_ColorItem C)
295
: OS(P.OS), UseColor(P.hasColor()) {
296
if (UseColor)
297
applyColor(C);
298
}
299
300
WithColor::~WithColor() {
301
if (UseColor)
302
OS.resetColor();
303
}
304
305
void WithColor::applyColor(PDB_ColorItem C) {
306
switch (C) {
307
case PDB_ColorItem::None:
308
OS.resetColor();
309
return;
310
case PDB_ColorItem::Comment:
311
OS.changeColor(raw_ostream::GREEN, false);
312
return;
313
case PDB_ColorItem::Address:
314
OS.changeColor(raw_ostream::YELLOW, /*bold=*/true);
315
return;
316
case PDB_ColorItem::Keyword:
317
OS.changeColor(raw_ostream::MAGENTA, true);
318
return;
319
case PDB_ColorItem::Register:
320
case PDB_ColorItem::Offset:
321
OS.changeColor(raw_ostream::YELLOW, false);
322
return;
323
case PDB_ColorItem::Type:
324
OS.changeColor(raw_ostream::CYAN, true);
325
return;
326
case PDB_ColorItem::Identifier:
327
OS.changeColor(raw_ostream::CYAN, false);
328
return;
329
case PDB_ColorItem::Path:
330
OS.changeColor(raw_ostream::CYAN, false);
331
return;
332
case PDB_ColorItem::Padding:
333
case PDB_ColorItem::SectionHeader:
334
OS.changeColor(raw_ostream::RED, true);
335
return;
336
case PDB_ColorItem::LiteralValue:
337
OS.changeColor(raw_ostream::GREEN, true);
338
return;
339
}
340
}
341
342