[sanitizer] Improve FreeBSD ASLR detection
[llvm-project.git] / llvm / tools / llvm-pdbutil / LinePrinter.cpp
blobdd6ca5bf41b168805b88f052ee8d170be78652ec
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 //===----------------------------------------------------------------------===//
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"
24 #include <algorithm>
26 using namespace llvm;
27 using namespace llvm::msf;
28 using namespace llvm::pdb;
30 namespace {
31 bool IsItemExcluded(llvm::StringRef Item,
32 std::list<llvm::Regex> &IncludeFilters,
33 std::list<llvm::Regex> &ExcludeFilters) {
34 if (Item.empty())
35 return false;
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))
42 return true;
44 if (any_of(ExcludeFilters, match_pred))
45 return true;
47 return false;
51 using namespace llvm;
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) {
71 if (Amount == 0)
72 Amount = IndentSpaces;
73 CurrentIndent += Amount;
76 void LinePrinter::Unindent(uint32_t Amount) {
77 if (Amount == 0)
78 Amount = IndentSpaces;
79 CurrentIndent = std::max<int>(0, CurrentIndent - Amount);
82 void LinePrinter::NewLine() {
83 OS << "\n";
84 OS.indent(CurrentIndent);
87 void LinePrinter::print(const Twine &T) { OS << T; }
89 void LinePrinter::printLine(const Twine &T) {
90 NewLine();
91 OS << T;
94 bool LinePrinter::IsClassExcluded(const ClassLayout &Class) {
95 if (IsTypeExcluded(Class.getName(), Class.getSize()))
96 return true;
97 if (Class.deepPaddingSize() < opts::pretty::PaddingThreshold)
98 return true;
99 return false;
102 void LinePrinter::formatBinary(StringRef Label, ArrayRef<uint8_t> Data,
103 uint64_t StartOffset) {
104 NewLine();
105 OS << Label << " (";
106 if (!Data.empty()) {
107 OS << "\n";
108 OS << format_bytes_with_ascii(Data, StartOffset, 32, 4,
109 CurrentIndent + IndentSpaces, true);
110 NewLine();
112 OS << ")";
115 void LinePrinter::formatBinary(StringRef Label, ArrayRef<uint8_t> Data,
116 uint64_t Base, uint64_t StartOffset) {
117 NewLine();
118 OS << Label << " (";
119 if (!Data.empty()) {
120 OS << "\n";
121 Base += StartOffset;
122 OS << format_bytes_with_ascii(Data, Base, 32, 4,
123 CurrentIndent + IndentSpaces, true);
124 NewLine();
126 OS << ")";
129 namespace {
130 struct Run {
131 Run() = default;
132 explicit Run(uint32_t Block) : Block(Block) {}
133 uint32_t Block = 0;
134 uint64_t ByteLen = 0;
136 } // namespace
138 static std::vector<Run> computeBlockRuns(uint32_t BlockSize,
139 const msf::MSFStreamLayout &Layout) {
140 std::vector<Run> Runs;
141 if (Layout.Length == 0)
142 return Runs;
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();
156 uint64_t Used =
157 std::min(static_cast<uint64_t>(BlockSize), StreamBytesRemaining);
158 CurrentRun->ByteLen += Used;
159 StreamBytesRemaining -= Used;
160 CurrentBlock = NextBlock;
161 Blocks = Blocks.drop_front();
163 return Runs;
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);
170 Offset -= R.ByteLen;
172 llvm_unreachable("Invalid offset!");
175 void LinePrinter::formatMsfStreamData(StringRef Label, PDBFile &File,
176 uint32_t StreamIdx,
177 StringRef StreamPurpose, uint64_t Offset,
178 uint64_t Size) {
179 if (StreamIdx >= File.getNumStreams()) {
180 formatLine("Stream {0}: Not present", StreamIdx);
181 return;
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;
190 auto S = File.createIndexedStream(StreamIdx);
191 if (!S) {
192 NewLine();
193 formatLine("Stream {0}: Not present", StreamIdx);
194 return;
197 uint64_t End =
198 (Size == 0) ? S->getLength() : std::min(Offset + Size, S->getLength());
199 Size = End - Offset;
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);
220 NewLine();
221 OS << Label << " (";
222 while (Reader.bytesRemaining() > 0) {
223 OS << "\n";
225 Run FoundRun;
226 uint64_t RunOffset;
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) {
237 NewLine();
238 OS << formatv(" {0}",
239 fmt_align("<discontinuity>", AlignStyle::Center, 114, '-'));
241 Substream.Offset += Len;
243 NewLine();
244 OS << ")";
247 void LinePrinter::formatMsfStreamBlocks(
248 PDBFile &File, const msf::MSFStreamLayout &StreamLayout) {
249 auto Blocks = makeArrayRef(StreamLayout.Blocks);
250 uint64_t L = StreamLayout.Length;
252 while (L > 0) {
253 NewLine();
254 assert(!Blocks.empty());
255 OS << formatv("Block {0} (\n", uint32_t(Blocks.front()));
256 uint64_t UsedBytes =
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);
264 NewLine();
265 OS << ")";
266 NewLine();
267 L -= UsedBytes;
268 Blocks = Blocks.drop_front();
272 bool LinePrinter::IsTypeExcluded(llvm::StringRef TypeName, uint64_t Size) {
273 if (IsItemExcluded(TypeName, IncludeTypeFilters, ExcludeTypeFilters))
274 return true;
275 if (Size < opts::pretty::SizeThreshold)
276 return true;
277 return false;
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()) {
291 if (UseColor)
292 applyColor(C);
295 WithColor::~WithColor() {
296 if (UseColor)
297 OS.resetColor();
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;