• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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