/* Mudflap: narrow-pointer bounds-checking by tree rewriting.
- Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+ Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012
Free Software Foundation, Inc.
Contributed by Frank Ch. Eigler <fche@redhat.com>
and Graydon Hoare <graydon@redhat.com>
#include "system.h"
#include "coretypes.h"
#include "tm.h"
-#include "hard-reg-set.h"
-#include "rtl.h"
#include "tree.h"
#include "tm_p.h"
#include "basic-block.h"
#include "tree-pass.h"
#include "hashtab.h"
#include "diagnostic.h"
-#include <demangle.h>
+#include "demangle.h"
#include "langhooks.h"
#include "ggc.h"
#include "cgraph.h"
-#include "toplev.h"
#include "gimple.h"
/* Internal function decls */
/* Indirection-related instrumentation. */
static void mf_decl_cache_locals (void);
static void mf_decl_clear_locals (void);
-static void mf_xform_derefs (void);
+static void mf_xform_statements (void);
static unsigned int execute_mudflap_function_ops (void);
/* Addressable variables instrumentation. */
static gimple_seq mx_register_decls (tree, gimple_seq, location_t);
static unsigned int execute_mudflap_function_decls (void);
+/* Return true if DECL is artificial stub that shouldn't be instrumented by
+ mf. We should instrument clones of non-artificial functions. */
+static inline bool
+mf_artificial (const_tree decl)
+{
+ return DECL_ARTIFICIAL (DECL_ORIGIN (decl));
+}
/* ------------------------------------------------------------------------ */
/* Some generally helpful functions for mudflap instrumentation. */
tree result = mf_mark (build_string (len + 1, string));
TREE_TYPE (result) = build_array_type
- (char_type_node, build_index_type (build_int_cst (NULL_TREE, len)));
+ (char_type_node, build_index_type (size_int (len)));
TREE_CONSTANT (result) = 1;
TREE_READONLY (result) = 1;
TREE_STATIC (result) = 1;
static inline tree
mf_make_builtin (enum tree_code category, const char *name, tree type)
{
- tree decl = mf_mark (build_decl (category, get_identifier (name), type));
+ tree decl = mf_mark (build_decl (UNKNOWN_LOCATION,
+ category, get_identifier (name), type));
TREE_PUBLIC (decl) = 1;
DECL_EXTERNAL (decl) = 1;
lang_hooks.decls.pushdecl (decl);
/* There is, abominably, no language-independent way to construct a
RECORD_TYPE. So we have to call the basic type construction
primitives by hand. */
- tree fieldlo = build_decl (FIELD_DECL, get_identifier ("low"), field_type);
- tree fieldhi = build_decl (FIELD_DECL, get_identifier ("high"), field_type);
+ tree fieldlo = build_decl (UNKNOWN_LOCATION,
+ FIELD_DECL, get_identifier ("low"), field_type);
+ tree fieldhi = build_decl (UNKNOWN_LOCATION,
+ FIELD_DECL, get_identifier ("high"), field_type);
tree struct_type = make_node (RECORD_TYPE);
DECL_CONTEXT (fieldlo) = struct_type;
DECL_CONTEXT (fieldhi) = struct_type;
- TREE_CHAIN (fieldlo) = fieldhi;
+ DECL_CHAIN (fieldlo) = fieldhi;
TYPE_FIELDS (struct_type) = fieldlo;
TYPE_NAME (struct_type) = get_identifier ("__mf_cache");
layout_type (struct_type);
return struct_type;
}
-#define build_function_type_0(rtype) \
- build_function_type (rtype, void_list_node)
-#define build_function_type_1(rtype, arg1) \
- build_function_type (rtype, tree_cons (0, arg1, void_list_node))
-#define build_function_type_3(rtype, arg1, arg2, arg3) \
- build_function_type (rtype, \
- tree_cons (0, arg1, \
- tree_cons (0, arg2, \
- tree_cons (0, arg3, \
- void_list_node))))
-#define build_function_type_4(rtype, arg1, arg2, arg3, arg4) \
- build_function_type (rtype, \
- tree_cons (0, arg1, \
- tree_cons (0, arg2, \
- tree_cons (0, arg3, \
- tree_cons (0, arg4, \
- void_list_node)))))
-
/* Initialize the global tree nodes that correspond to mf-runtime.h
declarations. */
void
mf_cache_structptr_type = build_pointer_type (mf_cache_struct_type);
mf_cache_array_type = build_array_type (mf_cache_struct_type, 0);
mf_check_register_fntype =
- build_function_type_4 (void_type_node, ptr_type_node, size_type_node,
- integer_type_node, mf_const_string_type);
+ build_function_type_list (void_type_node, ptr_type_node, size_type_node,
+ integer_type_node, mf_const_string_type, NULL_TREE);
mf_unregister_fntype =
- build_function_type_3 (void_type_node, ptr_type_node, size_type_node,
- integer_type_node);
+ build_function_type_list (void_type_node, ptr_type_node, size_type_node,
+ integer_type_node, NULL_TREE);
mf_init_fntype =
- build_function_type_0 (void_type_node);
+ build_function_type_list (void_type_node, NULL_TREE);
mf_set_options_fntype =
- build_function_type_1 (integer_type_node, mf_const_string_type);
+ build_function_type_list (integer_type_node, mf_const_string_type, NULL_TREE);
mf_cache_array_decl = mf_make_builtin (VAR_DECL, "__mf_lookup_cache",
mf_cache_array_type);
mf_set_options_fndecl = mf_make_builtin (FUNCTION_DECL, "__mf_set_options",
mf_set_options_fntype);
}
-#undef build_function_type_4
-#undef build_function_type_3
-#undef build_function_type_1
-#undef build_function_type_0
/* ------------------------------------------------------------------------ */
-/* Memory reference transforms. Perform the mudflap indirection-related
- tree transforms on the current function.
-
- This is the second part of the mudflap instrumentation. It works on
+/* This is the second part of the mudflap instrumentation. It works on
low-level GIMPLE using the CFG, because we want to run this pass after
tree optimizations have been performed, but we have to preserve the CFG
- for expansion from trees to RTL. */
+ for expansion from trees to RTL.
+ Below is the list of transformations performed on statements in the
+ current function.
+
+ 1) Memory reference transforms: Perform the mudflap indirection-related
+ tree transforms on memory references.
+
+ 2) Mark BUILTIN_ALLOCA calls not inlineable.
+
+ */
static unsigned int
execute_mudflap_function_ops (void)
/* Don't instrument functions such as the synthetic constructor
built during mudflap_finish_file. */
- if (mf_marked_p (current_function_decl) ||
- DECL_ARTIFICIAL (current_function_decl))
+ if (mf_marked_p (current_function_decl)
+ || mf_artificial (current_function_decl))
return 0;
push_gimplify_context (&gctx);
+ add_referenced_var (mf_cache_array_decl);
+ add_referenced_var (mf_cache_shift_decl);
+ add_referenced_var (mf_cache_mask_decl);
+
/* In multithreaded mode, don't cache the lookup cache parameters. */
if (! flag_mudflap_threads)
mf_decl_cache_locals ();
- mf_xform_derefs ();
+ mf_xform_statements ();
if (! flag_mudflap_threads)
mf_decl_clear_locals ();
/* Build: __mf_base = (uintptr_t) <base address expression>. */
seq = gimple_seq_alloc ();
- t = fold_convert (mf_uintptr_type, unshare_expr (base));
+ t = fold_convert_loc (location, mf_uintptr_type,
+ unshare_expr (base));
t = force_gimple_operand (t, &stmts, false, NULL_TREE);
gimple_seq_add_seq (&seq, stmts);
g = gimple_build_assign (mf_base, t);
gimple_seq_add_stmt (&seq, g);
/* Build: __mf_limit = (uintptr_t) <limit address expression>. */
- t = fold_convert (mf_uintptr_type, unshare_expr (limit));
+ t = fold_convert_loc (location, mf_uintptr_type,
+ unshare_expr (limit));
t = force_gimple_operand (t, &stmts, false, NULL_TREE);
gimple_seq_add_seq (&seq, stmts);
g = gimple_build_assign (mf_limit, t);
u = build3 (COMPONENT_REF, mf_uintptr_type,
build1 (INDIRECT_REF, mf_cache_struct_type, mf_elem),
- TREE_CHAIN (TYPE_FIELDS (mf_cache_struct_type)), NULL_TREE);
+ DECL_CHAIN (TYPE_FIELDS (mf_cache_struct_type)), NULL_TREE);
v = mf_limit;
/* u is a string, so it is already a gimple value. */
u = mf_file_function_line_tree (location);
/* NB: we pass the overall [base..limit] range to mf_check. */
- v = fold_build2 (PLUS_EXPR, mf_uintptr_type,
- fold_build2 (MINUS_EXPR, mf_uintptr_type, mf_limit, mf_base),
+ v = fold_build2_loc (location, PLUS_EXPR, mf_uintptr_type,
+ fold_build2_loc (location,
+ MINUS_EXPR, mf_uintptr_type, mf_limit, mf_base),
build_int_cst (mf_uintptr_type, 1));
v = force_gimple_operand (v, &stmts, true, NULL_TREE);
gimple_seq_add_seq (&seq, stmts);
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. */
+ out: looking just at the outer node is not enough. */
tree var;
int component_ref_only = (TREE_CODE (t) == COMPONENT_REF);
/* If we have a bitfield component reference, we must note the
&& (TREE_CODE (var) == ARRAY_REF
|| TREE_CODE (var) == COMPONENT_REF))
elt = var;
-
+
if (TREE_CODE (var) == ARRAY_REF)
{
component_ref_only = 0;
}
else if (TREE_CODE (var) == COMPONENT_REF)
var = TREE_OPERAND (var, 0);
- else if (INDIRECT_REF_P (var))
+ else if (INDIRECT_REF_P (var)
+ || TREE_CODE (var) == MEM_REF)
{
base = TREE_OPERAND (var, 0);
break;
&& TREE_CODE (var) != STRING_CST)
return;
}
- else
+ else
{
- gcc_assert (TREE_CODE (var) == VAR_DECL
+ gcc_assert (TREE_CODE (var) == VAR_DECL
|| TREE_CODE (var) == PARM_DECL
|| TREE_CODE (var) == RESULT_DECL
|| TREE_CODE (var) == STRING_CST);
if (TREE_CODE (DECL_SIZE_UNIT (field)) == INTEGER_CST)
size = DECL_SIZE_UNIT (field);
-
+
if (elt)
elt = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (elt)),
elt);
- addr = fold_convert (ptr_type_node, elt ? elt : base);
- addr = fold_build2 (POINTER_PLUS_EXPR, ptr_type_node,
- addr, fold_convert (sizetype,
- byte_position (field)));
+ addr = fold_convert_loc (location, ptr_type_node, elt ? elt : base);
+ addr = fold_build_pointer_plus_loc (location,
+ addr, byte_position (field));
}
else
addr = build1 (ADDR_EXPR, build_pointer_type (type), t);
- limit = fold_build2 (MINUS_EXPR, mf_uintptr_type,
- fold_build2 (PLUS_EXPR, mf_uintptr_type,
- convert (mf_uintptr_type, addr),
+ limit = fold_build2_loc (location, MINUS_EXPR, mf_uintptr_type,
+ fold_build2_loc (location, PLUS_EXPR, mf_uintptr_type,
+ fold_convert (mf_uintptr_type, addr),
size),
integer_one_node);
}
case INDIRECT_REF:
addr = TREE_OPERAND (t, 0);
base = addr;
- limit = fold_build2 (POINTER_PLUS_EXPR, ptr_type_node,
- fold_build2 (POINTER_PLUS_EXPR, ptr_type_node, base,
- size),
- size_int (-1));
+ limit = fold_build_pointer_plus_hwi_loc
+ (location, fold_build_pointer_plus_loc (location, base, size), -1);
+ break;
+
+ case MEM_REF:
+ addr = fold_build_pointer_plus_loc (location, TREE_OPERAND (t, 0),
+ TREE_OPERAND (t, 1));
+ base = addr;
+ limit = fold_build_pointer_plus_hwi_loc (location,
+ fold_build_pointer_plus_loc (location,
+ base, size), -1);
break;
case TARGET_MEM_REF:
addr = tree_mem_ref_addr (ptr_type_node, t);
base = addr;
- limit = fold_build2 (POINTER_PLUS_EXPR, ptr_type_node,
- fold_build2 (POINTER_PLUS_EXPR, ptr_type_node, base,
- size),
- size_int (-1));
+ limit = fold_build_pointer_plus_hwi_loc (location,
+ fold_build_pointer_plus_loc (location,
+ base, size), -1);
break;
case ARRAY_RANGE_REF:
return;
bpu = bitsize_int (BITS_PER_UNIT);
- ofs = convert (bitsizetype, TREE_OPERAND (t, 2));
- rem = size_binop (TRUNC_MOD_EXPR, ofs, bpu);
- ofs = fold_convert (sizetype, size_binop (TRUNC_DIV_EXPR, ofs, bpu));
+ ofs = fold_convert (bitsizetype, TREE_OPERAND (t, 2));
+ rem = size_binop_loc (location, TRUNC_MOD_EXPR, ofs, bpu);
+ ofs = size_binop_loc (location, TRUNC_DIV_EXPR, ofs, bpu);
- size = convert (bitsizetype, TREE_OPERAND (t, 1));
- size = size_binop (PLUS_EXPR, size, rem);
- size = size_binop (CEIL_DIV_EXPR, size, bpu);
- size = convert (sizetype, size);
+ size = fold_convert (bitsizetype, TREE_OPERAND (t, 1));
+ size = size_binop_loc (location, PLUS_EXPR, size, rem);
+ size = size_binop_loc (location, CEIL_DIV_EXPR, size, bpu);
+ size = fold_convert (sizetype, size);
addr = TREE_OPERAND (TREE_OPERAND (t, 0), 0);
- addr = convert (ptr_type_node, addr);
- addr = fold_build2 (POINTER_PLUS_EXPR, ptr_type_node, addr, ofs);
+ addr = fold_convert (ptr_type_node, addr);
+ addr = fold_build_pointer_plus_loc (location, addr, ofs);
base = addr;
- limit = fold_build2 (POINTER_PLUS_EXPR, ptr_type_node,
- fold_build2 (POINTER_PLUS_EXPR, ptr_type_node,
- base, size),
- size_int (-1));
+ limit = fold_build_pointer_plus_hwi_loc (location,
+ fold_build_pointer_plus_loc (location,
+ base, size), -1);
}
break;
mf_build_check_statement_for (base, limit, iter, location, dirflag);
}
-
+/* Transform
+ 1) Memory references.
+*/
static void
-mf_xform_derefs (void)
+mf_xform_statements (void)
{
basic_block bb, next;
gimple_stmt_iterator i;
/* Don't instrument functions such as the synthetic constructor
built during mudflap_finish_file. */
- if (mf_marked_p (current_function_decl) ||
- DECL_ARTIFICIAL (current_function_decl))
+ if (mf_marked_p (current_function_decl)
+ || mf_artificial (current_function_decl))
return 0;
push_gimplify_context (&gctx);
while (decl != NULL_TREE)
{
- if (mf_decl_eligible_p (decl)
+ if (mf_decl_eligible_p (decl)
/* Not already processed. */
&& ! mf_marked_p (decl)
/* Automatic variable. */
/* Variable-sized objects should have sizes already been
gimplified when we got here. */
- size = convert (size_type_node, TYPE_SIZE_UNIT (TREE_TYPE (decl)));
+ size = fold_convert (size_type_node,
+ TYPE_SIZE_UNIT (TREE_TYPE (decl)));
gcc_assert (is_gimple_val (size));
-
+
unregister_fncall_param =
mf_mark (build1 (ADDR_EXPR,
unregister_fncall = gimple_build_call (mf_unregister_fndecl, 3,
unregister_fncall_param,
size,
- build_int_cst (NULL_TREE, 3));
+ integer_three_node);
variable_name = mf_varname_tree (decl);
register_fncall = gimple_build_call (mf_register_fndecl, 4,
register_fncall_param,
size,
- build_int_cst (NULL_TREE, 3),
+ integer_three_node,
variable_name);
-
+
/* Accumulate the two calls. */
gimple_set_location (register_fncall, location);
/* Add the __mf_register call at the current appending point. */
if (gsi_end_p (initially_stmts))
{
- if (!DECL_ARTIFICIAL (decl))
+ if (!mf_artificial (decl))
warning (OPT_Wmudflap,
"mudflap cannot track %qE in stub function",
DECL_NAME (decl));
mf_mark (decl);
}
- decl = TREE_CHAIN (decl);
+ decl = DECL_CHAIN (decl);
}
/* Actually, (initially_stmts!=NULL) <=> (finally_stmts!=NULL) */
tree arg, call_stmt;
arg = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (obj)), obj);
- arg = convert (ptr_type_node, arg);
+ arg = fold_convert (ptr_type_node, arg);
call_stmt = build_call_expr (mf_register_fndecl, 4,
arg,
- convert (size_type_node, object_size),
+ fold_convert (size_type_node, object_size),
/* __MF_TYPE_STATIC */
- build_int_cst (NULL_TREE, 4),
+ build_int_cst (integer_type_node, 4),
varname);
append_to_statement_list (call_stmt, &enqueued_call_stmt_chain);
during mudflap_finish_file (). That would confuse the user,
since the text would refer to variables that don't show up in the
user's source code. */
- if (DECL_P (obj) && DECL_EXTERNAL (obj) && DECL_ARTIFICIAL (obj))
+ if (DECL_P (obj) && DECL_EXTERNAL (obj) && mf_artificial (obj))
return;
VEC_safe_push (tree, gc, deferred_static_decls, obj);
return;
if (TREE_CODE (obj) == STRING_CST)
- object_size = build_int_cst (NULL_TREE, TREE_STRING_LENGTH (obj));
+ object_size = size_int (TREE_STRING_LENGTH (obj));
else
object_size = size_in_bytes (TREE_TYPE (obj));
tree ctor_statements = NULL_TREE;
/* No need to continue when there were errors. */
- if (errorcount != 0 || sorrycount != 0)
+ if (seen_error ())
return;
/* Insert a call to __mf_init. */
tree call2_stmt = build_call_expr (mf_init_fndecl, 0);
append_to_statement_list (call2_stmt, &ctor_statements);
}
-
+
/* If appropriate, call __mf_set_options to pass along read-ignore mode. */
if (flag_mudflap_ignore_reads)
{
{
size_t i;
tree obj;
- for (i = 0; VEC_iterate (tree, deferred_static_decls, i, obj); i++)
+ FOR_EACH_VEC_ELT (tree, deferred_static_decls, i, obj)
{
gcc_assert (DECL_P (obj));
DECL_NAME (obj));
continue;
}
-
- mudflap_register_call (obj,
+
+ mudflap_register_call (obj,
size_in_bytes (TREE_TYPE (obj)),
mf_varname_tree (obj));
}
enqueued_call_stmt_chain = NULL_TREE;
}
- cgraph_build_static_cdtor ('I', ctor_statements,
+ cgraph_build_static_cdtor ('I', ctor_statements,
MAX_RESERVED_INIT_PRIORITY-1);
}
return flag_mudflap != 0;
}
-struct gimple_opt_pass pass_mudflap_1 =
+struct gimple_opt_pass pass_mudflap_1 =
{
{
GIMPLE_PASS,
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- TODO_dump_func /* todo_flags_finish */
+ 0 /* todo_flags_finish */
}
};
-struct gimple_opt_pass pass_mudflap_2 =
+struct gimple_opt_pass pass_mudflap_2 =
{
{
GIMPLE_PASS,
0, /* properties_destroyed */
0, /* todo_flags_start */
TODO_verify_flow | TODO_verify_stmts
- | TODO_dump_func | TODO_update_ssa /* todo_flags_finish */
+ | TODO_update_ssa /* todo_flags_finish */
}
};