summaryrefslogtreecommitdiff
path: root/gcc/function.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/function.c')
-rw-r--r--gcc/function.c268
1 files changed, 248 insertions, 20 deletions
diff --git a/gcc/function.c b/gcc/function.c
index 91e3b2c14fb..0ffff5b77bc 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -78,6 +78,8 @@ along with GCC; see the file COPYING3. If not see
#include "shrink-wrap.h"
#include "toplev.h"
#include "rtl-iter.h"
+#include "tree-chkp.h"
+#include "rtl-chkp.h"
/* So we can assign to cfun in this file. */
#undef cfun
@@ -2101,6 +2103,14 @@ use_register_for_decl (const_tree decl)
if (TREE_ADDRESSABLE (decl))
return false;
+ /* Decl is implicitly addressible by bound stores and loads
+ if it is an aggregate holding bounds. */
+ if (chkp_function_instrumented_p (current_function_decl)
+ && TREE_TYPE (decl)
+ && !BOUNDED_P (decl)
+ && chkp_type_has_pointer (TREE_TYPE (decl)))
+ return false;
+
/* Only register-like things go in registers. */
if (DECL_MODE (decl) == BLKmode)
return false;
@@ -2221,6 +2231,15 @@ struct assign_parm_data_one
BOOL_BITFIELD loaded_in_reg : 1;
};
+struct bounds_parm_data
+{
+ assign_parm_data_one parm_data;
+ tree bounds_parm;
+ tree ptr_parm;
+ rtx ptr_entry;
+ int bound_no;
+};
+
/* A subroutine of assign_parms. Initialize ALL. */
static void
@@ -2332,6 +2351,23 @@ assign_parms_augmented_arg_list (struct assign_parm_data_all *all)
fnargs.safe_insert (0, decl);
all->function_result_decl = decl;
+
+ /* If function is instrumented then bounds of the
+ passed structure address is the second argument. */
+ if (chkp_function_instrumented_p (fndecl))
+ {
+ decl = build_decl (DECL_SOURCE_LOCATION (fndecl),
+ PARM_DECL, get_identifier (".result_bnd"),
+ pointer_bounds_type_node);
+ DECL_ARG_TYPE (decl) = pointer_bounds_type_node;
+ DECL_ARTIFICIAL (decl) = 1;
+ DECL_NAMELESS (decl) = 1;
+ TREE_CONSTANT (decl) = 1;
+
+ DECL_CHAIN (decl) = DECL_CHAIN (all->orig_fnargs);
+ DECL_CHAIN (all->orig_fnargs) = decl;
+ fnargs.safe_insert (1, decl);
+ }
}
/* If the target wants to split complex arguments into scalars, do so. */
@@ -2472,7 +2508,7 @@ assign_parm_find_entry_rtl (struct assign_parm_data_all *all,
it came in a register so that REG_PARM_STACK_SPACE isn't skipped.
In this case, we call FUNCTION_ARG with NAMED set to 1 instead of 0
as it was the previous time. */
- in_regs = entry_parm != 0;
+ in_regs = (entry_parm != 0) || POINTER_BOUNDS_TYPE_P (data->passed_type);
#ifdef STACK_PARMS_IN_REG_PARM_AREA
in_regs = true;
#endif
@@ -2561,8 +2597,12 @@ static bool
assign_parm_is_stack_parm (struct assign_parm_data_all *all,
struct assign_parm_data_one *data)
{
+ /* Bounds are never passed on the stack to keep compatibility
+ with not instrumented code. */
+ if (POINTER_BOUNDS_TYPE_P (data->passed_type))
+ return false;
/* Trivially true if we've no incoming register. */
- if (data->entry_parm == NULL)
+ else if (data->entry_parm == NULL)
;
/* Also true if we're partially in registers and partially not,
since we've arranged to drop the entire argument on the stack. */
@@ -3371,6 +3411,123 @@ assign_parms_unsplit_complex (struct assign_parm_data_all *all,
}
}
+/* Load bounds of PARM from bounds table. */
+static void
+assign_parm_load_bounds (struct assign_parm_data_one *data,
+ tree parm,
+ rtx entry,
+ unsigned bound_no)
+{
+ bitmap_iterator bi;
+ unsigned i, offs = 0;
+ int bnd_no = -1;
+ rtx slot = NULL, ptr = NULL;
+
+ if (parm)
+ {
+ bitmap slots;
+ bitmap_obstack_initialize (NULL);
+ slots = BITMAP_ALLOC (NULL);
+ chkp_find_bound_slots (TREE_TYPE (parm), slots);
+ EXECUTE_IF_SET_IN_BITMAP (slots, 0, i, bi)
+ {
+ if (bound_no)
+ bound_no--;
+ else
+ {
+ bnd_no = i;
+ break;
+ }
+ }
+ BITMAP_FREE (slots);
+ bitmap_obstack_release (NULL);
+ }
+
+ /* We may have bounds not associated with any pointer. */
+ if (bnd_no != -1)
+ offs = bnd_no * POINTER_SIZE / BITS_PER_UNIT;
+
+ /* Find associated pointer. */
+ if (bnd_no == -1)
+ {
+ /* If bounds are not associated with any bounds,
+ then it is passed in a register or special slot. */
+ gcc_assert (data->entry_parm);
+ ptr = const0_rtx;
+ }
+ else if (MEM_P (entry))
+ slot = adjust_address (entry, Pmode, offs);
+ else if (REG_P (entry))
+ ptr = gen_rtx_REG (Pmode, REGNO (entry) + bnd_no);
+ else if (GET_CODE (entry) == PARALLEL)
+ ptr = chkp_get_value_with_offs (entry, GEN_INT (offs));
+ else
+ gcc_unreachable ();
+ data->entry_parm = targetm.calls.load_bounds_for_arg (slot, ptr,
+ data->entry_parm);
+}
+
+/* Assign RTL expressions to the function's bounds parameters BNDARGS. */
+
+static void
+assign_bounds (vec<bounds_parm_data> &bndargs,
+ struct assign_parm_data_all &all)
+{
+ unsigned i, pass, handled = 0;
+ bounds_parm_data *pbdata;
+
+ if (!bndargs.exists ())
+ return;
+
+ /* We make few passes to store input bounds. Firstly handle bounds
+ passed in registers. After that we load bounds passed in special
+ slots. Finally we load bounds from Bounds Table. */
+ for (pass = 0; pass < 3; pass++)
+ FOR_EACH_VEC_ELT (bndargs, i, pbdata)
+ {
+ /* Pass 0 => regs only. */
+ if (pass == 0
+ && (!pbdata->parm_data.entry_parm
+ || GET_CODE (pbdata->parm_data.entry_parm) != REG))
+ continue;
+ /* Pass 1 => slots only. */
+ else if (pass == 1
+ && (!pbdata->parm_data.entry_parm
+ || GET_CODE (pbdata->parm_data.entry_parm) == REG))
+ continue;
+ /* Pass 2 => BT only. */
+ else if (pass == 2
+ && pbdata->parm_data.entry_parm)
+ continue;
+
+ if (!pbdata->parm_data.entry_parm
+ || GET_CODE (pbdata->parm_data.entry_parm) != REG)
+ assign_parm_load_bounds (&pbdata->parm_data, pbdata->ptr_parm,
+ pbdata->ptr_entry, pbdata->bound_no);
+
+ set_decl_incoming_rtl (pbdata->bounds_parm,
+ pbdata->parm_data.entry_parm, false);
+
+ if (assign_parm_setup_block_p (&pbdata->parm_data))
+ assign_parm_setup_block (&all, pbdata->bounds_parm,
+ &pbdata->parm_data);
+ else if (pbdata->parm_data.passed_pointer
+ || use_register_for_decl (pbdata->bounds_parm))
+ assign_parm_setup_reg (&all, pbdata->bounds_parm,
+ &pbdata->parm_data);
+ else
+ assign_parm_setup_stack (&all, pbdata->bounds_parm,
+ &pbdata->parm_data);
+
+ /* Count handled bounds to make sure we miss nothing. */
+ handled++;
+ }
+
+ gcc_assert (handled == bndargs.length ());
+
+ bndargs.release ();
+}
+
/* Assign RTL expressions to the function's parameters. This may involve
copying them into registers and using those registers as the DECL_RTL. */
@@ -3380,7 +3537,11 @@ assign_parms (tree fndecl)
struct assign_parm_data_all all;
tree parm;
vec<tree> fnargs;
- unsigned i;
+ unsigned i, bound_no = 0;
+ tree last_arg = NULL;
+ rtx last_arg_entry = NULL;
+ vec<bounds_parm_data> bndargs = vNULL;
+ bounds_parm_data bdata;
crtl->args.internal_arg_pointer
= targetm.calls.internal_arg_pointer ();
@@ -3422,9 +3583,6 @@ assign_parms (tree fndecl)
}
}
- if (cfun->stdarg && !DECL_CHAIN (parm))
- assign_parms_setup_varargs (&all, &data, false);
-
/* Find out where the parameter arrives in this function. */
assign_parm_find_entry_rtl (&all, &data);
@@ -3434,7 +3592,15 @@ assign_parms (tree fndecl)
assign_parm_find_stack_rtl (parm, &data);
assign_parm_adjust_entry_rtl (&data);
}
-
+ if (!POINTER_BOUNDS_TYPE_P (data.passed_type))
+ {
+ /* Remember where last non bounds arg was passed in case
+ we have to load associated bounds for it from Bounds
+ Table. */
+ last_arg = parm;
+ last_arg_entry = data.entry_parm;
+ bound_no = 0;
+ }
/* Record permanently how this parm was passed. */
if (data.passed_pointer)
{
@@ -3446,20 +3612,63 @@ assign_parms (tree fndecl)
else
set_decl_incoming_rtl (parm, data.entry_parm, false);
+ /* Boudns should be loaded in the particular order to
+ have registers allocated correctly. Collect info about
+ input bounds and load them later. */
+ if (POINTER_BOUNDS_TYPE_P (data.passed_type))
+ {
+ /* Expect bounds in instrumented functions only. */
+ gcc_assert (chkp_function_instrumented_p (fndecl));
+
+ bdata.parm_data = data;
+ bdata.bounds_parm = parm;
+ bdata.ptr_parm = last_arg;
+ bdata.ptr_entry = last_arg_entry;
+ bdata.bound_no = bound_no;
+ bndargs.safe_push (bdata);
+ }
+ else
+ {
+ assign_parm_adjust_stack_rtl (&data);
+
+ if (assign_parm_setup_block_p (&data))
+ assign_parm_setup_block (&all, parm, &data);
+ else if (data.passed_pointer || use_register_for_decl (parm))
+ assign_parm_setup_reg (&all, parm, &data);
+ else
+ assign_parm_setup_stack (&all, parm, &data);
+ }
+
+ if (cfun->stdarg && !DECL_CHAIN (parm))
+ {
+ int pretend_bytes = 0;
+
+ assign_parms_setup_varargs (&all, &data, false);
+
+ if (chkp_function_instrumented_p (fndecl))
+ {
+ /* We expect this is the last parm. Otherwise it is wrong
+ to assign bounds right now. */
+ gcc_assert (i == (fnargs.length () - 1));
+ assign_bounds (bndargs, all);
+ targetm.calls.setup_incoming_vararg_bounds (all.args_so_far,
+ data.promoted_mode,
+ data.passed_type,
+ &pretend_bytes,
+ false);
+ }
+ }
+
/* Update info on where next arg arrives in registers. */
targetm.calls.function_arg_advance (all.args_so_far, data.promoted_mode,
data.passed_type, data.named_arg);
- assign_parm_adjust_stack_rtl (&data);
-
- if (assign_parm_setup_block_p (&data))
- assign_parm_setup_block (&all, parm, &data);
- else if (data.passed_pointer || use_register_for_decl (parm))
- assign_parm_setup_reg (&all, parm, &data);
- else
- assign_parm_setup_stack (&all, parm, &data);
+ if (POINTER_BOUNDS_TYPE_P (data.passed_type))
+ bound_no++;
}
+ assign_bounds (bndargs, all);
+
if (targetm.calls.split_complex_arg)
assign_parms_unsplit_complex (&all, fnargs);
@@ -3585,6 +3794,10 @@ assign_parms (tree fndecl)
real_decl_rtl = targetm.calls.function_value (TREE_TYPE (decl_result),
fndecl, true);
+ if (chkp_function_instrumented_p (fndecl))
+ crtl->return_bnd
+ = targetm.calls.chkp_function_value_bounds (TREE_TYPE (decl_result),
+ fndecl, true);
REG_FUNCTION_VALUE_P (real_decl_rtl) = 1;
/* The delay slot scheduler assumes that crtl->return_rtx
holds the hard register containing the return value, not a
@@ -4815,6 +5028,14 @@ expand_function_start (tree subr)
/* Set DECL_REGISTER flag so that expand_function_end will copy the
result to the real return register(s). */
DECL_REGISTER (DECL_RESULT (subr)) = 1;
+
+ if (chkp_function_instrumented_p (current_function_decl))
+ {
+ tree return_type = TREE_TYPE (DECL_RESULT (subr));
+ rtx bounds = targetm.calls.chkp_function_value_bounds (return_type,
+ subr, 1);
+ SET_DECL_BOUNDS_RTL (DECL_RESULT (subr), bounds);
+ }
}
/* Initialize rtx for parameters and local variables.
@@ -4918,14 +5139,11 @@ expand_dummy_function_end (void)
in_dummy_function = false;
}
-/* Call DOIT for each hard register used as a return value from
- the current function. */
+/* Helper for diddle_return_value. */
void
-diddle_return_value (void (*doit) (rtx, void *), void *arg)
+diddle_return_value_1 (void (*doit) (rtx, void *), void *arg, rtx outgoing)
{
- rtx outgoing = crtl->return_rtx;
-
if (! outgoing)
return;
@@ -4945,6 +5163,16 @@ diddle_return_value (void (*doit) (rtx, void *), void *arg)
}
}
+/* Call DOIT for each hard register used as a return value from
+ the current function. */
+
+void
+diddle_return_value (void (*doit) (rtx, void *), void *arg)
+{
+ diddle_return_value_1 (doit, arg, crtl->return_rtx);
+ diddle_return_value_1 (doit, arg, crtl->return_bnd);
+}
+
static void
do_clobber_return_reg (rtx reg, void *arg ATTRIBUTE_UNUSED)
{