Index: llvm/trunk/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h +++ llvm/trunk/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h @@ -14,6 +14,7 @@ #include "llvm/DebugInfo/CodeView/RecordIterator.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/CodeView/TypeStream.h" #include "llvm/Support/ErrorOr.h" namespace llvm { @@ -110,6 +111,7 @@ /// Visits individual member records of a field list record. Member records do /// not describe their own length, and need special handling. void visitFieldList(TypeLeafKind Leaf, ArrayRef FieldData) { + auto *DerivedThis = static_cast(this); while (!FieldData.empty()) { const ulittle16_t *LeafPtr; if (!CVTypeVisitor::consumeObject(FieldData, LeafPtr)) @@ -119,7 +121,7 @@ default: // Field list records do not describe their own length, so we cannot // continue parsing past an unknown member type. - visitUnknownMember(Leaf); + DerivedThis->visitUnknownMember(Leaf); return parseError(); #define MEMBER_RECORD(EnumName, EnumVal, Name) \ case EnumName: { \ @@ -127,7 +129,7 @@ auto Result = Name##Record::deserialize(RK, FieldData); \ if (Result.getError()) \ return parseError(); \ - static_cast(this)->visit##Name(Leaf, *Result); \ + DerivedThis->visit##Name(Leaf, *Result); \ break; \ } #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \ Index: llvm/trunk/include/llvm/DebugInfo/CodeView/FieldListRecordBuilder.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/CodeView/FieldListRecordBuilder.h +++ llvm/trunk/include/llvm/DebugInfo/CodeView/FieldListRecordBuilder.h @@ -11,6 +11,7 @@ #define LLVM_DEBUGINFO_CODEVIEW_FIELDLISTRECORDBUILDER_H #include "llvm/DebugInfo/CodeView/ListRecordBuilder.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" namespace llvm { namespace codeview { @@ -46,31 +47,15 @@ public: FieldListRecordBuilder(); - void writeBaseClass(MemberAccess Access, TypeIndex Type, uint64_t Offset); - void writeEnumerate(MemberAccess Access, uint64_t Value, StringRef Name); - void writeIndirectVirtualBaseClass(MemberAccess Access, TypeIndex Type, - TypeIndex VirtualBasePointerType, - int64_t VirtualBasePointerOffset, - uint64_t SlotIndex); - void writeMember(MemberAccess Access, TypeIndex Type, uint64_t Offset, - StringRef Name); - void writeOneMethod(MemberAccess Access, MethodKind Kind, - MethodOptions Options, TypeIndex Type, - int32_t VTableSlotOffset, StringRef Name); - void writeOneMethod(const MethodInfo &Method, StringRef Name); - void writeMethod(uint16_t OverloadCount, TypeIndex MethodList, - StringRef Name); - void writeNestedType(TypeIndex Type, StringRef Name); - void writeStaticMember(MemberAccess Access, TypeIndex Type, StringRef Name); - void writeVirtualBaseClass(MemberAccess Access, TypeIndex Type, - TypeIndex VirtualBasePointerType, - int64_t VirtualBasePointerOffset, - uint64_t SlotIndex); - void writeVirtualBaseClass(TypeRecordKind Kind, MemberAccess Access, - TypeIndex Type, TypeIndex VirtualBasePointerType, - int64_t VirtualBasePointerOffset, - uint64_t SlotIndex); - void writeVirtualFunctionTablePointer(TypeIndex Type); + void writeBaseClass(const BaseClassRecord &Record); + void writeEnumerator(const EnumeratorRecord &Record); + void writeDataMember(const DataMemberRecord &Record); + void writeOneMethod(const OneMethodRecord &Record); + void writeOverloadedMethod(const OverloadedMethodRecord &Record); + void writeNestedType(const NestedTypeRecord &Record); + void writeStaticDataMember(const StaticDataMemberRecord &Record); + void writeVirtualBaseClass(const VirtualBaseClassRecord &Record); + void writeVFPtr(const VFPtrRecord &Type); }; } } Index: llvm/trunk/include/llvm/DebugInfo/CodeView/ListRecordBuilder.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/CodeView/ListRecordBuilder.h +++ llvm/trunk/include/llvm/DebugInfo/CodeView/ListRecordBuilder.h @@ -28,6 +28,8 @@ public: llvm::StringRef str() { return Builder.str(); } + void reset() { Builder.reset(); } + protected: void finishSubRecord(); Index: llvm/trunk/include/llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h +++ llvm/trunk/include/llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h @@ -55,7 +55,7 @@ } } -private: +protected: TypeIndex writeRecord(llvm::StringRef Data) override; private: Index: llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecord.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecord.h +++ llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecord.h @@ -30,6 +30,9 @@ /// Equvalent to CV_fldattr_t in cvinfo.h. struct MemberAttributes { ulittle16_t Attrs; + enum { + MethodKindShift = 2, + }; /// Get the access specifier. Valid for any kind of member. MemberAccess getAccess() const { @@ -39,7 +42,8 @@ /// Indicates if a method is defined with friend, virtual, static, etc. MethodKind getMethodKind() const { return MethodKind( - (unsigned(Attrs) & unsigned(MethodOptions::MethodKindMask)) >> 2); + (unsigned(Attrs) & unsigned(MethodOptions::MethodKindMask)) >> + MethodKindShift); } /// Get the flags that are not included in access control or method @@ -75,6 +79,10 @@ PointerToMemberRepresentation Representation) : ContainingType(ContainingType), Representation(Representation) {} + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); + static ErrorOr deserialize(ArrayRef &Data) { const Layout *L = nullptr; if (auto EC = consumeObject(Data, L)) @@ -120,6 +128,10 @@ : TypeRecord(TypeRecordKind::Modifier), ModifiedType(ModifiedType), Modifiers(Modifiers) {} + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); + static ErrorOr deserialize(TypeRecordKind Kind, ArrayRef &Data) { const Layout *L = nullptr; @@ -155,6 +167,10 @@ CallConv(CallConv), Options(Options), ParameterCount(ParameterCount), ArgumentList(ArgumentList) {} + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); + static ErrorOr deserialize(TypeRecordKind Kind, ArrayRef &Data) { const Layout *L = nullptr; @@ -202,6 +218,10 @@ ArgumentList(ArgumentList), ThisPointerAdjustment(ThisPointerAdjustment) {} + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); + static ErrorOr deserialize(TypeRecordKind Kind, ArrayRef &Data) { const Layout *L = nullptr; @@ -251,8 +271,12 @@ : TypeRecord(TypeRecordKind::MemberFuncId), ClassType(ClassType), FunctionType(FunctionType), Name(Name) {} + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); + static ErrorOr deserialize(TypeRecordKind Kind, - ArrayRef &Data) { + ArrayRef &Data) { const Layout *L = nullptr; StringRef Name; CV_DESERIALIZE(Data, L, Name); @@ -281,6 +305,10 @@ ArgListRecord(TypeRecordKind Kind, ArrayRef Indices) : TypeRecord(Kind), StringIndices(Indices) {} + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); + static ErrorOr deserialize(TypeRecordKind Kind, ArrayRef &Data) { if (Kind != TypeRecordKind::StringList && Kind != TypeRecordKind::ArgList) @@ -303,7 +331,7 @@ // ArgTypes[]: Type indicies of arguments }; - ArrayRef StringIndices; + std::vector StringIndices; }; // LF_POINTER @@ -330,6 +358,10 @@ PtrKind(Kind), Mode(Mode), Options(Options), Size(Size), MemberInfo(Member) {} + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); + static ErrorOr deserialize(TypeRecordKind Kind, ArrayRef &Data) { const Layout *L = nullptr; @@ -421,6 +453,10 @@ NestedTypeRecord(TypeIndex Type, StringRef Name) : TypeRecord(TypeRecordKind::NestedType), Type(Type), Name(Name) {} + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); + static ErrorOr deserialize(TypeRecordKind Kind, ArrayRef &Data) { const Layout *L = nullptr; @@ -452,6 +488,10 @@ : TypeRecord(TypeRecordKind::Array), ElementType(ElementType), IndexType(IndexType), Size(Size), Name(Name) {} + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); + static ErrorOr deserialize(TypeRecordKind Kind, ArrayRef &Data) { const Layout *L = nullptr; @@ -489,6 +529,10 @@ FieldList(FieldList), Name(Name), UniqueName(UniqueName) {} public: + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); + static const int HfaKindShift = 11; static const int HfaKindMask = 0x1800; static const int WinRTKindShift = 14; @@ -519,6 +563,10 @@ Hfa(Hfa), WinRTKind(WinRTKind), DerivationList(DerivationList), VTableShape(VTableShape), Size(Size) {} + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); + static ErrorOr deserialize(TypeRecordKind Kind, ArrayRef &Data) { uint64_t Size = 0; @@ -629,6 +677,9 @@ UniqueName), UnderlyingType(UnderlyingType) {} + /// Rewrite member type indices with IndexMap. Returns false if a type index is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); + static ErrorOr deserialize(TypeRecordKind Kind, ArrayRef &Data) { const Layout *L = nullptr; @@ -679,8 +730,12 @@ explicit VFTableShapeRecord(std::vector Slots) : TypeRecord(TypeRecordKind::VFTableShape), Slots(Slots) {} + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); + static ErrorOr deserialize(TypeRecordKind Kind, - ArrayRef &Data) { + ArrayRef &Data) { const Layout *L = nullptr; if (auto EC = consumeObject(Data, L)) return EC; @@ -733,6 +788,10 @@ : TypeRecord(TypeRecordKind::TypeServer2), Guid(Guid), Age(Age), Name(Name) {} + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); + static ErrorOr deserialize(TypeRecordKind Kind, ArrayRef &Data) { const Layout *L = nullptr; @@ -766,6 +825,10 @@ StringIdRecord(TypeIndex Id, StringRef String) : TypeRecord(TypeRecordKind::StringId), Id(Id), String(String) {} + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); + static ErrorOr deserialize(TypeRecordKind Kind, ArrayRef &Data) { const Layout *L = nullptr; @@ -796,6 +859,10 @@ : TypeRecord(TypeRecordKind::FuncId), ParentScope(ParentScope), FunctionType(FunctionType), Name(Name) {} + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); + static ErrorOr deserialize(TypeRecordKind Kind, ArrayRef &Data) { const Layout *L = nullptr; @@ -830,6 +897,10 @@ : TypeRecord(TypeRecordKind::UdtSourceLine), UDT(UDT), SourceFile(SourceFile), LineNumber(LineNumber) {} + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); + static ErrorOr deserialize(TypeRecordKind Kind, ArrayRef &Data) { const Layout *L = nullptr; @@ -858,7 +929,12 @@ class BuildInfoRecord : public TypeRecord { public: BuildInfoRecord(ArrayRef ArgIndices) - : TypeRecord(TypeRecordKind::Modifier), ArgIndices(ArgIndices) {} + : TypeRecord(TypeRecordKind::BuildInfo), + ArgIndices(ArgIndices.begin(), ArgIndices.end()) {} + + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); static ErrorOr deserialize(TypeRecordKind Kind, ArrayRef &Data) { @@ -876,7 +952,7 @@ ulittle16_t NumArgs; // Number of arguments // ArgTypes[]: Type indicies of arguments }; - ArrayRef ArgIndices; + SmallVector ArgIndices; }; // LF_VFTABLE @@ -895,6 +971,10 @@ CompleteClass(CompleteClass), OverriddenVFTable(OverriddenVFTable), VFPtrOffset(VFPtrOffset), Name(Name), MethodNames(Methods) {} + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); + static ErrorOr deserialize(TypeRecordKind Kind, ArrayRef &Data) { const Layout *L = nullptr; @@ -943,11 +1023,15 @@ Options(Options), Access(Access), VFTableOffset(VFTableOffset), Name(Name) {} + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); + static ErrorOr deserialize(TypeRecordKind Kind, ArrayRef &Data) { const Layout *L = nullptr; StringRef Name; - int32_t VFTableOffset = 0; + int32_t VFTableOffset = -1; CV_DESERIALIZE(Data, L, CV_CONDITIONAL_FIELD( VFTableOffset, L->Attrs.isIntroducedVirtual()), @@ -994,17 +1078,19 @@ // LF_METHODLIST class MethodOverloadListRecord : public TypeRecord { public: - MethodOverloadListRecord(ArrayRef Methods) - : TypeRecord(TypeRecordKind::MethodOverloadList), MethodsRef(Methods) {} MethodOverloadListRecord(std::vector &Methods) : TypeRecord(TypeRecordKind::MethodOverloadList), Methods(Methods) {} + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); + static ErrorOr deserialize(TypeRecordKind Kind, ArrayRef &Data) { std::vector Methods; while (!Data.empty()) { const Layout *L = nullptr; - int32_t VFTableOffset = 0; + int32_t VFTableOffset = -1; CV_DESERIALIZE( Data, L, CV_CONDITIONAL_FIELD(VFTableOffset, L->Attrs.isIntroducedVirtual())); @@ -1019,11 +1105,7 @@ return MethodOverloadListRecord(Methods); } - ArrayRef getMethods() const { - if (!MethodsRef.empty()) - return MethodsRef; - return Methods; - } + ArrayRef getMethods() const { return Methods; } private: struct Layout { @@ -1035,7 +1117,6 @@ // VFTableOffset: int32_t offset in vftable }; - ArrayRef MethodsRef; std::vector Methods; }; @@ -1047,6 +1128,10 @@ : TypeRecord(TypeRecordKind::OverloadedMethod), NumOverloads(NumOverloads), MethodList(MethodList), Name(Name) {} + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); + static ErrorOr deserialize(TypeRecordKind Kind, ArrayRef &Data) { const Layout *L = nullptr; @@ -1080,6 +1165,10 @@ : TypeRecord(TypeRecordKind::DataMember), Access(Access), Type(Type), FieldOffset(Offset), Name(Name) {} + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); + static ErrorOr deserialize(TypeRecordKind Kind, ArrayRef &Data) { const Layout *L = nullptr; @@ -1116,6 +1205,10 @@ : TypeRecord(TypeRecordKind::StaticDataMember), Access(Access), Type(Type), Name(Name) {} + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); + static ErrorOr deserialize(TypeRecordKind Kind, ArrayRef &Data) { const Layout *L = nullptr; @@ -1148,6 +1241,10 @@ : TypeRecord(TypeRecordKind::Enumerator), Access(Access), Value(Value), Name(Name) {} + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); + static ErrorOr deserialize(TypeRecordKind Kind, ArrayRef &Data) { const Layout *L = nullptr; @@ -1179,6 +1276,11 @@ public: VFPtrRecord(TypeIndex Type) : TypeRecord(TypeRecordKind::VFPtr), Type(Type) {} + + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); + static ErrorOr deserialize(TypeRecordKind Kind, ArrayRef &Data) { const Layout *L = nullptr; @@ -1205,6 +1307,10 @@ : TypeRecord(TypeRecordKind::BaseClass), Access(Access), Type(Type), Offset(Offset) {} + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); + static ErrorOr deserialize(TypeRecordKind Kind, ArrayRef &Data) { const Layout *L = nullptr; @@ -1238,6 +1344,10 @@ BaseType(BaseType), VBPtrType(VBPtrType), VBPtrOffset(Offset), VTableIndex(Index) {} + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); + static ErrorOr deserialize(TypeRecordKind Kind, ArrayRef &Data) { const Layout *L = nullptr; Index: llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecordBuilder.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecordBuilder.h +++ llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecordBuilder.h @@ -41,11 +41,14 @@ void writeEncodedUnsignedInteger(uint64_t Value); void writeNullTerminatedString(const char *Value); void writeNullTerminatedString(StringRef Value); + void writeGuid(StringRef Guid); llvm::StringRef str(); uint64_t size() const { return Stream.tell(); } + void reset() { Buffer.clear(); } + private: llvm::SmallVector Buffer; llvm::raw_svector_ostream Stream; Index: llvm/trunk/include/llvm/DebugInfo/CodeView/TypeStreamMerger.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/CodeView/TypeStreamMerger.h +++ llvm/trunk/include/llvm/DebugInfo/CodeView/TypeStreamMerger.h @@ -0,0 +1,27 @@ +//===- TypeStreamMerger.h ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_TYPESTREAMMERGER_H +#define LLVM_DEBUGINFO_CODEVIEW_TYPESTREAMMERGER_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h" + +namespace llvm { +namespace codeview { + +/// Merges one type stream into another. Returns true on success. +bool mergeTypeStreams(TypeTableBuilder &DestStream, + ArrayRef SrcStream); + +} // end namespace codeview +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_CODEVIEW_TYPESTREAMMERGER_H Index: llvm/trunk/include/llvm/DebugInfo/CodeView/TypeTableBuilder.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/CodeView/TypeTableBuilder.h +++ llvm/trunk/include/llvm/DebugInfo/CodeView/TypeTableBuilder.h @@ -41,18 +41,26 @@ TypeIndex writeProcedure(const ProcedureRecord &Record); TypeIndex writeMemberFunction(const MemberFunctionRecord &Record); TypeIndex writeArgList(const ArgListRecord &Record); - TypeIndex writeRecord(TypeRecordBuilder &builder); TypeIndex writePointer(const PointerRecord &Record); TypeIndex writeArray(const ArrayRecord &Record); TypeIndex writeClass(const ClassRecord &Record); + TypeIndex writeUnion(const UnionRecord &Record); TypeIndex writeEnum(const EnumRecord &Record); TypeIndex writeBitField(const BitFieldRecord &Record); TypeIndex writeVFTableShape(const VFTableShapeRecord &Record); + TypeIndex writeStringId(const StringIdRecord &Record); + TypeIndex writeVFTable(const VFTableRecord &Record); + TypeIndex writeUdtSourceLine(const UdtSourceLineRecord &Record); + TypeIndex writeFuncId(const FuncIdRecord &Record); + TypeIndex writeMemberFuncId(const MemberFuncIdRecord &Record); + TypeIndex writeBuildInfo(const BuildInfoRecord &Record); + TypeIndex writeMethodOverloadList(const MethodOverloadListRecord &Record); + TypeIndex writeTypeServer2(const TypeServer2Record &Record); TypeIndex writeFieldList(FieldListRecordBuilder &FieldList); - TypeIndex writeMethodList(MethodListRecordBuilder &MethodList); -private: + TypeIndex writeRecord(TypeRecordBuilder &builder); + virtual TypeIndex writeRecord(llvm::StringRef record) = 0; }; } Index: llvm/trunk/lib/DebugInfo/CodeView/CMakeLists.txt =================================================================== --- llvm/trunk/lib/DebugInfo/CodeView/CMakeLists.txt +++ llvm/trunk/lib/DebugInfo/CodeView/CMakeLists.txt @@ -6,7 +6,9 @@ MethodListRecordBuilder.cpp RecordSerialization.cpp TypeDumper.cpp + TypeRecord.cpp TypeRecordBuilder.cpp + TypeStreamMerger.cpp TypeTableBuilder.cpp ADDITIONAL_HEADER_DIRS Index: llvm/trunk/lib/DebugInfo/CodeView/FieldListRecordBuilder.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/CodeView/FieldListRecordBuilder.cpp +++ llvm/trunk/lib/DebugInfo/CodeView/FieldListRecordBuilder.cpp @@ -15,151 +15,118 @@ 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(Access)); - Builder.writeTypeIndex(Type); - Builder.writeEncodedUnsignedInteger(Offset); + Builder.writeUInt16(static_cast(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(Access)); - Builder.writeEncodedUnsignedInteger(Value); - Builder.writeNullTerminatedString(Name); + Builder.writeUInt16(static_cast(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(Access)); - Builder.writeTypeIndex(Type); - Builder.writeEncodedUnsignedInteger(Offset); - Builder.writeNullTerminatedString(Name); + Builder.writeTypeRecordKind(Record.getKind()); + Builder.writeUInt16(static_cast(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(Access); - Flags |= static_cast(Kind) << MethodKindShift; - Flags |= static_cast(Options); + uint16_t Flags = static_cast(Record.getAccess()); + Flags |= static_cast(Record.getKind()) << MethodKindShift; + Flags |= static_cast(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(Access)); - Builder.writeTypeIndex(Type); - Builder.writeNullTerminatedString(Name); + Builder.writeTypeRecordKind(Record.getKind()); + Builder.writeUInt16(static_cast(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(Access)); - Builder.writeTypeIndex(Type); - Builder.writeTypeIndex(VirtualBasePointerType); - Builder.writeEncodedInteger(VirtualBasePointerOffset); - Builder.writeEncodedUnsignedInteger(SlotIndex); + Builder.writeTypeRecordKind(Record.getKind()); + Builder.writeUInt16(static_cast(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(); } Index: llvm/trunk/lib/DebugInfo/CodeView/TypeDumper.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/CodeView/TypeDumper.cpp +++ llvm/trunk/lib/DebugInfo/CodeView/TypeDumper.cpp @@ -280,6 +280,7 @@ // 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(); Index: llvm/trunk/lib/DebugInfo/CodeView/TypeRecord.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/CodeView/TypeRecord.cpp +++ llvm/trunk/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 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 IndexMap) { + return remapIndex(IndexMap, ModifiedType); +} + +bool ProcedureRecord::remapTypeIndices(ArrayRef IndexMap) { + bool Success = true; + Success &= remapIndex(IndexMap, ReturnType); + Success &= remapIndex(IndexMap, ArgumentList); + return Success; +} + +bool MemberFunctionRecord::remapTypeIndices(ArrayRef 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 IndexMap) { + bool Success = true; + Success &= remapIndex(IndexMap, ClassType); + Success &= remapIndex(IndexMap, FunctionType); + return Success; +} + +bool ArgListRecord::remapTypeIndices(ArrayRef IndexMap) { + bool Success = true; + for (TypeIndex &Str : StringIndices) + Success &= remapIndex(IndexMap, Str); + return Success; +} + +bool MemberPointerInfo::remapTypeIndices(ArrayRef IndexMap) { + return remapIndex(IndexMap, ContainingType); +} + +bool PointerRecord::remapTypeIndices(ArrayRef IndexMap) { + bool Success = true; + Success &= remapIndex(IndexMap, ReferentType); + if (isPointerToMember()) + Success &= MemberInfo.remapTypeIndices(IndexMap); + return Success; +} + +bool NestedTypeRecord::remapTypeIndices(ArrayRef IndexMap) { + return remapIndex(IndexMap, Type); +} + +bool ArrayRecord::remapTypeIndices(ArrayRef IndexMap) { + bool Success = true; + Success &= remapIndex(IndexMap, ElementType); + Success &= remapIndex(IndexMap, IndexType); + return Success; +} + +bool TagRecord::remapTypeIndices(ArrayRef IndexMap) { + return remapIndex(IndexMap, FieldList); +} + +bool ClassRecord::remapTypeIndices(ArrayRef IndexMap) { + bool Success = true; + Success &= TagRecord::remapTypeIndices(IndexMap); + Success &= remapIndex(IndexMap, DerivationList); + Success &= remapIndex(IndexMap, VTableShape); + return Success; +} + +bool EnumRecord::remapTypeIndices(ArrayRef IndexMap) { + bool Success = true; + Success &= TagRecord::remapTypeIndices(IndexMap); + Success &= remapIndex(IndexMap, UnderlyingType); + return Success; +} + +bool VFTableShapeRecord::remapTypeIndices(ArrayRef IndexMap) { + return true; +} + +bool TypeServer2Record::remapTypeIndices(ArrayRef IndexMap) { + return true; +} + +bool StringIdRecord::remapTypeIndices(ArrayRef IndexMap) { + return remapIndex(IndexMap, Id); +} + +bool FuncIdRecord::remapTypeIndices(ArrayRef IndexMap) { + bool Success = true; + Success &= remapIndex(IndexMap, ParentScope); + Success &= remapIndex(IndexMap, FunctionType); + return Success; +} + +bool UdtSourceLineRecord::remapTypeIndices(ArrayRef IndexMap) { + bool Success = true; + Success &= remapIndex(IndexMap, UDT); + Success &= remapIndex(IndexMap, SourceFile); + return Success; +} + +bool BuildInfoRecord::remapTypeIndices(ArrayRef IndexMap) { + bool Success = true; + for (TypeIndex &Arg : ArgIndices) + Success &= remapIndex(IndexMap, Arg); + return Success; +} + +bool VFTableRecord::remapTypeIndices(ArrayRef IndexMap) { + bool Success = true; + Success &= remapIndex(IndexMap, CompleteClass); + Success &= remapIndex(IndexMap, OverriddenVFTable); + return Success; +} + +bool OneMethodRecord::remapTypeIndices(ArrayRef IndexMap) { + bool Success = true; + Success &= remapIndex(IndexMap, Type); + return Success; +} + +bool MethodOverloadListRecord::remapTypeIndices(ArrayRef IndexMap) { + bool Success = true; + for (OneMethodRecord &Meth : Methods) + if ((Success = Meth.remapTypeIndices(IndexMap))) + return Success; + return Success; +} + +bool OverloadedMethodRecord::remapTypeIndices(ArrayRef IndexMap) { + return remapIndex(IndexMap, MethodList); +} + +bool DataMemberRecord::remapTypeIndices(ArrayRef IndexMap) { + return remapIndex(IndexMap, Type); +} + +bool StaticDataMemberRecord::remapTypeIndices(ArrayRef IndexMap) { + return remapIndex(IndexMap, Type); +} + +bool EnumeratorRecord::remapTypeIndices(ArrayRef IndexMap) { + return true; +} + +bool VFPtrRecord::remapTypeIndices(ArrayRef IndexMap) { + return remapIndex(IndexMap, Type); +} + +bool BaseClassRecord::remapTypeIndices(ArrayRef IndexMap) { + return remapIndex(IndexMap, Type); +} + +bool VirtualBaseClassRecord::remapTypeIndices(ArrayRef IndexMap) { + bool Success = true; + Success &= remapIndex(IndexMap, BaseType); + Success &= remapIndex(IndexMap, VBPtrType); + return Success; +} Index: llvm/trunk/lib/DebugInfo/CodeView/TypeRecordBuilder.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/CodeView/TypeRecordBuilder.cpp +++ llvm/trunk/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 @@ writeUInt8(0); } +void TypeRecordBuilder::writeGuid(StringRef Guid) { + assert(Guid.size() == 16); + Stream.write(Guid.data(), 16); +} + void TypeRecordBuilder::writeTypeIndex(TypeIndex TypeInd) { writeUInt32(TypeInd.getIndex()); } Index: llvm/trunk/lib/DebugInfo/CodeView/TypeStreamMerger.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/CodeView/TypeStreamMerger.cpp +++ llvm/trunk/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 { +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 RecordData); + void visitTypeEnd(TypeLeafKind Leaf, ArrayRef RecordData); + + void visitFieldList(TypeLeafKind Leaf, ArrayRef FieldData); + + bool mergeStream(ArrayRef 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 IndexMap; +}; + +} // end anonymous namespace + +void TypeStreamMerger::visitTypeBegin(TypeLeafKind Leaf, + ArrayRef RecordData) { + BeginIndexMapSize = IndexMap.size(); +} + +void TypeStreamMerger::visitTypeEnd(TypeLeafKind Leaf, + ArrayRef RecordData) { + assert(IndexMap.size() == BeginIndexMapSize + 1); +} + +void TypeStreamMerger::visitFieldList(TypeLeafKind Leaf, + ArrayRef 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 SrcStream) { + assert(IndexMap.empty()); + visitTypeStream(SrcStream); + IndexMap.clear(); + return !hadError(); +} + +bool llvm::codeview::mergeTypeStreams(TypeTableBuilder &DestStream, + ArrayRef SrcStream) { + return TypeStreamMerger(DestStream).mergeStream(SrcStream); +} Index: llvm/trunk/lib/DebugInfo/CodeView/TypeTableBuilder.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/CodeView/TypeTableBuilder.cpp +++ llvm/trunk/lib/DebugInfo/CodeView/TypeTableBuilder.cpp @@ -128,6 +128,23 @@ return writeRecord(Builder); } +TypeIndex TypeTableBuilder::writeUnion(const UnionRecord &Record) { + TypeRecordBuilder Builder(TypeRecordKind::Union); + Builder.writeUInt16(Record.getMemberCount()); + uint16_t Flags = + static_cast(Record.getOptions()) | + (static_cast(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 @@ 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 @@ 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(Method.getAccess()); + Flags |= static_cast(Method.getKind()) + << MemberAttributes::MethodKindShift; + Flags |= static_cast(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); } Index: llvm/trunk/test/tools/llvm-readobj/codeview-merging.test =================================================================== --- llvm/trunk/test/tools/llvm-readobj/codeview-merging.test +++ llvm/trunk/test/tools/llvm-readobj/codeview-merging.test @@ -0,0 +1,65 @@ +# To regenerate t1.obj and t2.obj, run the following: +# $ cat t.cpp +# #ifdef CONFIG1 +# struct A; +# struct B { +# A *a; +# }; +# int f(A *a); +# int g(B *b) { return f(b->a); } +# #else +# struct B; +# struct A { +# B *b; +# }; +# int g(B *b); +# int f(A *a) { return g(a->b); } +# #endif +# $ cl -c -DCONFIG1 -Z7 t.cpp -Fot1.obj && cl -c -Z7 t.cpp -Fot2.obj + +RUN: llvm-readobj -codeview %S/Inputs/codeview-merging-1.obj | FileCheck %s --check-prefix=OBJ1 +RUN: llvm-readobj -codeview %S/Inputs/codeview-merging-2.obj | FileCheck %s --check-prefix=OBJ2 +RUN: llvm-readobj -codeview-merged-types %S/Inputs/codeview-merging-1.obj %S/Inputs/codeview-merging-2.obj | FileCheck %s + +OBJ1: FuncId (0x100D) { +OBJ1-NEXT: TypeLeafKind: LF_FUNC_ID (0x1601) +OBJ1-NEXT: ParentScope: 0x0 +OBJ1-NEXT: FunctionType: int (B*) (0x100C) +OBJ1-NEXT: Name: g +OBJ1-NEXT: } +OBJ1-NEXT: FuncId (0x100E) { +OBJ1-NEXT: TypeLeafKind: LF_FUNC_ID (0x1601) +OBJ1-NEXT: ParentScope: 0x0 +OBJ1-NEXT: FunctionType: int (A*) (0x1003) +OBJ1-NEXT: Name: f +OBJ1-NEXT: } +OBJ1-NOT: FuncId + +OBJ2: FuncId (0x100D) { +OBJ2-NEXT: TypeLeafKind: LF_FUNC_ID (0x1601) +OBJ2-NEXT: ParentScope: 0x0 +OBJ2-NEXT: FunctionType: int (A*) (0x100C) +OBJ2-NEXT: Name: f +OBJ2-NEXT: } + +OBJ2: FuncId (0x1069) { +OBJ2-NEXT: TypeLeafKind: LF_FUNC_ID (0x1601) +OBJ2-NEXT: ParentScope: 0x0 +OBJ2-NEXT: FunctionType: int (B*) (0x1003) +OBJ2-NEXT: Name: g +OBJ2-NEXT: } +OBJ2-NOT: FuncId + +CHECK: FuncId (0x100D) { +CHECK-NEXT: TypeLeafKind: LF_FUNC_ID (0x1601) +CHECK-NEXT: ParentScope: 0x0 +CHECK-NEXT: FunctionType: int (B*) (0x100C) +CHECK-NEXT: Name: g +CHECK-NEXT: } +CHECK-NEXT: FuncId (0x100E) { +CHECK-NEXT: TypeLeafKind: LF_FUNC_ID (0x1601) +CHECK-NEXT: ParentScope: 0x0 +CHECK-NEXT: FunctionType: int (A*) (0x1003) +CHECK-NEXT: Name: f +CHECK-NEXT: } +CHECK-NOT: FuncId Index: llvm/trunk/tools/llvm-readobj/CMakeLists.txt =================================================================== --- llvm/trunk/tools/llvm-readobj/CMakeLists.txt +++ llvm/trunk/tools/llvm-readobj/CMakeLists.txt @@ -2,6 +2,7 @@ DebugInfoCodeView Object Support + DebugInfoCodeView ) add_llvm_tool(llvm-readobj Index: llvm/trunk/tools/llvm-readobj/COFFDumper.cpp =================================================================== --- llvm/trunk/tools/llvm-readobj/COFFDumper.cpp +++ llvm/trunk/tools/llvm-readobj/COFFDumper.cpp @@ -25,11 +25,13 @@ #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/CodeView/Line.h" #include "llvm/DebugInfo/CodeView/RecordSerialization.h" +#include "llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h" #include "llvm/DebugInfo/CodeView/TypeDumper.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/CodeView/TypeStream.h" +#include "llvm/DebugInfo/CodeView/TypeStreamMerger.h" #include "llvm/Object/COFF.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/COFF.h" @@ -71,6 +73,8 @@ void printCOFFDirectives() override; void printCOFFBaseReloc() override; void printCodeViewDebugInfo() override; + void + mergeCodeViewTypes(llvm::codeview::MemoryTypeTableBuilder &CVTypes) override; void printStackMap() const override; private: void printSymbol(const SymbolRef &Sym); @@ -1621,6 +1625,25 @@ W.printHex(Label, getFileNameForFileOffset(FileOffset), FileOffset); } +void COFFDumper::mergeCodeViewTypes(MemoryTypeTableBuilder &CVTypes) { + for (const SectionRef &S : Obj->sections()) { + StringRef SectionName; + error(S.getName(SectionName)); + if (SectionName == ".debug$T") { + StringRef Data; + error(S.getContents(Data)); + unsigned Magic = *reinterpret_cast(Data.data()); + if (Magic != 4) + error(object_error::parse_failed); + Data = Data.drop_front(4); + ArrayRef Bytes(reinterpret_cast(Data.data()), + Data.size()); + if (!mergeTypeStreams(CVTypes, Bytes)) + return error(object_error::parse_failed); + } + } +} + void COFFDumper::printCodeViewTypeSection(StringRef SectionName, const SectionRef &Section) { ListScope D(W, "CodeViewTypes"); @@ -2076,3 +2099,23 @@ prettyPrintStackMap(llvm::outs(), StackMapV1Parser(StackMapContentsArray)); } + +void llvm::dumpCodeViewMergedTypes( + ScopedPrinter &Writer, llvm::codeview::MemoryTypeTableBuilder &CVTypes) { + // Flatten it first, then run our dumper on it. + ListScope S(Writer, "MergedTypeStream"); + SmallString<0> Buf; + CVTypes.ForEachRecord([&](TypeIndex TI, MemoryTypeTableBuilder::Record *R) { + // The record data doesn't include the 16 bit size. + Buf.push_back(R->size() & 0xff); + Buf.push_back((R->size() >> 8) & 0xff); + Buf.append(R->data(), R->data() + R->size()); + }); + CVTypeDumper CVTD(Writer, opts::CodeViewSubsectionBytes); + ArrayRef BinaryData(reinterpret_cast(Buf.data()), + Buf.size()); + if (!CVTD.dump(BinaryData)) { + Writer.flush(); + error(object_error::parse_failed); + } +} Index: llvm/trunk/tools/llvm-readobj/ObjDumper.h =================================================================== --- llvm/trunk/tools/llvm-readobj/ObjDumper.h +++ llvm/trunk/tools/llvm-readobj/ObjDumper.h @@ -18,6 +18,9 @@ class COFFImportFile; class ObjectFile; } +namespace codeview { +class MemoryTypeTableBuilder; +}; class ScopedPrinter; @@ -60,6 +63,8 @@ virtual void printCOFFDirectives() { } virtual void printCOFFBaseReloc() { } virtual void printCodeViewDebugInfo() { } + virtual void + mergeCodeViewTypes(llvm::codeview::MemoryTypeTableBuilder &CVTypes) {} // Only implemented for MachO. virtual void printMachODataInCode() { } @@ -89,6 +94,9 @@ void dumpCOFFImportFile(const object::COFFImportFile *File); +void dumpCodeViewMergedTypes(ScopedPrinter &Writer, + llvm::codeview::MemoryTypeTableBuilder &CVTypes); + } // namespace llvm #endif Index: llvm/trunk/tools/llvm-readobj/llvm-readobj.cpp =================================================================== --- llvm/trunk/tools/llvm-readobj/llvm-readobj.cpp +++ llvm/trunk/tools/llvm-readobj/llvm-readobj.cpp @@ -22,6 +22,7 @@ #include "llvm-readobj.h" #include "Error.h" #include "ObjDumper.h" +#include "llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h" #include "llvm/Object/Archive.h" #include "llvm/Object/COFFImportFile.h" #include "llvm/Object/ELFObjectFile.h" @@ -144,6 +145,11 @@ cl::opt CodeView("codeview", cl::desc("Display CodeView debug information")); + // -codeview-merged-types + cl::opt + CodeViewMergedTypes("codeview-merged-types", + cl::desc("Display the merged CodeView type stream")); + // -codeview-subsection-bytes cl::opt CodeViewSubsectionBytes( "codeview-subsection-bytes", @@ -296,6 +302,8 @@ } } +static llvm::codeview::MemoryTypeTableBuilder CVTypes; + /// @brief Creates an format-specific object file dumper. static std::error_code createDumper(const ObjectFile *Obj, ScopedPrinter &Writer, @@ -386,6 +394,8 @@ Dumper->printCOFFBaseReloc(); if (opts::CodeView) Dumper->printCodeViewDebugInfo(); + if (opts::CodeViewMergedTypes) + Dumper->mergeCodeViewTypes(CVTypes); } if (Obj->isMachO()) { if (opts::MachODataInCode) @@ -478,5 +488,10 @@ std::for_each(opts::InputFilenames.begin(), opts::InputFilenames.end(), dumpInput); + if (opts::CodeViewMergedTypes) { + ScopedPrinter W(outs()); + dumpCodeViewMergedTypes(W, CVTypes); + } + return 0; }