diff options
Diffstat (limited to 'llvm/lib/DebugInfo/CodeView')
| -rw-r--r-- | llvm/lib/DebugInfo/CodeView/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | llvm/lib/DebugInfo/CodeView/FieldListRecordBuilder.cpp | 133 | ||||
| -rw-r--r-- | llvm/lib/DebugInfo/CodeView/TypeDumper.cpp | 1 | ||||
| -rw-r--r-- | llvm/lib/DebugInfo/CodeView/TypeRecord.cpp | 191 | ||||
| -rw-r--r-- | llvm/lib/DebugInfo/CodeView/TypeRecordBuilder.cpp | 9 | ||||
| -rw-r--r-- | llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp | 144 | ||||
| -rw-r--r-- | llvm/lib/DebugInfo/CodeView/TypeTableBuilder.cpp | 112 |
7 files changed, 504 insertions, 88 deletions
diff --git a/llvm/lib/DebugInfo/CodeView/CMakeLists.txt b/llvm/lib/DebugInfo/CodeView/CMakeLists.txt index cdca673474d..ecddfaf9d7b 100644 --- a/llvm/lib/DebugInfo/CodeView/CMakeLists.txt +++ b/llvm/lib/DebugInfo/CodeView/CMakeLists.txt @@ -6,7 +6,9 @@ add_llvm_library(LLVMDebugInfoCodeView MethodListRecordBuilder.cpp RecordSerialization.cpp TypeDumper.cpp + TypeRecord.cpp TypeRecordBuilder.cpp + TypeStreamMerger.cpp TypeTableBuilder.cpp ADDITIONAL_HEADER_DIRS diff --git a/llvm/lib/DebugInfo/CodeView/FieldListRecordBuilder.cpp b/llvm/lib/DebugInfo/CodeView/FieldListRecordBuilder.cpp index 62bc4c481cb..5f229e3d9f9 100644 --- a/llvm/lib/DebugInfo/CodeView/FieldListRecordBuilder.cpp +++ b/llvm/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::Enumerator); - Builder.writeUInt16(static_cast<uint16_t>(Access)); - Builder.writeEncodedUnsignedInteger(Value); - Builder.writeNullTerminatedString(Name); + 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::DataMember); - 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::OverloadedMethod); - Builder.writeUInt16(OverloadCount); - Builder.writeTypeIndex(MethodList); - Builder.writeNullTerminatedString(Name); + 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::StaticDataMember); - 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::VFPtr); Builder.writeUInt16(0); - Builder.writeTypeIndex(Type); + Builder.writeTypeIndex(Record.getType()); finishSubRecord(); } diff --git a/llvm/lib/DebugInfo/CodeView/TypeDumper.cpp b/llvm/lib/DebugInfo/CodeView/TypeDumper.cpp index 6a42fc42433..50a7e6c841b 100644 --- a/llvm/lib/DebugInfo/CodeView/TypeDumper.cpp +++ b/llvm/lib/DebugInfo/CodeView/TypeDumper.cpp @@ -280,6 +280,7 @@ void CVTypeDumperImpl::visitStringId(TypeLeafKind Leaf, // Put this in CVUDTNames so it gets printed with LF_UDT_SRC_LINE. Name = String.getString(); } + void CVTypeDumperImpl::visitArgList(TypeLeafKind Leaf, ArgListRecord &Args) { auto Indices = Args.getIndices(); uint32_t Size = Indices.size(); diff --git a/llvm/lib/DebugInfo/CodeView/TypeRecord.cpp b/llvm/lib/DebugInfo/CodeView/TypeRecord.cpp new file mode 100644 index 00000000000..57cd5b7e264 --- /dev/null +++ b/llvm/lib/DebugInfo/CodeView/TypeRecord.cpp @@ -0,0 +1,191 @@ +//===-- 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" + +using namespace llvm; +using namespace llvm::codeview; + +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 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 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; +} diff --git a/llvm/lib/DebugInfo/CodeView/TypeRecordBuilder.cpp b/llvm/lib/DebugInfo/CodeView/TypeRecordBuilder.cpp index 3cc56ba2c19..f1c293e39fd 100644 --- a/llvm/lib/DebugInfo/CodeView/TypeRecordBuilder.cpp +++ b/llvm/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); } @@ -104,6 +104,11 @@ void TypeRecordBuilder::writeNullTerminatedString(StringRef Value) { 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/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp b/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp new file mode 100644 index 00000000000..5ee7cb17000 --- /dev/null +++ b/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp @@ -0,0 +1,144 @@ +//===-- 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/TypeIndex.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/CodeView/TypeStream.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 CVTypeVisitor<TypeStreamMerger> { +public: + TypeStreamMerger(TypeTableBuilder &DestStream) : DestStream(DestStream) { + assert(!hadError()); + } + + /// CVTypeVisitor overrides. +#define TYPE_RECORD(EnumName, EnumVal, Name) \ + void visit##Name(TypeLeafKind LeafType, Name##Record &Record); +#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) +#define MEMBER_RECORD(EnumName, EnumVal, Name) \ + void visit##Name(TypeLeafKind LeafType, Name##Record &Record); +#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) +#include "llvm/DebugInfo/CodeView/TypeRecords.def" + + void visitUnknownMember(TypeLeafKind Leaf); + + void visitTypeBegin(TypeLeafKind Leaf, ArrayRef<uint8_t> RecordData); + void visitTypeEnd(TypeLeafKind Leaf, ArrayRef<uint8_t> RecordData); + + void visitFieldList(TypeLeafKind Leaf, ArrayRef<uint8_t> FieldData); + + bool mergeStream(ArrayRef<uint8_t> SrcStream); + +private: + bool hadError() { return FoundBadTypeIndex || CVTypeVisitor::hadError(); } + + 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 + +void TypeStreamMerger::visitTypeBegin(TypeLeafKind Leaf, + ArrayRef<uint8_t> RecordData) { + BeginIndexMapSize = IndexMap.size(); +} + +void TypeStreamMerger::visitTypeEnd(TypeLeafKind Leaf, + ArrayRef<uint8_t> RecordData) { + assert(IndexMap.size() == BeginIndexMapSize + 1); +} + +void TypeStreamMerger::visitFieldList(TypeLeafKind Leaf, + ArrayRef<uint8_t> FieldData) { + CVTypeVisitor::visitFieldList(Leaf, FieldData); + IndexMap.push_back(DestStream.writeFieldList(FieldBuilder)); + FieldBuilder.reset(); +} + +#define TYPE_RECORD(EnumName, EnumVal, Name) \ + void TypeStreamMerger::visit##Name(TypeLeafKind LeafType, \ + Name##Record &Record) { \ + FoundBadTypeIndex |= !Record.remapTypeIndices(IndexMap); \ + IndexMap.push_back(DestStream.write##Name(Record)); \ + } +#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) +#define MEMBER_RECORD(EnumName, EnumVal, Name) \ + void TypeStreamMerger::visit##Name(TypeLeafKind LeafType, \ + Name##Record &Record) { \ + FoundBadTypeIndex |= !Record.remapTypeIndices(IndexMap); \ + FieldBuilder.write##Name(Record); \ + } +#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) +#include "llvm/DebugInfo/CodeView/TypeRecords.def" + +void TypeStreamMerger::visitUnknownMember(TypeLeafKind LF) { + // We failed to translate a type. Translate this index as "not translated". + IndexMap.push_back( + TypeIndex(SimpleTypeKind::NotTranslated, SimpleTypeMode::Direct)); + parseError(); +} + +bool TypeStreamMerger::mergeStream(ArrayRef<uint8_t> SrcStream) { + assert(IndexMap.empty()); + visitTypeStream(SrcStream); + IndexMap.clear(); + return !hadError(); +} + +bool llvm::codeview::mergeTypeStreams(TypeTableBuilder &DestStream, + ArrayRef<uint8_t> SrcStream) { + return TypeStreamMerger(DestStream).mergeStream(SrcStream); +} diff --git a/llvm/lib/DebugInfo/CodeView/TypeTableBuilder.cpp b/llvm/lib/DebugInfo/CodeView/TypeTableBuilder.cpp index 39e2a82f40a..3f48f6495f2 100644 --- a/llvm/lib/DebugInfo/CodeView/TypeTableBuilder.cpp +++ b/llvm/lib/DebugInfo/CodeView/TypeTableBuilder.cpp @@ -128,6 +128,23 @@ TypeIndex TypeTableBuilder::writeClass(const ClassRecord &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(Record.getKind()); @@ -172,6 +189,70 @@ TypeTableBuilder::writeVFTableShape(const VFTableShapeRecord &Record) { 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::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()); } @@ -182,9 +263,34 @@ TypeIndex TypeTableBuilder::writeFieldList(FieldListRecordBuilder &FieldList) { return writeRecord(FieldList.str()); } -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); } |

