<commit_before>/*
 *
 * honggfuzz - architecture dependent code (LINUX/PERF)
 * -----------------------------------------
 *
 * Author: <NAME> <<EMAIL>>
 *
 * Copyright 2010-2015 by Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License. You may obtain
 * a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * permissions and limitations under the License.
 *
 */

#include "common.h"

#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <linux/hw_breakpoint.h>
#include <linux/perf_event.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/poll.h>
#include <sys/ptrace.h>
#include <sys/syscall.h>
#include <unistd.h>

#include "linux/perf.h"
#include "log.h"

#define _HF_RT_SIG (SIGRTMIN + 10)

/* Buffer used with BTS (branch recording) */
static __thread uint8_t *perfMmapBuf = NULL;
/* By default it's 1MB which allows to run 1 fuzzing thread */
static __thread size_t perfMmapSz = 0UL;
/* Have we seen PERF_RECRORD_LOST events */
static __thread unsigned int perfRecordLost = 0;
/* Don't record branches using address above this parameter */
static __thread uint64_t perfCutOffAddr = ~(1ULL);

#define _HF_PERF_BRANCHES_SZ (1024 * 16)
/*  *INDENT-OFF* */
static __thread struct {
  uint64_t from;
  uint64_t to;
} perfBranch[_HF_PERF_BRANCHES_SZ];
/*  *INDENT-ON* */

static size_t arch_perfCountBranches(void)
{
    size_t i = 0;
    for (i = 0; i < _HF_PERF_BRANCHES_SZ; i++) {
        if (perfBranch[i].from == 0ULL && perfBranch[i].to == 0ULL) {
            return i;
        }
        LOGMSG(l_DEBUG, "Branch entry: FROM: %" PRIx64 ", TO: %" PRIx64, perfBranch[i].from,
               perfBranch[i].to);
    }
    LOGMSG(l_FATAL, "Branch buffer too small (%zu elements)", ARRAYSIZE(perfBranch));
    return i;
}

static inline void arch_perfAddBranch(uint64_t from, uint64_t to)
{
    /*
     * Kernel sometimes reports branches from the kernel (iret), we are not interested in that as it
     * makes the whole concept of unique branch counting less predictable
     */
    if (from > 0xFFFFFFFF00000000 || to > 0xFFFFFFFF00000000) {
        return;
    }
    if (from >= perfCutOffAddr || to >= perfCutOffAddr) {
        return;
    }
    for (size_t i = 0; i < _HF_PERF_BRANCHES_SZ; i++) {
        if (perfBranch[i].from == from && perfBranch[i].to == to) {
            break;
        }
        if (perfBranch[i].from == 0ULL && perfBranch[i].to == 0ULL) {
            perfBranch[i].from = from;
            perfBranch[i].to = to;
            break;
        }
    }
}

static inline void arch_perfSkip(size_t skip)
{
    struct perf_event_mmap_page *pem = (struct perf_event_mmap_page *)perfMmapBuf;
    uint64_t dataTailOff = pem->data_tail;
    dataTailOff += skip;
    if (dataTailOff > perfMmapSz) {
        dataTailOff %= perfMmapSz;
    }
    pem->data_tail = dataTailOff;
}

/* Memory Barriers */
#if defined(__x86_64__)
#define rmb()	__asm__ __volatile__ ("lfence" ::: "memory")
#elif defined(__i386__)
#define rmb()	__asm__ __volatile__ ("lock; addl $0,0(%%esp)" ::: "memory")
#else
#define rmb()	__asm__ __volatile__ ("" ::: "memory")
#endif
static inline uint64_t arch_perfGetMulti64(void)
{
    struct perf_event_mmap_page *pem = (struct perf_event_mmap_page *)perfMmapBuf;
    uint64_t dataHeadOff = pem->data_head % perfMmapSz;
    rmb();
    uint64_t dataTailOff = pem->data_tail % perfMmapSz;
//    LOGMSG(l_ERROR, "HEAD: %llu TAIL: %llu", dataHeadOff, dataTailOff);

    int64_t dataLen = 0;
    if (dataHeadOff > dataTailOff) {
        dataLen = dataHeadOff - dataTailOff;
    }
    if (dataHeadOff < dataTailOff) {
        dataLen = perfMmapSz - dataTailOff + dataHeadOff;
    }

    if (dataLen < (int64_t) sizeof(uint64_t)) {
        return 0ULL;
    }

    uint64_t ret = *(uint64_t *) (perfMmapBuf + getpagesize() + dataTailOff);

    dataTailOff = (dataTailOff + sizeof(uint64_t)) % perfMmapSz;
    pem->data_tail = dataTailOff;

    return ret;
}

