// addSubprogram - Add subprgoram into SPs. bool DebugInfoFinder::addSubprogram(DISubprogram SP) { if (SP.isNull()) return false; if (!NodesSeen.insert(SP.getNode())) return false; SPs.push_back(SP.getNode()); return true; }
/// EmitFunctionStart - Constructs the debug code for entering a function - /// "llvm.dbg.func.start." void DebugInfo::EmitFunctionStart(tree FnDecl) { setCurrentLexicalBlock(FnDecl); DISubprogram SP = CreateSubprogramFromFnDecl(FnDecl); // Push function on region stack. RegionStack.push_back(WeakVH(SP.getNode())); }
/// createStructType - Create StructType for struct or union or class. DIType DebugInfo::createStructType(tree type) { // struct { a; b; ... z; }; | union { a; b; ... z; }; unsigned Tag = TREE_CODE(type) == RECORD_TYPE ? DW_TAG_structure_type : DW_TAG_union_type; unsigned RunTimeLang = 0; if (TYPE_LANG_SPECIFIC (type) && lang_hooks.types.is_runtime_specific_type (type)) { unsigned CULang = TheCU.getLanguage(); switch (CULang) { case DW_LANG_ObjC_plus_plus : RunTimeLang = DW_LANG_ObjC_plus_plus; break; case DW_LANG_ObjC : RunTimeLang = DW_LANG_ObjC; break; case DW_LANG_C_plus_plus : RunTimeLang = DW_LANG_C_plus_plus; break; default: break; } } // Records and classes and unions can all be recursive. To handle them, // we first generate a debug descriptor for the struct as a forward // declaration. Then (if it is a definition) we go through and get debug // info for all of its members. Finally, we create a descriptor for the // complete type (which may refer to the forward decl if the struct is // recursive) and replace all uses of the forward declaration with the // final definition. expanded_location Loc = GetNodeLocation(TREE_CHAIN(type), false); // FIXME: findRegion() is not able to find context all the time. This // means when type names in different context match then FwdDecl is // reused because MDNodes are uniqued. To avoid this, use type context /// also while creating FwdDecl for now. std::string FwdName; if (TYPE_CONTEXT(type)) { StringRef TypeContextName = GetNodeName(TYPE_CONTEXT(type)); if (!TypeContextName.empty()) FwdName = TypeContextName; } StringRef TypeName = GetNodeName(type); if (!TypeName.empty()) FwdName = FwdName + TypeName.data(); unsigned SFlags = 0; if (TYPE_BLOCK_IMPL_STRUCT(type)) SFlags |= llvm::DIType::FlagAppleBlock; if (type_is_block_byref_struct(type)) SFlags |= llvm::DIType::FlagBlockByrefStruct; DIDescriptor TyContext = findRegion(TYPE_CONTEXT(type)); // Check if this type is created while creating context information // descriptor. std::map<tree_node *, WeakVH >::iterator I = TypeCache.find(type); if (I != TypeCache.end()) if (MDNode *TN = dyn_cast_or_null<MDNode>(I->second)) return DIType(TN); llvm::DICompositeType FwdDecl = DebugFactory.CreateCompositeType(Tag, TyContext, FwdName.c_str(), getOrCreateFile(Loc.file), Loc.line, 0, 0, 0, SFlags | llvm::DIType::FlagFwdDecl, llvm::DIType(), llvm::DIArray(), RunTimeLang); // forward declaration, if (TYPE_SIZE(type) == 0) return FwdDecl; // Insert into the TypeCache so that recursive uses will find it. llvm::TrackingVH<llvm::MDNode> FwdDeclNode = FwdDecl.getNode(); TypeCache[type] = WeakVH(FwdDecl.getNode()); // Push the struct on region stack. RegionStack.push_back(WeakVH(FwdDecl.getNode())); RegionMap[type] = WeakVH(FwdDecl.getNode()); // Convert all the elements. llvm::SmallVector<llvm::DIDescriptor, 16> EltTys; if (tree binfo = TYPE_BINFO(type)) { VEC(tree,gc) *accesses = BINFO_BASE_ACCESSES (binfo); for (unsigned i = 0, e = BINFO_N_BASE_BINFOS(binfo); i != e; ++i) { tree BInfo = BINFO_BASE_BINFO(binfo, i); tree BInfoType = BINFO_TYPE (BInfo); DIType BaseClass = getOrCreateType(BInfoType); unsigned BFlags = 0; if (BINFO_VIRTUAL_P (BInfo)) BFlags = llvm::DIType::FlagVirtual; if (accesses) { tree access = VEC_index (tree, accesses, i); if (access == access_protected_node) BFlags |= llvm::DIType::FlagProtected; else if (access == access_private_node) BFlags |= llvm::DIType::FlagPrivate; } // Check for zero BINFO_OFFSET. // FIXME : Is this correct ? unsigned Offset = BINFO_OFFSET(BInfo) ? getINTEGER_CSTVal(BINFO_OFFSET(BInfo))*8 : 0; if (BINFO_VIRTUAL_P (BInfo)) Offset = 0 - getINTEGER_CSTVal(BINFO_VPTR_FIELD (BInfo)); // FIXME : name, size, align etc... DIType DTy = DebugFactory.CreateDerivedType(DW_TAG_inheritance, findRegion(TYPE_CONTEXT(type)), StringRef(), llvm::DIFile(), 0,0,0, Offset, BFlags, BaseClass); EltTys.push_back(DTy); } } // Now add members of this class. for (tree Member = TYPE_FIELDS(type); Member; Member = TREE_CHAIN(Member)) { // Should we skip. if (DECL_P(Member) && DECL_IGNORED_P(Member)) continue; // Get the location of the member. expanded_location MemLoc = GetNodeLocation(Member, false); if (TREE_CODE(Member) != FIELD_DECL) // otherwise is a static variable, whose debug info is emitted // when through EmitGlobalVariable(). continue; if (DECL_FIELD_OFFSET(Member) == 0 || TREE_CODE(DECL_FIELD_OFFSET(Member)) != INTEGER_CST) // FIXME: field with variable position, skip it for now. continue; /* Ignore nameless fields. */ if (DECL_NAME (Member) == NULL_TREE && !(TREE_CODE (TREE_TYPE (Member)) == UNION_TYPE || TREE_CODE (TREE_TYPE (Member)) == RECORD_TYPE)) continue; // Field type is the declared type of the field. tree FieldNodeType = FieldType(Member); DIType MemberType = getOrCreateType(FieldNodeType); StringRef MemberName = GetNodeName(Member); unsigned MFlags = 0; if (TREE_PROTECTED(Member)) MFlags = llvm::DIType::FlagProtected; else if (TREE_PRIVATE(Member)) MFlags = llvm::DIType::FlagPrivate; DIType DTy = DebugFactory.CreateDerivedType(DW_TAG_member, findRegion(DECL_CONTEXT(Member)), MemberName, getOrCreateFile(MemLoc.file), MemLoc.line, NodeSizeInBits(Member), NodeAlignInBits(FieldNodeType), int_bit_position(Member), MFlags, MemberType); EltTys.push_back(DTy); } for (tree Member = TYPE_METHODS(type); Member; Member = TREE_CHAIN(Member)) { if (DECL_ABSTRACT_ORIGIN (Member)) continue; // Ignore unused aritificial members. if (DECL_ARTIFICIAL (Member) && !TREE_USED (Member)) continue; // In C++, TEMPLATE_DECLs are marked Ignored, and should be. if (DECL_P (Member) && DECL_IGNORED_P (Member)) continue; std::map<tree_node *, WeakVH >::iterator I = SPCache.find(Member); if (I != SPCache.end()) EltTys.push_back(DISubprogram(cast<MDNode>(I->second))); else { // Get the location of the member. expanded_location MemLoc = GetNodeLocation(Member, false); StringRef MemberName = getFunctionName(Member); StringRef LinkageName = getLinkageName(Member); DIType SPTy = getOrCreateType(TREE_TYPE(Member)); unsigned Virtuality = 0; unsigned VIndex = 0; DIType ContainingType; if (DECL_VINDEX (Member)) { if (host_integerp (DECL_VINDEX (Member), 0)) VIndex = tree_low_cst (DECL_VINDEX (Member), 0); Virtuality = dwarf::DW_VIRTUALITY_virtual; ContainingType = getOrCreateType(DECL_CONTEXT(Member)); } DISubprogram SP = DebugFactory.CreateSubprogram(findRegion(DECL_CONTEXT(Member)), MemberName, MemberName, LinkageName, getOrCreateFile(MemLoc.file), MemLoc.line, SPTy, false, false, Virtuality, VIndex, ContainingType, DECL_ARTIFICIAL (Member), optimize); EltTys.push_back(SP); SPCache[Member] = WeakVH(SP.getNode()); } } llvm::DIArray Elements = DebugFactory.GetOrCreateArray(EltTys.data(), EltTys.size()); RegionStack.pop_back(); std::map<tree_node *, WeakVH>::iterator RI = RegionMap.find(type); if (RI != RegionMap.end()) RegionMap.erase(RI); llvm::DIType ContainingType; if (TYPE_VFIELD (type)) { tree vtype = DECL_FCONTEXT (TYPE_VFIELD (type)); ContainingType = getOrCreateType(vtype); } llvm::DICompositeType RealDecl = DebugFactory.CreateCompositeType(Tag, findRegion(TYPE_CONTEXT(type)), GetNodeName(type), getOrCreateFile(Loc.file), Loc.line, NodeSizeInBits(type), NodeAlignInBits(type), 0, SFlags, llvm::DIType(), Elements, RunTimeLang, ContainingType.getNode()); RegionMap[type] = WeakVH(RealDecl.getNode()); // Now that we have a real decl for the struct, replace anything using the // old decl with the new one. This will recursively update the debug info. llvm::DIDerivedType(FwdDeclNode).replaceAllUsesWith(RealDecl); return RealDecl; }
/// CreateSubprogramFromFnDecl - Constructs the debug code for /// entering a function - "llvm.dbg.func.start." DISubprogram DebugInfo::CreateSubprogramFromFnDecl(tree FnDecl) { DISubprogram SPDecl; bool SPDeclIsSet = false; // True if we're currently generating LLVM for this function. bool definition = llvm_set_decl_p(FnDecl); DIType FNType = getOrCreateType(TREE_TYPE(FnDecl)); std::map<tree_node *, WeakVH >::iterator I = SPCache.find(FnDecl); if (I != SPCache.end()) { SPDecl = DISubprogram(cast<MDNode>(I->second)); SPDeclIsSet = true; // If we've already created the defining instance, OR this // invocation won't create the defining instance, return what we // already have. if (SPDecl.isDefinition() || !definition) return SPDecl; } bool ArtificialFnWithAbstractOrigin = false; // If this artificial function has abstract origin then put this function // at module scope. The abstract copy will be placed in appropriate region. if (DECL_ARTIFICIAL (FnDecl) && DECL_ABSTRACT_ORIGIN (FnDecl) && DECL_ABSTRACT_ORIGIN (FnDecl) != FnDecl) ArtificialFnWithAbstractOrigin = true; DIDescriptor SPContext = ArtificialFnWithAbstractOrigin ? getOrCreateFile(main_input_filename) : findRegion (DECL_CONTEXT(FnDecl)); // Declare block_invoke functions at file scope for GDB. if (BLOCK_SYNTHESIZED_FUNC(FnDecl)) SPContext = findRegion(NULL_TREE); // Creating context may have triggered creation of this SP descriptor. So // check the cache again. if (!SPDeclIsSet) { I = SPCache.find(FnDecl); if (I != SPCache.end()) { SPDecl = DISubprogram(cast<MDNode>(I->second)); DISubprogram SP = DebugFactory.CreateSubprogramDefinition(SPDecl); SPDecl.getNode()->replaceAllUsesWith(SP.getNode()); // Push function on region stack. RegionStack.push_back(WeakVH(SP.getNode())); RegionMap[FnDecl] = WeakVH(SP.getNode()); return SP; } } // Gather location information. expanded_location Loc = GetNodeLocation(FnDecl, false); // If the name isn't public, omit the linkage name. Adding a // linkage name to a class method can confuse GDB. StringRef LinkageName = TREE_PUBLIC(FnDecl) ? getLinkageName(FnDecl) : StringRef(); unsigned lineno = LOCATION_LINE(Loc); if (isCopyOrDestroyHelper(FnDecl)) lineno = 0; unsigned Virtuality = 0; unsigned VIndex = 0; DIType ContainingType; if (DECL_VINDEX (FnDecl)) { if (host_integerp (DECL_VINDEX (FnDecl), 0)) VIndex = tree_low_cst (DECL_VINDEX (FnDecl), 0); Virtuality = dwarf::DW_VIRTUALITY_virtual; ContainingType = getOrCreateType(DECL_CONTEXT (FnDecl)); } StringRef FnName = getFunctionName(FnDecl); // If the Function * hasn't been created yet, use a bogus value for // the debug internal linkage bit. bool hasInternalLinkage = true; Function *Fn = 0; if (GET_DECL_LLVM_INDEX(FnDecl)) { Fn = cast<Function>DECL_LLVM(FnDecl); if (Fn) hasInternalLinkage = Fn->hasInternalLinkage(); } DISubprogram SP = DebugFactory.CreateSubprogram(SPContext, FnName, FnName, LinkageName, getOrCreateFile(Loc.file), lineno, FNType, hasInternalLinkage, definition, Virtuality, VIndex, ContainingType, DECL_ARTIFICIAL (FnDecl), optimize, Fn); SPCache[FnDecl] = WeakVH(SP.getNode()); RegionMap[FnDecl] = WeakVH(SP.getNode()); if (SPDeclIsSet && SPDecl.getNode() != SP.getNode()) SPDecl.getNode()->replaceAllUsesWith(SP.getNode()); return SP; }