Hi In my perspective:
1. Do we need to assign unique id for every comparison ? Yes, I suggest to implement it like -fsanitize-coverage=trace-pc-guard . Because some fuzzing targets may invoke dlopen() like functions to load libraries(modules) after fork(), while these libraries are compiled with trace-cmp as well. With ALSR enabled by linker and/or kernel, return address can't be a unique id for every comparison. 2. Should we merge cmp1(),cmp2(),cmp4(),cmp8(),cmpf(),cmpd() into one cmp() ? No, It may reduce the performance of fuzzing. It may wastes registers. But the number "switch" statements are much less than "if", I forgive "switch"'s wasting behaviors. 3.Should we record operands(<,>,==,<= ......) ? Probably no. As comparison,"<" , "==" and ">" all of them are meaningful, because programmers must have some reasons to do that. As practice , "==" is more meaningful. 4.Should we record comparisons for counting loop checks ? Not sure. With Regards Wish Wu of Ant-financial Light-Year Security Lab On Thu, Jul 13, 2017 at 4:09 PM, Dmitry Vyukov <dvyu...@google.com> wrote: > On Tue, Jul 11, 2017 at 1:59 PM, Wish Wu <wishwu...@gmail.com> wrote: >> Hi >> >> I wrote a test for "-fsanitize-coverage=trace-cmp" . >> >> Is there anybody tells me if these codes could be merged into gcc ? > > > Nice! > > We are currently working on Linux kernel fuzzing that use the > comparison tracing. We use clang at the moment, but having this > support in gcc would be great for kernel land. > > One concern I have: do we want to do some final refinements to the API > before we implement this in both compilers? > > 2 things we considered from our perspective: > - communicating to the runtime which operands are constants > - communicating to the runtime which comparisons are counting loop checks > > First is useful if you do "find one operand in input and replace with > the other one" thing. Second is useful because counting loop checks > are usually not useful (at least all but one). > In the original Go implementation I also conveyed signedness of > operands, exact comparison operation (<, >, etc): > https://github.com/dvyukov/go-fuzz/blob/master/go-fuzz-defs/defs.go#L13 > But I did not find any use for that. > I also gave all comparisons unique IDs: > https://github.com/dvyukov/go-fuzz/blob/master/go-fuzz-dep/sonar.go#L24 > That turned out to be useful. And there are chances we will want this > for C/C++ as well. > > Kostya, did anything like this pop up in your work on libfuzzer? > Can we still change the clang API? At least add an additional argument > to the callbacks? > > At the very least I would suggest that we add an additional arg that > contains some flags (1/2 arg is a const, this is counting loop check, > etc). If we do that we can also have just 1 callback that accepts > uint64's for args because we can pass operand size in the flags: > > void __sanitizer_cov_trace_cmp(uint64 arg1, uint64 arg2, uint64 flags); > > But I wonder if 3 uint64 args will be too inefficient for 32 bit archs?... > > If we create a global per comparison then we could put the flags into > the global: > > void __sanitizer_cov_trace_cmp(uint64 arg1, uint64 arg2, something_t *global); > > Thoughts? > > > > >> Index: gcc/testsuite/gcc.dg/sancov/basic3.c >> =================================================================== >> --- gcc/testsuite/gcc.dg/sancov/basic3.c (nonexistent) >> +++ gcc/testsuite/gcc.dg/sancov/basic3.c (working copy) >> @@ -0,0 +1,42 @@ >> +/* Basic test on number of inserted callbacks. */ >> +/* { dg-do compile } */ >> +/* { dg-options "-fsanitize-coverage=trace-cmp -fdump-tree-optimized" } */ >> + >> +void foo(char *a, short *b, int *c, long long *d, float *e, double *f) >> +{ >> + if (*a) >> + *a += 1; >> + if (*b) >> + *b = *a; >> + if (*c) >> + *c += 1; >> + if(*d) >> + *d = *c; >> + if(*e == *c) >> + *e = *c; >> + if(*f == *e) >> + *f = *e; >> + switch(*a) >> + { >> + case 2: >> + *b += 2; >> + break; >> + default: >> + break; >> + } >> + switch(*d) >> + { >> + case 3: >> + *d += 3; >> + case -4: >> + *d -= 4; >> + } >> +} >> + >> +/* { dg-final { scan-tree-dump-times >> "__builtin___sanitizer_cov_trace_cmp1 \\(" 1 "optimized" } } */ >> +/* { dg-final { scan-tree-dump-times >> "__builtin___sanitizer_cov_trace_cmp2 \\(" 1 "optimized" } } */ >> +/* { dg-final { scan-tree-dump-times >> "__builtin___sanitizer_cov_trace_cmp4 \\(" 1 "optimized" } } */ >> +/* { dg-final { scan-tree-dump-times >> "__builtin___sanitizer_cov_trace_cmp8 \\(" 1 "optimized" } } */ >> +/* { dg-final { scan-tree-dump-times >> "__builtin___sanitizer_cov_trace_cmpf \\(" 1 "optimized" } } */ >> +/* { dg-final { scan-tree-dump-times >> "__builtin___sanitizer_cov_trace_cmpd \\(" 1 "optimized" } } */ >> +/* { dg-final { scan-tree-dump-times >> "__builtin___sanitizer_cov_trace_switch \\(" 2 "optimized" } } */ >> >> >> With Regards >> Wish Wu >> >> On Mon, Jul 10, 2017 at 8:07 PM, 吴潍浠(此彼) <weixi....@antfin.com> wrote: >>> Hi >>> >>> I write some codes to make gcc support comparison-guided fuzzing. >>> It is very like >>> http://clang.llvm.org/docs/SanitizerCoverage.html#tracing-data-flow . >>> With -fsanitize-coverage=trace-cmp the compiler will insert extra >>> instrumentation around comparison instructions and switch statements. >>> I think it is useful for fuzzing. :D >>> >>> Patch is below, I may supply test cases later. >>> >>> With Regards >>> Wish Wu >>> >>> Index: gcc/asan.c >>> =================================================================== >>> --- gcc/asan.c (revision 250082) >>> +++ gcc/asan.c (working copy) >>> @@ -2705,6 +2705,29 @@ initialize_sanitizer_builtins (void) >>> tree BT_FN_SIZE_CONST_PTR_INT >>> = build_function_type_list (size_type_node, const_ptr_type_node, >>> integer_type_node, NULL_TREE); >>> + >>> + tree BT_FN_VOID_UINT8_UINT8 >>> + = build_function_type_list (void_type_node, unsigned_char_type_node, >>> + unsigned_char_type_node, NULL_TREE); >>> + tree BT_FN_VOID_UINT16_UINT16 >>> + = build_function_type_list (void_type_node, uint16_type_node, >>> + uint16_type_node, NULL_TREE); >>> + tree BT_FN_VOID_UINT32_UINT32 >>> + = build_function_type_list (void_type_node, uint32_type_node, >>> + uint32_type_node, NULL_TREE); >>> + tree BT_FN_VOID_UINT64_UINT64 >>> + = build_function_type_list (void_type_node, uint64_type_node, >>> + uint64_type_node, NULL_TREE); >>> + tree BT_FN_VOID_FLOAT_FLOAT >>> + = build_function_type_list (void_type_node, float_type_node, >>> + float_type_node, NULL_TREE); >>> + tree BT_FN_VOID_DOUBLE_DOUBLE >>> + = build_function_type_list (void_type_node, double_type_node, >>> + double_type_node, NULL_TREE); >>> + tree BT_FN_VOID_UINT64_PTR >>> + = build_function_type_list (void_type_node, uint64_type_node, >>> + ptr_type_node, NULL_TREE); >>> + >>> tree BT_FN_BOOL_VPTR_PTR_IX_INT_INT[5]; >>> tree BT_FN_IX_CONST_VPTR_INT[5]; >>> tree BT_FN_IX_VPTR_IX_INT[5]; >>> Index: gcc/builtin-types.def >>> =================================================================== >>> --- gcc/builtin-types.def (revision 250082) >>> +++ gcc/builtin-types.def (working copy) >>> @@ -338,8 +338,20 @@ DEF_FUNCTION_TYPE_2 (BT_FN_VOID_PTRMODE_PTR, >>> BT_VOID, BT_PTRMODE, BT_PTR) >>> DEF_FUNCTION_TYPE_2 (BT_FN_VOID_PTR_PTRMODE, >>> BT_VOID, BT_PTR, BT_PTRMODE) >>> +DEF_FUNCTION_TYPE_2 (BT_FN_VOID_UINT8_UINT8, >>> + BT_VOID, BT_UINT8, BT_UINT8) >>> +DEF_FUNCTION_TYPE_2 (BT_FN_VOID_UINT16_UINT16, >>> + BT_VOID, BT_UINT16, BT_UINT16) >>> +DEF_FUNCTION_TYPE_2 (BT_FN_VOID_UINT32_UINT32, >>> + BT_VOID, BT_UINT32, BT_UINT32) >>> DEF_FUNCTION_TYPE_2 (BT_FN_VOID_UINT64_UINT64, >>> BT_VOID, BT_UINT64, BT_UINT64) >>> +DEF_FUNCTION_TYPE_2 (BT_FN_VOID_FLOAT_FLOAT, >>> + BT_VOID, BT_FLOAT, BT_FLOAT) >>> +DEF_FUNCTION_TYPE_2 (BT_FN_VOID_DOUBLE_DOUBLE, >>> + BT_VOID, BT_DOUBLE, BT_DOUBLE) >>> +DEF_FUNCTION_TYPE_2 (BT_FN_VOID_UINT64_PTR, >>> + BT_VOID, BT_UINT64, BT_PTR) >>> DEF_FUNCTION_TYPE_2 (BT_FN_VOID_VALIST_REF_VALIST_ARG, >>> BT_VOID, BT_VALIST_REF, BT_VALIST_ARG) >>> DEF_FUNCTION_TYPE_2 (BT_FN_LONG_LONG_LONG, >>> Index: gcc/common.opt >>> =================================================================== >>> --- gcc/common.opt (revision 250082) >>> +++ gcc/common.opt (working copy) >>> @@ -226,10 +226,9 @@ unsigned int flag_sanitize >>> Variable >>> unsigned int flag_sanitize_recover = (SANITIZE_UNDEFINED | >>> SANITIZE_UNDEFINED_NONDEFAULT | SANITIZE_KERNEL_ADDRESS) & >>> ~(SANITIZE_UNREACHABLE | SANITIZE_RETURN) >>> >>> -fsanitize-coverage=trace-pc >>> -Common Report Var(flag_sanitize_coverage) >>> -Enable coverage-guided fuzzing code instrumentation. >>> -Inserts call to __sanitizer_cov_trace_pc into every basic block. >>> +; What the coverage sanitizers should instrument >>> +Variable >>> +unsigned int flag_sanitize_coverage >>> >>> ; Flag whether a prefix has been added to dump_base_name >>> Variable >>> @@ -975,6 +974,10 @@ fsanitize= >>> Common Driver Report Joined >>> Select what to sanitize. >>> >>> +fsanitize-coverage= >>> +Common Driver Report Joined >>> +Select what to coverage sanitize. >>> + >>> fasan-shadow-offset= >>> Common Joined RejectNegative Var(common_deferred_options) Defer >>> -fasan-shadow-offset=<number> Use custom shadow memory offset. >>> Index: gcc/flag-types.h >>> =================================================================== >>> --- gcc/flag-types.h (revision 250082) >>> +++ gcc/flag-types.h (working copy) >>> @@ -250,6 +250,14 @@ enum sanitize_code { >>> | SANITIZE_BOUNDS_STRICT >>> }; >>> >>> +/* Different trace modes */ >>> +enum sanitize_coverage_code { >>> + /* Trace PC */ >>> + SANITIZE_COV_TRACE_PC = 1UL << 0, >>> + /* Trace Compare */ >>> + SANITIZE_COV_TRACE_CMP = 1UL << 1 >>> +}; >>> + >>> /* flag_vtable_verify initialization levels. */ >>> enum vtv_priority { >>> VTV_NO_PRIORITY = 0, /* i.E. Do NOT do vtable verification. */ >>> Index: gcc/opts.c >>> =================================================================== >>> --- gcc/opts.c (revision 250082) >>> +++ gcc/opts.c (working copy) >>> @@ -1518,6 +1518,17 @@ const struct sanitizer_opts_s sanitizer_opts[] = >>> { NULL, 0U, 0UL, false } >>> }; >>> >>> +/* -f{,no-}sanitize-coverage= suboptions. */ >>> +const struct sanitizer_opts_s coverage_sanitizer_opts[] = >>> +{ >>> +#define SANITIZER_OPT(name, flags, recover) \ >>> + { #name, flags, sizeof #name - 1, recover } >>> + SANITIZER_OPT (trace-pc, SANITIZE_COV_TRACE_PC, false), >>> + SANITIZER_OPT (trace-cmp, SANITIZE_COV_TRACE_CMP, false), >>> +#undef SANITIZER_OPT >>> + { NULL, 0U, 0UL, false } >>> +}; >>> + >>> /* A struct for describing a run of chars within a string. */ >>> >>> struct string_fragment >>> @@ -1665,6 +1676,85 @@ parse_sanitizer_options (const char *p, location_t >>> return flags; >>> } >>> >>> +/* Given ARG, an unrecognized coverage sanitizer option, return the best >>> + matching coverage sanitizer option, or NULL if there isn't one. >>> + VALUE is non-zero for the regular form of the option, zero >>> + for the "no-" form (e.g. "-fno-sanitize-coverage="). */ >>> + >>> +static const char * >>> +get_closest_coverage_sanitizer_option (const string_fragment &arg, int >>> value) >>> +{ >>> + best_match <const string_fragment &, const char*> bm (arg); >>> + for (int i = 0; coverage_sanitizer_opts[i].name != NULL; ++i) >>> + { >>> + bm.consider (coverage_sanitizer_opts[i].name); >>> + } >>> + return bm.get_best_meaningful_candidate (); >>> +} >>> + >>> +/* Parse comma separated sanitizer suboptions from P for option SCODE, >>> + adjust previous FLAGS and return new ones. If COMPLAIN is false, >>> + don't issue diagnostics. */ >>> + >>> +unsigned int >>> +parse_coverage_sanitizer_options (const char *p, location_t loc, >>> + unsigned int flags, int value, bool complain) >>> +{ >>> + while (*p != 0) >>> + { >>> + size_t len, i; >>> + bool found = false; >>> + const char *comma = strchr (p, ','); >>> + >>> + if (comma == NULL) >>> + len = strlen (p); >>> + else >>> + len = comma - p; >>> + if (len == 0) >>> + { >>> + p = comma + 1; >>> + continue; >>> + } >>> + >>> + /* Check to see if the string matches an option class name. */ >>> + for (i = 0; coverage_sanitizer_opts[i].name != NULL; ++i) >>> + if (len == coverage_sanitizer_opts[i].len >>> + && memcmp (p, coverage_sanitizer_opts[i].name, len) == 0) >>> + { >>> + if (value) >>> + flags |= coverage_sanitizer_opts[i].flag; >>> + else >>> + flags &= ~coverage_sanitizer_opts[i].flag; >>> + found = true; >>> + break; >>> + } >>> + >>> + if (! found && complain) >>> + { >>> + const char *hint >>> + = get_closest_coverage_sanitizer_option (string_fragment (p, >>> len), >>> + value); >>> + >>> + if (hint) >>> + error_at (loc, >>> + "unrecognized argument to -f%ssanitize-coverage= >>> option: %q.*s;" >>> + " did you mean %qs?", >>> + value ? "" : "no-", >>> + (int) len, p, hint); >>> + else >>> + error_at (loc, >>> + "unrecognized argument to -f%ssanitize-coverage= >>> option: %q.*s", >>> + value ? "" : "no-", >>> + (int) len, p); >>> + } >>> + >>> + if (comma == NULL) >>> + break; >>> + p = comma + 1; >>> + } >>> + return flags; >>> +} >>> + >>> /* Parse string values of no_sanitize attribute passed in VALUE. >>> Values are separated with comma. Wrong argument is stored to >>> WRONG_ARGUMENT variable. */ >>> @@ -1942,6 +2032,12 @@ common_handle_option (struct gcc_options *opts, >>> &= ~(SANITIZE_UNDEFINED | SANITIZE_UNDEFINED_NONDEFAULT); >>> break; >>> >>> + case OPT_fsanitize_coverage_: >>> + opts->x_flag_sanitize_coverage >>> + = parse_coverage_sanitizer_options (arg, loc, >>> + opts->x_flag_sanitize_coverage, value, >>> true); >>> + break; >>> + >>> case OPT_O: >>> case OPT_Os: >>> case OPT_Ofast: >>> Index: gcc/sancov.c >>> =================================================================== >>> --- gcc/sancov.c (revision 250082) >>> +++ gcc/sancov.c (working copy) >>> @@ -29,31 +29,194 @@ along with GCC; see the file COPYING3. If not see >>> #include "flags.h" >>> #include "stmt.h" >>> #include "gimple-iterator.h" >>> +#include "tree-core.h" >>> #include "tree-cfg.h" >>> #include "tree-pass.h" >>> #include "tree-iterator.h" >>> +#include "fold-const.h" >>> +#include "stringpool.h" >>> +#include "output.h" >>> +#include "cgraph.h" >>> #include "asan.h" >>> >>> namespace { >>> >>> +static void >>> +instrument_cond (gimple_stmt_iterator *gsi, gimple *stmt) >>> +{ >>> + tree lhs = gimple_cond_lhs (stmt); >>> + tree rhs = gimple_cond_rhs (stmt); >>> + unsigned int bitno = TYPE_PRECISION (TREE_TYPE (lhs)) > TYPE_PRECISION >>> (TREE_TYPE (rhs)) ? >>> + TYPE_PRECISION (TREE_TYPE (lhs)) : TYPE_PRECISION >>> (TREE_TYPE (rhs)); >>> + if (TREE_CODE (TREE_TYPE (lhs)) == INTEGER_TYPE) >>> + { >>> + enum built_in_function fncode; >>> + switch (bitno) >>> + { >>> + case 8: >>> + fncode = BUILT_IN_SANITIZER_COV_TRACE_CMP1; >>> + break; >>> + >>> + case 16: >>> + fncode = BUILT_IN_SANITIZER_COV_TRACE_CMP2; >>> + break; >>> + >>> + case 32: >>> + fncode = BUILT_IN_SANITIZER_COV_TRACE_CMP4; >>> + break; >>> + >>> + case 64: >>> + fncode = BUILT_IN_SANITIZER_COV_TRACE_CMP8; >>> + break; >>> + >>> + default: >>> + return; >>> + break; >>> + } >>> + tree fndecl = builtin_decl_implicit (fncode); >>> + gimple *gcall = gimple_build_call (fndecl, 2, lhs, rhs); >>> + gimple_set_location (gcall, gimple_location (stmt)); >>> + gsi_insert_before (gsi, gcall, GSI_SAME_STMT); >>> + } >>> + else if (TREE_CODE (TREE_TYPE (lhs)) == REAL_TYPE) >>> + { >>> + enum built_in_function fncode; >>> + switch (bitno) >>> + { >>> + case 32: >>> + fncode = BUILT_IN_SANITIZER_COV_TRACE_CMPF; >>> + break; >>> + >>> + case 64: >>> + fncode = BUILT_IN_SANITIZER_COV_TRACE_CMPD; >>> + break; >>> + >>> + default: >>> + return; >>> + break; >>> + } >>> + tree fndecl = builtin_decl_implicit (fncode); >>> + gimple *gcall = gimple_build_call (fndecl, 2, lhs, rhs); >>> + gimple_set_location (gcall, gimple_location (stmt)); >>> + gsi_insert_before (gsi, gcall, GSI_SAME_STMT); >>> + } >>> +} >>> + >>> +static void >>> +instrument_switch (gimple_stmt_iterator *gsi, gimple *stmt, function *fun) >>> +{ >>> + gswitch *switch_stmt = as_a<gswitch *> (stmt); >>> + tree index = gimple_switch_index (switch_stmt); >>> + unsigned bitno = TYPE_PRECISION (TREE_TYPE (index)); >>> + unsigned i, n = gimple_switch_num_labels (switch_stmt), num = 0; >>> + for (i = 0; i < n; ++i) >>> + { >>> + tree label = gimple_switch_label (switch_stmt, i); >>> + tree low_case = CASE_LOW (label); >>> + if (low_case != NULL_TREE) >>> + num++; >>> + tree high_case = CASE_HIGH (label); >>> + if (high_case != NULL_TREE) >>> + num++; >>> + } >>> + >>> + tree case_array_elem_type = build_type_variant (uint64_type_node, 1, 0); >>> + tree case_array_type = build_array_type (case_array_elem_type, >>> + build_index_type (size_int (num >>> + 2 - 1))); >>> + char name[64]; >>> + static size_t case_array_count = 0; >>> + snprintf(name, sizeof(name) - 1, >>> "__sanitizer_cov_trace_switch_array%lu", case_array_count++); >>> + tree case_array_var = build_decl (UNKNOWN_LOCATION, VAR_DECL, >>> + get_identifier (name), case_array_type); >>> + TREE_STATIC (case_array_var) = 1; >>> + TREE_PUBLIC (case_array_var) = 0; >>> + TREE_CONSTANT (case_array_var) = 1; >>> + TREE_READONLY (case_array_var) = 1; >>> + DECL_EXTERNAL (case_array_var) = 0; >>> + DECL_ARTIFICIAL (case_array_var) = 1; >>> + DECL_IGNORED_P (case_array_var) = 1; >>> + >>> + vec <constructor_elt, va_gc> *v = NULL; >>> + vec_alloc (v, num + 2); >>> + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (uint64_type_node, >>> num)); >>> + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (uint64_type_node, >>> bitno)); >>> + for (i = 0; i < n; ++i) >>> + { >>> + tree label = gimple_switch_label (switch_stmt, i); >>> + >>> + tree low_case = CASE_LOW (label); >>> + if (low_case != NULL_TREE) >>> + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, >>> + build_int_cst (uint64_type_node, >>> TREE_INT_CST_LOW (low_case))); >>> + >>> + tree high_case = CASE_HIGH (label); >>> + if (high_case != NULL_TREE) >>> + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, >>> + build_int_cst (uint64_type_node, >>> TREE_INT_CST_LOW (high_case))); >>> + } >>> + tree ctor = build_constructor (case_array_type, v); >>> + TREE_STATIC (ctor) = 1; >>> + TREE_PUBLIC (ctor) = 0; >>> + TREE_CONSTANT (ctor) = 1; >>> + TREE_READONLY (ctor) = 1; >>> + DECL_EXTERNAL (ctor) = 0; >>> + DECL_INITIAL (case_array_var) = ctor; >>> + varpool_node::finalize_decl (case_array_var); >>> + >>> + tree case_array_var_ref = build_fold_addr_expr (case_array_var); >>> + add_local_decl (fun, case_array_var); >>> + tree fndecl = builtin_decl_implicit >>> (BUILT_IN_SANITIZER_COV_TRACE_SWITCH); >>> + gimple *gcall = gimple_build_call (fndecl, 2, index, case_array_var_ref); >>> + gimple_set_location (gcall, gimple_location (stmt)); >>> + gsi_insert_before(gsi, gcall, GSI_SAME_STMT); >>> +} >>> + >>> unsigned >>> sancov_pass (function *fun) >>> { >>> initialize_sanitizer_builtins (); >>> >>> + basic_block bb; >>> + >>> /* 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, fun) >>> + if (flag_sanitize_coverage & SANITIZE_COV_TRACE_PC) >>> { >>> - gimple_stmt_iterator gsi = gsi_start_nondebug_after_labels_bb (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); >>> + tree fndecl = builtin_decl_implicit >>> (BUILT_IN_SANITIZER_COV_TRACE_PC); >>> + FOR_EACH_BB_FN (bb, fun) >>> + { >>> + gimple_stmt_iterator gsi = gsi_start_nondebug_after_labels_bb >>> (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); >>> + } >>> } >>> + >>> + /* Insert callback to every compare statments. */ >>> + if (flag_sanitize_coverage & SANITIZE_COV_TRACE_CMP) >>> + { >>> + FOR_EACH_BB_FN (bb, fun) >>> + { >>> + gimple_stmt_iterator gsi; >>> + for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) >>> + { >>> + gimple *stmt = gsi_stmt (gsi); >>> + switch (gimple_code (stmt)) >>> + { >>> + case GIMPLE_COND: >>> + instrument_cond (&gsi, stmt); >>> + break; >>> + case GIMPLE_SWITCH: >>> + instrument_switch (&gsi, stmt, fun); >>> + break; >>> + default: >>> + break; >>> + } >>> + } >>> + } >>> + } >>> return 0; >>> } >>> >>> Index: gcc/sanitizer.def >>> =================================================================== >>> --- gcc/sanitizer.def (revision 250082) >>> +++ gcc/sanitizer.def (working copy) >>> @@ -529,6 +529,27 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_DYNAMI >>> DEF_SANITIZER_BUILTIN(BUILT_IN_SANITIZER_COV_TRACE_PC, >>> "__sanitizer_cov_trace_pc", >>> BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST) >>> +DEF_SANITIZER_BUILTIN(BUILT_IN_SANITIZER_COV_TRACE_CMP1, >>> + "__sanitizer_cov_trace_cmp1", >>> + BT_FN_VOID_UINT8_UINT8, ATTR_NOTHROW_LEAF_LIST) >>> +DEF_SANITIZER_BUILTIN(BUILT_IN_SANITIZER_COV_TRACE_CMP2, >>> + "__sanitizer_cov_trace_cmp2", >>> + BT_FN_VOID_UINT16_UINT16, ATTR_NOTHROW_LEAF_LIST) >>> +DEF_SANITIZER_BUILTIN(BUILT_IN_SANITIZER_COV_TRACE_CMP4, >>> + "__sanitizer_cov_trace_cmp4", >>> + BT_FN_VOID_UINT32_UINT32, ATTR_NOTHROW_LEAF_LIST) >>> +DEF_SANITIZER_BUILTIN(BUILT_IN_SANITIZER_COV_TRACE_CMP8, >>> + "__sanitizer_cov_trace_cmp8", >>> + BT_FN_VOID_UINT64_UINT64, ATTR_NOTHROW_LEAF_LIST) >>> +DEF_SANITIZER_BUILTIN(BUILT_IN_SANITIZER_COV_TRACE_CMPF, >>> + "__sanitizer_cov_trace_cmpf", >>> + BT_FN_VOID_FLOAT_FLOAT, ATTR_NOTHROW_LEAF_LIST) >>> +DEF_SANITIZER_BUILTIN(BUILT_IN_SANITIZER_COV_TRACE_CMPD, >>> + "__sanitizer_cov_trace_cmpd", >>> + BT_FN_VOID_DOUBLE_DOUBLE, ATTR_NOTHROW_LEAF_LIST) >>> +DEF_SANITIZER_BUILTIN(BUILT_IN_SANITIZER_COV_TRACE_SWITCH, >>> + "__sanitizer_cov_trace_switch", >>> + BT_FN_VOID_UINT64_PTR, ATTR_NOTHROW_LEAF_LIST) >>> >>> /* This has to come after all the sanitizer builtins. */ >>> DEF_BUILTIN_STUB(END_SANITIZER_BUILTINS, (const char *)0)