]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/processor-trace/libipt/src/pt_sync.c
MFV r357687: Import NFS fix for O_SEARCH tests
[FreeBSD/FreeBSD.git] / contrib / processor-trace / libipt / src / pt_sync.c
1 /*
2  * Copyright (c) 2013-2019, Intel Corporation
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  *  * Redistributions of source code must retain the above copyright notice,
8  *    this list of conditions and the following disclaimer.
9  *  * Redistributions in binary form must reproduce the above copyright notice,
10  *    this list of conditions and the following disclaimer in the documentation
11  *    and/or other materials provided with the distribution.
12  *  * Neither the name of Intel Corporation nor the names of its contributors
13  *    may be used to endorse or promote products derived from this software
14  *    without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "pt_sync.h"
30 #include "pt_packet.h"
31 #include "pt_opcodes.h"
32
33 #include "intel-pt.h"
34
35
36 /* A psb packet contains a unique 2-byte repeating pattern.
37  *
38  * There are only two ways to fill up a 64bit work with such a pattern.
39  */
40 static const uint64_t psb_pattern[] = {
41         ((uint64_t) pt_psb_lohi         | (uint64_t) pt_psb_lohi << 16 |
42          (uint64_t) pt_psb_lohi << 32   | (uint64_t) pt_psb_lohi << 48),
43         ((uint64_t) pt_psb_hilo         | (uint64_t) pt_psb_hilo << 16 |
44          (uint64_t) pt_psb_hilo << 32   | (uint64_t) pt_psb_hilo << 48)
45 };
46
47 static const uint8_t *truncate(const uint8_t *pointer, size_t alignment)
48 {
49         uintptr_t raw = (uintptr_t) pointer;
50
51         raw /= alignment;
52         raw *= alignment;
53
54         return (const uint8_t *) raw;
55 }
56
57 static const uint8_t *align(const uint8_t *pointer, size_t alignment)
58 {
59         return truncate(pointer + alignment - 1, alignment);
60 }
61
62 /* Find a psb packet given a position somewhere in the payload.
63  *
64  * Return the position of the psb packet.
65  * Return NULL, if this is not a psb packet.
66  */
67 static const uint8_t *pt_find_psb(const uint8_t *pos,
68                                   const struct pt_config *config)
69 {
70         const uint8_t *begin, *end;
71         int errcode;
72
73         if (!pos || !config)
74                 return NULL;
75
76         begin = config->begin;
77         end = config->end;
78
79         /* Navigate to the end of the psb payload pattern.
80          *
81          * Beware that PSB is an extended opcode. We must not confuse the extend
82          * opcode of the following packet as belonging to the PSB.
83          */
84         if (*pos != pt_psb_hi)
85                 pos++;
86
87         for (; (pos + 1) < end; pos += 2) {
88                 uint8_t hi, lo;
89
90                 hi = pos[0];
91                 lo = pos[1];
92
93                 if (hi != pt_psb_hi)
94                         break;
95
96                 if (lo != pt_psb_lo)
97                         break;
98         }
99         /*
100          * We're right after the psb payload and within the buffer.
101          * Navigate to the expected beginning of the psb packet.
102          */
103         pos -= ptps_psb;
104
105         /* Check if we're still inside the buffer. */
106         if (pos < begin)
107                 return NULL;
108
109         /* Check that this is indeed a psb packet we're at. */
110         if (pos[0] != pt_opc_psb || pos[1] != pt_ext_psb)
111                 return NULL;
112
113         errcode = pt_pkt_read_psb(pos, config);
114         if (errcode < 0)
115                 return NULL;
116
117         return pos;
118 }
119
120 static int pt_sync_within_bounds(const uint8_t *pos, const uint8_t *begin,
121                                  const uint8_t *end)
122 {
123         /* We allow @pos == @end representing the very end of the trace.
124          *
125          * This will result in -pte_eos when we actually try to read from @pos.
126          */
127         return (begin <= pos) && (pos <= end);
128 }
129
130 int pt_sync_set(const uint8_t **sync, const uint8_t *pos,
131                 const struct pt_config *config)
132 {
133         const uint8_t *begin, *end;
134         int errcode;
135
136         if (!sync || !pos || !config)
137                 return -pte_internal;
138
139         begin = config->begin;
140         end = config->end;
141
142         if (!pt_sync_within_bounds(pos, begin, end))
143                 return -pte_eos;
144
145         if (end < pos + 2)
146                 return -pte_eos;
147
148         /* Check that this is indeed a psb packet we're at. */
149         if (pos[0] != pt_opc_psb || pos[1] != pt_ext_psb)
150                 return -pte_nosync;
151
152         errcode = pt_pkt_read_psb(pos, config);
153         if (errcode < 0)
154                 return errcode;
155
156         *sync = pos;
157
158         return 0;
159 }
160
161 int pt_sync_forward(const uint8_t **sync, const uint8_t *pos,
162                     const struct pt_config *config)
163 {
164         const uint8_t *begin, *end, *start;
165
166         if (!sync || !pos || !config)
167                 return -pte_internal;
168
169         start = pos;
170         begin = config->begin;
171         end = config->end;
172
173         if (!pt_sync_within_bounds(pos, begin, end))
174                 return -pte_internal;
175
176         /* We search for a full 64bit word. It's OK to skip the current one. */
177         pos = align(pos, sizeof(*psb_pattern));
178
179         /* Search for the psb payload pattern in the buffer. */
180         for (;;) {
181                 const uint8_t *current = pos;
182                 uint64_t val;
183
184                 pos += sizeof(uint64_t);
185                 if (end < pos)
186                         return -pte_eos;
187
188                 val = * (const uint64_t *) current;
189
190                 if ((val != psb_pattern[0]) && (val != psb_pattern[1]))
191                         continue;
192
193                 /* We found a 64bit word's worth of psb payload pattern. */
194                 current = pt_find_psb(pos, config);
195                 if (!current)
196                         continue;
197
198                 /* If @start points inside a PSB, we may find that one.  Ignore
199                  * it unless @start points to its beginning.
200                  */
201                 if (current < start)
202                         continue;
203
204                 *sync = current;
205                 return 0;
206         }
207 }
208
209 int pt_sync_backward(const uint8_t **sync, const uint8_t *pos,
210                     const struct pt_config *config)
211 {
212         const uint8_t *begin, *end;
213
214         if (!sync || !pos || !config)
215                 return -pte_internal;
216
217         begin = config->begin;
218         end = config->end;
219
220         if (!pt_sync_within_bounds(pos, begin, end))
221                 return -pte_internal;
222
223         /* We search for a full 64bit word. It's OK to skip the current one. */
224         pos = truncate(pos, sizeof(*psb_pattern));
225
226         /* Search for the psb payload pattern in the buffer. */
227         for (;;) {
228                 const uint8_t *next = pos;
229                 uint64_t val;
230
231                 pos -= sizeof(uint64_t);
232                 if (pos < begin)
233                         return -pte_eos;
234
235                 val = * (const uint64_t *) pos;
236
237                 if ((val != psb_pattern[0]) && (val != psb_pattern[1]))
238                         continue;
239
240                 /* We found a 64bit word's worth of psb payload pattern. */
241                 next = pt_find_psb(next, config);
242                 if (!next)
243                         continue;
244
245                 *sync = next;
246                 return 0;
247         }
248 }