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 12:41 PM, Wish Wu <wishwu007@gmail.com> wrote:
> Hi
>
> In fact, under linux with "return address" and file "/proc/self/maps",
> we can give unique id for every comparison.

Yes, it's doable. But you expressed worries about performance hit of
merging callbacks for different sizes. Mapping pc + info from
/proc/self/maps to a unique id via an external map is an order of
magnitude slower than the hit of merged callbacks.


> For fuzzing, we may give 3 bits for every comparison as marker of if
> "<", "==" or ">" is showed. :D
>
> With Regards
> Wish Wu of Ant-financial Light-Year Security Lab
>
> On Thu, Jul 13, 2017 at 6:04 PM, Wish Wu <wishwu007@gmail.com> wrote:
>> 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 <dvyukov@google.com> wrote:
>>> On Tue, Jul 11, 2017 at 1:59 PM, Wish Wu <wishwu007@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.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]