xref: /freebsd/contrib/processor-trace/libipt/src/pt_insn.c (revision a25896ca1270e25b657ceaa8d47d5699515f5c25)
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 }
373