CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(ModifierOptions)
enum class ModuleSubstreamKind : uint32_t {
+ None = 0,
Symbols = 0xf1,
Lines = 0xf2,
StringTable = 0xf3,
ArrayRef<EnumEntry<unsigned>> getCPUTypeNames();
ArrayRef<EnumEntry<uint32_t>> getFrameProcSymFlagNames();
ArrayRef<EnumEntry<uint16_t>> getExportSymFlagNames();
+ArrayRef<EnumEntry<uint32_t>> getModuleSubstreamKindNames();
ArrayRef<EnumEntry<uint8_t>> getThunkOrdinalNames();
ArrayRef<EnumEntry<uint16_t>> getTrampolineNames();
ArrayRef<EnumEntry<COFF::SectionCharacteristics>>
: Stream(&Stream), ViewOffset(0), Length(Stream.getLength()) {}
StreamRef(const StreamInterface &Stream, uint32_t Offset, uint32_t Length)
: Stream(&Stream), ViewOffset(Offset), Length(Length) {}
+
+ StreamRef(const StreamRef &Stream, uint32_t Offset, uint32_t Length) = delete;
StreamRef(const StreamRef &Other)
: Stream(Other.Stream), ViewOffset(Other.ViewOffset),
Length(Other.Length) {}
#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/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;
+
private:
const ModInfo &Mod;
codeview::StreamRef LinesSubstream;
codeview::StreamRef C13LinesSubstream;
codeview::StreamRef GlobalRefsSubstream;
+
+ LineInfoArray 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
CV_ENUM_CLASS_ENT(FrameProcedureOptions, GuardCfw),
};
+static const EnumEntry<uint32_t> ModuleSubstreamKindNames[] = {
+ CV_ENUM_CLASS_ENT(ModuleSubstreamKind, None),
+ CV_ENUM_CLASS_ENT(ModuleSubstreamKind, Symbols),
+ CV_ENUM_CLASS_ENT(ModuleSubstreamKind, Lines),
+ CV_ENUM_CLASS_ENT(ModuleSubstreamKind, StringTable),
+ CV_ENUM_CLASS_ENT(ModuleSubstreamKind, FileChecksums),
+ CV_ENUM_CLASS_ENT(ModuleSubstreamKind, FrameData),
+ CV_ENUM_CLASS_ENT(ModuleSubstreamKind, InlineeLines),
+ CV_ENUM_CLASS_ENT(ModuleSubstreamKind, CrossScopeImports),
+ CV_ENUM_CLASS_ENT(ModuleSubstreamKind, CrossScopeExports),
+ CV_ENUM_CLASS_ENT(ModuleSubstreamKind, ILLines),
+ CV_ENUM_CLASS_ENT(ModuleSubstreamKind, FuncMDTokenMap),
+ CV_ENUM_CLASS_ENT(ModuleSubstreamKind, TypeMDTokenMap),
+ CV_ENUM_CLASS_ENT(ModuleSubstreamKind, MergedAssemblyInput),
+ CV_ENUM_CLASS_ENT(ModuleSubstreamKind, CoffSymbolRVA),
+};
+
static const EnumEntry<uint16_t> ExportSymFlagNames[] = {
CV_ENUM_CLASS_ENT(ExportFlags, IsConstant),
CV_ENUM_CLASS_ENT(ExportFlags, IsData),
ArrayRef<EnumEntry<uint16_t>> getExportSymFlagNames() {
return makeArrayRef(ExportSymFlagNames);
}
+ArrayRef<EnumEntry<uint32_t>> getModuleSubstreamKindNames() {
+ return makeArrayRef(ModuleSubstreamKindNames);
+}
ArrayRef<EnumEntry<uint8_t>> getThunkOrdinalNames() {
return makeArrayRef(ThunkOrdinalNames);
}
using namespace llvm;
using namespace llvm::codeview;
-StreamReader::StreamReader(StreamRef Stream) : Stream(Stream), Offset(0) {}
+StreamReader::StreamReader(StreamRef S) : Stream(S), Offset(0) {}
Error StreamReader::readBytes(ArrayRef<uint8_t> &Buffer, uint32_t Size) {
if (auto EC = Stream.readBytes(Offset, Size, Buffer))
Raw/InfoStream.cpp
Raw/MappedBlockStream.cpp
Raw/ModInfo.cpp
+ Raw/ModuleSubstreamRecord.cpp
Raw/ModStream.cpp
Raw/NameHashTable.cpp
Raw/NameMap.cpp
#include "llvm/DebugInfo/PDB/Raw/ModInfo.h"
#include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
#include "llvm/DebugInfo/PDB/Raw/RawError.h"
+#include "llvm/DebugInfo/PDB/Raw/RawTypes.h"
using namespace llvm;
using namespace llvm::pdb;
return EC;
if (auto EC = Reader.readStreamRef(C13LinesSubstream, C13Size))
return EC;
- ArrayRef<uint8_t> LineBytes;
- codeview::StreamReader LinesReader(C13LinesSubstream);
- if (auto EC = LinesReader.readBytes(LineBytes, C13LinesSubstream.getLength()))
+
+ codeview::StreamReader LineReader(C13LinesSubstream);
+ if (auto EC = LineReader.readArray(LineInfo, LineReader.bytesRemaining()))
return EC;
uint32_t GlobalRefsSize;
return llvm::make_range(SymbolsSubstream.begin(HadError),
SymbolsSubstream.end());
}
+
+iterator_range<ModStream::LineInfoArray::Iterator>
+ModStream::lines(bool *HadError) const {
+ return llvm::make_range(LineInfo.begin(HadError), LineInfo.end());
+}
--- /dev/null
+//===- 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<ModuleSubstreamKind>(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; }
; RUN: llvm-pdbdump -raw-headers -raw-tpi-records -raw-tpi-record-bytes -raw-module-syms \
; RUN: -raw-sym-record-bytes -raw-publics -raw-module-files -raw-stream-name=/names \
; RUN: -raw-stream-summary -raw-stream-blocks -raw-ipi-records -raw-ipi-record-bytes \
-; RUN: -raw-section-contribs -raw-section-map -raw-section-headers %p/Inputs/empty.pdb \
-; RUN: | FileCheck -check-prefix=EMPTY %s
+; RUN: -raw-section-contribs -raw-section-map -raw-section-headers -raw-line-info \
+; RUN: %p/Inputs/empty.pdb | FileCheck -check-prefix=EMPTY %s
; RUN: llvm-pdbdump -raw-all %p/Inputs/empty.pdb | FileCheck -check-prefix=ALL %s
; RUN: llvm-pdbdump -raw-headers -raw-stream-name=/names -raw-modules -raw-module-files \
; RUN: %p/Inputs/big-read.pdb | FileCheck -check-prefix=BIG %s
; EMPTY-NEXT: )
; EMPTY-NEXT: }
; EMPTY-NEXT: ]
+; EMPTY-NEXT: LineInfo [
+; EMPTY-NEXT: {
+; EMPTY-NEXT: Kind: Lines (0xF2)
+; 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: Data (
+; EMPTY-NEXT: 0000: 56000000 1001A0A5 BD0D3ECD 93FC29D1 |V.........>...).|
+; EMPTY-NEXT: 0010: 9DE826FB F4BC0000 |..&.....|
+; EMPTY-NEXT: )
+; EMPTY-NEXT: }
+; EMPTY-NEXT: ]
; EMPTY-NEXT: }
; EMPTY-NEXT: {
; EMPTY-NEXT: Name: * Linker *
; EMPTY-NEXT: )
; EMPTY-NEXT: }
; EMPTY-NEXT: ]
+; EMPTY-NEXT: LineInfo [
+; EMPTY-NEXT: ]
; EMPTY-NEXT: }
; EMPTY-NEXT: ]
; EMPTY-NEXT: }
cl::opt<bool> DumpSectionContribs("raw-section-contribs",
cl::desc("dump section contributions"),
cl::cat(NativeOptions));
+cl::opt<bool> DumpLineInfo("raw-line-info",
+ cl::desc("dump file and line information"),
+ cl::cat(NativeOptions));
cl::opt<bool> DumpSectionMap("raw-section-map", cl::desc("dump section map"),
cl::cat(NativeOptions));
cl::opt<bool>
static Error dumpDbiStream(ScopedPrinter &P, PDBFile &File,
codeview::CVTypeDumper &TD) {
- bool DumpModules =
- opts::DumpModules || opts::DumpModuleSyms || opts::DumpModuleFiles;
+ bool DumpModules = opts::DumpModules || opts::DumpModuleSyms ||
+ opts::DumpModuleFiles || opts::DumpLineInfo;
if (!opts::DumpHeaders && !DumpModules)
return Error::success();
(Modi.Info.getModuleStreamIndex() < File.getNumStreams());
bool ShouldDumpSymbols =
(opts::DumpModuleSyms || opts::DumpSymRecordBytes);
- if (HasModuleDI && ShouldDumpSymbols) {
- ListScope SS(P, "Symbols");
+ if (HasModuleDI && (ShouldDumpSymbols || opts::DumpLineInfo)) {
ModStream ModS(File, Modi.Info);
if (auto EC = ModS.reload())
return EC;
- codeview::CVSymbolDumper SD(P, TD, nullptr, false);
- bool HadError = false;
- for (auto &S : ModS.symbols(&HadError)) {
- DictScope DD(P, "");
-
- if (opts::DumpModuleSyms)
- SD.dump(S);
- if (opts::DumpSymRecordBytes)
- P.printBinaryBlock("Bytes", S.Data);
+ if (ShouldDumpSymbols) {
+ ListScope SS(P, "Symbols");
+ codeview::CVSymbolDumper SD(P, TD, nullptr, false);
+ bool HadError = false;
+ for (auto &S : ModS.symbols(&HadError)) {
+ DictScope DD(P, "");
+
+ if (opts::DumpModuleSyms)
+ SD.dump(S);
+ if (opts::DumpSymRecordBytes)
+ P.printBinaryBlock("Bytes", S.Data);
+ }
+ if (HadError)
+ return make_error<RawError>(
+ raw_error_code::corrupt_file,
+ "DBI stream contained corrupt symbol record");
+ }
+ 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");
+ }
+ P.printBinaryBlock("Data", Data);
+ }
}
- if (HadError)
- return make_error<RawError>(raw_error_code::corrupt_file,
- "DBI stream contained corrupt record");
}
}
}
return true;
if (opts::DumpSectionMap)
return true;
+ if (opts::DumpLineInfo)
+ return true;
return false;
}
opts::DumpIpiRecords = true;
opts::DumpSectionMap = true;
opts::DumpSectionContribs = true;
+ opts::DumpLineInfo = true;
}
// When adding filters for excluded compilands and types, we need to remember