1 //===- BytesOutputStyle.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 "BytesOutputStyle.h" 11 12 #include "FormatUtil.h" 13 #include "StreamUtil.h" 14 #include "llvm-pdbutil.h" 15 16 #include "llvm/DebugInfo/CodeView/Formatters.h" 17 #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" 18 #include "llvm/DebugInfo/MSF/MSFCommon.h" 19 #include "llvm/DebugInfo/MSF/MappedBlockStream.h" 20 #include "llvm/DebugInfo/PDB/Native/DbiStream.h" 21 #include "llvm/DebugInfo/PDB/Native/InfoStream.h" 22 #include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h" 23 #include "llvm/DebugInfo/PDB/Native/PDBFile.h" 24 #include "llvm/DebugInfo/PDB/Native/RawError.h" 25 #include "llvm/DebugInfo/PDB/Native/TpiStream.h" 26 #include "llvm/Support/BinaryStreamReader.h" 27 #include "llvm/Support/FormatAdapters.h" 28 #include "llvm/Support/FormatVariadic.h" 29 30 using namespace llvm; 31 using namespace llvm::codeview; 32 using namespace llvm::msf; 33 using namespace llvm::pdb; 34 35 namespace { 36 struct StreamSpec { 37 uint32_t SI = 0; 38 uint32_t Begin = 0; 39 uint32_t Size = 0; 40 }; 41 } // namespace 42 43 static Expected<StreamSpec> parseStreamSpec(StringRef Str) { 44 StreamSpec Result; 45 if (Str.consumeInteger(0, Result.SI)) 46 return make_error<RawError>(raw_error_code::invalid_format, 47 "Invalid Stream Specification"); 48 if (Str.consume_front(":")) { 49 if (Str.consumeInteger(0, Result.Begin)) 50 return make_error<RawError>(raw_error_code::invalid_format, 51 "Invalid Stream Specification"); 52 } 53 if (Str.consume_front("@")) { 54 if (Str.consumeInteger(0, Result.Size)) 55 return make_error<RawError>(raw_error_code::invalid_format, 56 "Invalid Stream Specification"); 57 } 58 59 if (!Str.empty()) 60 return make_error<RawError>(raw_error_code::invalid_format, 61 "Invalid Stream Specification"); 62 return Result; 63 } 64 65 static SmallVector<StreamSpec, 2> parseStreamSpecs(LinePrinter &P) { 66 SmallVector<StreamSpec, 2> Result; 67 68 for (auto &Str : opts::bytes::DumpStreamData) { 69 auto ESS = parseStreamSpec(Str); 70 if (!ESS) { 71 P.formatLine("Error parsing stream spec {0}: {1}", Str, 72 toString(ESS.takeError())); 73 continue; 74 } 75 Result.push_back(*ESS); 76 } 77 return Result; 78 } 79 80 static void printHeader(LinePrinter &P, const Twine &S) { 81 P.NewLine(); 82 P.formatLine("{0,=60}", S); 83 P.formatLine("{0}", fmt_repeat('=', 60)); 84 } 85 86 BytesOutputStyle::BytesOutputStyle(PDBFile &File) 87 : File(File), P(2, false, outs()) {} 88 89 Error BytesOutputStyle::dump() { 90 91 if (opts::bytes::DumpBlockRange.hasValue()) { 92 auto &R = *opts::bytes::DumpBlockRange; 93 uint32_t Max = R.Max.getValueOr(R.Min); 94 95 if (Max < R.Min) 96 return make_error<StringError>( 97 "Invalid block range specified. Max < Min", 98 inconvertibleErrorCode()); 99 if (Max >= File.getBlockCount()) 100 return make_error<StringError>( 101 "Invalid block range specified. Requested block out of bounds", 102 inconvertibleErrorCode()); 103 104 dumpBlockRanges(R.Min, Max); 105 P.NewLine(); 106 } 107 108 if (opts::bytes::DumpByteRange.hasValue()) { 109 auto &R = *opts::bytes::DumpByteRange; 110 uint32_t Max = R.Max.getValueOr(File.getFileSize()); 111 112 if (Max < R.Min) 113 return make_error<StringError>("Invalid byte range specified. Max < Min", 114 inconvertibleErrorCode()); 115 if (Max >= File.getFileSize()) 116 return make_error<StringError>( 117 "Invalid byte range specified. Requested byte larger than file size", 118 inconvertibleErrorCode()); 119 120 dumpByteRanges(R.Min, Max); 121 P.NewLine(); 122 } 123 124 if (opts::bytes::Fpm) { 125 dumpFpm(); 126 P.NewLine(); 127 } 128 129 if (!opts::bytes::DumpStreamData.empty()) { 130 dumpStreamBytes(); 131 P.NewLine(); 132 } 133 134 if (opts::bytes::NameMap) { 135 dumpNameMap(); 136 P.NewLine(); 137 } 138 139 if (opts::bytes::SectionContributions) { 140 dumpSectionContributions(); 141 P.NewLine(); 142 } 143 144 if (opts::bytes::SectionMap) { 145 dumpSectionMap(); 146 P.NewLine(); 147 } 148 149 if (opts::bytes::ModuleInfos) { 150 dumpModuleInfos(); 151 P.NewLine(); 152 } 153 154 if (opts::bytes::FileInfo) { 155 dumpFileInfo(); 156 P.NewLine(); 157 } 158 159 if (opts::bytes::TypeServerMap) { 160 dumpTypeServerMap(); 161 P.NewLine(); 162 } 163 164 if (opts::bytes::ECData) { 165 dumpECData(); 166 P.NewLine(); 167 } 168 169 if (!opts::bytes::TypeIndex.empty()) { 170 dumpTypeIndex(StreamTPI, opts::bytes::TypeIndex); 171 P.NewLine(); 172 } 173 174 if (!opts::bytes::IdIndex.empty()) { 175 dumpTypeIndex(StreamIPI, opts::bytes::IdIndex); 176 P.NewLine(); 177 } 178 179 if (opts::bytes::ModuleSyms) { 180 dumpModuleSyms(); 181 P.NewLine(); 182 } 183 184 if (opts::bytes::ModuleC11) { 185 dumpModuleC11(); 186 P.NewLine(); 187 } 188 189 if (opts::bytes::ModuleC13) { 190 dumpModuleC13(); 191 P.NewLine(); 192 } 193 194 return Error::success(); 195 } 196 197 void BytesOutputStyle::dumpNameMap() { 198 printHeader(P, "Named Stream Map"); 199 200 AutoIndent Indent(P); 201 202 auto &InfoS = Err(File.getPDBInfoStream()); 203 BinarySubstreamRef NS = InfoS.getNamedStreamsBuffer(); 204 auto Layout = File.getStreamLayout(StreamPDB); 205 P.formatMsfStreamData("Named Stream Map", File, Layout, NS); 206 } 207 208 void BytesOutputStyle::dumpBlockRanges(uint32_t Min, uint32_t Max) { 209 printHeader(P, "MSF Blocks"); 210 211 AutoIndent Indent(P); 212 for (uint32_t I = Min; I <= Max; ++I) { 213 uint64_t Base = I; 214 Base *= File.getBlockSize(); 215 216 auto ExpectedData = File.getBlockData(I, File.getBlockSize()); 217 if (!ExpectedData) { 218 P.formatLine("Could not get block {0}. Reason = {1}", I, 219 toString(ExpectedData.takeError())); 220 continue; 221 } 222 std::string Label = formatv("Block {0}", I).str(); 223 P.formatBinary(Label, *ExpectedData, Base, 0); 224 } 225 } 226 227 void BytesOutputStyle::dumpSectionContributions() { 228 printHeader(P, "Section Contributions"); 229 230 AutoIndent Indent(P); 231 232 auto &DbiS = Err(File.getPDBDbiStream()); 233 BinarySubstreamRef NS = DbiS.getSectionContributionData(); 234 auto Layout = File.getStreamLayout(StreamDBI); 235 P.formatMsfStreamData("Section Contributions", File, Layout, NS); 236 } 237 238 void BytesOutputStyle::dumpSectionMap() { 239 printHeader(P, "Section Map"); 240 241 AutoIndent Indent(P); 242 243 auto &DbiS = Err(File.getPDBDbiStream()); 244 BinarySubstreamRef NS = DbiS.getSecMapSubstreamData(); 245 auto Layout = File.getStreamLayout(StreamDBI); 246 P.formatMsfStreamData("Section Map", File, Layout, NS); 247 } 248 249 void BytesOutputStyle::dumpModuleInfos() { 250 printHeader(P, "Module Infos"); 251 252 AutoIndent Indent(P); 253 254 auto &DbiS = Err(File.getPDBDbiStream()); 255 BinarySubstreamRef NS = DbiS.getModiSubstreamData(); 256 auto Layout = File.getStreamLayout(StreamDBI); 257 P.formatMsfStreamData("Module Infos", File, Layout, NS); 258 } 259 260 void BytesOutputStyle::dumpFileInfo() { 261 printHeader(P, "File Info"); 262 263 AutoIndent Indent(P); 264 265 auto &DbiS = Err(File.getPDBDbiStream()); 266 BinarySubstreamRef NS = DbiS.getFileInfoSubstreamData(); 267 auto Layout = File.getStreamLayout(StreamDBI); 268 P.formatMsfStreamData("File Info", File, Layout, NS); 269 } 270 271 void BytesOutputStyle::dumpTypeServerMap() { 272 printHeader(P, "Type Server Map"); 273 274 AutoIndent Indent(P); 275 276 auto &DbiS = Err(File.getPDBDbiStream()); 277 BinarySubstreamRef NS = DbiS.getTypeServerMapSubstreamData(); 278 auto Layout = File.getStreamLayout(StreamDBI); 279 P.formatMsfStreamData("Type Server Map", File, Layout, NS); 280 } 281 282 void BytesOutputStyle::dumpECData() { 283 printHeader(P, "Edit and Continue Data"); 284 285 AutoIndent Indent(P); 286 287 auto &DbiS = Err(File.getPDBDbiStream()); 288 BinarySubstreamRef NS = DbiS.getECSubstreamData(); 289 auto Layout = File.getStreamLayout(StreamDBI); 290 P.formatMsfStreamData("Edit and Continue Data", File, Layout, NS); 291 } 292 293 void BytesOutputStyle::dumpTypeIndex(uint32_t StreamIdx, 294 ArrayRef<uint32_t> Indices) { 295 assert(StreamIdx == StreamTPI || StreamIdx == StreamIPI); 296 assert(!Indices.empty()); 297 298 bool IsTpi = (StreamIdx == StreamTPI); 299 300 StringRef Label = IsTpi ? "Type (TPI) Records" : "Index (IPI) Records"; 301 printHeader(P, Label); 302 auto &Stream = Err(IsTpi ? File.getPDBTpiStream() : File.getPDBIpiStream()); 303 304 AutoIndent Indent(P); 305 306 auto Substream = Stream.getTypeRecordsSubstream(); 307 auto &Types = Err(initializeTypes(StreamIdx)); 308 auto Layout = File.getStreamLayout(StreamIdx); 309 for (const auto &Id : Indices) { 310 TypeIndex TI(Id); 311 if (TI.toArrayIndex() >= Types.capacity()) { 312 P.formatLine("Error: TypeIndex {0} does not exist", TI); 313 continue; 314 } 315 316 auto Type = Types.getType(TI); 317 uint32_t Offset = Types.getOffsetOfType(TI); 318 auto OneType = Substream.slice(Offset, Type.length()); 319 P.formatMsfStreamData(formatv("Type {0}", TI).str(), File, Layout, OneType); 320 } 321 } 322 323 template <typename CallbackT> 324 static void iterateOneModule(PDBFile &File, LinePrinter &P, 325 const DbiModuleList &Modules, uint32_t I, 326 uint32_t Digits, uint32_t IndentLevel, 327 CallbackT Callback) { 328 if (I >= Modules.getModuleCount()) { 329 P.formatLine("Mod {0:4} | Invalid module index ", 330 fmt_align(I, AlignStyle::Right, std::max(Digits, 4U))); 331 return; 332 } 333 334 auto Modi = Modules.getModuleDescriptor(I); 335 P.formatLine("Mod {0:4} | `{1}`: ", 336 fmt_align(I, AlignStyle::Right, std::max(Digits, 4U)), 337 Modi.getModuleName()); 338 339 uint16_t ModiStream = Modi.getModuleStreamIndex(); 340 AutoIndent Indent2(P, IndentLevel); 341 if (ModiStream == kInvalidStreamIndex) 342 return; 343 344 auto ModStreamData = MappedBlockStream::createIndexedStream( 345 File.getMsfLayout(), File.getMsfBuffer(), ModiStream, 346 File.getAllocator()); 347 ModuleDebugStreamRef ModStream(Modi, std::move(ModStreamData)); 348 if (auto EC = ModStream.reload()) { 349 P.formatLine("Could not parse debug information."); 350 return; 351 } 352 auto Layout = File.getStreamLayout(ModiStream); 353 Callback(I, ModStream, Layout); 354 } 355 356 template <typename CallbackT> 357 static void iterateModules(PDBFile &File, LinePrinter &P, uint32_t IndentLevel, 358 CallbackT Callback) { 359 AutoIndent Indent(P); 360 if (!File.hasPDBDbiStream()) { 361 P.formatLine("DBI Stream not present"); 362 return; 363 } 364 365 ExitOnError Err("Unexpected error processing modules"); 366 367 auto &Stream = Err(File.getPDBDbiStream()); 368 369 const DbiModuleList &Modules = Stream.modules(); 370 371 if (opts::bytes::ModuleIndex.getNumOccurrences() > 0) { 372 iterateOneModule(File, P, Modules, opts::bytes::ModuleIndex, 1, IndentLevel, 373 Callback); 374 } else { 375 uint32_t Count = Modules.getModuleCount(); 376 uint32_t Digits = NumDigits(Count); 377 for (uint32_t I = 0; I < Count; ++I) { 378 iterateOneModule(File, P, Modules, I, Digits, IndentLevel, Callback); 379 } 380 } 381 } 382 383 void BytesOutputStyle::dumpModuleSyms() { 384 printHeader(P, "Module Symbols"); 385 386 AutoIndent Indent(P); 387 388 iterateModules(File, P, 2, 389 [this](uint32_t Modi, const ModuleDebugStreamRef &Stream, 390 const MSFStreamLayout &Layout) { 391 auto Symbols = Stream.getSymbolsSubstream(); 392 P.formatMsfStreamData("Symbols", File, Layout, Symbols); 393 }); 394 } 395 396 void BytesOutputStyle::dumpModuleC11() { 397 printHeader(P, "C11 Debug Chunks"); 398 399 AutoIndent Indent(P); 400 401 iterateModules(File, P, 2, 402 [this](uint32_t Modi, const ModuleDebugStreamRef &Stream, 403 const MSFStreamLayout &Layout) { 404 auto Chunks = Stream.getC11LinesSubstream(); 405 P.formatMsfStreamData("C11 Debug Chunks", File, Layout, 406 Chunks); 407 }); 408 } 409 410 void BytesOutputStyle::dumpModuleC13() { 411 printHeader(P, "Debug Chunks"); 412 413 AutoIndent Indent(P); 414 415 iterateModules( 416 File, P, 2, 417 [this](uint32_t Modi, const ModuleDebugStreamRef &Stream, 418 const MSFStreamLayout &Layout) { 419 auto Chunks = Stream.getC13LinesSubstream(); 420 if (opts::bytes::SplitChunks) { 421 for (const auto &SS : Stream.subsections()) { 422 BinarySubstreamRef ThisChunk; 423 std::tie(ThisChunk, Chunks) = Chunks.split(SS.getRecordLength()); 424 P.formatMsfStreamData(formatChunkKind(SS.kind()), File, Layout, 425 ThisChunk); 426 } 427 } else { 428 P.formatMsfStreamData("Debug Chunks", File, Layout, Chunks); 429 } 430 }); 431 } 432 433 void BytesOutputStyle::dumpByteRanges(uint32_t Min, uint32_t Max) { 434 printHeader(P, "MSF Bytes"); 435 436 AutoIndent Indent(P); 437 438 BinaryStreamReader Reader(File.getMsfBuffer()); 439 ArrayRef<uint8_t> Data; 440 consumeError(Reader.skip(Min)); 441 uint32_t Size = Max - Min + 1; 442 auto EC = Reader.readBytes(Data, Size); 443 assert(!EC); 444 consumeError(std::move(EC)); 445 P.formatBinary("Bytes", Data, Min); 446 } 447 448 Expected<codeview::LazyRandomTypeCollection &> 449 BytesOutputStyle::initializeTypes(uint32_t StreamIdx) { 450 auto &TypeCollection = (StreamIdx == StreamTPI) ? TpiTypes : IpiTypes; 451 if (TypeCollection) 452 return *TypeCollection; 453 454 auto Tpi = (StreamIdx == StreamTPI) ? File.getPDBTpiStream() 455 : File.getPDBIpiStream(); 456 if (!Tpi) 457 return Tpi.takeError(); 458 459 auto &Types = Tpi->typeArray(); 460 uint32_t Count = Tpi->getNumTypeRecords(); 461 auto Offsets = Tpi->getTypeIndexOffsets(); 462 TypeCollection = 463 llvm::make_unique<LazyRandomTypeCollection>(Types, Count, Offsets); 464 465 return *TypeCollection; 466 } 467 468 void BytesOutputStyle::dumpFpm() { 469 printHeader(P, "Free Page Map"); 470 471 msf::MSFStreamLayout FpmLayout = File.getFpmStreamLayout(); 472 P.formatMsfStreamBlocks(File, FpmLayout); 473 } 474 475 void BytesOutputStyle::dumpStreamBytes() { 476 if (StreamPurposes.empty()) 477 discoverStreamPurposes(File, StreamPurposes); 478 479 printHeader(P, "Stream Data"); 480 ExitOnError Err("Unexpected error reading stream data"); 481 482 auto Specs = parseStreamSpecs(P); 483 484 for (const auto &Spec : Specs) { 485 AutoIndent Indent(P); 486 if (Spec.SI >= StreamPurposes.size()) { 487 P.formatLine("Stream {0}: Not present", Spec.SI); 488 continue; 489 } 490 P.formatMsfStreamData("Data", File, Spec.SI, 491 StreamPurposes[Spec.SI].getShortName(), Spec.Begin, 492 Spec.Size); 493 } 494 } 495