Index: include/llvm/DebugInfo/CodeView/ModuleSubstream.h =================================================================== --- /dev/null +++ include/llvm/DebugInfo/CodeView/ModuleSubstream.h @@ -0,0 +1,87 @@ +//===- ModuleSubstream.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_MODULESUBSTREAM_H +#define LLVM_DEBUGINFO_CODEVIEW_MODULESUBSTREAM_H + +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/StreamArray.h" +#include "llvm/DebugInfo/CodeView/StreamRef.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" + +namespace llvm { +namespace codeview { + +// Corresponds to the `CV_DebugSSubsectionHeader_t` structure. +struct ModuleSubsectionHeader { + support::ulittle32_t Kind; // codeview::ModuleSubstreamKind enum + support::ulittle32_t Length; // number of bytes occupied by this record. +}; + +// Corresponds to the `CV_DebugSLinesHeader_t` structure. +struct LineSubstreamHeader { + support::ulittle32_t RelocOffset; // Code offset of line contribution. + support::ulittle16_t RelocSegment; // Code segment of line contribution. + support::ulittle16_t Flags; // See LineFlags enumeration. + support::ulittle32_t CodeSize; // Code size of this line contribution. +}; + +// Corresponds to the `CV_DebugSLinesFileBlockHeader_t` structure. +struct LineFileBlockHeader { + support::ulittle32_t FileOffset; + support::ulittle32_t NumLines; // Number of lines + support::ulittle32_t BlockSize; // Code size of block, in bytes. + // The following two variable length arrays appear immediately after the + // header. The structure definitions follow. + // LineNumberEntry Lines[NumLines]; + // ColumnNumberEntry Columns[NumLines]; +}; + +// Corresponds to `CV_Line_t` structure +struct LineNumberEntry { + support::ulittle32_t Offset; // Offset to start of code bytes for line number + support::ulittle32_t Flags; // Start:24, End:7, IsStatement:1 +}; + +// Corresponds to `CV_Column_t` structure +struct ColumnNumberEntry { + support::ulittle16_t StartColumn; + support::ulittle16_t EndColumn; +}; + +class ModuleSubstream { +public: + ModuleSubstream(); + ModuleSubstream(ModuleSubstreamKind Kind, StreamRef Data); + static Error initialize(StreamRef Stream, ModuleSubstream &Info); + uint32_t getRecordLength() const; + ModuleSubstreamKind getSubstreamKind() const; + StreamRef getRecordData() const; + +private: + ModuleSubstreamKind Kind; + StreamRef Data; +}; + +template <> struct VarStreamArrayExtractor { + Error operator()(StreamRef Stream, uint32_t &Length, + ModuleSubstream &Info) const { + if (auto EC = ModuleSubstream::initialize(Stream, Info)) + return EC; + Length = Info.getRecordLength(); + return Error::success(); + } +}; + +typedef VarStreamArray ModuleSubstreamArray; +} +} + +#endif // LLVM_DEBUGINFO_CODEVIEW_MODULESUBSTREAM_H Index: include/llvm/DebugInfo/CodeView/ModuleSubstreamVisitor.h =================================================================== --- /dev/null +++ include/llvm/DebugInfo/CodeView/ModuleSubstreamVisitor.h @@ -0,0 +1,93 @@ +//===- ModuleSubstreamVisitor.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_MODULESUBSTREAMVISITOR_H +#define LLVM_DEBUGINFO_CODEVIEW_MODULESUBSTREAMVISITOR_H + +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/CodeViewError.h" +#include "llvm/DebugInfo/CodeView/Line.h" +#include "llvm/DebugInfo/CodeView/ModuleSubstream.h" +#include "llvm/DebugInfo/CodeView/StreamReader.h" +#include "llvm/DebugInfo/CodeView/StreamRef.h" + +namespace llvm { +namespace codeview { + +struct LineColumnEntry { + support::ulittle32_t Offset; + FixedStreamArray LineNumbers; + FixedStreamArray Columns; +}; + +class FileLineInfoExtractor { +public: + FileLineInfoExtractor(const LineSubstreamHeader *Header) : Header(Header) {} + + Error operator()(StreamRef Stream, uint32_t &Len, + LineColumnEntry &Item) const { + const LineFileBlockHeader *BlockHeader; + StreamReader Reader(Stream); + if (auto EC = Reader.readObject(BlockHeader)) + return EC; + bool HasColumn = Header->Flags & LineFlags::HaveColumns; + uint32_t LineInfoSize = + BlockHeader->NumLines * + (sizeof(LineNumberEntry) + (HasColumn ? sizeof(ColumnNumberEntry) : 0)); + uint32_t Size = BlockHeader->BlockSize - sizeof(LineFileBlockHeader); + if (LineInfoSize > Size) + return make_error(cv_error_code::corrupt_record, + "Invalid line block record size"); + // The value recorded in BlockHeader->BlockSize includes the size of + // LineFileBlockHeader. + Len = BlockHeader->BlockSize; + Item.Offset = BlockHeader->FileOffset; + if (auto EC = Reader.readArray(Item.LineNumbers, BlockHeader->NumLines)) + return EC; + if (HasColumn) { + if (auto EC = Reader.readArray(Item.Columns, BlockHeader->NumLines)) + return EC; + } + return Error::success(); + } + +private: + const LineSubstreamHeader *Header; +}; + +typedef VarStreamArray LineInfoArray; + +class IModuleSubstreamVisitor { +public: + virtual ~IModuleSubstreamVisitor() {} + + virtual Error visitUnknown(ModuleSubstreamKind Kind, StreamRef Data) = 0; + virtual Error visitSymbols(StreamRef Data); + virtual Error visitLines(StreamRef Data, const LineSubstreamHeader *Header, + LineInfoArray Lines); + virtual Error visitStringTable(StreamRef Data); + virtual Error visitFileChecksums(StreamRef Data); + virtual Error visitFrameData(StreamRef Data); + virtual Error visitInlineeLines(StreamRef Data); + virtual Error visitCrossScopeImports(StreamRef Data); + virtual Error visitCrossScopeExports(StreamRef Data); + virtual Error visitILLines(StreamRef Data); + virtual Error visitFuncMDTokenMap(StreamRef Data); + virtual Error visitTypeMDTokenMap(StreamRef Data); + virtual Error visitMergedAssemblyInput(StreamRef Data); + virtual Error visitCoffSymbolRVA(StreamRef Data); +}; + +Error visitModuleSubstream(const ModuleSubstream &R, + IModuleSubstreamVisitor &V); + +} // namespace codeview +} // namespace llvm + +#endif // LLVM_DEBUGINFO_CODEVIEW_MODULESUBSTREAMVISITOR_H Index: include/llvm/DebugInfo/CodeView/StreamArray.h =================================================================== --- include/llvm/DebugInfo/CodeView/StreamArray.h +++ include/llvm/DebugInfo/CodeView/StreamArray.h @@ -52,17 +52,25 @@ typedef VarStreamArrayIterator Iterator; VarStreamArray() {} + VarStreamArray(const Extractor &E) : E(E) {} VarStreamArray(StreamRef Stream) : Stream(Stream) {} + VarStreamArray(StreamRef Stream, const Extractor &E) : Stream(Stream), E(E) {} + + VarStreamArray(const VarStreamArray &Other) + : Stream(Other.Stream), E(Other.E) {} Iterator begin(bool *HadError = nullptr) const { - return Iterator(*this, HadError); + return Iterator(*this, E, HadError); } - Iterator end() const { return Iterator(); } + Iterator end() const { return Iterator(E); } + + const Extractor &getExtractor() const { return E; } private: StreamRef Stream; + Extractor E; }; template class VarStreamArrayIterator { @@ -70,9 +78,10 @@ typedef VarStreamArray ArrayType; public: - VarStreamArrayIterator(const ArrayType &Array, bool *HadError = nullptr) + VarStreamArrayIterator(const ArrayType &Array, const Extractor &E, + bool *HadError = nullptr) : Array(&Array), IterRef(Array.Stream), HasError(false), - HadError(HadError) { + HadError(HadError), Extract(E) { auto EC = Extract(IterRef, ThisLen, ThisValue); if (EC) { consumeError(std::move(EC)); @@ -82,6 +91,9 @@ VarStreamArrayIterator() : Array(nullptr), ThisLen(0), ThisValue(), IterRef(), HasError(false), HadError(nullptr) {} + VarStreamArrayIterator(const Extractor &E) + : Array(nullptr), ThisLen(0), ThisValue(), IterRef(), HasError(false), + HadError(nullptr), Extract(E) {} ~VarStreamArrayIterator() {} bool operator==(const IterType &R) const { @@ -197,7 +209,10 @@ FixedStreamArrayIterator(const FixedStreamArray &Array) : Array(Array), Index(uint32_t(-1)) {} FixedStreamArrayIterator(const FixedStreamArray &Array, uint32_t Index) - : Array(Array), Index(Index) {} + : Array(Array), Index(Index) { + if (Array.size() <= Index) + this->Index = uint32_t(-1); + } bool operator==(const FixedStreamArrayIterator &R) { assert(&Array == &R.Array); Index: include/llvm/DebugInfo/CodeView/StreamReader.h =================================================================== --- include/llvm/DebugInfo/CodeView/StreamReader.h +++ include/llvm/DebugInfo/CodeView/StreamReader.h @@ -52,12 +52,12 @@ return Error::success(); } - template - Error readArray(VarStreamArray &Array, uint32_t Size) { + template + Error readArray(VarStreamArray &Array, uint32_t Size) { StreamRef S; if (auto EC = readStreamRef(S, Size)) return EC; - Array = VarStreamArray(S); + Array = VarStreamArray(S, Array.getExtractor()); return Error::success(); } Index: include/llvm/DebugInfo/PDB/Raw/DbiStream.h =================================================================== --- include/llvm/DebugInfo/PDB/Raw/DbiStream.h +++ include/llvm/DebugInfo/PDB/Raw/DbiStream.h @@ -10,12 +10,12 @@ #ifndef LLVM_DEBUGINFO_PDB_RAW_PDBDBISTREAM_H #define LLVM_DEBUGINFO_PDB_RAW_PDBDBISTREAM_H +#include "llvm/DebugInfo/CodeView/ModuleSubstream.h" #include "llvm/DebugInfo/CodeView/StreamArray.h" #include "llvm/DebugInfo/CodeView/StreamRef.h" #include "llvm/DebugInfo/PDB/PDBTypes.h" #include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" #include "llvm/DebugInfo/PDB/Raw/ModInfo.h" -#include "llvm/DebugInfo/PDB/Raw/ModuleSubstreamRecord.h" #include "llvm/DebugInfo/PDB/Raw/NameHashTable.h" #include "llvm/DebugInfo/PDB/Raw/RawConstants.h" #include "llvm/DebugInfo/PDB/Raw/RawTypes.h" Index: include/llvm/DebugInfo/PDB/Raw/ModStream.h =================================================================== --- include/llvm/DebugInfo/PDB/Raw/ModStream.h +++ include/llvm/DebugInfo/PDB/Raw/ModStream.h @@ -12,11 +12,11 @@ #include "llvm/ADT/iterator_range.h" #include "llvm/DebugInfo/CodeView/CVRecord.h" +#include "llvm/DebugInfo/CodeView/ModuleSubstream.h" #include "llvm/DebugInfo/CodeView/StreamArray.h" #include "llvm/DebugInfo/CodeView/StreamRef.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h" #include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" -#include "llvm/DebugInfo/PDB/Raw/ModuleSubstreamRecord.h" #include "llvm/Support/Error.h" namespace llvm { @@ -26,8 +26,6 @@ class ModStream { public: - typedef codeview::VarStreamArray LineInfoArray; - ModStream(PDBFile &File, const ModInfo &Module); ~ModStream(); @@ -36,7 +34,8 @@ iterator_range symbols(bool *HadError) const; - iterator_range lines(bool *HadError) const; + iterator_range + lines(bool *HadError) const; private: const ModInfo &Mod; @@ -48,7 +47,7 @@ codeview::StreamRef C13LinesSubstream; codeview::StreamRef GlobalRefsSubstream; - LineInfoArray LineInfo; + codeview::ModuleSubstreamArray LineInfo; }; } } Index: include/llvm/DebugInfo/PDB/Raw/ModuleSubstreamRecord.h =================================================================== --- include/llvm/DebugInfo/PDB/Raw/ModuleSubstreamRecord.h +++ /dev/null @@ -1,51 +0,0 @@ -//===- ModuleSubstreamRecord.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_PDB_RAW_MODULESUBSTREAMRECORD_H -#define LLVM_DEBUGINFO_PDB_RAW_MODULESUBSTREAMRECORD_H - -#include "llvm/DebugInfo/CodeView/CodeView.h" -#include "llvm/DebugInfo/CodeView/StreamArray.h" -#include "llvm/DebugInfo/CodeView/StreamRef.h" -#include "llvm/Support/Error.h" - -namespace llvm { - -namespace pdb { -class ModuleSubstreamRecord { -public: - ModuleSubstreamRecord(); - ModuleSubstreamRecord(codeview::ModuleSubstreamKind Kind, - codeview::StreamRef Data); - static Error initialize(codeview::StreamRef Stream, - ModuleSubstreamRecord &Info); - uint32_t getRecordLength() const; - codeview::ModuleSubstreamKind getSubstreamKind() const; - codeview::StreamRef getRecordData() const; - -private: - codeview::ModuleSubstreamKind Kind; - codeview::StreamRef Data; -}; -} - -namespace codeview { -template <> struct VarStreamArrayExtractor { - Error operator()(StreamRef Stream, uint32_t &Length, - pdb::ModuleSubstreamRecord &Info) const { - if (auto EC = pdb::ModuleSubstreamRecord::initialize(Stream, Info)) - return EC; - Length = Info.getRecordLength(); - return Error::success(); - } -}; -} -} - -#endif // LLVM_DEBUGINFO_PDB_RAW_MODULESUBSTREAMRECORD_H Index: include/llvm/DebugInfo/PDB/Raw/RawTypes.h =================================================================== --- include/llvm/DebugInfo/PDB/Raw/RawTypes.h +++ include/llvm/DebugInfo/PDB/Raw/RawTypes.h @@ -72,45 +72,6 @@ support::ulittle32_t SecByteLength; // Byte count of the segment or group. }; -// Corresponds to the `CV_DebugSSubsectionHeader_t` structure. -struct ModuleSubsectionHeader { - support::ulittle32_t Kind; // codeview::ModuleSubstreamKind enum - support::ulittle32_t Length; // number of bytes occupied by this record. -}; - -// Corresponds to the `CV_DebugSLinesHeader_t` structure. -struct LineTableSubsectionHeader { - support::ulittle32_t OffCon; - support::ulittle16_t SegCon; - support::ulittle16_t Flags; - support::ulittle32_t CbCon; -}; - -// Corresponds to the `CV_DebugSLinesFileBlockHeader_t` structure. -struct SourceFileBlockHeader { - support::ulittle32_t offFile; - support::ulittle32_t nLines; - support::ulittle32_t cbBlock; - // LineInfo lines[nLines]; - // ColumnInfo columns[nColumns]; -}; - -// Corresponds to `CV_Line_t` structure -struct LineInfo { - unsigned long Offset; // Offset to start of code bytes for line number - unsigned long LinenumStart : 24; // line where statement/expression starts - unsigned long - DeltaLineEnd : 7; // delta to line where statement ends (optional) - unsigned long FStatement : 1; // true if a statement linenumber, else an - // expression line num -}; - -// Corresponds to `CV_Column_t` structure -struct ColumnInfo { - support::ulittle16_t OffColumnStart; - support::ulittle16_t OffColumnEnd; -}; - } // namespace pdb } // namespace llvm Index: lib/DebugInfo/CodeView/CMakeLists.txt =================================================================== --- lib/DebugInfo/CodeView/CMakeLists.txt +++ lib/DebugInfo/CodeView/CMakeLists.txt @@ -7,6 +7,8 @@ ListRecordBuilder.cpp MemoryTypeTableBuilder.cpp MethodListRecordBuilder.cpp + ModuleSubstream.cpp + ModuleSubstreamVisitor.cpp RecordSerialization.cpp StreamReader.cpp SymbolDumper.cpp Index: lib/DebugInfo/CodeView/ModuleSubstream.cpp =================================================================== --- /dev/null +++ lib/DebugInfo/CodeView/ModuleSubstream.cpp @@ -0,0 +1,42 @@ +//===- ModuleSubstream.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/ModuleSubstream.h" + +#include "llvm/DebugInfo/CodeView/StreamReader.h" + +using namespace llvm; +using namespace llvm::codeview; + +ModuleSubstream::ModuleSubstream() : Kind(ModuleSubstreamKind::None) {} + +ModuleSubstream::ModuleSubstream(ModuleSubstreamKind Kind, StreamRef Data) + : Kind(Kind), Data(Data) {} + +Error ModuleSubstream::initialize(StreamRef Stream, ModuleSubstream &Info) { + const ModuleSubsectionHeader *Header; + StreamReader Reader(Stream); + if (auto EC = Reader.readObject(Header)) + return EC; + + ModuleSubstreamKind Kind = + static_cast(uint32_t(Header->Kind)); + if (auto EC = Reader.readStreamRef(Info.Data, Header->Length)) + return EC; + Info.Kind = Kind; + return Error::success(); +} + +uint32_t ModuleSubstream::getRecordLength() const { + return sizeof(ModuleSubsectionHeader) + Data.getLength(); +} + +ModuleSubstreamKind ModuleSubstream::getSubstreamKind() const { return Kind; } + +StreamRef ModuleSubstream::getRecordData() const { return Data; } Index: lib/DebugInfo/CodeView/ModuleSubstreamVisitor.cpp =================================================================== --- /dev/null +++ lib/DebugInfo/CodeView/ModuleSubstreamVisitor.cpp @@ -0,0 +1,98 @@ +//===- ModuleSubstreamVisitor.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/ModuleSubstreamVisitor.h" + +using namespace llvm; +using namespace llvm::codeview; + +Error IModuleSubstreamVisitor::visitSymbols(StreamRef Data) { + return visitUnknown(ModuleSubstreamKind::Symbols, Data); +} +Error IModuleSubstreamVisitor::visitLines(StreamRef Data, + const LineSubstreamHeader *Header, + LineInfoArray Lines) { + return visitUnknown(ModuleSubstreamKind::Lines, Data); +} +Error IModuleSubstreamVisitor::visitStringTable(StreamRef Data) { + return visitUnknown(ModuleSubstreamKind::StringTable, Data); +} +Error IModuleSubstreamVisitor::visitFileChecksums(StreamRef Data) { + return visitUnknown(ModuleSubstreamKind::FileChecksums, Data); +} +Error IModuleSubstreamVisitor::visitFrameData(StreamRef Data) { + return visitUnknown(ModuleSubstreamKind::FrameData, Data); +} +Error IModuleSubstreamVisitor::visitInlineeLines(StreamRef Data) { + return visitUnknown(ModuleSubstreamKind::InlineeLines, Data); +} +Error IModuleSubstreamVisitor::visitCrossScopeImports(StreamRef Data) { + return visitUnknown(ModuleSubstreamKind::CrossScopeExports, Data); +} +Error IModuleSubstreamVisitor::visitCrossScopeExports(StreamRef Data) { + return visitUnknown(ModuleSubstreamKind::CrossScopeImports, Data); +} +Error IModuleSubstreamVisitor::visitILLines(StreamRef Data) { + return visitUnknown(ModuleSubstreamKind::ILLines, Data); +} +Error IModuleSubstreamVisitor::visitFuncMDTokenMap(StreamRef Data) { + return visitUnknown(ModuleSubstreamKind::FuncMDTokenMap, Data); +} +Error IModuleSubstreamVisitor::visitTypeMDTokenMap(StreamRef Data) { + return visitUnknown(ModuleSubstreamKind::TypeMDTokenMap, Data); +} +Error IModuleSubstreamVisitor::visitMergedAssemblyInput(StreamRef Data) { + return visitUnknown(ModuleSubstreamKind::MergedAssemblyInput, Data); +} +Error IModuleSubstreamVisitor::visitCoffSymbolRVA(StreamRef Data) { + return visitUnknown(ModuleSubstreamKind::CoffSymbolRVA, Data); +} + +Error llvm::codeview::visitModuleSubstream(const ModuleSubstream &R, + IModuleSubstreamVisitor &V) { + switch (R.getSubstreamKind()) { + case ModuleSubstreamKind::Symbols: + return V.visitSymbols(R.getRecordData()); + case ModuleSubstreamKind::Lines: { + StreamReader Reader(R.getRecordData()); + const LineSubstreamHeader *Header; + if (auto EC = Reader.readObject(Header)) + return EC; + FileLineInfoExtractor E(Header); + LineInfoArray LineInfos(E); + if (auto EC = Reader.readArray(LineInfos, Reader.bytesRemaining())) + return EC; + return V.visitLines(R.getRecordData(), Header, LineInfos); + } + case ModuleSubstreamKind::StringTable: + return V.visitStringTable(R.getRecordData()); + case ModuleSubstreamKind::FileChecksums: + return V.visitFileChecksums(R.getRecordData()); + case ModuleSubstreamKind::FrameData: + return V.visitFrameData(R.getRecordData()); + case ModuleSubstreamKind::InlineeLines: + return V.visitInlineeLines(R.getRecordData()); + case ModuleSubstreamKind::CrossScopeImports: + return V.visitCrossScopeImports(R.getRecordData()); + case ModuleSubstreamKind::CrossScopeExports: + return V.visitCrossScopeExports(R.getRecordData()); + case ModuleSubstreamKind::ILLines: + return V.visitILLines(R.getRecordData()); + case ModuleSubstreamKind::FuncMDTokenMap: + return V.visitFuncMDTokenMap(R.getRecordData()); + case ModuleSubstreamKind::TypeMDTokenMap: + return V.visitTypeMDTokenMap(R.getRecordData()); + case ModuleSubstreamKind::MergedAssemblyInput: + return V.visitMergedAssemblyInput(R.getRecordData()); + case ModuleSubstreamKind::CoffSymbolRVA: + return V.visitCoffSymbolRVA(R.getRecordData()); + default: + return V.visitUnknown(R.getSubstreamKind(), R.getRecordData()); + } +} Index: lib/DebugInfo/PDB/CMakeLists.txt =================================================================== --- lib/DebugInfo/PDB/CMakeLists.txt +++ lib/DebugInfo/PDB/CMakeLists.txt @@ -33,7 +33,6 @@ Raw/InfoStream.cpp Raw/MappedBlockStream.cpp Raw/ModInfo.cpp - Raw/ModuleSubstreamRecord.cpp Raw/ModStream.cpp Raw/NameHashTable.cpp Raw/NameMap.cpp Index: lib/DebugInfo/PDB/Raw/ModStream.cpp =================================================================== --- lib/DebugInfo/PDB/Raw/ModStream.cpp +++ lib/DebugInfo/PDB/Raw/ModStream.cpp @@ -69,7 +69,7 @@ SymbolsSubstream.end()); } -iterator_range +iterator_range ModStream::lines(bool *HadError) const { return llvm::make_range(LineInfo.begin(HadError), LineInfo.end()); } Index: lib/DebugInfo/PDB/Raw/ModuleSubstreamRecord.cpp =================================================================== --- lib/DebugInfo/PDB/Raw/ModuleSubstreamRecord.cpp +++ /dev/null @@ -1,49 +0,0 @@ -//===- ModuleSubstreamRecord.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/PDB/Raw/ModuleSubstreamRecord.h" - -#include "llvm/DebugInfo/CodeView/StreamReader.h" -#include "llvm/DebugInfo/PDB/Raw/RawTypes.h" - -using namespace llvm; -using namespace llvm::codeview; -using namespace llvm::pdb; - -ModuleSubstreamRecord::ModuleSubstreamRecord() - : Kind(ModuleSubstreamKind::None) {} - -ModuleSubstreamRecord::ModuleSubstreamRecord(ModuleSubstreamKind Kind, - StreamRef Data) - : Kind(Kind), Data(Data) {} - -Error ModuleSubstreamRecord::initialize(StreamRef Stream, - ModuleSubstreamRecord &Info) { - const ModuleSubsectionHeader *Header; - StreamReader Reader(Stream); - if (auto EC = Reader.readObject(Header)) - return EC; - - ModuleSubstreamKind Kind = - static_cast(uint32_t(Header->Kind)); - if (auto EC = Reader.readStreamRef(Info.Data, Header->Length)) - return EC; - Info.Kind = Kind; - return Error::success(); -} - -uint32_t ModuleSubstreamRecord::getRecordLength() const { - return sizeof(ModuleSubsectionHeader) + Data.getLength(); -} - -ModuleSubstreamKind ModuleSubstreamRecord::getSubstreamKind() const { - return Kind; -} - -StreamRef ModuleSubstreamRecord::getRecordData() const { return Data; } Index: test/DebugInfo/PDB/pdbdump-headers.test =================================================================== --- test/DebugInfo/PDB/pdbdump-headers.test +++ test/DebugInfo/PDB/pdbdump-headers.test @@ -331,16 +331,33 @@ ; EMPTY-NEXT: } ; EMPTY-NEXT: ] ; EMPTY-NEXT: LineInfo [ -; EMPTY-NEXT: { -; EMPTY-NEXT: Kind: Lines (0xF2) +; EMPTY-NEXT: LineInfo { +; EMPTY-NEXT: FileOffset: 0 +; EMPTY-NEXT: Line { +; EMPTY-NEXT: Offset: 0 +; EMPTY-NEXT: StartLine: 5 +; EMPTY-NEXT: EndDelta: 0 +; EMPTY-NEXT: IsStatement: Yes +; EMPTY-NEXT: } +; EMPTY-NEXT: Line { +; EMPTY-NEXT: Offset: 3 +; EMPTY-NEXT: StartLine: 6 +; EMPTY-NEXT: EndDelta: 0 +; EMPTY-NEXT: IsStatement: Yes +; EMPTY-NEXT: } +; EMPTY-NEXT: Line { +; EMPTY-NEXT: Offset: 8 +; EMPTY-NEXT: StartLine: 7 +; EMPTY-NEXT: EndDelta: 0 +; EMPTY-NEXT: IsStatement: Yes +; EMPTY-NEXT: } ; EMPTY-NEXT: Data ( ; EMPTY-NEXT: 0000: 10000000 01000000 0A000000 00000000 |................| ; EMPTY-NEXT: 0010: 03000000 24000000 00000000 05000080 |....$...........| ; EMPTY-NEXT: 0020: 03000000 06000080 08000000 07000080 |................| ; EMPTY-NEXT: ) ; EMPTY-NEXT: } -; EMPTY-NEXT: { -; EMPTY-NEXT: Kind: FileChecksums (0xF4) +; EMPTY-NEXT: FileChecksums { ; EMPTY-NEXT: Data ( ; EMPTY-NEXT: 0000: 56000000 1001A0A5 BD0D3ECD 93FC29D1 |V.........>...).| ; EMPTY-NEXT: 0010: 9DE826FB F4BC0000 |..&.....| Index: tools/llvm-pdbdump/llvm-pdbdump.cpp =================================================================== --- tools/llvm-pdbdump/llvm-pdbdump.cpp +++ tools/llvm-pdbdump/llvm-pdbdump.cpp @@ -27,6 +27,8 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/Config/config.h" #include "llvm/DebugInfo/CodeView/EnumTables.h" +#include "llvm/DebugInfo/CodeView/Line.h" +#include "llvm/DebugInfo/CodeView/ModuleSubstreamVisitor.h" #include "llvm/DebugInfo/CodeView/StreamReader.h" #include "llvm/DebugInfo/CodeView/SymbolDumper.h" #include "llvm/DebugInfo/CodeView/TypeDumper.h" @@ -68,6 +70,7 @@ #include "llvm/Support/raw_ostream.h" using namespace llvm; +using namespace llvm::codeview; using namespace llvm::pdb; namespace opts { @@ -515,18 +518,62 @@ if (opts::DumpLineInfo) { ListScope SS(P, "LineInfo"); bool HadError = false; - for (auto &L : ModS.lines(&HadError)) { - DictScope DD(P, ""); - P.printEnum("Kind", uint32_t(L.getSubstreamKind()), - codeview::getModuleSubstreamKindNames()); - ArrayRef Data; - codeview::StreamReader R(L.getRecordData()); - if (auto EC = R.readBytes(Data, R.bytesRemaining())) { - return make_error( - raw_error_code::corrupt_file, - "DBI stream contained corrupt line info record"); + // Define a locally scoped visitor to print the different + // substream types types. + class RecordVisitor : public codeview::IModuleSubstreamVisitor { + public: + RecordVisitor(ScopedPrinter &P) : P(P) {} + Error visitUnknown(ModuleSubstreamKind Kind, + StreamRef Data) override { + DictScope DD(P, "Unknown"); + return printBinaryData(Data); + } + Error visitFileChecksums(StreamRef Data) override { + DictScope DD(P, "FileChecksums"); + return printBinaryData(Data); + } + + Error visitLines(StreamRef Data, const LineSubstreamHeader *Header, + LineInfoArray Lines) override { + DictScope DD(P, "LineInfo"); + for (auto &L : Lines) { + P.printNumber("FileOffset", L.Offset); + for (auto &N : L.LineNumbers) { + DictScope DDD(P, "Line"); + LineInfo LI(N.Flags); + P.printNumber("Offset", N.Offset); + P.printNumber("StartLine", LI.getStartLine()); + P.printNumber("EndDelta", LI.getLineDelta()); + P.printBoolean("IsStatement", LI.isStatement()); + } + for (auto &C : L.Columns) { + DictScope DDD(P, "Column"); + P.printNumber("Start", C.StartColumn); + P.printNumber("End", C.EndColumn); + } + } + return printBinaryData(Data); + } + + private: + Error printBinaryData(StreamRef Stream) { + ArrayRef Data; + StreamReader R(Stream); + if (auto EC = R.readBytes(Data, R.bytesRemaining())) { + return make_error( + raw_error_code::corrupt_file, + "DBI stream contained corrupt line info record"); + } + P.printBinaryBlock("Data", Data); + P.flush(); + return Error::success(); } - P.printBinaryBlock("Data", Data); + ScopedPrinter &P; + }; + RecordVisitor V(P); + for (auto &L : ModS.lines(&HadError)) { + if (auto EC = codeview::visitModuleSubstream(L, V)) + return EC; } } } Index: tools/llvm-readobj/COFFDumper.cpp =================================================================== --- tools/llvm-readobj/COFFDumper.cpp +++ tools/llvm-readobj/COFFDumper.cpp @@ -774,6 +774,7 @@ initializeFileAndStringTables(Data); + // TODO: Convert this over to using ModuleSubstreamVisitor. while (!Data.empty()) { // The section consists of a number of subsection in the following format: // |SubSectionType|SubSectionSize|Contents...|