]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/processor-trace/libipt/src/pt_insn.c
Update mandoc to 1.14.5
[FreeBSD/FreeBSD.git] / contrib / processor-trace / libipt / src / pt_insn.c
1 /*
2  * Copyright (c) 2016-2018, 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 += iext->variant.branch.displacement;
191                         break;
192                 }
193
194                 fallthrough;
195         default:
196                 return -pte_bad_query;
197
198         case ptic_error:
199                 return -pte_bad_insn;
200         }
201
202         if (pip)
203                 *pip = ip;
204
205         return 0;
206 }
207
208 /* Retry decoding an instruction after a preceding decode error.
209  *
210  * Instruction length decode typically fails due to 'not enough
211  * bytes'.
212  *
213  * This may be caused by partial updates of text sections
214  * represented via new image sections overlapping the original
215  * text section's image section.  We stop reading memory at the
216  * end of the section so we do not read the full instruction if
217  * parts of it have been overwritten by the update.
218  *
219  * Try to read the remaining bytes and decode the instruction again.  If we
220  * succeed, set @insn->truncated to indicate that the instruction is truncated
221  * in @insn->isid.
222  *
223  * Returns zero on success, a negative error code otherwise.
224  * Returns -pte_bad_insn if the instruction could not be decoded.
225  */
226 static int pt_insn_decode_retry(struct pt_insn *insn, struct pt_insn_ext *iext,
227                                 struct pt_image *image,
228                                 const struct pt_asid *asid)
229 {
230         int size, errcode, isid;
231         uint8_t isize, remaining;
232
233         if (!insn)
234                 return -pte_internal;
235
236         isize = insn->size;
237         remaining = sizeof(insn->raw) - isize;
238
239         /* We failed for real if we already read the maximum number of bytes for
240          * an instruction.
241          */
242         if (!remaining)
243                 return -pte_bad_insn;
244
245         /* Read the remaining bytes from the image. */
246         size = pt_image_read(image, &isid, &insn->raw[isize], remaining, asid,
247                              insn->ip + isize);
248         if (size <= 0) {
249                 /* We should have gotten an error if we were not able to read at
250                  * least one byte.  Check this to guarantee termination.
251                  */
252                 if (!size)
253                         return -pte_internal;
254
255                 /* Preserve the original error if there are no more bytes. */
256                 if (size == -pte_nomap)
257                         size = -pte_bad_insn;
258
259                 return size;
260         }
261
262         /* Add the newly read bytes to the instruction's size. */
263         insn->size += (uint8_t) size;
264
265         /* Store the new size to avoid infinite recursion in case instruction
266          * decode fails after length decode, which would set @insn->size to the
267          * actual length.
268          */
269         size = insn->size;
270
271         /* Try to decode the instruction again.
272          *
273          * If we fail again, we recursively retry again until we either fail to
274          * read more bytes or reach the maximum number of bytes for an
275          * instruction.
276          */
277         errcode = pt_ild_decode(insn, iext);
278         if (errcode < 0) {
279                 if (errcode != -pte_bad_insn)
280                         return errcode;
281
282                 /* If instruction length decode already determined the size,
283                  * there's no point in reading more bytes.
284                  */
285                 if (insn->size != (uint8_t) size)
286                         return errcode;
287
288                 return pt_insn_decode_retry(insn, iext, image, asid);
289         }
290
291         /* We succeeded this time, so the instruction crosses image section
292          * boundaries.
293          *
294          * This poses the question which isid to use for the instruction.
295          *
296          * To reconstruct exactly this instruction at a later time, we'd need to
297          * store all isids involved together with the number of bytes read for
298          * each isid.  Since @insn already provides the exact bytes for this
299          * instruction, we assume that the isid will be used solely for source
300          * correlation.  In this case, it should refer to the first byte of the
301          * instruction - as it already does.
302          */
303         insn->truncated = 1;
304
305         return errcode;
306 }
307
308 int pt_insn_decode(struct pt_insn *insn, struct pt_insn_ext *iext,
309                    struct pt_image *image, const struct pt_asid *asid)
310 {
311         int size, errcode;
312
313         if (!insn)
314                 return -pte_internal;
315
316         /* Read the memory at the current IP in the current address space. */
317         size = pt_image_read(image, &insn->isid, insn->raw, sizeof(insn->raw),
318                              asid, insn->ip);
319         if (size < 0)
320                 return size;
321
322         /* We initialize @insn->size to the maximal possible size.  It will be
323          * set to the actual size during instruction decode.
324          */
325         insn->size = (uint8_t) size;
326
327         errcode = pt_ild_decode(insn, iext);
328         if (errcode < 0) {
329                 if (errcode != -pte_bad_insn)
330                         return errcode;
331
332                 /* If instruction length decode already determined the size,
333                  * there's no point in reading more bytes.
334                  */
335                 if (insn->size != (uint8_t) size)
336                         return errcode;
337
338                 return pt_insn_decode_retry(insn, iext, image, asid);
339         }
340
341         return errcode;
342 }
343
344 int pt_insn_range_is_contiguous(uint64_t begin, uint64_t end,
345                                 enum pt_exec_mode mode, struct pt_image *image,
346                                 const struct pt_asid *asid, size_t steps)
347 {
348         struct pt_insn_ext iext;
349         struct pt_insn insn;
350
351         memset(&insn, 0, sizeof(insn));
352
353         insn.mode = mode;
354         insn.ip = begin;
355
356         while (insn.ip != end) {
357                 int errcode;
358
359                 if (!steps--)
360                         return 0;
361
362                 errcode = pt_insn_decode(&insn, &iext, image, asid);
363                 if (errcode < 0)
364                         return errcode;
365
366                 errcode = pt_insn_next_ip(&insn.ip, &insn, &iext);
367                 if (errcode < 0)
368                         return errcode;
369         }
370
371         return 1;
372 }