Index: llvm/tools/llvm-pdbdump/CMakeLists.txt =================================================================== --- llvm/tools/llvm-pdbdump/CMakeLists.txt +++ llvm/tools/llvm-pdbdump/CMakeLists.txt @@ -7,6 +7,7 @@ ) add_llvm_tool(llvm-pdbdump + CompactTypeDumpVisitor.cpp llvm-pdbdump.cpp YamlSymbolDumper.cpp YamlTypeDumper.cpp Index: llvm/tools/llvm-pdbdump/CompactTypeDumpVisitor.h =================================================================== --- /dev/null +++ llvm/tools/llvm-pdbdump/CompactTypeDumpVisitor.h @@ -0,0 +1,47 @@ +//===-- CompactTypeDumpVisitor.h - CodeView type info dumper ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_COMPACTTYPEDUMPVISITOR_H +#define LLVM_DEBUGINFO_CODEVIEW_COMPACTTYPEDUMPVISITOR_H + +#include "llvm/DebugInfo/CodeView/TypeIndex.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" + +namespace llvm { +class ScopedPrinter; +namespace codeview { +class TypeDatabase; +} + +namespace pdb { + +/// Dumper for CodeView type streams found in COFF object files and PDB files. +/// Dumps records on a single line, and ignores member records. +class CompactTypeDumpVisitor : public codeview::TypeVisitorCallbacks { +public: + CompactTypeDumpVisitor(codeview::TypeDatabase &TypeDB, ScopedPrinter *W); + + /// Paired begin/end actions for all types. Receives all record data, + /// including the fixed-length record prefix. + Error visitTypeBegin(codeview::CVType &Record) override; + Error visitTypeEnd(codeview::CVType &Record) override; + +private: + ScopedPrinter *W; + + codeview::TypeIndex TI; + uint32_t Offset; + codeview::TypeDatabase &TypeDB; +}; + +} // end namespace pdb +} // end namespace llvm + +#endif Index: llvm/tools/llvm-pdbdump/CompactTypeDumpVisitor.cpp =================================================================== --- /dev/null +++ llvm/tools/llvm-pdbdump/CompactTypeDumpVisitor.cpp @@ -0,0 +1,57 @@ +//===-- CompactTypeDumpVisitor.cpp - CodeView type info dumper --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "CompactTypeDumpVisitor.h" +#include "llvm/DebugInfo/CodeView/TypeDatabase.h" +#include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/ScopedPrinter.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +static const EnumEntry LeafTypeNames[] = { +#define CV_TYPE(enum, val) {#enum, enum}, +#include "llvm/DebugInfo/CodeView/TypeRecords.def" +}; + +static StringRef getLeafName(TypeLeafKind K) { + for (const auto &E : LeafTypeNames) { + if (E.Value == K) + return E.Name; + } + return StringRef(); +} + +CompactTypeDumpVisitor::CompactTypeDumpVisitor(TypeDatabase &TypeDB, + ScopedPrinter *W) + : W(W), TI(TypeIndex::None()), Offset(0), TypeDB(TypeDB) {} + +Error CompactTypeDumpVisitor::visitTypeBegin(CVType &Record) { + if (TI == TypeIndex::None()) + TI.setIndex(TypeIndex::FirstNonSimpleIndex); + else + TI.setIndex(TI.getIndex() + 1); + + return Error::success(); +} + +Error CompactTypeDumpVisitor::visitTypeEnd(CVType &Record) { + uint32_t I = TI.getIndex(); + StringRef Leaf = getLeafName(Record.Type); + StringRef Name = TypeDB.getTypeName(TI); + W->printString( + llvm::formatv("Index: {0:x} ({1:N} bytes, offset {2:N}) {3} \"{4}\"", I, + Record.length(), Offset, Leaf, Name) + .str()); + + Offset += Record.length(); + + return Error::success(); +} Index: llvm/tools/llvm-pdbdump/LLVMOutputStyle.cpp =================================================================== --- llvm/tools/llvm-pdbdump/LLVMOutputStyle.cpp +++ llvm/tools/llvm-pdbdump/LLVMOutputStyle.cpp @@ -9,7 +9,9 @@ #include "LLVMOutputStyle.h" +#include "CompactTypeDumpVisitor.h" #include "llvm-pdbdump.h" + #include "llvm/DebugInfo/CodeView/CVTypeDumper.h" #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" #include "llvm/DebugInfo/CodeView/EnumTables.h" @@ -34,6 +36,7 @@ #include "llvm/DebugInfo/PDB/Raw/RawError.h" #include "llvm/DebugInfo/PDB/Raw/TpiStream.h" #include "llvm/Object/COFF.h" +#include "llvm/Support/FormatVariadic.h" #include @@ -524,22 +527,40 @@ if (!Tpi) return Tpi.takeError(); - CVTypeDumper Dumper(TypeDB); + // 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); + CompactTypeDumpVisitor CTDV(TypeDB, &P); + TypeDumpVisitor TDV(TypeDB, &P, false); + TypeDeserializer Deserializer; + TypeVisitorCallbackPipeline Pipeline; + Pipeline.addCallbackToPipeline(Deserializer); + Pipeline.addCallbackToPipeline(DBV); + + CVTypeVisitor Visitor(Pipeline); + if (DumpRecords || DumpRecordBytes) { DictScope D(P, Label); P.printNumber(VerLabel, Tpi->getTpiVersion()); P.printNumber("Record count", Tpi->NumTypeRecords()); - ListScope L(P, "Records"); bool HadError = false; - for (auto &Type : Tpi->types(&HadError)) { - DictScope DD(P, ""); + if (opts::raw::CompactRecords) + Pipeline.addCallbackToPipeline(CTDV); + else + Pipeline.addCallbackToPipeline(TDV); + + for (auto Type : Tpi->types(&HadError)) { + std::unique_ptr Scope; + if (!opts::raw::CompactRecords) + Scope.reset(new DictScope(P, "")); if (DumpRecords) { - TypeDumpVisitor TDV(TypeDB, &P, false); - if (auto EC = Dumper.dump(Type, TDV)) + if (auto EC = Visitor.visitTypeRecord(Type)) return EC; } @@ -550,18 +571,16 @@ if (HadError) return make_error(raw_error_code::corrupt_file, "TPI stream contained corrupt record"); + { + ListScope L(P, "TypeIndexOffsets"); + for (const auto &IO : Tpi->getTypeIndexOffsets()) { + P.printString(llvm::formatv("Index: {0:x}, Offset: {1:N}", + IO.Type.getIndex(), (uint32_t)IO.Offset) + .str()); + } + } + } 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)) { Index: llvm/tools/llvm-pdbdump/llvm-pdbdump.h =================================================================== --- llvm/tools/llvm-pdbdump/llvm-pdbdump.h +++ llvm/tools/llvm-pdbdump/llvm-pdbdump.h @@ -43,6 +43,7 @@ extern llvm::Optional DumpBlockRange; extern llvm::cl::list DumpStreamData; +extern llvm::cl::opt CompactRecords; extern llvm::cl::opt DumpGlobals; extern llvm::cl::opt DumpHeaders; extern llvm::cl::opt DumpStreamBlocks; Index: llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp =================================================================== --- llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp +++ llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp @@ -187,6 +187,11 @@ // TYPE OPTIONS cl::opt + CompactRecords("compact-records", + cl::desc("Dump type and symbol records with less detail"), + cl::cat(TypeOptions), cl::sub(RawSubcommand)); + +cl::opt DumpTpiRecords("tpi-records", cl::desc("dump CodeView type records from TPI stream"), cl::cat(TypeOptions), cl::sub(RawSubcommand)); @@ -556,24 +561,34 @@ } } - if (opts::RawSubcommand && opts::raw::RawAll) { - opts::raw::DumpHeaders = true; - opts::raw::DumpModules = true; - opts::raw::DumpModuleFiles = true; - opts::raw::DumpModuleSyms = true; - opts::raw::DumpGlobals = true; - opts::raw::DumpPublics = true; - opts::raw::DumpSectionHeaders = true; - opts::raw::DumpStreamSummary = true; - opts::raw::DumpPageStats = true; - opts::raw::DumpStreamBlocks = true; - opts::raw::DumpTpiRecords = true; - opts::raw::DumpTpiHash = true; - opts::raw::DumpIpiRecords = true; - opts::raw::DumpSectionMap = true; - opts::raw::DumpSectionContribs = true; - opts::raw::DumpLineInfo = true; - opts::raw::DumpFpo = true; + if (opts::RawSubcommand) { + if (opts::raw::RawAll) { + opts::raw::DumpHeaders = true; + opts::raw::DumpModules = true; + opts::raw::DumpModuleFiles = true; + opts::raw::DumpModuleSyms = true; + opts::raw::DumpGlobals = true; + opts::raw::DumpPublics = true; + opts::raw::DumpSectionHeaders = true; + opts::raw::DumpStreamSummary = true; + opts::raw::DumpPageStats = true; + opts::raw::DumpStreamBlocks = true; + opts::raw::DumpTpiRecords = true; + opts::raw::DumpTpiHash = true; + opts::raw::DumpIpiRecords = true; + opts::raw::DumpSectionMap = true; + opts::raw::DumpSectionContribs = true; + opts::raw::DumpLineInfo = true; + opts::raw::DumpFpo = true; + } + + if (opts::raw::CompactRecords && + (opts::raw::DumpTpiRecordBytes || opts::raw::DumpIpiRecordBytes)) { + errs() << "-compact-records is incompatible with -tpi-record-bytes and " + "-ipi-record-bytes.\n"; + errs().flush(); + exit(1); + } } llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::MultiThreaded);