static rtx gen_symbol_ref_rtx_for_label (const_rtx label) { char name[20]; rtx sym; ASM_GENERATE_INTERNAL_LABEL (name, "L", CODE_LABEL_NUMBER (label)); sym = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (name)); SYMBOL_REF_FLAGS (sym) = SYMBOL_FLAG_LOCAL; return sym; }
static tree make_alias_for_thunk (tree function) { tree alias; char buf[256]; ASM_GENERATE_INTERNAL_LABEL (buf, "LTHUNK", thunk_labelno); thunk_labelno++; alias = make_alias_for (function, get_identifier (buf)); if (!flag_syntax_only) assemble_alias (alias, DECL_ASSEMBLER_NAME (function)); return alias; }
static tree make_alias_for_thunk (tree function) { tree alias; char buf[256]; #if defined (TARGET_IS_PE_COFF) if (DECL_ONE_ONLY (function)) return function; #endif ASM_GENERATE_INTERNAL_LABEL (buf, "LTHUNK", thunk_labelno); thunk_labelno++; alias = build_decl (FUNCTION_DECL, get_identifier (buf), TREE_TYPE (function)); DECL_LANG_SPECIFIC (alias) = DECL_LANG_SPECIFIC (function); cxx_dup_lang_specific_decl (alias); DECL_CONTEXT (alias) = NULL; TREE_READONLY (alias) = TREE_READONLY (function); TREE_THIS_VOLATILE (alias) = TREE_THIS_VOLATILE (function); TREE_PUBLIC (alias) = 0; DECL_INTERFACE_KNOWN (alias) = 1; DECL_NOT_REALLY_EXTERN (alias) = 1; DECL_THIS_STATIC (alias) = 1; DECL_SAVED_FUNCTION_DATA (alias) = NULL; DECL_DESTRUCTOR_P (alias) = 0; DECL_CONSTRUCTOR_P (alias) = 0; DECL_CLONED_FUNCTION (alias) = NULL_TREE; DECL_EXTERNAL (alias) = 0; DECL_ARTIFICIAL (alias) = 1; DECL_NO_STATIC_CHAIN (alias) = 1; DECL_PENDING_INLINE_P (alias) = 0; DECL_INLINE (alias) = 0; DECL_DECLARED_INLINE_P (alias) = 0; DECL_DEFERRED_FN (alias) = 0; DECL_USE_TEMPLATE (alias) = 0; DECL_TEMPLATE_INSTANTIATED (alias) = 0; DECL_TEMPLATE_INFO (alias) = NULL; DECL_INITIAL (alias) = error_mark_node; TREE_ADDRESSABLE (alias) = 1; TREE_USED (alias) = 1; SET_DECL_ASSEMBLER_NAME (alias, DECL_NAME (alias)); TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (alias)) = 1; if (!flag_syntax_only) assemble_alias (alias, DECL_ASSEMBLER_NAME (function)); return alias; }
static tree make_alias_for_thunk (tree function) { tree alias; char buf[256]; ASM_GENERATE_INTERNAL_LABEL (buf, "LTHUNK", thunk_labelno); thunk_labelno++; alias = make_alias_for (function, get_identifier (buf)); if (!flag_syntax_only) { bool ok = cgraph_same_body_alias (alias, function); DECL_ASSEMBLER_NAME (function); gcc_assert (ok); } return alias; }
tree ubsan_create_data (const char *name, const location_t *ploc, const struct ubsan_mismatch_data *mismatch, ...) { va_list args; tree ret, t; tree fields[5]; vec<tree, va_gc> *saved_args = NULL; size_t i = 0; location_t loc = UNKNOWN_LOCATION; /* Firstly, create a pointer to type descriptor type. */ tree td_type = ubsan_type_descriptor_type (); TYPE_READONLY (td_type) = 1; td_type = build_pointer_type (td_type); /* Create the structure type. */ ret = make_node (RECORD_TYPE); if (ploc != NULL) { loc = LOCATION_LOCUS (*ploc); fields[i] = build_decl (UNKNOWN_LOCATION, FIELD_DECL, NULL_TREE, ubsan_source_location_type ()); DECL_CONTEXT (fields[i]) = ret; i++; } va_start (args, mismatch); for (t = va_arg (args, tree); t != NULL_TREE; i++, t = va_arg (args, tree)) { gcc_checking_assert (i < 3); /* Save the tree arguments for later use. */ vec_safe_push (saved_args, t); fields[i] = build_decl (UNKNOWN_LOCATION, FIELD_DECL, NULL_TREE, td_type); DECL_CONTEXT (fields[i]) = ret; if (i) DECL_CHAIN (fields[i - 1]) = fields[i]; } va_end (args); if (mismatch != NULL) { /* We have to add two more decls. */ fields[i] = build_decl (UNKNOWN_LOCATION, FIELD_DECL, NULL_TREE, pointer_sized_int_node); DECL_CONTEXT (fields[i]) = ret; DECL_CHAIN (fields[i - 1]) = fields[i]; i++; fields[i] = build_decl (UNKNOWN_LOCATION, FIELD_DECL, NULL_TREE, unsigned_char_type_node); DECL_CONTEXT (fields[i]) = ret; DECL_CHAIN (fields[i - 1]) = fields[i]; i++; } TYPE_FIELDS (ret) = fields[0]; TYPE_NAME (ret) = get_identifier (name); layout_type (ret); /* Now, fill in the type. */ char tmp_name[32]; static unsigned int ubsan_var_id_num; ASM_GENERATE_INTERNAL_LABEL (tmp_name, "Lubsan_data", ubsan_var_id_num++); tree var = build_decl (UNKNOWN_LOCATION, VAR_DECL, get_identifier (tmp_name), ret); TREE_STATIC (var) = 1; TREE_PUBLIC (var) = 0; DECL_ARTIFICIAL (var) = 1; DECL_IGNORED_P (var) = 1; DECL_EXTERNAL (var) = 0; vec<constructor_elt, va_gc> *v; vec_alloc (v, i); tree ctor = build_constructor (ret, v); /* If desirable, set the __ubsan_source_location element. */ if (ploc != NULL) CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, ubsan_source_location (loc)); size_t nelts = vec_safe_length (saved_args); for (i = 0; i < nelts; i++) { t = (*saved_args)[i]; CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, t); } if (mismatch != NULL) { /* Append the pointer data. */ CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, mismatch->align); CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, mismatch->ckind); } TREE_CONSTANT (ctor) = 1; TREE_STATIC (ctor) = 1; DECL_INITIAL (var) = ctor; varpool_finalize_decl (var); return var; }
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); }
tree ubsan_type_descriptor (tree type) { /* See through any typedefs. */ type = TYPE_MAIN_VARIANT (type); tree decl = decl_for_type_lookup (type); if (decl != NULL_TREE) return decl; tree dtype = ubsan_type_descriptor_type (); const char *tname; unsigned short tkind, tinfo; /* At least for INTEGER_TYPE/REAL_TYPE/COMPLEX_TYPE, this should work. ??? For e.g. type_unsigned_for (type), the TYPE_NAME would be NULL. */ if (TYPE_NAME (type) != NULL) tname = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))); else tname = "<unknown>"; if (TREE_CODE (type) == INTEGER_TYPE) { /* For INTEGER_TYPE, this is 0x0000. */ tkind = 0x000; tinfo = get_ubsan_type_info_for_type (type); } else if (TREE_CODE (type) == REAL_TYPE) /* We don't have float support yet. */ gcc_unreachable (); else gcc_unreachable (); /* 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 (tname); tree str = build_string (len + 1, tname); 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 address of the VAR_DECL into the pointer map. */ decl = build_fold_addr_expr (decl); decl_for_type_insert (type, decl); return decl; }
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); }
tree ubsan_create_data (const char *name, location_t loc, ...) { va_list args; tree ret, t; tree fields[3]; VEC(tree, gc) *saved_args = NULL; size_t i = 0; /* Firstly, create a pointer to type descriptor type. */ tree td_type = ubsan_type_descriptor_type (); TYPE_READONLY (td_type) = 1; td_type = build_pointer_type (td_type); /* Create the structure type. */ ret = make_node (RECORD_TYPE); if (loc != UNKNOWN_LOCATION) { fields[i] = build_decl (UNKNOWN_LOCATION, FIELD_DECL, NULL_TREE, ubsan_source_location_type ()); DECL_CONTEXT (fields[i]) = ret; i++; } va_start (args, loc); for (t = va_arg (args, tree); t != NULL_TREE; i++, t = va_arg (args, tree)) { gcc_checking_assert (i < 3); /* Save the tree argument for later use. */ VEC_safe_push (tree, gc, saved_args, t); fields[i] = build_decl (UNKNOWN_LOCATION, FIELD_DECL, NULL_TREE, td_type); DECL_CONTEXT (fields[i]) = ret; if (i) DECL_CHAIN (fields[i - 1]) = fields[i]; } TYPE_FIELDS (ret) = fields[0]; TYPE_NAME (ret) = get_identifier (name); layout_type (ret); va_end (args); /* Now, fill in the type. */ char tmp_name[32]; static unsigned int ubsan_var_id_num; ASM_GENERATE_INTERNAL_LABEL (tmp_name, "Lubsan_data", ubsan_var_id_num++); tree var = build_decl (UNKNOWN_LOCATION, VAR_DECL, get_identifier (tmp_name), ret); TREE_STATIC (var) = 1; TREE_PUBLIC (var) = 0; DECL_ARTIFICIAL (var) = 1; DECL_IGNORED_P (var) = 1; DECL_EXTERNAL (var) = 0; VEC(constructor_elt, gc) *v; v = VEC_alloc (constructor_elt, gc, i); tree ctor = build_constructor (ret, v); /* If desirable, set the __ubsan_source_location element. */ if (loc != UNKNOWN_LOCATION) CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, ubsan_source_location (loc)); size_t nelts = VEC_length (tree, saved_args); for (i = 0; i < nelts; i++) { t = VEC_index (tree, saved_args, i); CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, t); } TREE_CONSTANT (ctor) = 1; TREE_STATIC (ctor) = 1; DECL_INITIAL (var) = ctor; rest_of_decl_compilation (var, 1, 0); return var; }