Home | History | Annotate | Download | only in linux
      1 /*
      2  *
      3  * honggfuzz - Intel PT decoder
      4  * -----------------------------------------
      5  *
      6  * Author: Robert Swiecki <swiecki (at) google.com>
      7  *
      8  * Copyright 2010-2018 by Google Inc. All Rights Reserved.
      9  *
     10  * Licensed under the Apache License, Version 2.0 (the "License"); you may
     11  * not use this file except in compliance with the License. You may obtain
     12  * a copy of the License at
     13  *
     14  * http://www.apache.org/licenses/LICENSE-2.0
     15  *
     16  * Unless required by applicable law or agreed to in writing, software
     17  * distributed under the License is distributed on an "AS IS" BASIS,
     18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
     19  * implied. See the License for the specific language governing
     20  * permissions and limitations under the License.
     21  *
     22  */
     23 
     24 #include "libhfcommon/common.h"
     25 
     26 #include <inttypes.h>
     27 #include <linux/perf_event.h>
     28 #include <stdio.h>
     29 
     30 #include "libhfcommon/log.h"
     31 #include "libhfcommon/util.h"
     32 #include "pt.h"
     33 
     34 #ifdef _HF_LINUX_INTEL_PT_LIB
     35 
     36 #include <intel-pt.h>
     37 
     38 struct pt_cpu ptCpu = {
     39     .vendor = pcv_unknown,
     40     .family = 0,
     41     .model = 0,
     42     .stepping = 0,
     43 };
     44 
     45 void perf_ptInit(void) {
     46     FILE* f = fopen("/proc/cpuinfo", "rb");
     47     if (!f) {
     48         PLOG_E("Couldn't open '/proc/cpuinfo'");
     49         return;
     50     }
     51     for (;;) {
     52         char k[1024], t[1024], v[1024];
     53         int ret = fscanf(f, "%1023[^\t]%1023[\t]: %1023[^\n]\n", k, t, v);
     54         if (ret == EOF) {
     55             break;
     56         }
     57         if (ret != 3) {
     58             break;
     59         }
     60         if (strcmp(k, "vendor_id") == 0) {
     61             if (strcmp(v, "GenuineIntel") == 0) {
     62                 ptCpu.vendor = pcv_intel;
     63                 LOG_D("IntelPT vendor: Intel");
     64             } else {
     65                 ptCpu.vendor = pcv_unknown;
     66                 LOG_D("Current processor is not Intel, IntelPT will not work");
     67             }
     68         }
     69         if (strcmp(k, "cpu family") == 0) {
     70             ptCpu.family = atoi(v);
     71             LOG_D("IntelPT family: %" PRIu16, ptCpu.family);
     72         }
     73         if (strcmp(k, "model") == 0) {
     74             ptCpu.model = atoi(v);
     75             LOG_D("IntelPT model: %" PRIu8, ptCpu.model);
     76         }
     77         if (strcmp(k, "stepping") == 0) {
     78             ptCpu.stepping = atoi(v);
     79             LOG_D("IntelPT stepping: %" PRIu8, ptCpu.stepping);
     80         }
     81     }
     82     fclose(f);
     83 }
     84 
     85 /* Sign-extend a uint64_t value. */
     86 inline static uint64_t sext(uint64_t val, uint8_t sign) {
     87     uint64_t signbit, mask;
     88 
     89     signbit = 1ull << (sign - 1);
     90     mask = ~0ull << sign;
     91 
     92     return val & signbit ? val | mask : val & ~mask;
     93 }
     94 
     95 __attribute__((hot)) inline static void perf_ptAnalyzePkt(run_t* run, struct pt_packet* packet) {
     96     if (packet->type != ppt_tip) {
     97         return;
     98     }
     99 
    100     uint64_t ip;
    101     switch (packet->payload.ip.ipc) {
    102         case pt_ipc_update_16:
    103             ip = packet->payload.ip.ip & 0xFFFF;
    104             break;
    105         case pt_ipc_update_32:
    106             ip = packet->payload.ip.ip & 0xFFFFFFFF;
    107             break;
    108         case pt_ipc_update_48:
    109             ip = packet->payload.ip.ip & 0xFFFFFFFFFFFF;
    110             break;
    111         case pt_ipc_sext_48:
    112             ip = sext(packet->payload.ip.ip, 48);
    113             break;
    114         case pt_ipc_full:
    115             ip = packet->payload.ip.ip;
    116             break;
    117         default:
    118             return;
    119     }
    120 
    121     if (ip >= run->global->linux.dynamicCutOffAddr) {
    122         return;
    123     }
    124 
    125     ip &= _HF_PERF_BITMAP_BITSZ_MASK;
    126     register uint8_t prev = ATOMIC_BTS(run->global->feedback.feedbackMap->bbMapPc, ip);
    127     if (!prev) {
    128         run->linux.hwCnts.newBBCnt++;
    129     }
    130     return;
    131 }
    132 
    133 void arch_ptAnalyze(run_t* run) {
    134     struct perf_event_mmap_page* pem = (struct perf_event_mmap_page*)run->linux.perfMmapBuf;
    135 
    136     uint64_t aux_tail = ATOMIC_GET(pem->aux_tail);
    137     uint64_t aux_head = ATOMIC_GET(pem->aux_head);
    138 
    139     /* smp_rmb() required as per /usr/include/linux/perf_event.h */
    140     rmb();
    141 
    142     struct pt_config ptc;
    143     pt_config_init(&ptc);
    144     ptc.begin = &run->linux.perfMmapAux[aux_tail];
    145     ptc.end = &run->linux.perfMmapAux[aux_head];
    146     ptc.cpu = ptCpu;
    147 
    148     int errcode = pt_cpu_errata(&ptc.errata, &ptc.cpu);
    149     if (errcode < 0) {
    150         LOG_F("pt_errata() failed: %s", pt_errstr(-errcode));
    151     }
    152 
    153     struct pt_packet_decoder* ptd = pt_pkt_alloc_decoder(&ptc);
    154     if (ptd == NULL) {
    155         LOG_F("pt_pkt_alloc_decoder() failed");
    156     }
    157     defer {
    158         pt_pkt_free_decoder(ptd);
    159     };
    160 
    161     errcode = pt_pkt_sync_forward(ptd);
    162     if (errcode < 0) {
    163         LOG_W("pt_pkt_sync_forward() failed: %s", pt_errstr(-errcode));
    164         return;
    165     }
    166 
    167     for (;;) {
    168         struct pt_packet packet;
    169         errcode = pt_pkt_next(ptd, &packet, sizeof(packet));
    170         if (errcode == -pte_eos) {
    171             break;
    172         }
    173         if (errcode < 0) {
    174             LOG_W("pt_pkt_next() failed: %s", pt_errstr(-errcode));
    175             break;
    176         }
    177         perf_ptAnalyzePkt(run, &packet);
    178     }
    179 }
    180 
    181 #else /* _HF_LINUX_INTEL_PT_LIB */
    182 
    183 void perf_ptInit(void) {
    184     return;
    185 }
    186 
    187 void arch_ptAnalyze(run_t* fuzzer HF_ATTR_UNUSED) {
    188     LOG_F(
    189         "The program has not been linked against the Intel's Processor Trace Library (libipt.so)");
    190 }
    191 
    192 #endif /* _HF_LINUX_INTEL_PT_LIB */
    193