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 "InputFile.h" 14 #include "MinimalSymbolDumper.h" 15 #include "MinimalTypeDumper.h" 16 #include "StreamUtil.h" 17 #include "llvm-pdbutil.h" 18 19 #include "llvm/ADT/STLExtras.h" 20 #include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h" 21 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" 22 #include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h" 23 #include "llvm/DebugInfo/CodeView/DebugCrossExSubsection.h" 24 #include "llvm/DebugInfo/CodeView/DebugCrossImpSubsection.h" 25 #include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h" 26 #include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h" 27 #include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h" 28 #include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h" 29 #include "llvm/DebugInfo/CodeView/DebugSymbolsSubsection.h" 30 #include "llvm/DebugInfo/CodeView/Formatters.h" 31 #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" 32 #include "llvm/DebugInfo/CodeView/Line.h" 33 #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" 34 #include "llvm/DebugInfo/CodeView/SymbolVisitorCallbackPipeline.h" 35 #include "llvm/DebugInfo/CodeView/SymbolVisitorCallbacks.h" 36 #include "llvm/DebugInfo/CodeView/TypeHashing.h" 37 #include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h" 38 #include "llvm/DebugInfo/MSF/MappedBlockStream.h" 39 #include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h" 40 #include "llvm/DebugInfo/PDB/Native/DbiStream.h" 41 #include "llvm/DebugInfo/PDB/Native/GlobalsStream.h" 42 #include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h" 43 #include "llvm/DebugInfo/PDB/Native/InfoStream.h" 44 #include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h" 45 #include "llvm/DebugInfo/PDB/Native/PDBFile.h" 46 #include "llvm/DebugInfo/PDB/Native/PublicsStream.h" 47 #include "llvm/DebugInfo/PDB/Native/RawError.h" 48 #include "llvm/DebugInfo/PDB/Native/SymbolStream.h" 49 #include "llvm/DebugInfo/PDB/Native/TpiHashing.h" 50 #include "llvm/DebugInfo/PDB/Native/TpiStream.h" 51 #include "llvm/Object/COFF.h" 52 #include "llvm/Support/BinaryStreamReader.h" 53 #include "llvm/Support/FormatAdapters.h" 54 #include "llvm/Support/FormatVariadic.h" 55 56 #include <cctype> 57 58 using namespace llvm; 59 using namespace llvm::codeview; 60 using namespace llvm::msf; 61 using namespace llvm::pdb; 62 63 DumpOutputStyle::DumpOutputStyle(InputFile &File) 64 : File(File), P(2, false, outs()) {} 65 66 PDBFile &DumpOutputStyle::getPdb() { return File.pdb(); } 67 object::COFFObjectFile &DumpOutputStyle::getObj() { return File.obj(); } 68 69 void DumpOutputStyle::printStreamNotValidForObj() { 70 AutoIndent Indent(P, 4); 71 P.formatLine("Dumping this stream is not valid for object files"); 72 } 73 74 void DumpOutputStyle::printStreamNotPresent(StringRef StreamName) { 75 AutoIndent Indent(P, 4); 76 P.formatLine("{0} stream not present", StreamName); 77 } 78 79 Error DumpOutputStyle::dump() { 80 if (opts::dump::DumpSummary) { 81 if (auto EC = dumpFileSummary()) 82 return EC; 83 P.NewLine(); 84 } 85 86 if (opts::dump::DumpStreams) { 87 if (auto EC = dumpStreamSummary()) 88 return EC; 89 P.NewLine(); 90 } 91 92 if (opts::dump::DumpSymbolStats) { 93 if (auto EC = dumpSymbolStats()) 94 return EC; 95 P.NewLine(); 96 } 97 98 if (opts::dump::DumpUdtStats) { 99 if (auto EC = dumpUdtStats()) 100 return EC; 101 P.NewLine(); 102 } 103 104 if (opts::dump::DumpNamedStreams) { 105 if (auto EC = dumpNamedStreams()) 106 return EC; 107 P.NewLine(); 108 } 109 110 if (opts::dump::DumpStringTable || opts::dump::DumpStringTableDetails) { 111 if (auto EC = dumpStringTable()) 112 return EC; 113 P.NewLine(); 114 } 115 116 if (opts::dump::DumpModules) { 117 if (auto EC = dumpModules()) 118 return EC; 119 } 120 121 if (opts::dump::DumpModuleFiles) { 122 if (auto EC = dumpModuleFiles()) 123 return EC; 124 } 125 126 if (opts::dump::DumpLines) { 127 if (auto EC = dumpLines()) 128 return EC; 129 } 130 131 if (opts::dump::DumpInlineeLines) { 132 if (auto EC = dumpInlineeLines()) 133 return EC; 134 } 135 136 if (opts::dump::DumpXmi) { 137 if (auto EC = dumpXmi()) 138 return EC; 139 } 140 141 if (opts::dump::DumpXme) { 142 if (auto EC = dumpXme()) 143 return EC; 144 } 145 146 if (opts::dump::DumpFpo) { 147 if (auto EC = dumpFpo()) 148 return EC; 149 } 150 151 if (File.isObj()) { 152 if (opts::dump::DumpTypes || !opts::dump::DumpTypeIndex.empty() || 153 opts::dump::DumpTypeExtras) 154 if (auto EC = dumpTypesFromObjectFile()) 155 return EC; 156 } else { 157 if (opts::dump::DumpTypes || !opts::dump::DumpTypeIndex.empty() || 158 opts::dump::DumpTypeExtras) { 159 if (auto EC = dumpTpiStream(StreamTPI)) 160 return EC; 161 } 162 163 if (opts::dump::DumpIds || !opts::dump::DumpIdIndex.empty() || 164 opts::dump::DumpIdExtras) { 165 if (auto EC = dumpTpiStream(StreamIPI)) 166 return EC; 167 } 168 } 169 170 if (opts::dump::DumpGSIRecords) { 171 if (auto EC = dumpGSIRecords()) 172 return EC; 173 } 174 175 if (opts::dump::DumpGlobals) { 176 if (auto EC = dumpGlobals()) 177 return EC; 178 } 179 180 if (opts::dump::DumpPublics) { 181 if (auto EC = dumpPublics()) 182 return EC; 183 } 184 185 if (opts::dump::DumpSymbols) { 186 auto EC = File.isPdb() ? dumpModuleSymsForPdb() : dumpModuleSymsForObj(); 187 if (EC) 188 return EC; 189 } 190 191 if (opts::dump::DumpSectionHeaders) { 192 if (auto EC = dumpSectionHeaders()) 193 return EC; 194 } 195 196 if (opts::dump::DumpSectionContribs) { 197 if (auto EC = dumpSectionContribs()) 198 return EC; 199 } 200 201 if (opts::dump::DumpSectionMap) { 202 if (auto EC = dumpSectionMap()) 203 return EC; 204 } 205 206 return Error::success(); 207 } 208 209 static void printHeader(LinePrinter &P, const Twine &S) { 210 P.NewLine(); 211 P.formatLine("{0,=60}", S); 212 P.formatLine("{0}", fmt_repeat('=', 60)); 213 } 214 215 Error DumpOutputStyle::dumpFileSummary() { 216 printHeader(P, "Summary"); 217 218 if (File.isObj()) { 219 printStreamNotValidForObj(); 220 return Error::success(); 221 } 222 223 AutoIndent Indent(P); 224 ExitOnError Err("Invalid PDB Format: "); 225 226 P.formatLine("Block Size: {0}", getPdb().getBlockSize()); 227 P.formatLine("Number of blocks: {0}", getPdb().getBlockCount()); 228 P.formatLine("Number of streams: {0}", getPdb().getNumStreams()); 229 230 auto &PS = Err(getPdb().getPDBInfoStream()); 231 P.formatLine("Signature: {0}", PS.getSignature()); 232 P.formatLine("Age: {0}", PS.getAge()); 233 P.formatLine("GUID: {0}", fmt_guid(PS.getGuid().Guid)); 234 P.formatLine("Features: {0:x+}", static_cast<uint32_t>(PS.getFeatures())); 235 P.formatLine("Has Debug Info: {0}", getPdb().hasPDBDbiStream()); 236 P.formatLine("Has Types: {0}", getPdb().hasPDBTpiStream()); 237 P.formatLine("Has IDs: {0}", getPdb().hasPDBIpiStream()); 238 P.formatLine("Has Globals: {0}", getPdb().hasPDBGlobalsStream()); 239 P.formatLine("Has Publics: {0}", getPdb().hasPDBPublicsStream()); 240 if (getPdb().hasPDBDbiStream()) { 241 auto &DBI = Err(getPdb().getPDBDbiStream()); 242 P.formatLine("Is incrementally linked: {0}", DBI.isIncrementallyLinked()); 243 P.formatLine("Has conflicting types: {0}", DBI.hasCTypes()); 244 P.formatLine("Is stripped: {0}", DBI.isStripped()); 245 } 246 247 return Error::success(); 248 } 249 250 static StatCollection getSymbolStats(const SymbolGroup &SG, 251 StatCollection &CumulativeStats) { 252 StatCollection Stats; 253 if (SG.getFile().isPdb() && SG.hasDebugStream()) { 254 // For PDB files, all symbols are packed into one stream. 255 for (const auto &S : SG.getPdbModuleStream().symbols(nullptr)) { 256 Stats.update(S.kind(), S.length()); 257 CumulativeStats.update(S.kind(), S.length()); 258 } 259 return Stats; 260 } 261 262 for (const auto &SS : SG.getDebugSubsections()) { 263 // For object files, all symbols are spread across multiple Symbol 264 // subsections of a given .debug$S section. 265 if (SS.kind() != DebugSubsectionKind::Symbols) 266 continue; 267 DebugSymbolsSubsectionRef Symbols; 268 BinaryStreamReader Reader(SS.getRecordData()); 269 cantFail(Symbols.initialize(Reader)); 270 for (const auto &S : Symbols) { 271 Stats.update(S.kind(), S.length()); 272 CumulativeStats.update(S.kind(), S.length()); 273 } 274 } 275 return Stats; 276 } 277 278 static StatCollection getChunkStats(const SymbolGroup &SG, 279 StatCollection &CumulativeStats) { 280 StatCollection Stats; 281 for (const auto &Chunk : SG.getDebugSubsections()) { 282 Stats.update(uint32_t(Chunk.kind()), Chunk.getRecordLength()); 283 CumulativeStats.update(uint32_t(Chunk.kind()), Chunk.getRecordLength()); 284 } 285 return Stats; 286 } 287 288 static inline std::string formatModuleDetailKind(DebugSubsectionKind K) { 289 return formatChunkKind(K, false); 290 } 291 292 static inline std::string formatModuleDetailKind(SymbolKind K) { 293 return formatSymbolKind(K); 294 } 295 296 template <typename Kind> 297 static void printModuleDetailStats(LinePrinter &P, StringRef Label, 298 const StatCollection &Stats) { 299 P.NewLine(); 300 P.formatLine(" {0}", Label); 301 AutoIndent Indent(P); 302 P.formatLine("{0,40}: {1,7} entries ({2,8} bytes)", "Total", 303 Stats.Totals.Count, Stats.Totals.Size); 304 P.formatLine("{0}", fmt_repeat('-', 74)); 305 for (const auto &K : Stats.Individual) { 306 std::string KindName = formatModuleDetailKind(Kind(K.first)); 307 P.formatLine("{0,40}: {1,7} entries ({2,8} bytes)", KindName, 308 K.second.Count, K.second.Size); 309 } 310 } 311 312 static bool isMyCode(const SymbolGroup &Group) { 313 if (Group.getFile().isObj()) 314 return true; 315 316 StringRef Name = Group.name(); 317 if (Name.startswith("Import:")) 318 return false; 319 if (Name.endswith_lower(".dll")) 320 return false; 321 if (Name.equals_lower("* linker *")) 322 return false; 323 if (Name.startswith_lower("f:\\binaries\\Intermediate\\vctools")) 324 return false; 325 if (Name.startswith_lower("f:\\dd\\vctools\\crt")) 326 return false; 327 return true; 328 } 329 330 static bool shouldDumpSymbolGroup(uint32_t Idx, const SymbolGroup &Group) { 331 if (opts::dump::JustMyCode && !isMyCode(Group)) 332 return false; 333 334 // If the arg was not specified on the command line, always dump all modules. 335 if (opts::dump::DumpModi.getNumOccurrences() == 0) 336 return true; 337 338 // Otherwise, only dump if this is the same module specified. 339 return (opts::dump::DumpModi == Idx); 340 } 341 342 Error DumpOutputStyle::dumpStreamSummary() { 343 printHeader(P, "Streams"); 344 345 if (File.isObj()) { 346 printStreamNotValidForObj(); 347 return Error::success(); 348 } 349 350 AutoIndent Indent(P); 351 352 if (StreamPurposes.empty()) 353 discoverStreamPurposes(getPdb(), StreamPurposes); 354 355 uint32_t StreamCount = getPdb().getNumStreams(); 356 uint32_t MaxStreamSize = getPdb().getMaxStreamSize(); 357 358 for (uint16_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) { 359 P.formatLine( 360 "Stream {0} ({1} bytes): [{2}]", 361 fmt_align(StreamIdx, AlignStyle::Right, NumDigits(StreamCount)), 362 fmt_align(getPdb().getStreamByteSize(StreamIdx), AlignStyle::Right, 363 NumDigits(MaxStreamSize)), 364 StreamPurposes[StreamIdx].getLongName()); 365 366 if (opts::dump::DumpStreamBlocks) { 367 auto Blocks = getPdb().getStreamBlockList(StreamIdx); 368 std::vector<uint32_t> BV(Blocks.begin(), Blocks.end()); 369 P.formatLine(" {0} Blocks: [{1}]", 370 fmt_repeat(' ', NumDigits(StreamCount)), 371 make_range(BV.begin(), BV.end())); 372 } 373 } 374 375 return Error::success(); 376 } 377 378 static Expected<ModuleDebugStreamRef> getModuleDebugStream(PDBFile &File, 379 uint32_t Index) { 380 ExitOnError Err("Unexpected error: "); 381 382 auto &Dbi = Err(File.getPDBDbiStream()); 383 const auto &Modules = Dbi.modules(); 384 auto Modi = Modules.getModuleDescriptor(Index); 385 386 uint16_t ModiStream = Modi.getModuleStreamIndex(); 387 if (ModiStream == kInvalidStreamIndex) 388 return make_error<RawError>(raw_error_code::no_stream, 389 "Module stream not present"); 390 391 auto ModStreamData = File.createIndexedStream(ModiStream); 392 393 ModuleDebugStreamRef ModS(Modi, std::move(ModStreamData)); 394 if (auto EC = ModS.reload()) 395 return make_error<RawError>(raw_error_code::corrupt_file, 396 "Invalid module stream"); 397 398 return std::move(ModS); 399 } 400 401 template <typename CallbackT> 402 static void 403 iterateOneModule(InputFile &File, const Optional<PrintScope> &HeaderScope, 404 const SymbolGroup &SG, uint32_t Modi, CallbackT Callback) { 405 if (HeaderScope) { 406 HeaderScope->P.formatLine( 407 "Mod {0:4} | `{1}`: ", 408 fmt_align(Modi, AlignStyle::Right, HeaderScope->LabelWidth), SG.name()); 409 } 410 411 AutoIndent Indent(HeaderScope); 412 Callback(Modi, SG); 413 } 414 415 template <typename CallbackT> 416 static void iterateSymbolGroups(InputFile &Input, 417 const Optional<PrintScope> &HeaderScope, 418 CallbackT Callback) { 419 AutoIndent Indent(HeaderScope); 420 421 ExitOnError Err("Unexpected error processing modules: "); 422 423 if (opts::dump::DumpModi.getNumOccurrences() > 0) { 424 assert(opts::dump::DumpModi.getNumOccurrences() == 1); 425 uint32_t Modi = opts::dump::DumpModi; 426 SymbolGroup SG(&Input, Modi); 427 iterateOneModule(Input, withLabelWidth(HeaderScope, NumDigits(Modi)), SG, 428 Modi, Callback); 429 return; 430 } 431 432 uint32_t I = 0; 433 434 for (const auto &SG : Input.symbol_groups()) { 435 if (shouldDumpSymbolGroup(I, SG)) 436 iterateOneModule(Input, withLabelWidth(HeaderScope, NumDigits(I)), SG, I, 437 Callback); 438 439 ++I; 440 } 441 } 442 443 template <typename SubsectionT> 444 static void iterateModuleSubsections( 445 InputFile &File, const Optional<PrintScope> &HeaderScope, 446 llvm::function_ref<void(uint32_t, const SymbolGroup &, SubsectionT &)> 447 Callback) { 448 449 iterateSymbolGroups(File, HeaderScope, 450 [&](uint32_t Modi, const SymbolGroup &SG) { 451 for (const auto &SS : SG.getDebugSubsections()) { 452 SubsectionT Subsection; 453 454 if (SS.kind() != Subsection.kind()) 455 continue; 456 457 BinaryStreamReader Reader(SS.getRecordData()); 458 if (auto EC = Subsection.initialize(Reader)) 459 continue; 460 Callback(Modi, SG, Subsection); 461 } 462 }); 463 } 464 465 static Expected<std::pair<std::unique_ptr<MappedBlockStream>, 466 ArrayRef<llvm::object::coff_section>>> 467 loadSectionHeaders(PDBFile &File, DbgHeaderType Type) { 468 if (!File.hasPDBDbiStream()) 469 return make_error<StringError>( 470 "Section headers require a DBI Stream, which could not be loaded", 471 inconvertibleErrorCode()); 472 473 auto &Dbi = cantFail(File.getPDBDbiStream()); 474 uint32_t SI = Dbi.getDebugStreamIndex(Type); 475 476 if (SI == kInvalidStreamIndex) 477 return make_error<StringError>( 478 "PDB does not contain the requested image section header type", 479 inconvertibleErrorCode()); 480 481 auto Stream = File.createIndexedStream(SI); 482 if (!Stream) 483 return make_error<StringError>("Could not load the required stream data", 484 inconvertibleErrorCode()); 485 486 ArrayRef<object::coff_section> Headers; 487 if (Stream->getLength() % sizeof(object::coff_section) != 0) 488 return make_error<StringError>( 489 "Section header array size is not a multiple of section header size", 490 inconvertibleErrorCode()); 491 492 uint32_t NumHeaders = Stream->getLength() / sizeof(object::coff_section); 493 BinaryStreamReader Reader(*Stream); 494 cantFail(Reader.readArray(Headers, NumHeaders)); 495 return std::make_pair(std::move(Stream), Headers); 496 } 497 498 static std::vector<std::string> getSectionNames(PDBFile &File) { 499 auto ExpectedHeaders = loadSectionHeaders(File, DbgHeaderType::SectionHdr); 500 if (!ExpectedHeaders) 501 return {}; 502 503 std::unique_ptr<MappedBlockStream> Stream; 504 ArrayRef<object::coff_section> Headers; 505 std::tie(Stream, Headers) = std::move(*ExpectedHeaders); 506 std::vector<std::string> Names; 507 for (const auto &H : Headers) 508 Names.push_back(H.Name); 509 return Names; 510 } 511 512 static void dumpSectionContrib(LinePrinter &P, const SectionContrib &SC, 513 ArrayRef<std::string> SectionNames, 514 uint32_t FieldWidth) { 515 std::string NameInsert; 516 if (SC.ISect > 0 && SC.ISect <= SectionNames.size()) { 517 StringRef SectionName = SectionNames[SC.ISect - 1]; 518 NameInsert = formatv("[{0}]", SectionName).str(); 519 } else 520 NameInsert = "[???]"; 521 P.formatLine("SC{5} | mod = {2}, {0}, size = {1}, data crc = {3}, reloc " 522 "crc = {4}", 523 formatSegmentOffset(SC.ISect, SC.Off), fmtle(SC.Size), 524 fmtle(SC.Imod), fmtle(SC.DataCrc), fmtle(SC.RelocCrc), 525 fmt_align(NameInsert, AlignStyle::Left, FieldWidth + 2)); 526 AutoIndent Indent(P, FieldWidth + 2); 527 P.formatLine(" {0}", 528 formatSectionCharacteristics(P.getIndentLevel() + 6, 529 SC.Characteristics, 3, " | ")); 530 } 531 532 static void dumpSectionContrib(LinePrinter &P, const SectionContrib2 &SC, 533 ArrayRef<std::string> SectionNames, 534 uint32_t FieldWidth) { 535 P.formatLine("SC2[{6}] | mod = {2}, {0}, size = {1}, data crc = {3}, reloc " 536 "crc = {4}, coff section = {5}", 537 formatSegmentOffset(SC.Base.ISect, SC.Base.Off), 538 fmtle(SC.Base.Size), fmtle(SC.Base.Imod), fmtle(SC.Base.DataCrc), 539 fmtle(SC.Base.RelocCrc), fmtle(SC.ISectCoff)); 540 P.formatLine(" {0}", 541 formatSectionCharacteristics(P.getIndentLevel() + 6, 542 SC.Base.Characteristics, 3, " | ")); 543 } 544 545 Error DumpOutputStyle::dumpModules() { 546 printHeader(P, "Modules"); 547 548 if (File.isObj()) { 549 printStreamNotValidForObj(); 550 return Error::success(); 551 } 552 553 if (!getPdb().hasPDBDbiStream()) { 554 printStreamNotPresent("DBI"); 555 return Error::success(); 556 } 557 558 AutoIndent Indent(P); 559 ExitOnError Err("Unexpected error processing modules: "); 560 561 auto &Stream = Err(getPdb().getPDBDbiStream()); 562 563 const DbiModuleList &Modules = Stream.modules(); 564 iterateSymbolGroups( 565 File, PrintScope{P, 11}, [&](uint32_t Modi, const SymbolGroup &Strings) { 566 auto Desc = Modules.getModuleDescriptor(Modi); 567 if (opts::dump::DumpSectionContribs) { 568 std::vector<std::string> Sections = getSectionNames(getPdb()); 569 dumpSectionContrib(P, Desc.getSectionContrib(), Sections, 0); 570 } 571 P.formatLine("Obj: `{0}`: ", Desc.getObjFileName()); 572 P.formatLine("debug stream: {0}, # files: {1}, has ec info: {2}", 573 Desc.getModuleStreamIndex(), Desc.getNumberOfFiles(), 574 Desc.hasECInfo()); 575 StringRef PdbFilePath = 576 Err(Stream.getECName(Desc.getPdbFilePathNameIndex())); 577 StringRef SrcFilePath = 578 Err(Stream.getECName(Desc.getSourceFileNameIndex())); 579 P.formatLine("pdb file ni: {0} `{1}`, src file ni: {2} `{3}`", 580 Desc.getPdbFilePathNameIndex(), PdbFilePath, 581 Desc.getSourceFileNameIndex(), SrcFilePath); 582 }); 583 return Error::success(); 584 } 585 586 Error DumpOutputStyle::dumpModuleFiles() { 587 printHeader(P, "Files"); 588 589 if (File.isObj()) { 590 printStreamNotValidForObj(); 591 return Error::success(); 592 } 593 594 if (!getPdb().hasPDBDbiStream()) { 595 printStreamNotPresent("DBI"); 596 return Error::success(); 597 } 598 599 ExitOnError Err("Unexpected error processing modules: "); 600 601 iterateSymbolGroups(File, PrintScope{P, 11}, 602 [this, &Err](uint32_t Modi, const SymbolGroup &Strings) { 603 auto &Stream = Err(getPdb().getPDBDbiStream()); 604 605 const DbiModuleList &Modules = Stream.modules(); 606 for (const auto &F : Modules.source_files(Modi)) { 607 Strings.formatFromFileName(P, F); 608 } 609 }); 610 return Error::success(); 611 } 612 613 Error DumpOutputStyle::dumpSymbolStats() { 614 printHeader(P, "Module Stats"); 615 616 if (File.isPdb() && !getPdb().hasPDBDbiStream()) { 617 printStreamNotPresent("DBI"); 618 return Error::success(); 619 } 620 621 ExitOnError Err("Unexpected error processing modules: "); 622 623 StatCollection SymStats; 624 StatCollection ChunkStats; 625 626 Optional<PrintScope> Scope; 627 if (File.isPdb()) 628 Scope.emplace(P, 2); 629 630 iterateSymbolGroups(File, Scope, [&](uint32_t Modi, const SymbolGroup &SG) { 631 StatCollection SS = getSymbolStats(SG, SymStats); 632 StatCollection CS = getChunkStats(SG, ChunkStats); 633 634 if (SG.getFile().isPdb()) { 635 AutoIndent Indent(P); 636 auto Modules = cantFail(File.pdb().getPDBDbiStream()).modules(); 637 uint32_t ModCount = Modules.getModuleCount(); 638 DbiModuleDescriptor Desc = Modules.getModuleDescriptor(Modi); 639 uint32_t StreamIdx = Desc.getModuleStreamIndex(); 640 641 if (StreamIdx == kInvalidStreamIndex) { 642 P.formatLine("Mod {0} (debug info not present): [{1}]", 643 fmt_align(Modi, AlignStyle::Right, NumDigits(ModCount)), 644 Desc.getModuleName()); 645 return; 646 } 647 P.formatLine("Stream {0}, {1} bytes", StreamIdx, 648 getPdb().getStreamByteSize(StreamIdx)); 649 650 printModuleDetailStats<SymbolKind>(P, "Symbols", SS); 651 printModuleDetailStats<DebugSubsectionKind>(P, "Chunks", CS); 652 } 653 }); 654 655 if (SymStats.Totals.Count > 0) { 656 P.printLine(" Summary |"); 657 AutoIndent Indent(P, 4); 658 printModuleDetailStats<SymbolKind>(P, "Symbols", SymStats); 659 printModuleDetailStats<DebugSubsectionKind>(P, "Chunks", ChunkStats); 660 } 661 662 return Error::success(); 663 } 664 665 static bool isValidNamespaceIdentifier(StringRef S) { 666 if (S.empty()) 667 return false; 668 669 if (std::isdigit(S[0])) 670 return false; 671 672 return llvm::all_of(S, [](char C) { return std::isalnum(C); }); 673 } 674 675 namespace { 676 constexpr uint32_t kNoneUdtKind = 0; 677 constexpr uint32_t kSimpleUdtKind = 1; 678 constexpr uint32_t kUnknownUdtKind = 2; 679 const StringRef NoneLabel("<none type>"); 680 const StringRef SimpleLabel("<simple type>"); 681 const StringRef UnknownLabel("<unknown type>"); 682 683 } // namespace 684 685 static StringRef getUdtStatLabel(uint32_t Kind) { 686 if (Kind == kNoneUdtKind) 687 return NoneLabel; 688 689 if (Kind == kSimpleUdtKind) 690 return SimpleLabel; 691 692 if (Kind == kUnknownUdtKind) 693 return UnknownLabel; 694 695 return formatTypeLeafKind(static_cast<TypeLeafKind>(Kind)); 696 } 697 698 static uint32_t getLongestTypeLeafName(const StatCollection &Stats) { 699 size_t L = 0; 700 for (const auto &Stat : Stats.Individual) { 701 StringRef Label = getUdtStatLabel(Stat.first); 702 L = std::max(L, Label.size()); 703 } 704 return static_cast<uint32_t>(L); 705 } 706 707 Error DumpOutputStyle::dumpUdtStats() { 708 printHeader(P, "S_UDT Record Stats"); 709 710 if (File.isPdb() && !getPdb().hasPDBGlobalsStream()) { 711 printStreamNotPresent("Globals"); 712 return Error::success(); 713 } 714 715 StatCollection UdtStats; 716 StatCollection UdtTargetStats; 717 AutoIndent Indent(P, 4); 718 719 auto &TpiTypes = File.types(); 720 721 StringMap<StatCollection::Stat> NamespacedStats; 722 723 size_t LongestNamespace = 0; 724 auto HandleOneSymbol = [&](const CVSymbol &Sym) { 725 if (Sym.kind() != SymbolKind::S_UDT) 726 return; 727 UdtStats.update(SymbolKind::S_UDT, Sym.length()); 728 729 UDTSym UDT = cantFail(SymbolDeserializer::deserializeAs<UDTSym>(Sym)); 730 731 uint32_t Kind = 0; 732 uint32_t RecordSize = 0; 733 734 if (UDT.Type.isNoneType()) 735 Kind = kNoneUdtKind; 736 else if (UDT.Type.isSimple()) 737 Kind = kSimpleUdtKind; 738 else if (Optional<CVType> T = TpiTypes.tryGetType(UDT.Type)) { 739 Kind = T->kind(); 740 RecordSize = T->length(); 741 } else 742 Kind = kUnknownUdtKind; 743 744 UdtTargetStats.update(Kind, RecordSize); 745 746 size_t Pos = UDT.Name.find("::"); 747 if (Pos == StringRef::npos) 748 return; 749 750 StringRef Scope = UDT.Name.take_front(Pos); 751 if (Scope.empty() || !isValidNamespaceIdentifier(Scope)) 752 return; 753 754 LongestNamespace = std::max(LongestNamespace, Scope.size()); 755 NamespacedStats[Scope].update(RecordSize); 756 }; 757 758 P.NewLine(); 759 760 if (File.isPdb()) { 761 auto &SymbolRecords = cantFail(getPdb().getPDBSymbolStream()); 762 auto ExpGlobals = getPdb().getPDBGlobalsStream(); 763 if (!ExpGlobals) 764 return ExpGlobals.takeError(); 765 766 for (uint32_t PubSymOff : ExpGlobals->getGlobalsTable()) { 767 CVSymbol Sym = SymbolRecords.readRecord(PubSymOff); 768 HandleOneSymbol(Sym); 769 } 770 } else { 771 for (const auto &Sec : File.symbol_groups()) { 772 for (const auto &SS : Sec.getDebugSubsections()) { 773 if (SS.kind() != DebugSubsectionKind::Symbols) 774 continue; 775 776 DebugSymbolsSubsectionRef Symbols; 777 BinaryStreamReader Reader(SS.getRecordData()); 778 cantFail(Symbols.initialize(Reader)); 779 for (const auto &S : Symbols) 780 HandleOneSymbol(S); 781 } 782 } 783 } 784 785 LongestNamespace += StringRef(" namespace ''").size(); 786 size_t LongestTypeLeafKind = getLongestTypeLeafName(UdtTargetStats); 787 size_t FieldWidth = std::max(LongestNamespace, LongestTypeLeafKind); 788 789 // Compute the max number of digits for count and size fields, including comma 790 // separators. 791 StringRef CountHeader("Count"); 792 StringRef SizeHeader("Size"); 793 size_t CD = NumDigits(UdtStats.Totals.Count); 794 CD += (CD - 1) / 3; 795 CD = std::max(CD, CountHeader.size()); 796 797 size_t SD = NumDigits(UdtStats.Totals.Size); 798 SD += (SD - 1) / 3; 799 SD = std::max(SD, SizeHeader.size()); 800 801 uint32_t TableWidth = FieldWidth + 3 + CD + 2 + SD + 1; 802 803 P.formatLine("{0} | {1} {2}", 804 fmt_align("Record Kind", AlignStyle::Right, FieldWidth), 805 fmt_align(CountHeader, AlignStyle::Right, CD), 806 fmt_align(SizeHeader, AlignStyle::Right, SD)); 807 808 P.formatLine("{0}", fmt_repeat('-', TableWidth)); 809 for (const auto &Stat : UdtTargetStats.Individual) { 810 StringRef Label = getUdtStatLabel(Stat.first); 811 P.formatLine("{0} | {1:N} {2:N}", 812 fmt_align(Label, AlignStyle::Right, FieldWidth), 813 fmt_align(Stat.second.Count, AlignStyle::Right, CD), 814 fmt_align(Stat.second.Size, AlignStyle::Right, SD)); 815 } 816 P.formatLine("{0}", fmt_repeat('-', TableWidth)); 817 P.formatLine("{0} | {1:N} {2:N}", 818 fmt_align("Total (S_UDT)", AlignStyle::Right, FieldWidth), 819 fmt_align(UdtStats.Totals.Count, AlignStyle::Right, CD), 820 fmt_align(UdtStats.Totals.Size, AlignStyle::Right, SD)); 821 P.formatLine("{0}", fmt_repeat('-', TableWidth)); 822 for (const auto &Stat : NamespacedStats) { 823 std::string Label = formatv("namespace '{0}'", Stat.getKey()); 824 P.formatLine("{0} | {1:N} {2:N}", 825 fmt_align(Label, AlignStyle::Right, FieldWidth), 826 fmt_align(Stat.second.Count, AlignStyle::Right, CD), 827 fmt_align(Stat.second.Size, AlignStyle::Right, SD)); 828 } 829 return Error::success(); 830 } 831 832 static void typesetLinesAndColumns(LinePrinter &P, uint32_t Start, 833 const LineColumnEntry &E) { 834 const uint32_t kMaxCharsPerLineNumber = 4; // 4 digit line number 835 uint32_t MinColumnWidth = kMaxCharsPerLineNumber + 5; 836 837 // Let's try to keep it under 100 characters 838 constexpr uint32_t kMaxRowLength = 100; 839 // At least 3 spaces between columns. 840 uint32_t ColumnsPerRow = kMaxRowLength / (MinColumnWidth + 3); 841 uint32_t ItemsLeft = E.LineNumbers.size(); 842 auto LineIter = E.LineNumbers.begin(); 843 while (ItemsLeft != 0) { 844 uint32_t RowColumns = std::min(ItemsLeft, ColumnsPerRow); 845 for (uint32_t I = 0; I < RowColumns; ++I) { 846 LineInfo Line(LineIter->Flags); 847 std::string LineStr; 848 if (Line.isAlwaysStepInto()) 849 LineStr = "ASI"; 850 else if (Line.isNeverStepInto()) 851 LineStr = "NSI"; 852 else 853 LineStr = utostr(Line.getStartLine()); 854 char Statement = Line.isStatement() ? ' ' : '!'; 855 P.format("{0} {1:X-} {2} ", 856 fmt_align(LineStr, AlignStyle::Right, kMaxCharsPerLineNumber), 857 fmt_align(Start + LineIter->Offset, AlignStyle::Right, 8, '0'), 858 Statement); 859 ++LineIter; 860 --ItemsLeft; 861 } 862 P.NewLine(); 863 } 864 } 865 866 Error DumpOutputStyle::dumpLines() { 867 printHeader(P, "Lines"); 868 869 if (File.isPdb() && !getPdb().hasPDBDbiStream()) { 870 printStreamNotPresent("DBI"); 871 return Error::success(); 872 } 873 874 uint32_t LastModi = UINT32_MAX; 875 uint32_t LastNameIndex = UINT32_MAX; 876 iterateModuleSubsections<DebugLinesSubsectionRef>( 877 File, PrintScope{P, 4}, 878 [this, &LastModi, &LastNameIndex](uint32_t Modi, 879 const SymbolGroup &Strings, 880 DebugLinesSubsectionRef &Lines) { 881 uint16_t Segment = Lines.header()->RelocSegment; 882 uint32_t Begin = Lines.header()->RelocOffset; 883 uint32_t End = Begin + Lines.header()->CodeSize; 884 for (const auto &Block : Lines) { 885 if (LastModi != Modi || LastNameIndex != Block.NameIndex) { 886 LastModi = Modi; 887 LastNameIndex = Block.NameIndex; 888 Strings.formatFromChecksumsOffset(P, Block.NameIndex); 889 } 890 891 AutoIndent Indent(P, 2); 892 P.formatLine("{0:X-4}:{1:X-8}-{2:X-8}, ", Segment, Begin, End); 893 uint32_t Count = Block.LineNumbers.size(); 894 if (Lines.hasColumnInfo()) 895 P.format("line/column/addr entries = {0}", Count); 896 else 897 P.format("line/addr entries = {0}", Count); 898 899 P.NewLine(); 900 typesetLinesAndColumns(P, Begin, Block); 901 } 902 }); 903 904 return Error::success(); 905 } 906 907 Error DumpOutputStyle::dumpInlineeLines() { 908 printHeader(P, "Inlinee Lines"); 909 910 if (File.isPdb() && !getPdb().hasPDBDbiStream()) { 911 printStreamNotPresent("DBI"); 912 return Error::success(); 913 } 914 915 iterateModuleSubsections<DebugInlineeLinesSubsectionRef>( 916 File, PrintScope{P, 2}, 917 [this](uint32_t Modi, const SymbolGroup &Strings, 918 DebugInlineeLinesSubsectionRef &Lines) { 919 P.formatLine("{0,+8} | {1,+5} | {2}", "Inlinee", "Line", "Source File"); 920 for (const auto &Entry : Lines) { 921 P.formatLine("{0,+8} | {1,+5} | ", Entry.Header->Inlinee, 922 fmtle(Entry.Header->SourceLineNum)); 923 Strings.formatFromChecksumsOffset(P, Entry.Header->FileID, true); 924 } 925 P.NewLine(); 926 }); 927 928 return Error::success(); 929 } 930 931 Error DumpOutputStyle::dumpXmi() { 932 printHeader(P, "Cross Module Imports"); 933 934 if (File.isPdb() && !getPdb().hasPDBDbiStream()) { 935 printStreamNotPresent("DBI"); 936 return Error::success(); 937 } 938 939 iterateModuleSubsections<DebugCrossModuleImportsSubsectionRef>( 940 File, PrintScope{P, 2}, 941 [this](uint32_t Modi, const SymbolGroup &Strings, 942 DebugCrossModuleImportsSubsectionRef &Imports) { 943 P.formatLine("{0,=32} | {1}", "Imported Module", "Type IDs"); 944 945 for (const auto &Xmi : Imports) { 946 auto ExpectedModule = 947 Strings.getNameFromStringTable(Xmi.Header->ModuleNameOffset); 948 StringRef Module; 949 SmallString<32> ModuleStorage; 950 if (!ExpectedModule) { 951 Module = "(unknown module)"; 952 consumeError(ExpectedModule.takeError()); 953 } else 954 Module = *ExpectedModule; 955 if (Module.size() > 32) { 956 ModuleStorage = "..."; 957 ModuleStorage += Module.take_back(32 - 3); 958 Module = ModuleStorage; 959 } 960 std::vector<std::string> TIs; 961 for (const auto I : Xmi.Imports) 962 TIs.push_back(formatv("{0,+10:X+}", fmtle(I))); 963 std::string Result = 964 typesetItemList(TIs, P.getIndentLevel() + 35, 12, " "); 965 P.formatLine("{0,+32} | {1}", Module, Result); 966 } 967 }); 968 969 return Error::success(); 970 } 971 972 Error DumpOutputStyle::dumpXme() { 973 printHeader(P, "Cross Module Exports"); 974 975 if (File.isPdb() && !getPdb().hasPDBDbiStream()) { 976 printStreamNotPresent("DBI"); 977 return Error::success(); 978 } 979 980 iterateModuleSubsections<DebugCrossModuleExportsSubsectionRef>( 981 File, PrintScope{P, 2}, 982 [this](uint32_t Modi, const SymbolGroup &Strings, 983 DebugCrossModuleExportsSubsectionRef &Exports) { 984 P.formatLine("{0,-10} | {1}", "Local ID", "Global ID"); 985 for (const auto &Export : Exports) { 986 P.formatLine("{0,+10:X+} | {1}", TypeIndex(Export.Local), 987 TypeIndex(Export.Global)); 988 } 989 }); 990 991 return Error::success(); 992 } 993 994 std::string formatFrameType(object::frame_type FT) { 995 switch (FT) { 996 case object::frame_type::Fpo: 997 return "FPO"; 998 case object::frame_type::NonFpo: 999 return "Non-FPO"; 1000 case object::frame_type::Trap: 1001 return "Trap"; 1002 case object::frame_type::Tss: 1003 return "TSS"; 1004 } 1005 return "<unknown>"; 1006 } 1007 1008 Error DumpOutputStyle::dumpOldFpo(PDBFile &File) { 1009 printHeader(P, "Old FPO Data"); 1010 1011 ExitOnError Err("Error dumping old fpo data:"); 1012 auto &Dbi = Err(File.getPDBDbiStream()); 1013 1014 uint32_t Index = Dbi.getDebugStreamIndex(DbgHeaderType::FPO); 1015 if (Index == kInvalidStreamIndex) { 1016 printStreamNotPresent("FPO"); 1017 return Error::success(); 1018 } 1019 1020 std::unique_ptr<MappedBlockStream> OldFpo = File.createIndexedStream(Index); 1021 BinaryStreamReader Reader(*OldFpo); 1022 FixedStreamArray<object::FpoData> Records; 1023 Err(Reader.readArray(Records, 1024 Reader.bytesRemaining() / sizeof(object::FpoData))); 1025 1026 P.printLine(" RVA | Code | Locals | Params | Prolog | Saved Regs | Use " 1027 "BP | Has SEH | Frame Type"); 1028 1029 for (const object::FpoData &FD : Records) { 1030 P.formatLine("{0:X-8} | {1,4} | {2,6} | {3,6} | {4,6} | {5,10} | {6,6} | " 1031 "{7,7} | {8,9}", 1032 uint32_t(FD.Offset), uint32_t(FD.Size), uint32_t(FD.NumLocals), 1033 uint32_t(FD.NumParams), FD.getPrologSize(), 1034 FD.getNumSavedRegs(), FD.useBP(), FD.hasSEH(), 1035 formatFrameType(FD.getFP())); 1036 } 1037 return Error::success(); 1038 } 1039 1040 Error DumpOutputStyle::dumpNewFpo(PDBFile &File) { 1041 printHeader(P, "New FPO Data"); 1042 1043 ExitOnError Err("Error dumping new fpo data:"); 1044 auto &Dbi = Err(File.getPDBDbiStream()); 1045 1046 uint32_t Index = Dbi.getDebugStreamIndex(DbgHeaderType::NewFPO); 1047 if (Index == kInvalidStreamIndex) { 1048 printStreamNotPresent("New FPO"); 1049 return Error::success(); 1050 } 1051 1052 std::unique_ptr<MappedBlockStream> NewFpo = File.createIndexedStream(Index); 1053 1054 DebugFrameDataSubsectionRef FDS; 1055 if (auto EC = FDS.initialize(*NewFpo)) 1056 return make_error<RawError>(raw_error_code::corrupt_file, 1057 "Invalid new fpo stream"); 1058 1059 P.printLine(" RVA | Code | Locals | Params | Stack | Prolog | Saved Regs " 1060 "| Has SEH | Has C++EH | Start | Program"); 1061 for (const FrameData &FD : FDS) { 1062 bool IsFuncStart = FD.Flags & FrameData::IsFunctionStart; 1063 bool HasEH = FD.Flags & FrameData::HasEH; 1064 bool HasSEH = FD.Flags & FrameData::HasSEH; 1065 1066 auto &StringTable = Err(File.getStringTable()); 1067 1068 auto Program = Err(StringTable.getStringForID(FD.FrameFunc)); 1069 P.formatLine("{0:X-8} | {1,4} | {2,6} | {3,6} | {4,5} | {5,6} | {6,10} | " 1070 "{7,7} | {8,9} | {9,5} | {10}", 1071 uint32_t(FD.RvaStart), uint32_t(FD.CodeSize), 1072 uint32_t(FD.LocalSize), uint32_t(FD.ParamsSize), 1073 uint32_t(FD.MaxStackSize), uint16_t(FD.PrologSize), 1074 uint16_t(FD.SavedRegsSize), HasSEH, HasEH, IsFuncStart, 1075 Program); 1076 } 1077 return Error::success(); 1078 } 1079 1080 Error DumpOutputStyle::dumpFpo() { 1081 if (!File.isPdb()) { 1082 printStreamNotValidForObj(); 1083 return Error::success(); 1084 } 1085 1086 PDBFile &File = getPdb(); 1087 if (!File.hasPDBDbiStream()) { 1088 printStreamNotPresent("DBI"); 1089 return Error::success(); 1090 } 1091 1092 if (auto EC = dumpOldFpo(File)) 1093 return EC; 1094 if (auto EC = dumpNewFpo(File)) 1095 return EC; 1096 return Error::success(); 1097 } 1098 1099 Error DumpOutputStyle::dumpStringTableFromPdb() { 1100 AutoIndent Indent(P); 1101 auto IS = getPdb().getStringTable(); 1102 if (!IS) { 1103 P.formatLine("Not present in file"); 1104 consumeError(IS.takeError()); 1105 return Error::success(); 1106 } 1107 1108 if (opts::dump::DumpStringTable) { 1109 if (IS->name_ids().empty()) 1110 P.formatLine("Empty"); 1111 else { 1112 auto MaxID = 1113 std::max_element(IS->name_ids().begin(), IS->name_ids().end()); 1114 uint32_t Digits = NumDigits(*MaxID); 1115 1116 P.formatLine("{0} | {1}", fmt_align("ID", AlignStyle::Right, Digits), 1117 "String"); 1118 1119 std::vector<uint32_t> SortedIDs(IS->name_ids().begin(), 1120 IS->name_ids().end()); 1121 llvm::sort(SortedIDs); 1122 for (uint32_t I : SortedIDs) { 1123 auto ES = IS->getStringForID(I); 1124 llvm::SmallString<32> Str; 1125 if (!ES) { 1126 consumeError(ES.takeError()); 1127 Str = "Error reading string"; 1128 } else if (!ES->empty()) { 1129 Str.append("'"); 1130 Str.append(*ES); 1131 Str.append("'"); 1132 } 1133 1134 if (!Str.empty()) 1135 P.formatLine("{0} | {1}", fmt_align(I, AlignStyle::Right, Digits), 1136 Str); 1137 } 1138 } 1139 } 1140 1141 if (opts::dump::DumpStringTableDetails) { 1142 P.NewLine(); 1143 { 1144 P.printLine("String Table Header:"); 1145 AutoIndent Indent(P); 1146 P.formatLine("Signature: {0}", IS->getSignature()); 1147 P.formatLine("Hash Version: {0}", IS->getHashVersion()); 1148 P.formatLine("Name Buffer Size: {0}", IS->getByteSize()); 1149 P.NewLine(); 1150 } 1151 1152 BinaryStreamRef NameBuffer = IS->getStringTable().getBuffer(); 1153 ArrayRef<uint8_t> Contents; 1154 cantFail(NameBuffer.readBytes(0, NameBuffer.getLength(), Contents)); 1155 P.formatBinary("Name Buffer", Contents, 0); 1156 P.NewLine(); 1157 { 1158 P.printLine("Hash Table:"); 1159 AutoIndent Indent(P); 1160 P.formatLine("Bucket Count: {0}", IS->name_ids().size()); 1161 for (const auto &Entry : enumerate(IS->name_ids())) 1162 P.formatLine("Bucket[{0}] : {1}", Entry.index(), 1163 uint32_t(Entry.value())); 1164 P.formatLine("Name Count: {0}", IS->getNameCount()); 1165 } 1166 } 1167 return Error::success(); 1168 } 1169 1170 Error DumpOutputStyle::dumpStringTableFromObj() { 1171 iterateModuleSubsections<DebugStringTableSubsectionRef>( 1172 File, PrintScope{P, 4}, 1173 [&](uint32_t Modi, const SymbolGroup &Strings, 1174 DebugStringTableSubsectionRef &Strings2) { 1175 BinaryStreamRef StringTableBuffer = Strings2.getBuffer(); 1176 BinaryStreamReader Reader(StringTableBuffer); 1177 while (Reader.bytesRemaining() > 0) { 1178 StringRef Str; 1179 uint32_t Offset = Reader.getOffset(); 1180 cantFail(Reader.readCString(Str)); 1181 if (Str.empty()) 1182 continue; 1183 1184 P.formatLine("{0} | {1}", fmt_align(Offset, AlignStyle::Right, 4), 1185 Str); 1186 } 1187 }); 1188 return Error::success(); 1189 } 1190 1191 Error DumpOutputStyle::dumpNamedStreams() { 1192 printHeader(P, "Named Streams"); 1193 1194 if (File.isObj()) { 1195 printStreamNotValidForObj(); 1196 return Error::success(); 1197 } 1198 1199 AutoIndent Indent(P); 1200 ExitOnError Err("Invalid PDB File: "); 1201 1202 auto &IS = Err(File.pdb().getPDBInfoStream()); 1203 const NamedStreamMap &NS = IS.getNamedStreams(); 1204 for (const auto &Entry : NS.entries()) { 1205 P.printLine(Entry.getKey()); 1206 AutoIndent Indent2(P, 2); 1207 P.formatLine("Index: {0}", Entry.getValue()); 1208 P.formatLine("Size in bytes: {0}", 1209 File.pdb().getStreamByteSize(Entry.getValue())); 1210 } 1211 1212 return Error::success(); 1213 } 1214 1215 Error DumpOutputStyle::dumpStringTable() { 1216 printHeader(P, "String Table"); 1217 1218 if (File.isPdb()) 1219 return dumpStringTableFromPdb(); 1220 1221 return dumpStringTableFromObj(); 1222 } 1223 1224 static void buildDepSet(LazyRandomTypeCollection &Types, 1225 ArrayRef<TypeIndex> Indices, 1226 std::map<TypeIndex, CVType> &DepSet) { 1227 SmallVector<TypeIndex, 4> DepList; 1228 for (const auto &I : Indices) { 1229 TypeIndex TI(I); 1230 if (DepSet.find(TI) != DepSet.end() || TI.isSimple() || TI.isNoneType()) 1231 continue; 1232 1233 CVType Type = Types.getType(TI); 1234 DepSet[TI] = Type; 1235 codeview::discoverTypeIndices(Type, DepList); 1236 buildDepSet(Types, DepList, DepSet); 1237 } 1238 } 1239 1240 static void 1241 dumpFullTypeStream(LinePrinter &Printer, LazyRandomTypeCollection &Types, 1242 uint32_t NumTypeRecords, uint32_t NumHashBuckets, 1243 FixedStreamArray<support::ulittle32_t> HashValues, 1244 TpiStream *Stream, bool Bytes, bool Extras) { 1245 1246 Printer.formatLine("Showing {0:N} records", NumTypeRecords); 1247 uint32_t Width = NumDigits(TypeIndex::FirstNonSimpleIndex + NumTypeRecords); 1248 1249 MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types, 1250 NumHashBuckets, HashValues, Stream); 1251 1252 if (auto EC = codeview::visitTypeStream(Types, V)) { 1253 Printer.formatLine("An error occurred dumping type records: {0}", 1254 toString(std::move(EC))); 1255 } 1256 } 1257 1258 static void dumpPartialTypeStream(LinePrinter &Printer, 1259 LazyRandomTypeCollection &Types, 1260 TpiStream &Stream, ArrayRef<TypeIndex> TiList, 1261 bool Bytes, bool Extras, bool Deps) { 1262 uint32_t Width = 1263 NumDigits(TypeIndex::FirstNonSimpleIndex + Stream.getNumTypeRecords()); 1264 1265 MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types, 1266 Stream.getNumHashBuckets(), Stream.getHashValues(), 1267 &Stream); 1268 1269 if (opts::dump::DumpTypeDependents) { 1270 // If we need to dump all dependents, then iterate each index and find 1271 // all dependents, adding them to a map ordered by TypeIndex. 1272 std::map<TypeIndex, CVType> DepSet; 1273 buildDepSet(Types, TiList, DepSet); 1274 1275 Printer.formatLine( 1276 "Showing {0:N} records and their dependents ({1:N} records total)", 1277 TiList.size(), DepSet.size()); 1278 1279 for (auto &Dep : DepSet) { 1280 if (auto EC = codeview::visitTypeRecord(Dep.second, Dep.first, V)) 1281 Printer.formatLine("An error occurred dumping type record {0}: {1}", 1282 Dep.first, toString(std::move(EC))); 1283 } 1284 } else { 1285 Printer.formatLine("Showing {0:N} records.", TiList.size()); 1286 1287 for (const auto &I : TiList) { 1288 TypeIndex TI(I); 1289 CVType Type = Types.getType(TI); 1290 if (auto EC = codeview::visitTypeRecord(Type, TI, V)) 1291 Printer.formatLine("An error occurred dumping type record {0}: {1}", TI, 1292 toString(std::move(EC))); 1293 } 1294 } 1295 } 1296 1297 Error DumpOutputStyle::dumpTypesFromObjectFile() { 1298 LazyRandomTypeCollection Types(100); 1299 1300 for (const auto &S : getObj().sections()) { 1301 StringRef SectionName; 1302 if (auto EC = S.getName(SectionName)) 1303 return errorCodeToError(EC); 1304 1305 // .debug$T is a standard CodeView type section, while .debug$P is the same 1306 // format but used for MSVC precompiled header object files. 1307 if (SectionName == ".debug$T") 1308 printHeader(P, "Types (.debug$T)"); 1309 else if (SectionName == ".debug$P") 1310 printHeader(P, "Precompiled Types (.debug$P)"); 1311 else 1312 continue; 1313 1314 StringRef Contents; 1315 if (auto EC = S.getContents(Contents)) 1316 return errorCodeToError(EC); 1317 1318 uint32_t Magic; 1319 BinaryStreamReader Reader(Contents, llvm::support::little); 1320 if (auto EC = Reader.readInteger(Magic)) 1321 return EC; 1322 if (Magic != COFF::DEBUG_SECTION_MAGIC) 1323 return make_error<StringError>("Invalid CodeView debug section.", 1324 inconvertibleErrorCode()); 1325 1326 Types.reset(Reader, 100); 1327 1328 if (opts::dump::DumpTypes) { 1329 dumpFullTypeStream(P, Types, 0, 0, {}, nullptr, opts::dump::DumpTypeData, 1330 false); 1331 } else if (opts::dump::DumpTypeExtras) { 1332 auto LocalHashes = LocallyHashedType::hashTypeCollection(Types); 1333 auto GlobalHashes = GloballyHashedType::hashTypeCollection(Types); 1334 assert(LocalHashes.size() == GlobalHashes.size()); 1335 1336 P.formatLine("Local / Global hashes:"); 1337 TypeIndex TI(TypeIndex::FirstNonSimpleIndex); 1338 for (const auto &H : zip(LocalHashes, GlobalHashes)) { 1339 AutoIndent Indent2(P); 1340 LocallyHashedType &L = std::get<0>(H); 1341 GloballyHashedType &G = std::get<1>(H); 1342 1343 P.formatLine("TI: {0}, LocalHash: {1:X}, GlobalHash: {2}", TI, L, G); 1344 1345 ++TI; 1346 } 1347 P.NewLine(); 1348 } 1349 } 1350 1351 return Error::success(); 1352 } 1353 1354 Error DumpOutputStyle::dumpTpiStream(uint32_t StreamIdx) { 1355 assert(StreamIdx == StreamTPI || StreamIdx == StreamIPI); 1356 1357 if (StreamIdx == StreamTPI) { 1358 printHeader(P, "Types (TPI Stream)"); 1359 } else if (StreamIdx == StreamIPI) { 1360 printHeader(P, "Types (IPI Stream)"); 1361 } 1362 1363 assert(!File.isObj()); 1364 1365 bool Present = false; 1366 bool DumpTypes = false; 1367 bool DumpBytes = false; 1368 bool DumpExtras = false; 1369 std::vector<uint32_t> Indices; 1370 if (StreamIdx == StreamTPI) { 1371 Present = getPdb().hasPDBTpiStream(); 1372 DumpTypes = opts::dump::DumpTypes; 1373 DumpBytes = opts::dump::DumpTypeData; 1374 DumpExtras = opts::dump::DumpTypeExtras; 1375 Indices.assign(opts::dump::DumpTypeIndex.begin(), 1376 opts::dump::DumpTypeIndex.end()); 1377 } else if (StreamIdx == StreamIPI) { 1378 Present = getPdb().hasPDBIpiStream(); 1379 DumpTypes = opts::dump::DumpIds; 1380 DumpBytes = opts::dump::DumpIdData; 1381 DumpExtras = opts::dump::DumpIdExtras; 1382 Indices.assign(opts::dump::DumpIdIndex.begin(), 1383 opts::dump::DumpIdIndex.end()); 1384 } 1385 1386 if (!Present) { 1387 printStreamNotPresent(StreamIdx == StreamTPI ? "TPI" : "IPI"); 1388 return Error::success(); 1389 } 1390 1391 AutoIndent Indent(P); 1392 ExitOnError Err("Unexpected error processing types: "); 1393 1394 auto &Stream = Err((StreamIdx == StreamTPI) ? getPdb().getPDBTpiStream() 1395 : getPdb().getPDBIpiStream()); 1396 1397 auto &Types = (StreamIdx == StreamTPI) ? File.types() : File.ids(); 1398 1399 // Enable resolving forward decls. 1400 Stream.buildHashMap(); 1401 1402 if (DumpTypes || !Indices.empty()) { 1403 if (Indices.empty()) 1404 dumpFullTypeStream(P, Types, Stream.getNumTypeRecords(), 1405 Stream.getNumHashBuckets(), Stream.getHashValues(), 1406 &Stream, DumpBytes, DumpExtras); 1407 else { 1408 std::vector<TypeIndex> TiList(Indices.begin(), Indices.end()); 1409 dumpPartialTypeStream(P, Types, Stream, TiList, DumpBytes, DumpExtras, 1410 opts::dump::DumpTypeDependents); 1411 } 1412 } 1413 1414 if (DumpExtras) { 1415 P.NewLine(); 1416 auto IndexOffsets = Stream.getTypeIndexOffsets(); 1417 P.formatLine("Type Index Offsets:"); 1418 for (const auto &IO : IndexOffsets) { 1419 AutoIndent Indent2(P); 1420 P.formatLine("TI: {0}, Offset: {1}", IO.Type, fmtle(IO.Offset)); 1421 } 1422 1423 if (getPdb().hasPDBStringTable()) { 1424 P.NewLine(); 1425 P.formatLine("Hash Adjusters:"); 1426 auto &Adjusters = Stream.getHashAdjusters(); 1427 auto &Strings = Err(getPdb().getStringTable()); 1428 for (const auto &A : Adjusters) { 1429 AutoIndent Indent2(P); 1430 auto ExpectedStr = Strings.getStringForID(A.first); 1431 TypeIndex TI(A.second); 1432 if (ExpectedStr) 1433 P.formatLine("`{0}` -> {1}", *ExpectedStr, TI); 1434 else { 1435 P.formatLine("unknown str id ({0}) -> {1}", A.first, TI); 1436 consumeError(ExpectedStr.takeError()); 1437 } 1438 } 1439 } 1440 } 1441 return Error::success(); 1442 } 1443 1444 Error DumpOutputStyle::dumpModuleSymsForObj() { 1445 printHeader(P, "Symbols"); 1446 1447 AutoIndent Indent(P); 1448 1449 ExitOnError Err("Unexpected error processing symbols: "); 1450 1451 auto &Types = File.types(); 1452 1453 SymbolVisitorCallbackPipeline Pipeline; 1454 SymbolDeserializer Deserializer(nullptr, CodeViewContainer::ObjectFile); 1455 MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Types, Types); 1456 1457 Pipeline.addCallbackToPipeline(Deserializer); 1458 Pipeline.addCallbackToPipeline(Dumper); 1459 CVSymbolVisitor Visitor(Pipeline); 1460 1461 std::unique_ptr<llvm::Error> SymbolError; 1462 1463 iterateModuleSubsections<DebugSymbolsSubsectionRef>( 1464 File, PrintScope{P, 2}, 1465 [&](uint32_t Modi, const SymbolGroup &Strings, 1466 DebugSymbolsSubsectionRef &Symbols) { 1467 Dumper.setSymbolGroup(&Strings); 1468 for (auto Symbol : Symbols) { 1469 if (auto EC = Visitor.visitSymbolRecord(Symbol)) { 1470 SymbolError = llvm::make_unique<Error>(std::move(EC)); 1471 return; 1472 } 1473 } 1474 }); 1475 1476 if (SymbolError) 1477 return std::move(*SymbolError); 1478 1479 return Error::success(); 1480 } 1481 1482 Error DumpOutputStyle::dumpModuleSymsForPdb() { 1483 printHeader(P, "Symbols"); 1484 1485 if (File.isPdb() && !getPdb().hasPDBDbiStream()) { 1486 printStreamNotPresent("DBI"); 1487 return Error::success(); 1488 } 1489 1490 AutoIndent Indent(P); 1491 ExitOnError Err("Unexpected error processing symbols: "); 1492 1493 auto &Ids = File.ids(); 1494 auto &Types = File.types(); 1495 1496 iterateSymbolGroups( 1497 File, PrintScope{P, 2}, [&](uint32_t I, const SymbolGroup &Strings) { 1498 auto ExpectedModS = getModuleDebugStream(File.pdb(), I); 1499 if (!ExpectedModS) { 1500 P.formatLine("Error loading module stream {0}. {1}", I, 1501 toString(ExpectedModS.takeError())); 1502 return; 1503 } 1504 1505 ModuleDebugStreamRef &ModS = *ExpectedModS; 1506 1507 SymbolVisitorCallbackPipeline Pipeline; 1508 SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb); 1509 MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Strings, 1510 Ids, Types); 1511 1512 Pipeline.addCallbackToPipeline(Deserializer); 1513 Pipeline.addCallbackToPipeline(Dumper); 1514 CVSymbolVisitor Visitor(Pipeline); 1515 auto SS = ModS.getSymbolsSubstream(); 1516 if (auto EC = 1517 Visitor.visitSymbolStream(ModS.getSymbolArray(), SS.Offset)) { 1518 P.formatLine("Error while processing symbol records. {0}", 1519 toString(std::move(EC))); 1520 return; 1521 } 1522 }); 1523 return Error::success(); 1524 } 1525 1526 Error DumpOutputStyle::dumpGSIRecords() { 1527 printHeader(P, "GSI Records"); 1528 1529 if (File.isObj()) { 1530 printStreamNotValidForObj(); 1531 return Error::success(); 1532 } 1533 1534 if (!getPdb().hasPDBSymbolStream()) { 1535 printStreamNotPresent("GSI Common Symbol"); 1536 return Error::success(); 1537 } 1538 1539 AutoIndent Indent(P); 1540 1541 auto &Records = cantFail(getPdb().getPDBSymbolStream()); 1542 auto &Types = File.types(); 1543 auto &Ids = File.ids(); 1544 1545 P.printLine("Records"); 1546 SymbolVisitorCallbackPipeline Pipeline; 1547 SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb); 1548 MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Ids, Types); 1549 1550 Pipeline.addCallbackToPipeline(Deserializer); 1551 Pipeline.addCallbackToPipeline(Dumper); 1552 CVSymbolVisitor Visitor(Pipeline); 1553 1554 BinaryStreamRef SymStream = Records.getSymbolArray().getUnderlyingStream(); 1555 if (auto E = Visitor.visitSymbolStream(Records.getSymbolArray(), 0)) 1556 return E; 1557 return Error::success(); 1558 } 1559 1560 Error DumpOutputStyle::dumpGlobals() { 1561 printHeader(P, "Global Symbols"); 1562 1563 if (File.isObj()) { 1564 printStreamNotValidForObj(); 1565 return Error::success(); 1566 } 1567 1568 if (!getPdb().hasPDBGlobalsStream()) { 1569 printStreamNotPresent("Globals"); 1570 return Error::success(); 1571 } 1572 1573 AutoIndent Indent(P); 1574 ExitOnError Err("Error dumping globals stream: "); 1575 auto &Globals = Err(getPdb().getPDBGlobalsStream()); 1576 1577 if (opts::dump::DumpGlobalNames.empty()) { 1578 const GSIHashTable &Table = Globals.getGlobalsTable(); 1579 Err(dumpSymbolsFromGSI(Table, opts::dump::DumpGlobalExtras)); 1580 } else { 1581 SymbolStream &SymRecords = cantFail(getPdb().getPDBSymbolStream()); 1582 auto &Types = File.types(); 1583 auto &Ids = File.ids(); 1584 1585 SymbolVisitorCallbackPipeline Pipeline; 1586 SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb); 1587 MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Ids, Types); 1588 1589 Pipeline.addCallbackToPipeline(Deserializer); 1590 Pipeline.addCallbackToPipeline(Dumper); 1591 CVSymbolVisitor Visitor(Pipeline); 1592 1593 using ResultEntryType = std::pair<uint32_t, CVSymbol>; 1594 for (StringRef Name : opts::dump::DumpGlobalNames) { 1595 AutoIndent Indent(P); 1596 P.formatLine("Global Name `{0}`", Name); 1597 std::vector<ResultEntryType> Results = 1598 Globals.findRecordsByName(Name, SymRecords); 1599 if (Results.empty()) { 1600 AutoIndent Indent(P); 1601 P.printLine("(no matching records found)"); 1602 continue; 1603 } 1604 1605 for (ResultEntryType Result : Results) { 1606 if (auto E = Visitor.visitSymbolRecord(Result.second, Result.first)) 1607 return E; 1608 } 1609 } 1610 } 1611 return Error::success(); 1612 } 1613 1614 Error DumpOutputStyle::dumpPublics() { 1615 printHeader(P, "Public Symbols"); 1616 1617 if (File.isObj()) { 1618 printStreamNotValidForObj(); 1619 return Error::success(); 1620 } 1621 1622 if (!getPdb().hasPDBPublicsStream()) { 1623 printStreamNotPresent("Publics"); 1624 return Error::success(); 1625 } 1626 1627 AutoIndent Indent(P); 1628 ExitOnError Err("Error dumping publics stream: "); 1629 auto &Publics = Err(getPdb().getPDBPublicsStream()); 1630 1631 const GSIHashTable &PublicsTable = Publics.getPublicsTable(); 1632 if (opts::dump::DumpPublicExtras) { 1633 P.printLine("Publics Header"); 1634 AutoIndent Indent(P); 1635 P.formatLine("sym hash = {0}, thunk table addr = {1}", Publics.getSymHash(), 1636 formatSegmentOffset(Publics.getThunkTableSection(), 1637 Publics.getThunkTableOffset())); 1638 } 1639 Err(dumpSymbolsFromGSI(PublicsTable, opts::dump::DumpPublicExtras)); 1640 1641 // Skip the rest if we aren't dumping extras. 1642 if (!opts::dump::DumpPublicExtras) 1643 return Error::success(); 1644 1645 P.formatLine("Address Map"); 1646 { 1647 // These are offsets into the publics stream sorted by secidx:secrel. 1648 AutoIndent Indent2(P); 1649 for (uint32_t Addr : Publics.getAddressMap()) 1650 P.formatLine("off = {0}", Addr); 1651 } 1652 1653 // The thunk map is optional debug info used for ILT thunks. 1654 if (!Publics.getThunkMap().empty()) { 1655 P.formatLine("Thunk Map"); 1656 AutoIndent Indent2(P); 1657 for (uint32_t Addr : Publics.getThunkMap()) 1658 P.formatLine("{0:x8}", Addr); 1659 } 1660 1661 // The section offsets table appears to be empty when incremental linking 1662 // isn't in use. 1663 if (!Publics.getSectionOffsets().empty()) { 1664 P.formatLine("Section Offsets"); 1665 AutoIndent Indent2(P); 1666 for (const SectionOffset &SO : Publics.getSectionOffsets()) 1667 P.formatLine("{0:x4}:{1:x8}", uint16_t(SO.Isect), uint32_t(SO.Off)); 1668 } 1669 1670 return Error::success(); 1671 } 1672 1673 Error DumpOutputStyle::dumpSymbolsFromGSI(const GSIHashTable &Table, 1674 bool HashExtras) { 1675 auto ExpectedSyms = getPdb().getPDBSymbolStream(); 1676 if (!ExpectedSyms) 1677 return ExpectedSyms.takeError(); 1678 auto &Types = File.types(); 1679 auto &Ids = File.ids(); 1680 1681 if (HashExtras) { 1682 P.printLine("GSI Header"); 1683 AutoIndent Indent(P); 1684 P.formatLine("sig = {0:X}, hdr = {1:X}, hr size = {2}, num buckets = {3}", 1685 Table.getVerSignature(), Table.getVerHeader(), 1686 Table.getHashRecordSize(), Table.getNumBuckets()); 1687 } 1688 1689 { 1690 P.printLine("Records"); 1691 SymbolVisitorCallbackPipeline Pipeline; 1692 SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb); 1693 MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Ids, Types); 1694 1695 Pipeline.addCallbackToPipeline(Deserializer); 1696 Pipeline.addCallbackToPipeline(Dumper); 1697 CVSymbolVisitor Visitor(Pipeline); 1698 1699 1700 BinaryStreamRef SymStream = 1701 ExpectedSyms->getSymbolArray().getUnderlyingStream(); 1702 for (uint32_t PubSymOff : Table) { 1703 Expected<CVSymbol> Sym = readSymbolFromStream(SymStream, PubSymOff); 1704 if (!Sym) 1705 return Sym.takeError(); 1706 if (auto E = Visitor.visitSymbolRecord(*Sym, PubSymOff)) 1707 return E; 1708 } 1709 } 1710 1711 // Return early if we aren't dumping public hash table and address map info. 1712 if (HashExtras) { 1713 P.formatLine("Hash Entries"); 1714 { 1715 AutoIndent Indent2(P); 1716 for (const PSHashRecord &HR : Table.HashRecords) 1717 P.formatLine("off = {0}, refcnt = {1}", uint32_t(HR.Off), 1718 uint32_t(HR.CRef)); 1719 } 1720 1721 P.formatLine("Hash Buckets"); 1722 { 1723 AutoIndent Indent2(P); 1724 for (uint32_t Hash : Table.HashBuckets) 1725 P.formatLine("{0:x8}", Hash); 1726 } 1727 } 1728 1729 return Error::success(); 1730 } 1731 1732 static std::string formatSegMapDescriptorFlag(uint32_t IndentLevel, 1733 OMFSegDescFlags Flags) { 1734 std::vector<std::string> Opts; 1735 if (Flags == OMFSegDescFlags::None) 1736 return "none"; 1737 1738 PUSH_FLAG(OMFSegDescFlags, Read, Flags, "read"); 1739 PUSH_FLAG(OMFSegDescFlags, Write, Flags, "write"); 1740 PUSH_FLAG(OMFSegDescFlags, Execute, Flags, "execute"); 1741 PUSH_FLAG(OMFSegDescFlags, AddressIs32Bit, Flags, "32 bit addr"); 1742 PUSH_FLAG(OMFSegDescFlags, IsSelector, Flags, "selector"); 1743 PUSH_FLAG(OMFSegDescFlags, IsAbsoluteAddress, Flags, "absolute addr"); 1744 PUSH_FLAG(OMFSegDescFlags, IsGroup, Flags, "group"); 1745 return typesetItemList(Opts, IndentLevel, 4, " | "); 1746 } 1747 1748 Error DumpOutputStyle::dumpSectionHeaders() { 1749 dumpSectionHeaders("Section Headers", DbgHeaderType::SectionHdr); 1750 dumpSectionHeaders("Original Section Headers", DbgHeaderType::SectionHdrOrig); 1751 return Error::success(); 1752 } 1753 1754 void DumpOutputStyle::dumpSectionHeaders(StringRef Label, DbgHeaderType Type) { 1755 printHeader(P, Label); 1756 1757 if (File.isObj()) { 1758 printStreamNotValidForObj(); 1759 return; 1760 } 1761 1762 if (!getPdb().hasPDBDbiStream()) { 1763 printStreamNotPresent("DBI"); 1764 return; 1765 } 1766 1767 AutoIndent Indent(P); 1768 ExitOnError Err("Error dumping section headers: "); 1769 std::unique_ptr<MappedBlockStream> Stream; 1770 ArrayRef<object::coff_section> Headers; 1771 auto ExpectedHeaders = loadSectionHeaders(getPdb(), Type); 1772 if (!ExpectedHeaders) { 1773 P.printLine(toString(ExpectedHeaders.takeError())); 1774 return; 1775 } 1776 std::tie(Stream, Headers) = std::move(*ExpectedHeaders); 1777 1778 uint32_t I = 1; 1779 for (const auto &Header : Headers) { 1780 P.NewLine(); 1781 P.formatLine("SECTION HEADER #{0}", I); 1782 P.formatLine("{0,8} name", Header.Name); 1783 P.formatLine("{0,8:X-} virtual size", uint32_t(Header.VirtualSize)); 1784 P.formatLine("{0,8:X-} virtual address", uint32_t(Header.VirtualAddress)); 1785 P.formatLine("{0,8:X-} size of raw data", uint32_t(Header.SizeOfRawData)); 1786 P.formatLine("{0,8:X-} file pointer to raw data", 1787 uint32_t(Header.PointerToRawData)); 1788 P.formatLine("{0,8:X-} file pointer to relocation table", 1789 uint32_t(Header.PointerToRelocations)); 1790 P.formatLine("{0,8:X-} file pointer to line numbers", 1791 uint32_t(Header.PointerToLinenumbers)); 1792 P.formatLine("{0,8:X-} number of relocations", 1793 uint32_t(Header.NumberOfRelocations)); 1794 P.formatLine("{0,8:X-} number of line numbers", 1795 uint32_t(Header.NumberOfLinenumbers)); 1796 P.formatLine("{0,8:X-} flags", uint32_t(Header.Characteristics)); 1797 AutoIndent IndentMore(P, 9); 1798 P.formatLine("{0}", formatSectionCharacteristics( 1799 P.getIndentLevel(), Header.Characteristics, 1, "")); 1800 ++I; 1801 } 1802 return; 1803 } 1804 1805 Error DumpOutputStyle::dumpSectionContribs() { 1806 printHeader(P, "Section Contributions"); 1807 1808 if (File.isObj()) { 1809 printStreamNotValidForObj(); 1810 return Error::success(); 1811 } 1812 1813 if (!getPdb().hasPDBDbiStream()) { 1814 printStreamNotPresent("DBI"); 1815 return Error::success(); 1816 } 1817 1818 AutoIndent Indent(P); 1819 ExitOnError Err("Error dumping section contributions: "); 1820 1821 auto &Dbi = Err(getPdb().getPDBDbiStream()); 1822 1823 class Visitor : public ISectionContribVisitor { 1824 public: 1825 Visitor(LinePrinter &P, ArrayRef<std::string> Names) : P(P), Names(Names) { 1826 auto Max = std::max_element( 1827 Names.begin(), Names.end(), 1828 [](StringRef S1, StringRef S2) { return S1.size() < S2.size(); }); 1829 MaxNameLen = (Max == Names.end() ? 0 : Max->size()); 1830 } 1831 void visit(const SectionContrib &SC) override { 1832 dumpSectionContrib(P, SC, Names, MaxNameLen); 1833 } 1834 void visit(const SectionContrib2 &SC) override { 1835 dumpSectionContrib(P, SC, Names, MaxNameLen); 1836 } 1837 1838 private: 1839 LinePrinter &P; 1840 uint32_t MaxNameLen; 1841 ArrayRef<std::string> Names; 1842 }; 1843 1844 std::vector<std::string> Names = getSectionNames(getPdb()); 1845 Visitor V(P, makeArrayRef(Names)); 1846 Dbi.visitSectionContributions(V); 1847 return Error::success(); 1848 } 1849 1850 Error DumpOutputStyle::dumpSectionMap() { 1851 printHeader(P, "Section Map"); 1852 1853 if (File.isObj()) { 1854 printStreamNotValidForObj(); 1855 return Error::success(); 1856 } 1857 1858 if (!getPdb().hasPDBDbiStream()) { 1859 printStreamNotPresent("DBI"); 1860 return Error::success(); 1861 } 1862 1863 AutoIndent Indent(P); 1864 ExitOnError Err("Error dumping section map: "); 1865 1866 auto &Dbi = Err(getPdb().getPDBDbiStream()); 1867 1868 uint32_t I = 0; 1869 for (auto &M : Dbi.getSectionMap()) { 1870 P.formatLine( 1871 "Section {0:4} | ovl = {1}, group = {2}, frame = {3}, name = {4}", I, 1872 fmtle(M.Ovl), fmtle(M.Group), fmtle(M.Frame), fmtle(M.SecName)); 1873 P.formatLine(" class = {0}, offset = {1}, size = {2}", 1874 fmtle(M.ClassName), fmtle(M.Offset), fmtle(M.SecByteLength)); 1875 P.formatLine(" flags = {0}", 1876 formatSegMapDescriptorFlag( 1877 P.getIndentLevel() + 13, 1878 static_cast<OMFSegDescFlags>(uint16_t(M.Flags)))); 1879 ++I; 1880 } 1881 return Error::success(); 1882 } 1883