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