Index: llvm/trunk/include/llvm/DebugInfo/CodeView/DebugStringTableSubsection.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/CodeView/DebugStringTableSubsection.h +++ llvm/trunk/include/llvm/DebugInfo/CodeView/DebugStringTableSubsection.h @@ -39,6 +39,7 @@ } Error initialize(BinaryStreamRef Contents); + Error initialize(BinaryStreamReader &Reader); Expected getString(uint32_t Offset) const; Index: llvm/trunk/include/llvm/DebugInfo/CodeView/DebugSubsectionVisitor.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/CodeView/DebugSubsectionVisitor.h +++ llvm/trunk/include/llvm/DebugInfo/CodeView/DebugSubsectionVisitor.h @@ -23,8 +23,59 @@ class DebugCrossModuleExportsSubsectionRef; class DebugCrossModuleImportsSubsectionRef; class DebugLinesSubsectionRef; +class DebugStringTableSubsectionRef; class DebugUnknownSubsectionRef; +struct DebugSubsectionState { +public: + // If no subsections are known about initially, we find as much as we can. + DebugSubsectionState(); + + // If only a string table subsection is given, we find a checksums subsection. + explicit DebugSubsectionState(const DebugStringTableSubsectionRef &Strings); + + // If both subsections are given, we don't need to find anything. + DebugSubsectionState(const DebugStringTableSubsectionRef &Strings, + const DebugChecksumsSubsectionRef &Checksums); + + template void initialize(T &&FragmentRange) { + for (const DebugSubsectionRecord &R : FragmentRange) { + if (Strings && Checksums) + return; + if (R.kind() == DebugSubsectionKind::FileChecksums) { + initializeChecksums(R); + continue; + } + if (R.kind() == DebugSubsectionKind::StringTable && !Strings) { + // While in practice we should never encounter a string table even + // though the string table is already initialized, in theory it's + // possible. PDBs are supposed to have one global string table and + // then this subsection should not appear. Whereas object files are + // supposed to have this subsection appear exactly once. However, + // for testing purposes it's nice to be able to test this subsection + // independently of one format or the other, so for some tests we + // manually construct a PDB that contains this subsection in addition + // to a global string table. + initializeStrings(R); + continue; + } + } + } + + const DebugStringTableSubsectionRef &strings() const { return *Strings; } + const DebugChecksumsSubsectionRef &checksums() const { return *Checksums; } + +private: + void initializeStrings(const DebugSubsectionRecord &SR); + void initializeChecksums(const DebugSubsectionRecord &FCR); + + std::unique_ptr OwnedStrings; + std::unique_ptr OwnedChecksums; + + const DebugStringTableSubsectionRef *Strings = nullptr; + const DebugChecksumsSubsectionRef *Checksums = nullptr; +}; + class DebugSubsectionVisitor { public: virtual ~DebugSubsectionVisitor() = default; @@ -32,44 +83,61 @@ virtual Error visitUnknown(DebugUnknownSubsectionRef &Unknown) { return Error::success(); } - virtual Error visitLines(DebugLinesSubsectionRef &Lines) { - return Error::success(); - } - - virtual Error visitFileChecksums(DebugChecksumsSubsectionRef &Checksums) { - return Error::success(); - } - - virtual Error visitInlineeLines(DebugInlineeLinesSubsectionRef &Inlinees) { - return Error::success(); - } - + virtual Error visitLines(DebugLinesSubsectionRef &Lines, + const DebugSubsectionState &State) = 0; + virtual Error visitFileChecksums(DebugChecksumsSubsectionRef &Checksums, + const DebugSubsectionState &State) = 0; + virtual Error visitInlineeLines(DebugInlineeLinesSubsectionRef &Inlinees, + const DebugSubsectionState &State) = 0; virtual Error - visitCrossModuleExports(DebugCrossModuleExportsSubsectionRef &CSE) { - return Error::success(); - } - + visitCrossModuleExports(DebugCrossModuleExportsSubsectionRef &CSE, + const DebugSubsectionState &State) = 0; virtual Error - visitCrossModuleImports(DebugCrossModuleImportsSubsectionRef &CSE) { - return Error::success(); - } - - virtual Error finished() { return Error::success(); } + visitCrossModuleImports(DebugCrossModuleImportsSubsectionRef &CSE, + const DebugSubsectionState &State) = 0; }; Error visitDebugSubsection(const DebugSubsectionRecord &R, - DebugSubsectionVisitor &V); + DebugSubsectionVisitor &V, + const DebugSubsectionState &State); +namespace detail { template -Error visitDebugSubsections(T &&FragmentRange, DebugSubsectionVisitor &V) { +Error visitDebugSubsections(T &&FragmentRange, DebugSubsectionVisitor &V, + DebugSubsectionState &State) { + State.initialize(std::forward(FragmentRange)); + for (const auto &L : FragmentRange) { - if (auto EC = visitDebugSubsection(L, V)) + if (auto EC = visitDebugSubsection(L, V, State)) return EC; } - if (auto EC = V.finished()) - return EC; return Error::success(); } +} // namespace detail + +template +Error visitDebugSubsections(T &&FragmentRange, DebugSubsectionVisitor &V) { + DebugSubsectionState State; + return detail::visitDebugSubsections(std::forward(FragmentRange), V, + State); +} + +template +Error visitDebugSubsections(T &&FragmentRange, DebugSubsectionVisitor &V, + const DebugStringTableSubsectionRef &Strings) { + DebugSubsectionState State(Strings); + return detail::visitDebugSubsections(std::forward(FragmentRange), V, + State); +} + +template +Error visitDebugSubsections(T &&FragmentRange, DebugSubsectionVisitor &V, + const DebugStringTableSubsectionRef &Strings, + const DebugChecksumsSubsectionRef &Checksums) { + DebugSubsectionState State(Strings, Checksums); + return detail::visitDebugSubsections(std::forward(FragmentRange), V, + State); +} } // end namespace codeview Index: llvm/trunk/lib/DebugInfo/CodeView/DebugStringTableSubsection.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/CodeView/DebugStringTableSubsection.cpp +++ llvm/trunk/lib/DebugInfo/CodeView/DebugStringTableSubsection.cpp @@ -23,6 +23,9 @@ Stream = Contents; return Error::success(); } +Error DebugStringTableSubsectionRef::initialize(BinaryStreamReader &Reader) { + return Reader.readStreamRef(Stream, Reader.bytesRemaining()); +} Expected DebugStringTableSubsectionRef::getString(uint32_t Offset) const { Index: llvm/trunk/lib/DebugInfo/CodeView/DebugSubsectionVisitor.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/CodeView/DebugSubsectionVisitor.cpp +++ llvm/trunk/lib/DebugInfo/CodeView/DebugSubsectionVisitor.cpp @@ -14,6 +14,7 @@ #include "llvm/DebugInfo/CodeView/DebugCrossImpSubsection.h" #include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h" #include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h" +#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h" #include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h" #include "llvm/DebugInfo/CodeView/DebugUnknownSubsection.h" #include "llvm/Support/BinaryStreamReader.h" @@ -22,8 +23,40 @@ using namespace llvm; using namespace llvm::codeview; +DebugSubsectionState::DebugSubsectionState() {} + +DebugSubsectionState::DebugSubsectionState( + const DebugStringTableSubsectionRef &Strings) + : Strings(&Strings) {} + +DebugSubsectionState::DebugSubsectionState( + const DebugStringTableSubsectionRef &Strings, + const DebugChecksumsSubsectionRef &Checksums) + : Strings(&Strings), Checksums(&Checksums) {} + +void DebugSubsectionState::initializeStrings(const DebugSubsectionRecord &SR) { + assert(SR.kind() == DebugSubsectionKind::StringTable); + assert(!Strings && "Found a string table even though we already have one!"); + + OwnedStrings = llvm::make_unique(); + consumeError(OwnedStrings->initialize(SR.getRecordData())); + Strings = OwnedStrings.get(); +} + +void DebugSubsectionState::initializeChecksums( + const DebugSubsectionRecord &FCR) { + assert(FCR.kind() == DebugSubsectionKind::FileChecksums); + if (Checksums) + return; + + OwnedChecksums = llvm::make_unique(); + consumeError(OwnedChecksums->initialize(FCR.getRecordData())); + Checksums = OwnedChecksums.get(); +} + Error llvm::codeview::visitDebugSubsection(const DebugSubsectionRecord &R, - DebugSubsectionVisitor &V) { + DebugSubsectionVisitor &V, + const DebugSubsectionState &State) { BinaryStreamReader Reader(R.getRecordData()); switch (R.kind()) { case DebugSubsectionKind::Lines: { @@ -31,32 +64,32 @@ if (auto EC = Fragment.initialize(Reader)) return EC; - return V.visitLines(Fragment); + return V.visitLines(Fragment, State); } case DebugSubsectionKind::FileChecksums: { DebugChecksumsSubsectionRef Fragment; if (auto EC = Fragment.initialize(Reader)) return EC; - return V.visitFileChecksums(Fragment); + return V.visitFileChecksums(Fragment, State); } case DebugSubsectionKind::InlineeLines: { DebugInlineeLinesSubsectionRef Fragment; if (auto EC = Fragment.initialize(Reader)) return EC; - return V.visitInlineeLines(Fragment); + return V.visitInlineeLines(Fragment, State); } case DebugSubsectionKind::CrossScopeExports: { DebugCrossModuleExportsSubsectionRef Section; if (auto EC = Section.initialize(Reader)) return EC; - return V.visitCrossModuleExports(Section); + return V.visitCrossModuleExports(Section, State); } case DebugSubsectionKind::CrossScopeImports: { DebugCrossModuleImportsSubsectionRef Section; if (auto EC = Section.initialize(Reader)) return EC; - return V.visitCrossModuleImports(Section); + return V.visitCrossModuleImports(Section, State); } default: { DebugUnknownSubsectionRef Fragment(R.kind(), R.getRecordData()); Index: llvm/trunk/lib/ObjectYAML/CodeViewYAMLDebugSections.cpp =================================================================== --- llvm/trunk/lib/ObjectYAML/CodeViewYAMLDebugSections.cpp +++ llvm/trunk/lib/ObjectYAML/CodeViewYAMLDebugSections.cpp @@ -533,25 +533,21 @@ namespace { struct SubsectionConversionVisitor : public DebugSubsectionVisitor { - explicit SubsectionConversionVisitor( - const DebugStringTableSubsectionRef &Strings, - const DebugChecksumsSubsectionRef &Checksums) - : Strings(Strings), Checksums(Checksums) {} + SubsectionConversionVisitor() {} Error visitUnknown(DebugUnknownSubsectionRef &Unknown) override; - Error visitLines(DebugLinesSubsectionRef &Lines) override; - Error visitFileChecksums(DebugChecksumsSubsectionRef &Checksums) override; - Error visitInlineeLines(DebugInlineeLinesSubsectionRef &Inlinees) override; - Error visitCrossModuleExports( - DebugCrossModuleExportsSubsectionRef &Checksums) override; - Error visitCrossModuleImports( - DebugCrossModuleImportsSubsectionRef &Inlinees) override; + Error visitLines(DebugLinesSubsectionRef &Lines, + const DebugSubsectionState &State) override; + Error visitFileChecksums(DebugChecksumsSubsectionRef &Checksums, + const DebugSubsectionState &State) override; + Error visitInlineeLines(DebugInlineeLinesSubsectionRef &Inlinees, + const DebugSubsectionState &State) override; + Error visitCrossModuleExports(DebugCrossModuleExportsSubsectionRef &Checksums, + const DebugSubsectionState &State) override; + Error visitCrossModuleImports(DebugCrossModuleImportsSubsectionRef &Inlinees, + const DebugSubsectionState &State) override; YAMLDebugSubsection Subsection; - -private: - const DebugStringTableSubsectionRef &Strings; - const DebugChecksumsSubsectionRef &Checksums; }; Error SubsectionConversionVisitor::visitUnknown( @@ -559,9 +555,10 @@ return make_error(cv_error_code::operation_unsupported); } -Error SubsectionConversionVisitor::visitLines(DebugLinesSubsectionRef &Lines) { - auto Result = - YAMLLinesSubsection::fromCodeViewSubsection(Strings, Checksums, Lines); +Error SubsectionConversionVisitor::visitLines( + DebugLinesSubsectionRef &Lines, const DebugSubsectionState &State) { + auto Result = YAMLLinesSubsection::fromCodeViewSubsection( + State.strings(), State.checksums(), Lines); if (!Result) return Result.takeError(); Subsection.Subsection = *Result; @@ -569,9 +566,9 @@ } Error SubsectionConversionVisitor::visitFileChecksums( - DebugChecksumsSubsectionRef &Checksums) { - auto Result = - YAMLChecksumsSubsection::fromCodeViewSubsection(Strings, Checksums); + DebugChecksumsSubsectionRef &Checksums, const DebugSubsectionState &State) { + auto Result = YAMLChecksumsSubsection::fromCodeViewSubsection(State.strings(), + Checksums); if (!Result) return Result.takeError(); Subsection.Subsection = *Result; @@ -579,9 +576,10 @@ } Error SubsectionConversionVisitor::visitInlineeLines( - DebugInlineeLinesSubsectionRef &Inlinees) { + DebugInlineeLinesSubsectionRef &Inlinees, + const DebugSubsectionState &State) { auto Result = YAMLInlineeLinesSubsection::fromCodeViewSubsection( - Strings, Checksums, Inlinees); + State.strings(), State.checksums(), Inlinees); if (!Result) return Result.takeError(); Subsection.Subsection = *Result; @@ -589,7 +587,8 @@ } Error SubsectionConversionVisitor::visitCrossModuleExports( - DebugCrossModuleExportsSubsectionRef &Exports) { + DebugCrossModuleExportsSubsectionRef &Exports, + const DebugSubsectionState &State) { auto Result = YAMLCrossModuleExportsSubsection::fromCodeViewSubsection(Exports); if (!Result) @@ -599,9 +598,10 @@ } Error SubsectionConversionVisitor::visitCrossModuleImports( - DebugCrossModuleImportsSubsectionRef &Imports) { + DebugCrossModuleImportsSubsectionRef &Imports, + const DebugSubsectionState &State) { auto Result = YAMLCrossModuleImportsSubsection::fromCodeViewSubsection( - Strings, Imports); + State.strings(), Imports); if (!Result) return Result.takeError(); Subsection.Subsection = *Result; @@ -613,8 +613,9 @@ const DebugStringTableSubsectionRef &Strings, const DebugChecksumsSubsectionRef &Checksums, const DebugSubsectionRecord &SS) { - SubsectionConversionVisitor V(Strings, Checksums); - if (auto EC = visitDebugSubsection(SS, V)) + DebugSubsectionState State(Strings, Checksums); + SubsectionConversionVisitor V; + if (auto EC = visitDebugSubsection(SS, V, State)) return std::move(EC); return V.Subsection; Index: llvm/trunk/test/DebugInfo/PDB/pdbdump-debug-subsections.test =================================================================== --- llvm/trunk/test/DebugInfo/PDB/pdbdump-debug-subsections.test +++ llvm/trunk/test/DebugInfo/PDB/pdbdump-debug-subsections.test @@ -73,27 +73,37 @@ RAW-NEXT: { RAW-NEXT: Name: Foo.obj RAW: Subsections [ -RAW-NEXT: CrossModuleExports { -RAW-NEXT: Local: 0x12F4 -RAW-NEXT: Global: 0x2443 -RAW-NEXT: Local: 0x80001083 -RAW-NEXT: Global: 0x23A3 -RAW-NEXT: } +RAW-NEXT: CrossModuleExports [ +RAW-NEXT: Export { +RAW-NEXT: Local: 0x12F4 +RAW-NEXT: Global: 0x2443 +RAW-NEXT: } +RAW-NEXT: Export { +RAW-NEXT: Local: 0x80001083 +RAW-NEXT: Global: 0x23A3 +RAW-NEXT: } +RAW-NEXT: ] RAW-NEXT: ] RAW-NEXT: } RAW-NEXT: { RAW-NEXT: Name: Bar.obj RAW: Subsections [ -RAW-NEXT: CrossModuleExports { -RAW-NEXT: Local: 0x10A9 -RAW-NEXT: Global: 0x17D1 -RAW-NEXT: Local: 0x10C9 -RAW-NEXT: Global: 0x1245 -RAW-NEXT: } -RAW-NEXT: CrossModuleImports { -RAW-NEXT: Module: Foo.obj -RAW-NEXT: Imports: [0x12F4, 0x80001083] -RAW-NEXT: } +RAW-NEXT: CrossModuleExports [ +RAW-NEXT: Export { +RAW-NEXT: Local: 0x10A9 +RAW-NEXT: Global: 0x17D1 +RAW-NEXT: } +RAW-NEXT: Export { +RAW-NEXT: Local: 0x10C9 +RAW-NEXT: Global: 0x1245 +RAW-NEXT: } +RAW-NEXT: ] +RAW-NEXT: CrossModuleImports [ +RAW-NEXT: ModuleImport { +RAW-NEXT: Module: Foo.obj +RAW-NEXT: Imports: [0x12F4, 0x80001083] +RAW-NEXT: } +RAW-NEXT: ] RAW-NEXT: ] RAW-NEXT: } RAW-NEXT: { @@ -116,31 +126,29 @@ RAW-NEXT: } RAW-NEXT: } RAW-NEXT: Lines { -RAW-NEXT: Block { -RAW-NEXT: RelocSegment: 1 -RAW-NEXT: RelocOffset: 16 -RAW-NEXT: CodeSize: 10 -RAW-NEXT: HasColumns: No -RAW-NEXT: Lines { -RAW-NEXT: FileName: d:\src\llvm\test\debuginfo\pdb\inputs\empty.cpp -RAW-NEXT: Line { -RAW-NEXT: Offset: 0 -RAW-NEXT: LineNumberStart: 5 -RAW-NEXT: EndDelta: 0 -RAW-NEXT: IsStatement: Yes -RAW-NEXT: } -RAW-NEXT: Line { -RAW-NEXT: Offset: 3 -RAW-NEXT: LineNumberStart: 6 -RAW-NEXT: EndDelta: 0 -RAW-NEXT: IsStatement: Yes -RAW-NEXT: } -RAW-NEXT: Line { -RAW-NEXT: Offset: 8 -RAW-NEXT: LineNumberStart: 7 -RAW-NEXT: EndDelta: 0 -RAW-NEXT: IsStatement: Yes -RAW-NEXT: } +RAW-NEXT: RelocSegment: 1 +RAW-NEXT: RelocOffset: 16 +RAW-NEXT: CodeSize: 10 +RAW-NEXT: HasColumns: No +RAW-NEXT: FileEntry { +RAW-NEXT: FileName: d:\src\llvm\test\debuginfo\pdb\inputs\empty.cpp +RAW-NEXT: Line { +RAW-NEXT: Offset: 0 +RAW-NEXT: LineNumberStart: 5 +RAW-NEXT: EndDelta: 0 +RAW-NEXT: IsStatement: Yes +RAW-NEXT: } +RAW-NEXT: Line { +RAW-NEXT: Offset: 3 +RAW-NEXT: LineNumberStart: 6 +RAW-NEXT: EndDelta: 0 +RAW-NEXT: IsStatement: Yes +RAW-NEXT: } +RAW-NEXT: Line { +RAW-NEXT: Offset: 8 +RAW-NEXT: LineNumberStart: 7 +RAW-NEXT: EndDelta: 0 +RAW-NEXT: IsStatement: Yes RAW-NEXT: } RAW-NEXT: } RAW-NEXT: } Index: llvm/trunk/test/DebugInfo/PDB/pdbdump-headers.test =================================================================== --- llvm/trunk/test/DebugInfo/PDB/pdbdump-headers.test +++ llvm/trunk/test/DebugInfo/PDB/pdbdump-headers.test @@ -485,6 +485,33 @@ ; EMPTY-NEXT: } ; EMPTY-NEXT: ] ; EMPTY-NEXT: Subsections [ +; EMPTY-NEXT: Lines { +; EMPTY-NEXT: RelocSegment: 1 +; EMPTY-NEXT: RelocOffset: 16 +; EMPTY-NEXT: CodeSize: 10 +; EMPTY-NEXT: HasColumns: No +; EMPTY-NEXT: FileEntry { +; EMPTY-NEXT: FileName: d:\src\llvm\test\debuginfo\pdb\inputs\empty.cpp +; EMPTY-NEXT: Line { +; EMPTY-NEXT: Offset: 0 +; EMPTY-NEXT: LineNumberStart: 5 +; EMPTY-NEXT: EndDelta: 0 +; EMPTY-NEXT: IsStatement: Yes +; EMPTY-NEXT: } +; EMPTY-NEXT: Line { +; EMPTY-NEXT: Offset: 3 +; EMPTY-NEXT: LineNumberStart: 6 +; EMPTY-NEXT: EndDelta: 0 +; EMPTY-NEXT: IsStatement: Yes +; EMPTY-NEXT: } +; EMPTY-NEXT: Line { +; EMPTY-NEXT: Offset: 8 +; EMPTY-NEXT: LineNumberStart: 7 +; EMPTY-NEXT: EndDelta: 0 +; EMPTY-NEXT: IsStatement: Yes +; EMPTY-NEXT: } +; EMPTY-NEXT: } +; EMPTY-NEXT: } ; EMPTY-NEXT: FileChecksums { ; EMPTY-NEXT: Checksum { ; EMPTY-NEXT: FileName: d:\src\llvm\test\debuginfo\pdb\inputs\empty.cpp @@ -494,35 +521,6 @@ ; EMPTY-NEXT: ) ; EMPTY-NEXT: } ; EMPTY-NEXT: } -; EMPTY-NEXT: Lines { -; EMPTY-NEXT: Block { -; EMPTY-NEXT: RelocSegment: 1 -; EMPTY-NEXT: RelocOffset: 16 -; EMPTY-NEXT: CodeSize: 10 -; EMPTY-NEXT: HasColumns: No -; EMPTY-NEXT: Lines { -; EMPTY-NEXT: FileName: d:\src\llvm\test\debuginfo\pdb\inputs\empty.cpp -; EMPTY-NEXT: Line { -; EMPTY-NEXT: Offset: 0 -; EMPTY-NEXT: LineNumberStart: 5 -; EMPTY-NEXT: EndDelta: 0 -; EMPTY-NEXT: IsStatement: Yes -; EMPTY-NEXT: } -; EMPTY-NEXT: Line { -; EMPTY-NEXT: Offset: 3 -; EMPTY-NEXT: LineNumberStart: 6 -; EMPTY-NEXT: EndDelta: 0 -; EMPTY-NEXT: IsStatement: Yes -; EMPTY-NEXT: } -; EMPTY-NEXT: Line { -; EMPTY-NEXT: Offset: 8 -; EMPTY-NEXT: LineNumberStart: 7 -; EMPTY-NEXT: EndDelta: 0 -; EMPTY-NEXT: IsStatement: Yes -; EMPTY-NEXT: } -; EMPTY-NEXT: } -; EMPTY-NEXT: } -; EMPTY-NEXT: } ; EMPTY-NEXT: ] ; EMPTY-NEXT: } ; EMPTY-NEXT: { Index: llvm/trunk/tools/llvm-pdbdump/C13DebugFragmentVisitor.h =================================================================== --- llvm/trunk/tools/llvm-pdbdump/C13DebugFragmentVisitor.h +++ llvm/trunk/tools/llvm-pdbdump/C13DebugFragmentVisitor.h @@ -1,70 +0,0 @@ -//===- C13DebugFragmentVisitor.h - Visitor for CodeView Info ----*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TOOLS_LLVMPDBDUMP_C13DEBUGFRAGMENTVISITOR_H -#define LLVM_TOOLS_LLVMPDBDUMP_C13DEBUGFRAGMENTVISITOR_H - -#include "llvm/ADT/Optional.h" -#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h" -#include "llvm/DebugInfo/CodeView/DebugSubsectionVisitor.h" -#include "llvm/Support/Error.h" - -#include - -namespace llvm { - -namespace pdb { - -class PDBFile; - -class C13DebugFragmentVisitor : public codeview::DebugSubsectionVisitor { -public: - C13DebugFragmentVisitor(PDBFile &F); - ~C13DebugFragmentVisitor(); - - Error visitUnknown(codeview::DebugUnknownSubsectionRef &Fragment) final; - - Error - visitFileChecksums(codeview::DebugChecksumsSubsectionRef &Checksums) final; - - Error visitLines(codeview::DebugLinesSubsectionRef &Lines) final; - - Error - visitInlineeLines(codeview::DebugInlineeLinesSubsectionRef &Lines) final; - - Error visitCrossModuleExports( - codeview::DebugCrossModuleExportsSubsectionRef &Lines) final; - - Error visitCrossModuleImports( - codeview::DebugCrossModuleImportsSubsectionRef &Imports) final; - - Error finished() final; - -protected: - virtual Error handleFileChecksums() { return Error::success(); } - virtual Error handleLines() { return Error::success(); } - virtual Error handleInlineeLines() { return Error::success(); } - virtual Error handleCrossModuleExports() { return Error::success(); } - virtual Error handleCrossModuleImports() { return Error::success(); } - - Expected getNameFromStringTable(uint32_t Offset); - Expected getNameFromChecksumsBuffer(uint32_t Offset); - - Optional Checksums; - std::vector InlineeLines; - std::vector Lines; - std::vector CrossExports; - std::vector CrossImports; - - PDBFile &F; -}; -} -} - -#endif Index: llvm/trunk/tools/llvm-pdbdump/C13DebugFragmentVisitor.cpp =================================================================== --- llvm/trunk/tools/llvm-pdbdump/C13DebugFragmentVisitor.cpp +++ llvm/trunk/tools/llvm-pdbdump/C13DebugFragmentVisitor.cpp @@ -1,105 +0,0 @@ -//===- C13DebugFragmentVisitor.cpp -------------------------------*- C++-*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "C13DebugFragmentVisitor.h" - -#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h" -#include "llvm/DebugInfo/CodeView/DebugCrossExSubsection.h" -#include "llvm/DebugInfo/CodeView/DebugCrossImpSubsection.h" -#include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h" -#include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h" -#include "llvm/DebugInfo/PDB/Native/PDBFile.h" -#include "llvm/DebugInfo/PDB/Native/PDBStringTable.h" -#include "llvm/DebugInfo/PDB/Native/RawError.h" - -using namespace llvm; -using namespace llvm::codeview; -using namespace llvm::pdb; - -C13DebugFragmentVisitor::C13DebugFragmentVisitor(PDBFile &F) : F(F) {} - -C13DebugFragmentVisitor::~C13DebugFragmentVisitor() {} - -Error C13DebugFragmentVisitor::visitUnknown( - codeview::DebugUnknownSubsectionRef &Fragment) { - return Error::success(); -} - -Error C13DebugFragmentVisitor::visitFileChecksums( - codeview::DebugChecksumsSubsectionRef &Checksums) { - assert(!this->Checksums.hasValue()); - this->Checksums = Checksums; - return Error::success(); -} - -Error C13DebugFragmentVisitor::visitLines( - codeview::DebugLinesSubsectionRef &Lines) { - this->Lines.push_back(Lines); - return Error::success(); -} - -Error C13DebugFragmentVisitor::visitInlineeLines( - codeview::DebugInlineeLinesSubsectionRef &Lines) { - this->InlineeLines.push_back(Lines); - return Error::success(); -} - -Error C13DebugFragmentVisitor::visitCrossModuleExports( - codeview::DebugCrossModuleExportsSubsectionRef &Exports) { - this->CrossExports.push_back(Exports); - return Error::success(); -} - -Error C13DebugFragmentVisitor::visitCrossModuleImports( - codeview::DebugCrossModuleImportsSubsectionRef &Imports) { - this->CrossImports.push_back(Imports); - return Error::success(); -} - -Error C13DebugFragmentVisitor::finished() { - if (Checksums.hasValue()) { - if (auto EC = handleFileChecksums()) - return EC; - - if (auto EC = handleLines()) - return EC; - - if (auto EC = handleInlineeLines()) - return EC; - } - - if (auto EC = handleCrossModuleExports()) - return EC; - - if (auto EC = handleCrossModuleImports()) - return EC; - - return Error::success(); -} - -Expected -C13DebugFragmentVisitor::getNameFromStringTable(uint32_t Offset) { - auto ST = F.getStringTable(); - if (!ST) - return ST.takeError(); - - return ST->getStringForID(Offset); -} - -Expected -C13DebugFragmentVisitor::getNameFromChecksumsBuffer(uint32_t Offset) { - assert(Checksums.hasValue()); - - auto Array = Checksums->getArray(); - auto ChecksumIter = Array.at(Offset); - if (ChecksumIter == Array.end()) - return make_error(raw_error_code::invalid_format); - const auto &Entry = *ChecksumIter; - return getNameFromStringTable(Entry.FileNameOffset); -} Index: llvm/trunk/tools/llvm-pdbdump/CMakeLists.txt =================================================================== --- llvm/trunk/tools/llvm-pdbdump/CMakeLists.txt +++ llvm/trunk/tools/llvm-pdbdump/CMakeLists.txt @@ -9,7 +9,6 @@ add_llvm_tool(llvm-pdbdump Analyze.cpp - C13DebugFragmentVisitor.cpp CompactTypeDumpVisitor.cpp Diff.cpp llvm-pdbdump.cpp Index: llvm/trunk/tools/llvm-pdbdump/LLVMOutputStyle.cpp =================================================================== --- llvm/trunk/tools/llvm-pdbdump/LLVMOutputStyle.cpp +++ llvm/trunk/tools/llvm-pdbdump/LLVMOutputStyle.cpp @@ -9,7 +9,6 @@ #include "LLVMOutputStyle.h" -#include "C13DebugFragmentVisitor.h" #include "CompactTypeDumpVisitor.h" #include "StreamUtil.h" #include "llvm-pdbdump.h" @@ -83,64 +82,61 @@ BitVector UseAfterFreePages; }; -class C13RawVisitor : public C13DebugFragmentVisitor { +class C13RawVisitor : public DebugSubsectionVisitor { public: - C13RawVisitor(ScopedPrinter &P, PDBFile &F, LazyRandomTypeCollection &IPI) - : C13DebugFragmentVisitor(F), P(P), IPI(IPI) {} + C13RawVisitor(ScopedPrinter &P, LazyRandomTypeCollection &IPI) + : P(P), IPI(IPI) {} - Error handleLines() override { - if (Lines.empty() || - !opts::checkModuleSubsection(opts::ModuleSubsection::Lines)) + Error visitLines(DebugLinesSubsectionRef &Lines, + const DebugSubsectionState &State) override { + if (!opts::checkModuleSubsection(opts::ModuleSubsection::Lines)) return Error::success(); DictScope DD(P, "Lines"); - for (const auto &Fragment : Lines) { - DictScope DDD(P, "Block"); - P.printNumber("RelocSegment", Fragment.header()->RelocSegment); - P.printNumber("RelocOffset", Fragment.header()->RelocOffset); - P.printNumber("CodeSize", Fragment.header()->CodeSize); - P.printBoolean("HasColumns", Fragment.hasColumnInfo()); + P.printNumber("RelocSegment", Lines.header()->RelocSegment); + P.printNumber("RelocOffset", Lines.header()->RelocOffset); + P.printNumber("CodeSize", Lines.header()->CodeSize); + P.printBoolean("HasColumns", Lines.hasColumnInfo()); - for (const auto &L : Fragment) { - DictScope DDDD(P, "Lines"); + for (const auto &L : Lines) { + DictScope DDDD(P, "FileEntry"); - if (auto EC = printFileName("FileName", L.NameIndex)) - return EC; + if (auto EC = printFileName("FileName", L.NameIndex, State)) + return EC; - for (const auto &N : L.LineNumbers) { - DictScope DDD(P, "Line"); - LineInfo LI(N.Flags); - P.printNumber("Offset", N.Offset); - if (LI.isAlwaysStepInto()) - P.printString("StepInto", StringRef("Always")); - else if (LI.isNeverStepInto()) - P.printString("StepInto", StringRef("Never")); - else - P.printNumber("LineNumberStart", LI.getStartLine()); - P.printNumber("EndDelta", LI.getLineDelta()); - P.printBoolean("IsStatement", LI.isStatement()); - } - for (const auto &C : L.Columns) { - DictScope DDD(P, "Column"); - P.printNumber("Start", C.StartColumn); - P.printNumber("End", C.EndColumn); - } + for (const auto &N : L.LineNumbers) { + DictScope DDD(P, "Line"); + LineInfo LI(N.Flags); + P.printNumber("Offset", N.Offset); + if (LI.isAlwaysStepInto()) + P.printString("StepInto", StringRef("Always")); + else if (LI.isNeverStepInto()) + P.printString("StepInto", StringRef("Never")); + else + P.printNumber("LineNumberStart", LI.getStartLine()); + P.printNumber("EndDelta", LI.getLineDelta()); + P.printBoolean("IsStatement", LI.isStatement()); + } + for (const auto &C : L.Columns) { + DictScope DDD(P, "Column"); + P.printNumber("Start", C.StartColumn); + P.printNumber("End", C.EndColumn); } } return Error::success(); } - Error handleFileChecksums() override { - if (!Checksums.hasValue() || - !opts::checkModuleSubsection(opts::ModuleSubsection::FileChecksums)) + Error visitFileChecksums(DebugChecksumsSubsectionRef &Checksums, + const DebugSubsectionState &State) override { + if (!opts::checkModuleSubsection(opts::ModuleSubsection::FileChecksums)) return Error::success(); DictScope DD(P, "FileChecksums"); - for (const auto &CS : *Checksums) { + for (const auto &CS : Checksums) { DictScope DDD(P, "Checksum"); - if (auto Result = getNameFromStringTable(CS.FileNameOffset)) + if (auto Result = getNameFromStringTable(CS.FileNameOffset, State)) P.printString("FileName", *Result); else return Result.takeError(); @@ -150,65 +146,60 @@ return Error::success(); } - Error handleInlineeLines() override { - if (InlineeLines.empty() || - !opts::checkModuleSubsection(opts::ModuleSubsection::InlineeLines)) + Error visitInlineeLines(DebugInlineeLinesSubsectionRef &Inlinees, + const DebugSubsectionState &State) override { + if (!opts::checkModuleSubsection(opts::ModuleSubsection::InlineeLines)) return Error::success(); DictScope D(P, "InlineeLines"); - for (const auto &IL : InlineeLines) { - P.printBoolean("HasExtraFiles", IL.hasExtraFiles()); - ListScope LS(P, "Lines"); - for (const auto &L : IL) { - DictScope DDD(P, "Inlinee"); - if (auto EC = printFileName("FileName", L.Header->FileID)) - return EC; + P.printBoolean("HasExtraFiles", Inlinees.hasExtraFiles()); + ListScope LS(P, "Lines"); + for (const auto &L : Inlinees) { + DictScope DDD(P, "Inlinee"); + if (auto EC = printFileName("FileName", L.Header->FileID, State)) + return EC; - if (auto EC = dumpTypeRecord("Function", L.Header->Inlinee)) - return EC; - P.printNumber("SourceLine", L.Header->SourceLineNum); - if (IL.hasExtraFiles()) { - ListScope DDDD(P, "ExtraFiles"); - for (const auto &EF : L.ExtraFiles) { - if (auto EC = printFileName("File", EF)) - return EC; - } + if (auto EC = dumpTypeRecord("Function", L.Header->Inlinee)) + return EC; + P.printNumber("SourceLine", L.Header->SourceLineNum); + if (Inlinees.hasExtraFiles()) { + ListScope DDDD(P, "ExtraFiles"); + for (const auto &EF : L.ExtraFiles) { + if (auto EC = printFileName("File", EF, State)) + return EC; } } } return Error::success(); } - Error handleCrossModuleExports() override { - if (CrossExports.empty() || - !opts::checkModuleSubsection(opts::ModuleSubsection::CrossScopeExports)) + Error visitCrossModuleExports(DebugCrossModuleExportsSubsectionRef &CSE, + const DebugSubsectionState &State) override { + if (!opts::checkModuleSubsection(opts::ModuleSubsection::CrossScopeExports)) return Error::success(); - for (const auto &M : CrossExports) { - DictScope D(P, "CrossModuleExports"); - for (const auto &E : M) { - P.printHex("Local", E.Local); - P.printHex("Global", E.Global); - } + ListScope D(P, "CrossModuleExports"); + for (const auto &M : CSE) { + DictScope D(P, "Export"); + P.printHex("Local", M.Local); + P.printHex("Global", M.Global); } return Error::success(); } - Error handleCrossModuleImports() override { - if (CrossImports.empty() || - !opts::checkModuleSubsection(opts::ModuleSubsection::CrossScopeImports)) + Error visitCrossModuleImports(DebugCrossModuleImportsSubsectionRef &CSI, + const DebugSubsectionState &State) override { + if (!opts::checkModuleSubsection(opts::ModuleSubsection::CrossScopeImports)) return Error::success(); - for (const auto &M : CrossImports) { - DictScope D(P, "CrossModuleImports"); - for (const auto &ImportGroup : M) { - auto Name = - getNameFromStringTable(ImportGroup.Header->ModuleNameOffset); - if (!Name) - return Name.takeError(); - P.printString("Module", *Name); - P.printHexList("Imports", ImportGroup.Imports); - } + ListScope L(P, "CrossModuleImports"); + for (const auto &M : CSI) { + DictScope D(P, "ModuleImport"); + auto Name = getNameFromStringTable(M.Header->ModuleNameOffset, State); + if (!Name) + return Name.takeError(); + P.printString("Module", *Name); + P.printHexList("Imports", M.Imports); } return Error::success(); } @@ -228,14 +219,31 @@ } return Error::success(); } - Error printFileName(StringRef Label, uint32_t Offset) { - if (auto Result = getNameFromChecksumsBuffer(Offset)) { + Error printFileName(StringRef Label, uint32_t Offset, + const DebugSubsectionState &State) { + if (auto Result = getNameFromChecksumsBuffer(Offset, State)) { P.printString(Label, *Result); return Error::success(); } else return Result.takeError(); } + Expected + getNameFromStringTable(uint32_t Offset, const DebugSubsectionState &State) { + return State.strings().getString(Offset); + } + + Expected + getNameFromChecksumsBuffer(uint32_t Offset, + const DebugSubsectionState &State) { + auto Array = State.checksums().getArray(); + auto ChecksumIter = Array.at(Offset); + if (ChecksumIter == Array.end()) + return make_error(raw_error_code::invalid_format); + const auto &Entry = *ChecksumIter; + return getNameFromStringTable(Entry.FileNameOffset, State); + } + ScopedPrinter &P; LazyRandomTypeCollection &IPI; }; @@ -872,8 +880,16 @@ if (!ExpectedTypes) return ExpectedTypes.takeError(); auto &IpiItems = *ExpectedTypes; - C13RawVisitor V(P, File, IpiItems); - if (auto EC = codeview::visitDebugSubsections(ModS.subsections(), V)) + auto ExpectedStrings = File.getStringTable(); + if (!ExpectedStrings) + return joinErrors( + make_error(raw_error_code::no_stream, + "Could not get string table!"), + std::move(ExpectedStrings.takeError())); + + C13RawVisitor V(P, IpiItems); + if (auto EC = codeview::visitDebugSubsections( + ModS.subsections(), V, ExpectedStrings->getStringTable())) return EC; } } Index: llvm/trunk/tools/llvm-pdbdump/YAMLOutputStyle.cpp =================================================================== --- llvm/trunk/tools/llvm-pdbdump/YAMLOutputStyle.cpp +++ llvm/trunk/tools/llvm-pdbdump/YAMLOutputStyle.cpp @@ -9,7 +9,6 @@ #include "YAMLOutputStyle.h" -#include "C13DebugFragmentVisitor.h" #include "PdbYaml.h" #include "llvm-pdbdump.h"