1 /*
2 *
3 * honggfuzz - Intel PT decoder
4 * -----------------------------------------
5 *
6 * Author: Robert Swiecki <swiecki@google.com>
7 *
8 * Copyright 2010-2016 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 "common.h"
25 #include "linux/pt.h"
26
27 #include <linux/perf_event.h>
28 #include <inttypes.h>
29
30 #include "log.h"
31
32 #ifdef _HF_LINUX_INTEL_PT_LIB
33
34 #include <intel-pt.h>
35
36 /*
37 * Copyright (c) 2013-2016, Intel Corporation
38 *
39 * Redistribution and use in source and binary forms, with or without
40 * modification, are permitted provided that the following conditions are met:
41 *
42 * * Redistributions of source code must retain the above copyright notice,
43 * this list of conditions and the following disclaimer.
44 * * Redistributions in binary form must reproduce the above copyright notice,
45 * this list of conditions and the following disclaimer in the documentation
46 * and/or other materials provided with the distribution.
47 * * Neither the name of Intel Corporation nor the names of its contributors
48 * may be used to endorse or promote products derived from this software
49 * without specific prior written permission.
50 *
51 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
52 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
55 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
56 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
57 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
58 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
59 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
60 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
61 * POSSIBILITY OF SUCH DAMAGE.
62 */
63
64 /* Keeping track of the last-ip in Intel PT packets. */
65 struct pt_last_ip {
66 /* The last IP. */
67 uint64_t ip;
68
69 /* Flags governing the handling of IP updates and queries:
70 *
71 * - we have seen an IP update.
72 */
73 uint32_t have_ip:1;
74 /* - the IP has been suppressed in the last update. */
75 uint32_t suppressed:1;
76 };
77
pt_last_ip_init(struct pt_last_ip * last_ip)78 inline static void pt_last_ip_init(struct pt_last_ip *last_ip)
79 {
80 if (!last_ip)
81 return;
82
83 last_ip->ip = 0ull;
84 last_ip->have_ip = 0;
85 last_ip->suppressed = 0;
86 }
87
pt_last_ip_query(uint64_t * ip,const struct pt_last_ip * last_ip)88 inline static int pt_last_ip_query(uint64_t * ip, const struct pt_last_ip *last_ip)
89 {
90 if (!last_ip)
91 return -pte_invalid;
92
93 if (!last_ip->have_ip) {
94 if (ip)
95 *ip = 0ull;
96 return -pte_noip;
97 }
98
99 if (last_ip->suppressed) {
100 if (ip)
101 *ip = 0ull;
102 return -pte_ip_suppressed;
103 }
104
105 if (ip)
106 *ip = last_ip->ip;
107
108 return 0;
109 }
110
111 /* Sign-extend a uint64_t value. */
sext(uint64_t val,uint8_t sign)112 inline static uint64_t sext(uint64_t val, uint8_t sign)
113 {
114 uint64_t signbit, mask;
115
116 signbit = 1ull << (sign - 1);
117 mask = ~0ull << sign;
118
119 return val & signbit ? val | mask : val & ~mask;
120 }
121
pt_last_ip_update_ip(struct pt_last_ip * last_ip,const struct pt_packet_ip * packet,const struct pt_config * config)122 inline static int pt_last_ip_update_ip(struct pt_last_ip *last_ip,
123 const struct pt_packet_ip *packet,
124 const struct pt_config *config)
125 {
126 (void)config;
127
128 if (!last_ip || !packet)
129 return -pte_invalid;
130
131 switch (packet->ipc) {
132 case pt_ipc_suppressed:
133 last_ip->suppressed = 1;
134 return 0;
135
136 case pt_ipc_sext_48:
137 last_ip->ip = sext(packet->ip, 48);
138 last_ip->have_ip = 1;
139 last_ip->suppressed = 0;
140 return 0;
141
142 case pt_ipc_update_16:
143 last_ip->ip = (last_ip->ip & ~0xffffull)
144 | (packet->ip & 0xffffull);
145 last_ip->have_ip = 1;
146 last_ip->suppressed = 0;
147 return 0;
148
149 case pt_ipc_update_32:
150 last_ip->ip = (last_ip->ip & ~0xffffffffull)
151 | (packet->ip & 0xffffffffull);
152 last_ip->have_ip = 1;
153 last_ip->suppressed = 0;
154 return 0;
155
156 case pt_ipc_update_48:
157 last_ip->ip = (last_ip->ip & ~0xffffffffffffull)
158 | (packet->ip & 0xffffffffffffull);
159 last_ip->have_ip = 1;
160 last_ip->suppressed = 0;
161 return 0;
162
163 case pt_ipc_full:
164 last_ip->ip = packet->ip;
165 last_ip->have_ip = 1;
166 last_ip->suppressed = 0;
167 return 0;
168 }
169
170 return -pte_bad_packet;
171 }
172
perf_ptAnalyzePkt(struct pt_packet * packet,struct pt_config * ptc,struct pt_last_ip * last_ip,void (* add_branch)(uint64_t from,uint64_t to))173 inline static void perf_ptAnalyzePkt(struct pt_packet *packet, struct pt_config *ptc,
174 struct pt_last_ip *last_ip, void (*add_branch) (uint64_t from,
175 uint64_t to))
176 {
177 switch (packet->type) {
178 case ppt_tip:
179 case ppt_fup:
180 case ppt_tip_pge:
181 case ppt_tip_pgd:
182 break;
183 default:
184 return;
185 }
186
187 int errcode = pt_last_ip_update_ip(last_ip, &(packet->payload.ip), ptc);
188 if (errcode < 0) {
189 LOG_F("pt_last_ip_update_ip() failed: %s", pt_errstr(errcode));
190 }
191
192 uint64_t ip;
193 errcode = pt_last_ip_query(&ip, last_ip);
194 if (errcode < 0) {
195 return;
196 }
197
198 /* Update only on TIP, other packets don't indicate a branch */
199 if (packet->type == ppt_tip) {
200 add_branch(ip, 0UL);
201 }
202 }
203
arch_ptAnalyze(struct perf_event_mmap_page * pem,uint8_t * auxBuf,void (* add_branch)(uint64_t from,uint64_t to))204 void arch_ptAnalyze(struct perf_event_mmap_page *pem, uint8_t * auxBuf,
205 void (*add_branch) (uint64_t from, uint64_t to))
206 {
207 struct pt_config ptc;
208 pt_config_init(&ptc);
209 ptc.begin = &auxBuf[pem->aux_tail];
210 ptc.end = &auxBuf[pem->aux_head - 1];
211
212 int errcode = pt_cpu_errata(&ptc.errata, &ptc.cpu);
213 if (errcode < 0) {
214 LOG_F("pt_errata() failed: %s", pt_errstr(errcode));
215 }
216
217 struct pt_packet_decoder *ptd = pt_pkt_alloc_decoder(&ptc);
218 if (ptd == NULL) {
219 LOG_F("pt_pkt_alloc_decoder() failed");
220 }
221
222 errcode = pt_pkt_sync_forward(ptd);
223 if (errcode < 0) {
224 LOG_W("pt_pkt_sync_forward() failed: %s", pt_errstr(errcode));
225 return;
226 }
227
228 struct pt_last_ip last_ip;
229 pt_last_ip_init(&last_ip);
230 for (;;) {
231 struct pt_packet packet;
232 errcode = pt_pkt_next(ptd, &packet, sizeof(packet));
233 if (errcode == -pte_eos) {
234 break;
235 }
236 if (errcode < 0) {
237 LOG_W("pt_pkt_next() failed: %s", pt_errstr(errcode));
238 return;
239 }
240 perf_ptAnalyzePkt(&packet, &ptc, &last_ip, add_branch);
241 }
242
243 pt_pkt_free_decoder(ptd);
244 }
245
246 #else /* _HF_LINUX_INTEL_PT_LIB */
247
arch_ptAnalyze(struct perf_event_mmap_page * pem UNUSED,uint8_t * auxBuf UNUSED,void (* add_branch)(uint64_t from,uint64_t to)UNUSED)248 void arch_ptAnalyze(struct perf_event_mmap_page *pem UNUSED, uint8_t * auxBuf UNUSED,
249 void (*add_branch) (uint64_t from, uint64_t to) UNUSED)
250 {
251 LOG_F
252 ("The program has not been linked against the Intel's Processor Trace Library (libipt.so)");
253 }
254
255 #endif /* _HF_LINUX_INTEL_PT_LIB */
256