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