--- /dev/null
+//===- 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<ModuleSubstream> {
+ 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<ModuleSubstream> ModuleSubstreamArray;
+}
+}
+
+#endif // LLVM_DEBUGINFO_CODEVIEW_MODULESUBSTREAM_H
--- /dev/null
+//===- 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<LineNumberEntry> LineNumbers;
+ FixedStreamArray<ColumnNumberEntry> 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));
+ if (BlockHeader->BlockSize < sizeof(LineFileBlockHeader))
+ return make_error<CodeViewError>(cv_error_code::corrupt_record,
+ "Invalid line block record size");
+ uint32_t Size = BlockHeader->BlockSize - sizeof(LineFileBlockHeader);
+ if (LineInfoSize > Size)
+ return make_error<CodeViewError>(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<LineColumnEntry, FileLineInfoExtractor> 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
namespace codeview {
/// VarStreamArrayExtractor is intended to be specialized to provide customized
-/// extraction logic. It should return the total number of bytes of the next
-/// record (so that the array knows how much data to skip to get to the next
-/// record, and it should initialize the second parameter with the desired
-/// value type.
+/// extraction logic. On input it receives a StreamRef pointing to the
+/// beginning of the next record, but where the length of the record is not yet
+/// known. Upon completion, it should return an appropriate Error instance if
+/// a record could not be extracted, or if one could be extracted it should
+/// return success and set Len to the number of bytes this record occupied in
+/// the underlying stream, and it should fill out the fields of the value type
+/// Item appropriately to represent the current record.
+///
+/// You can specialize this template for your own custom value types to avoid
+/// having to specify a second template argument to VarStreamArray (documented
+/// below).
template <typename T> struct VarStreamArrayExtractor {
// Method intentionally deleted. You must provide an explicit specialization
- // with the following method implemented. On output return `Len` should
- // contain the number of bytes to consume from the stream, and `Item` should
- // be initialized with the proper value.
+ // with the following method implemented.
Error operator()(StreamRef Stream, uint32_t &Len, T &Item) const = delete;
};
/// example, could mean allocating huge amounts of memory just to allow
/// re-ordering of stream data to be contiguous before iterating over it. By
/// abstracting this out, we need not duplicate this memory, and we can
-/// iterate over arrays in arbitrarily formatted streams.
+/// iterate over arrays in arbitrarily formatted streams. Elements are parsed
+/// lazily on iteration, so there is no upfront cost associated with building
+/// a VarStreamArray, no matter how large it may be.
+///
+/// You create a VarStreamArray by specifying a ValueType and an Extractor type.
+/// If you do not specify an Extractor type, it expects you to specialize
+/// VarStreamArrayExtractor<T> for your ValueType.
+///
+/// By default an Extractor is default constructed in the class, but in some
+/// cases you might find it useful for an Extractor to maintain state across
+/// extractions. In this case you can provide your own Extractor through a
+/// secondary constructor. The following examples show various ways of
+/// creating a VarStreamArray.
+///
+/// // Will use VarStreamArrayExtractor<MyType> as the extractor.
+/// VarStreamArray<MyType> MyTypeArray;
+///
+/// // Will use a default-constructed MyExtractor as the extractor.
+/// VarStreamArray<MyType, MyExtractor> MyTypeArray2;
+///
+/// // Will use the specific instance of MyExtractor provided.
+/// // MyExtractor need not be default-constructible in this case.
+/// MyExtractor E(SomeContext);
+/// VarStreamArray<MyType, MyExtractor> MyTypeArray3(E);
+///
template <typename ValueType, typename Extractor> class VarStreamArrayIterator;
template <typename ValueType,
typedef VarStreamArrayIterator<ValueType, Extractor> Iterator;
VarStreamArray() {}
+ explicit VarStreamArray(const Extractor &E) : E(E) {}
- VarStreamArray(StreamRef Stream) : Stream(Stream) {}
+ explicit VarStreamArray(StreamRef Stream) : Stream(Stream) {}
+ VarStreamArray(StreamRef Stream, const Extractor &E) : Stream(Stream), E(E) {}
+
+ VarStreamArray(const VarStreamArray<ValueType, Extractor> &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 <typename ValueType, typename Extractor> class VarStreamArrayIterator {
typedef VarStreamArray<ValueType, Extractor> ArrayType;
public:
- VarStreamArrayIterator(const ArrayType &Array, bool *HadError = nullptr)
- : Array(&Array), IterRef(Array.Stream), HasError(false),
- HadError(HadError) {
+ VarStreamArrayIterator(const ArrayType &Array, const Extractor &E,
+ bool *HadError = nullptr)
+ : IterRef(Array.Stream), Array(&Array), HadError(HadError), Extract(E) {
auto EC = Extract(IterRef, ThisLen, ThisValue);
if (EC) {
consumeError(std::move(EC));
markError();
}
}
- VarStreamArrayIterator()
- : Array(nullptr), ThisLen(0), ThisValue(), IterRef(), HasError(false),
- HadError(nullptr) {}
+ VarStreamArrayIterator() {}
+ explicit VarStreamArrayIterator(const Extractor &E) : Extract(E) {}
~VarStreamArrayIterator() {}
bool operator==(const IterType &R) const {
*HadError = true;
}
- const ArrayType *Array;
- uint32_t ThisLen;
ValueType ThisValue;
StreamRef IterRef;
- bool HasError;
- bool *HadError;
+ const ArrayType *Array{nullptr};
+ uint32_t ThisLen{0};
+ bool HasError{false};
+ bool *HadError{nullptr};
Extractor Extract;
};
public:
FixedStreamArrayIterator(const FixedStreamArray<T> &Array)
: Array(Array), Index(uint32_t(-1)) {}
- FixedStreamArrayIterator(const FixedStreamArray<T> &Array, uint32_t Index)
- : Array(Array), Index(Index) {}
+ FixedStreamArrayIterator(const FixedStreamArray<T> &Array, uint32_t ArrayIndex)
+ : Array(Array), Index(ArrayIndex) {
+ if (Array.size() <= Index)
+ Index = uint32_t(-1);
+ }
bool operator==(const FixedStreamArrayIterator<T> &R) {
assert(&Array == &R.Array);
return Error::success();
}
- template <typename T>
- Error readArray(VarStreamArray<T> &Array, uint32_t Size) {
+ template <typename T, typename U>
+ Error readArray(VarStreamArray<T, U> &Array, uint32_t Size) {
StreamRef S;
if (auto EC = readStreamRef(S, Size))
return EC;
- Array = VarStreamArray<T>(S);
+ Array = VarStreamArray<T, U>(S, Array.getExtractor());
return Error::success();
}
#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"
#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 {
class ModStream {
public:
- typedef codeview::VarStreamArray<ModuleSubstreamRecord> LineInfoArray;
-
ModStream(PDBFile &File, const ModInfo &Module);
~ModStream();
iterator_range<codeview::CVSymbolArray::Iterator>
symbols(bool *HadError) const;
- iterator_range<LineInfoArray::Iterator> lines(bool *HadError) const;
+ iterator_range<codeview::ModuleSubstreamArray::Iterator>
+ lines(bool *HadError) const;
private:
const ModInfo &Mod;
codeview::StreamRef C13LinesSubstream;
codeview::StreamRef GlobalRefsSubstream;
- LineInfoArray LineInfo;
+ codeview::ModuleSubstreamArray LineInfo;
};
}
}
+++ /dev/null
-//===- 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<pdb::ModuleSubstreamRecord> {
- 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
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
ListRecordBuilder.cpp
MemoryTypeTableBuilder.cpp
MethodListRecordBuilder.cpp
+ ModuleSubstream.cpp
+ ModuleSubstreamVisitor.cpp
RecordSerialization.cpp
StreamReader.cpp
SymbolDumper.cpp
-//===- ModuleSubstreamRecord.cpp --------------------------------*- C++ -*-===//
+//===- ModuleSubstream.cpp --------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
//
//===----------------------------------------------------------------------===//
-#include "llvm/DebugInfo/PDB/Raw/ModuleSubstreamRecord.h"
+#include "llvm/DebugInfo/CodeView/ModuleSubstream.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) {}
+ModuleSubstream::ModuleSubstream() : Kind(ModuleSubstreamKind::None) {}
-ModuleSubstreamRecord::ModuleSubstreamRecord(ModuleSubstreamKind Kind,
- StreamRef Data)
+ModuleSubstream::ModuleSubstream(ModuleSubstreamKind Kind, StreamRef Data)
: Kind(Kind), Data(Data) {}
-Error ModuleSubstreamRecord::initialize(StreamRef Stream,
- ModuleSubstreamRecord &Info) {
+Error ModuleSubstream::initialize(StreamRef Stream, ModuleSubstream &Info) {
const ModuleSubsectionHeader *Header;
StreamReader Reader(Stream);
if (auto EC = Reader.readObject(Header))
return Error::success();
}
-uint32_t ModuleSubstreamRecord::getRecordLength() const {
+uint32_t ModuleSubstream::getRecordLength() const {
return sizeof(ModuleSubsectionHeader) + Data.getLength();
}
-ModuleSubstreamKind ModuleSubstreamRecord::getSubstreamKind() const {
- return Kind;
-}
+ModuleSubstreamKind ModuleSubstream::getSubstreamKind() const { return Kind; }
-StreamRef ModuleSubstreamRecord::getRecordData() const { return Data; }
+StreamRef ModuleSubstream::getRecordData() const { return Data; }
--- /dev/null
+//===- 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());
+ }
+}
Raw/InfoStream.cpp
Raw/MappedBlockStream.cpp
Raw/ModInfo.cpp
- Raw/ModuleSubstreamRecord.cpp
Raw/ModStream.cpp
Raw/NameHashTable.cpp
Raw/NameMap.cpp
SymbolsSubstream.end());
}
-iterator_range<ModStream::LineInfoArray::Iterator>
+iterator_range<codeview::ModuleSubstreamArray::Iterator>
ModStream::lines(bool *HadError) const {
return llvm::make_range(LineInfo.begin(HadError), LineInfo.end());
}
; EMPTY-NEXT: }
; EMPTY-NEXT: ]
; EMPTY-NEXT: LineInfo [
-; EMPTY-NEXT: {
-; EMPTY-NEXT: Kind: Lines (0xF2)
+; EMPTY-NEXT: Lines {
+; EMPTY-NEXT: FileOffset: 0
+; EMPTY-NEXT: Line {
+; EMPTY-NEXT: Offset: 0
+; EMPTY-NEXT: LineNumberStart: 5
+; EMPTY-NEXT: EndDelta: 0
+; EMPTY-NEXT: IsStatement: Yes
+; EMPTY-NEXT: }
+; EMPTY-NEXT: Line {
+; EMPTY-NEXT: Offset: 3
+; EMPTY-NEXT: LineNumberStart: 6
+; EMPTY-NEXT: EndDelta: 0
+; EMPTY-NEXT: IsStatement: Yes
+; EMPTY-NEXT: }
+; EMPTY-NEXT: Line {
+; EMPTY-NEXT: Offset: 8
+; EMPTY-NEXT: LineNumberStart: 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 |..&.....|
#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"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
+using namespace llvm::codeview;
using namespace llvm::pdb;
namespace opts {
ListScope SS(P, "Symbols");
codeview::CVSymbolDumper SD(P, TD, nullptr, false);
bool HadError = false;
- for (auto &S : ModS.symbols(&HadError)) {
+ for (const auto &S : ModS.symbols(&HadError)) {
DictScope DD(P, "");
if (opts::DumpModuleSyms)
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<uint8_t> Data;
- codeview::StreamReader R(L.getRecordData());
- if (auto EC = R.readBytes(Data, R.bytesRemaining())) {
- return make_error<RawError>(
- 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, "Lines");
+ for (const auto &L : Lines) {
+ P.printNumber("FileOffset", L.Offset);
+ for (const auto &N : L.LineNumbers) {
+ DictScope DDD(P, "Line");
+ LineInfo LI(N.Flags);
+ P.printNumber("Offset", N.Offset);
+ if (LI.isAlwaysStepInto())
+ P.printString("StepInto", StringRef("Always"));
+ else if (LI.isNeverStepInto())
+ P.printString("StepInto", StringRef("Never"));
+ else
+ P.printNumber("LineNumberStart", LI.getStartLine());
+ P.printNumber("EndDelta", LI.getLineDelta());
+ P.printBoolean("IsStatement", LI.isStatement());
+ }
+ for (const 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<uint8_t> Data;
+ StreamReader R(Stream);
+ if (auto EC = R.readBytes(Data, R.bytesRemaining())) {
+ return make_error<RawError>(
+ 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 (const auto &L : ModS.lines(&HadError)) {
+ if (auto EC = codeview::visitModuleSubstream(L, V))
+ return EC;
}
}
}
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...|