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 { 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 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 71 void LinePrinter::Indent(uint32_t Amount) { 72 if (Amount == 0) 73 Amount = IndentSpaces; 74 CurrentIndent += Amount; 75 } 76 77 void LinePrinter::Unindent(uint32_t Amount) { 78 if (Amount == 0) 79 Amount = IndentSpaces; 80 CurrentIndent = std::max<int>(0, CurrentIndent - Amount); 81 } 82 83 void LinePrinter::NewLine() { 84 OS << "\n"; 85 OS.indent(CurrentIndent); 86 } 87 88 void LinePrinter::print(const Twine &T) { OS << T; } 89 90 void LinePrinter::printLine(const Twine &T) { 91 NewLine(); 92 OS << T; 93 } 94 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 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 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; 133 explicit Run(uint32_t Block) : Block(Block) {} 134 uint32_t Block = 0; 135 uint32_t ByteLen = 0; 136 }; 137 } // namespace 138 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 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 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 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 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 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 280 bool LinePrinter::IsSymbolExcluded(llvm::StringRef SymbolName) { 281 return IsItemExcluded(SymbolName, IncludeSymbolFilters, ExcludeSymbolFilters); 282 } 283 284 bool LinePrinter::IsCompilandExcluded(llvm::StringRef CompilandName) { 285 return IsItemExcluded(CompilandName, IncludeCompilandFilters, 286 ExcludeCompilandFilters); 287 } 288 289 WithColor::WithColor(LinePrinter &P, PDB_ColorItem C) 290 : OS(P.OS), UseColor(P.hasColor()) { 291 if (UseColor) 292 applyColor(C); 293 } 294 295 WithColor::~WithColor() { 296 if (UseColor) 297 OS.resetColor(); 298 } 299 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