1//===- LLVMOutputStyle.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 "LLVMOutputStyle.h" 11 12#include "llvm-pdbdump.h" 13#include "llvm/DebugInfo/CodeView/EnumTables.h" 14#include "llvm/DebugInfo/CodeView/ModuleSubstreamVisitor.h" 15#include "llvm/DebugInfo/CodeView/SymbolDumper.h" 16#include "llvm/DebugInfo/PDB/PDBExtras.h" 17#include "llvm/DebugInfo/PDB/Raw/DbiStream.h" 18#include "llvm/DebugInfo/PDB/Raw/EnumTables.h" 19#include "llvm/DebugInfo/PDB/Raw/ISectionContribVisitor.h" 20#include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.h" 21#include "llvm/DebugInfo/PDB/Raw/InfoStream.h" 22#include "llvm/DebugInfo/PDB/Raw/ModInfo.h" 23#include "llvm/DebugInfo/PDB/Raw/ModStream.h" 24#include "llvm/DebugInfo/PDB/Raw/PDBFile.h" 25#include "llvm/DebugInfo/PDB/Raw/PublicsStream.h" 26#include "llvm/DebugInfo/PDB/Raw/RawError.h" 27#include "llvm/DebugInfo/PDB/Raw/TpiStream.h" 28#include "llvm/Object/COFF.h" 29 30#include <unordered_map> 31 32using namespace llvm; 33using namespace llvm::codeview; 34using namespace llvm::pdb; 35 36static void printSectionOffset(llvm::raw_ostream &OS, 37 const SectionOffset &Off) { 38 OS << Off.Off << ", " << Off.Isect; 39} 40 41LLVMOutputStyle::LLVMOutputStyle(PDBFile &File) 42 : File(File), P(outs()), TD(&P, false) {} 43 44Error LLVMOutputStyle::dump() { 45 if (auto EC = dumpFileHeaders()) 46 return EC; 47 48 if (auto EC = dumpStreamSummary()) 49 return EC; 50 51 if (auto EC = dumpStreamBlocks()) 52 return EC; 53 54 if (auto EC = dumpStreamData()) 55 return EC; 56 57 if (auto EC = dumpInfoStream()) 58 return EC; 59 60 if (auto EC = dumpNamedStream()) 61 return EC; 62 63 if (auto EC = dumpTpiStream(StreamTPI)) 64 return EC; 65 66 if (auto EC = dumpTpiStream(StreamIPI)) 67 return EC; 68 69 if (auto EC = dumpDbiStream()) 70 return EC; 71 72 if (auto EC = dumpSectionContribs()) 73 return EC; 74 75 if (auto EC = dumpSectionMap()) 76 return EC; 77 78 if (auto EC = dumpPublicsStream()) 79 return EC; 80 81 if (auto EC = dumpSectionHeaders()) 82 return EC; 83 84 if (auto EC = dumpFpoStream()) 85 return EC; 86 87 flush(); 88 89 return Error::success(); 90} 91 92Error LLVMOutputStyle::dumpFileHeaders() { 93 if (!opts::raw::DumpHeaders) 94 return Error::success(); 95 96 DictScope D(P, "FileHeaders"); 97 P.printNumber("BlockSize", File.getBlockSize()); 98 P.printNumber("Unknown0", File.getUnknown0()); 99 P.printNumber("NumBlocks", File.getBlockCount()); 100 P.printNumber("NumDirectoryBytes", File.getNumDirectoryBytes()); 101 P.printNumber("Unknown1", File.getUnknown1()); 102 P.printNumber("BlockMapAddr", File.getBlockMapIndex()); 103 P.printNumber("NumDirectoryBlocks", File.getNumDirectoryBlocks()); 104 P.printNumber("BlockMapOffset", File.getBlockMapOffset()); 105 106 // The directory is not contiguous. Instead, the block map contains a 107 // contiguous list of block numbers whose contents, when concatenated in 108 // order, make up the directory. 109 P.printList("DirectoryBlocks", File.getDirectoryBlockArray()); 110 P.printNumber("NumStreams", File.getNumStreams()); 111 return Error::success(); 112} 113 114Error LLVMOutputStyle::dumpStreamSummary() { 115 if (!opts::raw::DumpStreamSummary) 116 return Error::success(); 117 118 // It's OK if we fail to load some of these streams, we still attempt to print 119 // what we can. 120 auto Dbi = File.getPDBDbiStream(); 121 auto Tpi = File.getPDBTpiStream(); 122 auto Ipi = File.getPDBIpiStream(); 123 auto Info = File.getPDBInfoStream(); 124 125 ListScope L(P, "Streams"); 126 uint32_t StreamCount = File.getNumStreams(); 127 std::unordered_map<uint16_t, const ModuleInfoEx *> ModStreams; 128 std::unordered_map<uint16_t, std::string> NamedStreams; 129 130 if (Dbi) { 131 for (auto &ModI : Dbi->modules()) { 132 uint16_t SN = ModI.Info.getModuleStreamIndex(); 133 ModStreams[SN] = &ModI; 134 } 135 } 136 if (Info) { 137 for (auto &NSE : Info->named_streams()) { 138 NamedStreams[NSE.second] = NSE.first(); 139 } 140 } 141 142 for (uint16_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) { 143 std::string Label("Stream "); 144 Label += to_string(StreamIdx); 145 std::string Value; 146 if (StreamIdx == OldMSFDirectory) 147 Value = "Old MSF Directory"; 148 else if (StreamIdx == StreamPDB) 149 Value = "PDB Stream"; 150 else if (StreamIdx == StreamDBI) 151 Value = "DBI Stream"; 152 else if (StreamIdx == StreamTPI) 153 Value = "TPI Stream"; 154 else if (StreamIdx == StreamIPI) 155 Value = "IPI Stream"; 156 else if (Dbi && StreamIdx == Dbi->getGlobalSymbolStreamIndex()) 157 Value = "Global Symbol Hash"; 158 else if (Dbi && StreamIdx == Dbi->getPublicSymbolStreamIndex()) 159 Value = "Public Symbol Hash"; 160 else if (Dbi && StreamIdx == Dbi->getSymRecordStreamIndex()) 161 Value = "Public Symbol Records"; 162 else if (Tpi && StreamIdx == Tpi->getTypeHashStreamIndex()) 163 Value = "TPI Hash"; 164 else if (Tpi && StreamIdx == Tpi->getTypeHashStreamAuxIndex()) 165 Value = "TPI Aux Hash"; 166 else if (Ipi && StreamIdx == Ipi->getTypeHashStreamIndex()) 167 Value = "IPI Hash"; 168 else if (Ipi && StreamIdx == Ipi->getTypeHashStreamAuxIndex()) 169 Value = "IPI Aux Hash"; 170 else if (Dbi && 171 StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Exception)) 172 Value = "Exception Data"; 173 else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Fixup)) 174 Value = "Fixup Data"; 175 else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::FPO)) 176 Value = "FPO Data"; 177 else if (Dbi && 178 StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::NewFPO)) 179 Value = "New FPO Data"; 180 else if (Dbi && 181 StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::OmapFromSrc)) 182 Value = "Omap From Source Data"; 183 else if (Dbi && 184 StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::OmapToSrc)) 185 Value = "Omap To Source Data"; 186 else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Pdata)) 187 Value = "Pdata"; 188 else if (Dbi && 189 StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::SectionHdr)) 190 Value = "Section Header Data"; 191 else if (Dbi && 192 StreamIdx == 193 Dbi->getDebugStreamIndex(DbgHeaderType::SectionHdrOrig)) 194 Value = "Section Header Original Data"; 195 else if (Dbi && 196 StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::TokenRidMap)) 197 Value = "Token Rid Data"; 198 else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Xdata)) 199 Value = "Xdata"; 200 else { 201 auto ModIter = ModStreams.find(StreamIdx); 202 auto NSIter = NamedStreams.find(StreamIdx); 203 if (ModIter != ModStreams.end()) { 204 Value = "Module \""; 205 Value += ModIter->second->Info.getModuleName().str(); 206 Value += "\""; 207 } else if (NSIter != NamedStreams.end()) { 208 Value = "Named Stream \""; 209 Value += NSIter->second; 210 Value += "\""; 211 } else { 212 Value = "???"; 213 } 214 } 215 Value = "[" + Value + "]"; 216 Value = 217 Value + " (" + to_string(File.getStreamByteSize(StreamIdx)) + " bytes)"; 218 219 P.printString(Label, Value); 220 } 221 222 // Consume errors from missing streams. 223 if (!Dbi) 224 consumeError(Dbi.takeError()); 225 if (!Tpi) 226 consumeError(Tpi.takeError()); 227 if (!Ipi) 228 consumeError(Ipi.takeError()); 229 if (!Info) 230 consumeError(Info.takeError()); 231 232 P.flush(); 233 return Error::success(); 234} 235 236Error LLVMOutputStyle::dumpStreamBlocks() { 237 if (!opts::raw::DumpStreamBlocks) 238 return Error::success(); 239 240 ListScope L(P, "StreamBlocks"); 241 uint32_t StreamCount = File.getNumStreams(); 242 for (uint32_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) { 243 std::string Name("Stream "); 244 Name += to_string(StreamIdx); 245 auto StreamBlocks = File.getStreamBlockList(StreamIdx); 246 P.printList(Name, StreamBlocks); 247 } 248 return Error::success(); 249} 250 251Error LLVMOutputStyle::dumpStreamData() { 252 uint32_t StreamCount = File.getNumStreams(); 253 StringRef DumpStreamStr = opts::raw::DumpStreamDataIdx; 254 uint32_t DumpStreamNum; 255 if (DumpStreamStr.getAsInteger(/*Radix=*/0U, DumpStreamNum)) 256 return Error::success(); 257 258 if (DumpStreamNum >= StreamCount) 259 return make_error<RawError>(raw_error_code::no_stream); 260 261 auto S = MappedBlockStream::createIndexedStream(DumpStreamNum, File); 262 if (!S) 263 return S.takeError(); 264 codeview::StreamReader R(**S); 265 while (R.bytesRemaining() > 0) { 266 ArrayRef<uint8_t> Data; 267 uint32_t BytesToReadInBlock = std::min( 268 R.bytesRemaining(), static_cast<uint32_t>(File.getBlockSize())); 269 if (auto EC = R.readBytes(Data, BytesToReadInBlock)) 270 return EC; 271 P.printBinaryBlock( 272 "Data", 273 StringRef(reinterpret_cast<const char *>(Data.begin()), Data.size())); 274 } 275 return Error::success(); 276} 277 278Error LLVMOutputStyle::dumpInfoStream() { 279 if (!opts::raw::DumpHeaders) 280 return Error::success(); 281 auto IS = File.getPDBInfoStream(); 282 if (!IS) 283 return IS.takeError(); 284 285 DictScope D(P, "PDB Stream"); 286 P.printNumber("Version", IS->getVersion()); 287 P.printHex("Signature", IS->getSignature()); 288 P.printNumber("Age", IS->getAge()); 289 P.printObject("Guid", IS->getGuid()); 290 return Error::success(); 291} 292 293Error LLVMOutputStyle::dumpNamedStream() { 294 if (opts::raw::DumpStreamDataName.empty()) 295 return Error::success(); 296 297 auto IS = File.getPDBInfoStream(); 298 if (!IS) 299 return IS.takeError(); 300 301 uint32_t NameStreamIndex = 302 IS->getNamedStreamIndex(opts::raw::DumpStreamDataName); 303 if (NameStreamIndex == 0 || NameStreamIndex >= File.getNumStreams()) 304 return make_error<RawError>(raw_error_code::no_stream); 305 306 if (NameStreamIndex != 0) { 307 std::string Name("Stream '"); 308 Name += opts::raw::DumpStreamDataName; 309 Name += "'"; 310 DictScope D(P, Name); 311 P.printNumber("Index", NameStreamIndex); 312 313 auto NameStream = 314 MappedBlockStream::createIndexedStream(NameStreamIndex, File); 315 if (!NameStream) 316 return NameStream.takeError(); 317 codeview::StreamReader Reader(**NameStream); 318 319 NameHashTable NameTable; 320 if (auto EC = NameTable.load(Reader)) 321 return EC; 322 323 P.printHex("Signature", NameTable.getSignature()); 324 P.printNumber("Version", NameTable.getHashVersion()); 325 P.printNumber("Name Count", NameTable.getNameCount()); 326 ListScope L(P, "Names"); 327 for (uint32_t ID : NameTable.name_ids()) { 328 StringRef Str = NameTable.getStringForID(ID); 329 if (!Str.empty()) 330 P.printString(to_string(ID), Str); 331 } 332 } 333 return Error::success(); 334} 335 336static void printTypeIndexOffset(raw_ostream &OS, 337 const TypeIndexOffset &TIOff) { 338 OS << "{" << TIOff.Type.getIndex() << ", " << TIOff.Offset << "}"; 339} 340 341static void dumpTpiHash(ScopedPrinter &P, TpiStream &Tpi) { 342 if (!opts::raw::DumpTpiHash) 343 return; 344 DictScope DD(P, "Hash"); 345 P.printNumber("Number of Hash Buckets", Tpi.NumHashBuckets()); 346 P.printNumber("Hash Key Size", Tpi.getHashKeySize()); 347 P.printList("Values", Tpi.getHashValues()); 348 P.printList("Type Index Offsets", Tpi.getTypeIndexOffsets(), 349 printTypeIndexOffset); 350 P.printList("Hash Adjustments", Tpi.getHashAdjustments(), 351 printTypeIndexOffset); 352} 353 354Error LLVMOutputStyle::dumpTpiStream(uint32_t StreamIdx) { 355 assert(StreamIdx == StreamTPI || StreamIdx == StreamIPI); 356 357 bool DumpRecordBytes = false; 358 bool DumpRecords = false; 359 StringRef Label; 360 StringRef VerLabel; 361 if (StreamIdx == StreamTPI) { 362 DumpRecordBytes = opts::raw::DumpTpiRecordBytes; 363 DumpRecords = opts::raw::DumpTpiRecords; 364 Label = "Type Info Stream (TPI)"; 365 VerLabel = "TPI Version"; 366 } else if (StreamIdx == StreamIPI) { 367 DumpRecordBytes = opts::raw::DumpIpiRecordBytes; 368 DumpRecords = opts::raw::DumpIpiRecords; 369 Label = "Type Info Stream (IPI)"; 370 VerLabel = "IPI Version"; 371 } 372 if (!DumpRecordBytes && !DumpRecords && !opts::raw::DumpModuleSyms) 373 return Error::success(); 374 375 auto Tpi = (StreamIdx == StreamTPI) ? File.getPDBTpiStream() 376 : File.getPDBIpiStream(); 377 if (!Tpi) 378 return Tpi.takeError(); 379 380 if (DumpRecords || DumpRecordBytes) { 381 DictScope D(P, Label); 382 383 P.printNumber(VerLabel, Tpi->getTpiVersion()); 384 P.printNumber("Record count", Tpi->NumTypeRecords()); 385 386 ListScope L(P, "Records"); 387 388 bool HadError = false; 389 for (auto &Type : Tpi->types(&HadError)) { 390 DictScope DD(P, ""); 391 392 if (DumpRecords) { 393 if (auto EC = TD.dump(Type)) 394 return EC; 395 } 396 397 if (DumpRecordBytes) 398 P.printBinaryBlock("Bytes", Type.Data); 399 } 400 dumpTpiHash(P, *Tpi); 401 if (HadError) 402 return make_error<RawError>(raw_error_code::corrupt_file, 403 "TPI stream contained corrupt record"); 404 } else if (opts::raw::DumpModuleSyms) { 405 // Even if the user doesn't want to dump type records, we still need to 406 // iterate them in order to build the list of types so that we can print 407 // them when dumping module symbols. So when they want to dump symbols 408 // but not types, use a null output stream. 409 ScopedPrinter *OldP = TD.getPrinter(); 410 TD.setPrinter(nullptr); 411 412 bool HadError = false; 413 for (auto &Type : Tpi->types(&HadError)) { 414 if (auto EC = TD.dump(Type)) 415 return EC; 416 } 417 418 TD.setPrinter(OldP); 419 dumpTpiHash(P, *Tpi); 420 if (HadError) 421 return make_error<RawError>(raw_error_code::corrupt_file, 422 "TPI stream contained corrupt record"); 423 } 424 P.flush(); 425 return Error::success(); 426} 427 428Error LLVMOutputStyle::dumpDbiStream() { 429 bool DumpModules = opts::raw::DumpModules || opts::raw::DumpModuleSyms || 430 opts::raw::DumpModuleFiles || opts::raw::DumpLineInfo; 431 if (!opts::raw::DumpHeaders && !DumpModules) 432 return Error::success(); 433 434 auto DS = File.getPDBDbiStream(); 435 if (!DS) 436 return DS.takeError(); 437 438 DictScope D(P, "DBI Stream"); 439 P.printNumber("Dbi Version", DS->getDbiVersion()); 440 P.printNumber("Age", DS->getAge()); 441 P.printBoolean("Incremental Linking", DS->isIncrementallyLinked()); 442 P.printBoolean("Has CTypes", DS->hasCTypes()); 443 P.printBoolean("Is Stripped", DS->isStripped()); 444 P.printObject("Machine Type", DS->getMachineType()); 445 P.printNumber("Symbol Record Stream Index", DS->getSymRecordStreamIndex()); 446 P.printNumber("Public Symbol Stream Index", DS->getPublicSymbolStreamIndex()); 447 P.printNumber("Global Symbol Stream Index", DS->getGlobalSymbolStreamIndex()); 448 449 uint16_t Major = DS->getBuildMajorVersion(); 450 uint16_t Minor = DS->getBuildMinorVersion(); 451 P.printVersion("Toolchain Version", Major, Minor); 452 453 std::string DllName; 454 raw_string_ostream DllStream(DllName); 455 DllStream << "mspdb" << Major << Minor << ".dll version"; 456 DllStream.flush(); 457 P.printVersion(DllName, Major, Minor, DS->getPdbDllVersion()); 458 459 if (DumpModules) { 460 ListScope L(P, "Modules"); 461 for (auto &Modi : DS->modules()) { 462 DictScope DD(P); 463 P.printString("Name", Modi.Info.getModuleName().str()); 464 P.printNumber("Debug Stream Index", Modi.Info.getModuleStreamIndex()); 465 P.printString("Object File Name", Modi.Info.getObjFileName().str()); 466 P.printNumber("Num Files", Modi.Info.getNumberOfFiles()); 467 P.printNumber("Source File Name Idx", Modi.Info.getSourceFileNameIndex()); 468 P.printNumber("Pdb File Name Idx", Modi.Info.getPdbFilePathNameIndex()); 469 P.printNumber("Line Info Byte Size", Modi.Info.getLineInfoByteSize()); 470 P.printNumber("C13 Line Info Byte Size", 471 Modi.Info.getC13LineInfoByteSize()); 472 P.printNumber("Symbol Byte Size", Modi.Info.getSymbolDebugInfoByteSize()); 473 P.printNumber("Type Server Index", Modi.Info.getTypeServerIndex()); 474 P.printBoolean("Has EC Info", Modi.Info.hasECInfo()); 475 if (opts::raw::DumpModuleFiles) { 476 std::string FileListName = 477 to_string(Modi.SourceFiles.size()) + " Contributing Source Files"; 478 ListScope LL(P, FileListName); 479 for (auto File : Modi.SourceFiles) 480 P.printString(File.str()); 481 } 482 bool HasModuleDI = 483 (Modi.Info.getModuleStreamIndex() < File.getNumStreams()); 484 bool ShouldDumpSymbols = 485 (opts::raw::DumpModuleSyms || opts::raw::DumpSymRecordBytes); 486 if (HasModuleDI && (ShouldDumpSymbols || opts::raw::DumpLineInfo)) { 487 auto ModStreamData = MappedBlockStream::createIndexedStream( 488 Modi.Info.getModuleStreamIndex(), File); 489 if (!ModStreamData) 490 return ModStreamData.takeError(); 491 ModStream ModS(Modi.Info, std::move(*ModStreamData)); 492 if (auto EC = ModS.reload()) 493 return EC; 494 495 if (ShouldDumpSymbols) { 496 ListScope SS(P, "Symbols"); 497 codeview::CVSymbolDumper SD(P, TD, nullptr, false); 498 bool HadError = false; 499 for (const auto &S : ModS.symbols(&HadError)) { 500 DictScope DD(P, ""); 501 502 if (opts::raw::DumpModuleSyms) 503 SD.dump(S); 504 if (opts::raw::DumpSymRecordBytes) 505 P.printBinaryBlock("Bytes", S.Data); 506 } 507 if (HadError) 508 return make_error<RawError>( 509 raw_error_code::corrupt_file, 510 "DBI stream contained corrupt symbol record"); 511 } 512 if (opts::raw::DumpLineInfo) { 513 ListScope SS(P, "LineInfo"); 514 bool HadError = false; 515 // Define a locally scoped visitor to print the different 516 // substream types types. 517 class RecordVisitor : public codeview::IModuleSubstreamVisitor { 518 public: 519 RecordVisitor(ScopedPrinter &P, PDBFile &F) : P(P), F(F) {} 520 Error visitUnknown(ModuleSubstreamKind Kind, 521 StreamRef Stream) override { 522 DictScope DD(P, "Unknown"); 523 ArrayRef<uint8_t> Data; 524 StreamReader R(Stream); 525 if (auto EC = R.readBytes(Data, R.bytesRemaining())) { 526 return make_error<RawError>( 527 raw_error_code::corrupt_file, 528 "DBI stream contained corrupt line info record"); 529 } 530 P.printBinaryBlock("Data", Data); 531 return Error::success(); 532 } 533 Error 534 visitFileChecksums(StreamRef Data, 535 const FileChecksumArray &Checksums) override { 536 DictScope DD(P, "FileChecksums"); 537 for (const auto &C : Checksums) { 538 DictScope DDD(P, "Checksum"); 539 if (auto Result = getFileNameForOffset(C.FileNameOffset)) 540 P.printString("FileName", Result.get()); 541 else 542 return Result.takeError(); 543 P.flush(); 544 P.printEnum("Kind", uint8_t(C.Kind), getFileChecksumNames()); 545 P.printBinaryBlock("Checksum", C.Checksum); 546 } 547 return Error::success(); 548 } 549 550 Error visitLines(StreamRef Data, const LineSubstreamHeader *Header, 551 const LineInfoArray &Lines) override { 552 DictScope DD(P, "Lines"); 553 for (const auto &L : Lines) { 554 if (auto Result = getFileNameForOffset2(L.NameIndex)) 555 P.printString("FileName", Result.get()); 556 else 557 return Result.takeError(); 558 P.flush(); 559 for (const auto &N : L.LineNumbers) { 560 DictScope DDD(P, "Line"); 561 LineInfo LI(N.Flags); 562 P.printNumber("Offset", N.Offset); 563 if (LI.isAlwaysStepInto()) 564 P.printString("StepInto", StringRef("Always")); 565 else if (LI.isNeverStepInto()) 566 P.printString("StepInto", StringRef("Never")); 567 else 568 P.printNumber("LineNumberStart", LI.getStartLine()); 569 P.printNumber("EndDelta", LI.getLineDelta()); 570 P.printBoolean("IsStatement", LI.isStatement()); 571 } 572 for (const auto &C : L.Columns) { 573 DictScope DDD(P, "Column"); 574 P.printNumber("Start", C.StartColumn); 575 P.printNumber("End", C.EndColumn); 576 } 577 } 578 return Error::success(); 579 } 580 581 private: 582 Expected<StringRef> getFileNameForOffset(uint32_t Offset) { 583 auto ST = F.getStringTable(); 584 if (!ST) 585 return ST.takeError(); 586 587 return ST->getStringForID(Offset); 588 } 589 Expected<StringRef> getFileNameForOffset2(uint32_t Offset) { 590 auto DS = F.getPDBDbiStream(); 591 if (!DS) 592 return DS.takeError(); 593 return DS->getFileNameForIndex(Offset); 594 } 595 ScopedPrinter &P; 596 PDBFile &F; 597 }; 598 599 RecordVisitor V(P, File); 600 for (const auto &L : ModS.lines(&HadError)) { 601 if (auto EC = codeview::visitModuleSubstream(L, V)) 602 return EC; 603 } 604 } 605 } 606 } 607 } 608 return Error::success(); 609} 610 611Error LLVMOutputStyle::dumpSectionContribs() { 612 if (!opts::raw::DumpSectionContribs) 613 return Error::success(); 614 615 auto Dbi = File.getPDBDbiStream(); 616 if (!Dbi) 617 return Dbi.takeError(); 618 619 ListScope L(P, "Section Contributions"); 620 class Visitor : public ISectionContribVisitor { 621 public: 622 Visitor(ScopedPrinter &P, DbiStream &DS) : P(P), DS(DS) {} 623 void visit(const SectionContrib &SC) override { 624 DictScope D(P, "Contribution"); 625 P.printNumber("ISect", SC.ISect); 626 P.printNumber("Off", SC.Off); 627 P.printNumber("Size", SC.Size); 628 P.printFlags("Characteristics", SC.Characteristics, 629 codeview::getImageSectionCharacteristicNames(), 630 COFF::SectionCharacteristics(0x00F00000)); 631 { 632 DictScope DD(P, "Module"); 633 P.printNumber("Index", SC.Imod); 634 auto M = DS.modules(); 635 if (M.size() > SC.Imod) { 636 P.printString("Name", M[SC.Imod].Info.getModuleName()); 637 } 638 } 639 P.printNumber("Data CRC", SC.DataCrc); 640 P.printNumber("Reloc CRC", SC.RelocCrc); 641 P.flush(); 642 } 643 void visit(const SectionContrib2 &SC) override { 644 visit(SC.Base); 645 P.printNumber("ISect Coff", SC.ISectCoff); 646 P.flush(); 647 } 648 649 private: 650 ScopedPrinter &P; 651 DbiStream &DS; 652 }; 653 Visitor V(P, *Dbi); 654 Dbi->visitSectionContributions(V); 655 return Error::success(); 656} 657 658Error LLVMOutputStyle::dumpSectionMap() { 659 if (!opts::raw::DumpSectionMap) 660 return Error::success(); 661 662 auto Dbi = File.getPDBDbiStream(); 663 if (!Dbi) 664 return Dbi.takeError(); 665 666 ListScope L(P, "Section Map"); 667 for (auto &M : Dbi->getSectionMap()) { 668 DictScope D(P, "Entry"); 669 P.printFlags("Flags", M.Flags, getOMFSegMapDescFlagNames()); 670 P.printNumber("Flags", M.Flags); 671 P.printNumber("Ovl", M.Ovl); 672 P.printNumber("Group", M.Group); 673 P.printNumber("Frame", M.Frame); 674 P.printNumber("SecName", M.SecName); 675 P.printNumber("ClassName", M.ClassName); 676 P.printNumber("Offset", M.Offset); 677 P.printNumber("SecByteLength", M.SecByteLength); 678 P.flush(); 679 } 680 return Error::success(); 681} 682 683Error LLVMOutputStyle::dumpPublicsStream() { 684 if (!opts::raw::DumpPublics) 685 return Error::success(); 686 687 DictScope D(P, "Publics Stream"); 688 auto Publics = File.getPDBPublicsStream(); 689 if (!Publics) 690 return Publics.takeError(); 691 692 auto Dbi = File.getPDBDbiStream(); 693 if (!Dbi) 694 return Dbi.takeError(); 695 696 P.printNumber("Stream number", Dbi->getPublicSymbolStreamIndex()); 697 P.printNumber("SymHash", Publics->getSymHash()); 698 P.printNumber("AddrMap", Publics->getAddrMap()); 699 P.printNumber("Number of buckets", Publics->getNumBuckets()); 700 P.printList("Hash Buckets", Publics->getHashBuckets()); 701 P.printList("Address Map", Publics->getAddressMap()); 702 P.printList("Thunk Map", Publics->getThunkMap()); 703 P.printList("Section Offsets", Publics->getSectionOffsets(), 704 printSectionOffset); 705 ListScope L(P, "Symbols"); 706 codeview::CVSymbolDumper SD(P, TD, nullptr, false); 707 bool HadError = false; 708 for (auto S : Publics->getSymbols(&HadError)) { 709 DictScope DD(P, ""); 710 711 SD.dump(S); 712 if (opts::raw::DumpSymRecordBytes) 713 P.printBinaryBlock("Bytes", S.Data); 714 } 715 if (HadError) 716 return make_error<RawError>( 717 raw_error_code::corrupt_file, 718 "Public symbol stream contained corrupt record"); 719 720 return Error::success(); 721} 722 723Error LLVMOutputStyle::dumpSectionHeaders() { 724 if (!opts::raw::DumpSectionHeaders) 725 return Error::success(); 726 727 auto Dbi = File.getPDBDbiStream(); 728 if (!Dbi) 729 return Dbi.takeError(); 730 731 ListScope D(P, "Section Headers"); 732 for (const object::coff_section &Section : Dbi->getSectionHeaders()) { 733 DictScope DD(P, ""); 734 735 // If a name is 8 characters long, there is no NUL character at end. 736 StringRef Name(Section.Name, strnlen(Section.Name, sizeof(Section.Name))); 737 P.printString("Name", Name); 738 P.printNumber("Virtual Size", Section.VirtualSize); 739 P.printNumber("Virtual Address", Section.VirtualAddress); 740 P.printNumber("Size of Raw Data", Section.SizeOfRawData); 741 P.printNumber("File Pointer to Raw Data", Section.PointerToRawData); 742 P.printNumber("File Pointer to Relocations", Section.PointerToRelocations); 743 P.printNumber("File Pointer to Linenumbers", Section.PointerToLinenumbers); 744 P.printNumber("Number of Relocations", Section.NumberOfRelocations); 745 P.printNumber("Number of Linenumbers", Section.NumberOfLinenumbers); 746 P.printFlags("Characteristics", Section.Characteristics, 747 getImageSectionCharacteristicNames()); 748 } 749 return Error::success(); 750} 751 752Error LLVMOutputStyle::dumpFpoStream() { 753 if (!opts::raw::DumpFpo) 754 return Error::success(); 755 756 auto Dbi = File.getPDBDbiStream(); 757 if (!Dbi) 758 return Dbi.takeError(); 759 760 ListScope D(P, "New FPO"); 761 for (const object::FpoData &Fpo : Dbi->getFpoRecords()) { 762 DictScope DD(P, ""); 763 P.printNumber("Offset", Fpo.Offset); 764 P.printNumber("Size", Fpo.Size); 765 P.printNumber("Number of locals", Fpo.NumLocals); 766 P.printNumber("Number of params", Fpo.NumParams); 767 P.printNumber("Size of Prolog", Fpo.getPrologSize()); 768 P.printNumber("Number of Saved Registers", Fpo.getNumSavedRegs()); 769 P.printBoolean("Has SEH", Fpo.hasSEH()); 770 P.printBoolean("Use BP", Fpo.useBP()); 771 P.printNumber("Frame Pointer", Fpo.getFP()); 772 } 773 return Error::success(); 774} 775 776void LLVMOutputStyle::flush() { P.flush(); } 777