aboutsummaryrefslogtreecommitdiff
path: root/tools/llvm-pdbdump/LLVMOutputStyle.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/llvm-pdbdump/LLVMOutputStyle.cpp')
-rw-r--r--tools/llvm-pdbdump/LLVMOutputStyle.cpp337
1 files changed, 149 insertions, 188 deletions
diff --git a/tools/llvm-pdbdump/LLVMOutputStyle.cpp b/tools/llvm-pdbdump/LLVMOutputStyle.cpp
index 629ba40b113c..8348751703f1 100644
--- a/tools/llvm-pdbdump/LLVMOutputStyle.cpp
+++ b/tools/llvm-pdbdump/LLVMOutputStyle.cpp
@@ -9,7 +9,10 @@
#include "LLVMOutputStyle.h"
+#include "CompactTypeDumpVisitor.h"
+#include "StreamUtil.h"
#include "llvm-pdbdump.h"
+
#include "llvm/DebugInfo/CodeView/CVTypeDumper.h"
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
#include "llvm/DebugInfo/CodeView/EnumTables.h"
@@ -20,20 +23,21 @@
#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
-#include "llvm/DebugInfo/MSF/StreamReader.h"
+#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
+#include "llvm/DebugInfo/PDB/Native/EnumTables.h"
+#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
+#include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h"
+#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
+#include "llvm/DebugInfo/PDB/Native/ModInfo.h"
+#include "llvm/DebugInfo/PDB/Native/ModStream.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/PublicsStream.h"
+#include "llvm/DebugInfo/PDB/Native/RawError.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
#include "llvm/DebugInfo/PDB/PDBExtras.h"
-#include "llvm/DebugInfo/PDB/Raw/DbiStream.h"
-#include "llvm/DebugInfo/PDB/Raw/EnumTables.h"
-#include "llvm/DebugInfo/PDB/Raw/GlobalsStream.h"
-#include "llvm/DebugInfo/PDB/Raw/ISectionContribVisitor.h"
-#include "llvm/DebugInfo/PDB/Raw/InfoStream.h"
-#include "llvm/DebugInfo/PDB/Raw/ModInfo.h"
-#include "llvm/DebugInfo/PDB/Raw/ModStream.h"
-#include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
-#include "llvm/DebugInfo/PDB/Raw/PublicsStream.h"
-#include "llvm/DebugInfo/PDB/Raw/RawError.h"
-#include "llvm/DebugInfo/PDB/Raw/TpiStream.h"
#include "llvm/Object/COFF.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/FormatVariadic.h"
#include <unordered_map>
@@ -110,6 +114,9 @@ Error LLVMOutputStyle::dump() {
if (auto EC = dumpStreamBytes())
return EC;
+ if (auto EC = dumpStringTable())
+ return EC;
+
if (auto EC = dumpInfoStream())
return EC;
@@ -166,124 +173,12 @@ Error LLVMOutputStyle::dumpFileHeaders() {
return Error::success();
}
-void LLVMOutputStyle::discoverStreamPurposes() {
- if (!StreamPurposes.empty())
- return;
-
- // It's OK if we fail to load some of these streams, we still attempt to print
- // what we can.
- auto Dbi = File.getPDBDbiStream();
- auto Tpi = File.getPDBTpiStream();
- auto Ipi = File.getPDBIpiStream();
- auto Info = File.getPDBInfoStream();
-
- uint32_t StreamCount = File.getNumStreams();
- std::unordered_map<uint16_t, const ModuleInfoEx *> ModStreams;
- std::unordered_map<uint16_t, std::string> NamedStreams;
-
- if (Dbi) {
- for (auto &ModI : Dbi->modules()) {
- uint16_t SN = ModI.Info.getModuleStreamIndex();
- ModStreams[SN] = &ModI;
- }
- }
- if (Info) {
- for (auto &NSE : Info->named_streams()) {
- NamedStreams[NSE.second] = NSE.first();
- }
- }
-
- StreamPurposes.resize(StreamCount);
- for (uint16_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) {
- std::string Value;
- if (StreamIdx == OldMSFDirectory)
- Value = "Old MSF Directory";
- else if (StreamIdx == StreamPDB)
- Value = "PDB Stream";
- else if (StreamIdx == StreamDBI)
- Value = "DBI Stream";
- else if (StreamIdx == StreamTPI)
- Value = "TPI Stream";
- else if (StreamIdx == StreamIPI)
- Value = "IPI Stream";
- else if (Dbi && StreamIdx == Dbi->getGlobalSymbolStreamIndex())
- Value = "Global Symbol Hash";
- else if (Dbi && StreamIdx == Dbi->getPublicSymbolStreamIndex())
- Value = "Public Symbol Hash";
- else if (Dbi && StreamIdx == Dbi->getSymRecordStreamIndex())
- Value = "Public Symbol Records";
- else if (Tpi && StreamIdx == Tpi->getTypeHashStreamIndex())
- Value = "TPI Hash";
- else if (Tpi && StreamIdx == Tpi->getTypeHashStreamAuxIndex())
- Value = "TPI Aux Hash";
- else if (Ipi && StreamIdx == Ipi->getTypeHashStreamIndex())
- Value = "IPI Hash";
- else if (Ipi && StreamIdx == Ipi->getTypeHashStreamAuxIndex())
- Value = "IPI Aux Hash";
- else if (Dbi &&
- StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Exception))
- Value = "Exception Data";
- else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Fixup))
- Value = "Fixup Data";
- else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::FPO))
- Value = "FPO Data";
- else if (Dbi &&
- StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::NewFPO))
- Value = "New FPO Data";
- else if (Dbi &&
- StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::OmapFromSrc))
- Value = "Omap From Source Data";
- else if (Dbi &&
- StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::OmapToSrc))
- Value = "Omap To Source Data";
- else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Pdata))
- Value = "Pdata";
- else if (Dbi &&
- StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::SectionHdr))
- Value = "Section Header Data";
- else if (Dbi &&
- StreamIdx ==
- Dbi->getDebugStreamIndex(DbgHeaderType::SectionHdrOrig))
- Value = "Section Header Original Data";
- else if (Dbi &&
- StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::TokenRidMap))
- Value = "Token Rid Data";
- else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Xdata))
- Value = "Xdata";
- else {
- auto ModIter = ModStreams.find(StreamIdx);
- auto NSIter = NamedStreams.find(StreamIdx);
- if (ModIter != ModStreams.end()) {
- Value = "Module \"";
- Value += ModIter->second->Info.getModuleName().str();
- Value += "\"";
- } else if (NSIter != NamedStreams.end()) {
- Value = "Named Stream \"";
- Value += NSIter->second;
- Value += "\"";
- } else {
- Value = "???";
- }
- }
- StreamPurposes[StreamIdx] = Value;
- }
-
- // Consume errors from missing streams.
- if (!Dbi)
- consumeError(Dbi.takeError());
- if (!Tpi)
- consumeError(Tpi.takeError());
- if (!Ipi)
- consumeError(Ipi.takeError());
- if (!Info)
- consumeError(Info.takeError());
-}
-
Error LLVMOutputStyle::dumpStreamSummary() {
if (!opts::raw::DumpStreamSummary)
return Error::success();
- discoverStreamPurposes();
+ if (StreamPurposes.empty())
+ discoverStreamPurposes(File, StreamPurposes);
uint32_t StreamCount = File.getNumStreams();
@@ -425,7 +320,8 @@ Error LLVMOutputStyle::dumpStreamBytes() {
if (opts::raw::DumpStreamData.empty())
return Error::success();
- discoverStreamPurposes();
+ if (StreamPurposes.empty())
+ discoverStreamPurposes(File, StreamPurposes);
DictScope D(P, "Stream Data");
for (uint32_t SI : opts::raw::DumpStreamData) {
@@ -444,7 +340,7 @@ Error LLVMOutputStyle::dumpStreamBytes() {
auto Blocks = File.getMsfLayout().StreamMap[SI];
P.printList("Blocks", Blocks);
- StreamReader R(*S);
+ BinaryStreamReader R(*S);
ArrayRef<uint8_t> StreamData;
if (auto EC = R.readBytes(StreamData, S->getLength()))
return EC;
@@ -453,6 +349,28 @@ Error LLVMOutputStyle::dumpStreamBytes() {
return Error::success();
}
+Error LLVMOutputStyle::dumpStringTable() {
+ if (!opts::raw::DumpStringTable)
+ return Error::success();
+
+ auto IS = File.getStringTable();
+ if (!IS)
+ return IS.takeError();
+
+ DictScope D(P, "String Table");
+ for (uint32_t I : IS->name_ids()) {
+ StringRef S = IS->getStringForID(I);
+ if (!S.empty()) {
+ llvm::SmallString<32> Str;
+ Str.append("'");
+ Str.append(S);
+ Str.append("'");
+ P.printString(Str);
+ }
+ }
+ return Error::success();
+}
+
Error LLVMOutputStyle::dumpInfoStream() {
if (!opts::raw::DumpHeaders)
return Error::success();
@@ -469,25 +387,28 @@ Error LLVMOutputStyle::dumpInfoStream() {
P.printHex("Signature", IS->getSignature());
P.printNumber("Age", IS->getAge());
P.printObject("Guid", IS->getGuid());
+ P.printHex("Features", IS->getFeatures());
+ {
+ DictScope DD(P, "Named Streams");
+ for (const auto &S : IS->getNamedStreams().entries())
+ P.printObject(S.getKey(), S.getValue());
+ }
return Error::success();
}
-static void printTypeIndexOffset(raw_ostream &OS,
- const TypeIndexOffset &TIOff) {
- OS << "{" << TIOff.Type.getIndex() << ", " << TIOff.Offset << "}";
-}
+namespace {
+class RecordBytesVisitor : public TypeVisitorCallbacks {
+public:
+ explicit RecordBytesVisitor(ScopedPrinter &P) : P(P) {}
-static void dumpTpiHash(ScopedPrinter &P, TpiStream &Tpi) {
- if (!opts::raw::DumpTpiHash)
- return;
- DictScope DD(P, "Hash");
- P.printNumber("Number of Hash Buckets", Tpi.NumHashBuckets());
- P.printNumber("Hash Key Size", Tpi.getHashKeySize());
- P.printList("Values", Tpi.getHashValues());
- P.printList("Type Index Offsets", Tpi.getTypeIndexOffsets(),
- printTypeIndexOffset);
- P.printList("Hash Adjustments", Tpi.getHashAdjustments(),
- printTypeIndexOffset);
+ Error visitTypeEnd(CVType &Record) override {
+ P.printBinaryBlock("Bytes", Record.content());
+ return Error::success();
+ }
+
+private:
+ ScopedPrinter &P;
+};
}
Error LLVMOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
@@ -495,6 +416,7 @@ Error LLVMOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
bool DumpRecordBytes = false;
bool DumpRecords = false;
+ bool DumpTpiHash = false;
StringRef Label;
StringRef VerLabel;
if (StreamIdx == StreamTPI) {
@@ -504,6 +426,7 @@ Error LLVMOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
}
DumpRecordBytes = opts::raw::DumpTpiRecordBytes;
DumpRecords = opts::raw::DumpTpiRecords;
+ DumpTpiHash = opts::raw::DumpTpiHash;
Label = "Type Info Stream (TPI)";
VerLabel = "TPI Version";
} else if (StreamIdx == StreamIPI) {
@@ -516,64 +439,102 @@ Error LLVMOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
Label = "Type Info Stream (IPI)";
VerLabel = "IPI Version";
}
- if (!DumpRecordBytes && !DumpRecords && !opts::raw::DumpModuleSyms)
+ if (!DumpRecordBytes && !DumpRecords && !DumpTpiHash &&
+ !opts::raw::DumpModuleSyms)
return Error::success();
+ bool IsSilentDatabaseBuild = !DumpRecordBytes && !DumpRecords && !DumpTpiHash;
+
auto Tpi = (StreamIdx == StreamTPI) ? File.getPDBTpiStream()
: File.getPDBIpiStream();
if (!Tpi)
return Tpi.takeError();
- CVTypeDumper Dumper(TypeDB);
- if (DumpRecords || DumpRecordBytes) {
- DictScope D(P, Label);
+ std::unique_ptr<DictScope> StreamScope;
+ std::unique_ptr<ListScope> RecordScope;
+ if (!IsSilentDatabaseBuild) {
+ StreamScope = llvm::make_unique<DictScope>(P, Label);
P.printNumber(VerLabel, Tpi->getTpiVersion());
P.printNumber("Record count", Tpi->NumTypeRecords());
+ }
- ListScope L(P, "Records");
+ TypeDatabase &StreamDB = (StreamIdx == StreamTPI) ? TypeDB : ItemDB;
+
+ TypeDatabaseVisitor DBV(StreamDB);
+ CompactTypeDumpVisitor CTDV(StreamDB, &P);
+ TypeDumpVisitor TDV(TypeDB, &P, false);
+ if (StreamIdx == StreamIPI)
+ TDV.setItemDB(ItemDB);
+ RecordBytesVisitor RBV(P);
+ TypeDeserializer Deserializer;
+
+ // We always need to deserialize and add it to the type database. This is
+ // true if even if we're not dumping anything, because we could need the
+ // type database for the purposes of dumping symbols.
+ TypeVisitorCallbackPipeline Pipeline;
+ Pipeline.addCallbackToPipeline(Deserializer);
+ Pipeline.addCallbackToPipeline(DBV);
+
+ // If we're in dump mode, add a dumper with the appropriate detail level.
+ if (DumpRecords) {
+ if (opts::raw::CompactRecords)
+ Pipeline.addCallbackToPipeline(CTDV);
+ else
+ Pipeline.addCallbackToPipeline(TDV);
+ }
+ if (DumpRecordBytes)
+ Pipeline.addCallbackToPipeline(RBV);
- bool HadError = false;
- for (auto &Type : Tpi->types(&HadError)) {
- DictScope DD(P, "");
+ CVTypeVisitor Visitor(Pipeline);
- if (DumpRecords) {
- TypeDumpVisitor TDV(TypeDB, &P, false);
- if (auto EC = Dumper.dump(Type, TDV))
- return EC;
- }
+ if (DumpRecords || DumpRecordBytes)
+ RecordScope = llvm::make_unique<ListScope>(P, "Records");
- if (DumpRecordBytes)
- P.printBinaryBlock("Bytes", Type.content());
- }
- dumpTpiHash(P, *Tpi);
- if (HadError)
- return make_error<RawError>(raw_error_code::corrupt_file,
- "TPI stream contained corrupt record");
- } else if (opts::raw::DumpModuleSyms) {
- // Even if the user doesn't want to dump type records, we still need to
- // iterate them in order to build the type database. So when they want to
- // dump symbols but not types, don't stick a dumper on the end, just build
- // the type database.
- TypeDatabaseVisitor DBV(TypeDB);
- TypeDeserializer Deserializer;
- TypeVisitorCallbackPipeline Pipeline;
- Pipeline.addCallbackToPipeline(Deserializer);
- Pipeline.addCallbackToPipeline(DBV);
-
- CVTypeVisitor Visitor(Pipeline);
-
- bool HadError = false;
- for (auto Type : Tpi->types(&HadError)) {
- if (auto EC = Visitor.visitTypeRecord(Type))
- return EC;
+ bool HadError = false;
+
+ TypeIndex T(TypeIndex::FirstNonSimpleIndex);
+ for (auto Type : Tpi->types(&HadError)) {
+ std::unique_ptr<DictScope> OneRecordScope;
+
+ if ((DumpRecords || DumpRecordBytes) && !opts::raw::CompactRecords)
+ OneRecordScope = llvm::make_unique<DictScope>(P, "");
+
+ if (auto EC = Visitor.visitTypeRecord(Type))
+ return EC;
+ }
+ if (HadError)
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "TPI stream contained corrupt record");
+
+ if (DumpTpiHash) {
+ DictScope DD(P, "Hash");
+ P.printNumber("Number of Hash Buckets", Tpi->NumHashBuckets());
+ P.printNumber("Hash Key Size", Tpi->getHashKeySize());
+ P.printList("Values", Tpi->getHashValues());
+
+ ListScope LHA(P, "Adjusters");
+ auto ExpectedST = File.getStringTable();
+ if (!ExpectedST)
+ return ExpectedST.takeError();
+ const auto &ST = *ExpectedST;
+ for (const auto &E : Tpi->getHashAdjusters()) {
+ DictScope DHA(P);
+ StringRef Name = ST.getStringForID(E.first);
+ P.printString("Type", Name);
+ P.printHex("TI", E.second);
}
+ }
- dumpTpiHash(P, *Tpi);
- if (HadError)
- return make_error<RawError>(raw_error_code::corrupt_file,
- "TPI stream contained corrupt record");
+ if (!IsSilentDatabaseBuild) {
+ ListScope L(P, "TypeIndexOffsets");
+ for (const auto &IO : Tpi->getTypeIndexOffsets()) {
+ P.printString(formatv("Index: {0:x}, Offset: {1:N}", IO.Type.getIndex(),
+ (uint32_t)IO.Offset)
+ .str());
+ }
}
+
P.flush();
return Error::success();
}
@@ -679,10 +640,10 @@ Error LLVMOutputStyle::dumpDbiStream() {
public:
RecordVisitor(ScopedPrinter &P, PDBFile &F) : P(P), F(F) {}
Error visitUnknown(ModuleSubstreamKind Kind,
- ReadableStreamRef Stream) override {
+ BinaryStreamRef Stream) override {
DictScope DD(P, "Unknown");
ArrayRef<uint8_t> Data;
- StreamReader R(Stream);
+ BinaryStreamReader R(Stream);
if (auto EC = R.readBytes(Data, R.bytesRemaining())) {
return make_error<RawError>(
raw_error_code::corrupt_file,
@@ -692,7 +653,7 @@ Error LLVMOutputStyle::dumpDbiStream() {
return Error::success();
}
Error
- visitFileChecksums(ReadableStreamRef Data,
+ visitFileChecksums(BinaryStreamRef Data,
const FileChecksumArray &Checksums) override {
DictScope DD(P, "FileChecksums");
for (const auto &C : Checksums) {
@@ -708,7 +669,7 @@ Error LLVMOutputStyle::dumpDbiStream() {
return Error::success();
}
- Error visitLines(ReadableStreamRef Data,
+ Error visitLines(BinaryStreamRef Data,
const LineSubstreamHeader *Header,
const LineInfoArray &Lines) override {
DictScope DD(P, "Lines");