From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 81532 invoked by alias); 13 Jul 2017 10:47:24 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 80598 invoked by uid 89); 13 Jul 2017 10:47:22 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-12.1 required=5.0 tests=AWL,BAYES_00,BODY_8BITS,GARBLED_BODY,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,KAM_ASCII_DIVIDERS,RCVD_IN_DNSWL_NONE,RP_MATCHES_RCVD,SPF_PASS autolearn=ham version=3.3.2 spammy=worries X-HELO: mail-oi0-f48.google.com Received: from mail-oi0-f48.google.com (HELO mail-oi0-f48.google.com) (209.85.218.48) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 13 Jul 2017 10:47:18 +0000 Received: by mail-oi0-f48.google.com with SMTP id 191so42544573oii.2 for ; Thu, 13 Jul 2017 03:47:18 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to:cc:content-transfer-encoding; bh=YHwyjVionPL2/2BY9Z6lRtS0EOEWpxRSsDY4eKHfPN8=; b=D76GqL8L2n0vkfXV89zKnLOoajpLY2vHmyGZNmaSgFBkZA1ZLgcQIhCT7DidAeWcje rPA5cvcY9Ai6tBaIZ4Z1fUjt0pAnAXwwJvmgn+Xv/tDaTd6KrtFjuqOniI2jvmAvpVt2 xZaTuauwUSFqGJyaEQJ6xtMOd2M70WkxpNOLxcBSGMX0xVQKAksrUUKMn+E3p8Rh9DqA dLmg7p3Sg1KIX2TRZu7Kbp05H0xSNZ9gw+WyubSLkUjvSeXYiQWR0LcUiAbQjeSxIiNN 7VIKFNE+66DxHjUoUaObu2fiDtm6kDOwBAd3OszHrwAVz/o4MxBeVUb1E0DslqmhTJYS zOsQ== X-Gm-Message-State: AIVw110uT6VDCpt4jHAebUgYeisCDsnNwB8d4K4bJzAxrHIdkdKgAcd2 v9GiWRyj0Kst8NAvkWwCda77GUOEM6Uk X-Received: by 10.202.245.5 with SMTP id t5mr2134328oih.176.1499942835922; Thu, 13 Jul 2017 03:47:15 -0700 (PDT) MIME-Version: 1.0 Received: by 10.74.64.65 with HTTP; Thu, 13 Jul 2017 03:46:55 -0700 (PDT) In-Reply-To: References: <234840fd-a06a-4dfd-a1c5-254e26144754.weixi.wwx@antfin.com> From: "Dmitry Vyukov via gcc-patches" Reply-To: Dmitry Vyukov Date: Thu, 13 Jul 2017 10:47:00 -0000 Message-ID: Subject: Re: Add support to trace comparison instructions and switch statements To: Wish Wu Cc: gcc , gcc-patches , weixi.wwx@antfin.com, Kostya Serebryany , Alexander Potapenko , andreyknvl , Victor Chibotaru , Yuri Gribov Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-IsSubscribed: yes X-SW-Source: 2017-07/txt/msg00725.txt.bz2 On Thu, Jul 13, 2017 at 12:41 PM, Wish Wu 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 > "<", "=3D=3D" 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 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=3Dtrace-pc-g= uard . >> 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 cm= p() ? >> 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(<,>,=3D=3D,<=3D ......) ? >> Probably no. As comparison,"<" , "=3D=3D" and ">" all of them are >> meaningful, because programmers must have some reasons to do that. As >> practice , "=3D=3D" 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 wrot= e: >>> On Tue, Jul 11, 2017 at 1:59 PM, Wish Wu wrote: >>>> Hi >>>> >>>> I wrote a test for "-fsanitize-coverage=3Dtrace-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 che= cks >>> >>> 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 *g= lobal); >>> >>> Thoughts? >>> >>> >>> >>> >>>> Index: gcc/testsuite/gcc.dg/sancov/basic3.c >>>> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >>>> --- 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=3Dtrace-cmp -fdump-tree-optimize= d" } */ >>>> + >>>> +void foo(char *a, short *b, int *c, long long *d, float *e, double *f) >>>> +{ >>>> + if (*a) >>>> + *a +=3D 1; >>>> + if (*b) >>>> + *b =3D *a; >>>> + if (*c) >>>> + *c +=3D 1; >>>> + if(*d) >>>> + *d =3D *c; >>>> + if(*e =3D=3D *c) >>>> + *e =3D *c; >>>> + if(*f =3D=3D *e) >>>> + *f =3D *e; >>>> + switch(*a) >>>> + { >>>> + case 2: >>>> + *b +=3D 2; >>>> + break; >>>> + default: >>>> + break; >>>> + } >>>> + switch(*d) >>>> + { >>>> + case 3: >>>> + *d +=3D 3; >>>> + case -4: >>>> + *d -=3D 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, =E5=90=B4=E6=BD=8D=E6=B5=A0(=E6=AD=A4= =E5=BD=BC) wrote: >>>>> Hi >>>>> >>>>> I write some codes to make gcc support comparison-guided fuzzing. >>>>> It is very like http://clang.llvm.org/docs/SanitizerCoverage.html#tra= cing-data-flow . >>>>> With -fsanitize-coverage=3Dtrace-cmp the compiler will insert extra i= nstrumentation 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 >>>>> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >>>>> --- 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 >>>>> =3D build_function_type_list (size_type_node, const_ptr_type_nod= e, >>>>> integer_type_node, NULL_TREE); >>>>> + >>>>> + tree BT_FN_VOID_UINT8_UINT8 >>>>> + =3D build_function_type_list (void_type_node, unsigned_char_type= _node, >>>>> + unsigned_char_type_node, NULL_TREE); >>>>> + tree BT_FN_VOID_UINT16_UINT16 >>>>> + =3D build_function_type_list (void_type_node, uint16_type_node, >>>>> + uint16_type_node, NULL_TREE); >>>>> + tree BT_FN_VOID_UINT32_UINT32 >>>>> + =3D build_function_type_list (void_type_node, uint32_type_node, >>>>> + uint32_type_node, NULL_TREE); >>>>> + tree BT_FN_VOID_UINT64_UINT64 >>>>> + =3D build_function_type_list (void_type_node, uint64_type_node, >>>>> + uint64_type_node, NULL_TREE); >>>>> + tree BT_FN_VOID_FLOAT_FLOAT >>>>> + =3D build_function_type_list (void_type_node, float_type_node, >>>>> + float_type_node, NULL_TREE); >>>>> + tree BT_FN_VOID_DOUBLE_DOUBLE >>>>> + =3D build_function_type_list (void_type_node, double_type_node, >>>>> + double_type_node, NULL_TREE); >>>>> + tree BT_FN_VOID_UINT64_PTR >>>>> + =3D 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 >>>>> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >>>>> --- 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 >>>>> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >>>>> --- gcc/common.opt (revision 250082) >>>>> +++ gcc/common.opt (working copy) >>>>> @@ -226,10 +226,9 @@ unsigned int flag_sanitize >>>>> Variable >>>>> unsigned int flag_sanitize_recover =3D (SANITIZE_UNDEFINED | SANITIZ= E_UNDEFINED_NONDEFAULT | SANITIZE_KERNEL_ADDRESS) & ~(SANITIZE_UNREACHABLE = | SANITIZE_RETURN) >>>>> >>>>> -fsanitize-coverage=3Dtrace-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=3D >>>>> Common Driver Report Joined >>>>> Select what to sanitize. >>>>> >>>>> +fsanitize-coverage=3D >>>>> +Common Driver Report Joined >>>>> +Select what to coverage sanitize. >>>>> + >>>>> fasan-shadow-offset=3D >>>>> Common Joined RejectNegative Var(common_deferred_options) Defer >>>>> -fasan-shadow-offset=3D Use custom shadow memory offset. >>>>> Index: gcc/flag-types.h >>>>> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >>>>> --- 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 =3D 1UL << 0, >>>>> + /* Trace Compare */ >>>>> + SANITIZE_COV_TRACE_CMP =3D 1UL << 1 >>>>> +}; >>>>> + >>>>> /* flag_vtable_verify initialization levels. */ >>>>> enum vtv_priority { >>>>> VTV_NO_PRIORITY =3D 0, /* i.E. Do NOT do vtable verificatio= n. */ >>>>> Index: gcc/opts.c >>>>> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >>>>> --- gcc/opts.c (revision 250082) >>>>> +++ gcc/opts.c (working copy) >>>>> @@ -1518,6 +1518,17 @@ const struct sanitizer_opts_s sanitizer_opts[]= =3D >>>>> { NULL, 0U, 0UL, false } >>>>> }; >>>>> >>>>> +/* -f{,no-}sanitize-coverage=3D suboptions. */ >>>>> +const struct sanitizer_opts_s coverage_sanitizer_opts[] =3D >>>>> +{ >>>>> +#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, locati= on_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=3D"). */ >>>>> + >>>>> +static const char * >>>>> +get_closest_coverage_sanitizer_option (const string_fragment &arg, i= nt value) >>>>> +{ >>>>> + best_match bm (arg); >>>>> + for (int i =3D 0; coverage_sanitizer_opts[i].name !=3D NULL; ++i) >>>>> + { >>>>> + bm.consider (coverage_sanitizer_opts[i].name); >>>>> + } >>>>> + return bm.get_best_meaningful_candidate (); >>>>> +} >>>>> + >>>>> +/* Parse comma separated sanitizer suboptions from P for option SCOD= E, >>>>> + 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 !=3D 0) >>>>> + { >>>>> + size_t len, i; >>>>> + bool found =3D false; >>>>> + const char *comma =3D strchr (p, ','); >>>>> + >>>>> + if (comma =3D=3D NULL) >>>>> + len =3D strlen (p); >>>>> + else >>>>> + len =3D comma - p; >>>>> + if (len =3D=3D 0) >>>>> + { >>>>> + p =3D comma + 1; >>>>> + continue; >>>>> + } >>>>> + >>>>> + /* Check to see if the string matches an option class name. */ >>>>> + for (i =3D 0; coverage_sanitizer_opts[i].name !=3D NULL; ++i) >>>>> + if (len =3D=3D coverage_sanitizer_opts[i].len >>>>> + && memcmp (p, coverage_sanitizer_opts[i].name, len) =3D= =3D 0) >>>>> + { >>>>> + if (value) >>>>> + flags |=3D coverage_sanitizer_opts[i].flag; >>>>> + else >>>>> + flags &=3D ~coverage_sanitizer_opts[i].flag; >>>>> + found =3D true; >>>>> + break; >>>>> + } >>>>> + >>>>> + if (! found && complain) >>>>> + { >>>>> + const char *hint >>>>> + =3D get_closest_coverage_sanitizer_option (string_fragmen= t (p, len), >>>>> + value); >>>>> + >>>>> + if (hint) >>>>> + error_at (loc, >>>>> + "unrecognized argument to -f%ssanitize-coverage= =3D option: %q.*s;" >>>>> + " did you mean %qs?", >>>>> + value ? "" : "no-", >>>>> + (int) len, p, hint); >>>>> + else >>>>> + error_at (loc, >>>>> + "unrecognized argument to -f%ssanitize-coverage= =3D option: %q.*s", >>>>> + value ? "" : "no-", >>>>> + (int) len, p); >>>>> + } >>>>> + >>>>> + if (comma =3D=3D NULL) >>>>> + break; >>>>> + p =3D 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, >>>>> &=3D ~(SANITIZE_UNDEFINED | SANITIZE_UNDEFINED_NONDEFAULT); >>>>> break; >>>>> >>>>> + case OPT_fsanitize_coverage_: >>>>> + opts->x_flag_sanitize_coverage >>>>> + =3D parse_coverage_sanitizer_options (arg, loc, >>>>> + opts->x_flag_sanitize_coverage, va= lue, true); >>>>> + break; >>>>> + >>>>> case OPT_O: >>>>> case OPT_Os: >>>>> case OPT_Ofast: >>>>> Index: gcc/sancov.c >>>>> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >>>>> --- gcc/sancov.c (revision 250082) >>>>> +++ gcc/sancov.c (working copy) >>>>> @@ -29,31 +29,194 @@ along with GCC; see the file COPYING3. If not s= ee >>>>> #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 =3D gimple_cond_lhs (stmt); >>>>> + tree rhs =3D gimple_cond_rhs (stmt); >>>>> + unsigned int bitno =3D TYPE_PRECISION (TREE_TYPE (lhs)) > TYPE_PRE= CISION (TREE_TYPE (rhs)) ? >>>>> + TYPE_PRECISION (TREE_TYPE (lhs)) : TYPE_PRECIS= ION (TREE_TYPE (rhs)); >>>>> + if (TREE_CODE (TREE_TYPE (lhs)) =3D=3D INTEGER_TYPE) >>>>> + { >>>>> + enum built_in_function fncode; >>>>> + switch (bitno) >>>>> + { >>>>> + case 8: >>>>> + fncode =3D BUILT_IN_SANITIZER_COV_TRACE_CMP1; >>>>> + break; >>>>> + >>>>> + case 16: >>>>> + fncode =3D BUILT_IN_SANITIZER_COV_TRACE_CMP2; >>>>> + break; >>>>> + >>>>> + case 32: >>>>> + fncode =3D BUILT_IN_SANITIZER_COV_TRACE_CMP4; >>>>> + break; >>>>> + >>>>> + case 64: >>>>> + fncode =3D BUILT_IN_SANITIZER_COV_TRACE_CMP8; >>>>> + break; >>>>> + >>>>> + default: >>>>> + return; >>>>> + break; >>>>> + } >>>>> + tree fndecl =3D builtin_decl_implicit (fncode); >>>>> + gimple *gcall =3D 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)) =3D=3D REAL_TYPE) >>>>> + { >>>>> + enum built_in_function fncode; >>>>> + switch (bitno) >>>>> + { >>>>> + case 32: >>>>> + fncode =3D BUILT_IN_SANITIZER_COV_TRACE_CMPF; >>>>> + break; >>>>> + >>>>> + case 64: >>>>> + fncode =3D BUILT_IN_SANITIZER_COV_TRACE_CMPD; >>>>> + break; >>>>> + >>>>> + default: >>>>> + return; >>>>> + break; >>>>> + } >>>>> + tree fndecl =3D builtin_decl_implicit (fncode); >>>>> + gimple *gcall =3D 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 =3D as_a (stmt); >>>>> + tree index =3D gimple_switch_index (switch_stmt); >>>>> + unsigned bitno =3D TYPE_PRECISION (TREE_TYPE (index)); >>>>> + unsigned i, n =3D gimple_switch_num_labels (switch_stmt), num =3D = 0; >>>>> + for (i =3D 0; i < n; ++i) >>>>> + { >>>>> + tree label =3D gimple_switch_label (switch_stmt, i); >>>>> + tree low_case =3D CASE_LOW (label); >>>>> + if (low_case !=3D NULL_TREE) >>>>> + num++; >>>>> + tree high_case =3D CASE_HIGH (label); >>>>> + if (high_case !=3D NULL_TREE) >>>>> + num++; >>>>> + } >>>>> + >>>>> + tree case_array_elem_type =3D build_type_variant (uint64_type_node= , 1, 0); >>>>> + tree case_array_type =3D build_array_type (case_array_elem_type, >>>>> + build_index_type (size_int= (num + 2 - 1))); >>>>> + char name[64]; >>>>> + static size_t case_array_count =3D 0; >>>>> + snprintf(name, sizeof(name) - 1, "__sanitizer_cov_trace_switch_arr= ay%lu", case_array_count++); >>>>> + tree case_array_var =3D build_decl (UNKNOWN_LOCATION, VAR_DECL, >>>>> + get_identifier (name), case_array= _type); >>>>> + TREE_STATIC (case_array_var) =3D 1; >>>>> + TREE_PUBLIC (case_array_var) =3D 0; >>>>> + TREE_CONSTANT (case_array_var) =3D 1; >>>>> + TREE_READONLY (case_array_var) =3D 1; >>>>> + DECL_EXTERNAL (case_array_var) =3D 0; >>>>> + DECL_ARTIFICIAL (case_array_var) =3D 1; >>>>> + DECL_IGNORED_P (case_array_var) =3D 1; >>>>> + >>>>> + vec *v =3D NULL; >>>>> + vec_alloc (v, num + 2); >>>>> + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (uint64_type_n= ode, num)); >>>>> + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (uint64_type_n= ode, bitno)); >>>>> + for (i =3D 0; i < n; ++i) >>>>> + { >>>>> + tree label =3D gimple_switch_label (switch_stmt, i); >>>>> + >>>>> + tree low_case =3D CASE_LOW (label); >>>>> + if (low_case !=3D NULL_TREE) >>>>> + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, >>>>> + build_int_cst (uint64_type_node, TREE= _INT_CST_LOW (low_case))); >>>>> + >>>>> + tree high_case =3D CASE_HIGH (label); >>>>> + if (high_case !=3D NULL_TREE) >>>>> + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, >>>>> + build_int_cst (uint64_type_node, TREE= _INT_CST_LOW (high_case))); >>>>> + } >>>>> + tree ctor =3D build_constructor (case_array_type, v); >>>>> + TREE_STATIC (ctor) =3D 1; >>>>> + TREE_PUBLIC (ctor) =3D 0; >>>>> + TREE_CONSTANT (ctor) =3D 1; >>>>> + TREE_READONLY (ctor) =3D 1; >>>>> + DECL_EXTERNAL (ctor) =3D 0; >>>>> + DECL_INITIAL (case_array_var) =3D ctor; >>>>> + varpool_node::finalize_decl (case_array_var); >>>>> + >>>>> + tree case_array_var_ref =3D build_fold_addr_expr (case_array_var); >>>>> + add_local_decl (fun, case_array_var); >>>>> + tree fndecl =3D builtin_decl_implicit (BUILT_IN_SANITIZER_COV_TRAC= E_SWITCH); >>>>> + gimple *gcall =3D 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 =3D builtin_decl_implicit (BUILT_IN_SANITIZER_COV_TRAC= E_PC); >>>>> - basic_block bb; >>>>> - FOR_EACH_BB_FN (bb, fun) >>>>> + if (flag_sanitize_coverage & SANITIZE_COV_TRACE_PC) >>>>> { >>>>> - gimple_stmt_iterator gsi =3D gsi_start_nondebug_after_labels_b= b (bb); >>>>> - if (gsi_end_p (gsi)) >>>>> - continue; >>>>> - gimple *stmt =3D gsi_stmt (gsi); >>>>> - gimple *gcall =3D gimple_build_call (fndecl, 0); >>>>> - gimple_set_location (gcall, gimple_location (stmt)); >>>>> - gsi_insert_before (&gsi, gcall, GSI_SAME_STMT); >>>>> + tree fndecl =3D builtin_decl_implicit (BUILT_IN_SANITIZER_COV_= TRACE_PC); >>>>> + FOR_EACH_BB_FN (bb, fun) >>>>> + { >>>>> + gimple_stmt_iterator gsi =3D gsi_start_nondebug_after_labe= ls_bb (bb); >>>>> + if (gsi_end_p (gsi)) >>>>> + continue; >>>>> + gimple *stmt =3D gsi_stmt (gsi); >>>>> + gimple *gcall =3D 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 =3D gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next= (&gsi)) >>>>> + { >>>>> + gimple *stmt =3D 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 >>>>> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >>>>> --- gcc/sanitizer.def (revision 250082) >>>>> +++ gcc/sanitizer.def (working copy) >>>>> @@ -529,6 +529,27 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_DYNA= MI >>>>> 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_LIS= T) >>>>> +DEF_SANITIZER_BUILTIN(BUILT_IN_SANITIZER_COV_TRACE_CMP4, >>>>> + "__sanitizer_cov_trace_cmp4", >>>>> + BT_FN_VOID_UINT32_UINT32, ATTR_NOTHROW_LEAF_LIS= T) >>>>> +DEF_SANITIZER_BUILTIN(BUILT_IN_SANITIZER_COV_TRACE_CMP8, >>>>> + "__sanitizer_cov_trace_cmp8", >>>>> + BT_FN_VOID_UINT64_UINT64, ATTR_NOTHROW_LEAF_LIS= T) >>>>> +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_LIS= T) >>>>> +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)