static inline void arch_perfMmapParse(void)
{
    for (;;) {
        uint64_t tmp;
        if ((tmp = arch_perfGetMulti64()) == 0ULL) {
            break;
        }

        struct perf_event_header *peh = (struct perf_event_header *)&tmp;
        if (peh->type == PERF_RECORD_LOST) {
            perfRecordLost++;
            arch_perfSkip(peh->size - sizeof(uint64_t));
            continue;
        }
        if (peh->type != PERF_RECORD_SAMPLE) {
            LOGMSG(l_DEBUG, "(struct perf_event_header)->type != PERF_RECORD_SAMPLE (%" PRIu16 ")",
                   peh->type);
            arch_perfSkip(peh->size - sizeof(uint64_t));
            continue;
        }
        if (peh->misc != PERF_RECORD_MISC_USER && peh->misc != PERF_RECORD_MISC_KERNEL) {
            LOGMSG(l_FATAL,
                   "(struct perf_event_header)->type != PERF_RECORD_MISC_USER (%" PRIu16 ")",
                   peh->misc);
            arch_perfSkip(peh->size - sizeof(uint64_t));
            continue;
        }

        uint64_t from = arch_perfGetMulti64();
        if (from == 0ULL) {
            LOGMSG(l_FATAL, "from == 0");
        }
        uint64_t to = arch_perfGetMulti64();
        if (to == 0ULL) {
            LOGMSG(l_FATAL, "to == 0");
        }

        arch_perfAddBranch(from, to);
    }<commit_msg>mmap(0 parsing buffer takes pointer to uint64_t<commit_after>/*
 *
 * honggfuzz - architecture dependent code (LINUX/PERF)
 * -----------------------------------------
 *
 * Author: <NAME> <<EMAIL>>
 *
 * Copyright 2010-2015 by Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License. You may obtain
 * a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * permissions and limitations under the License.
 *
 */

#include "common.h"

#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <linux/hw_breakpoint.h>
#include <linux/perf_event.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/poll.h>
#include <sys/ptrace.h>
#include <sys/syscall.h>
#include <unistd.h>

#include "linux/perf.h"
#include "log.h"

#define _HF_RT_SIG (SIGRTMIN + 10)

/* Buffer used with BTS (branch recording) */
static __thread uint8_t *perfMmapBuf = NULL;
/* By default it's 1MB which allows to run 1 fuzzing thread */
static __thread size_t perfMmapSz = 0UL;
/* Have we seen PERF_RECRORD_LOST events */
static __thread unsigned int perfRecordLost = 0;
/* Don't record branches using address above this parameter */
static __thread uint64_t perfCutOffAddr = ~(1ULL);

#define _HF_PERF_BRANCHES_SZ (1024 * 16)
/*  *INDENT-OFF* */
static __thread struct {
  uint64_t from;
  uint64_t to;
} perfBranch[_HF_PERF_BRANCHES_SZ];
/*  *INDENT-ON* */

static size_t arch_perfCountBranches(void)
{
    size_t i = 0;
    for (i = 0; i < _HF_PERF_BRANCHES_SZ; i++) {
        if (perfBranch[i].from == 0ULL && perfBranch[i].to == 0ULL) {
            return i;
        }
        LOGMSG(l_DEBUG, "Branch entry: FROM: %" PRIx64 ", TO: %" PRIx64, perfBranch[i].from,
               perfBranch[i].to);
    }
    LOGMSG(l_FATAL, "Branch buffer too small (%zu elements)", ARRAYSIZE(perfBranch));
    return i;
}

static inline void arch_perfAddBranch(uint64_t from, uint64_t to)
{
    /*
     * Kernel sometimes reports branches from the kernel (iret), we are not interested in that as it
     * makes the whole concept of unique branch counting less predictable
     */
    if (from > 0xFFFFFFFF00000000 || to > 0xFFFFFFFF00000000) {
        return;
    }
    if (from >= perfCutOffAddr || to >= perfCutOffAddr) {
        return;
    }
    for (size_t i = 0; i < _HF_PERF_BRANCHES_SZ; i++) {
        if (perfBranch[i].from == from && perfBranch[i].to == to) {
            break;
        }
        if (perfBranch[i].from == 0ULL && perfBranch[i].to == 0ULL) {
            perfBranch[i].from = from;
            perfBranch[i].to = to;
            break;
        }
    }
}

static inline void arch_perfSkip(size_t skip)
{
    struct perf_event_mmap_page *pem = (struct perf_event_mmap_page *)perfMmapBuf;
    uint64_t dataTailOff = pem->data_tail;
    dataTailOff += skip;
    if (dataTailOff > perfMmapSz) {
        dataTailOff %= perfMmapSz;
    }
    pem->data_tail = dataTailOff;
}

/* Memory Barriers */
#if defined(__x86_64__)
#define rmb()	__asm__ __volatile__ ("lfence" ::: "memory")
#elif defined(__i386__)
#define rmb()	__asm__ __volatile__ ("lock; addl $0,0(%%esp)" ::: "memory")
#else
#define rmb()	__asm__ __volatile__ ("" ::: "memory")
#endif
static inline uint64_t arch_perfGetMulti64(uint64_t * ret)
{
    struct perf_event_mmap_page *pem = (struct perf_event_mmap_page *)perfMmapBuf;
    uint64_t dataHeadOff = pem->data_head % perfMmapSz;
    rmb();
    uint64_t dataTailOff = pem->data_tail % perfMmapSz;

#if 0
    LOGMSG(l_ERROR, "HEAD: %llu TAIL: %llu", dataHeadOff, dataTailOff);
#endif

    int64_t dataLen = 0;
    if (dataHeadOff > dataTailOff) {
        dataLen = dataHeadOff - dataTailOff;
    }
    if (dataHeadOff < dataTailOff) {
        dataLen = perfMmapSz - dataTailOff + dataHeadOff;
    }

    if (dataLen < (int64_t) sizeof(uint64_t)) {
        return false;
    }

    *ret = *(uint64_t *) (perfMmapBuf + getpagesize() + dataTailOff);

    dataTailOff = (dataTailOff + sizeof(uint64_t)) % perfMmapSz;
    pem->data_tail = dataTailOff;

    return true;
}

static inline void arch_perfMmapParse(void)
{
    for (;;) {
        uint64_t tmp;
        if (arch_perfGetMulti64(&tmp) == false) {
            break;
        }

        struct perf_event_header *peh = (struct perf_event_header *)&tmp;
        if (peh->type == PERF_RECORD_LOST) {
            perfRecordLost++;
            arch_perfSkip(peh->size - sizeof(uint64_t));
            continue;
        }
        if (peh->type != PERF_RECORD_SAMPLE) {
            LOGMSG(l_DEBUG, "(struct perf_event_header)->type != PERF_RECORD_SAMPLE (%" PRIu16 ")",
                   peh->type);
            arch_perfSkip(peh->size - sizeof(uint64_t));
            continue;
        }
        if (peh->misc != PERF_RECORD_MISC_USER && peh->misc != PERF_RECORD_MISC_KERNEL) {
            LOGMSG(l_FATAL,
                   "(struct perf_event_header)->type != PERF_RECORD_MISC_USER (%" PRIu16 ")",
                   peh->misc);
            arch_perfSkip(peh->size - sizeof(uint64_t));
            continue;
        }

        uint64_t from, to;
        if (arch_perfGetMulti64(&from) == false) {
            LOGMSG(l_FATAL, "arch_perfGetMulti64(&from) failed");
        }
        if (arch_perfGetMulti64(&to) == false) {
            LOGMSG(l_FATAL, "arch_perfGetMulti64(&to) failed");
        }

        arch_perfAddBranch(from, to);
    }
{'fraction_non_alphanumeric': 0.12988485694347524, 'fraction_numerical': 0.021807397069085833, 'mean_word_length': 2.785077583360845, 'pattern_counts': {'":': 0, '<': 45, '<?xml version=': 0, '>': 81, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 8, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1397905', 'n_tokens_mistral': 4206, 'n_tokens_neox': 3974, 'n_words': 979}