diff options
Diffstat (limited to 'gcc/esan.c')
-rw-r--r-- | gcc/esan.c | 305 |
1 files changed, 305 insertions, 0 deletions
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); +} |