static void record_target_from_binfo (vec <cgraph_node *> &nodes, tree binfo, tree otr_type, tree type_binfo, HOST_WIDE_INT otr_token, tree outer_type, HOST_WIDE_INT offset, pointer_set_t *inserted, pointer_set_t *matched_vtables, bool anonymous) { tree type = BINFO_TYPE (binfo); int i; tree base_binfo; gcc_checking_assert (BINFO_VTABLE (type_binfo)); if (types_same_for_odr (type, outer_type)) { tree inner_binfo = get_binfo_at_offset (type_binfo, offset, otr_type); /* For types in anonymous namespace first check if the respective vtable is alive. If not, we know the type can't be called. */ if (!flag_ltrans && anonymous) { tree vtable = BINFO_VTABLE (inner_binfo); struct varpool_node *vnode; if (TREE_CODE (vtable) == POINTER_PLUS_EXPR) vtable = TREE_OPERAND (TREE_OPERAND (vtable, 0), 0); vnode = varpool_get_node (vtable); if (!vnode || !vnode->definition) return; } gcc_assert (inner_binfo); if (!pointer_set_insert (matched_vtables, BINFO_VTABLE (inner_binfo))) { tree target = gimple_get_virt_method_for_binfo (otr_token, inner_binfo); if (target) maybe_record_node (nodes, target, inserted, NULL); } return; } /* Walk bases. */ for (i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++) /* Walking bases that have no virtual method is pointless excercise. */ if (polymorphic_type_binfo_p (base_binfo)) record_target_from_binfo (nodes, base_binfo, otr_type, /* In the case of single inheritance, the virtual table is shared with the outer type. */ BINFO_VTABLE (base_binfo) ? base_binfo : type_binfo, otr_token, outer_type, offset, inserted, matched_vtables, anonymous); }
/* Return varpool node assigned to DECL. Create new one when needed. */ varpool_node * varpool_node_for_decl (tree decl) { varpool_node *node = varpool_get_node (decl); gcc_checking_assert (TREE_CODE (decl) == VAR_DECL); if (node) return node; node = varpool_create_empty_node (); node->decl = decl; symtab_register_node (node); return node; }
/* Return varpool node assigned to DECL. Create new one when needed. */ struct varpool_node * varpool_node (tree decl) { struct varpool_node *node = varpool_get_node (decl); gcc_assert (TREE_CODE (decl) == VAR_DECL && (TREE_STATIC (decl) || DECL_EXTERNAL (decl) || in_lto_p)); if (node) return node; node = ggc_alloc_cleared_varpool_node (); node->symbol.type = SYMTAB_VARIABLE; node->symbol.decl = decl; symtab_register_node ((symtab_node)node); return node; }
void varpool_analyze_node (varpool_node *node) { tree decl = node->decl; /* When reading back varpool at LTO time, we re-construct the queue in order to have "needed" list right by inserting all needed nodes into varpool. We however don't want to re-analyze already analyzed nodes. */ if (!node->analyzed) { gcc_assert (!in_lto_p || cgraph_function_flags_ready); /* Compute the alignment early so function body expanders are already informed about increased alignment. */ align_variable (decl, 0); } if (node->alias) symtab_resolve_alias (node, varpool_get_node (node->alias_target)); else if (DECL_INITIAL (decl)) record_references_in_initializer (decl, node->analyzed); node->analyzed = true; }
tree ctor_for_folding (tree decl) { varpool_node *node, *real_node; tree real_decl; if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != CONST_DECL) return error_mark_node; if (TREE_CODE (decl) == CONST_DECL || DECL_IN_CONSTANT_POOL (decl)) return DECL_INITIAL (decl); if (TREE_THIS_VOLATILE (decl)) return error_mark_node; /* Do not care about automatic variables. Those are never initialized anyway, because gimplifier exapnds the code. */ if (!TREE_STATIC (decl) && !DECL_EXTERNAL (decl)) { gcc_assert (!TREE_PUBLIC (decl)); return error_mark_node; } gcc_assert (TREE_CODE (decl) == VAR_DECL); node = varpool_get_node (decl); if (node) { real_node = varpool_variable_node (node); real_decl = real_node->decl; } else real_decl = decl; /* See if we are dealing with alias. In most cases alias is just alternative symbol pointing to a given constructor. This allows us to use interposition rules of DECL constructor of REAL_NODE. However weakrefs are special by being just alternative name of their target (if defined). */ if (decl != real_decl) { gcc_assert (!DECL_INITIAL (decl) || DECL_INITIAL (decl) == error_mark_node); if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl))) { node = varpool_alias_target (node); decl = node->decl; } } /* Vtables are defined by their types and must match no matter of interposition rules. */ if (DECL_VIRTUAL_P (real_decl)) { gcc_checking_assert (TREE_READONLY (real_decl)); return DECL_INITIAL (real_decl); } /* If there is no constructor, we have nothing to do. */ if (DECL_INITIAL (real_decl) == error_mark_node) return error_mark_node; /* Non-readonly alias of readonly variable is also de-facto readonly, because the variable itself is in readonly section. We also honnor READONLY flag on alias assuming that user knows what he is doing. */ if (!TREE_READONLY (decl) && !TREE_READONLY (real_decl)) return error_mark_node; /* Variables declared 'const' without an initializer have zero as the initializer if they may not be overridden at link or run time. */ if (!DECL_INITIAL (real_decl) && (DECL_EXTERNAL (decl) || decl_replaceable_p (decl))) return error_mark_node; /* Variables declared `const' with an initializer are considered to not be overwritable with different initializer by default. ??? Previously we behaved so for scalar variables but not for array accesses. */ return DECL_INITIAL (real_decl); }
tree ubsan_type_descriptor (tree type, enum ubsan_print_style pstyle) { /* See through any typedefs. */ type = TYPE_MAIN_VARIANT (type); tree decl = decl_for_type_lookup (type); /* It is possible that some of the earlier created DECLs were found unused, in that case they weren't emitted and varpool_get_node returns NULL node on them. But now we really need them. Thus, renew them here. */ if (decl != NULL_TREE && varpool_get_node (decl)) return build_fold_addr_expr (decl); tree dtype = ubsan_type_descriptor_type (); tree type2 = type; const char *tname = NULL; char *pretty_name; unsigned char deref_depth = 0; unsigned short tkind, tinfo; /* Get the name of the type, or the name of the pointer type. */ if (pstyle == UBSAN_PRINT_POINTER) { gcc_assert (POINTER_TYPE_P (type)); type2 = TREE_TYPE (type); /* Remove any '*' operators from TYPE. */ while (POINTER_TYPE_P (type2)) deref_depth++, type2 = TREE_TYPE (type2); if (TREE_CODE (type2) == METHOD_TYPE) type2 = TYPE_METHOD_BASETYPE (type2); } /* If an array, get its type. */ type2 = strip_array_types (type2); if (pstyle == UBSAN_PRINT_ARRAY) { while (POINTER_TYPE_P (type2)) deref_depth++, type2 = TREE_TYPE (type2); } if (TYPE_NAME (type2) != NULL) { if (TREE_CODE (TYPE_NAME (type2)) == IDENTIFIER_NODE) tname = IDENTIFIER_POINTER (TYPE_NAME (type2)); else if (DECL_NAME (TYPE_NAME (type2)) != NULL) tname = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type2))); } if (tname == NULL) /* We weren't able to determine the type name. */ tname = "<unknown>"; /* Decorate the type name with '', '*', "struct", or "union". */ pretty_name = (char *) alloca (strlen (tname) + 16 + deref_depth); if (pstyle == UBSAN_PRINT_POINTER) { int pos = sprintf (pretty_name, "'%s%s%s%s%s%s%s", TYPE_VOLATILE (type2) ? "volatile " : "", TYPE_READONLY (type2) ? "const " : "", TYPE_RESTRICT (type2) ? "restrict " : "", TYPE_ATOMIC (type2) ? "_Atomic " : "", TREE_CODE (type2) == RECORD_TYPE ? "struct " : TREE_CODE (type2) == UNION_TYPE ? "union " : "", tname, deref_depth == 0 ? "" : " "); while (deref_depth-- > 0) pretty_name[pos++] = '*'; pretty_name[pos++] = '\''; pretty_name[pos] = '\0'; } else if (pstyle == UBSAN_PRINT_ARRAY) { /* Pretty print the array dimensions. */ gcc_assert (TREE_CODE (type) == ARRAY_TYPE); tree t = type; int pos = sprintf (pretty_name, "'%s ", tname); while (deref_depth-- > 0) pretty_name[pos++] = '*'; while (TREE_CODE (t) == ARRAY_TYPE) { pretty_name[pos++] = '['; tree dom = TYPE_DOMAIN (t); if (dom && TREE_CODE (TYPE_MAX_VALUE (dom)) == INTEGER_CST) pos += sprintf (&pretty_name[pos], HOST_WIDE_INT_PRINT_DEC, tree_to_shwi (TYPE_MAX_VALUE (dom)) + 1); else /* ??? We can't determine the variable name; print VLA unspec. */ pretty_name[pos++] = '*'; pretty_name[pos++] = ']'; t = TREE_TYPE (t); } pretty_name[pos++] = '\''; pretty_name[pos] = '\0'; /* Save the tree with stripped types. */ type = t; } else sprintf (pretty_name, "'%s'", tname); switch (TREE_CODE (type)) { case BOOLEAN_TYPE: case ENUMERAL_TYPE: case INTEGER_TYPE: tkind = 0x0000; break; case REAL_TYPE: /* FIXME: libubsan right now only supports float, double and long double type formats. */ if (TYPE_MODE (type) == TYPE_MODE (float_type_node) || TYPE_MODE (type) == TYPE_MODE (double_type_node) || TYPE_MODE (type) == TYPE_MODE (long_double_type_node)) tkind = 0x0001; else tkind = 0xffff; break; default: tkind = 0xffff; break; } tinfo = get_ubsan_type_info_for_type (type); /* Create a new VAR_DECL of type descriptor. */ char tmp_name[32]; static unsigned int type_var_id_num; ASM_GENERATE_INTERNAL_LABEL (tmp_name, "Lubsan_type", type_var_id_num++); decl = build_decl (UNKNOWN_LOCATION, VAR_DECL, get_identifier (tmp_name), dtype); TREE_STATIC (decl) = 1; TREE_PUBLIC (decl) = 0; DECL_ARTIFICIAL (decl) = 1; DECL_IGNORED_P (decl) = 1; DECL_EXTERNAL (decl) = 0; size_t len = strlen (pretty_name); tree str = build_string (len + 1, pretty_name); TREE_TYPE (str) = build_array_type (char_type_node, build_index_type (size_int (len))); TREE_READONLY (str) = 1; TREE_STATIC (str) = 1; tree ctor = build_constructor_va (dtype, 3, NULL_TREE, build_int_cst (short_unsigned_type_node, tkind), NULL_TREE, build_int_cst (short_unsigned_type_node, tinfo), NULL_TREE, str); TREE_CONSTANT (ctor) = 1; TREE_STATIC (ctor) = 1; DECL_INITIAL (decl) = ctor; varpool_finalize_decl (decl); /* Save the VAR_DECL into the hash table. */ decl_for_type_insert (type, decl); return build_fold_addr_expr (decl); }
static void lto_symtab_resolve_symbols (void **slot) { lto_symtab_entry_t e; lto_symtab_entry_t prevailing = NULL; /* Always set e->node so that edges are updated to reflect decl merging. */ for (e = (lto_symtab_entry_t) *slot; e; e = e->next) { if (TREE_CODE (e->decl) == FUNCTION_DECL) e->node = cgraph_get_node (e->decl); else if (TREE_CODE (e->decl) == VAR_DECL) e->vnode = varpool_get_node (e->decl); if (e->resolution == LDPR_PREVAILING_DEF_IRONLY || e->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP || e->resolution == LDPR_PREVAILING_DEF) prevailing = e; } /* If the chain is already resolved there is nothing else to do. */ if (prevailing) return; /* Find the single non-replaceable prevailing symbol and diagnose ODR violations. */ for (e = (lto_symtab_entry_t) *slot; e; e = e->next) { if (!lto_symtab_resolve_can_prevail_p (e)) { e->resolution = LDPR_RESOLVED_IR; e->guessed = true; continue; } /* Set a default resolution - the final prevailing one will get adjusted later. */ e->resolution = LDPR_PREEMPTED_IR; e->guessed = true; if (!lto_symtab_resolve_replaceable_p (e)) { if (prevailing) { error_at (DECL_SOURCE_LOCATION (e->decl), "%qD has already been defined", e->decl); inform (DECL_SOURCE_LOCATION (prevailing->decl), "previously defined here"); } prevailing = e; } } if (prevailing) goto found; /* Do a second round choosing one from the replaceable prevailing decls. */ for (e = (lto_symtab_entry_t) *slot; e; e = e->next) { if (e->resolution != LDPR_PREEMPTED_IR) continue; /* Choose the first function that can prevail as prevailing. */ if (TREE_CODE (e->decl) == FUNCTION_DECL) { prevailing = e; break; } /* From variables that can prevail choose the largest one. */ if (!prevailing || tree_int_cst_lt (DECL_SIZE (prevailing->decl), DECL_SIZE (e->decl))) prevailing = e; } if (!prevailing) return; found: /* If current lto files represent the whole program, it is correct to use LDPR_PREVALING_DEF_IRONLY. If current lto files are part of whole program, internal resolver doesn't know if it is LDPR_PREVAILING_DEF or LDPR_PREVAILING_DEF_IRONLY. Use IRONLY conforms to using -fwhole-program. Otherwise, it doesn't matter using either LDPR_PREVAILING_DEF or LDPR_PREVAILING_DEF_IRONLY FIXME: above workaround due to gold plugin makes some variables IRONLY, which are indeed PREVAILING_DEF in resolution file. These variables still need manual externally_visible attribute. */ prevailing->resolution = LDPR_PREVAILING_DEF_IRONLY; prevailing->guessed = true; }
tree ubsan_type_descriptor (tree type, bool want_pointer_type_p) { /* See through any typedefs. */ type = TYPE_MAIN_VARIANT (type); tree decl = decl_for_type_lookup (type); /* It is possible that some of the earlier created DECLs were found unused, in that case they weren't emitted and varpool_get_node returns NULL node on them. But now we really need them. Thus, renew them here. */ if (decl != NULL_TREE && varpool_get_node (decl)) return build_fold_addr_expr (decl); tree dtype = ubsan_type_descriptor_type (); tree type2 = type; const char *tname = NULL; char *pretty_name; unsigned char deref_depth = 0; unsigned short tkind, tinfo; /* Get the name of the type, or the name of the pointer type. */ if (want_pointer_type_p) { gcc_assert (POINTER_TYPE_P (type)); type2 = TREE_TYPE (type); /* Remove any '*' operators from TYPE. */ while (POINTER_TYPE_P (type2)) deref_depth++, type2 = TREE_TYPE (type2); if (TREE_CODE (type2) == METHOD_TYPE) type2 = TYPE_METHOD_BASETYPE (type2); } if (TYPE_NAME (type2) != NULL) { if (TREE_CODE (TYPE_NAME (type2)) == IDENTIFIER_NODE) tname = IDENTIFIER_POINTER (TYPE_NAME (type2)); else tname = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type2))); } if (tname == NULL) /* We weren't able to determine the type name. */ tname = "<unknown>"; /* Decorate the type name with '', '*', "struct", or "union". */ pretty_name = (char *) alloca (strlen (tname) + 16 + deref_depth); if (want_pointer_type_p) { int pos = sprintf (pretty_name, "'%s%s%s%s%s%s%s", TYPE_VOLATILE (type2) ? "volatile " : "", TYPE_READONLY (type2) ? "const " : "", TYPE_RESTRICT (type2) ? "restrict " : "", TYPE_ATOMIC (type2) ? "_Atomic " : "", TREE_CODE (type2) == RECORD_TYPE ? "struct " : TREE_CODE (type2) == UNION_TYPE ? "union " : "", tname, deref_depth == 0 ? "" : " "); while (deref_depth-- > 0) pretty_name[pos++] = '*'; pretty_name[pos++] = '\''; pretty_name[pos] = '\0'; } else sprintf (pretty_name, "'%s'", tname); switch (TREE_CODE (type)) { case INTEGER_TYPE: tkind = 0x0000; break; case REAL_TYPE: tkind = 0x0001; break; default: tkind = 0xffff; break; } tinfo = get_ubsan_type_info_for_type (type); /* Create a new VAR_DECL of type descriptor. */ char tmp_name[32]; static unsigned int type_var_id_num; ASM_GENERATE_INTERNAL_LABEL (tmp_name, "Lubsan_type", type_var_id_num++); decl = build_decl (UNKNOWN_LOCATION, VAR_DECL, get_identifier (tmp_name), dtype); TREE_STATIC (decl) = 1; TREE_PUBLIC (decl) = 0; DECL_ARTIFICIAL (decl) = 1; DECL_IGNORED_P (decl) = 1; DECL_EXTERNAL (decl) = 0; size_t len = strlen (pretty_name); tree str = build_string (len + 1, pretty_name); TREE_TYPE (str) = build_array_type (char_type_node, build_index_type (size_int (len))); TREE_READONLY (str) = 1; TREE_STATIC (str) = 1; tree ctor = build_constructor_va (dtype, 3, NULL_TREE, build_int_cst (short_unsigned_type_node, tkind), NULL_TREE, build_int_cst (short_unsigned_type_node, tinfo), NULL_TREE, str); TREE_CONSTANT (ctor) = 1; TREE_STATIC (ctor) = 1; DECL_INITIAL (decl) = ctor; rest_of_decl_compilation (decl, 1, 0); /* Save the VAR_DECL into the hash table. */ decl_for_type_insert (type, decl); return build_fold_addr_expr (decl); }