2 * Copyright 2011-2016 by Emese Revfy <re.emese@gmail.com>
3 * Licensed under the GPL v2, or (at your option) v3
6 * https://github.com/ephox-gcc-plugins/sancov
8 * This plugin inserts a __sanitizer_cov_trace_pc() call at the start of basic blocks.
9 * It supports all gcc versions with plugin support (from gcc-4.5 on).
10 * It is based on the commit "Add fuzzing coverage support" by Dmitry Vyukov <dvyukov@google.com>.
12 * You can read about it more here:
13 * https://gcc.gnu.org/viewcvs/gcc?limit_changes=0&view=revision&revision=231296
14 * http://lwn.net/Articles/674854/
15 * https://github.com/google/syzkaller
16 * https://lwn.net/Articles/677764/
22 #include "gcc-common.h"
24 __visible
int plugin_is_GPL_compatible
;
28 static struct plugin_info sancov_plugin_info
= {
29 .version
= "20160402",
30 .help
= "sancov plugin\n",
33 static unsigned int sancov_execute(void)
37 /* Remove this line when this plugin and kcov will be in the kernel.
38 if (!strcmp(DECL_NAME_POINTER(current_function_decl), DECL_NAME_POINTER(sancov_fndecl)))
42 FOR_EACH_BB_FN(bb
, cfun
) {
45 gimple_stmt_iterator gsi
= gsi_after_labels(bb
);
51 gcall
= as_a_gcall(gimple_build_call(sancov_fndecl
, 0));
52 gimple_set_location(gcall
, gimple_location(stmt
));
53 gsi_insert_before(&gsi
, gcall
, GSI_SAME_STMT
);
58 #define PASS_NAME sancov
61 #define TODO_FLAGS_FINISH TODO_dump_func | TODO_verify_stmts | TODO_update_ssa_no_phi | TODO_verify_flow
63 #include "gcc-generate-gimple-pass.h"
65 static void sancov_start_unit(void __unused
*gcc_data
, void __unused
*user_data
)
67 tree leaf_attr
, nothrow_attr
;
68 tree BT_FN_VOID
= build_function_type_list(void_type_node
, NULL_TREE
);
70 sancov_fndecl
= build_fn_decl("__sanitizer_cov_trace_pc", BT_FN_VOID
);
72 DECL_ASSEMBLER_NAME(sancov_fndecl
);
73 TREE_PUBLIC(sancov_fndecl
) = 1;
74 DECL_EXTERNAL(sancov_fndecl
) = 1;
75 DECL_ARTIFICIAL(sancov_fndecl
) = 1;
76 DECL_PRESERVE_P(sancov_fndecl
) = 1;
77 DECL_UNINLINABLE(sancov_fndecl
) = 1;
78 TREE_USED(sancov_fndecl
) = 1;
80 nothrow_attr
= tree_cons(get_identifier("nothrow"), NULL
, NULL
);
81 decl_attributes(&sancov_fndecl
, nothrow_attr
, 0);
82 gcc_assert(TREE_NOTHROW(sancov_fndecl
));
83 #if BUILDING_GCC_VERSION > 4005
84 leaf_attr
= tree_cons(get_identifier("leaf"), NULL
, NULL
);
85 decl_attributes(&sancov_fndecl
, leaf_attr
, 0);
89 __visible
int plugin_init(struct plugin_name_args
*plugin_info
, struct plugin_gcc_version
*version
)
92 struct register_pass_info sancov_plugin_pass_info
;
93 const char * const plugin_name
= plugin_info
->base_name
;
94 const int argc
= plugin_info
->argc
;
95 const struct plugin_argument
* const argv
= plugin_info
->argv
;
98 static const struct ggc_root_tab gt_ggc_r_gt_sancov
[] = {
100 .base
= &sancov_fndecl
,
102 .stride
= sizeof(sancov_fndecl
),
103 .cb
= >_ggc_mx_tree_node
,
104 .pchw
= >_pch_nx_tree_node
109 /* BBs can be split afterwards?? */
110 sancov_plugin_pass_info
.pass
= make_sancov_pass();
111 #if BUILDING_GCC_VERSION >= 4009
112 sancov_plugin_pass_info
.reference_pass_name
= "asan";
114 sancov_plugin_pass_info
.reference_pass_name
= "nrv";
116 sancov_plugin_pass_info
.ref_pass_instance_number
= 0;
117 sancov_plugin_pass_info
.pos_op
= PASS_POS_INSERT_BEFORE
;
119 if (!plugin_default_version_check(version
, &gcc_version
)) {
120 error(G_("incompatible gcc/plugin versions"));
124 for (i
= 0; i
< argc
; ++i
) {
125 if (!strcmp(argv
[i
].key
, "no-sancov")) {
129 error(G_("unkown option '-fplugin-arg-%s-%s'"), plugin_name
, argv
[i
].key
);
132 register_callback(plugin_name
, PLUGIN_INFO
, NULL
, &sancov_plugin_info
);
137 #if BUILDING_GCC_VERSION < 6000
138 register_callback(plugin_name
, PLUGIN_START_UNIT
, &sancov_start_unit
, NULL
);
139 register_callback(plugin_name
, PLUGIN_REGISTER_GGC_ROOTS
, NULL
, (void *)>_ggc_r_gt_sancov
);
140 register_callback(plugin_name
, PLUGIN_PASS_MANAGER_SETUP
, NULL
, &sancov_plugin_pass_info
);