diff options
24 files changed, 507 insertions, 67 deletions
diff --git a/llvm/include/llvm/DebugInfo/CodeView/Line.h b/llvm/include/llvm/DebugInfo/CodeView/Line.h index cb29aa2489e..ac229c33751 100644 --- a/llvm/include/llvm/DebugInfo/CodeView/Line.h +++ b/llvm/include/llvm/DebugInfo/CodeView/Line.h @@ -127,20 +127,6 @@ public: bool isNeverStepInto() const { return LineInf.isNeverStepInto(); } }; -enum class InlineeLinesSignature : uint32_t { - Normal, // CV_INLINEE_SOURCE_LINE_SIGNATURE - ExtraFiles // CV_INLINEE_SOURCE_LINE_SIGNATURE_EX -}; - -struct InlineeSourceLine { - TypeIndex Inlinee; // ID of the function that was inlined. - ulittle32_t FileID; // Offset into FileChecksums subsection. - ulittle32_t SourceLineNum; // First line of inlined code. - // If extra files present: - // ulittle32_t ExtraFileCount; - // ulittle32_t Files[]; -}; - } // namespace codeview } // namespace llvm diff --git a/llvm/include/llvm/DebugInfo/CodeView/ModuleDebugFragmentVisitor.h b/llvm/include/llvm/DebugInfo/CodeView/ModuleDebugFragmentVisitor.h index 90da3e03a15..1f55d202420 100644 --- a/llvm/include/llvm/DebugInfo/CodeView/ModuleDebugFragmentVisitor.h +++ b/llvm/include/llvm/DebugInfo/CodeView/ModuleDebugFragmentVisitor.h @@ -39,6 +39,10 @@ public: return Error::success(); } + virtual Error visitInlineeLines(ModuleDebugInlineeLineFragmentRef &Inlinees) { + return Error::success(); + } + virtual Error finished() { return Error::success(); } }; diff --git a/llvm/include/llvm/DebugInfo/CodeView/ModuleDebugInlineeLinesFragment.h b/llvm/include/llvm/DebugInfo/CodeView/ModuleDebugInlineeLinesFragment.h new file mode 100644 index 00000000000..177367c111c --- /dev/null +++ b/llvm/include/llvm/DebugInfo/CodeView/ModuleDebugInlineeLinesFragment.h @@ -0,0 +1,103 @@ +//===- ModuleDebugInlineeLinesFragment.h ------------------------*- 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_MODULEDEBUGINLINEELINESFRAGMENT_H +#define LLVM_DEBUGINFO_CODEVIEW_MODULEDEBUGINLINEELINESFRAGMENT_H + +#include "llvm/DebugInfo/CodeView/Line.h" +#include "llvm/DebugInfo/CodeView/ModuleDebugFragment.h" +#include "llvm/Support/BinaryStreamArray.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/Error.h" + +namespace llvm { +namespace codeview { + +class ModuleDebugInlineeLineFragmentRef; + +enum class InlineeLinesSignature : uint32_t { + Normal, // CV_INLINEE_SOURCE_LINE_SIGNATURE + ExtraFiles // CV_INLINEE_SOURCE_LINE_SIGNATURE_EX +}; + +struct InlineeSourceLineHeader { + TypeIndex Inlinee; // ID of the function that was inlined. + support::ulittle32_t FileID; // Offset into FileChecksums subsection. + support::ulittle32_t SourceLineNum; // First line of inlined code. + // If extra files present: + // ulittle32_t ExtraFileCount; + // ulittle32_t Files[]; +}; + +struct InlineeSourceLine { + const InlineeSourceLineHeader *Header; + FixedStreamArray<support::ulittle32_t> ExtraFiles; +}; +} + +template <> struct VarStreamArrayExtractor<codeview::InlineeSourceLine> { + typedef codeview::ModuleDebugInlineeLineFragmentRef ContextType; + + static Error extract(BinaryStreamRef Stream, uint32_t &Len, + codeview::InlineeSourceLine &Item, + ContextType *Fragment); +}; + +namespace codeview { +class ModuleDebugInlineeLineFragmentRef final : public ModuleDebugFragmentRef { + typedef VarStreamArray<InlineeSourceLine> LinesArray; + typedef LinesArray::Iterator Iterator; + +public: + ModuleDebugInlineeLineFragmentRef(); + + static bool classof(const ModuleDebugFragmentRef *S) { + return S->kind() == ModuleDebugFragmentKind::InlineeLines; + } + + Error initialize(BinaryStreamReader Reader); + bool hasExtraFiles() const; + + Iterator begin() const { return Lines.begin(); } + Iterator end() const { return Lines.end(); } + +private: + InlineeLinesSignature Signature; + VarStreamArray<InlineeSourceLine> Lines; +}; + +class ModuleDebugInlineeLineFragment final : public ModuleDebugFragment { +public: + explicit ModuleDebugInlineeLineFragment(bool HasExtraFiles); + + static bool classof(const ModuleDebugFragment *S) { + return S->kind() == ModuleDebugFragmentKind::InlineeLines; + } + + Error commit(BinaryStreamWriter &Writer) override; + uint32_t calculateSerializedLength() override; + + void addInlineSite(TypeIndex FuncId, uint32_t FileOffset, + uint32_t SourceLine); + void addExtraFile(uint32_t FileOffset); + +private: + bool HasExtraFiles = false; + uint32_t ExtraFileCount = 0; + + struct Entry { + std::vector<support::ulittle32_t> ExtraFiles; + InlineeSourceLineHeader Header; + }; + std::vector<Entry> Entries; +}; +} +} + +#endif diff --git a/llvm/include/llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h b/llvm/include/llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h index 582e0485715..8cc5db981f5 100644 --- a/llvm/include/llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h +++ b/llvm/include/llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h @@ -12,6 +12,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.h" +#include "llvm/DebugInfo/CodeView/ModuleDebugInlineeLinesFragment.h" #include "llvm/DebugInfo/CodeView/ModuleDebugLineFragment.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h" #include "llvm/DebugInfo/PDB/Native/RawTypes.h" @@ -48,8 +49,9 @@ public: void setObjFileName(StringRef Name); void addSymbol(codeview::CVSymbol Symbol); - void - addC13LineFragment(std::unique_ptr<codeview::ModuleDebugLineFragment> Lines); + void addC13Fragment(std::unique_ptr<codeview::ModuleDebugLineFragment> Lines); + void addC13Fragment( + std::unique_ptr<codeview::ModuleDebugInlineeLineFragment> Inlinees); void setC13FileChecksums( std::unique_ptr<codeview::ModuleDebugFileChecksumFragment> Checksums); @@ -80,8 +82,11 @@ private: std::string ObjFileName; std::vector<std::string> SourceFiles; std::vector<codeview::CVSymbol> Symbols; - std::vector<std::unique_ptr<codeview::ModuleDebugLineFragment>> LineInfo; + std::unique_ptr<codeview::ModuleDebugFileChecksumFragment> ChecksumInfo; + std::vector<std::unique_ptr<codeview::ModuleDebugLineFragment>> LineInfo; + std::vector<std::unique_ptr<codeview::ModuleDebugInlineeLineFragment>> + Inlinees; std::vector<std::unique_ptr<codeview::ModuleDebugFragmentRecordBuilder>> C13Builders; diff --git a/llvm/include/llvm/Support/BinaryStreamWriter.h b/llvm/include/llvm/Support/BinaryStreamWriter.h index 64f26b24543..6734a797ccc 100644 --- a/llvm/include/llvm/Support/BinaryStreamWriter.h +++ b/llvm/include/llvm/Support/BinaryStreamWriter.h @@ -30,6 +30,8 @@ namespace llvm { /// although no methods are overridable. class BinaryStreamWriter { public: + // FIXME: We should be able to slice and drop_front etc on Writers / Readers. + BinaryStreamWriter() = default; explicit BinaryStreamWriter(WritableBinaryStreamRef Stream); virtual ~BinaryStreamWriter() {} diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp index 4bfe3bf2b63..786b11618d7 100644 --- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -17,6 +17,7 @@ #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/CodeView/Line.h" +#include "llvm/DebugInfo/CodeView/ModuleDebugInlineeLinesFragment.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h" #include "llvm/DebugInfo/CodeView/TypeDatabase.h" #include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h" diff --git a/llvm/lib/DebugInfo/CodeView/CMakeLists.txt b/llvm/lib/DebugInfo/CodeView/CMakeLists.txt index 7655f6c651e..421f22ca5d8 100644 --- a/llvm/lib/DebugInfo/CodeView/CMakeLists.txt +++ b/llvm/lib/DebugInfo/CodeView/CMakeLists.txt @@ -11,6 +11,7 @@ add_llvm_library(LLVMDebugInfoCodeView ModuleDebugFragment.cpp ModuleDebugFragmentRecord.cpp ModuleDebugFragmentVisitor.cpp + ModuleDebugInlineeLinesFragment.cpp ModuleDebugLineFragment.cpp ModuleDebugUnknownFragment.cpp RecordSerialization.cpp diff --git a/llvm/lib/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.cpp b/llvm/lib/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.cpp index 79e5b9d690d..c349e7ecce9 100644 --- a/llvm/lib/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.cpp +++ b/llvm/lib/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.cpp @@ -68,7 +68,10 @@ void ModuleDebugFileChecksumFragment::addChecksum(uint32_t StringTableOffset, // This maps the offset of this string in the string table to the offset // of this checksum entry in the checksum buffer. OffsetMap[StringTableOffset] = SerializedSize; - SerializedSize += sizeof(FileChecksumEntryHeader) + Bytes.size(); + assert(SerializedSize % 4 == 0); + + uint32_t Len = alignTo(sizeof(FileChecksumEntryHeader) + Bytes.size(), 4); + SerializedSize += Len; } uint32_t ModuleDebugFileChecksumFragment::calculateSerializedLength() { @@ -85,6 +88,8 @@ Error ModuleDebugFileChecksumFragment::commit(BinaryStreamWriter &Writer) { return EC; if (auto EC = Writer.writeArray(makeArrayRef(FC.Checksum))) return EC; + if (auto EC = Writer.padToAlignment(4)) + return EC; } return Error::success(); } diff --git a/llvm/lib/DebugInfo/CodeView/ModuleDebugFragmentRecord.cpp b/llvm/lib/DebugInfo/CodeView/ModuleDebugFragmentRecord.cpp index 263b632da3f..b2543de7806 100644 --- a/llvm/lib/DebugInfo/CodeView/ModuleDebugFragmentRecord.cpp +++ b/llvm/lib/DebugInfo/CodeView/ModuleDebugFragmentRecord.cpp @@ -34,6 +34,7 @@ Error ModuleDebugFragmentRecord::initialize(BinaryStreamRef Stream, switch (Kind) { case ModuleDebugFragmentKind::FileChecksums: case ModuleDebugFragmentKind::Lines: + case ModuleDebugFragmentKind::InlineeLines: break; default: llvm_unreachable("Unexpected debug fragment kind!"); diff --git a/llvm/lib/DebugInfo/CodeView/ModuleDebugFragmentVisitor.cpp b/llvm/lib/DebugInfo/CodeView/ModuleDebugFragmentVisitor.cpp index b7a86ee6699..dc591f3990e 100644 --- a/llvm/lib/DebugInfo/CodeView/ModuleDebugFragmentVisitor.cpp +++ b/llvm/lib/DebugInfo/CodeView/ModuleDebugFragmentVisitor.cpp @@ -11,6 +11,7 @@ #include "llvm/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.h" #include "llvm/DebugInfo/CodeView/ModuleDebugFragmentRecord.h" +#include "llvm/DebugInfo/CodeView/ModuleDebugInlineeLinesFragment.h" #include "llvm/DebugInfo/CodeView/ModuleDebugLineFragment.h" #include "llvm/DebugInfo/CodeView/ModuleDebugUnknownFragment.h" #include "llvm/Support/BinaryStreamReader.h" @@ -37,6 +38,12 @@ Error llvm::codeview::visitModuleDebugFragment( return V.visitFileChecksums(Fragment); } + case ModuleDebugFragmentKind::InlineeLines: { + ModuleDebugInlineeLineFragmentRef Fragment; + if (auto EC = Fragment.initialize(Reader)) + return EC; + return V.visitInlineeLines(Fragment); + } default: { ModuleDebugUnknownFragmentRef Fragment(R.kind(), R.getRecordData()); return V.visitUnknown(Fragment); diff --git a/llvm/lib/DebugInfo/CodeView/ModuleDebugInlineeLinesFragment.cpp b/llvm/lib/DebugInfo/CodeView/ModuleDebugInlineeLinesFragment.cpp new file mode 100644 index 00000000000..483f7cb5c5a --- /dev/null +++ b/llvm/lib/DebugInfo/CodeView/ModuleDebugInlineeLinesFragment.cpp @@ -0,0 +1,116 @@ +//===- ModuleDebugInlineeLineFragment.cpp ------------------------*- C++-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/ModuleDebugInlineeLinesFragment.h" + +#include "llvm/DebugInfo/CodeView/CodeViewError.h" +#include "llvm/DebugInfo/CodeView/ModuleDebugFragmentRecord.h" + +using namespace llvm; +using namespace llvm::codeview; + +Error VarStreamArrayExtractor<InlineeSourceLine>::extract( + BinaryStreamRef Stream, uint32_t &Len, InlineeSourceLine &Item, + ContextType *Fragment) { + BinaryStreamReader Reader(Stream); + + if (auto EC = Reader.readObject(Item.Header)) + return EC; + + if (Fragment->hasExtraFiles()) { + uint32_t ExtraFileCount; + if (auto EC = Reader.readInteger(ExtraFileCount)) + return EC; + if (auto EC = Reader.readArray(Item.ExtraFiles, ExtraFileCount)) + return EC; + } + + Len = Reader.getOffset(); + return Error::success(); +} + +ModuleDebugInlineeLineFragmentRef::ModuleDebugInlineeLineFragmentRef() + : ModuleDebugFragmentRef(ModuleDebugFragmentKind::InlineeLines) {} + +Error ModuleDebugInlineeLineFragmentRef::initialize(BinaryStreamReader Reader) { + if (auto EC = Reader.readEnum(Signature)) + return EC; + + if (auto EC = Reader.readArray(Lines, Reader.bytesRemaining(), this)) + return EC; + + assert(Reader.bytesRemaining() == 0); + return Error::success(); +} + +bool ModuleDebugInlineeLineFragmentRef::hasExtraFiles() const { + return Signature == InlineeLinesSignature::ExtraFiles; +} + +ModuleDebugInlineeLineFragment::ModuleDebugInlineeLineFragment( + bool HasExtraFiles) + : ModuleDebugFragment(ModuleDebugFragmentKind::InlineeLines), + HasExtraFiles(HasExtraFiles) {} + +uint32_t ModuleDebugInlineeLineFragment::calculateSerializedLength() { + // 4 bytes for the signature + uint32_t Size = sizeof(InlineeLinesSignature); + + // one header for each entry. + Size += Entries.size() * sizeof(InlineeSourceLineHeader); + if (HasExtraFiles) { + // If extra files are enabled, one count for each entry. + Size += Entries.size() * sizeof(uint32_t); + + // And one file id for each file. + Size += ExtraFileCount * sizeof(uint32_t); + } + assert(Size % 4 == 0); + return Size; +} + +Error ModuleDebugInlineeLineFragment::commit(BinaryStreamWriter &Writer) { + InlineeLinesSignature Sig = InlineeLinesSignature::Normal; + if (HasExtraFiles) + Sig = InlineeLinesSignature::ExtraFiles; + + if (auto EC = Writer.writeEnum(Sig)) + return EC; + + for (const auto &E : Entries) { + if (auto EC = Writer.writeObject(E.Header)) + return EC; + + if (!HasExtraFiles) + continue; + + if (auto EC = Writer.writeInteger<uint32_t>(E.ExtraFiles.size())) + return EC; + if (auto EC = Writer.writeArray(makeArrayRef(E.ExtraFiles))) + return EC; + } + + return Error::success(); +} + +void ModuleDebugInlineeLineFragment::addExtraFile(uint32_t FileOffset) { + auto &Entry = Entries.back(); + Entry.ExtraFiles.push_back(ulittle32_t(FileOffset)); + ++ExtraFileCount; +} + +void ModuleDebugInlineeLineFragment::addInlineSite(TypeIndex FuncId, + uint32_t FileOffset, + uint32_t SourceLine) { + Entries.emplace_back(); + auto &Entry = Entries.back(); + Entry.Header.FileID = FileOffset; + Entry.Header.SourceLineNum = SourceLine; + Entry.Header.Inlinee = FuncId; +} diff --git a/llvm/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp b/llvm/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp index 41cb23a188f..f994b4538ef 100644 --- a/llvm/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp +++ b/llvm/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp @@ -161,7 +161,7 @@ Error DbiModuleDescriptorBuilder::commit(BinaryStreamWriter &ModiWriter, return Error::success(); } -void DbiModuleDescriptorBuilder::addC13LineFragment( +void DbiModuleDescriptorBuilder::addC13Fragment( std::unique_ptr<ModuleDebugLineFragment> Lines) { ModuleDebugLineFragment &Frag = *Lines; @@ -175,6 +175,20 @@ void DbiModuleDescriptorBuilder::addC13LineFragment( llvm::make_unique<ModuleDebugFragmentRecordBuilder>(Frag.kind(), Frag)); } +void DbiModuleDescriptorBuilder::addC13Fragment( + std::unique_ptr<codeview::ModuleDebugInlineeLineFragment> Inlinees) { + ModuleDebugInlineeLineFragment &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)); + C13Builders.push_back( + llvm::make_unique<ModuleDebugFragmentRecordBuilder>(Frag.kind(), Frag)); +} + void DbiModuleDescriptorBuilder::setC13FileChecksums( std::unique_ptr<ModuleDebugFileChecksumFragment> Checksums) { assert(!ChecksumInfo && "Can't have more than one checksum info!"); diff --git a/llvm/test/DebugInfo/PDB/Inputs/simple-line-info.yaml b/llvm/test/DebugInfo/PDB/Inputs/simple-line-info.yaml index 71ce0545d5c..66030020f8f 100644 --- a/llvm/test/DebugInfo/PDB/Inputs/simple-line-info.yaml +++ b/llvm/test/DebugInfo/PDB/Inputs/simple-line-info.yaml @@ -1,8 +1,4 @@ --- -StringTable: - - 'junk_a' - - 'd:\src\llvm\test\debuginfo\pdb\inputs\empty.cpp' - - 'junk_b' DbiStream: Modules: - Module: 'd:\src\llvm\test\DebugInfo\PDB\Inputs\empty.obj' @@ -14,6 +10,9 @@ DbiStream: - 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: [ ] @@ -35,4 +34,10 @@ DbiStream: IsStatement: true EndDelta: 0 Columns: + InlineeLines: + - HasExtraFiles: false + Sites: + - FileName: 'f:\dd\externalapis\windows\10\sdk\inc\winerror.h' + LineNum: 26950 + Inlinee: 22767 ... diff --git a/llvm/test/DebugInfo/PDB/pdbdump-yaml-lineinfo-write.test b/llvm/test/DebugInfo/PDB/pdbdump-yaml-lineinfo-write.test index 8e1fc01290c..1d63c85352a 100644 --- a/llvm/test/DebugInfo/PDB/pdbdump-yaml-lineinfo-write.test +++ b/llvm/test/DebugInfo/PDB/pdbdump-yaml-lineinfo-write.test @@ -18,6 +18,13 @@ LINES-NEXT: Checksum ( LINES-NEXT: 0000: A0A5BD0D 3ECD93FC 29D19DE8 26FBF4BC |....>...)...&...| LINES-NEXT: ) LINES-NEXT: } +LINES-NEXT: Checksum { +LINES-NEXT: FileName: f:\dd\externalapis\windows\10\sdk\inc\winerror.h +LINES-NEXT: Kind: MD5 (0x1) +LINES-NEXT: Checksum ( +LINES-NEXT: 0000: 1154D69F 5B265019 6E1FC34F 4134E56B |.T..[&P.n..OA4.k| +LINES-NEXT: ) +LINES-NEXT: } LINES-NEXT: } LINES-NEXT: Lines { LINES-NEXT: Block { @@ -48,5 +55,17 @@ LINES-NEXT: } LINES-NEXT: } LINES-NEXT: } LINES-NEXT: } +LINES-NEXT: InlineeLines { +LINES-NEXT: HasExtraFiles: No +LINES-NEXT: Lines [ +LINES-NEXT: Inlinee { +LINES-NEXT: FileName: f:\dd\externalapis\windows\10\sdk\inc\winerror.h +LINES-NEXT: Function { +LINES-NEXT: Index: 0x58ef (unknown function) +LINES-NEXT: } +LINES-NEXT: SourceLine: 26950 +LINES-NEXT: } +LINES-NEXT: ] +LINES-NEXT: } LINES-NEXT: ] LINES-NEXT: } diff --git a/llvm/tools/llvm-pdbdump/C13DebugFragmentVisitor.cpp b/llvm/tools/llvm-pdbdump/C13DebugFragmentVisitor.cpp index 940b38c4a8c..7c680ebb94c 100644 --- a/llvm/tools/llvm-pdbdump/C13DebugFragmentVisitor.cpp +++ b/llvm/tools/llvm-pdbdump/C13DebugFragmentVisitor.cpp @@ -10,6 +10,7 @@ #include "C13DebugFragmentVisitor.h" #include "llvm/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.h" +#include "llvm/DebugInfo/CodeView/ModuleDebugInlineeLinesFragment.h" #include "llvm/DebugInfo/CodeView/ModuleDebugLineFragment.h" #include "llvm/DebugInfo/PDB/Native/PDBFile.h" #include "llvm/DebugInfo/PDB/Native/RawError.h" @@ -41,6 +42,12 @@ Error C13DebugFragmentVisitor::visitLines( return Error::success(); } +Error C13DebugFragmentVisitor::visitInlineeLines( + codeview::ModuleDebugInlineeLineFragmentRef &Lines) { + this->InlineeLines.push_back(Lines); + return Error::success(); +} + Error C13DebugFragmentVisitor::finished() { if (!Checksums.hasValue()) { assert(Lines.empty()); @@ -52,6 +59,9 @@ Error C13DebugFragmentVisitor::finished() { if (auto EC = handleLines()) return EC; + if (auto EC = handleInlineeLines()) + return EC; + return Error::success(); } diff --git a/llvm/tools/llvm-pdbdump/C13DebugFragmentVisitor.h b/llvm/tools/llvm-pdbdump/C13DebugFragmentVisitor.h index f0a536c6adc..1054b0c9f6e 100644 --- a/llvm/tools/llvm-pdbdump/C13DebugFragmentVisitor.h +++ b/llvm/tools/llvm-pdbdump/C13DebugFragmentVisitor.h @@ -35,16 +35,21 @@ public: Error visitLines(codeview::ModuleDebugLineFragmentRef &Lines) final; + Error + visitInlineeLines(codeview::ModuleDebugInlineeLineFragmentRef &Lines) final; + Error finished() final; protected: virtual Error handleFileChecksums() { return Error::success(); } virtual Error handleLines() { return Error::success(); } + virtual Error handleInlineeLines() { return Error::success(); } Expected<StringRef> getNameFromStringTable(uint32_t Offset); Expected<StringRef> getNameFromChecksumsBuffer(uint32_t Offset); Optional<codeview::ModuleDebugFileChecksumFragmentRef> Checksums; + std::vector<codeview::ModuleDebugInlineeLineFragmentRef> InlineeLines; std::vector<codeview::ModuleDebugLineFragmentRef> Lines; PDBFile &F; diff --git a/llvm/tools/llvm-pdbdump/CompactTypeDumpVisitor.cpp b/llvm/tools/llvm-pdbdump/CompactTypeDumpVisitor.cpp index 1fc8dd5d51f..5ad0bfad26c 100644 --- a/llvm/tools/llvm-pdbdump/CompactTypeDumpVisitor.cpp +++ b/llvm/tools/llvm-pdbdump/CompactTypeDumpVisitor.cpp @@ -31,14 +31,15 @@ static StringRef getLeafName(TypeLeafKind K) { CompactTypeDumpVisitor::CompactTypeDumpVisitor(TypeDatabase &TypeDB, ScopedPrinter *W) - : W(W), TI(TypeIndex::None()), Offset(0), TypeDB(TypeDB) {} + : CompactTypeDumpVisitor(TypeDB, TypeIndex(TypeIndex::FirstNonSimpleIndex), + W) {} -Error CompactTypeDumpVisitor::visitTypeBegin(CVType &Record) { - if (TI == TypeIndex::None()) - TI.setIndex(TypeIndex::FirstNonSimpleIndex); - else - TI.setIndex(TI.getIndex() + 1); +CompactTypeDumpVisitor::CompactTypeDumpVisitor(TypeDatabase &TypeDB, + TypeIndex FirstTI, + ScopedPrinter *W) + : W(W), TI(FirstTI), Offset(0), TypeDB(TypeDB) {} +Error CompactTypeDumpVisitor::visitTypeBegin(CVType &Record) { return Error::success(); } @@ -52,6 +53,7 @@ Error CompactTypeDumpVisitor::visitTypeEnd(CVType &Record) { .str()); Offset += Record.length(); + TI.setIndex(TI.getIndex() + 1); return Error::success(); } diff --git a/llvm/tools/llvm-pdbdump/CompactTypeDumpVisitor.h b/llvm/tools/llvm-pdbdump/CompactTypeDumpVisitor.h index 180eea7b8d6..76fafc93e03 100644 --- a/llvm/tools/llvm-pdbdump/CompactTypeDumpVisitor.h +++ b/llvm/tools/llvm-pdbdump/CompactTypeDumpVisitor.h @@ -27,6 +27,8 @@ namespace pdb { class CompactTypeDumpVisitor : public codeview::TypeVisitorCallbacks { public: CompactTypeDumpVisitor(codeview::TypeDatabase &TypeDB, ScopedPrinter *W); + CompactTypeDumpVisitor(codeview::TypeDatabase &TypeDB, + codeview::TypeIndex FirstTI, ScopedPrinter *W); /// Paired begin/end actions for all types. Receives all record data, /// including the fixed-length record prefix. diff --git a/llvm/tools/llvm-pdbdump/LLVMOutputStyle.cpp b/llvm/tools/llvm-pdbdump/LLVMOutputStyle.cpp index 833cd810468..f3e28e0b08f 100644 --- a/llvm/tools/llvm-pdbdump/LLVMOutputStyle.cpp +++ b/llvm/tools/llvm-pdbdump/LLVMOutputStyle.cpp @@ -20,6 +20,7 @@ #include "llvm/DebugInfo/CodeView/Line.h" #include "llvm/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.h" #include "llvm/DebugInfo/CodeView/ModuleDebugFragmentVisitor.h" +#include "llvm/DebugInfo/CodeView/ModuleDebugInlineeLinesFragment.h" #include "llvm/DebugInfo/CodeView/ModuleDebugLineFragment.h" #include "llvm/DebugInfo/CodeView/ModuleDebugUnknownFragment.h" #include "llvm/DebugInfo/CodeView/SymbolDumper.h" @@ -82,10 +83,13 @@ struct PageStats { class C13RawVisitor : public C13DebugFragmentVisitor { public: - C13RawVisitor(ScopedPrinter &P, PDBFile &F) - : C13DebugFragmentVisitor(F), P(P) {} + C13RawVisitor(ScopedPrinter &P, PDBFile &F, TypeDatabase &IPI) + : C13DebugFragmentVisitor(F), P(P), IPI(IPI) {} Error handleLines() override { + if (Lines.empty()) + return Error::success(); + DictScope DD(P, "Lines"); for (const auto &Fragment : Lines) { @@ -126,6 +130,9 @@ public: } Error handleFileChecksums() override { + if (!Checksums.hasValue()) + return Error::success(); + DictScope DD(P, "FileChecksums"); for (const auto &CS : *Checksums) { DictScope DDD(P, "Checksum"); @@ -139,7 +146,50 @@ public: return Error::success(); } + Error handleInlineeLines() override { + if (InlineeLines.empty()) + 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; + + if (auto EC = dumpTypeRecord("Function", IPI, 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; + } + } + } + } + return Error::success(); + } + private: + Error dumpTypeRecord(StringRef Label, TypeDatabase &DB, TypeIndex Index) { + CompactTypeDumpVisitor CTDV(DB, Index, &P); + CVTypeVisitor Visitor(CTDV); + DictScope D(P, Label); + if (DB.containsTypeIndex(Index)) { + CVType &Type = DB.getTypeRecord(Index); + if (auto EC = Visitor.visitTypeRecord(Type)) + return EC; + } else { + P.printString( + llvm::formatv("Index: {0:x} (unknown function)", Index.getIndex()) + .str()); + } + return Error::success(); + } Error printFileName(StringRef Label, uint32_t Offset) { if (auto Result = getNameFromChecksumsBuffer(Offset)) { P.printString(Label, *Result); @@ -149,6 +199,7 @@ private: } ScopedPrinter &P; + TypeDatabase &IPI; }; } @@ -618,6 +669,7 @@ Error LLVMOutputStyle::dumpTpiStream(uint32_t StreamIdx) { if (auto EC = Visitor.visitTypeRecord(Type)) return EC; + T.setIndex(T.getIndex() + 1); } if (HadError) return make_error<RawError>(raw_error_code::corrupt_file, @@ -750,7 +802,7 @@ Error LLVMOutputStyle::dumpDbiStream() { if (opts::raw::DumpLineInfo) { ListScope SS(P, "LineInfo"); - C13RawVisitor V(P, File); + C13RawVisitor V(P, File, ItemDB); if (auto EC = codeview::visitModuleDebugFragments( ModS.linesAndChecksums(), V)) return EC; diff --git a/llvm/tools/llvm-pdbdump/PdbYaml.cpp b/llvm/tools/llvm-pdbdump/PdbYaml.cpp index 645f2dc607d..d6ba7d64545 100644 --- a/llvm/tools/llvm-pdbdump/PdbYaml.cpp +++ b/llvm/tools/llvm-pdbdump/PdbYaml.cpp @@ -41,6 +41,8 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::PdbSourceLineEntry) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::PdbSourceColumnEntry) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::PdbSourceLineBlock) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::PdbSourceLineInfo) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::PdbInlineeSite) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::PdbInlineeInfo) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::PdbSymbolRecord) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::PdbTpiRecord) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::StreamBlockList) @@ -336,6 +338,7 @@ void MappingContextTraits<pdb::yaml::PdbSourceLineInfo, mapping(IO &IO, PdbSourceLineInfo &Obj, pdb::yaml::SerializationContext &Context) { IO.mapRequired("CodeSize", Obj.CodeSize); + IO.mapRequired("Flags", Obj.Flags); IO.mapRequired("RelocOffset", Obj.RelocOffset); IO.mapRequired("RelocSegment", Obj.RelocSegment); @@ -348,6 +351,21 @@ void MappingContextTraits<pdb::yaml::PdbSourceFileInfo, pdb::yaml::SerializationContext &Context) { IO.mapOptionalWithContext("Checksums", Obj.FileChecksums, Context); IO.mapOptionalWithContext("Lines", Obj.LineFragments, Context); + IO.mapOptionalWithContext("InlineeLines", Obj.Inlinees, Context); +} + +void MappingContextTraits<PdbInlineeSite, SerializationContext>::mapping( + IO &IO, PdbInlineeSite &Obj, SerializationContext &Context) { + IO.mapRequired("FileName", Obj.FileName); + IO.mapRequired("LineNum", Obj.SourceLineNum); + IO.mapRequired("Inlinee", Obj.Inlinee); + IO.mapOptional("ExtraFiles", Obj.ExtraFiles); +} + +void MappingContextTraits<PdbInlineeInfo, SerializationContext>::mapping( + IO &IO, PdbInlineeInfo &Obj, SerializationContext &Context) { + IO.mapRequired("HasExtraFiles", Obj.HasExtraFiles); + IO.mapRequired("Sites", Obj.Sites, Context); } void MappingContextTraits<PdbTpiRecord, pdb::yaml::SerializationContext>:: diff --git a/llvm/tools/llvm-pdbdump/PdbYaml.h b/llvm/tools/llvm-pdbdump/PdbYaml.h index a998eafbb05..423845caeb3 100644 --- a/llvm/tools/llvm-pdbdump/PdbYaml.h +++ b/llvm/tools/llvm-pdbdump/PdbYaml.h @@ -102,9 +102,22 @@ struct PdbSourceLineInfo { std::vector<PdbSourceLineBlock> Blocks; }; +struct PdbInlineeSite { + codeview::TypeIndex Inlinee; + StringRef FileName; + uint32_t SourceLineNum; + std::vector<StringRef> ExtraFiles; +}; + +struct PdbInlineeInfo { + bool HasExtraFiles; + std::vector<PdbInlineeSite> Sites; +}; + struct PdbSourceFileInfo { std::vector<PdbSourceFileChecksumEntry> FileChecksums; std::vector<PdbSourceLineInfo> LineFragments; + std::vector<PdbInlineeInfo> Inlinees; }; struct PdbDbiModuleInfo { @@ -259,6 +272,20 @@ struct MappingContextTraits<pdb::yaml::PdbSourceFileInfo, }; template <> +struct MappingContextTraits<pdb::yaml::PdbInlineeInfo, + pdb::yaml::SerializationContext> { + static void mapping(IO &IO, pdb::yaml::PdbInlineeInfo &Obj, + pdb::yaml::SerializationContext &Context); +}; + +template <> +struct MappingContextTraits<pdb::yaml::PdbInlineeSite, + pdb::yaml::SerializationContext> { + static void mapping(IO &IO, pdb::yaml::PdbInlineeSite &Obj, + pdb::yaml::SerializationContext &Context); +}; + +template <> struct MappingContextTraits<pdb::yaml::PdbTpiRecord, pdb::yaml::SerializationContext> { static void mapping(IO &IO, pdb::yaml::PdbTpiRecord &Obj, diff --git a/llvm/tools/llvm-pdbdump/YAMLOutputStyle.cpp b/llvm/tools/llvm-pdbdump/YAMLOutputStyle.cpp index 18596a68a3c..807d7f8b82e 100644 --- a/llvm/tools/llvm-pdbdump/YAMLOutputStyle.cpp +++ b/llvm/tools/llvm-pdbdump/YAMLOutputStyle.cpp @@ -17,6 +17,7 @@ #include "llvm/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.h" #include "llvm/DebugInfo/CodeView/ModuleDebugFragment.h" #include "llvm/DebugInfo/CodeView/ModuleDebugFragmentVisitor.h" +#include "llvm/DebugInfo/CodeView/ModuleDebugInlineeLinesFragment.h" #include "llvm/DebugInfo/CodeView/ModuleDebugLineFragment.h" #include "llvm/DebugInfo/CodeView/ModuleDebugUnknownFragment.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" @@ -150,6 +151,35 @@ public: 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; + 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: llvm::pdb::yaml::PdbSourceFileInfo &Info; diff --git a/llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp b/llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp index 0bbc49eadbb..642e169613b 100644 --- a/llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp +++ b/llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp @@ -31,6 +31,9 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Config/config.h" +#include "llvm/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.h" +#include "llvm/DebugInfo/CodeView/ModuleDebugInlineeLinesFragment.h" +#include "llvm/DebugInfo/CodeView/ModuleDebugLineFragment.h" #include "llvm/DebugInfo/MSF/MSFBuilder.h" #include "llvm/DebugInfo/PDB/GenericError.h" #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" @@ -421,6 +424,21 @@ cl::list<std::string> InputFilename(cl::Positional, static ExitOnError ExitOnErr; +static uint32_t +getFileChecksumOffset(StringRef FileName, + ModuleDebugFileChecksumFragment &Checksums, + StringTableBuilder &Strings) { + // The offset in the line info record is the offset of the checksum + // entry for the corresponding file. That entry then contains an + // offset into the global string table of the file name. So to + // compute the proper offset to write into the line info record, we + // must first get its offset in the global string table, then ask the + // checksum builder to find the offset in its serialized buffer that + // it mapped that filename string table offset to. + uint32_t StringOffset = Strings.insert(FileName); + return Checksums.mapChecksumOffset(StringOffset); +} + static void yamlToPdb(StringRef Path) { BumpPtrAllocator Allocator; ErrorOr<std::unique_ptr<MemoryBuffer>> ErrorOrBuffer = @@ -503,12 +521,19 @@ static void yamlToPdb(StringRef Path) { if (!FLI.FileChecksums.empty()) { auto &Strings = Builder.getStringTableBuilder(); for (auto &FC : FLI.FileChecksums) { - uint32_t STOffset = Strings.getStringIndex(FC.FileName); + uint32_t STOffset = Strings.insert(FC.FileName); Checksums->addChecksum(STOffset, FC.Kind, FC.ChecksumBytes.Bytes); } } ModiBuilder.setC13FileChecksums(std::move(Checksums)); + // FIXME: StringTable / StringTableBuilder should really be in + // DebugInfoCodeView. This would allow us to construct the + // ModuleDebugLineFragment with a reference to the string table, + // and we could just pass strings around rather than having to + // remember how to calculate the right offset. + auto &Strings = Builder.getStringTableBuilder(); + for (const auto &Fragment : FLI.LineFragments) { auto Lines = llvm::make_unique<ModuleDebugLineFragment>(); Lines->setCodeSize(Fragment.CodeSize); @@ -516,21 +541,8 @@ static void yamlToPdb(StringRef Path) { Fragment.RelocOffset); Lines->setFlags(Fragment.Flags); for (const auto &LC : Fragment.Blocks) { - // FIXME: StringTable / StringTableBuilder should really be in - // DebugInfoCodeView. This would allow us to construct the - // ModuleDebugLineFragment with a reference to the string table, - // and we could just pass strings around rather than having to - // remember how to calculate the right offset. - auto &Strings = Builder.getStringTableBuilder(); - // The offset in the line info record is the offset of the checksum - // entry for the corresponding file. That entry then contains an - // offset into the global string table of the file name. So to - // compute the proper offset to write into the line info record, we - // must first get its offset in the global string table, then ask the - // checksum builder to find the offset in its serialized buffer that - // it mapped that filename string table offset to. - uint32_t StringOffset = Strings.getStringIndex(LC.FileName); - uint32_t ChecksumOffset = ChecksumRef.mapChecksumOffset(StringOffset); + uint32_t ChecksumOffset = + getFileChecksumOffset(LC.FileName, ChecksumRef, Strings); Lines->createBlock(ChecksumOffset); if (Lines->hasColumnInfo()) { @@ -550,7 +562,26 @@ static void yamlToPdb(StringRef Path) { } } } - ModiBuilder.addC13LineFragment(std::move(Lines)); + ModiBuilder.addC13Fragment(std::move(Lines)); + } + + for (const auto &Inlinee : FLI.Inlinees) { + auto Inlinees = llvm::make_unique<ModuleDebugInlineeLineFragment>( + Inlinee.HasExtraFiles); + for (const auto &Site : Inlinee.Sites) { + uint32_t FileOff = + getFileChecksumOffset(Site.FileName, ChecksumRef, Strings); + + Inlinees->addInlineSite(Site.Inlinee, FileOff, Site.SourceLineNum); + if (!Inlinee.HasExtraFiles) + continue; + + for (auto EF : Site.ExtraFiles) { + FileOff = getFileChecksumOffset(EF, ChecksumRef, Strings); + Inlinees->addExtraFile(FileOff); + } + } + ModiBuilder.addC13Fragment(std::move(Inlinees)); } } } diff --git a/llvm/tools/llvm-readobj/COFFDumper.cpp b/llvm/tools/llvm-readobj/COFFDumper.cpp index abe0e8d6965..a7088c1c741 100644 --- a/llvm/tools/llvm-readobj/COFFDumper.cpp +++ b/llvm/tools/llvm-readobj/COFFDumper.cpp @@ -26,6 +26,7 @@ #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/CodeView/Line.h" #include "llvm/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.h" +#include "llvm/DebugInfo/CodeView/ModuleDebugInlineeLinesFragment.h" #include "llvm/DebugInfo/CodeView/ModuleDebugLineFragment.h" #include "llvm/DebugInfo/CodeView/RecordSerialization.h" #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" @@ -986,27 +987,20 @@ void COFFDumper::printCodeViewFileChecksums(StringRef Subsection) { void COFFDumper::printCodeViewInlineeLines(StringRef Subsection) { BinaryByteStream S(Subsection, llvm::support::little); BinaryStreamReader SR(S); - uint32_t Signature; - error(SR.readInteger(Signature)); - bool HasExtraFiles = Signature == unsigned(InlineeLinesSignature::ExtraFiles); + ModuleDebugInlineeLineFragmentRef Lines; + error(Lines.initialize(SR)); - while (!SR.empty()) { - const InlineeSourceLine *ISL; - error(SR.readObject(ISL)); + for (auto &Line : Lines) { DictScope S(W, "InlineeSourceLine"); - printTypeIndex("Inlinee", ISL->Inlinee); - printFileNameForOffset("FileID", ISL->FileID); - W.printNumber("SourceLineNum", ISL->SourceLineNum); - - if (HasExtraFiles) { - uint32_t ExtraFileCount; - error(SR.readInteger(ExtraFileCount)); - W.printNumber("ExtraFileCount", ExtraFileCount); + printTypeIndex("Inlinee", Line.Header->Inlinee); + printFileNameForOffset("FileID", Line.Header->FileID); + W.printNumber("SourceLineNum", Line.Header->SourceLineNum); + + if (Lines.hasExtraFiles()) { + W.printNumber("ExtraFileCount", Line.ExtraFiles.size()); ListScope ExtraFiles(W, "ExtraFiles"); - for (unsigned I = 0; I < ExtraFileCount; ++I) { - uint32_t FileID; - error(SR.readInteger(FileID)); - printFileNameForOffset("FileID", FileID); + for (const auto &FID : Line.ExtraFiles) { + printFileNameForOffset("FileID", FID); } } } |