1 /*
2 *
3 * honggfuzz - Intel PT decoder
4 * -----------------------------------------
5 *
6 * Author: Robert Swiecki <swiecki@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
perf_ptInit(void)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. */
sext(uint64_t val,uint8_t sign)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
perf_ptAnalyzePkt(run_t * run,struct pt_packet * packet)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
arch_ptAnalyze(run_t * run)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
perf_ptInit(void)183 void perf_ptInit(void) {
184 return;
185 }
186
arch_ptAnalyze(run_t * fuzzer HF_ATTR_UNUSED)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