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