blob: 8f2f3fde9bcfd1818654b94839d27e9241087d06 [file] [log] [blame]
/* Code coverage instrumentation for fuzzing.
Copyright (C) 2015 Free Software Foundation, Inc.
Contributed by Dmitry Vyukov <dvyukov@google.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 "tree.h"
#include "basic-block.h"
#include "tree-ssa-alias.h"
#include "internal-fn.h"
#include "gimple-expr.h"
#include "is-a.h"
#include "gimple.h"
#include "gimple-iterator.h"
#include "tree-pass.h"
#include "asan.h"
unsigned
sancov_pass ()
{
initialize_sanitizer_builtins ();
/* Insert callback into beginning of every BB. */
tree fndecl = builtin_decl_implicit (BUILT_IN_SANITIZER_COV_TRACE_PC);
basic_block bb;
FOR_EACH_BB_FN (bb, cfun)
{
gimple_stmt_iterator gsi = gsi_after_labels (bb);
if (gsi_end_p (gsi))
continue;
gimple stmt = gsi_stmt (gsi);
gimple gcall = gimple_build_call (fndecl, 0);
gimple_set_location (gcall, gimple_location (stmt));
gsi_insert_before (&gsi, gcall, GSI_SAME_STMT);
}
return 0;
}
/* The pass's gate. */
static bool
sancov_gate (void)
{
return flag_sanitize_coverage;
}
/* The pass descriptor. */
namespace {
const pass_data pass_data_sancov =
{
GIMPLE_PASS, /* type */
"sancov", /* name */
OPTGROUP_NONE, /* optinfo_flags */
true, /* has_gate */
true, /* has_execute */
TV_NONE, /* tv_id */
( PROP_cfg ), /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
( TODO_update_ssa ), /* todo_flags_finish */
};
class pass_sancov : public gimple_opt_pass
{
public:
pass_sancov (gcc::context *ctxt)
: gimple_opt_pass (pass_data_sancov, ctxt)
{}
/* opt_pass methods: */
opt_pass * clone () { return new pass_sancov (m_ctxt); }
bool gate () { return sancov_gate (); }
unsigned int execute () { return sancov_pass (); }
}; // class pass_sancov
} // anon namespace
gimple_opt_pass *
make_pass_sancov (gcc::context *ctxt)
{
return new pass_sancov (ctxt);
}
static bool
sancov_gate_O0 (void)
{
return flag_sanitize_coverage && !optimize;
}
namespace {
const pass_data pass_data_sancov_O0 =
{
GIMPLE_PASS, /* type */
"sancov0", /* name */
OPTGROUP_NONE, /* optinfo_flags */
true, /* has_gate */
true, /* has_execute */
TV_NONE, /* tv_id */
( PROP_cfg ), /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
( TODO_update_ssa ), /* todo_flags_finish */
};
class pass_sancov_O0 : public gimple_opt_pass
{
public:
pass_sancov_O0 (gcc::context *ctxt)
: gimple_opt_pass (pass_data_sancov_O0, ctxt)
{}
/* opt_pass methods: */
bool gate () { return sancov_gate_O0 (); }
unsigned int execute () { return sancov_pass (); }
}; // class pass_sancov_O0
} // anon namespace
gimple_opt_pass *
make_pass_sancov_O0 (gcc::context *ctxt)
{
return new pass_sancov_O0 (ctxt);
}