Index: llvm/trunk/include/llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h +++ llvm/trunk/include/llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h @@ -60,8 +60,8 @@ Error initialize(BinaryStreamReader Reader); Error initialize(BinaryStreamRef Stream); - Iterator begin() { return Checksums.begin(); } - Iterator end() { return Checksums.end(); } + Iterator begin() const { return Checksums.begin(); } + Iterator end() const { return Checksums.end(); } const FileChecksumArray &getArray() const { return Checksums; } Index: llvm/trunk/include/llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h +++ llvm/trunk/include/llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h @@ -74,8 +74,13 @@ class DebugInlineeLinesSubsection final : public DebugSubsection { public: + struct Entry { + std::vector ExtraFiles; + InlineeSourceLineHeader Header; + }; + DebugInlineeLinesSubsection(DebugChecksumsSubsection &Checksums, - bool HasExtraFiles); + bool HasExtraFiles = false); static bool classof(const DebugSubsection *S) { return S->kind() == DebugSubsectionKind::InlineeLines; @@ -87,16 +92,18 @@ void addInlineSite(TypeIndex FuncId, StringRef FileName, uint32_t SourceLine); void addExtraFile(StringRef FileName); + bool hasExtraFiles() const { return HasExtraFiles; } + void setHasExtraFiles(bool Has) { HasExtraFiles = Has; } + + std::vector::const_iterator begin() const { return Entries.begin(); } + std::vector::const_iterator end() const { return Entries.end(); } + private: DebugChecksumsSubsection &Checksums; bool HasExtraFiles = false; uint32_t ExtraFileCount = 0; - struct Entry { - std::vector ExtraFiles; - InlineeSourceLineHeader Header; - }; std::vector Entries; }; } Index: llvm/trunk/include/llvm/DebugInfo/CodeView/DebugSubsectionRecord.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/CodeView/DebugSubsectionRecord.h +++ llvm/trunk/include/llvm/DebugInfo/CodeView/DebugSubsectionRecord.h @@ -49,15 +49,14 @@ class DebugSubsectionRecordBuilder { public: - DebugSubsectionRecordBuilder(DebugSubsectionKind Kind, DebugSubsection &Frag, + DebugSubsectionRecordBuilder(std::unique_ptr Subsection, CodeViewContainer Container); uint32_t calculateSerializedLength(); Error commit(BinaryStreamWriter &Writer); private: + std::unique_ptr Subsection; CodeViewContainer Container; - DebugSubsectionKind Kind; - DebugSubsection &Frag; }; } // namespace codeview Index: llvm/trunk/include/llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h +++ llvm/trunk/include/llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h @@ -49,11 +49,8 @@ void setObjFileName(StringRef Name); void addSymbol(codeview::CVSymbol Symbol); - void addC13Fragment(std::unique_ptr Lines); - void addC13Fragment( - std::unique_ptr Inlinees); - void setC13FileChecksums( - std::unique_ptr Checksums); + void + addDebugSubsection(std::unique_ptr Subsection); uint16_t getStreamIndex() const; StringRef getModuleName() const { return ModuleName; } @@ -83,10 +80,6 @@ std::vector SourceFiles; std::vector Symbols; - std::unique_ptr ChecksumInfo; - std::vector> LineInfo; - std::vector> Inlinees; - std::vector> C13Builders; Index: llvm/trunk/include/llvm/DebugInfo/PDB/Native/ModuleDebugStream.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/PDB/Native/ModuleDebugStream.h +++ llvm/trunk/include/llvm/DebugInfo/PDB/Native/ModuleDebugStream.h @@ -12,6 +12,7 @@ #include "llvm/ADT/iterator_range.h" #include "llvm/DebugInfo/CodeView/CVRecord.h" +#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h" #include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" @@ -25,7 +26,7 @@ class DbiModuleDescriptor; class ModuleDebugStreamRef { - typedef codeview::DebugSubsectionArray::Iterator LinesAndChecksumsIterator; + typedef codeview::DebugSubsectionArray::Iterator DebugSubsectionIterator; public: ModuleDebugStreamRef(const DbiModuleDescriptor &Module, @@ -39,12 +40,15 @@ iterator_range symbols(bool *HadError) const; - llvm::iterator_range linesAndChecksums() const; + llvm::iterator_range subsections() const; - bool hasLineInfo() const; + bool hasDebugSubsections() const; Error commit(); + Expected + findChecksumsSubsection() const; + private: const DbiModuleDescriptor &Mod; @@ -57,7 +61,7 @@ BinaryStreamRef C13LinesSubstream; BinaryStreamRef GlobalRefsSubstream; - codeview::DebugSubsectionArray LinesAndChecksums; + codeview::DebugSubsectionArray Subsections; }; } } Index: llvm/trunk/include/llvm/DebugInfo/PDB/Native/PDBStringTable.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/PDB/Native/PDBStringTable.h +++ llvm/trunk/include/llvm/DebugInfo/PDB/Native/PDBStringTable.h @@ -45,6 +45,8 @@ FixedStreamArray name_ids() const; + codeview::DebugStringTableSubsectionRef getStringTable() const; + private: Error readHeader(BinaryStreamReader &Reader); Error readStrings(BinaryStreamReader &Reader); Index: llvm/trunk/include/llvm/ObjectYAML/CodeViewYAMLDebugSections.h =================================================================== --- llvm/trunk/include/llvm/ObjectYAML/CodeViewYAMLDebugSections.h +++ llvm/trunk/include/llvm/ObjectYAML/CodeViewYAMLDebugSections.h @@ -17,12 +17,20 @@ #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/CodeView/DebugSubsection.h" +#include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h" #include "llvm/ObjectYAML/YAML.h" namespace llvm { + +namespace codeview { +class DebugStringTableSubsection; +class DebugStringTableSubsectionRef; +class DebugChecksumsSubsectionRef; +} namespace CodeViewYAML { + namespace detail { -struct C13FragmentBase; +struct YAMLSubsectionBase; } struct SourceLineEntry { @@ -74,18 +82,24 @@ std::vector Sites; }; -struct SourceFileInfo { - std::vector FileChecksums; - std::vector LineFragments; - std::vector Inlinees; +struct YAMLDebugSubsection { + static Expected + fromCodeViewSubection(const codeview::DebugStringTableSubsectionRef &Strings, + const codeview::DebugChecksumsSubsectionRef &Checksums, + const codeview::DebugSubsectionRecord &SS); + + std::shared_ptr Subsection; }; -struct C13DebugSection { - std::vector Fragments; -}; +Expected>> +convertSubsectionList(ArrayRef Subsections, + codeview::DebugStringTableSubsection &Strings); + } // namespace CodeViewYAML } // namespace llvm -LLVM_YAML_DECLARE_MAPPING_TRAITS(CodeViewYAML::SourceFileInfo) +LLVM_YAML_DECLARE_MAPPING_TRAITS(CodeViewYAML::YAMLDebugSubsection) + +LLVM_YAML_IS_SEQUENCE_VECTOR(CodeViewYAML::YAMLDebugSubsection) #endif Index: llvm/trunk/lib/DebugInfo/CodeView/DebugStringTableSubsection.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/CodeView/DebugStringTableSubsection.cpp +++ llvm/trunk/lib/DebugInfo/CodeView/DebugStringTableSubsection.cpp @@ -72,7 +72,7 @@ uint32_t DebugStringTableSubsection::size() const { return Strings.size(); } uint32_t DebugStringTableSubsection::getStringId(StringRef S) const { - auto P = Strings.find(S); - assert(P != Strings.end()); - return P->second; + auto Iter = Strings.find(S); + assert(Iter != Strings.end()); + return Iter->second; } Index: llvm/trunk/lib/DebugInfo/CodeView/DebugSubsectionRecord.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/CodeView/DebugSubsectionRecord.cpp +++ llvm/trunk/lib/DebugInfo/CodeView/DebugSubsectionRecord.cpp @@ -60,13 +60,13 @@ BinaryStreamRef DebugSubsectionRecord::getRecordData() const { return Data; } DebugSubsectionRecordBuilder::DebugSubsectionRecordBuilder( - DebugSubsectionKind Kind, DebugSubsection &Frag, - CodeViewContainer Container) - : Container(Container), Kind(Kind), Frag(Frag) {} + std::unique_ptr Subsection, CodeViewContainer Container) + : Subsection(std::move(Subsection)), Container(Container) {} uint32_t DebugSubsectionRecordBuilder::calculateSerializedLength() { - uint32_t Size = sizeof(DebugSubsectionHeader) + - alignTo(Frag.calculateSerializedSize(), alignOf(Container)); + uint32_t Size = + sizeof(DebugSubsectionHeader) + + alignTo(Subsection->calculateSerializedSize(), alignOf(Container)); return Size; } @@ -75,12 +75,12 @@ "Debug Subsection not properly aligned"); DebugSubsectionHeader Header; - Header.Kind = uint32_t(Kind); + Header.Kind = uint32_t(Subsection->kind()); Header.Length = calculateSerializedLength() - sizeof(DebugSubsectionHeader); if (auto EC = Writer.writeObject(Header)) return EC; - if (auto EC = Frag.commit(Writer)) + if (auto EC = Subsection->commit(Writer)) return EC; if (auto EC = Writer.padToAlignment(alignOf(Container))) return EC; Index: llvm/trunk/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp +++ llvm/trunk/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp @@ -174,42 +174,9 @@ return Error::success(); } -void DbiModuleDescriptorBuilder::addC13Fragment( - std::unique_ptr Lines) { - DebugLinesSubsection &Frag = *Lines; - - // File Checksums have to come first, so push an empty entry on if this - // is the first. - if (C13Builders.empty()) - C13Builders.push_back(nullptr); - - this->LineInfo.push_back(std::move(Lines)); - C13Builders.push_back(llvm::make_unique( - Frag.kind(), Frag, CodeViewContainer::Pdb)); -} - -void DbiModuleDescriptorBuilder::addC13Fragment( - std::unique_ptr Inlinees) { - DebugInlineeLinesSubsection &Frag = *Inlinees; - - // File Checksums have to come first, so push an empty entry on if this - // is the first. - if (C13Builders.empty()) - C13Builders.push_back(nullptr); - - this->Inlinees.push_back(std::move(Inlinees)); +void DbiModuleDescriptorBuilder::addDebugSubsection( + std::unique_ptr Subsection) { + assert(Subsection); C13Builders.push_back(llvm::make_unique( - Frag.kind(), Frag, CodeViewContainer::Pdb)); -} - -void DbiModuleDescriptorBuilder::setC13FileChecksums( - std::unique_ptr Checksums) { - assert(!ChecksumInfo && "Can't have more than one checksum info!"); - - if (C13Builders.empty()) - C13Builders.push_back(nullptr); - - ChecksumInfo = std::move(Checksums); - C13Builders[0] = llvm::make_unique( - ChecksumInfo->kind(), *ChecksumInfo, CodeViewContainer::Pdb); + std::move(Subsection), CodeViewContainer::Pdb)); } Index: llvm/trunk/lib/DebugInfo/PDB/Native/ModuleDebugStream.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/PDB/Native/ModuleDebugStream.cpp +++ llvm/trunk/lib/DebugInfo/PDB/Native/ModuleDebugStream.cpp @@ -55,9 +55,9 @@ if (auto EC = Reader.readStreamRef(C13LinesSubstream, C13Size)) return EC; - BinaryStreamReader LineReader(C13LinesSubstream); - if (auto EC = - LineReader.readArray(LinesAndChecksums, LineReader.bytesRemaining())) + BinaryStreamReader SubsectionsReader(C13LinesSubstream); + if (auto EC = SubsectionsReader.readArray(Subsections, + SubsectionsReader.bytesRemaining())) return EC; uint32_t GlobalRefsSize; @@ -77,13 +77,27 @@ return make_range(SymbolsSubstream.begin(HadError), SymbolsSubstream.end()); } -llvm::iterator_range -ModuleDebugStreamRef::linesAndChecksums() const { - return make_range(LinesAndChecksums.begin(), LinesAndChecksums.end()); +llvm::iterator_range +ModuleDebugStreamRef::subsections() const { + return make_range(Subsections.begin(), Subsections.end()); } -bool ModuleDebugStreamRef::hasLineInfo() const { +bool ModuleDebugStreamRef::hasDebugSubsections() const { return C13LinesSubstream.getLength() > 0; } Error ModuleDebugStreamRef::commit() { return Error::success(); } + +Expected +ModuleDebugStreamRef::findChecksumsSubsection() const { + for (const auto &SS : subsections()) { + if (SS.kind() != DebugSubsectionKind::FileChecksums) + continue; + + codeview::DebugChecksumsSubsectionRef Result; + if (auto EC = Result.initialize(SS.getRecordData())) + return std::move(EC); + return Result; + } + return make_error(raw_error_code::no_entry); +} Index: llvm/trunk/lib/DebugInfo/PDB/Native/PDBStringTable.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/PDB/Native/PDBStringTable.cpp +++ llvm/trunk/lib/DebugInfo/PDB/Native/PDBStringTable.cpp @@ -56,6 +56,10 @@ return Error::success(); } +codeview::DebugStringTableSubsectionRef PDBStringTable::getStringTable() const { + return Strings; +} + Error PDBStringTable::readHashTable(BinaryStreamReader &Reader) { const support::ulittle32_t *HashCount; if (auto EC = Reader.readObject(HashCount)) Index: llvm/trunk/lib/ObjectYAML/CodeViewYAMLDebugSections.cpp =================================================================== --- llvm/trunk/lib/ObjectYAML/CodeViewYAMLDebugSections.cpp +++ llvm/trunk/lib/ObjectYAML/CodeViewYAMLDebugSections.cpp @@ -17,6 +17,11 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/DebugInfo/CodeView/CodeViewError.h" +#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h" +#include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h" +#include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h" +#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h" +#include "llvm/DebugInfo/CodeView/DebugSubsectionVisitor.h" #include "llvm/DebugInfo/CodeView/EnumTables.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h" @@ -36,16 +41,80 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(StringRef) LLVM_YAML_DECLARE_SCALAR_TRAITS(HexFormattedString, false) +LLVM_YAML_DECLARE_ENUM_TRAITS(DebugSubsectionKind) LLVM_YAML_DECLARE_ENUM_TRAITS(FileChecksumKind) LLVM_YAML_DECLARE_BITSET_TRAITS(LineFlags) -LLVM_YAML_DECLARE_MAPPING_TRAITS(CodeViewYAML::SourceLineEntry) -LLVM_YAML_DECLARE_MAPPING_TRAITS(CodeViewYAML::SourceColumnEntry) -LLVM_YAML_DECLARE_MAPPING_TRAITS(CodeViewYAML::SourceFileChecksumEntry) -LLVM_YAML_DECLARE_MAPPING_TRAITS(CodeViewYAML::SourceLineInfo) -LLVM_YAML_DECLARE_MAPPING_TRAITS(CodeViewYAML::SourceLineBlock) -LLVM_YAML_DECLARE_MAPPING_TRAITS(CodeViewYAML::InlineeInfo) -LLVM_YAML_DECLARE_MAPPING_TRAITS(CodeViewYAML::InlineeSite) +LLVM_YAML_DECLARE_MAPPING_TRAITS(SourceLineEntry) +LLVM_YAML_DECLARE_MAPPING_TRAITS(SourceColumnEntry) +LLVM_YAML_DECLARE_MAPPING_TRAITS(SourceFileChecksumEntry) +LLVM_YAML_DECLARE_MAPPING_TRAITS(SourceLineBlock) +LLVM_YAML_DECLARE_MAPPING_TRAITS(InlineeSite) + +namespace llvm { +namespace CodeViewYAML { +namespace detail { +struct YAMLSubsectionBase { + explicit YAMLSubsectionBase(DebugSubsectionKind Kind) : Kind(Kind) {} + DebugSubsectionKind Kind; + virtual ~YAMLSubsectionBase() {} + + virtual void map(IO &IO) = 0; + virtual std::unique_ptr + toCodeViewSubsection(DebugStringTableSubsection *UseStrings, + DebugChecksumsSubsection *UseChecksums) const = 0; +}; +} +} +} + +namespace { +struct YAMLChecksumsSubsection : public YAMLSubsectionBase { + YAMLChecksumsSubsection() + : YAMLSubsectionBase(DebugSubsectionKind::FileChecksums) {} + + void map(IO &IO) override; + std::unique_ptr + toCodeViewSubsection(DebugStringTableSubsection *Strings, + DebugChecksumsSubsection *Checksums) const override; + static Expected> + fromCodeViewSubsection(const DebugStringTableSubsectionRef &Strings, + const DebugChecksumsSubsectionRef &FC); + + std::vector Checksums; +}; + +struct YAMLLinesSubsection : public YAMLSubsectionBase { + YAMLLinesSubsection() : YAMLSubsectionBase(DebugSubsectionKind::Lines) {} + + void map(IO &IO) override; + std::unique_ptr + toCodeViewSubsection(DebugStringTableSubsection *Strings, + DebugChecksumsSubsection *Checksums) const override; + static Expected> + fromCodeViewSubsection(const DebugStringTableSubsectionRef &Strings, + const DebugChecksumsSubsectionRef &Checksums, + const DebugLinesSubsectionRef &Lines); + + SourceLineInfo Lines; +}; + +struct YAMLInlineeLinesSubsection : public YAMLSubsectionBase { + YAMLInlineeLinesSubsection() + : YAMLSubsectionBase(DebugSubsectionKind::InlineeLines) {} + + void map(IO &IO) override; + std::unique_ptr + toCodeViewSubsection(DebugStringTableSubsection *Strings, + DebugChecksumsSubsection *Checksums) const override; + static Expected> + fromCodeViewSubsection(const DebugStringTableSubsectionRef &Strings, + const DebugChecksumsSubsectionRef &Checksums, + const DebugInlineeLinesSubsectionRef &Lines); + + InlineeInfo InlineeLines; +}; +} void ScalarBitSetTraits::bitset(IO &io, LineFlags &Flags) { io.bitSetCase(Flags, "HasColumnInfo", LF_HaveColumns); @@ -99,21 +168,6 @@ IO.mapRequired("Checksum", Obj.ChecksumBytes); } -void MappingTraits::mapping(IO &IO, SourceLineInfo &Obj) { - IO.mapRequired("CodeSize", Obj.CodeSize); - - IO.mapRequired("Flags", Obj.Flags); - IO.mapRequired("RelocOffset", Obj.RelocOffset); - IO.mapRequired("RelocSegment", Obj.RelocSegment); - IO.mapRequired("Blocks", Obj.Blocks); -} - -void MappingTraits::mapping(IO &IO, SourceFileInfo &Obj) { - IO.mapOptional("Checksums", Obj.FileChecksums); - IO.mapOptional("Lines", Obj.LineFragments); - IO.mapOptional("InlineeLines", Obj.Inlinees); -} - void MappingTraits::mapping(IO &IO, InlineeSite &Obj) { IO.mapRequired("FileName", Obj.FileName); IO.mapRequired("LineNum", Obj.SourceLineNum); @@ -121,7 +175,310 @@ IO.mapOptional("ExtraFiles", Obj.ExtraFiles); } -void MappingTraits::mapping(IO &IO, InlineeInfo &Obj) { - IO.mapRequired("HasExtraFiles", Obj.HasExtraFiles); - IO.mapRequired("Sites", Obj.Sites); +void YAMLChecksumsSubsection::map(IO &IO) { + IO.mapTag("!FileChecksums", true); + IO.mapRequired("Checksums", Checksums); +} + +void YAMLLinesSubsection::map(IO &IO) { + IO.mapTag("!Lines", true); + IO.mapRequired("CodeSize", Lines.CodeSize); + + IO.mapRequired("Flags", Lines.Flags); + IO.mapRequired("RelocOffset", Lines.RelocOffset); + IO.mapRequired("RelocSegment", Lines.RelocSegment); + IO.mapRequired("Blocks", Lines.Blocks); +} + +void YAMLInlineeLinesSubsection::map(IO &IO) { + IO.mapTag("!InlineeLines", true); + IO.mapRequired("HasExtraFiles", InlineeLines.HasExtraFiles); + IO.mapRequired("Sites", InlineeLines.Sites); +} + +void MappingTraits::mapping( + IO &IO, YAMLDebugSubsection &Subsection) { + if (!IO.outputting()) { + if (IO.mapTag("!FileChecksums")) { + auto SS = std::make_shared(); + Subsection.Subsection = SS; + } else if (IO.mapTag("!Lines")) { + Subsection.Subsection = std::make_shared(); + } else if (IO.mapTag("!InlineeLines")) { + Subsection.Subsection = std::make_shared(); + } else { + llvm_unreachable("Unexpected subsection tag!"); + } + } + Subsection.Subsection->map(IO); +} + +static Expected +findChecksums(ArrayRef Subsections) { + for (const auto &SS : Subsections) { + if (SS.Subsection->Kind == DebugSubsectionKind::FileChecksums) { + return static_cast(*SS.Subsection); + } + } + return make_error(cv_error_code::no_records); +} + +std::unique_ptr YAMLChecksumsSubsection::toCodeViewSubsection( + DebugStringTableSubsection *UseStrings, + DebugChecksumsSubsection *UseChecksums) const { + assert(UseStrings && !UseChecksums); + auto Result = llvm::make_unique(*UseStrings); + for (const auto &CS : Checksums) { + Result->addChecksum(CS.FileName, CS.Kind, CS.ChecksumBytes.Bytes); + } + return std::move(Result); +} + +std::unique_ptr YAMLLinesSubsection::toCodeViewSubsection( + DebugStringTableSubsection *UseStrings, + DebugChecksumsSubsection *UseChecksums) const { + assert(UseStrings && UseChecksums); + auto Result = + llvm::make_unique(*UseChecksums, *UseStrings); + Result->setCodeSize(Lines.CodeSize); + Result->setRelocationAddress(Lines.RelocSegment, Lines.RelocOffset); + Result->setFlags(Lines.Flags); + for (const auto &LC : Lines.Blocks) { + Result->createBlock(LC.FileName); + if (Result->hasColumnInfo()) { + for (const auto &Item : zip(LC.Lines, LC.Columns)) { + auto &L = std::get<0>(Item); + auto &C = std::get<1>(Item); + uint32_t LE = L.LineStart + L.EndDelta; + Result->addLineAndColumnInfo(L.Offset, + LineInfo(L.LineStart, LE, L.IsStatement), + C.StartColumn, C.EndColumn); + } + } else { + for (const auto &L : LC.Lines) { + uint32_t LE = L.LineStart + L.EndDelta; + Result->addLineInfo(L.Offset, LineInfo(L.LineStart, LE, L.IsStatement)); + } + } + } + return Result; +} + +std::unique_ptr +YAMLInlineeLinesSubsection::toCodeViewSubsection( + DebugStringTableSubsection *UseStrings, + DebugChecksumsSubsection *UseChecksums) const { + assert(UseChecksums); + auto Result = llvm::make_unique( + *UseChecksums, InlineeLines.HasExtraFiles); + + for (const auto &Site : InlineeLines.Sites) { + Result->addInlineSite(TypeIndex(Site.Inlinee), Site.FileName, + Site.SourceLineNum); + if (!InlineeLines.HasExtraFiles) + continue; + + for (auto EF : Site.ExtraFiles) { + Result->addExtraFile(EF); + } + } + return Result; +} + +static Expected +convertOneChecksum(const DebugStringTableSubsectionRef &Strings, + const FileChecksumEntry &CS) { + auto ExpectedString = Strings.getString(CS.FileNameOffset); + if (!ExpectedString) + return ExpectedString.takeError(); + + SourceFileChecksumEntry Result; + Result.ChecksumBytes.Bytes = CS.Checksum; + Result.Kind = CS.Kind; + Result.FileName = *ExpectedString; + return Result; +} + +static Expected +getFileName(const DebugStringTableSubsectionRef &Strings, + const DebugChecksumsSubsectionRef &Checksums, uint32_t FileID) { + auto Iter = Checksums.getArray().at(FileID); + if (Iter == Checksums.getArray().end()) + return make_error(cv_error_code::no_records); + uint32_t Offset = Iter->FileNameOffset; + return Strings.getString(Offset); +} + +Expected> +YAMLChecksumsSubsection::fromCodeViewSubsection( + const DebugStringTableSubsectionRef &Strings, + const DebugChecksumsSubsectionRef &FC) { + auto Result = std::make_shared(); + + for (const auto &CS : FC) { + auto ConvertedCS = convertOneChecksum(Strings, CS); + if (!ConvertedCS) + return ConvertedCS.takeError(); + Result->Checksums.push_back(*ConvertedCS); + } + return Result; +} + +Expected> +YAMLLinesSubsection::fromCodeViewSubsection( + const DebugStringTableSubsectionRef &Strings, + const DebugChecksumsSubsectionRef &Checksums, + const DebugLinesSubsectionRef &Lines) { + auto Result = std::make_shared(); + Result->Lines.CodeSize = Lines.header()->CodeSize; + Result->Lines.RelocOffset = Lines.header()->RelocOffset; + Result->Lines.RelocSegment = Lines.header()->RelocSegment; + Result->Lines.Flags = static_cast(uint16_t(Lines.header()->Flags)); + for (const auto &L : Lines) { + SourceLineBlock Block; + auto EF = getFileName(Strings, Checksums, L.NameIndex); + if (!EF) + return EF.takeError(); + Block.FileName = *EF; + if (Lines.hasColumnInfo()) { + for (const auto &C : L.Columns) { + SourceColumnEntry SCE; + SCE.EndColumn = C.EndColumn; + SCE.StartColumn = C.StartColumn; + Block.Columns.push_back(SCE); + } + } + for (const auto &LN : L.LineNumbers) { + SourceLineEntry SLE; + LineInfo LI(LN.Flags); + SLE.Offset = LN.Offset; + SLE.LineStart = LI.getStartLine(); + SLE.EndDelta = LI.getLineDelta(); + SLE.IsStatement = LI.isStatement(); + Block.Lines.push_back(SLE); + } + Result->Lines.Blocks.push_back(Block); + } + return Result; +} + +Expected> +YAMLInlineeLinesSubsection::fromCodeViewSubsection( + const DebugStringTableSubsectionRef &Strings, + const DebugChecksumsSubsectionRef &Checksums, + const DebugInlineeLinesSubsectionRef &Lines) { + auto Result = std::make_shared(); + + Result->InlineeLines.HasExtraFiles = Lines.hasExtraFiles(); + for (const auto &IL : Lines) { + InlineeSite Site; + auto ExpF = getFileName(Strings, Checksums, IL.Header->FileID); + if (!ExpF) + return ExpF.takeError(); + Site.FileName = *ExpF; + Site.Inlinee = IL.Header->Inlinee.getIndex(); + Site.SourceLineNum = IL.Header->SourceLineNum; + if (Lines.hasExtraFiles()) { + for (const auto EF : IL.ExtraFiles) { + auto ExpF2 = getFileName(Strings, Checksums, EF); + if (!ExpF2) + return ExpF2.takeError(); + Site.ExtraFiles.push_back(*ExpF2); + } + } + Result->InlineeLines.Sites.push_back(Site); + } + return Result; +} + +Expected>> +llvm::CodeViewYAML::convertSubsectionList( + ArrayRef Subsections, + DebugStringTableSubsection &Strings) { + std::vector> Result; + if (Subsections.empty()) + return Result; + + auto Checksums = findChecksums(Subsections); + if (!Checksums) + return Checksums.takeError(); + auto ChecksumsBase = Checksums->toCodeViewSubsection(&Strings, nullptr); + DebugChecksumsSubsection &CS = + llvm::cast(*ChecksumsBase); + for (const auto &SS : Subsections) { + // We've already converted the checksums subsection, don't do it + // twice. + std::unique_ptr CVS; + if (SS.Subsection->Kind == DebugSubsectionKind::FileChecksums) + CVS = std::move(ChecksumsBase); + else + CVS = SS.Subsection->toCodeViewSubsection(&Strings, &CS); + Result.push_back(std::move(CVS)); + } + return std::move(Result); +} + +namespace { +struct SubsectionConversionVisitor : public DebugSubsectionVisitor { + explicit SubsectionConversionVisitor( + const DebugStringTableSubsectionRef &Strings, + const DebugChecksumsSubsectionRef &Checksums) + : Strings(Strings), Checksums(Checksums) {} + + Error visitUnknown(DebugUnknownSubsectionRef &Unknown) override; + Error visitLines(DebugLinesSubsectionRef &Lines) override; + Error visitFileChecksums(DebugChecksumsSubsectionRef &Checksums) override; + Error visitInlineeLines(DebugInlineeLinesSubsectionRef &Inlinees) override; + + YAMLDebugSubsection Subsection; + +private: + const DebugStringTableSubsectionRef &Strings; + const DebugChecksumsSubsectionRef &Checksums; +}; + +Error SubsectionConversionVisitor::visitUnknown( + DebugUnknownSubsectionRef &Unknown) { + return make_error(cv_error_code::operation_unsupported); +} + +Error SubsectionConversionVisitor::visitLines(DebugLinesSubsectionRef &Lines) { + auto Result = + YAMLLinesSubsection::fromCodeViewSubsection(Strings, Checksums, Lines); + if (!Result) + return Result.takeError(); + Subsection.Subsection = *Result; + return Error::success(); +} + +Error SubsectionConversionVisitor::visitFileChecksums( + DebugChecksumsSubsectionRef &Checksums) { + auto Result = + YAMLChecksumsSubsection::fromCodeViewSubsection(Strings, Checksums); + if (!Result) + return Result.takeError(); + Subsection.Subsection = *Result; + return Error::success(); +} + +Error SubsectionConversionVisitor::visitInlineeLines( + DebugInlineeLinesSubsectionRef &Inlinees) { + auto Result = YAMLInlineeLinesSubsection::fromCodeViewSubsection( + Strings, Checksums, Inlinees); + if (!Result) + return Result.takeError(); + Subsection.Subsection = *Result; + return Error::success(); +} +} + +Expected YAMLDebugSubsection::fromCodeViewSubection( + const DebugStringTableSubsectionRef &Strings, + const DebugChecksumsSubsectionRef &Checksums, + const DebugSubsectionRecord &SS) { + SubsectionConversionVisitor V(Strings, Checksums); + if (auto EC = visitDebugSubsection(SS, V)) + return std::move(EC); + + return V.Subsection; } Index: llvm/trunk/test/DebugInfo/PDB/Inputs/simple-line-info.yaml =================================================================== --- llvm/trunk/test/DebugInfo/PDB/Inputs/simple-line-info.yaml +++ llvm/trunk/test/DebugInfo/PDB/Inputs/simple-line-info.yaml @@ -5,39 +5,40 @@ ObjFile: 'd:\src\llvm\test\DebugInfo\PDB\Inputs\empty.obj' SourceFiles: - 'd:\src\llvm\test\debuginfo\pdb\inputs\empty.cpp' - LineInfo: - Checksums: - - FileName: 'd:\src\llvm\test\debuginfo\pdb\inputs\empty.cpp' - Kind: MD5 - Checksum: A0A5BD0D3ECD93FC29D19DE826FBF4BC - - FileName: 'f:\dd\externalapis\windows\10\sdk\inc\winerror.h' - Kind: MD5 - Checksum: 1154D69F5B2650196E1FC34F4134E56B - Lines: - - CodeSize: 10 - Flags: [ ] - RelocOffset: 16 - RelocSegment: 1 - Blocks: - - FileName: 'd:\src\llvm\test\debuginfo\pdb\inputs\empty.cpp' - Lines: - - Offset: 0 - LineStart: 5 - IsStatement: true - EndDelta: 0 - - Offset: 3 - LineStart: 6 - IsStatement: true - EndDelta: 0 - - Offset: 8 - LineStart: 7 - IsStatement: true - EndDelta: 0 - Columns: - InlineeLines: - - HasExtraFiles: false - Sites: - - FileName: 'f:\dd\externalapis\windows\10\sdk\inc\winerror.h' - LineNum: 26950 - Inlinee: 22767 + Subsections: + - !FileChecksums + Checksums: + - FileName: 'd:\src\llvm\test\debuginfo\pdb\inputs\empty.cpp' + Kind: MD5 + Checksum: A0A5BD0D3ECD93FC29D19DE826FBF4BC + - FileName: 'f:\dd\externalapis\windows\10\sdk\inc\winerror.h' + Kind: MD5 + Checksum: 1154D69F5B2650196E1FC34F4134E56B + - !Lines + CodeSize: 10 + Flags: [ ] + RelocOffset: 16 + RelocSegment: 1 + Blocks: + - FileName: 'd:\src\llvm\test\debuginfo\pdb\inputs\empty.cpp' + Lines: + - Offset: 0 + LineStart: 5 + IsStatement: true + EndDelta: 0 + - Offset: 3 + LineStart: 6 + IsStatement: true + EndDelta: 0 + - Offset: 8 + LineStart: 7 + IsStatement: true + EndDelta: 0 + Columns: + - !InlineeLines + HasExtraFiles: false + Sites: + - FileName: 'f:\dd\externalapis\windows\10\sdk\inc\winerror.h' + LineNum: 26950 + Inlinee: 22767 ... Index: llvm/trunk/test/DebugInfo/PDB/pdbdump-yaml-lineinfo.test =================================================================== --- llvm/trunk/test/DebugInfo/PDB/pdbdump-yaml-lineinfo.test +++ llvm/trunk/test/DebugInfo/PDB/pdbdump-yaml-lineinfo.test @@ -28,12 +28,8 @@ YAML: ObjFile: 'd:\src\llvm\test\DebugInfo\PDB\Inputs\empty.obj' YAML: SourceFiles: YAML: - 'd:\src\llvm\test\debuginfo\pdb\inputs\empty.cpp' -YAML: LineInfo: -YAML: Checksums: -YAML: - FileName: 'd:\src\llvm\test\debuginfo\pdb\inputs\empty.cpp' -YAML: Kind: MD5 -YAML: Checksum: A0A5BD0D3ECD93FC29D19DE826FBF4BC -YAML: Lines: +YAML: Subsections: +YAML: - !Lines YAML: CodeSize: 10 YAML: Flags: [ ] YAML: RelocOffset: 16 @@ -54,6 +50,11 @@ YAML: IsStatement: true YAML: EndDelta: 0 YAML: Columns: +YAML: - !FileChecksums +YAML: Checksums: +YAML: - FileName: 'd:\src\llvm\test\debuginfo\pdb\inputs\empty.cpp' +YAML: Kind: MD5 +YAML: Checksum: A0A5BD0D3ECD93FC29D19DE826FBF4BC YAML: - Module: '* Linker *' YAML: ObjFile: '' YAML: ... \ No newline at end of file Index: llvm/trunk/tools/llvm-pdbdump/LLVMOutputStyle.cpp =================================================================== --- llvm/trunk/tools/llvm-pdbdump/LLVMOutputStyle.cpp +++ llvm/trunk/tools/llvm-pdbdump/LLVMOutputStyle.cpp @@ -831,8 +831,7 @@ return ExpectedTypes.takeError(); auto &IpiItems = *ExpectedTypes; C13RawVisitor V(P, File, IpiItems); - if (auto EC = - codeview::visitDebugSubsections(ModS.linesAndChecksums(), V)) + if (auto EC = codeview::visitDebugSubsections(ModS.subsections(), V)) return EC; } } Index: llvm/trunk/tools/llvm-pdbdump/PdbYaml.h =================================================================== --- llvm/trunk/tools/llvm-pdbdump/PdbYaml.h +++ llvm/trunk/tools/llvm-pdbdump/PdbYaml.h @@ -28,6 +28,9 @@ #include namespace llvm { +namespace codeview { +class DebugStringTableSubsection; +} namespace pdb { namespace yaml { @@ -68,7 +71,7 @@ StringRef Obj; StringRef Mod; std::vector SourceFiles; - Optional FileLineInfo; + std::vector Subsections; Optional Modi; }; Index: llvm/trunk/tools/llvm-pdbdump/PdbYaml.cpp =================================================================== --- llvm/trunk/tools/llvm-pdbdump/PdbYaml.cpp +++ llvm/trunk/tools/llvm-pdbdump/PdbYaml.cpp @@ -12,6 +12,7 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h" #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" +#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h" #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" #include "llvm/DebugInfo/CodeView/SymbolVisitorCallbackPipeline.h" #include "llvm/DebugInfo/CodeView/TypeSerializer.h" @@ -21,6 +22,7 @@ #include "llvm/DebugInfo/PDB/Native/TpiHashing.h" #include "llvm/DebugInfo/PDB/PDBExtras.h" #include "llvm/DebugInfo/PDB/PDBTypes.h" +#include "llvm/ObjectYAML/CodeViewYAMLDebugSections.h" #include "llvm/ObjectYAML/CodeViewYAMLTypes.h" using namespace llvm; @@ -220,6 +222,6 @@ IO.mapRequired("Module", Obj.Mod); IO.mapOptional("ObjFile", Obj.Obj, Obj.Mod); IO.mapOptional("SourceFiles", Obj.SourceFiles); - IO.mapOptional("LineInfo", Obj.FileLineInfo); + IO.mapOptional("Subsections", Obj.Subsections); IO.mapOptional("Modi", Obj.Modi); } Index: llvm/trunk/tools/llvm-pdbdump/YAMLOutputStyle.h =================================================================== --- llvm/trunk/tools/llvm-pdbdump/YAMLOutputStyle.h +++ llvm/trunk/tools/llvm-pdbdump/YAMLOutputStyle.h @@ -27,9 +27,6 @@ Error dump() override; private: - Expected> - getFileLineInfo(const pdb::ModuleDebugStreamRef &ModS); - Error dumpStringTable(); Error dumpFileHeaders(); Error dumpStreamMetadata(); Index: llvm/trunk/tools/llvm-pdbdump/YAMLOutputStyle.cpp =================================================================== --- llvm/trunk/tools/llvm-pdbdump/YAMLOutputStyle.cpp +++ llvm/trunk/tools/llvm-pdbdump/YAMLOutputStyle.cpp @@ -101,117 +101,6 @@ return Error::success(); } -namespace { -class C13YamlVisitor : public C13DebugFragmentVisitor { -public: - C13YamlVisitor(CodeViewYAML::SourceFileInfo &Info, PDBFile &F) - : C13DebugFragmentVisitor(F), Info(Info) {} - - Error handleFileChecksums() override { - for (const auto &C : *Checksums) { - CodeViewYAML::SourceFileChecksumEntry Entry; - if (auto Result = getNameFromStringTable(C.FileNameOffset)) - Entry.FileName = *Result; - else - return Result.takeError(); - - Entry.Kind = C.Kind; - Entry.ChecksumBytes.Bytes = C.Checksum; - Info.FileChecksums.push_back(Entry); - } - return Error::success(); - } - - Error handleLines() override { - for (const auto &LF : Lines) { - Info.LineFragments.emplace_back(); - auto &Fragment = Info.LineFragments.back(); - - Fragment.CodeSize = LF.header()->CodeSize; - Fragment.Flags = - static_cast(uint16_t(LF.header()->Flags)); - Fragment.RelocOffset = LF.header()->RelocOffset; - Fragment.RelocSegment = LF.header()->RelocSegment; - - for (const auto &L : LF) { - Fragment.Blocks.emplace_back(); - auto &Block = Fragment.Blocks.back(); - - if (auto Result = getNameFromChecksumsBuffer(L.NameIndex)) - Block.FileName = *Result; - else - return Result.takeError(); - - for (const auto &N : L.LineNumbers) { - CodeViewYAML::SourceLineEntry Line; - Line.Offset = N.Offset; - codeview::LineInfo LI(N.Flags); - Line.LineStart = LI.getStartLine(); - Line.EndDelta = LI.getLineDelta(); - Line.IsStatement = LI.isStatement(); - Block.Lines.push_back(Line); - } - - if (LF.hasColumnInfo()) { - for (const auto &C : L.Columns) { - CodeViewYAML::SourceColumnEntry Column; - Column.StartColumn = C.StartColumn; - Column.EndColumn = C.EndColumn; - Block.Columns.push_back(Column); - } - } - } - } - return Error::success(); - } - - Error handleInlineeLines() override { - for (const auto &ILF : InlineeLines) { - Info.Inlinees.emplace_back(); - auto &Inlinee = Info.Inlinees.back(); - - Inlinee.HasExtraFiles = ILF.hasExtraFiles(); - for (const auto &IL : ILF) { - Inlinee.Sites.emplace_back(); - auto &Site = Inlinee.Sites.back(); - if (auto Result = getNameFromChecksumsBuffer(IL.Header->FileID)) - Site.FileName = *Result; - else - return Result.takeError(); - - Site.Inlinee = IL.Header->Inlinee.getIndex(); - Site.SourceLineNum = IL.Header->SourceLineNum; - if (ILF.hasExtraFiles()) { - for (const auto &EF : IL.ExtraFiles) { - if (auto Result = getNameFromChecksumsBuffer(EF)) - Site.ExtraFiles.push_back(*Result); - else - return Result.takeError(); - } - } - } - } - return Error::success(); - } - -private: - CodeViewYAML::SourceFileInfo &Info; -}; -} - -Expected> -YAMLOutputStyle::getFileLineInfo(const pdb::ModuleDebugStreamRef &ModS) { - if (!ModS.hasLineInfo()) - return None; - - CodeViewYAML::SourceFileInfo Info; - C13YamlVisitor Visitor(Info, File); - if (auto EC = - codeview::visitDebugSubsections(ModS.linesAndChecksums(), Visitor)) - return std::move(EC); - - return Info; -} Error YAMLOutputStyle::dumpFileHeaders() { if (opts::pdb2yaml::NoFileHeaders) @@ -236,14 +125,17 @@ } Error YAMLOutputStyle::dumpStringTable() { - if (!opts::pdb2yaml::StringTable) + bool RequiresStringTable = opts::pdb2yaml::DbiModuleSourceFileInfo || + opts::pdb2yaml::DbiModuleSourceLineInfo; + bool RequestedStringTable = opts::pdb2yaml::StringTable; + if (!RequiresStringTable && !RequestedStringTable) return Error::success(); - Obj.StringTable.emplace(); auto ExpectedST = File.getStringTable(); if (!ExpectedST) return ExpectedST.takeError(); + Obj.StringTable.emplace(); const auto &ST = ExpectedST.get(); for (auto ID : ST.name_ids()) { auto S = ST.getStringForID(ID); @@ -343,11 +235,23 @@ if (auto EC = ModS.reload()) return EC; - if (opts::pdb2yaml::DbiModuleSourceLineInfo) { - auto ExpectedInfo = getFileLineInfo(ModS); - if (!ExpectedInfo) - return ExpectedInfo.takeError(); - DMI.FileLineInfo = *ExpectedInfo; + auto ExpectedST = File.getStringTable(); + if (!ExpectedST) + return ExpectedST.takeError(); + if (opts::pdb2yaml::DbiModuleSourceLineInfo && + ModS.hasDebugSubsections()) { + auto ExpectedChecksums = ModS.findChecksumsSubsection(); + if (!ExpectedChecksums) + return ExpectedChecksums.takeError(); + + for (const auto &SS : ModS.subsections()) { + auto Converted = + CodeViewYAML::YAMLDebugSubsection::fromCodeViewSubection( + ExpectedST->getStringTable(), *ExpectedChecksums, SS); + if (!Converted) + return Converted.takeError(); + DMI.Subsections.push_back(*Converted); + } } if (opts::pdb2yaml::DbiModuleSyms) { Index: llvm/trunk/tools/llvm-pdbdump/llvm-pdbdump.cpp =================================================================== --- llvm/trunk/tools/llvm-pdbdump/llvm-pdbdump.cpp +++ llvm/trunk/tools/llvm-pdbdump/llvm-pdbdump.cpp @@ -476,7 +476,6 @@ std::unique_ptr &Buffer = ErrorOrBuffer.get(); llvm::yaml::Input In(Buffer->getBuffer()); - In.setContext(&Allocator); pdb::yaml::PdbObject YamlObj(Allocator); In >> YamlObj; @@ -540,64 +539,11 @@ Symbol.toCodeViewSymbol(Allocator, CodeViewContainer::Pdb)); } } - if (MI.FileLineInfo.hasValue()) { - const auto &FLI = *MI.FileLineInfo; - // File Checksums must be emitted before line information, because line - // info records use offsets into the checksum buffer to reference a file's - // source file name. - auto Checksums = llvm::make_unique(Strings); - auto &ChecksumRef = *Checksums; - if (!FLI.FileChecksums.empty()) { - for (auto &FC : FLI.FileChecksums) - Checksums->addChecksum(FC.FileName, FC.Kind, FC.ChecksumBytes.Bytes); - } - ModiBuilder.setC13FileChecksums(std::move(Checksums)); - - for (const auto &Fragment : FLI.LineFragments) { - auto Lines = - llvm::make_unique(ChecksumRef, Strings); - Lines->setCodeSize(Fragment.CodeSize); - Lines->setRelocationAddress(Fragment.RelocSegment, - Fragment.RelocOffset); - Lines->setFlags(Fragment.Flags); - for (const auto &LC : Fragment.Blocks) { - Lines->createBlock(LC.FileName); - if (Lines->hasColumnInfo()) { - for (const auto &Item : zip(LC.Lines, LC.Columns)) { - auto &L = std::get<0>(Item); - auto &C = std::get<1>(Item); - uint32_t LE = L.LineStart + L.EndDelta; - Lines->addLineAndColumnInfo( - L.Offset, LineInfo(L.LineStart, LE, L.IsStatement), - C.StartColumn, C.EndColumn); - } - } else { - for (const auto &L : LC.Lines) { - uint32_t LE = L.LineStart + L.EndDelta; - Lines->addLineInfo(L.Offset, - LineInfo(L.LineStart, LE, L.IsStatement)); - } - } - } - ModiBuilder.addC13Fragment(std::move(Lines)); - } - - for (const auto &Inlinee : FLI.Inlinees) { - auto Inlinees = llvm::make_unique( - ChecksumRef, Inlinee.HasExtraFiles); - for (const auto &Site : Inlinee.Sites) { - Inlinees->addInlineSite(TypeIndex(Site.Inlinee), Site.FileName, - Site.SourceLineNum); - if (!Inlinee.HasExtraFiles) - continue; - - for (auto EF : Site.ExtraFiles) { - Inlinees->addExtraFile(EF); - } - } - ModiBuilder.addC13Fragment(std::move(Inlinees)); - } + auto CodeViewSubsections = + ExitOnErr(CodeViewYAML::convertSubsectionList(MI.Subsections, Strings)); + for (auto &SS : CodeViewSubsections) { + ModiBuilder.addDebugSubsection(std::move(SS)); } }