summaryrefslogtreecommitdiffstats
path: root/llvm/lib/DebugInfo/CodeView
diff options
context:
space:
mode:
authorDave Bartolomeo <dbartol@microsoft.com>2015-12-24 18:12:38 +0000
committerDave Bartolomeo <dbartol@microsoft.com>2015-12-24 18:12:38 +0000
commit89ba802b92883c2237130ca6f3dfe19499efd1f4 (patch)
treeab03ceb85f8a6c7f9ee6492e3f3e09507be5a53a /llvm/lib/DebugInfo/CodeView
parent1119191c4f2d02090acc5e80ce2ceac359a6ea09 (diff)
downloadbcm5719-llvm-89ba802b92883c2237130ca6f3dfe19499efd1f4.tar.gz
bcm5719-llvm-89ba802b92883c2237130ca6f3dfe19499efd1f4.zip
LLVM CodeView library
Summary: This diff is the initial implementation of the LLVM CodeView library. There is much more work to be done, namely a CodeView dumper and tests. This patch should help others make progress on the LLVM->CodeView debug info emission while I continue with the implementation of the dumper and tests. This library implements support for emitting debug info in the CodeView format. This phase of the implementation only includes support for CodeView type records. Clients that need to emit type records will use a class derived from TypeTableBuilder. TypeTableBuilder provides member functions for writing each kind of type record; each of these functions eventually calls the writeRecord virtual function to emit the actual bits of the record. Derived classes override writeRecord to implement the folding of duplicate records and the actual emission to the appropriate destination. LLVMCodeView provides MemoryTypeTableBuilder, which creates the table in memory. In the future, other classes derived from TypeTableBuilder will write to other destinations, such as the type stream in a PDB. The rest of the types in LLVMCodeView define the actual CodeView type records and all of the supporting enums and other types used in the type records. The TypeIndex class is of particular interest, because it is used by clients as a handle to a type in the type table. The library provides a relatively low-level interface based on the actual on-disk format of CodeView. For example, type records refer to other type records by TypeIndex, rather than by an actual pointer to the referent record. This allows clients to emit type records one at a time, rather than having to keep the entire transitive closure of type records in memory until everything has been emitted. At some point, having a higher-level interface layered on top of this one may be useful for debuggers and other tools that want a more holistic view of the debug info. The lower-level interface should be sufficient for compilers and linkers to do the debug info manipulation that they need to do efficiently. Reviewers: rnk, majnemer Subscribers: silvas, rnk, jevinskie, llvm-commits Differential Revision: http://reviews.llvm.org/D14961 llvm-svn: 256385
Diffstat (limited to 'llvm/lib/DebugInfo/CodeView')
-rw-r--r--llvm/lib/DebugInfo/CodeView/CMakeLists.txt9
-rw-r--r--llvm/lib/DebugInfo/CodeView/FieldListRecordBuilder.cpp165
-rw-r--r--llvm/lib/DebugInfo/CodeView/LLVMBuild.txt22
-rw-r--r--llvm/lib/DebugInfo/CodeView/Line.cpp22
-rw-r--r--llvm/lib/DebugInfo/CodeView/ListRecordBuilder.cpp31
-rw-r--r--llvm/lib/DebugInfo/CodeView/MemoryTypeTableBuilder.cpp35
-rw-r--r--llvm/lib/DebugInfo/CodeView/MethodListRecordBuilder.cpp49
-rw-r--r--llvm/lib/DebugInfo/CodeView/TypeRecordBuilder.cpp113
-rw-r--r--llvm/lib/DebugInfo/CodeView/TypeTableBuilder.cpp221
9 files changed, 667 insertions, 0 deletions
diff --git a/llvm/lib/DebugInfo/CodeView/CMakeLists.txt b/llvm/lib/DebugInfo/CodeView/CMakeLists.txt
new file mode 100644
index 00000000000..7853949bdb5
--- /dev/null
+++ b/llvm/lib/DebugInfo/CodeView/CMakeLists.txt
@@ -0,0 +1,9 @@
+add_llvm_library(LLVMCodeView
+ FieldListRecordBuilder.cpp
+ Line.cpp
+ ListRecordBuilder.cpp
+ MemoryTypeTableBuilder.cpp
+ MethodListRecordBuilder.cpp
+ TypeRecordBuilder.cpp
+ TypeTableBuilder.cpp
+ )
diff --git a/llvm/lib/DebugInfo/CodeView/FieldListRecordBuilder.cpp b/llvm/lib/DebugInfo/CodeView/FieldListRecordBuilder.cpp
new file mode 100644
index 00000000000..91b71cc4b11
--- /dev/null
+++ b/llvm/lib/DebugInfo/CodeView/FieldListRecordBuilder.cpp
@@ -0,0 +1,165 @@
+//===-- FieldListRecordBuilder.cpp ----------------------------------------===//
+//
+// 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/FieldListRecordBuilder.h"
+
+using namespace llvm;
+using namespace codeview;
+
+FieldListRecordBuilder::FieldListRecordBuilder()
+ : ListRecordBuilder(TypeRecordKind::FieldList) {}
+
+void FieldListRecordBuilder::writeBaseClass(MemberAccess Access, TypeIndex Type,
+ uint64_t Offset) {
+ TypeRecordBuilder &Builder = getBuilder();
+
+ Builder.writeTypeRecordKind(TypeRecordKind::BaseClass);
+ Builder.writeUInt16(static_cast<uint16_t>(Access));
+ Builder.writeTypeIndex(Type);
+ Builder.writeEncodedUnsignedInteger(Offset);
+
+ finishSubRecord();
+}
+
+void FieldListRecordBuilder::writeEnumerate(MemberAccess Access, uint64_t Value,
+ StringRef Name) {
+ TypeRecordBuilder &Builder = getBuilder();
+
+ Builder.writeTypeRecordKind(TypeRecordKind::Enumerate);
+ Builder.writeUInt16(static_cast<uint16_t>(Access));
+ Builder.writeEncodedUnsignedInteger(Value);
+ Builder.writeNullTerminatedString(Name);
+
+ finishSubRecord();
+}
+
+void FieldListRecordBuilder::writeMember(MemberAccess Access, TypeIndex Type,
+ uint64_t Offset, StringRef Name) {
+ TypeRecordBuilder &Builder = getBuilder();
+
+ Builder.writeTypeRecordKind(TypeRecordKind::Member);
+ Builder.writeUInt16(static_cast<uint16_t>(Access));
+ Builder.writeTypeIndex(Type);
+ Builder.writeEncodedUnsignedInteger(Offset);
+ Builder.writeNullTerminatedString(Name);
+
+ finishSubRecord();
+}
+
+void FieldListRecordBuilder::writeMethod(uint16_t OverloadCount,
+ TypeIndex MethodList, StringRef Name) {
+ TypeRecordBuilder &Builder = getBuilder();
+
+ Builder.writeTypeRecordKind(TypeRecordKind::Method);
+ Builder.writeUInt16(OverloadCount);
+ Builder.writeTypeIndex(MethodList);
+ Builder.writeNullTerminatedString(Name);
+
+ finishSubRecord();
+}
+
+void FieldListRecordBuilder::writeOneMethod(
+ MemberAccess Access, MethodKind Kind, MethodOptions Options, TypeIndex Type,
+ int32_t VTableSlotOffset, StringRef Name) {
+ TypeRecordBuilder &Builder = getBuilder();
+
+ uint16_t Flags = static_cast<uint16_t>(Access);
+ Flags |= static_cast<uint16_t>(Kind) << MethodKindShift;
+ Flags |= static_cast<uint16_t>(Options);
+
+ 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.writeNullTerminatedString(Name);
+
+ 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) {
+ TypeRecordBuilder &Builder = getBuilder();
+
+ Builder.writeTypeRecordKind(TypeRecordKind::NestedType);
+ Builder.writeUInt16(0);
+ Builder.writeTypeIndex(Type);
+ Builder.writeNullTerminatedString(Name);
+
+ finishSubRecord();
+}
+
+void FieldListRecordBuilder::writeStaticMember(MemberAccess Access,
+ TypeIndex Type, StringRef Name) {
+ TypeRecordBuilder &Builder = getBuilder();
+
+ Builder.writeTypeRecordKind(TypeRecordKind::StaticMember);
+ Builder.writeUInt16(static_cast<uint16_t>(Access));
+ Builder.writeTypeIndex(Type);
+ Builder.writeNullTerminatedString(Name);
+
+ 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) {
+ 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);
+
+ finishSubRecord();
+}
+
+void FieldListRecordBuilder::writeVirtualFunctionTablePointer(TypeIndex Type) {
+ TypeRecordBuilder &Builder = getBuilder();
+
+ Builder.writeTypeRecordKind(TypeRecordKind::VirtualFunctionTablePointer);
+ Builder.writeUInt16(0);
+ Builder.writeTypeIndex(Type);
+
+ finishSubRecord();
+} \ No newline at end of file
diff --git a/llvm/lib/DebugInfo/CodeView/LLVMBuild.txt b/llvm/lib/DebugInfo/CodeView/LLVMBuild.txt
new file mode 100644
index 00000000000..8df016c5c50
--- /dev/null
+++ b/llvm/lib/DebugInfo/CodeView/LLVMBuild.txt
@@ -0,0 +1,22 @@
+;===- ./lib/CodeView/LLVMBuild.txt -------------------------------*- Conf -*--===;
+;
+; The LLVM Compiler Infrastructure
+;
+; This file is distributed under the University of Illinois Open Source
+; License. See LICENSE.TXT for details.
+;
+;===------------------------------------------------------------------------===;
+;
+; This is an LLVMBuild description file for the components in this subdirectory.
+;
+; For more information on the LLVMBuild system, please see:
+;
+; http://llvm.org/docs/LLVMBuild.html
+;
+;===------------------------------------------------------------------------===;
+
+[component_0]
+type = Library
+name = CodeView
+parent = Libraries
+required_libraries = Support
diff --git a/llvm/lib/DebugInfo/CodeView/Line.cpp b/llvm/lib/DebugInfo/CodeView/Line.cpp
new file mode 100644
index 00000000000..4cb766b5fd2
--- /dev/null
+++ b/llvm/lib/DebugInfo/CodeView/Line.cpp
@@ -0,0 +1,22 @@
+//===-- Line.cpp ----------------------------------------------------------===//
+//
+// 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/Line.h"
+
+using namespace llvm;
+using namespace codeview;
+
+LineInfo::LineInfo(uint32_t StartLine, uint32_t EndLine, bool IsStatement) {
+ LineData = StartLine & StartLineMask;
+ uint32_t LineDelta = EndLine - StartLine;
+ LineData |= (LineDelta << EndLineDeltaShift) & EndLineDeltaMask;
+ if (IsStatement) {
+ LineData |= StatementFlag;
+ }
+}
diff --git a/llvm/lib/DebugInfo/CodeView/ListRecordBuilder.cpp b/llvm/lib/DebugInfo/CodeView/ListRecordBuilder.cpp
new file mode 100644
index 00000000000..69c7e87330e
--- /dev/null
+++ b/llvm/lib/DebugInfo/CodeView/ListRecordBuilder.cpp
@@ -0,0 +1,31 @@
+//===-- ListRecordBuilder.cpp ---------------------------------------------===//
+//
+// 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/ListRecordBuilder.h"
+
+using namespace llvm;
+using namespace codeview;
+
+ListRecordBuilder::ListRecordBuilder(TypeRecordKind Kind) : Builder(Kind) {}
+
+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;
+ if (Remainder != 0) {
+ for (int32_t PaddingBytesLeft = 4 - Remainder; PaddingBytesLeft > 0;
+ --PaddingBytesLeft) {
+ Builder.writeUInt8(0xf0 + 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);
+}
diff --git a/llvm/lib/DebugInfo/CodeView/MemoryTypeTableBuilder.cpp b/llvm/lib/DebugInfo/CodeView/MemoryTypeTableBuilder.cpp
new file mode 100644
index 00000000000..9afce92eeb1
--- /dev/null
+++ b/llvm/lib/DebugInfo/CodeView/MemoryTypeTableBuilder.cpp
@@ -0,0 +1,35 @@
+//===-- MemoryTypeTableBuilder.cpp ----------------------------------------===//
+//
+// 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/MemoryTypeTableBuilder.h"
+#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+
+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) {
+ auto I = HashedRecords.find(Data);
+ if (I != HashedRecords.end()) {
+ return I->second;
+ }
+
+ std::unique_ptr<Record> R(new Record(Data));
+
+ 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));
+
+ return TI;
+}
diff --git a/llvm/lib/DebugInfo/CodeView/MethodListRecordBuilder.cpp b/llvm/lib/DebugInfo/CodeView/MethodListRecordBuilder.cpp
new file mode 100644
index 00000000000..889302556b2
--- /dev/null
+++ b/llvm/lib/DebugInfo/CodeView/MethodListRecordBuilder.cpp
@@ -0,0 +1,49 @@
+//===-- MethodListRecordBuilder.cpp ---------------------------------------===//
+//
+// 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/MethodListRecordBuilder.h"
+#include "llvm/DebugInfo/CodeView/FieldListRecordBuilder.h"
+
+using namespace llvm;
+using namespace codeview;
+
+MethodListRecordBuilder::MethodListRecordBuilder()
+ : ListRecordBuilder(TypeRecordKind::MethodList) {}
+
+void MethodListRecordBuilder::writeMethod(MemberAccess Access, MethodKind Kind,
+ MethodOptions Options, TypeIndex Type,
+ int32_t VTableSlotOffset) {
+ TypeRecordBuilder &Builder = getBuilder();
+
+ uint16_t Flags = static_cast<uint16_t>(Access);
+ Flags |= static_cast<uint16_t>(Kind) << MethodKindShift;
+ Flags |= static_cast<uint16_t>(Options);
+
+ Builder.writeUInt16(Flags);
+ Builder.writeUInt16(0);
+ Builder.writeTypeIndex(Type);
+ switch (Kind) {
+ case MethodKind::IntroducingVirtual:
+ case MethodKind::PureIntroducingVirtual:
+ assert(VTableSlotOffset >= 0);
+ Builder.writeInt32(VTableSlotOffset);
+ break;
+
+ default:
+ assert(VTableSlotOffset == -1);
+ break;
+ }
+
+ // TODO: Fail if too big?
+}
+
+void MethodListRecordBuilder::writeMethod(const MethodInfo &Method) {
+ writeMethod(Method.getAccess(), Method.getKind(), Method.getOptions(),
+ Method.getType(), Method.getVTableSlotOffset());
+}
diff --git a/llvm/lib/DebugInfo/CodeView/TypeRecordBuilder.cpp b/llvm/lib/DebugInfo/CodeView/TypeRecordBuilder.cpp
new file mode 100644
index 00000000000..cbf464fd766
--- /dev/null
+++ b/llvm/lib/DebugInfo/CodeView/TypeRecordBuilder.cpp
@@ -0,0 +1,113 @@
+//===-- TypeRecordBuilder.cpp ---------------------------------------------===//
+//
+// 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/TypeRecordBuilder.h"
+
+using namespace llvm;
+using namespace codeview;
+
+TypeRecordBuilder::TypeRecordBuilder(TypeRecordKind Kind) : Stream(Buffer),
+ Writer(Stream) {
+ writeTypeRecordKind(Kind);
+}
+
+StringRef TypeRecordBuilder::str() {
+ return StringRef(Buffer.data(), Buffer.size());
+}
+
+void TypeRecordBuilder::writeUInt8(uint8_t Value) {
+ Writer.write(Value);
+}
+
+void TypeRecordBuilder::writeInt16(int16_t Value) {
+ Writer.write(Value);
+}
+
+void TypeRecordBuilder::writeUInt16(uint16_t Value) {
+ Writer.write(Value);
+}
+
+void TypeRecordBuilder::writeInt32(int32_t Value) {
+ Writer.write(Value);
+}
+
+void TypeRecordBuilder::writeUInt32(uint32_t Value) {
+ Writer.write(Value);
+}
+
+void TypeRecordBuilder::writeInt64(int64_t Value) {
+ Writer.write(Value);
+}
+
+void TypeRecordBuilder::writeUInt64(uint64_t Value) {
+ Writer.write(Value);
+}
+
+void TypeRecordBuilder::writeEncodedInteger(int64_t Value) {
+ if (Value >= 0) {
+ writeEncodedUnsignedInteger(static_cast<uint64_t>(Value));
+ } else {
+ writeEncodedSignedInteger(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));
+ 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));
+ 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));
+ writeInt32(static_cast<int32_t>(Value));
+ } else {
+ writeUInt16(static_cast<uint16_t>(TypeRecordKind::Int64));
+ writeInt64(Value);
+ }
+}
+
+void TypeRecordBuilder::writeEncodedUnsignedInteger(uint64_t Value) {
+ if (Value < static_cast<uint16_t>(TypeRecordKind::SByte)) {
+ writeUInt16(static_cast<uint16_t>(Value));
+ } else if (Value <= std::numeric_limits<uint16_t>::max()) {
+ writeUInt16(static_cast<uint16_t>(TypeRecordKind::UInt16));
+ writeUInt16(static_cast<uint16_t>(Value));
+ } else if (Value <= std::numeric_limits<uint32_t>::max()) {
+ writeUInt16(static_cast<uint16_t>(TypeRecordKind::UInt32));
+ writeUInt32(static_cast<uint32_t>(Value));
+ } else {
+ writeUInt16(static_cast<uint16_t>(TypeRecordKind::UInt64));
+ 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) {
+ Stream.write(Value.data(), Value.size());
+ writeUInt8(0);
+}
+
+void TypeRecordBuilder::writeTypeIndex(TypeIndex TypeInd) {
+ writeUInt32(TypeInd.getIndex());
+}
+
+void TypeRecordBuilder::writeTypeRecordKind(TypeRecordKind Kind) {
+ writeUInt16(static_cast<uint16_t>(Kind));
+}
diff --git a/llvm/lib/DebugInfo/CodeView/TypeTableBuilder.cpp b/llvm/lib/DebugInfo/CodeView/TypeTableBuilder.cpp
new file mode 100644
index 00000000000..3f20caa31c5
--- /dev/null
+++ b/llvm/lib/DebugInfo/CodeView/TypeTableBuilder.cpp
@@ -0,0 +1,221 @@
+//===-- TypeTableBuilder.cpp ----------------------------------------------===//
+//
+// 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/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"
+#include "llvm/DebugInfo/CodeView/TypeRecordBuilder.h"
+#include "llvm/support/raw_ostream.h"
+
+using namespace llvm;
+using namespace codeview;
+
+namespace {
+
+const uint32_t PointerKindMask = 0x0000001f;
+const int PointerKindShift = 0;
+const uint32_t PointerModeMask = 0x000000e0;
+const int PointerModeShift = 5;
+const uint32_t PointerSizeMask = 0x0007e000;
+const int PointerSizeShift = 13;
+const uint32_t PointerOptionsMask = 0x00081f00;
+
+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);
+
+ Builder.writeTypeIndex(Record.getModifiedType());
+ Builder.writeUInt16(static_cast<uint16_t>(Record.getOptions()));
+
+ return writeRecord(Builder);
+}
+
+TypeIndex TypeTableBuilder::writeProcedure(const ProcedureRecord &Record) {
+ TypeRecordBuilder Builder(TypeRecordKind::Procedure);
+
+ Builder.writeTypeIndex(Record.getReturnType());
+ Builder.writeUInt8(static_cast<uint8_t>(Record.getCallConv()));
+ Builder.writeUInt8(static_cast<uint8_t>(Record.getOptions()));
+ Builder.writeUInt16(Record.getParameterCount());
+ Builder.writeTypeIndex(Record.getArgumentList());
+
+ return writeRecord(Builder);
+}
+
+TypeIndex
+TypeTableBuilder::writeMemberFunction(const MemberFunctionRecord &Record) {
+ TypeRecordBuilder Builder(TypeRecordKind::MemberFunction);
+
+ Builder.writeTypeIndex(Record.getReturnType());
+ Builder.writeTypeIndex(Record.getClassType());
+ Builder.writeTypeIndex(Record.getThisType());
+ Builder.writeUInt8(static_cast<uint8_t>(Record.getCallConv()));
+ Builder.writeUInt8(static_cast<uint8_t>(Record.getOptions()));
+ Builder.writeUInt16(Record.getParameterCount());
+ Builder.writeTypeIndex(Record.getArgumentList());
+ Builder.writeInt32(Record.getThisPointerAdjustment());
+
+ return writeRecord(Builder);
+}
+
+TypeIndex
+TypeTableBuilder::writeArgumentList(const ArgumentListRecord &Record) {
+ TypeRecordBuilder Builder(TypeRecordKind::ArgumentList);
+
+ Builder.writeUInt32(Record.getArgumentTypes().size());
+ for (TypeIndex TI : Record.getArgumentTypes()) {
+ Builder.writeTypeIndex(TI);
+ }
+
+ return writeRecord(Builder);
+}
+
+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);
+
+ writePointerBase(Builder, Record);
+
+ Builder.writeTypeIndex(Record.getContainingType());
+ Builder.writeUInt16(static_cast<uint16_t>(Record.getRepresentation()));
+
+ return writeRecord(Builder);
+}
+
+TypeIndex TypeTableBuilder::writeArray(const ArrayRecord &Record) {
+ TypeRecordBuilder Builder(TypeRecordKind::Array);
+
+ Builder.writeTypeIndex(Record.getElementType());
+ Builder.writeTypeIndex(Record.getIndexType());
+ Builder.writeEncodedUnsignedInteger(Record.getSize());
+ Builder.writeNullTerminatedString(Record.getName());
+
+ return writeRecord(Builder);
+}
+
+TypeIndex TypeTableBuilder::writeAggregate(const AggregateRecord &Record) {
+ assert((Record.getKind() == TypeRecordKind::Structure) ||
+ (Record.getKind() == TypeRecordKind::Class) ||
+ (Record.getKind() == TypeRecordKind::Union));
+
+ 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.getWinRTKind())
+ << ClassWindowsRTClassKindShift);
+ 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.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);
+
+ Builder.writeUInt16(Record.getMemberCount());
+ Builder.writeUInt16(static_cast<uint16_t>(Record.getOptions()));
+ Builder.writeTypeIndex(Record.getUnderlyingType());
+ Builder.writeTypeIndex(Record.getFieldList());
+ Builder.writeNullTerminatedString(Record.getName());
+ if ((Record.getOptions() & ClassOptions::HasUniqueName) !=
+ ClassOptions::None) {
+ Builder.writeNullTerminatedString(Record.getUniqueName());
+ }
+
+ return writeRecord(Builder);
+}
+
+TypeIndex TypeTableBuilder::writeBitField(const BitFieldRecord &Record) {
+ TypeRecordBuilder Builder(TypeRecordKind::BitField);
+
+ Builder.writeTypeIndex(Record.getType());
+ Builder.writeUInt8(Record.getBitSize());
+ Builder.writeUInt8(Record.getBitOffset());
+
+ return writeRecord(Builder);
+}
+
+TypeIndex TypeTableBuilder::writeVirtualTableShape(
+ const VirtualTableShapeRecord &Record) {
+ TypeRecordBuilder Builder(TypeRecordKind::VirtualTableShape);
+
+ ArrayRef<VirtualTableSlotKind> Slots = Record.getSlots();
+
+ Builder.writeUInt16(Slots.size());
+ for (size_t SlotIndex = 0; SlotIndex < Slots.size(); SlotIndex += 2) {
+ uint8_t Byte = static_cast<uint8_t>(Slots[SlotIndex]) << 4;
+ if ((SlotIndex + 1) < Slots.size()) {
+ Byte |= static_cast<uint8_t>(Slots[SlotIndex + 1]);
+ }
+ Builder.writeUInt8(Byte);
+ }
+
+ 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());
+}
+
+TypeIndex
+TypeTableBuilder::writeMethodList(MethodListRecordBuilder &MethodList) {
+ // 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());
+}
OpenPOWER on IntegriCloud