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 uint32_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
, uint32_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 uint32_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 uint32_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();
156 uint32_t Used
= std::min(BlockSize
, StreamBytesRemaining
);
157 CurrentRun
->ByteLen
+= Used
;
158 StreamBytesRemaining
-= Used
;
159 CurrentBlock
= NextBlock
;
160 Blocks
= Blocks
.drop_front();
165 static std::pair
<Run
, uint32_t> findRun(uint32_t Offset
, ArrayRef
<Run
> Runs
) {
166 for (const auto &R
: Runs
) {
167 if (Offset
< R
.ByteLen
)
168 return std::make_pair(R
, Offset
);
171 llvm_unreachable("Invalid offset!");
174 void LinePrinter::formatMsfStreamData(StringRef Label
, PDBFile
&File
,
176 StringRef StreamPurpose
, uint32_t Offset
,
178 if (StreamIdx
>= File
.getNumStreams()) {
179 formatLine("Stream {0}: Not present", StreamIdx
);
182 if (Size
+ Offset
> File
.getStreamByteSize(StreamIdx
)) {
184 "Stream {0}: Invalid offset and size, range out of stream bounds",
189 auto S
= File
.createIndexedStream(StreamIdx
);
192 formatLine("Stream {0}: Not present", StreamIdx
);
197 (Size
== 0) ? S
->getLength() : std::min(Offset
+ Size
, S
->getLength());
200 formatLine("Stream {0}: {1} (dumping {2:N} / {3:N} bytes)", StreamIdx
,
201 StreamPurpose
, Size
, S
->getLength());
202 AutoIndent
Indent(*this);
203 BinaryStreamRef
Slice(*S
);
204 BinarySubstreamRef Substream
;
205 Substream
.Offset
= Offset
;
206 Substream
.StreamData
= Slice
.drop_front(Offset
).keep_front(Size
);
208 auto Layout
= File
.getStreamLayout(StreamIdx
);
209 formatMsfStreamData(Label
, File
, Layout
, Substream
);
212 void LinePrinter::formatMsfStreamData(StringRef Label
, PDBFile
&File
,
213 const msf::MSFStreamLayout
&Stream
,
214 BinarySubstreamRef Substream
) {
215 BinaryStreamReader
Reader(Substream
.StreamData
);
217 auto Runs
= computeBlockRuns(File
.getBlockSize(), Stream
);
221 while (Reader
.bytesRemaining() > 0) {
226 std::tie(FoundRun
, RunOffset
) = findRun(Substream
.Offset
, Runs
);
227 assert(FoundRun
.ByteLen
>= RunOffset
);
228 uint32_t Len
= FoundRun
.ByteLen
- RunOffset
;
229 Len
= std::min(Len
, Reader
.bytesRemaining());
230 uint64_t Base
= FoundRun
.Block
* File
.getBlockSize() + RunOffset
;
231 ArrayRef
<uint8_t> Data
;
232 consumeError(Reader
.readBytes(Data
, Len
));
233 OS
<< format_bytes_with_ascii(Data
, Base
, 32, 4,
234 CurrentIndent
+ IndentSpaces
, true);
235 if (Reader
.bytesRemaining() > 0) {
237 OS
<< formatv(" {0}",
238 fmt_align("<discontinuity>", AlignStyle::Center
, 114, '-'));
240 Substream
.Offset
+= Len
;
246 void LinePrinter::formatMsfStreamBlocks(
247 PDBFile
&File
, const msf::MSFStreamLayout
&StreamLayout
) {
248 auto Blocks
= makeArrayRef(StreamLayout
.Blocks
);
249 uint32_t L
= StreamLayout
.Length
;
253 assert(!Blocks
.empty());
254 OS
<< formatv("Block {0} (\n", uint32_t(Blocks
.front()));
255 uint32_t UsedBytes
= std::min(L
, File
.getBlockSize());
256 ArrayRef
<uint8_t> BlockData
=
257 cantFail(File
.getBlockData(Blocks
.front(), File
.getBlockSize()));
258 uint64_t BaseOffset
= Blocks
.front();
259 BaseOffset
*= File
.getBlockSize();
260 OS
<< format_bytes_with_ascii(BlockData
, BaseOffset
, 32, 4,
261 CurrentIndent
+ IndentSpaces
, true);
266 Blocks
= Blocks
.drop_front();
270 bool LinePrinter::IsTypeExcluded(llvm::StringRef TypeName
, uint32_t Size
) {
271 if (IsItemExcluded(TypeName
, IncludeTypeFilters
, ExcludeTypeFilters
))
273 if (Size
< opts::pretty::SizeThreshold
)
278 bool LinePrinter::IsSymbolExcluded(llvm::StringRef SymbolName
) {
279 return IsItemExcluded(SymbolName
, IncludeSymbolFilters
, ExcludeSymbolFilters
);
282 bool LinePrinter::IsCompilandExcluded(llvm::StringRef CompilandName
) {
283 return IsItemExcluded(CompilandName
, IncludeCompilandFilters
,
284 ExcludeCompilandFilters
);
287 WithColor::WithColor(LinePrinter
&P
, PDB_ColorItem C
)
288 : OS(P
.OS
), UseColor(P
.hasColor()) {
293 WithColor::~WithColor() {
298 void WithColor::applyColor(PDB_ColorItem C
) {
300 case PDB_ColorItem::None
:
303 case PDB_ColorItem::Comment
:
304 OS
.changeColor(raw_ostream::GREEN
, false);
306 case PDB_ColorItem::Address
:
307 OS
.changeColor(raw_ostream::YELLOW
, /*bold=*/true);
309 case PDB_ColorItem::Keyword
:
310 OS
.changeColor(raw_ostream::MAGENTA
, true);
312 case PDB_ColorItem::Register
:
313 case PDB_ColorItem::Offset
:
314 OS
.changeColor(raw_ostream::YELLOW
, false);
316 case PDB_ColorItem::Type
:
317 OS
.changeColor(raw_ostream::CYAN
, true);
319 case PDB_ColorItem::Identifier
:
320 OS
.changeColor(raw_ostream::CYAN
, false);
322 case PDB_ColorItem::Path
:
323 OS
.changeColor(raw_ostream::CYAN
, false);
325 case PDB_ColorItem::Padding
:
326 case PDB_ColorItem::SectionHeader
:
327 OS
.changeColor(raw_ostream::RED
, true);
329 case PDB_ColorItem::LiteralValue
:
330 OS
.changeColor(raw_ostream::GREEN
, true);