1 //===- DumpOutputStyle.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 "DumpOutputStyle.h" 11 12 #include "FormatUtil.h" 13 #include "MinimalSymbolDumper.h" 14 #include "MinimalTypeDumper.h" 15 #include "StreamUtil.h" 16 #include "llvm-pdbutil.h" 17 18 #include "llvm/ADT/STLExtras.h" 19 #include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h" 20 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" 21 #include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h" 22 #include "llvm/DebugInfo/CodeView/DebugCrossExSubsection.h" 23 #include "llvm/DebugInfo/CodeView/DebugCrossImpSubsection.h" 24 #include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h" 25 #include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h" 26 #include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h" 27 #include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h" 28 #include "llvm/DebugInfo/CodeView/DebugSubsectionVisitor.h" 29 #include "llvm/DebugInfo/CodeView/DebugSymbolsSubsection.h" 30 #include "llvm/DebugInfo/CodeView/DebugUnknownSubsection.h" 31 #include "llvm/DebugInfo/CodeView/EnumTables.h" 32 #include "llvm/DebugInfo/CodeView/Formatters.h" 33 #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" 34 #include "llvm/DebugInfo/CodeView/Line.h" 35 #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" 36 #include "llvm/DebugInfo/CodeView/SymbolDumper.h" 37 #include "llvm/DebugInfo/CodeView/SymbolVisitorCallbackPipeline.h" 38 #include "llvm/DebugInfo/CodeView/SymbolVisitorCallbacks.h" 39 #include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h" 40 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h" 41 #include "llvm/DebugInfo/MSF/MappedBlockStream.h" 42 #include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h" 43 #include "llvm/DebugInfo/PDB/Native/DbiStream.h" 44 #include "llvm/DebugInfo/PDB/Native/EnumTables.h" 45 #include "llvm/DebugInfo/PDB/Native/GlobalsStream.h" 46 #include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h" 47 #include "llvm/DebugInfo/PDB/Native/InfoStream.h" 48 #include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h" 49 #include "llvm/DebugInfo/PDB/Native/PDBFile.h" 50 #include "llvm/DebugInfo/PDB/Native/PublicsStream.h" 51 #include "llvm/DebugInfo/PDB/Native/RawError.h" 52 #include "llvm/DebugInfo/PDB/Native/TpiHashing.h" 53 #include "llvm/DebugInfo/PDB/Native/TpiStream.h" 54 #include "llvm/DebugInfo/PDB/PDBExtras.h" 55 #include "llvm/Object/COFF.h" 56 #include "llvm/Support/BinaryStreamReader.h" 57 #include "llvm/Support/FormatAdapters.h" 58 #include "llvm/Support/FormatVariadic.h" 59 60 #include <unordered_map> 61 62 using namespace llvm; 63 using namespace llvm::codeview; 64 using namespace llvm::msf; 65 using namespace llvm::pdb; 66 67 DumpOutputStyle::DumpOutputStyle(PDBFile &File) 68 : File(File), P(2, false, outs()) {} 69 70 Error DumpOutputStyle::dump() { 71 if (opts::dump::DumpSummary) { 72 if (auto EC = dumpFileSummary()) 73 return EC; 74 P.NewLine(); 75 } 76 77 if (opts::dump::DumpStreams) { 78 if (auto EC = dumpStreamSummary()) 79 return EC; 80 P.NewLine(); 81 } 82 83 if (opts::dump::DumpStringTable) { 84 if (auto EC = dumpStringTable()) 85 return EC; 86 P.NewLine(); 87 } 88 89 if (opts::dump::DumpModules) { 90 if (auto EC = dumpModules()) 91 return EC; 92 } 93 94 if (opts::dump::DumpModuleFiles) { 95 if (auto EC = dumpModuleFiles()) 96 return EC; 97 } 98 99 if (opts::dump::DumpLines) { 100 if (auto EC = dumpLines()) 101 return EC; 102 } 103 104 if (opts::dump::DumpInlineeLines) { 105 if (auto EC = dumpInlineeLines()) 106 return EC; 107 } 108 109 if (opts::dump::DumpXmi) { 110 if (auto EC = dumpXmi()) 111 return EC; 112 } 113 114 if (opts::dump::DumpXme) { 115 if (auto EC = dumpXme()) 116 return EC; 117 } 118 119 if (opts::dump::DumpTypes || opts::dump::DumpTypeExtras) { 120 if (auto EC = dumpTpiStream(StreamTPI)) 121 return EC; 122 } 123 124 if (opts::dump::DumpIds || opts::dump::DumpIdExtras) { 125 if (auto EC = dumpTpiStream(StreamIPI)) 126 return EC; 127 } 128 129 if (opts::dump::DumpPublics) { 130 if (auto EC = dumpPublics()) 131 return EC; 132 } 133 134 if (opts::dump::DumpSymbols) { 135 if (auto EC = dumpModuleSyms()) 136 return EC; 137 } 138 139 if (opts::dump::DumpSectionContribs) { 140 if (auto EC = dumpSectionContribs()) 141 return EC; 142 } 143 144 if (opts::dump::DumpSectionMap) { 145 if (auto EC = dumpSectionMap()) 146 return EC; 147 } 148 149 return Error::success(); 150 } 151 152 static void printHeader(LinePrinter &P, const Twine &S) { 153 P.NewLine(); 154 P.formatLine("{0,=60}", S); 155 P.formatLine("{0}", fmt_repeat('=', 60)); 156 } 157 158 Error DumpOutputStyle::dumpFileSummary() { 159 printHeader(P, "Summary"); 160 161 ExitOnError Err("Invalid PDB Format"); 162 163 AutoIndent Indent(P); 164 P.formatLine("Block Size: {0}", File.getBlockSize()); 165 P.formatLine("Number of blocks: {0}", File.getBlockCount()); 166 P.formatLine("Number of streams: {0}", File.getNumStreams()); 167 168 auto &PS = Err(File.getPDBInfoStream()); 169 P.formatLine("Signature: {0}", PS.getSignature()); 170 P.formatLine("Age: {0}", PS.getAge()); 171 P.formatLine("GUID: {0}", fmt_guid(PS.getGuid().Guid)); 172 P.formatLine("Features: {0:x+}", static_cast<uint32_t>(PS.getFeatures())); 173 P.formatLine("Has Debug Info: {0}", File.hasPDBDbiStream()); 174 P.formatLine("Has Types: {0}", File.hasPDBTpiStream()); 175 P.formatLine("Has IDs: {0}", File.hasPDBIpiStream()); 176 P.formatLine("Has Globals: {0}", File.hasPDBGlobalsStream()); 177 P.formatLine("Has Publics: {0}", File.hasPDBPublicsStream()); 178 if (File.hasPDBDbiStream()) { 179 auto &DBI = Err(File.getPDBDbiStream()); 180 P.formatLine("Is incrementally linked: {0}", DBI.isIncrementallyLinked()); 181 P.formatLine("Has conflicting types: {0}", DBI.hasCTypes()); 182 P.formatLine("Is stripped: {0}", DBI.isStripped()); 183 } 184 185 return Error::success(); 186 } 187 188 Error DumpOutputStyle::dumpStreamSummary() { 189 printHeader(P, "Streams"); 190 191 if (StreamPurposes.empty()) 192 discoverStreamPurposes(File, StreamPurposes); 193 194 AutoIndent Indent(P); 195 uint32_t StreamCount = File.getNumStreams(); 196 197 for (uint16_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) { 198 P.formatLine( 199 "Stream {0}: [{1}] ({2} bytes)", 200 fmt_align(StreamIdx, AlignStyle::Right, NumDigits(StreamCount)), 201 StreamPurposes[StreamIdx], File.getStreamByteSize(StreamIdx)); 202 if (opts::dump::DumpStreamBlocks) { 203 auto Blocks = File.getStreamBlockList(StreamIdx); 204 std::vector<uint32_t> BV(Blocks.begin(), Blocks.end()); 205 P.formatLine(" {0} Blocks: [{1}]", 206 fmt_repeat(' ', NumDigits(StreamCount)), 207 make_range(BV.begin(), BV.end())); 208 } 209 } 210 211 return Error::success(); 212 } 213 214 static Expected<ModuleDebugStreamRef> getModuleDebugStream(PDBFile &File, 215 uint32_t Index) { 216 ExitOnError Err("Unexpected error"); 217 218 auto &Dbi = Err(File.getPDBDbiStream()); 219 const auto &Modules = Dbi.modules(); 220 auto Modi = Modules.getModuleDescriptor(Index); 221 222 uint16_t ModiStream = Modi.getModuleStreamIndex(); 223 if (ModiStream == kInvalidStreamIndex) 224 return make_error<RawError>(raw_error_code::no_stream, 225 "Module stream not present"); 226 227 auto ModStreamData = MappedBlockStream::createIndexedStream( 228 File.getMsfLayout(), File.getMsfBuffer(), ModiStream, 229 File.getAllocator()); 230 231 ModuleDebugStreamRef ModS(Modi, std::move(ModStreamData)); 232 if (auto EC = ModS.reload()) 233 return make_error<RawError>(raw_error_code::corrupt_file, 234 "Invalid module stream"); 235 236 return std::move(ModS); 237 } 238 239 static std::string formatChecksumKind(FileChecksumKind Kind) { 240 switch (Kind) { 241 RETURN_CASE(FileChecksumKind, None, "None"); 242 RETURN_CASE(FileChecksumKind, MD5, "MD5"); 243 RETURN_CASE(FileChecksumKind, SHA1, "SHA-1"); 244 RETURN_CASE(FileChecksumKind, SHA256, "SHA-256"); 245 } 246 return formatUnknownEnum(Kind); 247 } 248 249 namespace { 250 class StringsAndChecksumsPrinter { 251 const DebugStringTableSubsectionRef &extractStringTable(PDBFile &File) { 252 ExitOnError Err("Unexpected error processing modules"); 253 return Err(File.getStringTable()).getStringTable(); 254 } 255 256 template <typename... Args> 257 void formatInternal(LinePrinter &Printer, bool Append, 258 Args &&... args) const { 259 if (Append) 260 Printer.format(std::forward<Args>(args)...); 261 else 262 Printer.formatLine(std::forward<Args>(args)...); 263 } 264 265 public: 266 StringsAndChecksumsPrinter(PDBFile &File, uint32_t Modi) 267 : Records(extractStringTable(File)) { 268 auto MDS = getModuleDebugStream(File, Modi); 269 if (!MDS) { 270 consumeError(MDS.takeError()); 271 return; 272 } 273 274 DebugStream = llvm::make_unique<ModuleDebugStreamRef>(std::move(*MDS)); 275 Records.initialize(MDS->subsections()); 276 if (Records.hasChecksums()) { 277 for (const auto &Entry : Records.checksums()) { 278 auto S = Records.strings().getString(Entry.FileNameOffset); 279 if (!S) 280 continue; 281 ChecksumsByFile[*S] = Entry; 282 } 283 } 284 } 285 286 Expected<StringRef> getNameFromStringTable(uint32_t Offset) const { 287 return Records.strings().getString(Offset); 288 } 289 290 void formatFromFileName(LinePrinter &Printer, StringRef File, 291 bool Append = false) const { 292 auto FC = ChecksumsByFile.find(File); 293 if (FC == ChecksumsByFile.end()) { 294 formatInternal(Printer, Append, "- (no checksum) {0}", File); 295 return; 296 } 297 298 formatInternal(Printer, Append, "- ({0}: {1}) {2}", 299 formatChecksumKind(FC->getValue().Kind), 300 toHex(FC->getValue().Checksum), File); 301 } 302 303 void formatFromChecksumsOffset(LinePrinter &Printer, uint32_t Offset, 304 bool Append = false) const { 305 if (!Records.hasChecksums()) { 306 formatInternal(Printer, Append, "(unknown file name offset {0})", Offset); 307 return; 308 } 309 310 auto Iter = Records.checksums().getArray().at(Offset); 311 if (Iter == Records.checksums().getArray().end()) { 312 formatInternal(Printer, Append, "(unknown file name offset {0})", Offset); 313 return; 314 } 315 316 uint32_t FO = Iter->FileNameOffset; 317 auto ExpectedFile = getNameFromStringTable(FO); 318 if (!ExpectedFile) { 319 formatInternal(Printer, Append, "(unknown file name offset {0})", Offset); 320 consumeError(ExpectedFile.takeError()); 321 return; 322 } 323 if (Iter->Kind == FileChecksumKind::None) { 324 formatInternal(Printer, Append, "{0} (no checksum)", *ExpectedFile); 325 } else { 326 formatInternal(Printer, Append, "{0} ({1}: {2})", *ExpectedFile, 327 formatChecksumKind(Iter->Kind), toHex(Iter->Checksum)); 328 } 329 } 330 331 std::unique_ptr<ModuleDebugStreamRef> DebugStream; 332 StringsAndChecksumsRef Records; 333 StringMap<FileChecksumEntry> ChecksumsByFile; 334 }; 335 } // namespace 336 337 template <typename CallbackT> 338 static void iterateModules(PDBFile &File, LinePrinter &P, uint32_t IndentLevel, 339 CallbackT Callback) { 340 AutoIndent Indent(P); 341 if (!File.hasPDBDbiStream()) { 342 P.formatLine("DBI Stream not present"); 343 return; 344 } 345 346 ExitOnError Err("Unexpected error processing modules"); 347 348 auto &Stream = Err(File.getPDBDbiStream()); 349 350 const DbiModuleList &Modules = Stream.modules(); 351 uint32_t Count = Modules.getModuleCount(); 352 uint32_t Digits = NumDigits(Count); 353 for (uint32_t I = 0; I < Count; ++I) { 354 auto Modi = Modules.getModuleDescriptor(I); 355 P.formatLine("Mod {0:4} | `{1}`: ", fmt_align(I, AlignStyle::Right, Digits), 356 Modi.getModuleName()); 357 358 StringsAndChecksumsPrinter Strings(File, I); 359 AutoIndent Indent2(P, IndentLevel); 360 Callback(I, Strings); 361 } 362 } 363 364 template <typename SubsectionT> 365 static void iterateModuleSubsections( 366 PDBFile &File, LinePrinter &P, uint32_t IndentLevel, 367 llvm::function_ref<void(uint32_t, StringsAndChecksumsPrinter &, 368 SubsectionT &)> 369 Callback) { 370 371 iterateModules( 372 File, P, IndentLevel, 373 [&File, &Callback](uint32_t Modi, StringsAndChecksumsPrinter &Strings) { 374 auto MDS = getModuleDebugStream(File, Modi); 375 if (!MDS) { 376 consumeError(MDS.takeError()); 377 return; 378 } 379 380 for (const auto &SS : MDS->subsections()) { 381 SubsectionT Subsection; 382 383 if (SS.kind() != Subsection.kind()) 384 continue; 385 386 BinaryStreamReader Reader(SS.getRecordData()); 387 if (auto EC = Subsection.initialize(Reader)) 388 continue; 389 Callback(Modi, Strings, Subsection); 390 } 391 }); 392 } 393 394 Error DumpOutputStyle::dumpModules() { 395 printHeader(P, "Modules"); 396 397 AutoIndent Indent(P); 398 if (!File.hasPDBDbiStream()) { 399 P.formatLine("DBI Stream not present"); 400 return Error::success(); 401 } 402 403 ExitOnError Err("Unexpected error processing modules"); 404 405 auto &Stream = Err(File.getPDBDbiStream()); 406 407 const DbiModuleList &Modules = Stream.modules(); 408 uint32_t Count = Modules.getModuleCount(); 409 uint32_t Digits = NumDigits(Count); 410 for (uint32_t I = 0; I < Count; ++I) { 411 auto Modi = Modules.getModuleDescriptor(I); 412 P.formatLine("Mod {0:4} | Name: `{1}`: ", 413 fmt_align(I, AlignStyle::Right, Digits), Modi.getModuleName()); 414 P.formatLine(" Obj: `{0}`: ", Modi.getObjFileName()); 415 P.formatLine(" debug stream: {0}, # files: {1}, has ec info: {2}", 416 Modi.getModuleStreamIndex(), Modi.getNumberOfFiles(), 417 Modi.hasECInfo()); 418 } 419 return Error::success(); 420 } 421 422 Error DumpOutputStyle::dumpModuleFiles() { 423 printHeader(P, "Files"); 424 425 ExitOnError Err("Unexpected error processing modules"); 426 427 iterateModules( 428 File, P, 11, 429 [this, &Err](uint32_t Modi, StringsAndChecksumsPrinter &Strings) { 430 auto &Stream = Err(File.getPDBDbiStream()); 431 432 const DbiModuleList &Modules = Stream.modules(); 433 for (const auto &F : Modules.source_files(Modi)) { 434 Strings.formatFromFileName(P, F); 435 } 436 }); 437 return Error::success(); 438 } 439 440 static void typesetLinesAndColumns(PDBFile &File, LinePrinter &P, 441 uint32_t Start, const LineColumnEntry &E) { 442 const uint32_t kMaxCharsPerLineNumber = 4; // 4 digit line number 443 uint32_t MinColumnWidth = kMaxCharsPerLineNumber + 5; 444 445 // Let's try to keep it under 100 characters 446 constexpr uint32_t kMaxRowLength = 100; 447 // At least 3 spaces between columns. 448 uint32_t ColumnsPerRow = kMaxRowLength / (MinColumnWidth + 3); 449 uint32_t ItemsLeft = E.LineNumbers.size(); 450 auto LineIter = E.LineNumbers.begin(); 451 while (ItemsLeft != 0) { 452 uint32_t RowColumns = std::min(ItemsLeft, ColumnsPerRow); 453 for (uint32_t I = 0; I < RowColumns; ++I) { 454 LineInfo Line(LineIter->Flags); 455 std::string LineStr; 456 if (Line.isAlwaysStepInto()) 457 LineStr = "ASI"; 458 else if (Line.isNeverStepInto()) 459 LineStr = "NSI"; 460 else 461 LineStr = utostr(Line.getStartLine()); 462 char Statement = Line.isStatement() ? ' ' : '!'; 463 P.format("{0} {1:X-} {2} ", 464 fmt_align(LineStr, AlignStyle::Right, kMaxCharsPerLineNumber), 465 fmt_align(Start + LineIter->Offset, AlignStyle::Right, 8, '0'), 466 Statement); 467 ++LineIter; 468 --ItemsLeft; 469 } 470 P.NewLine(); 471 } 472 } 473 474 Error DumpOutputStyle::dumpLines() { 475 printHeader(P, "Lines"); 476 477 uint32_t LastModi = UINT32_MAX; 478 uint32_t LastNameIndex = UINT32_MAX; 479 iterateModuleSubsections<DebugLinesSubsectionRef>( 480 File, P, 4, 481 [this, &LastModi, &LastNameIndex](uint32_t Modi, 482 StringsAndChecksumsPrinter &Strings, 483 DebugLinesSubsectionRef &Lines) { 484 uint16_t Segment = Lines.header()->RelocSegment; 485 uint32_t Begin = Lines.header()->RelocOffset; 486 uint32_t End = Begin + Lines.header()->CodeSize; 487 for (const auto &Block : Lines) { 488 if (LastModi != Modi || LastNameIndex != Block.NameIndex) { 489 LastModi = Modi; 490 LastNameIndex = Block.NameIndex; 491 Strings.formatFromChecksumsOffset(P, Block.NameIndex); 492 } 493 494 AutoIndent Indent(P, 2); 495 P.formatLine("{0:X-4}:{1:X-8}-{2:X-8}, ", Segment, Begin, End); 496 uint32_t Count = Block.LineNumbers.size(); 497 if (Lines.hasColumnInfo()) 498 P.format("line/column/addr entries = {0}", Count); 499 else 500 P.format("line/addr entries = {0}", Count); 501 502 P.NewLine(); 503 typesetLinesAndColumns(File, P, Begin, Block); 504 } 505 }); 506 507 return Error::success(); 508 } 509 510 Error DumpOutputStyle::dumpInlineeLines() { 511 printHeader(P, "Inlinee Lines"); 512 513 iterateModuleSubsections<DebugInlineeLinesSubsectionRef>( 514 File, P, 2, 515 [this](uint32_t Modi, StringsAndChecksumsPrinter &Strings, 516 DebugInlineeLinesSubsectionRef &Lines) { 517 P.formatLine("{0,+8} | {1,+5} | {2}", "Inlinee", "Line", "Source File"); 518 for (const auto &Entry : Lines) { 519 P.formatLine("{0,+8} | {1,+5} | ", Entry.Header->Inlinee, 520 fmtle(Entry.Header->SourceLineNum)); 521 Strings.formatFromChecksumsOffset(P, Entry.Header->FileID, true); 522 } 523 P.NewLine(); 524 }); 525 526 return Error::success(); 527 } 528 529 Error DumpOutputStyle::dumpXmi() { 530 printHeader(P, "Cross Module Imports"); 531 iterateModuleSubsections<DebugCrossModuleImportsSubsectionRef>( 532 File, P, 2, 533 [this](uint32_t Modi, StringsAndChecksumsPrinter &Strings, 534 DebugCrossModuleImportsSubsectionRef &Imports) { 535 P.formatLine("{0,=32} | {1}", "Imported Module", "Type IDs"); 536 537 for (const auto &Xmi : Imports) { 538 auto ExpectedModule = 539 Strings.getNameFromStringTable(Xmi.Header->ModuleNameOffset); 540 StringRef Module; 541 SmallString<32> ModuleStorage; 542 if (!ExpectedModule) { 543 Module = "(unknown module)"; 544 consumeError(ExpectedModule.takeError()); 545 } else 546 Module = *ExpectedModule; 547 if (Module.size() > 32) { 548 ModuleStorage = "..."; 549 ModuleStorage += Module.take_back(32 - 3); 550 Module = ModuleStorage; 551 } 552 std::vector<std::string> TIs; 553 for (const auto I : Xmi.Imports) 554 TIs.push_back(formatv("{0,+10:X+}", fmtle(I))); 555 std::string Result = 556 typesetItemList(TIs, P.getIndentLevel() + 35, 12, " "); 557 P.formatLine("{0,+32} | {1}", Module, Result); 558 } 559 }); 560 561 return Error::success(); 562 } 563 564 Error DumpOutputStyle::dumpXme() { 565 printHeader(P, "Cross Module Exports"); 566 567 iterateModuleSubsections<DebugCrossModuleExportsSubsectionRef>( 568 File, P, 2, 569 [this](uint32_t Modi, StringsAndChecksumsPrinter &Strings, 570 DebugCrossModuleExportsSubsectionRef &Exports) { 571 P.formatLine("{0,-10} | {1}", "Local ID", "Global ID"); 572 for (const auto &Export : Exports) { 573 P.formatLine("{0,+10:X+} | {1}", TypeIndex(Export.Local), 574 TypeIndex(Export.Global)); 575 } 576 }); 577 578 return Error::success(); 579 } 580 581 Error DumpOutputStyle::dumpStringTable() { 582 printHeader(P, "String Table"); 583 584 AutoIndent Indent(P); 585 auto IS = File.getStringTable(); 586 if (!IS) { 587 P.formatLine("Not present in file"); 588 consumeError(IS.takeError()); 589 return Error::success(); 590 } 591 592 if (IS->name_ids().empty()) { 593 P.formatLine("Empty"); 594 return Error::success(); 595 } 596 597 auto MaxID = std::max_element(IS->name_ids().begin(), IS->name_ids().end()); 598 uint32_t Digits = NumDigits(*MaxID); 599 600 P.formatLine("{0} | {1}", fmt_align("ID", AlignStyle::Right, Digits), 601 "String"); 602 603 std::vector<uint32_t> SortedIDs(IS->name_ids().begin(), IS->name_ids().end()); 604 std::sort(SortedIDs.begin(), SortedIDs.end()); 605 for (uint32_t I : SortedIDs) { 606 auto ES = IS->getStringForID(I); 607 llvm::SmallString<32> Str; 608 if (!ES) { 609 consumeError(ES.takeError()); 610 Str = "Error reading string"; 611 } else if (!ES->empty()) { 612 Str.append("'"); 613 Str.append(*ES); 614 Str.append("'"); 615 } 616 617 if (!Str.empty()) 618 P.formatLine("{0} | {1}", fmt_align(I, AlignStyle::Right, Digits), Str); 619 } 620 return Error::success(); 621 } 622 623 Error DumpOutputStyle::dumpTpiStream(uint32_t StreamIdx) { 624 assert(StreamIdx == StreamTPI || StreamIdx == StreamIPI); 625 626 bool Present = false; 627 bool DumpTypes = false; 628 bool DumpBytes = false; 629 bool DumpExtras = false; 630 std::vector<uint32_t> Indices; 631 if (StreamIdx == StreamTPI) { 632 printHeader(P, "Types (TPI Stream)"); 633 Present = File.hasPDBTpiStream(); 634 DumpTypes = opts::dump::DumpTypes; 635 DumpBytes = opts::dump::DumpTypeData; 636 DumpExtras = opts::dump::DumpTypeExtras; 637 Indices.assign(opts::dump::DumpTypeIndex.begin(), 638 opts::dump::DumpTypeIndex.end()); 639 } else if (StreamIdx == StreamIPI) { 640 printHeader(P, "Types (IPI Stream)"); 641 Present = File.hasPDBIpiStream(); 642 DumpTypes = opts::dump::DumpIds; 643 DumpBytes = opts::dump::DumpIdData; 644 DumpExtras = opts::dump::DumpIdExtras; 645 Indices.assign(opts::dump::DumpIdIndex.begin(), 646 opts::dump::DumpIdIndex.end()); 647 } 648 649 AutoIndent Indent(P); 650 if (!Present) { 651 P.formatLine("Stream not present"); 652 return Error::success(); 653 } 654 655 ExitOnError Err("Unexpected error processing types"); 656 657 auto &Stream = Err((StreamIdx == StreamTPI) ? File.getPDBTpiStream() 658 : File.getPDBIpiStream()); 659 660 auto &Types = Err(initializeTypes(StreamIdx)); 661 662 if (DumpTypes) { 663 P.formatLine("Showing {0:N} records", Stream.getNumTypeRecords()); 664 uint32_t Width = 665 NumDigits(TypeIndex::FirstNonSimpleIndex + Stream.getNumTypeRecords()); 666 667 MinimalTypeDumpVisitor V(P, Width + 2, DumpBytes, DumpExtras, Types, 668 Stream.getHashValues()); 669 670 if (Indices.empty()) { 671 if (auto EC = codeview::visitTypeStream(Types, V)) { 672 P.formatLine("An error occurred dumping type records: {0}", 673 toString(std::move(EC))); 674 } 675 } else { 676 for (const auto &I : Indices) { 677 TypeIndex TI(I); 678 CVType Type = Types.getType(TI); 679 if (auto EC = codeview::visitTypeRecord(Type, TI, V)) 680 P.formatLine("An error occurred dumping type record {0}: {1}", TI, 681 toString(std::move(EC))); 682 } 683 } 684 } 685 686 if (DumpExtras) { 687 P.NewLine(); 688 auto IndexOffsets = Stream.getTypeIndexOffsets(); 689 P.formatLine("Type Index Offsets:"); 690 for (const auto &IO : IndexOffsets) { 691 AutoIndent Indent2(P); 692 P.formatLine("TI: {0}, Offset: {1}", IO.Type, fmtle(IO.Offset)); 693 } 694 695 P.NewLine(); 696 P.formatLine("Hash Adjusters:"); 697 auto &Adjusters = Stream.getHashAdjusters(); 698 auto &Strings = Err(File.getStringTable()); 699 for (const auto &A : Adjusters) { 700 AutoIndent Indent2(P); 701 auto ExpectedStr = Strings.getStringForID(A.first); 702 TypeIndex TI(A.second); 703 if (ExpectedStr) 704 P.formatLine("`{0}` -> {1}", *ExpectedStr, TI); 705 else { 706 P.formatLine("unknown str id ({0}) -> {1}", A.first, TI); 707 consumeError(ExpectedStr.takeError()); 708 } 709 } 710 } 711 return Error::success(); 712 } 713 714 Expected<codeview::LazyRandomTypeCollection &> 715 DumpOutputStyle::initializeTypes(uint32_t SN) { 716 auto &TypeCollection = (SN == StreamTPI) ? TpiTypes : IpiTypes; 717 auto Tpi = 718 (SN == StreamTPI) ? File.getPDBTpiStream() : File.getPDBIpiStream(); 719 if (!Tpi) 720 return Tpi.takeError(); 721 722 if (!TypeCollection) { 723 auto &Types = Tpi->typeArray(); 724 uint32_t Count = Tpi->getNumTypeRecords(); 725 auto Offsets = Tpi->getTypeIndexOffsets(); 726 TypeCollection = 727 llvm::make_unique<LazyRandomTypeCollection>(Types, Count, Offsets); 728 } 729 730 return *TypeCollection; 731 } 732 733 Error DumpOutputStyle::dumpModuleSyms() { 734 printHeader(P, "Symbols"); 735 736 AutoIndent Indent(P); 737 if (!File.hasPDBDbiStream()) { 738 P.formatLine("DBI Stream not present"); 739 return Error::success(); 740 } 741 742 ExitOnError Err("Unexpected error processing symbols"); 743 744 auto &Stream = Err(File.getPDBDbiStream()); 745 746 auto &Types = Err(initializeTypes(StreamTPI)); 747 748 const DbiModuleList &Modules = Stream.modules(); 749 uint32_t Count = Modules.getModuleCount(); 750 uint32_t Digits = NumDigits(Count); 751 for (uint32_t I = 0; I < Count; ++I) { 752 auto Modi = Modules.getModuleDescriptor(I); 753 P.formatLine("Mod {0:4} | `{1}`: ", fmt_align(I, AlignStyle::Right, Digits), 754 Modi.getModuleName()); 755 uint16_t ModiStream = Modi.getModuleStreamIndex(); 756 if (ModiStream == kInvalidStreamIndex) { 757 P.formatLine(" <symbols not present>"); 758 continue; 759 } 760 auto ModStreamData = MappedBlockStream::createIndexedStream( 761 File.getMsfLayout(), File.getMsfBuffer(), ModiStream, 762 File.getAllocator()); 763 764 ModuleDebugStreamRef ModS(Modi, std::move(ModStreamData)); 765 if (auto EC = ModS.reload()) { 766 P.formatLine("Error loading module stream {0}. {1}", I, 767 toString(std::move(EC))); 768 continue; 769 } 770 771 SymbolVisitorCallbackPipeline Pipeline; 772 SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb); 773 MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Types); 774 775 Pipeline.addCallbackToPipeline(Deserializer); 776 Pipeline.addCallbackToPipeline(Dumper); 777 CVSymbolVisitor Visitor(Pipeline); 778 if (auto EC = Visitor.visitSymbolStream(ModS.getSymbolArray())) { 779 P.formatLine("Error while processing symbol records. {0}", 780 toString(std::move(EC))); 781 continue; 782 } 783 } 784 return Error::success(); 785 } 786 787 Error DumpOutputStyle::dumpPublics() { 788 printHeader(P, "Public Symbols"); 789 790 AutoIndent Indent(P); 791 if (!File.hasPDBPublicsStream()) { 792 P.formatLine("Publics stream not present"); 793 return Error::success(); 794 } 795 796 ExitOnError Err("Error dumping publics stream"); 797 798 auto &Types = Err(initializeTypes(StreamTPI)); 799 auto &Publics = Err(File.getPDBPublicsStream()); 800 SymbolVisitorCallbackPipeline Pipeline; 801 SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb); 802 MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Types); 803 804 Pipeline.addCallbackToPipeline(Deserializer); 805 Pipeline.addCallbackToPipeline(Dumper); 806 CVSymbolVisitor Visitor(Pipeline); 807 auto ExpectedSymbols = Publics.getSymbolArray(); 808 if (!ExpectedSymbols) { 809 P.formatLine("Could not read public symbol record stream"); 810 return Error::success(); 811 } 812 813 if (auto EC = Visitor.visitSymbolStream(*ExpectedSymbols)) 814 P.formatLine("Error while processing public symbol records. {0}", 815 toString(std::move(EC))); 816 817 return Error::success(); 818 } 819 820 static std::string formatSectionCharacteristics(uint32_t IndentLevel, 821 uint32_t C) { 822 using SC = COFF::SectionCharacteristics; 823 std::vector<std::string> Opts; 824 if (C == COFF::SC_Invalid) 825 return "invalid"; 826 if (C == 0) 827 return "none"; 828 829 PUSH_FLAG(SC, IMAGE_SCN_TYPE_NOLOAD, C, "IMAGE_SCN_TYPE_NOLOAD"); 830 PUSH_FLAG(SC, IMAGE_SCN_TYPE_NO_PAD, C, "IMAGE_SCN_TYPE_NO_PAD"); 831 PUSH_FLAG(SC, IMAGE_SCN_CNT_CODE, C, "IMAGE_SCN_CNT_CODE"); 832 PUSH_FLAG(SC, IMAGE_SCN_CNT_INITIALIZED_DATA, C, 833 "IMAGE_SCN_CNT_INITIALIZED_DATA"); 834 PUSH_FLAG(SC, IMAGE_SCN_CNT_UNINITIALIZED_DATA, C, 835 "IMAGE_SCN_CNT_UNINITIALIZED_DATA"); 836 PUSH_FLAG(SC, IMAGE_SCN_LNK_OTHER, C, "IMAGE_SCN_LNK_OTHER"); 837 PUSH_FLAG(SC, IMAGE_SCN_LNK_INFO, C, "IMAGE_SCN_LNK_INFO"); 838 PUSH_FLAG(SC, IMAGE_SCN_LNK_REMOVE, C, "IMAGE_SCN_LNK_REMOVE"); 839 PUSH_FLAG(SC, IMAGE_SCN_LNK_COMDAT, C, "IMAGE_SCN_LNK_COMDAT"); 840 PUSH_FLAG(SC, IMAGE_SCN_GPREL, C, "IMAGE_SCN_GPREL"); 841 PUSH_FLAG(SC, IMAGE_SCN_MEM_PURGEABLE, C, "IMAGE_SCN_MEM_PURGEABLE"); 842 PUSH_FLAG(SC, IMAGE_SCN_MEM_16BIT, C, "IMAGE_SCN_MEM_16BIT"); 843 PUSH_FLAG(SC, IMAGE_SCN_MEM_LOCKED, C, "IMAGE_SCN_MEM_LOCKED"); 844 PUSH_FLAG(SC, IMAGE_SCN_MEM_PRELOAD, C, "IMAGE_SCN_MEM_PRELOAD"); 845 PUSH_FLAG(SC, IMAGE_SCN_GPREL, C, "IMAGE_SCN_GPREL"); 846 PUSH_FLAG(SC, IMAGE_SCN_GPREL, C, "IMAGE_SCN_GPREL"); 847 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_1BYTES, C, 848 "IMAGE_SCN_ALIGN_1BYTES"); 849 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_2BYTES, C, 850 "IMAGE_SCN_ALIGN_2BYTES"); 851 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_4BYTES, C, 852 "IMAGE_SCN_ALIGN_4BYTES"); 853 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_8BYTES, C, 854 "IMAGE_SCN_ALIGN_8BYTES"); 855 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_16BYTES, C, 856 "IMAGE_SCN_ALIGN_16BYTES"); 857 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_32BYTES, C, 858 "IMAGE_SCN_ALIGN_32BYTES"); 859 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_64BYTES, C, 860 "IMAGE_SCN_ALIGN_64BYTES"); 861 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_128BYTES, C, 862 "IMAGE_SCN_ALIGN_128BYTES"); 863 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_256BYTES, C, 864 "IMAGE_SCN_ALIGN_256BYTES"); 865 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_512BYTES, C, 866 "IMAGE_SCN_ALIGN_512BYTES"); 867 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_1024BYTES, C, 868 "IMAGE_SCN_ALIGN_1024BYTES"); 869 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_2048BYTES, C, 870 "IMAGE_SCN_ALIGN_2048BYTES"); 871 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_4096BYTES, C, 872 "IMAGE_SCN_ALIGN_4096BYTES"); 873 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_8192BYTES, C, 874 "IMAGE_SCN_ALIGN_8192BYTES"); 875 PUSH_FLAG(SC, IMAGE_SCN_LNK_NRELOC_OVFL, C, "IMAGE_SCN_LNK_NRELOC_OVFL"); 876 PUSH_FLAG(SC, IMAGE_SCN_MEM_DISCARDABLE, C, "IMAGE_SCN_MEM_DISCARDABLE"); 877 PUSH_FLAG(SC, IMAGE_SCN_MEM_NOT_CACHED, C, "IMAGE_SCN_MEM_NOT_CACHED"); 878 PUSH_FLAG(SC, IMAGE_SCN_MEM_NOT_PAGED, C, "IMAGE_SCN_MEM_NOT_PAGED"); 879 PUSH_FLAG(SC, IMAGE_SCN_MEM_SHARED, C, "IMAGE_SCN_MEM_SHARED"); 880 PUSH_FLAG(SC, IMAGE_SCN_MEM_EXECUTE, C, "IMAGE_SCN_MEM_EXECUTE"); 881 PUSH_FLAG(SC, IMAGE_SCN_MEM_READ, C, "IMAGE_SCN_MEM_READ"); 882 PUSH_FLAG(SC, IMAGE_SCN_MEM_WRITE, C, "IMAGE_SCN_MEM_WRITE"); 883 return typesetItemList(Opts, IndentLevel, 3, " | "); 884 } 885 886 static std::string formatSegMapDescriptorFlag(uint32_t IndentLevel, 887 OMFSegDescFlags Flags) { 888 std::vector<std::string> Opts; 889 if (Flags == OMFSegDescFlags::None) 890 return "none"; 891 892 PUSH_FLAG(OMFSegDescFlags, Read, Flags, "read"); 893 PUSH_FLAG(OMFSegDescFlags, Write, Flags, "write"); 894 PUSH_FLAG(OMFSegDescFlags, Execute, Flags, "execute"); 895 PUSH_FLAG(OMFSegDescFlags, AddressIs32Bit, Flags, "32 bit addr"); 896 PUSH_FLAG(OMFSegDescFlags, IsSelector, Flags, "selector"); 897 PUSH_FLAG(OMFSegDescFlags, IsAbsoluteAddress, Flags, "absolute addr"); 898 PUSH_FLAG(OMFSegDescFlags, IsGroup, Flags, "group"); 899 return typesetItemList(Opts, IndentLevel, 4, " | "); 900 } 901 902 Error DumpOutputStyle::dumpSectionContribs() { 903 printHeader(P, "Section Contributions"); 904 ExitOnError Err("Error dumping publics stream"); 905 906 AutoIndent Indent(P); 907 if (!File.hasPDBDbiStream()) { 908 P.formatLine( 909 "Section contribs require a DBI Stream, which could not be loaded"); 910 return Error::success(); 911 } 912 913 auto &Dbi = Err(File.getPDBDbiStream()); 914 915 class Visitor : public ISectionContribVisitor { 916 public: 917 Visitor(LinePrinter &P) : P(P) {} 918 void visit(const SectionContrib &SC) override { 919 P.formatLine( 920 "SC | mod = {2}, {0}, size = {1}, data crc = {3}, reloc crc = {4}", 921 formatSegmentOffset(SC.ISect, SC.Off), fmtle(SC.Size), fmtle(SC.Imod), 922 fmtle(SC.DataCrc), fmtle(SC.RelocCrc)); 923 P.formatLine(" {0}", 924 formatSectionCharacteristics(P.getIndentLevel() + 6, 925 SC.Characteristics)); 926 } 927 void visit(const SectionContrib2 &SC) override { 928 P.formatLine("SC2 | mod = {2}, {0}, size = {1}, data crc = {3}, reloc " 929 "crc = {4}, coff section = {5}", 930 formatSegmentOffset(SC.Base.ISect, SC.Base.Off), 931 fmtle(SC.Base.Size), fmtle(SC.Base.Imod), 932 fmtle(SC.Base.DataCrc), fmtle(SC.Base.RelocCrc), 933 fmtle(SC.ISectCoff)); 934 P.formatLine(" {0}", 935 formatSectionCharacteristics(P.getIndentLevel() + 6, 936 SC.Base.Characteristics)); 937 } 938 939 private: 940 LinePrinter &P; 941 }; 942 943 Visitor V(P); 944 Dbi.visitSectionContributions(V); 945 return Error::success(); 946 } 947 948 Error DumpOutputStyle::dumpSectionMap() { 949 printHeader(P, "Section Map"); 950 ExitOnError Err("Error dumping section map"); 951 952 AutoIndent Indent(P); 953 if (!File.hasPDBDbiStream()) { 954 P.formatLine("Dumping the section map requires a DBI Stream, which could " 955 "not be loaded"); 956 return Error::success(); 957 } 958 959 auto &Dbi = Err(File.getPDBDbiStream()); 960 961 uint32_t I = 0; 962 for (auto &M : Dbi.getSectionMap()) { 963 P.formatLine( 964 "Section {0:4} | ovl = {0}, group = {1}, frame = {2}, name = {3}", I, 965 fmtle(M.Ovl), fmtle(M.Group), fmtle(M.Frame), fmtle(M.SecName)); 966 P.formatLine(" class = {0}, offset = {1}, size = {2}", 967 fmtle(M.ClassName), fmtle(M.Offset), fmtle(M.SecByteLength)); 968 P.formatLine(" flags = {0}", 969 formatSegMapDescriptorFlag( 970 P.getIndentLevel() + 13, 971 static_cast<OMFSegDescFlags>(uint16_t(M.Flags)))); 972 ++I; 973 } 974 return Error::success(); 975 } 976