On Fri, Jul 14, 2017 at 5:23 AM, Dmitry Vyukov <dvyu...@google.com> wrote: > On Thu, Jul 13, 2017 at 11:18 PM, Kostya Serebryany <k...@google.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? >> >> >> I'd prefer not to change the API, but extend it (new compiler flag, new >> callbacks), if absolutely needed. >> Probably make it trace-cmp-guard (similar to trace-pc-guard, with an extra >> parameter that has the ID). >> I don't like the approach with compiler-generated constant IDs. > > Yes, if we do it for C/C++, we need to create globals and pass pointer > to a global to the callbacks. IDs do not work for C/C++. > >> Yes, it's a bit more efficient, but much less flexible in presence of >> multiple modules, DSOs, dlopen, etc. >> >> I was also looking at completely inlining this instrumentation because it's >> pretty expensive even in it's current form >> (adding more parameters will make things worse). >> This is going to be much less flexible, of course, so I'll attack it only >> once I settle on the algorithm to handle CMPs in libFuzzer. > > This will require a new, completely different API for > compiler<->runtime anyway, so we can put this aside for now. > > >>> 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: >> >> >> How many flag combinations do we need and do we *really* need them? >> >> If the number of flag combinations is small, I'd prefer to have separate >> callbacks (__sanitizer_cov_trace_cmp_loop_bound ?) >> >> Do we really need to know that one arg is a const? >> It could well be a constant in fact, but compiler won't see it. >> >> int foo(int n) { ... if (i < n) ... } >> ... >> foo(42); // not inlined. >> >> We need to handle both cases the same way. > > > Well, following this line of reasoning we would need only > __asan_load/storeN callbacks for asan and remove > __asan_load/store1/2/4/8, because compiler might not know the size at > compile time. Constant-ness is only an optimization. If compiler does > not know that something is a const, fine. Based on my experience with > go-fuzz and our early experience with kernel, we badly need const > hint. > Otherwise fuzzer generates gazillions of candidates based on > comparison arguments. Note that kernel is several order of magnitude > larger than what people usually fuzz in user-space, inputs are more > complex and at the same time execution speed is several order of > magnitude lower. We can't rely on raw speed. > > Thinking of this more, I don't thing that globals will be useful in > the kernel context (the main problem is that we have multiple > transient isolated kernels). If we track per-comparison site > information, we will probably use PCs. So I am ready to give up on > this. > > Both of you expressed concerns about performance. Kostya says we > should not break existing clang API. > If we limit this to only constant-ness, then I think we can make this > both forward and backward compatible, which means we don't need to > handle it now. E.g. we can: > - if both operands are const (if it's possible at all), don't emit any > callback > - if only one is const, emit __sanitizer_cov_trace_cmp_const1 and > pass the const in a known position (i.e. always first/second arg) > - if none are const, emit callback __sanitizer_cov_trace_cmp_dyn1 > Then compiler emits weak aliases form > __sanitizer_cov_trace_cmp_const/dyn1 to the old > __sanitizer_cov_trace_cmp1, which makes it backwards compatible. > New runtimes that implement __sanitizer_cov_trace_cmp_const/dyn1, also > need to provide the old __sanitizer_cov_trace_cmp1 for old compilers.
SGTM++ Although, maybe we can actually break the API this way to keep things simpler (no weak aliases) * leave __sanitizer_cov_trace_cmp[1248] for general case * add __sanitizer_cov_trace_cmp[1248]_const for constant in the 2-nd parameter * add __sanitizer_cov_trace_cmp[1248]_loop for loop bound in the 2nd parameter * do we need __sanitizer_cov_trace_cmp[1248]_const_loop ? > Similarly for counting loops, we can emit a new callback and provide a > weak alias to the old callback. > > No performance hit. Works both ways. So let's proceed with the current > implementation. > > > > >>> 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) >> >>