From 4f4ecfd875fefb250f6c0315989e889ebb67e830 Mon Sep 17 00:00:00 2001 From: fche Date: Thu, 28 Oct 2004 21:24:33 +0000 Subject: [PATCH] 2004-10-28 Frank Ch. Eigler * tree-mudflap.c (mudflap_init): Mark cache-lookup decls to prevent their later unnecessary registration. (mf_build_check_statement_for): Remove "addr" argument, and related "__mf_value" generated code. Update callers. (mf_decl_eligible_p): New function, factored from mx_register_decls. (mx_register_decls): Call it. (mf_xform_derefs_1): Rewrite COMPONENT_REF and ARRAY_REF cases to restore support for complex nested expressions. (mudflap_enqueue_decl): Simplify. Move registration call emission out ... (mudflap_finish_file): ... to here. (mudflap_enqueue_constant): Remove dump code. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@89784 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 15 +++ gcc/tree-mudflap.c | 324 +++++++++++++++++++++++++---------------------------- 2 files changed, 170 insertions(+), 169 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index bb2556900f6..a0b97c72268 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,18 @@ +2004-10-28 Frank Ch. Eigler + + * tree-mudflap.c (mudflap_init): Mark cache-lookup decls to + prevent their later unnecessary registration. + (mf_build_check_statement_for): Remove "addr" argument, and + related "__mf_value" generated code. Update callers. + (mf_decl_eligible_p): New function, factored from mx_register_decls. + (mx_register_decls): Call it. + (mf_xform_derefs_1): Rewrite COMPONENT_REF and ARRAY_REF cases + to restore support for complex nested expressions. + (mudflap_enqueue_decl): Simplify. Move registration call emission + out ... + (mudflap_finish_file): ... to here. + (mudflap_enqueue_constant): Remove dump code. + 2004-10-28 Zack Weinberg PR 18199 diff --git a/gcc/tree-mudflap.c b/gcc/tree-mudflap.c index a65d393649b..3ff50b61dd2 100644 --- a/gcc/tree-mudflap.c +++ b/gcc/tree-mudflap.c @@ -378,6 +378,11 @@ mudflap_init (void) unsigned_char_type_node); mf_cache_mask_decl = mf_make_builtin (VAR_DECL, "__mf_lc_mask", mf_uintptr_type); + /* Don't process these in mudflap_enqueue_decl, should they come by + there for some reason. */ + mf_mark (mf_cache_array_decl); + mf_mark (mf_cache_shift_decl); + mf_mark (mf_cache_mask_decl); mf_check_fndecl = mf_make_builtin (FUNCTION_DECL, "__mf_check", mf_check_register_fntype); mf_register_fndecl = mf_make_builtin (FUNCTION_DECL, "__mf_register", @@ -484,17 +489,15 @@ mf_decl_clear_locals (void) } static void -mf_build_check_statement_for (tree base, tree addr, tree limit, +mf_build_check_statement_for (tree base, tree limit, block_stmt_iterator *instr_bsi, location_t *locus, tree dirflag) { tree_stmt_iterator head, tsi; - tree ptrtype = TREE_TYPE (addr); block_stmt_iterator bsi; basic_block cond_bb, then_bb, join_bb; edge e; tree cond, t, u, v, l1, l2; - tree mf_value; tree mf_base; tree mf_elem; tree mf_limit; @@ -558,24 +561,17 @@ mf_build_check_statement_for (tree base, tree addr, tree limit, } /* Build our local variables. */ - mf_value = create_tmp_var (ptrtype, "__mf_value"); mf_elem = create_tmp_var (mf_cache_structptr_type, "__mf_elem"); mf_base = create_tmp_var (mf_uintptr_type, "__mf_base"); mf_limit = create_tmp_var (mf_uintptr_type, "__mf_limit"); - /* Build: __mf_value =
. */ - t = build (MODIFY_EXPR, void_type_node, mf_value, unshare_expr (addr)); - SET_EXPR_LOCUS (t, locus); - gimplify_to_stmt_list (&t); - head = tsi_start (t); - tsi = tsi_last (t); - /* Build: __mf_base = (uintptr_t) . */ t = build (MODIFY_EXPR, void_type_node, mf_base, convert (mf_uintptr_type, unshare_expr (base))); SET_EXPR_LOCUS (t, locus); gimplify_to_stmt_list (&t); - tsi_link_after (&tsi, t, TSI_CONTINUE_LINKING); + head = tsi_start (t); + tsi = tsi_last (t); /* Build: __mf_limit = (uintptr_t) . */ t = build (MODIFY_EXPR, void_type_node, mf_limit, @@ -679,8 +675,7 @@ mf_build_check_statement_for (tree base, tree addr, tree limit, : *locus), NULL_TREE); u = tree_cons (NULL_TREE, dirflag, u); - /* NB: we pass the overall [base..limit] range to mf_check, - not the [mf_value..mf_value+size-1] range. */ + /* NB: we pass the overall [base..limit] range to mf_check. */ u = tree_cons (NULL_TREE, fold (build (PLUS_EXPR, integer_type_node, fold (build (MINUS_EXPR, mf_uintptr_type, mf_limit, mf_base)), @@ -712,11 +707,33 @@ mf_build_check_statement_for (tree base, tree addr, tree limit, bsi_next (instr_bsi); } + +/* Check whether the given decl, generally a VAR_DECL or PARM_DECL, is + eligible for instrumentation. For the mudflap1 pass, this implies + that it should be registered with the libmudflap runtime. For the + mudflap2 pass this means instrumenting an indirection operation with + respect to the object. +*/ +static int +mf_decl_eligible_p (tree decl) +{ + return ((TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL) + /* The decl must have its address taken. In the case of + arrays, this flag is also set if the indexes are not + compile-time known valid constants. */ + && TREE_ADDRESSABLE (decl) + /* The type of the variable must be complete. */ + && COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (decl)) + /* The decl hasn't been decomposed somehow. */ + && DECL_VALUE_EXPR (decl) == NULL); +} + + static void mf_xform_derefs_1 (block_stmt_iterator *iter, tree *tp, location_t *locus, tree dirflag) { - tree type, ptr_type, addr, base, size, limit, t; + tree type, ptr_type, base, limit, addr, size, t; /* Don't instrument read operations. */ if (dirflag == integer_zero_node && flag_mudflap_ignore_reads) @@ -733,47 +750,90 @@ mf_xform_derefs_1 (block_stmt_iterator *iter, tree *tp, switch (TREE_CODE (t)) { case ARRAY_REF: + case COMPONENT_REF: { - /* Omit checking if we can statically determine that the access is - valid. For non-addressable local arrays this is not optional, - since we won't have called __mf_register for the object. */ - tree op0, op1; - - op0 = TREE_OPERAND (t, 0); - op1 = TREE_OPERAND (t, 1); - while (TREE_CODE (op1) == INTEGER_CST) + /* This is trickier than it may first appear. The reason is + that we are looking at expressions from the "inside out" at + this point. We may have a complex nested aggregate/array + expression (e.g. "a.b[i].c"), maybe with an indirection as + the leftmost operator ("p->a.b.d"), where instrumentation + is necessary. Or we may have an innocent "a.b.c" + expression that must not be instrumented. We need to + recurse all the way down the nesting structure to figure it + out: looking just at the outer node is not enough. */ + tree var; + int component_ref_only = TREE_CODE (t) == COMPONENT_REF; + + /* Iterate to the top of the ARRAY_REF/COMPONENT_REF + containment hierarchy to find the outermost VAR_DECL. */ + var = TREE_OPERAND (t, 0); + while (1) { - tree dom = TYPE_DOMAIN (TREE_TYPE (op0)); - - /* Test for index in range. Break if not. */ - if (!dom - || (! TYPE_MIN_VALUE (dom) - || ! really_constant_p (TYPE_MIN_VALUE (dom))) - || (! TYPE_MAX_VALUE (dom) - || ! really_constant_p (TYPE_MAX_VALUE (dom))) - || (tree_int_cst_lt (op1, TYPE_MIN_VALUE (dom)) - || tree_int_cst_lt (TYPE_MAX_VALUE (dom), op1))) - break; + if (TREE_CODE (var) == ARRAY_REF) + { + component_ref_only = 0; + var = TREE_OPERAND (var, 0); + } + else if (TREE_CODE (var) == COMPONENT_REF) + var = TREE_OPERAND (var, 0); + else if (INDIRECT_REF_P (var)) + { + component_ref_only = 0; + break; + } + else + { + gcc_assert (TREE_CODE (var) == VAR_DECL + || TREE_CODE (var) == PARM_DECL); + /* Don't instrument this access if the underlying + variable is not "eligible". This test matches + those arrays that have only known-valid indexes, + and thus are not labeled TREE_ADDRESSABLE. */ + if (! mf_decl_eligible_p (var)) + return; + else + break; + } + } - /* If we're looking at a non-external VAR_DECL, then the - access must be ok. */ - if (TREE_CODE (op0) == VAR_DECL && !DECL_EXTERNAL (op0)) - return; + /* Handle the case of ordinary non-indirection structure + accesses. These have only nested COMPONENT_REF nodes (no + INDIRECT_REF), but pass through the above filter loop. + Note that it's possible for such a struct variable to match + the eligible_p test because someone else might take its + address sometime. */ + if (component_ref_only) + return; - /* Only continue if we're still looking at an array. */ - if (TREE_CODE (op0) != ARRAY_REF) - break; + ptr_type = build_pointer_type (type); - op1 = TREE_OPERAND (op0, 1); - op0 = TREE_OPERAND (op0, 0); + /* We need special processing for bitfield components, because + their addresses cannot be taken. */ + if (TREE_CODE (t) == COMPONENT_REF + && DECL_BIT_FIELD_TYPE (TREE_OPERAND (t, 1))) + { + tree field = TREE_OPERAND (t, 1); + + if (TREE_CODE (DECL_SIZE_UNIT (field)) == INTEGER_CST) + size = DECL_SIZE_UNIT (field); + + addr = TREE_OPERAND (TREE_OPERAND (t, 0), 0); + addr = fold_convert (ptr_type_node, addr); + addr = fold (build (PLUS_EXPR, ptr_type_node, + addr, fold_convert (ptr_type_node, + byte_position (field)))); } - - /* If we got here, we couldn't statically the check. */ - ptr_type = build_pointer_type (type); - addr = build1 (ADDR_EXPR, ptr_type, t); - base = build1 (ADDR_EXPR, ptr_type, op0); + else + addr = build1 (ADDR_EXPR, build_pointer_type (type), t); + + if (INDIRECT_REF_P (var)) + base = TREE_OPERAND (var, 0); + else + base = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (var)), var); limit = fold (build (MINUS_EXPR, mf_uintptr_type, - fold (build2 (PLUS_EXPR, mf_uintptr_type, addr, size)), + fold (build2 (PLUS_EXPR, mf_uintptr_type, + convert (mf_uintptr_type, addr), + size)), integer_one_node)); } break; @@ -791,46 +851,8 @@ mf_xform_derefs_1 (block_stmt_iterator *iter, tree *tp, warning ("mudflap checking not yet implemented for ARRAY_RANGE_REF"); return; - case COMPONENT_REF: - { - tree field; - - /* If we're not dereferencing something, then the access - must be ok. */ - if (TREE_CODE (TREE_OPERAND (t, 0)) != INDIRECT_REF) - return; - - field = TREE_OPERAND (t, 1); - - /* If we're looking at a bit field, then we can't take its address - with ADDR_EXPR -- lang_hooks.mark_addressable will error. Do - things the hard way with PLUS. */ - if (DECL_BIT_FIELD_TYPE (field)) - { - if (TREE_CODE (DECL_SIZE_UNIT (field)) == INTEGER_CST) - size = DECL_SIZE_UNIT (field); - - addr = TREE_OPERAND (TREE_OPERAND (t, 0), 0); - addr = fold_convert (ptr_type_node, addr); - addr = fold (build (PLUS_EXPR, ptr_type_node, - addr, fold_convert (ptr_type_node, - byte_position (field)))); - } - else - { - ptr_type = build_pointer_type (type); - addr = build1 (ADDR_EXPR, ptr_type, t); - } - - /* XXXXXX */ - base = addr; - limit = fold (build (MINUS_EXPR, ptr_type_node, - fold (build (PLUS_EXPR, ptr_type_node, base, size)), - integer_one_node)); - } - break; - case BIT_FIELD_REF: + /* ??? merge with COMPONENT_REF code above? */ { tree ofs, rem, bpu; @@ -864,7 +886,7 @@ mf_xform_derefs_1 (block_stmt_iterator *iter, tree *tp, return; } - mf_build_check_statement_for (base, addr, limit, iter, locus, dirflag); + mf_build_check_statement_for (base, limit, iter, locus, dirflag); } static void @@ -959,19 +981,12 @@ mx_register_decls (tree decl, tree *stmt_list) while (decl != NULL_TREE) { - /* Eligible decl? */ - if ((TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL) - /* It must be a non-external, automatic variable. */ + if (mf_decl_eligible_p (decl) + /* Not already processed. */ + && ! mf_marked_p (decl) + /* Automatic variable. */ && ! DECL_EXTERNAL (decl) - && ! TREE_STATIC (decl) - /* The decl must have its address taken. */ - && TREE_ADDRESSABLE (decl) - /* The type of the variable must be complete. */ - && COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (decl)) - /* The decl hasn't been decomposed somehow. */ - && DECL_VALUE_EXPR (decl) == NULL - /* Don't process the same decl twice. */ - && ! mf_marked_p (decl)) + && ! TREE_STATIC (decl)) { tree size = NULL_TREE, variable_name; tree unregister_fncall, unregister_fncall_params; @@ -1180,50 +1195,13 @@ mudflap_enqueue_decl (tree obj) if (DECL_P (obj) && DECL_EXTERNAL (obj) && DECL_ARTIFICIAL (obj)) return; - if (COMPLETE_TYPE_P (TREE_TYPE (obj))) - { - tree object_size; - - mf_mark (obj); - - object_size = size_in_bytes (TREE_TYPE (obj)); - - if (dump_file) - { - fprintf (dump_file, "enqueue_decl obj=`"); - print_generic_expr (dump_file, obj, dump_flags); - fprintf (dump_file, "' size="); - print_generic_expr (dump_file, object_size, dump_flags); - fprintf (dump_file, "\n"); - } - - /* NB: the above condition doesn't require TREE_USED or - TREE_ADDRESSABLE. That's because this object may be a global - only used from other compilation units. XXX: Maybe static - objects could require those attributes being set. */ + if (! deferred_static_decls) + VARRAY_TREE_INIT (deferred_static_decls, 10, "deferred static list"); - mudflap_register_call (obj, object_size, mf_varname_tree (obj)); - } - else - { - size_t i; - - if (! deferred_static_decls) - VARRAY_TREE_INIT (deferred_static_decls, 10, "deferred static list"); - - /* Ugh, linear search... */ - for (i = 0; i < VARRAY_ACTIVE_SIZE (deferred_static_decls); i++) - if (VARRAY_TREE (deferred_static_decls, i) == obj) - { - warning ("mudflap cannot track unknown size extern %qs", - IDENTIFIER_POINTER (DECL_NAME (obj))); - return; - } - - VARRAY_PUSH_TREE (deferred_static_decls, obj); - } + VARRAY_PUSH_TREE (deferred_static_decls, obj); } + void mudflap_enqueue_constant (tree obj) { @@ -1237,15 +1215,6 @@ mudflap_enqueue_constant (tree obj) else object_size = size_in_bytes (TREE_TYPE (obj)); - if (dump_file) - { - fprintf (dump_file, "enqueue_constant obj=`"); - print_generic_expr (dump_file, obj, dump_flags); - fprintf (dump_file, "' size="); - print_generic_expr (dump_file, object_size, dump_flags); - fprintf (dump_file, "\n"); - } - if (TREE_CODE (obj) == STRING_CST) varname = mf_build_string ("string literal"); else @@ -1261,24 +1230,6 @@ mudflap_finish_file (void) { tree ctor_statements = NULL_TREE; - /* Try to give the deferred objects one final try. */ - if (deferred_static_decls) - { - size_t i; - - for (i = 0; i < VARRAY_ACTIVE_SIZE (deferred_static_decls); i++) - { - tree obj = VARRAY_TREE (deferred_static_decls, i); - - /* Call enqueue_decl again on the same object it has previously - put into the table. (It won't modify the table this time, so - infinite iteration is not a problem.) */ - mudflap_enqueue_decl (obj); - } - - VARRAY_CLEAR (deferred_static_decls); - } - /* Insert a call to __mf_init. */ { tree call2_stmt = build_function_call_expr (mf_init_fndecl, NULL_TREE); @@ -1294,6 +1245,41 @@ mudflap_finish_file (void) append_to_statement_list (call_stmt, &ctor_statements); } + /* Process all enqueued object decls. */ + if (deferred_static_decls) + { + size_t i; + for (i = 0; i < VARRAY_ACTIVE_SIZE (deferred_static_decls); i++) + { + tree obj = VARRAY_TREE (deferred_static_decls, i); + + gcc_assert (DECL_P (obj)); + + if (mf_marked_p (obj)) + continue; + + /* Omit registration for static unaddressed objects. NB: + Perform registration for non-static objects regardless of + TREE_USED or TREE_ADDRESSABLE, because they may be used + from other compilation units. */ + if (TREE_STATIC (obj) && ! TREE_ADDRESSABLE (obj)) + continue; + + if (! COMPLETE_TYPE_P (TREE_TYPE (obj))) + { + warning ("mudflap cannot track unknown size extern %qs", + IDENTIFIER_POINTER (DECL_NAME (obj))); + continue; + } + + mudflap_register_call (obj, + size_in_bytes (TREE_TYPE (obj)), + mf_varname_tree (obj)); + } + + VARRAY_CLEAR (deferred_static_decls); + } + /* Append all the enqueued registration calls. */ if (enqueued_call_stmt_chain) { -- 2.11.0