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