]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/processor-trace/libipt/src/pt_insn.c
MFV r353141 (by phillip):
[FreeBSD/FreeBSD.git] / contrib / processor-trace / libipt / src / pt_insn.c
1 /*
2  * Copyright (c) 2016-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_insn.h"
30 #include "pt_ild.h"
31 #include "pt_image.h"
32 #include "pt_compiler.h"
33
34 #include "intel-pt.h"
35
36
37 int pt_insn_changes_cpl(const struct pt_insn *insn,
38                         const struct pt_insn_ext *iext)
39 {
40         (void) insn;
41
42         if (!iext)
43                 return 0;
44
45         switch (iext->iclass) {
46         default:
47                 return 0;
48
49         case PTI_INST_INT:
50         case PTI_INST_INT3:
51         case PTI_INST_INT1:
52         case PTI_INST_INTO:
53         case PTI_INST_IRET:
54         case PTI_INST_SYSCALL:
55         case PTI_INST_SYSENTER:
56         case PTI_INST_SYSEXIT:
57         case PTI_INST_SYSRET:
58                 return 1;
59         }
60 }
61
62 int pt_insn_changes_cr3(const struct pt_insn *insn,
63                         const struct pt_insn_ext *iext)
64 {
65         (void) insn;
66
67         if (!iext)
68                 return 0;
69
70         switch (iext->iclass) {
71         default:
72                 return 0;
73
74         case PTI_INST_MOV_CR3:
75                 return 1;
76         }
77 }
78
79 int pt_insn_is_branch(const struct pt_insn *insn,
80                       const struct pt_insn_ext *iext)
81 {
82         (void) iext;
83
84         if (!insn)
85                 return 0;
86
87         switch (insn->iclass) {
88         default:
89                 return 0;
90
91         case ptic_call:
92         case ptic_return:
93         case ptic_jump:
94         case ptic_cond_jump:
95         case ptic_far_call:
96         case ptic_far_return:
97         case ptic_far_jump:
98                 return 1;
99         }
100 }
101
102 int pt_insn_is_far_branch(const struct pt_insn *insn,
103                           const struct pt_insn_ext *iext)
104 {
105         (void) iext;
106
107         if (!insn)
108                 return 0;
109
110         switch (insn->iclass) {
111         default:
112                 return 0;
113
114         case ptic_far_call:
115         case ptic_far_return:
116         case ptic_far_jump:
117                 return 1;
118         }
119 }
120
121 int pt_insn_binds_to_pip(const struct pt_insn *insn,
122                          const struct pt_insn_ext *iext)
123 {
124         if (!iext)
125                 return 0;
126
127         switch (iext->iclass) {
128         default:
129                 return pt_insn_is_far_branch(insn, iext);
130
131         case PTI_INST_MOV_CR3:
132         case PTI_INST_VMLAUNCH:
133         case PTI_INST_VMRESUME:
134                 return 1;
135         }
136 }
137
138 int pt_insn_binds_to_vmcs(const struct pt_insn *insn,
139                           const struct pt_insn_ext *iext)
140 {
141         if (!iext)
142                 return 0;
143
144         switch (iext->iclass) {
145         default:
146                 return pt_insn_is_far_branch(insn, iext);
147
148         case PTI_INST_VMPTRLD:
149         case PTI_INST_VMLAUNCH:
150         case PTI_INST_VMRESUME:
151                 return 1;
152         }
153 }
154
155 int pt_insn_is_ptwrite(const struct pt_insn *insn,
156                        const struct pt_insn_ext *iext)
157 {
158         (void) iext;
159
160         if (!insn)
161                 return 0;
162
163         switch (insn->iclass) {
164         default:
165                 return 0;
166
167         case ptic_ptwrite:
168                 return 1;
169         }
170 }
171
172 int pt_insn_next_ip(uint64_t *pip, const struct pt_insn *insn,
173                     const struct pt_insn_ext *iext)
174 {
175         uint64_t ip;
176
177         if (!insn || !iext)
178                 return -pte_internal;
179
180         ip = insn->ip + insn->size;
181
182         switch (insn->iclass) {
183         case ptic_ptwrite:
184         case ptic_other:
185                 break;
186
187         case ptic_call:
188         case ptic_jump:
189                 if (iext->variant.branch.is_direct) {
190                         ip += (uint64_t) (int64_t)
191                                 iext->variant.branch.displacement;
192                         break;
193                 }
194
195                 fallthrough;
196         default:
197                 return -pte_bad_query;
198
199         case ptic_error:
200                 return -pte_bad_insn;
201         }
202
203         if (pip)
204                 *pip = ip;
205
206         return 0;
207 }
208
209 /* Retry decoding an instruction after a preceding decode error.
210  *
211  * Instruction length decode typically fails due to 'not enough
212  * bytes'.
213  *
214  * This may be caused by partial updates of text sections
215  * represented via new image sections overlapping the original
216  * text section's image section.  We stop reading memory at the
217  * end of the section so we do not read the full instruction if
218  * parts of it have been overwritten by the update.
219  *
220  * Try to read the remaining bytes and decode the instruction again.  If we
221  * succeed, set @insn->truncated to indicate that the instruction is truncated
222  * in @insn->isid.
223  *
224  * Returns zero on success, a negative error code otherwise.
225  * Returns -pte_bad_insn if the instruction could not be decoded.
226  */
227 static int pt_insn_decode_retry(struct pt_insn *insn, struct pt_insn_ext *iext,
228                                 struct pt_image *image,
229                                 const struct pt_asid *asid)
230 {
231         int size, errcode, isid;
232         uint8_t isize, remaining;
233
234         if (!insn)
235                 return -pte_internal;
236
237         isize = insn->size;
238         remaining = sizeof(insn->raw) - isize;
239
240         /* We failed for real if we already read the maximum number of bytes for
241          * an instruction.
242          */
243         if (!remaining)
244                 return -pte_bad_insn;
245
246         /* Read the remaining bytes from the image. */
247         size = pt_image_read(image, &isid, &insn->raw[isize], remaining, asid,
248                              insn->ip + isize);
249         if (size <= 0) {
250                 /* We should have gotten an error if we were not able to read at
251                  * least one byte.  Check this to guarantee termination.
252                  */
253                 if (!size)
254                         return -pte_internal;
255
256                 /* Preserve the original error if there are no more bytes. */
257                 if (size == -pte_nomap)
258                         size = -pte_bad_insn;
259
260                 return size;
261         }
262
263         /* Add the newly read bytes to the instruction's size. */
264         insn->size += (uint8_t) size;
265
266         /* Store the new size to avoid infinite recursion in case instruction
267          * decode fails after length decode, which would set @insn->size to the
268          * actual length.
269          */
270         size = insn->size;
271
272         /* Try to decode the instruction again.
273          *
274          * If we fail again, we recursively retry again until we either fail to
275          * read more bytes or reach the maximum number of bytes for an
276          * instruction.
277          */
278         errcode = pt_ild_decode(insn, iext);
279         if (errcode < 0) {
280                 if (errcode != -pte_bad_insn)
281                         return errcode;
282
283                 /* If instruction length decode already determined the size,
284                  * there's no point in reading more bytes.
285                  */
286                 if (insn->size != (uint8_t) size)
287                         return errcode;
288
289                 return pt_insn_decode_retry(insn, iext, image, asid);
290         }
291
292         /* We succeeded this time, so the instruction crosses image section
293          * boundaries.
294          *
295          * This poses the question which isid to use for the instruction.
296          *
297          * To reconstruct exactly this instruction at a later time, we'd need to
298          * store all isids involved together with the number of bytes read for
299          * each isid.  Since @insn already provides the exact bytes for this
300          * instruction, we assume that the isid will be used solely for source
301          * correlation.  In this case, it should refer to the first byte of the
302          * instruction - as it already does.
303          */
304         insn->truncated = 1;
305
306         return errcode;
307 }
308
309 int pt_insn_decode(struct pt_insn *insn, struct pt_insn_ext *iext,
310                    struct pt_image *image, const struct pt_asid *asid)
311 {
312         int size, errcode;
313
314         if (!insn)
315                 return -pte_internal;
316
317         /* Read the memory at the current IP in the current address space. */
318         size = pt_image_read(image, &insn->isid, insn->raw, sizeof(insn->raw),
319                              asid, insn->ip);
320         if (size < 0)
321                 return size;
322
323         /* We initialize @insn->size to the maximal possible size.  It will be
324          * set to the actual size during instruction decode.
325          */
326         insn->size = (uint8_t) size;
327
328         errcode = pt_ild_decode(insn, iext);
329         if (errcode < 0) {
330                 if (errcode != -pte_bad_insn)
331                         return errcode;
332
333                 /* If instruction length decode already determined the size,
334                  * there's no point in reading more bytes.
335                  */
336                 if (insn->size != (uint8_t) size)
337                         return errcode;
338
339                 return pt_insn_decode_retry(insn, iext, image, asid);
340         }
341
342         return errcode;
343 }
344
345 int pt_insn_range_is_contiguous(uint64_t begin, uint64_t end,
346                                 enum pt_exec_mode mode, struct pt_image *image,
347                                 const struct pt_asid *asid, size_t steps)
348 {
349         struct pt_insn_ext iext;
350         struct pt_insn insn;
351
352         memset(&insn, 0, sizeof(insn));
353
354         insn.mode = mode;
355         insn.ip = begin;
356
357         while (insn.ip != end) {
358                 int errcode;
359
360                 if (!steps--)
361                         return 0;
362
363                 errcode = pt_insn_decode(&insn, &iext, image, asid);
364                 if (errcode < 0)
365                         return errcode;
366
367                 errcode = pt_insn_next_ip(&insn.ip, &insn, &iext);
368                 if (errcode < 0)
369                         return errcode;
370         }
371
372         return 1;
373 }