)
add_llvm_tool(llvm-pdbdump
+ CompactTypeDumpVisitor.cpp
llvm-pdbdump.cpp
YamlSymbolDumper.cpp
YamlTypeDumper.cpp
--- /dev/null
+//===-- 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<TypeLeafKind> 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();
+}
--- /dev/null
+//===-- 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
#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"
#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 <unordered_map>
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<DictScope> 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;
}
if (HadError)
return make_error<RawError>(raw_error_code::corrupt_file,
"TPI stream contained corrupt record");
+ {
+ 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());
+ }
+ }
+
} 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)) {
cl::cat(MsfOptions), cl::sub(RawSubcommand));
// TYPE OPTIONS
+cl::opt<bool>
+ CompactRecords("compact-records",
+ cl::desc("Dump type and symbol records with less detail"),
+ cl::cat(TypeOptions), cl::sub(RawSubcommand));
+
cl::opt<bool>
DumpTpiRecords("tpi-records",
cl::desc("dump CodeView type records from TPI stream"),
}
}
- 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";
+ exit(1);
+ }
}
llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::MultiThreaded);
extern llvm::Optional<BlockRange> DumpBlockRange;
extern llvm::cl::list<uint32_t> DumpStreamData;
+extern llvm::cl::opt<bool> CompactRecords;
extern llvm::cl::opt<bool> DumpGlobals;
extern llvm::cl::opt<bool> DumpHeaders;
extern llvm::cl::opt<bool> DumpStreamBlocks;