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)
>>
>>

Reply via email to