[codeview] Dump line number and column information.

To facilitate this, a couple of changes had to be made:

1. `ModuleSubstream` got moved from `DebugInfo/PDB` to
`DebugInfo/CodeView`, and various codeview related types are defined
there.  It turns out `DebugInfo/CodeView/Line.h` already defines many of
these structures, but this is really old code that is not endian aware,
doesn't interact well with `StreamInterface` and not very helpful for
getting stuff out of a PDB.  Eventually we should migrate the old readobj
`COFFDumper` code to these new structures, or at least merge their
functionality somehow.

2. A `ModuleSubstream` visitor is introduced.  Depending on where your
module substream array comes from, different subsets of record types can
be expected.  We are already hand parsing these substream arrays in many
places especially in `COFFDumper.cpp`.  In the future we can migrate these
paths to the visitor as well, which should reduce a lot of code in
`COFFDumper.cpp`.

Differential Revision: http://reviews.llvm.org/D20936
Reviewed By: ruiu, majnemer

llvm-svn: 271621
This commit is contained in:
Zachary Turner 2016-06-03 03:25:59 +00:00
parent 11c06b354c
commit a96cce64a5
16 changed files with 448 additions and 155 deletions

View File

@ -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<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

View File

@ -0,0 +1,96 @@
//===- 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

View File

@ -20,15 +20,20 @@ namespace llvm {
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;
};
@ -40,7 +45,31 @@ template <typename T> struct VarStreamArrayExtractor {
/// 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,
@ -52,17 +81,25 @@ public:
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 {
@ -70,18 +107,17 @@ 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 {
@ -146,12 +182,12 @@ private:
*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;
};
@ -196,8 +232,11 @@ template <typename T> class FixedStreamArrayIterator {
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);

View File

@ -52,12 +52,12 @@ public:
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();
}

View File

@ -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"

View File

@ -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 ModInfo;
class ModStream {
public:
typedef codeview::VarStreamArray<ModuleSubstreamRecord> LineInfoArray;
ModStream(PDBFile &File, const ModInfo &Module);
~ModStream();
@ -36,7 +34,8 @@ public:
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;
@ -48,7 +47,7 @@ private:
codeview::StreamRef C13LinesSubstream;
codeview::StreamRef GlobalRefsSubstream;
LineInfoArray LineInfo;
codeview::ModuleSubstreamArray LineInfo;
};
}
}

View File

@ -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<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

View File

@ -72,45 +72,6 @@ struct SecMapEntry {
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

View File

@ -7,6 +7,8 @@ add_llvm_library(LLVMDebugInfoCodeView
ListRecordBuilder.cpp
MemoryTypeTableBuilder.cpp
MethodListRecordBuilder.cpp
ModuleSubstream.cpp
ModuleSubstreamVisitor.cpp
RecordSerialization.cpp
StreamReader.cpp
SymbolDumper.cpp

View File

@ -1,4 +1,4 @@
//===- ModuleSubstreamRecord.cpp --------------------------------*- C++ -*-===//
//===- ModuleSubstream.cpp --------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@ -7,24 +7,19 @@
//
//===----------------------------------------------------------------------===//
#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))
@ -38,12 +33,10 @@ Error ModuleSubstreamRecord::initialize(StreamRef Stream,
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; }

View File

@ -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());
}
}

View File

@ -33,7 +33,6 @@ add_pdb_impl_folder(Raw
Raw/InfoStream.cpp
Raw/MappedBlockStream.cpp
Raw/ModInfo.cpp
Raw/ModuleSubstreamRecord.cpp
Raw/ModStream.cpp
Raw/NameHashTable.cpp
Raw/NameMap.cpp

View File

@ -69,7 +69,7 @@ ModStream::symbols(bool *HadError) const {
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());
}

View File

@ -331,16 +331,33 @@
; 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 |..&.....|

View File

@ -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 {
@ -499,7 +502,7 @@ static Error dumpDbiStream(ScopedPrinter &P, PDBFile &File,
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)
@ -515,18 +518,67 @@ static Error dumpDbiStream(ScopedPrinter &P, PDBFile &File,
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);
}
P.printBinaryBlock("Data", 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();
}
ScopedPrinter &P;
};
RecordVisitor V(P);
for (const auto &L : ModS.lines(&HadError)) {
if (auto EC = codeview::visitModuleSubstream(L, V))
return EC;
}
}
}

View File

@ -774,6 +774,7 @@ void COFFDumper::printCodeViewSymbolSection(StringRef SectionName,
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...|