From: Zachary Turner Date: Tue, 2 May 2017 16:56:09 +0000 (+0000) Subject: [PDB/CodeView] Read/write codeview inlinee line information. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e551b3a81e468d17b454e99e950a12ebb5b248aa;p=llvm [PDB/CodeView] Read/write codeview inlinee line information. Previously we wrote line information and file checksum information, but we did not write information about inlinee lines and functions. This patch adds support for that. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@301936 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/DebugInfo/CodeView/Line.h b/include/llvm/DebugInfo/CodeView/Line.h index cb29aa2489e..ac229c33751 100644 --- a/include/llvm/DebugInfo/CodeView/Line.h +++ b/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/include/llvm/DebugInfo/CodeView/ModuleDebugFragmentVisitor.h b/include/llvm/DebugInfo/CodeView/ModuleDebugFragmentVisitor.h index 90da3e03a15..1f55d202420 100644 --- a/include/llvm/DebugInfo/CodeView/ModuleDebugFragmentVisitor.h +++ b/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/include/llvm/DebugInfo/CodeView/ModuleDebugInlineeLinesFragment.h b/include/llvm/DebugInfo/CodeView/ModuleDebugInlineeLinesFragment.h new file mode 100644 index 00000000000..177367c111c --- /dev/null +++ b/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 ExtraFiles; +}; +} + +template <> struct VarStreamArrayExtractor { + 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 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 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 ExtraFiles; + InlineeSourceLineHeader Header; + }; + std::vector Entries; +}; +} +} + +#endif diff --git a/include/llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h b/include/llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h index 582e0485715..8cc5db981f5 100644 --- a/include/llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h +++ b/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 Lines); + void addC13Fragment(std::unique_ptr Lines); + void addC13Fragment( + std::unique_ptr Inlinees); void setC13FileChecksums( std::unique_ptr Checksums); @@ -80,8 +82,11 @@ private: std::string ObjFileName; std::vector SourceFiles; std::vector Symbols; - std::vector> LineInfo; + std::unique_ptr ChecksumInfo; + std::vector> LineInfo; + std::vector> + Inlinees; std::vector> C13Builders; diff --git a/include/llvm/Support/BinaryStreamWriter.h b/include/llvm/Support/BinaryStreamWriter.h index 64f26b24543..6734a797ccc 100644 --- a/include/llvm/Support/BinaryStreamWriter.h +++ b/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/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp index 4bfe3bf2b63..786b11618d7 100644 --- a/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ b/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/lib/DebugInfo/CodeView/CMakeLists.txt b/lib/DebugInfo/CodeView/CMakeLists.txt index 7655f6c651e..421f22ca5d8 100644 --- a/lib/DebugInfo/CodeView/CMakeLists.txt +++ b/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/lib/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.cpp b/lib/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.cpp index 79e5b9d690d..c349e7ecce9 100644 --- a/lib/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.cpp +++ b/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/lib/DebugInfo/CodeView/ModuleDebugFragmentRecord.cpp b/lib/DebugInfo/CodeView/ModuleDebugFragmentRecord.cpp index 263b632da3f..b2543de7806 100644 --- a/lib/DebugInfo/CodeView/ModuleDebugFragmentRecord.cpp +++ b/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/lib/DebugInfo/CodeView/ModuleDebugFragmentVisitor.cpp b/lib/DebugInfo/CodeView/ModuleDebugFragmentVisitor.cpp index b7a86ee6699..dc591f3990e 100644 --- a/lib/DebugInfo/CodeView/ModuleDebugFragmentVisitor.cpp +++ b/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/lib/DebugInfo/CodeView/ModuleDebugInlineeLinesFragment.cpp b/lib/DebugInfo/CodeView/ModuleDebugInlineeLinesFragment.cpp new file mode 100644 index 00000000000..483f7cb5c5a --- /dev/null +++ b/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::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(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/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp b/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp index 41cb23a188f..f994b4538ef 100644 --- a/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp +++ b/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 Lines) { ModuleDebugLineFragment &Frag = *Lines; @@ -175,6 +175,20 @@ void DbiModuleDescriptorBuilder::addC13LineFragment( llvm::make_unique(Frag.kind(), Frag)); } +void DbiModuleDescriptorBuilder::addC13Fragment( + std::unique_ptr 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(Frag.kind(), Frag)); +} + void DbiModuleDescriptorBuilder::setC13FileChecksums( std::unique_ptr Checksums) { assert(!ChecksumInfo && "Can't have more than one checksum info!"); diff --git a/test/DebugInfo/PDB/Inputs/simple-line-info.yaml b/test/DebugInfo/PDB/Inputs/simple-line-info.yaml index 71ce0545d5c..66030020f8f 100644 --- a/test/DebugInfo/PDB/Inputs/simple-line-info.yaml +++ b/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/test/DebugInfo/PDB/pdbdump-yaml-lineinfo-write.test b/test/DebugInfo/PDB/pdbdump-yaml-lineinfo-write.test index 8e1fc01290c..1d63c85352a 100644 --- a/test/DebugInfo/PDB/pdbdump-yaml-lineinfo-write.test +++ b/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/tools/llvm-pdbdump/C13DebugFragmentVisitor.cpp b/tools/llvm-pdbdump/C13DebugFragmentVisitor.cpp index 940b38c4a8c..7c680ebb94c 100644 --- a/tools/llvm-pdbdump/C13DebugFragmentVisitor.cpp +++ b/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/tools/llvm-pdbdump/C13DebugFragmentVisitor.h b/tools/llvm-pdbdump/C13DebugFragmentVisitor.h index f0a536c6adc..1054b0c9f6e 100644 --- a/tools/llvm-pdbdump/C13DebugFragmentVisitor.h +++ b/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 getNameFromStringTable(uint32_t Offset); Expected getNameFromChecksumsBuffer(uint32_t Offset); Optional Checksums; + std::vector InlineeLines; std::vector Lines; PDBFile &F; diff --git a/tools/llvm-pdbdump/CompactTypeDumpVisitor.cpp b/tools/llvm-pdbdump/CompactTypeDumpVisitor.cpp index 1fc8dd5d51f..5ad0bfad26c 100644 --- a/tools/llvm-pdbdump/CompactTypeDumpVisitor.cpp +++ b/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/tools/llvm-pdbdump/CompactTypeDumpVisitor.h b/tools/llvm-pdbdump/CompactTypeDumpVisitor.h index 180eea7b8d6..76fafc93e03 100644 --- a/tools/llvm-pdbdump/CompactTypeDumpVisitor.h +++ b/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/tools/llvm-pdbdump/LLVMOutputStyle.cpp b/tools/llvm-pdbdump/LLVMOutputStyle.cpp index 833cd810468..f3e28e0b08f 100644 --- a/tools/llvm-pdbdump/LLVMOutputStyle.cpp +++ b/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(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/tools/llvm-pdbdump/PdbYaml.cpp b/tools/llvm-pdbdump/PdbYaml.cpp index 645f2dc607d..d6ba7d64545 100644 --- a/tools/llvm-pdbdump/PdbYaml.cpp +++ b/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::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::mapping( + IO &IO, PdbInlineeInfo &Obj, SerializationContext &Context) { + IO.mapRequired("HasExtraFiles", Obj.HasExtraFiles); + IO.mapRequired("Sites", Obj.Sites, Context); } void MappingContextTraits:: diff --git a/tools/llvm-pdbdump/PdbYaml.h b/tools/llvm-pdbdump/PdbYaml.h index a998eafbb05..423845caeb3 100644 --- a/tools/llvm-pdbdump/PdbYaml.h +++ b/tools/llvm-pdbdump/PdbYaml.h @@ -102,9 +102,22 @@ struct PdbSourceLineInfo { std::vector Blocks; }; +struct PdbInlineeSite { + codeview::TypeIndex Inlinee; + StringRef FileName; + uint32_t SourceLineNum; + std::vector ExtraFiles; +}; + +struct PdbInlineeInfo { + bool HasExtraFiles; + std::vector Sites; +}; + struct PdbSourceFileInfo { std::vector FileChecksums; std::vector LineFragments; + std::vector Inlinees; }; struct PdbDbiModuleInfo { @@ -258,6 +271,20 @@ struct MappingContextTraits +struct MappingContextTraits { + static void mapping(IO &IO, pdb::yaml::PdbInlineeInfo &Obj, + pdb::yaml::SerializationContext &Context); +}; + +template <> +struct MappingContextTraits { + static void mapping(IO &IO, pdb::yaml::PdbInlineeSite &Obj, + pdb::yaml::SerializationContext &Context); +}; + template <> struct MappingContextTraits { diff --git a/tools/llvm-pdbdump/YAMLOutputStyle.cpp b/tools/llvm-pdbdump/YAMLOutputStyle.cpp index 18596a68a3c..807d7f8b82e 100644 --- a/tools/llvm-pdbdump/YAMLOutputStyle.cpp +++ b/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/tools/llvm-pdbdump/llvm-pdbdump.cpp b/tools/llvm-pdbdump/llvm-pdbdump.cpp index 0bbc49eadbb..642e169613b 100644 --- a/tools/llvm-pdbdump/llvm-pdbdump.cpp +++ b/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 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> 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(); 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( + 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/tools/llvm-readobj/COFFDumper.cpp b/tools/llvm-readobj/COFFDumper.cpp index abe0e8d6965..a7088c1c741 100644 --- a/tools/llvm-readobj/COFFDumper.cpp +++ b/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); } } }