"Fossies" - the Fresh Open Source Software Archive

Member "honggfuzz-2.2/libhfuzz/instrument.c" (23 Apr 2020, 28562 Bytes) of package /linux/privat/honggfuzz-2.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "instrument.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.1_vs_2.2.

    1 #include "instrument.h"
    2 
    3 #include <ctype.h>
    4 #include <dlfcn.h>
    5 #include <errno.h>
    6 #include <fcntl.h>
    7 #include <inttypes.h>
    8 #if defined(_HF_ARCH_LINUX)
    9 #include <linux/mman.h>
   10 #endif /* defined(_HF_ARCH_LINUX) */
   11 #include <stdbool.h>
   12 #include <stdint.h>
   13 #include <stdio.h>
   14 #include <stdlib.h>
   15 #include <string.h>
   16 #include <sys/mman.h>
   17 #include <sys/stat.h>
   18 #include <sys/types.h>
   19 #include <unistd.h>
   20 
   21 #include "honggfuzz.h"
   22 #include "libhfcommon/common.h"
   23 #include "libhfcommon/files.h"
   24 #include "libhfcommon/log.h"
   25 #include "libhfcommon/util.h"
   26 
   27 /* Cygwin doesn't support this */
   28 #if !defined(__CYGWIN__)
   29 __attribute__((visibility("hidden")))
   30 #endif /* !defined(__CYGWIN__) */
   31 __attribute__((used)) const char* const LIBHFUZZ_module_instrument = "LIBHFUZZ_module_instrument";
   32 
   33 /*
   34  * We require SSE4.2 with x86-(32|64) for the 'popcnt', as it's much faster than the software
   35  * emulation of gcc/clang
   36  */
   37 #if defined(__x86_64__) || defined(__i386__)
   38 #define HF_REQUIRE_SSE42_POPCNT __attribute__((__target__("sse4.2,popcnt")))
   39 #else
   40 #define HF_REQUIRE_SSE42_POPCNT
   41 #endif /* defined(__x86_64__) || defined(__i386__) */
   42 
   43 /*
   44  * If there's no _HF_COV_BITMAP_FD available (running without the honggfuzz
   45  * supervisor), use a dummy bitmap and control structure located in the BSS
   46  */
   47 static feedback_t bbMapFb;
   48 
   49 feedback_t* globalCovFeedback = &bbMapFb;
   50 feedback_t* localCovFeedback = &bbMapFb;
   51 cmpfeedback_t* globalCmpFeedback = NULL;
   52 
   53 uint32_t my_thread_no = 0;
   54 
   55 static int _memcmp(const void* m1, const void* m2, size_t n) {
   56     const unsigned char* s1 = (const unsigned char*)m1;
   57     const unsigned char* s2 = (const unsigned char*)m2;
   58 
   59     for (size_t i = 0; i < n; i++) {
   60         if (s1[i] != s2[i]) {
   61             return (int)s1[i] - (int)s2[i];
   62         }
   63     }
   64 
   65     return 0;
   66 }
   67 
   68 int (*libc_memcmp)(const void* s1, const void* s2, size_t n) = _memcmp;
   69 
   70 static void* getsym(const char* sym) {
   71 #if defined(RTLD_NEXT)
   72     return dlsym(RTLD_NEXT, sym);
   73 #else  /* defined(RTLD_NEXT) */
   74     void* dlh = dlopen(NULL, RTLD_LAZY);
   75     if (!dlh) {
   76         return NULL;
   77     }
   78     return dlsym(dlh, sym);
   79 #endif /* defined(RTLD_NEXT) */
   80 }
   81 
   82 static void initializeLibcFunctions(void) {
   83     libc_memcmp = (int (*)(const void* s1, const void* s2, size_t n))getsym("memcmp");
   84     if (!libc_memcmp) {
   85         LOG_W("dlsym(memcmp) failed: %s", dlerror());
   86         libc_memcmp = _memcmp;
   87     }
   88     LOG_D("libc_memcmp=%p, (_memcmp=%p, memcmp=%p)", libc_memcmp, _memcmp, memcmp);
   89 }
   90 
   91 static void* initialzeTryMapHugeTLB(int fd, size_t sz) {
   92     int mflags = 0;
   93 
   94 #if defined(_HF_ARCH_LINUX)
   95     /*
   96      * Try to map the local structure using HugeTLB. It'll be way fatser later to clean it with
   97      * { ftruncate(fd, 0); ftruncate(fd, size); }
   98      */
   99     mflags = files_getTmpMapFlags(MAP_SHARED | MAP_HUGE_2MB, /* nocore= */ true);
  100     void* ret = mmap(NULL, sz, PROT_READ | PROT_WRITE, mflags, fd, 0);
  101 #if defined(__x86_64__) || defined(__i386__)
  102     if (ret == MAP_FAILED) {
  103         PLOG_W("mmap(sz=%zu fd=%d flags=MAP_SHARED|MAP_HUGE_2MB) failed", sz, fd);
  104     }
  105 #endif /* defined(__x86_64__) || defined(__i386__) */
  106     if (ret != MAP_FAILED) {
  107         return ret;
  108     }
  109 #endif /* defined(_HF_ARCH_LINUX) */
  110 
  111     mflags = files_getTmpMapFlags(MAP_SHARED, /* nocore= */ true);
  112     return mmap(NULL, sz, PROT_READ | PROT_WRITE, mflags, fd, 0);
  113 }
  114 
  115 static void initializeCmpFeedback(void) {
  116     struct stat st;
  117     if (fstat(_HF_CMP_BITMAP_FD, &st) == -1) {
  118         return;
  119     }
  120     if (st.st_size != sizeof(cmpfeedback_t)) {
  121         LOG_W(
  122             "Size of the globalCmpFeedback structure mismatch: st.size != sizeof(cmpfeedback_t) "
  123             "(%zu != %zu). Link your fuzzed binaries with the newest honggfuzz and hfuzz-clang(++)",
  124             (size_t)st.st_size, sizeof(cmpfeedback_t));
  125         return;
  126     }
  127     void* ret = initialzeTryMapHugeTLB(_HF_CMP_BITMAP_FD, sizeof(cmpfeedback_t));
  128     if (ret == MAP_FAILED) {
  129         PLOG_W("mmap(_HF_CMP_BITMAP_FD=%d, size=%zu) of the feedback structure failed",
  130             _HF_CMP_BITMAP_FD, sizeof(cmpfeedback_t));
  131         return;
  132     }
  133     ATOMIC_SET(globalCmpFeedback, ret);
  134 }
  135 
  136 static bool initializeLocalCovFeedback(void) {
  137     struct stat st;
  138     if (fstat(_HF_PERTHREAD_BITMAP_FD, &st) == -1) {
  139         return false;
  140     }
  141     if ((size_t)st.st_size < sizeof(feedback_t)) {
  142         LOG_W("Size of the feedback structure mismatch: st.size < sizeof(feedback_t) (%zu < "
  143               "%zu). Build your honggfuzz binary from newer sources",
  144             (size_t)st.st_size, sizeof(feedback_t));
  145         return false;
  146     }
  147 
  148     localCovFeedback = initialzeTryMapHugeTLB(_HF_PERTHREAD_BITMAP_FD, sizeof(feedback_t));
  149     if (localCovFeedback == MAP_FAILED) {
  150         PLOG_W("mmap(_HF_PERTHREAD_BITMAP_FD=%d, size=%zu) of the local feedback structure failed",
  151             _HF_PERTHREAD_BITMAP_FD, sizeof(feedback_t));
  152         return false;
  153     }
  154     return true;
  155 }
  156 
  157 static bool initializeGlobalCovFeedback(void) {
  158     struct stat st;
  159     if (fstat(_HF_COV_BITMAP_FD, &st) == -1) {
  160         return false;
  161     }
  162     if ((size_t)st.st_size < sizeof(feedback_t)) {
  163         LOG_W("Size of the feedback structure mismatch: st.size < sizeof(feedback_t) (%zu < %zu). "
  164               "Build your honggfuzz binary from newer sources",
  165             (size_t)st.st_size, sizeof(feedback_t));
  166         return false;
  167     }
  168 
  169     globalCovFeedback = initialzeTryMapHugeTLB(_HF_COV_BITMAP_FD, sizeof(feedback_t));
  170     if (globalCovFeedback == MAP_FAILED) {
  171         PLOG_W("mmap(_HF_COV_BITMAP_FD=%d, size=%zu) of the feedback structure failed",
  172             _HF_COV_BITMAP_FD, sizeof(feedback_t));
  173         return false;
  174     }
  175     return true;
  176 }
  177 
  178 static void initializeInstrument(void) {
  179     if (fcntl(_HF_LOG_FD, F_GETFD) != -1) {
  180         enum llevel_t ll = INFO;
  181         const char* llstr = getenv(_HF_LOG_LEVEL_ENV);
  182         if (llstr) {
  183             ll = atoi(llstr);
  184         }
  185         logInitLogFile(NULL, _HF_LOG_FD, ll);
  186     }
  187     LOG_D("Initializing pid=%d", (int)getpid());
  188 
  189     char* my_thread_no_str = getenv(_HF_THREAD_NO_ENV);
  190     if (my_thread_no_str == NULL) {
  191         LOG_D("The '%s' envvar is not set", _HF_THREAD_NO_ENV);
  192         return;
  193     }
  194     my_thread_no = atoi(my_thread_no_str);
  195 
  196     if (my_thread_no >= _HF_THREAD_MAX) {
  197         LOG_F("Received (via envvar) my_thread_no > _HF_THREAD_MAX (%" PRIu32 " > %d)\n",
  198             my_thread_no, _HF_THREAD_MAX);
  199     }
  200 
  201     if (!initializeGlobalCovFeedback()) {
  202         globalCovFeedback = &bbMapFb;
  203         LOG_F("Could not intialize the global coverage feedback map");
  204     }
  205     if (!initializeLocalCovFeedback()) {
  206         localCovFeedback = &bbMapFb;
  207         LOG_F("Could not intialize the local coverage feedback map");
  208     }
  209     initializeCmpFeedback();
  210 
  211     /* Initialize native functions found in libc */
  212     initializeLibcFunctions();
  213 
  214     /* Reset coverage counters to their initial state */
  215     instrumentClearNewCov();
  216 }
  217 
  218 static __thread pthread_once_t localInitOnce = PTHREAD_ONCE_INIT;
  219 
  220 extern void hfuzzInstrumentInit(void);
  221 __attribute__((constructor)) void hfuzzInstrumentInit(void) {
  222     pthread_once(&localInitOnce, initializeInstrument);
  223 }
  224 
  225 __attribute__((weak)) size_t instrumentReserveGuard(size_t cnt) {
  226     static size_t guardCnt = 1;
  227     size_t base = guardCnt;
  228     guardCnt += cnt;
  229     if (guardCnt >= _HF_PC_GUARD_MAX) {
  230         LOG_F(
  231             "This process requested too many PC-guards, total:%zu, requested:%zu)", guardCnt, cnt);
  232     }
  233     if (ATOMIC_GET(globalCovFeedback->guardNb) < guardCnt) {
  234         ATOMIC_SET(globalCovFeedback->guardNb, guardCnt);
  235         wmb();
  236     }
  237     return base;
  238 }
  239 
  240 void instrumentResetLocalCovFeedback(void) {
  241     bzero(localCovFeedback->pcGuardMap, HF_MIN(instrumentReserveGuard(0), _HF_PC_GUARD_MAX));
  242 
  243     wmb();
  244 }
  245 
  246 /* Used to limit certain expensive actions, like adding values to dictionaries */
  247 static inline bool instrumentLimitEvery(uint64_t step) {
  248     static __thread uint64_t staticCnt = 0;
  249     if (((staticCnt++) % step) == 0) {
  250         return true;
  251     }
  252     return false;
  253 }
  254 
  255 static inline void instrumentAddConstMemInternal(const void* mem, size_t len) {
  256     if (len == 0) {
  257         return;
  258     }
  259     if (len > sizeof(globalCmpFeedback->valArr[0].val)) {
  260         len = sizeof(globalCmpFeedback->valArr[0].val);
  261     }
  262     uint32_t curroff = ATOMIC_GET(globalCmpFeedback->cnt);
  263     if (curroff >= ARRAYSIZE(globalCmpFeedback->valArr)) {
  264         return;
  265     }
  266 
  267     for (uint32_t i = 0; i < curroff; i++) {
  268         if ((len == ATOMIC_GET(globalCmpFeedback->valArr[i].len)) &&
  269             libc_memcmp(globalCmpFeedback->valArr[i].val, mem, len) == 0) {
  270             return;
  271         }
  272     }
  273 
  274     uint32_t newoff = ATOMIC_POST_INC(globalCmpFeedback->cnt);
  275     if (newoff >= ARRAYSIZE(globalCmpFeedback->valArr)) {
  276         ATOMIC_SET(globalCmpFeedback->cnt, ARRAYSIZE(globalCmpFeedback->valArr));
  277         return;
  278     }
  279 
  280     memcpy(globalCmpFeedback->valArr[newoff].val, mem, len);
  281     ATOMIC_SET(globalCmpFeedback->valArr[newoff].len, len);
  282     wmb();
  283 }
  284 
  285 /*
  286  * -finstrument-functions
  287  */
  288 HF_REQUIRE_SSE42_POPCNT void __cyg_profile_func_enter(void* func, void* caller) {
  289     register size_t pos =
  290         (((uintptr_t)func << 12) | ((uintptr_t)caller & 0xFFF)) & _HF_PERF_BITMAP_BITSZ_MASK;
  291     register bool prev = ATOMIC_BITMAP_SET(globalCovFeedback->bbMapPc, pos);
  292     if (!prev) {
  293         ATOMIC_PRE_INC(globalCovFeedback->pidNewPC[my_thread_no]);
  294         wmb();
  295     }
  296 }
  297 
  298 HF_REQUIRE_SSE42_POPCNT void __cyg_profile_func_exit(
  299     void* func HF_ATTR_UNUSED, void* caller HF_ATTR_UNUSED) {
  300     return;
  301 }
  302 
  303 /*
  304  * -fsanitize-coverage=trace-pc
  305  */
  306 HF_REQUIRE_SSE42_POPCNT static inline void hfuzz_trace_pc_internal(uintptr_t pc) {
  307     register uintptr_t ret = pc & _HF_PERF_BITMAP_BITSZ_MASK;
  308 
  309     register bool prev = ATOMIC_BITMAP_SET(globalCovFeedback->bbMapPc, ret);
  310     if (!prev) {
  311         ATOMIC_PRE_INC(globalCovFeedback->pidNewPC[my_thread_no]);
  312         wmb();
  313     }
  314 }
  315 
  316 HF_REQUIRE_SSE42_POPCNT void __sanitizer_cov_trace_pc(void) {
  317     hfuzz_trace_pc_internal((uintptr_t)__builtin_return_address(0));
  318 }
  319 
  320 HF_REQUIRE_SSE42_POPCNT void hfuzz_trace_pc(uintptr_t pc) {
  321     hfuzz_trace_pc_internal(pc);
  322 }
  323 
  324 /*
  325  * -fsanitize-coverage=trace-cmp
  326  */
  327 HF_REQUIRE_SSE42_POPCNT static inline void hfuzz_trace_cmp1_internal(
  328     uintptr_t pc, uint8_t Arg1, uint8_t Arg2) {
  329     uintptr_t pos = pc % _HF_PERF_BITMAP_SIZE_16M;
  330     register uint8_t v = ((sizeof(Arg1) * 8) - __builtin_popcount(Arg1 ^ Arg2));
  331     uint8_t prev = ATOMIC_GET(globalCovFeedback->bbMapCmp[pos]);
  332     if (prev < v) {
  333         ATOMIC_SET(globalCovFeedback->bbMapCmp[pos], v);
  334         ATOMIC_POST_ADD(globalCovFeedback->pidNewCmp[my_thread_no], v - prev);
  335         wmb();
  336     }
  337 }
  338 
  339 HF_REQUIRE_SSE42_POPCNT static inline void hfuzz_trace_cmp2_internal(
  340     uintptr_t pc, uint16_t Arg1, uint16_t Arg2) {
  341     uintptr_t pos = pc % _HF_PERF_BITMAP_SIZE_16M;
  342     register uint8_t v = ((sizeof(Arg1) * 8) - __builtin_popcount(Arg1 ^ Arg2));
  343     uint8_t prev = ATOMIC_GET(globalCovFeedback->bbMapCmp[pos]);
  344     if (prev < v) {
  345         ATOMIC_SET(globalCovFeedback->bbMapCmp[pos], v);
  346         ATOMIC_POST_ADD(globalCovFeedback->pidNewCmp[my_thread_no], v - prev);
  347         wmb();
  348     }
  349 }
  350 
  351 HF_REQUIRE_SSE42_POPCNT static inline void hfuzz_trace_cmp4_internal(
  352     uintptr_t pc, uint32_t Arg1, uint32_t Arg2) {
  353     uintptr_t pos = pc % _HF_PERF_BITMAP_SIZE_16M;
  354     register uint8_t v = ((sizeof(Arg1) * 8) - __builtin_popcount(Arg1 ^ Arg2));
  355     uint8_t prev = ATOMIC_GET(globalCovFeedback->bbMapCmp[pos]);
  356     if (prev < v) {
  357         ATOMIC_SET(globalCovFeedback->bbMapCmp[pos], v);
  358         ATOMIC_POST_ADD(globalCovFeedback->pidNewCmp[my_thread_no], v - prev);
  359         wmb();
  360     }
  361 }
  362 
  363 HF_REQUIRE_SSE42_POPCNT static inline void hfuzz_trace_cmp8_internal(
  364     uintptr_t pc, uint64_t Arg1, uint64_t Arg2) {
  365     uintptr_t pos = pc % _HF_PERF_BITMAP_SIZE_16M;
  366     register uint8_t v = ((sizeof(Arg1) * 8) - __builtin_popcountll(Arg1 ^ Arg2));
  367     uint8_t prev = ATOMIC_GET(globalCovFeedback->bbMapCmp[pos]);
  368     if (prev < v) {
  369         ATOMIC_SET(globalCovFeedback->bbMapCmp[pos], v);
  370         ATOMIC_POST_ADD(globalCovFeedback->pidNewCmp[my_thread_no], v - prev);
  371         wmb();
  372     }
  373 }
  374 
  375 /* Standard __sanitizer_cov_trace_cmp wrappers */
  376 void __sanitizer_cov_trace_cmp1(uint8_t Arg1, uint8_t Arg2) {
  377     hfuzz_trace_cmp1_internal((uintptr_t)__builtin_return_address(0), Arg1, Arg2);
  378 }
  379 
  380 void __sanitizer_cov_trace_cmp2(uint16_t Arg1, uint16_t Arg2) {
  381     hfuzz_trace_cmp2_internal((uintptr_t)__builtin_return_address(0), Arg1, Arg2);
  382 }
  383 
  384 void __sanitizer_cov_trace_cmp4(uint32_t Arg1, uint32_t Arg2) {
  385     /* Add 4byte values to the const_dictionary if they exist within the binary */
  386     if (globalCmpFeedback && instrumentLimitEvery(4095)) {
  387         if (Arg1 > 0xffff) {
  388             uint32_t bswp = __builtin_bswap32(Arg1);
  389             if (util_32bitValInBinary(Arg1) || util_32bitValInBinary(bswp)) {
  390                 instrumentAddConstMemInternal(&Arg1, sizeof(Arg1));
  391                 instrumentAddConstMemInternal(&bswp, sizeof(bswp));
  392             }
  393         }
  394         if (Arg2 > 0xffff) {
  395             uint32_t bswp = __builtin_bswap32(Arg2);
  396             if (util_32bitValInBinary(Arg2) || util_32bitValInBinary(bswp)) {
  397                 instrumentAddConstMemInternal(&Arg2, sizeof(Arg2));
  398                 instrumentAddConstMemInternal(&bswp, sizeof(bswp));
  399             }
  400         }
  401     }
  402 
  403     hfuzz_trace_cmp4_internal((uintptr_t)__builtin_return_address(0), Arg1, Arg2);
  404 }
  405 
  406 void __sanitizer_cov_trace_cmp8(uint64_t Arg1, uint64_t Arg2) {
  407     /* Add 8byte values to the const_dictionary if they exist within the binary */
  408     if (globalCmpFeedback && instrumentLimitEvery(4095)) {
  409         if (Arg1 > 0xffffff) {
  410             uint64_t bswp = __builtin_bswap64(Arg1);
  411             if (util_64bitValInBinary(Arg1) || util_64bitValInBinary(bswp)) {
  412                 instrumentAddConstMemInternal(&Arg1, sizeof(Arg1));
  413                 instrumentAddConstMemInternal(&bswp, sizeof(bswp));
  414             }
  415         }
  416         if (Arg2 > 0xffffff) {
  417             uint64_t bswp = __builtin_bswap64(Arg2);
  418             if (util_64bitValInBinary(Arg2) || util_64bitValInBinary(bswp)) {
  419                 instrumentAddConstMemInternal(&Arg2, sizeof(Arg2));
  420                 instrumentAddConstMemInternal(&bswp, sizeof(bswp));
  421             }
  422         }
  423     }
  424 
  425     hfuzz_trace_cmp8_internal((uintptr_t)__builtin_return_address(0), Arg1, Arg2);
  426 }
  427 
  428 /* Standard __sanitizer_cov_trace_const_cmp wrappers */
  429 void __sanitizer_cov_trace_const_cmp1(uint8_t Arg1, uint8_t Arg2) {
  430     instrumentAddConstMem(&Arg1, sizeof(Arg1), /* check_if_ro= */ false);
  431     hfuzz_trace_cmp1_internal((uintptr_t)__builtin_return_address(0), Arg1, Arg2);
  432 }
  433 
  434 void __sanitizer_cov_trace_const_cmp2(uint16_t Arg1, uint16_t Arg2) {
  435     if (Arg1) {
  436         uint16_t bswp = __builtin_bswap16(Arg1);
  437         instrumentAddConstMem(&bswp, sizeof(bswp), /* check_if_ro= */ false);
  438         instrumentAddConstMem(&Arg1, sizeof(Arg1), /* check_if_ro= */ false);
  439     }
  440     hfuzz_trace_cmp2_internal((uintptr_t)__builtin_return_address(0), Arg1, Arg2);
  441 }
  442 
  443 void __sanitizer_cov_trace_const_cmp4(uint32_t Arg1, uint32_t Arg2) {
  444     if (Arg1) {
  445         uint32_t bswp = __builtin_bswap32(Arg1);
  446         instrumentAddConstMem(&bswp, sizeof(bswp), /* check_if_ro= */ false);
  447         instrumentAddConstMem(&Arg1, sizeof(Arg1), /* check_if_ro= */ false);
  448     }
  449     hfuzz_trace_cmp4_internal((uintptr_t)__builtin_return_address(0), Arg1, Arg2);
  450 }
  451 
  452 void __sanitizer_cov_trace_const_cmp8(uint64_t Arg1, uint64_t Arg2) {
  453     if (Arg1) {
  454         uint64_t bswp = __builtin_bswap64(Arg1);
  455         instrumentAddConstMem(&bswp, sizeof(bswp), /* check_if_ro= */ false);
  456         instrumentAddConstMem(&Arg1, sizeof(Arg1), /* check_if_ro= */ false);
  457     }
  458     hfuzz_trace_cmp8_internal((uintptr_t)__builtin_return_address(0), Arg1, Arg2);
  459 }
  460 
  461 /* Custom functions for e.g. the qemu-honggfuzz code */
  462 void hfuzz_trace_cmp1(uintptr_t pc, uint8_t Arg1, uint8_t Arg2) {
  463     hfuzz_trace_cmp1_internal(pc, Arg1, Arg2);
  464 }
  465 
  466 void hfuzz_trace_cmp2(uintptr_t pc, uint16_t Arg1, uint16_t Arg2) {
  467     hfuzz_trace_cmp2_internal(pc, Arg1, Arg2);
  468 }
  469 
  470 void hfuzz_trace_cmp4(uintptr_t pc, uint32_t Arg1, uint32_t Arg2) {
  471     hfuzz_trace_cmp4_internal(pc, Arg1, Arg2);
  472 }
  473 
  474 void hfuzz_trace_cmp8(uintptr_t pc, uint64_t Arg1, uint64_t Arg2) {
  475     hfuzz_trace_cmp8_internal(pc, Arg1, Arg2);
  476 }
  477 
  478 /*
  479  * Old version of __sanitizer_cov_trace_cmp[n]. Remove it at some point
  480  */
  481 HF_REQUIRE_SSE42_POPCNT void __sanitizer_cov_trace_cmp(
  482     uint64_t SizeAndType, uint64_t Arg1, uint64_t Arg2) {
  483     uint64_t CmpSize = (SizeAndType >> 32) / 8;
  484     switch (CmpSize) {
  485         case (sizeof(uint8_t)):
  486             hfuzz_trace_cmp1_internal((uintptr_t)__builtin_return_address(0), Arg1, Arg2);
  487             return;
  488         case (sizeof(uint16_t)):
  489             hfuzz_trace_cmp2_internal((uintptr_t)__builtin_return_address(0), Arg1, Arg2);
  490             return;
  491         case (sizeof(uint32_t)):
  492             hfuzz_trace_cmp4_internal((uintptr_t)__builtin_return_address(0), Arg1, Arg2);
  493             return;
  494         case (sizeof(uint64_t)):
  495             hfuzz_trace_cmp8_internal((uintptr_t)__builtin_return_address(0), Arg1, Arg2);
  496             return;
  497     }
  498 }
  499 
  500 /*
  501  * Cases[0] is number of comparison entries
  502  * Cases[1] is length of Val in bits
  503  */
  504 HF_REQUIRE_SSE42_POPCNT void __sanitizer_cov_trace_switch(uint64_t Val, uint64_t* Cases) {
  505     for (uint64_t i = 0; i < Cases[0]; i++) {
  506         uintptr_t pos = ((uintptr_t)__builtin_return_address(0) + i) % _HF_PERF_BITMAP_SIZE_16M;
  507         uint8_t v = (uint8_t)Cases[1] - __builtin_popcountll(Val ^ Cases[i + 2]);
  508         uint8_t prev = ATOMIC_GET(globalCovFeedback->bbMapCmp[pos]);
  509         if (prev < v) {
  510             ATOMIC_SET(globalCovFeedback->bbMapCmp[pos], v);
  511             ATOMIC_POST_ADD(globalCovFeedback->pidNewCmp[my_thread_no], v - prev);
  512             wmb();
  513         }
  514     }
  515 }
  516 
  517 /*
  518  * gcc-8 -fsanitize-coverage=trace-cmp trace hooks
  519  * TODO: evaluate, whether it makes sense to implement them
  520  */
  521 HF_REQUIRE_SSE42_POPCNT void __sanitizer_cov_trace_cmpf(
  522     float Arg1 HF_ATTR_UNUSED, float Arg2 HF_ATTR_UNUSED) {
  523 }
  524 HF_REQUIRE_SSE42_POPCNT void __sanitizer_cov_trace_cmpd(
  525     double Arg1 HF_ATTR_UNUSED, double Arg2 HF_ATTR_UNUSED) {
  526 }
  527 
  528 /*
  529  * -fsanitize-coverage=trace-div
  530  */
  531 HF_REQUIRE_SSE42_POPCNT void __sanitizer_cov_trace_div8(uint64_t Val) {
  532     uintptr_t pos = (uintptr_t)__builtin_return_address(0) % _HF_PERF_BITMAP_SIZE_16M;
  533     uint8_t v = ((sizeof(Val) * 8) - __builtin_popcountll(Val));
  534     uint8_t prev = ATOMIC_GET(globalCovFeedback->bbMapCmp[pos]);
  535     if (prev < v) {
  536         ATOMIC_SET(globalCovFeedback->bbMapCmp[pos], v);
  537         ATOMIC_POST_ADD(globalCovFeedback->pidNewCmp[my_thread_no], v - prev);
  538         wmb();
  539     }
  540 }
  541 
  542 HF_REQUIRE_SSE42_POPCNT void __sanitizer_cov_trace_div4(uint32_t Val) {
  543     uintptr_t pos = (uintptr_t)__builtin_return_address(0) % _HF_PERF_BITMAP_SIZE_16M;
  544     uint8_t v = ((sizeof(Val) * 8) - __builtin_popcount(Val));
  545     uint8_t prev = ATOMIC_GET(globalCovFeedback->bbMapCmp[pos]);
  546     if (prev < v) {
  547         ATOMIC_SET(globalCovFeedback->bbMapCmp[pos], v);
  548         ATOMIC_POST_ADD(globalCovFeedback->pidNewCmp[my_thread_no], v - prev);
  549         wmb();
  550     }
  551 }
  552 
  553 /*
  554  * -fsanitize-coverage=indirect-calls
  555  */
  556 HF_REQUIRE_SSE42_POPCNT void __sanitizer_cov_trace_pc_indir(uintptr_t callee) {
  557     register size_t pos1 = (uintptr_t)__builtin_return_address(0) << 12;
  558     register size_t pos2 = callee & 0xFFF;
  559     register size_t pos = (pos1 | pos2) & _HF_PERF_BITMAP_BITSZ_MASK;
  560 
  561     register bool prev = ATOMIC_BITMAP_SET(globalCovFeedback->bbMapPc, pos);
  562     if (!prev) {
  563         ATOMIC_PRE_INC(globalCovFeedback->pidNewPC[my_thread_no]);
  564         wmb();
  565     }
  566 }
  567 
  568 /*
  569  * In LLVM-4.0 it's marked (probably mistakenly) as non-weak symbol, so we need to mark it as weak
  570  * here
  571  */
  572 __attribute__((weak)) HF_REQUIRE_SSE42_POPCNT void __sanitizer_cov_indir_call16(
  573     void* callee, void* callee_cache16[] HF_ATTR_UNUSED) {
  574     register size_t pos1 = (uintptr_t)__builtin_return_address(0) << 12;
  575     register size_t pos2 = (uintptr_t)callee & 0xFFF;
  576     register size_t pos = (pos1 | pos2) & _HF_PERF_BITMAP_BITSZ_MASK;
  577 
  578     register bool prev = ATOMIC_BITMAP_SET(globalCovFeedback->bbMapPc, pos);
  579     if (!prev) {
  580         ATOMIC_PRE_INC(globalCovFeedback->pidNewPC[my_thread_no]);
  581         wmb();
  582     }
  583 }
  584 
  585 /*
  586  * -fsanitize-coverage=trace-pc-guard
  587  */
  588 static bool guards_initialized = false;
  589 HF_REQUIRE_SSE42_POPCNT void __sanitizer_cov_trace_pc_guard_init(uint32_t* start, uint32_t* stop) {
  590     guards_initialized = true;
  591 
  592     /* Make sure that the feedback struct is already mmap()'d */
  593     hfuzzInstrumentInit();
  594 
  595     if ((uintptr_t)start == (uintptr_t)stop) {
  596         return;
  597     }
  598     /* If this module was already initialized, skip it */
  599     if (*start > 0) {
  600         LOG_D("Module %p-%p is already initialized", start, stop);
  601         return;
  602     }
  603 
  604     LOG_D("PC-Guard module initialization: %p-%p (count:%tu) at %zu", start, stop,
  605         ((uintptr_t)stop - (uintptr_t)start) / sizeof(*start), instrumentReserveGuard(0));
  606 
  607     for (uint32_t* x = start; x < stop; x++) {
  608         uint32_t guardNo = instrumentReserveGuard(1);
  609         *x = guardNo;
  610     }
  611 
  612     wmb();
  613 }
  614 
  615 /* Map number of visits to an edge into buckets */
  616 static uint8_t const instrumentCntMap[256] = {
  617     [0] = 0,
  618     [1] = 1U << 0,
  619     [2] = 1U << 1,
  620     [3] = 1U << 2,
  621     [4 ... 5] = 1U << 3,
  622     [6 ... 10] = 1U << 4,
  623     [11 ... 32] = 1U << 5,
  624     [33 ... 64] = 1U << 6,
  625     [65 ... 255] = 1U << 7,
  626 };
  627 
  628 HF_REQUIRE_SSE42_POPCNT void __sanitizer_cov_trace_pc_guard(uint32_t* guard_ptr) {
  629 #if defined(__ANDROID__)
  630     /*
  631      * ANDROID: Bionic invokes routines that Honggfuzz wraps, before either
  632      *          *SAN or Honggfuzz have initialized.  Check to see if Honggfuzz
  633      *          has initialized -- if not, force *SAN to initialize (otherwise
  634      *          _strcmp() will crash, as it is *SAN-instrumented).
  635      *
  636      *          Defer all trace_pc_guard activity until trace_pc_guard_init is
  637      *          invoked via sancov.module_ctor in the normal process of things.
  638      */
  639     if (!guards_initialized) {
  640         void __asan_init(void) __attribute__((weak));
  641         if (__asan_init) {
  642             __asan_init();
  643         }
  644         void __msan_init(void) __attribute__((weak));
  645         if (__msan_init) {
  646             __msan_init();
  647         }
  648         void __ubsan_init(void) __attribute__((weak));
  649         if (__ubsan_init) {
  650             __ubsan_init();
  651         }
  652         void __tsan_init(void) __attribute__((weak));
  653         if (__tsan_init) {
  654             __tsan_init();
  655         }
  656         return;
  657     }
  658 #endif /* defined(__ANDROID__) */
  659 
  660     /* This guard is uninteresting, it was probably maxed out already */
  661     const uint32_t guard = *guard_ptr;
  662     if (!guard) {
  663         return;
  664     }
  665 
  666     if (ATOMIC_GET(localCovFeedback->pcGuardMap[guard]) > 100) {
  667         /* This guard has been maxed out. Mark it as uninteresting */
  668         ATOMIC_CLEAR(*guard_ptr);
  669     }
  670 
  671     /* Update the total/local counters */
  672     const uint8_t v = ATOMIC_PRE_INC(localCovFeedback->pcGuardMap[guard]);
  673     if (v == 1) {
  674         ATOMIC_PRE_INC(globalCovFeedback->pidTotalEdge[my_thread_no]);
  675     } else {
  676         ATOMIC_PRE_INC(globalCovFeedback->pidTotalCmp[my_thread_no]);
  677     }
  678 
  679     /* Update the new/global counters */
  680     const uint8_t newval = instrumentCntMap[v];
  681     if (ATOMIC_GET(globalCovFeedback->pcGuardMap[guard]) < newval) {
  682         const uint8_t oldval = ATOMIC_POST_OR(globalCovFeedback->pcGuardMap[guard], newval);
  683         if (!oldval) {
  684             ATOMIC_PRE_INC(globalCovFeedback->pidNewEdge[my_thread_no]);
  685         } else if (oldval < newval) {
  686             ATOMIC_PRE_INC(globalCovFeedback->pidNewCmp[my_thread_no]);
  687         }
  688     }
  689     wmb();
  690 }
  691 
  692 /* Support up to 256 DSO modules with separate 8bit counters */
  693 static struct {
  694     uint8_t* start;
  695     size_t cnt;
  696     size_t guard;
  697 } hf8bitcounters[256] = {};
  698 
  699 void instrument8BitCountersCount(void) {
  700     rmb();
  701 
  702     uint64_t totalEdge = 0;
  703     uint64_t totalCmp = 0;
  704 
  705     for (size_t i = 0; i < ARRAYSIZE(hf8bitcounters) && hf8bitcounters[i].start; i++) {
  706         for (size_t j = 0; j < hf8bitcounters[i].cnt; j++) {
  707             const uint8_t v = hf8bitcounters[i].start[j];
  708             hf8bitcounters[i].start[j] = 0;
  709             if (!v) {
  710                 continue;
  711             }
  712 
  713             const uint8_t newval = instrumentCntMap[v];
  714             const size_t guard = hf8bitcounters[i].guard + j;
  715 
  716             /* New hits */
  717             if (ATOMIC_GET(globalCovFeedback->pcGuardMap[guard]) < newval) {
  718                 const uint8_t oldval = ATOMIC_POST_OR(globalCovFeedback->pcGuardMap[guard], newval);
  719                 if (!oldval) {
  720                     ATOMIC_PRE_INC(globalCovFeedback->pidNewEdge[my_thread_no]);
  721                 } else if (oldval < newval) {
  722                     ATOMIC_PRE_INC(globalCovFeedback->pidNewCmp[my_thread_no]);
  723                 }
  724             }
  725 
  726             /* Total hits */
  727             {
  728                 totalEdge++;
  729                 if (v > 1) {
  730                     totalCmp += newval;
  731                 }
  732             }
  733         }
  734     }
  735 
  736     ATOMIC_POST_ADD(globalCovFeedback->pidTotalEdge[my_thread_no], totalEdge);
  737     ATOMIC_POST_ADD(globalCovFeedback->pidTotalCmp[my_thread_no], totalCmp);
  738 
  739     wmb();
  740 }
  741 
  742 void __sanitizer_cov_8bit_counters_init(char* start, char* end) {
  743     /* Make sure that the feedback struct is already mmap()'d */
  744     hfuzzInstrumentInit();
  745 
  746     if ((uintptr_t)start == (uintptr_t)end) {
  747         return;
  748     }
  749     for (size_t i = 0; i < ARRAYSIZE(hf8bitcounters); i++) {
  750         if (hf8bitcounters[i].start == NULL) {
  751             hf8bitcounters[i].start = (uint8_t*)start;
  752             hf8bitcounters[i].cnt = (uintptr_t)end - (uintptr_t)start;
  753             hf8bitcounters[i].guard = instrumentReserveGuard(hf8bitcounters[i].cnt);
  754             LOG_D("8-bit module initialization %p-%p (count:%zu) at guard %zu", start, end,
  755                 hf8bitcounters[i].cnt, hf8bitcounters[i].guard);
  756             break;
  757         }
  758     }
  759 }
  760 
  761 /* Not implemented yet */
  762 void __sanitizer_cov_pcs_init(
  763     const uintptr_t* pcs_beg HF_ATTR_UNUSED, const uintptr_t* pcs_end HF_ATTR_UNUSED) {
  764 }
  765 
  766 unsigned instrumentThreadNo(void) {
  767     return my_thread_no;
  768 }
  769 
  770 /* Cygwin has problem with visibility of this symbol */
  771 #if !defined(__CYGWIN__)
  772 /* For some reason -fsanitize=fuzzer-no-link references this symbol */
  773 __attribute__((tls_model("initial-exec")))
  774 __attribute__((weak)) __thread uintptr_t __sancov_lowest_stack = 0;
  775 #endif /* !defined(__CYGWIN__) */
  776 
  777 bool instrumentUpdateCmpMap(uintptr_t addr, uint32_t v) {
  778     uintptr_t pos = addr % _HF_PERF_BITMAP_SIZE_16M;
  779     uint32_t prev = ATOMIC_GET(globalCovFeedback->bbMapCmp[pos]);
  780     if (prev < v) {
  781         ATOMIC_SET(globalCovFeedback->bbMapCmp[pos], v);
  782         ATOMIC_POST_ADD(globalCovFeedback->pidNewCmp[my_thread_no], v - prev);
  783         wmb();
  784         return true;
  785     }
  786     return false;
  787 }
  788 
  789 /* Reset the counters of newly discovered edges/pcs/features */
  790 void instrumentClearNewCov() {
  791     ATOMIC_CLEAR(globalCovFeedback->pidNewPC[my_thread_no]);
  792     ATOMIC_CLEAR(globalCovFeedback->pidNewEdge[my_thread_no]);
  793     ATOMIC_CLEAR(globalCovFeedback->pidNewCmp[my_thread_no]);
  794 
  795     ATOMIC_CLEAR(globalCovFeedback->pidTotalPC[my_thread_no]);
  796     ATOMIC_CLEAR(globalCovFeedback->pidTotalEdge[my_thread_no]);
  797     ATOMIC_CLEAR(globalCovFeedback->pidTotalCmp[my_thread_no]);
  798 
  799     wmb();
  800 }
  801 
  802 void instrumentAddConstMem(const void* mem, size_t len, bool check_if_ro) {
  803     if (!globalCmpFeedback) {
  804         return;
  805     }
  806     if (len == 0) {
  807         return;
  808     }
  809     if (!instrumentLimitEvery(127)) {
  810         return;
  811     }
  812     if (check_if_ro && util_getProgAddr(mem) == LHFC_ADDR_NOTFOUND) {
  813         return;
  814     }
  815     instrumentAddConstMemInternal(mem, len);
  816 }
  817 
  818 void instrumentAddConstStr(const char* s) {
  819     if (!globalCmpFeedback) {
  820         return;
  821     }
  822     if (!instrumentLimitEvery(127)) {
  823         return;
  824     }
  825     if (util_getProgAddr(s) == LHFC_ADDR_NOTFOUND) {
  826         return;
  827     }
  828     instrumentAddConstMemInternal(s, strlen(s));
  829 }
  830 
  831 void instrumentAddConstStrN(const char* s, size_t n) {
  832     if (!globalCmpFeedback) {
  833         return;
  834     }
  835     if (n == 0) {
  836         return;
  837     }
  838     if (!instrumentLimitEvery(127)) {
  839         return;
  840     }
  841     if (util_getProgAddr(s) == LHFC_ADDR_NOTFOUND) {
  842         return;
  843     }
  844     instrumentAddConstMemInternal(s, strnlen(s, n));
  845 }
  846 
  847 bool instrumentConstAvail(void) {
  848     return (ATOMIC_GET(globalCmpFeedback) != NULL);
  849 }