Index: include/llvm/DebugInfo/CodeView/TypeRecord.h =================================================================== --- include/llvm/DebugInfo/CodeView/TypeRecord.h +++ include/llvm/DebugInfo/CodeView/TypeRecord.h @@ -1359,9 +1359,10 @@ // LF_VBCLASS, LF_IVBCLASS class VirtualBaseClassRecord : public TypeRecord { public: - VirtualBaseClassRecord(MemberAccess Access, TypeIndex BaseType, + VirtualBaseClassRecord(bool Indirect, MemberAccess Access, TypeIndex BaseType, TypeIndex VBPtrType, uint64_t Offset, uint64_t Index) - : TypeRecord(TypeRecordKind::VirtualBaseClass), Access(Access), + : TypeRecord(Indirect ? TypeRecordKind::IndirectVirtualBaseClass + : TypeRecordKind::VirtualBaseClass), Access(Access), BaseType(BaseType), VBPtrType(VBPtrType), VBPtrOffset(Offset), VTableIndex(Index) {} @@ -1371,12 +1372,13 @@ static ErrorOr deserialize(TypeRecordKind Kind, ArrayRef &Data) { + bool Indirect = Kind == TypeRecordKind::IndirectVirtualBaseClass; const Layout *L = nullptr; uint64_t Offset; uint64_t Index; CV_DESERIALIZE(Data, L, CV_NUMERIC_FIELD(Offset), CV_NUMERIC_FIELD(Index)); - return VirtualBaseClassRecord(L->Attrs.getAccess(), L->BaseType, + return VirtualBaseClassRecord(Indirect, L->Attrs.getAccess(), L->BaseType, L->VBPtrType, Offset, Index); } Index: lib/CodeGen/AsmPrinter/CodeViewDebug.h =================================================================== --- lib/CodeGen/AsmPrinter/CodeViewDebug.h +++ lib/CodeGen/AsmPrinter/CodeViewDebug.h @@ -31,6 +31,7 @@ class StringRef; class LexicalScope; +struct ClassInfo; /// \brief Collects and handles line tables information in a CodeView format. class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase { @@ -117,6 +118,9 @@ /// to be confused with type indices for LF_FUNC_ID records. unsigned NextFuncId = 0; + /// Holds virtual base pointer type for compiler module. + codeview::TypeIndex VBPType; + InlineSite &getInlineSite(const DILocation *InlinedAt, const DISubprogram *Inlinee); @@ -138,12 +142,20 @@ /// Map from DI metadata nodes to CodeView type indices. Primarily indexed by /// DIType* and DISubprogram*. - DenseMap TypeIndices; + typedef DenseMap TypeIndicesMap; + /// Map from record type metadata nodes to TypeIndicesMap. Primarily indexed + /// by DIType*. + /// This is needed for methods as DISubroutineType representing static method + /// type are shared with non-method function type. + DenseMap TypeIndicesPerScope; /// Map from DICompositeType* to complete type index. Non-record types are /// always looked up in the normal TypeIndices map. DenseMap CompleteTypeIndices; + /// Map from DICompositeType* to class info. + DenseMap> ClassInfoMap; + typedef std::map FileToFilepathMapTy; FileToFilepathMapTy FileToFilepathMap; StringRef getFullFilepath(const DIFile *S); @@ -157,6 +169,10 @@ FileIdMap.clear(); FnDebugInfo.clear(); FileToFilepathMap.clear(); + TypeIndicesPerScope.clear(); + CompleteTypeIndices.clear(); + ClassInfoMap.clear(); + VBPType = codeview::TypeIndex(); } /// Emit the magic version number at the start of a CodeView type or symbol @@ -184,6 +200,9 @@ void emitLocalVariable(const LocalVariable &Var); + /// Return virtual base pointer type. Create it if it was not created yet. + codeview::TypeIndex getVBPType(); + /// Translates the DIType to codeview if necessary and returns a type index /// for it. codeview::TypeIndex getTypeIndex(DITypeRef TypeRef); @@ -195,6 +214,8 @@ codeview::TypeIndex lowerTypeMemberPointer(const DIDerivedType *Ty); codeview::TypeIndex lowerTypeModifier(const DIDerivedType *Ty); codeview::TypeIndex lowerTypeFunction(const DISubroutineType *Ty); + codeview::TypeIndex lowerTypeMemberFunction(const DISubroutineType *Ty, + const DIType *ClassTy); codeview::TypeIndex lowerTypeClass(const DICompositeType *Ty); codeview::TypeIndex lowerTypeUnion(const DICompositeType *Ty); @@ -208,14 +229,30 @@ codeview::TypeIndex lowerCompleteTypeClass(const DICompositeType *Ty); codeview::TypeIndex lowerCompleteTypeUnion(const DICompositeType *Ty); + codeview::TypeIndex lowerSubprogramType(const DISubprogram *SP); + + void collectClassInfoFromInheritance(ClassInfo &Info, + const DIDerivedType *InherTy, + bool &FinalizedOffset); + void collectMemberInfo(ClassInfo &Info, const DIDerivedType *DDTy); + ClassInfo &collectClassInfo(const DICompositeType *Ty); + /// Common record member lowering functionality for record types, which are /// structs, classes, and unions. Returns the field list index and the member /// count. - std::pair + std::tuple lowerRecordFieldList(const DICompositeType *Ty); - /// Inserts {Node, TI} into TypeIndices and checks for duplicates. - void recordTypeIndexForDINode(const DINode *Node, codeview::TypeIndex TI); + /// Inserts {Node, TI} into TypeIndicesPerScope[ClassTy], and checks for + /// duplicates. + void recordTypeIndexForDINode(const DINode *Node, codeview::TypeIndex TI, + const DIType *ClassTy = nullptr); + + TypeIndicesMap &getTypeIndices(const DIType *ClassTy = nullptr) { + return TypeIndicesPerScope[ClassTy]; + } + + unsigned getPointerSizeInBits(); public: CodeViewDebug(AsmPrinter *Asm); Index: lib/CodeGen/AsmPrinter/CodeViewDebug.cpp =================================================================== --- lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -24,9 +24,9 @@ #include "llvm/MC/MCSymbol.h" #include "llvm/Support/COFF.h" #include "llvm/Support/ScopedPrinter.h" -#include "llvm/Target/TargetSubtargetInfo.h" -#include "llvm/Target/TargetRegisterInfo.h" #include "llvm/Target/TargetFrameLowering.h" +#include "llvm/Target/TargetRegisterInfo.h" +#include "llvm/Target/TargetSubtargetInfo.h" using namespace llvm; using namespace llvm::codeview; @@ -130,25 +130,30 @@ return TypeIndex::None(); // Check if we've already translated this subprogram. - auto I = TypeIndices.find(SP); - if (I != TypeIndices.end()) + auto I = getTypeIndices().find(SP); + if (I != getTypeIndices().end()) return I->second; TypeIndex ParentScope = TypeIndex(0); StringRef DisplayName = SP->getDisplayName(); - FuncIdRecord FuncId(ParentScope, getTypeIndex(SP->getType()), DisplayName); + FuncIdRecord FuncId(ParentScope, lowerSubprogramType(SP), DisplayName); TypeIndex TI = TypeTable.writeFuncId(FuncId); recordTypeIndexForDINode(SP, TI); return TI; } -void CodeViewDebug::recordTypeIndexForDINode(const DINode *Node, TypeIndex TI) { - auto InsertResult = TypeIndices.insert({Node, TI}); +void CodeViewDebug::recordTypeIndexForDINode(const DINode *Node, TypeIndex TI, + const DIType *ClassTy) { + auto InsertResult = getTypeIndices(ClassTy).insert({Node, TI}); (void)InsertResult; assert(InsertResult.second && "DINode was already assigned a type index"); } +unsigned CodeViewDebug::getPointerSizeInBits() { + return MMI->getModule()->getDataLayout().getPointerSizeInBits(); +} + void CodeViewDebug::recordLocalVariable(LocalVariable &&Var, const DILocation *InlinedAt) { if (InlinedAt) { @@ -280,8 +285,7 @@ void CodeViewDebug::emitTypeInformation() { // Do nothing if we have no debug info or if no non-trivial types were emitted // to TypeTable during codegen. - NamedMDNode *CU_Nodes = - MMI->getModule()->getNamedMetadata("llvm.dbg.cu"); + NamedMDNode *CU_Nodes = MMI->getModule()->getNamedMetadata("llvm.dbg.cu"); if (!CU_Nodes) return; if (TypeTable.empty()) @@ -344,8 +348,8 @@ OS.EmitIntValue(unsigned(InlineeLinesSignature::Normal), 4); for (const DISubprogram *SP : InlinedSubprograms) { - assert(TypeIndices.count(SP)); - TypeIndex InlineeIdx = TypeIndices[SP]; + assert(getTypeIndices().count(SP)); + TypeIndex InlineeIdx = getTypeIndices()[SP]; OS.AddBlankLine(); unsigned FileId = maybeRecordFile(SP->getFile()); @@ -383,8 +387,8 @@ MCSymbol *InlineBegin = MMI->getContext().createTempSymbol(), *InlineEnd = MMI->getContext().createTempSymbol(); - assert(TypeIndices.count(Site.Inlinee)); - TypeIndex InlineeIdx = TypeIndices[Site.Inlinee]; + assert(getTypeIndices().count(Site.Inlinee)); + TypeIndex InlineeIdx = getTypeIndices()[Site.Inlinee]; // SymbolRecord OS.AddComment("Record length"); @@ -869,6 +873,14 @@ TypeIndex CodeViewDebug::lowerTypePointer(const DIDerivedType *Ty) { TypeIndex PointeeTI = getTypeIndex(Ty->getBaseType()); + // While processing the type being pointed to it is possible we already + // created this pointer type. If so, we check here and return the existing + // pointer type. + // + auto I = getTypeIndices().find(Ty); + if (I != getTypeIndices().end()) + return I->second; + // Pointers to simple types can use SimpleTypeMode, rather than having a // dedicated pointer type record. if (PointeeTI.isSimple() && @@ -906,12 +918,19 @@ TypeIndex CodeViewDebug::lowerTypeMemberPointer(const DIDerivedType *Ty) { assert(Ty->getTag() == dwarf::DW_TAG_ptr_to_member_type); TypeIndex ClassTI = getTypeIndex(Ty->getClassType()); - TypeIndex PointeeTI = getTypeIndex(Ty->getBaseType()); + DIType *BaseType = Ty->getBaseType().resolve(); PointerKind PK = Asm->MAI->getPointerSize() == 8 ? PointerKind::Near64 : PointerKind::Near32; - PointerMode PM = isa(Ty->getBaseType()) - ? PointerMode::PointerToMemberFunction - : PointerMode::PointerToDataMember; + TypeIndex PointeeTI; + PointerMode PM; + if (auto STy = dyn_cast_or_null(BaseType)) { + PointeeTI = lowerTypeMemberFunction(STy, Ty->getClassType().resolve()); + PM = PointerMode::PointerToMemberFunction; + } else { + PointeeTI = getTypeIndex(Ty->getBaseType()); + PM = PointerMode::PointerToDataMember; + } + PointerOptions PO = PointerOptions::None; // FIXME // FIXME: Thread this ABI info through metadata. PointerToMemberRepresentation PMR = PointerToMemberRepresentation::Unknown; @@ -941,6 +960,15 @@ BaseTy = cast(BaseTy)->getBaseType().resolve(); } TypeIndex ModifiedTI = getTypeIndex(BaseTy); + + // While processing the type being pointed to, it is possible we already + // created this modifier type. If so, we check here and return the existing + // modifier type. + // + auto I = getTypeIndices().find(Ty); + if (I != getTypeIndices().end()) + return I->second; + ModifierRecord MR(ModifiedTI, Mods); return TypeTable.writeModifier(MR); } @@ -963,14 +991,69 @@ // TODO: We should use DW_AT_calling_convention to determine what CC this // procedure record should have. - // TODO: Some functions are member functions, we should use a more appropriate - // record for those. ProcedureRecord Procedure(ReturnTypeIndex, CallingConvention::NearC, FunctionOptions::None, ArgTypeIndices.size(), ArgListIndex); return TypeTable.writeProcedure(Procedure); } +TypeIndex CodeViewDebug::lowerTypeMemberFunction(const DISubroutineType *Ty, + const DIType *ClassTy) { + // Lower the containing class type. + // + TypeIndex ClassType = getTypeIndex(ClassTy); + + // Check to see if a matching member function type exists for this class. + // + auto I = getTypeIndices(ClassTy).find(Ty); + if (I != getTypeIndices(ClassTy).end()) + return I->second; + + SmallVector ReturnAndArgTypeIndices; + for (DITypeRef ArgTypeRef : Ty->getTypeArray()) + ReturnAndArgTypeIndices.push_back(getTypeIndex(ArgTypeRef)); + + TypeIndex ReturnTypeIndex = TypeIndex::Void(); + ArrayRef ArgTypeIndices = None; + if (!ReturnAndArgTypeIndices.empty()) { + auto ReturnAndArgTypesRef = makeArrayRef(ReturnAndArgTypeIndices); + ReturnTypeIndex = ReturnAndArgTypesRef.front(); + ArgTypeIndices = ReturnAndArgTypesRef.drop_front(); + } + TypeIndex ThisTypeIndex = TypeIndex::Void(); + if (!ArgTypeIndices.empty()) { + ThisTypeIndex = ArgTypeIndices.front(); + ArgTypeIndices = ArgTypeIndices.drop_front(); + } + + ArgListRecord ArgListRec(TypeRecordKind::ArgList, ArgTypeIndices); + TypeIndex ArgListIndex = TypeTable.writeArgList(ArgListRec); + + // TODO: We should use DW_AT_calling_convention to determine what CC this + // procedure record should have. + // TODO: Need to use the correct values for: + // CallingConvention + // FunctionOptions + // ThisPointerAdjustment. + TypeIndex TI = TypeTable.writeMemberFunction(MemberFunctionRecord( + ReturnTypeIndex, ClassType, ThisTypeIndex, CallingConvention::ThisCall, + FunctionOptions::None, ArgTypeIndices.size(), ArgListIndex, 0)); + + recordTypeIndexForDINode(Ty, TI, ClassTy); + return TI; +} + +TypeIndex CodeViewDebug::lowerSubprogramType(const DISubprogram *SP) { + TypeIndex TI; + + if (auto ClassType = dyn_cast_or_null(SP->getScope().resolve())) + TI = lowerTypeMemberFunction(SP->getType(), ClassType); + else + TI = lowerType(SP->getType()); // Indirectly calls lowerTypeSubroutine(). + + return TI; +} + static MemberAccess translateAccessFlags(unsigned RecordTag, const DIType *Member) { switch (Member->getFlags() & DINode::FlagAccessibility) { @@ -985,6 +1068,49 @@ llvm_unreachable("access flags are exclusive"); } +static MemberAccess translateMethodAccessFlags(unsigned RecordTag, + const DISubprogram *SP) { + switch (SP->getFlags() & DINode::FlagAccessibility) { + case DINode::FlagPrivate: return MemberAccess::Private; + case DINode::FlagPublic: return MemberAccess::Public; + case DINode::FlagProtected: return MemberAccess::Protected; + case 0: + // If there was no explicit access control, provide the default for the tag. + return RecordTag == dwarf::DW_TAG_class_type ? MemberAccess::Private + : MemberAccess::Public; + } + llvm_unreachable("access flags are exclusive"); +} + +static MethodOptions translateMethodOptionFlags(const DISubprogram *SP) { + if (SP->isArtificial()) + return MethodOptions::CompilerGenerated; + + // FIXME: Handle other MethodOptions. + + return MethodOptions::None; +} + +static MethodKind translateMethodKindFlags(const DISubprogram *SP, + bool Introduced) { + switch (SP->getVirtuality()) { + case dwarf::DW_VIRTUALITY_none: + break; + case dwarf::DW_VIRTUALITY_virtual: + return Introduced ? MethodKind::IntroducingVirtual : MethodKind::Virtual; + case dwarf::DW_VIRTUALITY_pure_virtual: + return Introduced ? MethodKind::PureIntroducingVirtual + : MethodKind::PureVirtual; + default: + llvm_unreachable("unhandled virtuality case"); + } + + // if (isStaticMethod(SP->getLinkageName())) + // return MethodKind::Static; + + return MethodKind::Vanilla; +} + static TypeRecordKind getRecordKind(const DICompositeType *Ty) { switch (Ty->getTag()) { case dwarf::DW_TAG_class_type: return TypeRecordKind::Class; @@ -1003,6 +1129,294 @@ : ClassOptions::None; } +//===----------------------------------------------------------------------===// +// ClassInfo +//===----------------------------------------------------------------------===// + +struct llvm::ClassInfo { + typedef std::vector BaseClassList; + struct VirtualBaseClassInfo { + const DIDerivedType *InheritanceNode; + unsigned VBIndex; + bool Indirect; + + VirtualBaseClassInfo() + : InheritanceNode(nullptr), VBIndex(0), Indirect(false) {} + + VirtualBaseClassInfo(const DIDerivedType *N, unsigned I, bool InDir) + : InheritanceNode(N), VBIndex(I), Indirect(InDir) {} + }; + // ClassTypeNode -> {InheritanceNode, VBIndex, Indirect} + typedef MapVector + VirtualBaseClassInfoList; + // [] + typedef std::vector> MemberList; + // methodName -> [] + typedef std::map>> + MethodsMap; + // methodName -> [DISubroutineType] + typedef std::map> + VirtualMethodsMap; + + // Non-virtual base classes + BaseClassList BaseClasses; + // Virtual base classes (direct and indirect). + VirtualBaseClassInfoList VBClasses; + // Offset of virtual base pointer + int VBPOffset = ~0; + // Virtual function table (only if have introduced virtual methods) + const MDNode *VirtualFuncTab = nullptr; + // Direct members + MemberList Members; + // Direct methods (gathered by name), for each function: (introduced?) + MethodsMap Methods; + // Virtual methods (gathered by name), for DTOR use "~" name. + VirtualMethodsMap VirtualMethods; + // FIXME: add support to: CONSTRUCTOR, OVERLOAD, OVERLOADED ASSIGNMENT, etc. + // Class has Constructor + bool HasCTOR = false; + // Class has Destructor + bool HasDTOR = false; + // This class is nested within another aggregate type. + bool IsNested = false; + // Number of virtual methods (length of virtual function table) + unsigned VirtualMethodsCount = 0; +}; + +static bool isEqualVMethodPrototype(const DISubroutineType *Ty1, + const DISubroutineType *Ty2) { + DITypeRefArray Elements1 = Ty1->getTypeArray(); + DITypeRefArray Elements2 = Ty2->getTypeArray(); + + if (Elements1.size() != Elements2.size()) + return false; + + assert(Elements1.size() >= 2 && "non-trevial method"); + + for (unsigned i = 2, N = Elements1.size(); i < N; ++i) + if (Elements1[i].resolve() != Elements2[i].resolve()) + return false; + + return true; +} + +void CodeViewDebug::collectClassInfoFromInheritance( + ClassInfo &Info, const DIDerivedType *InherTy, bool &FinalizedOffset) { + bool IsVirtual = InherTy->isVirtual(); + + const DIType *BaseTy = InherTy->getBaseType().resolve(); + + // Base type of inheritance entry might be a typedef entry. + // Skip all typedef entries to get to the class entry. + while (!isa(BaseTy)) { + assert(isa(BaseTy) && + "Base type expected to be derived type"); + const DIDerivedType *DTy = cast(BaseTy); + assert(DTy->getTag() == dwarf::DW_TAG_typedef); + BaseTy = DTy->getBaseType().resolve(); + } + const DICompositeType *DDTy = dyn_cast(BaseTy); + ClassInfo &InherInfo = collectClassInfo(DDTy); + + for (auto &I : InherInfo.VBClasses) + if (!Info.VBClasses.count(I.first)) + Info.VBClasses[I.first] = ClassInfo::VirtualBaseClassInfo( + I.second.InheritanceNode, Info.VBClasses.size() + 1, true); + + if (IsVirtual) { + auto VBClass = Info.VBClasses.find(DDTy); + if (VBClass != Info.VBClasses.end()) + VBClass->second.Indirect = false; + else + Info.VBClasses[DDTy] = ClassInfo::VirtualBaseClassInfo( + InherTy, Info.VBClasses.size() + 1, false); + } else { + if (!FinalizedOffset) { + if (InherInfo.VBClasses.size()) { + FinalizedOffset = true; + Info.VBPOffset = + (InherTy->getOffsetInBits() >> 3) + InherInfo.VBPOffset; + Info.VirtualMethodsCount = InherInfo.VirtualMethodsCount; + } else { + Info.VBPOffset = + (InherTy->getOffsetInBits() + DDTy->getSizeInBits()) >> 3; + } + } + Info.BaseClasses.push_back(InherTy); + } + + // Append "InherInfo.VirtualMethods" to "Info.VirtualMethods" + for (auto &I : InherInfo.VirtualMethods) { + StringRef MethodName = I.first; + auto &VirtualMethodsDst = Info.VirtualMethods[MethodName]; + + for (auto *SPTy : I.second) { + bool found = false; + for (auto &VMTy : VirtualMethodsDst) + if (isEqualVMethodPrototype(VMTy, SPTy)) { + // virtual method is not introduced. + found = true; + break; + } + if (!found) { + VirtualMethodsDst.push_back(SPTy); + } + } + } +} + +void CodeViewDebug::collectMemberInfo(ClassInfo &Info, + const DIDerivedType *DDTy) { + if (!DDTy->getName().empty()) { + Info.Members.push_back(std::make_pair(DDTy, 0)); + return; + } + // Member with no name, must be nested structure/union, collects its memebers + assert((DDTy->getOffsetInBits() % 8) == 0 && "Unnamed bitfield member!"); + unsigned offset = DDTy->getOffsetInBits() >> 3; + const DIType *Ty = DDTy->getBaseType().resolve(); + assert(dyn_cast(Ty) && "Expects structure or union type"); + const DICompositeType *DCTy = dyn_cast(Ty); + ClassInfo &NestedInfo = collectClassInfo(DCTy); + ClassInfo::MemberList &Members = NestedInfo.Members; + for (unsigned i = 0, e = Members.size(); i != e; ++i) + Info.Members.push_back( + std::make_pair(Members[i].first, Members[i].second + offset)); + + // TODO: do we need to create the type of the unnamed member? + //(void)lowerType(Ty); +} + +//===----------------------------------------------------------------------===// +// stripScopesFromName(name) +// +// Subprogram names used to contain only the name, now they are fully +// qualified. We need to strip off the qualification to get the bare name. +// +// FIXME: The names should be fixed in CLANG and then this can be removed. +// +//===----------------------------------------------------------------------===// + +static StringRef stripScopesFromName(StringRef name) { + StringRef::size_type pos; + unsigned int template_level; + + if (name.empty()) + return name; + + for (pos = name.size() - 1, template_level = 0; pos > 1; --pos) { + switch (name[pos]) { + case '>': + template_level++; + break; + case '<': + if (template_level > 0) + template_level--; + break; + case ':': + if (template_level == 0 && name[pos - 1] == ':') + return name.substr(pos + 1); + break; + default: + break; + } + } + + return name; +} + +ClassInfo &CodeViewDebug::collectClassInfo(const DICompositeType *Ty) { + auto I = ClassInfoMap.find(Ty); + if (I != ClassInfoMap.end()) { + return *I->second; + } + + ClassInfoMap.insert( + std::make_pair(Ty, std::unique_ptr(new ClassInfo()))); + ClassInfo &Info = *(ClassInfoMap.find(Ty)->second); + + std::string ConstructorName = Ty->getName(); + std::string DestructorName = (Twine("~") + Twine(Ty->getName())).str(); + std::string VirtualTableName = (Twine("_vptr$") + Twine(Ty->getName())).str(); + + bool FinalizedOffset = false; + + // Add elements to structure type. + DINodeArray Elements = Ty->getElements(); + for (auto *Element : Elements) { + if (auto *SP = dyn_cast(Element)) { + StringRef MethodName = stripScopesFromName(SP->getName()); + Info.Methods[MethodName].push_back(std::make_pair(SP, true)); + + if (MethodName == ConstructorName) + Info.HasCTOR = true; + if (MethodName == DestructorName) + Info.HasDTOR = true; + + } else if (auto *DDTy = dyn_cast(Element)) { + if (DDTy->getTag() == dwarf::DW_TAG_member) + collectMemberInfo(Info, DDTy); + else if (DDTy->getTag() == dwarf::DW_TAG_inheritance) + collectClassInfoFromInheritance(Info, DDTy, FinalizedOffset); + else if (DDTy->getTag() == dwarf::DW_TAG_friend) { + // Ignore friend members. It appears that MSVC emitted info about + // friends in the past, but modern versions do not. + } else if (DDTy->getName() == VirtualTableName) { + assert(!Info.VirtualFuncTab && + "Class has more than one virtual table."); + Info.VirtualFuncTab = DDTy; + } + // FIXME: Get clang to emit nested types here and do something with + // them. + } + // Skip other unrecognized kinds of elements. + } + bool HasVirtualFuncTab = false; + for (auto &I : Info.Methods) { + StringRef MethodName = I.first; + if (MethodName == DestructorName) + MethodName = "~"; + + auto &VirtualMethods = Info.VirtualMethods[MethodName]; + for (auto &MethodInfo : I.second) { + auto *SP = MethodInfo.first; + + if (SP->getVirtuality() == dwarf::DW_VIRTUALITY_none) + // Non-virtual method, nothing to update. Just skip it. + continue; + + for (auto &VMTy : VirtualMethods) + if (isEqualVMethodPrototype(VMTy, SP->getType())) + // Virtual method is not introduced. + MethodInfo.second = false; + + if (MethodInfo.second) { + // An introduced virtual function, update counter and add to + // VirtualMethods. + Info.VirtualMethodsCount++; + VirtualMethods.push_back(SP->getType()); + HasVirtualFuncTab = true; + } + } + } + + if (!HasVirtualFuncTab) + Info.VirtualFuncTab = nullptr; + + if (Info.VBClasses.size() > 0 && Info.VBPOffset < 0) + // Class has virtual function pointer, add pointer size. + Info.VBPOffset = (Info.VirtualFuncTab) ? getPointerSizeInBits() >> 3 : 0; + + // If this type is contained within another type, then record it as being + // nested. + const DIScope *Scope = Ty->getScope().resolve(); + if (Scope && isa(Scope)) + Info.IsNested = true; + + return Info; +} + TypeIndex CodeViewDebug::lowerTypeClass(const DICompositeType *Ty) { // First, construct the forward decl. Don't look into Ty to compute the // forward decl options, since it might not be available in all TUs. @@ -1021,14 +1435,14 @@ // FIXME: Other ClassOptions, like ContainsNestedClass and NestedClass. ClassOptions CO = ClassOptions::None | getRecordUniqueNameOption(Ty); TypeIndex FTI; + TypeIndex VShapeTI; unsigned FieldCount; - std::tie(FTI, FieldCount) = lowerRecordFieldList(Ty); + std::tie(FTI, VShapeTI, FieldCount) = lowerRecordFieldList(Ty); uint64_t SizeInBytes = Ty->getSizeInBits() / 8; - return TypeTable.writeClass(ClassRecord(Kind, FieldCount, CO, HfaKind::None, - WindowsRTClassKind::None, FTI, - TypeIndex(), TypeIndex(), SizeInBytes, - Ty->getName(), Ty->getIdentifier())); + return TypeTable.writeClass(ClassRecord( + Kind, FieldCount, CO, HfaKind::None, WindowsRTClassKind::None, FTI, + TypeIndex(), VShapeTI, SizeInBytes, Ty->getName(), Ty->getIdentifier())); // FIXME: Make an LF_UDT_SRC_LINE record. } @@ -1044,8 +1458,9 @@ TypeIndex CodeViewDebug::lowerCompleteTypeUnion(const DICompositeType *Ty) { ClassOptions CO = ClassOptions::None | getRecordUniqueNameOption(Ty); TypeIndex FTI; + TypeIndex VShapeTI; // Dummy unsigned FieldCount; - std::tie(FTI, FieldCount) = lowerRecordFieldList(Ty); + std::tie(FTI, VShapeTI, FieldCount) = lowerRecordFieldList(Ty); uint64_t SizeInBytes = Ty->getSizeInBits() / 8; return TypeTable.writeUnion(UnionRecord(FieldCount, CO, HfaKind::None, FTI, SizeInBytes, Ty->getName(), @@ -1053,51 +1468,160 @@ // FIXME: Make an LF_UDT_SRC_LINE record. } -std::pair +/// If this type is derived from a base type then return base type size. +static uint64_t getBaseTypeSize(const DIDerivedType *Ty) { + unsigned Tag = Ty->getTag(); + + if (Tag != dwarf::DW_TAG_member && Tag != dwarf::DW_TAG_typedef && + Tag != dwarf::DW_TAG_const_type && Tag != dwarf::DW_TAG_volatile_type && + Tag != dwarf::DW_TAG_restrict_type) + return Ty->getSizeInBits(); + + DIType *BaseType = Ty->getBaseType().resolve(); + + // If this type is not derived from any type or the type is a declaration then + // take conservative approach. + if (!BaseType || BaseType->isForwardDecl()) + return Ty->getSizeInBits(); + + // If this is a derived type, go ahead and get the base type, unless it's a + // reference then it's just the size of the field. Pointer types have no need + // of this since they're a different type of qualification on the type. + if (BaseType->getTag() == dwarf::DW_TAG_reference_type || + BaseType->getTag() == dwarf::DW_TAG_rvalue_reference_type) + return Ty->getSizeInBits(); + + if (DIDerivedType *DT = dyn_cast(BaseType)) + return getBaseTypeSize(DT); + + return BaseType->getSizeInBits(); +} + +std::tuple CodeViewDebug::lowerRecordFieldList(const DICompositeType *Ty) { - // Manually count members. MSVC appears to count everything that generates a - // field list record. Each individual overload in a method overload group - // contributes to this count, even though the overload group is a single field - // list record. - unsigned MemberCount = 0; + ClassInfo &Info = collectClassInfo(Ty); FieldListRecordBuilder Fields; - for (const DINode *Element : Ty->getElements()) { - // We assume that the frontend provides all members in source declaration - // order, which is what MSVC does. - if (!Element) + TypeIndex VShapeTI; + + // Create base classes + for (auto Inheritance : Info.BaseClasses) + Fields.writeBaseClass( + BaseClassRecord(translateAccessFlags(Ty->getTag(), Inheritance), + getTypeIndex(Inheritance->getBaseType().resolve()), + Inheritance->getOffsetInBits() >> 3)); + + // Create virtual base classes + for (auto &VBInfo : Info.VBClasses) { + auto Inheritance = VBInfo.second.InheritanceNode; + Fields.writeVirtualBaseClass(VirtualBaseClassRecord( + VBInfo.second.Indirect, translateAccessFlags(Ty->getTag(), Inheritance), + getTypeIndex(Inheritance->getBaseType().resolve()), getVBPType(), + Info.VBPOffset, VBInfo.second.VBIndex)); + } + + // Create virtual function table descriptor. + if (Info.VirtualFuncTab) { + std::vector Kinds; + Kinds.assign(Info.VirtualMethodsCount, VFTableSlotKind::Outer); + + VShapeTI = TypeTable.writeVFTableShape(VFTableShapeRecord(Kinds)); + PointerKind PK = getPointerSizeInBits() == 64 ? PointerKind::Near64 + : PointerKind::Near32; + PointerMode PM = PointerMode::Pointer; + PointerOptions PO = PointerOptions::None; + PointerRecord PR(VShapeTI, PK, PM, PO, getPointerSizeInBits() / 8); + TypeIndex PointerTI = TypeTable.writePointer(PR); + + Fields.writeVFPtr(VFPtrRecord(PointerTI)); + } + + // Create members + for (auto &MemberInfo : Info.Members) { + const DIDerivedType *Member = MemberInfo.first; + TypeIndex MemberBaseType = getTypeIndex(Member->getBaseType().resolve()); + + if (Member->isStaticMember()) { + Fields.writeStaticDataMember( + StaticDataMemberRecord(translateAccessFlags(Ty->getTag(), Member), + MemberBaseType, Member->getName())); continue; - if (auto *SP = dyn_cast(Element)) { - // C++ method. - // FIXME: Overloaded methods are grouped together, so we'll need two - // passes to group them. - (void)SP; - } else if (auto *Member = dyn_cast(Element)) { - if (Member->getTag() == dwarf::DW_TAG_member) { - if (Member->isStaticMember()) { - // Static data member. - Fields.writeStaticDataMember(StaticDataMemberRecord( - translateAccessFlags(Ty->getTag(), Member), - getTypeIndex(Member->getBaseType()), Member->getName())); - MemberCount++; - } else { - // Data member. - // FIXME: Make a BitFieldRecord for bitfields. - Fields.writeDataMember(DataMemberRecord( - translateAccessFlags(Ty->getTag(), Member), - getTypeIndex(Member->getBaseType()), - Member->getOffsetInBits() / 8, Member->getName())); - MemberCount++; - } - } else if (Member->getTag() == dwarf::DW_TAG_friend) { - // Ignore friend members. It appears that MSVC emitted info about - // friends in the past, but modern versions do not. - } - // FIXME: Get clang to emit nested types here and do something with - // them. } - // Skip other unrecognized kinds of elements. + + // TODO: move the member size calculation to a helper function. + uint64_t Size = Member->getSizeInBits(); + uint64_t FieldSize = getBaseTypeSize(Member); + uint64_t OffsetInBytes = MemberInfo.second; + + if (Size != FieldSize) { + uint64_t Offset = Member->getOffsetInBits(); + uint64_t AlignMask = ~(Member->getAlignInBits() - 1); + uint64_t HiMark = (Offset + FieldSize) & AlignMask; + uint64_t FieldOffset = (HiMark - FieldSize); + Offset -= FieldOffset; + + // Maybe we need to work from the other end. + // if (ASM()->getDataLayout().isLittleEndian()) + // Offset = FieldSize - (Offset + Size); + + OffsetInBytes += FieldOffset >> 3; + MemberBaseType = TypeTable.writeBitField( + BitFieldRecord(MemberBaseType, (uint8_t)Size, (uint8_t)Offset)); + } else + // This is not a bitfield. + OffsetInBytes += Member->getOffsetInBits() >> 3; + + Fields.writeDataMember( + DataMemberRecord(translateAccessFlags(Ty->getTag(), Member), + MemberBaseType, OffsetInBytes, Member->getName())); + } + + // Create methods + for (auto &MethodItr : Info.Methods) { + StringRef Name = MethodItr.first; + + std::vector Methods; + for (auto &MethodInfo : MethodItr.second) { + auto *SP = MethodInfo.first; + bool Introduced = MethodInfo.second; + + TypeIndex Methodtype = lowerTypeMemberFunction(SP->getType(), Ty); + + unsigned VFTableOffset = -1; + if (Introduced) + VFTableOffset = SP->getVirtualIndex() * getPointerSizeInBits() >> 3; + + Methods.push_back(OneMethodRecord( + Methodtype, translateMethodKindFlags(SP, Introduced), + translateMethodOptionFlags(SP), + translateMethodAccessFlags(Ty->getTag(), SP), VFTableOffset, Name)); + } + assert(Methods.size() > 0 && "Empty methods map entry"); + if (Methods.size() == 1) + Fields.writeOneMethod(Methods[0]); + else + Fields.writeOverloadedMethod(OverloadedMethodRecord( + Methods.size(), TypeTable.writeMethodOverloadList(Methods), Name)); } - return {TypeTable.writeFieldList(Fields), MemberCount}; + + return std::make_tuple(TypeTable.writeFieldList(Fields), VShapeTI, + Ty->getElements().size()); +} + +TypeIndex CodeViewDebug::getVBPType() { + if (!VBPType.getIndex()) { + ModifierRecord MR(TypeIndex::Int32(), ModifierOptions::Const); + TypeIndex ModifiedTI = TypeTable.writeModifier(MR); + + PointerKind PK = getPointerSizeInBits() == 64 ? PointerKind::Near64 + : PointerKind::Near32; + PointerMode PM = PointerMode::Pointer; + PointerOptions PO = PointerOptions::None; + PointerRecord PR(ModifiedTI, PK, PM, PO, getPointerSizeInBits() / 8); + + VBPType = TypeTable.writePointer(PR); + } + + return VBPType; } TypeIndex CodeViewDebug::getTypeIndex(DITypeRef TypeRef) { @@ -1110,8 +1634,8 @@ // Check if we've already translated this type. Don't try to do a // get-or-create style insertion that caches the hash lookup across the // lowerType call. It will update the TypeIndices map. - auto I = TypeIndices.find(Ty); - if (I != TypeIndices.end()) + auto I = getTypeIndices().find(Ty); + if (I != getTypeIndices().end()) return I->second; TypeIndex TI = lowerType(Ty); Index: test/DebugInfo/COFF/types-basic.ll =================================================================== --- test/DebugInfo/COFF/types-basic.ll +++ test/DebugInfo/COFF/types-basic.ll @@ -115,23 +115,25 @@ ; CHECK: } ; CHECK: ArgList (0x1008) { ; CHECK: TypeLeafKind: LF_ARGLIST (0x1201) -; CHECK: NumArgs: 1 +; CHECK: NumArgs: 0 ; CHECK: Arguments [ -; CHECK: ArgType: A* (0x1007) -; CHECK: ] -; CHECK: } -; CHECK: Procedure (0x1009) { -; CHECK: TypeLeafKind: LF_PROCEDURE (0x1008) -; CHECK: ReturnType: void (0x3) -; CHECK: CallingConvention: NearC (0x0) -; CHECK: FunctionOptions [ (0x0) ; CHECK: ] -; CHECK: NumParameters: 1 -; CHECK: ArgListType: (A*) (0x1008) ; CHECK: } +; CHECK: MemberFunction (0x1009) { +; CHECK: TypeLeafKind: LF_MFUNCTION (0x1009) +; CHECK: ReturnType: void (0x3) +; CHECK: ClassType: A (0x1005) +; CHECK: ThisType: A* (0x1007) +; CHECK: CallingConvention: ThisCall (0xB) +; CHECK: FunctionOptions [ (0x0) +; CHECK: ] +; CHECK: NumParameters: 0 +; CHECK: ArgListType: () (0x1008) +; CHECK: ThisAdjustment: 0 +; CHECK: } ; CHECK: Pointer (0x100A) { ; CHECK: TypeLeafKind: LF_POINTER (0x1002) -; CHECK: PointeeType: void (A*) (0x1009) +; CHECK: PointeeType: void A::() (0x1009) ; CHECK: PointerAttributes: 0x1006C ; CHECK: PtrType: Near64 (0xC) ; CHECK: PtrMode: PointerToMemberFunction (0x3) @@ -160,25 +162,19 @@ ; CHECK: IsVolatile: 0 ; CHECK: IsUnaligned: 0 ; CHECK: } -; CHECK: ArgList (0x100D) { -; CHECK: TypeLeafKind: LF_ARGLIST (0x1201) -; CHECK: NumArgs: 0 -; CHECK: Arguments [ -; CHECK: ] -; CHECK: } -; CHECK: Procedure (0x100E) { +; CHECK: Procedure (0x100D) { ; CHECK: TypeLeafKind: LF_PROCEDURE (0x1008) ; CHECK: ReturnType: void (0x3) ; CHECK: CallingConvention: NearC (0x0) ; CHECK: FunctionOptions [ (0x0) ; CHECK: ] ; CHECK: NumParameters: 0 -; CHECK: ArgListType: () (0x100D) +; CHECK: ArgListType: () (0x1008) ; CHECK: } -; CHECK: FuncId (0x100F) { +; CHECK: FuncId (0x100E) { ; CHECK: TypeLeafKind: LF_FUNC_ID (0x1601) ; CHECK: ParentScope: 0x0 -; CHECK: FunctionType: void () (0x100E) +; CHECK: FunctionType: void () (0x100D) ; CHECK: Name: CharTypes ; CHECK: } ; CHECK: ] @@ -239,7 +235,7 @@ ; CHECK: VarName: v4 ; CHECK: } ; CHECK: Local { -; CHECK: Type: void (A*) A::* (0x100A) +; CHECK: Type: void A::() A::* (0x100A) ; CHECK: VarName: v5 ; CHECK: } ; CHECK: Local { @@ -267,7 +263,7 @@ ; CHECK: ] ; CHECK: Subsection [ ; CHECK: ProcStart { -; CHECK: Type: CharTypes (0x100F) +; CHECK: Type: CharTypes (0x100E) ; CHECK: DisplayName: CharTypes ; CHECK: LinkageName: ?CharTypes@@YAXXZ ; CHECK: } Index: test/DebugInfo/COFF/types-data-members.ll =================================================================== --- test/DebugInfo/COFF/types-data-members.ll +++ test/DebugInfo/COFF/types-data-members.ll @@ -206,7 +206,18 @@ ; CHECK: SizeOf: 0 ; CHECK: Name: DerivedClass ; CHECK: } -; CHECK: Procedure (0x100E) { +; CHECK: Pointer (0x100E) { +; CHECK: TypeLeafKind: LF_POINTER (0x1002) +; CHECK: PointeeType: const int (0x1004) +; CHECK: PointerAttributes: 0x1000C +; CHECK: PtrType: Near64 (0xC) +; CHECK: PtrMode: Pointer (0x0) +; CHECK: IsFlat: 0 +; CHECK: IsConst: 0 +; CHECK: IsVolatile: 0 +; CHECK: IsUnaligned: 0 +; CHECK: } +; CHECK: Procedure (0x100F) { ; CHECK: TypeLeafKind: LF_PROCEDURE (0x1008) ; CHECK: ReturnType: int (0x74) ; CHECK: CallingConvention: NearC (0x0) @@ -215,9 +226,9 @@ ; CHECK: NumParameters: 0 ; CHECK: ArgListType: () (0x1000) ; CHECK: } -; CHECK: Pointer (0x100F) { +; CHECK: Pointer (0x1010) { ; CHECK: TypeLeafKind: LF_POINTER (0x1002) -; CHECK: PointeeType: int () (0x100E) +; CHECK: PointeeType: int () (0x100F) ; CHECK: PointerAttributes: 0x1000C ; CHECK: PtrType: Near64 (0xC) ; CHECK: PtrMode: Pointer (0x0) @@ -226,9 +237,9 @@ ; CHECK: IsVolatile: 0 ; CHECK: IsUnaligned: 0 ; CHECK: } -; CHECK: Pointer (0x1010) { +; CHECK: Pointer (0x1011) { ; CHECK: TypeLeafKind: LF_POINTER (0x1002) -; CHECK: PointeeType: int ()* (0x100F) +; CHECK: PointeeType: int ()* (0x1010) ; CHECK: PointerAttributes: 0x1000C ; CHECK: PtrType: Near64 (0xC) ; CHECK: PtrMode: Pointer (0x0) @@ -237,11 +248,23 @@ ; CHECK: IsVolatile: 0 ; CHECK: IsUnaligned: 0 ; CHECK: } -; CHECK: UnknownLeaf (0x1011) { +; CHECK: UnknownLeaf (0x1012) { ; CHECK: TypeLeafKind: LF_FIELDLIST (0x1203) +; CHECK: BaseClass { +; CHECK: AccessSpecifier: Public (0x3) +; CHECK: BaseType: Struct (0x1003) +; CHECK: BaseOffset: 0x0 +; CHECK: } +; CHECK: VirtualBaseClass { +; CHECK: AccessSpecifier: Public (0x3) +; CHECK: BaseType: Class (0x100A) +; CHECK: VBPtrType: const int* (0x100E) +; CHECK: VBPtrOffset: 0xC +; CHECK: VBTableIndex: 0x1 +; CHECK: } ; CHECK: DataMember { ; CHECK: AccessSpecifier: Public (0x3) -; CHECK: Type: int ()** (0x1010) +; CHECK: Type: int ()** (0x1011) ; CHECK: FieldOffset: 0x0 ; CHECK: Name: _vptr$DerivedClass ; CHECK: } @@ -252,18 +275,18 @@ ; CHECK: Name: d ; CHECK: } ; CHECK: } -; CHECK: Struct (0x1012) { +; CHECK: Struct (0x1013) { ; CHECK: TypeLeafKind: LF_STRUCTURE (0x1505) -; CHECK: MemberCount: 2 +; CHECK: MemberCount: 4 ; CHECK: Properties [ (0x0) ; CHECK: ] -; CHECK: FieldList: d (0x1011) +; CHECK: FieldList: d (0x1012) ; CHECK: DerivedFrom: 0x0 ; CHECK: VShape: 0x0 ; CHECK: SizeOf: 48 ; CHECK: Name: DerivedClass ; CHECK: } -; CHECK: Struct (0x1013) { +; CHECK: Struct (0x1014) { ; CHECK: TypeLeafKind: LF_STRUCTURE (0x1505) ; CHECK: MemberCount: 0 ; CHECK: Properties [ (0x80) @@ -275,7 +298,7 @@ ; CHECK: SizeOf: 0 ; CHECK: Name: Nested ; CHECK: } -; CHECK: UnknownLeaf (0x1014) { +; CHECK: UnknownLeaf (0x1015) { ; CHECK: TypeLeafKind: LF_FIELDLIST (0x1203) ; CHECK: DataMember { ; CHECK: AccessSpecifier: Public (0x3) @@ -284,18 +307,18 @@ ; CHECK: Name: n ; CHECK: } ; CHECK: } -; CHECK: Struct (0x1015) { +; CHECK: Struct (0x1016) { ; CHECK: TypeLeafKind: LF_STRUCTURE (0x1505) ; CHECK: MemberCount: 1 ; CHECK: Properties [ (0x0) ; CHECK: ] -; CHECK: FieldList: n (0x1014) +; CHECK: FieldList: n (0x1015) ; CHECK: DerivedFrom: 0x0 ; CHECK: VShape: 0x0 ; CHECK: SizeOf: 4 ; CHECK: Name: Nested ; CHECK: } -; CHECK: Pointer (0x1016) { +; CHECK: Pointer (0x1017) { ; CHECK: TypeLeafKind: LF_POINTER (0x1002) ; CHECK: PointeeType: DerivedClass (0x100D) ; CHECK: PointerAttributes: 0x1000C @@ -306,26 +329,22 @@ ; CHECK: IsVolatile: 0 ; CHECK: IsUnaligned: 0 ; CHECK: } -; CHECK: ArgList (0x1017) { -; CHECK: TypeLeafKind: LF_ARGLIST (0x1201) -; CHECK: NumArgs: 1 -; CHECK: Arguments [ -; CHECK: ArgType: DerivedClass* (0x1016) -; CHECK: ] -; CHECK: } -; CHECK: Procedure (0x1018) { -; CHECK: TypeLeafKind: LF_PROCEDURE (0x1008) +; CHECK: MemberFunction (0x1018) { +; CHECK: TypeLeafKind: LF_MFUNCTION (0x1009) ; CHECK: ReturnType: void (0x3) -; CHECK: CallingConvention: NearC (0x0) +; CHECK: ClassType: DerivedClass (0x100D) +; CHECK: ThisType: DerivedClass* (0x1017) +; CHECK: CallingConvention: ThisCall (0xB) ; CHECK: FunctionOptions [ (0x0) ; CHECK: ] -; CHECK: NumParameters: 1 -; CHECK: ArgListType: (DerivedClass*) (0x1017) +; CHECK: NumParameters: 0 +; CHECK: ArgListType: () (0x1000) +; CHECK: ThisAdjustment: 0 ; CHECK: } ; CHECK: FuncId (0x1019) { ; CHECK: TypeLeafKind: LF_FUNC_ID (0x1601) ; CHECK: ParentScope: 0x0 -; CHECK: FunctionType: void (DerivedClass*) (0x1018) +; CHECK: FunctionType: void DerivedClass::() (0x1018) ; CHECK: Name: DerivedClass::DerivedClass ; CHECK: } ; CHECK: ]