1 //===- LinePrinter.cpp ------------------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #include "LinePrinter.h"
11 #include "llvm-pdbutil.h"
13 #include "llvm/ADT/STLExtras.h"
14 #include "llvm/DebugInfo/MSF/MSFCommon.h"
15 #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
16 #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
17 #include "llvm/DebugInfo/PDB/UDTLayout.h"
18 #include "llvm/Support/BinaryStreamReader.h"
19 #include "llvm/Support/Format.h"
20 #include "llvm/Support/FormatAdapters.h"
21 #include "llvm/Support/FormatVariadic.h"
22 #include "llvm/Support/Regex.h"
27 using namespace llvm::msf
;
28 using namespace llvm::pdb
;
31 bool IsItemExcluded(llvm::StringRef Item
,
32 std::list
<llvm::Regex
> &IncludeFilters
,
33 std::list
<llvm::Regex
> &ExcludeFilters
) {
37 auto match_pred
= [Item
](llvm::Regex
&R
) { return R
.match(Item
); };
39 // Include takes priority over exclude. If the user specified include
40 // filters, and none of them include this item, them item is gone.
41 if (!IncludeFilters
.empty() && !any_of(IncludeFilters
, match_pred
))
44 if (any_of(ExcludeFilters
, match_pred
))
53 LinePrinter::LinePrinter(int Indent
, bool UseColor
, llvm::raw_ostream
&Stream
)
54 : OS(Stream
), IndentSpaces(Indent
), CurrentIndent(0), UseColor(UseColor
) {
55 SetFilters(ExcludeTypeFilters
, opts::pretty::ExcludeTypes
.begin(),
56 opts::pretty::ExcludeTypes
.end());
57 SetFilters(ExcludeSymbolFilters
, opts::pretty::ExcludeSymbols
.begin(),
58 opts::pretty::ExcludeSymbols
.end());
59 SetFilters(ExcludeCompilandFilters
, opts::pretty::ExcludeCompilands
.begin(),
60 opts::pretty::ExcludeCompilands
.end());
62 SetFilters(IncludeTypeFilters
, opts::pretty::IncludeTypes
.begin(),
63 opts::pretty::IncludeTypes
.end());
64 SetFilters(IncludeSymbolFilters
, opts::pretty::IncludeSymbols
.begin(),
65 opts::pretty::IncludeSymbols
.end());
66 SetFilters(IncludeCompilandFilters
, opts::pretty::IncludeCompilands
.begin(),
67 opts::pretty::IncludeCompilands
.end());
70 void LinePrinter::Indent(uint32_t Amount
) {
72 Amount
= IndentSpaces
;
73 CurrentIndent
+= Amount
;
76 void LinePrinter::Unindent(uint32_t Amount
) {
78 Amount
= IndentSpaces
;
79 CurrentIndent
= std::max
<int>(0, CurrentIndent
- Amount
);
82 void LinePrinter::NewLine() {
84 OS
.indent(CurrentIndent
);
87 void LinePrinter::print(const Twine
&T
) { OS
<< T
; }
89 void LinePrinter::printLine(const Twine
&T
) {
94 bool LinePrinter::IsClassExcluded(const ClassLayout
&Class
) {
95 if (IsTypeExcluded(Class
.getName(), Class
.getSize()))
97 if (Class
.deepPaddingSize() < opts::pretty::PaddingThreshold
)
102 void LinePrinter::formatBinary(StringRef Label
, ArrayRef
<uint8_t> Data
,
103 uint64_t StartOffset
) {
108 OS
<< format_bytes_with_ascii(Data
, StartOffset
, 32, 4,
109 CurrentIndent
+ IndentSpaces
, true);
115 void LinePrinter::formatBinary(StringRef Label
, ArrayRef
<uint8_t> Data
,
116 uint64_t Base
, uint64_t StartOffset
) {
122 OS
<< format_bytes_with_ascii(Data
, Base
, 32, 4,
123 CurrentIndent
+ IndentSpaces
, true);
132 explicit Run(uint32_t Block
) : Block(Block
) {}
134 uint64_t ByteLen
= 0;
138 static std::vector
<Run
> computeBlockRuns(uint32_t BlockSize
,
139 const msf::MSFStreamLayout
&Layout
) {
140 std::vector
<Run
> Runs
;
141 if (Layout
.Length
== 0)
144 ArrayRef
<support::ulittle32_t
> Blocks
= Layout
.Blocks
;
145 assert(!Blocks
.empty());
146 uint64_t StreamBytesRemaining
= Layout
.Length
;
147 uint32_t CurrentBlock
= Blocks
[0];
148 Runs
.emplace_back(CurrentBlock
);
149 while (!Blocks
.empty()) {
150 Run
*CurrentRun
= &Runs
.back();
151 uint32_t NextBlock
= Blocks
.front();
152 if (NextBlock
< CurrentBlock
|| (NextBlock
- CurrentBlock
> 1)) {
153 Runs
.emplace_back(NextBlock
);
154 CurrentRun
= &Runs
.back();
157 std::min(static_cast<uint64_t>(BlockSize
), StreamBytesRemaining
);
158 CurrentRun
->ByteLen
+= Used
;
159 StreamBytesRemaining
-= Used
;
160 CurrentBlock
= NextBlock
;
161 Blocks
= Blocks
.drop_front();
166 static std::pair
<Run
, uint64_t> findRun(uint64_t Offset
, ArrayRef
<Run
> Runs
) {
167 for (const auto &R
: Runs
) {
168 if (Offset
< R
.ByteLen
)
169 return std::make_pair(R
, Offset
);
172 llvm_unreachable("Invalid offset!");
175 void LinePrinter::formatMsfStreamData(StringRef Label
, PDBFile
&File
,
177 StringRef StreamPurpose
, uint64_t Offset
,
179 if (StreamIdx
>= File
.getNumStreams()) {
180 formatLine("Stream {0}: Not present", StreamIdx
);
183 if (Size
+ Offset
> File
.getStreamByteSize(StreamIdx
)) {
185 "Stream {0}: Invalid offset and size, range out of stream bounds",
190 auto S
= File
.createIndexedStream(StreamIdx
);
193 formatLine("Stream {0}: Not present", StreamIdx
);
198 (Size
== 0) ? S
->getLength() : std::min(Offset
+ Size
, S
->getLength());
201 formatLine("Stream {0}: {1} (dumping {2:N} / {3:N} bytes)", StreamIdx
,
202 StreamPurpose
, Size
, S
->getLength());
203 AutoIndent
Indent(*this);
204 BinaryStreamRef
Slice(*S
);
205 BinarySubstreamRef Substream
;
206 Substream
.Offset
= Offset
;
207 Substream
.StreamData
= Slice
.drop_front(Offset
).keep_front(Size
);
209 auto Layout
= File
.getStreamLayout(StreamIdx
);
210 formatMsfStreamData(Label
, File
, Layout
, Substream
);
213 void LinePrinter::formatMsfStreamData(StringRef Label
, PDBFile
&File
,
214 const msf::MSFStreamLayout
&Stream
,
215 BinarySubstreamRef Substream
) {
216 BinaryStreamReader
Reader(Substream
.StreamData
);
218 auto Runs
= computeBlockRuns(File
.getBlockSize(), Stream
);
222 while (Reader
.bytesRemaining() > 0) {
227 std::tie(FoundRun
, RunOffset
) = findRun(Substream
.Offset
, Runs
);
228 assert(FoundRun
.ByteLen
>= RunOffset
);
229 uint64_t Len
= FoundRun
.ByteLen
- RunOffset
;
230 Len
= std::min(Len
, Reader
.bytesRemaining());
231 uint64_t Base
= FoundRun
.Block
* File
.getBlockSize() + RunOffset
;
232 ArrayRef
<uint8_t> Data
;
233 consumeError(Reader
.readBytes(Data
, Len
));
234 OS
<< format_bytes_with_ascii(Data
, Base
, 32, 4,
235 CurrentIndent
+ IndentSpaces
, true);
236 if (Reader
.bytesRemaining() > 0) {
238 OS
<< formatv(" {0}",
239 fmt_align("<discontinuity>", AlignStyle::Center
, 114, '-'));
241 Substream
.Offset
+= Len
;
247 void LinePrinter::formatMsfStreamBlocks(
248 PDBFile
&File
, const msf::MSFStreamLayout
&StreamLayout
) {
249 auto Blocks
= makeArrayRef(StreamLayout
.Blocks
);
250 uint64_t L
= StreamLayout
.Length
;
254 assert(!Blocks
.empty());
255 OS
<< formatv("Block {0} (\n", uint32_t(Blocks
.front()));
257 std::min(L
, static_cast<uint64_t>(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);
268 Blocks
= Blocks
.drop_front();
272 bool LinePrinter::IsTypeExcluded(llvm::StringRef TypeName
, uint64_t Size
) {
273 if (IsItemExcluded(TypeName
, IncludeTypeFilters
, ExcludeTypeFilters
))
275 if (Size
< opts::pretty::SizeThreshold
)
280 bool LinePrinter::IsSymbolExcluded(llvm::StringRef SymbolName
) {
281 return IsItemExcluded(SymbolName
, IncludeSymbolFilters
, ExcludeSymbolFilters
);
284 bool LinePrinter::IsCompilandExcluded(llvm::StringRef CompilandName
) {
285 return IsItemExcluded(CompilandName
, IncludeCompilandFilters
,
286 ExcludeCompilandFilters
);
289 WithColor::WithColor(LinePrinter
&P
, PDB_ColorItem C
)
290 : OS(P
.OS
), UseColor(P
.hasColor()) {
295 WithColor::~WithColor() {
300 void WithColor::applyColor(PDB_ColorItem C
) {
302 case PDB_ColorItem::None
:
305 case PDB_ColorItem::Comment
:
306 OS
.changeColor(raw_ostream::GREEN
, false);
308 case PDB_ColorItem::Address
:
309 OS
.changeColor(raw_ostream::YELLOW
, /*bold=*/true);
311 case PDB_ColorItem::Keyword
:
312 OS
.changeColor(raw_ostream::MAGENTA
, true);
314 case PDB_ColorItem::Register
:
315 case PDB_ColorItem::Offset
:
316 OS
.changeColor(raw_ostream::YELLOW
, false);
318 case PDB_ColorItem::Type
:
319 OS
.changeColor(raw_ostream::CYAN
, true);
321 case PDB_ColorItem::Identifier
:
322 OS
.changeColor(raw_ostream::CYAN
, false);
324 case PDB_ColorItem::Path
:
325 OS
.changeColor(raw_ostream::CYAN
, false);
327 case PDB_ColorItem::Padding
:
328 case PDB_ColorItem::SectionHeader
:
329 OS
.changeColor(raw_ostream::RED
, true);
331 case PDB_ColorItem::LiteralValue
:
332 OS
.changeColor(raw_ostream::GREEN
, true);