[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.
llvm-svn: 301936
diff --git a/llvm/include/llvm/DebugInfo/CodeView/Line.h b/llvm/include/llvm/DebugInfo/CodeView/Line.h
index cb29aa2..ac229c3 100644
--- a/llvm/include/llvm/DebugInfo/CodeView/Line.h
+++ b/llvm/include/llvm/DebugInfo/CodeView/Line.h
@@ -127,20 +127,6 @@
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 90da3e0..1f55d20 100644
--- a/llvm/include/llvm/DebugInfo/CodeView/ModuleDebugFragmentVisitor.h
+++ b/llvm/include/llvm/DebugInfo/CodeView/ModuleDebugFragmentVisitor.h
@@ -39,6 +39,10 @@
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 0000000..177367c
--- /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 582e048..8cc5db9 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 @@
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 @@
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 64f26b2..6734a79 100644
--- a/llvm/include/llvm/Support/BinaryStreamWriter.h
+++ b/llvm/include/llvm/Support/BinaryStreamWriter.h
@@ -30,6 +30,8 @@
/// 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 4bfe3bf..786b116 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 7655f6c..421f22c 100644
--- a/llvm/lib/DebugInfo/CodeView/CMakeLists.txt
+++ b/llvm/lib/DebugInfo/CodeView/CMakeLists.txt
@@ -11,6 +11,7 @@
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 79e5b9d..c349e7e 100644
--- a/llvm/lib/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.cpp
+++ b/llvm/lib/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.cpp
@@ -68,7 +68,10 @@
// 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 @@
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 263b632..b2543de 100644
--- a/llvm/lib/DebugInfo/CodeView/ModuleDebugFragmentRecord.cpp
+++ b/llvm/lib/DebugInfo/CodeView/ModuleDebugFragmentRecord.cpp
@@ -34,6 +34,7 @@
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 b7a86ee..dc591f3 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 @@
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 0000000..483f7cb
--- /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 41cb23a..f994b45 100644
--- a/llvm/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp
@@ -161,7 +161,7 @@
return Error::success();
}
-void DbiModuleDescriptorBuilder::addC13LineFragment(
+void DbiModuleDescriptorBuilder::addC13Fragment(
std::unique_ptr<ModuleDebugLineFragment> Lines) {
ModuleDebugLineFragment &Frag = *Lines;
@@ -175,6 +175,20 @@
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 71ce054..6603002 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 @@
- 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 @@
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 8e1fc01..1d63c85 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: 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: 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 940b38c..7c680eb 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 @@
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 @@
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 f0a536c..1054b0c 100644
--- a/llvm/tools/llvm-pdbdump/C13DebugFragmentVisitor.h
+++ b/llvm/tools/llvm-pdbdump/C13DebugFragmentVisitor.h
@@ -35,16 +35,21 @@
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 1fc8dd5..5ad0bfa 100644
--- a/llvm/tools/llvm-pdbdump/CompactTypeDumpVisitor.cpp
+++ b/llvm/tools/llvm-pdbdump/CompactTypeDumpVisitor.cpp
@@ -31,14 +31,15 @@
CompactTypeDumpVisitor::CompactTypeDumpVisitor(TypeDatabase &TypeDB,
ScopedPrinter *W)
- : W(W), TI(TypeIndex::None()), Offset(0), TypeDB(TypeDB) {}
+ : CompactTypeDumpVisitor(TypeDB, TypeIndex(TypeIndex::FirstNonSimpleIndex),
+ W) {}
+
+CompactTypeDumpVisitor::CompactTypeDumpVisitor(TypeDatabase &TypeDB,
+ TypeIndex FirstTI,
+ ScopedPrinter *W)
+ : W(W), TI(FirstTI), Offset(0), TypeDB(TypeDB) {}
Error CompactTypeDumpVisitor::visitTypeBegin(CVType &Record) {
- if (TI == TypeIndex::None())
- TI.setIndex(TypeIndex::FirstNonSimpleIndex);
- else
- TI.setIndex(TI.getIndex() + 1);
-
return Error::success();
}
@@ -52,6 +53,7 @@
.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 180eea7..76fafc9 100644
--- a/llvm/tools/llvm-pdbdump/CompactTypeDumpVisitor.h
+++ b/llvm/tools/llvm-pdbdump/CompactTypeDumpVisitor.h
@@ -27,6 +27,8 @@
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 833cd81..f3e28e0 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 @@
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 @@
}
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 @@
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 @@
}
ScopedPrinter &P;
+ TypeDatabase &IPI;
};
}
@@ -618,6 +669,7 @@
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 @@
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 645f2dc..d6ba7d6 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::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 @@
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 @@
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 a998eaf..423845c 100644
--- a/llvm/tools/llvm-pdbdump/PdbYaml.h
+++ b/llvm/tools/llvm-pdbdump/PdbYaml.h
@@ -102,9 +102,22 @@
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 @@
};
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 18596a6..807d7f8 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 @@
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 0bbc49e..642e169 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 @@
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 @@
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 @@
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 @@
}
}
}
- 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 abe0e8d..a7088c1 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::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);
+ printTypeIndex("Inlinee", Line.Header->Inlinee);
+ printFileNameForOffset("FileID", Line.Header->FileID);
+ W.printNumber("SourceLineNum", Line.Header->SourceLineNum);
- if (HasExtraFiles) {
- uint32_t ExtraFileCount;
- error(SR.readInteger(ExtraFileCount));
- W.printNumber("ExtraFileCount", ExtraFileCount);
+ 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);
}
}
}