summaryrefslogtreecommitdiff
path: root/lib/DebugInfo/CodeView
diff options
context:
space:
mode:
Diffstat (limited to 'lib/DebugInfo/CodeView')
-rw-r--r--lib/DebugInfo/CodeView/ByteStream.cpp79
-rw-r--r--lib/DebugInfo/CodeView/CMakeLists.txt13
-rw-r--r--lib/DebugInfo/CodeView/CVTypeVisitor.cpp123
-rw-r--r--lib/DebugInfo/CodeView/CodeViewError.cpp67
-rw-r--r--lib/DebugInfo/CodeView/EnumTables.cpp375
-rw-r--r--lib/DebugInfo/CodeView/FieldListRecordBuilder.cpp141
-rw-r--r--lib/DebugInfo/CodeView/ListRecordBuilder.cpp87
-rw-r--r--lib/DebugInfo/CodeView/Makefile14
-rw-r--r--lib/DebugInfo/CodeView/MemoryTypeTableBuilder.cpp27
-rw-r--r--lib/DebugInfo/CodeView/MethodListRecordBuilder.cpp2
-rw-r--r--lib/DebugInfo/CodeView/ModuleSubstream.cpp42
-rw-r--r--lib/DebugInfo/CodeView/ModuleSubstreamVisitor.cpp104
-rw-r--r--lib/DebugInfo/CodeView/RecordSerialization.cpp171
-rw-r--r--lib/DebugInfo/CodeView/StreamReader.cpp93
-rw-r--r--lib/DebugInfo/CodeView/StreamWriter.cpp77
-rw-r--r--lib/DebugInfo/CodeView/SymbolDumper.cpp642
-rw-r--r--lib/DebugInfo/CodeView/TypeDumper.cpp696
-rw-r--r--lib/DebugInfo/CodeView/TypeRecord.cpp572
-rw-r--r--lib/DebugInfo/CodeView/TypeRecordBuilder.cpp36
-rw-r--r--lib/DebugInfo/CodeView/TypeStreamMerger.cpp149
-rw-r--r--lib/DebugInfo/CodeView/TypeTableBuilder.cpp224
21 files changed, 3529 insertions, 205 deletions
diff --git a/lib/DebugInfo/CodeView/ByteStream.cpp b/lib/DebugInfo/CodeView/ByteStream.cpp
new file mode 100644
index 0000000000000..2c43bc6958d26
--- /dev/null
+++ b/lib/DebugInfo/CodeView/ByteStream.cpp
@@ -0,0 +1,79 @@
+//===- ByteStream.cpp - Reads stream data from a byte sequence ------------===//
+//
+// 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/ByteStream.h"
+#include "llvm/DebugInfo/CodeView/CodeViewError.h"
+#include "llvm/DebugInfo/CodeView/StreamReader.h"
+#include <cstring>
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+static Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Src,
+ ArrayRef<uint8_t> Dest) {
+ return make_error<CodeViewError>(cv_error_code::operation_unsupported,
+ "ByteStream is immutable.");
+}
+
+static Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Src,
+ MutableArrayRef<uint8_t> Dest) {
+ if (Dest.size() < Src.size())
+ return make_error<CodeViewError>(cv_error_code::insufficient_buffer);
+ if (Offset > Src.size() - Dest.size())
+ return make_error<CodeViewError>(cv_error_code::insufficient_buffer);
+
+ ::memcpy(Dest.data() + Offset, Src.data(), Src.size());
+ return Error::success();
+}
+
+template <bool Writable>
+Error ByteStream<Writable>::readBytes(uint32_t Offset, uint32_t Size,
+ ArrayRef<uint8_t> &Buffer) const {
+ if (Offset > Data.size())
+ return make_error<CodeViewError>(cv_error_code::insufficient_buffer);
+ if (Data.size() < Size + Offset)
+ return make_error<CodeViewError>(cv_error_code::insufficient_buffer);
+ Buffer = Data.slice(Offset, Size);
+ return Error::success();
+}
+
+template <bool Writable>
+Error ByteStream<Writable>::readLongestContiguousChunk(
+ uint32_t Offset, ArrayRef<uint8_t> &Buffer) const {
+ if (Offset >= Data.size())
+ return make_error<CodeViewError>(cv_error_code::insufficient_buffer);
+ Buffer = Data.slice(Offset);
+ return Error::success();
+}
+
+template <bool Writable>
+Error ByteStream<Writable>::writeBytes(uint32_t Offset,
+ ArrayRef<uint8_t> Buffer) const {
+ return ::writeBytes(Offset, Buffer, Data);
+}
+
+template <bool Writable> uint32_t ByteStream<Writable>::getLength() const {
+ return Data.size();
+}
+
+template <bool Writable> Error ByteStream<Writable>::commit() const {
+ return Error::success();
+}
+
+template <bool Writable> StringRef ByteStream<Writable>::str() const {
+ const char *CharData = reinterpret_cast<const char *>(Data.data());
+ return StringRef(CharData, Data.size());
+}
+
+namespace llvm {
+namespace codeview {
+template class ByteStream<true>;
+template class ByteStream<false>;
+}
+}
diff --git a/lib/DebugInfo/CodeView/CMakeLists.txt b/lib/DebugInfo/CodeView/CMakeLists.txt
index cfa0e4d8b401a..47297a9131ee2 100644
--- a/lib/DebugInfo/CodeView/CMakeLists.txt
+++ b/lib/DebugInfo/CodeView/CMakeLists.txt
@@ -1,10 +1,23 @@
add_llvm_library(LLVMDebugInfoCodeView
+ ByteStream.cpp
+ CodeViewError.cpp
+ CVTypeVisitor.cpp
+ EnumTables.cpp
FieldListRecordBuilder.cpp
Line.cpp
ListRecordBuilder.cpp
MemoryTypeTableBuilder.cpp
MethodListRecordBuilder.cpp
+ ModuleSubstream.cpp
+ ModuleSubstreamVisitor.cpp
+ RecordSerialization.cpp
+ StreamReader.cpp
+ StreamWriter.cpp
+ SymbolDumper.cpp
+ TypeDumper.cpp
+ TypeRecord.cpp
TypeRecordBuilder.cpp
+ TypeStreamMerger.cpp
TypeTableBuilder.cpp
ADDITIONAL_HEADER_DIRS
diff --git a/lib/DebugInfo/CodeView/CVTypeVisitor.cpp b/lib/DebugInfo/CodeView/CVTypeVisitor.cpp
new file mode 100644
index 0000000000000..09f72214c52b1
--- /dev/null
+++ b/lib/DebugInfo/CodeView/CVTypeVisitor.cpp
@@ -0,0 +1,123 @@
+//===- CVTypeVisitor.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/CVTypeVisitor.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+template <typename T>
+static Error takeObject(ArrayRef<uint8_t> &Data, const T *&Res) {
+ if (Data.size() < sizeof(*Res))
+ return llvm::make_error<CodeViewError>(cv_error_code::insufficient_buffer);
+ Res = reinterpret_cast<const T *>(Data.data());
+ Data = Data.drop_front(sizeof(*Res));
+ return Error::success();
+}
+
+CVTypeVisitor::CVTypeVisitor(TypeVisitorCallbacks &Callbacks)
+ : Callbacks(Callbacks) {}
+
+Error CVTypeVisitor::visitTypeRecord(const CVRecord<TypeLeafKind> &Record) {
+ ArrayRef<uint8_t> LeafData = Record.Data;
+ if (auto EC = Callbacks.visitTypeBegin(Record))
+ return EC;
+ switch (Record.Type) {
+ default:
+ if (auto EC = Callbacks.visitUnknownType(Record))
+ return EC;
+ break;
+ case LF_FIELDLIST:
+ if (auto EC = Callbacks.visitFieldListBegin(Record))
+ return EC;
+ if (auto EC = visitFieldList(Record))
+ return EC;
+ if (auto EC = Callbacks.visitFieldListEnd(Record))
+ return EC;
+ break;
+#define TYPE_RECORD(EnumName, EnumVal, Name) \
+ case EnumName: { \
+ TypeRecordKind RK = static_cast<TypeRecordKind>(EnumName); \
+ auto Result = Name##Record::deserialize(RK, LeafData); \
+ if (Result.getError()) \
+ return llvm::make_error<CodeViewError>(cv_error_code::corrupt_record); \
+ if (auto EC = Callbacks.visit##Name(*Result)) \
+ return EC; \
+ break; \
+ }
+#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \
+ TYPE_RECORD(EnumVal, EnumVal, AliasName)
+#define MEMBER_RECORD(EnumName, EnumVal, Name)
+#include "llvm/DebugInfo/CodeView/TypeRecords.def"
+ }
+ if (auto EC = Callbacks.visitTypeEnd(Record))
+ return EC;
+ return Error::success();
+}
+
+/// Visits the type records in Data. Sets the error flag on parse failures.
+Error CVTypeVisitor::visitTypeStream(const CVTypeArray &Types) {
+ for (const auto &I : Types) {
+ if (auto EC = visitTypeRecord(I))
+ return EC;
+ }
+ return Error::success();
+}
+
+Error CVTypeVisitor::skipPadding(ArrayRef<uint8_t> &Data) {
+ if (Data.empty())
+ return Error::success();
+ uint8_t Leaf = Data.front();
+ if (Leaf < LF_PAD0)
+ return Error::success();
+ // Leaf is greater than 0xf0. We should advance by the number of bytes in
+ // the low 4 bits.
+ unsigned BytesToAdvance = Leaf & 0x0F;
+ if (Data.size() < BytesToAdvance) {
+ return llvm::make_error<CodeViewError>(cv_error_code::corrupt_record,
+ "Invalid padding bytes!");
+ }
+ Data = Data.drop_front(BytesToAdvance);
+ return Error::success();
+}
+
+/// Visits individual member records of a field list record. Member records do
+/// not describe their own length, and need special handling.
+Error CVTypeVisitor::visitFieldList(const CVRecord<TypeLeafKind> &Record) {
+ ArrayRef<uint8_t> RecordData = Record.Data;
+ while (!RecordData.empty()) {
+ const ulittle16_t *LeafPtr;
+ if (auto EC = takeObject(RecordData, LeafPtr))
+ return EC;
+ TypeLeafKind Leaf = TypeLeafKind(unsigned(*LeafPtr));
+ switch (Leaf) {
+ default:
+ // Field list records do not describe their own length, so we cannot
+ // continue parsing past an unknown member type.
+ if (auto EC = Callbacks.visitUnknownMember(Record))
+ return llvm::make_error<CodeViewError>(cv_error_code::corrupt_record);
+#define MEMBER_RECORD(EnumName, EnumVal, Name) \
+ case EnumName: { \
+ TypeRecordKind RK = static_cast<TypeRecordKind>(EnumName); \
+ auto Result = Name##Record::deserialize(RK, RecordData); \
+ if (Result.getError()) \
+ return llvm::make_error<CodeViewError>(cv_error_code::corrupt_record); \
+ if (auto EC = Callbacks.visit##Name(*Result)) \
+ return EC; \
+ break; \
+ }
+#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \
+ MEMBER_RECORD(EnumVal, EnumVal, AliasName)
+#include "llvm/DebugInfo/CodeView/TypeRecords.def"
+ }
+ if (auto EC = skipPadding(RecordData))
+ return EC;
+ }
+ return Error::success();
+}
diff --git a/lib/DebugInfo/CodeView/CodeViewError.cpp b/lib/DebugInfo/CodeView/CodeViewError.cpp
new file mode 100644
index 0000000000000..aad1d8b25cd06
--- /dev/null
+++ b/lib/DebugInfo/CodeView/CodeViewError.cpp
@@ -0,0 +1,67 @@
+//===- CodeViewError.cpp - Error extensions for CodeView --------*- 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/CodeViewError.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/ManagedStatic.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+namespace {
+// FIXME: This class is only here to support the transition to llvm::Error. It
+// will be removed once this transition is complete. Clients should prefer to
+// deal with the Error value directly, rather than converting to error_code.
+class CodeViewErrorCategory : public std::error_category {
+public:
+ const char *name() const LLVM_NOEXCEPT override { return "llvm.codeview"; }
+
+ std::string message(int Condition) const override {
+ switch (static_cast<cv_error_code>(Condition)) {
+ case cv_error_code::unspecified:
+ return "An unknown error has occurred.";
+ case cv_error_code::insufficient_buffer:
+ return "The buffer is not large enough to read the requested number of "
+ "bytes.";
+ case cv_error_code::corrupt_record:
+ return "The CodeView record is corrupted.";
+ case cv_error_code::operation_unsupported:
+ return "The requested operation is not supported.";
+ }
+ llvm_unreachable("Unrecognized cv_error_code");
+ }
+};
+} // end anonymous namespace
+
+static ManagedStatic<CodeViewErrorCategory> Category;
+
+char CodeViewError::ID = 0;
+
+CodeViewError::CodeViewError(cv_error_code C) : CodeViewError(C, "") {}
+
+CodeViewError::CodeViewError(const std::string &Context)
+ : CodeViewError(cv_error_code::unspecified, Context) {}
+
+CodeViewError::CodeViewError(cv_error_code C, const std::string &Context)
+ : Code(C) {
+ ErrMsg = "CodeView Error: ";
+ std::error_code EC = convertToErrorCode();
+ if (Code != cv_error_code::unspecified)
+ ErrMsg += EC.message() + " ";
+ if (!Context.empty())
+ ErrMsg += Context;
+}
+
+void CodeViewError::log(raw_ostream &OS) const { OS << ErrMsg << "\n"; }
+
+const std::string &CodeViewError::getErrorMessage() const { return ErrMsg; }
+
+std::error_code CodeViewError::convertToErrorCode() const {
+ return std::error_code(static_cast<int>(Code), *Category);
+}
diff --git a/lib/DebugInfo/CodeView/EnumTables.cpp b/lib/DebugInfo/CodeView/EnumTables.cpp
new file mode 100644
index 0000000000000..d59271b2367ec
--- /dev/null
+++ b/lib/DebugInfo/CodeView/EnumTables.cpp
@@ -0,0 +1,375 @@
+//===- EnumTables.cpp - Enum to string conversion tables --------*- 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/EnumTables.h"
+
+using namespace llvm;
+using namespace codeview;
+
+#define CV_ENUM_CLASS_ENT(enum_class, enum) \
+ { #enum, std::underlying_type < enum_class > ::type(enum_class::enum) }
+
+#define CV_ENUM_ENT(ns, enum) \
+ { #enum, ns::enum }
+
+static const EnumEntry<SymbolKind> SymbolTypeNames[] = {
+#define CV_SYMBOL(enum, val) {#enum, enum},
+#include "llvm/DebugInfo/CodeView/CVSymbolTypes.def"
+#undef CV_SYMBOL
+};
+
+static const EnumEntry<uint16_t> RegisterNames[] = {
+ CV_ENUM_CLASS_ENT(RegisterId, Unknown),
+ CV_ENUM_CLASS_ENT(RegisterId, VFrame),
+ CV_ENUM_CLASS_ENT(RegisterId, AL),
+ CV_ENUM_CLASS_ENT(RegisterId, CL),
+ CV_ENUM_CLASS_ENT(RegisterId, DL),
+ CV_ENUM_CLASS_ENT(RegisterId, BL),
+ CV_ENUM_CLASS_ENT(RegisterId, AH),
+ CV_ENUM_CLASS_ENT(RegisterId, CH),
+ CV_ENUM_CLASS_ENT(RegisterId, DH),
+ CV_ENUM_CLASS_ENT(RegisterId, BH),
+ CV_ENUM_CLASS_ENT(RegisterId, AX),
+ CV_ENUM_CLASS_ENT(RegisterId, CX),
+ CV_ENUM_CLASS_ENT(RegisterId, DX),
+ CV_ENUM_CLASS_ENT(RegisterId, BX),
+ CV_ENUM_CLASS_ENT(RegisterId, SP),
+ CV_ENUM_CLASS_ENT(RegisterId, BP),
+ CV_ENUM_CLASS_ENT(RegisterId, SI),
+ CV_ENUM_CLASS_ENT(RegisterId, DI),
+ CV_ENUM_CLASS_ENT(RegisterId, EAX),
+ CV_ENUM_CLASS_ENT(RegisterId, ECX),
+ CV_ENUM_CLASS_ENT(RegisterId, EDX),
+ CV_ENUM_CLASS_ENT(RegisterId, EBX),
+ CV_ENUM_CLASS_ENT(RegisterId, ESP),
+ CV_ENUM_CLASS_ENT(RegisterId, EBP),
+ CV_ENUM_CLASS_ENT(RegisterId, ESI),
+ CV_ENUM_CLASS_ENT(RegisterId, EDI),
+ CV_ENUM_CLASS_ENT(RegisterId, ES),
+ CV_ENUM_CLASS_ENT(RegisterId, CS),
+ CV_ENUM_CLASS_ENT(RegisterId, SS),
+ CV_ENUM_CLASS_ENT(RegisterId, DS),
+ CV_ENUM_CLASS_ENT(RegisterId, FS),
+ CV_ENUM_CLASS_ENT(RegisterId, GS),
+ CV_ENUM_CLASS_ENT(RegisterId, IP),
+ CV_ENUM_CLASS_ENT(RegisterId, RAX),
+ CV_ENUM_CLASS_ENT(RegisterId, RBX),
+ CV_ENUM_CLASS_ENT(RegisterId, RCX),
+ CV_ENUM_CLASS_ENT(RegisterId, RDX),
+ CV_ENUM_CLASS_ENT(RegisterId, RSI),
+ CV_ENUM_CLASS_ENT(RegisterId, RDI),
+ CV_ENUM_CLASS_ENT(RegisterId, RBP),
+ CV_ENUM_CLASS_ENT(RegisterId, RSP),
+ CV_ENUM_CLASS_ENT(RegisterId, R8),
+ CV_ENUM_CLASS_ENT(RegisterId, R9),
+ CV_ENUM_CLASS_ENT(RegisterId, R10),
+ CV_ENUM_CLASS_ENT(RegisterId, R11),
+ CV_ENUM_CLASS_ENT(RegisterId, R12),
+ CV_ENUM_CLASS_ENT(RegisterId, R13),
+ CV_ENUM_CLASS_ENT(RegisterId, R14),
+ CV_ENUM_CLASS_ENT(RegisterId, R15),
+};
+
+static const EnumEntry<uint8_t> ProcSymFlagNames[] = {
+ CV_ENUM_CLASS_ENT(ProcSymFlags, HasFP),
+ CV_ENUM_CLASS_ENT(ProcSymFlags, HasIRET),
+ CV_ENUM_CLASS_ENT(ProcSymFlags, HasFRET),
+ CV_ENUM_CLASS_ENT(ProcSymFlags, IsNoReturn),
+ CV_ENUM_CLASS_ENT(ProcSymFlags, IsUnreachable),
+ CV_ENUM_CLASS_ENT(ProcSymFlags, HasCustomCallingConv),
+ CV_ENUM_CLASS_ENT(ProcSymFlags, IsNoInline),
+ CV_ENUM_CLASS_ENT(ProcSymFlags, HasOptimizedDebugInfo),
+};
+
+static const EnumEntry<uint16_t> LocalFlags[] = {
+ CV_ENUM_CLASS_ENT(LocalSymFlags, IsParameter),
+ CV_ENUM_CLASS_ENT(LocalSymFlags, IsAddressTaken),
+ CV_ENUM_CLASS_ENT(LocalSymFlags, IsCompilerGenerated),
+ CV_ENUM_CLASS_ENT(LocalSymFlags, IsAggregate),
+ CV_ENUM_CLASS_ENT(LocalSymFlags, IsAggregated),
+ CV_ENUM_CLASS_ENT(LocalSymFlags, IsAliased),
+ CV_ENUM_CLASS_ENT(LocalSymFlags, IsAlias),
+ CV_ENUM_CLASS_ENT(LocalSymFlags, IsReturnValue),
+ CV_ENUM_CLASS_ENT(LocalSymFlags, IsOptimizedOut),
+ CV_ENUM_CLASS_ENT(LocalSymFlags, IsEnregisteredGlobal),
+ CV_ENUM_CLASS_ENT(LocalSymFlags, IsEnregisteredStatic),
+};
+
+static const EnumEntry<uint8_t> FrameCookieKinds[] = {
+ CV_ENUM_CLASS_ENT(FrameCookieKind, Copy),
+ CV_ENUM_CLASS_ENT(FrameCookieKind, XorStackPointer),
+ CV_ENUM_CLASS_ENT(FrameCookieKind, XorFramePointer),
+ CV_ENUM_CLASS_ENT(FrameCookieKind, XorR13),
+};
+
+static const EnumEntry<codeview::SourceLanguage> SourceLanguages[] = {
+ CV_ENUM_ENT(SourceLanguage, C), CV_ENUM_ENT(SourceLanguage, Cpp),
+ CV_ENUM_ENT(SourceLanguage, Fortran), CV_ENUM_ENT(SourceLanguage, Masm),
+ CV_ENUM_ENT(SourceLanguage, Pascal), CV_ENUM_ENT(SourceLanguage, Basic),
+ CV_ENUM_ENT(SourceLanguage, Cobol), CV_ENUM_ENT(SourceLanguage, Link),
+ CV_ENUM_ENT(SourceLanguage, Cvtres), CV_ENUM_ENT(SourceLanguage, Cvtpgd),
+ CV_ENUM_ENT(SourceLanguage, CSharp), CV_ENUM_ENT(SourceLanguage, VB),
+ CV_ENUM_ENT(SourceLanguage, ILAsm), CV_ENUM_ENT(SourceLanguage, Java),
+ CV_ENUM_ENT(SourceLanguage, JScript), CV_ENUM_ENT(SourceLanguage, MSIL),
+ CV_ENUM_ENT(SourceLanguage, HLSL),
+};
+
+static const EnumEntry<uint32_t> CompileSym2FlagNames[] = {
+ CV_ENUM_CLASS_ENT(CompileSym2Flags, EC),
+ CV_ENUM_CLASS_ENT(CompileSym2Flags, NoDbgInfo),
+ CV_ENUM_CLASS_ENT(CompileSym2Flags, LTCG),
+ CV_ENUM_CLASS_ENT(CompileSym2Flags, NoDataAlign),
+ CV_ENUM_CLASS_ENT(CompileSym2Flags, ManagedPresent),
+ CV_ENUM_CLASS_ENT(CompileSym2Flags, SecurityChecks),
+ CV_ENUM_CLASS_ENT(CompileSym2Flags, HotPatch),
+ CV_ENUM_CLASS_ENT(CompileSym2Flags, CVTCIL),
+ CV_ENUM_CLASS_ENT(CompileSym2Flags, MSILModule),
+};
+
+static const EnumEntry<uint32_t> CompileSym3FlagNames[] = {
+ CV_ENUM_CLASS_ENT(CompileSym3Flags, EC),
+ CV_ENUM_CLASS_ENT(CompileSym3Flags, NoDbgInfo),
+ CV_ENUM_CLASS_ENT(CompileSym3Flags, LTCG),
+ CV_ENUM_CLASS_ENT(CompileSym3Flags, NoDataAlign),
+ CV_ENUM_CLASS_ENT(CompileSym3Flags, ManagedPresent),
+ CV_ENUM_CLASS_ENT(CompileSym3Flags, SecurityChecks),
+ CV_ENUM_CLASS_ENT(CompileSym3Flags, HotPatch),
+ CV_ENUM_CLASS_ENT(CompileSym3Flags, CVTCIL),
+ CV_ENUM_CLASS_ENT(CompileSym3Flags, MSILModule),
+ CV_ENUM_CLASS_ENT(CompileSym3Flags, Sdl),
+ CV_ENUM_CLASS_ENT(CompileSym3Flags, PGO),
+ CV_ENUM_CLASS_ENT(CompileSym3Flags, Exp),
+};
+
+static const EnumEntry<uint32_t> FileChecksumNames[] = {
+ CV_ENUM_CLASS_ENT(FileChecksumKind, None),
+ CV_ENUM_CLASS_ENT(FileChecksumKind, MD5),
+ CV_ENUM_CLASS_ENT(FileChecksumKind, SHA1),
+ CV_ENUM_CLASS_ENT(FileChecksumKind, SHA256),
+};
+
+static const EnumEntry<unsigned> CPUTypeNames[] = {
+ CV_ENUM_CLASS_ENT(CPUType, Intel8080),
+ CV_ENUM_CLASS_ENT(CPUType, Intel8086),
+ CV_ENUM_CLASS_ENT(CPUType, Intel80286),
+ CV_ENUM_CLASS_ENT(CPUType, Intel80386),
+ CV_ENUM_CLASS_ENT(CPUType, Intel80486),
+ CV_ENUM_CLASS_ENT(CPUType, Pentium),
+ CV_ENUM_CLASS_ENT(CPUType, PentiumPro),
+ CV_ENUM_CLASS_ENT(CPUType, Pentium3),
+ CV_ENUM_CLASS_ENT(CPUType, MIPS),
+ CV_ENUM_CLASS_ENT(CPUType, MIPS16),
+ CV_ENUM_CLASS_ENT(CPUType, MIPS32),
+ CV_ENUM_CLASS_ENT(CPUType, MIPS64),
+ CV_ENUM_CLASS_ENT(CPUType, MIPSI),
+ CV_ENUM_CLASS_ENT(CPUType, MIPSII),
+ CV_ENUM_CLASS_ENT(CPUType, MIPSIII),
+ CV_ENUM_CLASS_ENT(CPUType, MIPSIV),
+ CV_ENUM_CLASS_ENT(CPUType, MIPSV),
+ CV_ENUM_CLASS_ENT(CPUType, M68000),
+ CV_ENUM_CLASS_ENT(CPUType, M68010),
+ CV_ENUM_CLASS_ENT(CPUType, M68020),
+ CV_ENUM_CLASS_ENT(CPUType, M68030),
+ CV_ENUM_CLASS_ENT(CPUType, M68040),
+ CV_ENUM_CLASS_ENT(CPUType, Alpha),
+ CV_ENUM_CLASS_ENT(CPUType, Alpha21164),
+ CV_ENUM_CLASS_ENT(CPUType, Alpha21164A),
+ CV_ENUM_CLASS_ENT(CPUType, Alpha21264),
+ CV_ENUM_CLASS_ENT(CPUType, Alpha21364),
+ CV_ENUM_CLASS_ENT(CPUType, PPC601),
+ CV_ENUM_CLASS_ENT(CPUType, PPC603),
+ CV_ENUM_CLASS_ENT(CPUType, PPC604),
+ CV_ENUM_CLASS_ENT(CPUType, PPC620),
+ CV_ENUM_CLASS_ENT(CPUType, PPCFP),
+ CV_ENUM_CLASS_ENT(CPUType, PPCBE),
+ CV_ENUM_CLASS_ENT(CPUType, SH3),
+ CV_ENUM_CLASS_ENT(CPUType, SH3E),
+ CV_ENUM_CLASS_ENT(CPUType, SH3DSP),
+ CV_ENUM_CLASS_ENT(CPUType, SH4),
+ CV_ENUM_CLASS_ENT(CPUType, SHMedia),
+ CV_ENUM_CLASS_ENT(CPUType, ARM3),
+ CV_ENUM_CLASS_ENT(CPUType, ARM4),
+ CV_ENUM_CLASS_ENT(CPUType, ARM4T),
+ CV_ENUM_CLASS_ENT(CPUType, ARM5),
+ CV_ENUM_CLASS_ENT(CPUType, ARM5T),
+ CV_ENUM_CLASS_ENT(CPUType, ARM6),
+ CV_ENUM_CLASS_ENT(CPUType, ARM_XMAC),
+ CV_ENUM_CLASS_ENT(CPUType, ARM_WMMX),
+ CV_ENUM_CLASS_ENT(CPUType, ARM7),
+ CV_ENUM_CLASS_ENT(CPUType, Omni),
+ CV_ENUM_CLASS_ENT(CPUType, Ia64),
+ CV_ENUM_CLASS_ENT(CPUType, Ia64_2),
+ CV_ENUM_CLASS_ENT(CPUType, CEE),
+ CV_ENUM_CLASS_ENT(CPUType, AM33),
+ CV_ENUM_CLASS_ENT(CPUType, M32R),
+ CV_ENUM_CLASS_ENT(CPUType, TriCore),
+ CV_ENUM_CLASS_ENT(CPUType, X64),
+ CV_ENUM_CLASS_ENT(CPUType, EBC),
+ CV_ENUM_CLASS_ENT(CPUType, Thumb),
+ CV_ENUM_CLASS_ENT(CPUType, ARMNT),
+ CV_ENUM_CLASS_ENT(CPUType, D3D11_Shader),
+};
+
+static const EnumEntry<uint32_t> FrameProcSymFlagNames[] = {
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, HasAlloca),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, HasSetJmp),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, HasLongJmp),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, HasInlineAssembly),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, HasExceptionHandling),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, MarkedInline),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, HasStructuredExceptionHandling),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, Naked),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, SecurityChecks),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, AsynchronousExceptionHandling),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, NoStackOrderingForSecurityChecks),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, Inlined),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, StrictSecurityChecks),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, SafeBuffers),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, ProfileGuidedOptimization),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, ValidProfileCounts),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, OptimizedForSpeed),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, GuardCfg),
+ 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),
+ CV_ENUM_CLASS_ENT(ExportFlags, IsPrivate),
+ CV_ENUM_CLASS_ENT(ExportFlags, HasNoName),
+ CV_ENUM_CLASS_ENT(ExportFlags, HasExplicitOrdinal),
+ CV_ENUM_CLASS_ENT(ExportFlags, IsForwarder),
+};
+
+static const EnumEntry<uint8_t> ThunkOrdinalNames[] = {
+ CV_ENUM_CLASS_ENT(ThunkOrdinal, Standard),
+ CV_ENUM_CLASS_ENT(ThunkOrdinal, ThisAdjustor),
+ CV_ENUM_CLASS_ENT(ThunkOrdinal, Vcall),
+ CV_ENUM_CLASS_ENT(ThunkOrdinal, Pcode),
+ CV_ENUM_CLASS_ENT(ThunkOrdinal, UnknownLoad),
+ CV_ENUM_CLASS_ENT(ThunkOrdinal, TrampIncremental),
+ CV_ENUM_CLASS_ENT(ThunkOrdinal, BranchIsland),
+};
+
+static const EnumEntry<uint16_t> TrampolineNames[] = {
+ CV_ENUM_CLASS_ENT(TrampolineType, TrampIncremental),
+ CV_ENUM_CLASS_ENT(TrampolineType, BranchIsland),
+};
+
+static const EnumEntry<COFF::SectionCharacteristics>
+ ImageSectionCharacteristicNames[] = {
+ CV_ENUM_ENT(COFF, IMAGE_SCN_TYPE_NOLOAD),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_TYPE_NO_PAD),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_CNT_CODE),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_CNT_INITIALIZED_DATA),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_CNT_UNINITIALIZED_DATA),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_LNK_OTHER),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_LNK_INFO),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_LNK_REMOVE),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_LNK_COMDAT),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_GPREL),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_PURGEABLE),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_16BIT),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_LOCKED),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_PRELOAD),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_1BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_2BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_4BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_8BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_16BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_32BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_64BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_128BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_256BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_512BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_1024BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_2048BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_4096BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_8192BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_LNK_NRELOC_OVFL),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_DISCARDABLE),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_NOT_CACHED),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_NOT_PAGED),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_SHARED),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_EXECUTE),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_READ),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_WRITE)};
+
+namespace llvm {
+namespace codeview {
+ArrayRef<EnumEntry<SymbolKind>> getSymbolTypeNames() {
+ return makeArrayRef(SymbolTypeNames);
+}
+
+ArrayRef<EnumEntry<uint16_t>> getRegisterNames() {
+ return makeArrayRef(RegisterNames);
+}
+
+ArrayRef<EnumEntry<uint8_t>> getProcSymFlagNames() {
+ return makeArrayRef(ProcSymFlagNames);
+}
+ArrayRef<EnumEntry<uint16_t>> getLocalFlagNames() {
+ return makeArrayRef(LocalFlags);
+}
+ArrayRef<EnumEntry<uint8_t>> getFrameCookieKindNames() {
+ return makeArrayRef(FrameCookieKinds);
+}
+ArrayRef<EnumEntry<SourceLanguage>> getSourceLanguageNames() {
+ return makeArrayRef(SourceLanguages);
+}
+ArrayRef<EnumEntry<uint32_t>> getCompileSym2FlagNames() {
+ return makeArrayRef(CompileSym2FlagNames);
+}
+ArrayRef<EnumEntry<uint32_t>> getCompileSym3FlagNames() {
+ return makeArrayRef(CompileSym3FlagNames);
+}
+ArrayRef<EnumEntry<uint32_t>> getFileChecksumNames() {
+ return makeArrayRef(FileChecksumNames);
+}
+ArrayRef<EnumEntry<unsigned>> getCPUTypeNames() {
+ return makeArrayRef(CPUTypeNames);
+}
+ArrayRef<EnumEntry<uint32_t>> getFrameProcSymFlagNames() {
+ return makeArrayRef(FrameProcSymFlagNames);
+}
+ArrayRef<EnumEntry<uint16_t>> getExportSymFlagNames() {
+ return makeArrayRef(ExportSymFlagNames);
+}
+ArrayRef<EnumEntry<uint32_t>> getModuleSubstreamKindNames() {
+ return makeArrayRef(ModuleSubstreamKindNames);
+}
+ArrayRef<EnumEntry<uint8_t>> getThunkOrdinalNames() {
+ return makeArrayRef(ThunkOrdinalNames);
+}
+ArrayRef<EnumEntry<uint16_t>> getTrampolineNames() {
+ return makeArrayRef(TrampolineNames);
+}
+ArrayRef<EnumEntry<COFF::SectionCharacteristics>>
+getImageSectionCharacteristicNames() {
+ return makeArrayRef(ImageSectionCharacteristicNames);
+}
+}
+}
diff --git a/lib/DebugInfo/CodeView/FieldListRecordBuilder.cpp b/lib/DebugInfo/CodeView/FieldListRecordBuilder.cpp
index 91b71cc4b1198..5f229e3d9f944 100644
--- a/lib/DebugInfo/CodeView/FieldListRecordBuilder.cpp
+++ b/lib/DebugInfo/CodeView/FieldListRecordBuilder.cpp
@@ -15,151 +15,118 @@ using namespace codeview;
FieldListRecordBuilder::FieldListRecordBuilder()
: ListRecordBuilder(TypeRecordKind::FieldList) {}
-void FieldListRecordBuilder::writeBaseClass(MemberAccess Access, TypeIndex Type,
- uint64_t Offset) {
+void FieldListRecordBuilder::writeBaseClass(const BaseClassRecord &Record) {
TypeRecordBuilder &Builder = getBuilder();
Builder.writeTypeRecordKind(TypeRecordKind::BaseClass);
- Builder.writeUInt16(static_cast<uint16_t>(Access));
- Builder.writeTypeIndex(Type);
- Builder.writeEncodedUnsignedInteger(Offset);
+ Builder.writeUInt16(static_cast<uint16_t>(Record.getAccess()));
+ Builder.writeTypeIndex(Record.getBaseType());
+ Builder.writeEncodedUnsignedInteger(Record.getBaseOffset());
finishSubRecord();
}
-void FieldListRecordBuilder::writeEnumerate(MemberAccess Access, uint64_t Value,
- StringRef Name) {
+void FieldListRecordBuilder::writeEnumerator(const EnumeratorRecord &Record) {
TypeRecordBuilder &Builder = getBuilder();
- Builder.writeTypeRecordKind(TypeRecordKind::Enumerate);
- Builder.writeUInt16(static_cast<uint16_t>(Access));
- Builder.writeEncodedUnsignedInteger(Value);
- Builder.writeNullTerminatedString(Name);
+ Builder.writeTypeRecordKind(TypeRecordKind::Enumerator);
+ Builder.writeUInt16(static_cast<uint16_t>(Record.getAccess()));
+ // FIXME: Handle full APInt such as __int128.
+ Builder.writeEncodedUnsignedInteger(Record.getValue().getZExtValue());
+ Builder.writeNullTerminatedString(Record.getName());
finishSubRecord();
}
-void FieldListRecordBuilder::writeMember(MemberAccess Access, TypeIndex Type,
- uint64_t Offset, StringRef Name) {
+void FieldListRecordBuilder::writeDataMember(const DataMemberRecord &Record) {
TypeRecordBuilder &Builder = getBuilder();
- Builder.writeTypeRecordKind(TypeRecordKind::Member);
- Builder.writeUInt16(static_cast<uint16_t>(Access));
- Builder.writeTypeIndex(Type);
- Builder.writeEncodedUnsignedInteger(Offset);
- Builder.writeNullTerminatedString(Name);
+ Builder.writeTypeRecordKind(Record.getKind());
+ Builder.writeUInt16(static_cast<uint16_t>(Record.getAccess()));
+ Builder.writeTypeIndex(Record.getType());
+ Builder.writeEncodedUnsignedInteger(Record.getFieldOffset());
+ Builder.writeNullTerminatedString(Record.getName());
finishSubRecord();
}
-void FieldListRecordBuilder::writeMethod(uint16_t OverloadCount,
- TypeIndex MethodList, StringRef Name) {
+void FieldListRecordBuilder::writeOverloadedMethod(
+ const OverloadedMethodRecord &Record) {
TypeRecordBuilder &Builder = getBuilder();
- Builder.writeTypeRecordKind(TypeRecordKind::Method);
- Builder.writeUInt16(OverloadCount);
- Builder.writeTypeIndex(MethodList);
- Builder.writeNullTerminatedString(Name);
+ Builder.writeTypeRecordKind(TypeRecordKind::OverloadedMethod);
+ Builder.writeUInt16(Record.getNumOverloads());
+ Builder.writeTypeIndex(Record.getMethodList());
+ Builder.writeNullTerminatedString(Record.getName());
finishSubRecord();
}
-void FieldListRecordBuilder::writeOneMethod(
- MemberAccess Access, MethodKind Kind, MethodOptions Options, TypeIndex Type,
- int32_t VTableSlotOffset, StringRef Name) {
+void FieldListRecordBuilder::writeOneMethod(const OneMethodRecord &Record) {
TypeRecordBuilder &Builder = getBuilder();
- uint16_t Flags = static_cast<uint16_t>(Access);
- Flags |= static_cast<uint16_t>(Kind) << MethodKindShift;
- Flags |= static_cast<uint16_t>(Options);
+ uint16_t Flags = static_cast<uint16_t>(Record.getAccess());
+ Flags |= static_cast<uint16_t>(Record.getKind()) << MethodKindShift;
+ Flags |= static_cast<uint16_t>(Record.getOptions());
Builder.writeTypeRecordKind(TypeRecordKind::OneMethod);
Builder.writeUInt16(Flags);
- Builder.writeTypeIndex(Type);
- switch (Kind) {
- case MethodKind::IntroducingVirtual:
- case MethodKind::PureIntroducingVirtual:
- assert(VTableSlotOffset >= 0);
- Builder.writeInt32(VTableSlotOffset);
- break;
-
- default:
- assert(VTableSlotOffset == -1);
- break;
+ Builder.writeTypeIndex(Record.getType());
+ if (Record.isIntroducingVirtual()) {
+ assert(Record.getVFTableOffset() >= 0);
+ Builder.writeInt32(Record.getVFTableOffset());
+ } else {
+ assert(Record.getVFTableOffset() == -1);
}
- Builder.writeNullTerminatedString(Name);
+ Builder.writeNullTerminatedString(Record.getName());
finishSubRecord();
}
-void FieldListRecordBuilder::writeOneMethod(const MethodInfo &Method,
- StringRef Name) {
- writeOneMethod(Method.getAccess(), Method.getKind(), Method.getOptions(),
- Method.getType(), Method.getVTableSlotOffset(), Name);
-}
-
-void FieldListRecordBuilder::writeNestedType(TypeIndex Type, StringRef Name) {
+void FieldListRecordBuilder::writeNestedType(const NestedTypeRecord &Record) {
TypeRecordBuilder &Builder = getBuilder();
- Builder.writeTypeRecordKind(TypeRecordKind::NestedType);
+ Builder.writeTypeRecordKind(Record.getKind());
Builder.writeUInt16(0);
- Builder.writeTypeIndex(Type);
- Builder.writeNullTerminatedString(Name);
+ Builder.writeTypeIndex(Record.getNestedType());
+ Builder.writeNullTerminatedString(Record.getName());
finishSubRecord();
}
-void FieldListRecordBuilder::writeStaticMember(MemberAccess Access,
- TypeIndex Type, StringRef Name) {
+void FieldListRecordBuilder::writeStaticDataMember(
+ const StaticDataMemberRecord &Record) {
TypeRecordBuilder &Builder = getBuilder();
- Builder.writeTypeRecordKind(TypeRecordKind::StaticMember);
- Builder.writeUInt16(static_cast<uint16_t>(Access));
- Builder.writeTypeIndex(Type);
- Builder.writeNullTerminatedString(Name);
+ Builder.writeTypeRecordKind(Record.getKind());
+ Builder.writeUInt16(static_cast<uint16_t>(Record.getAccess()));
+ Builder.writeTypeIndex(Record.getType());
+ Builder.writeNullTerminatedString(Record.getName());
finishSubRecord();
}
-void FieldListRecordBuilder::writeIndirectVirtualBaseClass(
- MemberAccess Access, TypeIndex Type, TypeIndex VirtualBasePointerType,
- int64_t VirtualBasePointerOffset, uint64_t SlotIndex) {
- writeVirtualBaseClass(TypeRecordKind::IndirectVirtualBaseClass, Access, Type,
- VirtualBasePointerType, VirtualBasePointerOffset,
- SlotIndex);
-}
-
void FieldListRecordBuilder::writeVirtualBaseClass(
- MemberAccess Access, TypeIndex Type, TypeIndex VirtualBasePointerType,
- int64_t VirtualBasePointerOffset, uint64_t SlotIndex) {
- writeVirtualBaseClass(TypeRecordKind::VirtualBaseClass, Access, Type,
- VirtualBasePointerType, VirtualBasePointerOffset,
- SlotIndex);
-}
-
-void FieldListRecordBuilder::writeVirtualBaseClass(
- TypeRecordKind Kind, MemberAccess Access, TypeIndex Type,
- TypeIndex VirtualBasePointerType, int64_t VirtualBasePointerOffset,
- uint64_t SlotIndex) {
+ const VirtualBaseClassRecord &Record) {
TypeRecordBuilder &Builder = getBuilder();
- Builder.writeTypeRecordKind(Kind);
- Builder.writeUInt16(static_cast<uint16_t>(Access));
- Builder.writeTypeIndex(Type);
- Builder.writeTypeIndex(VirtualBasePointerType);
- Builder.writeEncodedInteger(VirtualBasePointerOffset);
- Builder.writeEncodedUnsignedInteger(SlotIndex);
+ Builder.writeTypeRecordKind(Record.getKind());
+ Builder.writeUInt16(static_cast<uint16_t>(Record.getAccess()));
+ Builder.writeTypeIndex(Record.getBaseType());
+ Builder.writeTypeIndex(Record.getVBPtrType());
+ Builder.writeEncodedInteger(Record.getVBPtrOffset());
+ Builder.writeEncodedUnsignedInteger(Record.getVTableIndex());
finishSubRecord();
}
-void FieldListRecordBuilder::writeVirtualFunctionTablePointer(TypeIndex Type) {
+void FieldListRecordBuilder::writeVFPtr(const VFPtrRecord &Record) {
TypeRecordBuilder &Builder = getBuilder();
- Builder.writeTypeRecordKind(TypeRecordKind::VirtualFunctionTablePointer);
+ Builder.writeTypeRecordKind(TypeRecordKind::VFPtr);
Builder.writeUInt16(0);
- Builder.writeTypeIndex(Type);
+ Builder.writeTypeIndex(Record.getType());
finishSubRecord();
-} \ No newline at end of file
+}
diff --git a/lib/DebugInfo/CodeView/ListRecordBuilder.cpp b/lib/DebugInfo/CodeView/ListRecordBuilder.cpp
index 69c7e87330e6d..eb79e8ac9a3fe 100644
--- a/lib/DebugInfo/CodeView/ListRecordBuilder.cpp
+++ b/lib/DebugInfo/CodeView/ListRecordBuilder.cpp
@@ -7,25 +7,96 @@
//
//===----------------------------------------------------------------------===//
+#include "llvm/ADT/SmallString.h"
#include "llvm/DebugInfo/CodeView/ListRecordBuilder.h"
+#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
using namespace llvm;
using namespace codeview;
-ListRecordBuilder::ListRecordBuilder(TypeRecordKind Kind) : Builder(Kind) {}
+ListRecordBuilder::ListRecordBuilder(TypeRecordKind Kind)
+ : Kind(Kind), Builder(Kind) {}
+
+void ListRecordBuilder::writeListContinuation(const ListContinuationRecord &R) {
+ TypeRecordBuilder &Builder = getBuilder();
+
+ assert(getLastContinuationSize() < 65535 - 8 && "continuation won't fit");
+
+ Builder.writeTypeRecordKind(TypeRecordKind::ListContinuation);
+ Builder.writeUInt16(0);
+ Builder.writeTypeIndex(R.getContinuationIndex());
+
+ // End the current segment manually so that nothing comes after the
+ // continuation.
+ ContinuationOffsets.push_back(Builder.size());
+ SubrecordStart = Builder.size();
+}
void ListRecordBuilder::finishSubRecord() {
- // The builder starts at offset 2 in the actual CodeView buffer, so add an
- // additional offset of 2 before computing the alignment.
- uint32_t Remainder = (Builder.size() + 2) % 4;
+ // The type table inserts a 16 bit size field before each list, so factor that
+ // into our alignment padding.
+ uint32_t Remainder =
+ (Builder.size() + 2 * (ContinuationOffsets.size() + 1)) % 4;
if (Remainder != 0) {
for (int32_t PaddingBytesLeft = 4 - Remainder; PaddingBytesLeft > 0;
--PaddingBytesLeft) {
- Builder.writeUInt8(0xf0 + PaddingBytesLeft);
+ Builder.writeUInt8(LF_PAD0 + PaddingBytesLeft);
}
}
- // TODO: Split the list into multiple records if it's longer than 64KB, using
- // a subrecord of TypeRecordKind::Index to chain the records together.
- assert(Builder.size() < 65536);
+ // Check if this subrecord makes the current segment not fit in 64K minus the
+ // space for a continuation record (8 bytes). If the segment does not fit,
+ // back up and insert a continuation record, sliding the current subrecord
+ // down.
+ if (getLastContinuationSize() > 65535 - 8) {
+ assert(SubrecordStart != 0 && "can't slide from the start!");
+ SmallString<128> SubrecordCopy(
+ Builder.str().slice(SubrecordStart, Builder.size()));
+ assert(SubrecordCopy.size() < 65530 && "subrecord is too large to slide!");
+ Builder.truncate(SubrecordStart);
+
+ // Write a placeholder continuation record.
+ Builder.writeTypeRecordKind(TypeRecordKind::ListContinuation);
+ Builder.writeUInt16(0);
+ Builder.writeUInt32(0);
+ ContinuationOffsets.push_back(Builder.size());
+ assert(Builder.size() == SubrecordStart + 8 && "wrong continuation size");
+ assert(getLastContinuationSize() < 65535 && "segment too big");
+
+ // Start a new list record of the appropriate kind, and copy the previous
+ // subrecord into place.
+ Builder.writeTypeRecordKind(Kind);
+ Builder.writeBytes(SubrecordCopy);
+ }
+
+ SubrecordStart = Builder.size();
+}
+
+TypeIndex ListRecordBuilder::writeListRecord(TypeTableBuilder &Table) {
+ // Get the continuation segments as a reversed vector of StringRefs for
+ // convenience.
+ SmallVector<StringRef, 1> Segments;
+ StringRef Data = str();
+ size_t LastEnd = 0;
+ for (size_t SegEnd : ContinuationOffsets) {
+ Segments.push_back(Data.slice(LastEnd, SegEnd));
+ LastEnd = SegEnd;
+ }
+ Segments.push_back(Data.slice(LastEnd, Builder.size()));
+
+ // Pop the last record off and emit it directly.
+ StringRef LastRec = Segments.pop_back_val();
+ TypeIndex ContinuationIndex = Table.writeRecord(LastRec);
+
+ // Emit each record with a continuation in reverse order, so that each one
+ // references the previous record.
+ for (StringRef Rec : reverse(Segments)) {
+ assert(*reinterpret_cast<const ulittle16_t *>(Rec.data()) ==
+ unsigned(Kind));
+ ulittle32_t *ContinuationPtr =
+ reinterpret_cast<ulittle32_t *>(const_cast<char *>(Rec.end())) - 1;
+ *ContinuationPtr = ContinuationIndex.getIndex();
+ ContinuationIndex = Table.writeRecord(Rec);
+ }
+ return ContinuationIndex;
}
diff --git a/lib/DebugInfo/CodeView/Makefile b/lib/DebugInfo/CodeView/Makefile
deleted file mode 100644
index 535bc10b74426..0000000000000
--- a/lib/DebugInfo/CodeView/Makefile
+++ /dev/null
@@ -1,14 +0,0 @@
-##===- lib/DebugInfo/CodeView/Makefile ---------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-LEVEL = ../../..
-LIBRARYNAME = LLVMDebugInfoCodeView
-BUILD_ARCHIVE := 1
-
-include $(LEVEL)/Makefile.common
diff --git a/lib/DebugInfo/CodeView/MemoryTypeTableBuilder.cpp b/lib/DebugInfo/CodeView/MemoryTypeTableBuilder.cpp
index 9afce92eeb1d7..8b9e73b94ff5f 100644
--- a/lib/DebugInfo/CodeView/MemoryTypeTableBuilder.cpp
+++ b/lib/DebugInfo/CodeView/MemoryTypeTableBuilder.cpp
@@ -13,23 +13,34 @@
using namespace llvm;
using namespace codeview;
-MemoryTypeTableBuilder::Record::Record(StringRef RData)
- : Size(RData.size()), Data(new char[RData.size()]) {
- memcpy(Data.get(), RData.data(), RData.size());
-}
-
TypeIndex MemoryTypeTableBuilder::writeRecord(StringRef Data) {
+ assert(Data.size() <= UINT16_MAX);
auto I = HashedRecords.find(Data);
if (I != HashedRecords.end()) {
return I->second;
}
- std::unique_ptr<Record> R(new Record(Data));
+ // The record provided by the user lacks the 2 byte size field prefix and is
+ // not padded to 4 bytes. Ultimately, that is what gets emitted in the object
+ // file, so pad it out now.
+ const int SizeOfRecLen = 2;
+ const int Align = 4;
+ int TotalSize = alignTo(Data.size() + SizeOfRecLen, Align);
+ assert(TotalSize - SizeOfRecLen <= UINT16_MAX);
+ char *Mem =
+ reinterpret_cast<char *>(RecordStorage.Allocate(TotalSize, Align));
+ *reinterpret_cast<ulittle16_t *>(Mem) = uint16_t(TotalSize - SizeOfRecLen);
+ memcpy(Mem + SizeOfRecLen, Data.data(), Data.size());
+ for (int I = Data.size() + SizeOfRecLen; I < TotalSize; ++I)
+ Mem[I] = LF_PAD0 + (TotalSize - I);
TypeIndex TI(static_cast<uint32_t>(Records.size()) +
TypeIndex::FirstNonSimpleIndex);
- HashedRecords.insert(std::make_pair(StringRef(R->data(), R->size()), TI));
- Records.push_back(std::move(R));
+
+ // Use only the data supplied by the user as a key to the hash table, so that
+ // future lookups will succeed.
+ HashedRecords.insert(std::make_pair(StringRef(Mem + SizeOfRecLen, Data.size()), TI));
+ Records.push_back(StringRef(Mem, TotalSize));
return TI;
}
diff --git a/lib/DebugInfo/CodeView/MethodListRecordBuilder.cpp b/lib/DebugInfo/CodeView/MethodListRecordBuilder.cpp
index 889302556b2df..ae089a3520811 100644
--- a/lib/DebugInfo/CodeView/MethodListRecordBuilder.cpp
+++ b/lib/DebugInfo/CodeView/MethodListRecordBuilder.cpp
@@ -14,7 +14,7 @@ using namespace llvm;
using namespace codeview;
MethodListRecordBuilder::MethodListRecordBuilder()
- : ListRecordBuilder(TypeRecordKind::MethodList) {}
+ : ListRecordBuilder(TypeRecordKind::MethodOverloadList) {}
void MethodListRecordBuilder::writeMethod(MemberAccess Access, MethodKind Kind,
MethodOptions Options, TypeIndex Type,
diff --git a/lib/DebugInfo/CodeView/ModuleSubstream.cpp b/lib/DebugInfo/CodeView/ModuleSubstream.cpp
new file mode 100644
index 0000000000000..2e31ed6b5b7f6
--- /dev/null
+++ b/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<ModuleSubstreamKind>(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; }
diff --git a/lib/DebugInfo/CodeView/ModuleSubstreamVisitor.cpp b/lib/DebugInfo/CodeView/ModuleSubstreamVisitor.cpp
new file mode 100644
index 0000000000000..6f237ee67fe4b
--- /dev/null
+++ b/lib/DebugInfo/CodeView/ModuleSubstreamVisitor.cpp
@@ -0,0 +1,104 @@
+//===- 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,
+ const LineInfoArray &Lines) {
+ return visitUnknown(ModuleSubstreamKind::Lines, Data);
+}
+Error IModuleSubstreamVisitor::visitStringTable(StreamRef Data) {
+ return visitUnknown(ModuleSubstreamKind::StringTable, Data);
+}
+Error IModuleSubstreamVisitor::visitFileChecksums(
+ StreamRef Data, const FileChecksumArray &Checksums) {
+ 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;
+ VarStreamArrayExtractor<LineColumnEntry> 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: {
+ StreamReader Reader(R.getRecordData());
+ FileChecksumArray Checksums;
+ if (auto EC = Reader.readArray(Checksums, Reader.bytesRemaining()))
+ return EC;
+ return V.visitFileChecksums(R.getRecordData(), Checksums);
+ }
+ 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());
+ }
+}
diff --git a/lib/DebugInfo/CodeView/RecordSerialization.cpp b/lib/DebugInfo/CodeView/RecordSerialization.cpp
new file mode 100644
index 0000000000000..ab9206a33ec0a
--- /dev/null
+++ b/lib/DebugInfo/CodeView/RecordSerialization.cpp
@@ -0,0 +1,171 @@
+//===-- RecordSerialization.cpp -------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Utilities for serializing and deserializing CodeView records.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/RecordSerialization.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/APSInt.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::support;
+
+/// Reinterpret a byte array as an array of characters. Does not interpret as
+/// a C string, as StringRef has several helpers (split) that make that easy.
+StringRef llvm::codeview::getBytesAsCharacters(ArrayRef<uint8_t> LeafData) {
+ return StringRef(reinterpret_cast<const char *>(LeafData.data()),
+ LeafData.size());
+}
+
+StringRef llvm::codeview::getBytesAsCString(ArrayRef<uint8_t> LeafData) {
+ return getBytesAsCharacters(LeafData).split('\0').first;
+}
+
+std::error_code llvm::codeview::consume(ArrayRef<uint8_t> &Data, APSInt &Num) {
+ // Used to avoid overload ambiguity on APInt construtor.
+ bool FalseVal = false;
+ if (Data.size() < 2)
+ return std::make_error_code(std::errc::illegal_byte_sequence);
+ uint16_t Short = *reinterpret_cast<const ulittle16_t *>(Data.data());
+ Data = Data.drop_front(2);
+ if (Short < LF_NUMERIC) {
+ Num = APSInt(APInt(/*numBits=*/16, Short, /*isSigned=*/false),
+ /*isUnsigned=*/true);
+ return std::error_code();
+ }
+ switch (Short) {
+ case LF_CHAR:
+ if (Data.size() < 1)
+ return std::make_error_code(std::errc::illegal_byte_sequence);
+ Num = APSInt(APInt(/*numBits=*/8,
+ *reinterpret_cast<const int8_t *>(Data.data()),
+ /*isSigned=*/true),
+ /*isUnsigned=*/false);
+ Data = Data.drop_front(1);
+ return std::error_code();
+ case LF_SHORT:
+ if (Data.size() < 2)
+ return std::make_error_code(std::errc::illegal_byte_sequence);
+ Num = APSInt(APInt(/*numBits=*/16,
+ *reinterpret_cast<const little16_t *>(Data.data()),
+ /*isSigned=*/true),
+ /*isUnsigned=*/false);
+ Data = Data.drop_front(2);
+ return std::error_code();
+ case LF_USHORT:
+ if (Data.size() < 2)
+ return std::make_error_code(std::errc::illegal_byte_sequence);
+ Num = APSInt(APInt(/*numBits=*/16,
+ *reinterpret_cast<const ulittle16_t *>(Data.data()),
+ /*isSigned=*/false),
+ /*isUnsigned=*/true);
+ Data = Data.drop_front(2);
+ return std::error_code();
+ case LF_LONG:
+ if (Data.size() < 4)
+ return std::make_error_code(std::errc::illegal_byte_sequence);
+ Num = APSInt(APInt(/*numBits=*/32,
+ *reinterpret_cast<const little32_t *>(Data.data()),
+ /*isSigned=*/true),
+ /*isUnsigned=*/false);
+ Data = Data.drop_front(4);
+ return std::error_code();
+ case LF_ULONG:
+ if (Data.size() < 4)
+ return std::make_error_code(std::errc::illegal_byte_sequence);
+ Num = APSInt(APInt(/*numBits=*/32,
+ *reinterpret_cast<const ulittle32_t *>(Data.data()),
+ /*isSigned=*/FalseVal),
+ /*isUnsigned=*/true);
+ Data = Data.drop_front(4);
+ return std::error_code();
+ case LF_QUADWORD:
+ if (Data.size() < 8)
+ return std::make_error_code(std::errc::illegal_byte_sequence);
+ Num = APSInt(APInt(/*numBits=*/64,
+ *reinterpret_cast<const little64_t *>(Data.data()),
+ /*isSigned=*/true),
+ /*isUnsigned=*/false);
+ Data = Data.drop_front(8);
+ return std::error_code();
+ case LF_UQUADWORD:
+ if (Data.size() < 8)
+ return std::make_error_code(std::errc::illegal_byte_sequence);
+ Num = APSInt(APInt(/*numBits=*/64,
+ *reinterpret_cast<const ulittle64_t *>(Data.data()),
+ /*isSigned=*/false),
+ /*isUnsigned=*/true);
+ Data = Data.drop_front(8);
+ return std::error_code();
+ }
+ return std::make_error_code(std::errc::illegal_byte_sequence);
+}
+
+std::error_code llvm::codeview::consume(StringRef &Data, APSInt &Num) {
+ ArrayRef<uint8_t> Bytes(Data.bytes_begin(), Data.bytes_end());
+ auto EC = consume(Bytes, Num);
+ Data = StringRef(reinterpret_cast<const char *>(Bytes.data()), Bytes.size());
+ return EC;
+}
+
+/// Decode a numeric leaf value that is known to be a uint64_t.
+std::error_code llvm::codeview::consume_numeric(ArrayRef<uint8_t> &Data,
+ uint64_t &Num) {
+ APSInt N;
+ if (auto EC = consume(Data, N))
+ return EC;
+ if (N.isSigned() || !N.isIntN(64))
+ return std::make_error_code(std::errc::illegal_byte_sequence);
+ Num = N.getLimitedValue();
+ return std::error_code();
+}
+
+std::error_code llvm::codeview::consume(ArrayRef<uint8_t> &Data,
+ uint32_t &Item) {
+ const support::ulittle32_t *IntPtr;
+ if (auto EC = consumeObject(Data, IntPtr))
+ return EC;
+ Item = *IntPtr;
+ return std::error_code();
+}
+
+std::error_code llvm::codeview::consume(StringRef &Data, uint32_t &Item) {
+ ArrayRef<uint8_t> Bytes(Data.bytes_begin(), Data.bytes_end());
+ auto EC = consume(Bytes, Item);
+ Data = StringRef(reinterpret_cast<const char *>(Bytes.data()), Bytes.size());
+ return EC;
+}
+
+std::error_code llvm::codeview::consume(ArrayRef<uint8_t> &Data,
+ int32_t &Item) {
+ const support::little32_t *IntPtr;
+ if (auto EC = consumeObject(Data, IntPtr))
+ return EC;
+ Item = *IntPtr;
+ return std::error_code();
+}
+
+std::error_code llvm::codeview::consume(ArrayRef<uint8_t> &Data,
+ StringRef &Item) {
+ if (Data.empty())
+ return std::make_error_code(std::errc::illegal_byte_sequence);
+
+ StringRef Rest;
+ std::tie(Item, Rest) = getBytesAsCharacters(Data).split('\0');
+ // We expect this to be null terminated. If it was not, it is an error.
+ if (Data.size() == Item.size())
+ return std::make_error_code(std::errc::illegal_byte_sequence);
+
+ Data = ArrayRef<uint8_t>(Rest.bytes_begin(), Rest.bytes_end());
+ return std::error_code();
+}
diff --git a/lib/DebugInfo/CodeView/StreamReader.cpp b/lib/DebugInfo/CodeView/StreamReader.cpp
new file mode 100644
index 0000000000000..64e45487322ee
--- /dev/null
+++ b/lib/DebugInfo/CodeView/StreamReader.cpp
@@ -0,0 +1,93 @@
+//===- StreamReader.cpp - Reads bytes and objects from a stream -----------===//
+//
+// 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/StreamReader.h"
+
+#include "llvm/DebugInfo/CodeView/CodeViewError.h"
+#include "llvm/DebugInfo/CodeView/StreamRef.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+StreamReader::StreamReader(StreamRef S) : Stream(S), Offset(0) {}
+
+Error StreamReader::readLongestContiguousChunk(ArrayRef<uint8_t> &Buffer) {
+ if (auto EC = Stream.readLongestContiguousChunk(Offset, Buffer))
+ return EC;
+ Offset += Buffer.size();
+ return Error::success();
+}
+
+Error StreamReader::readBytes(ArrayRef<uint8_t> &Buffer, uint32_t Size) {
+ if (auto EC = Stream.readBytes(Offset, Size, Buffer))
+ return EC;
+ Offset += Size;
+ return Error::success();
+}
+
+Error StreamReader::readInteger(uint16_t &Dest) {
+ const support::ulittle16_t *P;
+ if (auto EC = readObject(P))
+ return EC;
+ Dest = *P;
+ return Error::success();
+}
+
+Error StreamReader::readInteger(uint32_t &Dest) {
+ const support::ulittle32_t *P;
+ if (auto EC = readObject(P))
+ return EC;
+ Dest = *P;
+ return Error::success();
+}
+
+Error StreamReader::readZeroString(StringRef &Dest) {
+ uint32_t Length = 0;
+ // First compute the length of the string by reading 1 byte at a time.
+ uint32_t OriginalOffset = getOffset();
+ const char *C;
+ do {
+ if (auto EC = readObject(C))
+ return EC;
+ if (*C != '\0')
+ ++Length;
+ } while (*C != '\0');
+ // Now go back and request a reference for that many bytes.
+ uint32_t NewOffset = getOffset();
+ setOffset(OriginalOffset);
+
+ ArrayRef<uint8_t> Data;
+ if (auto EC = readBytes(Data, Length))
+ return EC;
+ Dest = StringRef(reinterpret_cast<const char *>(Data.begin()), Data.size());
+
+ // Now set the offset back to where it was after we calculated the length.
+ setOffset(NewOffset);
+ return Error::success();
+}
+
+Error StreamReader::readFixedString(StringRef &Dest, uint32_t Length) {
+ ArrayRef<uint8_t> Bytes;
+ if (auto EC = readBytes(Bytes, Length))
+ return EC;
+ Dest = StringRef(reinterpret_cast<const char *>(Bytes.begin()), Bytes.size());
+ return Error::success();
+}
+
+Error StreamReader::readStreamRef(StreamRef &Ref) {
+ return readStreamRef(Ref, bytesRemaining());
+}
+
+Error StreamReader::readStreamRef(StreamRef &Ref, uint32_t Length) {
+ if (bytesRemaining() < Length)
+ return make_error<CodeViewError>(cv_error_code::insufficient_buffer);
+ Ref = Stream.slice(Offset, Length);
+ Offset += Length;
+ return Error::success();
+}
diff --git a/lib/DebugInfo/CodeView/StreamWriter.cpp b/lib/DebugInfo/CodeView/StreamWriter.cpp
new file mode 100644
index 0000000000000..f61c6b522f570
--- /dev/null
+++ b/lib/DebugInfo/CodeView/StreamWriter.cpp
@@ -0,0 +1,77 @@
+//===- StreamWrite.cpp - Writes bytes and objects to a stream -------------===//
+//
+// 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/StreamWriter.h"
+
+#include "llvm/DebugInfo/CodeView/CodeViewError.h"
+#include "llvm/DebugInfo/CodeView/StreamReader.h"
+#include "llvm/DebugInfo/CodeView/StreamRef.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+StreamWriter::StreamWriter(StreamRef S) : Stream(S), Offset(0) {}
+
+Error StreamWriter::writeBytes(ArrayRef<uint8_t> Buffer) {
+ if (auto EC = Stream.writeBytes(Offset, Buffer))
+ return EC;
+ Offset += Buffer.size();
+ return Error::success();
+}
+
+Error StreamWriter::writeInteger(uint16_t Int) {
+ return writeObject(support::ulittle16_t(Int));
+}
+
+Error StreamWriter::writeInteger(uint32_t Int) {
+ return writeObject(support::ulittle32_t(Int));
+}
+
+Error StreamWriter::writeZeroString(StringRef Str) {
+ if (auto EC = writeFixedString(Str))
+ return EC;
+ if (auto EC = writeObject('\0'))
+ return EC;
+
+ return Error::success();
+}
+
+Error StreamWriter::writeFixedString(StringRef Str) {
+ ArrayRef<uint8_t> Bytes(Str.bytes_begin(), Str.bytes_end());
+ if (auto EC = Stream.writeBytes(Offset, Bytes))
+ return EC;
+
+ Offset += Str.size();
+ return Error::success();
+}
+
+Error StreamWriter::writeStreamRef(StreamRef Ref) {
+ if (auto EC = writeStreamRef(Ref, Ref.getLength()))
+ return EC;
+ Offset += Ref.getLength();
+ return Error::success();
+}
+
+Error StreamWriter::writeStreamRef(StreamRef Ref, uint32_t Length) {
+ Ref = Ref.slice(0, Length);
+
+ StreamReader SrcReader(Ref);
+ // This is a bit tricky. If we just call readBytes, we are requiring that it
+ // return us the entire stream as a contiguous buffer. For large streams this
+ // will allocate a huge amount of space from the pool. Instead, iterate over
+ // each contiguous chunk until we've consumed the entire stream.
+ while (SrcReader.bytesRemaining() > 0) {
+ ArrayRef<uint8_t> Chunk;
+ if (auto EC = SrcReader.readLongestContiguousChunk(Chunk))
+ return EC;
+ if (auto EC = writeBytes(Chunk))
+ return EC;
+ }
+ return Error::success();
+}
diff --git a/lib/DebugInfo/CodeView/SymbolDumper.cpp b/lib/DebugInfo/CodeView/SymbolDumper.cpp
new file mode 100644
index 0000000000000..6763c3d562d72
--- /dev/null
+++ b/lib/DebugInfo/CodeView/SymbolDumper.cpp
@@ -0,0 +1,642 @@
+//===-- SymbolDumper.cpp - CodeView symbol info dumper ----------*- 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/SymbolDumper.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h"
+#include "llvm/DebugInfo/CodeView/EnumTables.h"
+#include "llvm/DebugInfo/CodeView/SymbolDumpDelegate.h"
+#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeDumper.h"
+#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+#include "llvm/Support/ScopedPrinter.h"
+
+#include <system_error>
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+namespace {
+/// Use this private dumper implementation to keep implementation details about
+/// the visitor out of SymbolDumper.h.
+class CVSymbolDumperImpl : public CVSymbolVisitor<CVSymbolDumperImpl> {
+public:
+ CVSymbolDumperImpl(CVTypeDumper &CVTD, SymbolDumpDelegate *ObjDelegate,
+ ScopedPrinter &W, bool PrintRecordBytes)
+ : CVSymbolVisitor(ObjDelegate), CVTD(CVTD), ObjDelegate(ObjDelegate),
+ W(W), PrintRecordBytes(PrintRecordBytes), InFunctionScope(false) {}
+
+/// CVSymbolVisitor overrides.
+#define SYMBOL_RECORD(EnumName, EnumVal, Name) \
+ void visit##Name(SymbolKind Kind, Name &Record);
+#define SYMBOL_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
+#include "llvm/DebugInfo/CodeView/CVSymbolTypes.def"
+
+ void visitSymbolBegin(SymbolKind Kind, ArrayRef<uint8_t> Data);
+ void visitSymbolEnd(SymbolKind Kind, ArrayRef<uint8_t> OriginalSymData);
+ void visitUnknownSymbol(SymbolKind Kind, ArrayRef<uint8_t> Data);
+
+private:
+ void printLocalVariableAddrRange(const LocalVariableAddrRange &Range,
+ uint32_t RelocationOffset);
+ void printLocalVariableAddrGap(ArrayRef<LocalVariableAddrGap> Gaps);
+
+ CVTypeDumper &CVTD;
+ SymbolDumpDelegate *ObjDelegate;
+ ScopedPrinter &W;
+
+ bool PrintRecordBytes;
+ bool InFunctionScope;
+};
+}
+
+void CVSymbolDumperImpl::printLocalVariableAddrRange(
+ const LocalVariableAddrRange &Range, uint32_t RelocationOffset) {
+ DictScope S(W, "LocalVariableAddrRange");
+ if (ObjDelegate)
+ ObjDelegate->printRelocatedField("OffsetStart", RelocationOffset,
+ Range.OffsetStart);
+ W.printHex("ISectStart", Range.ISectStart);
+ W.printHex("Range", Range.Range);
+}
+
+void CVSymbolDumperImpl::printLocalVariableAddrGap(
+ ArrayRef<LocalVariableAddrGap> Gaps) {
+ for (auto &Gap : Gaps) {
+ ListScope S(W, "LocalVariableAddrGap");
+ W.printHex("GapStartOffset", Gap.GapStartOffset);
+ W.printHex("Range", Gap.Range);
+ }
+}
+
+void CVSymbolDumperImpl::visitSymbolBegin(SymbolKind Kind,
+ ArrayRef<uint8_t> Data) {}
+
+void CVSymbolDumperImpl::visitSymbolEnd(SymbolKind Kind,
+ ArrayRef<uint8_t> OriginalSymData) {
+ if (PrintRecordBytes && ObjDelegate)
+ ObjDelegate->printBinaryBlockWithRelocs("SymData", OriginalSymData);
+}
+
+void CVSymbolDumperImpl::visitBlockSym(SymbolKind Kind, BlockSym &Block) {
+ DictScope S(W, "BlockStart");
+
+ StringRef LinkageName;
+ W.printHex("PtrParent", Block.Header.PtrParent);
+ W.printHex("PtrEnd", Block.Header.PtrEnd);
+ W.printHex("CodeSize", Block.Header.CodeSize);
+ if (ObjDelegate) {
+ ObjDelegate->printRelocatedField("CodeOffset", Block.getRelocationOffset(),
+ Block.Header.CodeOffset, &LinkageName);
+ }
+ W.printHex("Segment", Block.Header.Segment);
+ W.printString("BlockName", Block.Name);
+ W.printString("LinkageName", LinkageName);
+}
+
+void CVSymbolDumperImpl::visitThunk32Sym(SymbolKind Kind, Thunk32Sym &Thunk) {
+ DictScope S(W, "Thunk32");
+ W.printNumber("Parent", Thunk.Header.Parent);
+ W.printNumber("End", Thunk.Header.End);
+ W.printNumber("Next", Thunk.Header.Next);
+ W.printNumber("Off", Thunk.Header.Off);
+ W.printNumber("Seg", Thunk.Header.Seg);
+ W.printNumber("Len", Thunk.Header.Len);
+ W.printEnum("Ordinal", Thunk.Header.Ord, getThunkOrdinalNames());
+}
+
+void CVSymbolDumperImpl::visitTrampolineSym(SymbolKind Kind,
+ TrampolineSym &Tramp) {
+ DictScope S(W, "Trampoline");
+ W.printEnum("Type", Tramp.Header.Type, getTrampolineNames());
+ W.printNumber("Size", Tramp.Header.Size);
+ W.printNumber("ThunkOff", Tramp.Header.ThunkOff);
+ W.printNumber("TargetOff", Tramp.Header.TargetOff);
+ W.printNumber("ThunkSection", Tramp.Header.ThunkSection);
+ W.printNumber("TargetSection", Tramp.Header.TargetSection);
+}
+
+void CVSymbolDumperImpl::visitSectionSym(SymbolKind Kind, SectionSym &Section) {
+ DictScope S(W, "Section");
+ W.printNumber("SectionNumber", Section.Header.SectionNumber);
+ W.printNumber("Alignment", Section.Header.Alignment);
+ W.printNumber("Reserved", Section.Header.Reserved);
+ W.printNumber("Rva", Section.Header.Rva);
+ W.printNumber("Length", Section.Header.Length);
+ W.printFlags("Characteristics", Section.Header.Characteristics,
+ getImageSectionCharacteristicNames(),
+ COFF::SectionCharacteristics(0x00F00000));
+
+ W.printString("Name", Section.Name);
+}
+
+void CVSymbolDumperImpl::visitCoffGroupSym(SymbolKind Kind,
+ CoffGroupSym &CoffGroup) {
+ DictScope S(W, "COFF Group");
+ W.printNumber("Size", CoffGroup.Header.Size);
+ W.printFlags("Characteristics", CoffGroup.Header.Characteristics,
+ getImageSectionCharacteristicNames(),
+ COFF::SectionCharacteristics(0x00F00000));
+ W.printNumber("Offset", CoffGroup.Header.Offset);
+ W.printNumber("Segment", CoffGroup.Header.Segment);
+ W.printString("Name", CoffGroup.Name);
+}
+
+void CVSymbolDumperImpl::visitBPRelativeSym(SymbolKind Kind,
+ BPRelativeSym &BPRel) {
+ DictScope S(W, "BPRelativeSym");
+
+ W.printNumber("Offset", BPRel.Header.Offset);
+ CVTD.printTypeIndex("Type", BPRel.Header.Type);
+ W.printString("VarName", BPRel.Name);
+}
+
+void CVSymbolDumperImpl::visitBuildInfoSym(SymbolKind Kind,
+ BuildInfoSym &BuildInfo) {
+ DictScope S(W, "BuildInfo");
+
+ W.printNumber("BuildId", BuildInfo.Header.BuildId);
+}
+
+void CVSymbolDumperImpl::visitCallSiteInfoSym(SymbolKind Kind,
+ CallSiteInfoSym &CallSiteInfo) {
+ DictScope S(W, "CallSiteInfo");
+
+ StringRef LinkageName;
+ if (ObjDelegate) {
+ ObjDelegate->printRelocatedField(
+ "CodeOffset", CallSiteInfo.getRelocationOffset(),
+ CallSiteInfo.Header.CodeOffset, &LinkageName);
+ }
+ W.printHex("Segment", CallSiteInfo.Header.Segment);
+ W.printHex("Reserved", CallSiteInfo.Header.Reserved);
+ CVTD.printTypeIndex("Type", CallSiteInfo.Header.Type);
+ if (!LinkageName.empty())
+ W.printString("LinkageName", LinkageName);
+}
+
+void CVSymbolDumperImpl::visitEnvBlockSym(SymbolKind Kind,
+ EnvBlockSym &EnvBlock) {
+ DictScope S(W, "EnvBlock");
+
+ W.printNumber("Reserved", EnvBlock.Header.Reserved);
+ ListScope L(W, "Entries");
+ for (auto Entry : EnvBlock.Fields) {
+ W.printString(Entry);
+ }
+}
+
+void CVSymbolDumperImpl::visitFileStaticSym(SymbolKind Kind,
+ FileStaticSym &FileStatic) {
+ DictScope S(W, "FileStatic");
+ W.printNumber("Index", FileStatic.Header.Index);
+ W.printNumber("ModFilenameOffset", FileStatic.Header.ModFilenameOffset);
+ W.printFlags("Flags", uint16_t(FileStatic.Header.Flags), getLocalFlagNames());
+ W.printString("Name", FileStatic.Name);
+}
+
+void CVSymbolDumperImpl::visitExportSym(SymbolKind Kind, ExportSym &Export) {
+ DictScope S(W, "Export");
+ W.printNumber("Ordinal", Export.Header.Ordinal);
+ W.printFlags("Flags", Export.Header.Flags, getExportSymFlagNames());
+ W.printString("Name", Export.Name);
+}
+
+void CVSymbolDumperImpl::visitCompile2Sym(SymbolKind Kind,
+ Compile2Sym &Compile2) {
+ DictScope S(W, "CompilerFlags2");
+
+ W.printEnum("Language", Compile2.Header.getLanguage(),
+ getSourceLanguageNames());
+ W.printFlags("Flags", Compile2.Header.flags & ~0xff,
+ getCompileSym2FlagNames());
+ W.printEnum("Machine", unsigned(Compile2.Header.Machine), getCPUTypeNames());
+ std::string FrontendVersion;
+ {
+ raw_string_ostream Out(FrontendVersion);
+ Out << Compile2.Header.VersionFrontendMajor << '.'
+ << Compile2.Header.VersionFrontendMinor << '.'
+ << Compile2.Header.VersionFrontendBuild;
+ }
+ std::string BackendVersion;
+ {
+ raw_string_ostream Out(BackendVersion);
+ Out << Compile2.Header.VersionBackendMajor << '.'
+ << Compile2.Header.VersionBackendMinor << '.'
+ << Compile2.Header.VersionBackendBuild;
+ }
+ W.printString("FrontendVersion", FrontendVersion);
+ W.printString("BackendVersion", BackendVersion);
+ W.printString("VersionName", Compile2.Version);
+}
+
+void CVSymbolDumperImpl::visitCompile3Sym(SymbolKind Kind,
+ Compile3Sym &Compile3) {
+ DictScope S(W, "CompilerFlags3");
+
+ W.printEnum("Language", Compile3.Header.getLanguage(),
+ getSourceLanguageNames());
+ W.printFlags("Flags", Compile3.Header.flags & ~0xff,
+ getCompileSym3FlagNames());
+ W.printEnum("Machine", unsigned(Compile3.Header.Machine), getCPUTypeNames());
+ std::string FrontendVersion;
+ {
+ raw_string_ostream Out(FrontendVersion);
+ Out << Compile3.Header.VersionFrontendMajor << '.'
+ << Compile3.Header.VersionFrontendMinor << '.'
+ << Compile3.Header.VersionFrontendBuild << '.'
+ << Compile3.Header.VersionFrontendQFE;
+ }
+ std::string BackendVersion;
+ {
+ raw_string_ostream Out(BackendVersion);
+ Out << Compile3.Header.VersionBackendMajor << '.'
+ << Compile3.Header.VersionBackendMinor << '.'
+ << Compile3.Header.VersionBackendBuild << '.'
+ << Compile3.Header.VersionBackendQFE;
+ }
+ W.printString("FrontendVersion", FrontendVersion);
+ W.printString("BackendVersion", BackendVersion);
+ W.printString("VersionName", Compile3.Version);
+}
+
+void CVSymbolDumperImpl::visitConstantSym(SymbolKind Kind,
+ ConstantSym &Constant) {
+ DictScope S(W, "Constant");
+
+ CVTD.printTypeIndex("Type", Constant.Header.Type);
+ W.printNumber("Value", Constant.Value);
+ W.printString("Name", Constant.Name);
+}
+
+void CVSymbolDumperImpl::visitDataSym(SymbolKind Kind, DataSym &Data) {
+ DictScope S(W, "DataSym");
+
+ W.printEnum("Kind", uint16_t(Kind), getSymbolTypeNames());
+ StringRef LinkageName;
+ if (ObjDelegate) {
+ ObjDelegate->printRelocatedField("DataOffset", Data.getRelocationOffset(),
+ Data.Header.DataOffset, &LinkageName);
+ }
+ CVTD.printTypeIndex("Type", Data.Header.Type);
+ W.printString("DisplayName", Data.Name);
+ if (!LinkageName.empty())
+ W.printString("LinkageName", LinkageName);
+}
+
+void CVSymbolDumperImpl::visitDefRangeFramePointerRelFullScopeSym(
+ SymbolKind Kind,
+ DefRangeFramePointerRelFullScopeSym &DefRangeFramePointerRelFullScope) {
+ DictScope S(W, "DefRangeFramePointerRelFullScope");
+ W.printNumber("Offset", DefRangeFramePointerRelFullScope.Header.Offset);
+}
+
+void CVSymbolDumperImpl::visitDefRangeFramePointerRelSym(
+ SymbolKind Kind, DefRangeFramePointerRelSym &DefRangeFramePointerRel) {
+ DictScope S(W, "DefRangeFramePointerRel");
+
+ W.printNumber("Offset", DefRangeFramePointerRel.Header.Offset);
+ printLocalVariableAddrRange(DefRangeFramePointerRel.Header.Range,
+ DefRangeFramePointerRel.getRelocationOffset());
+ printLocalVariableAddrGap(DefRangeFramePointerRel.Gaps);
+}
+
+void CVSymbolDumperImpl::visitDefRangeRegisterRelSym(
+ SymbolKind Kind, DefRangeRegisterRelSym &DefRangeRegisterRel) {
+ DictScope S(W, "DefRangeRegisterRel");
+
+ W.printNumber("BaseRegister", DefRangeRegisterRel.Header.BaseRegister);
+ W.printBoolean("HasSpilledUDTMember",
+ DefRangeRegisterRel.hasSpilledUDTMember());
+ W.printNumber("OffsetInParent", DefRangeRegisterRel.offsetInParent());
+ W.printNumber("BasePointerOffset",
+ DefRangeRegisterRel.Header.BasePointerOffset);
+ printLocalVariableAddrRange(DefRangeRegisterRel.Header.Range,
+ DefRangeRegisterRel.getRelocationOffset());
+ printLocalVariableAddrGap(DefRangeRegisterRel.Gaps);
+}
+
+void CVSymbolDumperImpl::visitDefRangeRegisterSym(
+ SymbolKind Kind, DefRangeRegisterSym &DefRangeRegister) {
+ DictScope S(W, "DefRangeRegister");
+
+ W.printNumber("Register", DefRangeRegister.Header.Register);
+ W.printNumber("MayHaveNoName", DefRangeRegister.Header.MayHaveNoName);
+ printLocalVariableAddrRange(DefRangeRegister.Header.Range,
+ DefRangeRegister.getRelocationOffset());
+ printLocalVariableAddrGap(DefRangeRegister.Gaps);
+}
+
+void CVSymbolDumperImpl::visitDefRangeSubfieldRegisterSym(
+ SymbolKind Kind, DefRangeSubfieldRegisterSym &DefRangeSubfieldRegister) {
+ DictScope S(W, "DefRangeSubfieldRegister");
+
+ W.printNumber("Register", DefRangeSubfieldRegister.Header.Register);
+ W.printNumber("MayHaveNoName", DefRangeSubfieldRegister.Header.MayHaveNoName);
+ W.printNumber("OffsetInParent",
+ DefRangeSubfieldRegister.Header.OffsetInParent);
+ printLocalVariableAddrRange(DefRangeSubfieldRegister.Header.Range,
+ DefRangeSubfieldRegister.getRelocationOffset());
+ printLocalVariableAddrGap(DefRangeSubfieldRegister.Gaps);
+}
+
+void CVSymbolDumperImpl::visitDefRangeSubfieldSym(
+ SymbolKind Kind, DefRangeSubfieldSym &DefRangeSubfield) {
+ DictScope S(W, "DefRangeSubfield");
+
+ if (ObjDelegate) {
+ StringRef StringTable = ObjDelegate->getStringTable();
+ auto ProgramStringTableOffset = DefRangeSubfield.Header.Program;
+ if (ProgramStringTableOffset >= StringTable.size())
+ return parseError();
+ StringRef Program =
+ StringTable.drop_front(ProgramStringTableOffset).split('\0').first;
+ W.printString("Program", Program);
+ }
+ W.printNumber("OffsetInParent", DefRangeSubfield.Header.OffsetInParent);
+ printLocalVariableAddrRange(DefRangeSubfield.Header.Range,
+ DefRangeSubfield.getRelocationOffset());
+ printLocalVariableAddrGap(DefRangeSubfield.Gaps);
+}
+
+void CVSymbolDumperImpl::visitDefRangeSym(SymbolKind Kind,
+ DefRangeSym &DefRange) {
+ DictScope S(W, "DefRange");
+
+ if (ObjDelegate) {
+ StringRef StringTable = ObjDelegate->getStringTable();
+ auto ProgramStringTableOffset = DefRange.Header.Program;
+ if (ProgramStringTableOffset >= StringTable.size())
+ return parseError();
+ StringRef Program =
+ StringTable.drop_front(ProgramStringTableOffset).split('\0').first;
+ W.printString("Program", Program);
+ }
+ printLocalVariableAddrRange(DefRange.Header.Range,
+ DefRange.getRelocationOffset());
+ printLocalVariableAddrGap(DefRange.Gaps);
+}
+
+void CVSymbolDumperImpl::visitFrameCookieSym(SymbolKind Kind,
+ FrameCookieSym &FrameCookie) {
+ DictScope S(W, "FrameCookie");
+
+ StringRef LinkageName;
+ if (ObjDelegate) {
+ ObjDelegate->printRelocatedField(
+ "CodeOffset", FrameCookie.getRelocationOffset(),
+ FrameCookie.Header.CodeOffset, &LinkageName);
+ }
+ W.printHex("Register", FrameCookie.Header.Register);
+ W.printEnum("CookieKind", uint16_t(FrameCookie.Header.CookieKind),
+ getFrameCookieKindNames());
+ W.printHex("Flags", FrameCookie.Header.Flags);
+}
+
+void CVSymbolDumperImpl::visitFrameProcSym(SymbolKind Kind,
+ FrameProcSym &FrameProc) {
+ DictScope S(W, "FrameProc");
+
+ W.printHex("TotalFrameBytes", FrameProc.Header.TotalFrameBytes);
+ W.printHex("PaddingFrameBytes", FrameProc.Header.PaddingFrameBytes);
+ W.printHex("OffsetToPadding", FrameProc.Header.OffsetToPadding);
+ W.printHex("BytesOfCalleeSavedRegisters",
+ FrameProc.Header.BytesOfCalleeSavedRegisters);
+ W.printHex("OffsetOfExceptionHandler",
+ FrameProc.Header.OffsetOfExceptionHandler);
+ W.printHex("SectionIdOfExceptionHandler",
+ FrameProc.Header.SectionIdOfExceptionHandler);
+ W.printFlags("Flags", FrameProc.Header.Flags, getFrameProcSymFlagNames());
+}
+
+void CVSymbolDumperImpl::visitHeapAllocationSiteSym(
+ SymbolKind Kind, HeapAllocationSiteSym &HeapAllocSite) {
+ DictScope S(W, "HeapAllocationSite");
+
+ StringRef LinkageName;
+ if (ObjDelegate) {
+ ObjDelegate->printRelocatedField(
+ "CodeOffset", HeapAllocSite.getRelocationOffset(),
+ HeapAllocSite.Header.CodeOffset, &LinkageName);
+ }
+ W.printHex("Segment", HeapAllocSite.Header.Segment);
+ W.printHex("CallInstructionSize", HeapAllocSite.Header.CallInstructionSize);
+ CVTD.printTypeIndex("Type", HeapAllocSite.Header.Type);
+ if (!LinkageName.empty())
+ W.printString("LinkageName", LinkageName);
+}
+
+void CVSymbolDumperImpl::visitInlineSiteSym(SymbolKind Kind,
+ InlineSiteSym &InlineSite) {
+ DictScope S(W, "InlineSite");
+
+ W.printHex("PtrParent", InlineSite.Header.PtrParent);
+ W.printHex("PtrEnd", InlineSite.Header.PtrEnd);
+ CVTD.printTypeIndex("Inlinee", InlineSite.Header.Inlinee);
+
+ ListScope BinaryAnnotations(W, "BinaryAnnotations");
+ for (auto &Annotation : InlineSite.annotations()) {
+ switch (Annotation.OpCode) {
+ case BinaryAnnotationsOpCode::Invalid:
+ return parseError();
+ case BinaryAnnotationsOpCode::CodeOffset:
+ case BinaryAnnotationsOpCode::ChangeCodeOffset:
+ case BinaryAnnotationsOpCode::ChangeCodeLength:
+ W.printHex(Annotation.Name, Annotation.U1);
+ break;
+ case BinaryAnnotationsOpCode::ChangeCodeOffsetBase:
+ case BinaryAnnotationsOpCode::ChangeLineEndDelta:
+ case BinaryAnnotationsOpCode::ChangeRangeKind:
+ case BinaryAnnotationsOpCode::ChangeColumnStart:
+ case BinaryAnnotationsOpCode::ChangeColumnEnd:
+ W.printNumber(Annotation.Name, Annotation.U1);
+ break;
+ case BinaryAnnotationsOpCode::ChangeLineOffset:
+ case BinaryAnnotationsOpCode::ChangeColumnEndDelta:
+ W.printNumber(Annotation.Name, Annotation.S1);
+ break;
+ case BinaryAnnotationsOpCode::ChangeFile:
+ if (ObjDelegate) {
+ W.printHex("ChangeFile",
+ ObjDelegate->getFileNameForFileOffset(Annotation.U1),
+ Annotation.U1);
+ } else {
+ W.printHex("ChangeFile", Annotation.U1);
+ }
+
+ break;
+ case BinaryAnnotationsOpCode::ChangeCodeOffsetAndLineOffset: {
+ W.startLine() << "ChangeCodeOffsetAndLineOffset: {CodeOffset: "
+ << W.hex(Annotation.U1) << ", LineOffset: " << Annotation.S1
+ << "}\n";
+ break;
+ }
+ case BinaryAnnotationsOpCode::ChangeCodeLengthAndCodeOffset: {
+ W.startLine() << "ChangeCodeLengthAndCodeOffset: {CodeOffset: "
+ << W.hex(Annotation.U2)
+ << ", Length: " << W.hex(Annotation.U1) << "}\n";
+ break;
+ }
+ }
+ }
+}
+
+void CVSymbolDumperImpl::visitRegisterSym(SymbolKind Kind,
+ RegisterSym &Register) {
+ DictScope S(W, "RegisterSym");
+ W.printNumber("Type", Register.Header.Index);
+ W.printEnum("Seg", uint16_t(Register.Header.Register), getRegisterNames());
+ W.printString("Name", Register.Name);
+}
+
+void CVSymbolDumperImpl::visitPublicSym32(SymbolKind Kind,
+ PublicSym32 &Public) {
+ DictScope S(W, "PublicSym");
+ W.printNumber("Type", Public.Header.Index);
+ W.printNumber("Seg", Public.Header.Seg);
+ W.printNumber("Off", Public.Header.Off);
+ W.printString("Name", Public.Name);
+}
+
+void CVSymbolDumperImpl::visitProcRefSym(SymbolKind Kind, ProcRefSym &ProcRef) {
+ DictScope S(W, "ProcRef");
+ W.printNumber("SumName", ProcRef.Header.SumName);
+ W.printNumber("SymOffset", ProcRef.Header.SymOffset);
+ W.printNumber("Mod", ProcRef.Header.Mod);
+ W.printString("Name", ProcRef.Name);
+}
+
+void CVSymbolDumperImpl::visitLabelSym(SymbolKind Kind, LabelSym &Label) {
+ DictScope S(W, "Label");
+
+ StringRef LinkageName;
+ if (ObjDelegate) {
+ ObjDelegate->printRelocatedField("CodeOffset", Label.getRelocationOffset(),
+ Label.Header.CodeOffset, &LinkageName);
+ }
+ W.printHex("Segment", Label.Header.Segment);
+ W.printHex("Flags", Label.Header.Flags);
+ W.printFlags("Flags", Label.Header.Flags, getProcSymFlagNames());
+ W.printString("DisplayName", Label.Name);
+ if (!LinkageName.empty())
+ W.printString("LinkageName", LinkageName);
+}
+
+void CVSymbolDumperImpl::visitLocalSym(SymbolKind Kind, LocalSym &Local) {
+ DictScope S(W, "Local");
+
+ CVTD.printTypeIndex("Type", Local.Header.Type);
+ W.printFlags("Flags", uint16_t(Local.Header.Flags), getLocalFlagNames());
+ W.printString("VarName", Local.Name);
+}
+
+void CVSymbolDumperImpl::visitObjNameSym(SymbolKind Kind, ObjNameSym &ObjName) {
+ DictScope S(W, "ObjectName");
+
+ W.printHex("Signature", ObjName.Header.Signature);
+ W.printString("ObjectName", ObjName.Name);
+}
+
+void CVSymbolDumperImpl::visitProcSym(SymbolKind Kind, ProcSym &Proc) {
+ DictScope S(W, "ProcStart");
+
+ if (InFunctionScope)
+ return parseError();
+
+ InFunctionScope = true;
+
+ StringRef LinkageName;
+ W.printEnum("Kind", uint16_t(Kind), getSymbolTypeNames());
+ W.printHex("PtrParent", Proc.Header.PtrParent);
+ W.printHex("PtrEnd", Proc.Header.PtrEnd);
+ W.printHex("PtrNext", Proc.Header.PtrNext);
+ W.printHex("CodeSize", Proc.Header.CodeSize);
+ W.printHex("DbgStart", Proc.Header.DbgStart);
+ W.printHex("DbgEnd", Proc.Header.DbgEnd);
+ CVTD.printTypeIndex("FunctionType", Proc.Header.FunctionType);
+ if (ObjDelegate) {
+ ObjDelegate->printRelocatedField("CodeOffset", Proc.getRelocationOffset(),
+ Proc.Header.CodeOffset, &LinkageName);
+ }
+ W.printHex("Segment", Proc.Header.Segment);
+ W.printFlags("Flags", static_cast<uint8_t>(Proc.Header.Flags),
+ getProcSymFlagNames());
+ W.printString("DisplayName", Proc.Name);
+ if (!LinkageName.empty())
+ W.printString("LinkageName", LinkageName);
+}
+
+void CVSymbolDumperImpl::visitScopeEndSym(SymbolKind Kind,
+ ScopeEndSym &ScopeEnd) {
+ if (Kind == SymbolKind::S_END)
+ DictScope S(W, "BlockEnd");
+ else if (Kind == SymbolKind::S_PROC_ID_END)
+ DictScope S(W, "ProcEnd");
+ else if (Kind == SymbolKind::S_INLINESITE_END)
+ DictScope S(W, "InlineSiteEnd");
+
+ InFunctionScope = false;
+}
+
+void CVSymbolDumperImpl::visitCallerSym(SymbolKind Kind, CallerSym &Caller) {
+ ListScope S(W, Kind == S_CALLEES ? "Callees" : "Callers");
+ for (auto FuncID : Caller.Indices)
+ CVTD.printTypeIndex("FuncID", FuncID);
+}
+
+void CVSymbolDumperImpl::visitRegRelativeSym(SymbolKind Kind,
+ RegRelativeSym &RegRel) {
+ DictScope S(W, "RegRelativeSym");
+
+ W.printHex("Offset", RegRel.Header.Offset);
+ CVTD.printTypeIndex("Type", RegRel.Header.Type);
+ W.printHex("Register", RegRel.Header.Register);
+ W.printString("VarName", RegRel.Name);
+}
+
+void CVSymbolDumperImpl::visitThreadLocalDataSym(SymbolKind Kind,
+ ThreadLocalDataSym &Data) {
+ DictScope S(W, "ThreadLocalDataSym");
+
+ StringRef LinkageName;
+ if (ObjDelegate) {
+ ObjDelegate->printRelocatedField("DataOffset", Data.getRelocationOffset(),
+ Data.Header.DataOffset, &LinkageName);
+ }
+ CVTD.printTypeIndex("Type", Data.Header.Type);
+ W.printString("DisplayName", Data.Name);
+ if (!LinkageName.empty())
+ W.printString("LinkageName", LinkageName);
+}
+
+void CVSymbolDumperImpl::visitUDTSym(SymbolKind Kind, UDTSym &UDT) {
+ DictScope S(W, "UDT");
+ CVTD.printTypeIndex("Type", UDT.Header.Type);
+ W.printString("UDTName", UDT.Name);
+}
+
+void CVSymbolDumperImpl::visitUnknownSymbol(SymbolKind Kind,
+ ArrayRef<uint8_t> Data) {
+ DictScope S(W, "UnknownSym");
+ W.printEnum("Kind", uint16_t(Kind), getSymbolTypeNames());
+ W.printNumber("Length", uint32_t(Data.size()));
+}
+
+bool CVSymbolDumper::dump(const CVRecord<SymbolKind> &Record) {
+ CVSymbolDumperImpl Dumper(CVTD, ObjDelegate.get(), W, PrintRecordBytes);
+ Dumper.visitSymbolRecord(Record);
+ return !Dumper.hadError();
+}
+
+bool CVSymbolDumper::dump(const CVSymbolArray &Symbols) {
+ CVSymbolDumperImpl Dumper(CVTD, ObjDelegate.get(), W, PrintRecordBytes);
+ Dumper.visitSymbolStream(Symbols);
+ return !Dumper.hadError();
+}
diff --git a/lib/DebugInfo/CodeView/TypeDumper.cpp b/lib/DebugInfo/CodeView/TypeDumper.cpp
new file mode 100644
index 0000000000000..345e2a49888c7
--- /dev/null
+++ b/lib/DebugInfo/CodeView/TypeDumper.cpp
@@ -0,0 +1,696 @@
+//===-- TypeDumper.cpp - CodeView type info dumper --------------*- 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/TypeDumper.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
+#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/DebugInfo/CodeView/ByteStream.h"
+#include "llvm/Support/ScopedPrinter.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+/// The names here all end in "*". If the simple type is a pointer type, we
+/// return the whole name. Otherwise we lop off the last character in our
+/// StringRef.
+static const EnumEntry<SimpleTypeKind> SimpleTypeNames[] = {
+ {"void*", SimpleTypeKind::Void},
+ {"<not translated>*", SimpleTypeKind::NotTranslated},
+ {"HRESULT*", SimpleTypeKind::HResult},
+ {"signed char*", SimpleTypeKind::SignedCharacter},
+ {"unsigned char*", SimpleTypeKind::UnsignedCharacter},
+ {"char*", SimpleTypeKind::NarrowCharacter},
+ {"wchar_t*", SimpleTypeKind::WideCharacter},
+ {"char16_t*", SimpleTypeKind::Character16},
+ {"char32_t*", SimpleTypeKind::Character32},
+ {"__int8*", SimpleTypeKind::SByte},
+ {"unsigned __int8*", SimpleTypeKind::Byte},
+ {"short*", SimpleTypeKind::Int16Short},
+ {"unsigned short*", SimpleTypeKind::UInt16Short},
+ {"__int16*", SimpleTypeKind::Int16},
+ {"unsigned __int16*", SimpleTypeKind::UInt16},
+ {"long*", SimpleTypeKind::Int32Long},
+ {"unsigned long*", SimpleTypeKind::UInt32Long},
+ {"int*", SimpleTypeKind::Int32},
+ {"unsigned*", SimpleTypeKind::UInt32},
+ {"__int64*", SimpleTypeKind::Int64Quad},
+ {"unsigned __int64*", SimpleTypeKind::UInt64Quad},
+ {"__int64*", SimpleTypeKind::Int64},
+ {"unsigned __int64*", SimpleTypeKind::UInt64},
+ {"__int128*", SimpleTypeKind::Int128},
+ {"unsigned __int128*", SimpleTypeKind::UInt128},
+ {"__half*", SimpleTypeKind::Float16},
+ {"float*", SimpleTypeKind::Float32},
+ {"float*", SimpleTypeKind::Float32PartialPrecision},
+ {"__float48*", SimpleTypeKind::Float48},
+ {"double*", SimpleTypeKind::Float64},
+ {"long double*", SimpleTypeKind::Float80},
+ {"__float128*", SimpleTypeKind::Float128},
+ {"_Complex float*", SimpleTypeKind::Complex32},
+ {"_Complex double*", SimpleTypeKind::Complex64},
+ {"_Complex long double*", SimpleTypeKind::Complex80},
+ {"_Complex __float128*", SimpleTypeKind::Complex128},
+ {"bool*", SimpleTypeKind::Boolean8},
+ {"__bool16*", SimpleTypeKind::Boolean16},
+ {"__bool32*", SimpleTypeKind::Boolean32},
+ {"__bool64*", SimpleTypeKind::Boolean64},
+};
+
+static const EnumEntry<TypeLeafKind> LeafTypeNames[] = {
+#define CV_TYPE(enum, val) {#enum, enum},
+#include "llvm/DebugInfo/CodeView/TypeRecords.def"
+};
+
+#define ENUM_ENTRY(enum_class, enum) \
+ { #enum, std::underlying_type < enum_class > ::type(enum_class::enum) }
+
+static const EnumEntry<uint16_t> ClassOptionNames[] = {
+ ENUM_ENTRY(ClassOptions, Packed),
+ ENUM_ENTRY(ClassOptions, HasConstructorOrDestructor),
+ ENUM_ENTRY(ClassOptions, HasOverloadedOperator),
+ ENUM_ENTRY(ClassOptions, Nested),
+ ENUM_ENTRY(ClassOptions, ContainsNestedClass),
+ ENUM_ENTRY(ClassOptions, HasOverloadedAssignmentOperator),
+ ENUM_ENTRY(ClassOptions, HasConversionOperator),
+ ENUM_ENTRY(ClassOptions, ForwardReference),
+ ENUM_ENTRY(ClassOptions, Scoped),
+ ENUM_ENTRY(ClassOptions, HasUniqueName),
+ ENUM_ENTRY(ClassOptions, Sealed),
+ ENUM_ENTRY(ClassOptions, Intrinsic),
+};
+
+static const EnumEntry<uint8_t> MemberAccessNames[] = {
+ ENUM_ENTRY(MemberAccess, None),
+ ENUM_ENTRY(MemberAccess, Private),
+ ENUM_ENTRY(MemberAccess, Protected),
+ ENUM_ENTRY(MemberAccess, Public),
+};
+
+static const EnumEntry<uint16_t> MethodOptionNames[] = {
+ ENUM_ENTRY(MethodOptions, Pseudo),
+ ENUM_ENTRY(MethodOptions, NoInherit),
+ ENUM_ENTRY(MethodOptions, NoConstruct),
+ ENUM_ENTRY(MethodOptions, CompilerGenerated),
+ ENUM_ENTRY(MethodOptions, Sealed),
+};
+
+static const EnumEntry<uint16_t> MemberKindNames[] = {
+ ENUM_ENTRY(MethodKind, Vanilla),
+ ENUM_ENTRY(MethodKind, Virtual),
+ ENUM_ENTRY(MethodKind, Static),
+ ENUM_ENTRY(MethodKind, Friend),
+ ENUM_ENTRY(MethodKind, IntroducingVirtual),
+ ENUM_ENTRY(MethodKind, PureVirtual),
+ ENUM_ENTRY(MethodKind, PureIntroducingVirtual),
+};
+
+static const EnumEntry<uint8_t> PtrKindNames[] = {
+ ENUM_ENTRY(PointerKind, Near16),
+ ENUM_ENTRY(PointerKind, Far16),
+ ENUM_ENTRY(PointerKind, Huge16),
+ ENUM_ENTRY(PointerKind, BasedOnSegment),
+ ENUM_ENTRY(PointerKind, BasedOnValue),
+ ENUM_ENTRY(PointerKind, BasedOnSegmentValue),
+ ENUM_ENTRY(PointerKind, BasedOnAddress),
+ ENUM_ENTRY(PointerKind, BasedOnSegmentAddress),
+ ENUM_ENTRY(PointerKind, BasedOnType),
+ ENUM_ENTRY(PointerKind, BasedOnSelf),
+ ENUM_ENTRY(PointerKind, Near32),
+ ENUM_ENTRY(PointerKind, Far32),
+ ENUM_ENTRY(PointerKind, Near64),
+};
+
+static const EnumEntry<uint8_t> PtrModeNames[] = {
+ ENUM_ENTRY(PointerMode, Pointer),
+ ENUM_ENTRY(PointerMode, LValueReference),
+ ENUM_ENTRY(PointerMode, PointerToDataMember),
+ ENUM_ENTRY(PointerMode, PointerToMemberFunction),
+ ENUM_ENTRY(PointerMode, RValueReference),
+};
+
+static const EnumEntry<uint16_t> PtrMemberRepNames[] = {
+ ENUM_ENTRY(PointerToMemberRepresentation, Unknown),
+ ENUM_ENTRY(PointerToMemberRepresentation, SingleInheritanceData),
+ ENUM_ENTRY(PointerToMemberRepresentation, MultipleInheritanceData),
+ ENUM_ENTRY(PointerToMemberRepresentation, VirtualInheritanceData),
+ ENUM_ENTRY(PointerToMemberRepresentation, GeneralData),
+ ENUM_ENTRY(PointerToMemberRepresentation, SingleInheritanceFunction),
+ ENUM_ENTRY(PointerToMemberRepresentation, MultipleInheritanceFunction),
+ ENUM_ENTRY(PointerToMemberRepresentation, VirtualInheritanceFunction),
+ ENUM_ENTRY(PointerToMemberRepresentation, GeneralFunction),
+};
+
+static const EnumEntry<uint16_t> TypeModifierNames[] = {
+ ENUM_ENTRY(ModifierOptions, Const),
+ ENUM_ENTRY(ModifierOptions, Volatile),
+ ENUM_ENTRY(ModifierOptions, Unaligned),
+};
+
+static const EnumEntry<uint8_t> CallingConventions[] = {
+ ENUM_ENTRY(CallingConvention, NearC),
+ ENUM_ENTRY(CallingConvention, FarC),
+ ENUM_ENTRY(CallingConvention, NearPascal),
+ ENUM_ENTRY(CallingConvention, FarPascal),
+ ENUM_ENTRY(CallingConvention, NearFast),
+ ENUM_ENTRY(CallingConvention, FarFast),
+ ENUM_ENTRY(CallingConvention, NearStdCall),
+ ENUM_ENTRY(CallingConvention, FarStdCall),
+ ENUM_ENTRY(CallingConvention, NearSysCall),
+ ENUM_ENTRY(CallingConvention, FarSysCall),
+ ENUM_ENTRY(CallingConvention, ThisCall),
+ ENUM_ENTRY(CallingConvention, MipsCall),
+ ENUM_ENTRY(CallingConvention, Generic),
+ ENUM_ENTRY(CallingConvention, AlphaCall),
+ ENUM_ENTRY(CallingConvention, PpcCall),
+ ENUM_ENTRY(CallingConvention, SHCall),
+ ENUM_ENTRY(CallingConvention, ArmCall),
+ ENUM_ENTRY(CallingConvention, AM33Call),
+ ENUM_ENTRY(CallingConvention, TriCall),
+ ENUM_ENTRY(CallingConvention, SH5Call),
+ ENUM_ENTRY(CallingConvention, M32RCall),
+ ENUM_ENTRY(CallingConvention, ClrCall),
+ ENUM_ENTRY(CallingConvention, Inline),
+ ENUM_ENTRY(CallingConvention, NearVector),
+};
+
+static const EnumEntry<uint8_t> FunctionOptionEnum[] = {
+ ENUM_ENTRY(FunctionOptions, CxxReturnUdt),
+ ENUM_ENTRY(FunctionOptions, Constructor),
+ ENUM_ENTRY(FunctionOptions, ConstructorWithVirtualBases),
+};
+
+#undef ENUM_ENTRY
+
+static StringRef getLeafTypeName(TypeLeafKind LT) {
+ switch (LT) {
+#define TYPE_RECORD(ename, value, name) \
+ case ename: \
+ return #name;
+#include "llvm/DebugInfo/CodeView/TypeRecords.def"
+ case LF_FIELDLIST:
+ return "FieldList";
+ default:
+ break;
+ }
+ return "UnknownLeaf";
+}
+
+Error CVTypeDumper::visitTypeBegin(const CVRecord<TypeLeafKind> &Record) {
+ // Reset Name to the empty string. If the visitor sets it, we know it.
+ Name = "";
+
+ W->startLine() << getLeafTypeName(Record.Type) << " ("
+ << HexNumber(getNextTypeIndex()) << ") {\n";
+ W->indent();
+ W->printEnum("TypeLeafKind", unsigned(Record.Type),
+ makeArrayRef(LeafTypeNames));
+ return Error::success();
+}
+
+Error CVTypeDumper::visitTypeEnd(const CVRecord<TypeLeafKind> &Record) {
+ if (Record.Type == LF_FIELDLIST)
+ Name = "<field list>";
+
+ // Always record some name for every type, even if Name is empty. CVUDTNames
+ // is indexed by type index, and must have one entry for every type.
+ recordType(Name);
+
+ if (PrintRecordBytes)
+ W->printBinaryBlock("LeafData", getBytesAsCharacters(Record.Data));
+
+ W->unindent();
+ W->startLine() << "}\n";
+ return Error::success();
+}
+
+Error CVTypeDumper::visitStringId(StringIdRecord &String) {
+ printTypeIndex("Id", String.getId());
+ W->printString("StringData", String.getString());
+ // Put this in CVUDTNames so it gets printed with LF_UDT_SRC_LINE.
+ Name = String.getString();
+ return Error::success();
+}
+
+Error CVTypeDumper::visitArgList(ArgListRecord &Args) {
+ auto Indices = Args.getIndices();
+ uint32_t Size = Indices.size();
+ W->printNumber("NumArgs", Size);
+ ListScope Arguments(*W, "Arguments");
+ SmallString<256> TypeName("(");
+ for (uint32_t I = 0; I < Size; ++I) {
+ printTypeIndex("ArgType", Indices[I]);
+ StringRef ArgTypeName = getTypeName(Indices[I]);
+ TypeName.append(ArgTypeName);
+ if (I + 1 != Size)
+ TypeName.append(", ");
+ }
+ TypeName.push_back(')');
+ Name = saveName(TypeName);
+ return Error::success();
+}
+
+Error CVTypeDumper::visitClass(ClassRecord &Class) {
+ uint16_t Props = static_cast<uint16_t>(Class.getOptions());
+ W->printNumber("MemberCount", Class.getMemberCount());
+ W->printFlags("Properties", Props, makeArrayRef(ClassOptionNames));
+ printTypeIndex("FieldList", Class.getFieldList());
+ printTypeIndex("DerivedFrom", Class.getDerivationList());
+ printTypeIndex("VShape", Class.getVTableShape());
+ W->printNumber("SizeOf", Class.getSize());
+ W->printString("Name", Class.getName());
+ if (Props & uint16_t(ClassOptions::HasUniqueName))
+ W->printString("LinkageName", Class.getUniqueName());
+ Name = Class.getName();
+ return Error::success();
+}
+
+Error CVTypeDumper::visitUnion(UnionRecord &Union) {
+ uint16_t Props = static_cast<uint16_t>(Union.getOptions());
+ W->printNumber("MemberCount", Union.getMemberCount());
+ W->printFlags("Properties", Props, makeArrayRef(ClassOptionNames));
+ printTypeIndex("FieldList", Union.getFieldList());
+ W->printNumber("SizeOf", Union.getSize());
+ W->printString("Name", Union.getName());
+ if (Props & uint16_t(ClassOptions::HasUniqueName))
+ W->printString("LinkageName", Union.getUniqueName());
+ Name = Union.getName();
+ return Error::success();
+}
+
+Error CVTypeDumper::visitEnum(EnumRecord &Enum) {
+ uint16_t Props = static_cast<uint16_t>(Enum.getOptions());
+ W->printNumber("NumEnumerators", Enum.getMemberCount());
+ W->printFlags("Properties", uint16_t(Enum.getOptions()),
+ makeArrayRef(ClassOptionNames));
+ printTypeIndex("UnderlyingType", Enum.getUnderlyingType());
+ printTypeIndex("FieldListType", Enum.getFieldList());
+ W->printString("Name", Enum.getName());
+ if (Props & uint16_t(ClassOptions::HasUniqueName))
+ W->printString("LinkageName", Enum.getUniqueName());
+ Name = Enum.getName();
+ return Error::success();
+}
+
+Error CVTypeDumper::visitArray(ArrayRecord &AT) {
+ printTypeIndex("ElementType", AT.getElementType());
+ printTypeIndex("IndexType", AT.getIndexType());
+ W->printNumber("SizeOf", AT.getSize());
+ W->printString("Name", AT.getName());
+ Name = AT.getName();
+ return Error::success();
+}
+
+Error CVTypeDumper::visitVFTable(VFTableRecord &VFT) {
+ printTypeIndex("CompleteClass", VFT.getCompleteClass());
+ printTypeIndex("OverriddenVFTable", VFT.getOverriddenVTable());
+ W->printHex("VFPtrOffset", VFT.getVFPtrOffset());
+ W->printString("VFTableName", VFT.getName());
+ for (auto N : VFT.getMethodNames())
+ W->printString("MethodName", N);
+ Name = VFT.getName();
+ return Error::success();
+}
+
+Error CVTypeDumper::visitMemberFuncId(MemberFuncIdRecord &Id) {
+ printTypeIndex("ClassType", Id.getClassType());
+ printTypeIndex("FunctionType", Id.getFunctionType());
+ W->printString("Name", Id.getName());
+ Name = Id.getName();
+ return Error::success();
+}
+
+Error CVTypeDumper::visitProcedure(ProcedureRecord &Proc) {
+ printTypeIndex("ReturnType", Proc.getReturnType());
+ W->printEnum("CallingConvention", uint8_t(Proc.getCallConv()),
+ makeArrayRef(CallingConventions));
+ W->printFlags("FunctionOptions", uint8_t(Proc.getOptions()),
+ makeArrayRef(FunctionOptionEnum));
+ W->printNumber("NumParameters", Proc.getParameterCount());
+ printTypeIndex("ArgListType", Proc.getArgumentList());
+
+ StringRef ReturnTypeName = getTypeName(Proc.getReturnType());
+ StringRef ArgListTypeName = getTypeName(Proc.getArgumentList());
+ SmallString<256> TypeName(ReturnTypeName);
+ TypeName.push_back(' ');
+ TypeName.append(ArgListTypeName);
+ Name = saveName(TypeName);
+ return Error::success();
+}
+
+Error CVTypeDumper::visitMemberFunction(MemberFunctionRecord &MF) {
+ printTypeIndex("ReturnType", MF.getReturnType());
+ printTypeIndex("ClassType", MF.getClassType());
+ printTypeIndex("ThisType", MF.getThisType());
+ W->printEnum("CallingConvention", uint8_t(MF.getCallConv()),
+ makeArrayRef(CallingConventions));
+ W->printFlags("FunctionOptions", uint8_t(MF.getOptions()),
+ makeArrayRef(FunctionOptionEnum));
+ W->printNumber("NumParameters", MF.getParameterCount());
+ printTypeIndex("ArgListType", MF.getArgumentList());
+ W->printNumber("ThisAdjustment", MF.getThisPointerAdjustment());
+
+ StringRef ReturnTypeName = getTypeName(MF.getReturnType());
+ StringRef ClassTypeName = getTypeName(MF.getClassType());
+ StringRef ArgListTypeName = getTypeName(MF.getArgumentList());
+ SmallString<256> TypeName(ReturnTypeName);
+ TypeName.push_back(' ');
+ TypeName.append(ClassTypeName);
+ TypeName.append("::");
+ TypeName.append(ArgListTypeName);
+ Name = saveName(TypeName);
+ return Error::success();
+}
+
+Error CVTypeDumper::visitMethodOverloadList(
+ MethodOverloadListRecord &MethodList) {
+ for (auto &M : MethodList.getMethods()) {
+ ListScope S(*W, "Method");
+ printMemberAttributes(M.getAccess(), M.getKind(), M.getOptions());
+ printTypeIndex("Type", M.getType());
+ if (M.isIntroducingVirtual())
+ W->printHex("VFTableOffset", M.getVFTableOffset());
+ }
+ return Error::success();
+}
+
+Error CVTypeDumper::visitFuncId(FuncIdRecord &Func) {
+ printTypeIndex("ParentScope", Func.getParentScope());
+ printTypeIndex("FunctionType", Func.getFunctionType());
+ W->printString("Name", Func.getName());
+ Name = Func.getName();
+ return Error::success();
+}
+
+Error CVTypeDumper::visitTypeServer2(TypeServer2Record &TS) {
+ W->printBinary("Signature", TS.getGuid());
+ W->printNumber("Age", TS.getAge());
+ W->printString("Name", TS.getName());
+ Name = TS.getName();
+ return Error::success();
+}
+
+Error CVTypeDumper::visitPointer(PointerRecord &Ptr) {
+ printTypeIndex("PointeeType", Ptr.getReferentType());
+ W->printHex("PointerAttributes", uint32_t(Ptr.getOptions()));
+ W->printEnum("PtrType", unsigned(Ptr.getPointerKind()),
+ makeArrayRef(PtrKindNames));
+ W->printEnum("PtrMode", unsigned(Ptr.getMode()), makeArrayRef(PtrModeNames));
+
+ W->printNumber("IsFlat", Ptr.isFlat());
+ W->printNumber("IsConst", Ptr.isConst());
+ W->printNumber("IsVolatile", Ptr.isVolatile());
+ W->printNumber("IsUnaligned", Ptr.isUnaligned());
+ W->printNumber("SizeOf", Ptr.getSize());
+
+ if (Ptr.isPointerToMember()) {
+ const MemberPointerInfo &MI = Ptr.getMemberInfo();
+
+ printTypeIndex("ClassType", MI.getContainingType());
+ W->printEnum("Representation", uint16_t(MI.getRepresentation()),
+ makeArrayRef(PtrMemberRepNames));
+
+ StringRef PointeeName = getTypeName(Ptr.getReferentType());
+ StringRef ClassName = getTypeName(MI.getContainingType());
+ SmallString<256> TypeName(PointeeName);
+ TypeName.push_back(' ');
+ TypeName.append(ClassName);
+ TypeName.append("::*");
+ Name = saveName(TypeName);
+ } else {
+ SmallString<256> TypeName;
+ if (Ptr.isConst())
+ TypeName.append("const ");
+ if (Ptr.isVolatile())
+ TypeName.append("volatile ");
+ if (Ptr.isUnaligned())
+ TypeName.append("__unaligned ");
+
+ TypeName.append(getTypeName(Ptr.getReferentType()));
+
+ if (Ptr.getMode() == PointerMode::LValueReference)
+ TypeName.append("&");
+ else if (Ptr.getMode() == PointerMode::RValueReference)
+ TypeName.append("&&");
+ else if (Ptr.getMode() == PointerMode::Pointer)
+ TypeName.append("*");
+
+ if (!TypeName.empty())
+ Name = saveName(TypeName);
+ }
+ return Error::success();
+}
+
+Error CVTypeDumper::visitModifier(ModifierRecord &Mod) {
+ uint16_t Mods = static_cast<uint16_t>(Mod.getModifiers());
+ printTypeIndex("ModifiedType", Mod.getModifiedType());
+ W->printFlags("Modifiers", Mods, makeArrayRef(TypeModifierNames));
+
+ StringRef ModifiedName = getTypeName(Mod.getModifiedType());
+ SmallString<256> TypeName;
+ if (Mods & uint16_t(ModifierOptions::Const))
+ TypeName.append("const ");
+ if (Mods & uint16_t(ModifierOptions::Volatile))
+ TypeName.append("volatile ");
+ if (Mods & uint16_t(ModifierOptions::Unaligned))
+ TypeName.append("__unaligned ");
+ TypeName.append(ModifiedName);
+ Name = saveName(TypeName);
+ return Error::success();
+}
+
+Error CVTypeDumper::visitBitField(BitFieldRecord &BitField) {
+ printTypeIndex("Type", BitField.getType());
+ W->printNumber("BitSize", BitField.getBitSize());
+ W->printNumber("BitOffset", BitField.getBitOffset());
+ return Error::success();
+}
+
+Error CVTypeDumper::visitVFTableShape(VFTableShapeRecord &Shape) {
+ W->printNumber("VFEntryCount", Shape.getEntryCount());
+ return Error::success();
+}
+
+Error CVTypeDumper::visitUdtSourceLine(UdtSourceLineRecord &Line) {
+ printTypeIndex("UDT", Line.getUDT());
+ printTypeIndex("SourceFile", Line.getSourceFile());
+ W->printNumber("LineNumber", Line.getLineNumber());
+ return Error::success();
+}
+
+Error CVTypeDumper::visitUdtModSourceLine(UdtModSourceLineRecord &Line) {
+ printTypeIndex("UDT", Line.getUDT());
+ printTypeIndex("SourceFile", Line.getSourceFile());
+ W->printNumber("LineNumber", Line.getLineNumber());
+ W->printNumber("Module", Line.getModule());
+ return Error::success();
+}
+
+Error CVTypeDumper::visitBuildInfo(BuildInfoRecord &Args) {
+ W->printNumber("NumArgs", static_cast<uint32_t>(Args.getArgs().size()));
+
+ ListScope Arguments(*W, "Arguments");
+ for (auto Arg : Args.getArgs()) {
+ printTypeIndex("ArgType", Arg);
+ }
+ return Error::success();
+}
+
+void CVTypeDumper::printMemberAttributes(MemberAttributes Attrs) {
+ return printMemberAttributes(Attrs.getAccess(), Attrs.getMethodKind(),
+ Attrs.getFlags());
+}
+
+void CVTypeDumper::printMemberAttributes(MemberAccess Access, MethodKind Kind,
+ MethodOptions Options) {
+ W->printEnum("AccessSpecifier", uint8_t(Access),
+ makeArrayRef(MemberAccessNames));
+ // Data members will be vanilla. Don't try to print a method kind for them.
+ if (Kind != MethodKind::Vanilla)
+ W->printEnum("MethodKind", unsigned(Kind), makeArrayRef(MemberKindNames));
+ if (Options != MethodOptions::None) {
+ W->printFlags("MethodOptions", unsigned(Options),
+ makeArrayRef(MethodOptionNames));
+ }
+}
+
+Error CVTypeDumper::visitUnknownMember(const CVRecord<TypeLeafKind> &Record) {
+ W->printHex("UnknownMember", unsigned(Record.Type));
+ return Error::success();
+}
+
+Error CVTypeDumper::visitUnknownType(const CVRecord<TypeLeafKind> &Record) {
+ DictScope S(*W, "UnknownType");
+ W->printEnum("Kind", uint16_t(Record.Type), makeArrayRef(LeafTypeNames));
+ W->printNumber("Length", uint32_t(Record.Data.size()));
+ return Error::success();
+}
+
+Error CVTypeDumper::visitNestedType(NestedTypeRecord &Nested) {
+ DictScope S(*W, "NestedType");
+ printTypeIndex("Type", Nested.getNestedType());
+ W->printString("Name", Nested.getName());
+ Name = Nested.getName();
+ return Error::success();
+}
+
+Error CVTypeDumper::visitOneMethod(OneMethodRecord &Method) {
+ DictScope S(*W, "OneMethod");
+ MethodKind K = Method.getKind();
+ printMemberAttributes(Method.getAccess(), K, Method.getOptions());
+ printTypeIndex("Type", Method.getType());
+ // If virtual, then read the vftable offset.
+ if (Method.isIntroducingVirtual())
+ W->printHex("VFTableOffset", Method.getVFTableOffset());
+ W->printString("Name", Method.getName());
+ Name = Method.getName();
+ return Error::success();
+}
+
+Error CVTypeDumper::visitOverloadedMethod(OverloadedMethodRecord &Method) {
+ DictScope S(*W, "OverloadedMethod");
+ W->printHex("MethodCount", Method.getNumOverloads());
+ printTypeIndex("MethodListIndex", Method.getMethodList());
+ W->printString("Name", Method.getName());
+ Name = Method.getName();
+ return Error::success();
+}
+
+Error CVTypeDumper::visitDataMember(DataMemberRecord &Field) {
+ DictScope S(*W, "DataMember");
+ printMemberAttributes(Field.getAccess(), MethodKind::Vanilla,
+ MethodOptions::None);
+ printTypeIndex("Type", Field.getType());
+ W->printHex("FieldOffset", Field.getFieldOffset());
+ W->printString("Name", Field.getName());
+ Name = Field.getName();
+ return Error::success();
+}
+
+Error CVTypeDumper::visitStaticDataMember(StaticDataMemberRecord &Field) {
+ DictScope S(*W, "StaticDataMember");
+ printMemberAttributes(Field.getAccess(), MethodKind::Vanilla,
+ MethodOptions::None);
+ printTypeIndex("Type", Field.getType());
+ W->printString("Name", Field.getName());
+ Name = Field.getName();
+ return Error::success();
+}
+
+Error CVTypeDumper::visitVFPtr(VFPtrRecord &VFTable) {
+ DictScope S(*W, "VFPtr");
+ printTypeIndex("Type", VFTable.getType());
+ return Error::success();
+}
+
+Error CVTypeDumper::visitEnumerator(EnumeratorRecord &Enum) {
+ DictScope S(*W, "Enumerator");
+ printMemberAttributes(Enum.getAccess(), MethodKind::Vanilla,
+ MethodOptions::None);
+ W->printNumber("EnumValue", Enum.getValue());
+ W->printString("Name", Enum.getName());
+ Name = Enum.getName();
+ return Error::success();
+}
+
+Error CVTypeDumper::visitBaseClass(BaseClassRecord &Base) {
+ DictScope S(*W, "BaseClass");
+ printMemberAttributes(Base.getAccess(), MethodKind::Vanilla,
+ MethodOptions::None);
+ printTypeIndex("BaseType", Base.getBaseType());
+ W->printHex("BaseOffset", Base.getBaseOffset());
+ return Error::success();
+}
+
+Error CVTypeDumper::visitVirtualBaseClass(VirtualBaseClassRecord &Base) {
+ DictScope S(*W, "VirtualBaseClass");
+ printMemberAttributes(Base.getAccess(), MethodKind::Vanilla,
+ MethodOptions::None);
+ printTypeIndex("BaseType", Base.getBaseType());
+ printTypeIndex("VBPtrType", Base.getVBPtrType());
+ W->printHex("VBPtrOffset", Base.getVBPtrOffset());
+ W->printHex("VBTableIndex", Base.getVTableIndex());
+ return Error::success();
+}
+
+Error CVTypeDumper::visitListContinuation(ListContinuationRecord &Cont) {
+ DictScope S(*W, "ListContinuation");
+ printTypeIndex("ContinuationIndex", Cont.getContinuationIndex());
+ return Error::success();
+}
+
+StringRef CVTypeDumper::getTypeName(TypeIndex TI) {
+ if (TI.isNoneType())
+ return "<no type>";
+
+ if (TI.isSimple()) {
+ // This is a simple type.
+ for (const auto &SimpleTypeName : SimpleTypeNames) {
+ if (SimpleTypeName.Value == TI.getSimpleKind()) {
+ if (TI.getSimpleMode() == SimpleTypeMode::Direct)
+ return SimpleTypeName.Name.drop_back(1);
+ // Otherwise, this is a pointer type. We gloss over the distinction
+ // between near, far, 64, 32, etc, and just give a pointer type.
+ return SimpleTypeName.Name;
+ }
+ }
+ return "<unknown simple type>";
+ }
+
+ // User-defined type.
+ StringRef UDTName;
+ unsigned UDTIndex = TI.getIndex() - 0x1000;
+ if (UDTIndex < CVUDTNames.size())
+ return CVUDTNames[UDTIndex];
+
+ return "<unknown UDT>";
+}
+
+void CVTypeDumper::printTypeIndex(StringRef FieldName, TypeIndex TI) {
+ StringRef TypeName;
+ if (!TI.isNoneType())
+ TypeName = getTypeName(TI);
+ if (!TypeName.empty())
+ W->printHex(FieldName, TypeName, TI.getIndex());
+ else
+ W->printHex(FieldName, TI.getIndex());
+}
+
+Error CVTypeDumper::dump(const CVRecord<TypeLeafKind> &Record) {
+ assert(W && "printer should not be null");
+ CVTypeVisitor Visitor(*this);
+
+ if (auto EC = Visitor.visitTypeRecord(Record))
+ return EC;
+ return Error::success();
+}
+
+Error CVTypeDumper::dump(const CVTypeArray &Types) {
+ assert(W && "printer should not be null");
+ CVTypeVisitor Visitor(*this);
+ if (auto EC = Visitor.visitTypeStream(Types))
+ return EC;
+ return Error::success();
+}
+
+Error CVTypeDumper::dump(ArrayRef<uint8_t> Data) {
+ ByteStream<> Stream(Data);
+ CVTypeArray Types;
+ StreamReader Reader(Stream);
+ if (auto EC = Reader.readArray(Types, Reader.getLength()))
+ return EC;
+
+ return dump(Types);
+}
+
+void CVTypeDumper::setPrinter(ScopedPrinter *P) {
+ static ScopedPrinter NullP(llvm::nulls());
+ W = P ? P : &NullP;
+}
diff --git a/lib/DebugInfo/CodeView/TypeRecord.cpp b/lib/DebugInfo/CodeView/TypeRecord.cpp
new file mode 100644
index 0000000000000..f63371e8c14fe
--- /dev/null
+++ b/lib/DebugInfo/CodeView/TypeRecord.cpp
@@ -0,0 +1,572 @@
+//===-- TypeRecord.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/TypeRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+#include "llvm/DebugInfo/CodeView/RecordSerialization.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+//===----------------------------------------------------------------------===//
+// Type record deserialization
+//===----------------------------------------------------------------------===//
+
+ErrorOr<MemberPointerInfo>
+MemberPointerInfo::deserialize(ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ if (auto EC = consumeObject(Data, L))
+ return EC;
+
+ TypeIndex T = L->ClassType;
+ uint16_t R = L->Representation;
+ PointerToMemberRepresentation PMR =
+ static_cast<PointerToMemberRepresentation>(R);
+ return MemberPointerInfo(T, PMR);
+}
+
+ErrorOr<ModifierRecord> ModifierRecord::deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ if (auto EC = consumeObject(Data, L))
+ return EC;
+
+ TypeIndex M = L->ModifiedType;
+ uint16_t O = L->Modifiers;
+ ModifierOptions MO = static_cast<ModifierOptions>(O);
+ return ModifierRecord(M, MO);
+}
+
+ErrorOr<ProcedureRecord> ProcedureRecord::deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ if (auto EC = consumeObject(Data, L))
+ return EC;
+ return ProcedureRecord(L->ReturnType, L->CallConv, L->Options,
+ L->NumParameters, L->ArgListType);
+}
+
+ErrorOr<MemberFunctionRecord>
+MemberFunctionRecord::deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ CV_DESERIALIZE(Data, L);
+ return MemberFunctionRecord(L->ReturnType, L->ClassType, L->ThisType,
+ L->CallConv, L->Options, L->NumParameters,
+ L->ArgListType, L->ThisAdjustment);
+}
+
+ErrorOr<MemberFuncIdRecord>
+MemberFuncIdRecord::deserialize(TypeRecordKind Kind, ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ StringRef Name;
+ CV_DESERIALIZE(Data, L, Name);
+ return MemberFuncIdRecord(L->ClassType, L->FunctionType, Name);
+}
+
+ErrorOr<ArgListRecord> ArgListRecord::deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data) {
+ if (Kind != TypeRecordKind::StringList && Kind != TypeRecordKind::ArgList)
+ return std::make_error_code(std::errc::illegal_byte_sequence);
+
+ const Layout *L = nullptr;
+ ArrayRef<TypeIndex> Indices;
+ CV_DESERIALIZE(Data, L, CV_ARRAY_FIELD_N(Indices, L->NumArgs));
+ return ArgListRecord(Kind, Indices);
+}
+
+ErrorOr<PointerRecord> PointerRecord::deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ if (auto EC = consumeObject(Data, L))
+ return EC;
+
+ PointerKind PtrKind = L->getPtrKind();
+ PointerMode Mode = L->getPtrMode();
+ uint32_t Opts = L->Attrs;
+ PointerOptions Options = static_cast<PointerOptions>(Opts);
+ uint8_t Size = L->getPtrSize();
+
+ if (L->isPointerToMember()) {
+ auto E = MemberPointerInfo::deserialize(Data);
+ if (E.getError())
+ return std::make_error_code(std::errc::illegal_byte_sequence);
+ return PointerRecord(L->PointeeType, PtrKind, Mode, Options, Size, *E);
+ }
+
+ return PointerRecord(L->PointeeType, PtrKind, Mode, Options, Size);
+}
+
+ErrorOr<NestedTypeRecord>
+NestedTypeRecord::deserialize(TypeRecordKind Kind, ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ StringRef Name;
+ CV_DESERIALIZE(Data, L, Name);
+ return NestedTypeRecord(L->Type, Name);
+}
+
+ErrorOr<ArrayRecord> ArrayRecord::deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ uint64_t Size;
+ StringRef Name;
+ CV_DESERIALIZE(Data, L, CV_NUMERIC_FIELD(Size), Name);
+ return ArrayRecord(L->ElementType, L->IndexType, Size, Name);
+}
+
+ErrorOr<ClassRecord> ClassRecord::deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data) {
+ uint64_t Size = 0;
+ StringRef Name;
+ StringRef UniqueName;
+ uint16_t Props;
+ const Layout *L = nullptr;
+
+ CV_DESERIALIZE(Data, L, CV_NUMERIC_FIELD(Size), Name,
+ CV_CONDITIONAL_FIELD(UniqueName, L->hasUniqueName()));
+
+ Props = L->Properties;
+ uint16_t WrtValue = (Props & WinRTKindMask) >> WinRTKindShift;
+ WindowsRTClassKind WRT = static_cast<WindowsRTClassKind>(WrtValue);
+ uint16_t HfaMask = (Props & HfaKindMask) >> HfaKindShift;
+ HfaKind Hfa = static_cast<HfaKind>(HfaMask);
+
+ ClassOptions Options = static_cast<ClassOptions>(Props);
+ return ClassRecord(Kind, L->MemberCount, Options, Hfa, WRT, L->FieldList,
+ L->DerivedFrom, L->VShape, Size, Name, UniqueName);
+}
+
+ErrorOr<UnionRecord> UnionRecord::deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data) {
+ uint64_t Size = 0;
+ StringRef Name;
+ StringRef UniqueName;
+ uint16_t Props;
+
+ const Layout *L = nullptr;
+ CV_DESERIALIZE(Data, L, CV_NUMERIC_FIELD(Size), Name,
+ CV_CONDITIONAL_FIELD(UniqueName, L->hasUniqueName()));
+
+ Props = L->Properties;
+
+ uint16_t HfaMask = (Props & HfaKindMask) >> HfaKindShift;
+ HfaKind Hfa = static_cast<HfaKind>(HfaMask);
+ ClassOptions Options = static_cast<ClassOptions>(Props);
+ return UnionRecord(L->MemberCount, Options, Hfa, L->FieldList, Size, Name,
+ UniqueName);
+}
+
+ErrorOr<EnumRecord> EnumRecord::deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ StringRef Name;
+ StringRef UniqueName;
+ CV_DESERIALIZE(Data, L, Name,
+ CV_CONDITIONAL_FIELD(UniqueName, L->hasUniqueName()));
+
+ uint16_t P = L->Properties;
+ ClassOptions Options = static_cast<ClassOptions>(P);
+ return EnumRecord(L->NumEnumerators, Options, L->FieldListType, Name,
+ UniqueName, L->UnderlyingType);
+}
+
+ErrorOr<BitFieldRecord> BitFieldRecord::deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ CV_DESERIALIZE(Data, L);
+ return BitFieldRecord(L->Type, L->BitSize, L->BitOffset);
+}
+
+ErrorOr<VFTableShapeRecord>
+VFTableShapeRecord::deserialize(TypeRecordKind Kind, ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ if (auto EC = consumeObject(Data, L))
+ return EC;
+
+ std::vector<VFTableSlotKind> Slots;
+ uint16_t Count = L->VFEntryCount;
+ while (Count > 0) {
+ if (Data.empty())
+ return std::make_error_code(std::errc::illegal_byte_sequence);
+
+ // Process up to 2 nibbles at a time (if there are at least 2 remaining)
+ uint8_t Value = Data[0] & 0x0F;
+ Slots.push_back(static_cast<VFTableSlotKind>(Value));
+ if (--Count > 0) {
+ Value = (Data[0] & 0xF0) >> 4;
+ Slots.push_back(static_cast<VFTableSlotKind>(Value));
+ --Count;
+ }
+ Data = Data.slice(1);
+ }
+
+ return VFTableShapeRecord(Slots);
+}
+
+ErrorOr<TypeServer2Record>
+TypeServer2Record::deserialize(TypeRecordKind Kind, ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ StringRef Name;
+ CV_DESERIALIZE(Data, L, Name);
+ return TypeServer2Record(StringRef(L->Guid, 16), L->Age, Name);
+}
+
+ErrorOr<StringIdRecord> StringIdRecord::deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ StringRef Name;
+ CV_DESERIALIZE(Data, L, Name);
+ return StringIdRecord(L->id, Name);
+}
+
+ErrorOr<FuncIdRecord> FuncIdRecord::deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ StringRef Name;
+ CV_DESERIALIZE(Data, L, Name);
+ return FuncIdRecord(L->ParentScope, L->FunctionType, Name);
+}
+
+ErrorOr<UdtSourceLineRecord>
+UdtSourceLineRecord::deserialize(TypeRecordKind Kind, ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ CV_DESERIALIZE(Data, L);
+ return UdtSourceLineRecord(L->UDT, L->SourceFile, L->LineNumber);
+}
+
+ErrorOr<BuildInfoRecord> BuildInfoRecord::deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ ArrayRef<TypeIndex> Indices;
+ CV_DESERIALIZE(Data, L, CV_ARRAY_FIELD_N(Indices, L->NumArgs));
+ return BuildInfoRecord(Indices);
+}
+
+ErrorOr<VFTableRecord> VFTableRecord::deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ StringRef Name;
+ std::vector<StringRef> Names;
+ CV_DESERIALIZE(Data, L, Name, CV_ARRAY_FIELD_TAIL(Names));
+ return VFTableRecord(L->CompleteClass, L->OverriddenVFTable, L->VFPtrOffset,
+ Name, Names);
+}
+
+ErrorOr<OneMethodRecord> OneMethodRecord::deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ StringRef Name;
+ int32_t VFTableOffset = -1;
+
+ CV_DESERIALIZE(Data, L, CV_CONDITIONAL_FIELD(VFTableOffset,
+ L->Attrs.isIntroducedVirtual()),
+ Name);
+
+ MethodOptions Options = L->Attrs.getFlags();
+ MethodKind MethKind = L->Attrs.getMethodKind();
+ MemberAccess Access = L->Attrs.getAccess();
+ OneMethodRecord Method(L->Type, MethKind, Options, Access, VFTableOffset,
+ Name);
+ // Validate the vftable offset.
+ if (Method.isIntroducingVirtual() && Method.getVFTableOffset() < 0)
+ return std::make_error_code(std::errc::illegal_byte_sequence);
+ return Method;
+}
+
+ErrorOr<MethodOverloadListRecord>
+MethodOverloadListRecord::deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data) {
+ std::vector<OneMethodRecord> Methods;
+ while (!Data.empty()) {
+ const Layout *L = nullptr;
+ int32_t VFTableOffset = -1;
+ CV_DESERIALIZE(Data, L, CV_CONDITIONAL_FIELD(
+ VFTableOffset, L->Attrs.isIntroducedVirtual()));
+
+ MethodOptions Options = L->Attrs.getFlags();
+ MethodKind MethKind = L->Attrs.getMethodKind();
+ MemberAccess Access = L->Attrs.getAccess();
+
+ Methods.emplace_back(L->Type, MethKind, Options, Access, VFTableOffset,
+ StringRef());
+
+ // Validate the vftable offset.
+ auto &Method = Methods.back();
+ if (Method.isIntroducingVirtual() && Method.getVFTableOffset() < 0)
+ return std::make_error_code(std::errc::illegal_byte_sequence);
+ }
+ return MethodOverloadListRecord(Methods);
+}
+
+ErrorOr<OverloadedMethodRecord>
+OverloadedMethodRecord::deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ StringRef Name;
+ CV_DESERIALIZE(Data, L, Name);
+ return OverloadedMethodRecord(L->MethodCount, L->MethList, Name);
+}
+
+ErrorOr<DataMemberRecord>
+DataMemberRecord::deserialize(TypeRecordKind Kind, ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ uint64_t Offset;
+ StringRef Name;
+ CV_DESERIALIZE(Data, L, CV_NUMERIC_FIELD(Offset), Name);
+ return DataMemberRecord(L->Attrs.getAccess(), L->Type, Offset, Name);
+}
+
+ErrorOr<StaticDataMemberRecord>
+StaticDataMemberRecord::deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ StringRef Name;
+ CV_DESERIALIZE(Data, L, Name);
+ return StaticDataMemberRecord(L->Attrs.getAccess(), L->Type, Name);
+}
+
+ErrorOr<EnumeratorRecord>
+EnumeratorRecord::deserialize(TypeRecordKind Kind, ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ APSInt Value;
+ StringRef Name;
+ CV_DESERIALIZE(Data, L, Value, Name);
+ return EnumeratorRecord(L->Attrs.getAccess(), Value, Name);
+}
+
+ErrorOr<VFPtrRecord> VFPtrRecord::deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ if (auto EC = consumeObject(Data, L))
+ return EC;
+ return VFPtrRecord(L->Type);
+}
+
+ErrorOr<BaseClassRecord> BaseClassRecord::deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ uint64_t Offset;
+ CV_DESERIALIZE(Data, L, CV_NUMERIC_FIELD(Offset));
+ return BaseClassRecord(L->Attrs.getAccess(), L->BaseType, Offset);
+}
+
+ErrorOr<VirtualBaseClassRecord>
+VirtualBaseClassRecord::deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ uint64_t Offset;
+ uint64_t Index;
+ CV_DESERIALIZE(Data, L, CV_NUMERIC_FIELD(Offset), CV_NUMERIC_FIELD(Index));
+ return VirtualBaseClassRecord(L->Attrs.getAccess(), L->BaseType, L->VBPtrType,
+ Offset, Index);
+}
+
+ErrorOr<ListContinuationRecord>
+ListContinuationRecord::deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ CV_DESERIALIZE(Data, L);
+ return ListContinuationRecord(L->ContinuationIndex);
+}
+
+//===----------------------------------------------------------------------===//
+// Type index remapping
+//===----------------------------------------------------------------------===//
+
+static bool remapIndex(ArrayRef<TypeIndex> IndexMap, TypeIndex &Idx) {
+ // Simple types are unchanged.
+ if (Idx.isSimple())
+ return true;
+ unsigned MapPos = Idx.getIndex() - TypeIndex::FirstNonSimpleIndex;
+ if (MapPos < IndexMap.size()) {
+ Idx = IndexMap[MapPos];
+ return true;
+ }
+
+ // This type index is invalid. Remap this to "not translated by cvpack",
+ // and return failure.
+ Idx = TypeIndex(SimpleTypeKind::NotTranslated, SimpleTypeMode::Direct);
+ return false;
+}
+
+bool ModifierRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ return remapIndex(IndexMap, ModifiedType);
+}
+
+bool ProcedureRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ bool Success = true;
+ Success &= remapIndex(IndexMap, ReturnType);
+ Success &= remapIndex(IndexMap, ArgumentList);
+ return Success;
+}
+
+bool MemberFunctionRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ bool Success = true;
+ Success &= remapIndex(IndexMap, ReturnType);
+ Success &= remapIndex(IndexMap, ClassType);
+ Success &= remapIndex(IndexMap, ThisType);
+ Success &= remapIndex(IndexMap, ArgumentList);
+ return Success;
+}
+
+bool MemberFuncIdRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ bool Success = true;
+ Success &= remapIndex(IndexMap, ClassType);
+ Success &= remapIndex(IndexMap, FunctionType);
+ return Success;
+}
+
+bool ArgListRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ bool Success = true;
+ for (TypeIndex &Str : StringIndices)
+ Success &= remapIndex(IndexMap, Str);
+ return Success;
+}
+
+bool MemberPointerInfo::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ return remapIndex(IndexMap, ContainingType);
+}
+
+bool PointerRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ bool Success = true;
+ Success &= remapIndex(IndexMap, ReferentType);
+ if (isPointerToMember())
+ Success &= MemberInfo.remapTypeIndices(IndexMap);
+ return Success;
+}
+
+bool NestedTypeRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ return remapIndex(IndexMap, Type);
+}
+
+bool ArrayRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ bool Success = true;
+ Success &= remapIndex(IndexMap, ElementType);
+ Success &= remapIndex(IndexMap, IndexType);
+ return Success;
+}
+
+bool TagRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ return remapIndex(IndexMap, FieldList);
+}
+
+bool ClassRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ bool Success = true;
+ Success &= TagRecord::remapTypeIndices(IndexMap);
+ Success &= remapIndex(IndexMap, DerivationList);
+ Success &= remapIndex(IndexMap, VTableShape);
+ return Success;
+}
+
+bool EnumRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ bool Success = true;
+ Success &= TagRecord::remapTypeIndices(IndexMap);
+ Success &= remapIndex(IndexMap, UnderlyingType);
+ return Success;
+}
+
+bool BitFieldRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ return remapIndex(IndexMap, Type);
+}
+
+bool VFTableShapeRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ return true;
+}
+
+bool TypeServer2Record::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ return true;
+}
+
+bool StringIdRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ return remapIndex(IndexMap, Id);
+}
+
+bool FuncIdRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ bool Success = true;
+ Success &= remapIndex(IndexMap, ParentScope);
+ Success &= remapIndex(IndexMap, FunctionType);
+ return Success;
+}
+
+bool UdtSourceLineRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ bool Success = true;
+ Success &= remapIndex(IndexMap, UDT);
+ Success &= remapIndex(IndexMap, SourceFile);
+ return Success;
+}
+
+bool UdtModSourceLineRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ bool Success = true;
+ Success &= remapIndex(IndexMap, UDT);
+ Success &= remapIndex(IndexMap, SourceFile);
+ return Success;
+}
+
+bool BuildInfoRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ bool Success = true;
+ for (TypeIndex &Arg : ArgIndices)
+ Success &= remapIndex(IndexMap, Arg);
+ return Success;
+}
+
+bool VFTableRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ bool Success = true;
+ Success &= remapIndex(IndexMap, CompleteClass);
+ Success &= remapIndex(IndexMap, OverriddenVFTable);
+ return Success;
+}
+
+bool OneMethodRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ bool Success = true;
+ Success &= remapIndex(IndexMap, Type);
+ return Success;
+}
+
+bool MethodOverloadListRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ bool Success = true;
+ for (OneMethodRecord &Meth : Methods)
+ if ((Success = Meth.remapTypeIndices(IndexMap)))
+ return Success;
+ return Success;
+}
+
+bool OverloadedMethodRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ return remapIndex(IndexMap, MethodList);
+}
+
+bool DataMemberRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ return remapIndex(IndexMap, Type);
+}
+
+bool StaticDataMemberRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ return remapIndex(IndexMap, Type);
+}
+
+bool EnumeratorRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ return true;
+}
+
+bool VFPtrRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ return remapIndex(IndexMap, Type);
+}
+
+bool BaseClassRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ return remapIndex(IndexMap, Type);
+}
+
+bool VirtualBaseClassRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ bool Success = true;
+ Success &= remapIndex(IndexMap, BaseType);
+ Success &= remapIndex(IndexMap, VBPtrType);
+ return Success;
+}
+
+bool ListContinuationRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ return remapIndex(IndexMap, ContinuationIndex);
+}
diff --git a/lib/DebugInfo/CodeView/TypeRecordBuilder.cpp b/lib/DebugInfo/CodeView/TypeRecordBuilder.cpp
index cbf464fd76687..112612cc85eab 100644
--- a/lib/DebugInfo/CodeView/TypeRecordBuilder.cpp
+++ b/lib/DebugInfo/CodeView/TypeRecordBuilder.cpp
@@ -12,8 +12,8 @@
using namespace llvm;
using namespace codeview;
-TypeRecordBuilder::TypeRecordBuilder(TypeRecordKind Kind) : Stream(Buffer),
- Writer(Stream) {
+TypeRecordBuilder::TypeRecordBuilder(TypeRecordKind Kind)
+ : Stream(Buffer), Writer(Stream) {
writeTypeRecordKind(Kind);
}
@@ -60,50 +60,50 @@ void TypeRecordBuilder::writeEncodedInteger(int64_t Value) {
void TypeRecordBuilder::writeEncodedSignedInteger(int64_t Value) {
if (Value >= std::numeric_limits<int8_t>::min() &&
Value <= std::numeric_limits<int8_t>::max()) {
- writeUInt16(static_cast<uint16_t>(TypeRecordKind::SByte));
+ writeUInt16(LF_CHAR);
writeInt16(static_cast<int8_t>(Value));
} else if (Value >= std::numeric_limits<int16_t>::min() &&
Value <= std::numeric_limits<int16_t>::max()) {
- writeUInt16(static_cast<uint16_t>(TypeRecordKind::Int16));
+ writeUInt16(LF_SHORT);
writeInt16(static_cast<int16_t>(Value));
} else if (Value >= std::numeric_limits<int32_t>::min() &&
Value <= std::numeric_limits<int32_t>::max()) {
- writeUInt16(static_cast<uint32_t>(TypeRecordKind::Int32));
+ writeUInt16(LF_LONG);
writeInt32(static_cast<int32_t>(Value));
} else {
- writeUInt16(static_cast<uint16_t>(TypeRecordKind::Int64));
+ writeUInt16(LF_QUADWORD);
writeInt64(Value);
}
}
void TypeRecordBuilder::writeEncodedUnsignedInteger(uint64_t Value) {
- if (Value < static_cast<uint16_t>(TypeRecordKind::SByte)) {
+ if (Value < LF_CHAR) {
writeUInt16(static_cast<uint16_t>(Value));
} else if (Value <= std::numeric_limits<uint16_t>::max()) {
- writeUInt16(static_cast<uint16_t>(TypeRecordKind::UInt16));
+ writeUInt16(LF_USHORT);
writeUInt16(static_cast<uint16_t>(Value));
} else if (Value <= std::numeric_limits<uint32_t>::max()) {
- writeUInt16(static_cast<uint16_t>(TypeRecordKind::UInt32));
+ writeUInt16(LF_ULONG);
writeUInt32(static_cast<uint32_t>(Value));
} else {
- writeUInt16(static_cast<uint16_t>(TypeRecordKind::UInt64));
+ writeUInt16(LF_UQUADWORD);
writeUInt64(Value);
}
}
-void TypeRecordBuilder::writeNullTerminatedString(const char *Value) {
- assert(Value != nullptr);
-
- size_t Length = strlen(Value);
- Stream.write(Value, Length);
- writeUInt8(0);
-}
-
void TypeRecordBuilder::writeNullTerminatedString(StringRef Value) {
+ // Microsoft's linker seems to have trouble with symbol names longer than
+ // 0xffd8 bytes.
+ Value = Value.substr(0, 0xffd8);
Stream.write(Value.data(), Value.size());
writeUInt8(0);
}
+void TypeRecordBuilder::writeGuid(StringRef Guid) {
+ assert(Guid.size() == 16);
+ Stream.write(Guid.data(), 16);
+}
+
void TypeRecordBuilder::writeTypeIndex(TypeIndex TypeInd) {
writeUInt32(TypeInd.getIndex());
}
diff --git a/lib/DebugInfo/CodeView/TypeStreamMerger.cpp b/lib/DebugInfo/CodeView/TypeStreamMerger.cpp
new file mode 100644
index 0000000000000..ebfda2462be10
--- /dev/null
+++ b/lib/DebugInfo/CodeView/TypeStreamMerger.cpp
@@ -0,0 +1,149 @@
+//===-- TypeStreamMerger.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/TypeStreamMerger.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
+#include "llvm/DebugInfo/CodeView/FieldListRecordBuilder.h"
+#include "llvm/DebugInfo/CodeView/StreamRef.h"
+#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ScopedPrinter.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+namespace {
+
+/// Implementation of CodeView type stream merging.
+///
+/// A CodeView type stream is a series of records that reference each other
+/// through type indices. A type index is either "simple", meaning it is less
+/// than 0x1000 and refers to a builtin type, or it is complex, meaning it
+/// refers to a prior type record in the current stream. The type index of a
+/// record is equal to the number of records before it in the stream plus
+/// 0x1000.
+///
+/// Type records are only allowed to use type indices smaller than their own, so
+/// a type stream is effectively a topologically sorted DAG. Cycles occuring in
+/// the type graph of the source program are resolved with forward declarations
+/// of composite types. This class implements the following type stream merging
+/// algorithm, which relies on this DAG structure:
+///
+/// - Begin with a new empty stream, and a new empty hash table that maps from
+/// type record contents to new type index.
+/// - For each new type stream, maintain a map from source type index to
+/// destination type index.
+/// - For each record, copy it and rewrite its type indices to be valid in the
+/// destination type stream.
+/// - If the new type record is not already present in the destination stream
+/// hash table, append it to the destination type stream, assign it the next
+/// type index, and update the two hash tables.
+/// - If the type record already exists in the destination stream, discard it
+/// and update the type index map to forward the source type index to the
+/// existing destination type index.
+class TypeStreamMerger : public TypeVisitorCallbacks {
+public:
+ TypeStreamMerger(TypeTableBuilder &DestStream) : DestStream(DestStream) {
+ assert(!hadError());
+ }
+
+/// TypeVisitorCallbacks overrides.
+#define TYPE_RECORD(EnumName, EnumVal, Name) \
+ Error visit##Name(Name##Record &Record) override;
+#define MEMBER_RECORD(EnumName, EnumVal, Name) \
+ TYPE_RECORD(EnumName, EnumVal, Name)
+#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
+#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
+#include "llvm/DebugInfo/CodeView/TypeRecords.def"
+
+ Error visitUnknownType(const CVRecord<TypeLeafKind> &Record) override;
+
+ Error visitTypeBegin(const CVRecord<TypeLeafKind> &Record) override;
+ Error visitTypeEnd(const CVRecord<TypeLeafKind> &Record) override;
+
+ Error visitFieldListEnd(const CVRecord<TypeLeafKind> &Record) override;
+
+ bool mergeStream(const CVTypeArray &Types);
+
+private:
+ bool hadError() { return FoundBadTypeIndex; }
+
+ bool FoundBadTypeIndex = false;
+
+ FieldListRecordBuilder FieldBuilder;
+
+ TypeTableBuilder &DestStream;
+
+ size_t BeginIndexMapSize = 0;
+
+ /// Map from source type index to destination type index. Indexed by source
+ /// type index minus 0x1000.
+ SmallVector<TypeIndex, 0> IndexMap;
+};
+
+} // end anonymous namespace
+
+Error TypeStreamMerger::visitTypeBegin(const CVRecord<TypeLeafKind> &Rec) {
+ BeginIndexMapSize = IndexMap.size();
+ return Error::success();
+}
+
+Error TypeStreamMerger::visitTypeEnd(const CVRecord<TypeLeafKind> &Rec) {
+ assert(IndexMap.size() == BeginIndexMapSize + 1);
+ return Error::success();
+}
+
+Error TypeStreamMerger::visitFieldListEnd(const CVRecord<TypeLeafKind> &Rec) {
+ IndexMap.push_back(DestStream.writeFieldList(FieldBuilder));
+ FieldBuilder.reset();
+ return Error::success();
+}
+
+#define TYPE_RECORD(EnumName, EnumVal, Name) \
+ Error TypeStreamMerger::visit##Name(Name##Record &Record) { \
+ FoundBadTypeIndex |= !Record.remapTypeIndices(IndexMap); \
+ IndexMap.push_back(DestStream.write##Name(Record)); \
+ return Error::success(); \
+ }
+#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
+#define MEMBER_RECORD(EnumName, EnumVal, Name) \
+ Error TypeStreamMerger::visit##Name(Name##Record &Record) { \
+ FoundBadTypeIndex |= !Record.remapTypeIndices(IndexMap); \
+ FieldBuilder.write##Name(Record); \
+ return Error::success(); \
+ }
+#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
+#include "llvm/DebugInfo/CodeView/TypeRecords.def"
+
+Error TypeStreamMerger::visitUnknownType(const CVRecord<TypeLeafKind> &Rec) {
+ // We failed to translate a type. Translate this index as "not translated".
+ IndexMap.push_back(
+ TypeIndex(SimpleTypeKind::NotTranslated, SimpleTypeMode::Direct));
+ return llvm::make_error<CodeViewError>(cv_error_code::corrupt_record);
+}
+
+bool TypeStreamMerger::mergeStream(const CVTypeArray &Types) {
+ assert(IndexMap.empty());
+ CVTypeVisitor Visitor(*this);
+ if (auto EC = Visitor.visitTypeStream(Types)) {
+ consumeError(std::move(EC));
+ return false;
+ }
+ IndexMap.clear();
+ return !hadError();
+}
+
+bool llvm::codeview::mergeTypeStreams(TypeTableBuilder &DestStream,
+ const CVTypeArray &Types) {
+ return TypeStreamMerger(DestStream).mergeStream(Types);
+}
diff --git a/lib/DebugInfo/CodeView/TypeTableBuilder.cpp b/lib/DebugInfo/CodeView/TypeTableBuilder.cpp
index 4af5dcaf72289..647538ee8ceb6 100644
--- a/lib/DebugInfo/CodeView/TypeTableBuilder.cpp
+++ b/lib/DebugInfo/CodeView/TypeTableBuilder.cpp
@@ -8,7 +8,6 @@
//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
-#include "llvm/ADT/SmallVector.h"
#include "llvm/DebugInfo/CodeView/FieldListRecordBuilder.h"
#include "llvm/DebugInfo/CodeView/MethodListRecordBuilder.h"
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
@@ -18,42 +17,21 @@
using namespace llvm;
using namespace codeview;
-namespace {
-
-const int PointerKindShift = 0;
-const int PointerModeShift = 5;
-const int PointerSizeShift = 13;
-
-const int ClassHfaKindShift = 11;
-const int ClassWindowsRTClassKindShift = 14;
-
-void writePointerBase(TypeRecordBuilder &Builder,
- const PointerRecordBase &Record) {
- Builder.writeTypeIndex(Record.getReferentType());
- uint32_t flags =
- static_cast<uint32_t>(Record.getOptions()) |
- (Record.getSize() << PointerSizeShift) |
- (static_cast<uint32_t>(Record.getMode()) << PointerModeShift) |
- (static_cast<uint32_t>(Record.getPointerKind()) << PointerKindShift);
- Builder.writeUInt32(flags);
-}
-}
-
TypeTableBuilder::TypeTableBuilder() {}
TypeTableBuilder::~TypeTableBuilder() {}
TypeIndex TypeTableBuilder::writeModifier(const ModifierRecord &Record) {
- TypeRecordBuilder Builder(TypeRecordKind::Modifier);
+ TypeRecordBuilder Builder(Record.getKind());
Builder.writeTypeIndex(Record.getModifiedType());
- Builder.writeUInt16(static_cast<uint16_t>(Record.getOptions()));
+ Builder.writeUInt16(static_cast<uint16_t>(Record.getModifiers()));
return writeRecord(Builder);
}
TypeIndex TypeTableBuilder::writeProcedure(const ProcedureRecord &Record) {
- TypeRecordBuilder Builder(TypeRecordKind::Procedure);
+ TypeRecordBuilder Builder(Record.getKind());
Builder.writeTypeIndex(Record.getReturnType());
Builder.writeUInt8(static_cast<uint8_t>(Record.getCallConv()));
@@ -66,7 +44,7 @@ TypeIndex TypeTableBuilder::writeProcedure(const ProcedureRecord &Record) {
TypeIndex
TypeTableBuilder::writeMemberFunction(const MemberFunctionRecord &Record) {
- TypeRecordBuilder Builder(TypeRecordKind::MemberFunction);
+ TypeRecordBuilder Builder(Record.getKind());
Builder.writeTypeIndex(Record.getReturnType());
Builder.writeTypeIndex(Record.getClassType());
@@ -80,12 +58,11 @@ TypeTableBuilder::writeMemberFunction(const MemberFunctionRecord &Record) {
return writeRecord(Builder);
}
-TypeIndex
-TypeTableBuilder::writeArgumentList(const ArgumentListRecord &Record) {
- TypeRecordBuilder Builder(TypeRecordKind::ArgumentList);
+TypeIndex TypeTableBuilder::writeArgList(const ArgListRecord &Record) {
+ TypeRecordBuilder Builder(Record.getKind());
- Builder.writeUInt32(Record.getArgumentTypes().size());
- for (TypeIndex TI : Record.getArgumentTypes()) {
+ Builder.writeUInt32(Record.getIndices().size());
+ for (TypeIndex TI : Record.getIndices()) {
Builder.writeTypeIndex(TI);
}
@@ -93,27 +70,28 @@ TypeTableBuilder::writeArgumentList(const ArgumentListRecord &Record) {
}
TypeIndex TypeTableBuilder::writePointer(const PointerRecord &Record) {
- TypeRecordBuilder Builder(TypeRecordKind::Pointer);
-
- writePointerBase(Builder, Record);
-
- return writeRecord(Builder);
-}
-
-TypeIndex
-TypeTableBuilder::writePointerToMember(const PointerToMemberRecord &Record) {
- TypeRecordBuilder Builder(TypeRecordKind::Pointer);
+ TypeRecordBuilder Builder(Record.getKind());
- writePointerBase(Builder, Record);
+ Builder.writeTypeIndex(Record.getReferentType());
+ uint32_t flags = static_cast<uint32_t>(Record.getOptions()) |
+ (Record.getSize() << PointerRecord::PointerSizeShift) |
+ (static_cast<uint32_t>(Record.getMode())
+ << PointerRecord::PointerModeShift) |
+ (static_cast<uint32_t>(Record.getPointerKind())
+ << PointerRecord::PointerKindShift);
+ Builder.writeUInt32(flags);
- Builder.writeTypeIndex(Record.getContainingType());
- Builder.writeUInt16(static_cast<uint16_t>(Record.getRepresentation()));
+ if (Record.isPointerToMember()) {
+ const MemberPointerInfo &M = Record.getMemberInfo();
+ Builder.writeTypeIndex(M.getContainingType());
+ Builder.writeUInt16(static_cast<uint16_t>(M.getRepresentation()));
+ }
return writeRecord(Builder);
}
TypeIndex TypeTableBuilder::writeArray(const ArrayRecord &Record) {
- TypeRecordBuilder Builder(TypeRecordKind::Array);
+ TypeRecordBuilder Builder(Record.getKind());
Builder.writeTypeIndex(Record.getElementType());
Builder.writeTypeIndex(Record.getIndexType());
@@ -123,28 +101,23 @@ TypeIndex TypeTableBuilder::writeArray(const ArrayRecord &Record) {
return writeRecord(Builder);
}
-TypeIndex TypeTableBuilder::writeAggregate(const AggregateRecord &Record) {
- assert((Record.getKind() == TypeRecordKind::Structure) ||
+TypeIndex TypeTableBuilder::writeClass(const ClassRecord &Record) {
+ assert((Record.getKind() == TypeRecordKind::Struct) ||
(Record.getKind() == TypeRecordKind::Class) ||
- (Record.getKind() == TypeRecordKind::Union));
+ (Record.getKind() == TypeRecordKind::Interface));
TypeRecordBuilder Builder(Record.getKind());
Builder.writeUInt16(Record.getMemberCount());
uint16_t Flags =
static_cast<uint16_t>(Record.getOptions()) |
- (static_cast<uint16_t>(Record.getHfa()) << ClassHfaKindShift) |
+ (static_cast<uint16_t>(Record.getHfa()) << ClassRecord::HfaKindShift) |
(static_cast<uint16_t>(Record.getWinRTKind())
- << ClassWindowsRTClassKindShift);
+ << ClassRecord::WinRTKindShift);
Builder.writeUInt16(Flags);
Builder.writeTypeIndex(Record.getFieldList());
- if (Record.getKind() != TypeRecordKind::Union) {
- Builder.writeTypeIndex(Record.getDerivationList());
- Builder.writeTypeIndex(Record.getVTableShape());
- } else {
- assert(Record.getDerivationList() == TypeIndex());
- assert(Record.getVTableShape() == TypeIndex());
- }
+ Builder.writeTypeIndex(Record.getDerivationList());
+ Builder.writeTypeIndex(Record.getVTableShape());
Builder.writeEncodedUnsignedInteger(Record.getSize());
Builder.writeNullTerminatedString(Record.getName());
if ((Record.getOptions() & ClassOptions::HasUniqueName) !=
@@ -155,8 +128,25 @@ TypeIndex TypeTableBuilder::writeAggregate(const AggregateRecord &Record) {
return writeRecord(Builder);
}
+TypeIndex TypeTableBuilder::writeUnion(const UnionRecord &Record) {
+ TypeRecordBuilder Builder(TypeRecordKind::Union);
+ Builder.writeUInt16(Record.getMemberCount());
+ uint16_t Flags =
+ static_cast<uint16_t>(Record.getOptions()) |
+ (static_cast<uint16_t>(Record.getHfa()) << ClassRecord::HfaKindShift);
+ Builder.writeUInt16(Flags);
+ Builder.writeTypeIndex(Record.getFieldList());
+ Builder.writeEncodedUnsignedInteger(Record.getSize());
+ Builder.writeNullTerminatedString(Record.getName());
+ if ((Record.getOptions() & ClassOptions::HasUniqueName) !=
+ ClassOptions::None) {
+ Builder.writeNullTerminatedString(Record.getUniqueName());
+ }
+ return writeRecord(Builder);
+}
+
TypeIndex TypeTableBuilder::writeEnum(const EnumRecord &Record) {
- TypeRecordBuilder Builder(TypeRecordKind::Enum);
+ TypeRecordBuilder Builder(Record.getKind());
Builder.writeUInt16(Record.getMemberCount());
Builder.writeUInt16(static_cast<uint16_t>(Record.getOptions()));
@@ -172,7 +162,7 @@ TypeIndex TypeTableBuilder::writeEnum(const EnumRecord &Record) {
}
TypeIndex TypeTableBuilder::writeBitField(const BitFieldRecord &Record) {
- TypeRecordBuilder Builder(TypeRecordKind::BitField);
+ TypeRecordBuilder Builder(Record.getKind());
Builder.writeTypeIndex(Record.getType());
Builder.writeUInt8(Record.getBitSize());
@@ -181,11 +171,11 @@ TypeIndex TypeTableBuilder::writeBitField(const BitFieldRecord &Record) {
return writeRecord(Builder);
}
-TypeIndex TypeTableBuilder::writeVirtualTableShape(
- const VirtualTableShapeRecord &Record) {
- TypeRecordBuilder Builder(TypeRecordKind::VirtualTableShape);
+TypeIndex
+TypeTableBuilder::writeVFTableShape(const VFTableShapeRecord &Record) {
+ TypeRecordBuilder Builder(Record.getKind());
- ArrayRef<VirtualTableSlotKind> Slots = Record.getSlots();
+ ArrayRef<VFTableSlotKind> Slots = Record.getSlots();
Builder.writeUInt16(Slots.size());
for (size_t SlotIndex = 0; SlotIndex < Slots.size(); SlotIndex += 2) {
@@ -199,19 +189,115 @@ TypeIndex TypeTableBuilder::writeVirtualTableShape(
return writeRecord(Builder);
}
+TypeIndex
+TypeTableBuilder::writeVFTable(const VFTableRecord &Record) {
+ TypeRecordBuilder Builder(Record.getKind());
+ Builder.writeTypeIndex(Record.getCompleteClass());
+ Builder.writeTypeIndex(Record.getOverriddenVTable());
+ Builder.writeUInt32(Record.getVFPtrOffset());
+
+ // Sum up the lengths of the null-terminated names.
+ size_t NamesLen = Record.getName().size() + 1;
+ for (StringRef MethodName : Record.getMethodNames())
+ NamesLen += MethodName.size() + 1;
+
+ Builder.writeUInt32(NamesLen);
+ Builder.writeNullTerminatedString(Record.getName());
+ for (StringRef MethodName : Record.getMethodNames())
+ Builder.writeNullTerminatedString(MethodName);
+
+ return writeRecord(Builder);
+}
+
+TypeIndex TypeTableBuilder::writeStringId(const StringIdRecord &Record) {
+ TypeRecordBuilder Builder(TypeRecordKind::StringId);
+ Builder.writeTypeIndex(Record.getId());
+ Builder.writeNullTerminatedString(Record.getString());
+ return writeRecord(Builder);
+}
+
+TypeIndex
+TypeTableBuilder::writeUdtSourceLine(const UdtSourceLineRecord &Record) {
+ TypeRecordBuilder Builder(Record.getKind());
+ Builder.writeTypeIndex(Record.getUDT());
+ Builder.writeTypeIndex(Record.getSourceFile());
+ Builder.writeUInt32(Record.getLineNumber());
+ return writeRecord(Builder);
+}
+
+TypeIndex
+TypeTableBuilder::writeUdtModSourceLine(const UdtModSourceLineRecord &Record) {
+ TypeRecordBuilder Builder(Record.getKind());
+ Builder.writeTypeIndex(Record.getUDT());
+ Builder.writeTypeIndex(Record.getSourceFile());
+ Builder.writeUInt32(Record.getLineNumber());
+ Builder.writeUInt16(Record.getModule());
+ return writeRecord(Builder);
+}
+
+TypeIndex TypeTableBuilder::writeFuncId(const FuncIdRecord &Record) {
+ TypeRecordBuilder Builder(Record.getKind());
+ Builder.writeTypeIndex(Record.getParentScope());
+ Builder.writeTypeIndex(Record.getFunctionType());
+ Builder.writeNullTerminatedString(Record.getName());
+ return writeRecord(Builder);
+}
+
+TypeIndex
+TypeTableBuilder::writeMemberFuncId(const MemberFuncIdRecord &Record) {
+ TypeRecordBuilder Builder(Record.getKind());
+ Builder.writeTypeIndex(Record.getClassType());
+ Builder.writeTypeIndex(Record.getFunctionType());
+ Builder.writeNullTerminatedString(Record.getName());
+ return writeRecord(Builder);
+}
+
+TypeIndex
+TypeTableBuilder::writeBuildInfo(const BuildInfoRecord &Record) {
+ TypeRecordBuilder Builder(Record.getKind());
+ assert(Record.getArgs().size() <= UINT16_MAX);
+ Builder.writeUInt16(Record.getArgs().size());
+ for (TypeIndex Arg : Record.getArgs())
+ Builder.writeTypeIndex(Arg);
+ return writeRecord(Builder);
+}
+
TypeIndex TypeTableBuilder::writeRecord(TypeRecordBuilder &Builder) {
return writeRecord(Builder.str());
}
TypeIndex TypeTableBuilder::writeFieldList(FieldListRecordBuilder &FieldList) {
- // TODO: Split the list into multiple records if it's longer than 64KB, using
- // a subrecord of TypeRecordKind::Index to chain the records together.
- return writeRecord(FieldList.str());
+ return FieldList.writeListRecord(*this);
}
-TypeIndex
-TypeTableBuilder::writeMethodList(MethodListRecordBuilder &MethodList) {
+TypeIndex TypeTableBuilder::writeMethodOverloadList(
+ const MethodOverloadListRecord &Record) {
+ TypeRecordBuilder Builder(Record.getKind());
+ for (const OneMethodRecord &Method : Record.getMethods()) {
+ uint16_t Flags = static_cast<uint16_t>(Method.getAccess());
+ Flags |= static_cast<uint16_t>(Method.getKind())
+ << MemberAttributes::MethodKindShift;
+ Flags |= static_cast<uint16_t>(Method.getOptions());
+ Builder.writeUInt16(Flags);
+ Builder.writeUInt16(0); // padding
+ Builder.writeTypeIndex(Method.getType());
+ if (Method.isIntroducingVirtual()) {
+ assert(Method.getVFTableOffset() >= 0);
+ Builder.writeInt32(Method.getVFTableOffset());
+ } else {
+ assert(Method.getVFTableOffset() == -1);
+ }
+ }
+
// TODO: Split the list into multiple records if it's longer than 64KB, using
// a subrecord of TypeRecordKind::Index to chain the records together.
- return writeRecord(MethodList.str());
+ return writeRecord(Builder);
+}
+
+TypeIndex TypeTableBuilder::writeTypeServer2(const TypeServer2Record &Record) {
+ TypeRecordBuilder Builder(Record.getKind());
+ Builder.writeGuid(Record.getGuid());
+ Builder.writeUInt32(Record.getAge());
+ Builder.writeNullTerminatedString(Record.getName());
+ return writeRecord(Builder);
}