This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Add support to trace comparison instructions and switch statements


On Thu, Jul 13, 2017 at 11:18 PM, Kostya Serebryany <kcc@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.
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.wwx@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)
>
>


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]