summaryrefslogtreecommitdiff
path: root/gcc/esan.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/esan.c')
-rw-r--r--gcc/esan.c305
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);
+}