diff options
Diffstat (limited to 'llvm/lib/DebugInfo/CodeView')
-rw-r--r-- | llvm/lib/DebugInfo/CodeView/CMakeLists.txt | 1 | ||||
-rw-r--r-- | llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp | 88 | ||||
-rw-r--r-- | llvm/lib/DebugInfo/CodeView/CodeViewError.cpp | 2 | ||||
-rw-r--r-- | llvm/lib/DebugInfo/CodeView/FieldListRecordBuilder.cpp | 18 | ||||
-rw-r--r-- | llvm/lib/DebugInfo/CodeView/ListRecordBuilder.cpp | 2 | ||||
-rw-r--r-- | llvm/lib/DebugInfo/CodeView/TypeDeserializer.cpp | 81 | ||||
-rw-r--r-- | llvm/lib/DebugInfo/CodeView/TypeDumper.cpp | 106 | ||||
-rw-r--r-- | llvm/lib/DebugInfo/CodeView/TypeRecord.cpp | 5 | ||||
-rw-r--r-- | llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp | 59 | ||||
-rw-r--r-- | llvm/lib/DebugInfo/CodeView/TypeTableBuilder.cpp | 48 |
10 files changed, 245 insertions, 165 deletions
diff --git a/llvm/lib/DebugInfo/CodeView/CMakeLists.txt b/llvm/lib/DebugInfo/CodeView/CMakeLists.txt index d8c21953967..92ffd3d24d7 100644 --- a/llvm/lib/DebugInfo/CodeView/CMakeLists.txt +++ b/llvm/lib/DebugInfo/CodeView/CMakeLists.txt @@ -11,6 +11,7 @@ add_llvm_library(LLVMDebugInfoCodeView ModuleSubstreamVisitor.cpp RecordSerialization.cpp SymbolDumper.cpp + TypeDeserializer.cpp TypeDumper.cpp TypeRecord.cpp TypeRecordBuilder.cpp diff --git a/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp b/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp index a7b7f3a2793..01dd5d4591c 100644 --- a/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp +++ b/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp @@ -8,47 +8,39 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" + #include "llvm/DebugInfo/CodeView/CodeViewError.h" +#include "llvm/DebugInfo/Msf/ByteStream.h" using namespace llvm; using namespace llvm::codeview; +CVTypeVisitor::CVTypeVisitor(TypeVisitorCallbacks &Callbacks) + : Callbacks(Callbacks) {} + 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)); +static Error visitKnownRecord(const CVRecord<TypeLeafKind> &Record, + TypeVisitorCallbacks &Callbacks) { + TypeRecordKind RK = static_cast<TypeRecordKind>(Record.Type); + T KnownRecord(RK); + if (auto EC = Callbacks.visitKnownRecord(Record, KnownRecord)) + return EC; 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 ExpectedRecord = Name##Record::deserialize(RK, LeafData); \ - if (!ExpectedRecord) \ - return ExpectedRecord.takeError(); \ - if (auto EC = Callbacks.visit##Name(*ExpectedRecord)) \ + if (auto EC = visitKnownRecord<Name##Record>(Record, Callbacks)) \ return EC; \ break; \ } @@ -57,8 +49,10 @@ Error CVTypeVisitor::visitTypeRecord(const CVRecord<TypeLeafKind> &Record) { #define MEMBER_RECORD(EnumName, EnumVal, Name) #include "llvm/DebugInfo/CodeView/TypeRecords.def" } + if (auto EC = Callbacks.visitTypeEnd(Record)) return EC; + return Error::success(); } @@ -70,55 +64,3 @@ Error CVTypeVisitor::visitTypeStream(const CVTypeArray &Types) { } 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 ExpectedRecord = Name##Record::deserialize(RK, RecordData); \ - if (!ExpectedRecord) \ - return ExpectedRecord.takeError(); \ - if (auto EC = Callbacks.visit##Name(*ExpectedRecord)) \ - 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/llvm/lib/DebugInfo/CodeView/CodeViewError.cpp b/llvm/lib/DebugInfo/CodeView/CodeViewError.cpp index aad1d8b25cd..e9678db7a5b 100644 --- a/llvm/lib/DebugInfo/CodeView/CodeViewError.cpp +++ b/llvm/lib/DebugInfo/CodeView/CodeViewError.cpp @@ -33,6 +33,8 @@ public: return "The CodeView record is corrupted."; case cv_error_code::operation_unsupported: return "The requested operation is not supported."; + case cv_error_code::unknown_member_record: + return "The member record is of an unknown type."; } llvm_unreachable("Unrecognized cv_error_code"); } diff --git a/llvm/lib/DebugInfo/CodeView/FieldListRecordBuilder.cpp b/llvm/lib/DebugInfo/CodeView/FieldListRecordBuilder.cpp index 5f229e3d9f9..ac2ef3972b6 100644 --- a/llvm/lib/DebugInfo/CodeView/FieldListRecordBuilder.cpp +++ b/llvm/lib/DebugInfo/CodeView/FieldListRecordBuilder.cpp @@ -15,7 +15,7 @@ using namespace codeview; FieldListRecordBuilder::FieldListRecordBuilder() : ListRecordBuilder(TypeRecordKind::FieldList) {} -void FieldListRecordBuilder::writeBaseClass(const BaseClassRecord &Record) { +void FieldListRecordBuilder::writeMemberType(const BaseClassRecord &Record) { TypeRecordBuilder &Builder = getBuilder(); Builder.writeTypeRecordKind(TypeRecordKind::BaseClass); @@ -26,7 +26,7 @@ void FieldListRecordBuilder::writeBaseClass(const BaseClassRecord &Record) { finishSubRecord(); } -void FieldListRecordBuilder::writeEnumerator(const EnumeratorRecord &Record) { +void FieldListRecordBuilder::writeMemberType(const EnumeratorRecord &Record) { TypeRecordBuilder &Builder = getBuilder(); Builder.writeTypeRecordKind(TypeRecordKind::Enumerator); @@ -38,7 +38,7 @@ void FieldListRecordBuilder::writeEnumerator(const EnumeratorRecord &Record) { finishSubRecord(); } -void FieldListRecordBuilder::writeDataMember(const DataMemberRecord &Record) { +void FieldListRecordBuilder::writeMemberType(const DataMemberRecord &Record) { TypeRecordBuilder &Builder = getBuilder(); Builder.writeTypeRecordKind(Record.getKind()); @@ -50,7 +50,7 @@ void FieldListRecordBuilder::writeDataMember(const DataMemberRecord &Record) { finishSubRecord(); } -void FieldListRecordBuilder::writeOverloadedMethod( +void FieldListRecordBuilder::writeMemberType( const OverloadedMethodRecord &Record) { TypeRecordBuilder &Builder = getBuilder(); @@ -62,7 +62,7 @@ void FieldListRecordBuilder::writeOverloadedMethod( finishSubRecord(); } -void FieldListRecordBuilder::writeOneMethod(const OneMethodRecord &Record) { +void FieldListRecordBuilder::writeMemberType(const OneMethodRecord &Record) { TypeRecordBuilder &Builder = getBuilder(); uint16_t Flags = static_cast<uint16_t>(Record.getAccess()); @@ -84,7 +84,7 @@ void FieldListRecordBuilder::writeOneMethod(const OneMethodRecord &Record) { finishSubRecord(); } -void FieldListRecordBuilder::writeNestedType(const NestedTypeRecord &Record) { +void FieldListRecordBuilder::writeMemberType(const NestedTypeRecord &Record) { TypeRecordBuilder &Builder = getBuilder(); Builder.writeTypeRecordKind(Record.getKind()); @@ -95,7 +95,7 @@ void FieldListRecordBuilder::writeNestedType(const NestedTypeRecord &Record) { finishSubRecord(); } -void FieldListRecordBuilder::writeStaticDataMember( +void FieldListRecordBuilder::writeMemberType( const StaticDataMemberRecord &Record) { TypeRecordBuilder &Builder = getBuilder(); @@ -107,7 +107,7 @@ void FieldListRecordBuilder::writeStaticDataMember( finishSubRecord(); } -void FieldListRecordBuilder::writeVirtualBaseClass( +void FieldListRecordBuilder::writeMemberType( const VirtualBaseClassRecord &Record) { TypeRecordBuilder &Builder = getBuilder(); @@ -121,7 +121,7 @@ void FieldListRecordBuilder::writeVirtualBaseClass( finishSubRecord(); } -void FieldListRecordBuilder::writeVFPtr(const VFPtrRecord &Record) { +void FieldListRecordBuilder::writeMemberType(const VFPtrRecord &Record) { TypeRecordBuilder &Builder = getBuilder(); Builder.writeTypeRecordKind(TypeRecordKind::VFPtr); diff --git a/llvm/lib/DebugInfo/CodeView/ListRecordBuilder.cpp b/llvm/lib/DebugInfo/CodeView/ListRecordBuilder.cpp index eb79e8ac9a3..ab019c44c5b 100644 --- a/llvm/lib/DebugInfo/CodeView/ListRecordBuilder.cpp +++ b/llvm/lib/DebugInfo/CodeView/ListRecordBuilder.cpp @@ -17,7 +17,7 @@ using namespace codeview; ListRecordBuilder::ListRecordBuilder(TypeRecordKind Kind) : Kind(Kind), Builder(Kind) {} -void ListRecordBuilder::writeListContinuation(const ListContinuationRecord &R) { +void ListRecordBuilder::writeMemberType(const ListContinuationRecord &R) { TypeRecordBuilder &Builder = getBuilder(); assert(getLastContinuationSize() < 65535 - 8 && "continuation won't fit"); diff --git a/llvm/lib/DebugInfo/CodeView/TypeDeserializer.cpp b/llvm/lib/DebugInfo/CodeView/TypeDeserializer.cpp new file mode 100644 index 00000000000..3593458565f --- /dev/null +++ b/llvm/lib/DebugInfo/CodeView/TypeDeserializer.cpp @@ -0,0 +1,81 @@ +//===- TypeDeserializer.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/TypeDeserializer.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(); +} + +Error TypeDeserializer::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR, + FieldListRecord &Record) { + ArrayRef<uint8_t> FieldListRecordData = CVR.Data; + auto ExpectedRecord = FieldListRecord::deserialize(TypeRecordKind::FieldList, + FieldListRecordData); + if (!ExpectedRecord) + return ExpectedRecord.takeError(); + + Record = *ExpectedRecord; + ArrayRef<uint8_t> MemberData = Record.getFieldListData(); + + while (!MemberData.empty()) { + const ulittle16_t *LeafPtr; + if (auto EC = takeObject(MemberData, 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 a type that we don't know how to deserialize. + if (auto EC = Recipient.visitUnknownMember(CVR)) + return EC; + return llvm::make_error<CodeViewError>( + cv_error_code::unknown_member_record); +#define MEMBER_RECORD(EnumName, EnumVal, Name) \ + case EnumName: { \ + TypeRecordKind RK = static_cast<TypeRecordKind>(Leaf); \ + Name##Record Member(RK); \ + if (auto EC = visitKnownMember(MemberData, Leaf, Member)) \ + 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(MemberData)) + return EC; + } + return Error::success(); +} + +Error TypeDeserializer::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(); +} diff --git a/llvm/lib/DebugInfo/CodeView/TypeDumper.cpp b/llvm/lib/DebugInfo/CodeView/TypeDumper.cpp index 5ceaa59a79e..e1ec5ce9802 100644 --- a/llvm/lib/DebugInfo/CodeView/TypeDumper.cpp +++ b/llvm/lib/DebugInfo/CodeView/TypeDumper.cpp @@ -10,6 +10,7 @@ #include "llvm/DebugInfo/CodeView/TypeDumper.h" #include "llvm/ADT/SmallString.h" #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" +#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/MSF/ByteStream.h" @@ -195,8 +196,6 @@ static StringRef getLeafTypeName(TypeLeafKind LT) { case ename: \ return #name; #include "llvm/DebugInfo/CodeView/TypeRecords.def" - case LF_FIELDLIST: - return "FieldList"; default: break; } @@ -231,7 +230,13 @@ Error CVTypeDumper::visitTypeEnd(const CVRecord<TypeLeafKind> &Record) { return Error::success(); } -Error CVTypeDumper::visitStringId(StringIdRecord &String) { +Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR, + FieldListRecord &FieldList) { + return Error::success(); +} + +Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR, + StringIdRecord &String) { printTypeIndex("Id", String.getId()); W->printString("StringData", String.getString()); // Put this in CVUDTNames so it gets printed with LF_UDT_SRC_LINE. @@ -239,7 +244,8 @@ Error CVTypeDumper::visitStringId(StringIdRecord &String) { return Error::success(); } -Error CVTypeDumper::visitArgList(ArgListRecord &Args) { +Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR, + ArgListRecord &Args) { auto Indices = Args.getIndices(); uint32_t Size = Indices.size(); W->printNumber("NumArgs", Size); @@ -257,7 +263,8 @@ Error CVTypeDumper::visitArgList(ArgListRecord &Args) { return Error::success(); } -Error CVTypeDumper::visitClass(ClassRecord &Class) { +Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR, + ClassRecord &Class) { uint16_t Props = static_cast<uint16_t>(Class.getOptions()); W->printNumber("MemberCount", Class.getMemberCount()); W->printFlags("Properties", Props, makeArrayRef(ClassOptionNames)); @@ -272,7 +279,8 @@ Error CVTypeDumper::visitClass(ClassRecord &Class) { return Error::success(); } -Error CVTypeDumper::visitUnion(UnionRecord &Union) { +Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR, + UnionRecord &Union) { uint16_t Props = static_cast<uint16_t>(Union.getOptions()); W->printNumber("MemberCount", Union.getMemberCount()); W->printFlags("Properties", Props, makeArrayRef(ClassOptionNames)); @@ -285,7 +293,8 @@ Error CVTypeDumper::visitUnion(UnionRecord &Union) { return Error::success(); } -Error CVTypeDumper::visitEnum(EnumRecord &Enum) { +Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR, + EnumRecord &Enum) { uint16_t Props = static_cast<uint16_t>(Enum.getOptions()); W->printNumber("NumEnumerators", Enum.getMemberCount()); W->printFlags("Properties", uint16_t(Enum.getOptions()), @@ -299,7 +308,8 @@ Error CVTypeDumper::visitEnum(EnumRecord &Enum) { return Error::success(); } -Error CVTypeDumper::visitArray(ArrayRecord &AT) { +Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR, + ArrayRecord &AT) { printTypeIndex("ElementType", AT.getElementType()); printTypeIndex("IndexType", AT.getIndexType()); W->printNumber("SizeOf", AT.getSize()); @@ -308,7 +318,8 @@ Error CVTypeDumper::visitArray(ArrayRecord &AT) { return Error::success(); } -Error CVTypeDumper::visitVFTable(VFTableRecord &VFT) { +Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR, + VFTableRecord &VFT) { printTypeIndex("CompleteClass", VFT.getCompleteClass()); printTypeIndex("OverriddenVFTable", VFT.getOverriddenVTable()); W->printHex("VFPtrOffset", VFT.getVFPtrOffset()); @@ -319,7 +330,8 @@ Error CVTypeDumper::visitVFTable(VFTableRecord &VFT) { return Error::success(); } -Error CVTypeDumper::visitMemberFuncId(MemberFuncIdRecord &Id) { +Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR, + MemberFuncIdRecord &Id) { printTypeIndex("ClassType", Id.getClassType()); printTypeIndex("FunctionType", Id.getFunctionType()); W->printString("Name", Id.getName()); @@ -327,7 +339,8 @@ Error CVTypeDumper::visitMemberFuncId(MemberFuncIdRecord &Id) { return Error::success(); } -Error CVTypeDumper::visitProcedure(ProcedureRecord &Proc) { +Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR, + ProcedureRecord &Proc) { printTypeIndex("ReturnType", Proc.getReturnType()); W->printEnum("CallingConvention", uint8_t(Proc.getCallConv()), makeArrayRef(CallingConventions)); @@ -345,7 +358,8 @@ Error CVTypeDumper::visitProcedure(ProcedureRecord &Proc) { return Error::success(); } -Error CVTypeDumper::visitMemberFunction(MemberFunctionRecord &MF) { +Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR, + MemberFunctionRecord &MF) { printTypeIndex("ReturnType", MF.getReturnType()); printTypeIndex("ClassType", MF.getClassType()); printTypeIndex("ThisType", MF.getThisType()); @@ -369,8 +383,8 @@ Error CVTypeDumper::visitMemberFunction(MemberFunctionRecord &MF) { return Error::success(); } -Error CVTypeDumper::visitMethodOverloadList( - MethodOverloadListRecord &MethodList) { +Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR, + MethodOverloadListRecord &MethodList) { for (auto &M : MethodList.getMethods()) { ListScope S(*W, "Method"); printMemberAttributes(M.getAccess(), M.getKind(), M.getOptions()); @@ -381,7 +395,8 @@ Error CVTypeDumper::visitMethodOverloadList( return Error::success(); } -Error CVTypeDumper::visitFuncId(FuncIdRecord &Func) { +Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR, + FuncIdRecord &Func) { printTypeIndex("ParentScope", Func.getParentScope()); printTypeIndex("FunctionType", Func.getFunctionType()); W->printString("Name", Func.getName()); @@ -389,7 +404,8 @@ Error CVTypeDumper::visitFuncId(FuncIdRecord &Func) { return Error::success(); } -Error CVTypeDumper::visitTypeServer2(TypeServer2Record &TS) { +Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR, + TypeServer2Record &TS) { W->printBinary("Signature", TS.getGuid()); W->printNumber("Age", TS.getAge()); W->printString("Name", TS.getName()); @@ -397,7 +413,8 @@ Error CVTypeDumper::visitTypeServer2(TypeServer2Record &TS) { return Error::success(); } -Error CVTypeDumper::visitPointer(PointerRecord &Ptr) { +Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR, + PointerRecord &Ptr) { printTypeIndex("PointeeType", Ptr.getReferentType()); W->printHex("PointerAttributes", uint32_t(Ptr.getOptions())); W->printEnum("PtrType", unsigned(Ptr.getPointerKind()), @@ -448,7 +465,8 @@ Error CVTypeDumper::visitPointer(PointerRecord &Ptr) { return Error::success(); } -Error CVTypeDumper::visitModifier(ModifierRecord &Mod) { +Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR, + ModifierRecord &Mod) { uint16_t Mods = static_cast<uint16_t>(Mod.getModifiers()); printTypeIndex("ModifiedType", Mod.getModifiedType()); W->printFlags("Modifiers", Mods, makeArrayRef(TypeModifierNames)); @@ -466,26 +484,30 @@ Error CVTypeDumper::visitModifier(ModifierRecord &Mod) { return Error::success(); } -Error CVTypeDumper::visitBitField(BitFieldRecord &BitField) { +Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR, + BitFieldRecord &BitField) { printTypeIndex("Type", BitField.getType()); W->printNumber("BitSize", BitField.getBitSize()); W->printNumber("BitOffset", BitField.getBitOffset()); return Error::success(); } -Error CVTypeDumper::visitVFTableShape(VFTableShapeRecord &Shape) { +Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR, + VFTableShapeRecord &Shape) { W->printNumber("VFEntryCount", Shape.getEntryCount()); return Error::success(); } -Error CVTypeDumper::visitUdtSourceLine(UdtSourceLineRecord &Line) { +Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR, + UdtSourceLineRecord &Line) { printTypeIndex("UDT", Line.getUDT()); printTypeIndex("SourceFile", Line.getSourceFile()); W->printNumber("LineNumber", Line.getLineNumber()); return Error::success(); } -Error CVTypeDumper::visitUdtModSourceLine(UdtModSourceLineRecord &Line) { +Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR, + UdtModSourceLineRecord &Line) { printTypeIndex("UDT", Line.getUDT()); printTypeIndex("SourceFile", Line.getSourceFile()); W->printNumber("LineNumber", Line.getLineNumber()); @@ -493,7 +515,8 @@ Error CVTypeDumper::visitUdtModSourceLine(UdtModSourceLineRecord &Line) { return Error::success(); } -Error CVTypeDumper::visitBuildInfo(BuildInfoRecord &Args) { +Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR, + BuildInfoRecord &Args) { W->printNumber("NumArgs", static_cast<uint32_t>(Args.getArgs().size())); ListScope Arguments(*W, "Arguments"); @@ -533,7 +556,8 @@ Error CVTypeDumper::visitUnknownType(const CVRecord<TypeLeafKind> &Record) { return Error::success(); } -Error CVTypeDumper::visitNestedType(NestedTypeRecord &Nested) { +Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR, + NestedTypeRecord &Nested) { DictScope S(*W, "NestedType"); printTypeIndex("Type", Nested.getNestedType()); W->printString("Name", Nested.getName()); @@ -541,7 +565,8 @@ Error CVTypeDumper::visitNestedType(NestedTypeRecord &Nested) { return Error::success(); } -Error CVTypeDumper::visitOneMethod(OneMethodRecord &Method) { +Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR, + OneMethodRecord &Method) { DictScope S(*W, "OneMethod"); MethodKind K = Method.getKind(); printMemberAttributes(Method.getAccess(), K, Method.getOptions()); @@ -554,7 +579,8 @@ Error CVTypeDumper::visitOneMethod(OneMethodRecord &Method) { return Error::success(); } -Error CVTypeDumper::visitOverloadedMethod(OverloadedMethodRecord &Method) { +Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR, + OverloadedMethodRecord &Method) { DictScope S(*W, "OverloadedMethod"); W->printHex("MethodCount", Method.getNumOverloads()); printTypeIndex("MethodListIndex", Method.getMethodList()); @@ -563,7 +589,8 @@ Error CVTypeDumper::visitOverloadedMethod(OverloadedMethodRecord &Method) { return Error::success(); } -Error CVTypeDumper::visitDataMember(DataMemberRecord &Field) { +Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR, + DataMemberRecord &Field) { DictScope S(*W, "DataMember"); printMemberAttributes(Field.getAccess(), MethodKind::Vanilla, MethodOptions::None); @@ -574,7 +601,8 @@ Error CVTypeDumper::visitDataMember(DataMemberRecord &Field) { return Error::success(); } -Error CVTypeDumper::visitStaticDataMember(StaticDataMemberRecord &Field) { +Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR, + StaticDataMemberRecord &Field) { DictScope S(*W, "StaticDataMember"); printMemberAttributes(Field.getAccess(), MethodKind::Vanilla, MethodOptions::None); @@ -584,13 +612,15 @@ Error CVTypeDumper::visitStaticDataMember(StaticDataMemberRecord &Field) { return Error::success(); } -Error CVTypeDumper::visitVFPtr(VFPtrRecord &VFTable) { +Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR, + VFPtrRecord &VFTable) { DictScope S(*W, "VFPtr"); printTypeIndex("Type", VFTable.getType()); return Error::success(); } -Error CVTypeDumper::visitEnumerator(EnumeratorRecord &Enum) { +Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR, + EnumeratorRecord &Enum) { DictScope S(*W, "Enumerator"); printMemberAttributes(Enum.getAccess(), MethodKind::Vanilla, MethodOptions::None); @@ -600,7 +630,8 @@ Error CVTypeDumper::visitEnumerator(EnumeratorRecord &Enum) { return Error::success(); } -Error CVTypeDumper::visitBaseClass(BaseClassRecord &Base) { +Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR, + BaseClassRecord &Base) { DictScope S(*W, "BaseClass"); printMemberAttributes(Base.getAccess(), MethodKind::Vanilla, MethodOptions::None); @@ -609,7 +640,8 @@ Error CVTypeDumper::visitBaseClass(BaseClassRecord &Base) { return Error::success(); } -Error CVTypeDumper::visitVirtualBaseClass(VirtualBaseClassRecord &Base) { +Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR, + VirtualBaseClassRecord &Base) { DictScope S(*W, "VirtualBaseClass"); printMemberAttributes(Base.getAccess(), MethodKind::Vanilla, MethodOptions::None); @@ -620,7 +652,8 @@ Error CVTypeDumper::visitVirtualBaseClass(VirtualBaseClassRecord &Base) { return Error::success(); } -Error CVTypeDumper::visitListContinuation(ListContinuationRecord &Cont) { +Error CVTypeDumper::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR, + ListContinuationRecord &Cont) { DictScope S(*W, "ListContinuation"); printTypeIndex("ContinuationIndex", Cont.getContinuationIndex()); return Error::success(); @@ -665,7 +698,8 @@ void CVTypeDumper::printTypeIndex(StringRef FieldName, TypeIndex TI) { Error CVTypeDumper::dump(const CVRecord<TypeLeafKind> &Record) { assert(W && "printer should not be null"); - CVTypeVisitor Visitor(*this); + TypeDeserializer Deserializer(*this); + CVTypeVisitor Visitor(Deserializer); if (auto EC = Visitor.visitTypeRecord(Record)) return EC; @@ -674,7 +708,9 @@ Error CVTypeDumper::dump(const CVRecord<TypeLeafKind> &Record) { Error CVTypeDumper::dump(const CVTypeArray &Types) { assert(W && "printer should not be null"); - CVTypeVisitor Visitor(*this); + TypeDeserializer Deserializer(*this); + CVTypeVisitor Visitor(Deserializer); + if (auto EC = Visitor.visitTypeStream(Types)) return EC; return Error::success(); diff --git a/llvm/lib/DebugInfo/CodeView/TypeRecord.cpp b/llvm/lib/DebugInfo/CodeView/TypeRecord.cpp index 4bbd2616bb5..e630be87345 100644 --- a/llvm/lib/DebugInfo/CodeView/TypeRecord.cpp +++ b/llvm/lib/DebugInfo/CodeView/TypeRecord.cpp @@ -114,6 +114,11 @@ NestedTypeRecord::deserialize(TypeRecordKind Kind, ArrayRef<uint8_t> &Data) { return NestedTypeRecord(L->Type, Name); } +Expected<FieldListRecord> +FieldListRecord::deserialize(TypeRecordKind Kind, ArrayRef<uint8_t> &Data) { + return FieldListRecord(Data); +} + Expected<ArrayRecord> ArrayRecord::deserialize(TypeRecordKind Kind, ArrayRef<uint8_t> &Data) { const Layout *L = nullptr; diff --git a/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp b/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp index 8c2bc072cd9..58c8c3fecb4 100644 --- a/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp +++ b/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp @@ -12,6 +12,7 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" #include "llvm/DebugInfo/CodeView/FieldListRecordBuilder.h" +#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" @@ -58,7 +59,8 @@ public: /// TypeVisitorCallbacks overrides. #define TYPE_RECORD(EnumName, EnumVal, Name) \ - Error visit##Name(Name##Record &Record) override; + Error visitKnownRecord(const CVRecord<TypeLeafKind> &CVR, \ + Name##Record &Record) override; #define MEMBER_RECORD(EnumName, EnumVal, Name) \ TYPE_RECORD(EnumName, EnumVal, Name) #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) @@ -70,11 +72,28 @@ public: 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: + template <typename RecordType> + Error visitKnownRecordImpl(RecordType &Record) { + FoundBadTypeIndex |= !Record.remapTypeIndices(IndexMap); + IndexMap.push_back(DestStream.writeKnownType(Record)); + return Error::success(); + } + + Error visitKnownRecordImpl(FieldListRecord &Record) { + // Don't do anything, this will get written in the call to visitTypeEnd(). + return Error::success(); + } + + template <typename RecordType> + Error visitKnownMemberRecordImpl(RecordType &Record) { + FoundBadTypeIndex |= !Record.remapTypeIndices(IndexMap); + FieldBuilder.writeMemberType(Record); + return Error::success(); + } + bool hadError() { return FoundBadTypeIndex; } bool FoundBadTypeIndex = false; @@ -93,33 +112,31 @@ private: } // end anonymous namespace Error TypeStreamMerger::visitTypeBegin(const CVRecord<TypeLeafKind> &Rec) { - BeginIndexMapSize = IndexMap.size(); + if (Rec.Type != TypeLeafKind::LF_FIELDLIST) + 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(); + if (Rec.Type == TypeLeafKind::LF_FIELDLIST) { + IndexMap.push_back(DestStream.writeFieldList(FieldBuilder)); + FieldBuilder.reset(); + } else { + assert(IndexMap.size() == BeginIndexMapSize + 1); + } 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(); \ + Error TypeStreamMerger::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR, \ + Name##Record &Record) { \ + return visitKnownRecordImpl(Record); \ } #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(); \ + Error TypeStreamMerger::visitKnownRecord(const CVRecord<TypeLeafKind> &CVR, \ + Name##Record &Record) { \ + return visitKnownMemberRecordImpl(Record); \ } #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) #include "llvm/DebugInfo/CodeView/TypeRecords.def" @@ -133,7 +150,9 @@ Error TypeStreamMerger::visitUnknownType(const CVRecord<TypeLeafKind> &Rec) { bool TypeStreamMerger::mergeStream(const CVTypeArray &Types) { assert(IndexMap.empty()); - CVTypeVisitor Visitor(*this); + TypeDeserializer Deserializer(*this); + CVTypeVisitor Visitor(Deserializer); + if (auto EC = Visitor.visitTypeStream(Types)) { consumeError(std::move(EC)); return false; diff --git a/llvm/lib/DebugInfo/CodeView/TypeTableBuilder.cpp b/llvm/lib/DebugInfo/CodeView/TypeTableBuilder.cpp index 647538ee8ce..0fcf4f92d43 100644 --- a/llvm/lib/DebugInfo/CodeView/TypeTableBuilder.cpp +++ b/llvm/lib/DebugInfo/CodeView/TypeTableBuilder.cpp @@ -21,7 +21,7 @@ TypeTableBuilder::TypeTableBuilder() {} TypeTableBuilder::~TypeTableBuilder() {} -TypeIndex TypeTableBuilder::writeModifier(const ModifierRecord &Record) { +TypeIndex TypeTableBuilder::writeKnownType(const ModifierRecord &Record) { TypeRecordBuilder Builder(Record.getKind()); Builder.writeTypeIndex(Record.getModifiedType()); @@ -30,7 +30,7 @@ TypeIndex TypeTableBuilder::writeModifier(const ModifierRecord &Record) { return writeRecord(Builder); } -TypeIndex TypeTableBuilder::writeProcedure(const ProcedureRecord &Record) { +TypeIndex TypeTableBuilder::writeKnownType(const ProcedureRecord &Record) { TypeRecordBuilder Builder(Record.getKind()); Builder.writeTypeIndex(Record.getReturnType()); @@ -42,8 +42,7 @@ TypeIndex TypeTableBuilder::writeProcedure(const ProcedureRecord &Record) { return writeRecord(Builder); } -TypeIndex -TypeTableBuilder::writeMemberFunction(const MemberFunctionRecord &Record) { +TypeIndex TypeTableBuilder::writeKnownType(const MemberFunctionRecord &Record) { TypeRecordBuilder Builder(Record.getKind()); Builder.writeTypeIndex(Record.getReturnType()); @@ -58,7 +57,7 @@ TypeTableBuilder::writeMemberFunction(const MemberFunctionRecord &Record) { return writeRecord(Builder); } -TypeIndex TypeTableBuilder::writeArgList(const ArgListRecord &Record) { +TypeIndex TypeTableBuilder::writeKnownType(const ArgListRecord &Record) { TypeRecordBuilder Builder(Record.getKind()); Builder.writeUInt32(Record.getIndices().size()); @@ -69,7 +68,7 @@ TypeIndex TypeTableBuilder::writeArgList(const ArgListRecord &Record) { return writeRecord(Builder); } -TypeIndex TypeTableBuilder::writePointer(const PointerRecord &Record) { +TypeIndex TypeTableBuilder::writeKnownType(const PointerRecord &Record) { TypeRecordBuilder Builder(Record.getKind()); Builder.writeTypeIndex(Record.getReferentType()); @@ -90,7 +89,7 @@ TypeIndex TypeTableBuilder::writePointer(const PointerRecord &Record) { return writeRecord(Builder); } -TypeIndex TypeTableBuilder::writeArray(const ArrayRecord &Record) { +TypeIndex TypeTableBuilder::writeKnownType(const ArrayRecord &Record) { TypeRecordBuilder Builder(Record.getKind()); Builder.writeTypeIndex(Record.getElementType()); @@ -101,7 +100,7 @@ TypeIndex TypeTableBuilder::writeArray(const ArrayRecord &Record) { return writeRecord(Builder); } -TypeIndex TypeTableBuilder::writeClass(const ClassRecord &Record) { +TypeIndex TypeTableBuilder::writeKnownType(const ClassRecord &Record) { assert((Record.getKind() == TypeRecordKind::Struct) || (Record.getKind() == TypeRecordKind::Class) || (Record.getKind() == TypeRecordKind::Interface)); @@ -128,7 +127,7 @@ TypeIndex TypeTableBuilder::writeClass(const ClassRecord &Record) { return writeRecord(Builder); } -TypeIndex TypeTableBuilder::writeUnion(const UnionRecord &Record) { +TypeIndex TypeTableBuilder::writeKnownType(const UnionRecord &Record) { TypeRecordBuilder Builder(TypeRecordKind::Union); Builder.writeUInt16(Record.getMemberCount()); uint16_t Flags = @@ -145,7 +144,7 @@ TypeIndex TypeTableBuilder::writeUnion(const UnionRecord &Record) { return writeRecord(Builder); } -TypeIndex TypeTableBuilder::writeEnum(const EnumRecord &Record) { +TypeIndex TypeTableBuilder::writeKnownType(const EnumRecord &Record) { TypeRecordBuilder Builder(Record.getKind()); Builder.writeUInt16(Record.getMemberCount()); @@ -161,7 +160,7 @@ TypeIndex TypeTableBuilder::writeEnum(const EnumRecord &Record) { return writeRecord(Builder); } -TypeIndex TypeTableBuilder::writeBitField(const BitFieldRecord &Record) { +TypeIndex TypeTableBuilder::writeKnownType(const BitFieldRecord &Record) { TypeRecordBuilder Builder(Record.getKind()); Builder.writeTypeIndex(Record.getType()); @@ -171,8 +170,7 @@ TypeIndex TypeTableBuilder::writeBitField(const BitFieldRecord &Record) { return writeRecord(Builder); } -TypeIndex -TypeTableBuilder::writeVFTableShape(const VFTableShapeRecord &Record) { +TypeIndex TypeTableBuilder::writeKnownType(const VFTableShapeRecord &Record) { TypeRecordBuilder Builder(Record.getKind()); ArrayRef<VFTableSlotKind> Slots = Record.getSlots(); @@ -189,8 +187,7 @@ TypeTableBuilder::writeVFTableShape(const VFTableShapeRecord &Record) { return writeRecord(Builder); } -TypeIndex -TypeTableBuilder::writeVFTable(const VFTableRecord &Record) { +TypeIndex TypeTableBuilder::writeKnownType(const VFTableRecord &Record) { TypeRecordBuilder Builder(Record.getKind()); Builder.writeTypeIndex(Record.getCompleteClass()); Builder.writeTypeIndex(Record.getOverriddenVTable()); @@ -209,15 +206,14 @@ TypeTableBuilder::writeVFTable(const VFTableRecord &Record) { return writeRecord(Builder); } -TypeIndex TypeTableBuilder::writeStringId(const StringIdRecord &Record) { +TypeIndex TypeTableBuilder::writeKnownType(const StringIdRecord &Record) { TypeRecordBuilder Builder(TypeRecordKind::StringId); Builder.writeTypeIndex(Record.getId()); Builder.writeNullTerminatedString(Record.getString()); return writeRecord(Builder); } -TypeIndex -TypeTableBuilder::writeUdtSourceLine(const UdtSourceLineRecord &Record) { +TypeIndex TypeTableBuilder::writeKnownType(const UdtSourceLineRecord &Record) { TypeRecordBuilder Builder(Record.getKind()); Builder.writeTypeIndex(Record.getUDT()); Builder.writeTypeIndex(Record.getSourceFile()); @@ -226,7 +222,7 @@ TypeTableBuilder::writeUdtSourceLine(const UdtSourceLineRecord &Record) { } TypeIndex -TypeTableBuilder::writeUdtModSourceLine(const UdtModSourceLineRecord &Record) { +TypeTableBuilder::writeKnownType(const UdtModSourceLineRecord &Record) { TypeRecordBuilder Builder(Record.getKind()); Builder.writeTypeIndex(Record.getUDT()); Builder.writeTypeIndex(Record.getSourceFile()); @@ -235,7 +231,7 @@ TypeTableBuilder::writeUdtModSourceLine(const UdtModSourceLineRecord &Record) { return writeRecord(Builder); } -TypeIndex TypeTableBuilder::writeFuncId(const FuncIdRecord &Record) { +TypeIndex TypeTableBuilder::writeKnownType(const FuncIdRecord &Record) { TypeRecordBuilder Builder(Record.getKind()); Builder.writeTypeIndex(Record.getParentScope()); Builder.writeTypeIndex(Record.getFunctionType()); @@ -243,8 +239,7 @@ TypeIndex TypeTableBuilder::writeFuncId(const FuncIdRecord &Record) { return writeRecord(Builder); } -TypeIndex -TypeTableBuilder::writeMemberFuncId(const MemberFuncIdRecord &Record) { +TypeIndex TypeTableBuilder::writeKnownType(const MemberFuncIdRecord &Record) { TypeRecordBuilder Builder(Record.getKind()); Builder.writeTypeIndex(Record.getClassType()); Builder.writeTypeIndex(Record.getFunctionType()); @@ -252,8 +247,7 @@ TypeTableBuilder::writeMemberFuncId(const MemberFuncIdRecord &Record) { return writeRecord(Builder); } -TypeIndex -TypeTableBuilder::writeBuildInfo(const BuildInfoRecord &Record) { +TypeIndex TypeTableBuilder::writeKnownType(const BuildInfoRecord &Record) { TypeRecordBuilder Builder(Record.getKind()); assert(Record.getArgs().size() <= UINT16_MAX); Builder.writeUInt16(Record.getArgs().size()); @@ -270,8 +264,8 @@ TypeIndex TypeTableBuilder::writeFieldList(FieldListRecordBuilder &FieldList) { return FieldList.writeListRecord(*this); } -TypeIndex TypeTableBuilder::writeMethodOverloadList( - const MethodOverloadListRecord &Record) { +TypeIndex +TypeTableBuilder::writeKnownType(const MethodOverloadListRecord &Record) { TypeRecordBuilder Builder(Record.getKind()); for (const OneMethodRecord &Method : Record.getMethods()) { uint16_t Flags = static_cast<uint16_t>(Method.getAccess()); @@ -294,7 +288,7 @@ TypeIndex TypeTableBuilder::writeMethodOverloadList( return writeRecord(Builder); } -TypeIndex TypeTableBuilder::writeTypeServer2(const TypeServer2Record &Record) { +TypeIndex TypeTableBuilder::writeKnownType(const TypeServer2Record &Record) { TypeRecordBuilder Builder(Record.getKind()); Builder.writeGuid(Record.getGuid()); Builder.writeUInt32(Record.getAge()); |