diff options
-rw-r--r-- | gcc/Makefile.in | 2 | ||||
-rw-r--r-- | gcc/builtins.def | 3 | ||||
-rw-r--r-- | gcc/esan.c | 305 | ||||
-rw-r--r-- | gcc/esan.h | 26 | ||||
-rw-r--r-- | gcc/flag-types.h | 1 | ||||
-rw-r--r-- | gcc/opts.c | 1 | ||||
-rw-r--r-- | gcc/passes.def | 3 | ||||
-rw-r--r-- | gcc/sanitizer.def | 47 | ||||
-rw-r--r-- | gcc/toplev.c | 4 | ||||
-rw-r--r-- | gcc/tree-pass.h | 2 |
10 files changed, 393 insertions, 1 deletions
diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 72afff1ab36..ddb799fe6f9 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1436,6 +1436,7 @@ OBJS = \ tree-affine.o \ asan.o \ tsan.o \ + esan.o \ ubsan.o \ sanopt.o \ sancov.o \ @@ -2415,6 +2416,7 @@ GTFILES = $(CPP_ID_DATA_H) $(srcdir)/input.h $(srcdir)/coretypes.h \ $(srcdir)/asan.c \ $(srcdir)/ubsan.c \ $(srcdir)/tsan.c \ + $(srcdir)/esan.c \ $(srcdir)/sanopt.c \ $(srcdir)/sancov.c \ $(srcdir)/ipa-devirt.c \ diff --git a/gcc/builtins.def b/gcc/builtins.def index 2fc7f65d95a..5a1f5b08601 100644 --- a/gcc/builtins.def +++ b/gcc/builtins.def @@ -210,7 +210,8 @@ along with GCC; see the file COPYING3. If not see DEF_BUILTIN (ENUM, "__builtin_" NAME, BUILT_IN_NORMAL, TYPE, TYPE, \ true, true, true, ATTRS, true, \ (flag_sanitize & (SANITIZE_ADDRESS | SANITIZE_THREAD \ - | SANITIZE_UNDEFINED | SANITIZE_NONDEFAULT) \ + | SANITIZE_UNDEFINED | SANITIZE_NONDEFAULT \ + | SANITIZE_EFFICIENCY_WORKING_SET) \ || flag_sanitize_coverage)) #undef DEF_CILKPLUS_BUILTIN diff --git a/gcc/esan.c b/gcc/esan.c new file mode 100644 index 00000000000..7bd66169e03 --- /dev/null +++ b/gcc/esan.c @@ -0,0 +1,305 @@ +/* EfficiencySanitizer. + Copyright (C) 2011-2018 Free Software Foundation, Inc. + Contributed by Denis Khalikov <d.khalikov@partner.samsung.com> + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "backend.h" +#include "rtl.h" +#include "tree.h" +#include "memmodel.h" +#include "gimple.h" +#include "tree-pass.h" +#include "cgraph.h" +#include "fold-const.h" +#include "gimplify.h" +#include "gimple-iterator.h" +#include "gimplify-me.h" +#include "tree-cfg.h" +#include "tree-iterator.h" +#include "esan.h" +#include "stringpool.h" +#include "attribs.h" +#include "builtins.h" +#include "asan.h" + +static tree +get_memory_access_decl (bool is_store, unsigned size, bool unaligned) +{ + enum built_in_function fcode; + if (!unaligned) + { + if (size <= 1) + fcode = is_store ? BUILT_IN_ESAN_ALIGNED_STORE1 + : BUILT_IN_ESAN_ALIGNED_LOAD1; + else if (size <= 3) + fcode = is_store ? BUILT_IN_ESAN_ALIGNED_STORE2 + : BUILT_IN_ESAN_ALIGNED_LOAD2; + else if (size <= 7) + fcode = is_store ? BUILT_IN_ESAN_ALIGNED_STORE4 + : BUILT_IN_ESAN_ALIGNED_LOAD4; + else if (size <= 15) + fcode = is_store ? BUILT_IN_ESAN_ALIGNED_STORE8 + : BUILT_IN_ESAN_ALIGNED_LOAD8; + else + fcode = is_store ? BUILT_IN_ESAN_ALIGNED_STORE16 + : BUILT_IN_ESAN_ALIGNED_LOAD16; + } else { + if (size <= 1) + fcode = is_store ? BUILT_IN_ESAN_UNALIGNED_STORE1 + : BUILT_IN_ESAN_UNALIGNED_LOAD1; + else if (size <= 3) + fcode = is_store ? BUILT_IN_ESAN_UNALIGNED_STORE2 + : BUILT_IN_ESAN_UNALIGNED_LOAD2; + else if (size <= 7) + fcode = is_store ? BUILT_IN_ESAN_UNALIGNED_STORE4 + : BUILT_IN_ESAN_UNALIGNED_LOAD4; + else if (size <= 15) + fcode = is_store ? BUILT_IN_ESAN_UNALIGNED_STORE8 + : BUILT_IN_ESAN_UNALIGNED_LOAD8; + else + fcode = is_store ? BUILT_IN_ESAN_UNALIGNED_STORE16 + : BUILT_IN_ESAN_UNALIGNED_LOAD16; + } + + return builtin_decl_implicit (fcode); +} + +static void +instrument_expr (gimple_stmt_iterator gsi, tree expr, bool is_store) +{ + tree base, expr_ptr; + basic_block bb; + HOST_WIDE_INT size; + gimple *stmt, *g; + gimple_seq seq; + location_t loc; + bool unaligned; + unsigned int align; + + size = int_size_in_bytes (TREE_TYPE (expr)); + if (size <= 0) + return; + + HOST_WIDE_INT unused_bitsize, unused_bitpos; + tree offset; + machine_mode mode; + int unsignedp, reversep, volatilep = 0; + base = get_inner_reference (expr, &unused_bitsize, &unused_bitpos, &offset, + &mode, &unsignedp, &reversep, &volatilep, false); + + if (TREE_READONLY (base) || (VAR_P (base) && DECL_HARD_REGISTER (base))) + return; + + stmt = gsi_stmt (gsi); + loc = gimple_location (stmt); + align = get_object_alignment (expr); + unaligned = false; + if (align < BITS_PER_UNIT) { + /* TODO: Instrument unaligned access. */ + } + + expr_ptr = build_fold_addr_expr (unshare_expr (expr)); + + expr_ptr = force_gimple_operand (expr_ptr, &seq, true, NULL_TREE); + g = gimple_build_call (get_memory_access_decl (is_store, size, unaligned), 1, expr_ptr); + gimple_set_location (g, loc); + gimple_seq_add_stmt_without_update (&seq, g); + + if (is_gimple_call (stmt) && is_store) + { + if (is_ctrl_altering_stmt (stmt)) + { + edge e; + + bb = gsi_bb (gsi); + e = find_fallthru_edge (bb->succs); + if (e) + gsi_insert_seq_on_edge_immediate (e, seq); + } + else + gsi_insert_seq_after (&gsi, seq, GSI_NEW_STMT); + } + else + gsi_insert_seq_before (&gsi, seq, GSI_SAME_STMT); +} + +static void +instrument_gimple (gimple_stmt_iterator *gsi) +{ + gimple *stmt; + tree rhs, lhs; + + stmt = gsi_stmt (*gsi); + if (is_gimple_call (stmt) + && (gimple_call_fndecl (stmt) + != builtin_decl_implicit (BUILT_IN_ESAN_INIT)) + && (gimple_call_fndecl (stmt) + != builtin_decl_implicit (BUILT_IN_ESAN_EXIT))) + { + return; + } + else if (is_gimple_assign (stmt) && !gimple_clobber_p (stmt)) + { + if (gimple_store_p (stmt)) + { + lhs = gimple_assign_lhs (stmt); + instrument_expr (*gsi, lhs, true); + } + if (gimple_assign_load_p (stmt)) + { + rhs = gimple_assign_rhs1 (stmt); + instrument_expr (*gsi, rhs, false); + } + } +} + +static void +instrument_memory_accesses (void) +{ + basic_block bb; + gimple_stmt_iterator gsi; + + FOR_EACH_BB_FN (bb, cfun) + { + for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) + { + instrument_gimple (&gsi); + } + } +} + +/* EfficiencySanitizer instrumentation pass. */ + +static unsigned +esan_pass (void) +{ + initialize_sanitizer_builtins (); + instrument_memory_accesses (); + return 0; +} + +/* Inserts __esan_init () into the list of CTORs and + __esan_exit() into the listof DCTORs. */ + +void +esan_finish_file (void) +{ + /* TODO: Implement params to esan_init and esan_exit + since that is needed for Cache fragmentation tool. */ + tree ctor_statements = NULL_TREE; + tree dctor_statements = NULL_TREE; + initialize_sanitizer_builtins (); + + tree init_decl = builtin_decl_implicit (BUILT_IN_ESAN_INIT); + tree exit_decl = builtin_decl_implicit (BUILT_IN_ESAN_EXIT); + + append_to_statement_list (build_call_expr (init_decl, 0), &ctor_statements); + cgraph_build_static_cdtor ('I', ctor_statements, + MAX_RESERVED_INIT_PRIORITY - 1); + + append_to_statement_list (build_call_expr (exit_decl, 0), &dctor_statements); + cgraph_build_static_cdtor ('D', dctor_statements, + MAX_RESERVED_INIT_PRIORITY - 1); +} + +/* The pass descriptor. */ + +namespace { + +const pass_data pass_data_esan = +{ + GIMPLE_PASS, /* type */ + "esan", /* name */ + OPTGROUP_NONE, /* optinfo_flags */ + TV_NONE, /* tv_id */ + ( PROP_ssa | PROP_cfg ), /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_update_ssa, /* todo_flags_finish */ +}; + +class pass_esan : public gimple_opt_pass +{ +public: + pass_esan (gcc::context *ctxt) + : gimple_opt_pass (pass_data_esan, ctxt) + {} + + /* opt_pass methods: */ + opt_pass * clone () { return new pass_esan (m_ctxt); } + virtual bool gate (function *) +{ + return (flag_sanitize & SANITIZE_EFFICIENCY_WORKING_SET) != 0; +} + + virtual unsigned int execute (function *) { return esan_pass (); } + +}; // class pass_esan + +} // anon namespace + +gimple_opt_pass * +make_pass_esan (gcc::context *ctxt) +{ + return new pass_esan (ctxt); +} + +namespace { + +const pass_data pass_data_esan_O0 = +{ + GIMPLE_PASS, /* type */ + "esan0", /* name */ + OPTGROUP_NONE, /* optinfo_flags */ + TV_NONE, /* tv_id */ + ( PROP_ssa | PROP_cfg ), /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_update_ssa, /* todo_flags_finish */ +}; + +class pass_esan_O0 : public gimple_opt_pass +{ +public: + pass_esan_O0 (gcc::context *ctxt) + : gimple_opt_pass (pass_data_esan_O0, ctxt) + {} + + /* opt_pass methods: */ + virtual bool gate (function *) + { + return ((flag_sanitize & SANITIZE_EFFICIENCY_WORKING_SET) != 0 + && !optimize); + } + + virtual unsigned int execute (function *) { return esan_pass (); } + +}; // class pass_esan_O0 + +} // anon namespace + +gimple_opt_pass * +make_pass_esan_O0 (gcc::context *ctxt) +{ + return new pass_esan_O0 (ctxt); +} diff --git a/gcc/esan.h b/gcc/esan.h new file mode 100644 index 00000000000..d948abfc8e8 --- /dev/null +++ b/gcc/esan.h @@ -0,0 +1,26 @@ +/* EfficiencySanitizer. + Copyright (C) 2011-2018 Free Software Foundation, Inc. + Contributed by Denis Khalikov <d.khalikov@partner.samsung.com> + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#ifndef TREE_ESAN +#define TREE_ESAN + +extern void esan_finish_file (void); + +#endif /* TREE_ESAN */ diff --git a/gcc/flag-types.h b/gcc/flag-types.h index 18cf0a3ed0d..bba059cd66e 100644 --- a/gcc/flag-types.h +++ b/gcc/flag-types.h @@ -254,6 +254,7 @@ enum sanitize_code { SANITIZE_VPTR = 1UL << 21, SANITIZE_BOUNDS_STRICT = 1UL << 22, SANITIZE_UI_OVERFLOW = 1 << 23, + SANITIZE_EFFICIENCY_WORKING_SET = 1UL << 24, SANITIZE_UNDEFINED = SANITIZE_SHIFT | SANITIZE_DIVIDE | SANITIZE_UNREACHABLE | SANITIZE_VLA | SANITIZE_NULL | SANITIZE_RETURN | SANITIZE_SI_OVERFLOW | SANITIZE_BOOL | SANITIZE_ENUM diff --git a/gcc/opts.c b/gcc/opts.c index 99542cbc358..e36ba9220b1 100644 --- a/gcc/opts.c +++ b/gcc/opts.c @@ -1466,6 +1466,7 @@ const struct sanitizer_opts_s sanitizer_opts[] = SANITIZER_OPT (returns-nonnull-attribute, SANITIZE_RETURNS_NONNULL_ATTRIBUTE), SANITIZER_OPT (object-size, SANITIZE_OBJECT_SIZE), SANITIZER_OPT (vptr, SANITIZE_VPTR), + SANITIZER_OPT (efficiency-working-set, SANITIZE_EFFICIENCY_WORKING_SET), SANITIZER_OPT (all, ~0), #undef SANITIZER_OPT { NULL, 0, 0 } diff --git a/gcc/passes.def b/gcc/passes.def index 7aed1444542..792e6fa2e81 100644 --- a/gcc/passes.def +++ b/gcc/passes.def @@ -250,6 +250,7 @@ along with GCC; see the file COPYING3. If not see NEXT_PASS (pass_sancov); NEXT_PASS (pass_asan); NEXT_PASS (pass_tsan); + NEXT_PASS (pass_esan); /* Pass group that runs when 1) enabled, 2) there are loops in the function. Make sure to run pass_fix_loops before to discover/remove loops before running the gate function @@ -354,6 +355,7 @@ along with GCC; see the file COPYING3. If not see NEXT_PASS (pass_sancov); NEXT_PASS (pass_asan); NEXT_PASS (pass_tsan); + NEXT_PASS (pass_esan); /* ??? We do want some kind of loop invariant motion, but we possibly need to adjust LIM to be more friendly towards preserving accurate debug information here. */ @@ -378,6 +380,7 @@ along with GCC; see the file COPYING3. If not see NEXT_PASS (pass_sancov_O0); NEXT_PASS (pass_asan_O0); NEXT_PASS (pass_tsan_O0); + NEXT_PASS (pass_esan_O0); NEXT_PASS (pass_sanopt); NEXT_PASS (pass_cleanup_eh); NEXT_PASS (pass_lower_resx); diff --git a/gcc/sanitizer.def b/gcc/sanitizer.def index b229d5c94ff..b8fdc33a4cc 100644 --- a/gcc/sanitizer.def +++ b/gcc/sanitizer.def @@ -166,6 +166,53 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_AFTER_DYNAMIC_INIT, "__asan_after_dynamic_init", BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST) +/* Efficiency Sanitizer */ +DEF_SANITIZER_BUILTIN(BUILT_IN_ESAN_INIT, "__esan_init", + BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST) +DEF_SANITIZER_BUILTIN(BUILT_IN_ESAN_EXIT, "__esan_exit", + BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST) +DEF_SANITIZER_BUILTIN (BUILT_IN_ESAN_ALIGNED_STORE1, "__esan_aligned_store1", + BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST) +DEF_SANITIZER_BUILTIN (BUILT_IN_ESAN_ALIGNED_LOAD1, "__esan_aligned_load1", + BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST) +DEF_SANITIZER_BUILTIN (BUILT_IN_ESAN_ALIGNED_STORE2, "__esan_aligned_store2", + BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST) +DEF_SANITIZER_BUILTIN (BUILT_IN_ESAN_ALIGNED_LOAD2, "__esan_aligned_load2", + BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST) +DEF_SANITIZER_BUILTIN (BUILT_IN_ESAN_ALIGNED_STORE4, "__esan_aligned_store4", + BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST) +DEF_SANITIZER_BUILTIN (BUILT_IN_ESAN_ALIGNED_LOAD4, "__esan_aligned_load4", + BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST) +DEF_SANITIZER_BUILTIN (BUILT_IN_ESAN_ALIGNED_STORE8, "__esan_aligned_store8", + BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST) +DEF_SANITIZER_BUILTIN (BUILT_IN_ESAN_ALIGNED_LOAD8, "__esan_aligned_load8", + BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST) +DEF_SANITIZER_BUILTIN (BUILT_IN_ESAN_ALIGNED_STORE16, "__esan_aligned_store16", + BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST) +DEF_SANITIZER_BUILTIN (BUILT_IN_ESAN_ALIGNED_LOAD16, "__esan_aligned_load16", + BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST) +DEF_SANITIZER_BUILTIN (BUILT_IN_ESAN_UNALIGNED_STORE1, "__esan_unaligned_store1", + BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST) +DEF_SANITIZER_BUILTIN (BUILT_IN_ESAN_UNALIGNED_LOAD1, "__esan_unaligned_load1", + BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST) +DEF_SANITIZER_BUILTIN (BUILT_IN_ESAN_UNALIGNED_STORE2, "__esan_unaligned_store2", + BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST) +DEF_SANITIZER_BUILTIN (BUILT_IN_ESAN_UNALIGNED_LOAD2, "__esan_unaligned_load2", + BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST) +DEF_SANITIZER_BUILTIN (BUILT_IN_ESAN_UNALIGNED_STORE4, "__esan_unaligned_store4", + BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST) +DEF_SANITIZER_BUILTIN (BUILT_IN_ESAN_UNALIGNED_LOAD4, "__esan_unaligned_load4", + BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST) +DEF_SANITIZER_BUILTIN (BUILT_IN_ESAN_UNALIGNED_STORE8, "__esan_unaligned_store8", + BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST) +DEF_SANITIZER_BUILTIN (BUILT_IN_ESAN_UNALIGNED_LOAD8, "__esan_unaligned_load8", + BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST) +DEF_SANITIZER_BUILTIN (BUILT_IN_ESAN_UNALIGNED_STORE16, "__esan_unaligned_store16", + BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST) +DEF_SANITIZER_BUILTIN (BUILT_IN_ESAN_UNALIGNED_LOAD16, "__esan_unaligned_load16", + BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST) + + /* Thread Sanitizer */ DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_INIT, "__tsan_init", BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST) diff --git a/gcc/toplev.c b/gcc/toplev.c index 3e0b54ae246..511292c291a 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -64,6 +64,7 @@ along with GCC; see the file COPYING3. If not see #include "opts-diagnostic.h" #include "asan.h" #include "tsan.h" +#include "esan.h" #include "plugin.h" #include "context.h" #include "pass_manager.h" @@ -519,6 +520,9 @@ compile_file (void) if (flag_sanitize & SANITIZE_THREAD) tsan_finish_file (); + if (flag_sanitize & SANITIZE_EFFICIENCY_WORKING_SET) + esan_finish_file (); + if (flag_check_pointer_bounds) chkp_finish_file (); diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h index 5f5055d3a6c..17b31704181 100644 --- a/gcc/tree-pass.h +++ b/gcc/tree-pass.h @@ -351,6 +351,8 @@ extern gimple_opt_pass *make_pass_asan (gcc::context *ctxt); extern gimple_opt_pass *make_pass_asan_O0 (gcc::context *ctxt); extern gimple_opt_pass *make_pass_tsan (gcc::context *ctxt); extern gimple_opt_pass *make_pass_tsan_O0 (gcc::context *ctxt); +extern gimple_opt_pass *make_pass_esan (gcc::context *ctxt); +extern gimple_opt_pass *make_pass_esan_O0 (gcc::context *ctxt); extern gimple_opt_pass *make_pass_sancov (gcc::context *ctxt); extern gimple_opt_pass *make_pass_sancov_O0 (gcc::context *ctxt); extern gimple_opt_pass *make_pass_lower_cf (gcc::context *ctxt); |